[Lldb-commits] [lldb] r216747 - Allow "breakpoint command add" to add commands to more than one breakpoint at a time.
Jim Ingham
jingham at apple.com
Fri Aug 29 10:34:18 PDT 2014
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
More information about the lldb-commits
mailing list