Add SetAsync=false; not sure of the real effect now.
[llgdb.git] / src / LLGDBMain.cpp
index 39dac35..1729f77 100644 (file)
@@ -3,23 +3,23 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <boost/format.hpp>
+#include <deque>
+#include <error.h>
+#include <lldb/API/SBCommandInterpreter.h>
+#include <lldb/API/SBCommandReturnObject.h>
+#include <lldb/API/SBDebugger.h>
 #include <lldb/API/SBHostOS.h>
+#include <lldb/API/SBStringList.h>
+#include <lldb/Utility/StreamString.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/Support/PrettyStackTrace.h>
-#include <lldb/API/SBDebugger.h>
-#include <lldb/Utility/StreamString.h>
 #include <llvm/Support/Signals.h>
-#include <lldb/API/SBCommandInterpreter.h>
-#include <lldb/API/SBCommandReturnObject.h>
-#include <lldb/API/SBStringList.h>
-#include <boost/format.hpp>
-#include <readline/readline.h>
 #include <readline/history.h>
-#include <vector>
-#include <deque>
+#include <readline/readline.h>
 #include <setjmp.h>
 #include <signal.h>
-#include <error.h>
+#include <vector>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -115,16 +115,24 @@ static void history_save(int rc, void *arg) {
   write_history(history_filename);
 }
 
