forked from OSchip/llvm-project
[lldb/bindings] Add Python ScriptedProcess base class to lldb module
In order to facilitate the writting of Scripted Processes, this patch introduces a `ScriptedProcess` python base class in the lldb module. The base class holds the python interface with all the - abstract - methods that need to be implemented by the inherited class but also some methods that can be overwritten. This patch also provides an example of a Scripted Process with the `MyScriptedProcess` class. rdar://65508855 Differential Revision: https://reviews.llvm.org/D95712 Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
This commit is contained in:
parent
182f0d1a34
commit
2cff3dec11
|
@ -104,6 +104,13 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
|
|||
FILES "${LLDB_SOURCE_DIR}/examples/python/in_call_stack.py"
|
||||
"${LLDB_SOURCE_DIR}/examples/python/symbolication.py")
|
||||
|
||||
create_python_package(
|
||||
${swig_target}
|
||||
${lldb_python_target_dir}
|
||||
"plugins"
|
||||
FILES
|
||||
"${LLDB_SOURCE_DIR}/examples/python/scripted_process/scripted_process.py")
|
||||
|
||||
if(APPLE)
|
||||
create_python_package(
|
||||
${swig_target}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import os
|
||||
|
||||
import lldb
|
||||
from lldb.plugins.scripted_process import ScriptedProcess
|
||||
|
||||
class MyScriptedProcess(ScriptedProcess):
|
||||
def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
|
||||
super().__init__(target, args)
|
||||
|
||||
def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
|
||||
return self.memory_regions[0]
|
||||
|
||||
def get_thread_with_id(self, tid: int):
|
||||
return {}
|
||||
|
||||
def get_registers_for_thread(self, tid: int):
|
||||
return {}
|
||||
|
||||
def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
|
||||
data = lldb.SBData().CreateDataFromCString(
|
||||
self.target.GetByteOrder(),
|
||||
self.target.GetCodeByteSize(),
|
||||
"Hello, world!")
|
||||
return data
|
||||
|
||||
def get_loaded_images(self):
|
||||
return self.loaded_images
|
||||
|
||||
def get_process_id(self) -> int:
|
||||
return 42
|
||||
|
||||
def is_alive(self) -> bool:
|
||||
return True
|
||||
|
||||
def __lldb_init_module(debugger, dict):
|
||||
if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ:
|
||||
debugger.HandleCommand(
|
||||
"process launch -C %s.%s" % (__name__,
|
||||
MyScriptedProcess.__name__))
|
||||
else:
|
||||
print("Name of the class that will manage the scripted process: '%s.%s'"
|
||||
% (__name__, MyScriptedProcess.__name__))
|
|
@ -0,0 +1,147 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
import six
|
||||
|
||||
import lldb
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class ScriptedProcess:
|
||||
|
||||
"""
|
||||
The base class for a scripted process.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, target, args):
|
||||
""" Construct a scripted process.
|
||||
|
||||
Args:
|
||||
target (lldb.SBTarget): The target launching the scripted process.
|
||||
args (lldb.SBStructuredData): A Dictionary holding arbitrary
|
||||
key/value pairs used by the scripted process.
|
||||
"""
|
||||
self.target = None
|
||||
self.args = None
|
||||
if isinstance(target, lldb.SBTarget) and target.IsValid():
|
||||
self.target = target
|
||||
if isinstance(args, lldb.SBStructuredData) and args.IsValid():
|
||||
self.args = args
|
||||
|
||||
@abstractmethod
|
||||
def get_memory_region_containing_address(addr):
|
||||
""" Get the memory region for the scripted process, containing a
|
||||
specific address.
|
||||
|
||||
Args:
|
||||
addr (int): Address to look for in the scripted process memory
|
||||
regions.
|
||||
|
||||
Returns:
|
||||
lldb.SBMemoryRegionInfo: The memory region containing the address.
|
||||
None if out of bounds.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_thread_with_id(tid):
|
||||
""" Get the scripted process thread with a specific ID.
|
||||
|
||||
Args:
|
||||
tid (int): Thread ID to look for in the scripted process.
|
||||
|
||||
Returns:
|
||||
Dict: The thread represented as a dictionary, withr the
|
||||
tid thread ID. None if tid doesn't match any of the scripted
|
||||
process threads.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_registers_for_thread(tid):
|
||||
""" Get the register context dictionary for a certain thread of
|
||||
the scripted process.
|
||||
|
||||
Args:
|
||||
tid (int): Thread ID for the thread's register context.
|
||||
|
||||
Returns:
|
||||
Dict: The register context represented as a dictionary, for the
|
||||
tid thread. None if tid doesn't match any of the scripted
|
||||
process threads.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def read_memory_at_address(addr, size):
|
||||
""" Get a memory buffer from the scripted process at a certain address,
|
||||
of a certain size.
|
||||
|
||||
Args:
|
||||
addr (int): Address from which we should start reading.
|
||||
size (int): Size of the memory to read.
|
||||
|
||||
Returns:
|
||||
lldb.SBData: An `lldb.SBData` buffer with the target byte size and
|
||||
byte order storing the memory read.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_loaded_images(self):
|
||||
""" Get the list of loaded images for the scripted process.
|
||||
|
||||
```
|
||||
class ScriptedProcessImage:
|
||||
def __init__(name, file_spec, uuid, load_address):
|
||||
self.name = name
|
||||
self.file_spec = file_spec
|
||||
self.uuid = uuid
|
||||
self.load_address = load_address
|
||||
```
|
||||
|
||||
Returns:
|
||||
List[ScriptedProcessImage]: A list of `ScriptedProcessImage`
|
||||
containing for each entry, the name of the library, a UUID,
|
||||
an `lldb.SBFileSpec` and a load address.
|
||||
None if the list is empty.
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_process_id(self):
|
||||
""" Get the scripted process identifier.
|
||||
|
||||
Returns:
|
||||
int: The scripted process identifier.
|
||||
"""
|
||||
return 0
|
||||
|
||||
|
||||
def launch(self):
|
||||
""" Simulate the scripted process launch.
|
||||
|
||||
Returns:
|
||||
lldb.SBError: An `lldb.SBError` with error code 0.
|
||||
"""
|
||||
return lldb.SBError()
|
||||
|
||||
def resume(self):
|
||||
""" Simulate the scripted process resume.
|
||||
|
||||
Returns:
|
||||
lldb.SBError: An `lldb.SBError` with error code 0.
|
||||
"""
|
||||
return lldb.SBError()
|
||||
|
||||
@abstractmethod
|
||||
def is_alive(self):
|
||||
""" Check if the scripted process is alive.
|
||||
|
||||
Returns:
|
||||
bool: True if scripted process is alive. False otherwise.
|
||||
"""
|
||||
pass
|
|
@ -0,0 +1,4 @@
|
|||
C_SOURCES := main.c
|
||||
|
||||
include Makefile.rules
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
"""
|
||||
Test python scripted process in lldb
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
from lldbsuite.test import lldbtest
|
||||
|
||||
|
||||
class PlatformProcessCrashInfoTestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
def setUp(self):
|
||||
TestBase.setUp(self)
|
||||
self.source = "main.c"
|
||||
|
||||
def tearDown(self):
|
||||
TestBase.tearDown(self)
|
||||
|
||||
def test_python_plugin_package(self):
|
||||
"""Test that the lldb python module has a `plugins.scripted_process`
|
||||
package."""
|
||||
self.expect('script import lldb.plugins',
|
||||
substrs=["ModuleNotFoundError"], matching=False)
|
||||
|
||||
self.expect('script dir(lldb.plugins)',
|
||||
substrs=["scripted_process"])
|
||||
|
||||
self.expect('script import lldb.plugins.scripted_process',
|
||||
substrs=["ModuleNotFoundError"], matching=False)
|
||||
|
||||
self.expect('script dir(lldb.plugins.scripted_process)',
|
||||
substrs=["ScriptedProcess"])
|
||||
|
||||
self.expect('script from lldb.plugins.scripted_process import ScriptedProcess',
|
||||
substrs=["ImportError"], matching=False)
|
||||
|
||||
self.expect('script dir(ScriptedProcess)',
|
||||
substrs=["launch"])
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
return 0; // break here
|
||||
}
|
Loading…
Reference in New Issue