From 738af7a6241c98164625b9cd1ba9f8af4e36f197 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 25 Oct 2019 14:05:07 -0700 Subject: Add the ability to pass extra args to a Python breakpoint callback. For example, it is pretty easy to write a breakpoint command that implements "stop when my caller is Foo", and it is pretty easy to write a breakpoint command that implements "stop when my caller is Bar". But there's no way to write a generic "stop when my caller is..." function, and then specify the caller when you add the command to a breakpoint. With this patch, you can pass this data in a SBStructuredData dictionary. That will get stored in the PythonCommandBaton for the breakpoint, and passed to the implementation function (if it has the right signature) when the breakpoint is hit. Then in lldb, you can say: (lldb) break com add -F caller_is -k caller_name -v Foo More generally this will allow us to write reusable Python breakpoint commands. Differential Revision: https://reviews.llvm.org/D68671 --- lldb/source/Commands/CommandObjectBreakpoint.cpp | 8 ++-- .../Commands/CommandObjectBreakpointCommand.cpp | 48 +++++++++++----------- lldb/source/Commands/CommandObjectThread.cpp | 12 +++--- lldb/source/Commands/Options.td | 7 ---- 4 files changed, 36 insertions(+), 39 deletions(-) (limited to 'lldb/source/Commands') diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index ad699975b50..042fc06a2bf 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -242,10 +242,10 @@ public: interpreter, "breakpoint set", "Sets a breakpoint or set of breakpoints in the executable.", "breakpoint set "), - 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 @@ protected: 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 @@ protected: 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()) { diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index a6bcd1d8dc3..ab853bc743a 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/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 @@ public: 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 @@ LLDB to stop." "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 @@ are no syntax errors may indicate that a function was declared but never called. ~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 @@ are no syntax errors may indicate that a function was declared but never called. } } - 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 @@ are no syntax errors may indicate that a function was declared but never called. 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 @@ are no syntax errors may indicate that a function was declared but never called. 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 @@ are no syntax errors may indicate that a function was declared but never called. 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 @@ protected: 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 @@ protected: 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 @@ protected: private: CommandOptions m_options; + OptionGroupPythonClassWithDict m_func_options; + OptionGroupOptions m_all_options; + std::vector m_bp_options_vec; // This stores the // breakpoint options that // we are currently diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 8c527455390..d498418601d 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -546,7 +546,9 @@ public: 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 @@ protected: } 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 @@ protected: 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 { diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 87f5506c305..ce9c3fa184a 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -268,10 +268,6 @@ let Command = "breakpoint command add" in { 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 @@ let Command = "thread step scope" in { 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 { -- cgit v1.2.3