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 | |
30 import cmd | 31 import cmd |
31 import ctypes | 32 import ctypes |
32 import mmap | 33 import mmap |
33 import optparse | 34 import optparse |
34 import os | 35 import os |
35 import disasm | 36 import disasm |
Michael Starzinger
2012/09/19 09:54:32
I know you didn't touch, but can we alpha-sort the
Vyacheslav Egorov (Google)
2012/09/26 12:48:57
Done.
| |
36 import sys | 37 import sys |
37 import types | 38 import types |
38 import codecs | 39 import codecs |
39 import re | 40 import re |
40 import struct | 41 import struct |
41 | 42 |
42 | 43 |
43 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] | 44 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] |
44 | 45 |
45 Minidump analyzer. | 46 Minidump analyzer. |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 ("checksum", ctypes.c_uint32), | 174 ("checksum", ctypes.c_uint32), |
174 ("time_date_stampt", ctypes.c_uint32), | 175 ("time_date_stampt", ctypes.c_uint32), |
175 ("flags", ctypes.c_uint64) | 176 ("flags", ctypes.c_uint64) |
176 ]) | 177 ]) |
177 | 178 |
178 MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ | 179 MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ |
179 ("data_size", ctypes.c_uint32), | 180 ("data_size", ctypes.c_uint32), |
180 ("rva", ctypes.c_uint32) | 181 ("rva", ctypes.c_uint32) |
181 ]) | 182 ]) |
182 | 183 |
184 MINIDUMP_STRING = Descriptor([ | |
185 ("length", ctypes.c_uint32), | |
186 ("buffer", lambda t: ctypes.c_uint8 * (t.length + 2)) | |
187 ]) | |
188 | |
183 MINIDUMP_DIRECTORY = Descriptor([ | 189 MINIDUMP_DIRECTORY = Descriptor([ |
184 ("stream_type", ctypes.c_uint32), | 190 ("stream_type", ctypes.c_uint32), |
185 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 191 ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) |
186 ]) | 192 ]) |
187 | 193 |
188 MD_EXCEPTION_MAXIMUM_PARAMETERS = 15 | 194 MD_EXCEPTION_MAXIMUM_PARAMETERS = 15 |
189 | 195 |
190 MINIDUMP_EXCEPTION = Descriptor([ | 196 MINIDUMP_EXCEPTION = Descriptor([ |
191 ("code", ctypes.c_uint32), | 197 ("code", ctypes.c_uint32), |
192 ("flags", ctypes.c_uint32), | 198 ("flags", ctypes.c_uint32), |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 ("ted", ctypes.c_uint64), | 399 ("ted", ctypes.c_uint64), |
394 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), | 400 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), |
395 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 401 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) |
396 ]) | 402 ]) |
397 | 403 |
398 MINIDUMP_THREAD_LIST = Descriptor([ | 404 MINIDUMP_THREAD_LIST = Descriptor([ |
399 ("thread_count", ctypes.c_uint32), | 405 ("thread_count", ctypes.c_uint32), |
400 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) | 406 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) |
401 ]) | 407 ]) |
402 | 408 |
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 | |
403 MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ | 427 MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ |
404 ("processor_architecture", ctypes.c_uint16) | 428 ("processor_architecture", ctypes.c_uint16) |
405 ]) | 429 ]) |
406 | 430 |
407 MD_CPU_ARCHITECTURE_X86 = 0 | 431 MD_CPU_ARCHITECTURE_X86 = 0 |
408 MD_CPU_ARCHITECTURE_AMD64 = 9 | 432 MD_CPU_ARCHITECTURE_AMD64 = 9 |
409 | 433 |
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 | |
410 class MinidumpReader(object): | 448 class MinidumpReader(object): |
411 """Minidump (.dmp) reader.""" | 449 """Minidump (.dmp) reader.""" |
412 | 450 |
413 _HEADER_MAGIC = 0x504d444d | 451 _HEADER_MAGIC = 0x504d444d |
414 | 452 |
415 def __init__(self, options, minidump_name): | 453 def __init__(self, options, minidump_name): |
416 self.minidump_name = minidump_name | 454 self.minidump_name = minidump_name |
417 self.minidump_file = open(minidump_name, "r") | 455 self.minidump_file = open(minidump_name, "r") |
418 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) | 456 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) |
419 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) | 457 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) |
420 if self.header.signature != MinidumpReader._HEADER_MAGIC: | 458 if self.header.signature != MinidumpReader._HEADER_MAGIC: |
421 print >>sys.stderr, "Warning: Unsupported minidump header magic!" | 459 print >>sys.stderr, "Warning: Unsupported minidump header magic!" |
422 DebugPrint(self.header) | 460 DebugPrint(self.header) |
423 directories = [] | 461 directories = [] |
424 offset = self.header.stream_directories_rva | 462 offset = self.header.stream_directories_rva |
425 for _ in xrange(self.header.stream_count): | 463 for _ in xrange(self.header.stream_count): |
426 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) | 464 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) |
427 offset += MINIDUMP_DIRECTORY.size | 465 offset += MINIDUMP_DIRECTORY.size |
428 self.arch = None | 466 self.arch = None |
429 self.exception = None | 467 self.exception = None |
430 self.exception_context = None | 468 self.exception_context = None |
431 self.memory_list = None | 469 self.memory_list = None |
432 self.memory_list64 = None | 470 self.memory_list64 = None |
471 self.module_list = None | |
433 self.thread_map = {} | 472 self.thread_map = {} |
434 | 473 |
474 self.symdir = options.symdir | |
475 self.modules_with_symbols = [] | |
476 self.symbols = [] | |
477 | |
435 # Find MDRawSystemInfo stream and determine arch. | 478 # Find MDRawSystemInfo stream and determine arch. |
436 for d in directories: | 479 for d in directories: |
437 if d.stream_type == MD_SYSTEM_INFO_STREAM: | 480 if d.stream_type == MD_SYSTEM_INFO_STREAM: |
438 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read( | 481 system_info = MINIDUMP_RAW_SYSTEM_INFO.Read( |
439 self.minidump, d.location.rva) | 482 self.minidump, d.location.rva) |
440 self.arch = system_info.processor_architecture | 483 self.arch = system_info.processor_architecture |
441 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86] | 484 assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86] |
442 assert not self.arch is None | 485 assert not self.arch is None |
443 | 486 |
444 for d in directories: | 487 for d in directories: |
445 DebugPrint(d) | 488 DebugPrint(d) |
446 if d.stream_type == MD_EXCEPTION_STREAM: | 489 if d.stream_type == MD_EXCEPTION_STREAM: |
447 self.exception = MINIDUMP_EXCEPTION_STREAM.Read( | 490 self.exception = MINIDUMP_EXCEPTION_STREAM.Read( |
448 self.minidump, d.location.rva) | 491 self.minidump, d.location.rva) |
449 DebugPrint(self.exception) | 492 DebugPrint(self.exception) |
450 if self.arch == MD_CPU_ARCHITECTURE_X86: | 493 if self.arch == MD_CPU_ARCHITECTURE_X86: |
451 self.exception_context = MINIDUMP_CONTEXT_X86.Read( | 494 self.exception_context = MINIDUMP_CONTEXT_X86.Read( |
452 self.minidump, self.exception.thread_context.rva) | 495 self.minidump, self.exception.thread_context.rva) |
453 elif self.arch == MD_CPU_ARCHITECTURE_AMD64: | 496 elif self.arch == MD_CPU_ARCHITECTURE_AMD64: |
454 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read( | 497 self.exception_context = MINIDUMP_CONTEXT_AMD64.Read( |
455 self.minidump, self.exception.thread_context.rva) | 498 self.minidump, self.exception.thread_context.rva) |
456 DebugPrint(self.exception_context) | 499 DebugPrint(self.exception_context) |
457 elif d.stream_type == MD_THREAD_LIST_STREAM: | 500 elif d.stream_type == MD_THREAD_LIST_STREAM: |
458 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) | 501 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) |
459 assert ctypes.sizeof(thread_list) == d.location.data_size | 502 assert ctypes.sizeof(thread_list) == d.location.data_size |
460 DebugPrint(thread_list) | 503 DebugPrint(thread_list) |
461 for thread in thread_list.threads: | 504 for thread in thread_list.threads: |
462 DebugPrint(thread) | 505 DebugPrint(thread) |
463 self.thread_map[thread.id] = thread | 506 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 | |
464 elif d.stream_type == MD_MEMORY_LIST_STREAM: | 512 elif d.stream_type == MD_MEMORY_LIST_STREAM: |
465 print >>sys.stderr, "Warning: This is not a full minidump!" | 513 print >>sys.stderr, "Warning: This is not a full minidump!" |
466 assert self.memory_list is None | 514 assert self.memory_list is None |
467 self.memory_list = MINIDUMP_MEMORY_LIST.Read( | 515 self.memory_list = MINIDUMP_MEMORY_LIST.Read( |
468 self.minidump, d.location.rva) | 516 self.minidump, d.location.rva) |
469 assert ctypes.sizeof(self.memory_list) == d.location.data_size | 517 assert ctypes.sizeof(self.memory_list) == d.location.data_size |
470 DebugPrint(self.memory_list) | 518 DebugPrint(self.memory_list) |
471 elif d.stream_type == MD_MEMORY_64_LIST_STREAM: | 519 elif d.stream_type == MD_MEMORY_64_LIST_STREAM: |
472 assert self.memory_list64 is None | 520 assert self.memory_list64 is None |
473 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( | 521 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
637 | 685 |
638 def PointerSize(self): | 686 def PointerSize(self): |
639 if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 687 if self.arch == MD_CPU_ARCHITECTURE_AMD64: |
640 return 8 | 688 return 8 |
641 elif self.arch == MD_CPU_ARCHITECTURE_X86: | 689 elif self.arch == MD_CPU_ARCHITECTURE_X86: |
642 return 4 | 690 return 4 |
643 | 691 |
644 def Register(self, name): | 692 def Register(self, name): |
645 return self.exception_context.__getattribute__(name) | 693 return self.exception_context.__getattribute__(name) |
646 | 694 |
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(r"^FUNC ([a-f0-9]+) ([a-f0-9]+) ([a-f0-9]+) (.*)$", li ne) | |
Michael Starzinger
2012/09/19 09:54:32
More than 80 characters.
Vyacheslav Egorov (Google)
2012/09/26 12:48:57
Done.
| |
710 if result is not None: | |
711 start = int(result.group(1), 16) | |
712 size = int(result.group(2), 16) | |
713 name = result.group(4).rstrip() | |
714 bisect.insort_left(self.symbols, FuncSymbol(baseaddr + start, size, na me)) | |
Michael Starzinger
2012/09/19 09:54:32
More than 80 characters.
Vyacheslav Egorov (Google)
2012/09/26 12:48:57
Done.
| |
715 print " ... done" | |
716 | |
717 def TryLoadSymbolsFor(self, modulename, module): | |
718 try: | |
719 symfile = os.path.join(self.symdir, | |
720 modulename.replace('.', '_') + ".pdb.sym") | |
721 self._LoadSymbolsFrom(symfile, module.base_of_image) | |
722 self.modules_with_symbols.append(module) | |
723 except Exception as e: | |
724 print " ... failure (%s)" % (e) | |
725 | |
726 # Returns true if address is covered by some module that has loaded symbols. | |
727 def _IsInModuleWithSymbols(self, addr): | |
728 for module in self.modules_with_symbols: | |
729 start = module.base_of_image | |
730 end = start + module.size_of_image | |
731 if (start <= addr) and (addr < end): | |
732 return True | |
733 return False | |
734 | |
735 # Find symbol covering the given address and return its name in format | |
736 # <symbol name>+<offset from the start> | |
737 def FindSymbol(self, addr): | |
738 if not self._IsInModuleWithSymbols(addr): | |
739 return None | |
740 | |
741 i = bisect.bisect_left(self.symbols, addr) | |
742 symbol = None | |
743 if (0 < i) and self.symbols[i - 1].Covers(addr): | |
744 symbol = self.symbols[i - 1] | |
745 elif (i < len(self.symbols)) and self.symbols[i].Covers(addr): | |
746 symbol = self.symbols[i] | |
747 else: | |
748 return None | |
749 diff = addr - symbol.start | |
750 return "%s+0x%x" % (symbol.name, diff) | |
751 | |
752 | |
647 | 753 |
648 # List of V8 instance types. Obtained by adding the code below to any .cc file. | 754 # List of V8 instance types. Obtained by adding the code below to any .cc file. |
649 # | 755 # |
650 # #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T); | 756 # #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T); |
651 # struct P { | 757 # struct P { |
652 # P() { | 758 # P() { |
653 # printf("INSTANCE_TYPES = {\n"); | 759 # printf("INSTANCE_TYPES = {\n"); |
654 # INSTANCE_TYPE_LIST(DUMP_TYPE) | 760 # INSTANCE_TYPE_LIST(DUMP_TYPE) |
655 # printf("}\n"); | 761 # printf("}\n"); |
656 # } | 762 # } |
(...skipping 975 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1632 EIP_PROXIMITY = 64 | 1738 EIP_PROXIMITY = 64 |
1633 | 1739 |
1634 CONTEXT_FOR_ARCH = { | 1740 CONTEXT_FOR_ARCH = { |
1635 MD_CPU_ARCHITECTURE_AMD64: | 1741 MD_CPU_ARCHITECTURE_AMD64: |
1636 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip', | 1742 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip', |
1637 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'], | 1743 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'], |
1638 MD_CPU_ARCHITECTURE_X86: | 1744 MD_CPU_ARCHITECTURE_X86: |
1639 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] | 1745 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] |
1640 } | 1746 } |
1641 | 1747 |
1748 KNOWN_MODULES = {'chrome.exe', 'chrome.dll'} | |
1749 | |
1750 def GetModuleName(reader, module): | |
1751 name = reader.ReadMinidumpString(module.module_name_rva) | |
1752 return str(os.path.basename(str(name).replace("\\", "/"))) | |
1642 | 1753 |
1643 def AnalyzeMinidump(options, minidump_name): | 1754 def AnalyzeMinidump(options, minidump_name): |
1644 reader = MinidumpReader(options, minidump_name) | 1755 reader = MinidumpReader(options, minidump_name) |
1645 heap = None | 1756 heap = None |
1646 DebugPrint("========================================") | 1757 DebugPrint("========================================") |
1647 if reader.exception is None: | 1758 if reader.exception is None: |
1648 print "Minidump has no exception info" | 1759 print "Minidump has no exception info" |
1649 else: | 1760 else: |
1650 print "Exception info:" | 1761 print "Exception info:" |
1651 exception_thread = reader.thread_map[reader.exception.thread_id] | 1762 exception_thread = reader.thread_map[reader.exception.thread_id] |
1652 print " thread id: %d" % exception_thread.id | 1763 print " thread id: %d" % exception_thread.id |
1653 print " code: %08X" % reader.exception.exception.code | 1764 print " code: %08X" % reader.exception.exception.code |
1654 print " context:" | 1765 print " context:" |
1655 for r in CONTEXT_FOR_ARCH[reader.arch]: | 1766 for r in CONTEXT_FOR_ARCH[reader.arch]: |
1656 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) | 1767 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) |
1657 # TODO(vitalyr): decode eflags. | 1768 # TODO(vitalyr): decode eflags. |
1658 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] | 1769 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] |
1659 print | 1770 print |
Michael Starzinger
2012/09/19 09:54:32
Can we move this empty print to after the modules
Vyacheslav Egorov (Google)
2012/09/26 12:48:57
I will add another one after modules. I like some
| |
1771 print " Modules:" | |
Michael Starzinger
2012/09/19 09:54:32
Lowercase "modules:" would be consistent with the
Vyacheslav Egorov (Google)
2012/09/26 12:48:58
Done.
| |
1772 for module in reader.module_list.modules: | |
1773 name = GetModuleName(reader, module) | |
1774 if name in KNOWN_MODULES: | |
1775 print " %s at %08X" % (name, module.base_of_image) | |
1776 reader.TryLoadSymbolsFor(name, module) | |
1660 | 1777 |
1661 stack_top = reader.ExceptionSP() | 1778 stack_top = reader.ExceptionSP() |
1662 stack_bottom = exception_thread.stack.start + \ | 1779 stack_bottom = exception_thread.stack.start + \ |
1663 exception_thread.stack.memory.data_size | 1780 exception_thread.stack.memory.data_size |
1664 stack_map = {reader.ExceptionIP(): -1} | 1781 stack_map = {reader.ExceptionIP(): -1} |
1665 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 1782 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): |
1666 maybe_address = reader.ReadUIntPtr(slot) | 1783 maybe_address = reader.ReadUIntPtr(slot) |
1667 if not maybe_address in stack_map: | 1784 if not maybe_address in stack_map: |
1668 stack_map[maybe_address] = slot | 1785 stack_map[maybe_address] = slot |
1669 heap = V8Heap(reader, stack_map) | 1786 heap = V8Heap(reader, stack_map) |
1670 | 1787 |
1671 print "Disassembly around exception.eip:" | 1788 print "Disassembly around exception.eip:" |
1789 print reader.FindSymbol(reader.ExceptionIP()) | |
Michael Starzinger
2012/09/19 09:54:32
This will print "None" when no symbol is found, ca
Vyacheslav Egorov (Google)
2012/09/26 12:48:58
Done.
| |
1672 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY | 1790 disasm_start = reader.ExceptionIP() - EIP_PROXIMITY |
1673 disasm_bytes = 2 * EIP_PROXIMITY | 1791 disasm_bytes = 2 * EIP_PROXIMITY |
1674 if (options.full): | 1792 if (options.full): |
1675 full_range = reader.FindRegion(reader.ExceptionIP()) | 1793 full_range = reader.FindRegion(reader.ExceptionIP()) |
1676 if full_range is not None: | 1794 if full_range is not None: |
1677 disasm_start = full_range[0] | 1795 disasm_start = full_range[0] |
1678 disasm_bytes = full_range[1] | 1796 disasm_bytes = full_range[1] |
1679 | 1797 |
1680 lines = reader.GetDisasmLines(disasm_start, disasm_bytes) | 1798 lines = reader.GetDisasmLines(disasm_start, disasm_bytes) |
1681 | 1799 |
1682 for line in lines: | 1800 for line in lines: |
1683 print FormatDisasmLine(disasm_start, heap, line) | 1801 print FormatDisasmLine(disasm_start, heap, line) |
1684 print | 1802 print |
1685 | 1803 |
1686 if heap is None: | 1804 if heap is None: |
1687 heap = V8Heap(reader, None) | 1805 heap = V8Heap(reader, None) |
1688 | 1806 |
1689 if options.full: | 1807 if options.full: |
1690 FullDump(reader, heap) | 1808 FullDump(reader, heap) |
1691 | 1809 |
1692 if options.shell: | 1810 if options.shell: |
1693 InspectionShell(reader, heap).cmdloop("type help to get help") | 1811 InspectionShell(reader, heap).cmdloop("type help to get help") |
1694 else: | 1812 else: |
1695 if reader.exception is not None: | 1813 if reader.exception is not None: |
1696 print "Annotated stack (from exception.esp to bottom):" | 1814 print "Annotated stack (from exception.esp to bottom):" |
1697 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 1815 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): |
1698 maybe_address = reader.ReadUIntPtr(slot) | 1816 maybe_address = reader.ReadUIntPtr(slot) |
1699 heap_object = heap.FindObject(maybe_address) | 1817 heap_object = heap.FindObject(maybe_address) |
1700 print "%s: %s" % (reader.FormatIntPtr(slot), | 1818 maybe_symbol = reader.FindSymbol(maybe_address) |
1701 reader.FormatIntPtr(maybe_address)) | 1819 if maybe_symbol is None: |
1820 maybe_symbol = "" | |
1821 | |
1822 print "%s: %s %s" % (reader.FormatIntPtr(slot), | |
1823 reader.FormatIntPtr(maybe_address), | |
1824 maybe_symbol) | |
Michael Starzinger
2012/09/19 09:54:32
Just use "maybe_symbol or ''" here and drop the if
Vyacheslav Egorov (Google)
2012/09/26 12:48:58
Done.
| |
1702 if heap_object: | 1825 if heap_object: |
1703 heap_object.Print(Printer()) | 1826 heap_object.Print(Printer()) |
1704 print | 1827 print |
1705 | 1828 |
1706 reader.Dispose() | 1829 reader.Dispose() |
1707 | 1830 |
1708 | 1831 |
1709 if __name__ == "__main__": | 1832 if __name__ == "__main__": |
1710 parser = optparse.OptionParser(USAGE) | 1833 parser = optparse.OptionParser(USAGE) |
1711 parser.add_option("-s", "--shell", dest="shell", action="store_true", | 1834 parser.add_option("-s", "--shell", dest="shell", action="store_true", |
1712 help="start an interactive inspector shell") | 1835 help="start an interactive inspector shell") |
1713 parser.add_option("-f", "--full", dest="full", action="store_true", | 1836 parser.add_option("-f", "--full", dest="full", action="store_true", |
1714 help="dump all information contained in the minidump") | 1837 help="dump all information contained in the minidump") |
1838 parser.add_option("--symdir", dest="symdir", default=".", | |
1839 help="directory containing *.pdb.sym file with symbols") | |
1715 options, args = parser.parse_args() | 1840 options, args = parser.parse_args() |
1716 if len(args) != 1: | 1841 if len(args) != 1: |
1717 parser.print_help() | 1842 parser.print_help() |
1718 sys.exit(1) | 1843 sys.exit(1) |
1719 AnalyzeMinidump(options, args[0]) | 1844 AnalyzeMinidump(options, args[0]) |
OLD | NEW |