summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/tools/grokdump.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/v8/tools/grokdump.py')
-rwxr-xr-xsrc/3rdparty/v8/tools/grokdump.py1939
1 files changed, 0 insertions, 1939 deletions
diff --git a/src/3rdparty/v8/tools/grokdump.py b/src/3rdparty/v8/tools/grokdump.py
deleted file mode 100755
index 603453a..0000000
--- a/src/3rdparty/v8/tools/grokdump.py
+++ /dev/null
@@ -1,1939 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2012 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import bisect
-import cmd
-import codecs
-import ctypes
-import disasm
-import mmap
-import optparse
-import os
-import re
-import struct
-import sys
-import types
-
-
-USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
-
-Minidump analyzer.
-
-Shows the processor state at the point of exception including the
-stack of the active thread and the referenced objects in the V8
-heap. Code objects are disassembled and the addresses linked from the
-stack (e.g. pushed return addresses) are marked with "=>".
-
-Examples:
- $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp"""
-
-
-DEBUG=False
-
-
-def DebugPrint(s):
- if not DEBUG: return
- print s
-
-
-class Descriptor(object):
- """Descriptor of a structure in a memory."""
-
- def __init__(self, fields):
- self.fields = fields
- self.is_flexible = False
- for _, type_or_func in fields:
- if isinstance(type_or_func, types.FunctionType):
- self.is_flexible = True
- break
- if not self.is_flexible:
- self.ctype = Descriptor._GetCtype(fields)
- self.size = ctypes.sizeof(self.ctype)
-
- def Read(self, memory, offset):
- if self.is_flexible:
- fields_copy = self.fields[:]
- last = 0
- for name, type_or_func in fields_copy:
- if isinstance(type_or_func, types.FunctionType):
- partial_ctype = Descriptor._GetCtype(fields_copy[:last])
- partial_object = partial_ctype.from_buffer(memory, offset)
- type = type_or_func(partial_object)
- if type is not None:
- fields_copy[last] = (name, type)
- last += 1
- else:
- last += 1
- complete_ctype = Descriptor._GetCtype(fields_copy[:last])
- else:
- complete_ctype = self.ctype
- return complete_ctype.from_buffer(memory, offset)
-
- @staticmethod
- def _GetCtype(fields):
- class Raw(ctypes.Structure):
- _fields_ = fields
- _pack_ = 1
-
- def __str__(self):
- return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field))
- for field, _ in Raw._fields_) + "}"
- return Raw
-
-
-def FullDump(reader, heap):
- """Dump all available memory regions."""
- def dump_region(reader, start, size, location):
- print
- while start & 3 != 0:
- start += 1
- size -= 1
- location += 1
- is_executable = reader.IsProbableExecutableRegion(location, size)
- is_ascii = reader.IsProbableASCIIRegion(location, size)
-
- if is_executable is not False:
- lines = reader.GetDisasmLines(start, size)
- for line in lines:
- print FormatDisasmLine(start, heap, line)
- print
-
- if is_ascii is not False:
- # Output in the same format as the Unix hd command
- addr = start
- for slot in xrange(location, location + size, 16):
- hex_line = ""
- asc_line = ""
- for i in xrange(0, 16):
- if slot + i < location + size:
- byte = ctypes.c_uint8.from_buffer(reader.minidump, slot + i).value
- if byte >= 0x20 and byte < 0x7f:
- asc_line += chr(byte)
- else:
- asc_line += "."
- hex_line += " %02x" % (byte)
- else:
- hex_line += " "
- if i == 7:
- hex_line += " "
- print "%s %s |%s|" % (reader.FormatIntPtr(addr),
- hex_line,
- asc_line)
- addr += 16
-
- if is_executable is not True and is_ascii is not True:
- print "%s - %s" % (reader.FormatIntPtr(start),
- reader.FormatIntPtr(start + size))
- for slot in xrange(start,
- start + size,
- reader.PointerSize()):
- maybe_address = reader.ReadUIntPtr(slot)
- heap_object = heap.FindObject(maybe_address)
- print "%s: %s" % (reader.FormatIntPtr(slot),
- reader.FormatIntPtr(maybe_address))
- if heap_object:
- heap_object.Print(Printer())
- print
-
- reader.ForEachMemoryRegion(dump_region)
-
-# Set of structures and constants that describe the layout of minidump
-# files. Based on MSDN and Google Breakpad.
-
-MINIDUMP_HEADER = Descriptor([
- ("signature", ctypes.c_uint32),
- ("version", ctypes.c_uint32),
- ("stream_count", ctypes.c_uint32),
- ("stream_directories_rva", ctypes.c_uint32),
- ("checksum", ctypes.c_uint32),
- ("time_date_stampt", ctypes.c_uint32),
- ("flags", ctypes.c_uint64)
-])
-
-MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
- ("data_size", ctypes.c_uint32),
- ("rva", ctypes.c_uint32)
-])
-
-MINIDUMP_STRING = Descriptor([
- ("length", ctypes.c_uint32),
- ("buffer", lambda t: ctypes.c_uint8 * (t.length + 2))
-])
-
-MINIDUMP_DIRECTORY = Descriptor([
- ("stream_type", ctypes.c_uint32),
- ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
-])
-
-MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
-
-MINIDUMP_EXCEPTION = Descriptor([
- ("code", ctypes.c_uint32),
- ("flags", ctypes.c_uint32),
- ("record", ctypes.c_uint64),
- ("address", ctypes.c_uint64),
- ("parameter_count", ctypes.c_uint32),
- ("unused_alignment", ctypes.c_uint32),
- ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
-])
-
-MINIDUMP_EXCEPTION_STREAM = Descriptor([
- ("thread_id", ctypes.c_uint32),
- ("unused_alignment", ctypes.c_uint32),
- ("exception", MINIDUMP_EXCEPTION.ctype),
- ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
-])
-
-# Stream types.
-MD_UNUSED_STREAM = 0
-MD_RESERVED_STREAM_0 = 1
-MD_RESERVED_STREAM_1 = 2
-MD_THREAD_LIST_STREAM = 3
-MD_MODULE_LIST_STREAM = 4
-MD_MEMORY_LIST_STREAM = 5
-MD_EXCEPTION_STREAM = 6
-MD_SYSTEM_INFO_STREAM = 7
-MD_THREAD_EX_LIST_STREAM = 8
-MD_MEMORY_64_LIST_STREAM = 9
-MD_COMMENT_STREAM_A = 10
-MD_COMMENT_STREAM_W = 11
-MD_HANDLE_DATA_STREAM = 12
-MD_FUNCTION_TABLE_STREAM = 13
-MD_UNLOADED_MODULE_LIST_STREAM = 14
-MD_MISC_INFO_STREAM = 15
-MD_MEMORY_INFO_LIST_STREAM = 16
-MD_THREAD_INFO_LIST_STREAM = 17
-MD_HANDLE_OPERATION_LIST_STREAM = 18
-
-MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
-
-MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
- ("control_word", ctypes.c_uint32),
- ("status_word", ctypes.c_uint32),
- ("tag_word", ctypes.c_uint32),
- ("error_offset", ctypes.c_uint32),
- ("error_selector", ctypes.c_uint32),
- ("data_offset", ctypes.c_uint32),
- ("data_selector", ctypes.c_uint32),
- ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
- ("cr0_npx_state", ctypes.c_uint32)
-])
-
-MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
-
-# Context flags.
-MD_CONTEXT_X86 = 0x00010000
-MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
-MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
-MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
-MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
-MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
-MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
-
-def EnableOnFlag(type, flag):
- return lambda o: [None, type][int((o.context_flags & flag) != 0)]
-
-MINIDUMP_CONTEXT_X86 = Descriptor([
- ("context_flags", ctypes.c_uint32),
- # MD_CONTEXT_X86_DEBUG_REGISTERS.
- ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
- ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
- ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
- ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
- ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
- ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
- # MD_CONTEXT_X86_FLOATING_POINT.
- ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
- MD_CONTEXT_X86_FLOATING_POINT)),
- # MD_CONTEXT_X86_SEGMENTS.
- ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
- ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
- ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
- ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
- # MD_CONTEXT_X86_INTEGER.
- ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
- ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
- ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
- ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
- ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
- ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
- # MD_CONTEXT_X86_CONTROL.
- ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
- ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
- ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
- ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
- ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
- ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
- # MD_CONTEXT_X86_EXTENDED_REGISTERS.
- ("extended_registers",
- EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
- MD_CONTEXT_X86_EXTENDED_REGISTERS))
-])
-
-MD_CONTEXT_ARM = 0x40000000
-MD_CONTEXT_ARM_INTEGER = (MD_CONTEXT_ARM | 0x00000002)
-MD_CONTEXT_ARM_FLOATING_POINT = (MD_CONTEXT_ARM | 0x00000004)
-MD_FLOATINGSAVEAREA_ARM_FPR_COUNT = 32
-MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT = 8
-
-MINIDUMP_FLOATING_SAVE_AREA_ARM = Descriptor([
- ("fpscr", ctypes.c_uint64),
- ("regs", ctypes.c_uint64 * MD_FLOATINGSAVEAREA_ARM_FPR_COUNT),
- ("extra", ctypes.c_uint64 * MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT)
-])
-
-MINIDUMP_CONTEXT_ARM = Descriptor([
- ("context_flags", ctypes.c_uint32),
- # MD_CONTEXT_ARM_INTEGER.
- ("r0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r4", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r5", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r8", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r9", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r10", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r11", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("r12", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("sp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("lr", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("pc", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_ARM_INTEGER)),
- ("cpsr", ctypes.c_uint32),
- ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_ARM.ctype,
- MD_CONTEXT_ARM_FLOATING_POINT))
-])
-
-MD_CONTEXT_AMD64 = 0x00100000
-MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
-MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
-MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
-MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
-MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
-
-MINIDUMP_CONTEXT_AMD64 = Descriptor([
- ("p1_home", ctypes.c_uint64),
- ("p2_home", ctypes.c_uint64),
- ("p3_home", ctypes.c_uint64),
- ("p4_home", ctypes.c_uint64),
- ("p5_home", ctypes.c_uint64),
- ("p6_home", ctypes.c_uint64),
- ("context_flags", ctypes.c_uint32),
- ("mx_csr", ctypes.c_uint32),
- # MD_CONTEXT_AMD64_CONTROL.
- ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
- # MD_CONTEXT_AMD64_SEGMENTS
- ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
- ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
- ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
- ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
- # MD_CONTEXT_AMD64_CONTROL.
- ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
- ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
- # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
- ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- # MD_CONTEXT_AMD64_INTEGER.
- ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- # MD_CONTEXT_AMD64_CONTROL.
- ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
- # MD_CONTEXT_AMD64_INTEGER.
- ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
- # MD_CONTEXT_AMD64_CONTROL.
- ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
- # MD_CONTEXT_AMD64_FLOATING_POINT
- ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
- MD_CONTEXT_AMD64_FLOATING_POINT)),
- ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
- MD_CONTEXT_AMD64_FLOATING_POINT)),
- ("vector_control", EnableOnFlag(ctypes.c_uint64,
- MD_CONTEXT_AMD64_FLOATING_POINT)),
- # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
- ("debug_control", EnableOnFlag(ctypes.c_uint64,
- MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
- MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
- MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
- MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
- ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
- MD_CONTEXT_AMD64_DEBUG_REGISTERS))
-])
-
-MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
- ("start", ctypes.c_uint64),
- ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
-])
-
-MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
- ("start", ctypes.c_uint64),
- ("size", ctypes.c_uint64)
-])
-
-MINIDUMP_MEMORY_LIST = Descriptor([
- ("range_count", ctypes.c_uint32),
- ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
-])
-
-MINIDUMP_MEMORY_LIST64 = Descriptor([
- ("range_count", ctypes.c_uint64),
- ("base_rva", ctypes.c_uint64),
- ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
-])
-
-MINIDUMP_THREAD = Descriptor([
- ("id", ctypes.c_uint32),
- ("suspend_count", ctypes.c_uint32),
- ("priority_class", ctypes.c_uint32),
- ("priority", ctypes.c_uint32),
- ("ted", ctypes.c_uint64),
- ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
- ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
-])
-
-MINIDUMP_THREAD_LIST = Descriptor([
- ("thread_count", ctypes.c_uint32),
- ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
-])
-
-MINIDUMP_RAW_MODULE = Descriptor([
- ("base_of_image", ctypes.c_uint64),
- ("size_of_image", ctypes.c_uint32),
- ("checksum", ctypes.c_uint32),
- ("time_date_stamp", ctypes.c_uint32),
- ("module_name_rva", ctypes.c_uint32),
- ("version_info", ctypes.c_uint32 * 13),
- ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
- ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
- ("reserved0", ctypes.c_uint32 * 2),
- ("reserved1", ctypes.c_uint32 * 2)
-])
-
-MINIDUMP_MODULE_LIST = Descriptor([
- ("number_of_modules", ctypes.c_uint32),
- ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules)
-])
-
-MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
- ("processor_architecture", ctypes.c_uint16)
-])
-
-MD_CPU_ARCHITECTURE_X86 = 0
-MD_CPU_ARCHITECTURE_ARM = 5
-MD_CPU_ARCHITECTURE_AMD64 = 9
-
-class FuncSymbol:
- def __init__(self, start, size, name):
- self.start = start
- self.end = self.start + size
- self.name = name
-
- def __cmp__(self, other):
- if isinstance(other, FuncSymbol):
- return self.start - other.start
- return self.start - other
-
- def Covers(self, addr):
- return (self.start <= addr) and (addr < self.end)
-
-class MinidumpReader(object):
- """Minidump (.dmp) reader."""
-
- _HEADER_MAGIC = 0x504d444d
-
- def __init__(self, options, minidump_name):
- self.minidump_name = minidump_name
- self.minidump_file = open(minidump_name, "r")
- self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
- self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
- if self.header.signature != MinidumpReader._HEADER_MAGIC:
- print >>sys.stderr, "Warning: Unsupported minidump header magic!"
- DebugPrint(self.header)
- directories = []
- offset = self.header.stream_directories_rva
- for _ in xrange(self.header.stream_count):
- directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
- offset += MINIDUMP_DIRECTORY.size
- self.arch = None
- self.exception = None
- self.exception_context = None
- self.memory_list = None
- self.memory_list64 = None
- self.module_list = None
- self.thread_map = {}
-
- self.symdir = options.symdir
- self.modules_with_symbols = []
- self.symbols = []
-
- # Find MDRawSystemInfo stream and determine arch.
- for d in directories:
- if d.stream_type == MD_SYSTEM_INFO_STREAM:
- system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
- self.minidump, d.location.rva)
- self.arch = system_info.processor_architecture
- assert self.arch in [MD_CPU_ARCHITECTURE_AMD64,
- MD_CPU_ARCHITECTURE_ARM,
- MD_CPU_ARCHITECTURE_X86]
- assert not self.arch is None
-
- for d in directories:
- DebugPrint(d)
- if d.stream_type == MD_EXCEPTION_STREAM:
- self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
- self.minidump, d.location.rva)
- DebugPrint(self.exception)
- if self.arch == MD_CPU_ARCHITECTURE_X86:
- self.exception_context = MINIDUMP_CONTEXT_X86.Read(
- self.minidump, self.exception.thread_context.rva)
- elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
- self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
- self.minidump, self.exception.thread_context.rva)
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- self.exception_context = MINIDUMP_CONTEXT_ARM.Read(
- self.minidump, self.exception.thread_context.rva)
- DebugPrint(self.exception_context)
- elif d.stream_type == MD_THREAD_LIST_STREAM:
- thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
- assert ctypes.sizeof(thread_list) == d.location.data_size
- DebugPrint(thread_list)
- for thread in thread_list.threads:
- DebugPrint(thread)
- self.thread_map[thread.id] = thread
- elif d.stream_type == MD_MODULE_LIST_STREAM:
- assert self.module_list is None
- self.module_list = MINIDUMP_MODULE_LIST.Read(
- self.minidump, d.location.rva)
- assert ctypes.sizeof(self.module_list) == d.location.data_size
- elif d.stream_type == MD_MEMORY_LIST_STREAM:
- print >>sys.stderr, "Warning: This is not a full minidump!"
- assert self.memory_list is None
- self.memory_list = MINIDUMP_MEMORY_LIST.Read(
- self.minidump, d.location.rva)
- assert ctypes.sizeof(self.memory_list) == d.location.data_size
- DebugPrint(self.memory_list)
- elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
- assert self.memory_list64 is None
- self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read(
- self.minidump, d.location.rva)
- assert ctypes.sizeof(self.memory_list64) == d.location.data_size
- DebugPrint(self.memory_list64)
-
- def IsValidAddress(self, address):
- return self.FindLocation(address) is not None
-
- def ReadU8(self, address):
- location = self.FindLocation(address)
- return ctypes.c_uint8.from_buffer(self.minidump, location).value
-
- def ReadU32(self, address):
- location = self.FindLocation(address)
- return ctypes.c_uint32.from_buffer(self.minidump, location).value
-
- def ReadU64(self, address):
- location = self.FindLocation(address)
- return ctypes.c_uint64.from_buffer(self.minidump, location).value
-
- def ReadUIntPtr(self, address):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return self.ReadU64(address)
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return self.ReadU32(address)
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return self.ReadU32(address)
-
- def ReadBytes(self, address, size):
- location = self.FindLocation(address)
- return self.minidump[location:location + size]
-
- def _ReadWord(self, location):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return ctypes.c_uint64.from_buffer(self.minidump, location).value
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return ctypes.c_uint32.from_buffer(self.minidump, location).value
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return ctypes.c_uint32.from_buffer(self.minidump, location).value
-
- def IsProbableASCIIRegion(self, location, length):
- ascii_bytes = 0
- non_ascii_bytes = 0
- for loc in xrange(location, location + length):
- byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
- if byte >= 0x7f:
- non_ascii_bytes += 1
- if byte < 0x20 and byte != 0:
- non_ascii_bytes += 1
- if byte < 0x7f and byte >= 0x20:
- ascii_bytes += 1
- if byte == 0xa: # newline
- ascii_bytes += 1
- if ascii_bytes * 10 <= length:
- return False
- if length > 0 and ascii_bytes > non_ascii_bytes * 7:
- return True
- if ascii_bytes > non_ascii_bytes * 3:
- return None # Maybe
- return False
-
- def IsProbableExecutableRegion(self, location, length):
- opcode_bytes = 0
- sixty_four = self.arch == MD_CPU_ARCHITECTURE_AMD64
- for loc in xrange(location, location + length):
- byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
- if (byte == 0x8b or # mov
- byte == 0x89 or # mov reg-reg
- (byte & 0xf0) == 0x50 or # push/pop
- (sixty_four and (byte & 0xf0) == 0x40) or # rex prefix
- byte == 0xc3 or # return
- byte == 0x74 or # jeq
- byte == 0x84 or # jeq far
- byte == 0x75 or # jne
- byte == 0x85 or # jne far
- byte == 0xe8 or # call
- byte == 0xe9 or # jmp far
- byte == 0xeb): # jmp near
- opcode_bytes += 1
- opcode_percent = (opcode_bytes * 100) / length
- threshold = 20
- if opcode_percent > threshold + 2:
- return True
- if opcode_percent > threshold - 2:
- return None # Maybe
- return False
-
- def FindRegion(self, addr):
- answer = [-1, -1]
- def is_in(reader, start, size, location):
- if addr >= start and addr < start + size:
- answer[0] = start
- answer[1] = size
- self.ForEachMemoryRegion(is_in)
- if answer[0] == -1:
- return None
- return answer
-
- def ForEachMemoryRegion(self, cb):
- if self.memory_list64 is not None:
- for r in self.memory_list64.ranges:
- location = self.memory_list64.base_rva + offset
- cb(self, r.start, r.size, location)
- offset += r.size
-
- if self.memory_list is not None:
- for r in self.memory_list.ranges:
- cb(self, r.start, r.memory.data_size, r.memory.rva)
-
- def FindWord(self, word, alignment=0):
- def search_inside_region(reader, start, size, location):
- location = (location + alignment) & ~alignment
- for loc in xrange(location, location + size - self.PointerSize()):
- if reader._ReadWord(loc) == word:
- slot = start + (loc - location)
- print "%s: %s" % (reader.FormatIntPtr(slot),
- reader.FormatIntPtr(word))
- self.ForEachMemoryRegion(search_inside_region)
-
- def FindLocation(self, address):
- offset = 0
- if self.memory_list64 is not None:
- for r in self.memory_list64.ranges:
- if r.start <= address < r.start + r.size:
- return self.memory_list64.base_rva + offset + address - r.start
- offset += r.size
- if self.memory_list is not None:
- for r in self.memory_list.ranges:
- if r.start <= address < r.start + r.memory.data_size:
- return r.memory.rva + address - r.start
- return None
-
- def GetDisasmLines(self, address, size):
- def CountUndefinedInstructions(lines):
- pattern = "<UNDEFINED>"
- return sum([line.count(pattern) for (ignore, line) in lines])
-
- location = self.FindLocation(address)
- if location is None: return []
- arch = None
- possible_objdump_flags = [""]
- if self.arch == MD_CPU_ARCHITECTURE_X86:
- arch = "ia32"
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- arch = "arm"
- possible_objdump_flags = ["", "--disassembler-options=force-thumb"]
- elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
- arch = "x64"
- results = [ disasm.GetDisasmLines(self.minidump_name,
- location,
- size,
- arch,
- False,
- objdump_flags)
- for objdump_flags in possible_objdump_flags ]
- return min(results, key=CountUndefinedInstructions)
-
-
- def Dispose(self):
- self.minidump.close()
- self.minidump_file.close()
-
- def ExceptionIP(self):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return self.exception_context.rip
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return self.exception_context.pc
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return self.exception_context.eip
-
- def ExceptionSP(self):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return self.exception_context.rsp
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return self.exception_context.sp
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return self.exception_context.esp
-
- def FormatIntPtr(self, value):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return "%016x" % value
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return "%08x" % value
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return "%08x" % value
-
- def PointerSize(self):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return 8
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return 4
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return 4
-
- def Register(self, name):
- return self.exception_context.__getattribute__(name)
-
- def ReadMinidumpString(self, rva):
- string = bytearray(MINIDUMP_STRING.Read(self.minidump, rva).buffer)
- string = string.decode("utf16")
- return string[0:len(string) - 1]
-
- # Load FUNC records from a BreakPad symbol file
- #
- # http://code.google.com/p/google-breakpad/wiki/SymbolFiles
- #
- def _LoadSymbolsFrom(self, symfile, baseaddr):
- print "Loading symbols from %s" % (symfile)
- funcs = []
- with open(symfile) as f:
- for line in f:
- result = re.match(
- r"^FUNC ([a-f0-9]+) ([a-f0-9]+) ([a-f0-9]+) (.*)$", line)
- if result is not None:
- start = int(result.group(1), 16)
- size = int(result.group(2), 16)
- name = result.group(4).rstrip()
- bisect.insort_left(self.symbols,
- FuncSymbol(baseaddr + start, size, name))
- print " ... done"
-
- def TryLoadSymbolsFor(self, modulename, module):
- try:
- symfile = os.path.join(self.symdir,
- modulename.replace('.', '_') + ".pdb.sym")
- self._LoadSymbolsFrom(symfile, module.base_of_image)
- self.modules_with_symbols.append(module)
- except Exception as e:
- print " ... failure (%s)" % (e)
-
- # Returns true if address is covered by some module that has loaded symbols.
- def _IsInModuleWithSymbols(self, addr):
- for module in self.modules_with_symbols:
- start = module.base_of_image
- end = start + module.size_of_image
- if (start <= addr) and (addr < end):
- return True
- return False
-
- # Find symbol covering the given address and return its name in format
- # <symbol name>+<offset from the start>
- def FindSymbol(self, addr):
- if not self._IsInModuleWithSymbols(addr):
- return None
-
- i = bisect.bisect_left(self.symbols, addr)
- symbol = None
- if (0 < i) and self.symbols[i - 1].Covers(addr):
- symbol = self.symbols[i - 1]
- elif (i < len(self.symbols)) and self.symbols[i].Covers(addr):
- symbol = self.symbols[i]
- else:
- return None
- diff = addr - symbol.start
- return "%s+0x%x" % (symbol.name, diff)
-
-
-
-# List of V8 instance types. Obtained by adding the code below to any .cc file.
-#
-# #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T);
-# struct P {
-# P() {
-# printf("INSTANCE_TYPES = {\n");
-# INSTANCE_TYPE_LIST(DUMP_TYPE)
-# printf("}\n");
-# }
-# };
-# static P p;
-INSTANCE_TYPES = {
- 64: "SYMBOL_TYPE",
- 68: "ASCII_SYMBOL_TYPE",
- 65: "CONS_SYMBOL_TYPE",
- 69: "CONS_ASCII_SYMBOL_TYPE",
- 66: "EXTERNAL_SYMBOL_TYPE",
- 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
- 70: "EXTERNAL_ASCII_SYMBOL_TYPE",
- 82: "SHORT_EXTERNAL_SYMBOL_TYPE",
- 90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
- 86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE",
- 0: "STRING_TYPE",
- 4: "ASCII_STRING_TYPE",
- 1: "CONS_STRING_TYPE",
- 5: "CONS_ASCII_STRING_TYPE",
- 3: "SLICED_STRING_TYPE",
- 2: "EXTERNAL_STRING_TYPE",
- 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
- 6: "EXTERNAL_ASCII_STRING_TYPE",
- 18: "SHORT_EXTERNAL_STRING_TYPE",
- 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
- 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE",
- 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE",
- 128: "MAP_TYPE",
- 129: "CODE_TYPE",
- 130: "ODDBALL_TYPE",
- 131: "JS_GLOBAL_PROPERTY_CELL_TYPE",
- 132: "HEAP_NUMBER_TYPE",
- 133: "FOREIGN_TYPE",
- 134: "BYTE_ARRAY_TYPE",
- 135: "FREE_SPACE_TYPE",
- 136: "EXTERNAL_BYTE_ARRAY_TYPE",
- 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
- 138: "EXTERNAL_SHORT_ARRAY_TYPE",
- 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
- 140: "EXTERNAL_INT_ARRAY_TYPE",
- 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
- 142: "EXTERNAL_FLOAT_ARRAY_TYPE",
- 144: "EXTERNAL_PIXEL_ARRAY_TYPE",
- 146: "FILLER_TYPE",
- 147: "DECLARED_ACCESSOR_DESCRIPTOR_TYPE",
- 148: "DECLARED_ACCESSOR_INFO_TYPE",
- 149: "EXECUTABLE_ACCESSOR_INFO_TYPE",
- 150: "ACCESSOR_PAIR_TYPE",
- 151: "ACCESS_CHECK_INFO_TYPE",
- 152: "INTERCEPTOR_INFO_TYPE",
- 153: "CALL_HANDLER_INFO_TYPE",
- 154: "FUNCTION_TEMPLATE_INFO_TYPE",
- 155: "OBJECT_TEMPLATE_INFO_TYPE",
- 156: "SIGNATURE_INFO_TYPE",
- 157: "TYPE_SWITCH_INFO_TYPE",
- 158: "ALLOCATION_SITE_INFO_TYPE",
- 159: "SCRIPT_TYPE",
- 160: "CODE_CACHE_TYPE",
- 161: "POLYMORPHIC_CODE_CACHE_TYPE",
- 162: "TYPE_FEEDBACK_INFO_TYPE",
- 163: "ALIASED_ARGUMENTS_ENTRY_TYPE",
- 166: "FIXED_ARRAY_TYPE",
- 145: "FIXED_DOUBLE_ARRAY_TYPE",
- 167: "SHARED_FUNCTION_INFO_TYPE",
- 168: "JS_MESSAGE_OBJECT_TYPE",
- 171: "JS_VALUE_TYPE",
- 172: "JS_DATE_TYPE",
- 173: "JS_OBJECT_TYPE",
- 174: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
- 175: "JS_MODULE_TYPE",
- 176: "JS_GLOBAL_OBJECT_TYPE",
- 177: "JS_BUILTINS_OBJECT_TYPE",
- 178: "JS_GLOBAL_PROXY_TYPE",
- 179: "JS_ARRAY_TYPE",
- 170: "JS_PROXY_TYPE",
- 182: "JS_WEAK_MAP_TYPE",
- 183: "JS_REGEXP_TYPE",
- 184: "JS_FUNCTION_TYPE",
- 169: "JS_FUNCTION_PROXY_TYPE",
- 164: "DEBUG_INFO_TYPE",
- 165: "BREAK_POINT_INFO_TYPE",
-}
-
-
-# List of known V8 maps. Used to determine the instance type and name
-# for maps that are part of the root-set and hence on the first page of
-# the map-space. Obtained by adding the code below to an IA32 release
-# build with enabled snapshots to the end of the Isolate::Init method.
-#
-# #define ROOT_LIST_CASE(type, name, camel_name) \
-# if (o == heap_.name()) n = #camel_name;
-# #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
-# if (o == heap_.name##_map()) n = #camel_name "Map";
-# HeapObjectIterator it(heap_.map_space());
-# printf("KNOWN_MAPS = {\n");
-# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
-# Map* m = Map::cast(o);
-# const char* n = "";
-# intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
-# int t = m->instance_type();
-# ROOT_LIST(ROOT_LIST_CASE)
-# STRUCT_LIST(STRUCT_LIST_CASE)
-# printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n);
-# }
-# printf("}\n");
-KNOWN_MAPS = {
- 0x08081: (134, "ByteArrayMap"),
- 0x080a9: (128, "MetaMap"),
- 0x080d1: (130, "OddballMap"),
- 0x080f9: (68, "AsciiSymbolMap"),
- 0x08121: (166, "FixedArrayMap"),
- 0x08149: (132, "HeapNumberMap"),
- 0x08171: (135, "FreeSpaceMap"),
- 0x08199: (146, "OnePointerFillerMap"),
- 0x081c1: (146, "TwoPointerFillerMap"),
- 0x081e9: (131, "GlobalPropertyCellMap"),
- 0x08211: (167, "SharedFunctionInfoMap"),
- 0x08239: (4, "AsciiStringMap"),
- 0x08261: (166, "NativeContextMap"),
- 0x08289: (129, "CodeMap"),
- 0x082b1: (166, "ScopeInfoMap"),
- 0x082d9: (166, "FixedCOWArrayMap"),
- 0x08301: (145, "FixedDoubleArrayMap"),
- 0x08329: (166, "HashTableMap"),
- 0x08351: (0, "StringMap"),
- 0x08379: (64, "SymbolMap"),
- 0x083a1: (1, "ConsStringMap"),
- 0x083c9: (5, "ConsAsciiStringMap"),
- 0x083f1: (3, "SlicedStringMap"),
- 0x08419: (7, "SlicedAsciiStringMap"),
- 0x08441: (65, "ConsSymbolMap"),
- 0x08469: (69, "ConsAsciiSymbolMap"),
- 0x08491: (66, "ExternalSymbolMap"),
- 0x084b9: (74, "ExternalSymbolWithAsciiDataMap"),
- 0x084e1: (70, "ExternalAsciiSymbolMap"),
- 0x08509: (2, "ExternalStringMap"),
- 0x08531: (10, "ExternalStringWithAsciiDataMap"),
- 0x08559: (6, "ExternalAsciiStringMap"),
- 0x08581: (82, "ShortExternalSymbolMap"),
- 0x085a9: (90, "ShortExternalSymbolWithAsciiDataMap"),
- 0x085d1: (86, "ShortExternalAsciiSymbolMap"),
- 0x085f9: (18, "ShortExternalStringMap"),
- 0x08621: (26, "ShortExternalStringWithAsciiDataMap"),
- 0x08649: (22, "ShortExternalAsciiStringMap"),
- 0x08671: (0, "UndetectableStringMap"),
- 0x08699: (4, "UndetectableAsciiStringMap"),
- 0x086c1: (144, "ExternalPixelArrayMap"),
- 0x086e9: (136, "ExternalByteArrayMap"),
- 0x08711: (137, "ExternalUnsignedByteArrayMap"),
- 0x08739: (138, "ExternalShortArrayMap"),
- 0x08761: (139, "ExternalUnsignedShortArrayMap"),
- 0x08789: (140, "ExternalIntArrayMap"),
- 0x087b1: (141, "ExternalUnsignedIntArrayMap"),
- 0x087d9: (142, "ExternalFloatArrayMap"),
- 0x08801: (143, "ExternalDoubleArrayMap"),
- 0x08829: (166, "NonStrictArgumentsElementsMap"),
- 0x08851: (166, "FunctionContextMap"),
- 0x08879: (166, "CatchContextMap"),
- 0x088a1: (166, "WithContextMap"),
- 0x088c9: (166, "BlockContextMap"),
- 0x088f1: (166, "ModuleContextMap"),
- 0x08919: (166, "GlobalContextMap"),
- 0x08941: (168, "JSMessageObjectMap"),
- 0x08969: (133, "ForeignMap"),
- 0x08991: (173, "NeanderMap"),
- 0x089b9: (158, "AllocationSiteInfoMap"),
- 0x089e1: (161, "PolymorphicCodeCacheMap"),
- 0x08a09: (159, "ScriptMap"),
- 0x08a31: (173, ""),
- 0x08a59: (173, "ExternalMap"),
- 0x08a81: (147, "DeclaredAccessorDescriptorMap"),
- 0x08aa9: (148, "DeclaredAccessorInfoMap"),
- 0x08ad1: (149, "ExecutableAccessorInfoMap"),
- 0x08af9: (150, "AccessorPairMap"),
- 0x08b21: (151, "AccessCheckInfoMap"),
- 0x08b49: (152, "InterceptorInfoMap"),
- 0x08b71: (153, "CallHandlerInfoMap"),
- 0x08b99: (154, "FunctionTemplateInfoMap"),
- 0x08bc1: (155, "ObjectTemplateInfoMap"),
- 0x08be9: (156, "SignatureInfoMap"),
- 0x08c11: (157, "TypeSwitchInfoMap"),
- 0x08c39: (160, "CodeCacheMap"),
- 0x08c61: (162, "TypeFeedbackInfoMap"),
- 0x08c89: (163, "AliasedArgumentsEntryMap"),
- 0x08cb1: (164, "DebugInfoMap"),
- 0x08cd9: (165, "BreakPointInfoMap"),
-}
-
-
-# List of known V8 objects. Used to determine name for objects that are
-# part of the root-set and hence on the first page of various old-space
-# paged. Obtained by adding the code below to an IA32 release build with
-# enabled snapshots to the end of the Isolate::Init method.
-#
-# #define ROOT_LIST_CASE(type, name, camel_name) \
-# if (o == heap_.name()) n = #camel_name;
-# OldSpaces spit(heap());
-# printf("KNOWN_OBJECTS = {\n");
-# for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
-# HeapObjectIterator it(s);
-# const char* sname = AllocationSpaceName(s->identity());
-# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
-# const char* n = NULL;
-# intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
-# ROOT_LIST(ROOT_LIST_CASE)
-# if (n != NULL) {
-# printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n);
-# }
-# }
-# }
-# printf("}\n");
-KNOWN_OBJECTS = {
- ("OLD_POINTER_SPACE", 0x08081): "NullValue",
- ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue",
- ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap",
- ("OLD_POINTER_SPACE", 0x080b1): "TrueValue",
- ("OLD_POINTER_SPACE", 0x080c1): "FalseValue",
- ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel",
- ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker",
- ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache",
- ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache",
- ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache",
- ("OLD_POINTER_SPACE", 0x08f09): "RegExpMultipleCache",
- ("OLD_POINTER_SPACE", 0x09311): "TerminationException",
- ("OLD_POINTER_SPACE", 0x09321): "MessageListeners",
- ("OLD_POINTER_SPACE", 0x0933d): "CodeStubs",
- ("OLD_POINTER_SPACE", 0x09fa5): "NonMonomorphicCache",
- ("OLD_POINTER_SPACE", 0x0a5b9): "PolymorphicCodeCache",
- ("OLD_POINTER_SPACE", 0x0a5c1): "NativesSourceCache",
- ("OLD_POINTER_SPACE", 0x0a601): "EmptyScript",
- ("OLD_POINTER_SPACE", 0x0a63d): "IntrinsicFunctionNames",
- ("OLD_POINTER_SPACE", 0x0d659): "ObservationState",
- ("OLD_POINTER_SPACE", 0x27415): "SymbolTable",
- ("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray",
- ("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray",
- ("OLD_DATA_SPACE", 0x080a9): "NanValue",
- ("OLD_DATA_SPACE", 0x08125): "EmptyByteArray",
- ("OLD_DATA_SPACE", 0x0812d): "EmptyString",
- ("OLD_DATA_SPACE", 0x08259): "InfinityValue",
- ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue",
- ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors",
- ("CODE_SPACE", 0x0aea1): "JsEntryCode",
- ("CODE_SPACE", 0x0b5c1): "JsConstructEntryCode",
-}
-
-
-class Printer(object):
- """Printer with indentation support."""
-
- def __init__(self):
- self.indent = 0
-
- def Indent(self):
- self.indent += 2
-
- def Dedent(self):
- self.indent -= 2
-
- def Print(self, string):
- print "%s%s" % (self._IndentString(), string)
-
- def PrintLines(self, lines):
- indent = self._IndentString()
- print "\n".join("%s%s" % (indent, line) for line in lines)
-
- def _IndentString(self):
- return self.indent * " "
-
-
-ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
-
-
-def FormatDisasmLine(start, heap, line):
- line_address = start + line[0]
- stack_slot = heap.stack_map.get(line_address)
- marker = " "
- if stack_slot:
- marker = "=>"
- code = AnnotateAddresses(heap, line[1])
- return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
-
-
-def AnnotateAddresses(heap, line):
- extra = []
- for m in ADDRESS_RE.finditer(line):
- maybe_address = int(m.group(0), 16)
- object = heap.FindObject(maybe_address)
- if not object: continue
- extra.append(str(object))
- if len(extra) == 0: return line
- return "%s ;; %s" % (line, ", ".join(extra))
-
-
-class HeapObject(object):
- def __init__(self, heap, map, address):
- self.heap = heap
- self.map = map
- self.address = address
-
- def Is(self, cls):
- return isinstance(self, cls)
-
- def Print(self, p):
- p.Print(str(self))
-
- def __str__(self):
- return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
- INSTANCE_TYPES[self.map.instance_type])
-
- def ObjectField(self, offset):
- field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
- return self.heap.FindObjectOrSmi(field_value)
-
- def SmiField(self, offset):
- field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
- assert (field_value & 1) == 0
- return field_value / 2
-
-
-class Map(HeapObject):
- def InstanceTypeOffset(self):
- return self.heap.PointerSize() + self.heap.IntSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.instance_type = \
- heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
-
-
-class String(HeapObject):
- def LengthOffset(self):
- return self.heap.PointerSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.length = self.SmiField(self.LengthOffset())
-
- def GetChars(self):
- return "?string?"
-
- def Print(self, p):
- p.Print(str(self))
-
- def __str__(self):
- return "\"%s\"" % self.GetChars()
-
-
-class SeqString(String):
- def CharsOffset(self):
- return self.heap.PointerSize() * 3
-
- def __init__(self, heap, map, address):
- String.__init__(self, heap, map, address)
- self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
- self.length)
-
- def GetChars(self):
- return self.chars
-
-
-class ExternalString(String):
- # TODO(vegorov) fix ExternalString for X64 architecture
- RESOURCE_OFFSET = 12
-
- WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
- WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
-
- def __init__(self, heap, map, address):
- String.__init__(self, heap, map, address)
- reader = heap.reader
- self.resource = \
- reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
- self.chars = "?external string?"
- if not reader.IsValidAddress(self.resource): return
- string_impl_address = self.resource + \
- ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
- if not reader.IsValidAddress(string_impl_address): return
- string_impl = reader.ReadU32(string_impl_address)
- chars_ptr_address = string_impl + \
- ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
- if not reader.IsValidAddress(chars_ptr_address): return
- chars_ptr = reader.ReadU32(chars_ptr_address)
- if not reader.IsValidAddress(chars_ptr): return
- raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
- self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
-
- def GetChars(self):
- return self.chars
-
-
-class ConsString(String):
- def LeftOffset(self):
- return self.heap.PointerSize() * 3
-
- def RightOffset(self):
- return self.heap.PointerSize() * 4
-
- def __init__(self, heap, map, address):
- String.__init__(self, heap, map, address)
- self.left = self.ObjectField(self.LeftOffset())
- self.right = self.ObjectField(self.RightOffset())
-
- def GetChars(self):
- try:
- return self.left.GetChars() + self.right.GetChars()
- except:
- return "***CAUGHT EXCEPTION IN GROKDUMP***"
-
-
-class Oddball(HeapObject):
- # Should match declarations in objects.h
- KINDS = [
- "False",
- "True",
- "TheHole",
- "Null",
- "ArgumentMarker",
- "Undefined",
- "Other"
- ]
-
- def ToStringOffset(self):
- return self.heap.PointerSize()
-
- def ToNumberOffset(self):
- return self.ToStringOffset() + self.heap.PointerSize()
-
- def KindOffset(self):
- return self.ToNumberOffset() + self.heap.PointerSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.to_string = self.ObjectField(self.ToStringOffset())
- self.kind = self.SmiField(self.KindOffset())
-
- def Print(self, p):
- p.Print(str(self))
-
- def __str__(self):
- if self.to_string:
- return "Oddball(%08x, <%s>)" % (self.address, self.to_string.GetChars())
- else:
- kind = "???"
- if 0 <= self.kind < len(Oddball.KINDS):
- kind = Oddball.KINDS[self.kind]
- return "Oddball(%08x, kind=%s)" % (self.address, kind)
-
-
-class FixedArray(HeapObject):
- def LengthOffset(self):
- return self.heap.PointerSize()
-
- def ElementsOffset(self):
- return self.heap.PointerSize() * 2
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.length = self.SmiField(self.LengthOffset())
-
- def Print(self, p):
- p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
- p.Indent()
- p.Print("length: %d" % self.length)
- base_offset = self.ElementsOffset()
- for i in xrange(self.length):
- offset = base_offset + 4 * i
- try:
- p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
- except TypeError:
- p.Dedent()
- p.Print("...")
- p.Print("}")
- return
- p.Dedent()
- p.Print("}")
-
- def __str__(self):
- return "FixedArray(%08x, length=%d)" % (self.address, self.length)
-
-
-class JSFunction(HeapObject):
- def CodeEntryOffset(self):
- return 3 * self.heap.PointerSize()
-
- def SharedOffset(self):
- return 5 * self.heap.PointerSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- code_entry = \
- heap.reader.ReadU32(self.address + self.CodeEntryOffset())
- self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
- self.shared = self.ObjectField(self.SharedOffset())
-
- def Print(self, p):
- source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
- p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
- p.Indent()
- p.Print("inferred name: %s" % self.shared.inferred_name)
- if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
- p.Print("script name: %s" % self.shared.script.name)
- p.Print("source:")
- p.PrintLines(self._GetSource().split("\n"))
- p.Print("code:")
- self.code.Print(p)
- if self.code != self.shared.code:
- p.Print("unoptimized code:")
- self.shared.code.Print(p)
- p.Dedent()
- p.Print("}")
-
- def __str__(self):
- inferred_name = ""
- if self.shared.Is(SharedFunctionInfo):
- inferred_name = self.shared.inferred_name
- return "JSFunction(%s, %s)" % \
- (self.heap.reader.FormatIntPtr(self.address), inferred_name)
-
- def _GetSource(self):
- source = "?source?"
- start = self.shared.start_position
- end = self.shared.end_position
- if not self.shared.script.Is(Script): return source
- script_source = self.shared.script.source
- if not script_source.Is(String): return source
- return script_source.GetChars()[start:end]
-
-
-class SharedFunctionInfo(HeapObject):
- def CodeOffset(self):
- return 2 * self.heap.PointerSize()
-
- def ScriptOffset(self):
- return 7 * self.heap.PointerSize()
-
- def InferredNameOffset(self):
- return 9 * self.heap.PointerSize()
-
- def EndPositionOffset(self):
- return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
-
- def StartPositionAndTypeOffset(self):
- return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.code = self.ObjectField(self.CodeOffset())
- self.script = self.ObjectField(self.ScriptOffset())
- self.inferred_name = self.ObjectField(self.InferredNameOffset())
- if heap.PointerSize() == 8:
- start_position_and_type = \
- heap.reader.ReadU32(self.StartPositionAndTypeOffset())
- self.start_position = start_position_and_type >> 2
- pseudo_smi_end_position = \
- heap.reader.ReadU32(self.EndPositionOffset())
- self.end_position = pseudo_smi_end_position >> 2
- else:
- start_position_and_type = \
- self.SmiField(self.StartPositionAndTypeOffset())
- self.start_position = start_position_and_type >> 2
- self.end_position = \
- self.SmiField(self.EndPositionOffset())
-
-
-class Script(HeapObject):
- def SourceOffset(self):
- return self.heap.PointerSize()
-
- def NameOffset(self):
- return self.SourceOffset() + self.heap.PointerSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.source = self.ObjectField(self.SourceOffset())
- self.name = self.ObjectField(self.NameOffset())
-
-
-class CodeCache(HeapObject):
- def DefaultCacheOffset(self):
- return self.heap.PointerSize()
-
- def NormalTypeCacheOffset(self):
- return self.DefaultCacheOffset() + self.heap.PointerSize()
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.default_cache = self.ObjectField(self.DefaultCacheOffset())
- self.normal_type_cache = self.ObjectField(self.NormalTypeCacheOffset())
-
- def Print(self, p):
- p.Print("CodeCache(%s) {" % self.heap.reader.FormatIntPtr(self.address))
- p.Indent()
- p.Print("default cache: %s" % self.default_cache)
- p.Print("normal type cache: %s" % self.normal_type_cache)
- p.Dedent()
- p.Print("}")
-
-
-class Code(HeapObject):
- CODE_ALIGNMENT_MASK = (1 << 5) - 1
-
- def InstructionSizeOffset(self):
- return self.heap.PointerSize()
-
- @staticmethod
- def HeaderSize(heap):
- return (heap.PointerSize() + heap.IntSize() + \
- 4 * heap.PointerSize() + 3 * heap.IntSize() + \
- Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
-
- def __init__(self, heap, map, address):
- HeapObject.__init__(self, heap, map, address)
- self.entry = self.address + Code.HeaderSize(heap)
- self.instruction_size = \
- heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
-
- def Print(self, p):
- lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
- p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
- p.Indent()
- p.Print("instruction_size: %d" % self.instruction_size)
- p.PrintLines(self._FormatLine(line) for line in lines)
- p.Dedent()
- p.Print("}")
-
- def _FormatLine(self, line):
- return FormatDisasmLine(self.entry, self.heap, line)
-
-
-class V8Heap(object):
- CLASS_MAP = {
- "SYMBOL_TYPE": SeqString,
- "ASCII_SYMBOL_TYPE": SeqString,
- "CONS_SYMBOL_TYPE": ConsString,
- "CONS_ASCII_SYMBOL_TYPE": ConsString,
- "EXTERNAL_SYMBOL_TYPE": ExternalString,
- "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
- "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
- "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString,
- "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
- "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
- "STRING_TYPE": SeqString,
- "ASCII_STRING_TYPE": SeqString,
- "CONS_STRING_TYPE": ConsString,
- "CONS_ASCII_STRING_TYPE": ConsString,
- "EXTERNAL_STRING_TYPE": ExternalString,
- "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
- "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
- "MAP_TYPE": Map,
- "ODDBALL_TYPE": Oddball,
- "FIXED_ARRAY_TYPE": FixedArray,
- "JS_FUNCTION_TYPE": JSFunction,
- "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
- "SCRIPT_TYPE": Script,
- "CODE_CACHE_TYPE": CodeCache,
- "CODE_TYPE": Code,
- }
-
- def __init__(self, reader, stack_map):
- self.reader = reader
- self.stack_map = stack_map
- self.objects = {}
-
- def FindObjectOrSmi(self, tagged_address):
- if (tagged_address & 1) == 0: return tagged_address / 2
- return self.FindObject(tagged_address)
-
- def FindObject(self, tagged_address):
- if tagged_address in self.objects:
- return self.objects[tagged_address]
- if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
- address = tagged_address - 1
- if not self.reader.IsValidAddress(address): return None
- map_tagged_address = self.reader.ReadUIntPtr(address)
- if tagged_address == map_tagged_address:
- # Meta map?
- meta_map = Map(self, None, address)
- instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
- if instance_type_name != "MAP_TYPE": return None
- meta_map.map = meta_map
- object = meta_map
- else:
- map = self.FindMap(map_tagged_address)
- if map is None: return None
- instance_type_name = INSTANCE_TYPES.get(map.instance_type)
- if instance_type_name is None: return None
- cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
- object = cls(self, map, address)
- self.objects[tagged_address] = object
- return object
-
- def FindMap(self, tagged_address):
- if (tagged_address & self.MapAlignmentMask()) != 1: return None
- address = tagged_address - 1
- if not self.reader.IsValidAddress(address): return None
- object = Map(self, None, address)
- return object
-
- def IntSize(self):
- return 4
-
- def PointerSize(self):
- return self.reader.PointerSize()
-
- def ObjectAlignmentMask(self):
- return self.PointerSize() - 1
-
- def MapAlignmentMask(self):
- if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
- return (1 << 4) - 1
- elif self.reader.arch == MD_CPU_ARCHITECTURE_ARM:
- return (1 << 4) - 1
- elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
- return (1 << 5) - 1
-
- def PageAlignmentMask(self):
- return (1 << 20) - 1
-
-
-class KnownObject(HeapObject):
- def __init__(self, heap, known_name):
- HeapObject.__init__(self, heap, None, None)
- self.known_name = known_name
-
- def __str__(self):
- return "<%s>" % self.known_name
-
-
-class KnownMap(HeapObject):
- def __init__(self, heap, known_name, instance_type):
- HeapObject.__init__(self, heap, None, None)
- self.instance_type = instance_type
- self.known_name = known_name
-
- def __str__(self):
- return "<%s>" % self.known_name
-
-
-class InspectionPadawan(object):
- """The padawan can improve annotations by sensing well-known objects."""
- def __init__(self, reader, heap):
- self.reader = reader
- self.heap = heap
- self.known_first_map_page = 0
- self.known_first_data_page = 0
- self.known_first_pointer_page = 0
-
- def __getattr__(self, name):
- """An InspectionPadawan can be used instead of V8Heap, even though
- it does not inherit from V8Heap (aka. mixin)."""
- return getattr(self.heap, name)
-
- def GetPageOffset(self, tagged_address):
- return tagged_address & self.heap.PageAlignmentMask()
-
- def IsInKnownMapSpace(self, tagged_address):
- page_address = tagged_address & ~self.heap.PageAlignmentMask()
- return page_address == self.known_first_map_page
-
- def IsInKnownOldSpace(self, tagged_address):
- page_address = tagged_address & ~self.heap.PageAlignmentMask()
- return page_address in [self.known_first_data_page,
- self.known_first_pointer_page]
-
- def ContainingKnownOldSpaceName(self, tagged_address):
- page_address = tagged_address & ~self.heap.PageAlignmentMask()
- if page_address == self.known_first_data_page: return "OLD_DATA_SPACE"
- if page_address == self.known_first_pointer_page: return "OLD_POINTER_SPACE"
- return None
-
- def SenseObject(self, tagged_address):
- if self.IsInKnownOldSpace(tagged_address):
- offset = self.GetPageOffset(tagged_address)
- lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset)
- known_obj_name = KNOWN_OBJECTS.get(lookup_key)
- if known_obj_name:
- return KnownObject(self, known_obj_name)
- if self.IsInKnownMapSpace(tagged_address):
- known_map = self.SenseMap(tagged_address)
- if known_map:
- return known_map
- found_obj = self.heap.FindObject(tagged_address)
- if found_obj: return found_obj
- address = tagged_address - 1
- if self.reader.IsValidAddress(address):
- map_tagged_address = self.reader.ReadUIntPtr(address)
- map = self.SenseMap(map_tagged_address)
- if map is None: return None
- instance_type_name = INSTANCE_TYPES.get(map.instance_type)
- if instance_type_name is None: return None
- cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
- return cls(self, map, address)
- return None
-
- def SenseMap(self, tagged_address):
- if self.IsInKnownMapSpace(tagged_address):
- offset = self.GetPageOffset(tagged_address)
- known_map_info = KNOWN_MAPS.get(offset)
- if known_map_info:
- known_map_type, known_map_name = known_map_info
- return KnownMap(self, known_map_name, known_map_type)
- found_map = self.heap.FindMap(tagged_address)
- if found_map: return found_map
- return None
-
- def FindObjectOrSmi(self, tagged_address):
- """When used as a mixin in place of V8Heap."""
- found_obj = self.SenseObject(tagged_address)
- if found_obj: return found_obj
- if (tagged_address & 1) == 0:
- return "Smi(%d)" % (tagged_address / 2)
- else:
- return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address)
-
- def FindObject(self, tagged_address):
- """When used as a mixin in place of V8Heap."""
- raise NotImplementedError
-
- def FindMap(self, tagged_address):
- """When used as a mixin in place of V8Heap."""
- raise NotImplementedError
-
- def PrintKnowledge(self):
- print " known_first_map_page = %s\n"\
- " known_first_data_page = %s\n"\
- " known_first_pointer_page = %s" % (
- self.reader.FormatIntPtr(self.known_first_map_page),
- self.reader.FormatIntPtr(self.known_first_data_page),
- self.reader.FormatIntPtr(self.known_first_pointer_page))
-
-
-class InspectionShell(cmd.Cmd):
- def __init__(self, reader, heap):
- cmd.Cmd.__init__(self)
- self.reader = reader
- self.heap = heap
- self.padawan = InspectionPadawan(reader, heap)
- self.prompt = "(grok) "
-
- def do_da(self, address):
- """
- Print ASCII string starting at specified address.
- """
- address = int(address, 16)
- string = ""
- while self.reader.IsValidAddress(address):
- code = self.reader.ReadU8(address)
- if code < 128:
- string += chr(code)
- else:
- break
- address += 1
- if string == "":
- print "Not an ASCII string at %s" % self.reader.FormatIntPtr(address)
- else:
- print "%s\n" % string
-
- def do_dd(self, address):
- """
- Interpret memory at the given address (if available) as a sequence
- of words. Automatic alignment is not performed.
- """
- start = int(address, 16)
- if (start & self.heap.ObjectAlignmentMask()) != 0:
- print "Warning: Dumping un-aligned memory, is this what you had in mind?"
- for slot in xrange(start,
- start + self.reader.PointerSize() * 10,
- self.reader.PointerSize()):
- if not self.reader.IsValidAddress(slot):
- print "Address is not contained within the minidump!"
- return
- maybe_address = self.reader.ReadUIntPtr(slot)
- heap_object = self.padawan.SenseObject(maybe_address)
- print "%s: %s %s" % (self.reader.FormatIntPtr(slot),
- self.reader.FormatIntPtr(maybe_address),
- heap_object or '')
-
- def do_do(self, address):
- """
- Interpret memory at the given address as a V8 object. Automatic
- alignment makes sure that you can pass tagged as well as un-tagged
- addresses.
- """
- address = int(address, 16)
- if (address & self.heap.ObjectAlignmentMask()) == 0:
- address = address + 1
- elif (address & self.heap.ObjectAlignmentMask()) != 1:
- print "Address doesn't look like a valid pointer!"
- return
- heap_object = self.padawan.SenseObject(address)
- if heap_object:
- heap_object.Print(Printer())
- else:
- print "Address cannot be interpreted as object!"
-
- def do_dp(self, address):
- """
- Interpret memory at the given address as being on a V8 heap page
- and print information about the page header (if available).
- """
- address = int(address, 16)
- page_address = address & ~self.heap.PageAlignmentMask()
- if self.reader.IsValidAddress(page_address):
- raise NotImplementedError
- else:
- print "Page header is not available!"
-
- def do_k(self, arguments):
- """
- Teach V8 heap layout information to the inspector. This increases
- the amount of annotations the inspector can produce while dumping
- data. The first page of each heap space is of particular interest
- because it contains known objects that do not move.
- """
- self.padawan.PrintKnowledge()
-
- def do_kd(self, address):
- """
- Teach V8 heap layout information to the inspector. Set the first
- data-space page by passing any pointer into that page.
- """
- address = int(address, 16)
- page_address = address & ~self.heap.PageAlignmentMask()
- self.padawan.known_first_data_page = page_address
-
- def do_km(self, address):
- """
- Teach V8 heap layout information to the inspector. Set the first
- map-space page by passing any pointer into that page.
- """
- address = int(address, 16)
- page_address = address & ~self.heap.PageAlignmentMask()
- self.padawan.known_first_map_page = page_address
-
- def do_kp(self, address):
- """
- Teach V8 heap layout information to the inspector. Set the first
- pointer-space page by passing any pointer into that page.
- """
- address = int(address, 16)
- page_address = address & ~self.heap.PageAlignmentMask()
- self.padawan.known_first_pointer_page = page_address
-
- def do_list(self, smth):
- """
- List all available memory regions.
- """
- def print_region(reader, start, size, location):
- print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start),
- reader.FormatIntPtr(start + size),
- size)
- print "Available memory regions:"
- self.reader.ForEachMemoryRegion(print_region)
-
- def do_s(self, word):
- """
- Search for a given word in available memory regions. The given word
- is expanded to full pointer size and searched at aligned as well as
- un-aligned memory locations. Use 'sa' to search aligned locations
- only.
- """
- try:
- word = int(word, 0)
- except ValueError:
- print "Malformed word, prefix with '0x' to use hexadecimal format."
- return
- print "Searching for word %d/0x%s:" % (word, self.reader.FormatIntPtr(word))
- self.reader.FindWord(word)
-
- def do_sh(self, none):
- """
- Search for the V8 Heap object in all available memory regions. You
- might get lucky and find this rare treasure full of invaluable
- information.
- """
- raise NotImplementedError
-
- def do_u(self, args):
- """
- u 0x<address> 0x<size>
- Unassemble memory in the region [address, address + size)
- """
- args = args.split(' ')
- start = int(args[0], 16)
- size = int(args[1], 16)
- lines = self.reader.GetDisasmLines(start, size)
- for line in lines:
- print FormatDisasmLine(start, self.heap, line)
- print
-
-EIP_PROXIMITY = 64
-
-CONTEXT_FOR_ARCH = {
- MD_CPU_ARCHITECTURE_AMD64:
- ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip',
- 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'],
- MD_CPU_ARCHITECTURE_ARM:
- ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9',
- 'r10', 'r11', 'r12', 'sp', 'lr', 'pc'],
- MD_CPU_ARCHITECTURE_X86:
- ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
-}
-
-KNOWN_MODULES = {'chrome.exe', 'chrome.dll'}
-
-def GetModuleName(reader, module):
- name = reader.ReadMinidumpString(module.module_name_rva)
- return str(os.path.basename(str(name).replace("\\", "/")))
-
-def AnalyzeMinidump(options, minidump_name):
- reader = MinidumpReader(options, minidump_name)
- heap = None
- DebugPrint("========================================")
- if reader.exception is None:
- print "Minidump has no exception info"
- else:
- print "Exception info:"
- exception_thread = reader.thread_map[reader.exception.thread_id]
- print " thread id: %d" % exception_thread.id
- print " code: %08X" % reader.exception.exception.code
- print " context:"
- for r in CONTEXT_FOR_ARCH[reader.arch]:
- print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
- # TODO(vitalyr): decode eflags.
- if reader.arch == MD_CPU_ARCHITECTURE_ARM:
- print " cpsr: %s" % bin(reader.exception_context.cpsr)[2:]
- else:
- print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
-
- print
- print " modules:"
- for module in reader.module_list.modules:
- name = GetModuleName(reader, module)
- if name in KNOWN_MODULES:
- print " %s at %08X" % (name, module.base_of_image)
- reader.TryLoadSymbolsFor(name, module)
- print
-
- stack_top = reader.ExceptionSP()
- stack_bottom = exception_thread.stack.start + \
- exception_thread.stack.memory.data_size
- stack_map = {reader.ExceptionIP(): -1}
- for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
- maybe_address = reader.ReadUIntPtr(slot)
- if not maybe_address in stack_map:
- stack_map[maybe_address] = slot
- heap = V8Heap(reader, stack_map)
-
- print "Disassembly around exception.eip:"
- eip_symbol = reader.FindSymbol(reader.ExceptionIP())
- if eip_symbol is not None:
- print eip_symbol
- disasm_start = reader.ExceptionIP() - EIP_PROXIMITY
- disasm_bytes = 2 * EIP_PROXIMITY
- if (options.full):
- full_range = reader.FindRegion(reader.ExceptionIP())
- if full_range is not None:
- disasm_start = full_range[0]
- disasm_bytes = full_range[1]
-
- lines = reader.GetDisasmLines(disasm_start, disasm_bytes)
-
- for line in lines:
- print FormatDisasmLine(disasm_start, heap, line)
- print
-
- if heap is None:
- heap = V8Heap(reader, None)
-
- if options.full:
- FullDump(reader, heap)
-
- if options.shell:
- InspectionShell(reader, heap).cmdloop("type help to get help")
- else:
- if reader.exception is not None:
- print "Annotated stack (from exception.esp to bottom):"
- for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
- maybe_address = reader.ReadUIntPtr(slot)
- heap_object = heap.FindObject(maybe_address)
- maybe_symbol = reader.FindSymbol(maybe_address)
- print "%s: %s %s" % (reader.FormatIntPtr(slot),
- reader.FormatIntPtr(maybe_address),
- maybe_symbol or "")
- if heap_object:
- heap_object.Print(Printer())
- print
-
- reader.Dispose()
-
-
-if __name__ == "__main__":
- parser = optparse.OptionParser(USAGE)
- parser.add_option("-s", "--shell", dest="shell", action="store_true",
- help="start an interactive inspector shell")
- parser.add_option("-f", "--full", dest="full", action="store_true",
- help="dump all information contained in the minidump")
- parser.add_option("--symdir", dest="symdir", default=".",
- help="directory containing *.pdb.sym file with symbols")
- parser.add_option("--objdump",
- default="/usr/bin/objdump",
- help="objdump tool to use [default: %default]")
- options, args = parser.parse_args()
- if os.path.exists(options.objdump):
- disasm.OBJDUMP_BIN = options.objdump
- OBJDUMP_BIN = options.objdump
- else:
- print "Cannot find %s, falling back to default objdump" % options.objdump
- if len(args) != 1:
- parser.print_help()
- sys.exit(1)
- AnalyzeMinidump(options, args[0])