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