Author: jingham Date: Fri Aug 29 12:34:17 2014 New Revision: 216747 URL: http://llvm.org/viewvc/llvm-project?rev=216747&view=rev Log: Allow "breakpoint command add" to add commands to more than one breakpoint at a time.
<rdar://problem/13314462> Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp lldb/trunk/source/Interpreter/ScriptInterpreter.cpp lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=216747&r1=216746&r2=216747&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original) +++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Fri Aug 29 12:34:17 2014 @@ -372,7 +372,7 @@ public: } virtual void - CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, + CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &options, CommandReturnObject &result); virtual void @@ -380,6 +380,10 @@ public: CommandReturnObject &result); /// Set the specified text as the callback for the breakpoint. + Error + SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, + const char *callback_text); + virtual Error SetBreakpointCommandCallback (BreakpointOptions *bp_options, const char *callback_text) @@ -389,6 +393,10 @@ public: return error; } + void + SetBreakpointCommandCallbackFunction (std::vector<BreakpointOptions *> &bp_options_vec, + const char *function_name); + /// Set a one-liner as the callback for the breakpoint. virtual void SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h?rev=216747&r1=216746&r2=216747&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h (original) +++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h Fri Aug 29 12:34:17 2014 @@ -225,7 +225,7 @@ public: AcquireInterpreterLock (); void - CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, + CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, CommandReturnObject &result); void Modified: lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp?rev=216747&r1=216746&r2=216747&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectBreakpointCommand.cpp Fri Aug 29 12:34:17 2014 @@ -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; }; Modified: lldb/trunk/source/Interpreter/ScriptInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreter.cpp?rev=216747&r1=216746&r2=216747&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/ScriptInterpreter.cpp (original) +++ lldb/trunk/source/Interpreter/ScriptInterpreter.cpp Fri Aug 29 12:34:17 2014 @@ -44,7 +44,7 @@ ScriptInterpreter::GetCommandInterpreter void ScriptInterpreter::CollectDataForBreakpointCommandCallback ( - BreakpointOptions *bp_options, + std::vector<BreakpointOptions *> &bp_options_vec, CommandReturnObject &result ) { @@ -81,6 +81,30 @@ ScriptInterpreter::LanguageToString (lld return return_value; } +Error +ScriptInterpreter::SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, + const char *callback_text) +{ + Error return_error; + for (BreakpointOptions *bp_options : bp_options_vec) + { + return_error = SetBreakpointCommandCallback(bp_options, callback_text); + if (return_error.Success()) + break; + } + return return_error; +} + +void +ScriptInterpreter::SetBreakpointCommandCallbackFunction (std::vector<BreakpointOptions *> &bp_options_vec, + const char *function_name) +{ + for (BreakpointOptions *bp_options : bp_options_vec) + { + SetBreakpointCommandCallbackFunction(bp_options, function_name); + } +} + std::unique_ptr<ScriptInterpreterLocker> ScriptInterpreter::AcquireInterpreterLock () { Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=216747&r1=216746&r2=216747&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original) +++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Fri Aug 29 12:34:17 2014 @@ -256,24 +256,30 @@ ScriptInterpreterPython::IOHandlerInputC break; case eIOHandlerBreakpoint: { - BreakpointOptions *bp_options = (BreakpointOptions *)io_handler.GetUserData(); - std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - if (data_ap.get()) + std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData(); + for (auto bp_options : *bp_options_vec) { - data_ap->user_source.SplitIntoLines(data); - - if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source).Success()) - { - BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); - bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); - } - else if (!batch_mode) - { - StreamFileSP error_sp = io_handler.GetErrorStreamFile(); - if (error_sp) + if (!bp_options) + continue; + + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines(data); + + if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source).Success()) { - error_sp->Printf ("Warning: No command attached to breakpoint.\n"); - error_sp->Flush(); + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + if (error_sp) + { + error_sp->Printf ("Warning: No command attached to breakpoint.\n"); + error_sp->Flush(); + } } } } @@ -307,8 +313,6 @@ ScriptInterpreterPython::IOHandlerInputC } break; } - - } @@ -1087,11 +1091,11 @@ ScriptInterpreterPython::ExecuteMultiple void -ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, +ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, CommandReturnObject &result) { m_active_io_handler = eIOHandlerBreakpoint; - m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, bp_options); + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, &bp_options_vec); } void Modified: lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py?rev=216747&r1=216746&r2=216747&view=diff ============================================================================== --- lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py (original) +++ lldb/trunk/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py Fri Aug 29 12:34:17 2014 @@ -52,9 +52,11 @@ class BreakpointCommandTestCase(TestBase lldbutil.run_break_set_by_file_and_line (self, None, self.line, num_expected_locations=1, loc_exact=True) lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True) lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True) + # Breakpoint 4 - set at the same location as breakpoint 1 to test setting breakpoint commands on two breakpoints at a time + lldbutil.run_break_set_by_file_and_line (self, None, self.line, num_expected_locations=1, loc_exact=True) # Now add callbacks for the breakpoints just created. - self.runCmd("breakpoint command add -s command -o 'frame variable --show-types --scope' 1") + self.runCmd("breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4") self.runCmd("breakpoint command add -s python -o 'here = open(\"output.txt\", \"w\"); print >> here, \"lldb\"; here.close()' 2") self.runCmd("breakpoint command add --python-function bktptcmd.function 3") @@ -83,6 +85,12 @@ class BreakpointCommandTestCase(TestBase substrs = ["Breakpoint commands:", "bktptcmd.function(frame, bp_loc, internal_dict)"]) + self.expect("breakpoint command list 4", "Breakpoint 4 command ok", + substrs = ["Breakpoint commands:", + "frame variable --show-types --scope"]) + + self.runCmd("breakpoint delete 4") + self.runCmd("command script import --allow-reload ./bktptcmd.py") # Next lets try some other breakpoint kinds. First break with a regular expression _______________________________________________ lldb-commits mailing list lldb-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits