int main (int argc, char const *argv[], const char *envp[]) { SBDebugger::Initialize(); SBHostOS::ThreadCreated ("<lldb.driver.main-thread>"); signal (SIGPIPE, SIG_IGN); signal (SIGWINCH, sigwinch_handler); signal (SIGINT, sigint_handler); signal (SIGTSTP, sigtstp_handler); signal (SIGCONT, sigcont_handler); // Create a scope for driver so that the driver object will destroy itself // before SBDebugger::Terminate() is called. { Driver driver; bool exiting = false; SBError error (driver.ParseArgs (argc, argv, stdout, exiting)); if (error.Fail()) { const char *error_cstr = error.GetCString (); if (error_cstr) ::fprintf (stderr, "error: %s\n", error_cstr); } else if (!exiting) { driver.MainLoop (); } } SBDebugger::Terminate(); return 0; }
void listener_func() { while (!g_done) { SBEvent event; bool got_event = g_listener.WaitForEvent(1, event); if (got_event) { if (!event.IsValid()) throw Exception("event is not valid in listener thread"); SBProcess process = SBProcess::GetProcessFromEvent(event); if (process.GetState() == eStateStopped) { SBError error = process.Continue(); if (!error.Success()) throw Exception(string("Cannot continue process from listener thread: ") + error.GetCString()); g_process_started.push(true); } } } }
int main (int argc, char const *argv[], const char *envp[]) { #if 1 // Enable for debug logging lldb::StreamSP logStream(new lldb_private::StreamCallback(LogOutput, 0)); const char* logCategories[] = { 0 }; lldb::LogSP log = lldb_private::EnableLog(logStream, 0, logCategories, 0); log->GetMask().Reset(LIBLLDB_LOG_ALL); #endif SBDebugger::Initialize(); SBHostOS::ThreadCreated ("<lldb.driver.main-thread>"); SetupPosixSignals(); // Create a scope for driver so that the driver object will destroy itself // before SBDebugger::Terminate() is called. { Driver driver; bool exit = false; SBError error = driver.ParseArgs (argc, argv, stdout, exit); if (error.Fail()) { const char *error_cstr = error.GetCString (); if (error_cstr) ::fprintf (stderr, "error: %s\n", error_cstr); } else if (!exit) { driver.Initialize(); } } SBDebugger::Terminate(); return 0; }
void Driver::MainLoop () { if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; atexit (reset_stdin_termios); } ::setbuf (stdin, NULL); ::setbuf (stdout, NULL); m_debugger.SetErrorFileHandle (stderr, false); m_debugger.SetOutputFileHandle (stdout, false); m_debugger.SetInputFileHandle (stdin, false); // Don't take ownership of STDIN yet... m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) { if (window_size.ws_col > 0) m_debugger.SetTerminalWidth (window_size.ws_col); } SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); // Before we handle any options from the command line, we parse the // .lldbinit file in the user's home directory. SBCommandReturnObject result; sb_interpreter.SourceInitFileInHomeDirectory(result); if (GetDebugMode()) { result.PutError (m_debugger.GetErrorFileHandle()); result.PutOutput (m_debugger.GetOutputFileHandle()); } // Now we handle options we got from the command line SBStream commands_stream; // First source in the commands specified to be run before the file arguments are processed. WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream); const size_t num_args = m_option_data.m_args.size(); if (num_args > 0) { char arch_name[64]; if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) commands_stream.Printf("target create --arch=%s %s", arch_name, EscapeString(m_option_data.m_args[0]).c_str()); else commands_stream.Printf("target create %s", EscapeString(m_option_data.m_args[0]).c_str()); if (!m_option_data.m_core_file.empty()) { commands_stream.Printf(" --core %s", EscapeString(m_option_data.m_core_file).c_str()); } commands_stream.Printf("\n"); if (num_args > 1) { commands_stream.Printf ("settings set -- target.run-args "); for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) commands_stream.Printf(" %s", EscapeString(m_option_data.m_args[arg_idx]).c_str()); commands_stream.Printf("\n"); } } else if (!m_option_data.m_core_file.empty()) { commands_stream.Printf("target create --core %s\n", EscapeString(m_option_data.m_core_file).c_str()); } else if (!m_option_data.m_process_name.empty()) { commands_stream.Printf ("process attach --name %s", EscapeString(m_option_data.m_process_name).c_str()); if (m_option_data.m_wait_for) commands_stream.Printf(" --waitfor"); commands_stream.Printf("\n"); } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) { commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid); } WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream); if (GetDebugMode()) { result.PutError(m_debugger.GetErrorFileHandle()); result.PutOutput(m_debugger.GetOutputFileHandle()); } bool handle_events = true; bool spawn_thread = false; if (m_option_data.m_repl) { const char *repl_options = NULL; if (!m_option_data.m_repl_options.empty()) repl_options = m_option_data.m_repl_options.c_str(); SBError error (m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options)); if (error.Fail()) { const char *error_cstr = error.GetCString(); if (error_cstr && error_cstr[0]) fprintf (stderr, "error: %s\n", error_cstr); else fprintf (stderr, "error: %u\n", error.GetError()); } } else { // Check if we have any data in the commands stream, and if so, save it to a temp file // so we can then run the command interpreter using the file contents. const char *commands_data = commands_stream.GetData(); const size_t commands_size = commands_stream.GetSize(); // The command file might have requested that we quit, this variable will track that. bool quit_requested = false; bool stopped_for_crash = false; if (commands_data && commands_size) { int initial_commands_fds[2]; bool success = true; FILE *commands_file = PrepareCommandsForSourcing (commands_data, commands_size, initial_commands_fds); if (commands_file) { m_debugger.SetInputFileHandle (commands_file, true); // Set the debugger into Sync mode when running the command file. Otherwise command files // that run the target won't run in a sensible way. bool old_async = m_debugger.GetAsync(); m_debugger.SetAsync(false); int num_errors; SBCommandInterpreterRunOptions options; options.SetStopOnError (true); if (m_option_data.m_batch) options.SetStopOnCrash (true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, quit_requested, stopped_for_crash); if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) { int crash_command_fds[2]; SBStream crash_commands_stream; WriteCommandsForSourcing (eCommandPlacementAfterCrash, crash_commands_stream); const char *crash_commands_data = crash_commands_stream.GetData(); const size_t crash_commands_size = crash_commands_stream.GetSize(); commands_file = PrepareCommandsForSourcing (crash_commands_data, crash_commands_size, crash_command_fds); if (commands_file) { bool local_quit_requested; bool local_stopped_for_crash; m_debugger.SetInputFileHandle (commands_file, true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, local_quit_requested, local_stopped_for_crash); if (local_quit_requested) quit_requested = true; } } m_debugger.SetAsync(old_async); } else success = false; // Close any pipes that we still have ownership of CleanupAfterCommandSourcing(initial_commands_fds); // Something went wrong with command pipe if (!success) { exit(1); } } // Now set the input file handle to STDIN and run the command // interpreter again in interactive mode and let the debugger // take ownership of stdin bool go_interactive = true; if (quit_requested) go_interactive = false; else if (m_option_data.m_batch && !stopped_for_crash) go_interactive = false; if (go_interactive) { m_debugger.SetInputFileHandle (stdin, true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread); } } reset_stdin_termios(); fclose (stdin); SBDebugger::Destroy (m_debugger); }
int main (int argc, char const *argv[]) { // Use a sentry object to properly initialize/terminate LLDB. LLDBSentry sentry; SBDebugger debugger (SBDebugger::Create()); // Create a debugger instance so we can create a target if (!debugger.IsValid()) fprintf (stderr, "error: failed to create a debugger object\n"); bool show_usage = false; bool verbose = false; bool canonical = false; bool external_only = false; const char *arch = NULL; const char *platform = NULL; std::string short_options("h?"); for (const struct option *opt = g_long_options; opt->name; ++opt) { if (isprint(opt->val)) { short_options.append(1, (char)opt->val); switch (opt->has_arg) { case no_argument: break; case required_argument: short_options.append(1, ':'); break; case optional_argument: short_options.append(2, ':'); break; } } } #ifdef __GLIBC__ optind = 0; #else optreset = 1; optind = 1; #endif char ch; while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1) { switch (ch) { case 0: break; case 'a': if (arch != NULL) { fprintf (stderr, "error: the --arch option can only be specified once\n"); exit(1); } arch = optarg; break; case 'c': canonical = true; break; case 'x': external_only = true; break; case 'p': platform = optarg; break; case 'v': verbose = true; break; case 'h': case '?': default: show_usage = true; break; } } argc -= optind; argv += optind; const bool add_dependent_libs = false; SBError error; for (int arg_idx = 0; arg_idx < argc; ++arg_idx) { // The first argument is the file path we want to look something up in const char *exe_file_path = argv[arg_idx]; // Create a target using the executable. SBTarget target = debugger.CreateTarget (exe_file_path, arch, platform, add_dependent_libs, error); if (error.Success()) { if (target.IsValid()) { SBFileSpec exe_file_spec (exe_file_path, true); SBModule module (target.FindModule (exe_file_spec)); SBFileSpecList comp_unit_list; if (module.IsValid()) { char command[1024]; lldb::SBCommandReturnObject command_result; snprintf (command, sizeof(command), "add-dsym --uuid %s", module.GetUUIDString()); debugger.GetCommandInterpreter().HandleCommand (command, command_result); if (!command_result.Succeeded()) { fprintf (stderr, "error: couldn't locate debug symbols for '%s'\n", exe_file_path); exit(1); } SBFileSpecList module_list; module_list.Append(exe_file_spec); SBBreakpoint bp = target.BreakpointCreateByRegex (".", module_list, comp_unit_list); const size_t num_locations = bp.GetNumLocations(); for (uint32_t bp_loc_idx=0; bp_loc_idx<num_locations; ++bp_loc_idx) { SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx); SBSymbolContext sc (bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything)); if (sc.IsValid()) { if (sc.GetBlock().GetContainingInlinedBlock().IsValid()) { // Skip inlined functions continue; } SBFunction function (sc.GetFunction()); if (function.IsValid()) { addr_t lo_pc = function.GetStartAddress().GetFileAddress(); if (lo_pc == LLDB_INVALID_ADDRESS) { // Skip functions that don't have concrete instances in the binary continue; } addr_t hi_pc = function.GetEndAddress().GetFileAddress(); const char *func_demangled_name = function.GetName(); const char *func_mangled_name = function.GetMangledName(); bool dump = true; const bool is_objc_method = ((func_demangled_name[0] == '-') || (func_demangled_name[0] == '+')) && (func_demangled_name[1] == '['); if (external_only) { // Dump all objective C methods, or external symbols dump = is_objc_method; if (!dump) dump = sc.GetSymbol().IsExternal(); } if (dump) { if (verbose) { printf ("\n name: %s\n", func_demangled_name); if (func_mangled_name) printf ("mangled: %s\n", func_mangled_name); printf (" range: [0x%16.16llx - 0x%16.16llx)\n type: ", lo_pc, hi_pc); } else { printf ("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc); } SBType function_type = function.GetType(); SBType return_type = function_type.GetFunctionReturnType(); if (canonical) return_type = return_type.GetCanonicalType(); if (func_mangled_name && func_mangled_name[0] == '_' && func_mangled_name[1] == 'Z') { printf ("%s %s\n", return_type.GetName(), func_demangled_name); } else { SBTypeList function_args = function_type.GetFunctionArgumentTypes(); const size_t num_function_args = function_args.GetSize(); if (is_objc_method) { const char *class_name_start = func_demangled_name + 2; if (num_function_args == 0) { printf("%c(%s)[%s\n", func_demangled_name[0], return_type.GetName(), class_name_start); } else { const char *class_name_end = strchr(class_name_start,' '); const int class_name_len = class_name_end - class_name_start; printf ("%c(%s)[%*.*s", func_demangled_name[0], return_type.GetName(), class_name_len, class_name_len, class_name_start); const char *selector_pos = class_name_end + 1; for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; ++function_arg_idx) { const char *selector_end = strchr(selector_pos, ':') + 1; const int selector_len = selector_end - selector_pos; SBType function_arg_type = function_args.GetTypeAtIndex(function_arg_idx); if (canonical) function_arg_type = function_arg_type.GetCanonicalType(); printf (" %*.*s", selector_len, selector_len, selector_pos); if (function_arg_type.IsValid()) { printf ("(%s)", function_arg_type.GetName()); } else { printf ("(?)"); } selector_pos = selector_end; } printf ("]\n"); } } else { printf ("%s ", return_type.GetName()); if (strchr (func_demangled_name, '(')) printf ("(*)("); else printf ("%s(", func_demangled_name); for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; ++function_arg_idx) { SBType function_arg_type = function_args.GetTypeAtIndex(function_arg_idx); if (canonical) function_arg_type = function_arg_type.GetCanonicalType(); if (function_arg_type.IsValid()) { printf ("%s%s", function_arg_idx > 0 ? ", " : "", function_arg_type.GetName()); } else { printf ("%s???", function_arg_idx > 0 ? ", " : ""); } } printf (")\n"); } } } } } } } } } else { fprintf (stderr, "error: %s\n", error.GetCString()); exit(1); } } return 0; }