blob: ccdc4b379ed6a67ce3b92aa98ef07aedc5ddd70e [file] [log] [blame]
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001#!/usr/bin/env python
2#
verwaest@chromium.org37141392012-05-31 13:27:02 +00003# Copyright 2012 the V8 project authors. All rights reserved.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
7#
8# * Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# * Redistributions in binary form must reproduce the above
11# copyright notice, this list of conditions and the following
12# disclaimer in the documentation and/or other materials provided
13# with the distribution.
14# * Neither the name of Google Inc. nor the names of its
15# contributors may be used to endorse or promote products derived
16# from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000030import bisect
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000031import cmd
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000032import codecs
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000033import ctypes
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000034import datetime
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000035import disasm
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000036import mmap
37import optparse
38import os
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +000039import re
40import struct
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000041import sys
42import types
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000043
verwaest@chromium.org37141392012-05-31 13:27:02 +000044USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000045
46Minidump analyzer.
47
48Shows the processor state at the point of exception including the
49stack of the active thread and the referenced objects in the V8
50heap. Code objects are disassembled and the addresses linked from the
verwaest@chromium.org37141392012-05-31 13:27:02 +000051stack (e.g. pushed return addresses) are marked with "=>".
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000052
53Examples:
verwaest@chromium.org37141392012-05-31 13:27:02 +000054 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp"""
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000055
ricow@chromium.org7ad65222011-12-19 12:13:11 +000056
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000057DEBUG=False
58
59
60def DebugPrint(s):
61 if not DEBUG: return
62 print s
63
64
65class Descriptor(object):
66 """Descriptor of a structure in a memory."""
67
68 def __init__(self, fields):
69 self.fields = fields
70 self.is_flexible = False
71 for _, type_or_func in fields:
72 if isinstance(type_or_func, types.FunctionType):
73 self.is_flexible = True
74 break
75 if not self.is_flexible:
76 self.ctype = Descriptor._GetCtype(fields)
77 self.size = ctypes.sizeof(self.ctype)
78
79 def Read(self, memory, offset):
80 if self.is_flexible:
81 fields_copy = self.fields[:]
82 last = 0
83 for name, type_or_func in fields_copy:
84 if isinstance(type_or_func, types.FunctionType):
85 partial_ctype = Descriptor._GetCtype(fields_copy[:last])
86 partial_object = partial_ctype.from_buffer(memory, offset)
87 type = type_or_func(partial_object)
88 if type is not None:
89 fields_copy[last] = (name, type)
90 last += 1
91 else:
92 last += 1
93 complete_ctype = Descriptor._GetCtype(fields_copy[:last])
94 else:
95 complete_ctype = self.ctype
96 return complete_ctype.from_buffer(memory, offset)
97
98 @staticmethod
99 def _GetCtype(fields):
100 class Raw(ctypes.Structure):
101 _fields_ = fields
102 _pack_ = 1
103
104 def __str__(self):
105 return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field))
106 for field, _ in Raw._fields_) + "}"
107 return Raw
108
109
verwaest@chromium.org37141392012-05-31 13:27:02 +0000110def FullDump(reader, heap):
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000111 """Dump all available memory regions."""
112 def dump_region(reader, start, size, location):
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000113 print
114 while start & 3 != 0:
115 start += 1
116 size -= 1
117 location += 1
118 is_executable = reader.IsProbableExecutableRegion(location, size)
119 is_ascii = reader.IsProbableASCIIRegion(location, size)
120
121 if is_executable is not False:
122 lines = reader.GetDisasmLines(start, size)
123 for line in lines:
124 print FormatDisasmLine(start, heap, line)
125 print
126
127 if is_ascii is not False:
128 # Output in the same format as the Unix hd command
129 addr = start
130 for slot in xrange(location, location + size, 16):
131 hex_line = ""
132 asc_line = ""
133 for i in xrange(0, 16):
134 if slot + i < location + size:
135 byte = ctypes.c_uint8.from_buffer(reader.minidump, slot + i).value
136 if byte >= 0x20 and byte < 0x7f:
137 asc_line += chr(byte)
138 else:
139 asc_line += "."
140 hex_line += " %02x" % (byte)
141 else:
142 hex_line += " "
143 if i == 7:
144 hex_line += " "
145 print "%s %s |%s|" % (reader.FormatIntPtr(addr),
146 hex_line,
147 asc_line)
148 addr += 16
149
150 if is_executable is not True and is_ascii is not True:
151 print "%s - %s" % (reader.FormatIntPtr(start),
152 reader.FormatIntPtr(start + size))
153 for slot in xrange(start,
154 start + size,
155 reader.PointerSize()):
156 maybe_address = reader.ReadUIntPtr(slot)
157 heap_object = heap.FindObject(maybe_address)
158 print "%s: %s" % (reader.FormatIntPtr(slot),
159 reader.FormatIntPtr(maybe_address))
160 if heap_object:
161 heap_object.Print(Printer())
162 print
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000163
164 reader.ForEachMemoryRegion(dump_region)
165
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000166# Set of structures and constants that describe the layout of minidump
167# files. Based on MSDN and Google Breakpad.
168
169MINIDUMP_HEADER = Descriptor([
170 ("signature", ctypes.c_uint32),
171 ("version", ctypes.c_uint32),
172 ("stream_count", ctypes.c_uint32),
173 ("stream_directories_rva", ctypes.c_uint32),
174 ("checksum", ctypes.c_uint32),
175 ("time_date_stampt", ctypes.c_uint32),
176 ("flags", ctypes.c_uint64)
177])
178
179MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
180 ("data_size", ctypes.c_uint32),
181 ("rva", ctypes.c_uint32)
182])
183
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000184MINIDUMP_STRING = Descriptor([
185 ("length", ctypes.c_uint32),
186 ("buffer", lambda t: ctypes.c_uint8 * (t.length + 2))
187])
188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000189MINIDUMP_DIRECTORY = Descriptor([
190 ("stream_type", ctypes.c_uint32),
191 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
192])
193
194MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
195
196MINIDUMP_EXCEPTION = Descriptor([
197 ("code", ctypes.c_uint32),
198 ("flags", ctypes.c_uint32),
199 ("record", ctypes.c_uint64),
200 ("address", ctypes.c_uint64),
201 ("parameter_count", ctypes.c_uint32),
202 ("unused_alignment", ctypes.c_uint32),
203 ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
204])
205
206MINIDUMP_EXCEPTION_STREAM = Descriptor([
207 ("thread_id", ctypes.c_uint32),
208 ("unused_alignment", ctypes.c_uint32),
209 ("exception", MINIDUMP_EXCEPTION.ctype),
210 ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
211])
212
213# Stream types.
214MD_UNUSED_STREAM = 0
215MD_RESERVED_STREAM_0 = 1
216MD_RESERVED_STREAM_1 = 2
217MD_THREAD_LIST_STREAM = 3
218MD_MODULE_LIST_STREAM = 4
219MD_MEMORY_LIST_STREAM = 5
220MD_EXCEPTION_STREAM = 6
221MD_SYSTEM_INFO_STREAM = 7
222MD_THREAD_EX_LIST_STREAM = 8
223MD_MEMORY_64_LIST_STREAM = 9
224MD_COMMENT_STREAM_A = 10
225MD_COMMENT_STREAM_W = 11
226MD_HANDLE_DATA_STREAM = 12
227MD_FUNCTION_TABLE_STREAM = 13
228MD_UNLOADED_MODULE_LIST_STREAM = 14
229MD_MISC_INFO_STREAM = 15
230MD_MEMORY_INFO_LIST_STREAM = 16
231MD_THREAD_INFO_LIST_STREAM = 17
232MD_HANDLE_OPERATION_LIST_STREAM = 18
233
234MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
235
236MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
237 ("control_word", ctypes.c_uint32),
238 ("status_word", ctypes.c_uint32),
239 ("tag_word", ctypes.c_uint32),
240 ("error_offset", ctypes.c_uint32),
241 ("error_selector", ctypes.c_uint32),
242 ("data_offset", ctypes.c_uint32),
243 ("data_selector", ctypes.c_uint32),
244 ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
245 ("cr0_npx_state", ctypes.c_uint32)
246])
247
248MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
249
250# Context flags.
251MD_CONTEXT_X86 = 0x00010000
252MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
253MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
254MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
255MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
256MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
257MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
258
259def EnableOnFlag(type, flag):
260 return lambda o: [None, type][int((o.context_flags & flag) != 0)]
261
262MINIDUMP_CONTEXT_X86 = Descriptor([
263 ("context_flags", ctypes.c_uint32),
264 # MD_CONTEXT_X86_DEBUG_REGISTERS.
265 ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
266 ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
267 ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
268 ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
269 ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
270 ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
271 # MD_CONTEXT_X86_FLOATING_POINT.
272 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
273 MD_CONTEXT_X86_FLOATING_POINT)),
274 # MD_CONTEXT_X86_SEGMENTS.
275 ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
276 ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
277 ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
278 ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
279 # MD_CONTEXT_X86_INTEGER.
280 ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
281 ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
282 ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
283 ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
284 ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
285 ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
286 # MD_CONTEXT_X86_CONTROL.
287 ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
288 ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
289 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
290 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
291 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
292 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
293 # MD_CONTEXT_X86_EXTENDED_REGISTERS.
294 ("extended_registers",
295 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
296 MD_CONTEXT_X86_EXTENDED_REGISTERS))
297])
298
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000299MD_CONTEXT_ARM = 0x40000000
300MD_CONTEXT_ARM_INTEGER = (MD_CONTEXT_ARM | 0x00000002)
301MD_CONTEXT_ARM_FLOATING_POINT = (MD_CONTEXT_ARM | 0x00000004)
302MD_FLOATINGSAVEAREA_ARM_FPR_COUNT = 32
303MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT = 8
304
305MINIDUMP_FLOATING_SAVE_AREA_ARM = Descriptor([
306 ("fpscr", ctypes.c_uint64),
307 ("regs", ctypes.c_uint64 * MD_FLOATINGSAVEAREA_ARM_FPR_COUNT),
308 ("extra", ctypes.c_uint64 * MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT)
309])
310
311MINIDUMP_CONTEXT_ARM = Descriptor([
312 ("context_flags", ctypes.c_uint32),
313 # MD_CONTEXT_ARM_INTEGER.
314 ("r0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
315 ("r1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
316 ("r2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
317 ("r3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
318 ("r4", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
319 ("r5", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
320 ("r6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
321 ("r7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
322 ("r8", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
323 ("r9", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
324 ("r10", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
325 ("r11", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
326 ("r12", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
327 ("sp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
328 ("lr", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
329 ("pc", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
330 ("cpsr", ctypes.c_uint32),
331 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_ARM.ctype,
332 MD_CONTEXT_ARM_FLOATING_POINT))
333])
334
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000335MD_CONTEXT_AMD64 = 0x00100000
336MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
337MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
338MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
339MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
340MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
341
342MINIDUMP_CONTEXT_AMD64 = Descriptor([
343 ("p1_home", ctypes.c_uint64),
344 ("p2_home", ctypes.c_uint64),
345 ("p3_home", ctypes.c_uint64),
346 ("p4_home", ctypes.c_uint64),
347 ("p5_home", ctypes.c_uint64),
348 ("p6_home", ctypes.c_uint64),
349 ("context_flags", ctypes.c_uint32),
350 ("mx_csr", ctypes.c_uint32),
351 # MD_CONTEXT_AMD64_CONTROL.
352 ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
353 # MD_CONTEXT_AMD64_SEGMENTS
354 ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
355 ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
356 ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
357 ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
358 # MD_CONTEXT_AMD64_CONTROL.
359 ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
360 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
361 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
362 ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
363 ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
364 ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
365 ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
366 ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
367 ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
368 # MD_CONTEXT_AMD64_INTEGER.
369 ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
370 ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
371 ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
372 ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
373 # MD_CONTEXT_AMD64_CONTROL.
374 ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
375 # MD_CONTEXT_AMD64_INTEGER.
376 ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
377 ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
378 ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
379 ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
380 ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
381 ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
382 ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
383 ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
384 ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
385 ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
386 ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
387 # MD_CONTEXT_AMD64_CONTROL.
388 ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
389 # MD_CONTEXT_AMD64_FLOATING_POINT
390 ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
391 MD_CONTEXT_AMD64_FLOATING_POINT)),
392 ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
393 MD_CONTEXT_AMD64_FLOATING_POINT)),
394 ("vector_control", EnableOnFlag(ctypes.c_uint64,
395 MD_CONTEXT_AMD64_FLOATING_POINT)),
396 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
397 ("debug_control", EnableOnFlag(ctypes.c_uint64,
398 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
399 ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
400 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
401 ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
402 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
403 ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
404 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
405 ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
406 MD_CONTEXT_AMD64_DEBUG_REGISTERS))
407])
408
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000409MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
410 ("start", ctypes.c_uint64),
411 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
412])
413
414MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
415 ("start", ctypes.c_uint64),
416 ("size", ctypes.c_uint64)
417])
418
419MINIDUMP_MEMORY_LIST = Descriptor([
420 ("range_count", ctypes.c_uint32),
421 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
422])
423
424MINIDUMP_MEMORY_LIST64 = Descriptor([
425 ("range_count", ctypes.c_uint64),
426 ("base_rva", ctypes.c_uint64),
427 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
428])
429
430MINIDUMP_THREAD = Descriptor([
431 ("id", ctypes.c_uint32),
432 ("suspend_count", ctypes.c_uint32),
433 ("priority_class", ctypes.c_uint32),
434 ("priority", ctypes.c_uint32),
435 ("ted", ctypes.c_uint64),
436 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
437 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
438])
439
440MINIDUMP_THREAD_LIST = Descriptor([
441 ("thread_count", ctypes.c_uint32),
442 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
443])
444
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000445MINIDUMP_VS_FIXEDFILEINFO = Descriptor([
446 ("dwSignature", ctypes.c_uint32),
447 ("dwStrucVersion", ctypes.c_uint32),
448 ("dwFileVersionMS", ctypes.c_uint32),
449 ("dwFileVersionLS", ctypes.c_uint32),
450 ("dwProductVersionMS", ctypes.c_uint32),
451 ("dwProductVersionLS", ctypes.c_uint32),
452 ("dwFileFlagsMask", ctypes.c_uint32),
453 ("dwFileFlags", ctypes.c_uint32),
454 ("dwFileOS", ctypes.c_uint32),
455 ("dwFileType", ctypes.c_uint32),
456 ("dwFileSubtype", ctypes.c_uint32),
457 ("dwFileDateMS", ctypes.c_uint32),
458 ("dwFileDateLS", ctypes.c_uint32)
459])
460
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000461MINIDUMP_RAW_MODULE = Descriptor([
462 ("base_of_image", ctypes.c_uint64),
463 ("size_of_image", ctypes.c_uint32),
464 ("checksum", ctypes.c_uint32),
465 ("time_date_stamp", ctypes.c_uint32),
466 ("module_name_rva", ctypes.c_uint32),
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000467 ("version_info", MINIDUMP_VS_FIXEDFILEINFO.ctype),
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000468 ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
469 ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
470 ("reserved0", ctypes.c_uint32 * 2),
471 ("reserved1", ctypes.c_uint32 * 2)
472])
473
474MINIDUMP_MODULE_LIST = Descriptor([
475 ("number_of_modules", ctypes.c_uint32),
476 ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules)
477])
478
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000479MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
480 ("processor_architecture", ctypes.c_uint16)
481])
482
483MD_CPU_ARCHITECTURE_X86 = 0
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000484MD_CPU_ARCHITECTURE_ARM = 5
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000485MD_CPU_ARCHITECTURE_AMD64 = 9
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000486
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000487class FuncSymbol:
488 def __init__(self, start, size, name):
489 self.start = start
490 self.end = self.start + size
491 self.name = name
492
493 def __cmp__(self, other):
494 if isinstance(other, FuncSymbol):
495 return self.start - other.start
496 return self.start - other
497
498 def Covers(self, addr):
499 return (self.start <= addr) and (addr < self.end)
500
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000501class MinidumpReader(object):
502 """Minidump (.dmp) reader."""
503
504 _HEADER_MAGIC = 0x504d444d
505
506 def __init__(self, options, minidump_name):
507 self.minidump_name = minidump_name
508 self.minidump_file = open(minidump_name, "r")
509 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
510 self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
511 if self.header.signature != MinidumpReader._HEADER_MAGIC:
verwaest@chromium.org37141392012-05-31 13:27:02 +0000512 print >>sys.stderr, "Warning: Unsupported minidump header magic!"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000513 DebugPrint(self.header)
514 directories = []
515 offset = self.header.stream_directories_rva
516 for _ in xrange(self.header.stream_count):
517 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
518 offset += MINIDUMP_DIRECTORY.size
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000519 self.arch = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000520 self.exception = None
521 self.exception_context = None
522 self.memory_list = None
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000523 self.memory_list64 = None
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000524 self.module_list = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000525 self.thread_map = {}
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000526
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000527 self.symdir = options.symdir
528 self.modules_with_symbols = []
529 self.symbols = []
530
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000531 # Find MDRawSystemInfo stream and determine arch.
532 for d in directories:
533 if d.stream_type == MD_SYSTEM_INFO_STREAM:
534 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
535 self.minidump, d.location.rva)
536 self.arch = system_info.processor_architecture
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000537 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64,
538 MD_CPU_ARCHITECTURE_ARM,
539 MD_CPU_ARCHITECTURE_X86]
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000540 assert not self.arch is None
541
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000542 for d in directories:
543 DebugPrint(d)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000544 if d.stream_type == MD_EXCEPTION_STREAM:
545 self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
546 self.minidump, d.location.rva)
547 DebugPrint(self.exception)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000548 if self.arch == MD_CPU_ARCHITECTURE_X86:
549 self.exception_context = MINIDUMP_CONTEXT_X86.Read(
550 self.minidump, self.exception.thread_context.rva)
551 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
552 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
553 self.minidump, self.exception.thread_context.rva)
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000554 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
555 self.exception_context = MINIDUMP_CONTEXT_ARM.Read(
556 self.minidump, self.exception.thread_context.rva)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000557 DebugPrint(self.exception_context)
558 elif d.stream_type == MD_THREAD_LIST_STREAM:
559 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
560 assert ctypes.sizeof(thread_list) == d.location.data_size
561 DebugPrint(thread_list)
562 for thread in thread_list.threads:
563 DebugPrint(thread)
564 self.thread_map[thread.id] = thread
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000565 elif d.stream_type == MD_MODULE_LIST_STREAM:
566 assert self.module_list is None
567 self.module_list = MINIDUMP_MODULE_LIST.Read(
568 self.minidump, d.location.rva)
569 assert ctypes.sizeof(self.module_list) == d.location.data_size
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000570 elif d.stream_type == MD_MEMORY_LIST_STREAM:
verwaest@chromium.org37141392012-05-31 13:27:02 +0000571 print >>sys.stderr, "Warning: This is not a full minidump!"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000572 assert self.memory_list is None
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000573 self.memory_list = MINIDUMP_MEMORY_LIST.Read(
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000574 self.minidump, d.location.rva)
575 assert ctypes.sizeof(self.memory_list) == d.location.data_size
576 DebugPrint(self.memory_list)
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000577 elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
578 assert self.memory_list64 is None
579 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read(
580 self.minidump, d.location.rva)
581 assert ctypes.sizeof(self.memory_list64) == d.location.data_size
582 DebugPrint(self.memory_list64)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000583
584 def IsValidAddress(self, address):
585 return self.FindLocation(address) is not None
586
587 def ReadU8(self, address):
588 location = self.FindLocation(address)
589 return ctypes.c_uint8.from_buffer(self.minidump, location).value
590
591 def ReadU32(self, address):
592 location = self.FindLocation(address)
593 return ctypes.c_uint32.from_buffer(self.minidump, location).value
594
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000595 def ReadU64(self, address):
596 location = self.FindLocation(address)
597 return ctypes.c_uint64.from_buffer(self.minidump, location).value
598
599 def ReadUIntPtr(self, address):
600 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
601 return self.ReadU64(address)
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000602 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
603 return self.ReadU32(address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000604 elif self.arch == MD_CPU_ARCHITECTURE_X86:
605 return self.ReadU32(address)
606
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000607 def ReadBytes(self, address, size):
608 location = self.FindLocation(address)
609 return self.minidump[location:location + size]
610
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000611 def _ReadWord(self, location):
612 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
613 return ctypes.c_uint64.from_buffer(self.minidump, location).value
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000614 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
615 return ctypes.c_uint32.from_buffer(self.minidump, location).value
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000616 elif self.arch == MD_CPU_ARCHITECTURE_X86:
617 return ctypes.c_uint32.from_buffer(self.minidump, location).value
618
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000619 def IsProbableASCIIRegion(self, location, length):
620 ascii_bytes = 0
621 non_ascii_bytes = 0
622 for loc in xrange(location, location + length):
623 byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
624 if byte >= 0x7f:
625 non_ascii_bytes += 1
626 if byte < 0x20 and byte != 0:
627 non_ascii_bytes += 1
628 if byte < 0x7f and byte >= 0x20:
629 ascii_bytes += 1
630 if byte == 0xa: # newline
631 ascii_bytes += 1
632 if ascii_bytes * 10 <= length:
633 return False
634 if length > 0 and ascii_bytes > non_ascii_bytes * 7:
635 return True
636 if ascii_bytes > non_ascii_bytes * 3:
637 return None # Maybe
638 return False
639
640 def IsProbableExecutableRegion(self, location, length):
641 opcode_bytes = 0
642 sixty_four = self.arch == MD_CPU_ARCHITECTURE_AMD64
643 for loc in xrange(location, location + length):
644 byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
645 if (byte == 0x8b or # mov
646 byte == 0x89 or # mov reg-reg
647 (byte & 0xf0) == 0x50 or # push/pop
648 (sixty_four and (byte & 0xf0) == 0x40) or # rex prefix
649 byte == 0xc3 or # return
650 byte == 0x74 or # jeq
651 byte == 0x84 or # jeq far
652 byte == 0x75 or # jne
653 byte == 0x85 or # jne far
654 byte == 0xe8 or # call
655 byte == 0xe9 or # jmp far
656 byte == 0xeb): # jmp near
657 opcode_bytes += 1
658 opcode_percent = (opcode_bytes * 100) / length
659 threshold = 20
660 if opcode_percent > threshold + 2:
661 return True
662 if opcode_percent > threshold - 2:
663 return None # Maybe
664 return False
665
666 def FindRegion(self, addr):
667 answer = [-1, -1]
668 def is_in(reader, start, size, location):
669 if addr >= start and addr < start + size:
670 answer[0] = start
671 answer[1] = size
672 self.ForEachMemoryRegion(is_in)
673 if answer[0] == -1:
674 return None
675 return answer
676
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000677 def ForEachMemoryRegion(self, cb):
678 if self.memory_list64 is not None:
679 for r in self.memory_list64.ranges:
680 location = self.memory_list64.base_rva + offset
681 cb(self, r.start, r.size, location)
682 offset += r.size
683
684 if self.memory_list is not None:
685 for r in self.memory_list.ranges:
686 cb(self, r.start, r.memory.data_size, r.memory.rva)
687
verwaest@chromium.org37141392012-05-31 13:27:02 +0000688 def FindWord(self, word, alignment=0):
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000689 def search_inside_region(reader, start, size, location):
verwaest@chromium.org37141392012-05-31 13:27:02 +0000690 location = (location + alignment) & ~alignment
691 for loc in xrange(location, location + size - self.PointerSize()):
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000692 if reader._ReadWord(loc) == word:
693 slot = start + (loc - location)
694 print "%s: %s" % (reader.FormatIntPtr(slot),
695 reader.FormatIntPtr(word))
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000696 self.ForEachMemoryRegion(search_inside_region)
697
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000698 def FindLocation(self, address):
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000699 offset = 0
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000700 if self.memory_list64 is not None:
701 for r in self.memory_list64.ranges:
702 if r.start <= address < r.start + r.size:
703 return self.memory_list64.base_rva + offset + address - r.start
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000704 offset += r.size
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000705 if self.memory_list is not None:
706 for r in self.memory_list.ranges:
707 if r.start <= address < r.start + r.memory.data_size:
708 return r.memory.rva + address - r.start
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000709 return None
710
711 def GetDisasmLines(self, address, size):
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000712 def CountUndefinedInstructions(lines):
713 pattern = "<UNDEFINED>"
714 return sum([line.count(pattern) for (ignore, line) in lines])
715
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000716 location = self.FindLocation(address)
717 if location is None: return []
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000718 arch = None
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000719 possible_objdump_flags = [""]
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000720 if self.arch == MD_CPU_ARCHITECTURE_X86:
721 arch = "ia32"
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000722 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
723 arch = "arm"
724 possible_objdump_flags = ["", "--disassembler-options=force-thumb"]
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000725 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
726 arch = "x64"
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000727 results = [ disasm.GetDisasmLines(self.minidump_name,
728 location,
729 size,
730 arch,
731 False,
732 objdump_flags)
733 for objdump_flags in possible_objdump_flags ]
734 return min(results, key=CountUndefinedInstructions)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000735
736
737 def Dispose(self):
738 self.minidump.close()
739 self.minidump_file.close()
740
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000741 def ExceptionIP(self):
742 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
743 return self.exception_context.rip
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000744 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
745 return self.exception_context.pc
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000746 elif self.arch == MD_CPU_ARCHITECTURE_X86:
747 return self.exception_context.eip
748
749 def ExceptionSP(self):
750 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
751 return self.exception_context.rsp
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000752 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
753 return self.exception_context.sp
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000754 elif self.arch == MD_CPU_ARCHITECTURE_X86:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000755 return self.exception_context.esp
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000756
757 def FormatIntPtr(self, value):
758 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
759 return "%016x" % value
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000760 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
761 return "%08x" % value
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000762 elif self.arch == MD_CPU_ARCHITECTURE_X86:
763 return "%08x" % value
764
765 def PointerSize(self):
766 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
767 return 8
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000768 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
769 return 4
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000770 elif self.arch == MD_CPU_ARCHITECTURE_X86:
771 return 4
772
773 def Register(self, name):
774 return self.exception_context.__getattribute__(name)
775
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000776 def ReadMinidumpString(self, rva):
777 string = bytearray(MINIDUMP_STRING.Read(self.minidump, rva).buffer)
778 string = string.decode("utf16")
779 return string[0:len(string) - 1]
780
781 # Load FUNC records from a BreakPad symbol file
782 #
783 # http://code.google.com/p/google-breakpad/wiki/SymbolFiles
784 #
785 def _LoadSymbolsFrom(self, symfile, baseaddr):
786 print "Loading symbols from %s" % (symfile)
787 funcs = []
788 with open(symfile) as f:
789 for line in f:
790 result = re.match(
791 r"^FUNC ([a-f0-9]+) ([a-f0-9]+) ([a-f0-9]+) (.*)$", line)
792 if result is not None:
793 start = int(result.group(1), 16)
794 size = int(result.group(2), 16)
795 name = result.group(4).rstrip()
796 bisect.insort_left(self.symbols,
797 FuncSymbol(baseaddr + start, size, name))
798 print " ... done"
799
800 def TryLoadSymbolsFor(self, modulename, module):
801 try:
802 symfile = os.path.join(self.symdir,
803 modulename.replace('.', '_') + ".pdb.sym")
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000804 if os.path.isfile(symfile):
805 self._LoadSymbolsFrom(symfile, module.base_of_image)
806 self.modules_with_symbols.append(module)
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000807 except Exception as e:
808 print " ... failure (%s)" % (e)
809
810 # Returns true if address is covered by some module that has loaded symbols.
811 def _IsInModuleWithSymbols(self, addr):
812 for module in self.modules_with_symbols:
813 start = module.base_of_image
814 end = start + module.size_of_image
815 if (start <= addr) and (addr < end):
816 return True
817 return False
818
819 # Find symbol covering the given address and return its name in format
820 # <symbol name>+<offset from the start>
821 def FindSymbol(self, addr):
822 if not self._IsInModuleWithSymbols(addr):
823 return None
824
825 i = bisect.bisect_left(self.symbols, addr)
826 symbol = None
827 if (0 < i) and self.symbols[i - 1].Covers(addr):
828 symbol = self.symbols[i - 1]
829 elif (i < len(self.symbols)) and self.symbols[i].Covers(addr):
830 symbol = self.symbols[i]
831 else:
832 return None
833 diff = addr - symbol.start
834 return "%s+0x%x" % (symbol.name, diff)
835
836
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000837
838# List of V8 instance types. Obtained by adding the code below to any .cc file.
839#
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000840# #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000841# struct P {
842# P() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000843# printf("INSTANCE_TYPES = {\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000844# INSTANCE_TYPE_LIST(DUMP_TYPE)
845# printf("}\n");
846# }
847# };
848# static P p;
849INSTANCE_TYPES = {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000850 0: "STRING_TYPE",
851 4: "ASCII_STRING_TYPE",
852 1: "CONS_STRING_TYPE",
853 5: "CONS_ASCII_STRING_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000854 3: "SLICED_STRING_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000855 2: "EXTERNAL_STRING_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000856 6: "EXTERNAL_ASCII_STRING_TYPE",
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000857 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000858 18: "SHORT_EXTERNAL_STRING_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000859 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE",
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000860 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
861 64: "INTERNALIZED_STRING_TYPE",
862 68: "ASCII_INTERNALIZED_STRING_TYPE",
863 65: "CONS_INTERNALIZED_STRING_TYPE",
864 69: "CONS_ASCII_INTERNALIZED_STRING_TYPE",
865 66: "EXTERNAL_INTERNALIZED_STRING_TYPE",
866 70: "EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE",
867 74: "EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE",
868 82: "SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE",
869 86: "SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE",
870 90: "SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE",
871 128: "SYMBOL_TYPE",
872 129: "MAP_TYPE",
873 130: "CODE_TYPE",
874 131: "ODDBALL_TYPE",
875 132: "JS_GLOBAL_PROPERTY_CELL_TYPE",
876 133: "HEAP_NUMBER_TYPE",
877 134: "FOREIGN_TYPE",
878 135: "BYTE_ARRAY_TYPE",
879 136: "FREE_SPACE_TYPE",
880 137: "EXTERNAL_BYTE_ARRAY_TYPE",
881 138: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
882 139: "EXTERNAL_SHORT_ARRAY_TYPE",
883 140: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
884 141: "EXTERNAL_INT_ARRAY_TYPE",
885 142: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
886 143: "EXTERNAL_FLOAT_ARRAY_TYPE",
887 145: "EXTERNAL_PIXEL_ARRAY_TYPE",
888 147: "FILLER_TYPE",
889 148: "DECLARED_ACCESSOR_DESCRIPTOR_TYPE",
890 149: "DECLARED_ACCESSOR_INFO_TYPE",
891 150: "EXECUTABLE_ACCESSOR_INFO_TYPE",
892 151: "ACCESSOR_PAIR_TYPE",
893 152: "ACCESS_CHECK_INFO_TYPE",
894 153: "INTERCEPTOR_INFO_TYPE",
895 154: "CALL_HANDLER_INFO_TYPE",
896 155: "FUNCTION_TEMPLATE_INFO_TYPE",
897 156: "OBJECT_TEMPLATE_INFO_TYPE",
898 157: "SIGNATURE_INFO_TYPE",
899 158: "TYPE_SWITCH_INFO_TYPE",
900 159: "ALLOCATION_SITE_INFO_TYPE",
901 160: "SCRIPT_TYPE",
902 161: "CODE_CACHE_TYPE",
903 162: "POLYMORPHIC_CODE_CACHE_TYPE",
904 163: "TYPE_FEEDBACK_INFO_TYPE",
905 164: "ALIASED_ARGUMENTS_ENTRY_TYPE",
906 167: "FIXED_ARRAY_TYPE",
907 146: "FIXED_DOUBLE_ARRAY_TYPE",
908 168: "SHARED_FUNCTION_INFO_TYPE",
909 169: "JS_MESSAGE_OBJECT_TYPE",
910 172: "JS_VALUE_TYPE",
911 173: "JS_DATE_TYPE",
912 174: "JS_OBJECT_TYPE",
913 175: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
914 176: "JS_MODULE_TYPE",
915 177: "JS_GLOBAL_OBJECT_TYPE",
916 178: "JS_BUILTINS_OBJECT_TYPE",
917 179: "JS_GLOBAL_PROXY_TYPE",
918 180: "JS_ARRAY_TYPE",
919 171: "JS_PROXY_TYPE",
920 183: "JS_WEAK_MAP_TYPE",
921 184: "JS_REGEXP_TYPE",
922 185: "JS_FUNCTION_TYPE",
923 170: "JS_FUNCTION_PROXY_TYPE",
924 165: "DEBUG_INFO_TYPE",
925 166: "BREAK_POINT_INFO_TYPE",
verwaest@chromium.org37141392012-05-31 13:27:02 +0000926}
927
928
929# List of known V8 maps. Used to determine the instance type and name
930# for maps that are part of the root-set and hence on the first page of
931# the map-space. Obtained by adding the code below to an IA32 release
932# build with enabled snapshots to the end of the Isolate::Init method.
933#
934# #define ROOT_LIST_CASE(type, name, camel_name) \
935# if (o == heap_.name()) n = #camel_name;
936# #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
937# if (o == heap_.name##_map()) n = #camel_name "Map";
938# HeapObjectIterator it(heap_.map_space());
939# printf("KNOWN_MAPS = {\n");
940# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
941# Map* m = Map::cast(o);
942# const char* n = "";
943# intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
944# int t = m->instance_type();
945# ROOT_LIST(ROOT_LIST_CASE)
946# STRUCT_LIST(STRUCT_LIST_CASE)
947# printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n);
948# }
949# printf("}\n");
950KNOWN_MAPS = {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000951 0x08081: (135, "ByteArrayMap"),
952 0x080a9: (129, "MetaMap"),
953 0x080d1: (131, "OddballMap"),
954 0x080f9: (68, "AsciiInternalizedStringMap"),
955 0x08121: (167, "FixedArrayMap"),
956 0x08149: (133, "HeapNumberMap"),
957 0x08171: (136, "FreeSpaceMap"),
958 0x08199: (147, "OnePointerFillerMap"),
959 0x081c1: (147, "TwoPointerFillerMap"),
960 0x081e9: (132, "GlobalPropertyCellMap"),
961 0x08211: (168, "SharedFunctionInfoMap"),
962 0x08239: (167, "NativeContextMap"),
963 0x08261: (130, "CodeMap"),
964 0x08289: (167, "ScopeInfoMap"),
965 0x082b1: (167, "FixedCOWArrayMap"),
966 0x082d9: (146, "FixedDoubleArrayMap"),
967 0x08301: (167, "HashTableMap"),
968 0x08329: (128, "SymbolMap"),
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000969 0x08351: (0, "StringMap"),
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000970 0x08379: (4, "AsciiStringMap"),
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000971 0x083a1: (1, "ConsStringMap"),
972 0x083c9: (5, "ConsAsciiStringMap"),
973 0x083f1: (3, "SlicedStringMap"),
974 0x08419: (7, "SlicedAsciiStringMap"),
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000975 0x08441: (2, "ExternalStringMap"),
976 0x08469: (10, "ExternalStringWithAsciiDataMap"),
977 0x08491: (6, "ExternalAsciiStringMap"),
978 0x084b9: (18, "ShortExternalStringMap"),
979 0x084e1: (26, "ShortExternalStringWithAsciiDataMap"),
980 0x08509: (64, "InternalizedStringMap"),
981 0x08531: (65, "ConsInternalizedStringMap"),
982 0x08559: (69, "ConsAsciiInternalizedStringMap"),
983 0x08581: (66, "ExternalInternalizedStringMap"),
984 0x085a9: (74, "ExternalInternalizedStringWithAsciiDataMap"),
985 0x085d1: (70, "ExternalAsciiInternalizedStringMap"),
986 0x085f9: (82, "ShortExternalInternalizedStringMap"),
987 0x08621: (90, "ShortExternalInternalizedStringWithAsciiDataMap"),
988 0x08649: (86, "ShortExternalAsciiInternalizedStringMap"),
989 0x08671: (22, "ShortExternalAsciiStringMap"),
990 0x08699: (0, "UndetectableStringMap"),
991 0x086c1: (4, "UndetectableAsciiStringMap"),
992 0x086e9: (145, "ExternalPixelArrayMap"),
993 0x08711: (137, "ExternalByteArrayMap"),
994 0x08739: (138, "ExternalUnsignedByteArrayMap"),
995 0x08761: (139, "ExternalShortArrayMap"),
996 0x08789: (140, "ExternalUnsignedShortArrayMap"),
997 0x087b1: (141, "ExternalIntArrayMap"),
998 0x087d9: (142, "ExternalUnsignedIntArrayMap"),
999 0x08801: (143, "ExternalFloatArrayMap"),
1000 0x08829: (144, "ExternalDoubleArrayMap"),
1001 0x08851: (167, "NonStrictArgumentsElementsMap"),
1002 0x08879: (167, "FunctionContextMap"),
1003 0x088a1: (167, "CatchContextMap"),
1004 0x088c9: (167, "WithContextMap"),
1005 0x088f1: (167, "BlockContextMap"),
1006 0x08919: (167, "ModuleContextMap"),
1007 0x08941: (167, "GlobalContextMap"),
1008 0x08969: (169, "JSMessageObjectMap"),
1009 0x08991: (134, "ForeignMap"),
1010 0x089b9: (174, "NeanderMap"),
1011 0x089e1: (159, "AllocationSiteInfoMap"),
1012 0x08a09: (162, "PolymorphicCodeCacheMap"),
1013 0x08a31: (160, "ScriptMap"),
1014 0x08a59: (174, ""),
1015 0x08a81: (174, "ExternalMap"),
1016 0x08aa9: (148, "DeclaredAccessorDescriptorMap"),
1017 0x08ad1: (149, "DeclaredAccessorInfoMap"),
1018 0x08af9: (150, "ExecutableAccessorInfoMap"),
1019 0x08b21: (151, "AccessorPairMap"),
1020 0x08b49: (152, "AccessCheckInfoMap"),
1021 0x08b71: (153, "InterceptorInfoMap"),
1022 0x08b99: (154, "CallHandlerInfoMap"),
1023 0x08bc1: (155, "FunctionTemplateInfoMap"),
1024 0x08be9: (156, "ObjectTemplateInfoMap"),
1025 0x08c11: (157, "SignatureInfoMap"),
1026 0x08c39: (158, "TypeSwitchInfoMap"),
1027 0x08c61: (161, "CodeCacheMap"),
1028 0x08c89: (163, "TypeFeedbackInfoMap"),
1029 0x08cb1: (164, "AliasedArgumentsEntryMap"),
1030 0x08cd9: (165, "DebugInfoMap"),
1031 0x08d01: (166, "BreakPointInfoMap"),
verwaest@chromium.org37141392012-05-31 13:27:02 +00001032}
1033
1034
1035# List of known V8 objects. Used to determine name for objects that are
1036# part of the root-set and hence on the first page of various old-space
1037# paged. Obtained by adding the code below to an IA32 release build with
1038# enabled snapshots to the end of the Isolate::Init method.
1039#
1040# #define ROOT_LIST_CASE(type, name, camel_name) \
1041# if (o == heap_.name()) n = #camel_name;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001042# OldSpaces spit(heap());
verwaest@chromium.org37141392012-05-31 13:27:02 +00001043# printf("KNOWN_OBJECTS = {\n");
1044# for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
1045# HeapObjectIterator it(s);
1046# const char* sname = AllocationSpaceName(s->identity());
1047# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
1048# const char* n = NULL;
1049# intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
1050# ROOT_LIST(ROOT_LIST_CASE)
1051# if (n != NULL) {
1052# printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n);
1053# }
1054# }
1055# }
1056# printf("}\n");
1057KNOWN_OBJECTS = {
1058 ("OLD_POINTER_SPACE", 0x08081): "NullValue",
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001059 ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue",
1060 ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap",
1061 ("OLD_POINTER_SPACE", 0x080b1): "TrueValue",
1062 ("OLD_POINTER_SPACE", 0x080c1): "FalseValue",
1063 ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel",
1064 ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker",
1065 ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache",
1066 ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache",
1067 ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache",
1068 ("OLD_POINTER_SPACE", 0x08f09): "RegExpMultipleCache",
1069 ("OLD_POINTER_SPACE", 0x09311): "TerminationException",
1070 ("OLD_POINTER_SPACE", 0x09321): "MessageListeners",
1071 ("OLD_POINTER_SPACE", 0x0933d): "CodeStubs",
1072 ("OLD_POINTER_SPACE", 0x09fa5): "NonMonomorphicCache",
1073 ("OLD_POINTER_SPACE", 0x0a5b9): "PolymorphicCodeCache",
1074 ("OLD_POINTER_SPACE", 0x0a5c1): "NativesSourceCache",
1075 ("OLD_POINTER_SPACE", 0x0a601): "EmptyScript",
1076 ("OLD_POINTER_SPACE", 0x0a63d): "IntrinsicFunctionNames",
1077 ("OLD_POINTER_SPACE", 0x0d659): "ObservationState",
1078 ("OLD_POINTER_SPACE", 0x27415): "SymbolTable",
1079 ("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray",
1080 ("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray",
1081 ("OLD_DATA_SPACE", 0x080a9): "NanValue",
1082 ("OLD_DATA_SPACE", 0x08125): "EmptyByteArray",
1083 ("OLD_DATA_SPACE", 0x0812d): "EmptyString",
1084 ("OLD_DATA_SPACE", 0x08259): "InfinityValue",
1085 ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue",
1086 ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors",
1087 ("CODE_SPACE", 0x0aea1): "JsEntryCode",
1088 ("CODE_SPACE", 0x0b5c1): "JsConstructEntryCode",
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001089}
1090
1091
1092class Printer(object):
1093 """Printer with indentation support."""
1094
1095 def __init__(self):
1096 self.indent = 0
1097
1098 def Indent(self):
1099 self.indent += 2
1100
1101 def Dedent(self):
1102 self.indent -= 2
1103
1104 def Print(self, string):
1105 print "%s%s" % (self._IndentString(), string)
1106
1107 def PrintLines(self, lines):
1108 indent = self._IndentString()
1109 print "\n".join("%s%s" % (indent, line) for line in lines)
1110
1111 def _IndentString(self):
1112 return self.indent * " "
1113
1114
1115ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
1116
1117
1118def FormatDisasmLine(start, heap, line):
1119 line_address = start + line[0]
1120 stack_slot = heap.stack_map.get(line_address)
1121 marker = " "
1122 if stack_slot:
1123 marker = "=>"
1124 code = AnnotateAddresses(heap, line[1])
1125 return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
1126
1127
1128def AnnotateAddresses(heap, line):
1129 extra = []
1130 for m in ADDRESS_RE.finditer(line):
1131 maybe_address = int(m.group(0), 16)
1132 object = heap.FindObject(maybe_address)
1133 if not object: continue
1134 extra.append(str(object))
1135 if len(extra) == 0: return line
1136 return "%s ;; %s" % (line, ", ".join(extra))
1137
1138
1139class HeapObject(object):
1140 def __init__(self, heap, map, address):
1141 self.heap = heap
1142 self.map = map
1143 self.address = address
1144
1145 def Is(self, cls):
1146 return isinstance(self, cls)
1147
1148 def Print(self, p):
1149 p.Print(str(self))
1150
1151 def __str__(self):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001152 return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
1153 INSTANCE_TYPES[self.map.instance_type])
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001154
1155 def ObjectField(self, offset):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001156 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001157 return self.heap.FindObjectOrSmi(field_value)
1158
1159 def SmiField(self, offset):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001160 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 assert (field_value & 1) == 0
1162 return field_value / 2
1163
1164
1165class Map(HeapObject):
ulan@chromium.org750145a2013-03-07 15:14:13 +00001166 def Decode(self, offset, size, value):
1167 return (value >> offset) & ((1 << size) - 1)
1168
1169 # Instance Sizes
1170 def InstanceSizesOffset(self):
1171 return self.heap.PointerSize()
1172
1173 def InstanceSizeOffset(self):
1174 return self.InstanceSizesOffset()
1175
1176 def InObjectProperties(self):
1177 return self.InstanceSizeOffset() + 1
1178
1179 def PreAllocatedPropertyFields(self):
1180 return self.InObjectProperties() + 1
1181
1182 def VisitorId(self):
1183 return self.PreAllocatedPropertyFields() + 1
1184
1185 # Instance Attributes
1186 def InstanceAttributesOffset(self):
1187 return self.InstanceSizesOffset() + self.heap.IntSize()
1188
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001189 def InstanceTypeOffset(self):
ulan@chromium.org750145a2013-03-07 15:14:13 +00001190 return self.InstanceAttributesOffset()
1191
1192 def UnusedPropertyFieldsOffset(self):
1193 return self.InstanceTypeOffset() + 1
1194
1195 def BitFieldOffset(self):
1196 return self.UnusedPropertyFieldsOffset() + 1
1197
1198 def BitField2Offset(self):
1199 return self.BitFieldOffset() + 1
1200
1201 # Other fields
1202 def PrototypeOffset(self):
1203 return self.InstanceAttributesOffset() + self.heap.IntSize()
1204
1205 def ConstructorOffset(self):
1206 return self.PrototypeOffset() + self.heap.PointerSize()
1207
1208 def TransitionsOrBackPointerOffset(self):
1209 return self.ConstructorOffset() + self.heap.PointerSize()
1210
1211 def DescriptorsOffset(self):
1212 return self.TransitionsOrBackPointerOffset() + self.heap.PointerSize()
1213
1214 def CodeCacheOffset(self):
1215 return self.DescriptorsOffset() + self.heap.PointerSize()
1216
1217 def DependentCodeOffset(self):
1218 return self.CodeCacheOffset() + self.heap.PointerSize()
1219
1220 def BitField3Offset(self):
1221 return self.DependentCodeOffset() + self.heap.PointerSize()
1222
1223 def ReadByte(self, offset):
1224 return self.heap.reader.ReadU8(self.address + offset)
1225
1226 def Print(self, p):
1227 p.Print("Map(%08x)" % (self.address))
1228 p.Print("- size: %d, inobject: %d, preallocated: %d, visitor: %d" % (
1229 self.ReadByte(self.InstanceSizeOffset()),
1230 self.ReadByte(self.InObjectProperties()),
1231 self.ReadByte(self.PreAllocatedPropertyFields()),
1232 self.VisitorId()))
1233
1234 bitfield = self.ReadByte(self.BitFieldOffset())
1235 bitfield2 = self.ReadByte(self.BitField2Offset())
1236 p.Print("- %s, unused: %d, bf: %d, bf2: %d" % (
1237 INSTANCE_TYPES[self.ReadByte(self.InstanceTypeOffset())],
1238 self.ReadByte(self.UnusedPropertyFieldsOffset()),
1239 bitfield, bitfield2))
1240
1241 p.Print("- kind: %s" % (self.Decode(3, 5, bitfield2)))
1242
1243 bitfield3 = self.ObjectField(self.BitField3Offset())
1244 p.Print(
1245 "- EnumLength: %d NumberOfOwnDescriptors: %d OwnsDescriptors: %s" % (
1246 self.Decode(0, 11, bitfield3),
1247 self.Decode(11, 11, bitfield3),
1248 self.Decode(25, 1, bitfield3)))
1249 p.Print("- IsShared: %s" % (self.Decode(22, 1, bitfield3)))
1250 p.Print("- FunctionWithPrototype: %s" % (self.Decode(23, 1, bitfield3)))
1251 p.Print("- DictionaryMap: %s" % (self.Decode(24, 1, bitfield3)))
1252
1253 descriptors = self.ObjectField(self.DescriptorsOffset())
1254 if descriptors.__class__ == FixedArray:
1255 DescriptorArray(descriptors).Print(p)
1256 else:
1257 p.Print("Descriptors: %s" % (descriptors))
1258
1259 transitions = self.ObjectField(self.TransitionsOrBackPointerOffset())
1260 if transitions.__class__ == FixedArray:
1261 TransitionArray(transitions).Print(p)
1262 else:
1263 p.Print("TransitionsOrBackPointer: %s" % (transitions))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001264
1265 def __init__(self, heap, map, address):
1266 HeapObject.__init__(self, heap, map, address)
1267 self.instance_type = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001268 heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001269
1270
1271class String(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001272 def LengthOffset(self):
1273 return self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001274
1275 def __init__(self, heap, map, address):
1276 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001277 self.length = self.SmiField(self.LengthOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001278
1279 def GetChars(self):
1280 return "?string?"
1281
1282 def Print(self, p):
1283 p.Print(str(self))
1284
1285 def __str__(self):
1286 return "\"%s\"" % self.GetChars()
1287
1288
1289class SeqString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001290 def CharsOffset(self):
1291 return self.heap.PointerSize() * 3
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001292
1293 def __init__(self, heap, map, address):
1294 String.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001295 self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001296 self.length)
1297
1298 def GetChars(self):
1299 return self.chars
1300
1301
1302class ExternalString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001303 # TODO(vegorov) fix ExternalString for X64 architecture
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001304 RESOURCE_OFFSET = 12
1305
1306 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
1307 WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
1308
1309 def __init__(self, heap, map, address):
1310 String.__init__(self, heap, map, address)
1311 reader = heap.reader
1312 self.resource = \
1313 reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
1314 self.chars = "?external string?"
1315 if not reader.IsValidAddress(self.resource): return
1316 string_impl_address = self.resource + \
1317 ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
1318 if not reader.IsValidAddress(string_impl_address): return
1319 string_impl = reader.ReadU32(string_impl_address)
1320 chars_ptr_address = string_impl + \
1321 ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
1322 if not reader.IsValidAddress(chars_ptr_address): return
1323 chars_ptr = reader.ReadU32(chars_ptr_address)
1324 if not reader.IsValidAddress(chars_ptr): return
1325 raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
1326 self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
1327
1328 def GetChars(self):
1329 return self.chars
1330
1331
1332class ConsString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001333 def LeftOffset(self):
1334 return self.heap.PointerSize() * 3
1335
1336 def RightOffset(self):
1337 return self.heap.PointerSize() * 4
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001338
1339 def __init__(self, heap, map, address):
1340 String.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001341 self.left = self.ObjectField(self.LeftOffset())
1342 self.right = self.ObjectField(self.RightOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001343
1344 def GetChars(self):
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001345 try:
1346 return self.left.GetChars() + self.right.GetChars()
1347 except:
1348 return "***CAUGHT EXCEPTION IN GROKDUMP***"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001349
1350
1351class Oddball(HeapObject):
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001352 # Should match declarations in objects.h
1353 KINDS = [
1354 "False",
1355 "True",
1356 "TheHole",
1357 "Null",
1358 "ArgumentMarker",
1359 "Undefined",
1360 "Other"
1361 ]
1362
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001363 def ToStringOffset(self):
1364 return self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001366 def ToNumberOffset(self):
1367 return self.ToStringOffset() + self.heap.PointerSize()
1368
1369 def KindOffset(self):
1370 return self.ToNumberOffset() + self.heap.PointerSize()
1371
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001372 def __init__(self, heap, map, address):
1373 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001374 self.to_string = self.ObjectField(self.ToStringOffset())
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001375 self.kind = self.SmiField(self.KindOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001376
1377 def Print(self, p):
1378 p.Print(str(self))
1379
1380 def __str__(self):
verwaest@chromium.org37141392012-05-31 13:27:02 +00001381 if self.to_string:
1382 return "Oddball(%08x, <%s>)" % (self.address, self.to_string.GetChars())
1383 else:
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001384 kind = "???"
1385 if 0 <= self.kind < len(Oddball.KINDS):
1386 kind = Oddball.KINDS[self.kind]
1387 return "Oddball(%08x, kind=%s)" % (self.address, kind)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001388
1389
1390class FixedArray(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001391 def LengthOffset(self):
1392 return self.heap.PointerSize()
1393
1394 def ElementsOffset(self):
1395 return self.heap.PointerSize() * 2
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001396
ulan@chromium.org750145a2013-03-07 15:14:13 +00001397 def MemberOffset(self, i):
1398 return self.ElementsOffset() + self.heap.PointerSize() * i
1399
1400 def Get(self, i):
1401 return self.ObjectField(self.MemberOffset(i))
1402
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001403 def __init__(self, heap, map, address):
1404 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001405 self.length = self.SmiField(self.LengthOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001406
1407 def Print(self, p):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001408 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001409 p.Indent()
1410 p.Print("length: %d" % self.length)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001411 base_offset = self.ElementsOffset()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001412 for i in xrange(self.length):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001413 offset = base_offset + 4 * i
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001414 try:
1415 p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
1416 except TypeError:
1417 p.Dedent()
1418 p.Print("...")
1419 p.Print("}")
1420 return
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001421 p.Dedent()
1422 p.Print("}")
1423
1424 def __str__(self):
1425 return "FixedArray(%08x, length=%d)" % (self.address, self.length)
1426
1427
ulan@chromium.org750145a2013-03-07 15:14:13 +00001428class DescriptorArray(object):
1429 def __init__(self, array):
1430 self.array = array
1431
1432 def Length(self):
1433 return self.array.Get(0)
1434
1435 def Decode(self, offset, size, value):
1436 return (value >> offset) & ((1 << size) - 1)
1437
1438 TYPES = [
1439 "normal",
1440 "field",
1441 "function",
1442 "callbacks"
1443 ]
1444
1445 def Type(self, value):
1446 return DescriptorArray.TYPES[self.Decode(0, 3, value)]
1447
1448 def Attributes(self, value):
1449 attributes = self.Decode(3, 3, value)
1450 result = []
1451 if (attributes & 0): result += ["ReadOnly"]
1452 if (attributes & 1): result += ["DontEnum"]
1453 if (attributes & 2): result += ["DontDelete"]
1454 return "[" + (",".join(result)) + "]"
1455
1456 def Deleted(self, value):
1457 return self.Decode(6, 1, value) == 1
1458
1459 def Storage(self, value):
1460 return self.Decode(7, 11, value)
1461
1462 def Pointer(self, value):
1463 return self.Decode(18, 11, value)
1464
1465 def Details(self, di, value):
1466 return (
1467 di,
1468 self.Type(value),
1469 self.Attributes(value),
1470 self.Storage(value),
1471 self.Pointer(value)
1472 )
1473
1474
1475 def Print(self, p):
1476 length = self.Length()
1477 array = self.array
1478
1479 p.Print("Descriptors(%08x, length=%d)" % (array.address, length))
1480 p.Print("[et] %s" % (array.Get(1)))
1481
1482 for di in xrange(length):
1483 i = 2 + di * 3
1484 p.Print("0x%x" % (array.address + array.MemberOffset(i)))
1485 p.Print("[%i] name: %s" % (di, array.Get(i + 0)))
1486 p.Print("[%i] details: %s %s enum %i pointer %i" % \
1487 self.Details(di, array.Get(i + 1)))
1488 p.Print("[%i] value: %s" % (di, array.Get(i + 2)))
1489
1490 end = self.array.length // 3
1491 if length != end:
1492 p.Print("[%i-%i] slack descriptors" % (length, end))
1493
1494
1495class TransitionArray(object):
1496 def __init__(self, array):
1497 self.array = array
1498
1499 def IsSimpleTransition(self):
1500 return self.array.length <= 2
1501
1502 def Length(self):
1503 # SimpleTransition cases
1504 if self.IsSimpleTransition():
1505 return self.array.length - 1
1506 return (self.array.length - 3) // 2
1507
1508 def Print(self, p):
1509 length = self.Length()
1510 array = self.array
1511
1512 p.Print("Transitions(%08x, length=%d)" % (array.address, length))
1513 p.Print("[backpointer] %s" % (array.Get(0)))
1514 if self.IsSimpleTransition():
1515 if length == 1:
1516 p.Print("[simple target] %s" % (array.Get(1)))
1517 return
1518
1519 elements = array.Get(1)
1520 if elements is not None:
1521 p.Print("[elements ] %s" % (elements))
1522
1523 prototype = array.Get(2)
1524 if prototype is not None:
1525 p.Print("[prototype ] %s" % (prototype))
1526
1527 for di in xrange(length):
1528 i = 3 + di * 2
1529 p.Print("[%i] symbol: %s" % (di, array.Get(i + 0)))
1530 p.Print("[%i] target: %s" % (di, array.Get(i + 1)))
1531
1532
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001533class JSFunction(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001534 def CodeEntryOffset(self):
1535 return 3 * self.heap.PointerSize()
1536
1537 def SharedOffset(self):
1538 return 5 * self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001539
1540 def __init__(self, heap, map, address):
1541 HeapObject.__init__(self, heap, map, address)
1542 code_entry = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001543 heap.reader.ReadU32(self.address + self.CodeEntryOffset())
1544 self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
1545 self.shared = self.ObjectField(self.SharedOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001546
1547 def Print(self, p):
1548 source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001549 p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001550 p.Indent()
1551 p.Print("inferred name: %s" % self.shared.inferred_name)
1552 if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
1553 p.Print("script name: %s" % self.shared.script.name)
1554 p.Print("source:")
1555 p.PrintLines(self._GetSource().split("\n"))
1556 p.Print("code:")
1557 self.code.Print(p)
1558 if self.code != self.shared.code:
1559 p.Print("unoptimized code:")
1560 self.shared.code.Print(p)
1561 p.Dedent()
1562 p.Print("}")
1563
1564 def __str__(self):
1565 inferred_name = ""
1566 if self.shared.Is(SharedFunctionInfo):
1567 inferred_name = self.shared.inferred_name
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001568 return "JSFunction(%s, %s)" % \
1569 (self.heap.reader.FormatIntPtr(self.address), inferred_name)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001570
1571 def _GetSource(self):
1572 source = "?source?"
1573 start = self.shared.start_position
1574 end = self.shared.end_position
1575 if not self.shared.script.Is(Script): return source
1576 script_source = self.shared.script.source
1577 if not script_source.Is(String): return source
1578 return script_source.GetChars()[start:end]
1579
1580
1581class SharedFunctionInfo(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001582 def CodeOffset(self):
1583 return 2 * self.heap.PointerSize()
1584
1585 def ScriptOffset(self):
1586 return 7 * self.heap.PointerSize()
1587
1588 def InferredNameOffset(self):
1589 return 9 * self.heap.PointerSize()
1590
1591 def EndPositionOffset(self):
1592 return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
1593
1594 def StartPositionAndTypeOffset(self):
1595 return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001596
1597 def __init__(self, heap, map, address):
1598 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001599 self.code = self.ObjectField(self.CodeOffset())
1600 self.script = self.ObjectField(self.ScriptOffset())
1601 self.inferred_name = self.ObjectField(self.InferredNameOffset())
1602 if heap.PointerSize() == 8:
1603 start_position_and_type = \
1604 heap.reader.ReadU32(self.StartPositionAndTypeOffset())
1605 self.start_position = start_position_and_type >> 2
1606 pseudo_smi_end_position = \
1607 heap.reader.ReadU32(self.EndPositionOffset())
1608 self.end_position = pseudo_smi_end_position >> 2
1609 else:
1610 start_position_and_type = \
1611 self.SmiField(self.StartPositionAndTypeOffset())
1612 self.start_position = start_position_and_type >> 2
1613 self.end_position = \
1614 self.SmiField(self.EndPositionOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001615
1616
1617class Script(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001618 def SourceOffset(self):
1619 return self.heap.PointerSize()
1620
1621 def NameOffset(self):
1622 return self.SourceOffset() + self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001623
1624 def __init__(self, heap, map, address):
1625 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001626 self.source = self.ObjectField(self.SourceOffset())
1627 self.name = self.ObjectField(self.NameOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001628
1629
verwaest@chromium.org37141392012-05-31 13:27:02 +00001630class CodeCache(HeapObject):
1631 def DefaultCacheOffset(self):
1632 return self.heap.PointerSize()
1633
1634 def NormalTypeCacheOffset(self):
1635 return self.DefaultCacheOffset() + self.heap.PointerSize()
1636
1637 def __init__(self, heap, map, address):
1638 HeapObject.__init__(self, heap, map, address)
1639 self.default_cache = self.ObjectField(self.DefaultCacheOffset())
1640 self.normal_type_cache = self.ObjectField(self.NormalTypeCacheOffset())
1641
1642 def Print(self, p):
1643 p.Print("CodeCache(%s) {" % self.heap.reader.FormatIntPtr(self.address))
1644 p.Indent()
1645 p.Print("default cache: %s" % self.default_cache)
1646 p.Print("normal type cache: %s" % self.normal_type_cache)
1647 p.Dedent()
1648 p.Print("}")
1649
1650
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001651class Code(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001652 CODE_ALIGNMENT_MASK = (1 << 5) - 1
1653
1654 def InstructionSizeOffset(self):
1655 return self.heap.PointerSize()
1656
1657 @staticmethod
1658 def HeaderSize(heap):
1659 return (heap.PointerSize() + heap.IntSize() + \
1660 4 * heap.PointerSize() + 3 * heap.IntSize() + \
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001661 Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001662
1663 def __init__(self, heap, map, address):
1664 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001665 self.entry = self.address + Code.HeaderSize(heap)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001666 self.instruction_size = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001667 heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001668
1669 def Print(self, p):
1670 lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001671 p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001672 p.Indent()
1673 p.Print("instruction_size: %d" % self.instruction_size)
1674 p.PrintLines(self._FormatLine(line) for line in lines)
1675 p.Dedent()
1676 p.Print("}")
1677
1678 def _FormatLine(self, line):
1679 return FormatDisasmLine(self.entry, self.heap, line)
1680
1681
1682class V8Heap(object):
1683 CLASS_MAP = {
1684 "SYMBOL_TYPE": SeqString,
1685 "ASCII_SYMBOL_TYPE": SeqString,
1686 "CONS_SYMBOL_TYPE": ConsString,
1687 "CONS_ASCII_SYMBOL_TYPE": ConsString,
1688 "EXTERNAL_SYMBOL_TYPE": ExternalString,
1689 "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
1690 "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001691 "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString,
1692 "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
1693 "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001694 "STRING_TYPE": SeqString,
1695 "ASCII_STRING_TYPE": SeqString,
1696 "CONS_STRING_TYPE": ConsString,
1697 "CONS_ASCII_STRING_TYPE": ConsString,
1698 "EXTERNAL_STRING_TYPE": ExternalString,
1699 "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
1700 "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001701 "MAP_TYPE": Map,
1702 "ODDBALL_TYPE": Oddball,
1703 "FIXED_ARRAY_TYPE": FixedArray,
1704 "JS_FUNCTION_TYPE": JSFunction,
1705 "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
1706 "SCRIPT_TYPE": Script,
verwaest@chromium.org37141392012-05-31 13:27:02 +00001707 "CODE_CACHE_TYPE": CodeCache,
1708 "CODE_TYPE": Code,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001709 }
1710
1711 def __init__(self, reader, stack_map):
1712 self.reader = reader
1713 self.stack_map = stack_map
1714 self.objects = {}
1715
1716 def FindObjectOrSmi(self, tagged_address):
1717 if (tagged_address & 1) == 0: return tagged_address / 2
1718 return self.FindObject(tagged_address)
1719
1720 def FindObject(self, tagged_address):
1721 if tagged_address in self.objects:
1722 return self.objects[tagged_address]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001723 if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001724 address = tagged_address - 1
1725 if not self.reader.IsValidAddress(address): return None
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001726 map_tagged_address = self.reader.ReadUIntPtr(address)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001727 if tagged_address == map_tagged_address:
1728 # Meta map?
1729 meta_map = Map(self, None, address)
1730 instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
1731 if instance_type_name != "MAP_TYPE": return None
1732 meta_map.map = meta_map
1733 object = meta_map
1734 else:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001735 map = self.FindMap(map_tagged_address)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001736 if map is None: return None
1737 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
1738 if instance_type_name is None: return None
1739 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
1740 object = cls(self, map, address)
1741 self.objects[tagged_address] = object
1742 return object
1743
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001744 def FindMap(self, tagged_address):
1745 if (tagged_address & self.MapAlignmentMask()) != 1: return None
1746 address = tagged_address - 1
1747 if not self.reader.IsValidAddress(address): return None
1748 object = Map(self, None, address)
1749 return object
1750
1751 def IntSize(self):
1752 return 4
1753
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001754 def PointerSize(self):
1755 return self.reader.PointerSize()
1756
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001757 def ObjectAlignmentMask(self):
1758 return self.PointerSize() - 1
1759
1760 def MapAlignmentMask(self):
1761 if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
1762 return (1 << 4) - 1
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001763 elif self.reader.arch == MD_CPU_ARCHITECTURE_ARM:
1764 return (1 << 4) - 1
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001765 elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
1766 return (1 << 5) - 1
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001767
verwaest@chromium.org37141392012-05-31 13:27:02 +00001768 def PageAlignmentMask(self):
1769 return (1 << 20) - 1
1770
1771
1772class KnownObject(HeapObject):
1773 def __init__(self, heap, known_name):
1774 HeapObject.__init__(self, heap, None, None)
1775 self.known_name = known_name
1776
1777 def __str__(self):
1778 return "<%s>" % self.known_name
1779
1780
1781class KnownMap(HeapObject):
1782 def __init__(self, heap, known_name, instance_type):
1783 HeapObject.__init__(self, heap, None, None)
1784 self.instance_type = instance_type
1785 self.known_name = known_name
1786
1787 def __str__(self):
1788 return "<%s>" % self.known_name
1789
1790
1791class InspectionPadawan(object):
1792 """The padawan can improve annotations by sensing well-known objects."""
1793 def __init__(self, reader, heap):
1794 self.reader = reader
1795 self.heap = heap
1796 self.known_first_map_page = 0
1797 self.known_first_data_page = 0
1798 self.known_first_pointer_page = 0
1799
1800 def __getattr__(self, name):
1801 """An InspectionPadawan can be used instead of V8Heap, even though
1802 it does not inherit from V8Heap (aka. mixin)."""
1803 return getattr(self.heap, name)
1804
1805 def GetPageOffset(self, tagged_address):
1806 return tagged_address & self.heap.PageAlignmentMask()
1807
1808 def IsInKnownMapSpace(self, tagged_address):
1809 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1810 return page_address == self.known_first_map_page
1811
1812 def IsInKnownOldSpace(self, tagged_address):
1813 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1814 return page_address in [self.known_first_data_page,
1815 self.known_first_pointer_page]
1816
1817 def ContainingKnownOldSpaceName(self, tagged_address):
1818 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1819 if page_address == self.known_first_data_page: return "OLD_DATA_SPACE"
1820 if page_address == self.known_first_pointer_page: return "OLD_POINTER_SPACE"
1821 return None
1822
1823 def SenseObject(self, tagged_address):
1824 if self.IsInKnownOldSpace(tagged_address):
1825 offset = self.GetPageOffset(tagged_address)
1826 lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset)
1827 known_obj_name = KNOWN_OBJECTS.get(lookup_key)
1828 if known_obj_name:
1829 return KnownObject(self, known_obj_name)
1830 if self.IsInKnownMapSpace(tagged_address):
1831 known_map = self.SenseMap(tagged_address)
1832 if known_map:
1833 return known_map
1834 found_obj = self.heap.FindObject(tagged_address)
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001835 if found_obj: return found_obj
verwaest@chromium.org37141392012-05-31 13:27:02 +00001836 address = tagged_address - 1
1837 if self.reader.IsValidAddress(address):
1838 map_tagged_address = self.reader.ReadUIntPtr(address)
1839 map = self.SenseMap(map_tagged_address)
1840 if map is None: return None
1841 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
1842 if instance_type_name is None: return None
1843 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
1844 return cls(self, map, address)
1845 return None
1846
1847 def SenseMap(self, tagged_address):
1848 if self.IsInKnownMapSpace(tagged_address):
1849 offset = self.GetPageOffset(tagged_address)
1850 known_map_info = KNOWN_MAPS.get(offset)
1851 if known_map_info:
1852 known_map_type, known_map_name = known_map_info
1853 return KnownMap(self, known_map_name, known_map_type)
1854 found_map = self.heap.FindMap(tagged_address)
1855 if found_map: return found_map
1856 return None
1857
1858 def FindObjectOrSmi(self, tagged_address):
1859 """When used as a mixin in place of V8Heap."""
1860 found_obj = self.SenseObject(tagged_address)
1861 if found_obj: return found_obj
1862 if (tagged_address & 1) == 0:
1863 return "Smi(%d)" % (tagged_address / 2)
1864 else:
1865 return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address)
1866
1867 def FindObject(self, tagged_address):
1868 """When used as a mixin in place of V8Heap."""
1869 raise NotImplementedError
1870
1871 def FindMap(self, tagged_address):
1872 """When used as a mixin in place of V8Heap."""
1873 raise NotImplementedError
1874
1875 def PrintKnowledge(self):
1876 print " known_first_map_page = %s\n"\
1877 " known_first_data_page = %s\n"\
1878 " known_first_pointer_page = %s" % (
1879 self.reader.FormatIntPtr(self.known_first_map_page),
1880 self.reader.FormatIntPtr(self.known_first_data_page),
1881 self.reader.FormatIntPtr(self.known_first_pointer_page))
1882
1883
1884class InspectionShell(cmd.Cmd):
1885 def __init__(self, reader, heap):
1886 cmd.Cmd.__init__(self)
1887 self.reader = reader
1888 self.heap = heap
1889 self.padawan = InspectionPadawan(reader, heap)
1890 self.prompt = "(grok) "
1891
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001892 def do_da(self, address):
1893 """
1894 Print ASCII string starting at specified address.
1895 """
1896 address = int(address, 16)
1897 string = ""
1898 while self.reader.IsValidAddress(address):
1899 code = self.reader.ReadU8(address)
1900 if code < 128:
1901 string += chr(code)
1902 else:
1903 break
1904 address += 1
1905 if string == "":
1906 print "Not an ASCII string at %s" % self.reader.FormatIntPtr(address)
1907 else:
1908 print "%s\n" % string
1909
verwaest@chromium.org37141392012-05-31 13:27:02 +00001910 def do_dd(self, address):
1911 """
1912 Interpret memory at the given address (if available) as a sequence
1913 of words. Automatic alignment is not performed.
1914 """
1915 start = int(address, 16)
1916 if (start & self.heap.ObjectAlignmentMask()) != 0:
1917 print "Warning: Dumping un-aligned memory, is this what you had in mind?"
1918 for slot in xrange(start,
1919 start + self.reader.PointerSize() * 10,
1920 self.reader.PointerSize()):
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001921 if not self.reader.IsValidAddress(slot):
1922 print "Address is not contained within the minidump!"
1923 return
verwaest@chromium.org37141392012-05-31 13:27:02 +00001924 maybe_address = self.reader.ReadUIntPtr(slot)
1925 heap_object = self.padawan.SenseObject(maybe_address)
1926 print "%s: %s %s" % (self.reader.FormatIntPtr(slot),
1927 self.reader.FormatIntPtr(maybe_address),
1928 heap_object or '')
1929
1930 def do_do(self, address):
1931 """
1932 Interpret memory at the given address as a V8 object. Automatic
1933 alignment makes sure that you can pass tagged as well as un-tagged
1934 addresses.
1935 """
1936 address = int(address, 16)
1937 if (address & self.heap.ObjectAlignmentMask()) == 0:
1938 address = address + 1
1939 elif (address & self.heap.ObjectAlignmentMask()) != 1:
1940 print "Address doesn't look like a valid pointer!"
1941 return
1942 heap_object = self.padawan.SenseObject(address)
1943 if heap_object:
1944 heap_object.Print(Printer())
1945 else:
1946 print "Address cannot be interpreted as object!"
1947
ulan@chromium.org750145a2013-03-07 15:14:13 +00001948 def do_do_desc(self, address):
1949 """
1950 Print a descriptor array in a readable format.
1951 """
1952 start = int(address, 16)
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001953 if ((start & 1) == 1): start = start - 1
ulan@chromium.org750145a2013-03-07 15:14:13 +00001954 DescriptorArray(FixedArray(self.heap, None, start)).Print(Printer())
1955
1956 def do_do_map(self, address):
1957 """
1958 Print a descriptor array in a readable format.
1959 """
1960 start = int(address, 16)
1961 if ((start & 1) == 1): start = start - 1
1962 Map(self.heap, None, start).Print(Printer())
1963
1964 def do_do_trans(self, address):
1965 """
1966 Print a transition array in a readable format.
1967 """
1968 start = int(address, 16)
1969 if ((start & 1) == 1): start = start - 1
1970 TransitionArray(FixedArray(self.heap, None, start)).Print(Printer())
1971
verwaest@chromium.org37141392012-05-31 13:27:02 +00001972 def do_dp(self, address):
1973 """
1974 Interpret memory at the given address as being on a V8 heap page
1975 and print information about the page header (if available).
1976 """
1977 address = int(address, 16)
1978 page_address = address & ~self.heap.PageAlignmentMask()
1979 if self.reader.IsValidAddress(page_address):
1980 raise NotImplementedError
1981 else:
1982 print "Page header is not available!"
1983
1984 def do_k(self, arguments):
1985 """
1986 Teach V8 heap layout information to the inspector. This increases
1987 the amount of annotations the inspector can produce while dumping
1988 data. The first page of each heap space is of particular interest
1989 because it contains known objects that do not move.
1990 """
1991 self.padawan.PrintKnowledge()
1992
verwaest@chromium.org37141392012-05-31 13:27:02 +00001993 def do_kd(self, address):
1994 """
1995 Teach V8 heap layout information to the inspector. Set the first
1996 data-space page by passing any pointer into that page.
1997 """
1998 address = int(address, 16)
1999 page_address = address & ~self.heap.PageAlignmentMask()
2000 self.padawan.known_first_data_page = page_address
2001
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002002 def do_km(self, address):
2003 """
2004 Teach V8 heap layout information to the inspector. Set the first
2005 map-space page by passing any pointer into that page.
2006 """
2007 address = int(address, 16)
2008 page_address = address & ~self.heap.PageAlignmentMask()
2009 self.padawan.known_first_map_page = page_address
2010
verwaest@chromium.org37141392012-05-31 13:27:02 +00002011 def do_kp(self, address):
2012 """
2013 Teach V8 heap layout information to the inspector. Set the first
2014 pointer-space page by passing any pointer into that page.
2015 """
2016 address = int(address, 16)
2017 page_address = address & ~self.heap.PageAlignmentMask()
2018 self.padawan.known_first_pointer_page = page_address
2019
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002020 def do_list(self, smth):
2021 """
2022 List all available memory regions.
2023 """
2024 def print_region(reader, start, size, location):
2025 print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start),
2026 reader.FormatIntPtr(start + size),
2027 size)
2028 print "Available memory regions:"
2029 self.reader.ForEachMemoryRegion(print_region)
2030
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002031 def do_lm(self, arg):
2032 """
2033 List details for all loaded modules in the minidump. An argument can
2034 be passed to limit the output to only those modules that contain the
2035 argument as a substring (case insensitive match).
2036 """
2037 for module in self.reader.module_list.modules:
2038 if arg:
2039 name = GetModuleName(self.reader, module).lower()
2040 if name.find(arg.lower()) >= 0:
2041 PrintModuleDetails(self.reader, module)
2042 else:
2043 PrintModuleDetails(self.reader, module)
2044 print
2045
verwaest@chromium.org37141392012-05-31 13:27:02 +00002046 def do_s(self, word):
2047 """
2048 Search for a given word in available memory regions. The given word
2049 is expanded to full pointer size and searched at aligned as well as
2050 un-aligned memory locations. Use 'sa' to search aligned locations
2051 only.
2052 """
2053 try:
2054 word = int(word, 0)
2055 except ValueError:
2056 print "Malformed word, prefix with '0x' to use hexadecimal format."
2057 return
2058 print "Searching for word %d/0x%s:" % (word, self.reader.FormatIntPtr(word))
2059 self.reader.FindWord(word)
2060
2061 def do_sh(self, none):
2062 """
2063 Search for the V8 Heap object in all available memory regions. You
2064 might get lucky and find this rare treasure full of invaluable
2065 information.
2066 """
2067 raise NotImplementedError
2068
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002069 def do_u(self, args):
verwaest@chromium.org37141392012-05-31 13:27:02 +00002070 """
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002071 Unassemble memory in the region [address, address + size). If the
2072 size is not specified, a default value of 32 bytes is used.
2073 Synopsis: u 0x<address> 0x<size>
verwaest@chromium.org37141392012-05-31 13:27:02 +00002074 """
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002075 args = args.split(' ')
2076 start = int(args[0], 16)
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002077 size = int(args[1], 16) if len(args) > 1 else 0x20
2078 if not self.reader.IsValidAddress(start):
2079 print "Address is not contained within the minidump!"
2080 return
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002081 lines = self.reader.GetDisasmLines(start, size)
2082 for line in lines:
2083 print FormatDisasmLine(start, self.heap, line)
2084 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002085
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002086 def do_EOF(self, none):
2087 raise KeyboardInterrupt
2088
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002089EIP_PROXIMITY = 64
2090
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002091CONTEXT_FOR_ARCH = {
2092 MD_CPU_ARCHITECTURE_AMD64:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002093 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip',
2094 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'],
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002095 MD_CPU_ARCHITECTURE_ARM:
2096 ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9',
2097 'r10', 'r11', 'r12', 'sp', 'lr', 'pc'],
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002098 MD_CPU_ARCHITECTURE_X86:
2099 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
2100}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002101
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002102KNOWN_MODULES = {'chrome.exe', 'chrome.dll'}
2103
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002104def GetVersionString(ms, ls):
2105 return "%d.%d.%d.%d" % (ms >> 16, ms & 0xffff, ls >> 16, ls & 0xffff)
2106
2107
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002108def GetModuleName(reader, module):
2109 name = reader.ReadMinidumpString(module.module_name_rva)
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002110 # simplify for path manipulation
2111 name = name.encode('utf-8')
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002112 return str(os.path.basename(str(name).replace("\\", "/")))
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002113
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002114
2115def PrintModuleDetails(reader, module):
2116 print "%s" % GetModuleName(reader, module)
2117 file_version = GetVersionString(module.version_info.dwFileVersionMS,
2118 module.version_info.dwFileVersionLS)
2119 product_version = GetVersionString(module.version_info.dwProductVersionMS,
2120 module.version_info.dwProductVersionLS)
2121 print " base: %s" % reader.FormatIntPtr(module.base_of_image)
2122 print " end: %s" % reader.FormatIntPtr(module.base_of_image +
2123 module.size_of_image)
2124 print " file version: %s" % file_version
2125 print " product version: %s" % product_version
2126 time_date_stamp = datetime.datetime.fromtimestamp(module.time_date_stamp)
2127 print " timestamp: %s" % time_date_stamp
2128
2129
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002130def AnalyzeMinidump(options, minidump_name):
2131 reader = MinidumpReader(options, minidump_name)
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002132 heap = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002133 DebugPrint("========================================")
2134 if reader.exception is None:
2135 print "Minidump has no exception info"
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002136 else:
2137 print "Exception info:"
2138 exception_thread = reader.thread_map[reader.exception.thread_id]
2139 print " thread id: %d" % exception_thread.id
2140 print " code: %08X" % reader.exception.exception.code
2141 print " context:"
2142 for r in CONTEXT_FOR_ARCH[reader.arch]:
2143 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
2144 # TODO(vitalyr): decode eflags.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002145 if reader.arch == MD_CPU_ARCHITECTURE_ARM:
2146 print " cpsr: %s" % bin(reader.exception_context.cpsr)[2:]
2147 else:
2148 print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
2149
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002150 print
2151 print " modules:"
2152 for module in reader.module_list.modules:
2153 name = GetModuleName(reader, module)
2154 if name in KNOWN_MODULES:
2155 print " %s at %08X" % (name, module.base_of_image)
2156 reader.TryLoadSymbolsFor(name, module)
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002157 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002158
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002159 stack_top = reader.ExceptionSP()
2160 stack_bottom = exception_thread.stack.start + \
2161 exception_thread.stack.memory.data_size
2162 stack_map = {reader.ExceptionIP(): -1}
2163 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
2164 maybe_address = reader.ReadUIntPtr(slot)
2165 if not maybe_address in stack_map:
2166 stack_map[maybe_address] = slot
2167 heap = V8Heap(reader, stack_map)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002168
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002169 print "Disassembly around exception.eip:"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002170 eip_symbol = reader.FindSymbol(reader.ExceptionIP())
2171 if eip_symbol is not None:
2172 print eip_symbol
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002173 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY
2174 disasm_bytes = 2 * EIP_PROXIMITY
2175 if (options.full):
2176 full_range = reader.FindRegion(reader.ExceptionIP())
2177 if full_range is not None:
2178 disasm_start = full_range[0]
2179 disasm_bytes = full_range[1]
2180
2181 lines = reader.GetDisasmLines(disasm_start, disasm_bytes)
2182
2183 for line in lines:
2184 print FormatDisasmLine(disasm_start, heap, line)
2185 print
2186
2187 if heap is None:
2188 heap = V8Heap(reader, None)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002189
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00002190 if options.full:
verwaest@chromium.org37141392012-05-31 13:27:02 +00002191 FullDump(reader, heap)
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00002192
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002193 if options.command:
2194 InspectionShell(reader, heap).onecmd(options.command)
2195
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002196 if options.shell:
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002197 try:
2198 InspectionShell(reader, heap).cmdloop("type help to get help")
2199 except KeyboardInterrupt:
2200 print "Kthxbye."
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002201 elif not options.command:
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002202 if reader.exception is not None:
2203 print "Annotated stack (from exception.esp to bottom):"
2204 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
2205 maybe_address = reader.ReadUIntPtr(slot)
2206 heap_object = heap.FindObject(maybe_address)
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002207 maybe_symbol = reader.FindSymbol(maybe_address)
2208 print "%s: %s %s" % (reader.FormatIntPtr(slot),
2209 reader.FormatIntPtr(maybe_address),
2210 maybe_symbol or "")
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00002211 if heap_object:
2212 heap_object.Print(Printer())
2213 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002214
2215 reader.Dispose()
2216
2217
2218if __name__ == "__main__":
2219 parser = optparse.OptionParser(USAGE)
verwaest@chromium.org37141392012-05-31 13:27:02 +00002220 parser.add_option("-s", "--shell", dest="shell", action="store_true",
2221 help="start an interactive inspector shell")
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00002222 parser.add_option("-c", "--command", dest="command", default="",
2223 help="run an interactive inspector shell command and exit")
verwaest@chromium.org37141392012-05-31 13:27:02 +00002224 parser.add_option("-f", "--full", dest="full", action="store_true",
2225 help="dump all information contained in the minidump")
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002226 parser.add_option("--symdir", dest="symdir", default=".",
2227 help="directory containing *.pdb.sym file with symbols")
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002228 parser.add_option("--objdump",
2229 default="/usr/bin/objdump",
2230 help="objdump tool to use [default: %default]")
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002231 options, args = parser.parse_args()
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002232 if os.path.exists(options.objdump):
2233 disasm.OBJDUMP_BIN = options.objdump
2234 OBJDUMP_BIN = options.objdump
2235 else:
2236 print "Cannot find %s, falling back to default objdump" % options.objdump
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002237 if len(args) != 1:
2238 parser.print_help()
2239 sys.exit(1)
2240 AnalyzeMinidump(options, args[0])