diff options
author | Jim Ingham <jingham@apple.com> | 2014-08-29 17:34:17 +0000 |
---|---|---|
committer | Jim Ingham <jingham@apple.com> | 2014-08-29 17:34:17 +0000 |
commit | b5796cb40e6f7a5e504d8da41d0f31d4539d7110 (patch) | |
tree | dc2a15b5074282ded8d7907e54b42676ed35e07d /lldb/source/Commands/CommandObjectBreakpointCommand.cpp | |
parent | 09366de7a3d183071400c175cb5cf7ddc2321358 (diff) | |
download | llvm-b5796cb40e6f7a5e504d8da41d0f31d4539d7110.zip llvm-b5796cb40e6f7a5e504d8da41d0f31d4539d7110.tar.gz llvm-b5796cb40e6f7a5e504d8da41d0f31d4539d7110.tar.bz2 |
Allow "breakpoint command add" to add commands to more than one breakpoint at a time.
<rdar://problem/13314462>
llvm-svn: 216747
Diffstat (limited to 'lldb/source/Commands/CommandObjectBreakpointCommand.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 128 |
1 files changed, 70 insertions, 58 deletions
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index a208850..fdb87d1 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -47,7 +47,7 @@ public: "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit." " If no breakpoint is specified, adds the commands to the last created breakpoint.", NULL), - IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand), + IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { SetHelpLong ( @@ -229,9 +229,12 @@ one command per line.\n" ); { io_handler.SetIsDone(true); - BreakpointOptions *bp_options = (BreakpointOptions *) io_handler.GetUserData(); - if (bp_options) + std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData(); + for (BreakpointOptions *bp_options : *bp_options_vec) { + if (!bp_options) + continue; + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); if (data_ap.get()) { @@ -240,36 +243,37 @@ one command per line.\n" ); bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); } } - } void - CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, + CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, CommandReturnObject &result) { m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt *this, // IOHandlerDelegate true, // Run IOHandler in async mode - bp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + &bp_options_vec); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions } /// Set a one-liner as the callback for the breakpoint. void - SetBreakpointCommandCallback (BreakpointOptions *bp_options, + SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, const char *oneliner) { - std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - - // It's necessary to set both user_source and script_source to the oneliner. - // The former is used to generate callback description (as in breakpoint command list) - // while the latter is used for Python to interpret during the actual callback. - data_ap->user_source.AppendString (oneliner); - data_ap->script_source.assign (oneliner); - data_ap->stop_on_error = m_options.m_stop_on_error; + for (auto bp_options : bp_options_vec) + { + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); - bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); + // It's necessary to set both user_source and script_source to the oneliner. + // The former is used to generate callback description (as in breakpoint command list) + // while the latter is used for Python to interpret during the actual callback. + data_ap->user_source.AppendString (oneliner); + data_ap->script_source.assign (oneliner); + data_ap->stop_on_error = m_options.m_stop_on_error; + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); + } return; } @@ -460,15 +464,11 @@ protected: BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + m_bp_options_vec.clear(); + if (result.Succeeded()) { const size_t count = valid_bp_ids.GetSize(); - if (count > 1) - { - result.AppendError ("can only add commands to one breakpoint at a time."); - result.SetStatus (eReturnStatusFailed); - return false; - } for (size_t i = 0; i < count; ++i) { @@ -490,44 +490,45 @@ protected: if (bp_loc_sp) bp_options = bp_loc_sp->GetLocationOptions(); } + if (bp_options) + m_bp_options_vec.push_back (bp_options); + } + } - // Skip this breakpoint if bp_options is not good. - if (bp_options == NULL) continue; - - // If we are using script language, get the script interpreter - // in order to set or collect command callback. Otherwise, call - // the methods associated with this object. - if (m_options.m_use_script_language) - { - // Special handling for one-liner specified inline. - if (m_options.m_use_one_liner) - { - m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, - m_options.m_one_liner.c_str()); - } - else if (m_options.m_function_name.size()) - { - m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options, - m_options.m_function_name.c_str()); - } - else - { - m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options, - result); - } - } - else - { - // Special handling for one-liner specified inline. - if (m_options.m_use_one_liner) - SetBreakpointCommandCallback (bp_options, - m_options.m_one_liner.c_str()); - else - CollectDataForBreakpointCommandCallback (bp_options, - result); - } + // If we are using script language, get the script interpreter + // in order to set or collect command callback. Otherwise, call + // the methods associated with this object. + if (m_options.m_use_script_language) + { + ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter(); + // Special handling for one-liner specified inline. + if (m_options.m_use_one_liner) + { + script_interp->SetBreakpointCommandCallback (m_bp_options_vec, + m_options.m_one_liner.c_str()); + } + else if (m_options.m_function_name.size()) + { + script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec, + m_options.m_function_name.c_str()); + } + else + { + script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec, + result); } } + else + { + // Special handling for one-liner specified inline. + if (m_options.m_use_one_liner) + SetBreakpointCommandCallback (m_bp_options_vec, + m_options.m_one_liner.c_str()); + else + CollectDataForBreakpointCommandCallback (m_bp_options_vec, + result); + } + } return result.Succeeded(); @@ -535,6 +536,17 @@ protected: private: CommandOptions m_options; + std::vector<BreakpointOptions *> m_bp_options_vec; // This stores the breakpoint options that we are currently + // collecting commands for. In the CollectData... calls we need + // to hand this off to the IOHandler, which may run asynchronously. + // So we have to have some way to keep it alive, and not leak it. + // Making it an ivar of the command object, which never goes away + // achieves this. Note that if we were able to run + // the same command concurrently in one interpreter we'd have to + // make this "per invocation". But there are many more reasons + // why it is not in general safe to do that in lldb at present, + // so it isn't worthwhile to come up with a more complex mechanism + // to address this particular weakness right now. static const char *g_reader_instructions; }; |