-static std::string settings_show_raw(SBDebugger &dbg, const char *setting, const char *type) {
+static std::string settings_show_raw(SBDebugger &dbg, const char *setting,
+                                     const char *type) {
   SBCommandReturnObject Result;
-  dbg.GetCommandInterpreter().HandleCommand(("settings show " + std::string(setting)).c_str(), Result, /*add_to_history*/ false);
+  dbg.GetCommandInterpreter().HandleCommand(
+      ("settings show " + std::string(setting)).c_str(), Result,
+      /*add_to_history*/ false);
   assert(Result.Succeeded());
   // <plugin.process.gdb-remote.packet-timeout (unsigned) = 1\n
   std::string str = Result.GetOutput();
-  const std::string expect = (boost::format("%1% (%2%) = ") % setting % type).str();
-  if (str.compare(0,expect.length(),expect)!=0||str[str.length()-1]!='\n')
-    error(1,0,"Unexpected 'settings show' response: expected=\"%s[...]\\n\" got=\"%s\"",expect.c_str(),str.c_str());
-  return str.substr(expect.length(),str.length()-1-expect.length());
+  const std::string expect =
+      (boost::format("%1% (%2%) = ") % setting % type).str();
+  if (str.compare(0, expect.length(), expect) != 0 ||
+      str[str.length() - 1] != '\n')
+    error(1, 0,
+          "Unexpected 'settings show' response: expected=\"%s[...]\\n\" "
+          "got=\"%s\"",
+          expect.c_str(), str.c_str());
+  return str.substr(expect.length(), str.length() - 1 - expect.length());
 }
 
 #if 0
@@ -151,15 +159,20 @@ static bool settings_show_bool(SBDebugger &dbg, const char *setting) {
 #endif
 
 static std::string settings_show_string(SBDebugger &dbg, const char *setting) {
-  std::string val = settings_show_raw(dbg,setting,"string");
-  if (val.length()<2 || val[0] != '"' || val[val.length()-1]!='"')
-    error(1,0,"Unexpected 'settings show' string response: expected '\"' quoting: %s", val.c_str());
-  return val.substr(1,val.length()-2);
+  std::string val = settings_show_raw(dbg, setting, "string");
+  if (val.length() < 2 || val[0] != '"' || val[val.length() - 1] != '"')
+    error(
+        1, 0,
+        "Unexpected 'settings show' string response: expected '\"' quoting: %s",
+        val.c_str());
+  return val.substr(1, val.length() - 2);
 }
 
-static SBCommandReturnObject subcommand(SBDebugger &dbg, const char *cmd, bool print_command=true, bool add_to_history=false) {
+static SBCommandReturnObject subcommand(SBDebugger &dbg, const char *cmd,
+                                        bool print_command = true,
+                                        bool add_to_history = false) {
   if (print_command)
-    printf("%s%s\n",settings_show_string(dbg, "prompt").c_str(),cmd);
+    printf("%s%s\n", settings_show_string(dbg, "prompt").c_str(), cmd);
   SBCommandReturnObject Result;
   dbg.GetCommandInterpreter().HandleCommand(cmd, Result, add_to_history);
   Result.PutOutput(stdout);
@@ -168,7 +181,7 @@ static SBCommandReturnObject subcommand(SBDebugger &dbg, const char *cmd, bool p
 }
 
 static void default_command(SBDebugger &dbg, const char *cmd) {
-  subcommand(dbg, cmd, false/*print_command*/, true/*add_to_history*/);
+  subcommand(dbg, cmd, false /*print_command*/, true /*add_to_history*/);
 }
 
 static void quit_command(SBDebugger &dbg, const char *cmd) {
@@ -178,7 +191,7 @@ static void quit_command(SBDebugger &dbg, const char *cmd) {
 static void start_command(SBDebugger &dbg, const char *cmd) {
   if (!subcommand(dbg, "b main").Succeeded())
     return;
-  subcommand(dbg, ("run "+std::string(cmd)).c_str());
+  subcommand(dbg, ("run " + std::string(cmd)).c_str());
 }
 
 static void commands_command(SBDebugger &dbg, const char *cmd_param) {
@@ -267,14 +280,15 @@ static void commands_command(SBDebugger &dbg, const char *cmd_param) {
 struct Cmd {
   const char *name;
   int min_shortcut;
-  typedef void (func_t)(SBDebugger &dbg, const char *cmd);
+  typedef void(func_t)(SBDebugger &dbg, const char *cmd);
   func_t *func;
-  Cmd(const char *name_, int min_shortcut_, func_t *func_):name(name_),min_shortcut(min_shortcut_),func(func_) {}
+  Cmd(const char *name_, int min_shortcut_, func_t *func_)
+      : name(name_), min_shortcut(min_shortcut_), func(func_) {}
 };
 const Cmd cmds[] = {
-  Cmd("quit", 1, quit_command),
-  Cmd("start", 5, start_command),
-  Cmd("commands", 4, commands_command),
+    Cmd("quit", 1, quit_command),
+    Cmd("start", 5, start_command),
+    Cmd("commands", 4, commands_command),
 };
 
 static void executecommand(SBDebugger &dbg, const char *cmd_s) {
@@ -300,9 +314,9 @@ static void executecommand(SBDebugger &dbg, const char *cmd_s) {
 }
 
 static char *xstrdup(const char *cs) {
-  char *s = static_cast<char *>(malloc(strlen(cs)+1));
+  char *s = static_cast<char *>(malloc(strlen(cs) + 1));
   assert(s);
-  strcpy(s,cs);
+  strcpy(s, cs);
   return s;
 }
 
@@ -314,26 +328,30 @@ static char *completion_entry_function(const char *text, int matches) {
   if (matches == 0) {
     found_vec.clear();
     SBStringList matches;
-    // LLDB: FIXME: These two values are not implemented. m_match_start_point; m_max_return_elements;
+    // LLDB: FIXME: These two values are not implemented. m_match_start_point;
+    // m_max_return_elements;
     const int match_start_point = 0;
     // LLDB: Only max_return_elements == -1 is supported at present:
     const int max_return_elements = -1;
-    int got=dbg.GetCommandInterpreter().HandleCompletion(text, strlen(text)/*cursor_pos*/, match_start_point, max_return_elements, matches);
+    int got = dbg.GetCommandInterpreter().HandleCompletion(
+        text, strlen(text) /*cursor_pos*/, match_start_point,
+        max_return_elements, matches);
     assert(matches.IsValid());
-    if (unsigned(got+1)!=matches.GetSize())
-      error(1,0,"HandleCompletion=%d +1 != %u=matches.GetSize()",got,matches.GetSize());
-    //for (size_t ix=0;ix<matches.GetSize();++ix)
+    if (unsigned(got + 1) != matches.GetSize())
+      error(1, 0, "HandleCompletion=%d +1 != %u=matches.GetSize()", got,
+            matches.GetSize());
+    // for (size_t ix=0;ix<matches.GetSize();++ix)
     //  fprintf(stderr,"match[%zu]=<%s>\n",ix,matches.GetStringAtIndex(ix));
-    const char *first=matches.GetStringAtIndex(0);
-    assert(matches.GetSize()>=1);
+    const char *first = matches.GetStringAtIndex(0);
+    assert(matches.GetSize() >= 1);
     if (first[0]) {
       std::string str(first);
-      while (!str.empty()&&str.back()==' ')
-       str.pop_back();
+      while (!str.empty() && str.back() == ' ')
+        str.pop_back();
       found_vec.push_back(text + str);
     } else
-      for (size_t ix=1;ix<matches.GetSize();++ix)
-       found_vec.push_back(matches.GetStringAtIndex(ix));
+      for (size_t ix = 1; ix < matches.GetSize(); ++ix)
+        found_vec.push_back(matches.GetStringAtIndex(ix));
   }
   if (size_t(matches) < found_vec.size())
     return xstrdup(found_vec[matches].c_str());
@@ -345,6 +363,7 @@ static char *completion_entry_function(const char *text, int matches) {
 
 static std::deque<std::string> opt_iex, opt_ex;
 static std::optional<std::string> opt_exec, opt_core;
+static std::optional<lldb::pid_t> opt_pid;
 static std::vector<std::string> opt_args;
 
 std::string string_quote(std::string &&str) {
@@ -376,6 +395,11 @@ std::optional<std::string> next_arg() {
     }
     return cmd;
   }
+  if (opt_pid) {
+    std::string retval = (boost::format("attach %1%") % *opt_pid).str();
+    opt_pid.reset();
+    return retval;
+  }
   if (!opt_ex.empty()) {
     std::string retval = opt_ex.front();
     opt_ex.pop_front();
@@ -391,6 +415,12 @@ int main(int argc, char **argv) {
 
   for (int argi = 1; argi < argc; ++argi) {
     std::string arg = argv[argi];
+    auto str_to_pid = [](const std::string &str) {
+      lldb::pid_t pid_test = atoi(str.c_str());
+      return (boost::format("%1%") % pid_test).str() != str || pid_test <= 0
+                 ? 0
+                 : pid_test;
+    };
     if (arg == "-iex") {
       const char *cmd = argv[++argi];
       assert(cmd);
@@ -405,36 +435,79 @@ int main(int argc, char **argv) {
       assert(!opt_exec);
       assert(!opt_core);
       assert(opt_args.empty());
-      opt_exec=std::string(exec);
-      while (++argi<argc) {
-       arg = argv[argi];
-       opt_args.push_back(std::move(arg));
+      opt_exec = std::string(exec);
+      while (++argi < argc) {
+        arg = argv[argi];
+        opt_args.push_back(std::move(arg));
       }
+    } else if ((arg == "-e" || arg == "--exec") && argv[argi + 1])
+      opt_exec = argv[++argi];
+    else if ((arg == "-p" || arg == "--pid") && argv[argi + 1]) {
+      opt_pid = str_to_pid(argv[++argi]);
+      if (opt_pid == 0)
+        error(1, 0, "Invalid PID: %s", argv[argi]);
+    } else if ((arg == "-c" || arg == "--core") && argv[argi + 1])
+      opt_core = argv[++argi];
+    else if (arg == "-h" || arg == "--help") {
+      puts("\
+This is the GNU debugger emulation by LLDB.  Usage:\n\
+\n\
+    llgdb [options] [executable-file [core-file or process-id]]\n\
+    llgdb [options] --args executable-file [inferior-arguments ...]\n\
+\n\
+Selection of debuggee and its files:\n\
+\n\
+  --args             Arguments after executable-file are passed to inferior\n\
+  --core=COREFILE    Analyze the core dump COREFILE.\n\
+  --exec=EXECFILE    Use EXECFILE as the executable.\n\
+  --pid=PID          Attach to running process PID.\n\
+\n\
+Initial commands and command files:\n\
+\n\
+  -ex COMMAND\n\
+                     Execute a single GDB command.\n\
+                     May be used multiple times and in conjunction\n\
+                     with --command.\n\
+  -iex COMMAND\n\
+                     Like -ex but before loading inferior.\n\
+\n\
+Operating modes:\n\
+\n\
+  --help             Print this message and then exit.\n\
+\n\
+Report bugs to jan.kratochvil -at- redhat.com.\n\
+");
+      exit(1);
     } else if (!opt_exec)
-      opt_exec=std::move(arg);
+      opt_exec = std::move(arg);
+    else if (!opt_pid && str_to_pid(arg) > 0)
+      opt_pid = str_to_pid(arg);
     else if (!opt_core)
-      opt_core=std::move(arg);
+      opt_core = std::move(arg);
     else
-      error(1,0,"Excessive argument: %s",arg.c_str());
+      error(1, 0, "Excessive argument: %s", arg.c_str());
   }
 
   SBDebugger::Initialize();
-  SBDebugger dbg = SBDebugger::Create();
-  dbg.HandleCommand("settings set symbols.enable-external-lookup false");
+  SBDebugger dbg = SBDebugger::Create(true /*source_init_files*/);
+  dbg.SetAsync(false);
 
-  completion_entry_function_dbgp=&dbg;
+  completion_entry_function_dbgp = &dbg;
   rl_completion_entry_function = completion_entry_function;
   rl_readline_name = "llgdb";
 
-  if (true/*settings_show_bool(dbg, "history save")*/) {
-    int history_size = 1000000; //settings_show_int(dbg, "history size");
+  if (true /*settings_show_bool(dbg, "history save")*/) {
+    int history_size = 1000000; // settings_show_int(dbg, "history size");
     const char *HOME = getenv("HOME");
     assert(HOME);
-    static const std::string history_filename = std::string(HOME) + "/.llgdb_history"; // settings_show_string(dbg, "history filename");
-    //gdb_set_bool(dbg, "history save", false);
+    static const std::string history_filename =
+        std::string(HOME) +
+        "/.llgdb_history"; // settings_show_string(dbg, "history filename");
+    // gdb_set_bool(dbg, "history save", false);
     stifle_history(history_size);
     read_history(history_filename.c_str());
-    on_exit(history_save, static_cast<void *>(const_cast<char *>(history_filename.c_str())));
+    on_exit(history_save,
+            static_cast<void *>(const_cast<char *>(history_filename.c_str())));
     /* Do not free HISTORY_FILENAME.  */
   }
 
@@ -446,8 +519,8 @@ int main(int argc, char **argv) {
     if (!arg) {
       char *cmd_s = llgdb_readline(prompt.c_str());
       if (cmd_s)
-       add_history(cmd_s);
-      cmd = cmd_s?:"quit";
+        add_history(cmd_s);
+      cmd = cmd_s ?: "quit";
       free(cmd_s);
     } else {
       puts((prompt + *arg).c_str());