114 lines · python
1from abc import ABCMeta, abstractmethod2 3import lldb4 5 6class ScriptedFrameProvider(metaclass=ABCMeta):7 """8 The base class for a scripted frame provider.9 10 A scripted frame provider allows you to provide custom stack frames for a11 thread, which can be used to augment or replace the standard unwinding12 mechanism. This is useful for:13 14 - Providing frames for custom calling conventions or languages15 - Reconstructing missing frames from crash dumps or core files16 - Adding diagnostic or synthetic frames for debugging17 - Visualizing state machines or async execution contexts18 19 Most of the base class methods are `@abstractmethod` that need to be20 overwritten by the inheriting class.21 22 Example usage:23 24 .. code-block:: python25 26 # Attach a frame provider to a thread27 thread = process.GetSelectedThread()28 error = thread.SetScriptedFrameProvider(29 "my_module.MyFrameProvider",30 lldb.SBStructuredData()31 )32 """33 34 @abstractmethod35 def __init__(self, input_frames, args):36 """Construct a scripted frame provider.37 38 Args:39 input_frames (lldb.SBFrameList): The frame list to use as input.40 This allows you to access frames by index. The frames are41 materialized lazily as you access them.42 args (lldb.SBStructuredData): A Dictionary holding arbitrary43 key/value pairs used by the scripted frame provider.44 """45 self.input_frames = None46 self.args = None47 self.thread = None48 self.target = None49 self.process = None50 51 if isinstance(input_frames, lldb.SBFrameList) and input_frames.IsValid():52 self.input_frames = input_frames53 self.thread = input_frames.GetThread()54 if self.thread and self.thread.IsValid():55 self.process = self.thread.GetProcess()56 if self.process and self.process.IsValid():57 self.target = self.process.GetTarget()58 59 if isinstance(args, lldb.SBStructuredData) and args.IsValid():60 self.args = args61 62 @abstractmethod63 def get_frame_at_index(self, index):64 """Get a single stack frame at the given index.65 66 This method is called lazily when a specific frame is needed in the67 thread's backtrace (e.g., via the 'bt' command). Each frame is68 requested individually as needed.69 70 Args:71 index (int): The frame index to retrieve (0 for youngest/top frame).72 73 Returns:74 Dict or None: A frame dictionary describing the stack frame, or None75 if no frame exists at this index. The dictionary should contain:76 77 Required fields:78 - idx (int): The synthetic frame index (0 for youngest/top frame)79 - pc (int): The program counter address for the synthetic frame80 81 Alternatively, you can return:82 - A ScriptedFrame object for full control over frame behavior83 - An integer representing an input frame index to reuse84 - None to indicate no more frames exist85 86 Example:87 88 .. code-block:: python89 90 def get_frame_at_index(self, index):91 # Return None when there are no more frames92 if index >= self.total_frames:93 return None94 95 # Re-use an input frame by returning its index96 if self.should_use_input_frame(index):97 return index # Returns input frame at this index98 99 # Or create a custom frame dictionary100 if index == 0:101 return {102 "idx": 0,103 "pc": 0x100001234,104 }105 106 return None107 108 Note:109 The frames are indexed from 0 (youngest/top) to N (oldest/bottom).110 This method will be called repeatedly with increasing indices until111 None is returned.112 """113 pass114