#!/usr/bin/env python
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, END, text=name, values=values # root item has an empty name
)
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()