diff options
-rw-r--r-- | lldb/tools/driver/Driver.cpp | 279 | ||||
-rw-r--r-- | lldb/tools/driver/Driver.h | 12 |
2 files changed, 193 insertions, 98 deletions
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 477b7d62457..206a2f6b6fb 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -110,6 +110,10 @@ static OptionDefinition g_options[] = "Tells the debugger to read in and execute the lldb commands in the given file, before any file provided on the command line has been loaded." }, { LLDB_3_TO_5, false, "one-line-before-file" , 'O', required_argument, 0, eArgTypeNone, "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." }, + { LLDB_3_TO_5, false, "one-line-on-crash" , 'k', required_argument, 0, eArgTypeNone, + "When in batch mode, tells the debugger to execute this one-line lldb command if the target crashes." }, + { LLDB_3_TO_5, false, "source-on-crash" , 'K', required_argument, 0, eArgTypeFilename, + "When in batch mode, tells the debugger to source this file of lldb commands if the target crashes." }, { LLDB_3_TO_5, false, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone, "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." }, { LLDB_3_TO_5, false, "batch" , 'b', no_argument , 0, eArgTypeNone, @@ -402,6 +406,7 @@ Driver::OptionData::OptionData () : m_crash_log (), m_initial_commands (), m_after_file_commands (), + m_after_crash_commands(), m_debug_mode (false), m_source_quietly(false), m_print_version (false), @@ -427,6 +432,15 @@ Driver::OptionData::Clear () m_script_lang = lldb::eScriptLanguageDefault; m_initial_commands.clear (); m_after_file_commands.clear (); + // If there is a local .lldbinit, source that: + SBFileSpec local_lldbinit("./.lldbinit", true); + if (local_lldbinit.Exists()) + { + char path[2048]; + local_lldbinit.GetPath(path, 2047); + m_after_file_commands.push_back (std::pair<bool, std::string> (true, path)); + } + m_debug_mode = false; m_source_quietly = false; m_print_help = false; @@ -436,17 +450,27 @@ Driver::OptionData::Clear () m_wait_for = false; m_process_name.erase(); m_batch = false; + m_after_crash_commands.clear(); + m_process_pid = LLDB_INVALID_PROCESS_ID; } void -Driver::OptionData::AddInitialCommand (const char *command, bool before_file, bool is_file, SBError &error) +Driver::OptionData::AddInitialCommand (const char *command, CommandPlacement placement, bool is_file, SBError &error) { std::vector<std::pair<bool, std::string> > *command_set; - if (before_file) + switch (placement) + { + case eCommandPlacementBeforeFile: command_set = &(m_initial_commands); - else + break; + case eCommandPlacementAfterFile: command_set = &(m_after_file_commands); + break; + case eCommandPlacementAfterCrash: + command_set = &(m_after_crash_commands); + break; + } if (is_file) { @@ -496,12 +520,23 @@ Driver::GetScriptLanguage() const } void -Driver::WriteInitialCommands (bool before_file, SBStream &strm) +Driver::WriteCommandsForSourcing (CommandPlacement placement, SBStream &strm) { - std::vector<std::pair<bool, std::string> > &command_set = before_file ? m_option_data.m_initial_commands : - m_option_data.m_after_file_commands; + std::vector<std::pair<bool, std::string> > *command_set; + switch (placement) + { + case eCommandPlacementBeforeFile: + command_set = &m_option_data.m_initial_commands; + break; + case eCommandPlacementAfterFile: + command_set = &m_option_data.m_after_file_commands; + break; + case eCommandPlacementAfterCrash: + command_set = &m_option_data.m_after_crash_commands; + break; + } - for (const auto &command_pair : command_set) + for (const auto &command_pair : *command_set) { const char *command = command_pair.second.c_str(); if (command_pair.first) @@ -712,6 +747,13 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) m_option_data.m_source_quietly = true; break; + case 'k': + m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, true, error); + break; + case 'K': + m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, false, error); + break; + case 'n': m_option_data.m_process_name = optarg; break; @@ -730,16 +772,16 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) } break; case 's': - m_option_data.AddInitialCommand(optarg, false, true, error); + m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, true, error); break; case 'o': - m_option_data.AddInitialCommand(optarg, false, false, error); + m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, false, error); break; case 'S': - m_option_data.AddInitialCommand(optarg, true, true, error); + m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, true, error); break; case 'O': - m_option_data.AddInitialCommand(optarg, true, false, error); + m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, false, error); break; default: m_option_data.m_print_help = true; @@ -822,6 +864,95 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) return error; } +static ::FILE * +PrepareCommandsForSourcing (const char *commands_data, size_t commands_size, int fds[2]) +{ + enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE + + bool success = true; + ::FILE *commands_file = NULL; + fds[0] = -1; + fds[1] = -1; + int err = 0; +#ifdef _WIN32 + err = _pipe(fds, commands_size, O_BINARY); +#else + err = pipe(fds); +#endif + if (err == 0) + { + ssize_t nrwr = write(fds[WRITE], commands_data, commands_size); + if (nrwr < 0) + { + fprintf(stderr, "error: write(%i, %p, %zd) failed (errno = %i) " + "when trying to open LLDB commands pipe\n", + fds[WRITE], commands_data, commands_size, errno); + success = false; + } + else if (static_cast<size_t>(nrwr) == commands_size) + { + // Close the write end of the pipe so when we give the read end to + // the debugger/command interpreter it will exit when it consumes all + // of the data +#ifdef _WIN32 + _close(fds[WRITE]); fds[WRITE] = -1; +#else + close(fds[WRITE]); fds[WRITE] = -1; +#endif + // Now open the read file descriptor in a FILE * that we can give to + // the debugger as an input handle + commands_file = fdopen(fds[READ], "r"); + if (commands_file) + { + fds[READ] = -1; // The FILE * 'commands_file' now owns the read descriptor + // Hand ownership if the FILE * over to the debugger for "commands_file". + } + else + { + fprintf(stderr, + "error: fdopen(%i, \"r\") failed (errno = %i) when " + "trying to open LLDB commands pipe\n", + fds[READ], errno); + success = false; + } + } + } + else + { + fprintf(stderr, "error: can't create pipe file descriptors for LLDB commands\n"); + success = false; + } + + return commands_file; +} + +void +CleanupAfterCommandSourcing (int fds[2]) +{ + enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE + + // Close any pipes that we still have ownership of + if ( fds[WRITE] != -1) + { +#ifdef _WIN32 + _close(fds[WRITE]); fds[WRITE] = -1; +#else + close(fds[WRITE]); fds[WRITE] = -1; +#endif + + } + + if ( fds[READ] != -1) + { +#ifdef _WIN32 + _close(fds[READ]); fds[READ] = -1; +#else + close(fds[READ]); fds[READ] = -1; +#endif + } + +} + void Driver::MainLoop () { @@ -864,7 +995,7 @@ Driver::MainLoop () SBStream commands_stream; // First source in the commands specified to be run before the file arguments are processed. - WriteInitialCommands(true, commands_stream); + WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream); const size_t num_args = m_option_data.m_args.size(); if (num_args > 0) @@ -914,11 +1045,8 @@ Driver::MainLoop () commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid); } - WriteInitialCommands(false, commands_stream); + WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream); - // Now that all option parsing is done, we try and parse the .lldbinit - // file in the current working directory - sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); if (GetDebugMode()) { result.PutError(m_debugger.GetErrorFileHandle()); @@ -938,104 +1066,63 @@ Driver::MainLoop () bool stopped_for_crash = false; if (commands_data && commands_size) { - enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE - + int initial_commands_fds[2]; bool success = true; - int fds[2] = { -1, -1 }; - int err = 0; -#ifdef _WIN32 - err = _pipe(fds, commands_size, O_BINARY); -#else - err = pipe(fds); -#endif - if (err == 0) + FILE *commands_file = PrepareCommandsForSourcing (commands_data, commands_size, initial_commands_fds); + if (commands_file) { - ssize_t nrwr = write(fds[WRITE], commands_data, commands_size); - if (nrwr < 0) - { - fprintf(stderr, "error: write(%i, %p, %zd) failed (errno = %i) " - "when trying to open LLDB commands pipe\n", - fds[WRITE], commands_data, commands_size, errno); - success = false; - } - else if (static_cast<size_t>(nrwr) == commands_size) + 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()) { - // Close the write end of the pipe so when we give the read end to - // the debugger/command interpreter it will exit when it consumes all - // of the data -#ifdef _WIN32 - _close(fds[WRITE]); fds[WRITE] = -1; -#else - close(fds[WRITE]); fds[WRITE] = -1; -#endif - // Now open the read file descriptor in a FILE * that we can give to - // the debugger as an input handle - FILE *commands_file = fdopen(fds[READ], "r"); + 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) { - fds[READ] = -1; // The FILE * 'commands_file' now owns the read descriptor - // Hand ownership if the FILE * over to the debugger for "commands_file". + bool local_quit_requested; + bool local_stopped_for_crash; 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); - m_debugger.SetAsync(old_async); - } - else - { - fprintf(stderr, - "error: fdopen(%i, \"r\") failed (errno = %i) when " - "trying to open LLDB commands pipe\n", - fds[READ], errno); - success = false; + local_quit_requested, + local_stopped_for_crash); + if (local_quit_requested) + quit_requested = true; + } } - else - { - assert(!"partial writes not handled"); - success = false; - } + m_debugger.SetAsync(old_async); } else - { - fprintf(stderr, "error: can't create pipe file descriptors for LLDB commands\n"); success = false; - } // Close any pipes that we still have ownership of - if ( fds[WRITE] != -1) - { -#ifdef _WIN32 - _close(fds[WRITE]); fds[WRITE] = -1; -#else - close(fds[WRITE]); fds[WRITE] = -1; -#endif - - } - - if ( fds[READ] != -1) - { -#ifdef _WIN32 - _close(fds[READ]); fds[READ] = -1; -#else - close(fds[READ]); fds[READ] = -1; -#endif - } + CleanupAfterCommandSourcing(initial_commands_fds); // Something went wrong with command pipe if (!success) diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h index c4faac16b52..5316c57f7d8 100644 --- a/lldb/tools/driver/Driver.h +++ b/lldb/tools/driver/Driver.h @@ -28,6 +28,13 @@ class IOChannel; class Driver : public lldb::SBBroadcaster { public: + typedef enum CommandPlacement + { + eCommandPlacementBeforeFile, + eCommandPlacementAfterFile, + eCommandPlacementAfterCrash, + } CommandPlacement; + Driver (); virtual @@ -52,7 +59,7 @@ public: GetScriptLanguage() const; void - WriteInitialCommands (bool before_file, lldb::SBStream &strm); + WriteCommandsForSourcing (CommandPlacement placement, lldb::SBStream &strm); bool GetDebugMode() const; @@ -68,7 +75,7 @@ public: Clear(); void - AddInitialCommand (const char *command, bool before_file, bool is_file, lldb::SBError &error); + AddInitialCommand (const char *command, CommandPlacement placement, bool is_file, lldb::SBError &error); //static OptionDefinition m_cmd_option_table[]; @@ -78,6 +85,7 @@ public: std::string m_crash_log; std::vector<std::pair<bool,std::string> > m_initial_commands; std::vector<std::pair<bool,std::string> > m_after_file_commands; + std::vector<std::pair<bool,std::string> > m_after_crash_commands; bool m_debug_mode; bool m_source_quietly; bool m_print_version; |