[Lldb-commits] [lldb] bb4ccc6 - [lldb] Add ScriptedPlatform python implementation

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Thu Jan 12 12:54:18 PST 2023


Author: Med Ismail Bennani
Date: 2023-01-12T12:49:05-08:00
New Revision: bb4ccc6688893d1bf38cfca76620d84f947b9de1

URL: https://github.com/llvm/llvm-project/commit/bb4ccc6688893d1bf38cfca76620d84f947b9de1
DIFF: https://github.com/llvm/llvm-project/commit/bb4ccc6688893d1bf38cfca76620d84f947b9de1.diff

LOG: [lldb] Add ScriptedPlatform python implementation

This patch introduces both the Scripted Platform python base
implementation and an example for it.

The base implementation is embedded in lldb python module under
`lldb.plugins.scripted_platform`.

This patch also refactor the various SWIG methods to create scripted
objects into a single method, that is now shared between the Scripted
Platform, Process and Thread. It also replaces the target argument by a
execution context object.

Differential Revision: https://reviews.llvm.org/D139250

Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>

Added: 
    lldb/examples/python/scripted_process/scripted_platform.py
    lldb/test/API/functionalities/scripted_platform/my_scripted_platform.py

Modified: 
    lldb/bindings/python/CMakeLists.txt
    lldb/bindings/python/python-wrapper.swig
    lldb/examples/python/scripted_process/crashlog_scripted_process.py
    lldb/examples/python/scripted_process/scripted_process.py
    lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
    lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
    lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py
    lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
    lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index afad367baa9fa..4f7941e6cff1d 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -109,6 +109,13 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
     FILES
     "${LLDB_SOURCE_DIR}/examples/python/scripted_process/scripted_process.py")
 
