blob: 9977289872bde66af4cef076dda312f27181e11b [file] [log] [blame]
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001#!/usr/bin/env python
2#
3# Copyright 2011 the V8 project authors. All rights reserved.
4# 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
30import ctypes
31import mmap
32import optparse
33import os
34import disasm
35import sys
36import types
37import codecs
38import re
39
40
41USAGE="""usage: %prog [OPTION]...
42
43Minidump analyzer.
44
45Shows the processor state at the point of exception including the
46stack of the active thread and the referenced objects in the V8
47heap. Code objects are disassembled and the addresses linked from the
48stack (pushed return addresses) are marked with "=>".
49
50
51Examples:
52 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp
53"""
54
Ben Murdoch3ef787d2012-04-12 10:51:47 +010055
Ben Murdoche0cee9b2011-05-25 10:26:03 +010056DEBUG=False
57
58
59def DebugPrint(s):
60 if not DEBUG: return
61 print s
62
63
64class Descriptor(object):
65 """Descriptor of a structure in a memory."""
66
67 def __init__(self, fields):
68 self.fields = fields
69 self.is_flexible = False
70 for _, type_or_func in fields:
71 if isinstance(type_or_func, types.FunctionType):
72 self.is_flexible = True
73 break
74 if not self.is_flexible:
75 self.ctype = Descriptor._GetCtype(fields)
76 self.size = ctypes.sizeof(self.ctype)
77
78 def Read(self, memory, offset):
79 if self.is_flexible:
80 fields_copy = self.fields[:]
81 last = 0
82 for name, type_or_func in fields_copy:
83 if isinstance(type_or_func, types.FunctionType):
84 partial_ctype = Descriptor._GetCtype(fields_copy[:last])
85 partial_object = partial_ctype.from_buffer(memory, offset)
86 type = type_or_func(partial_object)
87 if type is not None:
88 fields_copy[last] = (name, type)
89 last += 1
90 else:
91 last += 1
92 complete_ctype = Descriptor._GetCtype(fields_copy[:last])
93 else:
94 complete_ctype = self.ctype
95 return complete_ctype.from_buffer(memory, offset)
96
97 @staticmethod
98 def _GetCtype(fields):
99 class Raw(ctypes.Structure):
100 _fields_ = fields
101 _pack_ = 1
102
103 def __str__(self):
104 return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field))
105 for field, _ in Raw._fields_) + "}"
106 return Raw
107
108
109# Set of structures and constants that describe the layout of minidump
110# files. Based on MSDN and Google Breakpad.
111
112MINIDUMP_HEADER = Descriptor([
113 ("signature", ctypes.c_uint32),
114 ("version", ctypes.c_uint32),
115 ("stream_count", ctypes.c_uint32),
116 ("stream_directories_rva", ctypes.c_uint32),
117 ("checksum", ctypes.c_uint32),
118 ("time_date_stampt", ctypes.c_uint32),
119 ("flags", ctypes.c_uint64)
120])
121
122MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
123 ("data_size", ctypes.c_uint32),
124 ("rva", ctypes.c_uint32)
125])
126
127MINIDUMP_DIRECTORY = Descriptor([
128 ("stream_type", ctypes.c_uint32),
129 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
130])
131
132MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
133
134MINIDUMP_EXCEPTION = Descriptor([
135 ("code", ctypes.c_uint32),
136 ("flags", ctypes.c_uint32),
137 ("record", ctypes.c_uint64),
138 ("address", ctypes.c_uint64),
139 ("parameter_count", ctypes.c_uint32),
140 ("unused_alignment", ctypes.c_uint32),
141 ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
142])
143
144MINIDUMP_EXCEPTION_STREAM = Descriptor([
145 ("thread_id", ctypes.c_uint32),
146 ("unused_alignment", ctypes.c_uint32),
147 ("exception", MINIDUMP_EXCEPTION.ctype),
148 ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
149])
150
151# Stream types.
152MD_UNUSED_STREAM = 0
153MD_RESERVED_STREAM_0 = 1
154MD_RESERVED_STREAM_1 = 2
155MD_THREAD_LIST_STREAM = 3
156MD_MODULE_LIST_STREAM = 4
157MD_MEMORY_LIST_STREAM = 5
158MD_EXCEPTION_STREAM = 6
159MD_SYSTEM_INFO_STREAM = 7
160MD_THREAD_EX_LIST_STREAM = 8
161MD_MEMORY_64_LIST_STREAM = 9
162MD_COMMENT_STREAM_A = 10
163MD_COMMENT_STREAM_W = 11
164MD_HANDLE_DATA_STREAM = 12
165MD_FUNCTION_TABLE_STREAM = 13
166MD_UNLOADED_MODULE_LIST_STREAM = 14
167MD_MISC_INFO_STREAM = 15
168MD_MEMORY_INFO_LIST_STREAM = 16
169MD_THREAD_INFO_LIST_STREAM = 17
170MD_HANDLE_OPERATION_LIST_STREAM = 18
171
172MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
173
174MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
175 ("control_word", ctypes.c_uint32),
176 ("status_word", ctypes.c_uint32),
177 ("tag_word", ctypes.c_uint32),
178 ("error_offset", ctypes.c_uint32),
179 ("error_selector", ctypes.c_uint32),
180 ("data_offset", ctypes.c_uint32),
181 ("data_selector", ctypes.c_uint32),
182 ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
183 ("cr0_npx_state", ctypes.c_uint32)
184])
185
186MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
187
188# Context flags.
189MD_CONTEXT_X86 = 0x00010000
190MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
191MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
192MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
193MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
194MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
195MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
196
197def EnableOnFlag(type, flag):
198 return lambda o: [None, type][int((o.context_flags & flag) != 0)]
199
200MINIDUMP_CONTEXT_X86 = Descriptor([
201 ("context_flags", ctypes.c_uint32),
202 # MD_CONTEXT_X86_DEBUG_REGISTERS.
203 ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
204 ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
205 ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
206 ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
207 ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
208 ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
209 # MD_CONTEXT_X86_FLOATING_POINT.
210 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
211 MD_CONTEXT_X86_FLOATING_POINT)),
212 # MD_CONTEXT_X86_SEGMENTS.
213 ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
214 ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
215 ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
216 ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
217 # MD_CONTEXT_X86_INTEGER.
218 ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
219 ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
220 ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
221 ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
222 ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
223 ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
224 # MD_CONTEXT_X86_CONTROL.
225 ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
226 ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
227 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
228 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
229 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
230 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
231 # MD_CONTEXT_X86_EXTENDED_REGISTERS.
232 ("extended_registers",
233 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
234 MD_CONTEXT_X86_EXTENDED_REGISTERS))
235])
236
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100237MD_CONTEXT_AMD64 = 0x00100000
238MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
239MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
240MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
241MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
242MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
243
244MINIDUMP_CONTEXT_AMD64 = Descriptor([
245 ("p1_home", ctypes.c_uint64),
246 ("p2_home", ctypes.c_uint64),
247 ("p3_home", ctypes.c_uint64),
248 ("p4_home", ctypes.c_uint64),
249 ("p5_home", ctypes.c_uint64),
250 ("p6_home", ctypes.c_uint64),
251 ("context_flags", ctypes.c_uint32),
252 ("mx_csr", ctypes.c_uint32),
253 # MD_CONTEXT_AMD64_CONTROL.
254 ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
255 # MD_CONTEXT_AMD64_SEGMENTS
256 ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
257 ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
258 ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
259 ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
260 # MD_CONTEXT_AMD64_CONTROL.
261 ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
262 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
263 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
264 ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
265 ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
266 ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
267 ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
268 ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
269 ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
270 # MD_CONTEXT_AMD64_INTEGER.
271 ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
272 ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
273 ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
274 ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
275 # MD_CONTEXT_AMD64_CONTROL.
276 ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
277 # MD_CONTEXT_AMD64_INTEGER.
278 ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
279 ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
280 ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
281 ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
282 ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
283 ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
284 ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
285 ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
286 ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
287 ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
288 ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
289 # MD_CONTEXT_AMD64_CONTROL.
290 ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
291 # MD_CONTEXT_AMD64_FLOATING_POINT
292 ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
293 MD_CONTEXT_AMD64_FLOATING_POINT)),
294 ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
295 MD_CONTEXT_AMD64_FLOATING_POINT)),
296 ("vector_control", EnableOnFlag(ctypes.c_uint64,
297 MD_CONTEXT_AMD64_FLOATING_POINT)),
298 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
299 ("debug_control", EnableOnFlag(ctypes.c_uint64,
300 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
301 ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
302 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
303 ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
304 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
305 ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
306 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
307 ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
308 MD_CONTEXT_AMD64_DEBUG_REGISTERS))
309])
310
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100311MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
312 ("start", ctypes.c_uint64),
313 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
314])
315
316MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
317 ("start", ctypes.c_uint64),
318 ("size", ctypes.c_uint64)
319])
320
321MINIDUMP_MEMORY_LIST = Descriptor([
322 ("range_count", ctypes.c_uint32),
323 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
324])
325
326MINIDUMP_MEMORY_LIST64 = Descriptor([
327 ("range_count", ctypes.c_uint64),
328 ("base_rva", ctypes.c_uint64),
329 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
330])
331
332MINIDUMP_THREAD = Descriptor([
333 ("id", ctypes.c_uint32),
334 ("suspend_count", ctypes.c_uint32),
335 ("priority_class", ctypes.c_uint32),
336 ("priority", ctypes.c_uint32),
337 ("ted", ctypes.c_uint64),
338 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
339 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
340])
341
342MINIDUMP_THREAD_LIST = Descriptor([
343 ("thread_count", ctypes.c_uint32),
344 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
345])
346
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100347MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
348 ("processor_architecture", ctypes.c_uint16)
349])
350
351MD_CPU_ARCHITECTURE_X86 = 0
352MD_CPU_ARCHITECTURE_AMD64 = 9
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100353
354class MinidumpReader(object):
355 """Minidump (.dmp) reader."""
356
357 _HEADER_MAGIC = 0x504d444d
358
359 def __init__(self, options, minidump_name):
360 self.minidump_name = minidump_name
361 self.minidump_file = open(minidump_name, "r")
362 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
363 self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
364 if self.header.signature != MinidumpReader._HEADER_MAGIC:
365 print >>sys.stderr, "Warning: unsupported minidump header magic"
366 DebugPrint(self.header)
367 directories = []
368 offset = self.header.stream_directories_rva
369 for _ in xrange(self.header.stream_count):
370 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
371 offset += MINIDUMP_DIRECTORY.size
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100372 self.arch = None
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100373 self.exception = None
374 self.exception_context = None
375 self.memory_list = None
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000376 self.memory_list64 = None
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100377 self.thread_map = {}
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100378
379 # Find MDRawSystemInfo stream and determine arch.
380 for d in directories:
381 if d.stream_type == MD_SYSTEM_INFO_STREAM:
382 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
383 self.minidump, d.location.rva)
384 self.arch = system_info.processor_architecture
385 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86]
386 assert not self.arch is None
387
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100388 for d in directories:
389 DebugPrint(d)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100390 if d.stream_type == MD_EXCEPTION_STREAM:
391 self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
392 self.minidump, d.location.rva)
393 DebugPrint(self.exception)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100394 if self.arch == MD_CPU_ARCHITECTURE_X86:
395 self.exception_context = MINIDUMP_CONTEXT_X86.Read(
396 self.minidump, self.exception.thread_context.rva)
397 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
398 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
399 self.minidump, self.exception.thread_context.rva)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100400 DebugPrint(self.exception_context)
401 elif d.stream_type == MD_THREAD_LIST_STREAM:
402 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
403 assert ctypes.sizeof(thread_list) == d.location.data_size
404 DebugPrint(thread_list)
405 for thread in thread_list.threads:
406 DebugPrint(thread)
407 self.thread_map[thread.id] = thread
408 elif d.stream_type == MD_MEMORY_LIST_STREAM:
409 print >>sys.stderr, "Warning: not a full minidump"
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100410 assert self.memory_list is None
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000411 self.memory_list = MINIDUMP_MEMORY_LIST.Read(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100412 self.minidump, d.location.rva)
413 assert ctypes.sizeof(self.memory_list) == d.location.data_size
414 DebugPrint(self.memory_list)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000415 elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
416 assert self.memory_list64 is None
417 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read(
418 self.minidump, d.location.rva)
419 assert ctypes.sizeof(self.memory_list64) == d.location.data_size
420 DebugPrint(self.memory_list64)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100421
422 def IsValidAddress(self, address):
423 return self.FindLocation(address) is not None
424
425 def ReadU8(self, address):
426 location = self.FindLocation(address)
427 return ctypes.c_uint8.from_buffer(self.minidump, location).value
428
429 def ReadU32(self, address):
430 location = self.FindLocation(address)
431 return ctypes.c_uint32.from_buffer(self.minidump, location).value
432
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100433 def ReadU64(self, address):
434 location = self.FindLocation(address)
435 return ctypes.c_uint64.from_buffer(self.minidump, location).value
436
437 def ReadUIntPtr(self, address):
438 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
439 return self.ReadU64(address)
440 elif self.arch == MD_CPU_ARCHITECTURE_X86:
441 return self.ReadU32(address)
442
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100443 def ReadBytes(self, address, size):
444 location = self.FindLocation(address)
445 return self.minidump[location:location + size]
446
447 def FindLocation(self, address):
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100448 offset = 0
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000449 if self.memory_list64 is not None:
450 for r in self.memory_list64.ranges:
451 if r.start <= address < r.start + r.size:
452 return self.memory_list64.base_rva + offset + address - r.start
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000453 offset += r.size
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000454 if self.memory_list is not None:
455 for r in self.memory_list.ranges:
456 if r.start <= address < r.start + r.memory.data_size:
457 return r.memory.rva + address - r.start
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100458 return None
459
460 def GetDisasmLines(self, address, size):
461 location = self.FindLocation(address)
462 if location is None: return []
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100463 arch = None
464 if self.arch == MD_CPU_ARCHITECTURE_X86:
465 arch = "ia32"
466 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
467 arch = "x64"
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100468 return disasm.GetDisasmLines(self.minidump_name,
469 location,
470 size,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100471 arch,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100472 False)
473
474
475 def Dispose(self):
476 self.minidump.close()
477 self.minidump_file.close()
478
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479 def ExceptionIP(self):
480 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
481 return self.exception_context.rip
482 elif self.arch == MD_CPU_ARCHITECTURE_X86:
483 return self.exception_context.eip
484
485 def ExceptionSP(self):
486 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
487 return self.exception_context.rsp
488 elif self.arch == MD_CPU_ARCHITECTURE_X86:
489 return self.exception_context.esp
490
491 def FormatIntPtr(self, value):
492 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
493 return "%016x" % value
494 elif self.arch == MD_CPU_ARCHITECTURE_X86:
495 return "%08x" % value
496
497 def PointerSize(self):
498 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
499 return 8
500 elif self.arch == MD_CPU_ARCHITECTURE_X86:
501 return 4
502
503 def Register(self, name):
504 return self.exception_context.__getattribute__(name)
505
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100506
507# List of V8 instance types. Obtained by adding the code below to any .cc file.
508#
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100509# #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100510# struct P {
511# P() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100512# printf("INSTANCE_TYPES = {\n");
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100513# INSTANCE_TYPE_LIST(DUMP_TYPE)
514# printf("}\n");
515# }
516# };
517# static P p;
518INSTANCE_TYPES = {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000519 64: "SYMBOL_TYPE",
520 68: "ASCII_SYMBOL_TYPE",
521 65: "CONS_SYMBOL_TYPE",
522 69: "CONS_ASCII_SYMBOL_TYPE",
523 66: "EXTERNAL_SYMBOL_TYPE",
524 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
525 70: "EXTERNAL_ASCII_SYMBOL_TYPE",
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100526 82: "SHORT_EXTERNAL_SYMBOL_TYPE",
527 90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
528 86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE",
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000529 0: "STRING_TYPE",
530 4: "ASCII_STRING_TYPE",
531 1: "CONS_STRING_TYPE",
532 5: "CONS_ASCII_STRING_TYPE",
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100533 3: "SLICED_STRING_TYPE",
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000534 2: "EXTERNAL_STRING_TYPE",
535 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
536 6: "EXTERNAL_ASCII_STRING_TYPE",
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100537 18: "SHORT_EXTERNAL_STRING_TYPE",
538 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
539 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE",
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000540 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE",
541 128: "MAP_TYPE",
542 129: "CODE_TYPE",
543 130: "ODDBALL_TYPE",
544 131: "JS_GLOBAL_PROPERTY_CELL_TYPE",
545 132: "HEAP_NUMBER_TYPE",
546 133: "FOREIGN_TYPE",
547 134: "BYTE_ARRAY_TYPE",
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100548 135: "FREE_SPACE_TYPE",
549 136: "EXTERNAL_BYTE_ARRAY_TYPE",
550 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
551 138: "EXTERNAL_SHORT_ARRAY_TYPE",
552 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
553 140: "EXTERNAL_INT_ARRAY_TYPE",
554 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
555 142: "EXTERNAL_FLOAT_ARRAY_TYPE",
556 144: "EXTERNAL_PIXEL_ARRAY_TYPE",
557 146: "FILLER_TYPE",
558 147: "ACCESSOR_INFO_TYPE",
559 148: "ACCESSOR_PAIR_TYPE",
560 149: "ACCESS_CHECK_INFO_TYPE",
561 150: "INTERCEPTOR_INFO_TYPE",
562 151: "CALL_HANDLER_INFO_TYPE",
563 152: "FUNCTION_TEMPLATE_INFO_TYPE",
564 153: "OBJECT_TEMPLATE_INFO_TYPE",
565 154: "SIGNATURE_INFO_TYPE",
566 155: "TYPE_SWITCH_INFO_TYPE",
567 156: "SCRIPT_TYPE",
568 157: "CODE_CACHE_TYPE",
569 158: "POLYMORPHIC_CODE_CACHE_TYPE",
570 161: "FIXED_ARRAY_TYPE",
571 145: "FIXED_DOUBLE_ARRAY_TYPE",
572 162: "SHARED_FUNCTION_INFO_TYPE",
573 163: "JS_MESSAGE_OBJECT_TYPE",
574 166: "JS_VALUE_TYPE",
575 167: "JS_OBJECT_TYPE",
576 168: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
577 169: "JS_GLOBAL_OBJECT_TYPE",
578 170: "JS_BUILTINS_OBJECT_TYPE",
579 171: "JS_GLOBAL_PROXY_TYPE",
580 172: "JS_ARRAY_TYPE",
581 165: "JS_PROXY_TYPE",
582 175: "JS_WEAK_MAP_TYPE",
583 176: "JS_REGEXP_TYPE",
584 177: "JS_FUNCTION_TYPE",
585 164: "JS_FUNCTION_PROXY_TYPE",
586 159: "DEBUG_INFO_TYPE",
587 160: "BREAK_POINT_INFO_TYPE",
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100588}
589
590
591class Printer(object):
592 """Printer with indentation support."""
593
594 def __init__(self):
595 self.indent = 0
596
597 def Indent(self):
598 self.indent += 2
599
600 def Dedent(self):
601 self.indent -= 2
602
603 def Print(self, string):
604 print "%s%s" % (self._IndentString(), string)
605
606 def PrintLines(self, lines):
607 indent = self._IndentString()
608 print "\n".join("%s%s" % (indent, line) for line in lines)
609
610 def _IndentString(self):
611 return self.indent * " "
612
613
614ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
615
616
617def FormatDisasmLine(start, heap, line):
618 line_address = start + line[0]
619 stack_slot = heap.stack_map.get(line_address)
620 marker = " "
621 if stack_slot:
622 marker = "=>"
623 code = AnnotateAddresses(heap, line[1])
624 return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
625
626
627def AnnotateAddresses(heap, line):
628 extra = []
629 for m in ADDRESS_RE.finditer(line):
630 maybe_address = int(m.group(0), 16)
631 object = heap.FindObject(maybe_address)
632 if not object: continue
633 extra.append(str(object))
634 if len(extra) == 0: return line
635 return "%s ;; %s" % (line, ", ".join(extra))
636
637
638class HeapObject(object):
639 def __init__(self, heap, map, address):
640 self.heap = heap
641 self.map = map
642 self.address = address
643
644 def Is(self, cls):
645 return isinstance(self, cls)
646
647 def Print(self, p):
648 p.Print(str(self))
649
650 def __str__(self):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100651 return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
652 INSTANCE_TYPES[self.map.instance_type])
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100653
654 def ObjectField(self, offset):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100655 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100656 return self.heap.FindObjectOrSmi(field_value)
657
658 def SmiField(self, offset):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100659 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100660 assert (field_value & 1) == 0
661 return field_value / 2
662
663
664class Map(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100665 def InstanceTypeOffset(self):
666 return self.heap.PointerSize() + self.heap.IntSize()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100667
668 def __init__(self, heap, map, address):
669 HeapObject.__init__(self, heap, map, address)
670 self.instance_type = \
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100671 heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100672
673
674class String(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100675 def LengthOffset(self):
676 return self.heap.PointerSize()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100677
678 def __init__(self, heap, map, address):
679 HeapObject.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100680 self.length = self.SmiField(self.LengthOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100681
682 def GetChars(self):
683 return "?string?"
684
685 def Print(self, p):
686 p.Print(str(self))
687
688 def __str__(self):
689 return "\"%s\"" % self.GetChars()
690
691
692class SeqString(String):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100693 def CharsOffset(self):
694 return self.heap.PointerSize() * 3
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100695
696 def __init__(self, heap, map, address):
697 String.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100698 self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100699 self.length)
700
701 def GetChars(self):
702 return self.chars
703
704
705class ExternalString(String):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100706 # TODO(vegorov) fix ExternalString for X64 architecture
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100707 RESOURCE_OFFSET = 12
708
709 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
710 WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
711
712 def __init__(self, heap, map, address):
713 String.__init__(self, heap, map, address)
714 reader = heap.reader
715 self.resource = \
716 reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
717 self.chars = "?external string?"
718 if not reader.IsValidAddress(self.resource): return
719 string_impl_address = self.resource + \
720 ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
721 if not reader.IsValidAddress(string_impl_address): return
722 string_impl = reader.ReadU32(string_impl_address)
723 chars_ptr_address = string_impl + \
724 ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
725 if not reader.IsValidAddress(chars_ptr_address): return
726 chars_ptr = reader.ReadU32(chars_ptr_address)
727 if not reader.IsValidAddress(chars_ptr): return
728 raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
729 self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
730
731 def GetChars(self):
732 return self.chars
733
734
735class ConsString(String):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100736 def LeftOffset(self):
737 return self.heap.PointerSize() * 3
738
739 def RightOffset(self):
740 return self.heap.PointerSize() * 4
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100741
742 def __init__(self, heap, map, address):
743 String.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100744 self.left = self.ObjectField(self.LeftOffset())
745 self.right = self.ObjectField(self.RightOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100746
747 def GetChars(self):
748 return self.left.GetChars() + self.right.GetChars()
749
750
751class Oddball(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100752 def ToStringOffset(self):
753 return self.heap.PointerSize()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100754
755 def __init__(self, heap, map, address):
756 HeapObject.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100757 self.to_string = self.ObjectField(self.ToStringOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100758
759 def Print(self, p):
760 p.Print(str(self))
761
762 def __str__(self):
763 return "<%s>" % self.to_string.GetChars()
764
765
766class FixedArray(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100767 def LengthOffset(self):
768 return self.heap.PointerSize()
769
770 def ElementsOffset(self):
771 return self.heap.PointerSize() * 2
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100772
773 def __init__(self, heap, map, address):
774 HeapObject.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100775 self.length = self.SmiField(self.LengthOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100776
777 def Print(self, p):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100778 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100779 p.Indent()
780 p.Print("length: %d" % self.length)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100781 base_offset = self.ElementsOffset()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100782 for i in xrange(self.length):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100783 offset = base_offset + 4 * i
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100784 p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
785 p.Dedent()
786 p.Print("}")
787
788 def __str__(self):
789 return "FixedArray(%08x, length=%d)" % (self.address, self.length)
790
791
792class JSFunction(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100793 def CodeEntryOffset(self):
794 return 3 * self.heap.PointerSize()
795
796 def SharedOffset(self):
797 return 5 * self.heap.PointerSize()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100798
799 def __init__(self, heap, map, address):
800 HeapObject.__init__(self, heap, map, address)
801 code_entry = \
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100802 heap.reader.ReadU32(self.address + self.CodeEntryOffset())
803 self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
804 self.shared = self.ObjectField(self.SharedOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100805
806 def Print(self, p):
807 source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100808 p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100809 p.Indent()
810 p.Print("inferred name: %s" % self.shared.inferred_name)
811 if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
812 p.Print("script name: %s" % self.shared.script.name)
813 p.Print("source:")
814 p.PrintLines(self._GetSource().split("\n"))
815 p.Print("code:")
816 self.code.Print(p)
817 if self.code != self.shared.code:
818 p.Print("unoptimized code:")
819 self.shared.code.Print(p)
820 p.Dedent()
821 p.Print("}")
822
823 def __str__(self):
824 inferred_name = ""
825 if self.shared.Is(SharedFunctionInfo):
826 inferred_name = self.shared.inferred_name
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100827 return "JSFunction(%s, %s)" % \
828 (self.heap.reader.FormatIntPtr(self.address), inferred_name)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100829
830 def _GetSource(self):
831 source = "?source?"
832 start = self.shared.start_position
833 end = self.shared.end_position
834 if not self.shared.script.Is(Script): return source
835 script_source = self.shared.script.source
836 if not script_source.Is(String): return source
837 return script_source.GetChars()[start:end]
838
839
840class SharedFunctionInfo(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100841 def CodeOffset(self):
842 return 2 * self.heap.PointerSize()
843
844 def ScriptOffset(self):
845 return 7 * self.heap.PointerSize()
846
847 def InferredNameOffset(self):
848 return 9 * self.heap.PointerSize()
849
850 def EndPositionOffset(self):
851 return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
852
853 def StartPositionAndTypeOffset(self):
854 return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100855
856 def __init__(self, heap, map, address):
857 HeapObject.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100858 self.code = self.ObjectField(self.CodeOffset())
859 self.script = self.ObjectField(self.ScriptOffset())
860 self.inferred_name = self.ObjectField(self.InferredNameOffset())
861 if heap.PointerSize() == 8:
862 start_position_and_type = \
863 heap.reader.ReadU32(self.StartPositionAndTypeOffset())
864 self.start_position = start_position_and_type >> 2
865 pseudo_smi_end_position = \
866 heap.reader.ReadU32(self.EndPositionOffset())
867 self.end_position = pseudo_smi_end_position >> 2
868 else:
869 start_position_and_type = \
870 self.SmiField(self.StartPositionAndTypeOffset())
871 self.start_position = start_position_and_type >> 2
872 self.end_position = \
873 self.SmiField(self.EndPositionOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100874
875
876class Script(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100877 def SourceOffset(self):
878 return self.heap.PointerSize()
879
880 def NameOffset(self):
881 return self.SourceOffset() + self.heap.PointerSize()
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100882
883 def __init__(self, heap, map, address):
884 HeapObject.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100885 self.source = self.ObjectField(self.SourceOffset())
886 self.name = self.ObjectField(self.NameOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100887
888
889class Code(HeapObject):
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100890 CODE_ALIGNMENT_MASK = (1 << 5) - 1
891
892 def InstructionSizeOffset(self):
893 return self.heap.PointerSize()
894
895 @staticmethod
896 def HeaderSize(heap):
897 return (heap.PointerSize() + heap.IntSize() + \
898 4 * heap.PointerSize() + 3 * heap.IntSize() + \
899 Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100900
901 def __init__(self, heap, map, address):
902 HeapObject.__init__(self, heap, map, address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100903 self.entry = self.address + Code.HeaderSize(heap)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100904 self.instruction_size = \
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100905 heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100906
907 def Print(self, p):
908 lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100909 p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100910 p.Indent()
911 p.Print("instruction_size: %d" % self.instruction_size)
912 p.PrintLines(self._FormatLine(line) for line in lines)
913 p.Dedent()
914 p.Print("}")
915
916 def _FormatLine(self, line):
917 return FormatDisasmLine(self.entry, self.heap, line)
918
919
920class V8Heap(object):
921 CLASS_MAP = {
922 "SYMBOL_TYPE": SeqString,
923 "ASCII_SYMBOL_TYPE": SeqString,
924 "CONS_SYMBOL_TYPE": ConsString,
925 "CONS_ASCII_SYMBOL_TYPE": ConsString,
926 "EXTERNAL_SYMBOL_TYPE": ExternalString,
927 "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
928 "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100929 "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString,
930 "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
931 "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100932 "STRING_TYPE": SeqString,
933 "ASCII_STRING_TYPE": SeqString,
934 "CONS_STRING_TYPE": ConsString,
935 "CONS_ASCII_STRING_TYPE": ConsString,
936 "EXTERNAL_STRING_TYPE": ExternalString,
937 "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
938 "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
939
940 "MAP_TYPE": Map,
941 "ODDBALL_TYPE": Oddball,
942 "FIXED_ARRAY_TYPE": FixedArray,
943 "JS_FUNCTION_TYPE": JSFunction,
944 "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
945 "SCRIPT_TYPE": Script,
946 "CODE_TYPE": Code
947 }
948
949 def __init__(self, reader, stack_map):
950 self.reader = reader
951 self.stack_map = stack_map
952 self.objects = {}
953
954 def FindObjectOrSmi(self, tagged_address):
955 if (tagged_address & 1) == 0: return tagged_address / 2
956 return self.FindObject(tagged_address)
957
958 def FindObject(self, tagged_address):
959 if tagged_address in self.objects:
960 return self.objects[tagged_address]
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100961 if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100962 address = tagged_address - 1
963 if not self.reader.IsValidAddress(address): return None
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100964 map_tagged_address = self.reader.ReadUIntPtr(address)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100965 if tagged_address == map_tagged_address:
966 # Meta map?
967 meta_map = Map(self, None, address)
968 instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
969 if instance_type_name != "MAP_TYPE": return None
970 meta_map.map = meta_map
971 object = meta_map
972 else:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100973 map = self.FindMap(map_tagged_address)
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100974 if map is None: return None
975 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
976 if instance_type_name is None: return None
977 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
978 object = cls(self, map, address)
979 self.objects[tagged_address] = object
980 return object
981
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100982 def FindMap(self, tagged_address):
983 if (tagged_address & self.MapAlignmentMask()) != 1: return None
984 address = tagged_address - 1
985 if not self.reader.IsValidAddress(address): return None
986 object = Map(self, None, address)
987 return object
988
989 def IntSize(self):
990 return 4
991
992 def PointerSize(self):
993 return self.reader.PointerSize()
994
995 def ObjectAlignmentMask(self):
996 return self.PointerSize() - 1
997
998 def MapAlignmentMask(self):
999 if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
1000 return (1 << 4) - 1
1001 elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
1002 return (1 << 5) - 1
1003
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001004
1005EIP_PROXIMITY = 64
1006
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001007CONTEXT_FOR_ARCH = {
1008 MD_CPU_ARCHITECTURE_AMD64:
1009 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'],
1010 MD_CPU_ARCHITECTURE_X86:
1011 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
1012}
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001013
1014def AnalyzeMinidump(options, minidump_name):
1015 reader = MinidumpReader(options, minidump_name)
1016 DebugPrint("========================================")
1017 if reader.exception is None:
1018 print "Minidump has no exception info"
1019 return
1020 print "Exception info:"
1021 exception_thread = reader.thread_map[reader.exception.thread_id]
1022 print " thread id: %d" % exception_thread.id
1023 print " code: %08X" % reader.exception.exception.code
1024 print " context:"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001025 for r in CONTEXT_FOR_ARCH[reader.arch]:
1026 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001027 # TODO(vitalyr): decode eflags.
1028 print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
1029 print
1030
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001031 stack_top = reader.ExceptionSP()
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001032 stack_bottom = exception_thread.stack.start + \
1033 exception_thread.stack.memory.data_size
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001034 stack_map = {reader.ExceptionIP(): -1}
1035 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
1036 maybe_address = reader.ReadUIntPtr(slot)
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001037 if not maybe_address in stack_map:
1038 stack_map[maybe_address] = slot
1039 heap = V8Heap(reader, stack_map)
1040
1041 print "Disassembly around exception.eip:"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001042 start = reader.ExceptionIP() - EIP_PROXIMITY
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001043 lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY)
1044 for line in lines:
1045 print FormatDisasmLine(start, heap, line)
1046 print
1047
1048 print "Annotated stack (from exception.esp to bottom):"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001049 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
1050 maybe_address = reader.ReadUIntPtr(slot)
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001051 heap_object = heap.FindObject(maybe_address)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001052 print "%s: %s" % (reader.FormatIntPtr(slot),
1053 reader.FormatIntPtr(maybe_address))
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001054 if heap_object:
1055 heap_object.Print(Printer())
1056 print
1057
1058 reader.Dispose()
1059
1060
1061if __name__ == "__main__":
1062 parser = optparse.OptionParser(USAGE)
1063 options, args = parser.parse_args()
1064 if len(args) != 1:
1065 parser.print_help()
1066 sys.exit(1)
1067 AnalyzeMinidump(options, args[0])