summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Interpreter/ScriptInterpreter.h10
-rw-r--r--lldb/include/lldb/Interpreter/ScriptInterpreterPython.h2
-rw-r--r--lldb/source/Commands/CommandObjectBreakpointCommand.cpp128
-rw-r--r--lldb/source/Interpreter/ScriptInterpreter.cpp26
-rw-r--r--lldb/source/Interpreter/ScriptInterpreterPython.cpp42
-rw-r--r--lldb/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py10
6 files changed, 137 insertions, 81 deletions
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 10f6a85c0fb..5a8322f8eb4 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -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,
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h
index 187e5aee4a4..14a62d67fde 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -225,7 +225,7 @@ public:
AcquireInterpreterLock ();
void
- CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec,
CommandReturnObject &result);
void
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
index a2088504028..fdb87d11900 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;
};
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 561e881ac3b..b6c46f83bd9 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -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 (lldb::ScriptLanguage language)
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 ()
{
diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
index dd5ee748938..1b24fea7c21 100644
--- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp
@@ -256,24 +256,30 @@ ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::str
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)
+ if (!bp_options)
+ continue;
+
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+ if (data_ap.get())
{
- StreamFileSP error_sp = io_handler.GetErrorStreamFile();
- if (error_sp)
+ 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::IOHandlerInputComplete (IOHandler &io_handler, std::str
}
break;
}
-
-
}
@@ -1087,11 +1091,11 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
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
diff --git a/lldb/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py b/lldb/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
index 4b5e9830f22..3a3156bf203 100644
--- a/lldb/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
+++ b/lldb/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
@@ -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
OpenPOWER on IntegriCloud