Initial checkin of the LLVM Source-Level Debugger.  This is incomplete, but
a good start.  The status is documented in docs/SourceLevelDebugging.html


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10687 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/llvm-db/CLIDebugger.cpp b/tools/llvm-db/CLIDebugger.cpp
new file mode 100644
index 0000000..2b3937a
--- /dev/null
+++ b/tools/llvm-db/CLIDebugger.cpp
@@ -0,0 +1,285 @@
+//===-- 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 "Support/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 current program, stopping execution in main",
+    "This command creates an instance of the current program, but stops"
+    " execution immediately.",
+    &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",
+    "FIXME: document\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 not implemented yet.";
+  } 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;
+
+  // 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 {
+      // Look up the command and execute it.
+      getCommand(Command)->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;
+}