[Lldb-commits] [lldb] f732157 - [lldb/Interpreter] Introduce ScriptedStopHook{, Python}Interface & make use of it (#109498)

via lldb-commits lldb-commits at lists.llvm.org
Fri Sep 20 16:55:51 PDT 2024


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 <ismail at 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();
 }
 


        


More information about the lldb-commits mailing list