You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
619 lines
20 KiB
619 lines
20 KiB
#!/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()
|