diff options
author | Jim Ingham <jingham@apple.com> | 2014-10-14 01:20:07 +0000 |
---|---|---|
committer | Jim Ingham <jingham@apple.com> | 2014-10-14 01:20:07 +0000 |
commit | ffc9f1de340dcd49f872303c17a93aa69bf92fbc (patch) | |
tree | 797486122523a141b85ff3c9c21803f4504e52f0 | |
parent | 07e9ad3c12998ec2d6a9bb365e9237b7ebfb0343 (diff) | |
download | bcm5719-llvm-ffc9f1de340dcd49f872303c17a93aa69bf92fbc.tar.gz bcm5719-llvm-ffc9f1de340dcd49f872303c17a93aa69bf92fbc.zip |
This adds a "batch mode" to lldb kinda like the gdb batch mode. It will quit the debugger
after all the commands have been executed except if one of the commands was an execution control
command that stopped because of a signal or exception.
Also adds a variant of SBCommandInterpreter::HandleCommand that takes an SBExecutionContext. That
way you can run an lldb command targeted at a particular target, thread or process w/o having to
select same before running the command.
Also exposes CommandInterpreter::HandleCommandsFromFile to the SBCommandInterpreter API, since that
seemed generally useful.
llvm-svn: 219654
-rw-r--r-- | lldb/include/lldb/API/SBCommandInterpreter.h | 11 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBDebugger.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBExecutionContext.h | 2 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBFileSpec.h | 1 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/CommandInterpreter.h | 7 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme | 2 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBCommandInterpreter.i | 9 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBDebugger.i | 3 | ||||
-rw-r--r-- | lldb/source/API/SBCommandInterpreter.cpp | 68 | ||||
-rw-r--r-- | lldb/source/API/SBDebugger.cpp | 4 | ||||
-rw-r--r-- | lldb/source/API/SBExecutionContext.cpp | 6 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 99 | ||||
-rw-r--r-- | lldb/tools/driver/Driver.cpp | 31 | ||||
-rw-r--r-- | lldb/tools/driver/Driver.h | 1 |
14 files changed, 236 insertions, 11 deletions
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h index 6f9295bf740..947e3916414 100644 --- a/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/lldb/include/lldb/API/SBCommandInterpreter.h @@ -18,6 +18,8 @@ namespace lldb { class SBCommandInterpreterRunOptions { friend class SBDebugger; +friend class SBCommandInterpreter; + public: SBCommandInterpreterRunOptions(); ~SBCommandInterpreterRunOptions(); @@ -138,6 +140,15 @@ public: lldb::ReturnStatus HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false); + lldb::ReturnStatus + HandleCommand (const char *command_line, SBExecutionContext &exe_ctx, SBCommandReturnObject &result, bool add_to_history = false); + + void + HandleCommandsFromFile (lldb::SBFileSpec &file, + lldb::SBExecutionContext &override_context, + lldb::SBCommandInterpreterRunOptions &options, + lldb::SBCommandReturnObject result); + // The pointer based interface is not useful in SWIG, since the cursor & last_char arguments are string pointers INTO current_line // and you can't do that in a scripting language interface in general... diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h index de7d1a1c23b..6e43e12f7b1 100644 --- a/lldb/include/lldb/API/SBDebugger.h +++ b/lldb/include/lldb/API/SBDebugger.h @@ -327,7 +327,8 @@ public: bool spawn_thread, SBCommandInterpreterRunOptions &options, int &num_errors, - bool &quit_requested); + bool &quit_requested, + bool &stopped_for_crash); private: friend class SBCommandInterpreter; diff --git a/lldb/include/lldb/API/SBExecutionContext.h b/lldb/include/lldb/API/SBExecutionContext.h index e5cac1afe91..9d889139f5c 100644 --- a/lldb/include/lldb/API/SBExecutionContext.h +++ b/lldb/include/lldb/API/SBExecutionContext.h @@ -20,6 +20,8 @@ namespace lldb { class SBExecutionContext { +friend class SBCommandInterpreter; + public: SBExecutionContext(); diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h index d262b98d0fd..1eee3d10367 100644 --- a/lldb/include/lldb/API/SBFileSpec.h +++ b/lldb/include/lldb/API/SBFileSpec.h @@ -63,6 +63,7 @@ public: private: friend class SBAttachInfo; friend class SBBlock; + friend class SBCommandInterpreter; friend class SBCompileUnit; friend class SBDeclaration; friend class SBFileSpecList; diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 7047f21e716..ddc4dbab4c1 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -628,6 +628,12 @@ public: { return m_quit_requested; } + + bool + GetStoppedForCrash () const + { + return m_stopped_for_crash; + } protected: friend class Debugger; @@ -685,6 +691,7 @@ private: std::vector<uint32_t> m_command_source_flags; uint32_t m_num_errors; bool m_quit_requested; + bool m_stopped_for_crash; }; diff --git a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme index 34560feaaeb..bd7c34c49d2 100644 --- a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme +++ b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme @@ -84,7 +84,7 @@ <LaunchAction selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - launchStyle = "0" + launchStyle = "1" useCustomWorkingDirectory = "NO" customWorkingDirectory = "/Volumes/work/gclayton/Documents/devb/attach" buildConfiguration = "Debug" diff --git a/lldb/scripts/Python/interface/SBCommandInterpreter.i b/lldb/scripts/Python/interface/SBCommandInterpreter.i index 856038094f7..0a795adb038 100644 --- a/lldb/scripts/Python/interface/SBCommandInterpreter.i +++ b/lldb/scripts/Python/interface/SBCommandInterpreter.i @@ -182,6 +182,15 @@ public: lldb::ReturnStatus HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false); + lldb::ReturnStatus + HandleCommand (const char *command_line, SBExecutionContext &exe_ctx, SBCommandReturnObject &result, bool add_to_history = false); + + void + HandleCommandsFromFile (lldb::SBFileSpec &file, + lldb::SBExecutionContext &override_context, + lldb::SBCommandInterpreterRunOptions &options, + lldb::SBCommandReturnObject result); + int HandleCompletion (const char *current_line, uint32_t cursor_pos, diff --git a/lldb/scripts/Python/interface/SBDebugger.i b/lldb/scripts/Python/interface/SBDebugger.i index fb63fc362dc..48e0d5db638 100644 --- a/lldb/scripts/Python/interface/SBDebugger.i +++ b/lldb/scripts/Python/interface/SBDebugger.i @@ -369,7 +369,8 @@ public: bool spawn_thread, SBCommandInterpreterRunOptions &options, int &num_errors, - bool &quit_requested); + bool &quit_requested, + bool &stopped_for_crash); }; // class SBDebugger } // namespace lldb diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp index bc8d6d34aa9..4e65c4f857c 100644 --- a/lldb/source/API/SBCommandInterpreter.cpp +++ b/lldb/source/API/SBCommandInterpreter.cpp @@ -20,6 +20,7 @@ #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBListener.h" @@ -222,6 +223,13 @@ SBCommandInterpreter::GetIOHandlerControlSequence(char ch) lldb::ReturnStatus SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history) { + SBExecutionContext sb_exe_ctx; + return HandleCommand (command_line, sb_exe_ctx, result, add_to_history); +} + +lldb::ReturnStatus +SBCommandInterpreter::HandleCommand (const char *command_line, SBExecutionContext &override_context, SBCommandReturnObject &result, bool add_to_history) +{ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) @@ -229,11 +237,21 @@ SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnOb static_cast<void*>(m_opaque_ptr), command_line, static_cast<void*>(result.get()), add_to_history); + ExecutionContext ctx, *ctx_ptr; + if (override_context.get()) + { + ctx = override_context.get()->Lock(true); + ctx_ptr = &ctx; + } + else + ctx_ptr = nullptr; + + result.Clear(); if (command_line && m_opaque_ptr) { result.ref().SetInteractive(false); - m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref()); + m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref(), ctx_ptr); } else { @@ -256,6 +274,54 @@ SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnOb return result.GetStatus(); } +void +SBCommandInterpreter::HandleCommandsFromFile (lldb::SBFileSpec &file, + lldb::SBExecutionContext &override_context, + lldb::SBCommandInterpreterRunOptions &options, + lldb::SBCommandReturnObject result) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + { + SBStream s; + file.GetDescription (s); + log->Printf ("SBCommandInterpreter(%p)::HandleCommandsFromFile (file=\"%s\", SBCommandReturnObject(%p))", + static_cast<void*>(m_opaque_ptr), s.GetData(), + static_cast<void*>(result.get())); + } + + if (!m_opaque_ptr) + { + result->AppendError ("SBCommandInterpreter is not valid."); + result->SetStatus (eReturnStatusFailed); + return; + } + + if (!file.IsValid()) + { + SBStream s; + file.GetDescription (s); + result->AppendErrorWithFormat ("File is not valid: %s.", s.GetData()); + result->SetStatus (eReturnStatusFailed); + } + + FileSpec tmp_spec = file.ref(); + ExecutionContext ctx, *ctx_ptr; + if (override_context.get()) + { + ctx = override_context.get()->Lock(true); + ctx_ptr = &ctx; + } + else + ctx_ptr = nullptr; + + + m_opaque_ptr->HandleCommandsFromFile (tmp_spec, ctx_ptr, options.ref(), result.ref()); + +} + + int SBCommandInterpreter::HandleCompletion (const char *current_line, const char *cursor, diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index a655950926f..4b00f19d22a 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -986,7 +986,8 @@ SBDebugger::RunCommandInterpreter (bool auto_handle_events, bool spawn_thread, SBCommandInterpreterRunOptions &options, int &num_errors, - bool &quit_requested) + bool &quit_requested, + bool &stopped_for_crash) { if (m_opaque_sp) @@ -995,6 +996,7 @@ SBDebugger::RunCommandInterpreter (bool auto_handle_events, interp.RunCommandInterpreter(auto_handle_events, spawn_thread, options.ref()); num_errors = interp.GetNumErrors(); quit_requested = interp.GetQuitRequested(); + stopped_for_crash = interp.GetStoppedForCrash(); } } diff --git a/lldb/source/API/SBExecutionContext.cpp b/lldb/source/API/SBExecutionContext.cpp index d1c21eccb72..dc20c609213 100644 --- a/lldb/source/API/SBExecutionContext.cpp +++ b/lldb/source/API/SBExecutionContext.cpp @@ -69,6 +69,12 @@ SBExecutionContext::operator = (const lldb::SBExecutionContext &rhs) return *this; } +ExecutionContextRef * +SBExecutionContext::get () const +{ + return m_exe_ctx_sp.get(); +} + SBTarget SBExecutionContext::GetTarget () const { diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 28eafcbd1d9..b281bf1954c 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -121,7 +121,8 @@ CommandInterpreter::CommandInterpreter m_truncation_warning(eNoTruncation), m_command_source_depth (0), m_num_errors(0), - m_quit_requested(false) + m_quit_requested(false), + m_stopped_for_crash(false) { debugger.SetScriptLanguage (script_language); @@ -2568,6 +2569,42 @@ CommandInterpreter::HandleCommands (const StringList &commands, return; } } + + // Also check for "stop on crash here: + bool should_stop = false; + if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash()) + { + TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget()); + if (target_sp) + { + ProcessSP process_sp (target_sp->GetProcessSP()); + if (process_sp) + { + for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) + { + StopReason reason = thread_sp->GetStopReason(); + if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation) + { + should_stop = true; + break; + } + } + } + } + if (should_stop) + { + if (idx != num_lines - 1) + result.AppendErrorWithFormat("Aborting reading of commands after command #%" PRIu64 ": '%s' stopped with a signal or exception.\n", + (uint64_t)idx + 1, cmd); + else + result.AppendMessageWithFormat("Command #%" PRIu64 " '%s' stopped with a signal or exception.\n", (uint64_t)idx + 1, cmd); + + result.SetStatus(tmp_result.GetStatus()); + m_debugger.SetAsyncExecution (old_async_execution); + + return; + } + } } @@ -2639,6 +2676,19 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file, flags |= eHandleCommandFlagStopOnError; } + if (options.GetStopOnCrash()) + { + if (m_command_source_flags.empty()) + { + // Echo command by default + flags |= eHandleCommandFlagStopOnCrash; + } + else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) + { + flags |= eHandleCommandFlagStopOnCrash; + } + } + if (options.m_echo_commands == eLazyBoolCalculate) { if (m_command_source_flags.empty()) @@ -2694,7 +2744,7 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file, *this)); const bool old_async_execution = debugger.GetAsyncExecution(); - // Set synchronous execution if we not stopping when we continue + // Set synchronous execution if we are not stopping on continue if ((flags & eHandleCommandFlagStopOnContinue) == 0) debugger.SetAsyncExecution (false); @@ -3069,6 +3119,50 @@ CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string & io_handler.SetIsDone(true); break; } + + // Finally, if we're going to stop on crash, check that here: + if (!m_quit_requested + && result.GetDidChangeProcessState() + && io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash)) + { + bool should_stop = false; + TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget()); + if (target_sp) + { + ProcessSP process_sp (target_sp->GetProcessSP()); + if (process_sp) + { + for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) + { + StopReason reason = thread_sp->GetStopReason(); + if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation) + { + // If we are printing results, we ought to show the resaon why we are stopping here: + if (io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) + { + if (!result.GetImmediateOutputStream()) + { + const uint32_t start_frame = 0; + const uint32_t num_frames = 1; + const uint32_t num_frames_with_source = 1; + thread_sp->GetStatus (*io_handler.GetOutputStreamFile().get(), + start_frame, + num_frames, + num_frames_with_source); + } + } + should_stop = true; + break; + } + } + } + } + if (should_stop) + { + io_handler.SetIsDone(true); + m_stopped_for_crash = true; + } + } } bool @@ -3155,6 +3249,7 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, const bool multiple_lines = false; m_num_errors = 0; m_quit_requested = false; + m_stopped_for_crash = false; // Always re-create the IOHandlerEditline in case the input // changed. The old instance might have had a non-interactive diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index e4fdc77caea..cec56b4cb47 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -109,7 +109,10 @@ static OptionDefinition g_options[] = { 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, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone, - "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." }, + "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, + "Tells the debugger to running the commands from -s, -S, -o & -O, and then quit. However if any run command stopped due to a signal or crash, " + "the debugger will return to the interactive prompt at the place of the crash." }, { LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone, "Tells the debugger to open source files using the host's \"external editor\" mechanism." }, { LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone, @@ -406,6 +409,7 @@ Driver::OptionData::OptionData () : m_process_name(), m_process_pid(LLDB_INVALID_PROCESS_ID), m_use_external_editor(false), + m_batch(false), m_seen_options() { } @@ -429,6 +433,7 @@ Driver::OptionData::Clear () m_use_external_editor = false; m_wait_for = false; m_process_name.erase(); + m_batch = false; m_process_pid = LLDB_INVALID_PROCESS_ID; } @@ -641,6 +646,10 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) m_option_data.m_print_python_path = true; break; + case 'b': + m_option_data.m_batch = true; + break; + case 'c': { SBFileSpec file(optarg); @@ -924,6 +933,7 @@ Driver::MainLoop () // 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) { enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE @@ -973,8 +983,15 @@ Driver::MainLoop () SBCommandInterpreterRunOptions options; options.SetStopOnError (true); - - m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, quit_requested); + 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 @@ -1030,7 +1047,13 @@ Driver::MainLoop () // interpreter again in interactive mode and let the debugger // take ownership of stdin - if (!quit_requested) + 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); diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h index 8b6c6eebdd5..c4faac16b52 100644 --- a/lldb/tools/driver/Driver.h +++ b/lldb/tools/driver/Driver.h @@ -87,6 +87,7 @@ public: std::string m_process_name; lldb::pid_t m_process_pid; bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here. + bool m_batch; typedef std::set<char> OptionSet; OptionSet m_seen_options; }; |