blob: 826b15ceb2ac03e9905eb9ecb86e1988adc7a7c4 [file] [log] [blame]
Greg Claytonaa9d02b2012-01-20 03:15:45 +00001#!/usr/bin/python
2
3#----------------------------------------------------------------------
4# Be sure to add the python path that points to the LLDB shared library.
Greg Clayton5c0f4832012-01-21 00:37:19 +00005#
6# To use this in the embedded python interpreter using "lldb":
7#
8# cd /path/containing/crashlog.py
9# lldb
10# (lldb) script import crashlog
11# "crashlog" command installed, type "crashlog --help" for detailed help
12# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash
13#
14# The benefit of running the crashlog command inside lldb in the
15# embedded python interpreter is when the command completes, there
16# will be a target with all of the files loaded at the locations
17# described in the crash log. Only the files that have stack frames
18# in the backtrace will be loaded unless the "--load-all" option
19# has been specified. This allows users to explore the program in the
20# state it was in right at crash time.
21#
Greg Claytonaa9d02b2012-01-20 03:15:45 +000022# On MacOSX csh, tcsh:
Greg Clayton5c0f4832012-01-21 00:37:19 +000023# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )
24#
Greg Claytonaa9d02b2012-01-20 03:15:45 +000025# On MacOSX sh, bash:
Greg Clayton5c0f4832012-01-21 00:37:19 +000026# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash
Greg Claytonaa9d02b2012-01-20 03:15:45 +000027#----------------------------------------------------------------------
28
29import lldb
Greg Clayton5c0f4832012-01-21 00:37:19 +000030import commands
Greg Claytonaa9d02b2012-01-20 03:15:45 +000031import optparse
32import os
33import plistlib
Greg Clayton3c2c4bb2012-04-03 21:35:43 +000034import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args)
Greg Claytonaa9d02b2012-01-20 03:15:45 +000035import re
Greg Clayton53b43b02012-01-21 04:26:24 +000036import shlex
Greg Claytonaa9d02b2012-01-20 03:15:45 +000037import sys
38import time
Greg Clayton3d8d3db2012-01-20 06:12:47 +000039import uuid
Greg Claytoned3eee62012-04-25 01:49:50 +000040import lldb.utils.symbolication
Greg Claytonaa9d02b2012-01-20 03:15:45 +000041
42PARSE_MODE_NORMAL = 0
43PARSE_MODE_THREAD = 1
44PARSE_MODE_IMAGES = 2
45PARSE_MODE_THREGS = 3
46PARSE_MODE_SYSTEM = 4
47
Greg Claytoned3eee62012-04-25 01:49:50 +000048class CrashLog(lldb.utils.symbolication.Symbolicator):
Greg Claytonaa9d02b2012-01-20 03:15:45 +000049 """Class that does parses darwin crash logs"""
50 thread_state_regex = re.compile('^Thread ([0-9]+) crashed with')
51 thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)')
Greg Claytona32bfbe2012-01-20 03:32:35 +000052 frame_regex = re.compile('^([0-9]+) +([^ ]+) *\t(0x[0-9a-fA-F]+) +(.*)')
53 image_regex_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^<]+)<([-0-9a-fA-F]+)> (.*)');
54 image_regex_no_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^/]+)/(.*)');
Greg Claytonaa9d02b2012-01-20 03:15:45 +000055 empty_line_regex = re.compile('^$')
56
57 class Thread:
58 """Class that represents a thread in a darwin crash log"""
59 def __init__(self, index):
60 self.index = index
61 self.frames = list()
62 self.registers = dict()
63 self.reason = None
64 self.queue = None
65
66 def dump(self, prefix):
67 print "%sThread[%u] %s" % (prefix, self.index, self.reason)
68 if self.frames:
69 print "%s Frames:" % (prefix)
70 for frame in self.frames:
71 frame.dump(prefix + ' ')
72 if self.registers:
73 print "%s Registers:" % (prefix)
74 for reg in self.registers.keys():
75 print "%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg])
76
77 def did_crash(self):
78 return self.reason != None
79
80 def __str__(self):
81 s = "Thread[%u]" % self.index
82 if self.reason:
83 s += ' %s' % self.reason
84 return s
85
86
87 class Frame:
88 """Class that represents a stack frame in a thread in a darwin crash log"""
Greg Clayton3c2c4bb2012-04-03 21:35:43 +000089 def __init__(self, index, pc, description):
Greg Claytonaa9d02b2012-01-20 03:15:45 +000090 self.pc = pc
Greg Clayton3c2c4bb2012-04-03 21:35:43 +000091 self.description = description
92 self.index = index
Greg Claytonaa9d02b2012-01-20 03:15:45 +000093
94 def __str__(self):
Greg Clayton3c2c4bb2012-04-03 21:35:43 +000095 if self.description:
96 return "[%3u] 0x%16.16x %s" % (self.index, self.pc, self.description)
97 else:
Johnny Chen8e1fd432012-05-03 18:46:28 +000098 return "[%3u] 0x%16.16x" % (self.index, self.pc)
99
100 def dump(self, prefix):
101 print "%s%s" % (prefix, str(self))
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000102
Greg Claytoned3eee62012-04-25 01:49:50 +0000103 class DarwinImage(lldb.utils.symbolication.Image):
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000104 """Class that represents a binary images in a darwin crash log"""
Greg Claytona32bfbe2012-01-20 03:32:35 +0000105 dsymForUUIDBinary = os.path.expanduser('~rc/bin/dsymForUUID')
Greg Clayton3d8d3db2012-01-20 06:12:47 +0000106 if not os.path.exists(dsymForUUIDBinary):
107 dsymForUUIDBinary = commands.getoutput('which dsymForUUID')
108
109 dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*')
Greg Claytona32bfbe2012-01-20 03:32:35 +0000110
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000111 def __init__(self, text_addr_lo, text_addr_hi, identifier, version, uuid, path):
Greg Claytoned3eee62012-04-25 01:49:50 +0000112 lldb.utils.symbolication.Image.__init__(self, path, uuid);
113 self.add_section (lldb.utils.symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT"))
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000114 self.identifier = identifier
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000115 self.version = version
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000116
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000117 def locate_module_and_debug_symbols(self):
Greg Clayton3d8d3db2012-01-20 06:12:47 +0000118 if self.resolved_path:
119 # Don't load a module twice...
Greg Claytonf99295c2012-04-20 23:31:27 +0000120 return True
Greg Claytond712ef02012-04-25 18:40:20 +0000121 print 'Getting symbols for %s %s...' % (self.uuid, self.path),
Greg Claytona32bfbe2012-01-20 03:32:35 +0000122 if os.path.exists(self.dsymForUUIDBinary):
123 dsym_for_uuid_command = '%s %s' % (self.dsymForUUIDBinary, self.uuid)
Greg Claytona32bfbe2012-01-20 03:32:35 +0000124 s = commands.getoutput(dsym_for_uuid_command)
125 if s:
126 plist_root = plistlib.readPlistFromString (s)
127 if plist_root:
Greg Clayton3d8d3db2012-01-20 06:12:47 +0000128 plist = plist_root[self.uuid]
129 if plist:
130 if 'DBGArchitecture' in plist:
131 self.arch = plist['DBGArchitecture']
132 if 'DBGDSYMPath' in plist:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000133 self.symfile = os.path.realpath(plist['DBGDSYMPath'])
Greg Clayton3d8d3db2012-01-20 06:12:47 +0000134 if 'DBGSymbolRichExecutable' in plist:
135 self.resolved_path = os.path.expanduser (plist['DBGSymbolRichExecutable'])
136 if not self.resolved_path and os.path.exists(self.path):
137 dwarfdump_cmd_output = commands.getoutput('dwarfdump --uuid "%s"' % self.path)
138 self_uuid = uuid.UUID(self.uuid)
139 for line in dwarfdump_cmd_output.splitlines():
140 match = self.dwarfdump_uuid_regex.search (line)
141 if match:
142 dwarf_uuid_str = match.group(1)
143 dwarf_uuid = uuid.UUID(dwarf_uuid_str)
144 if self_uuid == dwarf_uuid:
145 self.resolved_path = self.path
146 self.arch = match.group(2)
147 break;
148 if not self.resolved_path:
149 print "error: file %s '%s' doesn't match the UUID in the installed file" % (self.uuid, self.path)
Greg Claytonf99295c2012-04-20 23:31:27 +0000150 return False
Greg Clayton3d8d3db2012-01-20 06:12:47 +0000151 if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)):
152 print 'ok'
Greg Claytond712ef02012-04-25 18:40:20 +0000153 # if self.resolved_path:
154 # print ' exe = "%s"' % self.resolved_path
155 # if self.symfile:
156 # print ' dsym = "%s"' % self.symfile
Greg Claytonf99295c2012-04-20 23:31:27 +0000157 return True
158 return False
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000159
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000160
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000161
162 def __init__(self, path):
163 """CrashLog constructor that take a path to a darwin crash log file"""
Greg Claytoned3eee62012-04-25 01:49:50 +0000164 lldb.utils.symbolication.Symbolicator.__init__(self);
Greg Clayton53b43b02012-01-21 04:26:24 +0000165 self.path = os.path.expanduser(path);
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000166 self.info_lines = list()
167 self.system_profile = list()
168 self.threads = list()
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000169 self.idents = list() # A list of the required identifiers for doing all stack backtraces
170 self.crashed_thread_idx = -1
171 self.version = -1
Greg Clayton53b43b02012-01-21 04:26:24 +0000172 self.error = None
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000173 # With possible initial component of ~ or ~user replaced by that user's home directory.
Greg Clayton53b43b02012-01-21 04:26:24 +0000174 try:
175 f = open(self.path)
176 except IOError:
177 self.error = 'error: cannot open "%s"' % self.path
178 return
179
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000180 self.file_lines = f.read().splitlines()
181 parse_mode = PARSE_MODE_NORMAL
182 thread = None
183 for line in self.file_lines:
184 # print line
185 line_len = len(line)
186 if line_len == 0:
187 if thread:
188 if parse_mode == PARSE_MODE_THREAD:
189 if thread.index == self.crashed_thread_idx:
190 thread.reason = ''
191 if self.thread_exception:
192 thread.reason += self.thread_exception
193 if self.thread_exception_data:
194 thread.reason += " (%s)" % self.thread_exception_data
195 self.threads.append(thread)
196 thread = None
197 else:
198 # only append an extra empty line if the previous line
199 # in the info_lines wasn't empty
200 if len(self.info_lines) > 0 and len(self.info_lines[-1]):
201 self.info_lines.append(line)
202 parse_mode = PARSE_MODE_NORMAL
203 # print 'PARSE_MODE_NORMAL'
204 elif parse_mode == PARSE_MODE_NORMAL:
205 if line.startswith ('Process:'):
206 (self.process_name, pid_with_brackets) = line[8:].strip().split()
207 self.process_id = pid_with_brackets.strip('[]')
208 elif line.startswith ('Path:'):
209 self.process_path = line[5:].strip()
210 elif line.startswith ('Identifier:'):
211 self.process_identifier = line[11:].strip()
212 elif line.startswith ('Version:'):
213 (self.process_version, compatability_version) = line[8:].strip().split()
214 self.process_compatability_version = compatability_version.strip('()')
215 elif line.startswith ('Parent Process:'):
216 (self.parent_process_name, pid_with_brackets) = line[15:].strip().split()
217 self.parent_process_id = pid_with_brackets.strip('[]')
218 elif line.startswith ('Exception Type:'):
219 self.thread_exception = line[15:].strip()
220 continue
221 elif line.startswith ('Exception Codes:'):
222 self.thread_exception_data = line[16:].strip()
223 continue
224 elif line.startswith ('Crashed Thread:'):
225 self.crashed_thread_idx = int(line[15:].strip().split()[0])
226 continue
227 elif line.startswith ('Report Version:'):
228 self.version = int(line[15:].strip())
229 continue
230 elif line.startswith ('System Profile:'):
231 parse_mode = PARSE_MODE_SYSTEM
232 continue
233 elif (line.startswith ('Interval Since Last Report:') or
234 line.startswith ('Crashes Since Last Report:') or
235 line.startswith ('Per-App Interval Since Last Report:') or
236 line.startswith ('Per-App Crashes Since Last Report:') or
237 line.startswith ('Sleep/Wake UUID:') or
238 line.startswith ('Anonymous UUID:')):
239 # ignore these
240 continue
241 elif line.startswith ('Thread'):
242 thread_state_match = self.thread_state_regex.search (line)
243 if thread_state_match:
244 thread_state_match = self.thread_regex.search (line)
245 thread_idx = int(thread_state_match.group(1))
246 parse_mode = PARSE_MODE_THREGS
247 thread = self.threads[thread_idx]
248 else:
249 thread_match = self.thread_regex.search (line)
250 if thread_match:
251 # print 'PARSE_MODE_THREAD'
252 parse_mode = PARSE_MODE_THREAD
253 thread_idx = int(thread_match.group(1))
254 thread = CrashLog.Thread(thread_idx)
255 continue
256 elif line.startswith ('Binary Images:'):
257 parse_mode = PARSE_MODE_IMAGES
258 continue
259 self.info_lines.append(line.strip())
260 elif parse_mode == PARSE_MODE_THREAD:
261 frame_match = self.frame_regex.search(line)
262 if frame_match:
263 ident = frame_match.group(2)
264 if not ident in self.idents:
265 self.idents.append(ident)
266 thread.frames.append (CrashLog.Frame(int(frame_match.group(1)), int(frame_match.group(3), 0), frame_match.group(4)))
267 else:
Greg Claytona32bfbe2012-01-20 03:32:35 +0000268 print 'error: frame regex failed for line: "%s"' % line
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000269 elif parse_mode == PARSE_MODE_IMAGES:
270 image_match = self.image_regex_uuid.search (line)
271 if image_match:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000272 image = CrashLog.DarwinImage (int(image_match.group(1),0),
273 int(image_match.group(2),0),
274 image_match.group(3).strip(),
275 image_match.group(4).strip(),
276 image_match.group(5),
277 image_match.group(6))
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000278 self.images.append (image)
279 else:
280 image_match = self.image_regex_no_uuid.search (line)
281 if image_match:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000282 image = CrashLog.DarwinImage (int(image_match.group(1),0),
283 int(image_match.group(2),0),
284 image_match.group(3).strip(),
285 image_match.group(4).strip(),
286 None,
287 image_match.group(5))
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000288 self.images.append (image)
289 else:
290 print "error: image regex failed for: %s" % line
291
292 elif parse_mode == PARSE_MODE_THREGS:
293 stripped_line = line.strip()
294 reg_values = stripped_line.split(' ')
295 for reg_value in reg_values:
296 (reg, value) = reg_value.split(': ')
297 thread.registers[reg.strip()] = int(value, 0)
298 elif parse_mode == PARSE_MODE_SYSTEM:
299 self.system_profile.append(line)
300 f.close()
301
302 def dump(self):
303 print "Crash Log File: %s" % (self.path)
304 print "\nThreads:"
305 for thread in self.threads:
306 thread.dump(' ')
307 print "\nImages:"
308 for image in self.images:
309 image.dump(' ')
310
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000311 def find_image_with_identifier(self, identifier):
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000312 for image in self.images:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000313 if image.identifier == identifier:
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000314 return image
315 return None
316
Greg Clayton42a6eb72012-01-20 19:25:32 +0000317 def create_target(self):
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000318 #print 'crashlog.create_target()...'
Greg Claytoned3eee62012-04-25 01:49:50 +0000319 target = lldb.utils.symbolication.Symbolicator.create_target(self)
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000320 if target:
321 return target
Greg Clayton42a6eb72012-01-20 19:25:32 +0000322 # We weren't able to open the main executable as, but we can still symbolicate
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000323 print 'crashlog.create_target()...2'
Greg Clayton42a6eb72012-01-20 19:25:32 +0000324 if self.idents:
Sean Callanan88685f22012-01-20 19:27:48 +0000325 for ident in self.idents:
Greg Clayton42a6eb72012-01-20 19:25:32 +0000326 image = self.find_image_with_identifier (ident)
327 if image:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000328 target = image.create_target ()
329 if target:
330 return target # success
331 print 'crashlog.create_target()...3'
Greg Clayton42a6eb72012-01-20 19:25:32 +0000332 for image in self.images:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000333 target = image.create_target ()
334 if target:
335 return target # success
336 print 'crashlog.create_target()...4'
337 print 'error: unable to locate any executables from the crash log'
338 return None
Greg Clayton42a6eb72012-01-20 19:25:32 +0000339
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000340
341def usage():
342 print "Usage: lldb-symbolicate.py [-n name] executable-image"
343 sys.exit(0)
344
345def Symbolicate(debugger, command, result, dict):
Greg Clayton53b43b02012-01-21 04:26:24 +0000346 try:
347 SymbolicateCrashLog (shlex.split(command))
348 except:
349 result.PutCString ("error: python exception %s" % sys.exc_info()[0])
350
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000351def SymbolicateCrashLog(command_args):
Greg Clayton5c0f4832012-01-21 00:37:19 +0000352 usage = "usage: %prog [options] <FILE> [FILE ...]"
353 description='''Symbolicate one or more darwin crash log files to provide source file and line information,
354inlined stack frames back to the concrete functions, and disassemble the location of the crash
355for the first frame of the crashed thread.
356If this script is imported into the LLDB command interpreter, a "crashlog" command will be added to the interpreter
357for use at the LLDB command line. After a crash log has been parsed and symbolicated, a target will have been
358created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows
359you to explore the program as if it were stopped at the locations described in the crash log and functions can
360be disassembled and lookups can be performed using the addresses found in the crash log.'''
361 parser = optparse.OptionParser(description=description, prog='crashlog.py',usage=usage)
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000362 parser.add_option('--platform', type='string', metavar='platform', dest='platform', help='specify one platform by name')
Greg Claytonbc48f322012-01-21 05:10:20 +0000363 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000364 parser.add_option('--no-images', action='store_false', dest='show_images', help='don\'t show images in stack frames', default=True)
Greg Claytonbc48f322012-01-21 05:10:20 +0000365 parser.add_option('-a', '--load-all', action='store_true', dest='load_all_images', help='load all executable images, not just the images found in the crashed stack frames', default=False)
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000366 parser.add_option('--image-list', action='store_true', dest='dump_image_list', help='show image list', default=False)
Greg Claytonbc48f322012-01-21 05:10:20 +0000367 parser.add_option('-g', '--debug-delay', type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0)
368 parser.add_option('-c', '--crashed-only', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False)
369 parser.add_option('-d', '--disasm-depth', type='int', dest='disassemble_depth', help='set the depth in stack frames that should be disassembled (default is 1)', default=1)
370 parser.add_option('-D', '--disasm-all', action='store_true', dest='disassemble_all_threads', help='enabled disassembly of frames on all threads (not just the crashed thread)', default=False)
371 parser.add_option('-B', '--disasm-before', type='int', dest='disassemble_before', help='the number of instructions to disassemble before the frame PC', default=4)
372 parser.add_option('-A', '--disasm-after', type='int', dest='disassemble_after', help='the number of instructions to disassemble after the frame PC', default=4)
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000373 loaded_addresses = False
Greg Clayton53b43b02012-01-21 04:26:24 +0000374 try:
375 (options, args) = parser.parse_args(command_args)
376 except:
377 return
378
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000379 if options.verbose:
Greg Clayton53b43b02012-01-21 04:26:24 +0000380 print 'command_args = %s' % command_args
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000381 print 'options', options
Greg Clayton53b43b02012-01-21 04:26:24 +0000382 print 'args', args
383
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000384 if options.debug_delay > 0:
385 print "Waiting %u seconds for debugger to attach..." % options.debug_delay
386 time.sleep(options.debug_delay)
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000387 error = lldb.SBError()
Greg Clayton42a6eb72012-01-20 19:25:32 +0000388 if args:
389 for crash_log_file in args:
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000390 crash_log = CrashLog(crash_log_file)
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000391
392 #pp = pprint.PrettyPrinter(indent=4); pp.pprint(args)
Greg Clayton53b43b02012-01-21 04:26:24 +0000393 if crash_log.error:
394 print crash_log.error
395 return
Greg Claytona32bfbe2012-01-20 03:32:35 +0000396 if options.verbose:
397 crash_log.dump()
Greg Clayton5c0f4832012-01-21 00:37:19 +0000398 if not crash_log.images:
399 print 'error: no images in crash log'
400 return
401
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000402 target = crash_log.create_target ()
403 if not target:
Greg Clayton5c0f4832012-01-21 00:37:19 +0000404 return
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000405 exe_module = target.GetModuleAtIndex(0)
Greg Clayton5c0f4832012-01-21 00:37:19 +0000406 images_to_load = list()
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000407 loaded_images = list()
Greg Clayton5c0f4832012-01-21 00:37:19 +0000408 if options.load_all_images:
409 # --load-all option was specified, load everything up
410 for image in crash_log.images:
411 images_to_load.append(image)
412 else:
413 # Only load the images found in stack frames for the crashed threads
414 for ident in crash_log.idents:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000415 images = crash_log.find_images_with_identifier (ident)
416 if images:
417 for image in images:
418 images_to_load.append(image)
Greg Clayton5c0f4832012-01-21 00:37:19 +0000419 else:
420 print 'error: can\'t find image for identifier "%s"' % ident
421
422 for image in images_to_load:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000423 if image in loaded_images:
Greg Clayton5c0f4832012-01-21 00:37:19 +0000424 print "warning: skipping %s loaded at %#16.16x duplicate entry (probably commpage)" % (image.path, image.text_addr_lo)
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000425 else:
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000426 err = image.add_module (target)
Greg Clayton5c0f4832012-01-21 00:37:19 +0000427 if err:
428 print err
429 else:
Greg Claytond712ef02012-04-25 18:40:20 +0000430 #print 'loaded %s' % image
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000431 loaded_images.append(image)
Greg Clayton5c0f4832012-01-21 00:37:19 +0000432
Greg Clayton5c0f4832012-01-21 00:37:19 +0000433 for thread in crash_log.threads:
434 this_thread_crashed = thread.did_crash()
435 if options.crashed_only and this_thread_crashed == False:
436 continue
437 print "%s" % thread
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000438 #prev_frame_index = -1
Greg Clayton5c0f4832012-01-21 00:37:19 +0000439 for frame_idx, frame in enumerate(thread.frames):
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000440 disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth;
441 symbolicated_frame_addresses = crash_log.symbolicate (frame.pc)
442 if symbolicated_frame_addresses:
443 symbolicated_frame_address_idx = 0
444 for symbolicated_frame_address in symbolicated_frame_addresses:
445 print '[%3u] %s' % (frame_idx, symbolicated_frame_address)
446
447 if symbolicated_frame_address_idx == 0:
448 if disassemble:
449 instructions = symbolicated_frame_address.get_instructions()
450 if instructions:
451 print
Greg Claytoned3eee62012-04-25 01:49:50 +0000452 lldb.utils.symbolication.disassemble_instructions (target,
453 instructions,
454 frame.pc,
455 options.disassemble_before,
456 options.disassemble_after, frame.index > 0)
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000457 print
458 symbolicated_frame_address_idx += 1
459 else:
460 print frame
Greg Clayton5c0f4832012-01-21 00:37:19 +0000461 print
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000462
Greg Clayton5c0f4832012-01-21 00:37:19 +0000463 if options.dump_image_list:
464 print "Binary Images:"
465 for image in crash_log.images:
466 print image
467
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000468if __name__ == '__main__':
Greg Clayton42a6eb72012-01-20 19:25:32 +0000469 # Create a new debugger instance
470 lldb.debugger = lldb.SBDebugger.Create()
Greg Clayton3c2c4bb2012-04-03 21:35:43 +0000471 SymbolicateCrashLog (sys.argv[1:])
Johnny Chen356782f2012-05-03 22:31:30 +0000472elif getattr(lldb, 'debugger', None):
Greg Claytoned3eee62012-04-25 01:49:50 +0000473 lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.Symbolicate crashlog')
Greg Clayton42a6eb72012-01-20 19:25:32 +0000474 print '"crashlog" command installed, type "crashlog --help" for detailed help'
Greg Claytonaa9d02b2012-01-20 03:15:45 +0000475