OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
11 # copyright notice, this list of conditions and the following | 11 # copyright notice, this list of conditions and the following |
12 # disclaimer in the documentation and/or other materials provided | 12 # disclaimer in the documentation and/or other materials provided |
13 # with the distribution. | 13 # with the distribution. |
14 # * Neither the name of Google Inc. nor the names of its | 14 # * Neither the name of Google Inc. nor the names of its |
15 # contributors may be used to endorse or promote products derived | 15 # contributors may be used to endorse or promote products derived |
16 # from this software without specific prior written permission. | 16 # from this software without specific prior written permission. |
17 # | 17 # |
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 import bisect | |
31 import cmd | 30 import cmd |
32 import codecs | |
33 import ctypes | 31 import ctypes |
34 import disasm | |
35 import mmap | 32 import mmap |
36 import optparse | 33 import optparse |
37 import os | 34 import os |
| 35 import disasm |
| 36 import sys |
| 37 import types |
| 38 import codecs |
38 import re | 39 import re |
39 import struct | 40 import struct |
40 import sys | |
41 import types | |
42 | 41 |
43 | 42 |
44 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] | 43 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] |
45 | 44 |
46 Minidump analyzer. | 45 Minidump analyzer. |
47 | 46 |
48 Shows the processor state at the point of exception including the | 47 Shows the processor state at the point of exception including the |
49 stack of the active thread and the referenced objects in the V8 | 48 stack of the active thread and the referenced objects in the V8 |
50 heap. Code objects are disassembled and the addresses linked from the | 49 heap. Code objects are disassembled and the addresses linked from the |
51 stack (e.g. pushed return addresses) are marked with "=>". | 50 stack (e.g. pushed return addresses) are marked with "=>". |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 ("checksum", ctypes.c_uint32), | 173 ("checksum", ctypes.c_uint32), |
175 ("time_date_stampt", ctypes.c_uint32), | 174 ("time_date_stampt", ctypes.c_uint32), |
176 ("flags", ctypes.c_uint64) | 175 ("flags", ctypes.c_uint64) |
177 ]) | 176 ]) |
178 | 177 |
179 MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ | 178 MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ |
180 ("data_size", ctypes.c_uint32), | 179 ("data_size", ctypes.c_uint32), |
181 ("rva", ctypes.c_uint32) | 180 ("rva", ctypes.c_uint32) |
182 ]) | 181 ]) |
183 | 182 |
184 MINIDUMP_STRING = Descriptor([ | |
185 ("length", ctypes.c_uint32), | |
186 ("buffer", lambda t: ctypes.c_uint8 * (t.length + 2)) | |
187 ]) | |
188 | |
189 MINIDUMP_DIRECTORY = Descriptor([ | 183 MINIDUMP_DIRECTORY = Descriptor([ |
190 ("stream_type", ctypes.c_uint32), | 184 ("stream_type", ctypes.c_uint32), |
191 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 185 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) |
192 ]) | 186 ]) |
193 | 187 |
194 MD_EXCEPTION_MAXIMUM_PARAMETERS = 15 | 188 MD_EXCEPTION_MAXIMUM_PARAMETERS = 15 |
195 | 189 |
196 MINIDUMP_EXCEPTION = Descriptor([ | 190 MINIDUMP_EXCEPTION = Descriptor([ |
197 ("code", ctypes.c_uint32), | 191 ("code", ctypes.c_uint32), |
198 ("flags", ctypes.c_uint32), | 192 ("flags", ctypes.c_uint32), |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 ("ted", ctypes.c_uint64), | 393 ("ted", ctypes.c_uint64), |
400 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), | 394 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), |
401 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 395 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) |
402 ]) | 396 ]) |
403 | 397 |
404 MINIDUMP_THREAD_LIST = Descriptor([ | 398 MINIDUMP_THREAD_LIST = Descriptor([ |
405 ("thread_count", ctypes.c_uint32), | 399 ("thread_count", ctypes.c_uint32), |
406 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) | 400 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) |
407 ]) | 401 ]) |
408 | 402 |
409 MINIDUMP_RAW_MODULE = Descriptor([ | |
410 ("base_of_image", ctypes.c_uint64), | |
411 ("size_of_image", ctypes.c_uint32), | |
412 ("checksum", ctypes.c_uint32), | |
413 ("time_date_stamp", ctypes.c_uint32), | |
414 ("module_name_rva", ctypes.c_uint32), | |
415 ("version_info", ctypes.c_uint32 * 13), | |
416 ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype), | |
417 ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype), | |
418 ("reserved0", ctypes.c_uint32 * 2), | |
419 ("reserved1", ctypes.c_uint32 * 2) | |
420 ]) | |
421 | |
422 MINIDUMP_MODULE_LIST = Descriptor([ | |
423 ("number_of_modules", ctypes.c_uint32), | |
424 ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules) | |
425 ]) | |
426 | |
427 MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ | 403 MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ |
428 ("processor_architecture", ctypes.c_uint16) | 404 ("processor_architecture", ctypes.c_uint16) |
429 ]) | 405 ]) |
430 | 406 |
431 MD_CPU_ARCHITECTURE_X86 = 0 | 407 MD_CPU_ARCHITECTURE_X86 = 0 |
432 MD_CPU_ARCHITECTURE_AMD64 = 9 | 408 MD_CPU_ARCHITECTURE_AMD64 = 9 |
433 | 409 |
434 class FuncSymbol: | |
435 def __init__(self, start, size, name): | |
436 self.start = start | |
437 self.end = self.start + size | |
438 self.name = name | |
439 | |
440 def __cmp__(self, other): | |
441 if isinstance(other, FuncSymbol): | |
442 return self.start - other.start | |
443 return self.start - other | |
444 | |
445 def Covers(self, addr): | |
446 return (self.start <= addr) and (addr < self.end) | |
447 | |
448 class MinidumpReader(object): | 410 class MinidumpReader(object): |
449 """Minidump (.dmp) reader.""" | 411 """Minidump (.dmp) reader.""" |
450 | 412 |
451 _HEADER_MAGIC = 0x504d444d | 413 _HEADER_MAGIC = 0x504d444d |
452 | 414 |
453 def __init__(self, options, minidump_name): | 415 def __init__(self, options, minidump_name): |
454 self.minidump_name = minidump_name | 416 self.minidump_name = minidump_name |
455 self.minidump_file = open(minidump_name, "r") | 417 self.minidump_file = open(minidump_name, "r") |
456 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) | 418 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) |
457 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) | 419 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) |
458 if self.header.signature != MinidumpReader._HEADER_MAGIC: | 420 if self.header.signature != MinidumpReader._HEADER_MAGIC: |
459 print >>sys.stderr, "Warning: Unsupported minidump header magic!" | 421 print >>sys.stderr, "Warning: Unsupported minidump header magic!" |
460 DebugPrint(self.header) | 422 DebugPrint(self.header) |
461 directories = [] | 423 directories = [] |
462 offset = self.header.stream_directories_rva | 424 offset = self.header.stream_directories_rva |
463 for _ in xrange(self.header.stream_count): | 425 for _ in xrange(self.header.stream_count): |
464 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) | 426 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) |
465 offset += MINIDUMP_DIRECTORY.size | 427 offset += MINIDUMP_DIRECTORY.size |
466 self.arch = None | 428 self.arch = None |
467 self.exception = None | 429 self.exception = None |
468 self.exception_context = None | 430 self.exception_context = None |
469 self.memory_list = None | 431 self.memory_list = None |
470 self.memory_list64 = None | 432 self.memory_list64 = None |
471 self.module_list = None | |
472 self.thread_map = {} | 433 self.thread_map = {} |
473 | 434 |
474 self.symdir = options.symdir | |
475 self.modules_with_symbols = [] | |
476 self.symbols = [] | |
477 | |
478 # Find MDRawSystemInfo stream and determine arch. | 435 # Find MDRawSystemInfo stream and determine arch. |
479 for d in directories: | 436 for d in directories: |
480 if d.stream_type == MD_SYSTEM_INFO_STREAM: | 437 if d.stream_type == MD_SYSTEM_INFO_STREAM: |
481 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read( | 438 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read( |
482 self.minidump, d.location.rva) | 439 self.minidump, d.location.rva) |
483 self.arch = system_info.processor_architecture | 440 self.arch = system_info.processor_architecture |
484 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86] | 441 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86] |
485 assert not self.arch is None | 442 assert not self.arch is None |
486 | 443 |
487 for d in directories: | 444 for d in directories: |
488 DebugPrint(d) | 445 DebugPrint(d) |
489 if d.stream_type == MD_EXCEPTION_STREAM: | 446 if d.stream_type == MD_EXCEPTION_STREAM: |
490 self.exception = MINIDUMP_EXCEPTION_STREAM.Read( | 447 self.exception = MINIDUMP_EXCEPTION_STREAM.Read( |
491 self.minidump, d.location.rva) | 448 self.minidump, d.location.rva) |
492 DebugPrint(self.exception) | 449 DebugPrint(self.exception) |
493 if self.arch == MD_CPU_ARCHITECTURE_X86: | 450 if self.arch == MD_CPU_ARCHITECTURE_X86: |
494 self.exception_context = MINIDUMP_CONTEXT_X86.Read( | 451 self.exception_context = MINIDUMP_CONTEXT_X86.Read( |
495 self.minidump, self.exception.thread_context.rva) | 452 self.minidump, self.exception.thread_context.rva) |
496 elif self.arch == MD_CPU_ARCHITECTURE_AMD64: | 453 elif self.arch == MD_CPU_ARCHITECTURE_AMD64: |
497 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read( | 454 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read( |
498 self.minidump, self.exception.thread_context.rva) | 455 self.minidump, self.exception.thread_context.rva) |
499 DebugPrint(self.exception_context) | 456 DebugPrint(self.exception_context) |
500 elif d.stream_type == MD_THREAD_LIST_STREAM: | 457 elif d.stream_type == MD_THREAD_LIST_STREAM: |
501 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) | 458 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) |
502 assert ctypes.sizeof(thread_list) == d.location.data_size | 459 assert ctypes.sizeof(thread_list) == d.location.data_size |
503 DebugPrint(thread_list) | 460 DebugPrint(thread_list) |
504 for thread in thread_list.threads: | 461 for thread in thread_list.threads: |
505 DebugPrint(thread) | 462 DebugPrint(thread) |
506 self.thread_map[thread.id] = thread | 463 self.thread_map[thread.id] = thread |
507 elif d.stream_type == MD_MODULE_LIST_STREAM: | |
508 assert self.module_list is None | |
509 self.module_list = MINIDUMP_MODULE_LIST.Read( | |
510 self.minidump, d.location.rva) | |
511 assert ctypes.sizeof(self.module_list) == d.location.data_size | |
512 elif d.stream_type == MD_MEMORY_LIST_STREAM: | 464 elif d.stream_type == MD_MEMORY_LIST_STREAM: |
513 print >>sys.stderr, "Warning: This is not a full minidump!" | 465 print >>sys.stderr, "Warning: This is not a full minidump!" |
514 assert self.memory_list is None | 466 assert self.memory_list is None |
515 self.memory_list = MINIDUMP_MEMORY_LIST.Read( | 467 self.memory_list = MINIDUMP_MEMORY_LIST.Read( |
516 self.minidump, d.location.rva) | 468 self.minidump, d.location.rva) |
517 assert ctypes.sizeof(self.memory_list) == d.location.data_size | 469 assert ctypes.sizeof(self.memory_list) == d.location.data_size |
518 DebugPrint(self.memory_list) | 470 DebugPrint(self.memory_list) |
519 elif d.stream_type == MD_MEMORY_64_LIST_STREAM: | 471 elif d.stream_type == MD_MEMORY_64_LIST_STREAM: |
520 assert self.memory_list64 is None | 472 assert self.memory_list64 is None |
521 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( | 473 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 | 637 |
686 def PointerSize(self): | 638 def PointerSize(self): |
687 if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 639 if self.arch == MD_CPU_ARCHITECTURE_AMD64: |
688 return 8 | 640 return 8 |
689 elif self.arch == MD_CPU_ARCHITECTURE_X86: | 641 elif self.arch == MD_CPU_ARCHITECTURE_X86: |
690 return 4 | 642 return 4 |
691 | 643 |
692 def Register(self, name): | 644 def Register(self, name): |
693 return self.exception_context.__getattribute__(name) | 645 return self.exception_context.__getattribute__(name) |
694 | 646 |
695 def ReadMinidumpString(self, rva): | |
696 string = bytearray(MINIDUMP_STRING.Read(self.minidump, rva).buffer) | |
697 string = string.decode("utf16") | |
698 return string[0:len(string) - 1] | |
699 | |
700 # Load FUNC records from a BreakPad symbol file | |
701 # | |
702 # http://code.google.com/p/google-breakpad/wiki/SymbolFiles | |
703 # | |
704 def _LoadSymbolsFrom(self, symfile, baseaddr): | |
705 print "Loading symbols from %s" % (symfile) | |
706 funcs = [] | |
707 with open(symfile) as f: | |
708 for line in f: | |
709 result = re.match( | |
710 r"^FUNC ([a-f0-9]+) ([a-f0-9]+) ([a-f0-9]+) (.*)$", line) | |
711 if result is not None: | |
712 start = int(result.group(1), 16) | |
713 size = int(result.group(2), 16) | |
714 name = result.group(4).rstrip() | |
715 bisect.insort_left(self.symbols, | |
716 FuncSymbol(baseaddr + start, size, name)) | |
717 print " ... done" | |
718 | |
719 def TryLoadSymbolsFor(self, modulename, module): | |
720 try: | |
721 symfile = os.path.join(self.symdir, | |
722 modulename.replace('.', '_') + ".pdb.sym") | |
723 self._LoadSymbolsFrom(symfile, module.base_of_image) | |
724 self.modules_with_symbols.append(module) | |
725 except Exception as e: | |
726 print " ... failure (%s)" % (e) | |
727 | |
728 # Returns true if address is covered by some module that has loaded symbols. | |
729 def _IsInModuleWithSymbols(self, addr): | |
730 for module in self.modules_with_symbols: | |
731 start = module.base_of_image | |
732 end = start + module.size_of_image | |
733 if (start <= addr) and (addr < end): | |
734 return True | |
735 return False | |
736 | |
737 # Find symbol covering the given address and return its name in format | |
738 # <symbol name>+<offset from the start> | |
739 def FindSymbol(self, addr): | |
740 if not self._IsInModuleWithSymbols(addr): | |
741 return None | |
742 | |
743 i = bisect.bisect_left(self.symbols, addr) | |
744 symbol = None | |
745 if (0 < i) and self.symbols[i - 1].Covers(addr): | |
746 symbol = self.symbols[i - 1] | |
747 elif (i < len(self.symbols)) and self.symbols[i].Covers(addr): | |
748 symbol = self.symbols[i] | |
749 else: | |
750 return None | |
751 diff = addr - symbol.start | |
752 return "%s+0x%x" % (symbol.name, diff) | |
753 | |
754 | |
755 | 647 |
756 # List of V8 instance types. Obtained by adding the code below to any .cc file. | 648 # List of V8 instance types. Obtained by adding the code below to any .cc file. |
757 # | 649 # |
758 # #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T); | 650 # #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T); |
759 # struct P { | 651 # struct P { |
760 # P() { | 652 # P() { |
761 # printf("INSTANCE_TYPES = {\n"); | 653 # printf("INSTANCE_TYPES = {\n"); |
762 # INSTANCE_TYPE_LIST(DUMP_TYPE) | 654 # INSTANCE_TYPE_LIST(DUMP_TYPE) |
763 # printf("}\n"); | 655 # printf("}\n"); |
764 # } | 656 # } |
(...skipping 975 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1740 EIP_PROXIMITY = 64 | 1632 EIP_PROXIMITY = 64 |
1741 | 1633 |
1742 CONTEXT_FOR_ARCH = { | 1634 CONTEXT_FOR_ARCH = { |
1743 MD_CPU_ARCHITECTURE_AMD64: | 1635 MD_CPU_ARCHITECTURE_AMD64: |
1744 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip', | 1636 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip', |
1745 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'], | 1637 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'], |
1746 MD_CPU_ARCHITECTURE_X86: | 1638 MD_CPU_ARCHITECTURE_X86: |
1747 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] | 1639 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] |
1748 } | 1640 } |
1749 | 1641 |
1750 KNOWN_MODULES = {'chrome.exe', 'chrome.dll'} | |
1751 | |
1752 def GetModuleName(reader, module): | |
1753 name = reader.ReadMinidumpString(module.module_name_rva) | |
1754 return str(os.path.basename(str(name).replace("\\", "/"))) | |
1755 | 1642 |
1756 def AnalyzeMinidump(options, minidump_name): | 1643 def AnalyzeMinidump(options, minidump_name): |
1757 reader = MinidumpReader(options, minidump_name) | 1644 reader = MinidumpReader(options, minidump_name) |
1758 heap = None | 1645 heap = None |
1759 DebugPrint("========================================") | 1646 DebugPrint("========================================") |
1760 if reader.exception is None: | 1647 if reader.exception is None: |
1761 print "Minidump has no exception info" | 1648 print "Minidump has no exception info" |
1762 else: | 1649 else: |
1763 print "Exception info:" | 1650 print "Exception info:" |
1764 exception_thread = reader.thread_map[reader.exception.thread_id] | 1651 exception_thread = reader.thread_map[reader.exception.thread_id] |
1765 print " thread id: %d" % exception_thread.id | 1652 print " thread id: %d" % exception_thread.id |
1766 print " code: %08X" % reader.exception.exception.code | 1653 print " code: %08X" % reader.exception.exception.code |
1767 print " context:" | 1654 print " context:" |
1768 for r in CONTEXT_FOR_ARCH[reader.arch]: | 1655 for r in CONTEXT_FOR_ARCH[reader.arch]: |
1769 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) | 1656 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) |
1770 # TODO(vitalyr): decode eflags. | 1657 # TODO(vitalyr): decode eflags. |
1771 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] | 1658 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] |
1772 print | 1659 print |
1773 print " modules:" | |
1774 for module in reader.module_list.modules: | |
1775 name = GetModuleName(reader, module) | |
1776 if name in KNOWN_MODULES: | |
1777 print " %s at %08X" % (name, module.base_of_image) | |
1778 reader.TryLoadSymbolsFor(name, module) | |
1779 print | |
1780 | 1660 |
1781 stack_top = reader.ExceptionSP() | 1661 stack_top = reader.ExceptionSP() |
1782 stack_bottom = exception_thread.stack.start + \ | 1662 stack_bottom = exception_thread.stack.start + \ |
1783 exception_thread.stack.memory.data_size | 1663 exception_thread.stack.memory.data_size |
1784 stack_map = {reader.ExceptionIP(): -1} | 1664 stack_map = {reader.ExceptionIP(): -1} |
1785 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 1665 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): |
1786 maybe_address = reader.ReadUIntPtr(slot) | 1666 maybe_address = reader.ReadUIntPtr(slot) |
1787 if not maybe_address in stack_map: | 1667 if not maybe_address in stack_map: |
1788 stack_map[maybe_address] = slot | 1668 stack_map[maybe_address] = slot |
1789 heap = V8Heap(reader, stack_map) | 1669 heap = V8Heap(reader, stack_map) |
1790 | 1670 |
1791 print "Disassembly around exception.eip:" | 1671 print "Disassembly around exception.eip:" |
1792 eip_symbol = reader.FindSymbol(reader.ExceptionIP()) | |
1793 if eip_symbol is not None: | |
1794 print eip_symbol | |
1795 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY | 1672 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY |
1796 disasm_bytes = 2 * EIP_PROXIMITY | 1673 disasm_bytes = 2 * EIP_PROXIMITY |
1797 if (options.full): | 1674 if (options.full): |
1798 full_range = reader.FindRegion(reader.ExceptionIP()) | 1675 full_range = reader.FindRegion(reader.ExceptionIP()) |
1799 if full_range is not None: | 1676 if full_range is not None: |
1800 disasm_start = full_range[0] | 1677 disasm_start = full_range[0] |
1801 disasm_bytes = full_range[1] | 1678 disasm_bytes = full_range[1] |
1802 | 1679 |
1803 lines = reader.GetDisasmLines(disasm_start, disasm_bytes) | 1680 lines = reader.GetDisasmLines(disasm_start, disasm_bytes) |
1804 | 1681 |
1805 for line in lines: | 1682 for line in lines: |
1806 print FormatDisasmLine(disasm_start, heap, line) | 1683 print FormatDisasmLine(disasm_start, heap, line) |
1807 print | 1684 print |
1808 | 1685 |
1809 if heap is None: | 1686 if heap is None: |
1810 heap = V8Heap(reader, None) | 1687 heap = V8Heap(reader, None) |
1811 | 1688 |
1812 if options.full: | 1689 if options.full: |
1813 FullDump(reader, heap) | 1690 FullDump(reader, heap) |
1814 | 1691 |
1815 if options.shell: | 1692 if options.shell: |
1816 InspectionShell(reader, heap).cmdloop("type help to get help") | 1693 InspectionShell(reader, heap).cmdloop("type help to get help") |
1817 else: | 1694 else: |
1818 if reader.exception is not None: | 1695 if reader.exception is not None: |
1819 print "Annotated stack (from exception.esp to bottom):" | 1696 print "Annotated stack (from exception.esp to bottom):" |
1820 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 1697 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): |
1821 maybe_address = reader.ReadUIntPtr(slot) | 1698 maybe_address = reader.ReadUIntPtr(slot) |
1822 heap_object = heap.FindObject(maybe_address) | 1699 heap_object = heap.FindObject(maybe_address) |
1823 maybe_symbol = reader.FindSymbol(maybe_address) | 1700 print "%s: %s" % (reader.FormatIntPtr(slot), |
1824 print "%s: %s %s" % (reader.FormatIntPtr(slot), | 1701 reader.FormatIntPtr(maybe_address)) |
1825 reader.FormatIntPtr(maybe_address), | |
1826 maybe_symbol or "") | |
1827 if heap_object: | 1702 if heap_object: |
1828 heap_object.Print(Printer()) | 1703 heap_object.Print(Printer()) |
1829 print | 1704 print |
1830 | 1705 |
1831 reader.Dispose() | 1706 reader.Dispose() |
1832 | 1707 |
1833 | 1708 |
1834 if __name__ == "__main__": | 1709 if __name__ == "__main__": |
1835 parser = optparse.OptionParser(USAGE) | 1710 parser = optparse.OptionParser(USAGE) |
1836 parser.add_option("-s", "--shell", dest="shell", action="store_true", | 1711 parser.add_option("-s", "--shell", dest="shell", action="store_true", |
1837 help="start an interactive inspector shell") | 1712 help="start an interactive inspector shell") |
1838 parser.add_option("-f", "--full", dest="full", action="store_true", | 1713 parser.add_option("-f", "--full", dest="full", action="store_true", |
1839 help="dump all information contained in the minidump") | 1714 help="dump all information contained in the minidump") |
1840 parser.add_option("--symdir", dest="symdir", default=".", | |
1841 help="directory containing *.pdb.sym file with symbols") | |
1842 options, args = parser.parse_args() | 1715 options, args = parser.parse_args() |
1843 if len(args) != 1: | 1716 if len(args) != 1: |
1844 parser.print_help() | 1717 parser.print_help() |
1845 sys.exit(1) | 1718 sys.exit(1) |
1846 AnalyzeMinidump(options, args[0]) | 1719 AnalyzeMinidump(options, args[0]) |
OLD | NEW |