jingham updated this revision to Diff 224929.
jingham added a comment.
Addressed Pavel's comments.
I explicitly want the number of fixed arguments, so I changed the function name
to GetNumFixedArguments. The docs say explicitly that you have to make the
function take either three or four fixed arguments, and that's what I have to
check against. I don't want to know about varargs and optional named arguments.
I added the Expected, though I didn't plumb the change into
PythonCallable::GetNumArguments. That's of marginal extra benefit, and
orthogonal to the purposes of this patch.
Note also, the fact that I was now checking argument signatures when adding the
command means you can no longer do:
(lldb) break command add -F myfunc.function
(lldb) command script import myfunc.py
which TestBreakpointCommand.py was doing. You have to make the Python function
available BEFORE adding it to the breakpoint. I don't think this was an
feature, and I don't see any harm in adding that requirement. But it is a
change in behavior so I thought I'd bring it up.
Repository:
rLLDB LLDB
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D68671/new/
https://reviews.llvm.org/D68671
Files:
lldb/include/lldb/API/SBBreakpoint.h
lldb/include/lldb/API/SBBreakpointLocation.h
lldb/include/lldb/API/SBBreakpointName.h
lldb/include/lldb/API/SBStructuredData.h
lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h
lldb/include/lldb/Interpreter/ScriptInterpreter.h
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
lldb/scripts/Python/python-wrapper.swig
lldb/scripts/interface/SBBreakpoint.i
lldb/scripts/interface/SBBreakpointLocation.i
lldb/scripts/interface/SBBreakpointName.i
lldb/source/API/SBBreakpoint.cpp
lldb/source/API/SBBreakpointLocation.cpp
lldb/source/API/SBBreakpointName.cpp
lldb/source/Commands/CommandObjectBreakpoint.cpp
lldb/source/Commands/CommandObjectBreakpointCommand.cpp
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Commands/Options.td
lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp
lldb/source/Interpreter/ScriptInterpreter.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
===================================================================
--- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -62,7 +62,8 @@
extern "C" bool LLDBSwigPythonBreakpointCallbackFunction(
const char *python_function_name, const char *session_dictionary_name,
const lldb::StackFrameSP &sb_frame,
- const lldb::BreakpointLocationSP &sb_bp_loc) {
+ const lldb::BreakpointLocationSP &sb_bp_loc,
+ StructuredDataImpl *args_impl) {
return false;
}
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -179,8 +179,10 @@
Status GenerateFunction(const char *signature,
const StringList &input) override;
- Status GenerateBreakpointCommandCallbackData(StringList &input,
- std::string &output) override;
+ Status GenerateBreakpointCommandCallbackData(
+ StringList &input,
+ std::string &output,
+ bool has_extra_args) override;
bool GenerateWatchpointCommandCallbackData(StringList &input,
std::string &output) override;
@@ -244,14 +246,22 @@
Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
const char *callback_body) override;
- void SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options,
- const char *function_name) override;
+ Status SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options,
+ const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) override;
/// This one is for deserialization:
Status SetBreakpointCommandCallback(
BreakpointOptions *bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &data_up) override;
+ Status SetBreakpointCommandCallback(
+ BreakpointOptions *bp_options,
+ const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp,
+ bool uses_extra_args);
+
/// Set a one-liner as the callback for the watchpoint.
void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
const char *oneliner) override;
@@ -366,6 +376,10 @@
PythonDictionary &GetSessionDictionary();
PythonDictionary &GetSysModuleDictionary();
+
+ llvm::Expected<size_t>
+ GetNumFixedArgumentsForCallable(const llvm::StringRef &callable_name)
+ override;
bool GetEmbeddedInterpreterModuleObjects();
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -17,6 +17,7 @@
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Core/IOHandler.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/lldb-private.h"
@@ -34,6 +35,13 @@
CommandDataPython() : BreakpointOptions::CommandData() {
interpreter = lldb::eScriptLanguagePython;
}
+ CommandDataPython(StructuredData::ObjectSP extra_args_sp) :
+ BreakpointOptions::CommandData(),
+ m_extra_args_up(new StructuredDataImpl()) {
+ interpreter = lldb::eScriptLanguagePython;
+ m_extra_args_up->SetObjectSP(extra_args_sp);
+ }
+ lldb::StructuredDataImplUP m_extra_args_up;
};
ScriptInterpreterPython(Debugger &debugger)
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -74,7 +74,8 @@
extern "C" bool LLDBSwigPythonBreakpointCallbackFunction(
const char *python_function_name, const char *session_dictionary_name,
const lldb::StackFrameSP &sb_frame,
- const lldb::BreakpointLocationSP &sb_bp_loc);
+ const lldb::BreakpointLocationSP &sb_bp_loc,
+ StructuredDataImpl *args_impl);
extern "C" bool LLDBSwigPythonWatchpointCallbackFunction(
const char *python_function_name, const char *session_dictionary_name,
@@ -551,8 +552,10 @@
break;
data_up->user_source.SplitIntoLines(data);
+ StructuredData::ObjectSP empty_args_sp;
if (GenerateBreakpointCommandCallbackData(data_up->user_source,
- data_up->script_source)
+ data_up->script_source,
+ false)
.Success()) {
auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>(
std::move(data_up));
@@ -777,6 +780,32 @@
return m_sys_module_dict;
}
+llvm::Expected<size_t>
+ScriptInterpreterPythonImpl::GetNumFixedArgumentsForCallable(
+ const llvm::StringRef &callable_name)
+{
+ if (callable_name.empty()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "called with empty callable name.");
+ }
+ Locker py_lock(this, Locker::AcquireLock |
+ Locker::InitSession |
+ Locker::NoSTDIN);
+ auto dict = PythonModule::MainModule()
+ .ResolveName<PythonDictionary>(m_dictionary_name);
+ auto pfunc
+ = PythonObject::ResolveNameWithDictionary<PythonCallable>(callable_name,
+ dict);
+ if (!pfunc.IsAllocated()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "can't find callable: %s", callable_name.str().c_str());
+ }
+ PythonCallable::ArgInfo arg_info = pfunc.GetNumArguments();
+ return arg_info.count;
+}
+
static std::string GenerateUniqueName(const char *base_name_wanted,
uint32_t &functions_counter,
const void *name_token = nullptr) {
@@ -1258,14 +1287,46 @@
" ", *this, true, wp_options);
}
-void ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options, const char *function_name) {
+Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options, const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) {
+ Status error;
// For now just cons up a oneliner that calls the provided function.
std::string oneliner("return ");
oneliner += function_name;
- oneliner += "(frame, bp_loc, internal_dict)";
- m_debugger.GetScriptInterpreter()->SetBreakpointCommandCallback(
- bp_options, oneliner.c_str());
+
+ llvm::Expected<size_t> maybe_args
+ = GetNumFixedArgumentsForCallable(function_name);
+ if (!maybe_args) {
+ error.SetErrorStringWithFormat("could not get num args: %s",
+ llvm::toString(maybe_args.takeError()).c_str());
+ return error;
+ }
+ size_t num_args = *maybe_args;
+
+ bool uses_extra_args = false;
+ if (num_args == 4) {
+ uses_extra_args = true;
+ oneliner += "(frame, bp_loc, extra_args, internal_dict)";
+ }
+ else if (num_args == 3) {
+ if (extra_args_sp) {
+ error.SetErrorString("cannot pass extra_args to a three argument callback"
+ );
+ return error;
+ }
+ uses_extra_args = false;
+ oneliner += "(frame, bp_loc, internal_dict)";
+ } else {
+ error.SetErrorStringWithFormat("expected 3 or 4 argument "
+ "function, %s has %d",
+ function_name, num_args);
+ return error;
+ }
+
+ SetBreakpointCommandCallback(bp_options, oneliner.c_str(), extra_args_sp,
+ uses_extra_args);
+ return error;
}
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
@@ -1273,7 +1334,8 @@
std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) {
Status error;
error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source,
- cmd_data_up->script_source);
+ cmd_data_up->script_source,
+ false);
if (error.Fail()) {
return error;
}
@@ -1284,11 +1346,17 @@
return error;
}
-// Set a Python one-liner as the callback for the breakpoint.
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
BreakpointOptions *bp_options, const char *command_body_text) {
- auto data_up = std::make_unique<CommandDataPython>();
+ return SetBreakpointCommandCallback(bp_options, command_body_text, {},false);
+}
+// Set a Python one-liner as the callback for the breakpoint.
+Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
+ BreakpointOptions *bp_options, const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp,
+ bool uses_extra_args) {
+ auto data_up = std::make_unique<CommandDataPython>(extra_args_sp);
// Split the command_body_text into lines, and pass that to
// GenerateBreakpointCommandCallbackData. That will wrap the body in an
// auto-generated function, and return the function name in script_source.
@@ -1296,7 +1364,8 @@
data_up->user_source.SplitIntoLines(command_body_text);
Status error = GenerateBreakpointCommandCallbackData(data_up->user_source,
- data_up->script_source);
+ data_up->script_source,
+ uses_extra_args);
if (error.Success()) {
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
@@ -2118,7 +2187,8 @@
}
Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData(
- StringList &user_input, std::string &output) {
+ StringList &user_input, std::string &output,
+ bool has_extra_args) {
static uint32_t num_created_functions = 0;
user_input.RemoveBlankLines();
StreamString sstr;
@@ -2130,8 +2200,12 @@
std::string auto_generated_function_name(GenerateUniqueName(
"lldb_autogen_python_bp_callback_func_", num_created_functions));
- sstr.Printf("def %s (frame, bp_loc, internal_dict):",
- auto_generated_function_name.c_str());
+ if (has_extra_args)
+ sstr.Printf("def %s (frame, bp_loc, extra_args, internal_dict):",
+ auto_generated_function_name.c_str());
+ else
+ sstr.Printf("def %s (frame, bp_loc, internal_dict):",
+ auto_generated_function_name.c_str());
error = GenerateFunction(sstr.GetData(), user_input);
if (!error.Success())
@@ -2251,7 +2325,8 @@
ret_val = LLDBSwigPythonBreakpointCallbackFunction(
python_function_name,
python_interpreter->m_dictionary_name.c_str(), stop_frame_sp,
- bp_loc_sp);
+ bp_loc_sp,
+ bp_option_data->m_extra_args_up.get());
}
return ret_val;
}
Index: lldb/source/Interpreter/ScriptInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/ScriptInterpreter.cpp
+++ lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -81,12 +81,18 @@
return return_error;
}
-void ScriptInterpreter::SetBreakpointCommandCallbackFunction(
+Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
std::vector<BreakpointOptions *> &bp_options_vec,
- const char *function_name) {
+ const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) {
+ Status error;
for (BreakpointOptions *bp_options : bp_options_vec) {
- SetBreakpointCommandCallbackFunction(bp_options, function_name);
+ error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
+ extra_args_sp);
+ if (!error.Success())
+ return error;
}
+ return error;
}
std::unique_ptr<ScriptInterpreterLocker>
Index: lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp
===================================================================
--- lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp
+++ lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp
@@ -15,30 +15,29 @@
OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict
(const char *class_use,
+ bool is_class,
int class_option,
int key_option,
- int value_option,
- const char *class_long_option,
- const char *key_long_option,
- const char *value_long_option,
- bool required) {
- m_key_usage_text.assign("The key for a key/value pair passed to the class"
- " that implements a ");
+ int value_option) : OptionGroup(), m_is_class(is_class) {
+ m_key_usage_text.assign("The key for a key/value pair passed to the "
+ "implementation of a ");
m_key_usage_text.append(class_use);
m_key_usage_text.append(". Pairs can be specified more than once.");
- m_value_usage_text.assign("The value for a previous key in the pair passed to"
- " the class that implements a ");
+ m_value_usage_text.assign("The value for the previous key in the pair passed "
+ "to the implementation of a ");
m_value_usage_text.append(class_use);
m_value_usage_text.append(". Pairs can be specified more than once.");
- m_class_usage_text.assign("The name of the class that will manage a ");
+ m_class_usage_text.assign("The name of the ");
+ m_class_usage_text.append(m_is_class ? "class" : "function");
+ m_class_usage_text.append(" that will manage a ");
m_class_usage_text.append(class_use);
m_class_usage_text.append(".");
m_option_definition[0].usage_mask = LLDB_OPT_SET_1;
- m_option_definition[0].required = required;
- m_option_definition[0].long_option = class_long_option;
+ m_option_definition[0].required = true;
+ m_option_definition[0].long_option = "script-class";
m_option_definition[0].short_option = class_option;
m_option_definition[0].validator = nullptr;
m_option_definition[0].option_has_arg = OptionParser::eRequiredArgument;
@@ -47,9 +46,9 @@
m_option_definition[0].argument_type = eArgTypePythonClass;
m_option_definition[0].usage_text = m_class_usage_text.data();
- m_option_definition[1].usage_mask = LLDB_OPT_SET_1;
- m_option_definition[1].required = required;
- m_option_definition[1].long_option = key_long_option;
+ m_option_definition[1].usage_mask = LLDB_OPT_SET_2;
+ m_option_definition[1].required = false;
+ m_option_definition[1].long_option = "structured-data-key";
m_option_definition[1].short_option = key_option;
m_option_definition[1].validator = nullptr;
m_option_definition[1].option_has_arg = OptionParser::eRequiredArgument;
@@ -58,9 +57,9 @@
m_option_definition[1].argument_type = eArgTypeNone;
m_option_definition[1].usage_text = m_key_usage_text.data();
- m_option_definition[2].usage_mask = LLDB_OPT_SET_1;
- m_option_definition[2].required = required;
- m_option_definition[2].long_option = value_long_option;
+ m_option_definition[2].usage_mask = LLDB_OPT_SET_2;
+ m_option_definition[2].required = false;
+ m_option_definition[2].long_option = "structured-data-value";
m_option_definition[2].short_option = value_option;
m_option_definition[2].validator = nullptr;
m_option_definition[2].option_has_arg = OptionParser::eRequiredArgument;
@@ -68,6 +67,18 @@
m_option_definition[2].completion_type = 0;
m_option_definition[2].argument_type = eArgTypeNone;
m_option_definition[2].usage_text = m_value_usage_text.data();
+
+ m_option_definition[3].usage_mask = LLDB_OPT_SET_3;
+ m_option_definition[3].required = true;
+ m_option_definition[3].long_option = "python-function";
+ m_option_definition[3].short_option = class_option;
+ m_option_definition[3].validator = nullptr;
+ m_option_definition[3].option_has_arg = OptionParser::eRequiredArgument;
+ m_option_definition[3].enum_values = {};
+ m_option_definition[3].completion_type = 0;
+ m_option_definition[3].argument_type = eArgTypePythonFunction;
+ m_option_definition[3].usage_text = m_class_usage_text.data();
+
}
OptionGroupPythonClassWithDict::~OptionGroupPythonClassWithDict() {}
@@ -78,10 +89,13 @@
ExecutionContext *execution_context) {
Status error;
switch (option_idx) {
- case 0: {
- m_class_name.assign(option_arg);
+ case 0:
+ case 3: {
+ m_name.assign(option_arg);
} break;
case 1: {
+ if (!m_dict_sp)
+ m_dict_sp = std::make_shared<StructuredData::Dictionary>();
if (m_current_key.empty())
m_current_key.assign(option_arg);
else
@@ -90,6 +104,8 @@
} break;
case 2: {
+ if (!m_dict_sp)
+ m_dict_sp = std::make_shared<StructuredData::Dictionary>();
if (!m_current_key.empty()) {
m_dict_sp->AddStringItem(m_current_key, option_arg);
m_current_key.clear();
@@ -107,7 +123,10 @@
void OptionGroupPythonClassWithDict::OptionParsingStarting(
ExecutionContext *execution_context) {
m_current_key.erase();
- m_dict_sp = std::make_shared<StructuredData::Dictionary>();
+ // Leave the dictionary shared pointer unset. That way you can tell that
+ // the user didn't pass any -k -v pairs. We want to be able to warn if these
+ // were passed when the function they passed won't use them.
+ m_dict_sp.reset();
}
Status OptionGroupPythonClassWithDict::OptionParsingFinished(
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -268,10 +268,6 @@
EnumArg<"None", "ScriptOptionEnum()">,
Desc<"Specify the language for the commands - if none is specified, the "
"lldb command interpreter will be used.">;
- def breakpoint_add_python_function : Option<"python-function", "F">,
- Group<2>, Arg<"PythonFunction">,
- Desc<"Give the name of a Python function to run as command for this "
- "breakpoint. Be sure to give a module name if appropriate.">;
def breakpoint_add_dummy_breakpoints : Option<"dummy-breakpoints", "D">,
Desc<"Sets Dummy breakpoints - i.e. breakpoints set before a file is "
"provided, which prime new targets.">;
@@ -907,9 +903,6 @@
def thread_step_scope_step_in_target : Option<"step-in-target", "t">,
Group<1>, Arg<"FunctionName">, Desc<"The name of the directly called "
"function step in should stop at when stepping into.">;
- def thread_step_scope_python_class : Option<"python-class", "C">, Group<2>,
- Arg<"PythonClass">, Desc<"The name of the class that will manage this step "
- "- only supported for Scripted Step.">;
}
let Command = "thread until" in {
Index: lldb/source/Commands/CommandObjectThread.cpp
===================================================================
--- lldb/source/Commands/CommandObjectThread.cpp
+++ lldb/source/Commands/CommandObjectThread.cpp
@@ -546,7 +546,9 @@
m_arguments.push_back(arg);
if (step_type == eStepTypeScripted) {
- m_all_options.Append(&m_class_options, LLDB_OPT_SET_1, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_class_options,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
+ LLDB_OPT_SET_1);
}
m_all_options.Append(&m_options);
m_all_options.Finalize();
@@ -596,15 +598,15 @@
}
if (m_step_type == eStepTypeScripted) {
- if (m_class_options.GetClassName().empty()) {
+ if (m_class_options.GetName().empty()) {
result.AppendErrorWithFormat("empty class name for scripted step.");
result.SetStatus(eReturnStatusFailed);
return false;
} else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists(
- m_class_options.GetClassName().c_str())) {
+ m_class_options.GetName().c_str())) {
result.AppendErrorWithFormat(
"class for scripted step: \"%s\" does not exist.",
- m_class_options.GetClassName().c_str());
+ m_class_options.GetName().c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -720,7 +722,7 @@
m_options.m_step_out_avoid_no_debug);
} else if (m_step_type == eStepTypeScripted) {
new_plan_sp = thread->QueueThreadPlanForStepScripted(
- abort_other_plans, m_class_options.GetClassName().c_str(),
+ abort_other_plans, m_class_options.GetName().c_str(),
m_class_options.GetStructuredData(),
bool_stop_other_threads, new_plan_status);
} else {
Index: lldb/source/Commands/CommandObjectBreakpointCommand.cpp
===================================================================
--- lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -17,6 +17,7 @@
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/State.h"
@@ -66,7 +67,7 @@
nullptr),
IOHandlerDelegateMultiline("DONE",
IOHandlerDelegate::Completion::LLDBCommand),
- m_options() {
+ m_options(), m_func_options("breakpoint command", false, 'F') {
SetHelpLong(
R"(
General information about entering breakpoint commands
@@ -201,6 +202,11 @@
"Final Note: A warning that no breakpoint command was generated when there \
are no syntax errors may indicate that a function was declared but never called.");
+ m_all_options.Append(&m_options);
+ m_all_options.Append(&m_func_options, LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
+ LLDB_OPT_SET_2);
+ m_all_options.Finalize();
+
CommandArgumentEntry arg;
CommandArgumentData bp_id_arg;
@@ -218,7 +224,7 @@
~CommandObjectBreakpointCommandAdd() override = default;
- Options *GetOptions() override { return &m_options; }
+ Options *GetOptions() override { return &m_all_options; }
void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
@@ -269,19 +275,20 @@
}
}
- class CommandOptions : public Options {
+ class CommandOptions : public OptionGroup {
public:
CommandOptions()
- : Options(), m_use_commands(false), m_use_script_language(false),
+ : OptionGroup(), m_use_commands(false), m_use_script_language(false),
m_script_language(eScriptLanguageNone), m_use_one_liner(false),
- m_one_liner(), m_function_name() {}
+ m_one_liner() {}
~CommandOptions() override = default;
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) override {
Status error;
- const int short_option = m_getopt_table[option_idx].val;
+ const int short_option
+ = g_breakpoint_command_add_options[option_idx].short_option;
switch (short_option) {
case 'o':
@@ -313,12 +320,6 @@
option_arg.str().c_str());
} break;
- case 'F':
- m_use_one_liner = false;
- m_use_script_language = true;
- m_function_name.assign(option_arg);
- break;
-
case 'D':
m_use_dummy = true;
break;
@@ -337,7 +338,6 @@
m_use_one_liner = false;
m_stop_on_error = true;
m_one_liner.clear();
- m_function_name.clear();
m_use_dummy = false;
}
@@ -355,7 +355,6 @@
bool m_use_one_liner;
std::string m_one_liner;
bool m_stop_on_error;
- std::string m_function_name;
bool m_use_dummy;
};
@@ -372,12 +371,9 @@
return false;
}
- if (!m_options.m_use_script_language &&
- !m_options.m_function_name.empty()) {
- result.AppendError("need to enable scripting to have a function run as a "
- "breakpoint command");
- result.SetStatus(eReturnStatusFailed);
- return false;
+ if (!m_func_options.GetName().empty()) {
+ m_options.m_use_one_liner = false;
+ m_options.m_use_script_language = true;
}
BreakpointIDList valid_bp_ids;
@@ -421,9 +417,12 @@
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.empty()) {
- script_interp->SetBreakpointCommandCallbackFunction(
- m_bp_options_vec, m_options.m_function_name.c_str());
+ } else if (!m_func_options.GetName().empty()) {
+ Status error = script_interp->SetBreakpointCommandCallbackFunction(
+ m_bp_options_vec, m_func_options.GetName().c_str(),
+ m_func_options.GetStructuredData());
+ if (!error.Success())
+ result.SetError(error);
} else {
script_interp->CollectDataForBreakpointCommandCallback(
m_bp_options_vec, result);
@@ -443,6 +442,9 @@
private:
CommandOptions m_options;
+ OptionGroupPythonClassWithDict m_func_options;
+ OptionGroupOptions m_all_options;
+
std::vector<BreakpointOptions *> m_bp_options_vec; // This stores the
// breakpoint options that
// we are currently
Index: lldb/source/Commands/CommandObjectBreakpoint.cpp
===================================================================
--- lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -242,10 +242,10 @@
interpreter, "breakpoint set",
"Sets a breakpoint or set of breakpoints in the executable.",
"breakpoint set <cmd-options>"),
- m_bp_opts(), m_python_class_options("scripted breakpoint", 'P'),
+ m_bp_opts(), m_python_class_options("scripted breakpoint", true, 'P'),
m_options() {
// We're picking up all the normal options, commands and disable.
- m_all_options.Append(&m_python_class_options, LLDB_OPT_SET_1,
+ m_all_options.Append(&m_python_class_options, LLDB_OPT_SET_1|LLDB_OPT_SET_2,
LLDB_OPT_SET_11);
m_all_options.Append(&m_bp_opts,
LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
@@ -543,7 +543,7 @@
BreakpointSetType break_type = eSetTypeInvalid;
- if (!m_python_class_options.GetClassName().empty())
+ if (!m_python_class_options.GetName().empty())
break_type = eSetTypeScripted;
else if (m_options.m_line_num != 0)
break_type = eSetTypeFileAndLine;
@@ -699,7 +699,7 @@
Status error;
bp_sp = target.CreateScriptedBreakpoint(
- m_python_class_options.GetClassName().c_str(), &(m_options.m_modules),
+ m_python_class_options.GetName().c_str(), &(m_options.m_modules),
&(m_options.m_filenames), false, m_options.m_hardware,
m_python_class_options.GetStructuredData(), &error);
if (error.Fail()) {
Index: lldb/source/API/SBBreakpointName.cpp
===================================================================
--- lldb/source/API/SBBreakpointName.cpp
+++ lldb/source/API/SBBreakpointName.cpp
@@ -12,11 +12,13 @@
#include "lldb/API/SBError.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBTarget.h"
#include "lldb/Breakpoint/BreakpointName.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Target.h"
@@ -565,24 +567,41 @@
}
void SBBreakpointName::SetScriptCallbackFunction(
- const char *callback_function_name) {
- LLDB_RECORD_METHOD(void, SBBreakpointName, SetScriptCallbackFunction,
- (const char *), callback_function_name);
-
+ const char *callback_function_name) {
+LLDB_RECORD_METHOD(void, SBBreakpointName, SetScriptCallbackFunction,
+ (const char *), callback_function_name);
+ SBStructuredData empty_args;
+ SetScriptCallbackFunction(callback_function_name, empty_args);
+}
+
+SBError SBBreakpointName::SetScriptCallbackFunction(
+ const char *callback_function_name,
+ SBStructuredData &extra_args) {
+ LLDB_RECORD_METHOD(SBError, SBBreakpointName, SetScriptCallbackFunction,
+ (const char *, SBStructuredData &),
+ callback_function_name, extra_args);
+ SBError sb_error;
BreakpointName *bp_name = GetBreakpointName();
- if (!bp_name)
- return;
+ if (!bp_name) {
+ sb_error.SetErrorString("unrecognized breakpoint name");
+ return LLDB_RECORD_RESULT(sb_error);
+ }
std::lock_guard<std::recursive_mutex> guard(
m_impl_up->GetTarget()->GetAPIMutex());
BreakpointOptions &bp_options = bp_name->GetOptions();
- m_impl_up->GetTarget()
+ Status error;
+ error = m_impl_up->GetTarget()
->GetDebugger()
.GetScriptInterpreter()
->SetBreakpointCommandCallbackFunction(&bp_options,
- callback_function_name);
+ callback_function_name,
+ extra_args.m_impl_up
+ ->GetObjectSP());
+ sb_error.SetError(error);
UpdateName(*bp_name);
+ return LLDB_RECORD_RESULT(sb_error);
}
SBError
@@ -728,6 +747,8 @@
(lldb::SBStream &));
LLDB_REGISTER_METHOD(void, SBBreakpointName, SetScriptCallbackFunction,
(const char *));
+ LLDB_REGISTER_METHOD(SBError, SBBreakpointName, SetScriptCallbackFunction,
+ (const char *, SBStructuredData &));
LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpointName, SetScriptCallbackBody,
(const char *));
LLDB_REGISTER_METHOD_CONST(bool, SBBreakpointName, GetAllowList, ());
Index: lldb/source/API/SBBreakpointLocation.cpp
===================================================================
--- lldb/source/API/SBBreakpointLocation.cpp
+++ lldb/source/API/SBBreakpointLocation.cpp
@@ -12,12 +12,14 @@
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBStringList.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Target.h"
@@ -207,23 +209,38 @@
}
void SBBreakpointLocation::SetScriptCallbackFunction(
- const char *callback_function_name) {
- LLDB_RECORD_METHOD(void, SBBreakpointLocation, SetScriptCallbackFunction,
- (const char *), callback_function_name);
+ const char *callback_function_name) {
+LLDB_RECORD_METHOD(void, SBBreakpointLocation, SetScriptCallbackFunction,
+ (const char *), callback_function_name);
+}
+SBError SBBreakpointLocation::SetScriptCallbackFunction(
+ const char *callback_function_name,
+ SBStructuredData &extra_args) {
+ LLDB_RECORD_METHOD(SBError, SBBreakpointLocation, SetScriptCallbackFunction,
+ (const char *, SBStructuredData &),
+ callback_function_name, extra_args);
+ SBError sb_error;
BreakpointLocationSP loc_sp = GetSP();
if (loc_sp) {
+ Status error;
std::lock_guard<std::recursive_mutex> guard(
loc_sp->GetTarget().GetAPIMutex());
BreakpointOptions *bp_options = loc_sp->GetLocationOptions();
- loc_sp->GetBreakpoint()
+ error = loc_sp->GetBreakpoint()
.GetTarget()
.GetDebugger()
.GetScriptInterpreter()
->SetBreakpointCommandCallbackFunction(bp_options,
- callback_function_name);
- }
+ callback_function_name,
+ extra_args.m_impl_up
+ ->GetObjectSP());
+ sb_error.SetError(error);
+ } else
+ sb_error.SetErrorString("invalid breakpoint");
+
+ return LLDB_RECORD_RESULT(sb_error);
}
SBError
@@ -482,6 +499,8 @@
LLDB_REGISTER_METHOD(bool, SBBreakpointLocation, GetAutoContinue, ());
LLDB_REGISTER_METHOD(void, SBBreakpointLocation, SetScriptCallbackFunction,
(const char *));
+ LLDB_REGISTER_METHOD(SBError, SBBreakpointLocation, SetScriptCallbackFunction,
+ (const char *, SBStructuredData &));
LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpointLocation,
SetScriptCallbackBody, (const char *));
LLDB_REGISTER_METHOD(void, SBBreakpointLocation, SetCommandLineCommands,
Index: lldb/source/API/SBBreakpoint.cpp
===================================================================
--- lldb/source/API/SBBreakpoint.cpp
+++ lldb/source/API/SBBreakpoint.cpp
@@ -14,6 +14,7 @@
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBThread.h"
#include "lldb/Breakpoint/Breakpoint.h"
@@ -25,6 +26,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Process.h"
@@ -590,22 +592,38 @@
}
void SBBreakpoint::SetScriptCallbackFunction(
- const char *callback_function_name) {
- LLDB_RECORD_METHOD(void, SBBreakpoint, SetScriptCallbackFunction,
- (const char *), callback_function_name);
-
+ const char *callback_function_name) {
+LLDB_RECORD_METHOD(void, SBBreakpoint, SetScriptCallbackFunction,
+ (const char *), callback_function_name);
+ SBStructuredData empty_args;
+ SetScriptCallbackFunction(callback_function_name, empty_args);
+}
+
+SBError SBBreakpoint::SetScriptCallbackFunction(
+ const char *callback_function_name,
+ SBStructuredData &extra_args) {
+ LLDB_RECORD_METHOD(SBError, SBBreakpoint, SetScriptCallbackFunction,
+ (const char *, SBStructuredData &), callback_function_name, extra_args);
+ SBError sb_error;
BreakpointSP bkpt_sp = GetSP();
if (bkpt_sp) {
+ Status error;
std::lock_guard<std::recursive_mutex> guard(
bkpt_sp->GetTarget().GetAPIMutex());
BreakpointOptions *bp_options = bkpt_sp->GetOptions();
- bkpt_sp->GetTarget()
+ error = bkpt_sp->GetTarget()
.GetDebugger()
.GetScriptInterpreter()
->SetBreakpointCommandCallbackFunction(bp_options,
- callback_function_name);
- }
+ callback_function_name,
+ extra_args.m_impl_up
+ ->GetObjectSP());
+ sb_error.SetError(error);
+ } else
+ sb_error.SetErrorString("invalid breakpoint");
+
+ return LLDB_RECORD_RESULT(sb_error);
}
SBError SBBreakpoint::SetScriptCallbackBody(const char *callback_body_text) {
@@ -992,6 +1010,8 @@
(lldb::SBAddress &));
LLDB_REGISTER_METHOD(void, SBBreakpoint, SetScriptCallbackFunction,
(const char *));
+ LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpoint, SetScriptCallbackFunction,
+ (const char *, SBStructuredData &));
LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpoint, SetScriptCallbackBody,
(const char *));
LLDB_REGISTER_METHOD(bool, SBBreakpoint, AddName, (const char *));
Index: lldb/scripts/interface/SBBreakpointName.i
===================================================================
--- lldb/scripts/interface/SBBreakpointName.i
+++ lldb/scripts/interface/SBBreakpointName.i
@@ -84,6 +84,10 @@
void SetScriptCallbackFunction(const char *callback_function_name);
+ SBError
+ SetScriptCallbackFunction (const char *callback_function_name,
+ SBStructuredData &extra_args);
+
void SetCommandLineCommands(SBStringList &commands);
bool GetCommandLineCommands(SBStringList &commands);
Index: lldb/scripts/interface/SBBreakpointLocation.i
===================================================================
--- lldb/scripts/interface/SBBreakpointLocation.i
+++ lldb/scripts/interface/SBBreakpointLocation.i
@@ -73,10 +73,19 @@
void SetAutoContinue(bool auto_continue);
%feature("docstring", "
- Set the callback to the given Python function name.") SetScriptCallbackFunction;
+ Set the callback to the given Python function name.
+ The function takes three arguments (frame, bp_loc, dict).") SetScriptCallbackFunction;
void
SetScriptCallbackFunction (const char *callback_function_name);
+ %feature("docstring", "
+ Set the name of the script function to be called when the breakpoint is hit.
+ To use this variant, the function should take (frame, bp_loc, extra_args, dict) and
+ when the breakpoint is hit the extra_args will be passed to the callback function.") SetScriptCallbackFunction;
+ SBError
+ SetScriptCallbackFunction (const char *callback_function_name,
+ SBStructuredData &extra_args);
+
%feature("docstring", "
Provide the body for the script function to be called when the breakpoint location is hit.
The body will be wrapped in a function, which be passed two arguments:
Index: lldb/scripts/interface/SBBreakpoint.i
===================================================================
--- lldb/scripts/interface/SBBreakpoint.i
+++ lldb/scripts/interface/SBBreakpoint.i
@@ -179,6 +179,14 @@
void
SetScriptCallbackFunction (const char *callback_function_name);
+ %feature("docstring", "
+ Set the name of the script function to be called when the breakpoint is hit.
+ To use this variant, the function should take (frame, bp_loc, extra_args, dict) and
+ when the breakpoint is hit the extra_args will be passed to the callback function.") SetScriptCallbackFunction;
+ SBError
+ SetScriptCallbackFunction (const char *callback_function_name,
+ SBStructuredData &extra_args);
+
%feature("docstring", "
Provide the body for the script function to be called when the breakpoint is hit.
The body will be wrapped in a function, which be passed two arguments:
Index: lldb/scripts/Python/python-wrapper.swig
===================================================================
--- lldb/scripts/Python/python-wrapper.swig
+++ lldb/scripts/Python/python-wrapper.swig
@@ -45,7 +45,8 @@
const char *python_function_name,
const char *session_dictionary_name,
const lldb::StackFrameSP& frame_sp,
- const lldb::BreakpointLocationSP& bp_loc_sp
+ const lldb::BreakpointLocationSP& bp_loc_sp,
+ lldb_private::StructuredDataImpl *args_impl
)
{
using namespace lldb_private;
@@ -63,7 +64,19 @@
PythonObject frame_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_frame));
PythonObject bp_loc_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_bp_loc));
- PythonObject result = pfunc(frame_arg, bp_loc_arg, dict);
+
+ PythonObject result;
+ // If the called function doesn't take extra_args, drop them here:
+ auto arg_info = pfunc.GetNumArguments();
+ if (arg_info.count == 3)
+ result = pfunc(frame_arg, bp_loc_arg, dict);
+ else if (arg_info.count == 4) {
+ lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl);
+ PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value));
+ result = pfunc(frame_arg, bp_loc_arg, args_arg, dict);
+ } else {
+ return stop_at_breakpoint;
+ }
if (result.get() == Py_False)
stop_at_breakpoint = false;
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py
@@ -1,5 +1,23 @@
from __future__ import print_function
import side_effect
+def useless_function(first, second):
+ print("I have the wrong number of arguments.")
+
def function(frame, bp_loc, dict):
side_effect.bktptcmd = "function was here"
+
+def another_function(frame, bp_loc, extra_args, dict):
+ se_value = extra_args.GetValueForKey("side_effect")
+ se_string = se_value.GetStringValue(100)
+ side_effect.fancy = se_string
+
+def a_third_function(frame, bp_loc, extra_args, dict):
+ se_value = extra_args.GetValueForKey("side_effect")
+ se_string = se_value.GetStringValue(100)
+ side_effect.fancier = se_string
+
+def empty_extra_args(frame, bp_loc, extra_args, dict):
+ if extra_args.IsValid():
+ side_effect.not_so_fancy = "Extra args should not be valid"
+ side_effect.not_so_fancy = "Not so fancy"
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py
@@ -19,10 +19,15 @@
@add_test_categories(['pyapi'])
def test_step_out_python(self):
- """Test stepping out using avoid-no-debug with dsyms."""
+ """Test stepping out using a python breakpoint command."""
self.build()
self.do_set_python_command_from_python()
+ def test_bkpt_cmd_bad_arguments(self):
+ """Test what happens when pass structured data to a command:"""
+ self.build()
+ self.do_bad_args_to_python_command()
+
def setUp(self):
TestBase.setUp(self)
self.main_source = "main.c"
@@ -43,6 +48,18 @@
"Set break point at this line.", self.main_source_spec)
self.assertTrue(func_bkpt, VALID_BREAKPOINT)
+ fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(fancy_bkpt, VALID_BREAKPOINT)
+
+ fancier_bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(fancier_bkpt, VALID_BREAKPOINT)
+
+ not_so_fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(not_so_fancy_bkpt, VALID_BREAKPOINT)
+
# Also test that setting a source regex breakpoint with an empty file
# spec list sets it on all files:
no_files_bkpt = self.target.BreakpointCreateBySourceRegex(
@@ -75,14 +92,37 @@
"Failed to set the script callback body: %s." %
(error.GetCString()))
- self.dbg.HandleCommand(
- "command script import --allow-reload ./bktptcmd.py")
+ self.expect("command script import --allow-reload ./bktptcmd.py")
+
func_bkpt.SetScriptCallbackFunction("bktptcmd.function")
+ extra_args = lldb.SBStructuredData()
+ stream = lldb.SBStream()
+ stream.Print('{"side_effect" : "I am fancy"}')
+ extra_args.SetFromJSON(stream)
+ error = fancy_bkpt.SetScriptCallbackFunction("bktptcmd.another_function", extra_args)
+ self.assertTrue(error.Success(), "Failed to add callback %s"%(error.GetCString()))
+
+ stream.Clear()
+ stream.Print('{"side_effect" : "I am so much fancier"}')
+ extra_args.SetFromJSON(stream)
+
+ # Fancier's callback is set up from the command line
+ id = fancier_bkpt.GetID()
+ self.expect("breakpoint command add -F bktptcmd.a_third_function -k side_effect -v 'I am fancier' %d"%(id))
+
+ # Not so fancy gets an empty extra_args:
+ empty_args = lldb.SBStructuredData()
+ error = not_so_fancy_bkpt.SetScriptCallbackFunction("bktptcmd.empty_extra_args", empty_args)
+ self.assertTrue(error.Success(), "Failed to add callback %s"%(error.GetCString()))
+
# Clear out canary variables
side_effect.bktptcmd = None
side_effect.callback = None
-
+ side_effect.fancy = None
+ side_effect.fancier = None
+ side_effect.not_so_fancy = None
+
# Now launch the process, and do not stop at entry point.
self.process = self.target.LaunchSimple(
None, None, self.get_process_working_directory())
@@ -97,3 +137,38 @@
self.assertEquals("callback was here", side_effect.callback)
self.assertEquals("function was here", side_effect.bktptcmd)
+ self.assertEquals("I am fancy", side_effect.fancy)
+ self.assertEquals("I am fancier", side_effect.fancier)
+ self.assertEquals("Not so fancy", side_effect.not_so_fancy)
+
+ def do_bad_args_to_python_command(self):
+ exe = self.getBuildArtifact("a.out")
+ error = lldb.SBError()
+
+ self.target = self.dbg.CreateTarget(exe)
+ self.assertTrue(self.target, VALID_TARGET)
+
+
+ self.expect("command script import --allow-reload ./bktptcmd.py")
+
+ bkpt = self.target.BreakpointCreateBySourceRegex(
+ "Set break point at this line.", self.main_source_spec)
+ self.assertTrue(bkpt, VALID_BREAKPOINT)
+
+ # Pass a breakpoint command function that doesn't take extra_args,
+ # but pass it extra args:
+
+ extra_args = lldb.SBStructuredData()
+ stream = lldb.SBStream()
+ stream.Print('{"side_effect" : "I am fancy"}')
+ extra_args.SetFromJSON(stream)
+
+ error = bkpt.SetScriptCallbackFunction("bktptcmd.function", extra_args)
+ self.assertTrue(error.Fail(), "Can't pass extra args if the function doesn't take them")
+
+ error = bkpt.SetScriptCallbackFunction("bktptcmd.useless_function", extra_args)
+ self.assertTrue(error.Fail(), "Can't pass extra args if the function has wrong number of args.")
+
+ error = bkpt.SetScriptCallbackFunction("bktptcmd.nosuch_function", extra_args)
+ self.assertTrue(error.Fail(), "Can't pass extra args if the function doesn't exist.")
+
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
@@ -18,7 +18,7 @@
mydir = TestBase.compute_mydir(__file__)
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
- def test_breakpoint_command_sequence(self):
+ def not_test_breakpoint_command_sequence(self):
"""Test a sequence of breakpoint command add, list, and delete."""
self.build()
self.breakpoint_command_sequence()
@@ -107,6 +107,10 @@
"breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4")
self.runCmd(
"breakpoint command add -s python -o 'import side_effect; side_effect.one_liner = \"one liner was here\"' 2")
+
+ import side_effect
+ self.runCmd("command script import --allow-reload ./bktptcmd.py")
+
self.runCmd(
"breakpoint command add --python-function bktptcmd.function 3")
@@ -151,8 +155,6 @@
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
# and then specify only one file. The first time we should get two locations,
# the second time only one:
Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h
===================================================================
--- lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -117,8 +117,10 @@
return error;
}
- virtual Status GenerateBreakpointCommandCallbackData(StringList &input,
- std::string &output) {
+ virtual Status GenerateBreakpointCommandCallbackData(
+ StringList &input,
+ std::string &output,
+ bool has_extra_args) {
Status error;
error.SetErrorString("not implemented");
return error;
@@ -308,14 +310,17 @@
return error;
}
- void SetBreakpointCommandCallbackFunction(
+ Status SetBreakpointCommandCallbackFunction(
std::vector<BreakpointOptions *> &bp_options_vec,
- const char *function_name);
+ const char *function_name,
+ StructuredData::ObjectSP extra_args_sp);
- /// Set a one-liner as the callback for the breakpoint.
- virtual void
- SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options,
- const char *function_name) {}
+ /// Set a script function as the callback for the breakpoint.
+ virtual Status
+ SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options,
+ const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) {}
/// Set a one-liner as the callback for the watchpoint.
virtual void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
@@ -460,6 +465,12 @@
const char *GetScriptInterpreterPtyName();
int GetMasterFileDescriptor();
+
+ virtual llvm::Expected<size_t>
+ GetNumFixedArgumentsForCallable(const llvm::StringRef &callable_name) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(), "Unimplemented function");
+ }
static std::string LanguageToString(lldb::ScriptLanguage language);
Index: lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h
===================================================================
--- lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h
+++ lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h
@@ -24,13 +24,10 @@
class OptionGroupPythonClassWithDict : public OptionGroup {
public:
OptionGroupPythonClassWithDict(const char *class_use,
- int class_option = 'C',
- int key_option = 'k',
- int value_option = 'v',
- const char *class_long_option = "python-class",
- const char *key_long_option = "python-class-key",
- const char *value_long_option = "python-class-value",
- bool required = false);
+ bool is_class = true,
+ int class_option = 'C',
+ int key_option = 'k',
+ int value_option = 'v');
~OptionGroupPythonClassWithDict() override;
@@ -48,16 +45,17 @@
const StructuredData::DictionarySP GetStructuredData() {
return m_dict_sp;
}
- const std::string &GetClassName() {
- return m_class_name;
+ const std::string &GetName() {
+ return m_name;
}
protected:
- std::string m_class_name;
+ std::string m_name;
std::string m_current_key;
StructuredData::DictionarySP m_dict_sp;
std::string m_class_usage_text, m_key_usage_text, m_value_usage_text;
- OptionDefinition m_option_definition[3];
+ bool m_is_class;
+ OptionDefinition m_option_definition[4];
};
} // namespace lldb_private
Index: lldb/include/lldb/API/SBStructuredData.h
===================================================================
--- lldb/include/lldb/API/SBStructuredData.h
+++ lldb/include/lldb/API/SBStructuredData.h
@@ -93,6 +93,9 @@
friend class SBTarget;
friend class SBThread;
friend class SBThreadPlan;
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
+ friend class SBBreakpointName;
StructuredDataImplUP m_impl_up;
};
Index: lldb/include/lldb/API/SBBreakpointName.h
===================================================================
--- lldb/include/lldb/API/SBBreakpointName.h
+++ lldb/include/lldb/API/SBBreakpointName.h
@@ -85,9 +85,12 @@
void SetScriptCallbackFunction(const char *callback_function_name);
- void SetCommandLineCommands(SBStringList &commands);
+ SBError SetScriptCallbackFunction(const char *callback_function_name,
+ SBStructuredData &extra_args);
- bool GetCommandLineCommands(SBStringList &commands);
+ void SetCommandLineCommands(lldb::SBStringList &commands);
+
+ bool GetCommandLineCommands(lldb::SBStringList &commands);
SBError SetScriptCallbackBody(const char *script_body_text);
Index: lldb/include/lldb/API/SBBreakpointLocation.h
===================================================================
--- lldb/include/lldb/API/SBBreakpointLocation.h
+++ lldb/include/lldb/API/SBBreakpointLocation.h
@@ -55,11 +55,14 @@
void SetScriptCallbackFunction(const char *callback_function_name);
+ SBError SetScriptCallbackFunction(const char *callback_function_name,
+ lldb::SBStructuredData &extra_args);
+
SBError SetScriptCallbackBody(const char *script_body_text);
- void SetCommandLineCommands(SBStringList &commands);
+ void SetCommandLineCommands(lldb::SBStringList &commands);
- bool GetCommandLineCommands(SBStringList &commands);
+ bool GetCommandLineCommands(lldb::SBStringList &commands);
void SetThreadID(lldb::tid_t sb_thread_id);
Index: lldb/include/lldb/API/SBBreakpoint.h
===================================================================
--- lldb/include/lldb/API/SBBreakpoint.h
+++ lldb/include/lldb/API/SBBreakpoint.h
@@ -94,6 +94,9 @@
void SetScriptCallbackFunction(const char *callback_function_name);
+ SBError SetScriptCallbackFunction(const char *callback_function_name,
+ SBStructuredData &extra_args);
+
void SetCommandLineCommands(SBStringList &commands);
bool GetCommandLineCommands(SBStringList &commands);
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits