Author: Jonas Devlieghere Date: 2020-09-28T09:04:32-07:00 New Revision: f775fe59640a2e837ad059a8f40e26989d4f9831
URL: https://github.com/llvm/llvm-project/commit/f775fe59640a2e837ad059a8f40e26989d4f9831 DIFF: https://github.com/llvm/llvm-project/commit/f775fe59640a2e837ad059a8f40e26989d4f9831.diff LOG: Revert "Add the ability to write target stop-hooks using the ScriptInterpreter." This temporarily reverts commit b65966cff65bfb66de59621347ffd97238d3f645 while Jim figures out why the test is failing on the bots. Added: Modified: lldb/bindings/python/python-swigsafecast.swig lldb/bindings/python/python-wrapper.swig lldb/docs/use/python-reference.rst lldb/include/lldb/Interpreter/ScriptInterpreter.h lldb/include/lldb/Symbol/SymbolContext.h lldb/include/lldb/Target/Target.h lldb/source/Commands/CommandObjectTarget.cpp lldb/source/Commands/Options.td lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h lldb/source/Symbol/SymbolContext.cpp lldb/source/Target/Target.cpp lldb/test/API/commands/target/stop-hooks/TestStopHooks.py lldb/test/API/commands/target/stop-hooks/main.c lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp Removed: lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py lldb/test/API/commands/target/stop-hooks/stop_hook.py lldb/test/Shell/Commands/Inputs/stop_hook.py lldb/test/Shell/Commands/command-stop-hook-output.test ################################################################################ diff --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig index 091fc29b1057..d5cafbfa67cb 100644 --- a/lldb/bindings/python/python-swigsafecast.swig +++ b/lldb/bindings/python/python-swigsafecast.swig @@ -152,10 +152,3 @@ SBTypeToSWIGWrapper (lldb::SBSymbolContext* sym_ctx_sb) { return SWIG_NewPointerObj((void *) sym_ctx_sb, SWIGTYPE_p_lldb__SBSymbolContext, 0); } - -template <> -PyObject* -SBTypeToSWIGWrapper (lldb::SBStream* stream_sb) -{ - return SWIG_NewPointerObj((void *) stream_sb, SWIGTYPE_p_lldb__SBStream, 0); -} diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig index cd326046b421..516590ed5771 100644 --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -468,124 +468,6 @@ LLDBSwigPythonCallBreakpointResolver return ret_val; } -SWIGEXPORT void * -LLDBSwigPythonCreateScriptedStopHook -( - lldb::TargetSP target_sp, - const char *python_class_name, - const char *session_dictionary_name, - lldb_private::StructuredDataImpl *args_impl, - Status &error -) -{ - if (python_class_name == NULL || python_class_name[0] == '\0') { - error.SetErrorString("Empty class name."); - Py_RETURN_NONE; - } - if (!session_dictionary_name) { - error.SetErrorString("No session dictionary"); - Py_RETURN_NONE; - } - - PyErr_Cleaner py_err_cleaner(true); - - auto dict = - PythonModule::MainModule().ResolveName<PythonDictionary>( - session_dictionary_name); - auto pfunc = - PythonObject::ResolveNameWithDictionary<PythonCallable>( - python_class_name, dict); - - if (!pfunc.IsAllocated()) { - error.SetErrorStringWithFormat("Could not find class: %s.", - python_class_name); - return nullptr; - } - - lldb::SBTarget *target_val - = new lldb::SBTarget(target_sp); - - PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(target_val)); - - lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl); - PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value)); - - PythonObject result = pfunc(target_arg, args_arg, dict); - - if (result.IsAllocated()) - { - // Check that the handle_stop callback is defined: - auto callback_func = result.ResolveName<PythonCallable>("handle_stop"); - if (callback_func.IsAllocated()) { - if (auto args_info = callback_func.GetArgInfo()) { - if ((*args_info).max_positional_args < 2) { - error.SetErrorStringWithFormat("Wrong number of args for " - "handle_stop callback, should be 2 (excluding self), got: %d", - (*args_info).max_positional_args); - } else - return result.release(); - } else { - error.SetErrorString("Couldn't get num arguments for handle_stop " - "callback."); - } - return result.release(); - } - else { - error.SetErrorStringWithFormat("Class \"%s\" is missing the required " - "handle_stop callback.", - python_class_name); - result.release(); - } - } - Py_RETURN_NONE; -} - -SWIGEXPORT bool -LLDBSwigPythonStopHookCallHandleStop -( - void *implementor, - lldb::ExecutionContextRefSP exc_ctx_sp, - lldb::StreamSP stream -) -{ - // handle_stop will return a bool with the meaning "should_stop"... - // If you return nothing we'll assume we are going to stop. - // Also any errors should return true, since we should stop on error. - - PyErr_Cleaner py_err_cleaner(false); - PythonObject self(PyRefType::Borrowed, static_cast<PyObject*>(implementor)); - auto pfunc = self.ResolveName<PythonCallable>("handle_stop"); - - if (!pfunc.IsAllocated()) - return true; - - PythonObject result; - lldb::SBExecutionContext sb_exc_ctx(exc_ctx_sp); - PythonObject exc_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_exc_ctx)); - lldb::SBStream sb_stream; - PythonObject sb_stream_arg(PyRefType::Owned, - SBTypeToSWIGWrapper(sb_stream)); - result = pfunc(exc_ctx_arg, sb_stream_arg); - - if (PyErr_Occurred()) - { - stream->PutCString("Python error occurred handling stop-hook."); - PyErr_Print(); - PyErr_Clear(); - return true; - } - - // Now add the result to the output stream. SBStream only - // makes an internally help StreamString which I can't interpose, so I - // have to copy it over here. - stream->PutCString(sb_stream.GetData()); - - if (result.get() == Py_False) - return false; - else - return true; -} - // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember diff --git a/lldb/docs/use/python-reference.rst b/lldb/docs/use/python-reference.rst index 60474c94f185..8c76ef1a0830 100644 --- a/lldb/docs/use/python-reference.rst +++ b/lldb/docs/use/python-reference.rst @@ -819,49 +819,3 @@ When the program is stopped at the beginning of the 'read' function in libc, we frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read (lldb) frame variable (int) fd = 3 - - Writing Target Stop-Hooks in Python: - ------------------------------------ - - Stop hooks fire whenever the process stops just before control is returned to the - user. Stop hooks can either be a set of lldb command-line commands, or can - be implemented by a suitably defined Python class. The Python based stop-hooks - can also be passed as set of -key -value pairs when they are added, and those - will get packaged up into a SBStructuredData Dictionary and passed to the - constructor of the Python object managing the stop hook. This allows for - parametrization of the stop hooks. - - To add a Python-based stop hook, first define a class with the following methods: - -+--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| Name | Arguments | Description | -+--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| **__init__** | **target: lldb.SBTarget** | This is the constructor for the new stop-hook. | -| | **extra_args: lldb.SBStructuredData** | | -| | | | -| | | **target** is the SBTarget to which the stop hook is added. | -| | | | -| | | **extra_args** is an SBStructuredData object that the user can pass in when creating instances of this | -| | | breakpoint. It is not required, but allows for reuse of stop-hook classes. | -+--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| **handle_stop** | **exe_ctx: lldb.SBExecutionContext** | This is the called when the target stops. | -| | **stream: lldb.SBStream** | | -| | | **exe_ctx** argument will be filled with the current stop point for which the stop hook is | -| | | being evaluated. | -| | | | -| | | **stream** an lldb.SBStream, anything written to this stream will be written to the debugger console. | -| | | | -| | | The return value is a "Should Stop" vote from this thread. If the method returns either True or no return | -| | | this thread votes to stop. If it returns False, then the thread votes to continue after all the stop-hooks | -| | | are evaluated. | -| | | Note, the --auto-continue flag to 'target stop-hook add' overrides a True return value from the method. | -+--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ - -To use this class in lldb, run the command: - -:: - - (lldb) command script import MyModule.py - (lldb) target stop-hook add -P MyModule.MyStopHook -k first -v 1 -k second -v 2 - -where MyModule.py is the file containing the class definition MyStopHook. diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index c38786fd50d4..491923e6a6c4 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -298,23 +298,6 @@ class ScriptInterpreter : public PluginInterface { return lldb::eSearchDepthModule; } - virtual StructuredData::GenericSP - CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, - StructuredDataImpl *args_data, Status &error) { - error.SetErrorString("Creating scripted stop-hooks with the current " - "script interpreter is not supported."); - return StructuredData::GenericSP(); - } - - // This dispatches to the handle_stop method of the stop-hook class. It - // returns a "should_stop" bool. - virtual bool - ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, - ExecutionContext &exc_ctx, - lldb::StreamSP stream_sp) { - return true; - } - virtual StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { return StructuredData::ObjectSP(); diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h index 0f99364596c2..cc49ce51c713 100644 --- a/lldb/include/lldb/Symbol/SymbolContext.h +++ b/lldb/include/lldb/Symbol/SymbolContext.h @@ -340,7 +340,7 @@ class SymbolContextSpecifier { void Clear(); - bool SymbolContextMatches(const SymbolContext &sc); + bool SymbolContextMatches(SymbolContext &sc); bool AddressMatches(lldb::addr_t addr); diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 94c6ebeac10d..92904682ffb6 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -28,7 +28,6 @@ #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/PathMappingList.h" #include "lldb/Target/SectionLoadHistory.h" -#include "lldb/Target/ThreadSpec.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/LLDBAssert.h" @@ -509,8 +508,6 @@ class Target : public std::enable_shared_from_this<Target>, static void SetDefaultArchitecture(const ArchSpec &arch); - bool IsDummyTarget() const { return m_is_dummy_target; } - /// Find a binary on the system and return its Module, /// or return an existing Module that is already in the Target. /// @@ -1142,27 +1139,23 @@ class Target : public std::enable_shared_from_this<Target>, class StopHook : public UserID { public: StopHook(const StopHook &rhs); - virtual ~StopHook() = default; - enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased }; + ~StopHook(); + + StringList *GetCommandPointer() { return &m_commands; } + + const StringList &GetCommands() { return m_commands; } lldb::TargetSP &GetTarget() { return m_target_sp; } + void SetCommands(StringList &in_commands) { m_commands = in_commands; } + // Set the specifier. The stop hook will own the specifier, and is // responsible for deleting it when we're done. void SetSpecifier(SymbolContextSpecifier *specifier); SymbolContextSpecifier *GetSpecifier() { return m_specifier_sp.get(); } - bool ExecutionContextPasses(const ExecutionContext &exe_ctx); - - // Called on stop, this gets passed the ExecutionContext for each "stop - // with a reason" thread. It should add to the stream whatever text it - // wants to show the user, and return False to indicate it wants the target - // not to stop. - virtual bool HandleStop(ExecutionContext &exe_ctx, - lldb::StreamSP output) = 0; - // Set the Thread Specifier. The stop hook will own the thread specifier, // and is responsible for deleting it when we're done. void SetThreadSpecifier(ThreadSpec *specifier); @@ -1180,79 +1173,26 @@ class Target : public std::enable_shared_from_this<Target>, bool GetAutoContinue() const { return m_auto_continue; } void GetDescription(Stream *s, lldb::DescriptionLevel level) const; - virtual void GetSubclassDescription(Stream *s, - lldb::DescriptionLevel level) const = 0; - protected: + private: lldb::TargetSP m_target_sp; + StringList m_commands; lldb::SymbolContextSpecifierSP m_specifier_sp; std::unique_ptr<ThreadSpec> m_thread_spec_up; bool m_active = true; bool m_auto_continue = false; - StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid); - }; - - class StopHookCommandLine : public StopHook { - public: - virtual ~StopHookCommandLine() = default; - - StringList &GetCommands() { return m_commands; } - void SetActionFromString(const std::string &strings); - void SetActionFromStrings(const std::vector<std::string> &strings); - - bool HandleStop(ExecutionContext &exc_ctx, - lldb::StreamSP output_sp) override; - void GetSubclassDescription(Stream *s, - lldb::DescriptionLevel level) const override; - - private: - StringList m_commands; // Use CreateStopHook to make a new empty stop hook. The GetCommandPointer // and fill it with commands, and SetSpecifier to set the specifier shared // pointer (can be null, that will match anything.) - StopHookCommandLine(lldb::TargetSP target_sp, lldb::user_id_t uid) - : StopHook(target_sp, uid) {} - friend class Target; - }; - - class StopHookScripted : public StopHook { - public: - virtual ~StopHookScripted() = default; - bool HandleStop(ExecutionContext &exc_ctx, lldb::StreamSP output) override; - - Status SetScriptCallback(std::string class_name, - StructuredData::ObjectSP extra_args_sp); - - void GetSubclassDescription(Stream *s, - lldb::DescriptionLevel level) const override; - - private: - std::string m_class_name; - /// This holds the dictionary of keys & values that can be used to - /// parametrize any given callback's behavior. - StructuredDataImpl *m_extra_args; // We own this structured data, - // but the SD itself manages the UP. - /// This holds the python callback object. - StructuredData::GenericSP m_implementation_sp; - - /// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer - /// and fill it with commands, and SetSpecifier to set the specifier shared - /// pointer (can be null, that will match anything.) - StopHookScripted(lldb::TargetSP target_sp, lldb::user_id_t uid) - : StopHook(target_sp, uid) {} + StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid); friend class Target; }; - typedef std::shared_ptr<StopHook> StopHookSP; - /// Add an empty stop hook to the Target's stop hook list, and returns a - /// shared pointer to it in new_hook. Returns the id of the new hook. - StopHookSP CreateStopHook(StopHook::StopHookKind kind); - - /// If you tried to create a stop hook, and that failed, call this to - /// remove the stop hook, as it will also reset the stop hook counter. - void UndoCreateStopHook(lldb::user_id_t uid); + // Add an empty stop hook to the Target's stop hook list, and returns a + // shared pointer to it in new_hook. Returns the id of the new hook. + StopHookSP CreateStopHook(); void RunStopHooks(); diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 98285289e3a9..431c2f3a19f0 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -24,7 +24,6 @@ #include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Interpreter/OptionGroupPlatform.h" -#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionGroupString.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionGroupUUID.h" @@ -4443,10 +4442,10 @@ class CommandObjectTargetSymbols : public CommandObjectMultiword { class CommandObjectTargetStopHookAdd : public CommandObjectParsed, public IOHandlerDelegateMultiline { public: - class CommandOptions : public OptionGroup { + class CommandOptions : public Options { public: CommandOptions() - : OptionGroup(), m_line_start(0), m_line_end(UINT_MAX), + : Options(), m_line_start(0), m_line_end(UINT_MAX), m_func_name_type_mask(eFunctionNameTypeAuto), m_sym_ctx_specified(false), m_thread_specified(false), m_use_one_liner(false), m_one_liner() {} @@ -4460,8 +4459,7 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { Status error; - const int short_option = - g_target_stop_hook_add_options[option_idx].short_option; + const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'c': @@ -4591,75 +4589,20 @@ class CommandObjectTargetStopHookAdd : public CommandObjectParsed, // Instance variables to hold the values for one_liner options. bool m_use_one_liner; std::vector<std::string> m_one_liner; - bool m_auto_continue; }; CommandObjectTargetStopHookAdd(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "target stop-hook add", - "Add a hook to be executed when the target stops." - "The hook can either be a list of commands or an " - "appropriately defined Python class. You can also " - "add filters so the hook only runs a certain stop " - "points.", + "Add a hook to be executed when the target stops.", "target stop-hook add"), IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), - m_options(), m_python_class_options("scripted stop-hook", true, 'P') { - SetHelpLong( - R"( -Command Based stop-hooks: -------------------------- - Stop hooks can run a list of lldb commands by providing one or more - --one-line-command options. The commands will get run in the order they are - added. Or you can provide no commands, in which case you will enter a - command editor where you can enter the commands to be run. - -Python Based Stop Hooks: ------------------------- - Stop hooks can be implemented with a suitably defined Python class, whose name - is passed in the --python-class option. - - When the stop hook is added, the class is initialized by calling: - - def __init__(self, target, extra_args, dict): - - target: The target that the stop hook is being added to. - extra_args: An SBStructuredData Dictionary filled with the -key -value - option pairs passed to the command. - dict: An implementation detail provided by lldb. - - Then when the stop-hook triggers, lldb will run the 'handle_stop' method. - The method has the signature: - - def handle_stop(self, exe_ctx, stream): - - exe_ctx: An SBExecutionContext for the thread that has stopped. - stream: An SBStream, anything written to this stream will be printed in the - the stop message when the process stops. - - Return Value: The method returns "should_stop". If should_stop is false - from all the stop hook executions on threads that stopped - with a reason, then the process will continue. Note that this - will happen only after all the stop hooks are run. - -Filter Options: ---------------- - Stop hooks can be set to always run, or to only run when the stopped thread - matches the filter options passed on the command line. The available filter - options include a shared library or a thread or queue specification, - a line range in a source file, a function name or a class name. - )"); - m_all_options.Append(&m_python_class_options, - LLDB_OPT_SET_1 | LLDB_OPT_SET_2, - LLDB_OPT_SET_FROM_TO(4, 6)); - m_all_options.Append(&m_options); - m_all_options.Finalize(); - } + m_options() {} ~CommandObjectTargetStopHookAdd() override = default; - Options *GetOptions() override { return &m_all_options; } + Options *GetOptions() override { return &m_options; } protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { @@ -4683,15 +4626,10 @@ Filter Options: error_sp->Flush(); } Target *target = GetDebugger().GetSelectedTarget().get(); - if (target) { - target->UndoCreateStopHook(m_stop_hook_sp->GetID()); - } + if (target) + target->RemoveStopHookByID(m_stop_hook_sp->GetID()); } else { - // The IOHandler editor is only for command lines stop hooks: - Target::StopHookCommandLine *hook_ptr = - static_cast<Target::StopHookCommandLine *>(m_stop_hook_sp.get()); - - hook_ptr->SetActionFromString(line); + m_stop_hook_sp->GetCommandPointer()->SplitIntoLines(line); StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); if (output_sp) { output_sp->Printf("Stop hook #%" PRIu64 " added.\n", @@ -4708,10 +4646,7 @@ Filter Options: m_stop_hook_sp.reset(); Target &target = GetSelectedOrDummyTarget(); - Target::StopHookSP new_hook_sp = - target.CreateStopHook(m_python_class_options.GetName().empty() ? - Target::StopHook::StopHookKind::CommandBased - : Target::StopHook::StopHookKind::ScriptBased); + Target::StopHookSP new_hook_sp = target.CreateStopHook(); // First step, make the specifier. std::unique_ptr<SymbolContextSpecifier> specifier_up; @@ -4780,30 +4715,11 @@ Filter Options: new_hook_sp->SetAutoContinue(m_options.m_auto_continue); if (m_options.m_use_one_liner) { - // This is a command line stop hook: - Target::StopHookCommandLine *hook_ptr = - static_cast<Target::StopHookCommandLine *>(new_hook_sp.get()); - hook_ptr->SetActionFromStrings(m_options.m_one_liner); + // Use one-liners. + for (auto cmd : m_options.m_one_liner) + new_hook_sp->GetCommandPointer()->AppendString(cmd.c_str()); result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", new_hook_sp->GetID()); - } else if (!m_python_class_options.GetName().empty()) { - // This is a scripted stop hook: - Target::StopHookScripted *hook_ptr = - static_cast<Target::StopHookScripted *>(new_hook_sp.get()); - Status error = hook_ptr->SetScriptCallback( - m_python_class_options.GetName(), - m_python_class_options.GetStructuredData()); - if (error.Success()) - result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", - new_hook_sp->GetID()); - else { - // FIXME: Set the stop hook ID counter back. - result.AppendErrorWithFormat("Couldn't add stop hook: %s", - error.AsCString()); - result.SetStatus(eReturnStatusFailed); - target.UndoCreateStopHook(new_hook_sp->GetID()); - return false; - } } else { m_stop_hook_sp = new_hook_sp; m_interpreter.GetLLDBCommandsFromIOHandler("> ", // Prompt @@ -4816,9 +4732,6 @@ Filter Options: private: CommandOptions m_options; - OptionGroupPythonClassWithDict m_python_class_options; - OptionGroupOptions m_all_options; - Target::StopHookSP m_stop_hook_sp; }; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index ad2f5fdae8e7..8c83fd20a366 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -879,7 +879,7 @@ let Command = "target modules lookup" in { } let Command = "target stop hook add" in { - def target_stop_hook_add_one_liner : Option<"one-liner", "o">, GroupRange<1,3>, + def target_stop_hook_add_one_liner : Option<"one-liner", "o">, Arg<"OneLiner">, Desc<"Add a command for the stop hook. Can be specified " "more than once, and commands will be run in the order they appear.">; def target_stop_hook_add_shlib : Option<"shlib", "s">, Arg<"ShlibName">, @@ -897,19 +897,19 @@ let Command = "target stop hook add" in { def target_stop_hook_add_queue_name : Option<"queue-name", "q">, Arg<"QueueName">, Desc<"The stop hook is run only for threads in the queue " "whose name is given by this argument.">; - def target_stop_hook_add_file : Option<"file", "f">, Groups<[1,4]>, + def target_stop_hook_add_file : Option<"file", "f">, Group<1>, Arg<"Filename">, Desc<"Specify the source file within which the stop-hook " "is to be run.">, Completion<"SourceFile">; - def target_stop_hook_add_start_line : Option<"start-line", "l">, Groups<[1,4]>, + def target_stop_hook_add_start_line : Option<"start-line", "l">, Group<1>, Arg<"LineNum">, Desc<"Set the start of the line range for which the " "stop-hook is to be run.">; - def target_stop_hook_add_end_line : Option<"end-line", "e">, Groups<[1,4]>, + def target_stop_hook_add_end_line : Option<"end-line", "e">, Group<1>, Arg<"LineNum">, Desc<"Set the end of the line range for which the stop-hook" " is to be run.">; - def target_stop_hook_add_classname : Option<"classname", "c">, Groups<[2,5]>, + def target_stop_hook_add_classname : Option<"classname", "c">, Group<2>, Arg<"ClassName">, Desc<"Specify the class within which the stop-hook is to be run.">; - def target_stop_hook_add_name : Option<"name", "n">, Groups<[3,6]>, + def target_stop_hook_add_name : Option<"name", "n">, Group<3>, Arg<"FunctionName">, Desc<"Set the function name within which the stop hook" " will be run.">, Completion<"Symbol">; def target_stop_hook_add_auto_continue : Option<"auto-continue", "G">, diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 34f311892775..9f56b4fa60a5 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -127,16 +127,6 @@ extern "C" unsigned int LLDBSwigPythonCallBreakpointResolver(void *implementor, const char *method_name, lldb_private::SymbolContext *sym_ctx); -extern "C" void *LLDBSwigPythonCreateScriptedStopHook( - TargetSP target_sp, const char *python_class_name, - const char *session_dictionary_name, lldb_private::StructuredDataImpl *args, - lldb_private::Status &error); - -extern "C" unsigned int -LLDBSwigPythonStopHookCallHandleStop(void *implementor, - lldb::ExecutionContextRefSP exc_ctx, - lldb::StreamSP stream); - extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor, uint32_t max); @@ -1989,60 +1979,6 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( return lldb::eSearchDepthModule; } -StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedStopHook( - TargetSP target_sp, const char *class_name, StructuredDataImpl *args_data, - Status &error) { - - if (!target_sp) { - error.SetErrorString("No target for scripted stop-hook."); - return StructuredData::GenericSP(); - } - - if (class_name == nullptr || class_name[0] == '\0') { - error.SetErrorString("No class name for scripted stop-hook."); - return StructuredData::GenericSP(); - } - - ScriptInterpreter *script_interpreter = m_debugger.GetScriptInterpreter(); - ScriptInterpreterPythonImpl *python_interpreter = - static_cast<ScriptInterpreterPythonImpl *>(script_interpreter); - - if (!script_interpreter) { - error.SetErrorString("No script interpreter for scripted stop-hook."); - return StructuredData::GenericSP(); - } - - void *ret_val; - - { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - - ret_val = LLDBSwigPythonCreateScriptedStopHook( - target_sp, class_name, python_interpreter->m_dictionary_name.c_str(), - args_data, error); - } - - return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); -} - -bool ScriptInterpreterPythonImpl::ScriptedStopHookHandleStop( - StructuredData::GenericSP implementor_sp, ExecutionContext &exc_ctx, - lldb::StreamSP stream_sp) { - assert(implementor_sp && - "can't call a stop hook with an invalid implementor"); - assert(stream_sp && "can't call a stop hook with an invalid stream"); - - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - - lldb::ExecutionContextRefSP exc_ctx_ref_sp(new ExecutionContextRef(exc_ctx)); - - bool ret_val = LLDBSwigPythonStopHookCallHandleStop( - implementor_sp->GetValue(), exc_ctx_ref_sp, stream_sp); - return ret_val; -} - StructuredData::ObjectSP ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index f89c3d461f7f..22b2c8152eac 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -105,14 +105,6 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython { lldb::SearchDepth ScriptedBreakpointResolverSearchDepth( StructuredData::GenericSP implementor_sp) override; - StructuredData::GenericSP - CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, - StructuredDataImpl *args_data, Status &error) override; - - bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, - ExecutionContext &exc_ctx, - lldb::StreamSP stream_sp) override; - StructuredData::GenericSP CreateFrameRecognizer(const char *class_name) override; diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index f20dc61996e0..51f56704cca6 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -1010,15 +1010,11 @@ void SymbolContextSpecifier::Clear() { m_type = eNothingSpecified; } -bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext &sc) { +bool SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) { if (m_type == eNothingSpecified) return true; - // Only compare targets if this specifier has one and it's not the Dummy - // target. Otherwise if a specifier gets made in the dummy target and - // copied over we'll artificially fail the comparision. - if (m_target_sp && !m_target_sp->IsDummyTarget() && - m_target_sp != sc.target_sp) + if (m_target_sp.get() != sc.target_sp.get()) return false; if (m_type & eModuleSpecified) { diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index a5250ddcef74..a529df998ba7 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2484,28 +2484,13 @@ ClangModulesDeclVendor *Target::GetClangModulesDeclVendor() { return m_clang_modules_decl_vendor_up.get(); } -Target::StopHookSP Target::CreateStopHook(StopHook::StopHookKind kind) { +Target::StopHookSP Target::CreateStopHook() { lldb::user_id_t new_uid = ++m_stop_hook_next_id; - Target::StopHookSP stop_hook_sp; - switch (kind) { - case StopHook::StopHookKind::CommandBased: - stop_hook_sp.reset(new StopHookCommandLine(shared_from_this(), new_uid)); - break; - case StopHook::StopHookKind::ScriptBased: - stop_hook_sp.reset(new StopHookScripted(shared_from_this(), new_uid)); - break; - } + Target::StopHookSP stop_hook_sp(new StopHook(shared_from_this(), new_uid)); m_stop_hooks[new_uid] = stop_hook_sp; return stop_hook_sp; } -void Target::UndoCreateStopHook(lldb::user_id_t user_id) { - if (!RemoveStopHookByID(user_id)) - return; - if (user_id == m_stop_hook_next_id) - m_stop_hook_next_id--; -} - bool Target::RemoveStopHookByID(lldb::user_id_t user_id) { size_t num_removed = m_stop_hooks.erase(user_id); return (num_removed != 0); @@ -2561,18 +2546,25 @@ void Target::RunStopHooks() { if (m_stop_hooks.empty()) return; + StopHookCollection::iterator pos, end = m_stop_hooks.end(); + // If there aren't any active stop hooks, don't bother either. + // Also see if any of the active hooks want to auto-continue. bool any_active_hooks = false; + bool auto_continue = false; for (auto hook : m_stop_hooks) { if (hook.second->IsActive()) { any_active_hooks = true; - break; + auto_continue |= hook.second->GetAutoContinue(); } } if (!any_active_hooks) return; + CommandReturnObject result(m_debugger.GetUseColor()); + std::vector<ExecutionContext> exc_ctx_with_reasons; + std::vector<SymbolContext> sym_ctx_with_reasons; ThreadList &cur_threadlist = m_process_sp->GetThreadList(); size_t num_threads = cur_threadlist.GetSize(); @@ -2580,8 +2572,10 @@ void Target::RunStopHooks() { lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex(i); if (cur_thread_sp->ThreadStoppedForAReason()) { lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0); - exc_ctx_with_reasons.emplace_back(m_process_sp.get(), cur_thread_sp.get(), - cur_frame_sp.get()); + exc_ctx_with_reasons.push_back(ExecutionContext( + m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get())); + sym_ctx_with_reasons.push_back( + cur_frame_sp->GetSymbolContext(eSymbolContextEverything)); } } @@ -2590,86 +2584,91 @@ void Target::RunStopHooks() { if (num_exe_ctx == 0) return; - StreamSP output_sp = m_debugger.GetAsyncOutputStream(); + result.SetImmediateOutputStream(m_debugger.GetAsyncOutputStream()); + result.SetImmediateErrorStream(m_debugger.GetAsyncErrorStream()); - bool auto_continue = false; + bool keep_going = true; bool hooks_ran = false; bool print_hook_header = (m_stop_hooks.size() != 1); bool print_thread_header = (num_exe_ctx != 1); - bool should_stop = false; - bool somebody_restarted = false; + bool did_restart = false; - for (auto stop_entry : m_stop_hooks) { - StopHookSP cur_hook_sp = stop_entry.second; + for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++) { + // result.Clear(); + StopHookSP cur_hook_sp = (*pos).second; if (!cur_hook_sp->IsActive()) continue; bool any_thread_matched = false; - for (auto exc_ctx : exc_ctx_with_reasons) { - // We detect somebody restarted in the stop-hook loop, and broke out of - // that loop back to here. So break out of here too. - if (somebody_restarted) - break; - - if (!cur_hook_sp->ExecutionContextPasses(exc_ctx)) - continue; - - // We only consult the auto-continue for a stop hook if it matched the - // specifier. - auto_continue |= cur_hook_sp->GetAutoContinue(); - - if (!hooks_ran) - hooks_ran = true; - - if (print_hook_header && !any_thread_matched) { - StreamString s; - cur_hook_sp->GetDescription(&s, eDescriptionLevelBrief); - if (s.GetSize() != 0) - output_sp->Printf("\n- Hook %" PRIu64 " (%s)\n", cur_hook_sp->GetID(), - s.GetData()); - else - output_sp->Printf("\n- Hook %" PRIu64 "\n", cur_hook_sp->GetID()); - any_thread_matched = true; - } + for (size_t i = 0; keep_going && i < num_exe_ctx; i++) { + if ((cur_hook_sp->GetSpecifier() == nullptr || + cur_hook_sp->GetSpecifier()->SymbolContextMatches( + sym_ctx_with_reasons[i])) && + (cur_hook_sp->GetThreadSpecifier() == nullptr || + cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests( + exc_ctx_with_reasons[i].GetThreadRef()))) { + if (!hooks_ran) { + hooks_ran = true; + } + if (print_hook_header && !any_thread_matched) { + const char *cmd = + (cur_hook_sp->GetCommands().GetSize() == 1 + ? cur_hook_sp->GetCommands().GetStringAtIndex(0) + : nullptr); + if (cmd) + result.AppendMessageWithFormat("\n- Hook %" PRIu64 " (%s)\n", + cur_hook_sp->GetID(), cmd); + else + result.AppendMessageWithFormat("\n- Hook %" PRIu64 "\n", + cur_hook_sp->GetID()); + any_thread_matched = true; + } - if (print_thread_header) - output_sp->Printf("-- Thread %d\n", - exc_ctx.GetThreadPtr()->GetIndexID()); - - bool this_should_stop = cur_hook_sp->HandleStop(exc_ctx, output_sp); - // If this hook is set to auto-continue that should override the - // HandleStop result... - if (cur_hook_sp->GetAutoContinue()) - this_should_stop = false; - - // If anybody wanted to stop, we should all stop. - if (!should_stop) - should_stop = this_should_stop; - - // We don't have a good way to prohibit people from restarting the target - // willy nilly in a stop hook. So see if the private state is running - // here and bag out if it is. - // FIXME: when we are doing non-stop mode for realz we'll have to instead - // track each thread, and only bag out if a thread is set running. - if (m_process_sp->GetPrivateState() != eStateStopped) { - output_sp->Printf("\nAborting stop hooks, hook %" PRIu64 - " set the program running.\n" - " Consider using '-G true' to make " - "stop hooks auto-continue.\n", - cur_hook_sp->GetID()); - somebody_restarted = true; - break; + if (print_thread_header) + result.AppendMessageWithFormat( + "-- Thread %d\n", + exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID()); + + CommandInterpreterRunOptions options; + options.SetStopOnContinue(true); + options.SetStopOnError(true); + options.SetEchoCommands(false); + options.SetPrintResults(true); + options.SetPrintErrors(true); + options.SetAddToHistory(false); + + // Force Async: + bool old_async = GetDebugger().GetAsyncExecution(); + GetDebugger().SetAsyncExecution(true); + GetDebugger().GetCommandInterpreter().HandleCommands( + cur_hook_sp->GetCommands(), &exc_ctx_with_reasons[i], options, + result); + GetDebugger().SetAsyncExecution(old_async); + // If the command started the target going again, we should bag out of + // running the stop hooks. + if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult) || + (result.GetStatus() == eReturnStatusSuccessContinuingResult)) { + // But only complain if there were more stop hooks to do: + StopHookCollection::iterator tmp = pos; + if (++tmp != end) + result.AppendMessageWithFormat( + "\nAborting stop hooks, hook %" PRIu64 + " set the program running.\n" + " Consider using '-G true' to make " + "stop hooks auto-continue.\n", + cur_hook_sp->GetID()); + keep_going = false; + did_restart = true; + } } } } - - output_sp->Flush(); - // Finally, if auto-continue was requested, do it now: - // We only compute should_stop against the hook results if a hook got to run - // which is why we have to do this conjoint test. - if (!somebody_restarted && ((hooks_ran && !should_stop) || auto_continue)) + if (!did_restart && auto_continue) m_process_sp->PrivateResume(); + + result.GetImmediateOutputStream()->Flush(); + result.GetImmediateErrorStream()->Flush(); } const TargetPropertiesSP &Target::GetGlobalProperties() { @@ -3129,17 +3128,20 @@ void Target::FinalizeFileActions(ProcessLaunchInfo &info) { // Target::StopHook Target::StopHook::StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid) - : UserID(uid), m_target_sp(target_sp), m_specifier_sp(), + : UserID(uid), m_target_sp(target_sp), m_commands(), m_specifier_sp(), m_thread_spec_up() {} Target::StopHook::StopHook(const StopHook &rhs) : UserID(rhs.GetID()), m_target_sp(rhs.m_target_sp), - m_specifier_sp(rhs.m_specifier_sp), m_thread_spec_up(), - m_active(rhs.m_active), m_auto_continue(rhs.m_auto_continue) { + m_commands(rhs.m_commands), m_specifier_sp(rhs.m_specifier_sp), + m_thread_spec_up(), m_active(rhs.m_active), + m_auto_continue(rhs.m_auto_continue) { if (rhs.m_thread_spec_up) m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up); } +Target::StopHook::~StopHook() = default; + void Target::StopHook::SetSpecifier(SymbolContextSpecifier *specifier) { m_specifier_sp.reset(specifier); } @@ -3148,31 +3150,8 @@ void Target::StopHook::SetThreadSpecifier(ThreadSpec *specifier) { m_thread_spec_up.reset(specifier); } -bool Target::StopHook::ExecutionContextPasses(const ExecutionContext &exc_ctx) { - SymbolContextSpecifier *specifier = GetSpecifier(); - if (!specifier) - return true; - - bool will_run = true; - if (exc_ctx.GetFramePtr()) - will_run = GetSpecifier()->SymbolContextMatches( - exc_ctx.GetFramePtr()->GetSymbolContext(eSymbolContextEverything)); - if (will_run && GetThreadSpecifier() != nullptr) - will_run = - GetThreadSpecifier()->ThreadPassesBasicTests(exc_ctx.GetThreadRef()); - - return will_run; -} - void Target::StopHook::GetDescription(Stream *s, lldb::DescriptionLevel level) const { - - // For brief descriptions, only print the subclass description: - if (level == eDescriptionLevelBrief) { - GetSubclassDescription(s, level); - return; - } - unsigned indent_level = s->GetIndentLevel(); s->SetIndentLevel(indent_level + 2); @@ -3203,148 +3182,15 @@ void Target::StopHook::GetDescription(Stream *s, s->PutCString("\n"); s->SetIndentLevel(indent_level + 2); } - GetSubclassDescription(s, level); -} -void Target::StopHookCommandLine::GetSubclassDescription( - Stream *s, lldb::DescriptionLevel level) const { - // The brief description just prints the first command. - if (level == eDescriptionLevelBrief) { - if (m_commands.GetSize() == 1) - s->PutCString(m_commands.GetStringAtIndex(0)); - return; - } s->Indent("Commands: \n"); - s->SetIndentLevel(s->GetIndentLevel() + 4); + s->SetIndentLevel(indent_level + 4); uint32_t num_commands = m_commands.GetSize(); for (uint32_t i = 0; i < num_commands; i++) { s->Indent(m_commands.GetStringAtIndex(i)); s->PutCString("\n"); } - s->SetIndentLevel(s->GetIndentLevel() - 4); -} - -// Target::StopHookCommandLine -void Target::StopHookCommandLine::SetActionFromString(const std::string &string) { - GetCommands().SplitIntoLines(string); -} - -void Target::StopHookCommandLine::SetActionFromStrings( - const std::vector<std::string> &strings) { - for (auto string : strings) - GetCommands().AppendString(string.c_str()); -} - -bool Target::StopHookCommandLine::HandleStop(ExecutionContext &exc_ctx, - StreamSP output_sp) { - assert(exc_ctx.GetTargetPtr() && "Can't call PerformAction on a context " - "with no target"); - - if (!m_commands.GetSize()) - return true; - - CommandReturnObject result(false); - result.SetImmediateOutputStream(output_sp); - Debugger &debugger = exc_ctx.GetTargetPtr()->GetDebugger(); - CommandInterpreterRunOptions options; - options.SetStopOnContinue(true); - options.SetStopOnError(true); - options.SetEchoCommands(false); - options.SetPrintResults(true); - options.SetPrintErrors(true); - options.SetAddToHistory(false); - - // Force Async: - bool old_async = debugger.GetAsyncExecution(); - debugger.SetAsyncExecution(true); - debugger.GetCommandInterpreter().HandleCommands(GetCommands(), &exc_ctx, - options, result); - debugger.SetAsyncExecution(old_async); - - return true; -} - -// Target::StopHookScripted -Status Target::StopHookScripted::SetScriptCallback( - std::string class_name, StructuredData::ObjectSP extra_args_sp) { - Status error; - - ScriptInterpreter *script_interp = - GetTarget()->GetDebugger().GetScriptInterpreter(); - if (!script_interp) { - error.SetErrorString("No script interpreter installed."); - return error; - } - - m_class_name = class_name; - - m_extra_args = new StructuredDataImpl(); - - if (extra_args_sp) - m_extra_args->SetObjectSP(extra_args_sp); - - m_implementation_sp = script_interp->CreateScriptedStopHook( - GetTarget(), m_class_name.c_str(), m_extra_args, error); - - return error; -} - -bool Target::StopHookScripted::HandleStop(ExecutionContext &exc_ctx, - StreamSP output_sp) { - assert(exc_ctx.GetTargetPtr() && "Can't call HandleStop on a context " - "with no target"); - - ScriptInterpreter *script_interp = - GetTarget()->GetDebugger().GetScriptInterpreter(); - if (!script_interp) - return true; - - bool should_stop = script_interp->ScriptedStopHookHandleStop( - m_implementation_sp, exc_ctx, output_sp); - - return should_stop; -} - -void Target::StopHookScripted::GetSubclassDescription( - Stream *s, lldb::DescriptionLevel level) const { - if (level == eDescriptionLevelBrief) { - s->PutCString(m_class_name); - return; - } - s->Indent("Class:"); - s->Printf("%s\n", m_class_name.c_str()); - - // Now print the extra args: - // FIXME: We should use StructuredData.GetDescription on the m_extra_args - // but that seems to rely on some printing plugin that doesn't exist. - if (!m_extra_args->IsValid()) - return; - StructuredData::ObjectSP object_sp = m_extra_args->GetObjectSP(); - if (!object_sp || !object_sp->IsValid()) - return; - - StructuredData::Dictionary *as_dict = object_sp->GetAsDictionary(); - if (!as_dict || !as_dict->IsValid()) - return; - - uint32_t num_keys = as_dict->GetSize(); - if (num_keys == 0) - return; - - s->Indent("Args:\n"); - s->SetIndentLevel(s->GetIndentLevel() + 4); - - auto print_one_element = [&s](ConstString key, - StructuredData::Object *object) { - s->Indent(); - s->Printf("%s : %s\n", key.GetCString(), - object->GetStringValue().str().c_str()); - return true; - }; - - as_dict->ForEach(print_one_element); - - s->SetIndentLevel(s->GetIndentLevel() - 4); + s->SetIndentLevel(indent_level); } static constexpr OptionEnumValueElement g_dynamic_value_types[] = { diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py b/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py deleted file mode 100644 index b3b65b82965f..000000000000 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -Test stop hook functionality -""" - - - -import lldb -import lldbsuite.test.lldbutil as lldbutil -from lldbsuite.test.lldbtest import * - - -class TestStopHooks(TestBase): - - mydir = TestBase.compute_mydir(__file__) - - # If your test case doesn't stress debug info, the - # set this to true. That way it won't be run once for - # each debug info format. - NO_DEBUG_INFO_TESTCASE = True - - def setUp(self): - TestBase.setUp(self) - self.build() - self.main_source_file = lldb.SBFileSpec("main.c") - full_path = os.path.join(self.getSourceDir(), "main.c") - self.main_start_line = line_number(full_path, "main()") - - def not_test_stop_hooks_scripted(self): - """Test that a scripted stop hook works with no specifiers""" - self.stop_hooks_scripted(5) - - def not_test_stop_hooks_scripted_right_func(self): - """Test that a scripted stop hook fires when there is a function match""" - self.stop_hooks_scripted(5, "-n step_out_of_me") - - def not_test_stop_hooks_scripted_wrong_func(self): - """Test that a scripted stop hook doesn't fire when the function does not match""" - self.stop_hooks_scripted(0, "-n main") - - def not_test_stop_hooks_scripted_right_lines(self): - """Test that a scripted stop hook fires when there is a function match""" - self.stop_hooks_scripted(5, "-f main.c -l 1 -e %d"%(self.main_start_line)) - - def not_test_stop_hooks_scripted_wrong_lines(self): - """Test that a scripted stop hook doesn't fire when the function does not match""" - self.stop_hooks_scripted(0, "-f main.c -l %d -e 100"%(self.main_start_line)) - - def not_test_stop_hooks_scripted_auto_continue(self): - """Test that the --auto-continue flag works""" - self.do_test_auto_continue(False) - - def test_stop_hooks_scripted_return_false(self): - """Test that the returning False from a stop hook works""" - self.do_test_auto_continue(True) - - def do_test_auto_continue(self, return_true): - """Test that auto-continue works.""" - # We set auto-continue to 1 but the stop hook only applies to step_out_of_me, - # so we should end up stopped in main, having run the expression only once. - self.script_setup() - - result = lldb.SBCommandReturnObject() - - if return_true: - command = "target stop-hook add -P stop_hook.stop_handler -k increment -v 5 -k return_false -v 1 -n step_out_of_me" - else: - command = "target stop-hook add -G 1 -P stop_hook.stop_handler -k increment -v 5 -n step_out_of_me" - - print("Running command: %s"%(command)) - - self.interp.HandleCommand(command, result) - self.assertTrue(result.Succeeded, "Set the target stop hook") - - # First run to main. If we go straight to the first stop hook hit, - # run_to_source_breakpoint will fail because we aren't at original breakpoint - - (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, - "Stop here first", self.main_source_file) - - # Now set the breakpoint on step_out_of_me, and make sure we run the - # expression, then continue back to main. - bkpt = target.BreakpointCreateBySourceRegex("Set a breakpoint here and step out", self.main_source_file) - self.assertTrue(bkpt.GetNumLocations() > 0, "Got breakpoints in step_out_of_me") - process.Continue() - - var = target.FindFirstGlobalVariable("g_var") - self.assertTrue(var.IsValid()) - self.assertEqual(var.GetValueAsUnsigned(), 5, "Updated g_var") - - func_name = process.GetSelectedThread().frames[0].GetFunctionName() - self.assertEqual("main", func_name, "Didn't stop at the expected function.") - - def script_setup(self): - self.interp = self.dbg.GetCommandInterpreter() - result = lldb.SBCommandReturnObject() - - # Bring in our script file: - script_name = os.path.join(self.getSourceDir(), "stop_hook.py") - command = "command script import " + script_name - self.interp.HandleCommand(command, result) - self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError())) - - # set a breakpoint at the end of main to catch our auto-continue tests. - # Do it in the dummy target so it will get copied to our target even when - # we don't have a chance to stop. - dummy_target = self.dbg.GetDummyTarget() - dummy_target.BreakpointCreateBySourceRegex("return result", self.main_source_file) - - - def stop_hooks_scripted(self, g_var_value, specifier = None): - self.script_setup() - - result = lldb.SBCommandReturnObject() - - command = "target stop-hook add -P stop_hook.stop_handler -k increment -v 5 " - if specifier: - command += specifier - print("Running command: %s"%(command)) - - self.interp.HandleCommand(command, result) - self.assertTrue(result.Succeeded, "Set the target stop hook") - (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, - "Set a breakpoint here", self.main_source_file) - # At this point we've hit our stop hook so we should have run our expression, - # which increments g_var by the amount specified by the increment key's value. - while process.GetState() == lldb.eStateRunning: - continue - - var = target.FindFirstGlobalVariable("g_var") - self.assertTrue(var.IsValid()) - self.assertEqual(var.GetValueAsUnsigned(), g_var_value, "Updated g_var") diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py index 43447a845156..64686afe627d 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py @@ -1,5 +1,5 @@ """ -Test stop hook functionality +Test that stop hooks trigger on "step-out" """ @@ -18,15 +18,10 @@ class TestStopHooks(TestBase): # each debug info format. NO_DEBUG_INFO_TESTCASE = True - def setUp(self): - TestBase.setUp(self) - self.build() - self.main_source_file = lldb.SBFileSpec("main.c") - full_path = os.path.join(self.getSourceDir(), "main.c") - self.main_start_line = line_number(full_path, "main()") - def test_stop_hooks_step_out(self): """Test that stop hooks fire on step-out.""" + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") self.step_out_test() def step_out_test(self): @@ -42,3 +37,4 @@ def step_out_test(self): self.assertTrue(var.IsValid()) self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var") + diff --git a/lldb/test/API/commands/target/stop-hooks/main.c b/lldb/test/API/commands/target/stop-hooks/main.c index 16bfc0ce5db6..d08ad14776b5 100644 --- a/lldb/test/API/commands/target/stop-hooks/main.c +++ b/lldb/test/API/commands/target/stop-hooks/main.c @@ -10,6 +10,5 @@ int step_out_of_me() int main() { - int result = step_out_of_me(); // Stop here first - return result; + return step_out_of_me(); } diff --git a/lldb/test/API/commands/target/stop-hooks/stop_hook.py b/lldb/test/API/commands/target/stop-hooks/stop_hook.py deleted file mode 100644 index 412c81acf737..000000000000 --- a/lldb/test/API/commands/target/stop-hooks/stop_hook.py +++ /dev/null @@ -1,34 +0,0 @@ -import lldb - -class stop_handler: - def __init__(self, target, extra_args, dict): - self.extra_args = extra_args - self.target = target - self.counter = 0 - ret_val = self.extra_args.GetValueForKey("return_false") - if ret_val: - self.ret_val = False - else: - self.ret_val = True - - def handle_stop(self, exe_ctx, stream): - self.counter += 1 - stream.Print("I have stopped %d times.\n"%(self.counter)) - increment = 1 - value = self.extra_args.GetValueForKey("increment") - if value: - incr_as_str = value.GetStringValue(100) - increment = int(incr_as_str) - else: - stream.Print("Could not find increment in extra_args\n") - frame = exe_ctx.GetFrame() - expression = "g_var += %d"%(increment) - expr_result = frame.EvaluateExpression(expression) - if not expr_result.GetError().Success(): - stream.Print("Error running expression: %s"%(expr_result.GetError().GetCString())) - value = exe_ctx.target.FindFirstGlobalVariable("g_var") - if not value.IsValid(): - stream.Print("Didn't get a valid value for g_var.") - else: - int_val = value.GetValueAsUnsigned() - return self.ret_val diff --git a/lldb/test/Shell/Commands/Inputs/stop_hook.py b/lldb/test/Shell/Commands/Inputs/stop_hook.py deleted file mode 100644 index e319ca9ec5bc..000000000000 --- a/lldb/test/Shell/Commands/Inputs/stop_hook.py +++ /dev/null @@ -1,10 +0,0 @@ -import lldb - -class stop_handler: - def __init__(self, target, extra_args, dict): - self.extra_args = extra_args - self.target = target - - def handle_stop(self, exe_ctx, stream): - stream.Print("I did indeed run\n") - return True diff --git a/lldb/test/Shell/Commands/command-stop-hook-output.test b/lldb/test/Shell/Commands/command-stop-hook-output.test deleted file mode 100644 index e7270c8f6631..000000000000 --- a/lldb/test/Shell/Commands/command-stop-hook-output.test +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: %clang_host -g %S/Inputs/main.c -o %t -# RUN: %lldb %t -O 'command script import %S/Inputs/stop_hook.py' -s %s -o exit | FileCheck %s - -b main -# CHECK-LABEL: b main -# CHECK: Breakpoint 1: where = {{.*}}`main - -target stop-hook add -P stop_hook.stop_handler -# CHECK-LABEL: target stop-hook add -P stop_hook.stop_handler -# CHECK: Stop hook #1 added. - -run -# CHECK-LABEL: run -# CHECK: I did indeed run -# CHECK: Process {{.*}} stopped -# CHECK: stop reason = breakpoint 1 -# CHECK: frame #0: {{.*}}`main at main.c - diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp index 58ddf0c40a26..f661835d191b 100644 --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -254,17 +254,3 @@ LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting, const lldb::TargetSP &target_sp) { return nullptr; } - -extern "C" void *LLDBSwigPythonCreateScriptedStopHook( - lldb::TargetSP target_sp, const char *python_class_name, - const char *session_dictionary_name, - lldb_private::StructuredDataImpl *args_impl, Status &error) { - return nullptr; -} - -extern "C" bool -LLDBSwigPythonStopHookCallHandleStop(void *implementor, - lldb::ExecutionContextRefSP exc_ctx_sp, - lldb::StreamSP stream) { - return false; -} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits