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 30import ctypes 31import mmap 32import optparse 33import os 34import disasm 35import sys 36import types 37import codecs 38import re 39 40 41USAGE="""usage: %prog [OPTION]... 42 43Minidump analyzer. 44 45Shows the processor state at the point of exception including the 46stack of the active thread and the referenced objects in the V8 47heap. Code objects are disassembled and the addresses linked from the 48stack (pushed return addresses) are marked with "=>". 49 50 51Examples: 52 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp 53""" 54 55 56DEBUG=False 57 58 59def DebugPrint(s): 60 if not DEBUG: return 61 print s 62 63 64class Descriptor(object): 65 """Descriptor of a structure in a memory.""" 66 67 def __init__(self, fields): 68 self.fields = fields 69 self.is_flexible = False 70 for _, type_or_func in fields: 71 if isinstance(type_or_func, types.FunctionType): 72 self.is_flexible = True 73 break 74 if not self.is_flexible: 75 self.ctype = Descriptor._GetCtype(fields) 76 self.size = ctypes.sizeof(self.ctype) 77 78 def Read(self, memory, offset): 79 if self.is_flexible: 80 fields_copy = self.fields[:] 81 last = 0 82 for name, type_or_func in fields_copy: 83 if isinstance(type_or_func, types.FunctionType): 84 partial_ctype = Descriptor._GetCtype(fields_copy[:last]) 85 partial_object = partial_ctype.from_buffer(memory, offset) 86 type = type_or_func(partial_object) 87 if type is not None: 88 fields_copy[last] = (name, type) 89 last += 1 90 else: 91 last += 1 92 complete_ctype = Descriptor._GetCtype(fields_copy[:last]) 93 else: 94 complete_ctype = self.ctype 95 return complete_ctype.from_buffer(memory, offset) 96 97 @staticmethod 98 def _GetCtype(fields): 99 class Raw(ctypes.Structure): 100 _fields_ = fields 101 _pack_ = 1 102 103 def __str__(self): 104 return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field)) 105 for field, _ in Raw._fields_) + "}" 106 return Raw 107 108 109# Set of structures and constants that describe the layout of minidump 110# files. Based on MSDN and Google Breakpad. 111 112MINIDUMP_HEADER = Descriptor([ 113 ("signature", ctypes.c_uint32), 114 ("version", ctypes.c_uint32), 115 ("stream_count", ctypes.c_uint32), 116 ("stream_directories_rva", ctypes.c_uint32), 117 ("checksum", ctypes.c_uint32), 118 ("time_date_stampt", ctypes.c_uint32), 119 ("flags", ctypes.c_uint64) 120]) 121 122MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ 123 ("data_size", ctypes.c_uint32), 124 ("rva", ctypes.c_uint32) 125]) 126 127MINIDUMP_DIRECTORY = Descriptor([ 128 ("stream_type", ctypes.c_uint32), 129 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) 130]) 131 132MD_EXCEPTION_MAXIMUM_PARAMETERS = 15 133 134MINIDUMP_EXCEPTION = Descriptor([ 135 ("code", ctypes.c_uint32), 136 ("flags", ctypes.c_uint32), 137 ("record", ctypes.c_uint64), 138 ("address", ctypes.c_uint64), 139 ("parameter_count", ctypes.c_uint32), 140 ("unused_alignment", ctypes.c_uint32), 141 ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS) 142]) 143 144MINIDUMP_EXCEPTION_STREAM = Descriptor([ 145 ("thread_id", ctypes.c_uint32), 146 ("unused_alignment", ctypes.c_uint32), 147 ("exception", MINIDUMP_EXCEPTION.ctype), 148 ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) 149]) 150 151# Stream types. 152MD_UNUSED_STREAM = 0 153MD_RESERVED_STREAM_0 = 1 154MD_RESERVED_STREAM_1 = 2 155MD_THREAD_LIST_STREAM = 3 156MD_MODULE_LIST_STREAM = 4 157MD_MEMORY_LIST_STREAM = 5 158MD_EXCEPTION_STREAM = 6 159MD_SYSTEM_INFO_STREAM = 7 160MD_THREAD_EX_LIST_STREAM = 8 161MD_MEMORY_64_LIST_STREAM = 9 162MD_COMMENT_STREAM_A = 10 163MD_COMMENT_STREAM_W = 11 164MD_HANDLE_DATA_STREAM = 12 165MD_FUNCTION_TABLE_STREAM = 13 166MD_UNLOADED_MODULE_LIST_STREAM = 14 167MD_MISC_INFO_STREAM = 15 168MD_MEMORY_INFO_LIST_STREAM = 16 169MD_THREAD_INFO_LIST_STREAM = 17 170MD_HANDLE_OPERATION_LIST_STREAM = 18 171 172MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80 173 174MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([ 175 ("control_word", ctypes.c_uint32), 176 ("status_word", ctypes.c_uint32), 177 ("tag_word", ctypes.c_uint32), 178 ("error_offset", ctypes.c_uint32), 179 ("error_selector", ctypes.c_uint32), 180 ("data_offset", ctypes.c_uint32), 181 ("data_selector", ctypes.c_uint32), 182 ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE), 183 ("cr0_npx_state", ctypes.c_uint32) 184]) 185 186MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512 187 188# Context flags. 189MD_CONTEXT_X86 = 0x00010000 190MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001) 191MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002) 192MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004) 193MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008) 194MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010) 195MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020) 196 197def EnableOnFlag(type, flag): 198 return lambda o: [None, type][int((o.context_flags & flag) != 0)] 199 200MINIDUMP_CONTEXT_X86 = Descriptor([ 201 ("context_flags", ctypes.c_uint32), 202 # MD_CONTEXT_X86_DEBUG_REGISTERS. 203 ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), 204 ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), 205 ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), 206 ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), 207 ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), 208 ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), 209 # MD_CONTEXT_X86_FLOATING_POINT. 210 ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype, 211 MD_CONTEXT_X86_FLOATING_POINT)), 212 # MD_CONTEXT_X86_SEGMENTS. 213 ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), 214 ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), 215 ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), 216 ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), 217 # MD_CONTEXT_X86_INTEGER. 218 ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), 219 ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), 220 ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), 221 ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), 222 ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), 223 ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), 224 # MD_CONTEXT_X86_CONTROL. 225 ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), 226 ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), 227 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), 228 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), 229 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), 230 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), 231 # MD_CONTEXT_X86_EXTENDED_REGISTERS. 232 ("extended_registers", 233 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE, 234 MD_CONTEXT_X86_EXTENDED_REGISTERS)) 235]) 236 237MD_CONTEXT_AMD64 = 0x00100000 238MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001) 239MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002) 240MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004) 241MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008) 242MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010) 243 244MINIDUMP_CONTEXT_AMD64 = Descriptor([ 245 ("p1_home", ctypes.c_uint64), 246 ("p2_home", ctypes.c_uint64), 247 ("p3_home", ctypes.c_uint64), 248 ("p4_home", ctypes.c_uint64), 249 ("p5_home", ctypes.c_uint64), 250 ("p6_home", ctypes.c_uint64), 251 ("context_flags", ctypes.c_uint32), 252 ("mx_csr", ctypes.c_uint32), 253 # MD_CONTEXT_AMD64_CONTROL. 254 ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)), 255 # MD_CONTEXT_AMD64_SEGMENTS 256 ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), 257 ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), 258 ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), 259 ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), 260 # MD_CONTEXT_AMD64_CONTROL. 261 ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)), 262 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)), 263 # MD_CONTEXT_AMD64_DEBUG_REGISTERS. 264 ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 265 ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 266 ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 267 ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 268 ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 269 ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 270 # MD_CONTEXT_AMD64_INTEGER. 271 ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 272 ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 273 ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 274 ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 275 # MD_CONTEXT_AMD64_CONTROL. 276 ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)), 277 # MD_CONTEXT_AMD64_INTEGER. 278 ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 279 ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 280 ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 281 ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 282 ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 283 ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 284 ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 285 ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 286 ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 287 ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 288 ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), 289 # MD_CONTEXT_AMD64_CONTROL. 290 ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)), 291 # MD_CONTEXT_AMD64_FLOATING_POINT 292 ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26), 293 MD_CONTEXT_AMD64_FLOATING_POINT)), 294 ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26), 295 MD_CONTEXT_AMD64_FLOATING_POINT)), 296 ("vector_control", EnableOnFlag(ctypes.c_uint64, 297 MD_CONTEXT_AMD64_FLOATING_POINT)), 298 # MD_CONTEXT_AMD64_DEBUG_REGISTERS. 299 ("debug_control", EnableOnFlag(ctypes.c_uint64, 300 MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 301 ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64, 302 MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 303 ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64, 304 MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 305 ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64, 306 MD_CONTEXT_AMD64_DEBUG_REGISTERS)), 307 ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64, 308 MD_CONTEXT_AMD64_DEBUG_REGISTERS)) 309]) 310 311MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([ 312 ("start", ctypes.c_uint64), 313 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype) 314]) 315 316MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([ 317 ("start", ctypes.c_uint64), 318 ("size", ctypes.c_uint64) 319]) 320 321MINIDUMP_MEMORY_LIST = Descriptor([ 322 ("range_count", ctypes.c_uint32), 323 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count) 324]) 325 326MINIDUMP_MEMORY_LIST64 = Descriptor([ 327 ("range_count", ctypes.c_uint64), 328 ("base_rva", ctypes.c_uint64), 329 ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count) 330]) 331 332MINIDUMP_THREAD = Descriptor([ 333 ("id", ctypes.c_uint32), 334 ("suspend_count", ctypes.c_uint32), 335 ("priority_class", ctypes.c_uint32), 336 ("priority", ctypes.c_uint32), 337 ("ted", ctypes.c_uint64), 338 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), 339 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) 340]) 341 342MINIDUMP_THREAD_LIST = Descriptor([ 343 ("thread_count", ctypes.c_uint32), 344 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) 345]) 346 347MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ 348 ("processor_architecture", ctypes.c_uint16) 349]) 350 351MD_CPU_ARCHITECTURE_X86 = 0 352MD_CPU_ARCHITECTURE_AMD64 = 9 353 354class MinidumpReader(object): 355 """Minidump (.dmp) reader.""" 356 357 _HEADER_MAGIC = 0x504d444d 358 359 def __init__(self, options, minidump_name): 360 self.minidump_name = minidump_name 361 self.minidump_file = open(minidump_name, "r") 362 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) 363 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) 364 if self.header.signature != MinidumpReader._HEADER_MAGIC: 365 print >>sys.stderr, "Warning: unsupported minidump header magic" 366 DebugPrint(self.header) 367 directories = [] 368 offset = self.header.stream_directories_rva 369 for _ in xrange(self.header.stream_count): 370 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) 371 offset += MINIDUMP_DIRECTORY.size 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; 518INSTANCE_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 591class Printer(object): 592 """Printer with indentation support.""" 593 594 def __init__(self): 595 self.indent = 0 596 597 def Indent(self): 598 self.indent += 2 599 600 def Dedent(self): 601 self.indent -= 2 602 603 def Print(self, string): 604 print "%s%s" % (self._IndentString(), string) 605 606 def PrintLines(self, lines): 607 indent = self._IndentString() 608 print "\n".join("%s%s" % (indent, line) for line in lines) 609 610 def _IndentString(self): 611 return self.indent * " " 612 613 614ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+") 615 616 617def FormatDisasmLine(start, heap, line): 618 line_address = start + line[0] 619 stack_slot = heap.stack_map.get(line_address) 620 marker = " " 621 if stack_slot: 622 marker = "=>" 623 code = AnnotateAddresses(heap, line[1]) 624 return "%s%08x %08x: %s" % (marker, line_address, line[0], code) 625 626 627def AnnotateAddresses(heap, line): 628 extra = [] 629 for m in ADDRESS_RE.finditer(line): 630 maybe_address = int(m.group(0), 16) 631 object = heap.FindObject(maybe_address) 632 if not object: continue 633 extra.append(str(object)) 634 if len(extra) == 0: return line 635 return "%s ;; %s" % (line, ", ".join(extra)) 636 637 638class HeapObject(object): 639 def __init__(self, heap, map, address): 640 self.heap = heap 641 self.map = map 642 self.address = address 643 644 def Is(self, cls): 645 return isinstance(self, cls) 646 647 def Print(self, p): 648 p.Print(str(self)) 649 650 def __str__(self): 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 664class 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 674class 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 692class 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 705class 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 735class 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 751class 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 766class 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 792class 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 840class 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 876class 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 889class 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 920class V8Heap(object): 921 CLASS_MAP = { 922 "SYMBOL_TYPE": SeqString, 923 "ASCII_SYMBOL_TYPE": SeqString, 924 "CONS_SYMBOL_TYPE": ConsString, 925 "CONS_ASCII_SYMBOL_TYPE": ConsString, 926 "EXTERNAL_SYMBOL_TYPE": ExternalString, 927 "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString, 928 "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString, 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 1005EIP_PROXIMITY = 64 1006 1007CONTEXT_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 1014def AnalyzeMinidump(options, minidump_name): 1015 reader = MinidumpReader(options, minidump_name) 1016 DebugPrint("========================================") 1017 if reader.exception is None: 1018 print "Minidump has no exception info" 1019 return 1020 print "Exception info:" 1021 exception_thread = reader.thread_map[reader.exception.thread_id] 1022 print " thread id: %d" % exception_thread.id 1023 print " code: %08X" % reader.exception.exception.code 1024 print " context:" 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 1061if __name__ == "__main__": 1062 parser = optparse.OptionParser(USAGE) 1063 options, args = parser.parse_args() 1064 if len(args) != 1: 1065 parser.print_help() 1066 sys.exit(1) 1067 AnalyzeMinidump(options, args[0]) 1068