| #!/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('<<TreeviewOpen>>', 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() |