blob: 24c9c5a92c10202031e974122535a2858077444b [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
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000030import cmd
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000031import ctypes
32import mmap
33import optparse
34import os
35import disasm
36import sys
37import types
38import codecs
39import re
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000040import struct
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000041
42
verwaest@chromium.org37141392012-05-31 13:27:02 +000043USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000044
45Minidump analyzer.
46
47Shows the processor state at the point of exception including the
48stack of the active thread and the referenced objects in the V8
49heap. Code objects are disassembled and the addresses linked from the
verwaest@chromium.org37141392012-05-31 13:27:02 +000050stack (e.g. pushed return addresses) are marked with "=>".
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000051
52Examples:
verwaest@chromium.org37141392012-05-31 13:27:02 +000053 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp"""
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000054
ricow@chromium.org7ad65222011-12-19 12:13:11 +000055
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000056DEBUG=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
verwaest@chromium.org37141392012-05-31 13:27:02 +0000109def FullDump(reader, heap):
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000110 """Dump all available memory regions."""
111 def dump_region(reader, start, size, location):
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000112 print
113 while start & 3 != 0:
114 start += 1
115 size -= 1
116 location += 1
117 is_executable = reader.IsProbableExecutableRegion(location, size)
118 is_ascii = reader.IsProbableASCIIRegion(location, size)
119
120 if is_executable is not False:
121 lines = reader.GetDisasmLines(start, size)
122 for line in lines:
123 print FormatDisasmLine(start, heap, line)
124 print
125
126 if is_ascii is not False:
127 # Output in the same format as the Unix hd command
128 addr = start
129 for slot in xrange(location, location + size, 16):
130 hex_line = ""
131 asc_line = ""
132 for i in xrange(0, 16):
133 if slot + i < location + size:
134 byte = ctypes.c_uint8.from_buffer(reader.minidump, slot + i).value
135 if byte >= 0x20 and byte < 0x7f:
136 asc_line += chr(byte)
137 else:
138 asc_line += "."
139 hex_line += " %02x" % (byte)
140 else:
141 hex_line += " "
142 if i == 7:
143 hex_line += " "
144 print "%s %s |%s|" % (reader.FormatIntPtr(addr),
145 hex_line,
146 asc_line)
147 addr += 16
148
149 if is_executable is not True and is_ascii is not True:
150 print "%s - %s" % (reader.FormatIntPtr(start),
151 reader.FormatIntPtr(start + size))
152 for slot in xrange(start,
153 start + size,
154 reader.PointerSize()):
155 maybe_address = reader.ReadUIntPtr(slot)
156 heap_object = heap.FindObject(maybe_address)
157 print "%s: %s" % (reader.FormatIntPtr(slot),
158 reader.FormatIntPtr(maybe_address))
159 if heap_object:
160 heap_object.Print(Printer())
161 print
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000162
163 reader.ForEachMemoryRegion(dump_region)
164
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000165# Set of structures and constants that describe the layout of minidump
166# files. Based on MSDN and Google Breakpad.
167
168MINIDUMP_HEADER = Descriptor([
169 ("signature", ctypes.c_uint32),
170 ("version", ctypes.c_uint32),
171 ("stream_count", ctypes.c_uint32),
172 ("stream_directories_rva", ctypes.c_uint32),
173 ("checksum", ctypes.c_uint32),
174 ("time_date_stampt", ctypes.c_uint32),
175 ("flags", ctypes.c_uint64)
176])
177
178MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
179 ("data_size", ctypes.c_uint32),
180 ("rva", ctypes.c_uint32)
181])
182
183MINIDUMP_DIRECTORY = Descriptor([
184 ("stream_type", ctypes.c_uint32),
185 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
186])
187
188MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
189
190MINIDUMP_EXCEPTION = Descriptor([
191 ("code", ctypes.c_uint32),
192 ("flags", ctypes.c_uint32),
193 ("record", ctypes.c_uint64),
194 ("address", ctypes.c_uint64),
195 ("parameter_count", ctypes.c_uint32),
196 ("unused_alignment", ctypes.c_uint32),
197 ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
198])
199
200MINIDUMP_EXCEPTION_STREAM = Descriptor([
201 ("thread_id", ctypes.c_uint32),
202 ("unused_alignment", ctypes.c_uint32),
203 ("exception", MINIDUMP_EXCEPTION.ctype),
204 ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
205])
206
207# Stream types.
208MD_UNUSED_STREAM = 0
209MD_RESERVED_STREAM_0 = 1
210MD_RESERVED_STREAM_1 = 2
211MD_THREAD_LIST_STREAM = 3
212MD_MODULE_LIST_STREAM = 4
213MD_MEMORY_LIST_STREAM = 5
214MD_EXCEPTION_STREAM = 6
215MD_SYSTEM_INFO_STREAM = 7
216MD_THREAD_EX_LIST_STREAM = 8
217MD_MEMORY_64_LIST_STREAM = 9
218MD_COMMENT_STREAM_A = 10
219MD_COMMENT_STREAM_W = 11
220MD_HANDLE_DATA_STREAM = 12
221MD_FUNCTION_TABLE_STREAM = 13
222MD_UNLOADED_MODULE_LIST_STREAM = 14
223MD_MISC_INFO_STREAM = 15
224MD_MEMORY_INFO_LIST_STREAM = 16
225MD_THREAD_INFO_LIST_STREAM = 17
226MD_HANDLE_OPERATION_LIST_STREAM = 18
227
228MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
229
230MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
231 ("control_word", ctypes.c_uint32),
232 ("status_word", ctypes.c_uint32),
233 ("tag_word", ctypes.c_uint32),
234 ("error_offset", ctypes.c_uint32),
235 ("error_selector", ctypes.c_uint32),
236 ("data_offset", ctypes.c_uint32),
237 ("data_selector", ctypes.c_uint32),
238 ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
239 ("cr0_npx_state", ctypes.c_uint32)
240])
241
242MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
243
244# Context flags.
245MD_CONTEXT_X86 = 0x00010000
246MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
247MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
248MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
249MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
250MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
251MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
252
253def EnableOnFlag(type, flag):
254 return lambda o: [None, type][int((o.context_flags & flag) != 0)]
255
256MINIDUMP_CONTEXT_X86 = Descriptor([
257 ("context_flags", ctypes.c_uint32),
258 # MD_CONTEXT_X86_DEBUG_REGISTERS.
259 ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
260 ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
261 ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
262 ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
263 ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
264 ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
265 # MD_CONTEXT_X86_FLOATING_POINT.
266 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
267 MD_CONTEXT_X86_FLOATING_POINT)),
268 # MD_CONTEXT_X86_SEGMENTS.
269 ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
270 ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
271 ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
272 ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
273 # MD_CONTEXT_X86_INTEGER.
274 ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
275 ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
276 ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
277 ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
278 ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
279 ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
280 # MD_CONTEXT_X86_CONTROL.
281 ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
282 ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
283 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
284 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
285 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
286 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
287 # MD_CONTEXT_X86_EXTENDED_REGISTERS.
288 ("extended_registers",
289 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
290 MD_CONTEXT_X86_EXTENDED_REGISTERS))
291])
292
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000293MD_CONTEXT_AMD64 = 0x00100000
294MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
295MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
296MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
297MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
298MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
299
300MINIDUMP_CONTEXT_AMD64 = Descriptor([
301 ("p1_home", ctypes.c_uint64),
302 ("p2_home", ctypes.c_uint64),
303 ("p3_home", ctypes.c_uint64),
304 ("p4_home", ctypes.c_uint64),
305 ("p5_home", ctypes.c_uint64),
306 ("p6_home", ctypes.c_uint64),
307 ("context_flags", ctypes.c_uint32),
308 ("mx_csr", ctypes.c_uint32),
309 # MD_CONTEXT_AMD64_CONTROL.
310 ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
311 # MD_CONTEXT_AMD64_SEGMENTS
312 ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
313 ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
314 ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
315 ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
316 # MD_CONTEXT_AMD64_CONTROL.
317 ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
318 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
319 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
320 ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
321 ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
322 ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
323 ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
324 ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
325 ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
326 # MD_CONTEXT_AMD64_INTEGER.
327 ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
328 ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
329 ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
330 ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
331 # MD_CONTEXT_AMD64_CONTROL.
332 ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
333 # MD_CONTEXT_AMD64_INTEGER.
334 ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
335 ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
336 ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
337 ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
338 ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
339 ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
340 ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
341 ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
342 ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
343 ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
344 ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
345 # MD_CONTEXT_AMD64_CONTROL.
346 ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
347 # MD_CONTEXT_AMD64_FLOATING_POINT
348 ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
349 MD_CONTEXT_AMD64_FLOATING_POINT)),
350 ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
351 MD_CONTEXT_AMD64_FLOATING_POINT)),
352 ("vector_control", EnableOnFlag(ctypes.c_uint64,
353 MD_CONTEXT_AMD64_FLOATING_POINT)),
354 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
355 ("debug_control", EnableOnFlag(ctypes.c_uint64,
356 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
357 ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
358 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
359 ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
360 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
361 ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
362 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
363 ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
364 MD_CONTEXT_AMD64_DEBUG_REGISTERS))
365])
366
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000367MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
368 ("start", ctypes.c_uint64),
369 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
370])
371
372MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
373 ("start", ctypes.c_uint64),
374 ("size", ctypes.c_uint64)
375])
376
377MINIDUMP_MEMORY_LIST = Descriptor([
378 ("range_count", ctypes.c_uint32),
379 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
380])
381
382MINIDUMP_MEMORY_LIST64 = Descriptor([
383 ("range_count", ctypes.c_uint64),
384 ("base_rva", ctypes.c_uint64),
385 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
386])
387
388MINIDUMP_THREAD = Descriptor([
389 ("id", ctypes.c_uint32),
390 ("suspend_count", ctypes.c_uint32),
391 ("priority_class", ctypes.c_uint32),
392 ("priority", ctypes.c_uint32),
393 ("ted", ctypes.c_uint64),
394 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
395 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
396])
397
398MINIDUMP_THREAD_LIST = Descriptor([
399 ("thread_count", ctypes.c_uint32),
400 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
401])
402
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000403MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
404 ("processor_architecture", ctypes.c_uint16)
405])
406
407MD_CPU_ARCHITECTURE_X86 = 0
408MD_CPU_ARCHITECTURE_AMD64 = 9
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000409
410class MinidumpReader(object):
411 """Minidump (.dmp) reader."""
412
413 _HEADER_MAGIC = 0x504d444d
414
415 def __init__(self, options, minidump_name):
416 self.minidump_name = minidump_name
417 self.minidump_file = open(minidump_name, "r")
418 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
419 self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
420 if self.header.signature != MinidumpReader._HEADER_MAGIC:
verwaest@chromium.org37141392012-05-31 13:27:02 +0000421 print >>sys.stderr, "Warning: Unsupported minidump header magic!"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000422 DebugPrint(self.header)
423 directories = []
424 offset = self.header.stream_directories_rva
425 for _ in xrange(self.header.stream_count):
426 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
427 offset += MINIDUMP_DIRECTORY.size
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000428 self.arch = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000429 self.exception = None
430 self.exception_context = None
431 self.memory_list = None
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000432 self.memory_list64 = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000433 self.thread_map = {}
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000434
435 # Find MDRawSystemInfo stream and determine arch.
436 for d in directories:
437 if d.stream_type == MD_SYSTEM_INFO_STREAM:
438 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
439 self.minidump, d.location.rva)
440 self.arch = system_info.processor_architecture
441 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86]
442 assert not self.arch is None
443
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000444 for d in directories:
445 DebugPrint(d)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000446 if d.stream_type == MD_EXCEPTION_STREAM:
447 self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
448 self.minidump, d.location.rva)
449 DebugPrint(self.exception)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000450 if self.arch == MD_CPU_ARCHITECTURE_X86:
451 self.exception_context = MINIDUMP_CONTEXT_X86.Read(
452 self.minidump, self.exception.thread_context.rva)
453 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
454 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
455 self.minidump, self.exception.thread_context.rva)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000456 DebugPrint(self.exception_context)
457 elif d.stream_type == MD_THREAD_LIST_STREAM:
458 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
459 assert ctypes.sizeof(thread_list) == d.location.data_size
460 DebugPrint(thread_list)
461 for thread in thread_list.threads:
462 DebugPrint(thread)
463 self.thread_map[thread.id] = thread
464 elif d.stream_type == MD_MEMORY_LIST_STREAM:
verwaest@chromium.org37141392012-05-31 13:27:02 +0000465 print >>sys.stderr, "Warning: This is not a full minidump!"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000466 assert self.memory_list is None
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000467 self.memory_list = MINIDUMP_MEMORY_LIST.Read(
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000468 self.minidump, d.location.rva)
469 assert ctypes.sizeof(self.memory_list) == d.location.data_size
470 DebugPrint(self.memory_list)
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000471 elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
472 assert self.memory_list64 is None
473 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read(
474 self.minidump, d.location.rva)
475 assert ctypes.sizeof(self.memory_list64) == d.location.data_size
476 DebugPrint(self.memory_list64)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000477
478 def IsValidAddress(self, address):
479 return self.FindLocation(address) is not None
480
481 def ReadU8(self, address):
482 location = self.FindLocation(address)
483 return ctypes.c_uint8.from_buffer(self.minidump, location).value
484
485 def ReadU32(self, address):
486 location = self.FindLocation(address)
487 return ctypes.c_uint32.from_buffer(self.minidump, location).value
488
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000489 def ReadU64(self, address):
490 location = self.FindLocation(address)
491 return ctypes.c_uint64.from_buffer(self.minidump, location).value
492
493 def ReadUIntPtr(self, address):
494 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
495 return self.ReadU64(address)
496 elif self.arch == MD_CPU_ARCHITECTURE_X86:
497 return self.ReadU32(address)
498
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000499 def ReadBytes(self, address, size):
500 location = self.FindLocation(address)
501 return self.minidump[location:location + size]
502
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000503 def _ReadWord(self, location):
504 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
505 return ctypes.c_uint64.from_buffer(self.minidump, location).value
506 elif self.arch == MD_CPU_ARCHITECTURE_X86:
507 return ctypes.c_uint32.from_buffer(self.minidump, location).value
508
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000509 def IsProbableASCIIRegion(self, location, length):
510 ascii_bytes = 0
511 non_ascii_bytes = 0
512 for loc in xrange(location, location + length):
513 byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
514 if byte >= 0x7f:
515 non_ascii_bytes += 1
516 if byte < 0x20 and byte != 0:
517 non_ascii_bytes += 1
518 if byte < 0x7f and byte >= 0x20:
519 ascii_bytes += 1
520 if byte == 0xa: # newline
521 ascii_bytes += 1
522 if ascii_bytes * 10 <= length:
523 return False
524 if length > 0 and ascii_bytes > non_ascii_bytes * 7:
525 return True
526 if ascii_bytes > non_ascii_bytes * 3:
527 return None # Maybe
528 return False
529
530 def IsProbableExecutableRegion(self, location, length):
531 opcode_bytes = 0
532 sixty_four = self.arch == MD_CPU_ARCHITECTURE_AMD64
533 for loc in xrange(location, location + length):
534 byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
535 if (byte == 0x8b or # mov
536 byte == 0x89 or # mov reg-reg
537 (byte & 0xf0) == 0x50 or # push/pop
538 (sixty_four and (byte & 0xf0) == 0x40) or # rex prefix
539 byte == 0xc3 or # return
540 byte == 0x74 or # jeq
541 byte == 0x84 or # jeq far
542 byte == 0x75 or # jne
543 byte == 0x85 or # jne far
544 byte == 0xe8 or # call
545 byte == 0xe9 or # jmp far
546 byte == 0xeb): # jmp near
547 opcode_bytes += 1
548 opcode_percent = (opcode_bytes * 100) / length
549 threshold = 20
550 if opcode_percent > threshold + 2:
551 return True
552 if opcode_percent > threshold - 2:
553 return None # Maybe
554 return False
555
556 def FindRegion(self, addr):
557 answer = [-1, -1]
558 def is_in(reader, start, size, location):
559 if addr >= start and addr < start + size:
560 answer[0] = start
561 answer[1] = size
562 self.ForEachMemoryRegion(is_in)
563 if answer[0] == -1:
564 return None
565 return answer
566
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000567 def ForEachMemoryRegion(self, cb):
568 if self.memory_list64 is not None:
569 for r in self.memory_list64.ranges:
570 location = self.memory_list64.base_rva + offset
571 cb(self, r.start, r.size, location)
572 offset += r.size
573
574 if self.memory_list is not None:
575 for r in self.memory_list.ranges:
576 cb(self, r.start, r.memory.data_size, r.memory.rva)
577
verwaest@chromium.org37141392012-05-31 13:27:02 +0000578 def FindWord(self, word, alignment=0):
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000579 def search_inside_region(reader, start, size, location):
verwaest@chromium.org37141392012-05-31 13:27:02 +0000580 location = (location + alignment) & ~alignment
581 for loc in xrange(location, location + size - self.PointerSize()):
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000582 if reader._ReadWord(loc) == word:
583 slot = start + (loc - location)
584 print "%s: %s" % (reader.FormatIntPtr(slot),
585 reader.FormatIntPtr(word))
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000586 self.ForEachMemoryRegion(search_inside_region)
587
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000588 def FindLocation(self, address):
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000589 offset = 0
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000590 if self.memory_list64 is not None:
591 for r in self.memory_list64.ranges:
592 if r.start <= address < r.start + r.size:
593 return self.memory_list64.base_rva + offset + address - r.start
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000594 offset += r.size
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000595 if self.memory_list is not None:
596 for r in self.memory_list.ranges:
597 if r.start <= address < r.start + r.memory.data_size:
598 return r.memory.rva + address - r.start
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000599 return None
600
601 def GetDisasmLines(self, address, size):
602 location = self.FindLocation(address)
603 if location is None: return []
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000604 arch = None
605 if self.arch == MD_CPU_ARCHITECTURE_X86:
606 arch = "ia32"
607 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
608 arch = "x64"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000609 return disasm.GetDisasmLines(self.minidump_name,
610 location,
611 size,
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000612 arch,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000613 False)
614
615
616 def Dispose(self):
617 self.minidump.close()
618 self.minidump_file.close()
619
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000620 def ExceptionIP(self):
621 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
622 return self.exception_context.rip
623 elif self.arch == MD_CPU_ARCHITECTURE_X86:
624 return self.exception_context.eip
625
626 def ExceptionSP(self):
627 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
628 return self.exception_context.rsp
629 elif self.arch == MD_CPU_ARCHITECTURE_X86:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000630 return self.exception_context.esp
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000631
632 def FormatIntPtr(self, value):
633 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
634 return "%016x" % value
635 elif self.arch == MD_CPU_ARCHITECTURE_X86:
636 return "%08x" % value
637
638 def PointerSize(self):
639 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
640 return 8
641 elif self.arch == MD_CPU_ARCHITECTURE_X86:
642 return 4
643
644 def Register(self, name):
645 return self.exception_context.__getattribute__(name)
646
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000647
648# List of V8 instance types. Obtained by adding the code below to any .cc file.
649#
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000650# #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000651# struct P {
652# P() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000653# printf("INSTANCE_TYPES = {\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000654# INSTANCE_TYPE_LIST(DUMP_TYPE)
655# printf("}\n");
656# }
657# };
658# static P p;
659INSTANCE_TYPES = {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000660 64: "SYMBOL_TYPE",
661 68: "ASCII_SYMBOL_TYPE",
662 65: "CONS_SYMBOL_TYPE",
663 69: "CONS_ASCII_SYMBOL_TYPE",
664 66: "EXTERNAL_SYMBOL_TYPE",
665 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
666 70: "EXTERNAL_ASCII_SYMBOL_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000667 82: "SHORT_EXTERNAL_SYMBOL_TYPE",
668 90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
669 86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000670 0: "STRING_TYPE",
671 4: "ASCII_STRING_TYPE",
672 1: "CONS_STRING_TYPE",
673 5: "CONS_ASCII_STRING_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000674 3: "SLICED_STRING_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000675 2: "EXTERNAL_STRING_TYPE",
676 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
677 6: "EXTERNAL_ASCII_STRING_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000678 18: "SHORT_EXTERNAL_STRING_TYPE",
679 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
680 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000681 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE",
682 128: "MAP_TYPE",
683 129: "CODE_TYPE",
684 130: "ODDBALL_TYPE",
685 131: "JS_GLOBAL_PROPERTY_CELL_TYPE",
686 132: "HEAP_NUMBER_TYPE",
687 133: "FOREIGN_TYPE",
688 134: "BYTE_ARRAY_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000689 135: "FREE_SPACE_TYPE",
690 136: "EXTERNAL_BYTE_ARRAY_TYPE",
691 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
692 138: "EXTERNAL_SHORT_ARRAY_TYPE",
693 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
694 140: "EXTERNAL_INT_ARRAY_TYPE",
695 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
696 142: "EXTERNAL_FLOAT_ARRAY_TYPE",
697 144: "EXTERNAL_PIXEL_ARRAY_TYPE",
698 146: "FILLER_TYPE",
699 147: "ACCESSOR_INFO_TYPE",
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000700 148: "ACCESSOR_PAIR_TYPE",
701 149: "ACCESS_CHECK_INFO_TYPE",
702 150: "INTERCEPTOR_INFO_TYPE",
703 151: "CALL_HANDLER_INFO_TYPE",
704 152: "FUNCTION_TEMPLATE_INFO_TYPE",
705 153: "OBJECT_TEMPLATE_INFO_TYPE",
706 154: "SIGNATURE_INFO_TYPE",
707 155: "TYPE_SWITCH_INFO_TYPE",
708 156: "SCRIPT_TYPE",
709 157: "CODE_CACHE_TYPE",
710 158: "POLYMORPHIC_CODE_CACHE_TYPE",
verwaest@chromium.org37141392012-05-31 13:27:02 +0000711 159: "TYPE_FEEDBACK_INFO_TYPE",
712 160: "ALIASED_ARGUMENTS_ENTRY_TYPE",
713 163: "FIXED_ARRAY_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000714 145: "FIXED_DOUBLE_ARRAY_TYPE",
verwaest@chromium.org37141392012-05-31 13:27:02 +0000715 164: "SHARED_FUNCTION_INFO_TYPE",
716 165: "JS_MESSAGE_OBJECT_TYPE",
717 168: "JS_VALUE_TYPE",
718 169: "JS_DATE_TYPE",
719 170: "JS_OBJECT_TYPE",
720 171: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
721 172: "JS_MODULE_TYPE",
722 173: "JS_GLOBAL_OBJECT_TYPE",
723 174: "JS_BUILTINS_OBJECT_TYPE",
724 175: "JS_GLOBAL_PROXY_TYPE",
725 176: "JS_ARRAY_TYPE",
726 167: "JS_PROXY_TYPE",
727 179: "JS_WEAK_MAP_TYPE",
728 180: "JS_REGEXP_TYPE",
729 181: "JS_FUNCTION_TYPE",
730 166: "JS_FUNCTION_PROXY_TYPE",
731 161: "DEBUG_INFO_TYPE",
732 162: "BREAK_POINT_INFO_TYPE",
733}
734
735
736# List of known V8 maps. Used to determine the instance type and name
737# for maps that are part of the root-set and hence on the first page of
738# the map-space. Obtained by adding the code below to an IA32 release
739# build with enabled snapshots to the end of the Isolate::Init method.
740#
741# #define ROOT_LIST_CASE(type, name, camel_name) \
742# if (o == heap_.name()) n = #camel_name;
743# #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
744# if (o == heap_.name##_map()) n = #camel_name "Map";
745# HeapObjectIterator it(heap_.map_space());
746# printf("KNOWN_MAPS = {\n");
747# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
748# Map* m = Map::cast(o);
749# const char* n = "";
750# intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
751# int t = m->instance_type();
752# ROOT_LIST(ROOT_LIST_CASE)
753# STRUCT_LIST(STRUCT_LIST_CASE)
754# printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n);
755# }
756# printf("}\n");
757KNOWN_MAPS = {
758 0x08081: (134, "ByteArrayMap"),
759 0x080a1: (128, "MetaMap"),
760 0x080c1: (130, "OddballMap"),
761 0x080e1: (163, "FixedArrayMap"),
762 0x08101: (68, "AsciiSymbolMap"),
763 0x08121: (132, "HeapNumberMap"),
764 0x08141: (135, "FreeSpaceMap"),
765 0x08161: (146, "OnePointerFillerMap"),
766 0x08181: (146, "TwoPointerFillerMap"),
767 0x081a1: (131, "GlobalPropertyCellMap"),
768 0x081c1: (164, "SharedFunctionInfoMap"),
769 0x081e1: (4, "AsciiStringMap"),
770 0x08201: (163, "GlobalContextMap"),
771 0x08221: (129, "CodeMap"),
772 0x08241: (163, "ScopeInfoMap"),
773 0x08261: (163, "FixedCOWArrayMap"),
774 0x08281: (145, "FixedDoubleArrayMap"),
775 0x082a1: (163, "HashTableMap"),
776 0x082c1: (0, "StringMap"),
777 0x082e1: (64, "SymbolMap"),
778 0x08301: (1, "ConsStringMap"),
779 0x08321: (5, "ConsAsciiStringMap"),
780 0x08341: (3, "SlicedStringMap"),
781 0x08361: (7, "SlicedAsciiStringMap"),
782 0x08381: (65, "ConsSymbolMap"),
783 0x083a1: (69, "ConsAsciiSymbolMap"),
784 0x083c1: (66, "ExternalSymbolMap"),
785 0x083e1: (74, "ExternalSymbolWithAsciiDataMap"),
786 0x08401: (70, "ExternalAsciiSymbolMap"),
787 0x08421: (2, "ExternalStringMap"),
788 0x08441: (10, "ExternalStringWithAsciiDataMap"),
789 0x08461: (6, "ExternalAsciiStringMap"),
790 0x08481: (82, "ShortExternalSymbolMap"),
791 0x084a1: (90, "ShortExternalSymbolWithAsciiDataMap"),
792 0x084c1: (86, "ShortExternalAsciiSymbolMap"),
793 0x084e1: (18, "ShortExternalStringMap"),
794 0x08501: (26, "ShortExternalStringWithAsciiDataMap"),
795 0x08521: (22, "ShortExternalAsciiStringMap"),
796 0x08541: (0, "UndetectableStringMap"),
797 0x08561: (4, "UndetectableAsciiStringMap"),
798 0x08581: (144, "ExternalPixelArrayMap"),
799 0x085a1: (136, "ExternalByteArrayMap"),
800 0x085c1: (137, "ExternalUnsignedByteArrayMap"),
801 0x085e1: (138, "ExternalShortArrayMap"),
802 0x08601: (139, "ExternalUnsignedShortArrayMap"),
803 0x08621: (140, "ExternalIntArrayMap"),
804 0x08641: (141, "ExternalUnsignedIntArrayMap"),
805 0x08661: (142, "ExternalFloatArrayMap"),
806 0x08681: (143, "ExternalDoubleArrayMap"),
807 0x086a1: (163, "NonStrictArgumentsElementsMap"),
808 0x086c1: (163, "FunctionContextMap"),
809 0x086e1: (163, "CatchContextMap"),
810 0x08701: (163, "WithContextMap"),
811 0x08721: (163, "BlockContextMap"),
812 0x08741: (163, "ModuleContextMap"),
813 0x08761: (165, "JSMessageObjectMap"),
814 0x08781: (133, "ForeignMap"),
815 0x087a1: (170, "NeanderMap"),
816 0x087c1: (158, "PolymorphicCodeCacheMap"),
817 0x087e1: (156, "ScriptMap"),
818 0x08801: (147, "AccessorInfoMap"),
819 0x08821: (148, "AccessorPairMap"),
820 0x08841: (149, "AccessCheckInfoMap"),
821 0x08861: (150, "InterceptorInfoMap"),
822 0x08881: (151, "CallHandlerInfoMap"),
823 0x088a1: (152, "FunctionTemplateInfoMap"),
824 0x088c1: (153, "ObjectTemplateInfoMap"),
825 0x088e1: (154, "SignatureInfoMap"),
826 0x08901: (155, "TypeSwitchInfoMap"),
827 0x08921: (157, "CodeCacheMap"),
828 0x08941: (159, "TypeFeedbackInfoMap"),
829 0x08961: (160, "AliasedArgumentsEntryMap"),
830 0x08981: (161, "DebugInfoMap"),
831 0x089a1: (162, "BreakPointInfoMap"),
832}
833
834
835# List of known V8 objects. Used to determine name for objects that are
836# part of the root-set and hence on the first page of various old-space
837# paged. Obtained by adding the code below to an IA32 release build with
838# enabled snapshots to the end of the Isolate::Init method.
839#
840# #define ROOT_LIST_CASE(type, name, camel_name) \
841# if (o == heap_.name()) n = #camel_name;
842# OldSpaces spit;
843# printf("KNOWN_OBJECTS = {\n");
844# for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
845# HeapObjectIterator it(s);
846# const char* sname = AllocationSpaceName(s->identity());
847# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
848# const char* n = NULL;
849# intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
850# ROOT_LIST(ROOT_LIST_CASE)
851# if (n != NULL) {
852# printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n);
853# }
854# }
855# }
856# printf("}\n");
857KNOWN_OBJECTS = {
858 ("OLD_POINTER_SPACE", 0x08081): "NullValue",
859 ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue",
860 ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap",
861 ("OLD_POINTER_SPACE", 0x080b1): "TrueValue",
862 ("OLD_POINTER_SPACE", 0x080c1): "FalseValue",
863 ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel",
864 ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker",
865 ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache",
866 ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache",
867 ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache",
868 ("OLD_POINTER_SPACE", 0x08f09): "TerminationException",
869 ("OLD_POINTER_SPACE", 0x08f19): "MessageListeners",
870 ("OLD_POINTER_SPACE", 0x08f35): "CodeStubs",
871 ("OLD_POINTER_SPACE", 0x09b61): "NonMonomorphicCache",
872 ("OLD_POINTER_SPACE", 0x0a175): "PolymorphicCodeCache",
873 ("OLD_POINTER_SPACE", 0x0a17d): "NativesSourceCache",
874 ("OLD_POINTER_SPACE", 0x0a1bd): "EmptyScript",
875 ("OLD_POINTER_SPACE", 0x0a1f9): "IntrinsicFunctionNames",
876 ("OLD_POINTER_SPACE", 0x24a49): "SymbolTable",
877 ("OLD_DATA_SPACE", 0x08081): "EmptyFixedArray",
878 ("OLD_DATA_SPACE", 0x080a1): "NanValue",
879 ("OLD_DATA_SPACE", 0x0811d): "EmptyByteArray",
880 ("OLD_DATA_SPACE", 0x08125): "EmptyString",
881 ("OLD_DATA_SPACE", 0x08131): "EmptyDescriptorArray",
882 ("OLD_DATA_SPACE", 0x08259): "InfinityValue",
883 ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue",
884 ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors",
885 ("CODE_SPACE", 0x12b81): "JsEntryCode",
886 ("CODE_SPACE", 0x12c61): "JsConstructEntryCode",
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000887}
888
889
890class Printer(object):
891 """Printer with indentation support."""
892
893 def __init__(self):
894 self.indent = 0
895
896 def Indent(self):
897 self.indent += 2
898
899 def Dedent(self):
900 self.indent -= 2
901
902 def Print(self, string):
903 print "%s%s" % (self._IndentString(), string)
904
905 def PrintLines(self, lines):
906 indent = self._IndentString()
907 print "\n".join("%s%s" % (indent, line) for line in lines)
908
909 def _IndentString(self):
910 return self.indent * " "
911
912
913ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
914
915
916def FormatDisasmLine(start, heap, line):
917 line_address = start + line[0]
918 stack_slot = heap.stack_map.get(line_address)
919 marker = " "
920 if stack_slot:
921 marker = "=>"
922 code = AnnotateAddresses(heap, line[1])
923 return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
924
925
926def AnnotateAddresses(heap, line):
927 extra = []
928 for m in ADDRESS_RE.finditer(line):
929 maybe_address = int(m.group(0), 16)
930 object = heap.FindObject(maybe_address)
931 if not object: continue
932 extra.append(str(object))
933 if len(extra) == 0: return line
934 return "%s ;; %s" % (line, ", ".join(extra))
935
936
937class HeapObject(object):
938 def __init__(self, heap, map, address):
939 self.heap = heap
940 self.map = map
941 self.address = address
942
943 def Is(self, cls):
944 return isinstance(self, cls)
945
946 def Print(self, p):
947 p.Print(str(self))
948
949 def __str__(self):
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000950 return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
951 INSTANCE_TYPES[self.map.instance_type])
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000952
953 def ObjectField(self, offset):
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000954 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000955 return self.heap.FindObjectOrSmi(field_value)
956
957 def SmiField(self, offset):
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000958 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000959 assert (field_value & 1) == 0
960 return field_value / 2
961
962
963class Map(HeapObject):
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000964 def InstanceTypeOffset(self):
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000965 return self.heap.PointerSize() + self.heap.IntSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000966
967 def __init__(self, heap, map, address):
968 HeapObject.__init__(self, heap, map, address)
969 self.instance_type = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000970 heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000971
972
973class String(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000974 def LengthOffset(self):
975 return self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000976
977 def __init__(self, heap, map, address):
978 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000979 self.length = self.SmiField(self.LengthOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000980
981 def GetChars(self):
982 return "?string?"
983
984 def Print(self, p):
985 p.Print(str(self))
986
987 def __str__(self):
988 return "\"%s\"" % self.GetChars()
989
990
991class SeqString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000992 def CharsOffset(self):
993 return self.heap.PointerSize() * 3
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000994
995 def __init__(self, heap, map, address):
996 String.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000997 self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000998 self.length)
999
1000 def GetChars(self):
1001 return self.chars
1002
1003
1004class ExternalString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001005 # TODO(vegorov) fix ExternalString for X64 architecture
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001006 RESOURCE_OFFSET = 12
1007
1008 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
1009 WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
1010
1011 def __init__(self, heap, map, address):
1012 String.__init__(self, heap, map, address)
1013 reader = heap.reader
1014 self.resource = \
1015 reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
1016 self.chars = "?external string?"
1017 if not reader.IsValidAddress(self.resource): return
1018 string_impl_address = self.resource + \
1019 ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
1020 if not reader.IsValidAddress(string_impl_address): return
1021 string_impl = reader.ReadU32(string_impl_address)
1022 chars_ptr_address = string_impl + \
1023 ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
1024 if not reader.IsValidAddress(chars_ptr_address): return
1025 chars_ptr = reader.ReadU32(chars_ptr_address)
1026 if not reader.IsValidAddress(chars_ptr): return
1027 raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
1028 self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
1029
1030 def GetChars(self):
1031 return self.chars
1032
1033
1034class ConsString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001035 def LeftOffset(self):
1036 return self.heap.PointerSize() * 3
1037
1038 def RightOffset(self):
1039 return self.heap.PointerSize() * 4
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001040
1041 def __init__(self, heap, map, address):
1042 String.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001043 self.left = self.ObjectField(self.LeftOffset())
1044 self.right = self.ObjectField(self.RightOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001045
1046 def GetChars(self):
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001047 try:
1048 return self.left.GetChars() + self.right.GetChars()
1049 except:
1050 return "***CAUGHT EXCEPTION IN GROKDUMP***"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001051
1052
1053class Oddball(HeapObject):
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001054 # Should match declarations in objects.h
1055 KINDS = [
1056 "False",
1057 "True",
1058 "TheHole",
1059 "Null",
1060 "ArgumentMarker",
1061 "Undefined",
1062 "Other"
1063 ]
1064
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001065 def ToStringOffset(self):
1066 return self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001067
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001068 def ToNumberOffset(self):
1069 return self.ToStringOffset() + self.heap.PointerSize()
1070
1071 def KindOffset(self):
1072 return self.ToNumberOffset() + self.heap.PointerSize()
1073
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001074 def __init__(self, heap, map, address):
1075 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001076 self.to_string = self.ObjectField(self.ToStringOffset())
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001077 self.kind = self.SmiField(self.KindOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001078
1079 def Print(self, p):
1080 p.Print(str(self))
1081
1082 def __str__(self):
verwaest@chromium.org37141392012-05-31 13:27:02 +00001083 if self.to_string:
1084 return "Oddball(%08x, <%s>)" % (self.address, self.to_string.GetChars())
1085 else:
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001086 kind = "???"
1087 if 0 <= self.kind < len(Oddball.KINDS):
1088 kind = Oddball.KINDS[self.kind]
1089 return "Oddball(%08x, kind=%s)" % (self.address, kind)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001090
1091
1092class FixedArray(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001093 def LengthOffset(self):
1094 return self.heap.PointerSize()
1095
1096 def ElementsOffset(self):
1097 return self.heap.PointerSize() * 2
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001098
1099 def __init__(self, heap, map, address):
1100 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001101 self.length = self.SmiField(self.LengthOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001102
1103 def Print(self, p):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001104 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001105 p.Indent()
1106 p.Print("length: %d" % self.length)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001107 base_offset = self.ElementsOffset()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001108 for i in xrange(self.length):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001109 offset = base_offset + 4 * i
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001110 p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
1111 p.Dedent()
1112 p.Print("}")
1113
1114 def __str__(self):
1115 return "FixedArray(%08x, length=%d)" % (self.address, self.length)
1116
1117
1118class JSFunction(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001119 def CodeEntryOffset(self):
1120 return 3 * self.heap.PointerSize()
1121
1122 def SharedOffset(self):
1123 return 5 * self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001124
1125 def __init__(self, heap, map, address):
1126 HeapObject.__init__(self, heap, map, address)
1127 code_entry = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001128 heap.reader.ReadU32(self.address + self.CodeEntryOffset())
1129 self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
1130 self.shared = self.ObjectField(self.SharedOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001131
1132 def Print(self, p):
1133 source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001134 p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001135 p.Indent()
1136 p.Print("inferred name: %s" % self.shared.inferred_name)
1137 if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
1138 p.Print("script name: %s" % self.shared.script.name)
1139 p.Print("source:")
1140 p.PrintLines(self._GetSource().split("\n"))
1141 p.Print("code:")
1142 self.code.Print(p)
1143 if self.code != self.shared.code:
1144 p.Print("unoptimized code:")
1145 self.shared.code.Print(p)
1146 p.Dedent()
1147 p.Print("}")
1148
1149 def __str__(self):
1150 inferred_name = ""
1151 if self.shared.Is(SharedFunctionInfo):
1152 inferred_name = self.shared.inferred_name
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001153 return "JSFunction(%s, %s)" % \
1154 (self.heap.reader.FormatIntPtr(self.address), inferred_name)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001155
1156 def _GetSource(self):
1157 source = "?source?"
1158 start = self.shared.start_position
1159 end = self.shared.end_position
1160 if not self.shared.script.Is(Script): return source
1161 script_source = self.shared.script.source
1162 if not script_source.Is(String): return source
1163 return script_source.GetChars()[start:end]
1164
1165
1166class SharedFunctionInfo(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001167 def CodeOffset(self):
1168 return 2 * self.heap.PointerSize()
1169
1170 def ScriptOffset(self):
1171 return 7 * self.heap.PointerSize()
1172
1173 def InferredNameOffset(self):
1174 return 9 * self.heap.PointerSize()
1175
1176 def EndPositionOffset(self):
1177 return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
1178
1179 def StartPositionAndTypeOffset(self):
1180 return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001181
1182 def __init__(self, heap, map, address):
1183 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001184 self.code = self.ObjectField(self.CodeOffset())
1185 self.script = self.ObjectField(self.ScriptOffset())
1186 self.inferred_name = self.ObjectField(self.InferredNameOffset())
1187 if heap.PointerSize() == 8:
1188 start_position_and_type = \
1189 heap.reader.ReadU32(self.StartPositionAndTypeOffset())
1190 self.start_position = start_position_and_type >> 2
1191 pseudo_smi_end_position = \
1192 heap.reader.ReadU32(self.EndPositionOffset())
1193 self.end_position = pseudo_smi_end_position >> 2
1194 else:
1195 start_position_and_type = \
1196 self.SmiField(self.StartPositionAndTypeOffset())
1197 self.start_position = start_position_and_type >> 2
1198 self.end_position = \
1199 self.SmiField(self.EndPositionOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001200
1201
1202class Script(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001203 def SourceOffset(self):
1204 return self.heap.PointerSize()
1205
1206 def NameOffset(self):
1207 return self.SourceOffset() + self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001208
1209 def __init__(self, heap, map, address):
1210 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001211 self.source = self.ObjectField(self.SourceOffset())
1212 self.name = self.ObjectField(self.NameOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001213
1214
verwaest@chromium.org37141392012-05-31 13:27:02 +00001215class CodeCache(HeapObject):
1216 def DefaultCacheOffset(self):
1217 return self.heap.PointerSize()
1218
1219 def NormalTypeCacheOffset(self):
1220 return self.DefaultCacheOffset() + self.heap.PointerSize()
1221
1222 def __init__(self, heap, map, address):
1223 HeapObject.__init__(self, heap, map, address)
1224 self.default_cache = self.ObjectField(self.DefaultCacheOffset())
1225 self.normal_type_cache = self.ObjectField(self.NormalTypeCacheOffset())
1226
1227 def Print(self, p):
1228 p.Print("CodeCache(%s) {" % self.heap.reader.FormatIntPtr(self.address))
1229 p.Indent()
1230 p.Print("default cache: %s" % self.default_cache)
1231 p.Print("normal type cache: %s" % self.normal_type_cache)
1232 p.Dedent()
1233 p.Print("}")
1234
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236class Code(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001237 CODE_ALIGNMENT_MASK = (1 << 5) - 1
1238
1239 def InstructionSizeOffset(self):
1240 return self.heap.PointerSize()
1241
1242 @staticmethod
1243 def HeaderSize(heap):
1244 return (heap.PointerSize() + heap.IntSize() + \
1245 4 * heap.PointerSize() + 3 * heap.IntSize() + \
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001246 Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001247
1248 def __init__(self, heap, map, address):
1249 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001250 self.entry = self.address + Code.HeaderSize(heap)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001251 self.instruction_size = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001252 heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001253
1254 def Print(self, p):
1255 lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001256 p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001257 p.Indent()
1258 p.Print("instruction_size: %d" % self.instruction_size)
1259 p.PrintLines(self._FormatLine(line) for line in lines)
1260 p.Dedent()
1261 p.Print("}")
1262
1263 def _FormatLine(self, line):
1264 return FormatDisasmLine(self.entry, self.heap, line)
1265
1266
1267class V8Heap(object):
1268 CLASS_MAP = {
1269 "SYMBOL_TYPE": SeqString,
1270 "ASCII_SYMBOL_TYPE": SeqString,
1271 "CONS_SYMBOL_TYPE": ConsString,
1272 "CONS_ASCII_SYMBOL_TYPE": ConsString,
1273 "EXTERNAL_SYMBOL_TYPE": ExternalString,
1274 "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
1275 "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001276 "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString,
1277 "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
1278 "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 "STRING_TYPE": SeqString,
1280 "ASCII_STRING_TYPE": SeqString,
1281 "CONS_STRING_TYPE": ConsString,
1282 "CONS_ASCII_STRING_TYPE": ConsString,
1283 "EXTERNAL_STRING_TYPE": ExternalString,
1284 "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
1285 "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001286 "MAP_TYPE": Map,
1287 "ODDBALL_TYPE": Oddball,
1288 "FIXED_ARRAY_TYPE": FixedArray,
1289 "JS_FUNCTION_TYPE": JSFunction,
1290 "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
1291 "SCRIPT_TYPE": Script,
verwaest@chromium.org37141392012-05-31 13:27:02 +00001292 "CODE_CACHE_TYPE": CodeCache,
1293 "CODE_TYPE": Code,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001294 }
1295
1296 def __init__(self, reader, stack_map):
1297 self.reader = reader
1298 self.stack_map = stack_map
1299 self.objects = {}
1300
1301 def FindObjectOrSmi(self, tagged_address):
1302 if (tagged_address & 1) == 0: return tagged_address / 2
1303 return self.FindObject(tagged_address)
1304
1305 def FindObject(self, tagged_address):
1306 if tagged_address in self.objects:
1307 return self.objects[tagged_address]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001308 if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001309 address = tagged_address - 1
1310 if not self.reader.IsValidAddress(address): return None
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001311 map_tagged_address = self.reader.ReadUIntPtr(address)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001312 if tagged_address == map_tagged_address:
1313 # Meta map?
1314 meta_map = Map(self, None, address)
1315 instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
1316 if instance_type_name != "MAP_TYPE": return None
1317 meta_map.map = meta_map
1318 object = meta_map
1319 else:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001320 map = self.FindMap(map_tagged_address)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001321 if map is None: return None
1322 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
1323 if instance_type_name is None: return None
1324 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
1325 object = cls(self, map, address)
1326 self.objects[tagged_address] = object
1327 return object
1328
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001329 def FindMap(self, tagged_address):
1330 if (tagged_address & self.MapAlignmentMask()) != 1: return None
1331 address = tagged_address - 1
1332 if not self.reader.IsValidAddress(address): return None
1333 object = Map(self, None, address)
1334 return object
1335
1336 def IntSize(self):
1337 return 4
1338
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001339 def PointerSize(self):
1340 return self.reader.PointerSize()
1341
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001342 def ObjectAlignmentMask(self):
1343 return self.PointerSize() - 1
1344
1345 def MapAlignmentMask(self):
1346 if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
1347 return (1 << 4) - 1
1348 elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
1349 return (1 << 5) - 1
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001350
verwaest@chromium.org37141392012-05-31 13:27:02 +00001351 def PageAlignmentMask(self):
1352 return (1 << 20) - 1
1353
1354
1355class KnownObject(HeapObject):
1356 def __init__(self, heap, known_name):
1357 HeapObject.__init__(self, heap, None, None)
1358 self.known_name = known_name
1359
1360 def __str__(self):
1361 return "<%s>" % self.known_name
1362
1363
1364class KnownMap(HeapObject):
1365 def __init__(self, heap, known_name, instance_type):
1366 HeapObject.__init__(self, heap, None, None)
1367 self.instance_type = instance_type
1368 self.known_name = known_name
1369
1370 def __str__(self):
1371 return "<%s>" % self.known_name
1372
1373
1374class InspectionPadawan(object):
1375 """The padawan can improve annotations by sensing well-known objects."""
1376 def __init__(self, reader, heap):
1377 self.reader = reader
1378 self.heap = heap
1379 self.known_first_map_page = 0
1380 self.known_first_data_page = 0
1381 self.known_first_pointer_page = 0
1382
1383 def __getattr__(self, name):
1384 """An InspectionPadawan can be used instead of V8Heap, even though
1385 it does not inherit from V8Heap (aka. mixin)."""
1386 return getattr(self.heap, name)
1387
1388 def GetPageOffset(self, tagged_address):
1389 return tagged_address & self.heap.PageAlignmentMask()
1390
1391 def IsInKnownMapSpace(self, tagged_address):
1392 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1393 return page_address == self.known_first_map_page
1394
1395 def IsInKnownOldSpace(self, tagged_address):
1396 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1397 return page_address in [self.known_first_data_page,
1398 self.known_first_pointer_page]
1399
1400 def ContainingKnownOldSpaceName(self, tagged_address):
1401 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1402 if page_address == self.known_first_data_page: return "OLD_DATA_SPACE"
1403 if page_address == self.known_first_pointer_page: return "OLD_POINTER_SPACE"
1404 return None
1405
1406 def SenseObject(self, tagged_address):
1407 if self.IsInKnownOldSpace(tagged_address):
1408 offset = self.GetPageOffset(tagged_address)
1409 lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset)
1410 known_obj_name = KNOWN_OBJECTS.get(lookup_key)
1411 if known_obj_name:
1412 return KnownObject(self, known_obj_name)
1413 if self.IsInKnownMapSpace(tagged_address):
1414 known_map = self.SenseMap(tagged_address)
1415 if known_map:
1416 return known_map
1417 found_obj = self.heap.FindObject(tagged_address)
1418 if found_obj: return found_ob
1419 address = tagged_address - 1
1420 if self.reader.IsValidAddress(address):
1421 map_tagged_address = self.reader.ReadUIntPtr(address)
1422 map = self.SenseMap(map_tagged_address)
1423 if map is None: return None
1424 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
1425 if instance_type_name is None: return None
1426 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
1427 return cls(self, map, address)
1428 return None
1429
1430 def SenseMap(self, tagged_address):
1431 if self.IsInKnownMapSpace(tagged_address):
1432 offset = self.GetPageOffset(tagged_address)
1433 known_map_info = KNOWN_MAPS.get(offset)
1434 if known_map_info:
1435 known_map_type, known_map_name = known_map_info
1436 return KnownMap(self, known_map_name, known_map_type)
1437 found_map = self.heap.FindMap(tagged_address)
1438 if found_map: return found_map
1439 return None
1440
1441 def FindObjectOrSmi(self, tagged_address):
1442 """When used as a mixin in place of V8Heap."""
1443 found_obj = self.SenseObject(tagged_address)
1444 if found_obj: return found_obj
1445 if (tagged_address & 1) == 0:
1446 return "Smi(%d)" % (tagged_address / 2)
1447 else:
1448 return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address)
1449
1450 def FindObject(self, tagged_address):
1451 """When used as a mixin in place of V8Heap."""
1452 raise NotImplementedError
1453
1454 def FindMap(self, tagged_address):
1455 """When used as a mixin in place of V8Heap."""
1456 raise NotImplementedError
1457
1458 def PrintKnowledge(self):
1459 print " known_first_map_page = %s\n"\
1460 " known_first_data_page = %s\n"\
1461 " known_first_pointer_page = %s" % (
1462 self.reader.FormatIntPtr(self.known_first_map_page),
1463 self.reader.FormatIntPtr(self.known_first_data_page),
1464 self.reader.FormatIntPtr(self.known_first_pointer_page))
1465
1466
1467class InspectionShell(cmd.Cmd):
1468 def __init__(self, reader, heap):
1469 cmd.Cmd.__init__(self)
1470 self.reader = reader
1471 self.heap = heap
1472 self.padawan = InspectionPadawan(reader, heap)
1473 self.prompt = "(grok) "
1474
1475 def do_dd(self, address):
1476 """
1477 Interpret memory at the given address (if available) as a sequence
1478 of words. Automatic alignment is not performed.
1479 """
1480 start = int(address, 16)
1481 if (start & self.heap.ObjectAlignmentMask()) != 0:
1482 print "Warning: Dumping un-aligned memory, is this what you had in mind?"
1483 for slot in xrange(start,
1484 start + self.reader.PointerSize() * 10,
1485 self.reader.PointerSize()):
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001486 if not self.reader.IsValidAddress(slot):
1487 print "Address is not contained within the minidump!"
1488 return
verwaest@chromium.org37141392012-05-31 13:27:02 +00001489 maybe_address = self.reader.ReadUIntPtr(slot)
1490 heap_object = self.padawan.SenseObject(maybe_address)
1491 print "%s: %s %s" % (self.reader.FormatIntPtr(slot),
1492 self.reader.FormatIntPtr(maybe_address),
1493 heap_object or '')
1494
1495 def do_do(self, address):
1496 """
1497 Interpret memory at the given address as a V8 object. Automatic
1498 alignment makes sure that you can pass tagged as well as un-tagged
1499 addresses.
1500 """
1501 address = int(address, 16)
1502 if (address & self.heap.ObjectAlignmentMask()) == 0:
1503 address = address + 1
1504 elif (address & self.heap.ObjectAlignmentMask()) != 1:
1505 print "Address doesn't look like a valid pointer!"
1506 return
1507 heap_object = self.padawan.SenseObject(address)
1508 if heap_object:
1509 heap_object.Print(Printer())
1510 else:
1511 print "Address cannot be interpreted as object!"
1512
1513 def do_dp(self, address):
1514 """
1515 Interpret memory at the given address as being on a V8 heap page
1516 and print information about the page header (if available).
1517 """
1518 address = int(address, 16)
1519 page_address = address & ~self.heap.PageAlignmentMask()
1520 if self.reader.IsValidAddress(page_address):
1521 raise NotImplementedError
1522 else:
1523 print "Page header is not available!"
1524
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00001525 def do_da(self, address):
1526 """
1527 Print ASCII string starting at specified address.
1528 """
1529 address = int(address, 16)
1530 string = ""
1531 while self.reader.IsValidAddress(address):
1532 code = self.reader.ReadU8(address)
1533 if code < 128:
1534 string += chr(code)
1535 else:
1536 break
1537 address += 1
1538 if string == "":
1539 print "Not an ASCII string at %s" % self.reader.FormatIntPtr(address)
1540 else:
1541 print "%s\n" % string
1542
verwaest@chromium.org37141392012-05-31 13:27:02 +00001543 def do_k(self, arguments):
1544 """
1545 Teach V8 heap layout information to the inspector. This increases
1546 the amount of annotations the inspector can produce while dumping
1547 data. The first page of each heap space is of particular interest
1548 because it contains known objects that do not move.
1549 """
1550 self.padawan.PrintKnowledge()
1551
1552 def do_km(self, address):
1553 """
1554 Teach V8 heap layout information to the inspector. Set the first
1555 map-space page by passing any pointer into that page.
1556 """
1557 address = int(address, 16)
1558 page_address = address & ~self.heap.PageAlignmentMask()
1559 self.padawan.known_first_map_page = page_address
1560
1561 def do_kd(self, address):
1562 """
1563 Teach V8 heap layout information to the inspector. Set the first
1564 data-space page by passing any pointer into that page.
1565 """
1566 address = int(address, 16)
1567 page_address = address & ~self.heap.PageAlignmentMask()
1568 self.padawan.known_first_data_page = page_address
1569
1570 def do_kp(self, address):
1571 """
1572 Teach V8 heap layout information to the inspector. Set the first
1573 pointer-space page by passing any pointer into that page.
1574 """
1575 address = int(address, 16)
1576 page_address = address & ~self.heap.PageAlignmentMask()
1577 self.padawan.known_first_pointer_page = page_address
1578
1579 def do_s(self, word):
1580 """
1581 Search for a given word in available memory regions. The given word
1582 is expanded to full pointer size and searched at aligned as well as
1583 un-aligned memory locations. Use 'sa' to search aligned locations
1584 only.
1585 """
1586 try:
1587 word = int(word, 0)
1588 except ValueError:
1589 print "Malformed word, prefix with '0x' to use hexadecimal format."
1590 return
1591 print "Searching for word %d/0x%s:" % (word, self.reader.FormatIntPtr(word))
1592 self.reader.FindWord(word)
1593
1594 def do_sh(self, none):
1595 """
1596 Search for the V8 Heap object in all available memory regions. You
1597 might get lucky and find this rare treasure full of invaluable
1598 information.
1599 """
1600 raise NotImplementedError
1601
1602 def do_list(self, smth):
1603 """
1604 List all available memory regions.
1605 """
1606 def print_region(reader, start, size, location):
1607 print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start),
1608 reader.FormatIntPtr(start + size),
1609 size)
1610 print "Available memory regions:"
1611 self.reader.ForEachMemoryRegion(print_region)
1612
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001613
1614EIP_PROXIMITY = 64
1615
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001616CONTEXT_FOR_ARCH = {
1617 MD_CPU_ARCHITECTURE_AMD64:
1618 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'],
1619 MD_CPU_ARCHITECTURE_X86:
1620 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
1621}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001622
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001623
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001624def AnalyzeMinidump(options, minidump_name):
1625 reader = MinidumpReader(options, minidump_name)
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001626 heap = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001627 DebugPrint("========================================")
1628 if reader.exception is None:
1629 print "Minidump has no exception info"
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001630 else:
1631 print "Exception info:"
1632 exception_thread = reader.thread_map[reader.exception.thread_id]
1633 print " thread id: %d" % exception_thread.id
1634 print " code: %08X" % reader.exception.exception.code
1635 print " context:"
1636 for r in CONTEXT_FOR_ARCH[reader.arch]:
1637 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
1638 # TODO(vitalyr): decode eflags.
1639 print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
1640 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001641
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001642 stack_top = reader.ExceptionSP()
1643 stack_bottom = exception_thread.stack.start + \
1644 exception_thread.stack.memory.data_size
1645 stack_map = {reader.ExceptionIP(): -1}
1646 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
1647 maybe_address = reader.ReadUIntPtr(slot)
1648 if not maybe_address in stack_map:
1649 stack_map[maybe_address] = slot
1650 heap = V8Heap(reader, stack_map)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001651
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001652 print "Disassembly around exception.eip:"
1653 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY
1654 disasm_bytes = 2 * EIP_PROXIMITY
1655 if (options.full):
1656 full_range = reader.FindRegion(reader.ExceptionIP())
1657 if full_range is not None:
1658 disasm_start = full_range[0]
1659 disasm_bytes = full_range[1]
1660
1661 lines = reader.GetDisasmLines(disasm_start, disasm_bytes)
1662
1663 for line in lines:
1664 print FormatDisasmLine(disasm_start, heap, line)
1665 print
1666
1667 if heap is None:
1668 heap = V8Heap(reader, None)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001669
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001670 if options.full:
verwaest@chromium.org37141392012-05-31 13:27:02 +00001671 FullDump(reader, heap)
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001672
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001673 if options.shell:
1674 InspectionShell(reader, heap).cmdloop("type help to get help")
1675 else:
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001676 if reader.exception is not None:
1677 print "Annotated stack (from exception.esp to bottom):"
1678 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
1679 maybe_address = reader.ReadUIntPtr(slot)
1680 heap_object = heap.FindObject(maybe_address)
1681 print "%s: %s" % (reader.FormatIntPtr(slot),
1682 reader.FormatIntPtr(maybe_address))
1683 if heap_object:
1684 heap_object.Print(Printer())
1685 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001686
1687 reader.Dispose()
1688
1689
1690if __name__ == "__main__":
1691 parser = optparse.OptionParser(USAGE)
verwaest@chromium.org37141392012-05-31 13:27:02 +00001692 parser.add_option("-s", "--shell", dest="shell", action="store_true",
1693 help="start an interactive inspector shell")
1694 parser.add_option("-f", "--full", dest="full", action="store_true",
1695 help="dump all information contained in the minidump")
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001696 options, args = parser.parse_args()
1697 if len(args) != 1:
1698 parser.print_help()
1699 sys.exit(1)
1700 AnalyzeMinidump(options, args[0])