101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton#!/usr/bin/python 201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton#---------------------------------------------------------------------- 401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton# Be sure to add the python path that points to the LLDB shared library. 5a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# 6a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# To use this in the embedded python interpreter using "lldb": 7a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# 8a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# cd /path/containing/crashlog.py 9a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# lldb 10a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# (lldb) script import crashlog 11a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# "crashlog" command installed, type "crashlog --help" for detailed help 12a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash 13a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# 14a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# The benefit of running the crashlog command inside lldb in the 15a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# embedded python interpreter is when the command completes, there 16a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# will be a target with all of the files loaded at the locations 17a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# described in the crash log. Only the files that have stack frames 18a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# in the backtrace will be loaded unless the "--load-all" option 19a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# has been specified. This allows users to explore the program in the 20a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# state it was in right at crash time. 21a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# 2201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton# On MacOSX csh, tcsh: 23a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) 24a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# 2501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton# On MacOSX sh, bash: 26a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash 2701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton#---------------------------------------------------------------------- 2801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 29a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytonimport commands 309d01042727a9c52cbab76237c8d290f2e337067dGreg Claytonimport cmd 31ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Claytonimport datetime 329d01042727a9c52cbab76237c8d290f2e337067dGreg Claytonimport glob 3301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonimport optparse 3401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonimport os 35ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Claytonimport platform 3601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonimport plistlib 373d39f83d308f4c147cff81e07c8059eb52dab89dGreg Claytonimport pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args) 3801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonimport re 39223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Claytonimport shlex 409d01042727a9c52cbab76237c8d290f2e337067dGreg Claytonimport string 4101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonimport sys 4201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonimport time 43cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Claytonimport uuid 445ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton 455ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Claytontry: 465ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton # Just try for LLDB in case PYTHONPATH is already correctly setup 475ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton import lldb 485ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Claytonexcept ImportError: 495ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton lldb_python_dirs = list() 505ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton # lldb is not in the PYTHONPATH, try some defaults for the current platform 515ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton platform_system = platform.system() 525ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton if platform_system == 'Darwin': 535ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton # On Darwin, try the currently selected Xcode directory 545ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton xcode_dir = commands.getoutput("xcode-select --print-path") 555ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton if xcode_dir: 565ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) 575ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 585ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 595ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton success = False 605ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton for lldb_python_dir in lldb_python_dirs: 615ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton if os.path.exists(lldb_python_dir): 625ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton if not (sys.path.__contains__(lldb_python_dir)): 635ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton sys.path.append(lldb_python_dir) 645ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton try: 655ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton import lldb 665ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton except ImportError: 675ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton pass 685ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton else: 695ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton print 'imported lldb from: "%s"' % (lldb_python_dir) 705ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton success = True 715ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton break 725ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton if not success: 735ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" 745ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton sys.exit(1) 755ec0d02ae49a90ffc840b5f0ac9d6ba921d0942dGreg Clayton 769d01042727a9c52cbab76237c8d290f2e337067dGreg Claytonfrom lldb.utils import symbolication 7701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 7801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg ClaytonPARSE_MODE_NORMAL = 0 7901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg ClaytonPARSE_MODE_THREAD = 1 8001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg ClaytonPARSE_MODE_IMAGES = 2 8101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg ClaytonPARSE_MODE_THREGS = 3 8201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg ClaytonPARSE_MODE_SYSTEM = 4 8301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 849d01042727a9c52cbab76237c8d290f2e337067dGreg Claytonclass CrashLog(symbolication.Symbolicator): 8501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton """Class that does parses darwin crash logs""" 864d258c616e9166fbb8336f77b588e5e2c5332c14Sean Callanan parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]'); 8701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_state_regex = re.compile('^Thread ([0-9]+) crashed with') 8801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)') 898b4bc2b81f72f3bdc47b9d492197e5ed7718c402Jason Molenda frame_regex = re.compile('^([0-9]+) +([^ ]+) *\t?(0x[0-9a-fA-F]+) +(.*)') 908077a5334dc4daef3a145d07307a970d00563055Greg Clayton image_regex_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^<]+)<([-0-9a-fA-F]+)> (.*)'); 918077a5334dc4daef3a145d07307a970d00563055Greg Clayton image_regex_no_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^/]+)/(.*)'); 9201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton empty_line_regex = re.compile('^$') 9301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 9401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton class Thread: 9501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton """Class that represents a thread in a darwin crash log""" 9601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def __init__(self, index): 9701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.index = index 9801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.frames = list() 99aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton self.idents = list() 10001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.registers = dict() 10101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.reason = None 10201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.queue = None 10301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 10401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def dump(self, prefix): 10501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "%sThread[%u] %s" % (prefix, self.index, self.reason) 10601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if self.frames: 10701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "%s Frames:" % (prefix) 10801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for frame in self.frames: 10901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton frame.dump(prefix + ' ') 11001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if self.registers: 11101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "%s Registers:" % (prefix) 11201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for reg in self.registers.keys(): 11301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg]) 11401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 115aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton def add_ident(self, ident): 116aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if not ident in self.idents: 117aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton self.idents.append(ident) 118aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton 11901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def did_crash(self): 12001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton return self.reason != None 12101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 12201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def __str__(self): 12301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton s = "Thread[%u]" % self.index 12401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if self.reason: 12501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton s += ' %s' % self.reason 12601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton return s 12701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 12801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 12901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton class Frame: 13001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton """Class that represents a stack frame in a thread in a darwin crash log""" 1313d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton def __init__(self, index, pc, description): 13201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.pc = pc 1333d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton self.description = description 1343d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton self.index = index 13501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 13601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def __str__(self): 1373d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton if self.description: 1383d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton return "[%3u] 0x%16.16x %s" % (self.index, self.pc, self.description) 1393d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton else: 1404e46867681f2a3a4587273228dbfac0030942a24Johnny Chen return "[%3u] 0x%16.16x" % (self.index, self.pc) 1414e46867681f2a3a4587273228dbfac0030942a24Johnny Chen 1424e46867681f2a3a4587273228dbfac0030942a24Johnny Chen def dump(self, prefix): 1434e46867681f2a3a4587273228dbfac0030942a24Johnny Chen print "%s%s" % (prefix, str(self)) 14401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 1459d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton class DarwinImage(symbolication.Image): 14601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton """Class that represents a binary images in a darwin crash log""" 1478077a5334dc4daef3a145d07307a970d00563055Greg Clayton dsymForUUIDBinary = os.path.expanduser('~rc/bin/dsymForUUID') 148cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if not os.path.exists(dsymForUUIDBinary): 149cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton dsymForUUIDBinary = commands.getoutput('which dsymForUUID') 150cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton 151cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') 1528077a5334dc4daef3a145d07307a970d00563055Greg Clayton 1533d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton def __init__(self, text_addr_lo, text_addr_hi, identifier, version, uuid, path): 1549d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton symbolication.Image.__init__(self, path, uuid); 1559d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton self.add_section (symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT")) 1563d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton self.identifier = identifier 15701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.version = version 15801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 1593d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton def locate_module_and_debug_symbols(self): 1601b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton # Don't load a module twice... 1611b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton if self.resolved: 1624c983c8b32996ac4543dcd95d76a0ecbeb1c6bbdGreg Clayton return True 1631b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton # Mark this as resolved so we don't keep trying 1641b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton self.resolved = True 165d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton uuid_str = self.get_normalized_uuid_string() 166d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton print 'Getting symbols for %s %s...' % (uuid_str, self.path), 1678077a5334dc4daef3a145d07307a970d00563055Greg Clayton if os.path.exists(self.dsymForUUIDBinary): 168d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton dsym_for_uuid_command = '%s %s' % (self.dsymForUUIDBinary, uuid_str) 1698077a5334dc4daef3a145d07307a970d00563055Greg Clayton s = commands.getoutput(dsym_for_uuid_command) 1708077a5334dc4daef3a145d07307a970d00563055Greg Clayton if s: 1718077a5334dc4daef3a145d07307a970d00563055Greg Clayton plist_root = plistlib.readPlistFromString (s) 1728077a5334dc4daef3a145d07307a970d00563055Greg Clayton if plist_root: 173d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton plist = plist_root[uuid_str] 174cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if plist: 175cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if 'DBGArchitecture' in plist: 176cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton self.arch = plist['DBGArchitecture'] 177cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if 'DBGDSYMPath' in plist: 1783d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton self.symfile = os.path.realpath(plist['DBGDSYMPath']) 179cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if 'DBGSymbolRichExecutable' in plist: 180cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton self.resolved_path = os.path.expanduser (plist['DBGSymbolRichExecutable']) 181cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if not self.resolved_path and os.path.exists(self.path): 182cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton dwarfdump_cmd_output = commands.getoutput('dwarfdump --uuid "%s"' % self.path) 183d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton self_uuid = self.get_uuid() 184cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton for line in dwarfdump_cmd_output.splitlines(): 185cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton match = self.dwarfdump_uuid_regex.search (line) 186cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if match: 187cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton dwarf_uuid_str = match.group(1) 188cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton dwarf_uuid = uuid.UUID(dwarf_uuid_str) 189cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if self_uuid == dwarf_uuid: 190cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton self.resolved_path = self.path 191cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton self.arch = match.group(2) 192cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton break; 193cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if not self.resolved_path: 1941b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton self.unavailable = True 1951b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton print "error\n error: unable to locate '%s' with UUID %s" % (self.path, uuid_str) 1964c983c8b32996ac4543dcd95d76a0ecbeb1c6bbdGreg Clayton return False 197cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)): 198cd793121caadf8eac0b13283bc2caa4cd467aebfGreg Clayton print 'ok' 1991dae6f39248e38ac84fc20c8b4c26e11bfcc19b7Greg Clayton # if self.resolved_path: 2001dae6f39248e38ac84fc20c8b4c26e11bfcc19b7Greg Clayton # print ' exe = "%s"' % self.resolved_path 2011dae6f39248e38ac84fc20c8b4c26e11bfcc19b7Greg Clayton # if self.symfile: 2021dae6f39248e38ac84fc20c8b4c26e11bfcc19b7Greg Clayton # print ' dsym = "%s"' % self.symfile 2034c983c8b32996ac4543dcd95d76a0ecbeb1c6bbdGreg Clayton return True 2041b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton else: 2051b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton self.unavailable = True 2064c983c8b32996ac4543dcd95d76a0ecbeb1c6bbdGreg Clayton return False 20701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 2083d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton 20901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 21001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def __init__(self, path): 21101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton """CrashLog constructor that take a path to a darwin crash log file""" 2129d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton symbolication.Symbolicator.__init__(self); 213223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton self.path = os.path.expanduser(path); 21401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.info_lines = list() 21501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.system_profile = list() 21601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.threads = list() 21701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.idents = list() # A list of the required identifiers for doing all stack backtraces 21801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.crashed_thread_idx = -1 21901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.version = -1 220223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton self.error = None 22101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # With possible initial component of ~ or ~user replaced by that user's home directory. 222223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton try: 223223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton f = open(self.path) 224223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton except IOError: 225223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton self.error = 'error: cannot open "%s"' % self.path 226223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton return 227223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton 22801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.file_lines = f.read().splitlines() 22901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton parse_mode = PARSE_MODE_NORMAL 23001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread = None 23101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for line in self.file_lines: 23201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # print line 23301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton line_len = len(line) 23401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if line_len == 0: 23501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if thread: 23601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if parse_mode == PARSE_MODE_THREAD: 23701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if thread.index == self.crashed_thread_idx: 23801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread.reason = '' 23901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if self.thread_exception: 24001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread.reason += self.thread_exception 24101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if self.thread_exception_data: 24201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread.reason += " (%s)" % self.thread_exception_data 24301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.threads.append(thread) 24401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread = None 24501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton else: 24601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # only append an extra empty line if the previous line 24701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # in the info_lines wasn't empty 24801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if len(self.info_lines) > 0 and len(self.info_lines[-1]): 24901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.info_lines.append(line) 25001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton parse_mode = PARSE_MODE_NORMAL 25101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # print 'PARSE_MODE_NORMAL' 25201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif parse_mode == PARSE_MODE_NORMAL: 25301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if line.startswith ('Process:'): 25440819bf6f7d3c2ed0c00877f9dc9efbf44beabb7Greg Clayton (self.process_name, pid_with_brackets) = line[8:].strip().split(' [') 25501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.process_id = pid_with_brackets.strip('[]') 25601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Path:'): 25701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.process_path = line[5:].strip() 25801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Identifier:'): 25901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.process_identifier = line[11:].strip() 26001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Version:'): 2612bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen version_string = line[8:].strip() 2622bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen matched_pair = re.search("(.+)\((.+)\)", version_string) 2632bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen if matched_pair: 2642bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen self.process_version = matched_pair.group(1) 2652bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen self.process_compatability_version = matched_pair.group(2) 2662bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen else: 2672bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen self.process = version_string 2682bb4de34c39f13a0d2ec3e96bc82d804a92395a3Johnny Chen self.process_compatability_version = version_string 2694d258c616e9166fbb8336f77b588e5e2c5332c14Sean Callanan elif self.parent_process_regex.search(line): 2704d258c616e9166fbb8336f77b588e5e2c5332c14Sean Callanan parent_process_match = self.parent_process_regex.search(line) 2714d258c616e9166fbb8336f77b588e5e2c5332c14Sean Callanan self.parent_process_name = parent_process_match.group(1) 2724d258c616e9166fbb8336f77b588e5e2c5332c14Sean Callanan self.parent_process_id = parent_process_match.group(2) 27301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Exception Type:'): 27401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.thread_exception = line[15:].strip() 27501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 27601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Exception Codes:'): 27701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.thread_exception_data = line[16:].strip() 27801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 27901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Crashed Thread:'): 28001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.crashed_thread_idx = int(line[15:].strip().split()[0]) 28101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 28201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Report Version:'): 28301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.version = int(line[15:].strip()) 28401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 28501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('System Profile:'): 28601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton parse_mode = PARSE_MODE_SYSTEM 28701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 28801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif (line.startswith ('Interval Since Last Report:') or 28901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton line.startswith ('Crashes Since Last Report:') or 29001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton line.startswith ('Per-App Interval Since Last Report:') or 29101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton line.startswith ('Per-App Crashes Since Last Report:') or 29201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton line.startswith ('Sleep/Wake UUID:') or 29301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton line.startswith ('Anonymous UUID:')): 29401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # ignore these 29501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 29601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Thread'): 29701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_state_match = self.thread_state_regex.search (line) 29801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if thread_state_match: 29901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_state_match = self.thread_regex.search (line) 30001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_idx = int(thread_state_match.group(1)) 30101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton parse_mode = PARSE_MODE_THREGS 30201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread = self.threads[thread_idx] 30301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton else: 30401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_match = self.thread_regex.search (line) 30501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if thread_match: 30601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton # print 'PARSE_MODE_THREAD' 30701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton parse_mode = PARSE_MODE_THREAD 30801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread_idx = int(thread_match.group(1)) 30901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread = CrashLog.Thread(thread_idx) 31001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 31101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif line.startswith ('Binary Images:'): 31201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton parse_mode = PARSE_MODE_IMAGES 31301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton continue 31401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.info_lines.append(line.strip()) 31501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif parse_mode == PARSE_MODE_THREAD: 316d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton if line.startswith ('Thread'): 317d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton continue 31801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton frame_match = self.frame_regex.search(line) 31901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if frame_match: 32001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton ident = frame_match.group(2) 321aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton thread.add_ident(ident) 32201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if not ident in self.idents: 32301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.idents.append(ident) 32401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread.frames.append (CrashLog.Frame(int(frame_match.group(1)), int(frame_match.group(3), 0), frame_match.group(4))) 32501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton else: 3268077a5334dc4daef3a145d07307a970d00563055Greg Clayton print 'error: frame regex failed for line: "%s"' % line 32701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif parse_mode == PARSE_MODE_IMAGES: 32801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton image_match = self.image_regex_uuid.search (line) 32901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if image_match: 3303d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image = CrashLog.DarwinImage (int(image_match.group(1),0), 3313d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton int(image_match.group(2),0), 3323d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image_match.group(3).strip(), 3333d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image_match.group(4).strip(), 334d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton uuid.UUID(image_match.group(5)), 3353d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image_match.group(6)) 33601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.images.append (image) 33701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton else: 33801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton image_match = self.image_regex_no_uuid.search (line) 33901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if image_match: 3403d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image = CrashLog.DarwinImage (int(image_match.group(1),0), 3413d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton int(image_match.group(2),0), 3423d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image_match.group(3).strip(), 3433d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image_match.group(4).strip(), 3443d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton None, 3453d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton image_match.group(5)) 34601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.images.append (image) 34701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton else: 34801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "error: image regex failed for: %s" % line 34901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 35001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif parse_mode == PARSE_MODE_THREGS: 35101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton stripped_line = line.strip() 35217d4a7f296122b43fe015771fa375a52f9d97798Jason Molenda # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00" 35317d4a7f296122b43fe015771fa375a52f9d97798Jason Molenda reg_values = re.findall ('([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line); 35401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for reg_value in reg_values: 355d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton #print 'reg_value = "%s"' % reg_value 35601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton (reg, value) = reg_value.split(': ') 357d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton #print 'reg = "%s"' % reg 358d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton #print 'value = "%s"' % value 35901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread.registers[reg.strip()] = int(value, 0) 36001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton elif parse_mode == PARSE_MODE_SYSTEM: 36101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton self.system_profile.append(line) 36201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton f.close() 3631b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton 36401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton def dump(self): 36501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "Crash Log File: %s" % (self.path) 36601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "\nThreads:" 36701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for thread in self.threads: 36801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton thread.dump(' ') 36901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "\nImages:" 37001f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for image in self.images: 37101f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton image.dump(' ') 37201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 3733d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton def find_image_with_identifier(self, identifier): 37401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton for image in self.images: 3753d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton if image.identifier == identifier: 37601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton return image 37701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton return None 37801f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 379e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton def create_target(self): 3803d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton #print 'crashlog.create_target()...' 3819d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton target = symbolication.Symbolicator.create_target(self) 3823d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton if target: 3833d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton return target 384e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton # We weren't able to open the main executable as, but we can still symbolicate 3853d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton print 'crashlog.create_target()...2' 386e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton if self.idents: 387f7fb7334f7cae880fe25069921202961ffb2dc39Sean Callanan for ident in self.idents: 388e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton image = self.find_image_with_identifier (ident) 389e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton if image: 3903d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton target = image.create_target () 3913d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton if target: 3923d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton return target # success 3933d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton print 'crashlog.create_target()...3' 394e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton for image in self.images: 3953d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton target = image.create_target () 3963d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton if target: 3973d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton return target # success 3983d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton print 'crashlog.create_target()...4' 3993d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton print 'error: unable to locate any executables from the crash log' 4003d39f83d308f4c147cff81e07c8059eb52dab89dGreg Clayton return None 4011b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton 40201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 40301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytondef usage(): 40401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "Usage: lldb-symbolicate.py [-n name] executable-image" 40501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton sys.exit(0) 40601f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 4079d01042727a9c52cbab76237c8d290f2e337067dGreg Claytonclass Interactive(cmd.Cmd): 4089d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton '''Interactive prompt for analyzing one or more Darwin crash logs, type "help" to see a list of supported commands.''' 4099d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton image_option_parser = None 4109d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 4119d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton def __init__(self, crash_logs): 4129d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton cmd.Cmd.__init__(self) 413dcf561419ff815256d63dedeba06d9b5c969702aGreg Clayton self.use_rawinput = False 4149d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton self.intro = 'Interactive crashlogs prompt, type "help" to see a list of supported commands.' 4159d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton self.crash_logs = crash_logs 4169d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton self.prompt = '% ' 4179d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 4189d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton def default(self, line): 4199d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton '''Catch all for unknown command, which will exit the interpreter.''' 4209d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton print "uknown command: %s" % line 4219d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton return True 4229d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 4239d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton def do_q(self, line): 4249d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton '''Quit command''' 4259d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton return True 4269d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 4279d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton def do_quit(self, line): 4289d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton '''Quit command''' 4299d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton return True 4309d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 431a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton def do_symbolicate(self, line): 432a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton description='''Symbolicate one or more darwin crash log files by index to provide source file and line information, 433a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton inlined stack frames back to the concrete functions, and disassemble the location of the crash 434a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton for the first frame of the crashed thread.''' 435a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton option_parser = CreateSymbolicateCrashLogOptions ('symbolicate', description, False) 436a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton command_args = shlex.split(line) 437a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton try: 438a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton (options, args) = option_parser.parse_args(command_args) 439a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton except: 440a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton return 441a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 442a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton if args: 443a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton # We have arguments, they must valid be crash log file indexes 444a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton for idx_str in args: 445a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton idx = int(idx_str) 446a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton if idx < len(self.crash_logs): 447a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton SymbolicateCrashLog (self.crash_logs[idx], options) 448a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton else: 449a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton print 'error: crash log index %u is out of range' % (idx) 450a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton else: 451a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton # No arguments, symbolicate all crash logs using the options provided 452a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton for idx in range(len(self.crash_logs)): 453a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton SymbolicateCrashLog (self.crash_logs[idx], options) 454a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 4559d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton def do_list(self, line=None): 4569d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton '''Dump a list of all crash logs that are currently loaded. 4579d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 4589d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton USAGE: list''' 4599d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton print '%u crash logs are loaded:' % len(self.crash_logs) 4609d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for (crash_log_idx, crash_log) in enumerate(self.crash_logs): 4619d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton print '[%u] = %s' % (crash_log_idx, crash_log.path) 4629d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 4639d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton def do_image(self, line): 464a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton '''Dump information about one or more binary images in the crash log given an image basename, or all images if no arguments are provided.''' 4659d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton usage = "usage: %prog [options] <PATH> [PATH ...]" 466a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton description='''Dump information about one or more images in all crash logs. The <PATH> can be a full path, image basename, or partial path. Searches are done in this order.''' 4679d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton command_args = shlex.split(line) 4689d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton if not self.image_option_parser: 4699d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton self.image_option_parser = optparse.OptionParser(description=description, prog='image',usage=usage) 4709d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton self.image_option_parser.add_option('-a', '--all', action='store_true', help='show all images', default=False) 4719d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton try: 4729d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton (options, args) = self.image_option_parser.parse_args(command_args) 4739d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton except: 4749d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton return 4759d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 476d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton if args: 477d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton for image_path in args: 478d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton fullpath_search = image_path[0] == '/' 479a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton for (crash_log_idx, crash_log) in enumerate(self.crash_logs): 480d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton matches_found = 0 481d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton for (image_idx, image) in enumerate(crash_log.images): 482d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton if fullpath_search: 483d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton if image.get_resolved_path() == image_path: 484d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton matches_found += 1 485a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton print '[%u] ' % (crash_log_idx), image 486d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton else: 487d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton image_basename = image.get_resolved_path_basename() 488d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton if image_basename == image_path: 489d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton matches_found += 1 490a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton print '[%u] ' % (crash_log_idx), image 491d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton if matches_found == 0: 492d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton for (image_idx, image) in enumerate(crash_log.images): 49335f62f8ff21c41cd6812704cf3c8c79f8755fef7Greg Clayton resolved_image_path = image.get_resolved_path() 49435f62f8ff21c41cd6812704cf3c8c79f8755fef7Greg Clayton if resolved_image_path and string.find(image.get_resolved_path(), image_path) >= 0: 495a838b421d5de1925ed7c1ca783796b8a0cfc5ed8Greg Clayton print '[%u] ' % (crash_log_idx), image 496d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton else: 4979d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for crash_log in self.crash_logs: 4989d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for (image_idx, image) in enumerate(crash_log.images): 499d8056e20e5a06bd0f7185f962fda3f5a179f71abGreg Clayton print '[%u] %s' % (image_idx, image) 5009d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton return False 5019d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 5029d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 5039d01042727a9c52cbab76237c8d290f2e337067dGreg Claytondef interactive_crashlogs(options, args): 5049d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton crash_log_files = list() 5059d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for arg in args: 5069d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for resolved_path in glob.glob(arg): 5079d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton crash_log_files.append(resolved_path) 5089d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 5099d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton crash_logs = list(); 5109d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for crash_log_file in crash_log_files: 5119d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton #print 'crash_log_file = "%s"' % crash_log_file 5129d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton crash_log = CrashLog(crash_log_file) 5139d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton if crash_log.error: 5149d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton print crash_log.error 5159d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton continue 5162b69a2bac83a9163903934eedd1a2264e8558f8bGreg Clayton if options.debug: 5179d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton crash_log.dump() 5189d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton if not crash_log.images: 5199d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton print 'error: no images in crash log "%s"' % (crash_log) 5209d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton continue 5219d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton else: 5229d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton crash_logs.append(crash_log) 5239d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 5249d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton interpreter = Interactive(crash_logs) 5259d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton # List all crash logs that were imported 5269d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton interpreter.do_list() 5279d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton interpreter.cmdloop() 5289d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 529ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton 530ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Claytondef save_crashlog(debugger, command, result, dict): 531ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton usage = "usage: %prog [options] <output-path>" 532ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton description='''Export the state of current target into a crashlog file''' 533ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton parser = optparse.OptionParser(description=description, prog='save_crashlog',usage=usage) 534ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) 535ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton try: 536ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton (options, args) = parser.parse_args(shlex.split(command)) 537ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton except: 538ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton result.PutCString ("error: invalid options"); 539ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton return 540ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if len(args) != 1: 541ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton result.PutCString ("error: invalid arguments, a single output file is the only valid argument") 542ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton return 543ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file = open(args[0], 'w') 544ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if not out_file: 545ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton result.PutCString ("error: failed to open file '%s' for writing...", args[0]); 546ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton return 547ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if lldb.target: 548ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton identifier = lldb.target.executable.basename 549ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if lldb.process: 550ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton pid = lldb.process.id 551ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if pid != lldb.LLDB_INVALID_PROCESS_ID: 552ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('Process: %s [%u]\n' % (identifier, pid)) 553ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('Path: %s\n' % (lldb.target.executable.fullpath)) 554ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('Identifier: %s\n' % (identifier)) 555ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('\nDate/Time: %s\n' % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) 556ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('OS Version: Mac OS X %s (%s)\n' % (platform.mac_ver()[0], commands.getoutput('sysctl -n kern.osversion'))); 557ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('Report Version: 9\n') 558ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton for thread_idx in range(lldb.process.num_threads): 559ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton thread = lldb.process.thread[thread_idx] 560ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('\nThread %u:\n' % (thread_idx)) 561ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton for (frame_idx, frame) in enumerate(thread.frames): 562ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton frame_pc = frame.pc 563ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton frame_offset = 0 564ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if frame.function: 565ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton block = frame.GetFrameBlock() 566ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton block_range = block.range[frame.addr] 567ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if block_range: 568ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton block_start_addr = block_range[0] 569ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton frame_offset = frame_pc - block_start_addr.load_addr 570ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton else: 571ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton frame_offset = frame_pc - frame.function.addr.load_addr 572ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton elif frame.symbol: 573ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton frame_offset = frame_pc - frame.symbol.addr.load_addr 574ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('%-3u %-32s 0x%16.16x %s' % (frame_idx, frame.module.file.basename, frame_pc, frame.name)) 575ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if frame_offset > 0: 576ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write(' + %u' % (frame_offset)) 577ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton line_entry = frame.line_entry 578ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if line_entry: 579ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if options.verbose: 580ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton # This will output the fullpath + line + column 581ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write(' %s' % (line_entry)) 582ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton else: 583ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write(' %s:%u' % (line_entry.file.basename, line_entry.line)) 584ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton column = line_entry.column 585ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if column: 586ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write(':%u' % (column)) 587ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('\n') 588ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton 589ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write('\nBinary Images:\n') 590ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton for module in lldb.target.modules: 591ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton text_segment = module.section['__TEXT'] 592ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if text_segment: 593ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton text_segment_load_addr = text_segment.GetLoadAddress(lldb.target) 594ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if text_segment_load_addr != lldb.LLDB_INVALID_ADDRESS: 595ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton text_segment_end_load_addr = text_segment_load_addr + text_segment.size 596ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton identifier = module.file.basename 597ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton module_version = '???' 598ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton module_version_array = module.GetVersion() 599ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton if module_version_array: 600ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton module_version = '.'.join(map(str,module_version_array)) 601ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.write (' 0x%16.16x - 0x%16.16x %s (%s - ???) <%s> %s\n' % (text_segment_load_addr, text_segment_end_load_addr, identifier, module_version, module.GetUUIDString(), module.file.fullpath)) 602ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton out_file.close() 603ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton else: 604ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton result.PutCString ("error: invalid target"); 6059d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 606ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton 60701f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytondef Symbolicate(debugger, command, result, dict): 608223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton try: 609a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton SymbolicateCrashLogs (shlex.split(command)) 610223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton except: 611223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton result.PutCString ("error: python exception %s" % sys.exc_info()[0]) 612a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 613a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Claytondef SymbolicateCrashLog(crash_log, options): 614a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if crash_log.error: 615a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print crash_log.error 616a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton return 6172b69a2bac83a9163903934eedd1a2264e8558f8bGreg Clayton if options.debug: 618a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton crash_log.dump() 619a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if not crash_log.images: 620a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print 'error: no images in crash log' 621a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton return 622a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 62349ce8969d3154e1560106cfe530444c09410f217Greg Clayton if options.dump_image_list: 62449ce8969d3154e1560106cfe530444c09410f217Greg Clayton print "Binary Images:" 62549ce8969d3154e1560106cfe530444c09410f217Greg Clayton for image in crash_log.images: 62649ce8969d3154e1560106cfe530444c09410f217Greg Clayton if options.verbose: 62749ce8969d3154e1560106cfe530444c09410f217Greg Clayton print image.debug_dump() 62849ce8969d3154e1560106cfe530444c09410f217Greg Clayton else: 62949ce8969d3154e1560106cfe530444c09410f217Greg Clayton print image 63049ce8969d3154e1560106cfe530444c09410f217Greg Clayton 631a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton target = crash_log.create_target () 632a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if not target: 633a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton return 634a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton exe_module = target.GetModuleAtIndex(0) 635a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton images_to_load = list() 636a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton loaded_images = list() 637a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if options.load_all_images: 638a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton # --load-all option was specified, load everything up 639a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton for image in crash_log.images: 640a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton images_to_load.append(image) 641a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton else: 642a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton # Only load the images found in stack frames for the crashed threads 643aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if options.crashed_only: 644aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton for thread in crash_log.threads: 645aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if thread.did_crash(): 646aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton for ident in thread.idents: 647aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton images = crash_log.find_images_with_identifier (ident) 648aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if images: 649aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton for image in images: 650aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton images_to_load.append(image) 651aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton else: 652aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton print 'error: can\'t find image for identifier "%s"' % ident 653aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton else: 654aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton for ident in crash_log.idents: 655aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton images = crash_log.find_images_with_identifier (ident) 656aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if images: 657aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton for image in images: 658aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton images_to_load.append(image) 659aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton else: 660aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton print 'error: can\'t find image for identifier "%s"' % ident 661a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 662a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton for image in images_to_load: 663a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if image in loaded_images: 664a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print "warning: skipping %s loaded at %#16.16x duplicate entry (probably commpage)" % (image.path, image.text_addr_lo) 665a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton else: 666a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton err = image.add_module (target) 667a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if err: 668a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print err 669a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton else: 670a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton #print 'loaded %s' % image 671a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton loaded_images.append(image) 672a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 673a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton for thread in crash_log.threads: 674a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton this_thread_crashed = thread.did_crash() 675a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if options.crashed_only and this_thread_crashed == False: 676a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton continue 677a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print "%s" % thread 678a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton #prev_frame_index = -1 679007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton display_frame_idx = -1 680a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton for frame_idx, frame in enumerate(thread.frames): 681a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth; 682a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if frame_idx == 0: 6834bb82ac1db085a11d22df3dff6def07119643255Greg Clayton symbolicated_frame_addresses = crash_log.symbolicate (frame.pc & crash_log.addr_mask, options.verbose) 684a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton else: 685a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton # Any frame above frame zero and we have to subtract one to get the previous line entry 6864bb82ac1db085a11d22df3dff6def07119643255Greg Clayton symbolicated_frame_addresses = crash_log.symbolicate ((frame.pc & crash_log.addr_mask) - 1, options.verbose) 687a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 688a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if symbolicated_frame_addresses: 689a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton symbolicated_frame_address_idx = 0 690a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton for symbolicated_frame_address in symbolicated_frame_addresses: 691007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton display_frame_idx += 1 692a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print '[%3u] %s' % (frame_idx, symbolicated_frame_address) 693007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton if (options.source_all or thread.did_crash()) and display_frame_idx < options.source_frames and options.source_context: 694007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton source_context = options.source_context 695aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton line_entry = symbolicated_frame_address.get_symbol_context().line_entry 696aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if line_entry.IsValid(): 697aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton strm = lldb.SBStream() 698aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if line_entry: 699007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton lldb.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers(line_entry.file, line_entry.line, source_context, source_context, "->", strm) 700aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton source_text = strm.GetData() 701aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton if source_text: 702aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton # Indent the source a bit 703aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton indent_str = ' ' 704aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton join_str = '\n' + indent_str 705aa7df343b30d147fe7755b407f631726ed1fe0f9Greg Clayton print '%s%s' % (indent_str, join_str.join(source_text.split('\n'))) 706a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if symbolicated_frame_address_idx == 0: 707a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if disassemble: 708a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton instructions = symbolicated_frame_address.get_instructions() 709a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if instructions: 710a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print 711a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton symbolication.disassemble_instructions (target, 712a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton instructions, 713a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton frame.pc, 714a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton options.disassemble_before, 715a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton options.disassemble_after, frame.index > 0) 716a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print 717a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton symbolicated_frame_address_idx += 1 718a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton else: 719a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print frame 720a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton print 721a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 722a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Claytondef CreateSymbolicateCrashLogOptions(command_name, description, add_interactive_options): 723a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton usage = "usage: %prog [options] <FILE> [FILE ...]" 724a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton option_parser = optparse.OptionParser(description=description, prog='crashlog',usage=usage) 725007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--verbose' , '-v', action='store_true', dest='verbose', help='display verbose debug info', default=False) 726007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--debug' , '-g', action='store_true', dest='debug', help='display verbose debug logging', default=False) 727007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--load-all' , '-a', action='store_true', dest='load_all_images', help='load all executable images, not just the images found in the crashed stack frames', default=False) 728007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--images' , action='store_true', dest='dump_image_list', help='show image list', default=False) 729007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--debug-delay' , type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0) 730007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--crashed-only' , '-c', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False) 731007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--disasm-depth' , '-d', type='int', dest='disassemble_depth', help='set the depth in stack frames that should be disassembled (default is 1)', default=1) 732007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--disasm-all' , '-D', action='store_true', dest='disassemble_all_threads', help='enabled disassembly of frames on all threads (not just the crashed thread)', default=False) 733007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--disasm-before' , '-B', type='int', dest='disassemble_before', help='the number of instructions to disassemble before the frame PC', default=4) 734007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--disasm-after' , '-A', type='int', dest='disassemble_after', help='the number of instructions to disassemble after the frame PC', default=4) 735007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--source-context', '-C', type='int', metavar='NLINES', dest='source_context', help='show NLINES source lines of source context (default = 4)', default=4) 736007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--source-frames' , type='int', metavar='NFRAMES', dest='source_frames', help='show source for NFRAMES (default = 4)', default=4) 737007f73a55393839e9c977a4ec8c06d5721eaba06Greg Clayton option_parser.add_option('--source-all' , action='store_true', dest='source_all', help='show source for all threads, not just the crashed thread', default=False) 738a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton if add_interactive_options: 739a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton option_parser.add_option('-i', '--interactive', action='store_true', help='parse all crash logs and enter interactive mode', default=False) 740a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton return option_parser 741a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton 742a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Claytondef SymbolicateCrashLogs(command_args): 743a3698c61d6c34bab696bf82e64062d1d0438d452Greg Clayton description='''Symbolicate one or more darwin crash log files to provide source file and line information, 744a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytoninlined stack frames back to the concrete functions, and disassemble the location of the crash 745a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytonfor the first frame of the crashed thread. 746a3698c61d6c34bab696bf82e64062d1d0438d452Greg ClaytonIf this script is imported into the LLDB command interpreter, a "crashlog" command will be added to the interpreter 747a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytonfor use at the LLDB command line. After a crash log has been parsed and symbolicated, a target will have been 748a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytoncreated that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows 749a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytonyou to explore the program as if it were stopped at the locations described in the crash log and functions can 750a3698c61d6c34bab696bf82e64062d1d0438d452Greg Claytonbe disassembled and lookups can be performed using the addresses found in the crash log.''' 751a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton option_parser = CreateSymbolicateCrashLogOptions ('crashlog', description, True) 752223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton try: 753a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton (options, args) = option_parser.parse_args(command_args) 754223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton except: 755223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton return 756223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton 7572b69a2bac83a9163903934eedd1a2264e8558f8bGreg Clayton if options.debug: 758223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton print 'command_args = %s' % command_args 75901f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print 'options', options 760223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton print 'args', args 761223e808ff04ddefb64861f8d8b99e1c6651a5222Greg Clayton 76201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton if options.debug_delay > 0: 76301f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton print "Waiting %u seconds for debugger to attach..." % options.debug_delay 76401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton time.sleep(options.debug_delay) 76501f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton error = lldb.SBError() 7669d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton 767e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton if args: 7689d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton if options.interactive: 7699d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton interactive_crashlogs(options, args) 7709d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton else: 7719d01042727a9c52cbab76237c8d290f2e337067dGreg Clayton for crash_log_file in args: 7721b62f5967aa04ebde2ae163f12c739a6740596e2Greg Clayton crash_log = CrashLog(crash_log_file) 773a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton SymbolicateCrashLog (crash_log, options) 77401f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Claytonif __name__ == '__main__': 775e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton # Create a new debugger instance 776e9ee550693aee8122d3d48b633fcff64e6a2f641Greg Clayton lldb.debugger = lldb.SBDebugger.Create() 777a3368ddf9c2cc0b29fb7d329b5f6dfe5a7443b1dGreg Clayton SymbolicateCrashLogs (sys.argv[1:]) 778a889aee9354d532a250a8c5b8661a6c6f191297fJohnny Chenelif getattr(lldb, 'debugger', None): 7796f2f0ab38426bdb5ed347f057ba57248667a40c3Greg Clayton lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.Symbolicate crashlog') 780ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.save_crashlog save_crashlog') 781ca1500f43dc65a0234dd4e8fb129ea366d512cc5Greg Clayton print '"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help' 78201f7c96144d4604d1d120fb27643f9a29d6d1ba7Greg Clayton 783