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