mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-03 14:21:30 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21428 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			309 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//===-- CLIDebugger.cpp - Command Line Interface to the Debugger ----------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file was developed by the LLVM research group and is distributed under
 | 
						|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file contains the main implementation of the Command Line Interface to
 | 
						|
// the debugger.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "CLIDebugger.h"
 | 
						|
#include "CLICommand.h"
 | 
						|
#include "llvm/Debugger/SourceFile.h"
 | 
						|
#include "llvm/ADT/StringExtras.h"
 | 
						|
#include <iostream>
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
/// CLIDebugger constructor - This initializes the debugger to its default
 | 
						|
/// state, and initializes the command table.
 | 
						|
///
 | 
						|
CLIDebugger::CLIDebugger()
 | 
						|
  : TheProgramInfo(0), TheRuntimeInfo(0), Prompt("(llvm-db) "), ListSize(10) {
 | 
						|
  // Initialize instance variables
 | 
						|
  CurrentFile = 0;
 | 
						|
  LineListedStart = 1;
 | 
						|
  LineListedEnd = 1;
 | 
						|
  LastCurrentFrame = 0;
 | 
						|
  CurrentLanguage = 0;
 | 
						|
 | 
						|
  CLICommand *C;
 | 
						|
  //===--------------------------------------------------------------------===//
 | 
						|
  // Program startup and shutdown options
 | 
						|
  //
 | 
						|
  addCommand("file", new BuiltinCLICommand(
 | 
						|
    "Use specified file as the program to be debugged",
 | 
						|
    "The debugger looks in the current directory and the program $PATH for the"
 | 
						|
    " specified LLVM program.  It then unloads the currently loaded program and"
 | 
						|
    " loads the specified program.\n",
 | 
						|
    &CLIDebugger::fileCommand));
 | 
						|
 | 
						|
  addCommand("create", new BuiltinCLICommand(
 | 
						|
    "Start the program, halting its execution in main",
 | 
						|
    "This command creates an instance of the current program, but stops"
 | 
						|
    "\nexecution immediately.\n",
 | 
						|
    &CLIDebugger::createCommand));
 | 
						|
 | 
						|
  addCommand("kill", new BuiltinCLICommand(
 | 
						|
    "Kills the execution of the current program being debugged", "",
 | 
						|
    &CLIDebugger::killCommand));
 | 
						|
 | 
						|
  addCommand("quit", new BuiltinCLICommand(
 | 
						|
    "Exit the debugger", "",
 | 
						|
    &CLIDebugger::quitCommand));
 | 
						|
 | 
						|
  //===--------------------------------------------------------------------===//
 | 
						|
  // Program execution commands
 | 
						|
  //
 | 
						|
  addCommand("run", C = new BuiltinCLICommand(
 | 
						|
    "Start the program running from the beginning", "",
 | 
						|
    &CLIDebugger::runCommand));
 | 
						|
  addCommand("r", C);
 | 
						|
 | 
						|
  addCommand("cont", C = new BuiltinCLICommand(
 | 
						|
    "Continue program being debugged until the next stop point", "",
 | 
						|
    &CLIDebugger::contCommand));
 | 
						|
  addCommand("c", C); addCommand("fg", C);
 | 
						|
 | 
						|
  addCommand("step", C = new BuiltinCLICommand(
 | 
						|
    "Step program until it reaches a new source line", "",
 | 
						|
    &CLIDebugger::stepCommand));
 | 
						|
  addCommand("s", C);
 | 
						|
 | 
						|
  addCommand("next", C = new BuiltinCLICommand(
 | 
						|
    "Step program until it reaches a new source line, stepping over calls", "",
 | 
						|
    &CLIDebugger::nextCommand));
 | 
						|
  addCommand("n", C);
 | 
						|
 | 
						|
  addCommand("finish", new BuiltinCLICommand(
 | 
						|
    "Execute until the selected stack frame returns",
 | 
						|
   "Upon return, the value returned is printed and put in the value history.\n",
 | 
						|
    &CLIDebugger::finishCommand));
 | 
						|
 | 
						|
  //===--------------------------------------------------------------------===//
 | 
						|
  // Stack frame commands
 | 
						|
  //
 | 
						|
  addCommand("backtrace", C = new BuiltinCLICommand(
 | 
						|
   "Print backtrace of all stack frames, or innermost COUNT frames",
 | 
						|
   "FIXME: describe.  Takes 'n', '-n' or 'full'\n",
 | 
						|
    &CLIDebugger::backtraceCommand));
 | 
						|
  addCommand("bt", C);
 | 
						|
 | 
						|
  addCommand("up", new BuiltinCLICommand(
 | 
						|
    "Select and print stack frame that called this one",
 | 
						|
    "An argument says how many frames up to go.\n",
 | 
						|
    &CLIDebugger::upCommand));
 | 
						|
 | 
						|
  addCommand("down", new BuiltinCLICommand(
 | 
						|
    "Select and print stack frame called by this one",
 | 
						|
    "An argument says how many frames down go.\n",
 | 
						|
    &CLIDebugger::downCommand));
 | 
						|
 | 
						|
  addCommand("frame", C = new BuiltinCLICommand(
 | 
						|
    "Select and print a stack frame",
 | 
						|
 "With no argument, print the selected stack frame.  (See also 'info frame').\n"
 | 
						|
 "An argument specifies the frame to select.\n",
 | 
						|
    &CLIDebugger::frameCommand));
 | 
						|
  addCommand("f", C);
 | 
						|
 | 
						|
  //===--------------------------------------------------------------------===//
 | 
						|
  // Breakpoint related commands
 | 
						|
  //
 | 
						|
  addCommand("break", C = new BuiltinCLICommand(
 | 
						|
   "Set breakpoint at specified line or function",
 | 
						|
   "FIXME: describe.\n",
 | 
						|
    &CLIDebugger::breakCommand));
 | 
						|
  addCommand("b", C);
 | 
						|
 | 
						|
 | 
						|
  //===--------------------------------------------------------------------===//
 | 
						|
  // Miscellaneous commands
 | 
						|
  //
 | 
						|
  addCommand("info", new BuiltinCLICommand(
 | 
						|
    "Generic command for showing things about the program being debugged",
 | 
						|
    "info functions: display information about functions in the program.\ninfo"
 | 
						|
    " source : display information about the current source file.\ninfo source"
 | 
						|
    "s : Display source file names for the program\ninfo target : print status"
 | 
						|
    " of inferior process\n",
 | 
						|
    &CLIDebugger::infoCommand));
 | 
						|
 | 
						|
  addCommand("list", C = new BuiltinCLICommand(
 | 
						|
    "List specified function or line",
 | 
						|
    "FIXME: document\n",
 | 
						|
    &CLIDebugger::listCommand));
 | 
						|
  addCommand("l", C);
 | 
						|
 | 
						|
  addCommand("set", new BuiltinCLICommand(
 | 
						|
    "Change program or debugger variable",
 | 
						|
    "FIXME: document\n",
 | 
						|
    &CLIDebugger::setCommand));
 | 
						|
 | 
						|
  addCommand("show", new BuiltinCLICommand(
 | 
						|
    "Generic command for showing things about the debugger",
 | 
						|
    "FIXME: document\n",
 | 
						|
    &CLIDebugger::showCommand));
 | 
						|
 | 
						|
  addCommand("help", C = new BuiltinCLICommand(
 | 
						|
    "Prints information about available commands", "",
 | 
						|
    &CLIDebugger::helpCommand));
 | 
						|
  addCommand("h", C);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/// addCommand - Add a command to the CommandTable, potentially displacing a
 | 
						|
/// preexisting command.
 | 
						|
void CLIDebugger::addCommand(const std::string &Option, CLICommand *Cmd) {
 | 
						|
  assert(Cmd && "Cannot set a null command!");
 | 
						|
  CLICommand *&CS = CommandTable[Option];
 | 
						|
  if (CS == Cmd) return; // noop
 | 
						|
 | 
						|
  // If we already have a command, decrement the command's reference count.
 | 
						|
  if (CS) {
 | 
						|
    CS->removeOptionName(Option);
 | 
						|
    CS->dropRef();
 | 
						|
  }
 | 
						|
  CS = Cmd;
 | 
						|
 | 
						|
  // Remember that we are using this command.
 | 
						|
  Cmd->addRef();
 | 
						|
  Cmd->addOptionName(Option);
 | 
						|
}
 | 
						|
 | 
						|
static bool isValidPrefix(const std::string &Prefix, const std::string &Option){
 | 
						|
  return Prefix.size() <= Option.size() &&
 | 
						|
         Prefix == std::string(Option.begin(), Option.begin()+Prefix.size());
 | 
						|
}
 | 
						|
 | 
						|
/// getCommand - This looks up the specified command using a fuzzy match.
 | 
						|
/// If the string exactly matches a command or is an unambiguous prefix of a
 | 
						|
/// command, it returns the command.  Otherwise it throws an exception
 | 
						|
/// indicating the possible ambiguous choices.
 | 
						|
CLICommand *CLIDebugger::getCommand(const std::string &Command) {
 | 
						|
 | 
						|
  // Look up the command in the table.
 | 
						|
  std::map<std::string, CLICommand*>::iterator CI =
 | 
						|
    CommandTable.lower_bound(Command);
 | 
						|
 | 
						|
  if (Command == "") {
 | 
						|
    throw "Null command should not get here!";
 | 
						|
  } else if (CI == CommandTable.end() ||
 | 
						|
             !isValidPrefix(Command, CI->first)) {
 | 
						|
    // If this command has no relation to anything in the command table,
 | 
						|
    // print the error message.
 | 
						|
    throw "Unknown command: '" + Command +
 | 
						|
          "'.  Use 'help' for list of commands.";
 | 
						|
  } else if (CI->first == Command) {
 | 
						|
    // We have an exact match on the command
 | 
						|
    return CI->second;
 | 
						|
  } else {
 | 
						|
    // Otherwise, we have a prefix match.  Check to see if this is
 | 
						|
    // unambiguous, and if so, run it.
 | 
						|
    std::map<std::string, CLICommand*>::iterator CI2 = CI;
 | 
						|
 | 
						|
    // If the next command is a valid completion of this one, we are
 | 
						|
    // ambiguous.
 | 
						|
    if (++CI2 != CommandTable.end() && isValidPrefix(Command, CI2->first)) {
 | 
						|
      std::string ErrorMsg =
 | 
						|
        "Ambiguous command '" + Command + "'.  Options: " + CI->first;
 | 
						|
      for (++CI; CI != CommandTable.end() &&
 | 
						|
             isValidPrefix(Command, CI->first); ++CI)
 | 
						|
        ErrorMsg += ", " + CI->first;
 | 
						|
      throw ErrorMsg;
 | 
						|
    } else {
 | 
						|
      // It's an unambiguous prefix of a command, use it.
 | 
						|
      return CI->second;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/// run - Start the debugger, returning when the user exits the debugger.  This
 | 
						|
/// starts the main event loop of the CLI debugger.
 | 
						|
///
 | 
						|
int CLIDebugger::run() {
 | 
						|
  std::string Command;
 | 
						|
  std::cout << Prompt;
 | 
						|
 | 
						|
  // Keep track of the last command issued, so that we can reissue it if the
 | 
						|
  // user hits enter as the command.
 | 
						|
  CLICommand *LastCommand = 0;
 | 
						|
  std::string LastArgs;
 | 
						|
 | 
						|
  // Continue reading commands until the end of file.
 | 
						|
  while (getline(std::cin, Command)) {
 | 
						|
    std::string Arguments = Command;
 | 
						|
 | 
						|
    // Split off the command from the arguments to the command.
 | 
						|
    Command = getToken(Arguments, " \t\n\v\f\r\\/;.*&");
 | 
						|
 | 
						|
    try {
 | 
						|
      CLICommand *CurCommand;
 | 
						|
 | 
						|
      if (Command == "") {
 | 
						|
        CurCommand = LastCommand;
 | 
						|
        Arguments = LastArgs;
 | 
						|
      } else {
 | 
						|
        CurCommand = getCommand(Command);
 | 
						|
      }
 | 
						|
 | 
						|
      // Save the command we are running in case the user wants us to repeat it
 | 
						|
      // next time.
 | 
						|
      LastCommand = CurCommand;
 | 
						|
      LastArgs = Arguments;
 | 
						|
 | 
						|
      // Finally, execute the command.
 | 
						|
      if (CurCommand)
 | 
						|
        CurCommand->runCommand(*this, Arguments);
 | 
						|
 | 
						|
    } catch (int RetVal) {
 | 
						|
      // The quit command exits the command loop by throwing an integer return
 | 
						|
      // code.
 | 
						|
      return RetVal;
 | 
						|
    } catch (const std::string &Error) {
 | 
						|
      std::cout << "Error: " << Error << "\n";
 | 
						|
    } catch (const char *Error) {
 | 
						|
      std::cout << "Error: " << Error << "\n";
 | 
						|
    } catch (const NonErrorException &E) {
 | 
						|
      std::cout << E.getMessage() << "\n";
 | 
						|
    } catch (...) {
 | 
						|
      std::cout << "ERROR: Debugger caught unexpected exception!\n";
 | 
						|
      // Attempt to continue.
 | 
						|
    }
 | 
						|
 | 
						|
    // Write the prompt to get the next bit of user input
 | 
						|
    std::cout << Prompt;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/// askYesNo - Ask the user a question, and demand a yes/no response.  If
 | 
						|
/// the user says yes, return true.
 | 
						|
///
 | 
						|
bool CLIDebugger::askYesNo(const std::string &Message) const {
 | 
						|
  std::string Answer;
 | 
						|
  std::cout << Message << " (y or n) " << std::flush;
 | 
						|
  while (getline(std::cin, Answer)) {
 | 
						|
    std::string Val = getToken(Answer);
 | 
						|
    if (getToken(Answer).empty()) {
 | 
						|
      if (Val == "yes" || Val == "y" || Val == "YES" || Val == "Y" ||
 | 
						|
          Val == "Yes")
 | 
						|
        return true;
 | 
						|
      if (Val == "no" || Val == "n" || Val == "NO" || Val == "N" ||
 | 
						|
          Val == "No")
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    std::cout << "Please answer y or n.\n" << Message << " (y or n) "
 | 
						|
              << std::flush;
 | 
						|
  }
 | 
						|
 | 
						|
  // Ran out of input?
 | 
						|
  return false;
 | 
						|
}
 |