| 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. |
| """ |
| |
| memory_regions = None |
| stack_memory_dump = None |
| loaded_images = None |
| |
| @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(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. |
| """ |
| pass |
| |
| @abstractmethod |
| def get_thread_with_id(self, 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(self, 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(self, 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 |
| |
| 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. |
| """ |
| return self.loaded_images |
| |
| 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 should_stop(self): |
| """ Check if the scripted process plugin should produce the stop event. |
| |
| Returns: |
| bool: True if scripted process should broadcast a stop event. |
| False otherwise. |
| """ |
| pass |
| |
| def stop(self): |
| """ Trigger the scripted process stop. |
| |
| 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 |
| |
| @abstractmethod |
| def get_scripted_thread_plugin(self): |
| """ Get scripted thread plugin name. |
| |
| Returns: |
| str: Name of the scripted thread plugin. |
| """ |
| return None |
| |
| @six.add_metaclass(ABCMeta) |
| class ScriptedThread: |
| |
| """ |
| 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, process, args): |
| """ Construct a scripted thread. |
| |
| Args: |
| process (lldb.SBProcess): 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.process = None |
| self.args = None |
| if isinstance(process, lldb.SBProcess) and process.IsValid(): |
| self.process = process |
| self.target = process.GetTarget() |
| |
| self.id = None |
| self.name = None |
| self.queue = None |
| self.state = None |
| self.stop_reason = None |
| self.register_info = None |
| self.register_ctx = {} |
| self.frames = [] |
| |
| @abstractmethod |
| def get_thread_id(self): |
| """ Get the scripted thread identifier. |
| |
| Returns: |
| int: The identifier of the scripted thread. |
| """ |
| pass |
| |
| @abstractmethod |
| def get_name(self): |
| """ Get the scripted thread name. |
| |
| Returns: |
| str: The name of the scripted thread. |
| """ |
| pass |
| |
| 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. |
| |
| 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. |
| """ |
| pass |
| |
| @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. |
| |
| ``` |
| class ScriptedStackFrame: |
| def __init__(idx, cfa, pc, symbol_ctx): |
| self.idx = idx |
| self.cfa = cfa |
| self.pc = pc |
| self.symbol_ctx = symbol_ctx |
| ``` |
| |
| Returns: |
| List[ScriptedFrame]: A list of `ScriptedStackFrame` |
| containing for each entry, the frame index, the canonical |
| frame address, the program counter value for that frame |
| and a symbol context. |
| None if the list is empty. |
| """ |
| return 0 |
| |
| def get_register_info(self): |
| if self.register_info is None: |
| self.register_info = dict() |
| triple = self.target.triple |
| if triple: |
| arch = triple.split('-')[0] |
| if arch == 'x86_64': |
| self.register_info['sets'] = ['General Purpose Registers'] |
| self.register_info['registers'] = [ |
| {'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}, |
| ] |
| 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 |