From 0d478f4f9c3b50cbed65641a100d1571ea31ac05 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 24 Jul 2019 11:46:09 +0200 Subject: [PATCH] init; based on: https://github.com/lldb-tools/lldb-mi --- .gitignore | 5 + CMakeLists.txt | 26 +++ src/CMakeLists.txt | 5 + src/LLGDBMain.cpp | 469 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 505 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 src/CMakeLists.txt create mode 100644 src/LLGDBMain.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f21acfe --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +CMakeFiles +Makefile +cmake_install.cmake +/CMakeCache.txt +src/llgdb diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3add18c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.11) +project(llgdb) + +find_package(LLVM REQUIRED CONFIG) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include_directories(${LLVM_INCLUDE_DIRS}) +if(LLVM_BUILD_MAIN_SRC_DIR) + include_directories(${LLVM_BUILD_MAIN_SRC_DIR}/tools/clang/include) + include_directories(${LLVM_BUILD_BINARY_DIR}/tools/clang/include) +endif() +link_directories(${LLVM_LIBRARY_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) + +add_definitions(-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS) + +include(CheckCXXCompilerFlag) +check_cxx_compiler_flag(-Wall temp) +if(temp) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +endif() + +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..df35350 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(llgdb + LLGDBMain.cpp +) + +target_link_libraries(llgdb lldb LLVM readline) diff --git a/src/LLGDBMain.cpp b/src/LLGDBMain.cpp new file mode 100644 index 0000000..39dac35 --- /dev/null +++ b/src/LLGDBMain.cpp @@ -0,0 +1,469 @@ +//===-- LLGDBMain.cpp -------------------------------------------*- C++ -*-===// +// +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace lldb; +using namespace lldb_private; + +static jmp_buf llgdb_readline_jmp_buf; + +static void llgdb_readline_sigint_handler(int signum) { + assert(signum == SIGINT); + longjmp(llgdb_readline_jmp_buf, 1); +} + +static char *llgdb_readline(const char *prompt) { + char *retval; + sighandler_t saved_handler; + sigset_t mask; + int i; + + i = sigprocmask(SIG_SETMASK, NULL, &mask); + assert(i == 0); + saved_handler = signal(SIGINT, llgdb_readline_sigint_handler); + if (setjmp(llgdb_readline_jmp_buf) != 0) { + rl_free_line_state(); + rl_cleanup_after_signal(); + + /* GDB prints this. */ + puts("Quit"); + + i = sigprocmask(SIG_SETMASK, &mask, NULL); + assert(i == 0); + } + retval = readline(prompt); + saved_handler = signal(SIGINT, saved_handler); + assert(saved_handler == llgdb_readline_sigint_handler); + return retval; +} + +#if 0 +static int console_cb_rows, console_cb_columns, console_cb_row, + console_cb_column; +static bool console_cb_drop; + +static void console_cb(const char *str, void *data) { + const char *cs; + + if (console_cb_drop) + return; + if (console_cb_rows == 0) { + fputs(str, stdout); + return; + } + + while (*str != '\0') { + int columns; + size_t size; + char *answer; + + cs = strchr(str, '\n'); + if (cs == NULL) + cs = &str[strlen(str)]; + columns = std::min(cs - str, long(console_cb_columns - console_cb_column)); + if (columns > 0) { + size = fwrite(str, 1, columns, stdout); + assert(size == size_t(columns)); + str += columns; + console_cb_column += columns; + continue; + } + if (*str == '\n') + str++; + else assert(console_cb_column < console_cb_columns); + putchar('\n'); + console_cb_row++; + console_cb_column = 0; + if (console_cb_row < console_cb_rows - 1) + continue; + answer = llgdb_readline("---Type to continue, or q to quit---"); + for (cs = answer; isspace(*cs); cs++) + ; + if (*cs == 'q') { + free(answer); + puts("Quit"); + console_cb_drop = true; + return; + } + free(answer); + console_cb_row = 0; + } +} +#endif + +static void history_save(int rc, void *arg) { + const char *history_filename = static_cast(arg); + write_history(history_filename); +} + +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); + assert(Result.Succeeded()); + // = 0) { + char *prompt, *data, *data2, *start, *end; + size_t data2_len; + int do_nest = 0; + + prompt = xstrprintf("%*s>", (int)nesting); + data = llgdb_readline(prompt); + free(prompt); + if (data == NULL) + data = xstrdup("end"); + + for (start = data; isspace(*start); start++) + ; + for (end = data + strlen(data); end > start && isspace(end[-1]); end--) + ; + data2 = malloc(end - start + 1); + memcpy(data2, start, end - start); + data2[end - start] = '\0'; + if (strcmp(data2, "python") == 0) + do_nest = 1; + if (strcmp(data2, "end") == 0) + do_nest = -1; + for (end = data2; *end && !isspace(*end); end++) + ; + *end = '\0'; + + /* Here is a bug in GDB, it does not recognize command shortcuts. */ + if (strcmp(data2, "while") == 0 || strcmp(data2, "if") == 0 || + strcmp(data2, "commands") == 0 || + strcmp(data2, "while-stepping") == 0 || + strcmp(data2, "stepping") == 0 || strcmp(data2, "ws") == 0) + do_nest = 1; + free(data2); + + nesting += do_nest; + if (nesting < 0) + break; + + data2 = mi_escape(data); + free(data); + data2_len = strlen(data2); + cmd = xrealloc(cmd, cmd_len + 2 + data2_len + 2); + cmd[cmd_len] = ' '; + cmd[cmd_len + 1] = '"'; + memcpy(&cmd[cmd_len + 2], data2, data2_len); + cmd[cmd_len + 2 + data2_len] = '"'; + cmd[cmd_len + 2 + data2_len + 1] = '\0'; + cmd_len += 2 + data2_len + 1; + free(data2); + } + + mi_send(h, "-break-commands %s%s\n", cmd_param, cmd); + free(cmd); + free(bpnum); + + res = mi_get_response_blk(h); + assert(res != NULL && res->next == NULL && res->tclass == MI_CL_DONE && + res->c == NULL); + mi_free_output(res); +#endif +} + +struct Cmd { + const char *name; + int min_shortcut; + 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_) {} +}; +const Cmd cmds[] = { + Cmd("quit", 1, quit_command), + Cmd("start", 5, start_command), + Cmd("commands", 4, commands_command), +}; + +static void executecommand(SBDebugger &dbg, const char *cmd_s) { + const char *start, *end, *cs; + + cs = cmd_s; + while (isspace(*cs)) + cs++; + start = cs; + while (isalnum(*cs)) + cs++; + end = cs; + while (isspace(*cs)) + cs++; + + for (const Cmd &cmd : cmds) + if (cmd.min_shortcut <= end - start && + size_t(end - start) <= strlen(cmd.name) && + strncmp(start, cmd.name, end - start) == 0) + return cmd.func(dbg, cs); + + return default_command(dbg, cmd_s); +} + +static char *xstrdup(const char *cs) { + char *s = static_cast(malloc(strlen(cs)+1)); + assert(s); + strcpy(s,cs); + return s; +} + +static SBDebugger *completion_entry_function_dbgp; +static char *completion_entry_function(const char *text, int matches) { + SBDebugger &dbg = *completion_entry_function_dbgp; + static std::vector found_vec; + assert(matches >= 0); + if (matches == 0) { + found_vec.clear(); + SBStringList matches; + // 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); + 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\n",ix,matches.GetStringAtIndex(ix)); + 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(); + found_vec.push_back(text + str); + } else + for (size_t ix=1;ix opt_iex, opt_ex; +static std::optional opt_exec, opt_core; +static std::vector opt_args; + +std::string string_quote(std::string &&str) { + std::string retval = "\""; + for (const char c : str) { + if (c != '"') + retval.push_back(c); + else + retval += "\\\""; + } + return retval + "\""; +} + +std::optional next_arg() { + if (!opt_iex.empty()) { + std::string retval = opt_iex.front(); + opt_iex.pop_front(); + return retval; + } + if (opt_exec || opt_core) { + std::string cmd = "target create"; + if (opt_exec) { + cmd += " " + string_quote(std::move(*opt_exec)); + opt_exec.reset(); + } + if (opt_core) { + cmd += " --core " + string_quote(std::move(*opt_core)); + opt_core.reset(); + } + return cmd; + } + if (!opt_ex.empty()) { + std::string retval = opt_ex.front(); + opt_ex.pop_front(); + return retval; + } + return {}; +} + +int main(int argc, char **argv) { + llvm::StringRef ToolName = argv[0]; + llvm::sys::PrintStackTraceOnErrorSignal(ToolName); + llvm::PrettyStackTraceProgram X(argc, argv); + + for (int argi = 1; argi < argc; ++argi) { + std::string arg = argv[argi]; + if (arg == "-iex") { + const char *cmd = argv[++argi]; + assert(cmd); + opt_iex.push_back(cmd); + } else if (arg == "-ex") { + const char *cmd = argv[++argi]; + assert(cmd); + opt_ex.push_back(cmd); + } else if (arg == "--args") { + const char *exec = argv[++argi]; + assert(exec); + assert(!opt_exec); + assert(!opt_core); + assert(opt_args.empty()); + opt_exec=std::string(exec); + while (++argi(const_cast(history_filename.c_str()))); + /* Do not free HISTORY_FILENAME. */ + } + + for (;;) { + + std::string prompt = settings_show_string(dbg, "prompt"); + std::optional arg = next_arg(); + std::string cmd; + if (!arg) { + char *cmd_s = llgdb_readline(prompt.c_str()); + if (cmd_s) + add_history(cmd_s); + cmd = cmd_s?:"quit"; + free(cmd_s); + } else { + puts((prompt + *arg).c_str()); + cmd = std::move(*arg); + } + +#if 0 + /* FIXME: -ex commands do not have pagination set. */ + if (false /*!settings_show_bool(h, "pagination")*/) + console_cb_rows = 0; + else + rl_get_screen_size(&console_cb_rows, &console_cb_columns); + console_cb_drop = false; + console_cb_row = console_cb_column = 0; +#endif + + executecommand(dbg, cmd.c_str()); + } +} -- 1.8.3.1