624 lines · python
1#!/usr/bin/env python2 3import lldb4import shlex5import sys6 7from tkinter import *8import tkinter.ttk as ttk9 10 11class ValueTreeItemDelegate(object):12 def __init__(self, value):13 self.value = value14 15 def get_item_dictionary(self):16 name = self.value.name17 if name is None:18 name = ""19 typename = self.value.type20 if typename is None:21 typename = ""22 value = self.value.value23 if value is None:24 value = ""25 summary = self.value.summary26 if summary is None:27 summary = ""28 has_children = self.value.MightHaveChildren()29 return {30 "#0": name,31 "typename": typename,32 "value": value,33 "summary": summary,34 "children": has_children,35 "tree-item-delegate": self,36 }37 38 def get_child_item_dictionaries(self):39 item_dicts = list()40 for i in range(self.value.num_children):41 item_delegate = ValueTreeItemDelegate(self.value.GetChildAtIndex(i))42 item_dicts.append(item_delegate.get_item_dictionary())43 return item_dicts44 45 46class FrameTreeItemDelegate(object):47 def __init__(self, frame):48 self.frame = frame49 50 def get_item_dictionary(self):51 id = self.frame.GetFrameID()52 name = "frame #%u" % (id)53 value = "0x%16.16x" % (self.frame.GetPC())54 stream = lldb.SBStream()55 self.frame.GetDescription(stream)56 summary = stream.GetData().split("`")[1]57 return {58 "#0": name,59 "value": value,60 "summary": summary,61 "children": self.frame.GetVariables(True, True, True, True).GetSize() > 0,62 "tree-item-delegate": self,63 }64 65 def get_child_item_dictionaries(self):66 item_dicts = list()67 variables = self.frame.GetVariables(True, True, True, True)68 n = variables.GetSize()69 for i in range(n):70 item_delegate = ValueTreeItemDelegate(variables[i])71 item_dicts.append(item_delegate.get_item_dictionary())72 return item_dicts73 74 75class ThreadTreeItemDelegate(object):76 def __init__(self, thread):77 self.thread = thread78 79 def get_item_dictionary(self):80 num_frames = self.thread.GetNumFrames()81 name = "thread #%u" % (self.thread.GetIndexID())82 value = "0x%x" % (self.thread.GetThreadID())83 summary = "%u frames" % (num_frames)84 return {85 "#0": name,86 "value": value,87 "summary": summary,88 "children": num_frames > 0,89 "tree-item-delegate": self,90 }91 92 def get_child_item_dictionaries(self):93 item_dicts = list()94 for frame in self.thread:95 item_delegate = FrameTreeItemDelegate(frame)96 item_dicts.append(item_delegate.get_item_dictionary())97 return item_dicts98 99 100class ProcessTreeItemDelegate(object):101 def __init__(self, process):102 self.process = process103 104 def get_item_dictionary(self):105 id = self.process.GetProcessID()106 num_threads = self.process.GetNumThreads()107 value = str(self.process.GetProcessID())108 summary = self.process.target.executable.fullpath109 return {110 "#0": "process",111 "value": value,112 "summary": summary,113 "children": num_threads > 0,114 "tree-item-delegate": self,115 }116 117 def get_child_item_dictionaries(self):118 item_dicts = list()119 for thread in self.process:120 item_delegate = ThreadTreeItemDelegate(thread)121 item_dicts.append(item_delegate.get_item_dictionary())122 return item_dicts123 124 125class TargetTreeItemDelegate(object):126 def __init__(self, target):127 self.target = target128 129 def get_item_dictionary(self):130 value = str(self.target.triple)131 summary = self.target.executable.fullpath132 return {133 "#0": "target",134 "value": value,135 "summary": summary,136 "children": True,137 "tree-item-delegate": self,138 }139 140 def get_child_item_dictionaries(self):141 item_dicts = list()142 image_item_delegate = TargetImagesTreeItemDelegate(self.target)143 item_dicts.append(image_item_delegate.get_item_dictionary())144 return item_dicts145 146 147class TargetImagesTreeItemDelegate(object):148 def __init__(self, target):149 self.target = target150 151 def get_item_dictionary(self):152 value = str(self.target.triple)153 summary = self.target.executable.fullpath154 num_modules = self.target.GetNumModules()155 return {156 "#0": "images",157 "value": "",158 "summary": "%u images" % num_modules,159 "children": num_modules > 0,160 "tree-item-delegate": self,161 }162 163 def get_child_item_dictionaries(self):164 item_dicts = list()165 for i in range(self.target.GetNumModules()):166 module = self.target.GetModuleAtIndex(i)167 image_item_delegate = ModuleTreeItemDelegate(self.target, module, i)168 item_dicts.append(image_item_delegate.get_item_dictionary())169 return item_dicts170 171 172class ModuleTreeItemDelegate(object):173 def __init__(self, target, module, index):174 self.target = target175 self.module = module176 self.index = index177 178 def get_item_dictionary(self):179 name = "module %u" % (self.index)180 value = self.module.file.basename181 summary = self.module.file.dirname182 return {183 "#0": name,184 "value": value,185 "summary": summary,186 "children": True,187 "tree-item-delegate": self,188 }189 190 def get_child_item_dictionaries(self):191 item_dicts = list()192 sections_item_delegate = ModuleSectionsTreeItemDelegate(193 self.target, self.module194 )195 item_dicts.append(sections_item_delegate.get_item_dictionary())196 197 symbols_item_delegate = ModuleSymbolsTreeItemDelegate(self.target, self.module)198 item_dicts.append(symbols_item_delegate.get_item_dictionary())199 200 comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(201 self.target, self.module202 )203 item_dicts.append(comp_units_item_delegate.get_item_dictionary())204 return item_dicts205 206 207class ModuleSectionsTreeItemDelegate(object):208 def __init__(self, target, module):209 self.target = target210 self.module = module211 212 def get_item_dictionary(self):213 name = "sections"214 value = ""215 summary = "%u sections" % (self.module.GetNumSections())216 return {217 "#0": name,218 "value": value,219 "summary": summary,220 "children": True,221 "tree-item-delegate": self,222 }223 224 def get_child_item_dictionaries(self):225 item_dicts = list()226 num_sections = self.module.GetNumSections()227 for i in range(num_sections):228 section = self.module.GetSectionAtIndex(i)229 image_item_delegate = SectionTreeItemDelegate(self.target, section)230 item_dicts.append(image_item_delegate.get_item_dictionary())231 return item_dicts232 233 234class SectionTreeItemDelegate(object):235 def __init__(self, target, section):236 self.target = target237 self.section = section238 239 def get_item_dictionary(self):240 name = self.section.name241 section_load_addr = self.section.GetLoadAddress(self.target)242 if section_load_addr != lldb.LLDB_INVALID_ADDRESS:243 value = "0x%16.16x" % (section_load_addr)244 else:245 value = "0x%16.16x *" % (self.section.file_addr)246 summary = ""247 return {248 "#0": name,249 "value": value,250 "summary": summary,251 "children": self.section.GetNumSubSections() > 0,252 "tree-item-delegate": self,253 }254 255 def get_child_item_dictionaries(self):256 item_dicts = list()257 num_sections = self.section.GetNumSubSections()258 for i in range(num_sections):259 section = self.section.GetSubSectionAtIndex(i)260 image_item_delegate = SectionTreeItemDelegate(self.target, section)261 item_dicts.append(image_item_delegate.get_item_dictionary())262 return item_dicts263 264 265class ModuleCompileUnitsTreeItemDelegate(object):266 def __init__(self, target, module):267 self.target = target268 self.module = module269 270 def get_item_dictionary(self):271 name = "compile units"272 value = ""273 summary = "%u compile units" % (self.module.GetNumSections())274 return {275 "#0": name,276 "value": value,277 "summary": summary,278 "children": self.module.GetNumCompileUnits() > 0,279 "tree-item-delegate": self,280 }281 282 def get_child_item_dictionaries(self):283 item_dicts = list()284 num_cus = self.module.GetNumCompileUnits()285 for i in range(num_cus):286 cu = self.module.GetCompileUnitAtIndex(i)287 image_item_delegate = CompileUnitTreeItemDelegate(self.target, cu)288 item_dicts.append(image_item_delegate.get_item_dictionary())289 return item_dicts290 291 292class CompileUnitTreeItemDelegate(object):293 def __init__(self, target, cu):294 self.target = target295 self.cu = cu296 297 def get_item_dictionary(self):298 name = self.cu.GetFileSpec().basename299 value = ""300 num_lines = self.cu.GetNumLineEntries()301 summary = ""302 return {303 "#0": name,304 "value": value,305 "summary": summary,306 "children": num_lines > 0,307 "tree-item-delegate": self,308 }309 310 def get_child_item_dictionaries(self):311 item_dicts = list()312 item_delegate = LineTableTreeItemDelegate(self.target, self.cu)313 item_dicts.append(item_delegate.get_item_dictionary())314 return item_dicts315 316 317class LineTableTreeItemDelegate(object):318 def __init__(self, target, cu):319 self.target = target320 self.cu = cu321 322 def get_item_dictionary(self):323 name = "line table"324 value = ""325 num_lines = self.cu.GetNumLineEntries()326 summary = "%u line entries" % (num_lines)327 return {328 "#0": name,329 "value": value,330 "summary": summary,331 "children": num_lines > 0,332 "tree-item-delegate": self,333 }334 335 def get_child_item_dictionaries(self):336 item_dicts = list()337 num_lines = self.cu.GetNumLineEntries()338 for i in range(num_lines):339 line_entry = self.cu.GetLineEntryAtIndex(i)340 item_delegate = LineEntryTreeItemDelegate(self.target, line_entry, i)341 item_dicts.append(item_delegate.get_item_dictionary())342 return item_dicts343 344 345class LineEntryTreeItemDelegate(object):346 def __init__(self, target, line_entry, index):347 self.target = target348 self.line_entry = line_entry349 self.index = index350 351 def get_item_dictionary(self):352 name = str(self.index)353 address = self.line_entry.GetStartAddress()354 load_addr = address.GetLoadAddress(self.target)355 if load_addr != lldb.LLDB_INVALID_ADDRESS:356 value = "0x%16.16x" % (load_addr)357 else:358 value = "0x%16.16x *" % (address.file_addr)359 summary = (360 self.line_entry.GetFileSpec().fullpath + ":" + str(self.line_entry.line)361 )362 return {363 "#0": name,364 "value": value,365 "summary": summary,366 "children": False,367 "tree-item-delegate": self,368 }369 370 def get_child_item_dictionaries(self):371 item_dicts = list()372 return item_dicts373 374 375class InstructionTreeItemDelegate(object):376 def __init__(self, target, instr):377 self.target = target378 self.instr = instr379 380 def get_item_dictionary(self):381 address = self.instr.GetAddress()382 load_addr = address.GetLoadAddress(self.target)383 if load_addr != lldb.LLDB_INVALID_ADDRESS:384 name = "0x%16.16x" % (load_addr)385 else:386 name = "0x%16.16x *" % (address.file_addr)387 value = (388 self.instr.GetMnemonic(self.target)389 + " "390 + self.instr.GetOperands(self.target)391 )392 summary = self.instr.GetComment(self.target)393 return {394 "#0": name,395 "value": value,396 "summary": summary,397 "children": False,398 "tree-item-delegate": self,399 }400 401 402class ModuleSymbolsTreeItemDelegate(object):403 def __init__(self, target, module):404 self.target = target405 self.module = module406 407 def get_item_dictionary(self):408 name = "symbols"409 value = ""410 summary = "%u symbols" % (self.module.GetNumSymbols())411 return {412 "#0": name,413 "value": value,414 "summary": summary,415 "children": True,416 "tree-item-delegate": self,417 }418 419 def get_child_item_dictionaries(self):420 item_dicts = list()421 num_symbols = self.module.GetNumSymbols()422 for i in range(num_symbols):423 symbol = self.module.GetSymbolAtIndex(i)424 image_item_delegate = SymbolTreeItemDelegate(self.target, symbol, i)425 item_dicts.append(image_item_delegate.get_item_dictionary())426 return item_dicts427 428 429class SymbolTreeItemDelegate(object):430 def __init__(self, target, symbol, index):431 self.target = target432 self.symbol = symbol433 self.index = index434 435 def get_item_dictionary(self):436 address = self.symbol.GetStartAddress()437 name = "[%u]" % self.index438 symbol_load_addr = address.GetLoadAddress(self.target)439 if symbol_load_addr != lldb.LLDB_INVALID_ADDRESS:440 value = "0x%16.16x" % (symbol_load_addr)441 else:442 value = "0x%16.16x *" % (address.file_addr)443 summary = self.symbol.name444 return {445 "#0": name,446 "value": value,447 "summary": summary,448 "children": False,449 "tree-item-delegate": self,450 }451 452 def get_child_item_dictionaries(self):453 item_dicts = list()454 return item_dicts455 456 457class DelegateTree(ttk.Frame):458 def __init__(self, column_dicts, delegate, title, name):459 ttk.Frame.__init__(self, name=name)460 self.pack(expand=Y, fill=BOTH)461 self.master.title(title)462 self.delegate = delegate463 self.columns_dicts = column_dicts464 self.item_id_to_item_dict = dict()465 frame = Frame(self)466 frame.pack(side=TOP, fill=BOTH, expand=Y)467 self._create_treeview(frame)468 self._populate_root()469 470 def _create_treeview(self, parent):471 frame = ttk.Frame(parent)472 frame.pack(side=TOP, fill=BOTH, expand=Y)473 474 column_ids = list()475 for i in range(1, len(self.columns_dicts)):476 column_ids.append(self.columns_dicts[i]["id"])477 # create the tree and scrollbars478 self.tree = ttk.Treeview(columns=column_ids)479 480 scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview)481 scroll_bar_h = ttk.Scrollbar(orient=HORIZONTAL, command=self.tree.xview)482 self.tree["yscroll"] = scroll_bar_v.set483 self.tree["xscroll"] = scroll_bar_h.set484 485 # setup column headings and columns properties486 for columns_dict in self.columns_dicts:487 self.tree.heading(488 columns_dict["id"],489 text=columns_dict["text"],490 anchor=columns_dict["anchor"],491 )492 self.tree.column(columns_dict["id"], stretch=columns_dict["stretch"])493 494 # add tree and scrollbars to frame495 self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)496 scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)497 scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)498 499 # set frame resizing priorities500 frame.rowconfigure(0, weight=1)501 frame.columnconfigure(0, weight=1)502 503 # action to perform when a node is expanded504 self.tree.bind("<<TreeviewOpen>>", self._update_tree)505 506 def insert_items(self, parent_id, item_dicts):507 for item_dict in item_dicts:508 name = None509 values = list()510 first = True511 for columns_dict in self.columns_dicts:512 if first:513 name = item_dict[columns_dict["id"]]514 first = False515 else:516 values.append(item_dict[columns_dict["id"]])517 item_id = self.tree.insert(518 parent_id, END, text=name, values=values # root item has an empty name519 )520 self.item_id_to_item_dict[item_id] = item_dict521 if item_dict["children"]:522 self.tree.insert(item_id, END, text="dummy")523 524 def _populate_root(self):525 # use current directory as root node526 self.insert_items("", self.delegate.get_child_item_dictionaries())527 528 def _update_tree(self, event):529 # user expanded a node - build the related directory530 item_id = self.tree.focus() # the id of the expanded node531 children = self.tree.get_children(item_id)532 if len(children):533 first_child = children[0]534 # if the node only has a 'dummy' child, remove it and535 # build new directory; skip if the node is already536 # populated537 if self.tree.item(first_child, option="text") == "dummy":538 self.tree.delete(first_child)539 item_dict = self.item_id_to_item_dict[item_id]540 item_dicts = item_dict[541 "tree-item-delegate"542 ].get_child_item_dictionaries()543 self.insert_items(item_id, item_dicts)544 545 546@lldb.command("tk-variables")547def tk_variable_display(debugger, command, result, dict):548 # needed for tree creation in TK library as it uses sys.argv...549 sys.argv = ["tk-variables"]550 target = debugger.GetSelectedTarget()551 if not target:552 print("invalid target", file=result)553 return554 process = target.GetProcess()555 if not process:556 print("invalid process", file=result)557 return558 thread = process.GetSelectedThread()559 if not thread:560 print("invalid thread", file=result)561 return562 frame = thread.GetSelectedFrame()563 if not frame:564 print("invalid frame", file=result)565 return566 # Parse command line args567 command_args = shlex.split(command)568 column_dicts = [569 {"id": "#0", "text": "Name", "anchor": W, "stretch": 0},570 {"id": "typename", "text": "Type", "anchor": W, "stretch": 0},571 {"id": "value", "text": "Value", "anchor": W, "stretch": 0},572 {"id": "summary", "text": "Summary", "anchor": W, "stretch": 1},573 ]574 tree = DelegateTree(575 column_dicts, FrameTreeItemDelegate(frame), "Variables", "lldb-tk-variables"576 )577 tree.mainloop()578 579 580@lldb.command("tk-process")581def tk_process_display(debugger, command, result, dict):582 # needed for tree creation in TK library as it uses sys.argv...583 sys.argv = ["tk-process"]584 target = debugger.GetSelectedTarget()585 if not target:586 print("invalid target", file=result)587 return588 process = target.GetProcess()589 if not process:590 print("invalid process", file=result)591 return592 # Parse command line args593 columnd_dicts = [594 {"id": "#0", "text": "Name", "anchor": W, "stretch": 0},595 {"id": "value", "text": "Value", "anchor": W, "stretch": 0},596 {"id": "summary", "text": "Summary", "anchor": W, "stretch": 1},597 ]598 command_args = shlex.split(command)599 tree = DelegateTree(600 columnd_dicts, ProcessTreeItemDelegate(process), "Process", "lldb-tk-process"601 )602 tree.mainloop()603 604 605@lldb.command("tk-target")606def tk_target_display(debugger, command, result, dict):607 # needed for tree creation in TK library as it uses sys.argv...608 sys.argv = ["tk-target"]609 target = debugger.GetSelectedTarget()610 if not target:611 print("invalid target", file=result)612 return613 # Parse command line args614 columnd_dicts = [615 {"id": "#0", "text": "Name", "anchor": W, "stretch": 0},616 {"id": "value", "text": "Value", "anchor": W, "stretch": 0},617 {"id": "summary", "text": "Summary", "anchor": W, "stretch": 1},618 ]619 command_args = shlex.split(command)620 tree = DelegateTree(621 columnd_dicts, TargetTreeItemDelegate(target), "Target", "lldb-tk-target"622 )623 tree.mainloop()624