Files
clang-p2996/lldb/examples/python/scripted_process/scripted_process.py
Jonas Devlieghere 2238dcc393 [NFC][Py Reformat] Reformat python files in lldb
This is an ongoing series of commits that are reformatting our Python
code. Reformatting is done with `black` (23.1.0).

If you end up having problems merging this commit because you have made
changes to a python file, the best way to handle that is to run `git
checkout --ours <yourfile>` and then reformat it with black.

RFC: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style

Differential revision: https://reviews.llvm.org/D151460
2023-05-25 12:54:09 -07:00

976 lines
23 KiB
Python

from abc import ABCMeta, abstractmethod
import lldb
class ScriptedProcess(metaclass=ABCMeta):
"""
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.
"""
capabilities = None
memory_regions = None
loaded_images = None
threads = None
metadata = None
@abstractmethod
def __init__(self, exe_ctx, args):
"""Construct a scripted process.
Args:
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
if triple:
self.arch = triple.split("-")[0]
self.dbg = target.GetDebugger()
if isinstance(args, lldb.SBStructuredData) and args.IsValid():
self.args = args
self.threads = {}
self.loaded_images = []
self.metadata = {}
self.capabilities = {}
self.pid = 42
def get_capabilities(self):
"""Get a dictionary containing the process capabilities.
Returns:
Dict[str:bool]: The dictionary of capability, with the capability
name as the key and a boolean flag as the value.
The dictionary can be empty.
"""
return self.capabilities
def get_memory_region_containing_address(self, 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.
"""
return None
def get_threads_info(self):
"""Get the dictionary describing the process' Scripted Threads.
Returns:
Dict: The dictionary of threads, with the thread ID as the key and
a Scripted Thread instance as the value.
The dictionary can be empty.
"""
return self.threads
@abstractmethod
def read_memory_at_address(self, addr, size, error):
"""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.
error (lldb.SBError): Error object.
Returns:
lldb.SBData: An `lldb.SBData` buffer with the target byte size and
byte order storing the memory read.
"""
pass
def write_memory_at_address(self, addr, data, error):
"""Write a buffer to the scripted process memory.
Args:
addr (int): Address from which we should start reading.
data (lldb.SBData): An `lldb.SBData` buffer to write to the
process memory.
error (lldb.SBError): Error object.
Returns:
size (int): Size of the memory to read.
"""
error.SetErrorString(
"%s doesn't support memory writes." % self.__class__.__name__
)
return 0
def get_loaded_images(self):
"""Get the list of loaded images for the scripted process.
```
scripted_image = {
uuid = "c6ea2b64-f77c-3d27-9528-74f507b9078b",
path = "/usr/lib/dyld"
load_addr = 0xbadc0ffee
}
```
Returns:
List[scripted_image]: A list of `scripted_image` dictionaries
containing for each entry the library UUID or its file path
and its load address.
None if the list is empty.
"""
return self.loaded_images
def get_process_id(self):
"""Get the scripted process identifier.
Returns:
int: The scripted process identifier.
"""
return self.pid
def launch(self):
"""Simulate the scripted process launch.
Returns:
lldb.SBError: An `lldb.SBError` with error code 0.
"""
return lldb.SBError()
def attach(self, attach_info):
"""Simulate the scripted process attach.
Args:
attach_info (lldb.SBAttachInfo): The information related to the
process we're attaching to.
Returns:
lldb.SBError: An `lldb.SBError` with error code 0.
"""
return lldb.SBError()
def resume(self, should_stop=True):
"""Simulate the scripted process resume.
Args:
should_stop (bool): If True, resume will also force the process
state to stopped after running it.
Returns:
lldb.SBError: An `lldb.SBError` with error code 0.
"""
process = self.target.GetProcess()
if not process:
error = lldb.SBError()
error.SetErrorString("Invalid process.")
return error
process.ForceScriptedState(lldb.eStateRunning)
if should_stop:
process.ForceScriptedState(lldb.eStateStopped)
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
@abstractmethod
def get_scripted_thread_plugin(self):
"""Get scripted thread plugin name.
Returns:
str: Name of the scripted thread plugin.
"""
return None
def get_process_metadata(self):
"""Get some metadata for the scripted process.
Returns:
Dict: A dictionary containing metadata for the scripted process.
None if the process as no metadata.
"""
return self.metadata
def create_breakpoint(self, addr, error):
"""Create a breakpoint in the scripted process from an address.
This is mainly used with interactive scripted process debugging.
Args:
addr (int): Address at which the breakpoint should be set.
error (lldb.SBError): Error object.
Returns:
SBBreakpoint: A valid breakpoint object that was created a the specified
address. None if the breakpoint creation failed.
"""
error.SetErrorString(
"%s doesn't support creating breakpoints." % self.__class__.__name__
)
return False
class ScriptedThread(metaclass=ABCMeta):
"""
The base class for a scripted thread.
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, scripted_process, args):
"""Construct a scripted thread.
Args:
process (ScriptedProcess): The scripted 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.process = None
self.args = None
self.idx = 0
self.tid = 0
self.idx = None
self.name = None
self.queue = None
self.state = None
self.stop_reason = None
self.register_info = None
self.register_ctx = {}
self.frames = []
self.extended_info = []
if isinstance(scripted_process, ScriptedProcess):
self.target = scripted_process.target
self.scripted_process = scripted_process
self.process = self.target.GetProcess()
self.get_register_info()
def get_thread_idx(self):
"""Get the scripted thread index.
Returns:
int: The index of the scripted thread in the scripted process.
"""
return self.idx
def get_thread_id(self):
"""Get the scripted thread identifier.
Returns:
int: The identifier of the scripted thread.
"""
return self.tid
def get_name(self):
"""Get the scripted thread name.
Returns:
str: The name of the scripted thread.
"""
return self.name
def get_state(self):
"""Get the scripted thread state type.
eStateStopped, ///< Process or thread is stopped and can be examined.
eStateRunning, ///< Process or thread is running and can't be examined.
eStateStepping, ///< Process or thread is in the process of stepping and can
/// not be examined.
eStateCrashed, ///< Process or thread has crashed and can be examined.
Returns:
int: The state type of the scripted thread.
Returns lldb.eStateStopped by default.
"""
return lldb.eStateStopped
def get_queue(self):
"""Get the scripted thread associated queue name.
This method is optional.
Returns:
str: The queue name associated with the scripted thread.
"""
return self.queue
@abstractmethod
def get_stop_reason(self):
"""Get the dictionary describing the stop reason type with some data.
This method is optional.
Returns:
Dict: The dictionary holding the stop reason type and the possibly
the stop reason data.
"""
pass
def get_stackframes(self):
"""Get the list of stack frames for the scripted thread.
```
scripted_frame = {
idx = 0,
pc = 0xbadc0ffee
}
```
Returns:
List[scripted_frame]: A list of `scripted_frame` dictionaries
containing at least for each entry, the frame index and
the program counter value for that frame.
The list can be empty.
"""
return self.frames
def get_register_info(self):
if self.register_info is None:
self.register_info = dict()
if self.scripted_process.arch == "x86_64":
self.register_info["sets"] = ["General Purpose Registers"]
self.register_info["registers"] = INTEL64_GPR
elif "arm64" in self.scripted_process.arch:
self.register_info["sets"] = ["General Purpose Registers"]
self.register_info["registers"] = ARM64_GPR
else:
raise ValueError("Unknown architecture", self.scripted_process.arch)
return self.register_info
@abstractmethod
def get_register_context(self):
"""Get the scripted thread register context
Returns:
str: A byte representing all register's value.
"""
pass
def get_extended_info(self):
"""Get scripted thread extended information.
Returns:
List: A list containing the extended information for the scripted process.
None if the thread as no extended information.
"""
return self.extended_info
ARM64_GPR = [
{
"name": "x0",
"bitsize": 64,
"offset": 0,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 0,
"dwarf": 0,
"generic": "arg0",
"alt-name": "arg0",
},
{
"name": "x1",
"bitsize": 64,
"offset": 8,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 1,
"dwarf": 1,
"generic": "arg1",
"alt-name": "arg1",
},
{
"name": "x2",
"bitsize": 64,
"offset": 16,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 2,
"dwarf": 2,
"generic": "arg2",
"alt-name": "arg2",
},
{
"name": "x3",
"bitsize": 64,
"offset": 24,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 3,
"dwarf": 3,
"generic": "arg3",
"alt-name": "arg3",
},
{
"name": "x4",
"bitsize": 64,
"offset": 32,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 4,
"dwarf": 4,
"generic": "arg4",
"alt-name": "arg4",
},
{
"name": "x5",
"bitsize": 64,
"offset": 40,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 5,
"dwarf": 5,
"generic": "arg5",
"alt-name": "arg5",
},
{
"name": "x6",
"bitsize": 64,
"offset": 48,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 6,
"dwarf": 6,
"generic": "arg6",
"alt-name": "arg6",
},
{
"name": "x7",
"bitsize": 64,
"offset": 56,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 7,
"dwarf": 7,
"generic": "arg7",
"alt-name": "arg7",
},
{
"name": "x8",
"bitsize": 64,
"offset": 64,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 8,
"dwarf": 8,
},
{
"name": "x9",
"bitsize": 64,
"offset": 72,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 9,
"dwarf": 9,
},
{
"name": "x10",
"bitsize": 64,
"offset": 80,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 10,
"dwarf": 10,
},
{
"name": "x11",
"bitsize": 64,
"offset": 88,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 11,
"dwarf": 11,
},
{
"name": "x12",
"bitsize": 64,
"offset": 96,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 12,
"dwarf": 12,
},
{
"name": "x13",
"bitsize": 64,
"offset": 104,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 13,
"dwarf": 13,
},
{
"name": "x14",
"bitsize": 64,
"offset": 112,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 14,
"dwarf": 14,
},
{
"name": "x15",
"bitsize": 64,
"offset": 120,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 15,
"dwarf": 15,
},
{
"name": "x16",
"bitsize": 64,
"offset": 128,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 16,
"dwarf": 16,
},
{
"name": "x17",
"bitsize": 64,
"offset": 136,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 17,
"dwarf": 17,
},
{
"name": "x18",
"bitsize": 64,
"offset": 144,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 18,
"dwarf": 18,
},
{
"name": "x19",
"bitsize": 64,
"offset": 152,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 19,
"dwarf": 19,
},
{
"name": "x20",
"bitsize": 64,
"offset": 160,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 20,
"dwarf": 20,
},
{
"name": "x21",
"bitsize": 64,
"offset": 168,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 21,
"dwarf": 21,
},
{
"name": "x22",
"bitsize": 64,
"offset": 176,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 22,
"dwarf": 22,
},
{
"name": "x23",
"bitsize": 64,
"offset": 184,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 23,
"dwarf": 23,
},
{
"name": "x24",
"bitsize": 64,
"offset": 192,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 24,
"dwarf": 24,
},
{
"name": "x25",
"bitsize": 64,
"offset": 200,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 25,
"dwarf": 25,
},
{
"name": "x26",
"bitsize": 64,
"offset": 208,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 26,
"dwarf": 26,
},
{
"name": "x27",
"bitsize": 64,
"offset": 216,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 27,
"dwarf": 27,
},
{
"name": "x28",
"bitsize": 64,
"offset": 224,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 28,
"dwarf": 28,
},
{
"name": "x29",
"bitsize": 64,
"offset": 232,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 29,
"dwarf": 29,
"generic": "fp",
"alt-name": "fp",
},
{
"name": "x30",
"bitsize": 64,
"offset": 240,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 30,
"dwarf": 30,
"generic": "lr",
"alt-name": "lr",
},
{
"name": "sp",
"bitsize": 64,
"offset": 248,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 31,
"dwarf": 31,
"generic": "sp",
"alt-name": "sp",
},
{
"name": "pc",
"bitsize": 64,
"offset": 256,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 32,
"dwarf": 32,
"generic": "pc",
"alt-name": "pc",
},
{
"name": "cpsr",
"bitsize": 32,
"offset": 264,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 33,
"dwarf": 33,
},
]
INTEL64_GPR = [
{
"name": "rax",
"bitsize": 64,
"offset": 0,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 0,
"dwarf": 0,
},
{
"name": "rbx",
"bitsize": 64,
"offset": 8,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 3,
"dwarf": 3,
},
{
"name": "rcx",
"bitsize": 64,
"offset": 16,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 2,
"dwarf": 2,
"generic": "arg4",
"alt-name": "arg4",
},
{
"name": "rdx",
"bitsize": 64,
"offset": 24,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 1,
"dwarf": 1,
"generic": "arg3",
"alt-name": "arg3",
},
{
"name": "rdi",
"bitsize": 64,
"offset": 32,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 5,
"dwarf": 5,
"generic": "arg1",
"alt-name": "arg1",
},
{
"name": "rsi",
"bitsize": 64,
"offset": 40,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 4,
"dwarf": 4,
"generic": "arg2",
"alt-name": "arg2",
},
{
"name": "rbp",
"bitsize": 64,
"offset": 48,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 6,
"dwarf": 6,
"generic": "fp",
"alt-name": "fp",
},
{
"name": "rsp",
"bitsize": 64,
"offset": 56,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 7,
"dwarf": 7,
"generic": "sp",
"alt-name": "sp",
},
{
"name": "r8",
"bitsize": 64,
"offset": 64,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 8,
"dwarf": 8,
"generic": "arg5",
"alt-name": "arg5",
},
{
"name": "r9",
"bitsize": 64,
"offset": 72,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 9,
"dwarf": 9,
"generic": "arg6",
"alt-name": "arg6",
},
{
"name": "r10",
"bitsize": 64,
"offset": 80,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 10,
"dwarf": 10,
},
{
"name": "r11",
"bitsize": 64,
"offset": 88,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 11,
"dwarf": 11,
},
{
"name": "r12",
"bitsize": 64,
"offset": 96,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 12,
"dwarf": 12,
},
{
"name": "r13",
"bitsize": 64,
"offset": 104,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 13,
"dwarf": 13,
},
{
"name": "r14",
"bitsize": 64,
"offset": 112,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 14,
"dwarf": 14,
},
{
"name": "r15",
"bitsize": 64,
"offset": 120,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 15,
"dwarf": 15,
},
{
"name": "rip",
"bitsize": 64,
"offset": 128,
"encoding": "uint",
"format": "hex",
"set": 0,
"gcc": 16,
"dwarf": 16,
"generic": "pc",
"alt-name": "pc",
},
{
"name": "rflags",
"bitsize": 64,
"offset": 136,
"encoding": "uint",
"format": "hex",
"set": 0,
"generic": "flags",
"alt-name": "flags",
},
{
"name": "cs",
"bitsize": 64,
"offset": 144,
"encoding": "uint",
"format": "hex",
"set": 0,
},
{
"name": "fs",
"bitsize": 64,
"offset": 152,
"encoding": "uint",
"format": "hex",
"set": 0,
},
{
"name": "gs",
"bitsize": 64,
"offset": 160,
"encoding": "uint",
"format": "hex",
"set": 0,
},
]