1 //===-- LLGDBMain.cpp -------------------------------------------*- C++ -*-===//
4 //===----------------------------------------------------------------------===//
6 #include <boost/format.hpp>
9 #include <lldb/API/SBCommandInterpreter.h>
10 #include <lldb/API/SBCommandReturnObject.h>
11 #include <lldb/API/SBDebugger.h>
12 #include <lldb/API/SBHostOS.h>
13 #include <lldb/API/SBStringList.h>
14 #include <lldb/Utility/StreamString.h>
15 #include <llvm/ADT/StringRef.h>
16 #include <llvm/Support/PrettyStackTrace.h>
17 #include <llvm/Support/Signals.h>
18 #include <readline/history.h>
19 #include <readline/readline.h>
25 using namespace lldb_private;
27 static jmp_buf llgdb_readline_jmp_buf;
29 static void llgdb_readline_sigint_handler(int signum) {
30 assert(signum == SIGINT);
31 longjmp(llgdb_readline_jmp_buf, 1);
34 static char *llgdb_readline(const char *prompt) {
36 sighandler_t saved_handler;
40 i = sigprocmask(SIG_SETMASK, NULL, &mask);
42 saved_handler = signal(SIGINT, llgdb_readline_sigint_handler);
43 if (setjmp(llgdb_readline_jmp_buf) != 0) {
45 rl_cleanup_after_signal();
47 /* GDB prints this. */
50 i = sigprocmask(SIG_SETMASK, &mask, NULL);
53 retval = readline(prompt);
54 saved_handler = signal(SIGINT, saved_handler);
55 assert(saved_handler == llgdb_readline_sigint_handler);
60 static int console_cb_rows, console_cb_columns, console_cb_row,
62 static bool console_cb_drop;
64 static void console_cb(const char *str, void *data) {
69 if (console_cb_rows == 0) {
74 while (*str != '\0') {
79 cs = strchr(str, '\n');
81 cs = &str[strlen(str)];
82 columns = std::min(cs - str, long(console_cb_columns - console_cb_column));
84 size = fwrite(str, 1, columns, stdout);
85 assert(size == size_t(columns));
87 console_cb_column += columns;
92 else assert(console_cb_column < console_cb_columns);
95 console_cb_column = 0;
96 if (console_cb_row < console_cb_rows - 1)
98 answer = llgdb_readline("---Type <return> to continue, or q <return> to quit---");
99 for (cs = answer; isspace(*cs); cs++)
104 console_cb_drop = true;
113 static void history_save(int rc, void *arg) {
114 const char *history_filename = static_cast<const char *>(arg);
115 write_history(history_filename);
118 static std::string settings_show_raw(SBDebugger &dbg, const char *setting,
120 SBCommandReturnObject Result;
121 dbg.GetCommandInterpreter().HandleCommand(
122 ("settings show " + std::string(setting)).c_str(), Result,
123 /*add_to_history*/ false);
124 assert(Result.Succeeded());
125 // <plugin.process.gdb-remote.packet-timeout (unsigned) = 1\n
126 std::string str = Result.GetOutput();
127 const std::string expect =
128 (boost::format("%1% (%2%) = ") % setting % type).str();
129 if (str.compare(0, expect.length(), expect) != 0 ||
130 str[str.length() - 1] != '\n')
132 "Unexpected 'settings show' response: expected=\"%s[...]\\n\" "
134 expect.c_str(), str.c_str());
135 return str.substr(expect.length(), str.length() - 1 - expect.length());
139 static int settings_show_int(SBDebugger &dbg, const char *setting) {
140 std::string string = settings_show_raw(dbg, setting,"unsigned");
146 retval = l = strtol(string.c_str(), &end, 10);
147 assert(errno == 0 && (end == NULL || *end == '\0') && retval == l);
151 static bool settings_show_bool(SBDebugger &dbg, const char *setting) {
152 std::string string = settings_show_raw(dbg, setting,"unsigned");
155 retval = (string == "on");
156 assert(retval || string == "off");
161 static std::string settings_show_string(SBDebugger &dbg, const char *setting) {
162 std::string val = settings_show_raw(dbg, setting, "string");
163 if (val.length() < 2 || val[0] != '"' || val[val.length() - 1] != '"')
166 "Unexpected 'settings show' string response: expected '\"' quoting: %s",
168 return val.substr(1, val.length() - 2);
171 static SBCommandReturnObject subcommand(SBDebugger &dbg, const char *cmd,
172 bool print_command = true,
173 bool add_to_history = false) {
175 printf("%s%s\n", settings_show_string(dbg, "prompt").c_str(), cmd);
176 SBCommandReturnObject Result;
177 dbg.GetCommandInterpreter().HandleCommand(cmd, Result, add_to_history);
178 Result.PutOutput(stdout);
179 Result.PutError(stdout);
183 static void default_command(SBDebugger &dbg, const char *cmd) {
184 subcommand(dbg, cmd, false /*print_command*/, true /*add_to_history*/);
187 static void quit_command(SBDebugger &dbg, const char *cmd) {
191 static void start_command(SBDebugger &dbg, const char *cmd) {
192 if (!subcommand(dbg, "b main").Succeeded())
194 subcommand(dbg, ("run " + std::string(cmd)).c_str());
197 static void commands_command(SBDebugger &dbg, const char *cmd_param) {
199 char *cmd = xstrdup("");
205 if (*cmd_param == '\0') {
206 mi_set_console_cb(h, commands_command_console_cb, &bpnum);
207 dbg.HandleCommand(h, "output $bpnum");
208 mi_set_console_cb(h, console_cb, NULL);
209 assert(bpnum != NULL);
213 printf(_("Type commands for breakpoint(s) %s, one per line.\n"
214 "End with a line saying just \"end\".\n"),
218 while (nesting >= 0) {
219 char *prompt, *data, *data2, *start, *end;
223 prompt = xstrprintf("%*s>", (int)nesting);
224 data = llgdb_readline(prompt);
227 data = xstrdup("end");
229 for (start = data; isspace(*start); start++)
231 for (end = data + strlen(data); end > start && isspace(end[-1]); end--)
233 data2 = malloc(end - start + 1);
234 memcpy(data2, start, end - start);
235 data2[end - start] = '\0';
236 if (strcmp(data2, "python") == 0)
238 if (strcmp(data2, "end") == 0)
240 for (end = data2; *end && !isspace(*end); end++)
244 /* Here is a bug in GDB, it does not recognize command shortcuts. */
245 if (strcmp(data2, "while") == 0 || strcmp(data2, "if") == 0 ||
246 strcmp(data2, "commands") == 0 ||
247 strcmp(data2, "while-stepping") == 0 ||
248 strcmp(data2, "stepping") == 0 || strcmp(data2, "ws") == 0)
256 data2 = mi_escape(data);
258 data2_len = strlen(data2);
259 cmd = xrealloc(cmd, cmd_len + 2 + data2_len + 2);
261 cmd[cmd_len + 1] = '"';
262 memcpy(&cmd[cmd_len + 2], data2, data2_len);
263 cmd[cmd_len + 2 + data2_len] = '"';
264 cmd[cmd_len + 2 + data2_len + 1] = '\0';
265 cmd_len += 2 + data2_len + 1;
269 mi_send(h, "-break-commands %s%s\n", cmd_param, cmd);
273 res = mi_get_response_blk(h);
274 assert(res != NULL && res->next == NULL && res->tclass == MI_CL_DONE &&
283 typedef void(func_t)(SBDebugger &dbg, const char *cmd);
285 Cmd(const char *name_, int min_shortcut_, func_t *func_)
286 : name(name_), min_shortcut(min_shortcut_), func(func_) {}
289 Cmd("quit", 1, quit_command),
290 Cmd("start", 5, start_command),
291 Cmd("commands", 4, commands_command),
294 static void executecommand(SBDebugger &dbg, const char *cmd_s) {
295 const char *start, *end, *cs;
307 for (const Cmd &cmd : cmds)
308 if (cmd.min_shortcut <= end - start &&
309 size_t(end - start) <= strlen(cmd.name) &&
310 strncmp(start, cmd.name, end - start) == 0)
311 return cmd.func(dbg, cs);
313 return default_command(dbg, cmd_s);
316 static char *xstrdup(const char *cs) {
317 char *s = static_cast<char *>(malloc(strlen(cs) + 1));
323 static SBDebugger *completion_entry_function_dbgp;
324 static char *completion_entry_function(const char *text, int matches) {
325 SBDebugger &dbg = *completion_entry_function_dbgp;
326 static std::vector<std::string> found_vec;
327 assert(matches >= 0);
330 SBStringList matches;
331 // LLDB: FIXME: These two values are not implemented. m_match_start_point;
332 // m_max_return_elements;
333 const int match_start_point = 0;
334 // LLDB: Only max_return_elements == -1 is supported at present:
335 const int max_return_elements = -1;
336 int got = dbg.GetCommandInterpreter().HandleCompletion(
337 text, strlen(text) /*cursor_pos*/, match_start_point,
338 max_return_elements, matches);
339 assert(matches.IsValid());
340 if (unsigned(got + 1) != matches.GetSize())
341 error(1, 0, "HandleCompletion=%d +1 != %u=matches.GetSize()", got,
343 // for (size_t ix=0;ix<matches.GetSize();++ix)
344 // fprintf(stderr,"match[%zu]=<%s>\n",ix,matches.GetStringAtIndex(ix));
345 const char *first = matches.GetStringAtIndex(0);
346 assert(matches.GetSize() >= 1);
348 std::string str(first);
349 while (!str.empty() && str.back() == ' ')
351 found_vec.push_back(text + str);
353 for (size_t ix = 1; ix < matches.GetSize(); ++ix)
354 found_vec.push_back(matches.GetStringAtIndex(ix));
356 if (size_t(matches) < found_vec.size())
357 return xstrdup(found_vec[matches].c_str());
358 else if (size_t(matches) == found_vec.size())
364 static std::deque<std::string> opt_iex, opt_ex;
365 static std::optional<std::string> opt_exec, opt_core;
366 static std::optional<lldb::pid_t> opt_pid;
367 static std::vector<std::string> opt_args;
369 std::string string_quote(std::string &&str) {
370 std::string retval = "\"";
371 for (const char c : str) {
377 return retval + "\"";
380 std::optional<std::string> next_arg() {
381 if (!opt_iex.empty()) {
382 std::string retval = opt_iex.front();
386 if (opt_exec || opt_core) {
387 std::string cmd = "target create";
389 cmd += " " + string_quote(std::move(*opt_exec));
393 cmd += " --core " + string_quote(std::move(*opt_core));
399 std::string retval = (boost::format("attach %1%") % *opt_pid).str();
403 if (!opt_ex.empty()) {
404 std::string retval = opt_ex.front();
411 int main(int argc, char **argv) {
412 llvm::StringRef ToolName = argv[0];
413 llvm::sys::PrintStackTraceOnErrorSignal(ToolName);
414 llvm::PrettyStackTraceProgram X(argc, argv);
416 for (int argi = 1; argi < argc; ++argi) {
417 std::string arg = argv[argi];
418 auto str_to_pid = [](const std::string &str) {
419 lldb::pid_t pid_test = atoi(str.c_str());
420 return (boost::format("%1%") % pid_test).str() != str || pid_test <= 0
425 const char *cmd = argv[++argi];
427 opt_iex.push_back(cmd);
428 } else if (arg == "-ex") {
429 const char *cmd = argv[++argi];
431 opt_ex.push_back(cmd);
432 } else if (arg == "--args") {
433 const char *exec = argv[++argi];
437 assert(opt_args.empty());
438 opt_exec = std::string(exec);
439 while (++argi < argc) {
441 opt_args.push_back(std::move(arg));
443 } else if ((arg == "-e" || arg == "--exec") && argv[argi + 1])
444 opt_exec = argv[++argi];
445 else if ((arg == "-p" || arg == "--pid") && argv[argi + 1]) {
446 opt_pid = str_to_pid(argv[++argi]);
448 error(1, 0, "Invalid PID: %s", argv[argi]);
449 } else if ((arg == "-c" || arg == "--core") && argv[argi + 1])
450 opt_core = argv[++argi];
451 else if (arg == "-h" || arg == "--help") {
453 This is the GNU debugger emulation by LLDB. Usage:\n\
455 llgdb [options] [executable-file [core-file or process-id]]\n\
456 llgdb [options] --args executable-file [inferior-arguments ...]\n\
458 Selection of debuggee and its files:\n\
460 --args Arguments after executable-file are passed to inferior\n\
461 --core=COREFILE Analyze the core dump COREFILE.\n\
462 --exec=EXECFILE Use EXECFILE as the executable.\n\
463 --pid=PID Attach to running process PID.\n\
465 Initial commands and command files:\n\
468 Execute a single GDB command.\n\
469 May be used multiple times and in conjunction\n\
472 Like -ex but before loading inferior.\n\
476 --help Print this message and then exit.\n\
478 Report bugs to jan.kratochvil -at- redhat.com.\n\
481 } else if (!opt_exec)
482 opt_exec = std::move(arg);
483 else if (!opt_pid && str_to_pid(arg) > 0)
484 opt_pid = str_to_pid(arg);
486 opt_core = std::move(arg);
488 error(1, 0, "Excessive argument: %s", arg.c_str());
491 SBDebugger::Initialize();
492 SBDebugger dbg = SBDebugger::Create(true /*source_init_files*/);
493 dbg.HandleCommand("settings set symbols.enable-external-lookup false");
495 completion_entry_function_dbgp = &dbg;
496 rl_completion_entry_function = completion_entry_function;
497 rl_readline_name = "llgdb";
499 if (true /*settings_show_bool(dbg, "history save")*/) {
500 int history_size = 1000000; // settings_show_int(dbg, "history size");
501 const char *HOME = getenv("HOME");
503 static const std::string history_filename =
505 "/.llgdb_history"; // settings_show_string(dbg, "history filename");
506 // gdb_set_bool(dbg, "history save", false);
507 stifle_history(history_size);
508 read_history(history_filename.c_str());
509 on_exit(history_save,
510 static_cast<void *>(const_cast<char *>(history_filename.c_str())));
511 /* Do not free HISTORY_FILENAME. */
516 std::string prompt = settings_show_string(dbg, "prompt");
517 std::optional<std::string> arg = next_arg();
520 char *cmd_s = llgdb_readline(prompt.c_str());
523 cmd = cmd_s ?: "quit";
526 puts((prompt + *arg).c_str());
527 cmd = std::move(*arg);
531 /* FIXME: -ex commands do not have pagination set. */
532 if (false /*!settings_show_bool(h, "pagination")*/)
535 rl_get_screen_size(&console_cb_rows, &console_cb_columns);
536 console_cb_drop = false;
537 console_cb_row = console_cb_column = 0;
540 executecommand(dbg, cmd.c_str());