[Lldb-commits] [lldb] ec456ba - [lldb] Add OperatingSystem base class to the lldb python module

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Thu Oct 26 15:12:34 PDT 2023


Author: Med Ismail Bennani
Date: 2023-10-26T15:12:22-07:00
New Revision: ec456ba9ca0a097da63daafbb031cb2024f5513a

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

LOG: [lldb] Add OperatingSystem base class to the lldb python module

This patch introduces an `OperatingSystem` base implementation in the
`lldb` python module to make it easier for lldb users to write their own
implementation.

The `OperatingSystem` base implementation is derived itself from the
`ScriptedThread` base implementation since they share some common grounds.

To achieve that, this patch makes changes to the `ScriptedThread`
initializer since it gets called by the `OperatingSystem` initializer.

I also took the opportunity to document the `OperatingSystem` base
class and methods.

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

Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>

Added: 
    lldb/examples/python/templates/operating_system.py

Modified: 
    lldb/bindings/python/CMakeLists.txt
    lldb/examples/python/templates/scripted_process.py
    lldb/test/API/functionalities/plugins/python_os_plugin/operating_system.py

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index c4806bda27049c6..c941f764dfc92ac 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -104,7 +104,8 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
     "plugins"
     FILES
     "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_process.py"
-    "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_platform.py")
+    "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_platform.py"
+    "${LLDB_SOURCE_DIR}/examples/python/templates/operating_system.py")
 
   if(APPLE)
     create_python_package(

diff  --git a/lldb/examples/python/templates/operating_system.py b/lldb/examples/python/templates/operating_system.py
new file mode 100644
index 000000000000000..a8053bcaa21afe7
--- /dev/null
+++ b/lldb/examples/python/templates/operating_system.py
@@ -0,0 +1,103 @@
+from abc import abstractmethod
+
+import lldb
+import struct
+
+from lldb.plugins.scripted_process import ScriptedThread
+
+
+class OperatingSystem(ScriptedThread):
+    """
+    Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class.
+
+    ```
+    thread_info = {
+        "tid": tid,
+        "name": "four",
+        "queue": "queue4",
+        "state": "stopped",
+        "stop_reason": "none",
+        "core" : 2
+    }
+    ```
+
+    - tid : thread ID (mandatory)
+    - name : thread name (optional key/value pair)
+    - queue : thread dispatch queue name (optional key/value pair)
+    - state : thread state (mandatory, set to 'stopped' for now)
+    - core : the index of the core (lldb) thread that this OS Thread should shadow
+    - stop_reason : thread stop reason. (mandatory, usually set to 'none')
+        Possible values include:
+        - 'breakpoint': thread is stopped at a breakpoint
+        - 'none': thread is stopped because the process is stopped
+        - 'trace': thread is stopped after single stepping
+        The usual value for this while threads are in memory is 'none'
+    - register_data_addr : the address of the register data in memory (optional key/value pair)
+        Specifying this key/value pair for a thread will avoid a call to get_register_data()
+        and can be used when your registers are in a thread context structure that is contiguous
+        in memory. Don't specify this if your register layout in memory doesn't match the layout
+        described by the dictionary returned from a call to the get_register_info() method.
+    """
+
+    def __init__(self, process):
+        """Initialization needs a valid lldb.SBProcess object. This plug-in
+        will get created after a live process is valid and has stopped for the
+        first time.
+
+        Args:
+            process (lldb.SBProcess): The process owning this thread.
+        """
+        self.registers = None
+        super().__init__(process, None)
+        self.registers = self.register_info
+        self.threads = []
+
+    def create_thread(self, tid, context):
+        """Lazily create an operating system thread using a thread information
+        dictionary and an optional operating system thread context address.
+        This method is called manually, using the SBAPI
+        `lldb.SBProcess.CreateOSPluginThread` affordance.
+
+        Args:
+            tid (int): Thread ID to get `thread_info` dictionary for.
+            context (int): Address of the operating system thread struct.
+
+        Returns:
+            Dict: The `thread_info` dictionary containing the various information
+            for lldb to create a Thread object and add it to the process thread list.
+        """
+        return None
+
+    @abstractmethod
+    def get_thread_info(self):
+        """Get the list of operating system threads. This method gets called
+        automatically every time the process stops and it needs to update its
+        thread list.
+
+        Returns:
+            List[thread_info]: A list of `os_thread` dictionaries
+                containing at least for each entry, the thread id, it's name,
+                queue, state, stop reason. It can also contain a
+                `register_data_addr`. The list can be empty.
+        """
+        pass
+
+    @abstractmethod
+    def get_register_data(self, tid):
+        """Get the operating system thread register context for given a thread
+        id. This method is called when unwinding the stack of one of the
+        operating system threads.
+
+        Args:
+            tid (int): Thread ID to get register context for.
+
+        Returns:
+            str: A byte representing all register's value.
+        """
+        pass
+
+    def get_register_context(self):
+        pass
+
+    def get_stop_reason(self):
+        pass

diff  --git a/lldb/examples/python/templates/scripted_process.py b/lldb/examples/python/templates/scripted_process.py
index d74ef02dec8591c..3ddcebd128eaa6e 100644
--- a/lldb/examples/python/templates/scripted_process.py
+++ b/lldb/examples/python/templates/scripted_process.py
@@ -244,16 +244,16 @@ class ScriptedThread(metaclass=ABCMeta):
     """
 
     @abstractmethod
-    def __init__(self, scripted_process, args):
+    def __init__(self, process, args):
         """Construct a scripted thread.
 
         Args:
-            process (ScriptedProcess): The scripted process owning this thread.
+            process (ScriptedProcess/lldb.SBProcess): The process owning this thread.
             args (lldb.SBStructuredData): A Dictionary holding arbitrary
                 key/value pairs used by the scripted thread.
         """
         self.target = None
-        self.scripted_process = None
+        self.originating_process = None
         self.process = None
         self.args = None
         self.idx = 0
@@ -268,9 +268,13 @@ def __init__(self, scripted_process, args):
         self.frames = []
         self.extended_info = []
 
-        if isinstance(scripted_process, ScriptedProcess):
-            self.target = scripted_process.target
-            self.scripted_process = scripted_process
+        if (
+            isinstance(process, ScriptedProcess)
+            or isinstance(process, lldb.SBProcess)
+            and process.IsValid()
+        ):
+            self.target = process.target
+            self.originating_process = process
             self.process = self.target.GetProcess()
             self.get_register_info()
 
@@ -354,14 +358,14 @@ def get_stackframes(self):
     def get_register_info(self):
         if self.register_info is None:
             self.register_info = dict()
-            if self.scripted_process.arch == "x86_64":
+            if self.originating_process.arch == "x86_64":
                 self.register_info["sets"] = ["General Purpose Registers"]
                 self.register_info["registers"] = INTEL64_GPR
-            elif "arm64" in self.scripted_process.arch:
+            elif "arm64" in self.originating_process.arch:
                 self.register_info["sets"] = ["General Purpose Registers"]
                 self.register_info["registers"] = ARM64_GPR
             else:
-                raise ValueError("Unknown architecture", self.scripted_process.arch)
+                raise ValueError("Unknown architecture", self.originating_process.arch)
         return self.register_info
 
     @abstractmethod
@@ -505,12 +509,12 @@ def get_stop_reason(self):
 
             # TODO: Passthrough stop reason from driving process
             if self.driving_thread.GetStopReason() != lldb.eStopReasonNone:
-                if "arm64" in self.scripted_process.arch:
+                if "arm64" in self.originating_process.arch:
                     stop_reason["type"] = lldb.eStopReasonException
                     stop_reason["data"][
                         "desc"
                     ] = self.driving_thread.GetStopDescription(100)
-                elif self.scripted_process.arch == "x86_64":
+                elif self.originating_process.arch == "x86_64":
                     stop_reason["type"] = lldb.eStopReasonSignal
                     stop_reason["data"]["signal"] = signal.SIGTRAP
                 else:

diff  --git a/lldb/test/API/functionalities/plugins/python_os_plugin/operating_system.py b/lldb/test/API/functionalities/plugins/python_os_plugin/operating_system.py
index 52c678fac2efedf..f4404d78492f98d 100644
--- a/lldb/test/API/functionalities/plugins/python_os_plugin/operating_system.py
+++ b/lldb/test/API/functionalities/plugins/python_os_plugin/operating_system.py
@@ -1,29 +1,14 @@
-#!/usr/bin/env python
-
 import lldb
 import struct
 
+from lldb.plugins.operating_system import OperatingSystem
+
 
-class OperatingSystemPlugIn(object):
+class OperatingSystemPlugIn(OperatingSystem):
     """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
 
     def __init__(self, process):
-        """Initialization needs a valid.SBProcess object.
-
-        This plug-in will get created after a live process is valid and has stopped for the
-        first time."""
-        self.process = None
-        self.registers = None
-        self.threads = None
-        if isinstance(process, lldb.SBProcess) and process.IsValid():
-            self.process = process
-            self.threads = None  # Will be an dictionary containing info for each thread
-
-    def get_target(self):
-        # NOTE: Don't use "lldb.target" when trying to get your target as the "lldb.target"
-        # tracks the current target in the LLDB command interpreter which isn't the
-        # correct thing to use for this plug-in.
-        return self.process.target
+        super().__init__(process)
 
     def create_thread(self, tid, context):
         if tid == 0x444444444:
@@ -40,23 +25,6 @@ def create_thread(self, tid, context):
 
     def get_thread_info(self):
         if not self.threads:
-            # The sample dictionary below shows the values that can be returned for a thread
-            # tid => thread ID (mandatory)
-            # name => thread name (optional key/value pair)
-            # queue => thread dispatch queue name (optional key/value pair)
-            # state => thred state (mandatory, set to 'stopped' for now)
-            # stop_reason => thread stop reason. (mandatory, usually set to 'none')
-            #  Possible values include:
-            #   'breakpoint' if the thread is stopped at a breakpoint
-            #   'none' thread is just stopped because the process is stopped
-            #   'trace' the thread just single stepped
-            #   The usual value for this while threads are in memory is 'none'
-            # register_data_addr => the address of the register data in memory (optional key/value pair)
-            #   Specifying this key/value pair for a thread will avoid a call to get_register_data()
-            #   and can be used when your registers are in a thread context structure that is contiguous
-            #   in memory. Don't specify this if your register layout in memory doesn't match the layout
-            # described by the dictionary returned from a call to the
-            # get_register_info() method.
             self.threads = [
                 {
                     "tid": 0x111111111,


        


More information about the lldb-commits mailing list