| from abc import abstractmethod | |
| from typing import Any, Optional | |
| 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. | |
| .. code-block:: python | |
| 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. | |
| """ | |
| registers: dict[str, Any] | |
| threads: list[dict] | |
| def __init__(self, process: lldb.SBProcess): | |
| """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: int, context: int) -> Optional[dict]: | |
| """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) -> list[dict]: | |
| """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: int) -> str: | |
| """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) -> Optional[str]: | |
| pass | |
| def get_stop_reason(self) -> Optional[dict[str, Any]]: | |
| pass |