+  create_python_package(
+    ${swig_target}
+    ${lldb_python_target_dir}
+    "plugins"
+    FILES
+    "${LLDB_SOURCE_DIR}/examples/python/scripted_process/scripted_platform.py")
+
   if(APPLE)
     create_python_package(
       ${swig_target}

diff  --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index 91b26fff05a1c..9a08c3000b79a 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -229,9 +229,9 @@ PythonObject lldb_private::LLDBSwigPythonCreateCommandObject(
   return pfunc(ToSWIGWrapper(std::move(debugger_sp)), dict);
 }
 
-PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess(
+PythonObject lldb_private::LLDBSwigPythonCreateScriptedObject(
     const char *python_class_name, const char *session_dictionary_name,
-    const lldb::TargetSP &target_sp,
+    lldb::ExecutionContextRefSP exe_ctx_sp,
     const lldb_private::StructuredDataImpl &args_impl,
     std::string &error_string) {
   if (python_class_name == NULL || python_class_name[0] == '\0' ||
@@ -251,8 +251,6 @@ PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess(
     return PythonObject();
   }
 
-  PythonObject target_arg = ToSWIGWrapper(target_sp);
-
   llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo();
   if (!arg_info) {
     llvm::handleAllErrors(
@@ -266,7 +264,7 @@ PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess(
 
   PythonObject result = {};
   if (arg_info.get().max_positional_args == 2) {
-    result = pfunc(target_arg, ToSWIGWrapper(args_impl));
+      result = pfunc(ToSWIGWrapper(exe_ctx_sp), ToSWIGWrapper(args_impl));
   } else {
     error_string.assign("wrong number of arguments in __init__, should be 2 "
                         "(not including self)");
@@ -274,46 +272,6 @@ PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess(
   return result;
 }
 
-PythonObject lldb_private::LLDBSwigPythonCreateScriptedThread(
-    const char *python_class_name, const char *session_dictionary_name,
-    const lldb::ProcessSP &process_sp, const StructuredDataImpl &args_impl,
-    std::string &error_string) {
-  if (python_class_name == NULL || python_class_name[0] == '\0' ||
-      !session_dictionary_name)
-    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_string.append("could not find script class: ");
-    error_string.append(python_class_name);
-    return PythonObject();
-  }
-
-  llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo();
-  if (!arg_info) {
-    llvm::handleAllErrors(
-        arg_info.takeError(),
-        [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },
-        [&](const llvm::ErrorInfoBase &E) {
-          error_string.append(E.message());
-        });
-    return PythonObject();
-  }
-
-  if (arg_info.get().max_positional_args == 2)
-    return pfunc(ToSWIGWrapper(process_sp), ToSWIGWrapper(args_impl));
-
-  error_string.assign("wrong number of arguments in __init__, should be 2 "
-                      "(not including self)");
-  return PythonObject();
-}
-
 PythonObject lldb_private::LLDBSwigPythonCreateScriptedThreadPlan(
     const char *python_class_name, const char *session_dictionary_name,
     const lldb_private::StructuredDataImpl &args_impl,

diff  --git a/lldb/examples/python/scripted_process/crashlog_scripted_process.py b/lldb/examples/python/scripted_process/crashlog_scripted_process.py
index 71cfff2ac5b03..eddf96786d9e4 100644
--- a/lldb/examples/python/scripted_process/crashlog_scripted_process.py
+++ b/lldb/examples/python/scripted_process/crashlog_scripted_process.py
@@ -62,8 +62,8 @@ def load_images(self, images):
                                                                self.addr_mask,
                                                                self.target)
 
-    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
-        super().__init__(target, args)
+    def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
+        super().__init__(exe_ctx, args)
 
         if not self.target or not self.target.IsValid():
             # Return error

diff  --git a/lldb/examples/python/scripted_process/scripted_platform.py b/lldb/examples/python/scripted_process/scripted_platform.py
new file mode 100644
index 0000000000000..95b97911fc1a3
--- /dev/null
+++ b/lldb/examples/python/scripted_process/scripted_platform.py
@@ -0,0 +1,96 @@
+from abc import ABCMeta, abstractmethod
+
+import lldb
+
+class ScriptedPlatform(metaclass=ABCMeta):
+
+    """
+    The base class for a scripted platform.
+
+    Most of the base class methods are `@abstractmethod` that need to be
+    overwritten by the inheriting class.
+
+    DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE.
+                THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE.
+    """
+
+    processes = None
+
+    @abstractmethod
+    def __init__(self, exe_ctx, args):
+        """ Construct a scripted platform.
+
+        Args:
+            exe_ctx (lldb.SBExecutionContext): The execution context for the scripted platform
+            args (lldb.SBStructuredData): A Dictionary holding arbitrary
+                key/value pairs used by the scripted platform.
+        """
+        processes = []
+
+    @abstractmethod
+    def list_processes(self):
+        """ Get a list of processes that are running or that can be attached to on the platform.
+
+        processes = {
+            420: {
+                    name: a.out,
+                    arch: aarch64,
+                    pid: 420,
+                    parent_pid: 42 (optional),
+                    uid: 0 (optional),
+                    gid: 0 (optional),
+            },
+        }
+
+        Returns:
+            Dict: The processes represented as a dictionary, with at least the
+                process ID, name, architecture. Optionally, the user can also
+                provide the parent process ID and the user and group IDs.
+                The dictionary can be empty.
+        """
+        pass
+
+    def get_process_info(self, pid):
+        """ Get the dictionary describing the process.
+
+        Returns:
+            Dict: The dictionary of process info that matched process ID.
+            None if the process doesn't exists
+        """
+        pass
+
+    @abstractmethod
+    def attach_to_process(self, attach_info):
+        """ Attach to a process.
+
+        Args:
+            attach_info (lldb.SBAttachInfo): The information related to attach to a process.
+
+        Returns:
+            lldb.SBError: A status object notifying if the attach succeeded.
+        """
+        pass
+
+    @abstractmethod
+    def launch_process(self, launch_info):
+        """ Launch a process.
+
+        Args:
+            launch_info (lldb.SBLaunchInfo): The information related to the process launch.
+
+        Returns:
+            lldb.SBError: A status object notifying if the launch succeeded.
+        """
+        pass
+
+    @abstractmethod
+    def kill_process(self, pid):
+        """ Kill a process.
+
+        Args:
+            pid (int): Process ID for the process to be killed.
+
+        Returns:
+            lldb.SBError: A status object notifying if the shutdown succeeded.
+        """
+        pass

diff  --git a/lldb/examples/python/scripted_process/scripted_process.py b/lldb/examples/python/scripted_process/scripted_process.py
index cc886c6ff467e..a84e057edc5ec 100644
--- a/lldb/examples/python/scripted_process/scripted_process.py
+++ b/lldb/examples/python/scripted_process/scripted_process.py
@@ -20,17 +20,20 @@ class ScriptedProcess(metaclass=ABCMeta):
     metadata = None
 
     @abstractmethod
-    def __init__(self, target, args):
+    def __init__(self, exe_ctx, args):
         """ Construct a scripted process.
 
         Args:
-            target (lldb.SBTarget): The target launching the scripted process.
+            exe_ctx (lldb.SBExecutionContext): The execution context for the scripted process.
             args (lldb.SBStructuredData): A Dictionary holding arbitrary
                 key/value pairs used by the scripted process.
         """
+        target = None
         self.target = None
         self.args = None
         self.arch = None
+        if isinstance(exe_ctx, lldb.SBExecutionContext):
+            target = exe_ctx.target
         if isinstance(target, lldb.SBTarget) and target.IsValid():
             self.target = target
             triple = self.target.triple

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 35c96215d4a58..3dc2864f8d424 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -96,14 +96,10 @@ void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data);
 // Although these are scripting-language specific, their definition depends on
 // the public API.
 
-python::PythonObject LLDBSwigPythonCreateScriptedProcess(
+python::PythonObject LLDBSwigPythonCreateScriptedObject(
     const char *python_class_name, const char *session_dictionary_name,
-    const lldb::TargetSP &target_sp, const StructuredDataImpl &args_impl,
-    std::string &error_string);
-
-python::PythonObject LLDBSwigPythonCreateScriptedThread(
-    const char *python_class_name, const char *session_dictionary_name,
-    const lldb::ProcessSP &process_sp, const StructuredDataImpl &args_impl,
+    lldb::ExecutionContextRefSP exe_ctx_sp,
+    const lldb_private::StructuredDataImpl &args_impl,
     std::string &error_string);
 
 llvm::Expected<bool> LLDBSwigPythonBreakpointCallbackFunction(

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
index 5fd085df26a8e..6f087e8390ced 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -37,16 +37,18 @@ StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
   if (class_name.empty())
     return {};
 
-  TargetSP target_sp = exe_ctx.GetTargetSP();
   StructuredDataImpl args_impl(args_sp);
   std::string error_string;
 
   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
                  Locker::FreeLock);
 
-  PythonObject ret_val = LLDBSwigPythonCreateScriptedProcess(
-      class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
-      args_impl, error_string);
+  lldb::ExecutionContextRefSP exe_ctx_ref_sp =
+      std::make_shared<ExecutionContextRef>(exe_ctx);
+
+  PythonObject ret_val = LLDBSwigPythonCreateScriptedObject(
+      class_name.str().c_str(), m_interpreter.GetDictionaryName(),
+      exe_ctx_ref_sp, args_impl, error_string);
 
   m_object_instance_sp =
       StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val)));

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
index 21d2ed35250f2..1b31ed2e58817 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp
@@ -35,7 +35,6 @@ StructuredData::GenericSP ScriptedThreadPythonInterface::CreatePluginObject(
   if (class_name.empty() && !script_obj)
     return {};
 
-  ProcessSP process_sp = exe_ctx.GetProcessSP();
   StructuredDataImpl args_impl(args_sp);
   std::string error_string;
 
@@ -44,11 +43,13 @@ StructuredData::GenericSP ScriptedThreadPythonInterface::CreatePluginObject(
 
   PythonObject ret_val;
 
-  if (!script_obj)
-    ret_val = LLDBSwigPythonCreateScriptedThread(
-        class_name.str().c_str(), m_interpreter.GetDictionaryName(), process_sp,
-        args_impl, error_string);
-  else
+  if (!script_obj) {
+    lldb::ExecutionContextRefSP exe_ctx_ref_sp =
+        std::make_shared<ExecutionContextRef>(exe_ctx);
+    ret_val = LLDBSwigPythonCreateScriptedObject(
+        class_name.str().c_str(), m_interpreter.GetDictionaryName(),
+        exe_ctx_ref_sp, args_impl, error_string);
+  } else
     ret_val = PythonObject(PyRefType::Borrowed,
                            static_cast<PyObject *>(script_obj->GetValue()));
 

diff  --git a/lldb/test/API/functionalities/scripted_platform/my_scripted_platform.py b/lldb/test/API/functionalities/scripted_platform/my_scripted_platform.py
new file mode 100644
index 0000000000000..3849f47b01adb
--- /dev/null
+++ b/lldb/test/API/functionalities/scripted_platform/my_scripted_platform.py
@@ -0,0 +1,38 @@
+import os
+
+import lldb
+from lldb.plugins.scripted_platform import ScriptedPlatform
+
+class MyScriptedPlatform(ScriptedPlatform):
+
+    def __init__(self, exe_ctx, args):
+        self.processes = {}
+
+        proc = {}
+        proc['name'] = 'a.out'
+        proc['arch'] = 'arm64-apple-macosx'
+        proc['pid'] = 420
+        proc['parent'] = 42
+        proc['uid'] = 501
+        proc['gid'] = 20
+        self.processes[420] = proc
+
+    def list_processes(self):
+        return self.processes
+
+    def get_process_info(self, pid):
+        return self.processes[pid]
+
+    def launch_process(self, launch_info):
+        return lldb.SBError()
+
+    def kill_process(self, pid):
+        return lldb.SBError()
+
+def __lldb_init_module(debugger, dict):
+    if not 'SKIP_SCRIPTED_PLATFORM_SELECT' in os.environ:
+        debugger.HandleCommand(
+            "platform select scripted-platform -C %s.%s" % (__name__, MyScriptedPlatform.__name__))
+    else:
+        print("Name of the class that will manage the scripted platform: '%s.%s'"
+                % (__name__, MyScriptedPlatform.__name__))

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 d4f7953907346..83df1ad8cbbb3 100644
--- a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
+++ b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
@@ -7,8 +7,8 @@
 from lldb.plugins.scripted_process import ScriptedThread
 
 class DummyScriptedProcess(ScriptedProcess):
-    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
-        super().__init__(target, args)
+    def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
+        super().__init__(exe_ctx, args)
         self.threads[0] = DummyScriptedThread(self, None)
 
     def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:

diff  --git a/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py b/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py
index 62db547a1baf6..5852df9625d98 100644
--- a/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py
+++ b/lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py
@@ -7,8 +7,8 @@
 from lldb.plugins.scripted_process import ScriptedThread
 
 class InvalidScriptedProcess(ScriptedProcess):
-    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
-        super().__init__(target, args)
+    def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
+        super().__init__(exe_ctx, args)
         self.threads[0] = InvalidScriptedThread(self, None)
 
     def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:

diff  --git a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
index 67a1256c8eef9..44a2a37fcc3f1 100644
--- a/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
+++ b/lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py
@@ -13,8 +13,8 @@ def get_module_with_name(self, target, name):
                 return module
         return None
 
-    def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
-        super().__init__(target, args)
+    def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
+        super().__init__(exe_ctx, args)
 
         self.corefile_target = None
         self.corefile_process = None
@@ -25,7 +25,7 @@ def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
                 idx = self.backing_target_idx.GetIntegerValue(42)
             if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString:
                 idx = int(self.backing_target_idx.GetStringValue(100))
-            self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx)
+            self.corefile_target = self.target.GetDebugger().GetTargetAtIndex(idx)
             self.corefile_process = self.corefile_target.GetProcess()
             for corefile_thread in self.corefile_process:
                 structured_data = lldb.SBStructuredData()

diff  --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index 4d2f27e0b0d76..75391e2ce4777 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -200,16 +200,9 @@ lldb_private::LLDBSWIGPythonCreateOSPlugin(const char *python_class_name,
   return python::PythonObject();
 }
 
-python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess(
+python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedObject(
     const char *python_class_name, const char *session_dictionary_name,
-    const lldb::TargetSP &target_sp, const StructuredDataImpl &args_impl,
-    std::string &error_string) {
-  return python::PythonObject();
-}
-
-python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedThread(
-    const char *python_class_name, const char *session_dictionary_name,
-    const lldb::ProcessSP &process_sp, const StructuredDataImpl &args_impl,
+    lldb::ExecutionContextRefSP exe_ctx_sp, const StructuredDataImpl &args_impl,
     std::string &error_string) {
   return python::PythonObject();
 }


        


More information about the lldb-commits mailing list