blob: 7a076754ee2f6ca041947e681f8e60db9759f45f [file] [log] [blame]
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001#!/usr/bin/env python
2#
verwaest@chromium.org37141392012-05-31 13:27:02 +00003# Copyright 2012 the V8 project authors. All rights reserved.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met:
7#
8# * Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# * Redistributions in binary form must reproduce the above
11# copyright notice, this list of conditions and the following
12# disclaimer in the documentation and/or other materials provided
13# with the distribution.
14# * Neither the name of Google Inc. nor the names of its
15# contributors may be used to endorse or promote products derived
16# from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000030import bisect
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000031import cmd
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000032import codecs
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000033import ctypes
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000034import disasm
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000035import mmap
36import optparse
37import os
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +000038import re
39import struct
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000040import sys
41import types
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000042
43
verwaest@chromium.org37141392012-05-31 13:27:02 +000044USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000045
46Minidump analyzer.
47
48Shows the processor state at the point of exception including the
49stack of the active thread and the referenced objects in the V8
50heap. Code objects are disassembled and the addresses linked from the
verwaest@chromium.org37141392012-05-31 13:27:02 +000051stack (e.g. pushed return addresses) are marked with "=>".
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000052
53Examples:
verwaest@chromium.org37141392012-05-31 13:27:02 +000054 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp"""
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000055
ricow@chromium.org7ad65222011-12-19 12:13:11 +000056
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000057DEBUG=False
58
59
60def DebugPrint(s):
61 if not DEBUG: return
62 print s
63
64
65class Descriptor(object):
66 """Descriptor of a structure in a memory."""
67
68 def __init__(self, fields):
69 self.fields = fields
70 self.is_flexible = False
71 for _, type_or_func in fields:
72 if isinstance(type_or_func, types.FunctionType):
73 self.is_flexible = True
74 break
75 if not self.is_flexible:
76 self.ctype = Descriptor._GetCtype(fields)
77 self.size = ctypes.sizeof(self.ctype)
78
79 def Read(self, memory, offset):
80 if self.is_flexible:
81 fields_copy = self.fields[:]
82 last = 0
83 for name, type_or_func in fields_copy:
84 if isinstance(type_or_func, types.FunctionType):
85 partial_ctype = Descriptor._GetCtype(fields_copy[:last])
86 partial_object = partial_ctype.from_buffer(memory, offset)
87 type = type_or_func(partial_object)
88 if type is not None:
89 fields_copy[last] = (name, type)
90 last += 1
91 else:
92 last += 1
93 complete_ctype = Descriptor._GetCtype(fields_copy[:last])
94 else:
95 complete_ctype = self.ctype
96 return complete_ctype.from_buffer(memory, offset)
97
98 @staticmethod
99 def _GetCtype(fields):
100 class Raw(ctypes.Structure):
101 _fields_ = fields
102 _pack_ = 1
103
104 def __str__(self):
105 return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field))
106 for field, _ in Raw._fields_) + "}"
107 return Raw
108
109
verwaest@chromium.org37141392012-05-31 13:27:02 +0000110def FullDump(reader, heap):
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000111 """Dump all available memory regions."""
112 def dump_region(reader, start, size, location):
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000113 print
114 while start & 3 != 0:
115 start += 1
116 size -= 1
117 location += 1
118 is_executable = reader.IsProbableExecutableRegion(location, size)
119 is_ascii = reader.IsProbableASCIIRegion(location, size)
120
121 if is_executable is not False:
122 lines = reader.GetDisasmLines(start, size)
123 for line in lines:
124 print FormatDisasmLine(start, heap, line)
125 print
126
127 if is_ascii is not False:
128 # Output in the same format as the Unix hd command
129 addr = start
130 for slot in xrange(location, location + size, 16):
131 hex_line = ""
132 asc_line = ""
133 for i in xrange(0, 16):
134 if slot + i < location + size:
135 byte = ctypes.c_uint8.from_buffer(reader.minidump, slot + i).value
136 if byte >= 0x20 and byte < 0x7f:
137 asc_line += chr(byte)
138 else:
139 asc_line += "."
140 hex_line += " %02x" % (byte)
141 else:
142 hex_line += " "
143 if i == 7:
144 hex_line += " "
145 print "%s %s |%s|" % (reader.FormatIntPtr(addr),
146 hex_line,
147 asc_line)
148 addr += 16
149
150 if is_executable is not True and is_ascii is not True:
151 print "%s - %s" % (reader.FormatIntPtr(start),
152 reader.FormatIntPtr(start + size))
153 for slot in xrange(start,
154 start + size,
155 reader.PointerSize()):
156 maybe_address = reader.ReadUIntPtr(slot)
157 heap_object = heap.FindObject(maybe_address)
158 print "%s: %s" % (reader.FormatIntPtr(slot),
159 reader.FormatIntPtr(maybe_address))
160 if heap_object:
161 heap_object.Print(Printer())
162 print
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000163
164 reader.ForEachMemoryRegion(dump_region)
165
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000166# Set of structures and constants that describe the layout of minidump
167# files. Based on MSDN and Google Breakpad.
168
169MINIDUMP_HEADER = Descriptor([
170 ("signature", ctypes.c_uint32),
171 ("version", ctypes.c_uint32),
172 ("stream_count", ctypes.c_uint32),
173 ("stream_directories_rva", ctypes.c_uint32),
174 ("checksum", ctypes.c_uint32),
175 ("time_date_stampt", ctypes.c_uint32),
176 ("flags", ctypes.c_uint64)
177])
178
179MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
180 ("data_size", ctypes.c_uint32),
181 ("rva", ctypes.c_uint32)
182])
183
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000184MINIDUMP_STRING = Descriptor([
185 ("length", ctypes.c_uint32),
186 ("buffer", lambda t: ctypes.c_uint8 * (t.length + 2))
187])
188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000189MINIDUMP_DIRECTORY = Descriptor([
190 ("stream_type", ctypes.c_uint32),
191 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
192])
193
194MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
195
196MINIDUMP_EXCEPTION = Descriptor([
197 ("code", ctypes.c_uint32),
198 ("flags", ctypes.c_uint32),
199 ("record", ctypes.c_uint64),
200 ("address", ctypes.c_uint64),
201 ("parameter_count", ctypes.c_uint32),
202 ("unused_alignment", ctypes.c_uint32),
203 ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
204])
205
206MINIDUMP_EXCEPTION_STREAM = Descriptor([
207 ("thread_id", ctypes.c_uint32),
208 ("unused_alignment", ctypes.c_uint32),
209 ("exception", MINIDUMP_EXCEPTION.ctype),
210 ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
211])
212
213# Stream types.
214MD_UNUSED_STREAM = 0
215MD_RESERVED_STREAM_0 = 1
216MD_RESERVED_STREAM_1 = 2
217MD_THREAD_LIST_STREAM = 3
218MD_MODULE_LIST_STREAM = 4
219MD_MEMORY_LIST_STREAM = 5
220MD_EXCEPTION_STREAM = 6
221MD_SYSTEM_INFO_STREAM = 7
222MD_THREAD_EX_LIST_STREAM = 8
223MD_MEMORY_64_LIST_STREAM = 9
224MD_COMMENT_STREAM_A = 10
225MD_COMMENT_STREAM_W = 11
226MD_HANDLE_DATA_STREAM = 12
227MD_FUNCTION_TABLE_STREAM = 13
228MD_UNLOADED_MODULE_LIST_STREAM = 14
229MD_MISC_INFO_STREAM = 15
230MD_MEMORY_INFO_LIST_STREAM = 16
231MD_THREAD_INFO_LIST_STREAM = 17
232MD_HANDLE_OPERATION_LIST_STREAM = 18
233
234MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
235
236MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
237 ("control_word", ctypes.c_uint32),
238 ("status_word", ctypes.c_uint32),
239 ("tag_word", ctypes.c_uint32),
240 ("error_offset", ctypes.c_uint32),
241 ("error_selector", ctypes.c_uint32),
242 ("data_offset", ctypes.c_uint32),
243 ("data_selector", ctypes.c_uint32),
244 ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
245 ("cr0_npx_state", ctypes.c_uint32)
246])
247
248MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
249
250# Context flags.
251MD_CONTEXT_X86 = 0x00010000
252MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
253MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
254MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
255MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
256MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
257MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
258
259def EnableOnFlag(type, flag):
260 return lambda o: [None, type][int((o.context_flags & flag) != 0)]
261
262MINIDUMP_CONTEXT_X86 = Descriptor([
263 ("context_flags", ctypes.c_uint32),
264 # MD_CONTEXT_X86_DEBUG_REGISTERS.
265 ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
266 ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
267 ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
268 ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
269 ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
270 ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
271 # MD_CONTEXT_X86_FLOATING_POINT.
272 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
273 MD_CONTEXT_X86_FLOATING_POINT)),
274 # MD_CONTEXT_X86_SEGMENTS.
275 ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
276 ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
277 ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
278 ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
279 # MD_CONTEXT_X86_INTEGER.
280 ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
281 ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
282 ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
283 ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
284 ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
285 ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
286 # MD_CONTEXT_X86_CONTROL.
287 ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
288 ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
289 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
290 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
291 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
292 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
293 # MD_CONTEXT_X86_EXTENDED_REGISTERS.
294 ("extended_registers",
295 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
296 MD_CONTEXT_X86_EXTENDED_REGISTERS))
297])
298
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000299MD_CONTEXT_ARM = 0x40000000
300MD_CONTEXT_ARM_INTEGER = (MD_CONTEXT_ARM | 0x00000002)
301MD_CONTEXT_ARM_FLOATING_POINT = (MD_CONTEXT_ARM | 0x00000004)
302MD_FLOATINGSAVEAREA_ARM_FPR_COUNT = 32
303MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT = 8
304
305MINIDUMP_FLOATING_SAVE_AREA_ARM = Descriptor([
306 ("fpscr", ctypes.c_uint64),
307 ("regs", ctypes.c_uint64 * MD_FLOATINGSAVEAREA_ARM_FPR_COUNT),
308 ("extra", ctypes.c_uint64 * MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT)
309])
310
311MINIDUMP_CONTEXT_ARM = Descriptor([
312 ("context_flags", ctypes.c_uint32),
313 # MD_CONTEXT_ARM_INTEGER.
314 ("r0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
315 ("r1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
316 ("r2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
317 ("r3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
318 ("r4", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
319 ("r5", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
320 ("r6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
321 ("r7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
322 ("r8", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
323 ("r9", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
324 ("r10", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
325 ("r11", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
326 ("r12", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
327 ("sp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
328 ("lr", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
329 ("pc", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
330 ("cpsr", ctypes.c_uint32),
331 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_ARM.ctype,
332 MD_CONTEXT_ARM_FLOATING_POINT))
333])
334
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000335MD_CONTEXT_AMD64 = 0x00100000
336MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
337MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
338MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
339MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
340MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
341
342MINIDUMP_CONTEXT_AMD64 = Descriptor([
343 ("p1_home", ctypes.c_uint64),
344 ("p2_home", ctypes.c_uint64),
345 ("p3_home", ctypes.c_uint64),
346 ("p4_home", ctypes.c_uint64),
347 ("p5_home", ctypes.c_uint64),
348 ("p6_home", ctypes.c_uint64),
349 ("context_flags", ctypes.c_uint32),
350 ("mx_csr", ctypes.c_uint32),
351 # MD_CONTEXT_AMD64_CONTROL.
352 ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
353 # MD_CONTEXT_AMD64_SEGMENTS
354 ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
355 ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
356 ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
357 ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
358 # MD_CONTEXT_AMD64_CONTROL.
359 ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
360 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
361 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
362 ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
363 ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
364 ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
365 ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
366 ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
367 ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
368 # MD_CONTEXT_AMD64_INTEGER.
369 ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
370 ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
371 ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
372 ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
373 # MD_CONTEXT_AMD64_CONTROL.
374 ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
375 # MD_CONTEXT_AMD64_INTEGER.
376 ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
377 ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
378 ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
379 ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
380 ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
381 ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
382 ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
383 ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
384 ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
385 ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
386 ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
387 # MD_CONTEXT_AMD64_CONTROL.
388 ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
389 # MD_CONTEXT_AMD64_FLOATING_POINT
390 ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
391 MD_CONTEXT_AMD64_FLOATING_POINT)),
392 ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
393 MD_CONTEXT_AMD64_FLOATING_POINT)),
394 ("vector_control", EnableOnFlag(ctypes.c_uint64,
395 MD_CONTEXT_AMD64_FLOATING_POINT)),
396 # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
397 ("debug_control", EnableOnFlag(ctypes.c_uint64,
398 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
399 ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
400 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
401 ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
402 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
403 ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
404 MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
405 ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
406 MD_CONTEXT_AMD64_DEBUG_REGISTERS))
407])
408
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000409MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
410 ("start", ctypes.c_uint64),
411 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
412])
413
414MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
415 ("start", ctypes.c_uint64),
416 ("size", ctypes.c_uint64)
417])
418
419MINIDUMP_MEMORY_LIST = Descriptor([
420 ("range_count", ctypes.c_uint32),
421 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
422])
423
424MINIDUMP_MEMORY_LIST64 = Descriptor([
425 ("range_count", ctypes.c_uint64),
426 ("base_rva", ctypes.c_uint64),
427 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
428])
429
430MINIDUMP_THREAD = Descriptor([
431 ("id", ctypes.c_uint32),
432 ("suspend_count", ctypes.c_uint32),
433 ("priority_class", ctypes.c_uint32),
434 ("priority", ctypes.c_uint32),
435 ("ted", ctypes.c_uint64),
436 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
437 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
438])
439
440MINIDUMP_THREAD_LIST = Descriptor([
441 ("thread_count", ctypes.c_uint32),
442 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
443])
444
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000445MINIDUMP_RAW_MODULE = Descriptor([
446 ("base_of_image", ctypes.c_uint64),
447 ("size_of_image", ctypes.c_uint32),
448 ("checksum", ctypes.c_uint32),
449 ("time_date_stamp", ctypes.c_uint32),
450 ("module_name_rva", ctypes.c_uint32),
451 ("version_info", ctypes.c_uint32 * 13),
452 ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
453 ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
454 ("reserved0", ctypes.c_uint32 * 2),
455 ("reserved1", ctypes.c_uint32 * 2)
456])
457
458MINIDUMP_MODULE_LIST = Descriptor([
459 ("number_of_modules", ctypes.c_uint32),
460 ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules)
461])
462
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000463MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
464 ("processor_architecture", ctypes.c_uint16)
465])
466
467MD_CPU_ARCHITECTURE_X86 = 0
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000468MD_CPU_ARCHITECTURE_ARM = 5
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000469MD_CPU_ARCHITECTURE_AMD64 = 9
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000470
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000471class FuncSymbol:
472 def __init__(self, start, size, name):
473 self.start = start
474 self.end = self.start + size
475 self.name = name
476
477 def __cmp__(self, other):
478 if isinstance(other, FuncSymbol):
479 return self.start - other.start
480 return self.start - other
481
482 def Covers(self, addr):
483 return (self.start <= addr) and (addr < self.end)
484
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000485class MinidumpReader(object):
486 """Minidump (.dmp) reader."""
487
488 _HEADER_MAGIC = 0x504d444d
489
490 def __init__(self, options, minidump_name):
491 self.minidump_name = minidump_name
492 self.minidump_file = open(minidump_name, "r")
493 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
494 self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
495 if self.header.signature != MinidumpReader._HEADER_MAGIC:
verwaest@chromium.org37141392012-05-31 13:27:02 +0000496 print >>sys.stderr, "Warning: Unsupported minidump header magic!"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000497 DebugPrint(self.header)
498 directories = []
499 offset = self.header.stream_directories_rva
500 for _ in xrange(self.header.stream_count):
501 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
502 offset += MINIDUMP_DIRECTORY.size
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000503 self.arch = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000504 self.exception = None
505 self.exception_context = None
506 self.memory_list = None
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000507 self.memory_list64 = None
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000508 self.module_list = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000509 self.thread_map = {}
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000510
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000511 self.symdir = options.symdir
512 self.modules_with_symbols = []
513 self.symbols = []
514
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000515 # Find MDRawSystemInfo stream and determine arch.
516 for d in directories:
517 if d.stream_type == MD_SYSTEM_INFO_STREAM:
518 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
519 self.minidump, d.location.rva)
520 self.arch = system_info.processor_architecture
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000521 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64,
522 MD_CPU_ARCHITECTURE_ARM,
523 MD_CPU_ARCHITECTURE_X86]
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000524 assert not self.arch is None
525
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000526 for d in directories:
527 DebugPrint(d)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000528 if d.stream_type == MD_EXCEPTION_STREAM:
529 self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
530 self.minidump, d.location.rva)
531 DebugPrint(self.exception)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000532 if self.arch == MD_CPU_ARCHITECTURE_X86:
533 self.exception_context = MINIDUMP_CONTEXT_X86.Read(
534 self.minidump, self.exception.thread_context.rva)
535 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
536 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
537 self.minidump, self.exception.thread_context.rva)
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000538 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
539 self.exception_context = MINIDUMP_CONTEXT_ARM.Read(
540 self.minidump, self.exception.thread_context.rva)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000541 DebugPrint(self.exception_context)
542 elif d.stream_type == MD_THREAD_LIST_STREAM:
543 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
544 assert ctypes.sizeof(thread_list) == d.location.data_size
545 DebugPrint(thread_list)
546 for thread in thread_list.threads:
547 DebugPrint(thread)
548 self.thread_map[thread.id] = thread
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000549 elif d.stream_type == MD_MODULE_LIST_STREAM:
550 assert self.module_list is None
551 self.module_list = MINIDUMP_MODULE_LIST.Read(
552 self.minidump, d.location.rva)
553 assert ctypes.sizeof(self.module_list) == d.location.data_size
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000554 elif d.stream_type == MD_MEMORY_LIST_STREAM:
verwaest@chromium.org37141392012-05-31 13:27:02 +0000555 print >>sys.stderr, "Warning: This is not a full minidump!"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000556 assert self.memory_list is None
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000557 self.memory_list = MINIDUMP_MEMORY_LIST.Read(
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000558 self.minidump, d.location.rva)
559 assert ctypes.sizeof(self.memory_list) == d.location.data_size
560 DebugPrint(self.memory_list)
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000561 elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
562 assert self.memory_list64 is None
563 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read(
564 self.minidump, d.location.rva)
565 assert ctypes.sizeof(self.memory_list64) == d.location.data_size
566 DebugPrint(self.memory_list64)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000567
568 def IsValidAddress(self, address):
569 return self.FindLocation(address) is not None
570
571 def ReadU8(self, address):
572 location = self.FindLocation(address)
573 return ctypes.c_uint8.from_buffer(self.minidump, location).value
574
575 def ReadU32(self, address):
576 location = self.FindLocation(address)
577 return ctypes.c_uint32.from_buffer(self.minidump, location).value
578
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000579 def ReadU64(self, address):
580 location = self.FindLocation(address)
581 return ctypes.c_uint64.from_buffer(self.minidump, location).value
582
583 def ReadUIntPtr(self, address):
584 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
585 return self.ReadU64(address)
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000586 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
587 return self.ReadU32(address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000588 elif self.arch == MD_CPU_ARCHITECTURE_X86:
589 return self.ReadU32(address)
590
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000591 def ReadBytes(self, address, size):
592 location = self.FindLocation(address)
593 return self.minidump[location:location + size]
594
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000595 def _ReadWord(self, location):
596 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
597 return ctypes.c_uint64.from_buffer(self.minidump, location).value
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000598 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
599 return ctypes.c_uint32.from_buffer(self.minidump, location).value
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000600 elif self.arch == MD_CPU_ARCHITECTURE_X86:
601 return ctypes.c_uint32.from_buffer(self.minidump, location).value
602
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000603 def IsProbableASCIIRegion(self, location, length):
604 ascii_bytes = 0
605 non_ascii_bytes = 0
606 for loc in xrange(location, location + length):
607 byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
608 if byte >= 0x7f:
609 non_ascii_bytes += 1
610 if byte < 0x20 and byte != 0:
611 non_ascii_bytes += 1
612 if byte < 0x7f and byte >= 0x20:
613 ascii_bytes += 1
614 if byte == 0xa: # newline
615 ascii_bytes += 1
616 if ascii_bytes * 10 <= length:
617 return False
618 if length > 0 and ascii_bytes > non_ascii_bytes * 7:
619 return True
620 if ascii_bytes > non_ascii_bytes * 3:
621 return None # Maybe
622 return False
623
624 def IsProbableExecutableRegion(self, location, length):
625 opcode_bytes = 0
626 sixty_four = self.arch == MD_CPU_ARCHITECTURE_AMD64
627 for loc in xrange(location, location + length):
628 byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
629 if (byte == 0x8b or # mov
630 byte == 0x89 or # mov reg-reg
631 (byte & 0xf0) == 0x50 or # push/pop
632 (sixty_four and (byte & 0xf0) == 0x40) or # rex prefix
633 byte == 0xc3 or # return
634 byte == 0x74 or # jeq
635 byte == 0x84 or # jeq far
636 byte == 0x75 or # jne
637 byte == 0x85 or # jne far
638 byte == 0xe8 or # call
639 byte == 0xe9 or # jmp far
640 byte == 0xeb): # jmp near
641 opcode_bytes += 1
642 opcode_percent = (opcode_bytes * 100) / length
643 threshold = 20
644 if opcode_percent > threshold + 2:
645 return True
646 if opcode_percent > threshold - 2:
647 return None # Maybe
648 return False
649
650 def FindRegion(self, addr):
651 answer = [-1, -1]
652 def is_in(reader, start, size, location):
653 if addr >= start and addr < start + size:
654 answer[0] = start
655 answer[1] = size
656 self.ForEachMemoryRegion(is_in)
657 if answer[0] == -1:
658 return None
659 return answer
660
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000661 def ForEachMemoryRegion(self, cb):
662 if self.memory_list64 is not None:
663 for r in self.memory_list64.ranges:
664 location = self.memory_list64.base_rva + offset
665 cb(self, r.start, r.size, location)
666 offset += r.size
667
668 if self.memory_list is not None:
669 for r in self.memory_list.ranges:
670 cb(self, r.start, r.memory.data_size, r.memory.rva)
671
verwaest@chromium.org37141392012-05-31 13:27:02 +0000672 def FindWord(self, word, alignment=0):
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000673 def search_inside_region(reader, start, size, location):
verwaest@chromium.org37141392012-05-31 13:27:02 +0000674 location = (location + alignment) & ~alignment
675 for loc in xrange(location, location + size - self.PointerSize()):
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000676 if reader._ReadWord(loc) == word:
677 slot = start + (loc - location)
678 print "%s: %s" % (reader.FormatIntPtr(slot),
679 reader.FormatIntPtr(word))
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000680 self.ForEachMemoryRegion(search_inside_region)
681
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000682 def FindLocation(self, address):
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000683 offset = 0
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000684 if self.memory_list64 is not None:
685 for r in self.memory_list64.ranges:
686 if r.start <= address < r.start + r.size:
687 return self.memory_list64.base_rva + offset + address - r.start
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000688 offset += r.size
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000689 if self.memory_list is not None:
690 for r in self.memory_list.ranges:
691 if r.start <= address < r.start + r.memory.data_size:
692 return r.memory.rva + address - r.start
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000693 return None
694
695 def GetDisasmLines(self, address, size):
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000696 def CountUndefinedInstructions(lines):
697 pattern = "<UNDEFINED>"
698 return sum([line.count(pattern) for (ignore, line) in lines])
699
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000700 location = self.FindLocation(address)
701 if location is None: return []
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000702 arch = None
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000703 possible_objdump_flags = [""]
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000704 if self.arch == MD_CPU_ARCHITECTURE_X86:
705 arch = "ia32"
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000706 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
707 arch = "arm"
708 possible_objdump_flags = ["", "--disassembler-options=force-thumb"]
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000709 elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
710 arch = "x64"
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000711 results = [ disasm.GetDisasmLines(self.minidump_name,
712 location,
713 size,
714 arch,
715 False,
716 objdump_flags)
717 for objdump_flags in possible_objdump_flags ]
718 return min(results, key=CountUndefinedInstructions)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000719
720
721 def Dispose(self):
722 self.minidump.close()
723 self.minidump_file.close()
724
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000725 def ExceptionIP(self):
726 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
727 return self.exception_context.rip
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000728 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
729 return self.exception_context.pc
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000730 elif self.arch == MD_CPU_ARCHITECTURE_X86:
731 return self.exception_context.eip
732
733 def ExceptionSP(self):
734 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
735 return self.exception_context.rsp
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000736 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
737 return self.exception_context.sp
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000738 elif self.arch == MD_CPU_ARCHITECTURE_X86:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000739 return self.exception_context.esp
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000740
741 def FormatIntPtr(self, value):
742 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
743 return "%016x" % value
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000744 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
745 return "%08x" % value
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000746 elif self.arch == MD_CPU_ARCHITECTURE_X86:
747 return "%08x" % value
748
749 def PointerSize(self):
750 if self.arch == MD_CPU_ARCHITECTURE_AMD64:
751 return 8
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000752 elif self.arch == MD_CPU_ARCHITECTURE_ARM:
753 return 4
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000754 elif self.arch == MD_CPU_ARCHITECTURE_X86:
755 return 4
756
757 def Register(self, name):
758 return self.exception_context.__getattribute__(name)
759
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000760 def ReadMinidumpString(self, rva):
761 string = bytearray(MINIDUMP_STRING.Read(self.minidump, rva).buffer)
762 string = string.decode("utf16")
763 return string[0:len(string) - 1]
764
765 # Load FUNC records from a BreakPad symbol file
766 #
767 # http://code.google.com/p/google-breakpad/wiki/SymbolFiles
768 #
769 def _LoadSymbolsFrom(self, symfile, baseaddr):
770 print "Loading symbols from %s" % (symfile)
771 funcs = []
772 with open(symfile) as f:
773 for line in f:
774 result = re.match(
775 r"^FUNC ([a-f0-9]+) ([a-f0-9]+) ([a-f0-9]+) (.*)$", line)
776 if result is not None:
777 start = int(result.group(1), 16)
778 size = int(result.group(2), 16)
779 name = result.group(4).rstrip()
780 bisect.insort_left(self.symbols,
781 FuncSymbol(baseaddr + start, size, name))
782 print " ... done"
783
784 def TryLoadSymbolsFor(self, modulename, module):
785 try:
786 symfile = os.path.join(self.symdir,
787 modulename.replace('.', '_') + ".pdb.sym")
788 self._LoadSymbolsFrom(symfile, module.base_of_image)
789 self.modules_with_symbols.append(module)
790 except Exception as e:
791 print " ... failure (%s)" % (e)
792
793 # Returns true if address is covered by some module that has loaded symbols.
794 def _IsInModuleWithSymbols(self, addr):
795 for module in self.modules_with_symbols:
796 start = module.base_of_image
797 end = start + module.size_of_image
798 if (start <= addr) and (addr < end):
799 return True
800 return False
801
802 # Find symbol covering the given address and return its name in format
803 # <symbol name>+<offset from the start>
804 def FindSymbol(self, addr):
805 if not self._IsInModuleWithSymbols(addr):
806 return None
807
808 i = bisect.bisect_left(self.symbols, addr)
809 symbol = None
810 if (0 < i) and self.symbols[i - 1].Covers(addr):
811 symbol = self.symbols[i - 1]
812 elif (i < len(self.symbols)) and self.symbols[i].Covers(addr):
813 symbol = self.symbols[i]
814 else:
815 return None
816 diff = addr - symbol.start
817 return "%s+0x%x" % (symbol.name, diff)
818
819
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000820
821# List of V8 instance types. Obtained by adding the code below to any .cc file.
822#
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000823# #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000824# struct P {
825# P() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000826# printf("INSTANCE_TYPES = {\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000827# INSTANCE_TYPE_LIST(DUMP_TYPE)
828# printf("}\n");
829# }
830# };
831# static P p;
832INSTANCE_TYPES = {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000833 64: "SYMBOL_TYPE",
834 68: "ASCII_SYMBOL_TYPE",
835 65: "CONS_SYMBOL_TYPE",
836 69: "CONS_ASCII_SYMBOL_TYPE",
837 66: "EXTERNAL_SYMBOL_TYPE",
838 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
839 70: "EXTERNAL_ASCII_SYMBOL_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000840 82: "SHORT_EXTERNAL_SYMBOL_TYPE",
841 90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
842 86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000843 0: "STRING_TYPE",
844 4: "ASCII_STRING_TYPE",
845 1: "CONS_STRING_TYPE",
846 5: "CONS_ASCII_STRING_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000847 3: "SLICED_STRING_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000848 2: "EXTERNAL_STRING_TYPE",
849 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
850 6: "EXTERNAL_ASCII_STRING_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000851 18: "SHORT_EXTERNAL_STRING_TYPE",
852 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
853 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE",
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000854 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE",
855 128: "MAP_TYPE",
856 129: "CODE_TYPE",
857 130: "ODDBALL_TYPE",
858 131: "JS_GLOBAL_PROPERTY_CELL_TYPE",
859 132: "HEAP_NUMBER_TYPE",
860 133: "FOREIGN_TYPE",
861 134: "BYTE_ARRAY_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000862 135: "FREE_SPACE_TYPE",
863 136: "EXTERNAL_BYTE_ARRAY_TYPE",
864 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
865 138: "EXTERNAL_SHORT_ARRAY_TYPE",
866 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
867 140: "EXTERNAL_INT_ARRAY_TYPE",
868 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
869 142: "EXTERNAL_FLOAT_ARRAY_TYPE",
870 144: "EXTERNAL_PIXEL_ARRAY_TYPE",
871 146: "FILLER_TYPE",
872 147: "ACCESSOR_INFO_TYPE",
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000873 148: "ACCESSOR_PAIR_TYPE",
874 149: "ACCESS_CHECK_INFO_TYPE",
875 150: "INTERCEPTOR_INFO_TYPE",
876 151: "CALL_HANDLER_INFO_TYPE",
877 152: "FUNCTION_TEMPLATE_INFO_TYPE",
878 153: "OBJECT_TEMPLATE_INFO_TYPE",
879 154: "SIGNATURE_INFO_TYPE",
880 155: "TYPE_SWITCH_INFO_TYPE",
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000881 156: "ALLOCATION_SITE_INFO_TYPE",
882 157: "SCRIPT_TYPE",
883 158: "CODE_CACHE_TYPE",
884 159: "POLYMORPHIC_CODE_CACHE_TYPE",
885 160: "TYPE_FEEDBACK_INFO_TYPE",
886 161: "ALIASED_ARGUMENTS_ENTRY_TYPE",
887 164: "FIXED_ARRAY_TYPE",
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000888 145: "FIXED_DOUBLE_ARRAY_TYPE",
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000889 165: "SHARED_FUNCTION_INFO_TYPE",
890 166: "JS_MESSAGE_OBJECT_TYPE",
891 169: "JS_VALUE_TYPE",
892 170: "JS_DATE_TYPE",
893 171: "JS_OBJECT_TYPE",
894 172: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
895 173: "JS_MODULE_TYPE",
896 174: "JS_GLOBAL_OBJECT_TYPE",
897 175: "JS_BUILTINS_OBJECT_TYPE",
898 176: "JS_GLOBAL_PROXY_TYPE",
899 177: "JS_ARRAY_TYPE",
900 168: "JS_PROXY_TYPE",
901 180: "JS_WEAK_MAP_TYPE",
902 181: "JS_REGEXP_TYPE",
903 182: "JS_FUNCTION_TYPE",
904 167: "JS_FUNCTION_PROXY_TYPE",
905 162: "DEBUG_INFO_TYPE",
906 163: "BREAK_POINT_INFO_TYPE",
verwaest@chromium.org37141392012-05-31 13:27:02 +0000907}
908
909
910# List of known V8 maps. Used to determine the instance type and name
911# for maps that are part of the root-set and hence on the first page of
912# the map-space. Obtained by adding the code below to an IA32 release
913# build with enabled snapshots to the end of the Isolate::Init method.
914#
915# #define ROOT_LIST_CASE(type, name, camel_name) \
916# if (o == heap_.name()) n = #camel_name;
917# #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
918# if (o == heap_.name##_map()) n = #camel_name "Map";
919# HeapObjectIterator it(heap_.map_space());
920# printf("KNOWN_MAPS = {\n");
921# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
922# Map* m = Map::cast(o);
923# const char* n = "";
924# intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
925# int t = m->instance_type();
926# ROOT_LIST(ROOT_LIST_CASE)
927# STRUCT_LIST(STRUCT_LIST_CASE)
928# printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n);
929# }
930# printf("}\n");
931KNOWN_MAPS = {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000932 0x08081: (134, "ByteArrayMap"),
933 0x080a9: (128, "MetaMap"),
934 0x080d1: (130, "OddballMap"),
935 0x080f9: (68, "AsciiSymbolMap"),
936 0x08121: (164, "FixedArrayMap"),
937 0x08149: (132, "HeapNumberMap"),
938 0x08171: (135, "FreeSpaceMap"),
939 0x08199: (146, "OnePointerFillerMap"),
940 0x081c1: (146, "TwoPointerFillerMap"),
941 0x081e9: (131, "GlobalPropertyCellMap"),
942 0x08211: (165, "SharedFunctionInfoMap"),
943 0x08239: (4, "AsciiStringMap"),
944 0x08261: (164, "NativeContextMap"),
945 0x08289: (129, "CodeMap"),
946 0x082b1: (164, "ScopeInfoMap"),
947 0x082d9: (164, "FixedCOWArrayMap"),
948 0x08301: (145, "FixedDoubleArrayMap"),
949 0x08329: (164, "HashTableMap"),
950 0x08351: (0, "StringMap"),
951 0x08379: (64, "SymbolMap"),
952 0x083a1: (1, "ConsStringMap"),
953 0x083c9: (5, "ConsAsciiStringMap"),
954 0x083f1: (3, "SlicedStringMap"),
955 0x08419: (7, "SlicedAsciiStringMap"),
956 0x08441: (65, "ConsSymbolMap"),
957 0x08469: (69, "ConsAsciiSymbolMap"),
958 0x08491: (66, "ExternalSymbolMap"),
959 0x084b9: (74, "ExternalSymbolWithAsciiDataMap"),
960 0x084e1: (70, "ExternalAsciiSymbolMap"),
961 0x08509: (2, "ExternalStringMap"),
962 0x08531: (10, "ExternalStringWithAsciiDataMap"),
963 0x08559: (6, "ExternalAsciiStringMap"),
964 0x08581: (82, "ShortExternalSymbolMap"),
965 0x085a9: (90, "ShortExternalSymbolWithAsciiDataMap"),
966 0x085d1: (86, "ShortExternalAsciiSymbolMap"),
967 0x085f9: (18, "ShortExternalStringMap"),
968 0x08621: (26, "ShortExternalStringWithAsciiDataMap"),
969 0x08649: (22, "ShortExternalAsciiStringMap"),
970 0x08671: (0, "UndetectableStringMap"),
971 0x08699: (4, "UndetectableAsciiStringMap"),
972 0x086c1: (144, "ExternalPixelArrayMap"),
973 0x086e9: (136, "ExternalByteArrayMap"),
974 0x08711: (137, "ExternalUnsignedByteArrayMap"),
975 0x08739: (138, "ExternalShortArrayMap"),
976 0x08761: (139, "ExternalUnsignedShortArrayMap"),
977 0x08789: (140, "ExternalIntArrayMap"),
978 0x087b1: (141, "ExternalUnsignedIntArrayMap"),
979 0x087d9: (142, "ExternalFloatArrayMap"),
980 0x08801: (143, "ExternalDoubleArrayMap"),
981 0x08829: (164, "NonStrictArgumentsElementsMap"),
982 0x08851: (164, "FunctionContextMap"),
983 0x08879: (164, "CatchContextMap"),
984 0x088a1: (164, "WithContextMap"),
985 0x088c9: (164, "BlockContextMap"),
986 0x088f1: (164, "ModuleContextMap"),
987 0x08919: (164, "GlobalContextMap"),
988 0x08941: (166, "JSMessageObjectMap"),
989 0x08969: (133, "ForeignMap"),
990 0x08991: (171, "NeanderMap"),
991 0x089b9: (156, "AllocationSiteInfoMap"),
992 0x089e1: (159, "PolymorphicCodeCacheMap"),
993 0x08a09: (157, "ScriptMap"),
994 0x08a31: (171, ""),
995 0x08a59: (171, "ExternalMap"),
996 0x08a81: (147, "AccessorInfoMap"),
997 0x08aa9: (148, "AccessorPairMap"),
998 0x08ad1: (149, "AccessCheckInfoMap"),
999 0x08af9: (150, "InterceptorInfoMap"),
1000 0x08b21: (151, "CallHandlerInfoMap"),
1001 0x08b49: (152, "FunctionTemplateInfoMap"),
1002 0x08b71: (153, "ObjectTemplateInfoMap"),
1003 0x08b99: (154, "SignatureInfoMap"),
1004 0x08bc1: (155, "TypeSwitchInfoMap"),
1005 0x08be9: (158, "CodeCacheMap"),
1006 0x08c11: (160, "TypeFeedbackInfoMap"),
1007 0x08c39: (161, "AliasedArgumentsEntryMap"),
1008 0x08c61: (162, "DebugInfoMap"),
1009 0x08c89: (163, "BreakPointInfoMap"),
verwaest@chromium.org37141392012-05-31 13:27:02 +00001010}
1011
1012
1013# List of known V8 objects. Used to determine name for objects that are
1014# part of the root-set and hence on the first page of various old-space
1015# paged. Obtained by adding the code below to an IA32 release build with
1016# enabled snapshots to the end of the Isolate::Init method.
1017#
1018# #define ROOT_LIST_CASE(type, name, camel_name) \
1019# if (o == heap_.name()) n = #camel_name;
1020# OldSpaces spit;
1021# printf("KNOWN_OBJECTS = {\n");
1022# for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
1023# HeapObjectIterator it(s);
1024# const char* sname = AllocationSpaceName(s->identity());
1025# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
1026# const char* n = NULL;
1027# intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
1028# ROOT_LIST(ROOT_LIST_CASE)
1029# if (n != NULL) {
1030# printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n);
1031# }
1032# }
1033# }
1034# printf("}\n");
1035KNOWN_OBJECTS = {
1036 ("OLD_POINTER_SPACE", 0x08081): "NullValue",
1037 ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue",
1038 ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap",
1039 ("OLD_POINTER_SPACE", 0x080b1): "TrueValue",
1040 ("OLD_POINTER_SPACE", 0x080c1): "FalseValue",
1041 ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel",
1042 ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker",
1043 ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache",
1044 ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache",
1045 ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache",
1046 ("OLD_POINTER_SPACE", 0x08f09): "TerminationException",
1047 ("OLD_POINTER_SPACE", 0x08f19): "MessageListeners",
1048 ("OLD_POINTER_SPACE", 0x08f35): "CodeStubs",
1049 ("OLD_POINTER_SPACE", 0x09b61): "NonMonomorphicCache",
1050 ("OLD_POINTER_SPACE", 0x0a175): "PolymorphicCodeCache",
1051 ("OLD_POINTER_SPACE", 0x0a17d): "NativesSourceCache",
1052 ("OLD_POINTER_SPACE", 0x0a1bd): "EmptyScript",
1053 ("OLD_POINTER_SPACE", 0x0a1f9): "IntrinsicFunctionNames",
1054 ("OLD_POINTER_SPACE", 0x24a49): "SymbolTable",
1055 ("OLD_DATA_SPACE", 0x08081): "EmptyFixedArray",
1056 ("OLD_DATA_SPACE", 0x080a1): "NanValue",
1057 ("OLD_DATA_SPACE", 0x0811d): "EmptyByteArray",
1058 ("OLD_DATA_SPACE", 0x08125): "EmptyString",
1059 ("OLD_DATA_SPACE", 0x08131): "EmptyDescriptorArray",
1060 ("OLD_DATA_SPACE", 0x08259): "InfinityValue",
1061 ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue",
1062 ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors",
1063 ("CODE_SPACE", 0x12b81): "JsEntryCode",
1064 ("CODE_SPACE", 0x12c61): "JsConstructEntryCode",
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001065}
1066
1067
1068class Printer(object):
1069 """Printer with indentation support."""
1070
1071 def __init__(self):
1072 self.indent = 0
1073
1074 def Indent(self):
1075 self.indent += 2
1076
1077 def Dedent(self):
1078 self.indent -= 2
1079
1080 def Print(self, string):
1081 print "%s%s" % (self._IndentString(), string)
1082
1083 def PrintLines(self, lines):
1084 indent = self._IndentString()
1085 print "\n".join("%s%s" % (indent, line) for line in lines)
1086
1087 def _IndentString(self):
1088 return self.indent * " "
1089
1090
1091ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
1092
1093
1094def FormatDisasmLine(start, heap, line):
1095 line_address = start + line[0]
1096 stack_slot = heap.stack_map.get(line_address)
1097 marker = " "
1098 if stack_slot:
1099 marker = "=>"
1100 code = AnnotateAddresses(heap, line[1])
1101 return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
1102
1103
1104def AnnotateAddresses(heap, line):
1105 extra = []
1106 for m in ADDRESS_RE.finditer(line):
1107 maybe_address = int(m.group(0), 16)
1108 object = heap.FindObject(maybe_address)
1109 if not object: continue
1110 extra.append(str(object))
1111 if len(extra) == 0: return line
1112 return "%s ;; %s" % (line, ", ".join(extra))
1113
1114
1115class HeapObject(object):
1116 def __init__(self, heap, map, address):
1117 self.heap = heap
1118 self.map = map
1119 self.address = address
1120
1121 def Is(self, cls):
1122 return isinstance(self, cls)
1123
1124 def Print(self, p):
1125 p.Print(str(self))
1126
1127 def __str__(self):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001128 return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
1129 INSTANCE_TYPES[self.map.instance_type])
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001130
1131 def ObjectField(self, offset):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001132 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001133 return self.heap.FindObjectOrSmi(field_value)
1134
1135 def SmiField(self, offset):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001136 field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001137 assert (field_value & 1) == 0
1138 return field_value / 2
1139
1140
1141class Map(HeapObject):
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001142 def InstanceTypeOffset(self):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001143 return self.heap.PointerSize() + self.heap.IntSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001144
1145 def __init__(self, heap, map, address):
1146 HeapObject.__init__(self, heap, map, address)
1147 self.instance_type = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001148 heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001149
1150
1151class String(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001152 def LengthOffset(self):
1153 return self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001154
1155 def __init__(self, heap, map, address):
1156 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001157 self.length = self.SmiField(self.LengthOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001158
1159 def GetChars(self):
1160 return "?string?"
1161
1162 def Print(self, p):
1163 p.Print(str(self))
1164
1165 def __str__(self):
1166 return "\"%s\"" % self.GetChars()
1167
1168
1169class SeqString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001170 def CharsOffset(self):
1171 return self.heap.PointerSize() * 3
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001172
1173 def __init__(self, heap, map, address):
1174 String.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001175 self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001176 self.length)
1177
1178 def GetChars(self):
1179 return self.chars
1180
1181
1182class ExternalString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001183 # TODO(vegorov) fix ExternalString for X64 architecture
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001184 RESOURCE_OFFSET = 12
1185
1186 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
1187 WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
1188
1189 def __init__(self, heap, map, address):
1190 String.__init__(self, heap, map, address)
1191 reader = heap.reader
1192 self.resource = \
1193 reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
1194 self.chars = "?external string?"
1195 if not reader.IsValidAddress(self.resource): return
1196 string_impl_address = self.resource + \
1197 ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
1198 if not reader.IsValidAddress(string_impl_address): return
1199 string_impl = reader.ReadU32(string_impl_address)
1200 chars_ptr_address = string_impl + \
1201 ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
1202 if not reader.IsValidAddress(chars_ptr_address): return
1203 chars_ptr = reader.ReadU32(chars_ptr_address)
1204 if not reader.IsValidAddress(chars_ptr): return
1205 raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
1206 self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
1207
1208 def GetChars(self):
1209 return self.chars
1210
1211
1212class ConsString(String):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001213 def LeftOffset(self):
1214 return self.heap.PointerSize() * 3
1215
1216 def RightOffset(self):
1217 return self.heap.PointerSize() * 4
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001218
1219 def __init__(self, heap, map, address):
1220 String.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001221 self.left = self.ObjectField(self.LeftOffset())
1222 self.right = self.ObjectField(self.RightOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001223
1224 def GetChars(self):
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001225 try:
1226 return self.left.GetChars() + self.right.GetChars()
1227 except:
1228 return "***CAUGHT EXCEPTION IN GROKDUMP***"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001229
1230
1231class Oddball(HeapObject):
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001232 # Should match declarations in objects.h
1233 KINDS = [
1234 "False",
1235 "True",
1236 "TheHole",
1237 "Null",
1238 "ArgumentMarker",
1239 "Undefined",
1240 "Other"
1241 ]
1242
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001243 def ToStringOffset(self):
1244 return self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001245
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001246 def ToNumberOffset(self):
1247 return self.ToStringOffset() + self.heap.PointerSize()
1248
1249 def KindOffset(self):
1250 return self.ToNumberOffset() + self.heap.PointerSize()
1251
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001252 def __init__(self, heap, map, address):
1253 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001254 self.to_string = self.ObjectField(self.ToStringOffset())
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001255 self.kind = self.SmiField(self.KindOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001256
1257 def Print(self, p):
1258 p.Print(str(self))
1259
1260 def __str__(self):
verwaest@chromium.org37141392012-05-31 13:27:02 +00001261 if self.to_string:
1262 return "Oddball(%08x, <%s>)" % (self.address, self.to_string.GetChars())
1263 else:
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001264 kind = "???"
1265 if 0 <= self.kind < len(Oddball.KINDS):
1266 kind = Oddball.KINDS[self.kind]
1267 return "Oddball(%08x, kind=%s)" % (self.address, kind)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001268
1269
1270class FixedArray(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001271 def LengthOffset(self):
1272 return self.heap.PointerSize()
1273
1274 def ElementsOffset(self):
1275 return self.heap.PointerSize() * 2
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001276
1277 def __init__(self, heap, map, address):
1278 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001279 self.length = self.SmiField(self.LengthOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001280
1281 def Print(self, p):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001282 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001283 p.Indent()
1284 p.Print("length: %d" % self.length)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001285 base_offset = self.ElementsOffset()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001286 for i in xrange(self.length):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001287 offset = base_offset + 4 * i
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001288 try:
1289 p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
1290 except TypeError:
1291 p.Dedent()
1292 p.Print("...")
1293 p.Print("}")
1294 return
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001295 p.Dedent()
1296 p.Print("}")
1297
1298 def __str__(self):
1299 return "FixedArray(%08x, length=%d)" % (self.address, self.length)
1300
1301
1302class JSFunction(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001303 def CodeEntryOffset(self):
1304 return 3 * self.heap.PointerSize()
1305
1306 def SharedOffset(self):
1307 return 5 * self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001308
1309 def __init__(self, heap, map, address):
1310 HeapObject.__init__(self, heap, map, address)
1311 code_entry = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001312 heap.reader.ReadU32(self.address + self.CodeEntryOffset())
1313 self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
1314 self.shared = self.ObjectField(self.SharedOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001315
1316 def Print(self, p):
1317 source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001318 p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001319 p.Indent()
1320 p.Print("inferred name: %s" % self.shared.inferred_name)
1321 if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
1322 p.Print("script name: %s" % self.shared.script.name)
1323 p.Print("source:")
1324 p.PrintLines(self._GetSource().split("\n"))
1325 p.Print("code:")
1326 self.code.Print(p)
1327 if self.code != self.shared.code:
1328 p.Print("unoptimized code:")
1329 self.shared.code.Print(p)
1330 p.Dedent()
1331 p.Print("}")
1332
1333 def __str__(self):
1334 inferred_name = ""
1335 if self.shared.Is(SharedFunctionInfo):
1336 inferred_name = self.shared.inferred_name
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001337 return "JSFunction(%s, %s)" % \
1338 (self.heap.reader.FormatIntPtr(self.address), inferred_name)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001339
1340 def _GetSource(self):
1341 source = "?source?"
1342 start = self.shared.start_position
1343 end = self.shared.end_position
1344 if not self.shared.script.Is(Script): return source
1345 script_source = self.shared.script.source
1346 if not script_source.Is(String): return source
1347 return script_source.GetChars()[start:end]
1348
1349
1350class SharedFunctionInfo(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001351 def CodeOffset(self):
1352 return 2 * self.heap.PointerSize()
1353
1354 def ScriptOffset(self):
1355 return 7 * self.heap.PointerSize()
1356
1357 def InferredNameOffset(self):
1358 return 9 * self.heap.PointerSize()
1359
1360 def EndPositionOffset(self):
1361 return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
1362
1363 def StartPositionAndTypeOffset(self):
1364 return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365
1366 def __init__(self, heap, map, address):
1367 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001368 self.code = self.ObjectField(self.CodeOffset())
1369 self.script = self.ObjectField(self.ScriptOffset())
1370 self.inferred_name = self.ObjectField(self.InferredNameOffset())
1371 if heap.PointerSize() == 8:
1372 start_position_and_type = \
1373 heap.reader.ReadU32(self.StartPositionAndTypeOffset())
1374 self.start_position = start_position_and_type >> 2
1375 pseudo_smi_end_position = \
1376 heap.reader.ReadU32(self.EndPositionOffset())
1377 self.end_position = pseudo_smi_end_position >> 2
1378 else:
1379 start_position_and_type = \
1380 self.SmiField(self.StartPositionAndTypeOffset())
1381 self.start_position = start_position_and_type >> 2
1382 self.end_position = \
1383 self.SmiField(self.EndPositionOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001384
1385
1386class Script(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001387 def SourceOffset(self):
1388 return self.heap.PointerSize()
1389
1390 def NameOffset(self):
1391 return self.SourceOffset() + self.heap.PointerSize()
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001392
1393 def __init__(self, heap, map, address):
1394 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001395 self.source = self.ObjectField(self.SourceOffset())
1396 self.name = self.ObjectField(self.NameOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001397
1398
verwaest@chromium.org37141392012-05-31 13:27:02 +00001399class CodeCache(HeapObject):
1400 def DefaultCacheOffset(self):
1401 return self.heap.PointerSize()
1402
1403 def NormalTypeCacheOffset(self):
1404 return self.DefaultCacheOffset() + self.heap.PointerSize()
1405
1406 def __init__(self, heap, map, address):
1407 HeapObject.__init__(self, heap, map, address)
1408 self.default_cache = self.ObjectField(self.DefaultCacheOffset())
1409 self.normal_type_cache = self.ObjectField(self.NormalTypeCacheOffset())
1410
1411 def Print(self, p):
1412 p.Print("CodeCache(%s) {" % self.heap.reader.FormatIntPtr(self.address))
1413 p.Indent()
1414 p.Print("default cache: %s" % self.default_cache)
1415 p.Print("normal type cache: %s" % self.normal_type_cache)
1416 p.Dedent()
1417 p.Print("}")
1418
1419
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001420class Code(HeapObject):
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001421 CODE_ALIGNMENT_MASK = (1 << 5) - 1
1422
1423 def InstructionSizeOffset(self):
1424 return self.heap.PointerSize()
1425
1426 @staticmethod
1427 def HeaderSize(heap):
1428 return (heap.PointerSize() + heap.IntSize() + \
1429 4 * heap.PointerSize() + 3 * heap.IntSize() + \
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001430 Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001431
1432 def __init__(self, heap, map, address):
1433 HeapObject.__init__(self, heap, map, address)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001434 self.entry = self.address + Code.HeaderSize(heap)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001435 self.instruction_size = \
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001436 heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001437
1438 def Print(self, p):
1439 lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001440 p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001441 p.Indent()
1442 p.Print("instruction_size: %d" % self.instruction_size)
1443 p.PrintLines(self._FormatLine(line) for line in lines)
1444 p.Dedent()
1445 p.Print("}")
1446
1447 def _FormatLine(self, line):
1448 return FormatDisasmLine(self.entry, self.heap, line)
1449
1450
1451class V8Heap(object):
1452 CLASS_MAP = {
1453 "SYMBOL_TYPE": SeqString,
1454 "ASCII_SYMBOL_TYPE": SeqString,
1455 "CONS_SYMBOL_TYPE": ConsString,
1456 "CONS_ASCII_SYMBOL_TYPE": ConsString,
1457 "EXTERNAL_SYMBOL_TYPE": ExternalString,
1458 "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
1459 "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001460 "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString,
1461 "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
1462 "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001463 "STRING_TYPE": SeqString,
1464 "ASCII_STRING_TYPE": SeqString,
1465 "CONS_STRING_TYPE": ConsString,
1466 "CONS_ASCII_STRING_TYPE": ConsString,
1467 "EXTERNAL_STRING_TYPE": ExternalString,
1468 "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
1469 "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001470 "MAP_TYPE": Map,
1471 "ODDBALL_TYPE": Oddball,
1472 "FIXED_ARRAY_TYPE": FixedArray,
1473 "JS_FUNCTION_TYPE": JSFunction,
1474 "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
1475 "SCRIPT_TYPE": Script,
verwaest@chromium.org37141392012-05-31 13:27:02 +00001476 "CODE_CACHE_TYPE": CodeCache,
1477 "CODE_TYPE": Code,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001478 }
1479
1480 def __init__(self, reader, stack_map):
1481 self.reader = reader
1482 self.stack_map = stack_map
1483 self.objects = {}
1484
1485 def FindObjectOrSmi(self, tagged_address):
1486 if (tagged_address & 1) == 0: return tagged_address / 2
1487 return self.FindObject(tagged_address)
1488
1489 def FindObject(self, tagged_address):
1490 if tagged_address in self.objects:
1491 return self.objects[tagged_address]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001492 if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001493 address = tagged_address - 1
1494 if not self.reader.IsValidAddress(address): return None
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001495 map_tagged_address = self.reader.ReadUIntPtr(address)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001496 if tagged_address == map_tagged_address:
1497 # Meta map?
1498 meta_map = Map(self, None, address)
1499 instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
1500 if instance_type_name != "MAP_TYPE": return None
1501 meta_map.map = meta_map
1502 object = meta_map
1503 else:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001504 map = self.FindMap(map_tagged_address)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001505 if map is None: return None
1506 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
1507 if instance_type_name is None: return None
1508 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
1509 object = cls(self, map, address)
1510 self.objects[tagged_address] = object
1511 return object
1512
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001513 def FindMap(self, tagged_address):
1514 if (tagged_address & self.MapAlignmentMask()) != 1: return None
1515 address = tagged_address - 1
1516 if not self.reader.IsValidAddress(address): return None
1517 object = Map(self, None, address)
1518 return object
1519
1520 def IntSize(self):
1521 return 4
1522
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001523 def PointerSize(self):
1524 return self.reader.PointerSize()
1525
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001526 def ObjectAlignmentMask(self):
1527 return self.PointerSize() - 1
1528
1529 def MapAlignmentMask(self):
1530 if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
1531 return (1 << 4) - 1
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001532 elif self.reader.arch == MD_CPU_ARCHITECTURE_ARM:
1533 return (1 << 4) - 1
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001534 elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
1535 return (1 << 5) - 1
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001536
verwaest@chromium.org37141392012-05-31 13:27:02 +00001537 def PageAlignmentMask(self):
1538 return (1 << 20) - 1
1539
1540
1541class KnownObject(HeapObject):
1542 def __init__(self, heap, known_name):
1543 HeapObject.__init__(self, heap, None, None)
1544 self.known_name = known_name
1545
1546 def __str__(self):
1547 return "<%s>" % self.known_name
1548
1549
1550class KnownMap(HeapObject):
1551 def __init__(self, heap, known_name, instance_type):
1552 HeapObject.__init__(self, heap, None, None)
1553 self.instance_type = instance_type
1554 self.known_name = known_name
1555
1556 def __str__(self):
1557 return "<%s>" % self.known_name
1558
1559
1560class InspectionPadawan(object):
1561 """The padawan can improve annotations by sensing well-known objects."""
1562 def __init__(self, reader, heap):
1563 self.reader = reader
1564 self.heap = heap
1565 self.known_first_map_page = 0
1566 self.known_first_data_page = 0
1567 self.known_first_pointer_page = 0
1568
1569 def __getattr__(self, name):
1570 """An InspectionPadawan can be used instead of V8Heap, even though
1571 it does not inherit from V8Heap (aka. mixin)."""
1572 return getattr(self.heap, name)
1573
1574 def GetPageOffset(self, tagged_address):
1575 return tagged_address & self.heap.PageAlignmentMask()
1576
1577 def IsInKnownMapSpace(self, tagged_address):
1578 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1579 return page_address == self.known_first_map_page
1580
1581 def IsInKnownOldSpace(self, tagged_address):
1582 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1583 return page_address in [self.known_first_data_page,
1584 self.known_first_pointer_page]
1585
1586 def ContainingKnownOldSpaceName(self, tagged_address):
1587 page_address = tagged_address & ~self.heap.PageAlignmentMask()
1588 if page_address == self.known_first_data_page: return "OLD_DATA_SPACE"
1589 if page_address == self.known_first_pointer_page: return "OLD_POINTER_SPACE"
1590 return None
1591
1592 def SenseObject(self, tagged_address):
1593 if self.IsInKnownOldSpace(tagged_address):
1594 offset = self.GetPageOffset(tagged_address)
1595 lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset)
1596 known_obj_name = KNOWN_OBJECTS.get(lookup_key)
1597 if known_obj_name:
1598 return KnownObject(self, known_obj_name)
1599 if self.IsInKnownMapSpace(tagged_address):
1600 known_map = self.SenseMap(tagged_address)
1601 if known_map:
1602 return known_map
1603 found_obj = self.heap.FindObject(tagged_address)
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001604 if found_obj: return found_obj
verwaest@chromium.org37141392012-05-31 13:27:02 +00001605 address = tagged_address - 1
1606 if self.reader.IsValidAddress(address):
1607 map_tagged_address = self.reader.ReadUIntPtr(address)
1608 map = self.SenseMap(map_tagged_address)
1609 if map is None: return None
1610 instance_type_name = INSTANCE_TYPES.get(map.instance_type)
1611 if instance_type_name is None: return None
1612 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
1613 return cls(self, map, address)
1614 return None
1615
1616 def SenseMap(self, tagged_address):
1617 if self.IsInKnownMapSpace(tagged_address):
1618 offset = self.GetPageOffset(tagged_address)
1619 known_map_info = KNOWN_MAPS.get(offset)
1620 if known_map_info:
1621 known_map_type, known_map_name = known_map_info
1622 return KnownMap(self, known_map_name, known_map_type)
1623 found_map = self.heap.FindMap(tagged_address)
1624 if found_map: return found_map
1625 return None
1626
1627 def FindObjectOrSmi(self, tagged_address):
1628 """When used as a mixin in place of V8Heap."""
1629 found_obj = self.SenseObject(tagged_address)
1630 if found_obj: return found_obj
1631 if (tagged_address & 1) == 0:
1632 return "Smi(%d)" % (tagged_address / 2)
1633 else:
1634 return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address)
1635
1636 def FindObject(self, tagged_address):
1637 """When used as a mixin in place of V8Heap."""
1638 raise NotImplementedError
1639
1640 def FindMap(self, tagged_address):
1641 """When used as a mixin in place of V8Heap."""
1642 raise NotImplementedError
1643
1644 def PrintKnowledge(self):
1645 print " known_first_map_page = %s\n"\
1646 " known_first_data_page = %s\n"\
1647 " known_first_pointer_page = %s" % (
1648 self.reader.FormatIntPtr(self.known_first_map_page),
1649 self.reader.FormatIntPtr(self.known_first_data_page),
1650 self.reader.FormatIntPtr(self.known_first_pointer_page))
1651
1652
1653class InspectionShell(cmd.Cmd):
1654 def __init__(self, reader, heap):
1655 cmd.Cmd.__init__(self)
1656 self.reader = reader
1657 self.heap = heap
1658 self.padawan = InspectionPadawan(reader, heap)
1659 self.prompt = "(grok) "
1660
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001661 def do_da(self, address):
1662 """
1663 Print ASCII string starting at specified address.
1664 """
1665 address = int(address, 16)
1666 string = ""
1667 while self.reader.IsValidAddress(address):
1668 code = self.reader.ReadU8(address)
1669 if code < 128:
1670 string += chr(code)
1671 else:
1672 break
1673 address += 1
1674 if string == "":
1675 print "Not an ASCII string at %s" % self.reader.FormatIntPtr(address)
1676 else:
1677 print "%s\n" % string
1678
verwaest@chromium.org37141392012-05-31 13:27:02 +00001679 def do_dd(self, address):
1680 """
1681 Interpret memory at the given address (if available) as a sequence
1682 of words. Automatic alignment is not performed.
1683 """
1684 start = int(address, 16)
1685 if (start & self.heap.ObjectAlignmentMask()) != 0:
1686 print "Warning: Dumping un-aligned memory, is this what you had in mind?"
1687 for slot in xrange(start,
1688 start + self.reader.PointerSize() * 10,
1689 self.reader.PointerSize()):
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001690 if not self.reader.IsValidAddress(slot):
1691 print "Address is not contained within the minidump!"
1692 return
verwaest@chromium.org37141392012-05-31 13:27:02 +00001693 maybe_address = self.reader.ReadUIntPtr(slot)
1694 heap_object = self.padawan.SenseObject(maybe_address)
1695 print "%s: %s %s" % (self.reader.FormatIntPtr(slot),
1696 self.reader.FormatIntPtr(maybe_address),
1697 heap_object or '')
1698
1699 def do_do(self, address):
1700 """
1701 Interpret memory at the given address as a V8 object. Automatic
1702 alignment makes sure that you can pass tagged as well as un-tagged
1703 addresses.
1704 """
1705 address = int(address, 16)
1706 if (address & self.heap.ObjectAlignmentMask()) == 0:
1707 address = address + 1
1708 elif (address & self.heap.ObjectAlignmentMask()) != 1:
1709 print "Address doesn't look like a valid pointer!"
1710 return
1711 heap_object = self.padawan.SenseObject(address)
1712 if heap_object:
1713 heap_object.Print(Printer())
1714 else:
1715 print "Address cannot be interpreted as object!"
1716
1717 def do_dp(self, address):
1718 """
1719 Interpret memory at the given address as being on a V8 heap page
1720 and print information about the page header (if available).
1721 """
1722 address = int(address, 16)
1723 page_address = address & ~self.heap.PageAlignmentMask()
1724 if self.reader.IsValidAddress(page_address):
1725 raise NotImplementedError
1726 else:
1727 print "Page header is not available!"
1728
1729 def do_k(self, arguments):
1730 """
1731 Teach V8 heap layout information to the inspector. This increases
1732 the amount of annotations the inspector can produce while dumping
1733 data. The first page of each heap space is of particular interest
1734 because it contains known objects that do not move.
1735 """
1736 self.padawan.PrintKnowledge()
1737
verwaest@chromium.org37141392012-05-31 13:27:02 +00001738 def do_kd(self, address):
1739 """
1740 Teach V8 heap layout information to the inspector. Set the first
1741 data-space page by passing any pointer into that page.
1742 """
1743 address = int(address, 16)
1744 page_address = address & ~self.heap.PageAlignmentMask()
1745 self.padawan.known_first_data_page = page_address
1746
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001747 def do_km(self, address):
1748 """
1749 Teach V8 heap layout information to the inspector. Set the first
1750 map-space page by passing any pointer into that page.
1751 """
1752 address = int(address, 16)
1753 page_address = address & ~self.heap.PageAlignmentMask()
1754 self.padawan.known_first_map_page = page_address
1755
verwaest@chromium.org37141392012-05-31 13:27:02 +00001756 def do_kp(self, address):
1757 """
1758 Teach V8 heap layout information to the inspector. Set the first
1759 pointer-space page by passing any pointer into that page.
1760 """
1761 address = int(address, 16)
1762 page_address = address & ~self.heap.PageAlignmentMask()
1763 self.padawan.known_first_pointer_page = page_address
1764
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001765 def do_list(self, smth):
1766 """
1767 List all available memory regions.
1768 """
1769 def print_region(reader, start, size, location):
1770 print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start),
1771 reader.FormatIntPtr(start + size),
1772 size)
1773 print "Available memory regions:"
1774 self.reader.ForEachMemoryRegion(print_region)
1775
verwaest@chromium.org37141392012-05-31 13:27:02 +00001776 def do_s(self, word):
1777 """
1778 Search for a given word in available memory regions. The given word
1779 is expanded to full pointer size and searched at aligned as well as
1780 un-aligned memory locations. Use 'sa' to search aligned locations
1781 only.
1782 """
1783 try:
1784 word = int(word, 0)
1785 except ValueError:
1786 print "Malformed word, prefix with '0x' to use hexadecimal format."
1787 return
1788 print "Searching for word %d/0x%s:" % (word, self.reader.FormatIntPtr(word))
1789 self.reader.FindWord(word)
1790
1791 def do_sh(self, none):
1792 """
1793 Search for the V8 Heap object in all available memory regions. You
1794 might get lucky and find this rare treasure full of invaluable
1795 information.
1796 """
1797 raise NotImplementedError
1798
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001799 def do_u(self, args):
verwaest@chromium.org37141392012-05-31 13:27:02 +00001800 """
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001801 u 0x<address> 0x<size>
1802 Unassemble memory in the region [address, address + size)
verwaest@chromium.org37141392012-05-31 13:27:02 +00001803 """
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001804 args = args.split(' ')
1805 start = int(args[0], 16)
1806 size = int(args[1], 16)
1807 lines = self.reader.GetDisasmLines(start, size)
1808 for line in lines:
1809 print FormatDisasmLine(start, self.heap, line)
1810 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001811
1812EIP_PROXIMITY = 64
1813
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001814CONTEXT_FOR_ARCH = {
1815 MD_CPU_ARCHITECTURE_AMD64:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001816 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip',
1817 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'],
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001818 MD_CPU_ARCHITECTURE_ARM:
1819 ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9',
1820 'r10', 'r11', 'r12', 'sp', 'lr', 'pc'],
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001821 MD_CPU_ARCHITECTURE_X86:
1822 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
1823}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001824
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001825KNOWN_MODULES = {'chrome.exe', 'chrome.dll'}
1826
1827def GetModuleName(reader, module):
1828 name = reader.ReadMinidumpString(module.module_name_rva)
1829 return str(os.path.basename(str(name).replace("\\", "/")))
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001830
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001831def AnalyzeMinidump(options, minidump_name):
1832 reader = MinidumpReader(options, minidump_name)
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001833 heap = None
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001834 DebugPrint("========================================")
1835 if reader.exception is None:
1836 print "Minidump has no exception info"
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001837 else:
1838 print "Exception info:"
1839 exception_thread = reader.thread_map[reader.exception.thread_id]
1840 print " thread id: %d" % exception_thread.id
1841 print " code: %08X" % reader.exception.exception.code
1842 print " context:"
1843 for r in CONTEXT_FOR_ARCH[reader.arch]:
1844 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
1845 # TODO(vitalyr): decode eflags.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001846 if reader.arch == MD_CPU_ARCHITECTURE_ARM:
1847 print " cpsr: %s" % bin(reader.exception_context.cpsr)[2:]
1848 else:
1849 print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
1850
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001851 print
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001852 print " modules:"
1853 for module in reader.module_list.modules:
1854 name = GetModuleName(reader, module)
1855 if name in KNOWN_MODULES:
1856 print " %s at %08X" % (name, module.base_of_image)
1857 reader.TryLoadSymbolsFor(name, module)
1858 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001859
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001860 stack_top = reader.ExceptionSP()
1861 stack_bottom = exception_thread.stack.start + \
1862 exception_thread.stack.memory.data_size
1863 stack_map = {reader.ExceptionIP(): -1}
1864 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
1865 maybe_address = reader.ReadUIntPtr(slot)
1866 if not maybe_address in stack_map:
1867 stack_map[maybe_address] = slot
1868 heap = V8Heap(reader, stack_map)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001869
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001870 print "Disassembly around exception.eip:"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001871 eip_symbol = reader.FindSymbol(reader.ExceptionIP())
1872 if eip_symbol is not None:
1873 print eip_symbol
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001874 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY
1875 disasm_bytes = 2 * EIP_PROXIMITY
1876 if (options.full):
1877 full_range = reader.FindRegion(reader.ExceptionIP())
1878 if full_range is not None:
1879 disasm_start = full_range[0]
1880 disasm_bytes = full_range[1]
1881
1882 lines = reader.GetDisasmLines(disasm_start, disasm_bytes)
1883
1884 for line in lines:
1885 print FormatDisasmLine(disasm_start, heap, line)
1886 print
1887
1888 if heap is None:
1889 heap = V8Heap(reader, None)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001890
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001891 if options.full:
verwaest@chromium.org37141392012-05-31 13:27:02 +00001892 FullDump(reader, heap)
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001893
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001894 if options.shell:
1895 InspectionShell(reader, heap).cmdloop("type help to get help")
1896 else:
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001897 if reader.exception is not None:
1898 print "Annotated stack (from exception.esp to bottom):"
1899 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
1900 maybe_address = reader.ReadUIntPtr(slot)
1901 heap_object = heap.FindObject(maybe_address)
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001902 maybe_symbol = reader.FindSymbol(maybe_address)
1903 print "%s: %s %s" % (reader.FormatIntPtr(slot),
1904 reader.FormatIntPtr(maybe_address),
1905 maybe_symbol or "")
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001906 if heap_object:
1907 heap_object.Print(Printer())
1908 print
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001909
1910 reader.Dispose()
1911
1912
1913if __name__ == "__main__":
1914 parser = optparse.OptionParser(USAGE)
verwaest@chromium.org37141392012-05-31 13:27:02 +00001915 parser.add_option("-s", "--shell", dest="shell", action="store_true",
1916 help="start an interactive inspector shell")
1917 parser.add_option("-f", "--full", dest="full", action="store_true",
1918 help="dump all information contained in the minidump")
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001919 parser.add_option("--symdir", dest="symdir", default=".",
1920 help="directory containing *.pdb.sym file with symbols")
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001921 parser.add_option("--objdump",
1922 default="/usr/bin/objdump",
1923 help="objdump tool to use [default: %default]")
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001924 options, args = parser.parse_args()
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001925 if os.path.exists(options.objdump):
1926 disasm.OBJDUMP_BIN = options.objdump
1927 OBJDUMP_BIN = options.objdump
1928 else:
1929 print "Cannot find %s, falling back to default objdump" % options.objdump
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001930 if len(args) != 1:
1931 parser.print_help()
1932 sys.exit(1)
1933 AnalyzeMinidump(options, args[0])