| """ |
| Intentionally malformed scripted extensions used by |
| TestScriptedExtensionsDiagnostics. |
| |
| Each class either omits a required abstract method or raises a Python |
| exception from one of its affordance methods. The corresponding test asserts |
| that LLDB surfaces those errors to the user instead of silently swallowing |
| them. |
| """ |
| |
| import lldb |
| from lldb.plugins.scripted_process import ScriptedProcess, ScriptedThread |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Process |
| # --------------------------------------------------------------------------- |
| |
| |
| class MissingMethodsScriptedProcess: |
| """Missing required abstract method `read_memory_at_address`.""" |
| |
| def __init__(self, exe_ctx, args): |
| self.exe_ctx = exe_ctx |
| self.args = args |
| |
| def get_scripted_thread_plugin(self): |
| return None |
| |
| def is_alive(self): |
| return True |
| |
| |
| class ExceptionScriptedProcess: |
| """All abstract methods present, but `launch` raises.""" |
| |
| def __init__(self, exe_ctx, args): |
| self.exe_ctx = exe_ctx |
| self.args = args |
| |
| def get_scripted_thread_plugin(self): |
| return None |
| |
| def is_alive(self): |
| return True |
| |
| def read_memory_at_address(self, addr, size, error): |
| return None |
| |
| def launch(self): |
| raise RuntimeError("intentional exception from launch()") |
| |
| |
| class TypoScriptedProcess: |
| """All abstract methods present, but `launch` has a typo (references an |
| undefined name) instead of an explicit `raise`, exercising a natural |
| Python runtime error (NameError) rather than a deliberately raised |
| exception.""" |
| |
| def __init__(self, exe_ctx, args): |
| self.exe_ctx = exe_ctx |
| self.args = args |
| |
| def get_scripted_thread_plugin(self): |
| return None |
| |
| def is_alive(self): |
| return True |
| |
| def read_memory_at_address(self, addr, size, error): |
| return None |
| |
| def launch(self): |
| return this_name_is_never_defined |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Thread |
| # --------------------------------------------------------------------------- |
| |
| |
| class ExceptionScriptedThread: |
| """Missing required abstract method `get_stop_reason`.""" |
| |
| def __init__(self, process, args): |
| self.process = process |
| self.args = args |
| |
| def get_thread_id(self): |
| raise ValueError("intentional exception from get_thread_id()") |
| |
| def get_register_context(self): |
| return "" |
| |
| def get_name(self): |
| return "ExceptionScriptedThread" |
| |
| def get_state(self): |
| return 0 |
| |
| |
| class ThreadListScriptedProcess: |
| """All abstract methods present, but `get_threads_info` hands back a |
| thread object (`ExceptionScriptedThread`) missing a required abstract |
| method.""" |
| |
| def __init__(self, exe_ctx, args): |
| self.exe_ctx = exe_ctx |
| self.args = args |
| |
| def get_scripted_thread_plugin(self): |
| return None |
| |
| def is_alive(self): |
| return True |
| |
| def read_memory_at_address(self, addr, size, error): |
| return None |
| |
| def launch(self): |
| return lldb.SBError() |
| |
| def get_threads_info(self): |
| return {1: ExceptionScriptedThread(self, None)} |
| |
| |
| class MissingMethodsScriptedFrame: |
| """Missing required abstract method `get_id`.""" |
| |
| def __init__(self, thread, args): |
| self.thread = thread |
| self.args = args |
| |
| |
| class StackFrameScriptedThread(ScriptedThread): |
| """A real, valid scripted thread (borrows the base class's default |
| register-info plumbing so construction succeeds), but `get_stackframes` |
| returns a scripted frame object (`MissingMethodsScriptedFrame`) missing a |
| required abstract method.""" |
| |
| def __init__(self, process, args): |
| super().__init__(process, args) |
| |
| def get_stop_reason(self): |
| return {"type": lldb.eStopReasonTrace, "data": {}} |
| |
| def get_register_context(self): |
| total_bytes = sum( |
| r["bitsize"] // 8 for r in self.get_register_info()["registers"] |
| ) |
| return "\x00" * total_bytes |
| |
| def get_stackframes(self): |
| return [MissingMethodsScriptedFrame(self, None)] |
| |
| |
| class StackFrameScriptedProcess(ScriptedProcess): |
| """All abstract methods present, but `get_threads_info` hands back a |
| thread (`StackFrameScriptedThread`) whose `get_stackframes` yields a |
| malformed scripted frame.""" |
| |
| def __init__(self, exe_ctx, args): |
| super().__init__(exe_ctx, args) |
| |
| def get_scripted_thread_plugin(self): |
| return None |
| |
| def is_alive(self): |
| return True |
| |
| def read_memory_at_address(self, addr, size, error): |
| return None |
| |
| def get_threads_info(self): |
| return {1: StackFrameScriptedThread(self, None)} |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Platform |
| # --------------------------------------------------------------------------- |
| |
| |
| class MissingMethodsScriptedPlatform: |
| """Missing required abstract method `list_processes`.""" |
| |
| def __init__(self, exe_ctx, args): |
| self.exe_ctx = exe_ctx |
| self.args = args |
| |
| |
| class ExceptionScriptedPlatform: |
| def __init__(self, exe_ctx, args): |
| self.exe_ctx = exe_ctx |
| self.args = args |
| |
| def list_processes(self): |
| raise RuntimeError("intentional exception from list_processes()") |
| |
| def get_process_info(self, pid): |
| return None |
| |
| def launch_process(self, launch_info): |
| return None |
| |
| def kill_process(self, pid): |
| return None |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Frame Provider |
| # --------------------------------------------------------------------------- |
| |
| |
| class ExceptionScriptedFrameProvider: |
| def __init__(self, frames, args): |
| self.frames = frames |
| self.args = args |
| |
| def get_num_frames(self): |
| raise RuntimeError("intentional exception from get_num_frames()") |
| |
| def get_frame_at_index(self, idx): |
| return None |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Thread Plan |
| # --------------------------------------------------------------------------- |
| |
| |
| class ExceptionScriptedThreadPlan: |
| def __init__(self, thread_plan, args): |
| self.thread_plan = thread_plan |
| self.args = args |
| |
| def explains_stop(self, event): |
| raise RuntimeError("intentional exception from explains_stop()") |
| |
| def should_stop(self, event): |
| return True |
| |
| def is_stale(self): |
| return False |
| |
| |
| class ExceptionInitScriptedThreadPlan: |
| """`__init__` raises.""" |
| |
| def __init__(self, thread_plan, args): |
| raise RuntimeError("intentional exception from __init__()") |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Breakpoint Resolver |
| # --------------------------------------------------------------------------- |
| |
| |
| class ExceptionScriptedBreakpointResolver: |
| def __init__(self, bkpt, args): |
| self.bkpt = bkpt |
| self.args = args |
| |
| def __callback__(self, sym_ctx): |
| raise RuntimeError("intentional exception from __callback__()") |
| |
| def get_short_help(self): |
| return "Exception breakpoint resolver" |
| |
| |
| class ExceptionInitScriptedBreakpointResolver: |
| """`__init__` raises. Everything else is implemented, so `__init__` is the |
| only thing wrong with this class: LLDB validates the class before it |
| constructs an instance, and a missing abstract method would otherwise be |
| reported first.""" |
| |
| def __init__(self, bkpt, args): |
| raise RuntimeError("intentional exception from __init__()") |
| |
| def __callback__(self, sym_ctx): |
| return False |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Stop Hook |
| # --------------------------------------------------------------------------- |
| |
| |
| class ExceptionScriptedStopHook: |
| def __init__(self, target, args): |
| self.target = target |
| self.args = args |
| |
| def handle_stop(self, exe_ctx, stream): |
| raise RuntimeError("intentional exception from handle_stop()") |
| |
| |
| class NoneReturningScriptedStopHook: |
| """`handle_stop` returns None, which is not an error: it means the hook |
| has no opinion on whether to stay stopped.""" |
| |
| def __init__(self, target, args): |
| self.target = target |
| self.args = args |
| |
| def handle_stop(self, exe_ctx, stream): |
| stream.Print("NoneReturningScriptedStopHook ran\n") |
| |
| |
| # --------------------------------------------------------------------------- |
| # Scripted Stack Frame Recognizer |
| # --------------------------------------------------------------------------- |
| |
| |
| class ExceptionScriptedStackFrameRecognizer: |
| """`__init__` raises.""" |
| |
| def __init__(self): |
| raise RuntimeError("intentional exception from __init__()") |
| |
| |
| # --------------------------------------------------------------------------- |
| # Operating System |
| # --------------------------------------------------------------------------- |
| |
| |
| class MissingMethodsOperatingSystem: |
| """Missing required abstract method `get_thread_info`.""" |
| |
| def __init__(self, process): |
| self.process = process |
| |
| |
| class ExceptionOperatingSystem: |
| def __init__(self, process): |
| self.process = process |
| |
| def get_thread_info(self): |
| raise RuntimeError("intentional exception from get_thread_info()") |
| |
| def get_register_info(self): |
| return {} |
| |
| def get_register_data(self, tid): |
| return b"" |