xref: /openbsd/gnu/llvm/lldb/examples/python/lldbtk.py (revision f6aab3d8)
1#!/usr/bin/env python
2
3import lldb
4import shlex
5import sys
6try:
7    from tkinter import *
8    import tkinter.ttk as ttk
9except ImportError:
10    from Tkinter import *
11    import ttk
12
13
14class ValueTreeItemDelegate(object):
15
16    def __init__(self, value):
17        self.value = value
18
19    def get_item_dictionary(self):
20        name = self.value.name
21        if name is None:
22            name = ''
23        typename = self.value.type
24        if typename is None:
25            typename = ''
26        value = self.value.value
27        if value is None:
28            value = ''
29        summary = self.value.summary
30        if summary is None:
31            summary = ''
32        has_children = self.value.MightHaveChildren()
33        return {'#0': name,
34                'typename': typename,
35                'value': value,
36                'summary': summary,
37                'children': has_children,
38                'tree-item-delegate': self}
39
40    def get_child_item_dictionaries(self):
41        item_dicts = list()
42        for i in range(self.value.num_children):
43            item_delegate = ValueTreeItemDelegate(
44                self.value.GetChildAtIndex(i))
45            item_dicts.append(item_delegate.get_item_dictionary())
46        return item_dicts
47
48
49class FrameTreeItemDelegate(object):
50
51    def __init__(self, frame):
52        self.frame = frame
53
54    def get_item_dictionary(self):
55        id = self.frame.GetFrameID()
56        name = 'frame #%u' % (id)
57        value = '0x%16.16x' % (self.frame.GetPC())
58        stream = lldb.SBStream()
59        self.frame.GetDescription(stream)
60        summary = stream.GetData().split("`")[1]
61        return {
62            '#0': name,
63            'value': value,
64            'summary': summary,
65            'children': self.frame.GetVariables(
66                True,
67                True,
68                True,
69                True).GetSize() > 0,
70            'tree-item-delegate': self}
71
72    def get_child_item_dictionaries(self):
73        item_dicts = list()
74        variables = self.frame.GetVariables(True, True, True, True)
75        n = variables.GetSize()
76        for i in range(n):
77            item_delegate = ValueTreeItemDelegate(variables[i])
78            item_dicts.append(item_delegate.get_item_dictionary())
79        return item_dicts
80
81
82class ThreadTreeItemDelegate(object):
83
84    def __init__(self, thread):
85        self.thread = thread
86
87    def get_item_dictionary(self):
88        num_frames = self.thread.GetNumFrames()
89        name = 'thread #%u' % (self.thread.GetIndexID())
90        value = '0x%x' % (self.thread.GetThreadID())
91        summary = '%u frames' % (num_frames)
92        return {'#0': name,
93                'value': value,
94                'summary': summary,
95                'children': num_frames > 0,
96                'tree-item-delegate': self}
97
98    def get_child_item_dictionaries(self):
99        item_dicts = list()
100        for frame in self.thread:
101            item_delegate = FrameTreeItemDelegate(frame)
102            item_dicts.append(item_delegate.get_item_dictionary())
103        return item_dicts
104
105
106class ProcessTreeItemDelegate(object):
107
108    def __init__(self, process):
109        self.process = process
110
111    def get_item_dictionary(self):
112        id = self.process.GetProcessID()
113        num_threads = self.process.GetNumThreads()
114        value = str(self.process.GetProcessID())
115        summary = self.process.target.executable.fullpath
116        return {'#0': 'process',
117                'value': value,
118                'summary': summary,
119                'children': num_threads > 0,
120                'tree-item-delegate': self}
121
122    def get_child_item_dictionaries(self):
123        item_dicts = list()
124        for thread in self.process:
125            item_delegate = ThreadTreeItemDelegate(thread)
126            item_dicts.append(item_delegate.get_item_dictionary())
127        return item_dicts
128
129
130class TargetTreeItemDelegate(object):
131
132    def __init__(self, target):
133        self.target = target
134
135    def get_item_dictionary(self):
136        value = str(self.target.triple)
137        summary = self.target.executable.fullpath
138        return {'#0': 'target',
139                'value': value,
140                'summary': summary,
141                'children': True,
142                'tree-item-delegate': self}
143
144    def get_child_item_dictionaries(self):
145        item_dicts = list()
146        image_item_delegate = TargetImagesTreeItemDelegate(self.target)
147        item_dicts.append(image_item_delegate.get_item_dictionary())
148        return item_dicts
149
150
151class TargetImagesTreeItemDelegate(object):
152
153    def __init__(self, target):
154        self.target = target
155
156    def get_item_dictionary(self):
157        value = str(self.target.triple)
158        summary = self.target.executable.fullpath
159        num_modules = self.target.GetNumModules()
160        return {'#0': 'images',
161                'value': '',
162                'summary': '%u images' % num_modules,
163                'children': num_modules > 0,
164                'tree-item-delegate': self}
165
166    def get_child_item_dictionaries(self):
167        item_dicts = list()
168        for i in range(self.target.GetNumModules()):
169            module = self.target.GetModuleAtIndex(i)
170            image_item_delegate = ModuleTreeItemDelegate(
171                self.target, module, i)
172            item_dicts.append(image_item_delegate.get_item_dictionary())
173        return item_dicts
174
175
176class ModuleTreeItemDelegate(object):
177
178    def __init__(self, target, module, index):
179        self.target = target
180        self.module = module
181        self.index = index
182
183    def get_item_dictionary(self):
184        name = 'module %u' % (self.index)
185        value = self.module.file.basename
186        summary = self.module.file.dirname
187        return {'#0': name,
188                'value': value,
189                'summary': summary,
190                'children': True,
191                'tree-item-delegate': self}
192
193    def get_child_item_dictionaries(self):
194        item_dicts = list()
195        sections_item_delegate = ModuleSectionsTreeItemDelegate(
196            self.target, self.module)
197        item_dicts.append(sections_item_delegate.get_item_dictionary())
198
199        symbols_item_delegate = ModuleSymbolsTreeItemDelegate(
200            self.target, self.module)
201        item_dicts.append(symbols_item_delegate.get_item_dictionary())
202
203        comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(
204            self.target, self.module)
205        item_dicts.append(comp_units_item_delegate.get_item_dictionary())
206        return item_dicts
207
208
209class ModuleSectionsTreeItemDelegate(object):
210
211    def __init__(self, target, module):
212        self.target = target
213        self.module = module
214
215    def get_item_dictionary(self):
216        name = 'sections'
217        value = ''
218        summary = '%u sections' % (self.module.GetNumSections())
219        return {'#0': name,
220                'value': value,
221                'summary': summary,
222                'children': True,
223                'tree-item-delegate': self}
224
225    def get_child_item_dictionaries(self):
226        item_dicts = list()
227        num_sections = self.module.GetNumSections()
228        for i in range(num_sections):
229            section = self.module.GetSectionAtIndex(i)
230            image_item_delegate = SectionTreeItemDelegate(self.target, section)
231            item_dicts.append(image_item_delegate.get_item_dictionary())
232        return item_dicts
233
234
235class SectionTreeItemDelegate(object):
236
237    def __init__(self, target, section):
238        self.target = target
239        self.section = section
240
241    def get_item_dictionary(self):
242        name = self.section.name
243        section_load_addr = self.section.GetLoadAddress(self.target)
244        if section_load_addr != lldb.LLDB_INVALID_ADDRESS:
245            value = '0x%16.16x' % (section_load_addr)
246        else:
247            value = '0x%16.16x *' % (self.section.file_addr)
248        summary = ''
249        return {'#0': name,
250                'value': value,
251                'summary': summary,
252                'children': self.section.GetNumSubSections() > 0,
253                'tree-item-delegate': self}
254
255    def get_child_item_dictionaries(self):
256        item_dicts = list()
257        num_sections = self.section.GetNumSubSections()
258        for i in range(num_sections):
259            section = self.section.GetSubSectionAtIndex(i)
260            image_item_delegate = SectionTreeItemDelegate(self.target, section)
261            item_dicts.append(image_item_delegate.get_item_dictionary())
262        return item_dicts
263
264
265class ModuleCompileUnitsTreeItemDelegate(object):
266
267    def __init__(self, target, module):
268        self.target = target
269        self.module = module
270
271    def get_item_dictionary(self):
272        name = 'compile units'
273        value = ''
274        summary = '%u compile units' % (self.module.GetNumSections())
275        return {'#0': name,
276                'value': value,
277                'summary': summary,
278                'children': self.module.GetNumCompileUnits() > 0,
279                'tree-item-delegate': self}
280
281    def get_child_item_dictionaries(self):
282        item_dicts = list()
283        num_cus = self.module.GetNumCompileUnits()
284        for i in range(num_cus):
285            cu = self.module.GetCompileUnitAtIndex(i)
286            image_item_delegate = CompileUnitTreeItemDelegate(self.target, cu)
287            item_dicts.append(image_item_delegate.get_item_dictionary())
288        return item_dicts
289
290
291class CompileUnitTreeItemDelegate(object):
292
293    def __init__(self, target, cu):
294        self.target = target
295        self.cu = cu
296
297    def get_item_dictionary(self):
298        name = self.cu.GetFileSpec().basename
299        value = ''
300        num_lines = self.cu.GetNumLineEntries()
301        summary = ''
302        return {'#0': name,
303                'value': value,
304                'summary': summary,
305                'children': num_lines > 0,
306                'tree-item-delegate': self}
307
308    def get_child_item_dictionaries(self):
309        item_dicts = list()
310        item_delegate = LineTableTreeItemDelegate(self.target, self.cu)
311        item_dicts.append(item_delegate.get_item_dictionary())
312        return item_dicts
313
314
315class LineTableTreeItemDelegate(object):
316
317    def __init__(self, target, cu):
318        self.target = target
319        self.cu = cu
320
321    def get_item_dictionary(self):
322        name = 'line table'
323        value = ''
324        num_lines = self.cu.GetNumLineEntries()
325        summary = '%u line entries' % (num_lines)
326        return {'#0': name,
327                'value': value,
328                'summary': summary,
329                'children': num_lines > 0,
330                'tree-item-delegate': self}
331
332    def get_child_item_dictionaries(self):
333        item_dicts = list()
334        num_lines = self.cu.GetNumLineEntries()
335        for i in range(num_lines):
336            line_entry = self.cu.GetLineEntryAtIndex(i)
337            item_delegate = LineEntryTreeItemDelegate(
338                self.target, line_entry, i)
339            item_dicts.append(item_delegate.get_item_dictionary())
340        return item_dicts
341
342
343class LineEntryTreeItemDelegate(object):
344
345    def __init__(self, target, line_entry, index):
346        self.target = target
347        self.line_entry = line_entry
348        self.index = index
349
350    def get_item_dictionary(self):
351        name = str(self.index)
352        address = self.line_entry.GetStartAddress()
353        load_addr = address.GetLoadAddress(self.target)
354        if load_addr != lldb.LLDB_INVALID_ADDRESS:
355            value = '0x%16.16x' % (load_addr)
356        else:
357            value = '0x%16.16x *' % (address.file_addr)
358        summary = self.line_entry.GetFileSpec().fullpath + ':' + \
359            str(self.line_entry.line)
360        return {'#0': name,
361                'value': value,
362                'summary': summary,
363                'children': False,
364                'tree-item-delegate': self}
365
366    def get_child_item_dictionaries(self):
367        item_dicts = list()
368        return item_dicts
369
370
371class InstructionTreeItemDelegate(object):
372
373    def __init__(self, target, instr):
374        self.target = target
375        self.instr = instr
376
377    def get_item_dictionary(self):
378        address = self.instr.GetAddress()
379        load_addr = address.GetLoadAddress(self.target)
380        if load_addr != lldb.LLDB_INVALID_ADDRESS:
381            name = '0x%16.16x' % (load_addr)
382        else:
383            name = '0x%16.16x *' % (address.file_addr)
384        value = self.instr.GetMnemonic(
385            self.target) + ' ' + self.instr.GetOperands(self.target)
386        summary = self.instr.GetComment(self.target)
387        return {'#0': name,
388                'value': value,
389                'summary': summary,
390                'children': False,
391                'tree-item-delegate': self}
392
393
394class ModuleSymbolsTreeItemDelegate(object):
395
396    def __init__(self, target, module):
397        self.target = target
398        self.module = module
399
400    def get_item_dictionary(self):
401        name = 'symbols'
402        value = ''
403        summary = '%u symbols' % (self.module.GetNumSymbols())
404        return {'#0': name,
405                'value': value,
406                'summary': summary,
407                'children': True,
408                'tree-item-delegate': self}
409
410    def get_child_item_dictionaries(self):
411        item_dicts = list()
412        num_symbols = self.module.GetNumSymbols()
413        for i in range(num_symbols):
414            symbol = self.module.GetSymbolAtIndex(i)
415            image_item_delegate = SymbolTreeItemDelegate(
416                self.target, symbol, i)
417            item_dicts.append(image_item_delegate.get_item_dictionary())
418        return item_dicts
419
420
421class SymbolTreeItemDelegate(object):
422
423    def __init__(self, target, symbol, index):
424        self.target = target
425        self.symbol = symbol
426        self.index = index
427
428    def get_item_dictionary(self):
429        address = self.symbol.GetStartAddress()
430        name = '[%u]' % self.index
431        symbol_load_addr = address.GetLoadAddress(self.target)
432        if symbol_load_addr != lldb.LLDB_INVALID_ADDRESS:
433            value = '0x%16.16x' % (symbol_load_addr)
434        else:
435            value = '0x%16.16x *' % (address.file_addr)
436        summary = self.symbol.name
437        return {'#0': name,
438                'value': value,
439                'summary': summary,
440                'children': False,
441                'tree-item-delegate': self}
442
443    def get_child_item_dictionaries(self):
444        item_dicts = list()
445        return item_dicts
446
447
448class DelegateTree(ttk.Frame):
449
450    def __init__(self, column_dicts, delegate, title, name):
451        ttk.Frame.__init__(self, name=name)
452        self.pack(expand=Y, fill=BOTH)
453        self.master.title(title)
454        self.delegate = delegate
455        self.columns_dicts = column_dicts
456        self.item_id_to_item_dict = dict()
457        frame = Frame(self)
458        frame.pack(side=TOP, fill=BOTH, expand=Y)
459        self._create_treeview(frame)
460        self._populate_root()
461
462    def _create_treeview(self, parent):
463        frame = ttk.Frame(parent)
464        frame.pack(side=TOP, fill=BOTH, expand=Y)
465
466        column_ids = list()
467        for i in range(1, len(self.columns_dicts)):
468            column_ids.append(self.columns_dicts[i]['id'])
469        # create the tree and scrollbars
470        self.tree = ttk.Treeview(columns=column_ids)
471
472        scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview)
473        scroll_bar_h = ttk.Scrollbar(
474            orient=HORIZONTAL, command=self.tree.xview)
475        self.tree['yscroll'] = scroll_bar_v.set
476        self.tree['xscroll'] = scroll_bar_h.set
477
478        # setup column headings and columns properties
479        for columns_dict in self.columns_dicts:
480            self.tree.heading(
481                columns_dict['id'],
482                text=columns_dict['text'],
483                anchor=columns_dict['anchor'])
484            self.tree.column(
485                columns_dict['id'],
486                stretch=columns_dict['stretch'])
487
488        # add tree and scrollbars to frame
489        self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)
490        scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)
491        scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)
492
493        # set frame resizing priorities
494        frame.rowconfigure(0, weight=1)
495        frame.columnconfigure(0, weight=1)
496
497        # action to perform when a node is expanded
498        self.tree.bind('<<TreeviewOpen>>', self._update_tree)
499
500    def insert_items(self, parent_id, item_dicts):
501        for item_dict in item_dicts:
502            name = None
503            values = list()
504            first = True
505            for columns_dict in self.columns_dicts:
506                if first:
507                    name = item_dict[columns_dict['id']]
508                    first = False
509                else:
510                    values.append(item_dict[columns_dict['id']])
511            item_id = self.tree.insert(parent_id,  # root item has an empty name
512                                       END,
513                                       text=name,
514                                       values=values)
515            self.item_id_to_item_dict[item_id] = item_dict
516            if item_dict['children']:
517                self.tree.insert(item_id, END, text='dummy')
518
519    def _populate_root(self):
520        # use current directory as root node
521        self.insert_items('', self.delegate.get_child_item_dictionaries())
522
523    def _update_tree(self, event):
524        # user expanded a node - build the related directory
525        item_id = self.tree.focus()      # the id of the expanded node
526        children = self.tree.get_children(item_id)
527        if len(children):
528            first_child = children[0]
529            # if the node only has a 'dummy' child, remove it and
530            # build new directory; skip if the node is already
531            # populated
532            if self.tree.item(first_child, option='text') == 'dummy':
533                self.tree.delete(first_child)
534                item_dict = self.item_id_to_item_dict[item_id]
535                item_dicts = item_dict[
536                    'tree-item-delegate'].get_child_item_dictionaries()
537                self.insert_items(item_id, item_dicts)
538
539
540@lldb.command("tk-variables")
541def tk_variable_display(debugger, command, result, dict):
542    # needed for tree creation in TK library as it uses sys.argv...
543    sys.argv = ['tk-variables']
544    target = debugger.GetSelectedTarget()
545    if not target:
546        print("invalid target", file=result)
547        return
548    process = target.GetProcess()
549    if not process:
550        print("invalid process", file=result)
551        return
552    thread = process.GetSelectedThread()
553    if not thread:
554        print("invalid thread", file=result)
555        return
556    frame = thread.GetSelectedFrame()
557    if not frame:
558        print("invalid frame", file=result)
559        return
560    # Parse command line args
561    command_args = shlex.split(command)
562    column_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
563                    {'id': 'typename', 'text': 'Type', 'anchor': W, 'stretch': 0},
564                    {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
565                    {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
566    tree = DelegateTree(
567        column_dicts,
568        FrameTreeItemDelegate(frame),
569        'Variables',
570        'lldb-tk-variables')
571    tree.mainloop()
572
573
574@lldb.command("tk-process")
575def tk_process_display(debugger, command, result, dict):
576    # needed for tree creation in TK library as it uses sys.argv...
577    sys.argv = ['tk-process']
578    target = debugger.GetSelectedTarget()
579    if not target:
580        print("invalid target", file=result)
581        return
582    process = target.GetProcess()
583    if not process:
584        print("invalid process", file=result)
585        return
586    # Parse command line args
587    columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
588                     {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
589                     {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
590    command_args = shlex.split(command)
591    tree = DelegateTree(
592        columnd_dicts,
593        ProcessTreeItemDelegate(process),
594        'Process',
595        'lldb-tk-process')
596    tree.mainloop()
597
598
599@lldb.command("tk-target")
600def tk_target_display(debugger, command, result, dict):
601    # needed for tree creation in TK library as it uses sys.argv...
602    sys.argv = ['tk-target']
603    target = debugger.GetSelectedTarget()
604    if not target:
605        print("invalid target", file=result)
606        return
607    # Parse command line args
608    columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
609                     {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
610                     {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
611    command_args = shlex.split(command)
612    tree = DelegateTree(
613        columnd_dicts,
614        TargetTreeItemDelegate(target),
615        'Target',
616        'lldb-tk-target')
617    tree.mainloop()
618