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