[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