2012-04-04 05:35:43 +08:00
#!/usr/bin/python
#----------------------------------------------------------------------
# Be sure to add the python path that points to the LLDB shared library.
#
# To use this in the embedded python interpreter using "lldb":
#
# cd /path/containing/crashlog.py
# lldb
# (lldb) script import crashlog
# "crashlog" command installed, type "crashlog --help" for detailed help
# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash
#
2016-09-07 04:57:50 +08:00
# The benefit of running the crashlog command inside lldb in the
# embedded python interpreter is when the command completes, there
2012-04-04 05:35:43 +08:00
# will be a target with all of the files loaded at the locations
# described in the crash log. Only the files that have stack frames
# in the backtrace will be loaded unless the "--load-all" option
# has been specified. This allows users to explore the program in the
2016-09-07 04:57:50 +08:00
# state it was in right at crash time.
2012-04-04 05:35:43 +08:00
#
# On MacOSX csh, tcsh:
# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )
#
# On MacOSX sh, bash:
# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash
#----------------------------------------------------------------------
import lldb
import commands
import optparse
import os
import plistlib
import re
import shlex
import sys
import time
import uuid
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
class Address :
""" Class that represents an address that will be symbolicated """
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def __init__ ( self , target , load_addr ) :
self . target = target
2016-09-07 04:57:50 +08:00
self . load_addr = load_addr # The load address that this object represents
# the resolved lldb.SBAddress (if any), named so_addr for
# section/offset address
self . so_addr = None
self . sym_ctx = None # The cached symbol context for this address
# Any original textual description of this address to be used as a
# backup in case symbolication fails
self . description = None
self . symbolication = None # The cached symbolicated string that describes this address
2012-04-04 05:35:43 +08:00
self . inlined = False
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def __str__ ( self ) :
s = " %#16.16x " % ( self . load_addr )
if self . symbolication :
s + = " %s " % ( self . symbolication )
elif self . description :
s + = " %s " % ( self . description )
elif self . so_addr :
s + = " %s " % ( self . so_addr )
return s
def resolve_addr ( self ) :
2016-09-07 04:57:50 +08:00
if self . so_addr is None :
self . so_addr = self . target . ResolveLoadAddress ( self . load_addr )
2012-04-04 05:35:43 +08:00
return self . so_addr
def is_inlined ( self ) :
return self . inlined
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def get_symbol_context ( self ) :
2016-09-07 04:57:50 +08:00
if self . sym_ctx is None :
2012-04-04 05:35:43 +08:00
sb_addr = self . resolve_addr ( )
if sb_addr :
2016-09-07 04:57:50 +08:00
self . sym_ctx = self . target . ResolveSymbolContextForAddress (
sb_addr , lldb . eSymbolContextEverything )
2012-04-04 05:35:43 +08:00
else :
self . sym_ctx = lldb . SBSymbolContext ( )
return self . sym_ctx
def get_instructions ( self ) :
sym_ctx = self . get_symbol_context ( )
if sym_ctx :
function = sym_ctx . GetFunction ( )
if function :
return function . GetInstructions ( self . target )
return sym_ctx . GetSymbol ( ) . GetInstructions ( self . target )
return None
2016-09-07 04:57:50 +08:00
def symbolicate ( self , verbose = False ) :
if self . symbolication is None :
2012-04-04 05:35:43 +08:00
self . symbolication = ' '
self . inlined = False
sym_ctx = self . get_symbol_context ( )
if sym_ctx :
module = sym_ctx . GetModule ( )
if module :
2012-06-29 02:10:14 +08:00
# Print full source file path in verbose mode
if verbose :
self . symbolication + = str ( module . GetFileSpec ( ) ) + ' ` '
else :
self . symbolication + = module . GetFileSpec ( ) . GetFilename ( ) + ' ` '
2012-04-04 05:35:43 +08:00
function_start_load_addr = - 1
function = sym_ctx . GetFunction ( )
block = sym_ctx . GetBlock ( )
line_entry = sym_ctx . GetLineEntry ( )
symbol = sym_ctx . GetSymbol ( )
2016-09-07 04:57:50 +08:00
inlined_block = block . GetContainingInlinedBlock ( )
2012-04-04 05:35:43 +08:00
if function :
self . symbolication + = function . GetName ( )
if inlined_block :
self . inlined = True
2016-09-07 04:57:50 +08:00
self . symbolication + = ' [inlined] ' + \
inlined_block . GetInlinedName ( )
block_range_idx = inlined_block . GetRangeIndexForBlockAddress (
self . so_addr )
2012-04-04 05:35:43 +08:00
if block_range_idx < lldb . UINT32_MAX :
2016-09-07 04:57:50 +08:00
block_range_start_addr = inlined_block . GetRangeStartAddress (
block_range_idx )
function_start_load_addr = block_range_start_addr . GetLoadAddress (
self . target )
2012-04-04 05:35:43 +08:00
if function_start_load_addr == - 1 :
2016-09-07 04:57:50 +08:00
function_start_load_addr = function . GetStartAddress ( ) . GetLoadAddress ( self . target )
2012-04-04 05:35:43 +08:00
elif symbol :
self . symbolication + = symbol . GetName ( )
2016-09-07 04:57:50 +08:00
function_start_load_addr = symbol . GetStartAddress ( ) . GetLoadAddress ( self . target )
2012-04-04 05:35:43 +08:00
else :
self . symbolication = ' '
return False
2016-09-07 04:57:50 +08:00
# Dump the offset from the current function or symbol if it
# is non zero
2012-04-04 05:35:43 +08:00
function_offset = self . load_addr - function_start_load_addr
if function_offset > 0 :
self . symbolication + = " + %u " % ( function_offset )
elif function_offset < 0 :
self . symbolication + = " %i (invalid negative offset, file a bug) " % function_offset
# Print out any line information if any is available
if line_entry . GetFileSpec ( ) :
2012-06-29 02:10:14 +08:00
# Print full source file path in verbose mode
if verbose :
self . symbolication + = ' at %s ' % line_entry . GetFileSpec ( )
else :
2012-04-04 05:35:43 +08:00
self . symbolication + = ' at %s ' % line_entry . GetFileSpec ( ) . GetFilename ( )
2016-09-07 04:57:50 +08:00
self . symbolication + = ' : %u ' % line_entry . GetLine ( )
2012-06-29 02:10:14 +08:00
column = line_entry . GetColumn ( )
if column > 0 :
self . symbolication + = ' : %u ' % column
2012-04-04 05:35:43 +08:00
return True
return False
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
class Section :
""" Class that represents an load address range """
sect_info_regex = re . compile ( ' (?P<name>[^=]+)=(?P<range>.*) ' )
addr_regex = re . compile ( ' ^ \ s*(?P<start>0x[0-9A-Fa-f]+) \ s*$ ' )
2016-09-07 04:57:50 +08:00
range_regex = re . compile (
' ^ \ s*(?P<start>0x[0-9A-Fa-f]+) \ s*(?P<op>[-+]) \ s*(?P<end>0x[0-9A-Fa-f]+) \ s*$ ' )
2012-04-04 05:35:43 +08:00
2016-09-07 04:57:50 +08:00
def __init__ ( self , start_addr = None , end_addr = None , name = None ) :
2012-04-04 05:35:43 +08:00
self . start_addr = start_addr
self . end_addr = end_addr
self . name = name
2016-09-07 04:57:50 +08:00
2014-05-28 08:21:15 +08:00
@classmethod
def InitWithSBTargetAndSBSection ( cls , target , section ) :
sect_load_addr = section . GetLoadAddress ( target )
if sect_load_addr != lldb . LLDB_INVALID_ADDRESS :
2016-09-07 04:57:50 +08:00
obj = cls (
sect_load_addr ,
sect_load_addr +
section . size ,
section . name )
2014-05-28 08:21:15 +08:00
return obj
else :
return None
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def contains ( self , addr ) :
2016-09-07 04:57:50 +08:00
return self . start_addr < = addr and addr < self . end_addr
2012-04-04 05:35:43 +08:00
def set_from_string ( self , s ) :
2016-09-07 04:57:50 +08:00
match = self . sect_info_regex . match ( s )
2012-04-04 05:35:43 +08:00
if match :
self . name = match . group ( ' name ' )
range_str = match . group ( ' range ' )
addr_match = self . addr_regex . match ( range_str )
if addr_match :
self . start_addr = int ( addr_match . group ( ' start ' ) , 16 )
self . end_addr = None
return True
range_match = self . range_regex . match ( range_str )
if range_match :
self . start_addr = int ( range_match . group ( ' start ' ) , 16 )
self . end_addr = int ( range_match . group ( ' end ' ) , 16 )
op = range_match . group ( ' op ' )
if op == ' + ' :
self . end_addr + = self . start_addr
return True
print ' error: invalid section info string " %s " ' % s
print ' Valid section info formats are: '
print ' Format Example Description '
print ' --------------------- ----------------------------------------------- '
print ' <name>=<base> __TEXT=0x123000 Section from base address only '
print ' <name>=<base>-<end> __TEXT=0x123000-0x124000 Section from base address and end address '
print ' <name>=<base>+<size> __TEXT=0x123000+0x1000 Section from base address and size '
return False
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def __str__ ( self ) :
if self . name :
2016-09-07 04:57:50 +08:00
if self . end_addr is not None :
if self . start_addr is not None :
return " %s =[0x %16.16x - 0x %16.16x ) " % (
self . name , self . start_addr , self . end_addr )
2012-04-04 05:35:43 +08:00
else :
2016-09-07 04:57:50 +08:00
if self . start_addr is not None :
2012-04-04 05:35:43 +08:00
return " %s =0x %16.16x " % ( self . name , self . start_addr )
return self . name
return " <invalid> "
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
class Image :
""" A class that represents an executable image and any associated data """
2016-09-07 04:57:50 +08:00
def __init__ ( self , path , uuid = None ) :
2012-04-04 05:35:43 +08:00
self . path = path
self . resolved_path = None
2012-06-05 07:22:17 +08:00
self . resolved = False
self . unavailable = False
2012-04-04 05:35:43 +08:00
self . uuid = uuid
self . section_infos = list ( )
self . identifier = None
self . version = None
self . arch = None
self . module = None
self . symfile = None
self . slide = None
2016-09-07 04:57:50 +08:00
2014-05-28 08:21:15 +08:00
@classmethod
def InitWithSBTargetAndSBModule ( cls , target , module ) :
2015-09-22 13:07:56 +08:00
''' Initialize this Image object with a module from a target. '''
2014-05-28 08:21:15 +08:00
obj = cls ( module . file . fullpath , module . uuid )
obj . resolved_path = module . platform_file . fullpath
obj . resolved = True
obj . arch = module . triple
for section in module . sections :
2016-09-07 04:57:50 +08:00
symb_section = Section . InitWithSBTargetAndSBSection (
target , section )
2014-05-28 08:21:15 +08:00
if symb_section :
2016-09-07 04:57:50 +08:00
obj . section_infos . append ( symb_section )
2014-05-28 08:21:15 +08:00
obj . arch = module . triple
obj . module = module
obj . symfile = None
obj . slide = None
return obj
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def dump ( self , prefix ) :
print " %s %s " % ( prefix , self )
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
def debug_dump ( self ) :
print ' path = " %s " ' % ( self . path )
print ' resolved_path = " %s " ' % ( self . resolved_path )
print ' resolved = %i ' % ( self . resolved )
print ' unavailable = %i ' % ( self . unavailable )
print ' uuid = %s ' % ( self . uuid )
print ' section_infos = %s ' % ( self . section_infos )
print ' identifier = " %s " ' % ( self . identifier )
print ' version = %s ' % ( self . version )
print ' arch = %s ' % ( self . arch )
print ' module = %s ' % ( self . module )
print ' symfile = " %s " ' % ( self . symfile )
print ' slide = %i (0x %x ) ' % ( self . slide , self . slide )
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def __str__ ( self ) :
2014-05-28 08:21:15 +08:00
s = ' '
if self . uuid :
s + = " %s " % ( self . get_uuid ( ) )
if self . arch :
s + = " %s " % ( self . arch )
if self . version :
s + = " %s " % ( self . version )
resolved_path = self . get_resolved_path ( )
if resolved_path :
s + = " %s " % ( resolved_path )
2012-04-04 05:35:43 +08:00
for section_info in self . section_infos :
s + = " , %s " % ( section_info )
2016-09-07 04:57:50 +08:00
if self . slide is not None :
2012-04-04 05:35:43 +08:00
s + = ' , slide = 0x %16.16x ' % self . slide
2016-09-07 04:57:50 +08:00
return s
2012-04-04 05:35:43 +08:00
def add_section ( self , section ) :
2016-09-07 04:57:50 +08:00
# print "added '%s' to '%s'" % (section, self.path)
self . section_infos . append ( section )
def get_section_containing_load_addr ( self , load_addr ) :
2012-04-04 05:35:43 +08:00
for section_info in self . section_infos :
if section_info . contains ( load_addr ) :
return section_info
return None
def get_resolved_path ( self ) :
if self . resolved_path :
return self . resolved_path
elif self . path :
return self . path
return None
def get_resolved_path_basename ( self ) :
path = self . get_resolved_path ( )
if path :
return os . path . basename ( path )
return None
def symfile_basename ( self ) :
if self . symfile :
return os . path . basename ( self . symfile )
return None
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def has_section_load_info ( self ) :
2016-09-07 04:57:50 +08:00
return self . section_infos or self . slide is not None
2012-04-04 05:35:43 +08:00
def load_module ( self , target ) :
2012-06-05 07:22:17 +08:00
if self . unavailable :
2016-09-07 04:57:50 +08:00
return None # We already warned that we couldn't find this module, so don't return an error string
2012-04-04 05:35:43 +08:00
# Load this module into "target" using the section infos to
# set the section load addresses
if self . has_section_load_info ( ) :
if target :
if self . module :
if self . section_infos :
num_sections_loaded = 0
for section_info in self . section_infos :
if section_info . name :
2016-09-07 04:57:50 +08:00
section = self . module . FindSection (
section_info . name )
2012-04-04 05:35:43 +08:00
if section :
2016-09-07 04:57:50 +08:00
error = target . SetSectionLoadAddress (
section , section_info . start_addr )
2012-04-04 05:35:43 +08:00
if error . Success ( ) :
num_sections_loaded + = 1
else :
return ' error: %s ' % error . GetCString ( )
else :
return ' error: unable to find the section named " %s " ' % section_info . name
else :
2016-09-07 04:57:50 +08:00
return ' error: unable to find " %s " section in " %s " ' % (
range . name , self . get_resolved_path ( ) )
2012-04-04 05:35:43 +08:00
if num_sections_loaded == 0 :
return ' error: no sections were successfully loaded '
else :
2016-09-07 04:57:50 +08:00
err = target . SetModuleLoadAddress (
self . module , self . slide )
2012-04-04 05:35:43 +08:00
if err . Fail ( ) :
return err . GetCString ( )
return None
else :
return ' error: invalid module '
else :
return ' error: invalid target '
else :
return ' error: no section infos '
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def add_module ( self , target ) :
''' Add the Image described in this object to " target " and load the sections if " load " is True. '''
if target :
2016-09-07 04:57:50 +08:00
# Try and find using UUID only first so that paths need not match
# up
2012-05-11 08:30:14 +08:00
uuid_str = self . get_normalized_uuid_string ( )
if uuid_str :
2016-09-07 04:57:50 +08:00
self . module = target . AddModule ( None , None , uuid_str )
2012-04-04 05:35:43 +08:00
if not self . module :
2016-09-07 04:57:50 +08:00
self . locate_module_and_debug_symbols ( )
2012-06-05 07:22:17 +08:00
if self . unavailable :
return None
2012-04-21 07:31:27 +08:00
resolved_path = self . get_resolved_path ( )
2016-09-07 04:57:50 +08:00
self . module = target . AddModule (
resolved_path , self . arch , uuid_str , self . symfile )
2012-04-04 05:35:43 +08:00
if not self . module :
2016-09-07 04:57:50 +08:00
return ' error: unable to get module for ( %s ) " %s " ' % (
self . arch , self . get_resolved_path ( ) )
2012-04-04 05:35:43 +08:00
if self . has_section_load_info ( ) :
return self . load_module ( target )
else :
2016-09-07 04:57:50 +08:00
return None # No sections, the module was added to the target, so success
2012-04-04 05:35:43 +08:00
else :
return ' error: invalid target '
2016-09-07 04:57:50 +08:00
def locate_module_and_debug_symbols ( self ) :
2012-04-04 05:35:43 +08:00
# By default, just use the paths that were supplied in:
# self.path
# self.resolved_path
# self.module
# self.symfile
# Subclasses can inherit from this class and override this function
2012-06-05 07:22:17 +08:00
self . resolved = True
2012-04-04 05:35:43 +08:00
return True
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def get_uuid ( self ) :
2012-05-11 08:30:14 +08:00
if not self . uuid and self . module :
2012-04-04 05:35:43 +08:00
self . uuid = uuid . UUID ( self . module . GetUUIDString ( ) )
return self . uuid
2012-05-11 08:30:14 +08:00
def get_normalized_uuid_string ( self ) :
if self . uuid :
return str ( self . uuid ) . upper ( )
return None
2012-04-04 05:35:43 +08:00
def create_target ( self ) :
''' Create a target using the information in this Image object. '''
2012-06-05 07:22:17 +08:00
if self . unavailable :
return None
2016-09-07 04:57:50 +08:00
if self . locate_module_and_debug_symbols ( ) :
resolved_path = self . get_resolved_path ( )
path_spec = lldb . SBFileSpec ( resolved_path )
2012-04-04 05:35:43 +08:00
#result.PutCString ('plist[%s] = %s' % (uuid, self.plist))
error = lldb . SBError ( )
2016-09-07 04:57:50 +08:00
target = lldb . debugger . CreateTarget (
resolved_path , self . arch , None , False , error )
2012-04-04 05:35:43 +08:00
if target :
self . module = target . FindModule ( path_spec )
if self . has_section_load_info ( ) :
err = self . load_module ( target )
if err :
print ' ERROR: ' , err
return target
else :
print ' error: unable to create a valid target for ( %s ) " %s " ' % ( self . arch , self . path )
else :
print ' error: unable to locate main executable ( %s ) " %s " ' % ( self . arch , self . path )
return None
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
class Symbolicator :
def __init__ ( self ) :
""" A class the represents the information needed to symbolicate addresses in a program """
self . target = None
2016-09-07 04:57:50 +08:00
self . images = list ( ) # a list of images to be used when symbolicating
2013-04-05 07:36:51 +08:00
self . addr_mask = 0xffffffffffffffff
2016-09-07 04:57:50 +08:00
2014-05-28 08:21:15 +08:00
@classmethod
def InitWithSBTarget ( cls , target ) :
obj = cls ( )
obj . target = target
2016-09-07 04:57:50 +08:00
obj . images = list ( )
2014-05-28 08:21:15 +08:00
triple = target . triple
if triple :
arch = triple . split ( ' - ' ) [ 0 ]
if " arm " in arch :
obj . addr_mask = 0xfffffffffffffffe
for module in target . modules :
image = Image . InitWithSBTargetAndSBModule ( target , module )
obj . images . append ( image )
return obj
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def __str__ ( self ) :
s = " Symbolicator: \n "
if self . target :
s + = " Target = ' %s ' \n " % ( self . target )
2014-05-28 08:21:15 +08:00
s + = " Target modules: \n "
2012-04-04 05:35:43 +08:00
for m in self . target . modules :
2014-05-28 08:21:15 +08:00
s + = str ( m ) + " \n "
2012-04-04 05:35:43 +08:00
s + = " Images: \n "
for image in self . images :
s + = ' %s \n ' % ( image )
return s
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def find_images_with_identifier ( self , identifier ) :
images = list ( )
for image in self . images :
if image . identifier == identifier :
images . append ( image )
2015-03-06 06:53:06 +08:00
if len ( images ) == 0 :
2016-06-11 04:09:33 +08:00
regex_text = ' ^.* \ . %s $ ' % ( re . escape ( identifier ) )
2015-03-06 06:53:06 +08:00
regex = re . compile ( regex_text )
for image in self . images :
if regex . match ( image . identifier ) :
images . append ( image )
2012-04-04 05:35:43 +08:00
return images
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def find_image_containing_load_addr ( self , load_addr ) :
for image in self . images :
2016-09-07 04:57:50 +08:00
if image . get_section_containing_load_addr ( load_addr ) :
2012-04-04 05:35:43 +08:00
return image
return None
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def create_target ( self ) :
if self . target :
return self . target
if self . images :
for image in self . images :
2016-09-07 04:57:50 +08:00
self . target = image . create_target ( )
2012-04-04 05:35:43 +08:00
if self . target :
2013-04-05 07:36:51 +08:00
if self . target . GetAddressByteSize ( ) == 4 :
triple = self . target . triple
if triple :
arch = triple . split ( ' - ' ) [ 0 ]
if " arm " in arch :
self . addr_mask = 0xfffffffffffffffe
2012-04-04 05:35:43 +08:00
return self . target
return None
2016-09-07 04:57:50 +08:00
def symbolicate ( self , load_addr , verbose = False ) :
2012-06-05 07:22:17 +08:00
if not self . target :
self . create_target ( )
2012-04-04 05:35:43 +08:00
if self . target :
2013-02-26 03:34:57 +08:00
live_process = False
process = self . target . process
if process :
state = process . state
2013-02-26 05:20:59 +08:00
if state > lldb . eStateUnloaded and state < lldb . eStateDetached :
2013-02-26 03:34:57 +08:00
live_process = True
# If we don't have a live process, we can attempt to find the image
# that a load address belongs to and lazily load its module in the
# target, but we shouldn't do any of this if we have a live process
if not live_process :
2016-09-07 04:57:50 +08:00
image = self . find_image_containing_load_addr ( load_addr )
2013-02-26 03:34:57 +08:00
if image :
2016-09-07 04:57:50 +08:00
image . add_module ( self . target )
2012-07-07 09:22:45 +08:00
symbolicated_address = Address ( self . target , load_addr )
2016-09-07 04:57:50 +08:00
if symbolicated_address . symbolicate ( verbose ) :
2012-07-07 09:22:45 +08:00
if symbolicated_address . so_addr :
symbolicated_addresses = list ( )
symbolicated_addresses . append ( symbolicated_address )
# See if we were able to reconstruct anything?
2016-09-07 04:57:50 +08:00
while True :
2012-07-07 09:22:45 +08:00
inlined_parent_so_addr = lldb . SBAddress ( )
2016-09-07 04:57:50 +08:00
inlined_parent_sym_ctx = symbolicated_address . sym_ctx . GetParentOfInlinedScope (
symbolicated_address . so_addr , inlined_parent_so_addr )
2012-07-07 09:22:45 +08:00
if not inlined_parent_sym_ctx :
break
if not inlined_parent_so_addr :
break
2012-04-04 05:35:43 +08:00
2016-09-07 04:57:50 +08:00
symbolicated_address = Address (
self . target , inlined_parent_so_addr . GetLoadAddress (
self . target ) )
2012-07-07 09:22:45 +08:00
symbolicated_address . sym_ctx = inlined_parent_sym_ctx
symbolicated_address . so_addr = inlined_parent_so_addr
2016-09-07 04:57:50 +08:00
symbolicated_address . symbolicate ( verbose )
2012-07-07 09:22:45 +08:00
# push the new frame onto the new frame stack
2016-09-07 04:57:50 +08:00
symbolicated_addresses . append ( symbolicated_address )
2012-07-07 09:22:45 +08:00
if symbolicated_addresses :
return symbolicated_addresses
2012-06-05 07:22:17 +08:00
else :
print ' error: no target in Symbolicator '
2012-04-04 05:35:43 +08:00
return None
2016-09-07 04:57:50 +08:00
def disassemble_instructions (
target ,
instructions ,
pc ,
insts_before_pc ,
insts_after_pc ,
non_zeroeth_frame ) :
2012-04-04 05:35:43 +08:00
lines = list ( )
pc_index = - 1
comment_column = 50
for inst_idx , inst in enumerate ( instructions ) :
2016-09-07 04:57:50 +08:00
inst_pc = inst . GetAddress ( ) . GetLoadAddress ( target )
2012-04-04 05:35:43 +08:00
if pc == inst_pc :
pc_index = inst_idx
2016-09-07 04:57:50 +08:00
mnemonic = inst . GetMnemonic ( target )
operands = inst . GetOperands ( target )
comment = inst . GetComment ( target )
2012-04-04 05:35:43 +08:00
#data = inst.GetData (target)
2016-09-07 04:57:50 +08:00
lines . append ( " %#16.16x : %8s %s " % ( inst_pc , mnemonic , operands ) )
2012-04-04 05:35:43 +08:00
if comment :
line_len = len ( lines [ - 1 ] )
if line_len < comment_column :
lines [ - 1 ] + = ' ' * ( comment_column - line_len )
lines [ - 1 ] + = " ; %s " % comment
if pc_index > = 0 :
2016-09-07 04:57:50 +08:00
# If we are disassembling the non-zeroeth frame, we need to backup the
# PC by 1
2012-04-04 05:35:43 +08:00
if non_zeroeth_frame and pc_index > 0 :
pc_index = pc_index - 1
if insts_before_pc == - 1 :
start_idx = 0
else :
start_idx = pc_index - insts_before_pc
if start_idx < 0 :
start_idx = 0
if insts_before_pc == - 1 :
end_idx = inst_idx
else :
end_idx = pc_index + insts_after_pc
if end_idx > inst_idx :
end_idx = inst_idx
2016-09-07 04:57:50 +08:00
for i in range ( start_idx , end_idx + 1 ) :
2012-04-04 05:35:43 +08:00
if i == pc_index :
print ' -> ' , lines [ i ]
else :
print ' ' , lines [ i ]
2016-09-07 04:57:50 +08:00
def print_module_section_data ( section ) :
2012-04-04 05:35:43 +08:00
print section
section_data = section . GetSectionData ( )
if section_data :
ostream = lldb . SBStream ( )
2016-09-07 04:57:50 +08:00
section_data . GetDescription ( ostream , section . GetFileAddress ( ) )
2012-04-04 05:35:43 +08:00
print ostream . GetData ( )
2016-09-07 04:57:50 +08:00
def print_module_section ( section , depth ) :
2012-04-04 05:35:43 +08:00
print section
if depth > 0 :
num_sub_sections = section . GetNumSubSections ( )
for sect_idx in range ( num_sub_sections ) :
2016-09-07 04:57:50 +08:00
print_module_section (
section . GetSubSectionAtIndex ( sect_idx ) , depth - 1 )
2012-04-04 05:35:43 +08:00
2016-09-07 04:57:50 +08:00
def print_module_sections ( module , depth ) :
2012-04-04 05:35:43 +08:00
for sect in module . section_iter ( ) :
2016-09-07 04:57:50 +08:00
print_module_section ( sect , depth )
2012-04-04 05:35:43 +08:00
2016-09-07 04:57:50 +08:00
def print_module_symbols ( module ) :
2012-04-04 05:35:43 +08:00
for sym in module :
print sym
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
def Symbolicate ( command_args ) :
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
usage = " usage: % prog [options] <addr1> [addr2 ...] "
2016-09-07 04:57:50 +08:00
description = ''' Symbolicate one or more addresses using LLDB ' s python scripting API.. '''
parser = optparse . OptionParser (
description = description ,
prog = ' crashlog.py ' ,
usage = usage )
parser . add_option (
' -v ' ,
' --verbose ' ,
action = ' store_true ' ,
dest = ' verbose ' ,
help = ' display verbose debug info ' ,
default = False )
parser . add_option (
' -p ' ,
' --platform ' ,
type = ' string ' ,
metavar = ' platform ' ,
dest = ' platform ' ,
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 " . ' )
parser . add_option (
' -f ' ,
' --file ' ,
type = ' string ' ,
metavar = ' file ' ,
dest = ' file ' ,
help = ' Specify a file to use when symbolicating ' )
parser . add_option (
' -a ' ,
' --arch ' ,
type = ' string ' ,
metavar = ' arch ' ,
dest = ' arch ' ,
help = ' Specify a architecture to use when symbolicating ' )
parser . add_option (
' -s ' ,
' --slide ' ,
type = ' int ' ,
metavar = ' slide ' ,
dest = ' slide ' ,
help = ' Specify the slide to use on the file specified with the --file option ' ,
default = None )
parser . add_option (
' --section ' ,
type = ' string ' ,
action = ' append ' ,
dest = ' section_strings ' ,
help = ' specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr> ' )
2012-04-04 05:35:43 +08:00
try :
( options , args ) = parser . parse_args ( command_args )
except :
return
symbolicator = Symbolicator ( )
2016-09-07 04:57:50 +08:00
images = list ( )
2012-04-04 05:35:43 +08:00
if options . file :
2016-09-07 04:57:50 +08:00
image = Image ( options . file )
2012-04-04 05:35:43 +08:00
image . arch = options . arch
2016-09-07 04:57:50 +08:00
# Add any sections that were specified with one or more --section
# options
2012-04-04 05:35:43 +08:00
if options . section_strings :
for section_str in options . section_strings :
section = Section ( )
2016-09-07 04:57:50 +08:00
if section . set_from_string ( section_str ) :
image . add_section ( section )
2012-04-04 05:35:43 +08:00
else :
sys . exit ( 1 )
2016-09-07 04:57:50 +08:00
if options . slide is not None :
2012-04-04 05:35:43 +08:00
image . slide = options . slide
symbolicator . images . append ( image )
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
target = symbolicator . create_target ( )
if options . verbose :
print symbolicator
if target :
for addr_str in args :
addr = int ( addr_str , 0 )
2016-09-07 04:57:50 +08:00
symbolicated_addrs = symbolicator . symbolicate (
addr , options . verbose )
2012-04-04 05:35:43 +08:00
for symbolicated_addr in symbolicated_addrs :
print symbolicated_addr
print
else :
print ' error: no target for %s ' % ( symbolicator )
2016-09-07 04:57:50 +08:00
2012-04-04 05:35:43 +08:00
if __name__ == ' __main__ ' :
# Create a new debugger instance
lldb . debugger = lldb . SBDebugger . Create ( )
2016-09-07 04:57:50 +08:00
Symbolicate ( sys . argv [ 1 : ] )