Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright 2011 the V8 project authors. All rights reserved.
      4 # Redistribution and use in source and binary forms, with or without
      5 # modification, are permitted provided that the following conditions are
      6 # met:
      7 #
      8 #     * Redistributions of source code must retain the above copyright
      9 #       notice, this list of conditions and the following disclaimer.
     10 #     * Redistributions in binary form must reproduce the above
     11 #       copyright notice, this list of conditions and the following
     12 #       disclaimer in the documentation and/or other materials provided
     13 #       with the distribution.
     14 #     * Neither the name of Google Inc. nor the names of its
     15 #       contributors may be used to endorse or promote products derived
     16 #       from this software without specific prior written permission.
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 import ctypes
     31 import mmap
     32 import optparse
     33 import os
     34 import disasm
     35 import sys
     36 import types
     37 import codecs
     38 import re
     39 
     40 
     41 USAGE="""usage: %prog [OPTION]...
     42 
     43 Minidump analyzer.
     44 
     45 Shows the processor state at the point of exception including the
     46 stack of the active thread and the referenced objects in the V8
     47 heap. Code objects are disassembled and the addresses linked from the
     48 stack (pushed return addresses) are marked with "=>".
     49 
     50 
     51 Examples:
     52   $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp
     53 """
     54 
     55 
     56 DEBUG=False
     57 
     58 
     59 def DebugPrint(s):
     60   if not DEBUG: return
     61   print s
     62 
     63 
     64 class Descriptor(object):
     65   """Descriptor of a structure in a memory."""
     66 
     67   def __init__(self, fields):
     68     self.fields = fields
     69     self.is_flexible = False
     70     for _, type_or_func in fields:
     71       if isinstance(type_or_func, types.FunctionType):
     72         self.is_flexible = True
     73         break
     74     if not self.is_flexible:
     75       self.ctype = Descriptor._GetCtype(fields)
     76       self.size = ctypes.sizeof(self.ctype)
     77 
     78   def Read(self, memory, offset):
     79     if self.is_flexible:
     80       fields_copy = self.fields[:]
     81       last = 0
     82       for name, type_or_func in fields_copy:
     83         if isinstance(type_or_func, types.FunctionType):
     84           partial_ctype = Descriptor._GetCtype(fields_copy[:last])
     85           partial_object = partial_ctype.from_buffer(memory, offset)
     86           type = type_or_func(partial_object)
     87           if type is not None:
     88             fields_copy[last] = (name, type)
     89             last += 1
     90         else:
     91           last += 1
     92       complete_ctype = Descriptor._GetCtype(fields_copy[:last])
     93     else:
     94       complete_ctype = self.ctype
     95     return complete_ctype.from_buffer(memory, offset)
     96 
     97   @staticmethod
     98   def _GetCtype(fields):
     99     class Raw(ctypes.Structure):
    100       _fields_ = fields
    101       _pack_ = 1
    102 
    103       def __str__(self):
    104         return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field))
    105                                for field, _ in Raw._fields_) + "}"
    106     return Raw
    107 
    108 
    109 # Set of structures and constants that describe the layout of minidump
    110 # files. Based on MSDN and Google Breakpad.
    111 
    112 MINIDUMP_HEADER = Descriptor([
    113   ("signature", ctypes.c_uint32),
    114   ("version", ctypes.c_uint32),
    115   ("stream_count", ctypes.c_uint32),
    116   ("stream_directories_rva", ctypes.c_uint32),
    117   ("checksum", ctypes.c_uint32),
    118   ("time_date_stampt", ctypes.c_uint32),
    119   ("flags", ctypes.c_uint64)
    120 ])
    121 
    122 MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([
    123   ("data_size", ctypes.c_uint32),
    124   ("rva", ctypes.c_uint32)
    125 ])
    126 
    127 MINIDUMP_DIRECTORY = Descriptor([
    128   ("stream_type", ctypes.c_uint32),
    129   ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
    130 ])
    131 
    132 MD_EXCEPTION_MAXIMUM_PARAMETERS = 15
    133 
    134 MINIDUMP_EXCEPTION = Descriptor([
    135   ("code", ctypes.c_uint32),
    136   ("flags", ctypes.c_uint32),
    137   ("record", ctypes.c_uint64),
    138   ("address", ctypes.c_uint64),
    139   ("parameter_count", ctypes.c_uint32),
    140   ("unused_alignment", ctypes.c_uint32),
    141   ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS)
    142 ])
    143 
    144 MINIDUMP_EXCEPTION_STREAM = Descriptor([
    145   ("thread_id", ctypes.c_uint32),
    146   ("unused_alignment", ctypes.c_uint32),
    147   ("exception", MINIDUMP_EXCEPTION.ctype),
    148   ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
    149 ])
    150 
    151 # Stream types.
    152 MD_UNUSED_STREAM = 0
    153 MD_RESERVED_STREAM_0 = 1
    154 MD_RESERVED_STREAM_1 = 2
    155 MD_THREAD_LIST_STREAM = 3
    156 MD_MODULE_LIST_STREAM = 4
    157 MD_MEMORY_LIST_STREAM = 5
    158 MD_EXCEPTION_STREAM = 6
    159 MD_SYSTEM_INFO_STREAM = 7
    160 MD_THREAD_EX_LIST_STREAM = 8
    161 MD_MEMORY_64_LIST_STREAM = 9
    162 MD_COMMENT_STREAM_A = 10
    163 MD_COMMENT_STREAM_W = 11
    164 MD_HANDLE_DATA_STREAM = 12
    165 MD_FUNCTION_TABLE_STREAM = 13
    166 MD_UNLOADED_MODULE_LIST_STREAM = 14
    167 MD_MISC_INFO_STREAM = 15
    168 MD_MEMORY_INFO_LIST_STREAM = 16
    169 MD_THREAD_INFO_LIST_STREAM = 17
    170 MD_HANDLE_OPERATION_LIST_STREAM = 18
    171 
    172 MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80
    173 
    174 MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([
    175   ("control_word", ctypes.c_uint32),
    176   ("status_word", ctypes.c_uint32),
    177   ("tag_word", ctypes.c_uint32),
    178   ("error_offset", ctypes.c_uint32),
    179   ("error_selector", ctypes.c_uint32),
    180   ("data_offset", ctypes.c_uint32),
    181   ("data_selector", ctypes.c_uint32),
    182   ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE),
    183   ("cr0_npx_state", ctypes.c_uint32)
    184 ])
    185 
    186 MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512
    187 
    188 # Context flags.
    189 MD_CONTEXT_X86 = 0x00010000
    190 MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001)
    191 MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002)
    192 MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004)
    193 MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008)
    194 MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010)
    195 MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020)
    196 
    197 def EnableOnFlag(type, flag):
    198   return lambda o: [None, type][int((o.context_flags & flag) != 0)]
    199 
    200 MINIDUMP_CONTEXT_X86 = Descriptor([
    201   ("context_flags", ctypes.c_uint32),
    202   # MD_CONTEXT_X86_DEBUG_REGISTERS.
    203   ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
    204   ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
    205   ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
    206   ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
    207   ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
    208   ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)),
    209   # MD_CONTEXT_X86_FLOATING_POINT.
    210   ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype,
    211                               MD_CONTEXT_X86_FLOATING_POINT)),
    212   # MD_CONTEXT_X86_SEGMENTS.
    213   ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
    214   ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
    215   ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
    216   ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)),
    217   # MD_CONTEXT_X86_INTEGER.
    218   ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
    219   ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
    220   ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
    221   ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
    222   ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
    223   ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)),
    224   # MD_CONTEXT_X86_CONTROL.
    225   ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
    226   ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
    227   ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
    228   ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
    229   ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
    230   ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)),
    231   # MD_CONTEXT_X86_EXTENDED_REGISTERS.
    232   ("extended_registers",
    233    EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE,
    234                 MD_CONTEXT_X86_EXTENDED_REGISTERS))
    235 ])
    236 
    237 MD_CONTEXT_AMD64 = 0x00100000
    238 MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
    239 MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
    240 MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
    241 MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
    242 MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
    243 
    244 MINIDUMP_CONTEXT_AMD64 = Descriptor([
    245   ("p1_home", ctypes.c_uint64),
    246   ("p2_home", ctypes.c_uint64),
    247   ("p3_home", ctypes.c_uint64),
    248   ("p4_home", ctypes.c_uint64),
    249   ("p5_home", ctypes.c_uint64),
    250   ("p6_home", ctypes.c_uint64),
    251   ("context_flags", ctypes.c_uint32),
    252   ("mx_csr", ctypes.c_uint32),
    253   # MD_CONTEXT_AMD64_CONTROL.
    254   ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
    255   # MD_CONTEXT_AMD64_SEGMENTS
    256   ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
    257   ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
    258   ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
    259   ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
    260   # MD_CONTEXT_AMD64_CONTROL.
    261   ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
    262   ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
    263   # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
    264   ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    265   ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    266   ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    267   ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    268   ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    269   ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    270   # MD_CONTEXT_AMD64_INTEGER.
    271   ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    272   ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    273   ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    274   ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    275   # MD_CONTEXT_AMD64_CONTROL.
    276   ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
    277   # MD_CONTEXT_AMD64_INTEGER.
    278   ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    279   ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    280   ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    281   ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    282   ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    283   ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    284   ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    285   ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    286   ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    287   ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    288   ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
    289   # MD_CONTEXT_AMD64_CONTROL.
    290   ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
    291   # MD_CONTEXT_AMD64_FLOATING_POINT
    292   ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
    293                                  MD_CONTEXT_AMD64_FLOATING_POINT)),
    294   ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
    295                                     MD_CONTEXT_AMD64_FLOATING_POINT)),
    296   ("vector_control", EnableOnFlag(ctypes.c_uint64,
    297                                   MD_CONTEXT_AMD64_FLOATING_POINT)),
    298   # MD_CONTEXT_AMD64_DEBUG_REGISTERS.
    299   ("debug_control", EnableOnFlag(ctypes.c_uint64,
    300                                  MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    301   ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
    302                                       MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    303   ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
    304                                         MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    305   ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
    306                                          MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
    307   ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
    308                                            MD_CONTEXT_AMD64_DEBUG_REGISTERS))
    309 ])
    310 
    311 MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
    312   ("start", ctypes.c_uint64),
    313   ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
    314 ])
    315 
    316 MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([
    317   ("start", ctypes.c_uint64),
    318   ("size", ctypes.c_uint64)
    319 ])
    320 
    321 MINIDUMP_MEMORY_LIST = Descriptor([
    322   ("range_count", ctypes.c_uint32),
    323   ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count)
    324 ])
    325 
    326 MINIDUMP_MEMORY_LIST64 = Descriptor([
    327   ("range_count", ctypes.c_uint64),
    328   ("base_rva", ctypes.c_uint64),
    329   ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count)
    330 ])
    331 
    332 MINIDUMP_THREAD = Descriptor([
    333   ("id", ctypes.c_uint32),
    334   ("suspend_count", ctypes.c_uint32),
    335   ("priority_class", ctypes.c_uint32),
    336   ("priority", ctypes.c_uint32),
    337   ("ted", ctypes.c_uint64),
    338   ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
    339   ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
    340 ])
    341 
    342 MINIDUMP_THREAD_LIST = Descriptor([
    343   ("thread_count", ctypes.c_uint32),
    344   ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
    345 ])
    346 
    347 MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
    348   ("processor_architecture", ctypes.c_uint16)
    349 ])
    350 
    351 MD_CPU_ARCHITECTURE_X86 = 0
    352 MD_CPU_ARCHITECTURE_AMD64 = 9
    353 
    354 class MinidumpReader(object):
    355   """Minidump (.dmp) reader."""
    356 
    357   _HEADER_MAGIC = 0x504d444d
    358 
    359   def __init__(self, options, minidump_name):
    360     self.minidump_name = minidump_name
    361     self.minidump_file = open(minidump_name, "r")
    362     self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
    363     self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
    364     if self.header.signature != MinidumpReader._HEADER_MAGIC:
    365       print >>sys.stderr, "Warning: unsupported minidump header magic"
    366     DebugPrint(self.header)
    367     directories = []
    368     offset = self.header.stream_directories_rva
    369     for _ in xrange(self.header.stream_count):
    370       directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
    371       offset += MINIDUMP_DIRECTORY.size
    372     self.arch = None
    373     self.exception = None
    374     self.exception_context = None
    375     self.memory_list = None
    376     self.memory_list64 = None
    377     self.thread_map = {}
    378 
    379     # Find MDRawSystemInfo stream and determine arch.
    380     for d in directories:
    381       if d.stream_type == MD_SYSTEM_INFO_STREAM:
    382         system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
    383             self.minidump, d.location.rva)
    384         self.arch = system_info.processor_architecture
    385         assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86]
    386     assert not self.arch is None
    387 
    388     for d in directories:
    389       DebugPrint(d)
    390       if d.stream_type == MD_EXCEPTION_STREAM:
    391         self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
    392           self.minidump, d.location.rva)
    393         DebugPrint(self.exception)
    394         if self.arch == MD_CPU_ARCHITECTURE_X86:
    395           self.exception_context = MINIDUMP_CONTEXT_X86.Read(
    396               self.minidump, self.exception.thread_context.rva)
    397         elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
    398           self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
    399               self.minidump, self.exception.thread_context.rva)
    400         DebugPrint(self.exception_context)
    401       elif d.stream_type == MD_THREAD_LIST_STREAM:
    402         thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
    403         assert ctypes.sizeof(thread_list) == d.location.data_size
    404         DebugPrint(thread_list)
    405         for thread in thread_list.threads:
    406           DebugPrint(thread)
    407           self.thread_map[thread.id] = thread
    408       elif d.stream_type == MD_MEMORY_LIST_STREAM:
    409         print >>sys.stderr, "Warning: not a full minidump"
    410         assert self.memory_list is None
    411         self.memory_list = MINIDUMP_MEMORY_LIST.Read(
    412           self.minidump, d.location.rva)
    413         assert ctypes.sizeof(self.memory_list) == d.location.data_size
    414         DebugPrint(self.memory_list)
    415       elif d.stream_type == MD_MEMORY_64_LIST_STREAM:
    416         assert self.memory_list64 is None
    417         self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read(
    418           self.minidump, d.location.rva)
    419         assert ctypes.sizeof(self.memory_list64) == d.location.data_size
    420         DebugPrint(self.memory_list64)
    421 
    422   def IsValidAddress(self, address):
    423     return self.FindLocation(address) is not None
    424 
    425   def ReadU8(self, address):
    426     location = self.FindLocation(address)
    427     return ctypes.c_uint8.from_buffer(self.minidump, location).value
    428 
    429   def ReadU32(self, address):
    430     location = self.FindLocation(address)
    431     return ctypes.c_uint32.from_buffer(self.minidump, location).value
    432 
    433   def ReadU64(self, address):
    434     location = self.FindLocation(address)
    435     return ctypes.c_uint64.from_buffer(self.minidump, location).value
    436 
    437   def ReadUIntPtr(self, address):
    438     if self.arch == MD_CPU_ARCHITECTURE_AMD64:
    439       return self.ReadU64(address)
    440     elif self.arch == MD_CPU_ARCHITECTURE_X86:
    441       return self.ReadU32(address)
    442 
    443   def ReadBytes(self, address, size):
    444     location = self.FindLocation(address)
    445     return self.minidump[location:location + size]
    446 
    447   def FindLocation(self, address):
    448     offset = 0
    449     if self.memory_list64 is not None:
    450       for r in self.memory_list64.ranges:
    451         if r.start <= address < r.start + r.size:
    452           return self.memory_list64.base_rva + offset + address - r.start
    453         offset += r.size
    454     if self.memory_list is not None:
    455       for r in self.memory_list.ranges:
    456         if r.start <= address < r.start + r.memory.data_size:
    457           return r.memory.rva + address - r.start
    458     return None
    459 
    460   def GetDisasmLines(self, address, size):
    461     location = self.FindLocation(address)
    462     if location is None: return []
    463     arch = None
    464     if self.arch == MD_CPU_ARCHITECTURE_X86:
    465       arch = "ia32"
    466     elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
    467       arch = "x64"
    468     return disasm.GetDisasmLines(self.minidump_name,
    469                                  location,
    470                                  size,
    471                                  arch,
    472                                  False)
    473 
    474 
    475   def Dispose(self):
    476     self.minidump.close()
    477     self.minidump_file.close()
    478 
    479   def ExceptionIP(self):
    480     if self.arch == MD_CPU_ARCHITECTURE_AMD64:
    481       return self.exception_context.rip
    482     elif self.arch == MD_CPU_ARCHITECTURE_X86:
    483       return self.exception_context.eip
    484 
    485   def ExceptionSP(self):
    486     if self.arch == MD_CPU_ARCHITECTURE_AMD64:
    487       return self.exception_context.rsp
    488     elif self.arch == MD_CPU_ARCHITECTURE_X86:
    489       return self.exception_context.esp
    490 
    491   def FormatIntPtr(self, value):
    492     if self.arch == MD_CPU_ARCHITECTURE_AMD64:
    493       return "%016x" % value
    494     elif self.arch == MD_CPU_ARCHITECTURE_X86:
    495       return "%08x" % value
    496 
    497   def PointerSize(self):
    498     if self.arch == MD_CPU_ARCHITECTURE_AMD64:
    499       return 8
    500     elif self.arch == MD_CPU_ARCHITECTURE_X86:
    501       return 4
    502 
    503   def Register(self, name):
    504     return self.exception_context.__getattribute__(name)
    505 
    506 
    507 # List of V8 instance types. Obtained by adding the code below to any .cc file.
    508 #
    509 # #define DUMP_TYPE(T) printf("  %d: \"%s\",\n", T, #T);
    510 # struct P {
    511 #   P() {
    512 #     printf("INSTANCE_TYPES = {\n");
    513 #     INSTANCE_TYPE_LIST(DUMP_TYPE)
    514 #     printf("}\n");
    515 #   }
    516 # };
    517 # static P p;
    518 INSTANCE_TYPES = {
    519   64: "SYMBOL_TYPE",
    520   68: "ASCII_SYMBOL_TYPE",
    521   65: "CONS_SYMBOL_TYPE",
    522   69: "CONS_ASCII_SYMBOL_TYPE",
    523   66: "EXTERNAL_SYMBOL_TYPE",
    524   74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
    525   70: "EXTERNAL_ASCII_SYMBOL_TYPE",
    526   82: "SHORT_EXTERNAL_SYMBOL_TYPE",
    527   90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE",
    528   86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE",
    529   0: "STRING_TYPE",
    530   4: "ASCII_STRING_TYPE",
    531   1: "CONS_STRING_TYPE",
    532   5: "CONS_ASCII_STRING_TYPE",
    533   3: "SLICED_STRING_TYPE",
    534   2: "EXTERNAL_STRING_TYPE",
    535   10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
    536   6: "EXTERNAL_ASCII_STRING_TYPE",
    537   18: "SHORT_EXTERNAL_STRING_TYPE",
    538   26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE",
    539   22: "SHORT_EXTERNAL_ASCII_STRING_TYPE",
    540   6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE",
    541   128: "MAP_TYPE",
    542   129: "CODE_TYPE",
    543   130: "ODDBALL_TYPE",
    544   131: "JS_GLOBAL_PROPERTY_CELL_TYPE",
    545   132: "HEAP_NUMBER_TYPE",
    546   133: "FOREIGN_TYPE",
    547   134: "BYTE_ARRAY_TYPE",
    548   135: "FREE_SPACE_TYPE",
    549   136: "EXTERNAL_BYTE_ARRAY_TYPE",
    550   137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE",
    551   138: "EXTERNAL_SHORT_ARRAY_TYPE",
    552   139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE",
    553   140: "EXTERNAL_INT_ARRAY_TYPE",
    554   141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE",
    555   142: "EXTERNAL_FLOAT_ARRAY_TYPE",
    556   144: "EXTERNAL_PIXEL_ARRAY_TYPE",
    557   146: "FILLER_TYPE",
    558   147: "ACCESSOR_INFO_TYPE",
    559   148: "ACCESSOR_PAIR_TYPE",
    560   149: "ACCESS_CHECK_INFO_TYPE",
    561   150: "INTERCEPTOR_INFO_TYPE",
    562   151: "CALL_HANDLER_INFO_TYPE",
    563   152: "FUNCTION_TEMPLATE_INFO_TYPE",
    564   153: "OBJECT_TEMPLATE_INFO_TYPE",
    565   154: "SIGNATURE_INFO_TYPE",
    566   155: "TYPE_SWITCH_INFO_TYPE",
    567   156: "SCRIPT_TYPE",
    568   157: "CODE_CACHE_TYPE",
    569   158: "POLYMORPHIC_CODE_CACHE_TYPE",
    570   161: "FIXED_ARRAY_TYPE",
    571   145: "FIXED_DOUBLE_ARRAY_TYPE",
    572   162: "SHARED_FUNCTION_INFO_TYPE",
    573   163: "JS_MESSAGE_OBJECT_TYPE",
    574   166: "JS_VALUE_TYPE",
    575   167: "JS_OBJECT_TYPE",
    576   168: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
    577   169: "JS_GLOBAL_OBJECT_TYPE",
    578   170: "JS_BUILTINS_OBJECT_TYPE",
    579   171: "JS_GLOBAL_PROXY_TYPE",
    580   172: "JS_ARRAY_TYPE",
    581   165: "JS_PROXY_TYPE",
    582   175: "JS_WEAK_MAP_TYPE",
    583   176: "JS_REGEXP_TYPE",
    584   177: "JS_FUNCTION_TYPE",
    585   164: "JS_FUNCTION_PROXY_TYPE",
    586   159: "DEBUG_INFO_TYPE",
    587   160: "BREAK_POINT_INFO_TYPE",
    588 }
    589 
    590 
    591 class Printer(object):
    592   """Printer with indentation support."""
    593 
    594   def __init__(self):
    595     self.indent = 0
    596 
    597   def Indent(self):
    598     self.indent += 2
    599 
    600   def Dedent(self):
    601     self.indent -= 2
    602 
    603   def Print(self, string):
    604     print "%s%s" % (self._IndentString(), string)
    605 
    606   def PrintLines(self, lines):
    607     indent = self._IndentString()
    608     print "\n".join("%s%s" % (indent, line) for line in lines)
    609 
    610   def _IndentString(self):
    611     return self.indent * " "
    612 
    613 
    614 ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+")
    615 
    616 
    617 def FormatDisasmLine(start, heap, line):
    618   line_address = start + line[0]
    619   stack_slot = heap.stack_map.get(line_address)
    620   marker = "  "
    621   if stack_slot:
    622     marker = "=>"
    623   code = AnnotateAddresses(heap, line[1])
    624   return "%s%08x %08x: %s" % (marker, line_address, line[0], code)
    625 
    626 
    627 def AnnotateAddresses(heap, line):
    628   extra = []
    629   for m in ADDRESS_RE.finditer(line):
    630     maybe_address = int(m.group(0), 16)
    631     object = heap.FindObject(maybe_address)
    632     if not object: continue
    633     extra.append(str(object))
    634   if len(extra) == 0: return line
    635   return "%s  ;; %s" % (line, ", ".join(extra))
    636 
    637 
    638 class HeapObject(object):
    639   def __init__(self, heap, map, address):
    640     self.heap = heap
    641     self.map = map
    642     self.address = address
    643 
    644   def Is(self, cls):
    645     return isinstance(self, cls)
    646 
    647   def Print(self, p):
    648     p.Print(str(self))
    649 
    650   def __str__(self):
    651     return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
    652                                    INSTANCE_TYPES[self.map.instance_type])
    653 
    654   def ObjectField(self, offset):
    655     field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
    656     return self.heap.FindObjectOrSmi(field_value)
    657 
    658   def SmiField(self, offset):
    659     field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
    660     assert (field_value & 1) == 0
    661     return field_value / 2
    662 
    663 
    664 class Map(HeapObject):
    665   def InstanceTypeOffset(self):
    666     return self.heap.PointerSize() + self.heap.IntSize()
    667 
    668   def __init__(self, heap, map, address):
    669     HeapObject.__init__(self, heap, map, address)
    670     self.instance_type = \
    671         heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
    672 
    673 
    674 class String(HeapObject):
    675   def LengthOffset(self):
    676     return self.heap.PointerSize()
    677 
    678   def __init__(self, heap, map, address):
    679     HeapObject.__init__(self, heap, map, address)
    680     self.length = self.SmiField(self.LengthOffset())
    681 
    682   def GetChars(self):
    683     return "?string?"
    684 
    685   def Print(self, p):
    686     p.Print(str(self))
    687 
    688   def __str__(self):
    689     return "\"%s\"" % self.GetChars()
    690 
    691 
    692 class SeqString(String):
    693   def CharsOffset(self):
    694     return self.heap.PointerSize() * 3
    695 
    696   def __init__(self, heap, map, address):
    697     String.__init__(self, heap, map, address)
    698     self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
    699                                        self.length)
    700 
    701   def GetChars(self):
    702     return self.chars
    703 
    704 
    705 class ExternalString(String):
    706   # TODO(vegorov) fix ExternalString for X64 architecture
    707   RESOURCE_OFFSET = 12
    708 
    709   WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
    710   WEBKIT_STRING_IMPL_CHARS_OFFSET = 8
    711 
    712   def __init__(self, heap, map, address):
    713     String.__init__(self, heap, map, address)
    714     reader = heap.reader
    715     self.resource = \
    716         reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET)
    717     self.chars = "?external string?"
    718     if not reader.IsValidAddress(self.resource): return
    719     string_impl_address = self.resource + \
    720         ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET
    721     if not reader.IsValidAddress(string_impl_address): return
    722     string_impl = reader.ReadU32(string_impl_address)
    723     chars_ptr_address = string_impl + \
    724         ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET
    725     if not reader.IsValidAddress(chars_ptr_address): return
    726     chars_ptr = reader.ReadU32(chars_ptr_address)
    727     if not reader.IsValidAddress(chars_ptr): return
    728     raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length)
    729     self.chars = codecs.getdecoder("utf16")(raw_chars)[0]
    730 
    731   def GetChars(self):
    732     return self.chars
    733 
    734 
    735 class ConsString(String):
    736   def LeftOffset(self):
    737     return self.heap.PointerSize() * 3
    738 
    739   def RightOffset(self):
    740     return self.heap.PointerSize() * 4
    741 
    742   def __init__(self, heap, map, address):
    743     String.__init__(self, heap, map, address)
    744     self.left = self.ObjectField(self.LeftOffset())
    745     self.right = self.ObjectField(self.RightOffset())
    746 
    747   def GetChars(self):
    748     return self.left.GetChars() + self.right.GetChars()
    749 
    750 
    751 class Oddball(HeapObject):
    752   def ToStringOffset(self):
    753     return self.heap.PointerSize()
    754 
    755   def __init__(self, heap, map, address):
    756     HeapObject.__init__(self, heap, map, address)
    757     self.to_string = self.ObjectField(self.ToStringOffset())
    758 
    759   def Print(self, p):
    760     p.Print(str(self))
    761 
    762   def __str__(self):
    763     return "<%s>" % self.to_string.GetChars()
    764 
    765 
    766 class FixedArray(HeapObject):
    767   def LengthOffset(self):
    768     return self.heap.PointerSize()
    769 
    770   def ElementsOffset(self):
    771     return self.heap.PointerSize() * 2
    772 
    773   def __init__(self, heap, map, address):
    774     HeapObject.__init__(self, heap, map, address)
    775     self.length = self.SmiField(self.LengthOffset())
    776 
    777   def Print(self, p):
    778     p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
    779     p.Indent()
    780     p.Print("length: %d" % self.length)
    781     base_offset = self.ElementsOffset()
    782     for i in xrange(self.length):
    783       offset = base_offset + 4 * i
    784       p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
    785     p.Dedent()
    786     p.Print("}")
    787 
    788   def __str__(self):
    789     return "FixedArray(%08x, length=%d)" % (self.address, self.length)
    790 
    791 
    792 class JSFunction(HeapObject):
    793   def CodeEntryOffset(self):
    794     return 3 * self.heap.PointerSize()
    795 
    796   def SharedOffset(self):
    797     return 5 * self.heap.PointerSize()
    798 
    799   def __init__(self, heap, map, address):
    800     HeapObject.__init__(self, heap, map, address)
    801     code_entry = \
    802         heap.reader.ReadU32(self.address + self.CodeEntryOffset())
    803     self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
    804     self.shared = self.ObjectField(self.SharedOffset())
    805 
    806   def Print(self, p):
    807     source = "\n".join("  %s" % line for line in self._GetSource().split("\n"))
    808     p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
    809     p.Indent()
    810     p.Print("inferred name: %s" % self.shared.inferred_name)
    811     if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
    812       p.Print("script name: %s" % self.shared.script.name)
    813     p.Print("source:")
    814     p.PrintLines(self._GetSource().split("\n"))
    815     p.Print("code:")
    816     self.code.Print(p)
    817     if self.code != self.shared.code:
    818       p.Print("unoptimized code:")
    819       self.shared.code.Print(p)
    820     p.Dedent()
    821     p.Print("}")
    822 
    823   def __str__(self):
    824     inferred_name = ""
    825     if self.shared.Is(SharedFunctionInfo):
    826       inferred_name = self.shared.inferred_name
    827     return "JSFunction(%s, %s)" % \
    828           (self.heap.reader.FormatIntPtr(self.address), inferred_name)
    829 
    830   def _GetSource(self):
    831     source = "?source?"
    832     start = self.shared.start_position
    833     end = self.shared.end_position
    834     if not self.shared.script.Is(Script): return source
    835     script_source = self.shared.script.source
    836     if not script_source.Is(String): return source
    837     return script_source.GetChars()[start:end]
    838 
    839 
    840 class SharedFunctionInfo(HeapObject):
    841   def CodeOffset(self):
    842     return 2 * self.heap.PointerSize()
    843 
    844   def ScriptOffset(self):
    845     return 7 * self.heap.PointerSize()
    846 
    847   def InferredNameOffset(self):
    848     return 9 * self.heap.PointerSize()
    849 
    850   def EndPositionOffset(self):
    851     return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
    852 
    853   def StartPositionAndTypeOffset(self):
    854     return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize()
    855 
    856   def __init__(self, heap, map, address):
    857     HeapObject.__init__(self, heap, map, address)
    858     self.code = self.ObjectField(self.CodeOffset())
    859     self.script = self.ObjectField(self.ScriptOffset())
    860     self.inferred_name = self.ObjectField(self.InferredNameOffset())
    861     if heap.PointerSize() == 8:
    862       start_position_and_type = \
    863           heap.reader.ReadU32(self.StartPositionAndTypeOffset())
    864       self.start_position = start_position_and_type >> 2
    865       pseudo_smi_end_position = \
    866           heap.reader.ReadU32(self.EndPositionOffset())
    867       self.end_position = pseudo_smi_end_position >> 2
    868     else:
    869       start_position_and_type = \
    870           self.SmiField(self.StartPositionAndTypeOffset())
    871       self.start_position = start_position_and_type >> 2
    872       self.end_position = \
    873           self.SmiField(self.EndPositionOffset())
    874 
    875 
    876 class Script(HeapObject):
    877   def SourceOffset(self):
    878     return self.heap.PointerSize()
    879 
    880   def NameOffset(self):
    881     return self.SourceOffset() + self.heap.PointerSize()
    882 
    883   def __init__(self, heap, map, address):
    884     HeapObject.__init__(self, heap, map, address)
    885     self.source = self.ObjectField(self.SourceOffset())
    886     self.name = self.ObjectField(self.NameOffset())
    887 
    888 
    889 class Code(HeapObject):
    890   CODE_ALIGNMENT_MASK = (1 << 5) - 1
    891 
    892   def InstructionSizeOffset(self):
    893     return self.heap.PointerSize()
    894 
    895   @staticmethod
    896   def HeaderSize(heap):
    897     return (heap.PointerSize() + heap.IntSize() + \
    898         4 * heap.PointerSize() + 3 * heap.IntSize() + \
    899         Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
    900 
    901   def __init__(self, heap, map, address):
    902     HeapObject.__init__(self, heap, map, address)
    903     self.entry = self.address + Code.HeaderSize(heap)
    904     self.instruction_size = \
    905         heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
    906 
    907   def Print(self, p):
    908     lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
    909     p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
    910     p.Indent()
    911     p.Print("instruction_size: %d" % self.instruction_size)
    912     p.PrintLines(self._FormatLine(line) for line in lines)
    913     p.Dedent()
    914     p.Print("}")
    915 
    916   def _FormatLine(self, line):
    917     return FormatDisasmLine(self.entry, self.heap, line)
    918 
    919 
    920 class V8Heap(object):
    921   CLASS_MAP = {
    922     "SYMBOL_TYPE": SeqString,
    923     "ASCII_SYMBOL_TYPE": SeqString,
    924     "CONS_SYMBOL_TYPE": ConsString,
    925     "CONS_ASCII_SYMBOL_TYPE": ConsString,
    926     "EXTERNAL_SYMBOL_TYPE": ExternalString,
    927     "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
    928     "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
    929     "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString,
    930     "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString,
    931     "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString,
    932     "STRING_TYPE": SeqString,
    933     "ASCII_STRING_TYPE": SeqString,
    934     "CONS_STRING_TYPE": ConsString,
    935     "CONS_ASCII_STRING_TYPE": ConsString,
    936     "EXTERNAL_STRING_TYPE": ExternalString,
    937     "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
    938     "EXTERNAL_ASCII_STRING_TYPE": ExternalString,
    939 
    940     "MAP_TYPE": Map,
    941     "ODDBALL_TYPE": Oddball,
    942     "FIXED_ARRAY_TYPE": FixedArray,
    943     "JS_FUNCTION_TYPE": JSFunction,
    944     "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
    945     "SCRIPT_TYPE": Script,
    946     "CODE_TYPE": Code
    947   }
    948 
    949   def __init__(self, reader, stack_map):
    950     self.reader = reader
    951     self.stack_map = stack_map
    952     self.objects = {}
    953 
    954   def FindObjectOrSmi(self, tagged_address):
    955     if (tagged_address & 1) == 0: return tagged_address / 2
    956     return self.FindObject(tagged_address)
    957 
    958   def FindObject(self, tagged_address):
    959     if tagged_address in self.objects:
    960       return self.objects[tagged_address]
    961     if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
    962     address = tagged_address - 1
    963     if not self.reader.IsValidAddress(address): return None
    964     map_tagged_address = self.reader.ReadUIntPtr(address)
    965     if tagged_address == map_tagged_address:
    966       # Meta map?
    967       meta_map = Map(self, None, address)
    968       instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type)
    969       if instance_type_name != "MAP_TYPE": return None
    970       meta_map.map = meta_map
    971       object = meta_map
    972     else:
    973       map = self.FindMap(map_tagged_address)
    974       if map is None: return None
    975       instance_type_name = INSTANCE_TYPES.get(map.instance_type)
    976       if instance_type_name is None: return None
    977       cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
    978       object = cls(self, map, address)
    979     self.objects[tagged_address] = object
    980     return object
    981 
    982   def FindMap(self, tagged_address):
    983     if (tagged_address & self.MapAlignmentMask()) != 1: return None
    984     address = tagged_address - 1
    985     if not self.reader.IsValidAddress(address): return None
    986     object = Map(self, None, address)
    987     return object
    988 
    989   def IntSize(self):
    990     return 4
    991 
    992   def PointerSize(self):
    993     return self.reader.PointerSize()
    994 
    995   def ObjectAlignmentMask(self):
    996     return self.PointerSize() - 1
    997 
    998   def MapAlignmentMask(self):
    999     if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
   1000       return (1 << 4) - 1
   1001     elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
   1002       return (1 << 5) - 1
   1003 
   1004 
   1005 EIP_PROXIMITY = 64
   1006 
   1007 CONTEXT_FOR_ARCH = {
   1008     MD_CPU_ARCHITECTURE_AMD64:
   1009       ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'],
   1010     MD_CPU_ARCHITECTURE_X86:
   1011       ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
   1012 }
   1013 
   1014 def AnalyzeMinidump(options, minidump_name):
   1015   reader = MinidumpReader(options, minidump_name)
   1016   DebugPrint("========================================")
   1017   if reader.exception is None:
   1018     print "Minidump has no exception info"
   1019     return
   1020   print "Exception info:"
   1021   exception_thread = reader.thread_map[reader.exception.thread_id]
   1022   print "  thread id: %d" % exception_thread.id
   1023   print "  code: %08X" % reader.exception.exception.code
   1024   print "  context:"
   1025   for r in CONTEXT_FOR_ARCH[reader.arch]:
   1026     print "    %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
   1027   # TODO(vitalyr): decode eflags.
   1028   print "    eflags: %s" % bin(reader.exception_context.eflags)[2:]
   1029   print
   1030 
   1031   stack_top = reader.ExceptionSP()
   1032   stack_bottom = exception_thread.stack.start + \
   1033       exception_thread.stack.memory.data_size
   1034   stack_map = {reader.ExceptionIP(): -1}
   1035   for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
   1036     maybe_address = reader.ReadUIntPtr(slot)
   1037     if not maybe_address in stack_map:
   1038       stack_map[maybe_address] = slot
   1039   heap = V8Heap(reader, stack_map)
   1040 
   1041   print "Disassembly around exception.eip:"
   1042   start = reader.ExceptionIP() - EIP_PROXIMITY
   1043   lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY)
   1044   for line in lines:
   1045     print FormatDisasmLine(start, heap, line)
   1046   print
   1047 
   1048   print "Annotated stack (from exception.esp to bottom):"
   1049   for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
   1050     maybe_address = reader.ReadUIntPtr(slot)
   1051     heap_object = heap.FindObject(maybe_address)
   1052     print "%s: %s" % (reader.FormatIntPtr(slot),
   1053                       reader.FormatIntPtr(maybe_address))
   1054     if heap_object:
   1055       heap_object.Print(Printer())
   1056       print
   1057 
   1058   reader.Dispose()
   1059 
   1060 
   1061 if __name__ == "__main__":
   1062   parser = optparse.OptionParser(USAGE)
   1063   options, args = parser.parse_args()
   1064   if len(args) != 1:
   1065     parser.print_help()
   1066     sys.exit(1)
   1067   AnalyzeMinidump(options, args[0])
   1068