Author: Med Ismail Bennani Date: 2024-09-20T16:55:47-07:00 New Revision: f732157a9d067e4d300905c831a964222e0eadee
URL: https://github.com/llvm/llvm-project/commit/f732157a9d067e4d300905c831a964222e0eadee DIFF: https://github.com/llvm/llvm-project/commit/f732157a9d067e4d300905c831a964222e0eadee.diff LOG: [lldb/Interpreter] Introduce ScriptedStopHook{,Python}Interface & make use of it (#109498) This patch re-lands #105449 and fixes the various test failures. --------- Signed-off-by: Med Ismail Bennani <ism...@bennani.ma> Added: lldb/include/lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.cpp lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.h Modified: lldb/bindings/python/python-swigsafecast.swig lldb/bindings/python/python-wrapper.swig lldb/include/lldb/API/SBExecutionContext.h lldb/include/lldb/Interpreter/ScriptInterpreter.h lldb/include/lldb/Target/Target.h lldb/include/lldb/lldb-forward.h lldb/source/Interpreter/ScriptInterpreter.cpp lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h lldb/source/Target/Target.cpp lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp Removed: ################################################################################ diff --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig index 0127ac6bfa4681..7a4f7e81f1cc3b 100644 --- a/lldb/bindings/python/python-swigsafecast.swig +++ b/lldb/bindings/python/python-swigsafecast.swig @@ -33,7 +33,7 @@ PythonObject SWIGBridge::ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp) { SWIGTYPE_p_lldb__SBBreakpoint); } -PythonObject SWIGBridge::ToSWIGWrapper(Status status) { +PythonObject SWIGBridge::ToSWIGWrapper(Status&& status) { return ToSWIGHelper(new lldb::SBError(std::move(status)), SWIGTYPE_p_lldb__SBError); } diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig index 810673aaec5d19..961fb2d1a76178 100644 --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -301,104 +301,6 @@ unsigned int lldb_private::python::SWIGBridge::LLDBSwigPythonCallBreakpointResol return ret_val; } -PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedStopHook( - lldb::TargetSP target_sp, const char *python_class_name, - const char *session_dictionary_name, const StructuredDataImpl &args_impl, - Status &error) { - if (python_class_name == NULL || python_class_name[0] == '\0') { - error = Status::FromErrorString("Empty class name."); - return PythonObject(); - } - if (!session_dictionary_name) { - error = Status::FromErrorString("No session dictionary"); - return PythonObject(); - } - - 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 = Status::FromErrorStringWithFormat("Could not find class: %s.", - python_class_name); - return PythonObject(); - } - - PythonObject result = - pfunc(SWIGBridge::ToSWIGWrapper(target_sp), SWIGBridge::ToSWIGWrapper(args_impl), 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()) { - size_t num_args = (*args_info).max_positional_args; - if (num_args != 2) { - error = Status::FromErrorStringWithFormat( - "Wrong number of args for " - "handle_stop callback, should be 2 (excluding self), got: %zu", - num_args); - return PythonObject(); - } else - return result; - } else { - error = Status::FromErrorString( - "Couldn't get num arguments for handle_stop " - "callback."); - return PythonObject(); - } - return result; - } else { - error = Status::FromErrorStringWithFormat( - "Class \"%s\" is missing the required " - "handle_stop callback.", - python_class_name); - } - } - return PythonObject(); -} - -bool lldb_private::python::SWIGBridge::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; - - std::shared_ptr<lldb::SBStream> sb_stream = std::make_shared<lldb::SBStream>(); - PythonObject sb_stream_arg = SWIGBridge::ToSWIGWrapper(sb_stream); - PythonObject result = - pfunc(SWIGBridge::ToSWIGWrapper(std::move(exc_ctx_sp)), 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()); - sb_stream_arg.release(); - - 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( @@ -677,6 +579,19 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyOb return sb_ptr; } +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject * + data) { + lldb::SBExecutionContext *sb_ptr = NULL; + + int valid_cast = SWIG_ConvertPtr(data, (void **)&sb_ptr, + SWIGTYPE_p_lldb__SBExecutionContext, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommand( const char *python_function_name, const char *session_dictionary_name, lldb::DebuggerSP debugger, const char *args, diff --git a/lldb/include/lldb/API/SBExecutionContext.h b/lldb/include/lldb/API/SBExecutionContext.h index e8de2ebe58785e..e1e08fe3f4aae4 100644 --- a/lldb/include/lldb/API/SBExecutionContext.h +++ b/lldb/include/lldb/API/SBExecutionContext.h @@ -16,6 +16,7 @@ #include <vector> namespace lldb_private { +class ScriptInterpreter; namespace python { class SWIGBridge; } @@ -55,6 +56,7 @@ class LLDB_API SBExecutionContext { protected: friend class lldb_private::python::SWIGBridge; + friend class lldb_private::ScriptInterpreter; lldb_private::ExecutionContextRef *get() const; diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h new file mode 100644 index 00000000000000..a829e62351fe85 --- /dev/null +++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h @@ -0,0 +1,33 @@ +//===-- ScriptedStopHookInterface.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H +#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H + +#include "lldb/lldb-private.h" + +#include "ScriptedInterface.h" + +namespace lldb_private { +class ScriptedStopHookInterface : public ScriptedInterface { +public: + virtual llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, lldb::TargetSP target_sp, + const StructuredDataImpl &args_sp) = 0; + + /// "handle_stop" will return a bool with the meaning "should_stop"... + /// If nothing is returned, we'll assume we are going to stop. + /// Also any errors should return true, since we should stop on error. + virtual llvm::Expected<bool> HandleStop(ExecutionContext &exe_ctx, + lldb::StreamSP &output_sp) { + return true; + } +}; +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index addb1394ab5652..901ecf3012d51d 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -14,6 +14,7 @@ #include "lldb/API/SBData.h" #include "lldb/API/SBError.h" #include "lldb/API/SBEvent.h" +#include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBMemoryRegionInfo.h" #include "lldb/API/SBStream.h" @@ -271,24 +272,6 @@ class ScriptInterpreter : public PluginInterface { return lldb::eSearchDepthModule; } - virtual StructuredData::GenericSP - CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, - const StructuredDataImpl &args_data, Status &error) { - error = - Status::FromErrorString("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(); @@ -561,6 +544,10 @@ class ScriptInterpreter : public PluginInterface { return {}; } + virtual lldb::ScriptedStopHookInterfaceSP CreateScriptedStopHookInterface() { + return {}; + } + virtual StructuredData::ObjectSP CreateStructuredDataFromScriptObject(ScriptObject obj) { return {}; @@ -587,6 +574,9 @@ class ScriptInterpreter : public PluginInterface { std::optional<MemoryRegionInfo> GetOpaqueTypeFromSBMemoryRegionInfo( const lldb::SBMemoryRegionInfo &mem_region) const; + lldb::ExecutionContextRefSP GetOpaqueTypeFromSBExecutionContext( + const lldb::SBExecutionContext &exe_ctx) const; + protected: Debugger &m_debugger; lldb::ScriptLanguage m_script_lang; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 50df01aac74004..e4848f19e64d62 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1391,8 +1391,7 @@ class Target : public std::enable_shared_from_this<Target>, /// This holds the dictionary of keys & values that can be used to /// parametrize any given callback's behavior. StructuredDataImpl m_extra_args; - /// This holds the python callback object. - StructuredData::GenericSP m_implementation_sp; + lldb::ScriptedStopHookInterfaceSP m_interface_sp; /// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer /// and fill it with commands, and SetSpecifier to set the specifier shared diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 5fb288ad43af48..d09edeeccaff1a 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -190,6 +190,7 @@ class ScriptInterpreterLocker; class ScriptedMetadata; class ScriptedPlatformInterface; class ScriptedProcessInterface; +class ScriptedStopHookInterface; class ScriptedThreadInterface; class ScriptedThreadPlanInterface; class ScriptedSyntheticChildren; @@ -408,6 +409,8 @@ typedef std::unique_ptr<lldb_private::ScriptedPlatformInterface> ScriptedPlatformInterfaceUP; typedef std::unique_ptr<lldb_private::ScriptedProcessInterface> ScriptedProcessInterfaceUP; +typedef std::shared_ptr<lldb_private::ScriptedStopHookInterface> + ScriptedStopHookInterfaceSP; typedef std::shared_ptr<lldb_private::ScriptedThreadInterface> ScriptedThreadInterfaceSP; typedef std::shared_ptr<lldb_private::ScriptedThreadPlanInterface> diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index 8b55221da6e761..559b8301c10106 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -125,6 +125,12 @@ ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo( return *mem_region.m_opaque_up.get(); } +lldb::ExecutionContextRefSP +ScriptInterpreter::GetOpaqueTypeFromSBExecutionContext( + const lldb::SBExecutionContext &exe_ctx) const { + return exe_ctx.m_exe_ctx_sp; +} + lldb::ScriptLanguage ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { if (language.equals_insensitive(LanguageToString(eScriptLanguageNone))) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt index 6ba714ed1c263e..ee5e48ad5cdc37 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt @@ -25,6 +25,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN ScriptedPlatformPythonInterface.cpp ScriptedProcessPythonInterface.cpp ScriptedPythonInterface.cpp + ScriptedStopHookPythonInterface.cpp ScriptedThreadPlanPythonInterface.cpp ScriptedThreadPythonInterface.cpp diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp index 38b644366080e4..1fd32993e385eb 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp @@ -28,6 +28,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() { OperatingSystemPythonInterface::Initialize(); ScriptedPlatformPythonInterface::Initialize(); ScriptedProcessPythonInterface::Initialize(); + ScriptedStopHookPythonInterface::Initialize(); ScriptedThreadPlanPythonInterface::Initialize(); } @@ -35,6 +36,7 @@ void ScriptInterpreterPythonInterfaces::Terminate() { OperatingSystemPythonInterface::Terminate(); ScriptedPlatformPythonInterface::Terminate(); ScriptedProcessPythonInterface::Terminate(); + ScriptedStopHookPythonInterface::Terminate(); ScriptedThreadPlanPythonInterface::Terminate(); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h index 36b521480cc85c..26c80b75686918 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h @@ -18,6 +18,7 @@ #include "OperatingSystemPythonInterface.h" #include "ScriptedPlatformPythonInterface.h" #include "ScriptedProcessPythonInterface.h" +#include "ScriptedStopHookPythonInterface.h" #include "ScriptedThreadPlanPythonInterface.h" namespace lldb_private { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp index a8e1d09da0bf12..cf11c06e8a95d4 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp @@ -159,4 +159,23 @@ ScriptedPythonInterface::ExtractValueFromPythonObject< return m_interpreter.GetOpaqueTypeFromSBMemoryRegionInfo(*sb_mem_reg_info); } +template <> +lldb::ExecutionContextRefSP +ScriptedPythonInterface::ExtractValueFromPythonObject< + lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error) { + + lldb::SBExecutionContext *sb_exe_ctx = + reinterpret_cast<lldb::SBExecutionContext *>( + python::LLDBSWIGPython_CastPyObjectToSBExecutionContext(p.get())); + + if (!sb_exe_ctx) { + error = Status::FromErrorStringWithFormat( + "Couldn't cast lldb::SBExecutionContext to " + "lldb::ExecutionContextRefSP."); + return {}; + } + + return m_interpreter.GetOpaqueTypeFromSBExecutionContext(*sb_exe_ctx); +} + #endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index c715295eb9ff02..4b9f463ef5605d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -180,12 +180,35 @@ class ScriptedPythonInterface : virtual public ScriptedInterface { llvm::Expected<PythonObject> expected_return_object = create_error("Resulting object is not initialized."); - std::apply( - [&init, &expected_return_object](auto &&...args) { - llvm::consumeError(expected_return_object.takeError()); - expected_return_object = init(args...); - }, - transformed_args); + // This relax the requirement on the number of argument for + // initializing scripting extension if the size of the interface + // parameter pack contains 1 less element than the extension maximum + // number of positional arguments for this initializer. + // + // This addresses the cases where the embedded interpreter session + // dictionary is passed to the extension initializer which is not used + // most of the time. + size_t num_args = sizeof...(Args); + if (num_args != arg_info->max_positional_args) { + if (num_args != arg_info->max_positional_args - 1) + return create_error("Passed arguments ({0}) doesn't match the number " + "of expected arguments ({1}).", + num_args, arg_info->max_positional_args); + + std::apply( + [&init, &expected_return_object](auto &&...args) { + llvm::consumeError(expected_return_object.takeError()); + expected_return_object = init(args...); + }, + std::tuple_cat(transformed_args, std::make_tuple(dict))); + } else { + std::apply( + [&init, &expected_return_object](auto &&...args) { + llvm::consumeError(expected_return_object.takeError()); + expected_return_object = init(args...); + }, + transformed_args); + } if (!expected_return_object) return expected_return_object.takeError(); @@ -405,6 +428,10 @@ class ScriptedPythonInterface : virtual public ScriptedInterface { return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(lldb::TargetSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::ProcessSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } @@ -557,6 +584,11 @@ std::optional<MemoryRegionInfo> ScriptedPythonInterface::ExtractValueFromPythonObject< std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); +template <> +lldb::ExecutionContextRefSP +ScriptedPythonInterface::ExtractValueFromPythonObject< + lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error); + } // namespace lldb_private #endif // LLDB_ENABLE_PYTHON diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.cpp new file mode 100644 index 00000000000000..eb052c24bab6da --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.cpp @@ -0,0 +1,75 @@ +//===-- ScriptedStopHookPythonInterface.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Config.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/Log.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// clang-format off +// LLDB Python header must be included first +#include "../lldb-python.h" +//clang-format on + +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" +#include "ScriptedStopHookPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; + +ScriptedStopHookPythonInterface::ScriptedStopHookPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedStopHookInterface(), ScriptedPythonInterface(interpreter) {} + +llvm::Expected<StructuredData::GenericSP> +ScriptedStopHookPythonInterface::CreatePluginObject(llvm::StringRef class_name, + lldb::TargetSP target_sp, + const StructuredDataImpl &args_sp) { + return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr, + target_sp, args_sp); +} + +llvm::Expected<bool> +ScriptedStopHookPythonInterface::HandleStop(ExecutionContext &exe_ctx, + lldb::StreamSP& output_sp) { + ExecutionContextRefSP exe_ctx_ref_sp = + std::make_shared<ExecutionContextRef>(exe_ctx); + Status error; + StructuredData::ObjectSP obj = Dispatch("handle_stop", error, exe_ctx_ref_sp, output_sp); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + if (!obj) + return true; + return error.ToError(); + } + + return obj->GetBooleanValue(); +} + + +void ScriptedStopHookPythonInterface::Initialize() { + const std::vector<llvm::StringRef> ci_usages = { + "target stop-hook add -P <script-name> [-k key -v value ...]"}; + const std::vector<llvm::StringRef> api_usages = {}; + PluginManager::RegisterPlugin( + GetPluginNameStatic(), + llvm::StringRef("Perform actions whenever the process stops, before control is returned to the user."), + CreateInstance, eScriptLanguagePython, {ci_usages, api_usages}); +} + +void ScriptedStopHookPythonInterface::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.h new file mode 100644 index 00000000000000..7f88098cb7fc70 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedStopHookPythonInterface.h @@ -0,0 +1,51 @@ +//===-- ScriptedStopHookPythonInterface.h -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTOPHOOKPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTOPHOOKPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" +#include "lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h" + +#if LLDB_ENABLE_PYTHON + +#include "ScriptedPythonInterface.h" + +namespace lldb_private { +class ScriptedStopHookPythonInterface : public ScriptedStopHookInterface, + public ScriptedPythonInterface, + public PluginInterface { +public: + ScriptedStopHookPythonInterface(ScriptInterpreterPythonImpl &interpreter); + + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, lldb::TargetSP target_sp, + const StructuredDataImpl &args_sp) override; + + llvm::SmallVector<AbstractMethodRequirement> + GetAbstractMethodRequirements() const override { + return llvm::SmallVector<AbstractMethodRequirement>({{"handle_stop", 2}}); + } + + llvm::Expected<bool> HandleStop(ExecutionContext &exe_ctx, + lldb::StreamSP &output_sp) override; + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { + return "ScriptedStopHookPythonInterface"; + } + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDSTOPHOOKPYTHONINTERFACE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 97a3837fd7aa62..81ee9ea0a2fa10 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -86,7 +86,7 @@ class SWIGBridge { static PythonObject ToSWIGWrapper(lldb::ProcessSP process_sp); static PythonObject ToSWIGWrapper(lldb::ThreadPlanSP thread_plan_sp); static PythonObject ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp); - static PythonObject ToSWIGWrapper(Status status); + static PythonObject ToSWIGWrapper(Status &&status); static PythonObject ToSWIGWrapper(const StructuredDataImpl &data_impl); static PythonObject ToSWIGWrapper(lldb::ThreadSP thread_sp); static PythonObject ToSWIGWrapper(lldb::StackFrameSP frame_sp); @@ -157,16 +157,6 @@ class SWIGBridge { const char *method_name, lldb_private::SymbolContext *sym_ctx); - static python::PythonObject LLDBSwigPythonCreateScriptedStopHook( - lldb::TargetSP target_sp, const char *python_class_name, - const char *session_dictionary_name, const StructuredDataImpl &args, - lldb_private::Status &error); - - static bool - LLDBSwigPythonStopHookCallHandleStop(void *implementor, - lldb::ExecutionContextRefSP exc_ctx, - lldb::StreamSP stream); - static size_t LLDBSwigPython_CalculateNumChildren(PyObject *implementor, uint32_t max); @@ -266,6 +256,7 @@ void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data); +void *LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *data); } // namespace python } // namespace lldb_private diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 63691d24f0dadb..155efc06eaf41a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1559,6 +1559,11 @@ ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() { return std::make_unique<ScriptedProcessPythonInterface>(*this); } +ScriptedStopHookInterfaceSP +ScriptInterpreterPythonImpl::CreateScriptedStopHookInterface() { + return std::make_shared<ScriptedStopHookPythonInterface>(*this); +} + ScriptedThreadInterfaceSP ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() { return std::make_shared<ScriptedThreadPythonInterface>(*this); @@ -1654,57 +1659,6 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( return lldb::eSearchDepthModule; } -StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedStopHook( - TargetSP target_sp, const char *class_name, - const StructuredDataImpl &args_data, Status &error) { - - if (!target_sp) { - error = Status::FromErrorString("No target for scripted stop-hook."); - return StructuredData::GenericSP(); - } - - if (class_name == nullptr || class_name[0] == '\0') { - error = Status::FromErrorString("No class name for scripted stop-hook."); - return StructuredData::GenericSP(); - } - - ScriptInterpreterPythonImpl *python_interpreter = - GetPythonInterpreter(m_debugger); - - if (!python_interpreter) { - error = Status::FromErrorString( - "No script interpreter for scripted stop-hook."); - return StructuredData::GenericSP(); - } - - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - - PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedStopHook( - target_sp, class_name, python_interpreter->m_dictionary_name.c_str(), - args_data, error); - - return StructuredData::GenericSP( - new StructuredPythonObject(std::move(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 = SWIGBridge::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 85d79955e45efc..d15e2fd76f683b 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -91,15 +91,6 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython { lldb::SearchDepth ScriptedBreakpointResolverSearchDepth( StructuredData::GenericSP implementor_sp) override; - StructuredData::GenericSP - CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, - const 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; @@ -112,6 +103,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython { lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override; + lldb::ScriptedStopHookInterfaceSP CreateScriptedStopHookInterface() override; + lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override; lldb::ScriptedThreadPlanInterfaceSP diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index f1659aae0800db..f9b6f7ded267ee 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -36,6 +36,7 @@ #include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h" #include "lldb/Interpreter/OptionGroupWatchpoint.h" #include "lldb/Interpreter/OptionValues.h" #include "lldb/Interpreter/Property.h" @@ -3868,13 +3869,32 @@ Status Target::StopHookScripted::SetScriptCallback( return error; } + m_interface_sp = script_interp->CreateScriptedStopHookInterface(); + if (!m_interface_sp) { + error = Status::FromErrorStringWithFormat( + "ScriptedStopHook::%s () - ERROR: %s", __FUNCTION__, + "Script interpreter couldn't create Scripted Stop Hook Interface"); + return error; + } + m_class_name = class_name; m_extra_args.SetObjectSP(extra_args_sp); - m_implementation_sp = script_interp->CreateScriptedStopHook( - GetTarget(), m_class_name.c_str(), m_extra_args, error); + auto obj_or_err = m_interface_sp->CreatePluginObject( + m_class_name, GetTarget(), m_extra_args); + if (!obj_or_err) { + return Status::FromError(obj_or_err.takeError()); + } - return error; + StructuredData::ObjectSP object_sp = *obj_or_err; + if (!object_sp || !object_sp->IsValid()) { + error = Status::FromErrorStringWithFormat( + "ScriptedStopHook::%s () - ERROR: %s", __FUNCTION__, + "Failed to create valid script object"); + return error; + } + + return {}; } Target::StopHook::StopHookResult @@ -3883,16 +3903,18 @@ Target::StopHookScripted::HandleStop(ExecutionContext &exc_ctx, assert(exc_ctx.GetTargetPtr() && "Can't call HandleStop on a context " "with no target"); - ScriptInterpreter *script_interp = - GetTarget()->GetDebugger().GetScriptInterpreter(); - if (!script_interp) + if (!m_interface_sp) return StopHookResult::KeepStopped; - bool should_stop = script_interp->ScriptedStopHookHandleStop( - m_implementation_sp, exc_ctx, output_sp); + lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>(); + auto should_stop_or_err = m_interface_sp->HandleStop(exc_ctx, stream); + output_sp->PutCString( + reinterpret_cast<StreamString *>(stream.get())->GetData()); + if (!should_stop_or_err) + return StopHookResult::KeepStopped; - return should_stop ? StopHookResult::KeepStopped - : StopHookResult::RequestContinue; + return *should_stop_or_err ? StopHookResult::KeepStopped + : StopHookResult::RequestContinue; } void Target::StopHookScripted::GetSubclassDescription( diff --git a/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py b/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py index b865fd0c0a44f3..7c10669442b1c2 100644 --- a/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py +++ b/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py @@ -32,7 +32,7 @@ def test_bad_handler(self): self.interp.HandleCommand(command, result) self.assertFalse(result.Succeeded(), "Set the target stop hook") self.assertIn( - "Wrong number of args", + "has unexpected argument count", result.GetError(), "Got the wrong number of args error", ) @@ -43,7 +43,7 @@ def test_bad_handler(self): self.interp.HandleCommand(command, result) self.assertFalse(result.Succeeded(), "Set the target stop hook") self.assertIn( - 'Class "stop_hook.no_handle_stop" is missing the required handle_stop callback', + "Abstract method no_handle_stop.handle_stop not implemented", result.GetError(), "Got the right error", ) diff --git a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py index cb07bf32c5080e..2721d961bcb9d5 100644 --- a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py +++ b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py @@ -8,7 +8,7 @@ class DummyStopHook: - def __init__(self, target, args, internal_dict): + def __init__(self, target, args): self.target = target self.args = args diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp index f2746c3e2516fd..c67a2b4bf46e64 100644 --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -154,6 +154,11 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo( return nullptr; } +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBExecutionContext( + PyObject *data) { + return nullptr; +} + lldb::ValueObjectSP lldb_private::python::SWIGBridge::LLDBSWIGPython_GetValueObjectSPFromSBValue( void *data) { @@ -269,21 +274,7 @@ void *lldb_private::python::SWIGBridge::LLDBSWIGPython_GetDynamicSetting( } python::PythonObject -lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedStopHook( - lldb::TargetSP target_sp, const char *python_class_name, - const char *session_dictionary_name, const StructuredDataImpl &args_impl, - Status &error) { - return python::PythonObject(); -} - -bool lldb_private::python::SWIGBridge::LLDBSwigPythonStopHookCallHandleStop( - void *implementor, lldb::ExecutionContextRefSP exc_ctx_sp, - lldb::StreamSP stream) { - return false; -} - -python::PythonObject -lldb_private::python::SWIGBridge::ToSWIGWrapper(Status status) { +lldb_private::python::SWIGBridge::ToSWIGWrapper(Status &&status) { return python::PythonObject(); } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits