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