1be691f3bSpatrick#!/usr/bin/env python 2061da546Spatrick 3061da546Spatrick#---------------------------------------------------------------------- 4061da546Spatrick# Be sure to add the python path that points to the LLDB shared library. 5061da546Spatrick# 6061da546Spatrick# To use this in the embedded python interpreter using "lldb": 7061da546Spatrick# 8061da546Spatrick# cd /path/containing/crashlog.py 9061da546Spatrick# lldb 10061da546Spatrick# (lldb) script import crashlog 11061da546Spatrick# "crashlog" command installed, type "crashlog --help" for detailed help 12061da546Spatrick# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash 13061da546Spatrick# 14061da546Spatrick# The benefit of running the crashlog command inside lldb in the 15061da546Spatrick# embedded python interpreter is when the command completes, there 16061da546Spatrick# will be a target with all of the files loaded at the locations 17061da546Spatrick# described in the crash log. Only the files that have stack frames 18061da546Spatrick# in the backtrace will be loaded unless the "--load-all" option 19061da546Spatrick# has been specified. This allows users to explore the program in the 20061da546Spatrick# state it was in right at crash time. 21061da546Spatrick# 22061da546Spatrick# On MacOSX csh, tcsh: 23061da546Spatrick# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) 24061da546Spatrick# 25061da546Spatrick# On MacOSX sh, bash: 26061da546Spatrick# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash 27061da546Spatrick#---------------------------------------------------------------------- 28061da546Spatrick 29061da546Spatrickimport lldb 30061da546Spatrickimport optparse 31061da546Spatrickimport os 32061da546Spatrickimport plistlib 33061da546Spatrickimport re 34061da546Spatrickimport shlex 35061da546Spatrickimport sys 36061da546Spatrickimport time 37061da546Spatrickimport uuid 38061da546Spatrick 39061da546Spatrick 40061da546Spatrickclass Address: 41061da546Spatrick """Class that represents an address that will be symbolicated""" 42061da546Spatrick 43061da546Spatrick def __init__(self, target, load_addr): 44061da546Spatrick self.target = target 45061da546Spatrick self.load_addr = load_addr # The load address that this object represents 46061da546Spatrick # the resolved lldb.SBAddress (if any), named so_addr for 47061da546Spatrick # section/offset address 48061da546Spatrick self.so_addr = None 49061da546Spatrick self.sym_ctx = None # The cached symbol context for this address 50061da546Spatrick # Any original textual description of this address to be used as a 51061da546Spatrick # backup in case symbolication fails 52061da546Spatrick self.description = None 53061da546Spatrick self.symbolication = None # The cached symbolicated string that describes this address 54061da546Spatrick self.inlined = False 55061da546Spatrick 56061da546Spatrick def __str__(self): 57061da546Spatrick s = "%#16.16x" % (self.load_addr) 58061da546Spatrick if self.symbolication: 59061da546Spatrick s += " %s" % (self.symbolication) 60061da546Spatrick elif self.description: 61061da546Spatrick s += " %s" % (self.description) 62061da546Spatrick elif self.so_addr: 63061da546Spatrick s += " %s" % (self.so_addr) 64061da546Spatrick return s 65061da546Spatrick 66061da546Spatrick def resolve_addr(self): 67061da546Spatrick if self.so_addr is None: 68061da546Spatrick self.so_addr = self.target.ResolveLoadAddress(self.load_addr) 69061da546Spatrick return self.so_addr 70061da546Spatrick 71061da546Spatrick def is_inlined(self): 72061da546Spatrick return self.inlined 73061da546Spatrick 74061da546Spatrick def get_symbol_context(self): 75061da546Spatrick if self.sym_ctx is None: 76061da546Spatrick sb_addr = self.resolve_addr() 77061da546Spatrick if sb_addr: 78061da546Spatrick self.sym_ctx = self.target.ResolveSymbolContextForAddress( 79061da546Spatrick sb_addr, lldb.eSymbolContextEverything) 80061da546Spatrick else: 81061da546Spatrick self.sym_ctx = lldb.SBSymbolContext() 82061da546Spatrick return self.sym_ctx 83061da546Spatrick 84061da546Spatrick def get_instructions(self): 85061da546Spatrick sym_ctx = self.get_symbol_context() 86061da546Spatrick if sym_ctx: 87061da546Spatrick function = sym_ctx.GetFunction() 88061da546Spatrick if function: 89061da546Spatrick return function.GetInstructions(self.target) 90061da546Spatrick return sym_ctx.GetSymbol().GetInstructions(self.target) 91061da546Spatrick return None 92061da546Spatrick 93061da546Spatrick def symbolicate(self, verbose=False): 94061da546Spatrick if self.symbolication is None: 95061da546Spatrick self.symbolication = '' 96061da546Spatrick self.inlined = False 97061da546Spatrick sym_ctx = self.get_symbol_context() 98061da546Spatrick if sym_ctx: 99061da546Spatrick module = sym_ctx.GetModule() 100061da546Spatrick if module: 101061da546Spatrick # Print full source file path in verbose mode 102061da546Spatrick if verbose: 103061da546Spatrick self.symbolication += str(module.GetFileSpec()) + '`' 104061da546Spatrick else: 105061da546Spatrick self.symbolication += module.GetFileSpec().GetFilename() + '`' 106061da546Spatrick function_start_load_addr = -1 107061da546Spatrick function = sym_ctx.GetFunction() 108061da546Spatrick block = sym_ctx.GetBlock() 109061da546Spatrick line_entry = sym_ctx.GetLineEntry() 110061da546Spatrick symbol = sym_ctx.GetSymbol() 111061da546Spatrick inlined_block = block.GetContainingInlinedBlock() 112061da546Spatrick if function: 113061da546Spatrick self.symbolication += function.GetName() 114061da546Spatrick 115061da546Spatrick if inlined_block: 116061da546Spatrick self.inlined = True 117061da546Spatrick self.symbolication += ' [inlined] ' + \ 118061da546Spatrick inlined_block.GetInlinedName() 119061da546Spatrick block_range_idx = inlined_block.GetRangeIndexForBlockAddress( 120061da546Spatrick self.so_addr) 121061da546Spatrick if block_range_idx < lldb.UINT32_MAX: 122061da546Spatrick block_range_start_addr = inlined_block.GetRangeStartAddress( 123061da546Spatrick block_range_idx) 124061da546Spatrick function_start_load_addr = block_range_start_addr.GetLoadAddress( 125061da546Spatrick self.target) 126061da546Spatrick if function_start_load_addr == -1: 127061da546Spatrick function_start_load_addr = function.GetStartAddress().GetLoadAddress(self.target) 128061da546Spatrick elif symbol: 129061da546Spatrick self.symbolication += symbol.GetName() 130061da546Spatrick function_start_load_addr = symbol.GetStartAddress().GetLoadAddress(self.target) 131061da546Spatrick else: 132061da546Spatrick self.symbolication = '' 133061da546Spatrick return False 134061da546Spatrick 135061da546Spatrick # Dump the offset from the current function or symbol if it 136061da546Spatrick # is non zero 137061da546Spatrick function_offset = self.load_addr - function_start_load_addr 138061da546Spatrick if function_offset > 0: 139061da546Spatrick self.symbolication += " + %u" % (function_offset) 140061da546Spatrick elif function_offset < 0: 141061da546Spatrick self.symbolication += " %i (invalid negative offset, file a bug) " % function_offset 142061da546Spatrick 143061da546Spatrick # Print out any line information if any is available 144061da546Spatrick if line_entry.GetFileSpec(): 145061da546Spatrick # Print full source file path in verbose mode 146061da546Spatrick if verbose: 147061da546Spatrick self.symbolication += ' at %s' % line_entry.GetFileSpec() 148061da546Spatrick else: 149061da546Spatrick self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename() 150061da546Spatrick self.symbolication += ':%u' % line_entry.GetLine() 151061da546Spatrick column = line_entry.GetColumn() 152061da546Spatrick if column > 0: 153061da546Spatrick self.symbolication += ':%u' % column 154061da546Spatrick return True 155061da546Spatrick return False 156061da546Spatrick 157061da546Spatrick 158061da546Spatrickclass Section: 159061da546Spatrick """Class that represents an load address range""" 160061da546Spatrick sect_info_regex = re.compile('(?P<name>[^=]+)=(?P<range>.*)') 161061da546Spatrick addr_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*$') 162061da546Spatrick range_regex = re.compile( 163061da546Spatrick '^\s*(?P<start>0x[0-9A-Fa-f]+)\s*(?P<op>[-+])\s*(?P<end>0x[0-9A-Fa-f]+)\s*$') 164061da546Spatrick 165061da546Spatrick def __init__(self, start_addr=None, end_addr=None, name=None): 166061da546Spatrick self.start_addr = start_addr 167061da546Spatrick self.end_addr = end_addr 168061da546Spatrick self.name = name 169061da546Spatrick 170061da546Spatrick @classmethod 171061da546Spatrick def InitWithSBTargetAndSBSection(cls, target, section): 172061da546Spatrick sect_load_addr = section.GetLoadAddress(target) 173061da546Spatrick if sect_load_addr != lldb.LLDB_INVALID_ADDRESS: 174061da546Spatrick obj = cls( 175061da546Spatrick sect_load_addr, 176061da546Spatrick sect_load_addr + 177061da546Spatrick section.size, 178061da546Spatrick section.name) 179061da546Spatrick return obj 180061da546Spatrick else: 181061da546Spatrick return None 182061da546Spatrick 183061da546Spatrick def contains(self, addr): 184061da546Spatrick return self.start_addr <= addr and addr < self.end_addr 185061da546Spatrick 186061da546Spatrick def set_from_string(self, s): 187061da546Spatrick match = self.sect_info_regex.match(s) 188061da546Spatrick if match: 189061da546Spatrick self.name = match.group('name') 190061da546Spatrick range_str = match.group('range') 191061da546Spatrick addr_match = self.addr_regex.match(range_str) 192061da546Spatrick if addr_match: 193061da546Spatrick self.start_addr = int(addr_match.group('start'), 16) 194061da546Spatrick self.end_addr = None 195061da546Spatrick return True 196061da546Spatrick 197061da546Spatrick range_match = self.range_regex.match(range_str) 198061da546Spatrick if range_match: 199061da546Spatrick self.start_addr = int(range_match.group('start'), 16) 200061da546Spatrick self.end_addr = int(range_match.group('end'), 16) 201061da546Spatrick op = range_match.group('op') 202061da546Spatrick if op == '+': 203061da546Spatrick self.end_addr += self.start_addr 204061da546Spatrick return True 205061da546Spatrick print('error: invalid section info string "%s"' % s) 206061da546Spatrick print('Valid section info formats are:') 207061da546Spatrick print('Format Example Description') 208061da546Spatrick print('--------------------- -----------------------------------------------') 209061da546Spatrick print('<name>=<base> __TEXT=0x123000 Section from base address only') 210061da546Spatrick print('<name>=<base>-<end> __TEXT=0x123000-0x124000 Section from base address and end address') 211061da546Spatrick print('<name>=<base>+<size> __TEXT=0x123000+0x1000 Section from base address and size') 212061da546Spatrick return False 213061da546Spatrick 214061da546Spatrick def __str__(self): 215061da546Spatrick if self.name: 216061da546Spatrick if self.end_addr is not None: 217061da546Spatrick if self.start_addr is not None: 218061da546Spatrick return "%s=[0x%16.16x - 0x%16.16x)" % ( 219061da546Spatrick self.name, self.start_addr, self.end_addr) 220061da546Spatrick else: 221061da546Spatrick if self.start_addr is not None: 222061da546Spatrick return "%s=0x%16.16x" % (self.name, self.start_addr) 223061da546Spatrick return self.name 224061da546Spatrick return "<invalid>" 225061da546Spatrick 226061da546Spatrick 227061da546Spatrickclass Image: 228061da546Spatrick """A class that represents an executable image and any associated data""" 229061da546Spatrick 230061da546Spatrick def __init__(self, path, uuid=None): 231061da546Spatrick self.path = path 232061da546Spatrick self.resolved_path = None 233061da546Spatrick self.resolved = False 234061da546Spatrick self.unavailable = False 235061da546Spatrick self.uuid = uuid 236061da546Spatrick self.section_infos = list() 237061da546Spatrick self.identifier = None 238061da546Spatrick self.version = None 239061da546Spatrick self.arch = None 240061da546Spatrick self.module = None 241061da546Spatrick self.symfile = None 242061da546Spatrick self.slide = None 243061da546Spatrick 244061da546Spatrick @classmethod 245061da546Spatrick def InitWithSBTargetAndSBModule(cls, target, module): 246061da546Spatrick '''Initialize this Image object with a module from a target.''' 247061da546Spatrick obj = cls(module.file.fullpath, module.uuid) 248061da546Spatrick obj.resolved_path = module.platform_file.fullpath 249061da546Spatrick obj.resolved = True 250061da546Spatrick for section in module.sections: 251061da546Spatrick symb_section = Section.InitWithSBTargetAndSBSection( 252061da546Spatrick target, section) 253061da546Spatrick if symb_section: 254061da546Spatrick obj.section_infos.append(symb_section) 255061da546Spatrick obj.arch = module.triple 256061da546Spatrick obj.module = module 257061da546Spatrick obj.symfile = None 258061da546Spatrick obj.slide = None 259061da546Spatrick return obj 260061da546Spatrick 261061da546Spatrick def dump(self, prefix): 262061da546Spatrick print("%s%s" % (prefix, self)) 263061da546Spatrick 264061da546Spatrick def debug_dump(self): 265061da546Spatrick print('path = "%s"' % (self.path)) 266061da546Spatrick print('resolved_path = "%s"' % (self.resolved_path)) 267061da546Spatrick print('resolved = %i' % (self.resolved)) 268061da546Spatrick print('unavailable = %i' % (self.unavailable)) 269061da546Spatrick print('uuid = %s' % (self.uuid)) 270061da546Spatrick print('section_infos = %s' % (self.section_infos)) 271061da546Spatrick print('identifier = "%s"' % (self.identifier)) 272061da546Spatrick print('version = %s' % (self.version)) 273061da546Spatrick print('arch = %s' % (self.arch)) 274061da546Spatrick print('module = %s' % (self.module)) 275061da546Spatrick print('symfile = "%s"' % (self.symfile)) 276061da546Spatrick print('slide = %i (0x%x)' % (self.slide, self.slide)) 277061da546Spatrick 278061da546Spatrick def __str__(self): 279061da546Spatrick s = '' 280061da546Spatrick if self.uuid: 281061da546Spatrick s += "%s " % (self.get_uuid()) 282061da546Spatrick if self.arch: 283061da546Spatrick s += "%s " % (self.arch) 284061da546Spatrick if self.version: 285061da546Spatrick s += "%s " % (self.version) 286061da546Spatrick resolved_path = self.get_resolved_path() 287061da546Spatrick if resolved_path: 288061da546Spatrick s += "%s " % (resolved_path) 289061da546Spatrick for section_info in self.section_infos: 290061da546Spatrick s += ", %s" % (section_info) 291061da546Spatrick if self.slide is not None: 292061da546Spatrick s += ', slide = 0x%16.16x' % self.slide 293061da546Spatrick return s 294061da546Spatrick 295061da546Spatrick def add_section(self, section): 296061da546Spatrick # print "added '%s' to '%s'" % (section, self.path) 297061da546Spatrick self.section_infos.append(section) 298061da546Spatrick 299061da546Spatrick def get_section_containing_load_addr(self, load_addr): 300061da546Spatrick for section_info in self.section_infos: 301061da546Spatrick if section_info.contains(load_addr): 302061da546Spatrick return section_info 303061da546Spatrick return None 304061da546Spatrick 305061da546Spatrick def get_resolved_path(self): 306061da546Spatrick if self.resolved_path: 307061da546Spatrick return self.resolved_path 308061da546Spatrick elif self.path: 309061da546Spatrick return self.path 310061da546Spatrick return None 311061da546Spatrick 312061da546Spatrick def get_resolved_path_basename(self): 313061da546Spatrick path = self.get_resolved_path() 314061da546Spatrick if path: 315061da546Spatrick return os.path.basename(path) 316061da546Spatrick return None 317061da546Spatrick 318061da546Spatrick def symfile_basename(self): 319061da546Spatrick if self.symfile: 320061da546Spatrick return os.path.basename(self.symfile) 321061da546Spatrick return None 322061da546Spatrick 323061da546Spatrick def has_section_load_info(self): 324061da546Spatrick return self.section_infos or self.slide is not None 325061da546Spatrick 326061da546Spatrick def load_module(self, target): 327061da546Spatrick if self.unavailable: 328061da546Spatrick return None # We already warned that we couldn't find this module, so don't return an error string 329061da546Spatrick # Load this module into "target" using the section infos to 330061da546Spatrick # set the section load addresses 331061da546Spatrick if self.has_section_load_info(): 332061da546Spatrick if target: 333061da546Spatrick if self.module: 334061da546Spatrick if self.section_infos: 335061da546Spatrick num_sections_loaded = 0 336061da546Spatrick for section_info in self.section_infos: 337061da546Spatrick if section_info.name: 338061da546Spatrick section = self.module.FindSection( 339061da546Spatrick section_info.name) 340061da546Spatrick if section: 341061da546Spatrick error = target.SetSectionLoadAddress( 342061da546Spatrick section, section_info.start_addr) 343061da546Spatrick if error.Success(): 344061da546Spatrick num_sections_loaded += 1 345061da546Spatrick else: 346061da546Spatrick return 'error: %s' % error.GetCString() 347061da546Spatrick else: 348061da546Spatrick return 'error: unable to find the section named "%s"' % section_info.name 349061da546Spatrick else: 350061da546Spatrick return 'error: unable to find "%s" section in "%s"' % ( 351061da546Spatrick range.name, self.get_resolved_path()) 352061da546Spatrick if num_sections_loaded == 0: 353061da546Spatrick return 'error: no sections were successfully loaded' 354061da546Spatrick else: 355061da546Spatrick err = target.SetModuleLoadAddress( 356061da546Spatrick self.module, self.slide) 357061da546Spatrick if err.Fail(): 358061da546Spatrick return err.GetCString() 359061da546Spatrick return None 360061da546Spatrick else: 361061da546Spatrick return 'error: invalid module' 362061da546Spatrick else: 363061da546Spatrick return 'error: invalid target' 364061da546Spatrick else: 365061da546Spatrick return 'error: no section infos' 366061da546Spatrick 367061da546Spatrick def add_module(self, target): 368061da546Spatrick '''Add the Image described in this object to "target" and load the sections if "load" is True.''' 369061da546Spatrick if target: 370061da546Spatrick # Try and find using UUID only first so that paths need not match 371061da546Spatrick # up 372061da546Spatrick uuid_str = self.get_normalized_uuid_string() 373061da546Spatrick if uuid_str: 374061da546Spatrick self.module = target.AddModule(None, None, uuid_str) 375061da546Spatrick if not self.module: 376061da546Spatrick self.locate_module_and_debug_symbols() 377061da546Spatrick if self.unavailable: 378061da546Spatrick return None 379061da546Spatrick resolved_path = self.get_resolved_path() 380061da546Spatrick self.module = target.AddModule( 381*f6aab3d8Srobert resolved_path, None, uuid_str, self.symfile) 382061da546Spatrick if not self.module: 383061da546Spatrick return 'error: unable to get module for (%s) "%s"' % ( 384061da546Spatrick self.arch, self.get_resolved_path()) 385061da546Spatrick if self.has_section_load_info(): 386061da546Spatrick return self.load_module(target) 387061da546Spatrick else: 388061da546Spatrick return None # No sections, the module was added to the target, so success 389061da546Spatrick else: 390061da546Spatrick return 'error: invalid target' 391061da546Spatrick 392061da546Spatrick def locate_module_and_debug_symbols(self): 393061da546Spatrick # By default, just use the paths that were supplied in: 394061da546Spatrick # self.path 395061da546Spatrick # self.resolved_path 396061da546Spatrick # self.module 397061da546Spatrick # self.symfile 398061da546Spatrick # Subclasses can inherit from this class and override this function 399061da546Spatrick self.resolved = True 400061da546Spatrick return True 401061da546Spatrick 402061da546Spatrick def get_uuid(self): 403061da546Spatrick if not self.uuid and self.module: 404061da546Spatrick self.uuid = uuid.UUID(self.module.GetUUIDString()) 405061da546Spatrick return self.uuid 406061da546Spatrick 407061da546Spatrick def get_normalized_uuid_string(self): 408061da546Spatrick if self.uuid: 409061da546Spatrick return str(self.uuid).upper() 410061da546Spatrick return None 411061da546Spatrick 412be691f3bSpatrick def create_target(self, debugger): 413061da546Spatrick '''Create a target using the information in this Image object.''' 414061da546Spatrick if self.unavailable: 415061da546Spatrick return None 416061da546Spatrick 417061da546Spatrick if self.locate_module_and_debug_symbols(): 418061da546Spatrick resolved_path = self.get_resolved_path() 419061da546Spatrick path_spec = lldb.SBFileSpec(resolved_path) 420061da546Spatrick error = lldb.SBError() 421be691f3bSpatrick target = debugger.CreateTarget( 422061da546Spatrick resolved_path, self.arch, None, False, error) 423061da546Spatrick if target: 424061da546Spatrick self.module = target.FindModule(path_spec) 425061da546Spatrick if self.has_section_load_info(): 426061da546Spatrick err = self.load_module(target) 427061da546Spatrick if err: 428061da546Spatrick print('ERROR: ', err) 429061da546Spatrick return target 430061da546Spatrick else: 431061da546Spatrick print('error: unable to create a valid target for (%s) "%s"' % (self.arch, self.path)) 432061da546Spatrick else: 433061da546Spatrick print('error: unable to locate main executable (%s) "%s"' % (self.arch, self.path)) 434061da546Spatrick return None 435061da546Spatrick 436061da546Spatrick 437061da546Spatrickclass Symbolicator: 438061da546Spatrick 439be691f3bSpatrick def __init__(self, debugger=None, target=None, images=list()): 440be691f3bSpatrick """A class the represents the information needed to symbolicate 441be691f3bSpatrick addresses in a program. 442be691f3bSpatrick 443be691f3bSpatrick Do not call this initializer directly, but rather use the factory 444be691f3bSpatrick methods. 445be691f3bSpatrick """ 446be691f3bSpatrick self.debugger = debugger 447be691f3bSpatrick self.target = target 448be691f3bSpatrick self.images = images # a list of images to be used when symbolicating 449061da546Spatrick self.addr_mask = 0xffffffffffffffff 450061da546Spatrick 451061da546Spatrick @classmethod 452061da546Spatrick def InitWithSBTarget(cls, target): 453be691f3bSpatrick """Initialize a new Symbolicator with an existing SBTarget.""" 454be691f3bSpatrick obj = cls(target=target) 455061da546Spatrick triple = target.triple 456061da546Spatrick if triple: 457061da546Spatrick arch = triple.split('-')[0] 458061da546Spatrick if "arm" in arch: 459061da546Spatrick obj.addr_mask = 0xfffffffffffffffe 460061da546Spatrick 461061da546Spatrick for module in target.modules: 462061da546Spatrick image = Image.InitWithSBTargetAndSBModule(target, module) 463061da546Spatrick obj.images.append(image) 464061da546Spatrick return obj 465061da546Spatrick 466be691f3bSpatrick @classmethod 467be691f3bSpatrick def InitWithSBDebugger(cls, debugger, images): 468be691f3bSpatrick """Initialize a new Symbolicator with an existing debugger and list of 469be691f3bSpatrick images. The Symbolicator will create the target.""" 470be691f3bSpatrick obj = cls(debugger=debugger, images=images) 471be691f3bSpatrick return obj 472be691f3bSpatrick 473061da546Spatrick def __str__(self): 474061da546Spatrick s = "Symbolicator:\n" 475061da546Spatrick if self.target: 476061da546Spatrick s += "Target = '%s'\n" % (self.target) 477061da546Spatrick s += "Target modules:\n" 478061da546Spatrick for m in self.target.modules: 479061da546Spatrick s += str(m) + "\n" 480061da546Spatrick s += "Images:\n" 481061da546Spatrick for image in self.images: 482061da546Spatrick s += ' %s\n' % (image) 483061da546Spatrick return s 484061da546Spatrick 485061da546Spatrick def find_images_with_identifier(self, identifier): 486061da546Spatrick images = list() 487061da546Spatrick for image in self.images: 488061da546Spatrick if image.identifier == identifier: 489061da546Spatrick images.append(image) 490061da546Spatrick if len(images) == 0: 491061da546Spatrick regex_text = '^.*\.%s$' % (re.escape(identifier)) 492061da546Spatrick regex = re.compile(regex_text) 493061da546Spatrick for image in self.images: 494061da546Spatrick if regex.match(image.identifier): 495061da546Spatrick images.append(image) 496061da546Spatrick return images 497061da546Spatrick 498061da546Spatrick def find_image_containing_load_addr(self, load_addr): 499061da546Spatrick for image in self.images: 500061da546Spatrick if image.get_section_containing_load_addr(load_addr): 501061da546Spatrick return image 502061da546Spatrick return None 503061da546Spatrick 504061da546Spatrick def create_target(self): 505061da546Spatrick if self.target: 506061da546Spatrick return self.target 507061da546Spatrick 508061da546Spatrick if self.images: 509061da546Spatrick for image in self.images: 510be691f3bSpatrick self.target = image.create_target(self.debugger) 511061da546Spatrick if self.target: 512061da546Spatrick if self.target.GetAddressByteSize() == 4: 513061da546Spatrick triple = self.target.triple 514061da546Spatrick if triple: 515061da546Spatrick arch = triple.split('-')[0] 516061da546Spatrick if "arm" in arch: 517061da546Spatrick self.addr_mask = 0xfffffffffffffffe 518061da546Spatrick return self.target 519061da546Spatrick return None 520061da546Spatrick 521061da546Spatrick def symbolicate(self, load_addr, verbose=False): 522061da546Spatrick if not self.target: 523061da546Spatrick self.create_target() 524061da546Spatrick if self.target: 525061da546Spatrick live_process = False 526061da546Spatrick process = self.target.process 527061da546Spatrick if process: 528061da546Spatrick state = process.state 529061da546Spatrick if state > lldb.eStateUnloaded and state < lldb.eStateDetached: 530061da546Spatrick live_process = True 531061da546Spatrick # If we don't have a live process, we can attempt to find the image 532061da546Spatrick # that a load address belongs to and lazily load its module in the 533061da546Spatrick # target, but we shouldn't do any of this if we have a live process 534061da546Spatrick if not live_process: 535061da546Spatrick image = self.find_image_containing_load_addr(load_addr) 536061da546Spatrick if image: 537061da546Spatrick image.add_module(self.target) 538061da546Spatrick symbolicated_address = Address(self.target, load_addr) 539061da546Spatrick if symbolicated_address.symbolicate(verbose): 540061da546Spatrick if symbolicated_address.so_addr: 541061da546Spatrick symbolicated_addresses = list() 542061da546Spatrick symbolicated_addresses.append(symbolicated_address) 543061da546Spatrick # See if we were able to reconstruct anything? 544061da546Spatrick while True: 545061da546Spatrick inlined_parent_so_addr = lldb.SBAddress() 546061da546Spatrick inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope( 547061da546Spatrick symbolicated_address.so_addr, inlined_parent_so_addr) 548061da546Spatrick if not inlined_parent_sym_ctx: 549061da546Spatrick break 550061da546Spatrick if not inlined_parent_so_addr: 551061da546Spatrick break 552061da546Spatrick 553061da546Spatrick symbolicated_address = Address( 554061da546Spatrick self.target, inlined_parent_so_addr.GetLoadAddress( 555061da546Spatrick self.target)) 556061da546Spatrick symbolicated_address.sym_ctx = inlined_parent_sym_ctx 557061da546Spatrick symbolicated_address.so_addr = inlined_parent_so_addr 558061da546Spatrick symbolicated_address.symbolicate(verbose) 559061da546Spatrick 560061da546Spatrick # push the new frame onto the new frame stack 561061da546Spatrick symbolicated_addresses.append(symbolicated_address) 562061da546Spatrick 563061da546Spatrick if symbolicated_addresses: 564061da546Spatrick return symbolicated_addresses 565061da546Spatrick else: 566061da546Spatrick print('error: no target in Symbolicator') 567061da546Spatrick return None 568061da546Spatrick 569061da546Spatrick 570061da546Spatrickdef disassemble_instructions( 571061da546Spatrick target, 572061da546Spatrick instructions, 573061da546Spatrick pc, 574061da546Spatrick insts_before_pc, 575061da546Spatrick insts_after_pc, 576061da546Spatrick non_zeroeth_frame): 577061da546Spatrick lines = list() 578061da546Spatrick pc_index = -1 579061da546Spatrick comment_column = 50 580061da546Spatrick for inst_idx, inst in enumerate(instructions): 581061da546Spatrick inst_pc = inst.GetAddress().GetLoadAddress(target) 582061da546Spatrick if pc == inst_pc: 583061da546Spatrick pc_index = inst_idx 584061da546Spatrick mnemonic = inst.GetMnemonic(target) 585061da546Spatrick operands = inst.GetOperands(target) 586061da546Spatrick comment = inst.GetComment(target) 587061da546Spatrick lines.append("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands)) 588061da546Spatrick if comment: 589061da546Spatrick line_len = len(lines[-1]) 590061da546Spatrick if line_len < comment_column: 591061da546Spatrick lines[-1] += ' ' * (comment_column - line_len) 592061da546Spatrick lines[-1] += "; %s" % comment 593061da546Spatrick 594061da546Spatrick if pc_index >= 0: 595061da546Spatrick # If we are disassembling the non-zeroeth frame, we need to backup the 596061da546Spatrick # PC by 1 597061da546Spatrick if non_zeroeth_frame and pc_index > 0: 598061da546Spatrick pc_index = pc_index - 1 599061da546Spatrick if insts_before_pc == -1: 600061da546Spatrick start_idx = 0 601061da546Spatrick else: 602061da546Spatrick start_idx = pc_index - insts_before_pc 603061da546Spatrick if start_idx < 0: 604061da546Spatrick start_idx = 0 605061da546Spatrick if insts_before_pc == -1: 606061da546Spatrick end_idx = inst_idx 607061da546Spatrick else: 608061da546Spatrick end_idx = pc_index + insts_after_pc 609061da546Spatrick if end_idx > inst_idx: 610061da546Spatrick end_idx = inst_idx 611061da546Spatrick for i in range(start_idx, end_idx + 1): 612061da546Spatrick if i == pc_index: 613061da546Spatrick print(' -> ', lines[i]) 614061da546Spatrick else: 615061da546Spatrick print(' ', lines[i]) 616061da546Spatrick 617061da546Spatrick 618061da546Spatrickdef print_module_section_data(section): 619061da546Spatrick print(section) 620061da546Spatrick section_data = section.GetSectionData() 621061da546Spatrick if section_data: 622061da546Spatrick ostream = lldb.SBStream() 623061da546Spatrick section_data.GetDescription(ostream, section.GetFileAddress()) 624061da546Spatrick print(ostream.GetData()) 625061da546Spatrick 626061da546Spatrick 627061da546Spatrickdef print_module_section(section, depth): 628061da546Spatrick print(section) 629061da546Spatrick if depth > 0: 630061da546Spatrick num_sub_sections = section.GetNumSubSections() 631061da546Spatrick for sect_idx in range(num_sub_sections): 632061da546Spatrick print_module_section( 633061da546Spatrick section.GetSubSectionAtIndex(sect_idx), depth - 1) 634061da546Spatrick 635061da546Spatrick 636061da546Spatrickdef print_module_sections(module, depth): 637061da546Spatrick for sect in module.section_iter(): 638061da546Spatrick print_module_section(sect, depth) 639061da546Spatrick 640061da546Spatrick 641061da546Spatrickdef print_module_symbols(module): 642061da546Spatrick for sym in module: 643061da546Spatrick print(sym) 644061da546Spatrick 645061da546Spatrick 646be691f3bSpatrickdef Symbolicate(debugger, command_args): 647061da546Spatrick 648061da546Spatrick usage = "usage: %prog [options] <addr1> [addr2 ...]" 649061da546Spatrick description = '''Symbolicate one or more addresses using LLDB's python scripting API..''' 650061da546Spatrick parser = optparse.OptionParser( 651061da546Spatrick description=description, 652061da546Spatrick prog='crashlog.py', 653061da546Spatrick usage=usage) 654061da546Spatrick parser.add_option( 655061da546Spatrick '-v', 656061da546Spatrick '--verbose', 657061da546Spatrick action='store_true', 658061da546Spatrick dest='verbose', 659061da546Spatrick help='display verbose debug info', 660061da546Spatrick default=False) 661061da546Spatrick parser.add_option( 662061da546Spatrick '-p', 663061da546Spatrick '--platform', 664061da546Spatrick type='string', 665061da546Spatrick metavar='platform', 666061da546Spatrick dest='platform', 667061da546Spatrick help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') 668061da546Spatrick parser.add_option( 669061da546Spatrick '-f', 670061da546Spatrick '--file', 671061da546Spatrick type='string', 672061da546Spatrick metavar='file', 673061da546Spatrick dest='file', 674061da546Spatrick help='Specify a file to use when symbolicating') 675061da546Spatrick parser.add_option( 676061da546Spatrick '-a', 677061da546Spatrick '--arch', 678061da546Spatrick type='string', 679061da546Spatrick metavar='arch', 680061da546Spatrick dest='arch', 681061da546Spatrick help='Specify a architecture to use when symbolicating') 682061da546Spatrick parser.add_option( 683061da546Spatrick '-s', 684061da546Spatrick '--slide', 685061da546Spatrick type='int', 686061da546Spatrick metavar='slide', 687061da546Spatrick dest='slide', 688061da546Spatrick help='Specify the slide to use on the file specified with the --file option', 689061da546Spatrick default=None) 690061da546Spatrick parser.add_option( 691061da546Spatrick '--section', 692061da546Spatrick type='string', 693061da546Spatrick action='append', 694061da546Spatrick dest='section_strings', 695061da546Spatrick help='specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr>') 696061da546Spatrick try: 697061da546Spatrick (options, args) = parser.parse_args(command_args) 698061da546Spatrick except: 699061da546Spatrick return 700be691f3bSpatrick symbolicator = Symbolicator(debugger) 701061da546Spatrick images = list() 702061da546Spatrick if options.file: 703061da546Spatrick image = Image(options.file) 704061da546Spatrick image.arch = options.arch 705061da546Spatrick # Add any sections that were specified with one or more --section 706061da546Spatrick # options 707061da546Spatrick if options.section_strings: 708061da546Spatrick for section_str in options.section_strings: 709061da546Spatrick section = Section() 710061da546Spatrick if section.set_from_string(section_str): 711061da546Spatrick image.add_section(section) 712061da546Spatrick else: 713061da546Spatrick sys.exit(1) 714061da546Spatrick if options.slide is not None: 715061da546Spatrick image.slide = options.slide 716061da546Spatrick symbolicator.images.append(image) 717061da546Spatrick 718061da546Spatrick target = symbolicator.create_target() 719061da546Spatrick if options.verbose: 720061da546Spatrick print(symbolicator) 721061da546Spatrick if target: 722061da546Spatrick for addr_str in args: 723061da546Spatrick addr = int(addr_str, 0) 724061da546Spatrick symbolicated_addrs = symbolicator.symbolicate( 725061da546Spatrick addr, options.verbose) 726061da546Spatrick for symbolicated_addr in symbolicated_addrs: 727061da546Spatrick print(symbolicated_addr) 728061da546Spatrick print() 729061da546Spatrick else: 730061da546Spatrick print('error: no target for %s' % (symbolicator)) 731061da546Spatrick 732061da546Spatrickif __name__ == '__main__': 733061da546Spatrick # Create a new debugger instance 734be691f3bSpatrick debugger = lldb.SBDebugger.Create() 735be691f3bSpatrick Symbolicate(debugger, sys.argv[1:]) 736be691f3bSpatrick SBDebugger.Destroy(debugger) 737