OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2011 the V8 project authors. All rights reserved. | 3 # Copyright 2011 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 cmd |
30 import ctypes | 31 import ctypes |
31 import mmap | 32 import mmap |
32 import optparse | 33 import optparse |
33 import os | 34 import os |
34 import disasm | 35 import disasm |
35 import sys | 36 import sys |
36 import types | 37 import types |
37 import codecs | 38 import codecs |
38 import re | 39 import re |
| 40 import struct |
39 | 41 |
40 | 42 |
41 USAGE="""usage: %prog [OPTION]... | 43 USAGE="""usage: %prog [OPTION]... |
42 | 44 |
43 Minidump analyzer. | 45 Minidump analyzer. |
44 | 46 |
45 Shows the processor state at the point of exception including the | 47 Shows the processor state at the point of exception including the |
46 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 |
47 heap. Code objects are disassembled and the addresses linked from the | 49 heap. Code objects are disassembled and the addresses linked from the |
48 stack (pushed return addresses) are marked with "=>". | 50 stack (pushed return addresses) are marked with "=>". |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 def ReadUIntPtr(self, address): | 439 def ReadUIntPtr(self, address): |
438 if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 440 if self.arch == MD_CPU_ARCHITECTURE_AMD64: |
439 return self.ReadU64(address) | 441 return self.ReadU64(address) |
440 elif self.arch == MD_CPU_ARCHITECTURE_X86: | 442 elif self.arch == MD_CPU_ARCHITECTURE_X86: |
441 return self.ReadU32(address) | 443 return self.ReadU32(address) |
442 | 444 |
443 def ReadBytes(self, address, size): | 445 def ReadBytes(self, address, size): |
444 location = self.FindLocation(address) | 446 location = self.FindLocation(address) |
445 return self.minidump[location:location + size] | 447 return self.minidump[location:location + size] |
446 | 448 |
| 449 def _ReadWord(self, location): |
| 450 if self.arch == MD_CPU_ARCHITECTURE_AMD64: |
| 451 return ctypes.c_uint64.from_buffer(self.minidump, location).value |
| 452 elif self.arch == MD_CPU_ARCHITECTURE_X86: |
| 453 return ctypes.c_uint32.from_buffer(self.minidump, location).value |
| 454 |
| 455 def ForEachMemoryRegion(self, cb): |
| 456 if self.memory_list64 is not None: |
| 457 for r in self.memory_list64.ranges: |
| 458 location = self.memory_list64.base_rva + offset |
| 459 cb(self, r.start, r.size, location) |
| 460 offset += r.size |
| 461 |
| 462 if self.memory_list is not None: |
| 463 for r in self.memory_list.ranges: |
| 464 cb(self, r.start, r.memory.data_size, r.memory.rva) |
| 465 |
| 466 def FindWord(self, word): |
| 467 def search_inside_region(reader, start, size, location): |
| 468 for loc in xrange(location, location + size): |
| 469 if reader._ReadWord(loc) == word: |
| 470 slot = start + (loc - location) |
| 471 print "%s: %s" % (reader.FormatIntPtr(slot), |
| 472 reader.FormatIntPtr(word)) |
| 473 |
| 474 self.ForEachMemoryRegion(search_inside_region) |
| 475 |
447 def FindLocation(self, address): | 476 def FindLocation(self, address): |
448 offset = 0 | 477 offset = 0 |
449 if self.memory_list64 is not None: | 478 if self.memory_list64 is not None: |
450 for r in self.memory_list64.ranges: | 479 for r in self.memory_list64.ranges: |
451 if r.start <= address < r.start + r.size: | 480 if r.start <= address < r.start + r.size: |
452 return self.memory_list64.base_rva + offset + address - r.start | 481 return self.memory_list64.base_rva + offset + address - r.start |
453 offset += r.size | 482 offset += r.size |
454 if self.memory_list is not None: | 483 if self.memory_list is not None: |
455 for r in self.memory_list.ranges: | 484 for r in self.memory_list.ranges: |
456 if r.start <= address < r.start + r.memory.data_size: | 485 if r.start <= address < r.start + r.memory.data_size: |
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1004 | 1033 |
1005 EIP_PROXIMITY = 64 | 1034 EIP_PROXIMITY = 64 |
1006 | 1035 |
1007 CONTEXT_FOR_ARCH = { | 1036 CONTEXT_FOR_ARCH = { |
1008 MD_CPU_ARCHITECTURE_AMD64: | 1037 MD_CPU_ARCHITECTURE_AMD64: |
1009 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'], | 1038 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'], |
1010 MD_CPU_ARCHITECTURE_X86: | 1039 MD_CPU_ARCHITECTURE_X86: |
1011 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] | 1040 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] |
1012 } | 1041 } |
1013 | 1042 |
| 1043 class InspectionShell(cmd.Cmd): |
| 1044 def __init__(self, reader, heap): |
| 1045 cmd.Cmd.__init__(self) |
| 1046 self.reader = reader |
| 1047 self.heap = heap |
| 1048 self.prompt = "(grok) " |
| 1049 |
| 1050 def do_dd(self, address): |
| 1051 """Interpret memory at the given address (if available) |
| 1052 as a sequence of words.""" |
| 1053 start = int(address, 0) |
| 1054 for slot in xrange(start, |
| 1055 start + self.reader.PointerSize() * 10, |
| 1056 self.reader.PointerSize()): |
| 1057 maybe_address = self.reader.ReadUIntPtr(slot) |
| 1058 heap_object = self.heap.FindObject(maybe_address) |
| 1059 print "%s: %s" % (self.reader.FormatIntPtr(slot), |
| 1060 self.reader.FormatIntPtr(maybe_address)) |
| 1061 if heap_object: |
| 1062 heap_object.Print(Printer()) |
| 1063 print |
| 1064 |
| 1065 def do_s(self, word): |
| 1066 "Search for a given word in available memory regions" |
| 1067 word = int(word, 0) |
| 1068 print "searching for word", word |
| 1069 self.reader.FindWord(word) |
| 1070 |
| 1071 def do_list(self, smth): |
| 1072 """List all available memory regions.""" |
| 1073 def print_region(reader, start, size, location): |
| 1074 print "%s - %s" % (reader.FormatIntPtr(start), |
| 1075 reader.FormatIntPtr(start + size)) |
| 1076 |
| 1077 self.reader.ForEachMemoryRegion(print_region) |
| 1078 |
1014 def AnalyzeMinidump(options, minidump_name): | 1079 def AnalyzeMinidump(options, minidump_name): |
1015 reader = MinidumpReader(options, minidump_name) | 1080 reader = MinidumpReader(options, minidump_name) |
1016 DebugPrint("========================================") | 1081 DebugPrint("========================================") |
1017 if reader.exception is None: | 1082 if reader.exception is None: |
1018 print "Minidump has no exception info" | 1083 print "Minidump has no exception info" |
1019 return | 1084 return |
1020 print "Exception info:" | 1085 print "Exception info:" |
1021 exception_thread = reader.thread_map[reader.exception.thread_id] | 1086 exception_thread = reader.thread_map[reader.exception.thread_id] |
1022 print " thread id: %d" % exception_thread.id | 1087 print " thread id: %d" % exception_thread.id |
1023 print " code: %08X" % reader.exception.exception.code | 1088 print " code: %08X" % reader.exception.exception.code |
(...skipping 14 matching lines...) Expand all Loading... |
1038 stack_map[maybe_address] = slot | 1103 stack_map[maybe_address] = slot |
1039 heap = V8Heap(reader, stack_map) | 1104 heap = V8Heap(reader, stack_map) |
1040 | 1105 |
1041 print "Disassembly around exception.eip:" | 1106 print "Disassembly around exception.eip:" |
1042 start = reader.ExceptionIP() - EIP_PROXIMITY | 1107 start = reader.ExceptionIP() - EIP_PROXIMITY |
1043 lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY) | 1108 lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY) |
1044 for line in lines: | 1109 for line in lines: |
1045 print FormatDisasmLine(start, heap, line) | 1110 print FormatDisasmLine(start, heap, line) |
1046 print | 1111 print |
1047 | 1112 |
1048 print "Annotated stack (from exception.esp to bottom):" | 1113 if options.shell: |
1049 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 1114 InspectionShell(reader, heap).cmdloop() |
1050 maybe_address = reader.ReadUIntPtr(slot) | 1115 else: |
1051 heap_object = heap.FindObject(maybe_address) | 1116 print "Annotated stack (from exception.esp to bottom):" |
1052 print "%s: %s" % (reader.FormatIntPtr(slot), | 1117 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): |
1053 reader.FormatIntPtr(maybe_address)) | 1118 maybe_address = reader.ReadUIntPtr(slot) |
1054 if heap_object: | 1119 heap_object = heap.FindObject(maybe_address) |
1055 heap_object.Print(Printer()) | 1120 print "%s: %s" % (reader.FormatIntPtr(slot), |
1056 print | 1121 reader.FormatIntPtr(maybe_address)) |
| 1122 if heap_object: |
| 1123 heap_object.Print(Printer()) |
| 1124 print |
1057 | 1125 |
1058 reader.Dispose() | 1126 reader.Dispose() |
1059 | 1127 |
1060 | 1128 |
1061 if __name__ == "__main__": | 1129 if __name__ == "__main__": |
1062 parser = optparse.OptionParser(USAGE) | 1130 parser = optparse.OptionParser(USAGE) |
| 1131 parser.add_option("-s", "--shell", dest="shell", action="store_true") |
1063 options, args = parser.parse_args() | 1132 options, args = parser.parse_args() |
1064 if len(args) != 1: | 1133 if len(args) != 1: |
1065 parser.print_help() | 1134 parser.print_help() |
1066 sys.exit(1) | 1135 sys.exit(1) |
1067 AnalyzeMinidump(options, args[0]) | 1136 AnalyzeMinidump(options, args[0]) |
OLD | NEW |