#!/usr/bin/env python from __future__ import print_function import lldb import shlex import sys try: from tkinter import * import tkinter.ttk as ttk except ImportError: from Tkinter import * import ttk class ValueTreeItemDelegate(object): def __init__(self, value): self.value = value def get_item_dictionary(self): name = self.value.name if name is None: name = '' typename = self.value.type if typename is None: typename = '' value = self.value.value if value is None: value = '' summary = self.value.summary if summary is None: summary = '' has_children = self.value.MightHaveChildren() return {'#0': name, 'typename': typename, 'value': value, 'summary': summary, 'children': has_children, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() for i in range(self.value.num_children): item_delegate = ValueTreeItemDelegate( self.value.GetChildAtIndex(i)) item_dicts.append(item_delegate.get_item_dictionary()) return item_dicts class FrameTreeItemDelegate(object): def __init__(self, frame): self.frame = frame def get_item_dictionary(self): id = self.frame.GetFrameID() name = 'frame #%u' % (id) value = '0x%16.16x' % (self.frame.GetPC()) stream = lldb.SBStream() self.frame.GetDescription(stream) summary = stream.GetData().split("`")[1] return { '#0': name, 'value': value, 'summary': summary, 'children': self.frame.GetVariables( True, True, True, True).GetSize() > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() variables = self.frame.GetVariables(True, True, True, True) n = variables.GetSize() for i in range(n): item_delegate = ValueTreeItemDelegate(variables[i]) item_dicts.append(item_delegate.get_item_dictionary()) return item_dicts class ThreadTreeItemDelegate(object): def __init__(self, thread): self.thread = thread def get_item_dictionary(self): num_frames = self.thread.GetNumFrames() name = 'thread #%u' % (self.thread.GetIndexID()) value = '0x%x' % (self.thread.GetThreadID()) summary = '%u frames' % (num_frames) return {'#0': name, 'value': value, 'summary': summary, 'children': num_frames > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() for frame in self.thread: item_delegate = FrameTreeItemDelegate(frame) item_dicts.append(item_delegate.get_item_dictionary()) return item_dicts class ProcessTreeItemDelegate(object): def __init__(self, process): self.process = process def get_item_dictionary(self): id = self.process.GetProcessID() num_threads = self.process.GetNumThreads() value = str(self.process.GetProcessID()) summary = self.process.target.executable.fullpath return {'#0': 'process', 'value': value, 'summary': summary, 'children': num_threads > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() for thread in self.process: item_delegate = ThreadTreeItemDelegate(thread) item_dicts.append(item_delegate.get_item_dictionary()) return item_dicts class TargetTreeItemDelegate(object): def __init__(self, target): self.target = target def get_item_dictionary(self): value = str(self.target.triple) summary = self.target.executable.fullpath return {'#0': 'target', 'value': value, 'summary': summary, 'children': True, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() image_item_delegate = TargetImagesTreeItemDelegate(self.target) item_dicts.append(image_item_delegate.get_item_dictionary()) return item_dicts class TargetImagesTreeItemDelegate(object): def __init__(self, target): self.target = target def get_item_dictionary(self): value = str(self.target.triple) summary = self.target.executable.fullpath num_modules = self.target.GetNumModules() return {'#0': 'images', 'value': '', 'summary': '%u images' % num_modules, 'children': num_modules > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() for i in range(self.target.GetNumModules()): module = self.target.GetModuleAtIndex(i) image_item_delegate = ModuleTreeItemDelegate( self.target, module, i) item_dicts.append(image_item_delegate.get_item_dictionary()) return item_dicts class ModuleTreeItemDelegate(object): def __init__(self, target, module, index): self.target = target self.module = module self.index = index def get_item_dictionary(self): name = 'module %u' % (self.index) value = self.module.file.basename summary = self.module.file.dirname return {'#0': name, 'value': value, 'summary': summary, 'children': True, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() sections_item_delegate = ModuleSectionsTreeItemDelegate( self.target, self.module) item_dicts.append(sections_item_delegate.get_item_dictionary()) symbols_item_delegate = ModuleSymbolsTreeItemDelegate( self.target, self.module) item_dicts.append(symbols_item_delegate.get_item_dictionary()) comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate( self.target, self.module) item_dicts.append(comp_units_item_delegate.get_item_dictionary()) return item_dicts class ModuleSectionsTreeItemDelegate(object): def __init__(self, target, module): self.target = target self.module = module def get_item_dictionary(self): name = 'sections' value = '' summary = '%u sections' % (self.module.GetNumSections()) return {'#0': name, 'value': value, 'summary': summary, 'children': True, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() num_sections = self.module.GetNumSections() for i in range(num_sections): section = self.module.GetSectionAtIndex(i) image_item_delegate = SectionTreeItemDelegate(self.target, section) item_dicts.append(image_item_delegate.get_item_dictionary()) return item_dicts class SectionTreeItemDelegate(object): def __init__(self, target, section): self.target = target self.section = section def get_item_dictionary(self): name = self.section.name section_load_addr = self.section.GetLoadAddress(self.target) if section_load_addr != lldb.LLDB_INVALID_ADDRESS: value = '0x%16.16x' % (section_load_addr) else: value = '0x%16.16x *' % (self.section.file_addr) summary = '' return {'#0': name, 'value': value, 'summary': summary, 'children': self.section.GetNumSubSections() > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() num_sections = self.section.GetNumSubSections() for i in range(num_sections): section = self.section.GetSubSectionAtIndex(i) image_item_delegate = SectionTreeItemDelegate(self.target, section) item_dicts.append(image_item_delegate.get_item_dictionary()) return item_dicts class ModuleCompileUnitsTreeItemDelegate(object): def __init__(self, target, module): self.target = target self.module = module def get_item_dictionary(self): name = 'compile units' value = '' summary = '%u compile units' % (self.module.GetNumSections()) return {'#0': name, 'value': value, 'summary': summary, 'children': self.module.GetNumCompileUnits() > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() num_cus = self.module.GetNumCompileUnits() for i in range(num_cus): cu = self.module.GetCompileUnitAtIndex(i) image_item_delegate = CompileUnitTreeItemDelegate(self.target, cu) item_dicts.append(image_item_delegate.get_item_dictionary()) return item_dicts class CompileUnitTreeItemDelegate(object): def __init__(self, target, cu): self.target = target self.cu = cu def get_item_dictionary(self): name = self.cu.GetFileSpec().basename value = '' num_lines = self.cu.GetNumLineEntries() summary = '' return {'#0': name, 'value': value, 'summary': summary, 'children': num_lines > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() item_delegate = LineTableTreeItemDelegate(self.target, self.cu) item_dicts.append(item_delegate.get_item_dictionary()) return item_dicts class LineTableTreeItemDelegate(object): def __init__(self, target, cu): self.target = target self.cu = cu def get_item_dictionary(self): name = 'line table' value = '' num_lines = self.cu.GetNumLineEntries() summary = '%u line entries' % (num_lines) return {'#0': name, 'value': value, 'summary': summary, 'children': num_lines > 0, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() num_lines = self.cu.GetNumLineEntries() for i in range(num_lines): line_entry = self.cu.GetLineEntryAtIndex(i) item_delegate = LineEntryTreeItemDelegate( self.target, line_entry, i) item_dicts.append(item_delegate.get_item_dictionary()) return item_dicts class LineEntryTreeItemDelegate(object): def __init__(self, target, line_entry, index): self.target = target self.line_entry = line_entry self.index = index def get_item_dictionary(self): name = str(self.index) address = self.line_entry.GetStartAddress() load_addr = address.GetLoadAddress(self.target) if load_addr != lldb.LLDB_INVALID_ADDRESS: value = '0x%16.16x' % (load_addr) else: value = '0x%16.16x *' % (address.file_addr) summary = self.line_entry.GetFileSpec().fullpath + ':' + \ str(self.line_entry.line) return {'#0': name, 'value': value, 'summary': summary, 'children': False, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() return item_dicts class InstructionTreeItemDelegate(object): def __init__(self, target, instr): self.target = target self.instr = instr def get_item_dictionary(self): address = self.instr.GetAddress() load_addr = address.GetLoadAddress(self.target) if load_addr != lldb.LLDB_INVALID_ADDRESS: name = '0x%16.16x' % (load_addr) else: name = '0x%16.16x *' % (address.file_addr) value = self.instr.GetMnemonic( self.target) + ' ' + self.instr.GetOperands(self.target) summary = self.instr.GetComment(self.target) return {'#0': name, 'value': value, 'summary': summary, 'children': False, 'tree-item-delegate': self} class ModuleSymbolsTreeItemDelegate(object): def __init__(self, target, module): self.target = target self.module = module def get_item_dictionary(self): name = 'symbols' value = '' summary = '%u symbols' % (self.module.GetNumSymbols()) return {'#0': name, 'value': value, 'summary': summary, 'children': True, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() num_symbols = self.module.GetNumSymbols() for i in range(num_symbols): symbol = self.module.GetSymbolAtIndex(i) image_item_delegate = SymbolTreeItemDelegate( self.target, symbol, i) item_dicts.append(image_item_delegate.get_item_dictionary()) return item_dicts class SymbolTreeItemDelegate(object): def __init__(self, target, symbol, index): self.target = target self.symbol = symbol self.index = index def get_item_dictionary(self): address = self.symbol.GetStartAddress() name = '[%u]' % self.index symbol_load_addr = address.GetLoadAddress(self.target) if symbol_load_addr != lldb.LLDB_INVALID_ADDRESS: value = '0x%16.16x' % (symbol_load_addr) else: value = '0x%16.16x *' % (address.file_addr) summary = self.symbol.name return {'#0': name, 'value': value, 'summary': summary, 'children': False, 'tree-item-delegate': self} def get_child_item_dictionaries(self): item_dicts = list() return item_dicts class DelegateTree(ttk.Frame): def __init__(self, column_dicts, delegate, title, name): ttk.Frame.__init__(self, name=name) self.pack(expand=Y, fill=BOTH) self.master.title(title) self.delegate = delegate self.columns_dicts = column_dicts self.item_id_to_item_dict = dict() frame = Frame(self) frame.pack(side=TOP, fill=BOTH, expand=Y) self._create_treeview(frame) self._populate_root() def _create_treeview(self, parent): frame = ttk.Frame(parent) frame.pack(side=TOP, fill=BOTH, expand=Y) column_ids = list() for i in range(1, len(self.columns_dicts)): column_ids.append(self.columns_dicts[i]['id']) # create the tree and scrollbars self.tree = ttk.Treeview(columns=column_ids) scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview) scroll_bar_h = ttk.Scrollbar( orient=HORIZONTAL, command=self.tree.xview) self.tree['yscroll'] = scroll_bar_v.set self.tree['xscroll'] = scroll_bar_h.set # setup column headings and columns properties for columns_dict in self.columns_dicts: self.tree.heading( columns_dict['id'], text=columns_dict['text'], anchor=columns_dict['anchor']) self.tree.column( columns_dict['id'], stretch=columns_dict['stretch']) # add tree and scrollbars to frame self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW) scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS) scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW) # set frame resizing priorities frame.rowconfigure(0, weight=1) frame.columnconfigure(0, weight=1) # action to perform when a node is expanded self.tree.bind('<>', self._update_tree) def insert_items(self, parent_id, item_dicts): for item_dict in item_dicts: name = None values = list() first = True for columns_dict in self.columns_dicts: if first: name = item_dict[columns_dict['id']] first = False else: values.append(item_dict[columns_dict['id']]) item_id = self.tree.insert(parent_id, # root item has an empty name END, text=name, values=values) self.item_id_to_item_dict[item_id] = item_dict if item_dict['children']: self.tree.insert(item_id, END, text='dummy') def _populate_root(self): # use current directory as root node self.insert_items('', self.delegate.get_child_item_dictionaries()) def _update_tree(self, event): # user expanded a node - build the related directory item_id = self.tree.focus() # the id of the expanded node children = self.tree.get_children(item_id) if len(children): first_child = children[0] # if the node only has a 'dummy' child, remove it and # build new directory; skip if the node is already # populated if self.tree.item(first_child, option='text') == 'dummy': self.tree.delete(first_child) item_dict = self.item_id_to_item_dict[item_id] item_dicts = item_dict[ 'tree-item-delegate'].get_child_item_dictionaries() self.insert_items(item_id, item_dicts) @lldb.command("tk-variables") def tk_variable_display(debugger, command, result, dict): # needed for tree creation in TK library as it uses sys.argv... sys.argv = ['tk-variables'] target = debugger.GetSelectedTarget() if not target: print("invalid target", file=result) return process = target.GetProcess() if not process: print("invalid process", file=result) return thread = process.GetSelectedThread() if not thread: print("invalid thread", file=result) return frame = thread.GetSelectedFrame() if not frame: print("invalid frame", file=result) return # Parse command line args command_args = shlex.split(command) column_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0}, {'id': 'typename', 'text': 'Type', 'anchor': W, 'stretch': 0}, {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0}, {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}] tree = DelegateTree( column_dicts, FrameTreeItemDelegate(frame), 'Variables', 'lldb-tk-variables') tree.mainloop() @lldb.command("tk-process") def tk_process_display(debugger, command, result, dict): # needed for tree creation in TK library as it uses sys.argv... sys.argv = ['tk-process'] target = debugger.GetSelectedTarget() if not target: print("invalid target", file=result) return process = target.GetProcess() if not process: print("invalid process", file=result) return # Parse command line args columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0}, {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0}, {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}] command_args = shlex.split(command) tree = DelegateTree( columnd_dicts, ProcessTreeItemDelegate(process), 'Process', 'lldb-tk-process') tree.mainloop() @lldb.command("tk-target") def tk_target_display(debugger, command, result, dict): # needed for tree creation in TK library as it uses sys.argv... sys.argv = ['tk-target'] target = debugger.GetSelectedTarget() if not target: print("invalid target", file=result) return # Parse command line args columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0}, {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0}, {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}] command_args = shlex.split(command) tree = DelegateTree( columnd_dicts, TargetTreeItemDelegate(target), 'Target', 'lldb-tk-target') tree.mainloop()