xref: /openbsd-src/gnu/llvm/lldb/examples/python/scripted_process/scripted_process.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1from abc import ABCMeta, abstractmethod
2
3import lldb
4
5class ScriptedProcess(metaclass=ABCMeta):
6
7    """
8    The base class for a scripted process.
9
10    Most of the base class methods are `@abstractmethod` that need to be
11    overwritten by the inheriting class.
12
13    DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE.
14                THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE.
15    """
16
17    memory_regions = None
18    loaded_images = None
19    threads = None
20    metadata = None
21
22    @abstractmethod
23    def __init__(self, exe_ctx, args):
24        """ Construct a scripted process.
25
26        Args:
27            exe_ctx (lldb.SBExecutionContext): The execution context for the scripted process.
28            args (lldb.SBStructuredData): A Dictionary holding arbitrary
29                key/value pairs used by the scripted process.
30        """
31        target = None
32        self.target = None
33        self.args = None
34        self.arch = None
35        if isinstance(exe_ctx, lldb.SBExecutionContext):
36            target = exe_ctx.target
37        if isinstance(target, lldb.SBTarget) and target.IsValid():
38            self.target = target
39            triple = self.target.triple
40            if triple:
41                self.arch = triple.split('-')[0]
42            self.dbg = target.GetDebugger()
43        if isinstance(args, lldb.SBStructuredData) and args.IsValid():
44            self.args = args
45        self.threads = {}
46        self.loaded_images = []
47        self.metadata = {}
48
49    @abstractmethod
50    def get_memory_region_containing_address(self, addr):
51        """ Get the memory region for the scripted process, containing a
52            specific address.
53
54        Args:
55            addr (int): Address to look for in the scripted process memory
56                regions.
57
58        Returns:
59            lldb.SBMemoryRegionInfo: The memory region containing the address.
60                None if out of bounds.
61        """
62        pass
63
64    def get_threads_info(self):
65        """ Get the dictionary describing the process' Scripted Threads.
66
67        Returns:
68            Dict: The dictionary of threads, with the thread ID as the key and
69            a Scripted Thread instance as the value.
70            The dictionary can be empty.
71        """
72        return self.threads
73
74    @abstractmethod
75    def get_thread_with_id(self, tid):
76        """ Get the scripted process thread with a specific ID.
77
78        Args:
79            tid (int): Thread ID to look for in the scripted process.
80
81        Returns:
82            Dict: The thread represented as a dictionary, with the
83                tid thread ID. None if tid doesn't match any of the scripted
84                process threads.
85        """
86        pass
87
88    @abstractmethod
89    def get_registers_for_thread(self, tid):
90        """ Get the register context dictionary for a certain thread of
91            the scripted process.
92
93        Args:
94            tid (int): Thread ID for the thread's register context.
95
96        Returns:
97            Dict: The register context represented as a dictionary, for the
98                tid thread. None if tid doesn't match any of the scripted
99                process threads.
100        """
101        pass
102
103    @abstractmethod
104    def read_memory_at_address(self, addr, size, error):
105        """ Get a memory buffer from the scripted process at a certain address,
106            of a certain size.
107
108        Args:
109            addr (int): Address from which we should start reading.
110            size (int): Size of the memory to read.
111            error (lldb.SBError): Error object.
112
113        Returns:
114            lldb.SBData: An `lldb.SBData` buffer with the target byte size and
115                byte order storing the memory read.
116        """
117        pass
118
119    def get_loaded_images(self):
120        """ Get the list of loaded images for the scripted process.
121
122        ```
123        scripted_image = {
124            uuid = "c6ea2b64-f77c-3d27-9528-74f507b9078b",
125            path = "/usr/lib/dyld"
126            load_addr = 0xbadc0ffee
127        }
128        ```
129
130        Returns:
131            List[scripted_image]: A list of `scripted_image` dictionaries
132                containing for each entry the library UUID or its file path
133                and its load address.
134                None if the list is empty.
135        """
136        return self.loaded_images
137
138    def get_process_id(self):
139        """ Get the scripted process identifier.
140
141        Returns:
142            int: The scripted process identifier.
143        """
144        return 0
145
146    def launch(self):
147        """ Simulate the scripted process launch.
148
149        Returns:
150            lldb.SBError: An `lldb.SBError` with error code 0.
151        """
152        return lldb.SBError()
153
154    def resume(self):
155        """ Simulate the scripted process resume.
156
157        Returns:
158            lldb.SBError: An `lldb.SBError` with error code 0.
159        """
160        return lldb.SBError()
161
162    @abstractmethod
163    def should_stop(self):
164        """ Check if the scripted process plugin should produce the stop event.
165
166        Returns:
167            bool: True if scripted process should broadcast a stop event.
168                  False otherwise.
169        """
170        pass
171
172    def stop(self):
173        """ Trigger the scripted process stop.
174
175        Returns:
176            lldb.SBError: An `lldb.SBError` with error code 0.
177        """
178        return lldb.SBError()
179
180    @abstractmethod
181    def is_alive(self):
182        """ Check if the scripted process is alive.
183
184        Returns:
185            bool: True if scripted process is alive. False otherwise.
186        """
187        pass
188
189    @abstractmethod
190    def get_scripted_thread_plugin(self):
191        """ Get scripted thread plugin name.
192
193        Returns:
194            str: Name of the scripted thread plugin.
195        """
196        return None
197
198    def get_process_metadata(self):
199        """ Get some metadata for the scripted process.
200
201        Returns:
202            Dict: A dictionary containing metadata for the scripted process.
203                  None is the process as no metadata.
204        """
205        return self.metadata
206
207class ScriptedThread(metaclass=ABCMeta):
208
209    """
210    The base class for a scripted thread.
211
212    Most of the base class methods are `@abstractmethod` that need to be
213    overwritten by the inheriting class.
214
215    DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE.
216                THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE.
217    """
218
219    @abstractmethod
220    def __init__(self, scripted_process, args):
221        """ Construct a scripted thread.
222
223        Args:
224            process (ScriptedProcess): The scripted process owning this thread.
225            args (lldb.SBStructuredData): A Dictionary holding arbitrary
226                key/value pairs used by the scripted thread.
227        """
228        self.target = None
229        self.scripted_process = None
230        self.process = None
231        self.args = None
232        self.idx = 0
233        self.tid = 0
234        self.idx = None
235        self.name = None
236        self.queue = None
237        self.state = None
238        self.stop_reason = None
239        self.register_info = None
240        self.register_ctx = {}
241        self.frames = []
242        self.extended_info = []
243
244        if isinstance(scripted_process, ScriptedProcess):
245            self.target = scripted_process.target
246            self.scripted_process = scripted_process
247            self.process = self.target.GetProcess()
248            self.get_register_info()
249
250    def get_thread_idx(self):
251        """ Get the scripted thread index.
252
253        Returns:
254            int: The index of the scripted thread in the scripted process.
255        """
256        return self.idx
257
258    def get_thread_id(self):
259        """ Get the scripted thread identifier.
260
261        Returns:
262            int: The identifier of the scripted thread.
263        """
264        return self.tid
265
266    def get_name(self):
267        """ Get the scripted thread name.
268
269        Returns:
270            str: The name of the scripted thread.
271        """
272        return self.name
273
274    def get_state(self):
275        """ Get the scripted thread state type.
276
277            eStateStopped,   ///< Process or thread is stopped and can be examined.
278            eStateRunning,   ///< Process or thread is running and can't be examined.
279            eStateStepping,  ///< Process or thread is in the process of stepping and can
280                             /// not be examined.
281            eStateCrashed,   ///< Process or thread has crashed and can be examined.
282
283        Returns:
284            int: The state type of the scripted thread.
285                 Returns lldb.eStateStopped by default.
286        """
287        return lldb.eStateStopped
288
289    def get_queue(self):
290        """ Get the scripted thread associated queue name.
291            This method is optional.
292
293        Returns:
294            str: The queue name associated with the scripted thread.
295        """
296        return self.queue
297
298    @abstractmethod
299    def get_stop_reason(self):
300        """ Get the dictionary describing the stop reason type with some data.
301            This method is optional.
302
303        Returns:
304            Dict: The dictionary holding the stop reason type and the possibly
305            the stop reason data.
306        """
307        pass
308
309    def get_stackframes(self):
310        """ Get the list of stack frames for the scripted thread.
311
312        ```
313        scripted_frame = {
314            idx = 0,
315            pc = 0xbadc0ffee
316        }
317        ```
318
319        Returns:
320            List[scripted_frame]: A list of `scripted_frame` dictionaries
321                containing at least for each entry, the frame index and
322                the program counter value for that frame.
323                The list can be empty.
324        """
325        return self.frames
326
327    def get_register_info(self):
328        if self.register_info is None:
329            self.register_info = dict()
330            if self.scripted_process.arch == 'x86_64':
331                self.register_info['sets'] = ['General Purpose Registers']
332                self.register_info['registers'] = INTEL64_GPR
333            elif 'arm64' in self.scripted_process.arch:
334                self.register_info['sets'] = ['General Purpose Registers']
335                self.register_info['registers'] = ARM64_GPR
336            else: raise ValueError('Unknown architecture', self.scripted_process.arch)
337        return self.register_info
338
339    @abstractmethod
340    def get_register_context(self):
341        """ Get the scripted thread register context
342
343        Returns:
344            str: A byte representing all register's value.
345        """
346        pass
347
348    def get_extended_info(self):
349        """ Get scripted thread extended information.
350
351        Returns:
352            List: A list containing the extended information for the scripted process.
353                  None is the thread as no extended information.
354        """
355        return self.extended_info
356
357ARM64_GPR = [ {'name': 'x0',   'bitsize': 64, 'offset': 0,   'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0,  'dwarf': 0,  'generic': 'arg0', 'alt-name': 'arg0'},
358              {'name': 'x1',   'bitsize': 64, 'offset': 8,   'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1,  'dwarf': 1,  'generic': 'arg1', 'alt-name': 'arg1'},
359              {'name': 'x2',   'bitsize': 64, 'offset': 16,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2,  'dwarf': 2,  'generic': 'arg2', 'alt-name': 'arg2'},
360              {'name': 'x3',   'bitsize': 64, 'offset': 24,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3,  'dwarf': 3,  'generic': 'arg3', 'alt-name': 'arg3'},
361              {'name': 'x4',   'bitsize': 64, 'offset': 32,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4,  'dwarf': 4,  'generic': 'arg4', 'alt-name': 'arg4'},
362              {'name': 'x5',   'bitsize': 64, 'offset': 40,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5,  'dwarf': 5,  'generic': 'arg5', 'alt-name': 'arg5'},
363              {'name': 'x6',   'bitsize': 64, 'offset': 48,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6,  'dwarf': 6,  'generic': 'arg6', 'alt-name': 'arg6'},
364              {'name': 'x7',   'bitsize': 64, 'offset': 56,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7,  'dwarf': 7,  'generic': 'arg7', 'alt-name': 'arg7'},
365              {'name': 'x8',   'bitsize': 64, 'offset': 64,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8,  'dwarf': 8 },
366              {'name': 'x9',   'bitsize': 64, 'offset': 72,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9,  'dwarf': 9 },
367              {'name': 'x10',  'bitsize': 64, 'offset': 80,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
368              {'name': 'x11',  'bitsize': 64, 'offset': 88,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
369              {'name': 'x12',  'bitsize': 64, 'offset': 96,  'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
370              {'name': 'x13',  'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13},
371              {'name': 'x14',  'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14},
372              {'name': 'x15',  'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15},
373              {'name': 'x16',  'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16},
374              {'name': 'x17',  'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 17, 'dwarf': 17},
375              {'name': 'x18',  'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 18, 'dwarf': 18},
376              {'name': 'x19',  'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 19, 'dwarf': 19},
377              {'name': 'x20',  'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 20, 'dwarf': 20},
378              {'name': 'x21',  'bitsize': 64, 'offset': 168, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 21, 'dwarf': 21},
379              {'name': 'x22',  'bitsize': 64, 'offset': 176, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 22, 'dwarf': 22},
380              {'name': 'x23',  'bitsize': 64, 'offset': 184, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 23, 'dwarf': 23},
381              {'name': 'x24',  'bitsize': 64, 'offset': 192, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 24, 'dwarf': 24},
382              {'name': 'x25',  'bitsize': 64, 'offset': 200, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 25, 'dwarf': 25},
383              {'name': 'x26',  'bitsize': 64, 'offset': 208, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 26, 'dwarf': 26},
384              {'name': 'x27',  'bitsize': 64, 'offset': 216, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 27, 'dwarf': 27},
385              {'name': 'x28',  'bitsize': 64, 'offset': 224, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 28, 'dwarf': 28},
386              {'name': 'x29',  'bitsize': 64, 'offset': 232, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 29, 'dwarf': 29, 'generic': 'fp', 'alt-name': 'fp'},
387              {'name': 'x30',  'bitsize': 64, 'offset': 240, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 30, 'dwarf': 30, 'generic': 'lr', 'alt-name': 'lr'},
388              {'name': 'sp',   'bitsize': 64, 'offset': 248, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 31, 'dwarf': 31, 'generic': 'sp', 'alt-name': 'sp'},
389              {'name': 'pc',   'bitsize': 64, 'offset': 256, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 32, 'dwarf': 32, 'generic': 'pc', 'alt-name': 'pc'},
390              {'name': 'cpsr', 'bitsize': 32, 'offset': 264, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 33, 'dwarf': 33}
391            ]
392
393INTEL64_GPR = [ {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0},
394                {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3},
395                {'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4'},
396                {'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3'},
397                {'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1'},
398                {'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2'},
399                {'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp'},
400                {'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp'},
401                {'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5'},
402                {'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6'},
403                {'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
404                {'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
405                {'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
406                {'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13},
407                {'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14},
408                {'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15},
409                {'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'},
410                {'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'},
411                {'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0},
412                {'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0},
413                {'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0}
414              ]
415
416
417