1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
from abc import ABCMeta, abstractmethod
import lldb
class ScriptedFrameProvider(metaclass=ABCMeta):
"""
The base class for a scripted frame provider.
A scripted frame provider allows you to provide custom stack frames for a
thread, which can be used to augment or replace the standard unwinding
mechanism. This is useful for:
- Providing frames for custom calling conventions or languages
- Reconstructing missing frames from crash dumps or core files
- Adding diagnostic or synthetic frames for debugging
- Visualizing state machines or async execution contexts
Most of the base class methods are `@abstractmethod` that need to be
overwritten by the inheriting class.
Example usage:
.. code-block:: python
# Attach a frame provider to a thread
thread = process.GetSelectedThread()
error = thread.SetScriptedFrameProvider(
"my_module.MyFrameProvider",
lldb.SBStructuredData()
)
"""
@staticmethod
def applies_to_thread(thread):
"""Determine if this frame provider should be used for a given thread.
This static method is called before creating an instance of the frame
provider to determine if it should be applied to a specific thread.
Override this method to provide custom filtering logic.
Args:
thread (lldb.SBThread): The thread to check.
Returns:
bool: True if this frame provider should be used for the thread,
False otherwise. The default implementation returns True for
all threads.
Example:
.. code-block:: python
@staticmethod
def applies_to_thread(thread):
# Only apply to thread 1
return thread.GetIndexID() == 1
"""
return True
@staticmethod
@abstractmethod
def get_description():
"""Get a description of this frame provider.
This method should return a human-readable string describing what
this frame provider does. The description is used for debugging
and display purposes.
Returns:
str: A description of the frame provider.
Example:
.. code-block:: python
def get_description(self):
return "Crash log frame provider for thread 1"
"""
pass
def __init__(self, input_frames, args):
"""Construct a scripted frame provider.
Args:
input_frames (lldb.SBFrameList): The frame list to use as input.
This allows you to access frames by index. The frames are
materialized lazily as you access them.
args (lldb.SBStructuredData): A Dictionary holding arbitrary
key/value pairs used by the scripted frame provider.
"""
self.input_frames = None
self.args = None
self.thread = None
self.target = None
self.process = None
if isinstance(input_frames, lldb.SBFrameList) and input_frames.IsValid():
self.input_frames = input_frames
self.thread = input_frames.GetThread()
if self.thread and self.thread.IsValid():
self.process = self.thread.GetProcess()
if self.process and self.process.IsValid():
self.target = self.process.GetTarget()
if isinstance(args, lldb.SBStructuredData) and args.IsValid():
self.args = args
@abstractmethod
def get_frame_at_index(self, index):
"""Get a single stack frame at the given index.
This method is called lazily when a specific frame is needed in the
thread's backtrace (e.g., via the 'bt' command). Each frame is
requested individually as needed.
Args:
index (int): The frame index to retrieve (0 for youngest/top frame).
Returns:
Dict or None: A frame dictionary describing the stack frame, or None
if no frame exists at this index. The dictionary should contain:
Required fields:
- idx (int): The synthetic frame index (0 for youngest/top frame)
- pc (int): The program counter address for the synthetic frame
Alternatively, you can return:
- A ScriptedFrame object for full control over frame behavior
- An integer representing an input frame index to reuse
- None to indicate no more frames exist
Example:
.. code-block:: python
def get_frame_at_index(self, index):
# Return None when there are no more frames
if index >= self.total_frames:
return None
# Re-use an input frame by returning its index
if self.should_use_input_frame(index):
return index # Returns input frame at this index
# Or create a custom frame dictionary
if index == 0:
return {
"idx": 0,
"pc": 0x100001234,
}
return None
Note:
The frames are indexed from 0 (youngest/top) to N (oldest/bottom).
This method will be called repeatedly with increasing indices until
None is returned.
"""
pass
|