Chromium Code Reviews| 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 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. |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 33 import optparse | 33 import optparse |
| 34 import os | 34 import os |
| 35 import disasm | 35 import disasm |
| 36 import sys | 36 import sys |
| 37 import types | 37 import types |
| 38 import codecs | 38 import codecs |
| 39 import re | 39 import re |
| 40 import struct | 40 import struct |
| 41 | 41 |
| 42 | 42 |
| 43 USAGE="""usage: %prog [OPTION]... | 43 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] |
| 44 | 44 |
| 45 Minidump analyzer. | 45 Minidump analyzer. |
| 46 | 46 |
| 47 Shows the processor state at the point of exception including the | 47 Shows the processor state at the point of exception including the |
| 48 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 |
| 49 heap. Code objects are disassembled and the addresses linked from the | 49 heap. Code objects are disassembled and the addresses linked from the |
| 50 stack (pushed return addresses) are marked with "=>". | 50 stack (e.g. pushed return addresses) are marked with "=>". |
| 51 | |
| 52 | 51 |
| 53 Examples: | 52 Examples: |
| 54 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp | 53 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp""" |
| 55 """ | |
| 56 | 54 |
| 57 | 55 |
| 58 DEBUG=False | 56 DEBUG=False |
| 59 | 57 |
| 60 | 58 |
| 61 def DebugPrint(s): | 59 def DebugPrint(s): |
| 62 if not DEBUG: return | 60 if not DEBUG: return |
| 63 print s | 61 print s |
| 64 | 62 |
| 65 | 63 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 class Raw(ctypes.Structure): | 99 class Raw(ctypes.Structure): |
| 102 _fields_ = fields | 100 _fields_ = fields |
| 103 _pack_ = 1 | 101 _pack_ = 1 |
| 104 | 102 |
| 105 def __str__(self): | 103 def __str__(self): |
| 106 return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field)) | 104 return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field)) |
| 107 for field, _ in Raw._fields_) + "}" | 105 for field, _ in Raw._fields_) + "}" |
| 108 return Raw | 106 return Raw |
| 109 | 107 |
| 110 | 108 |
| 111 def do_dump(reader, heap): | 109 def FullDump(reader, heap): |
| 112 """Dump all available memory regions.""" | 110 """Dump all available memory regions.""" |
| 113 def dump_region(reader, start, size, location): | 111 def dump_region(reader, start, size, location): |
| 114 print | 112 print |
| 115 while start & 3 != 0: | 113 while start & 3 != 0: |
| 116 start += 1 | 114 start += 1 |
| 117 size -= 1 | 115 size -= 1 |
| 118 location += 1 | 116 location += 1 |
| 119 is_executable = reader.IsProbableExecutableRegion(location, size) | 117 is_executable = reader.IsProbableExecutableRegion(location, size) |
| 120 is_ascii = reader.IsProbableASCIIRegion(location, size) | 118 is_ascii = reader.IsProbableASCIIRegion(location, size) |
| 121 | 119 |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 """Minidump (.dmp) reader.""" | 411 """Minidump (.dmp) reader.""" |
| 414 | 412 |
| 415 _HEADER_MAGIC = 0x504d444d | 413 _HEADER_MAGIC = 0x504d444d |
| 416 | 414 |
| 417 def __init__(self, options, minidump_name): | 415 def __init__(self, options, minidump_name): |
| 418 self.minidump_name = minidump_name | 416 self.minidump_name = minidump_name |
| 419 self.minidump_file = open(minidump_name, "r") | 417 self.minidump_file = open(minidump_name, "r") |
| 420 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) |
| 421 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) | 419 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) |
| 422 if self.header.signature != MinidumpReader._HEADER_MAGIC: | 420 if self.header.signature != MinidumpReader._HEADER_MAGIC: |
| 423 print >>sys.stderr, "Warning: unsupported minidump header magic" | 421 print >>sys.stderr, "WARNING: Unsupported minidump header magic!" |
| 424 DebugPrint(self.header) | 422 DebugPrint(self.header) |
| 425 directories = [] | 423 directories = [] |
| 426 offset = self.header.stream_directories_rva | 424 offset = self.header.stream_directories_rva |
| 427 for _ in xrange(self.header.stream_count): | 425 for _ in xrange(self.header.stream_count): |
| 428 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) | 426 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) |
| 429 offset += MINIDUMP_DIRECTORY.size | 427 offset += MINIDUMP_DIRECTORY.size |
| 430 self.arch = None | 428 self.arch = None |
| 431 self.exception = None | 429 self.exception = None |
| 432 self.exception_context = None | 430 self.exception_context = None |
| 433 self.memory_list = None | 431 self.memory_list = None |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 457 self.minidump, self.exception.thread_context.rva) | 455 self.minidump, self.exception.thread_context.rva) |
| 458 DebugPrint(self.exception_context) | 456 DebugPrint(self.exception_context) |
| 459 elif d.stream_type == MD_THREAD_LIST_STREAM: | 457 elif d.stream_type == MD_THREAD_LIST_STREAM: |
| 460 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) | 458 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) |
| 461 assert ctypes.sizeof(thread_list) == d.location.data_size | 459 assert ctypes.sizeof(thread_list) == d.location.data_size |
| 462 DebugPrint(thread_list) | 460 DebugPrint(thread_list) |
| 463 for thread in thread_list.threads: | 461 for thread in thread_list.threads: |
| 464 DebugPrint(thread) | 462 DebugPrint(thread) |
| 465 self.thread_map[thread.id] = thread | 463 self.thread_map[thread.id] = thread |
| 466 elif d.stream_type == MD_MEMORY_LIST_STREAM: | 464 elif d.stream_type == MD_MEMORY_LIST_STREAM: |
| 467 print >>sys.stderr, "Warning: not a full minidump" | 465 print >>sys.stderr, "WARNING: This is NOT a full minidump!" |
|
Erik Corry
2012/05/30 13:06:12
I prefer it if my tools don't SHOUT at me.
Michael Starzinger
2012/05/30 13:14:06
Done.
| |
| 468 assert self.memory_list is None | 466 assert self.memory_list is None |
| 469 self.memory_list = MINIDUMP_MEMORY_LIST.Read( | 467 self.memory_list = MINIDUMP_MEMORY_LIST.Read( |
| 470 self.minidump, d.location.rva) | 468 self.minidump, d.location.rva) |
| 471 assert ctypes.sizeof(self.memory_list) == d.location.data_size | 469 assert ctypes.sizeof(self.memory_list) == d.location.data_size |
| 472 DebugPrint(self.memory_list) | 470 DebugPrint(self.memory_list) |
| 473 elif d.stream_type == MD_MEMORY_64_LIST_STREAM: | 471 elif d.stream_type == MD_MEMORY_64_LIST_STREAM: |
| 474 assert self.memory_list64 is None | 472 assert self.memory_list64 is None |
| 475 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( | 473 self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( |
| 476 self.minidump, d.location.rva) | 474 self.minidump, d.location.rva) |
| 477 assert ctypes.sizeof(self.memory_list64) == d.location.data_size | 475 assert ctypes.sizeof(self.memory_list64) == d.location.data_size |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 570 if self.memory_list64 is not None: | 568 if self.memory_list64 is not None: |
| 571 for r in self.memory_list64.ranges: | 569 for r in self.memory_list64.ranges: |
| 572 location = self.memory_list64.base_rva + offset | 570 location = self.memory_list64.base_rva + offset |
| 573 cb(self, r.start, r.size, location) | 571 cb(self, r.start, r.size, location) |
| 574 offset += r.size | 572 offset += r.size |
| 575 | 573 |
| 576 if self.memory_list is not None: | 574 if self.memory_list is not None: |
| 577 for r in self.memory_list.ranges: | 575 for r in self.memory_list.ranges: |
| 578 cb(self, r.start, r.memory.data_size, r.memory.rva) | 576 cb(self, r.start, r.memory.data_size, r.memory.rva) |
| 579 | 577 |
| 580 def FindWord(self, word): | 578 def FindWord(self, word, alignment=0): |
| 581 def search_inside_region(reader, start, size, location): | 579 def search_inside_region(reader, start, size, location): |
| 582 for loc in xrange(location, location + size): | 580 location = (location + alignment) & ~alignment |
| 581 for loc in xrange(location, location + size - self.PointerSize()): | |
| 583 if reader._ReadWord(loc) == word: | 582 if reader._ReadWord(loc) == word: |
| 584 slot = start + (loc - location) | 583 slot = start + (loc - location) |
| 585 print "%s: %s" % (reader.FormatIntPtr(slot), | 584 print "%s: %s" % (reader.FormatIntPtr(slot), |
| 586 reader.FormatIntPtr(word)) | 585 reader.FormatIntPtr(word)) |
| 587 | |
| 588 self.ForEachMemoryRegion(search_inside_region) | 586 self.ForEachMemoryRegion(search_inside_region) |
| 589 | 587 |
| 590 def FindLocation(self, address): | 588 def FindLocation(self, address): |
| 591 offset = 0 | 589 offset = 0 |
| 592 if self.memory_list64 is not None: | 590 if self.memory_list64 is not None: |
| 593 for r in self.memory_list64.ranges: | 591 for r in self.memory_list64.ranges: |
| 594 if r.start <= address < r.start + r.size: | 592 if r.start <= address < r.start + r.size: |
| 595 return self.memory_list64.base_rva + offset + address - r.start | 593 return self.memory_list64.base_rva + offset + address - r.start |
| 596 offset += r.size | 594 offset += r.size |
| 597 if self.memory_list is not None: | 595 if self.memory_list is not None: |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 149: "ACCESS_CHECK_INFO_TYPE", | 701 149: "ACCESS_CHECK_INFO_TYPE", |
| 704 150: "INTERCEPTOR_INFO_TYPE", | 702 150: "INTERCEPTOR_INFO_TYPE", |
| 705 151: "CALL_HANDLER_INFO_TYPE", | 703 151: "CALL_HANDLER_INFO_TYPE", |
| 706 152: "FUNCTION_TEMPLATE_INFO_TYPE", | 704 152: "FUNCTION_TEMPLATE_INFO_TYPE", |
| 707 153: "OBJECT_TEMPLATE_INFO_TYPE", | 705 153: "OBJECT_TEMPLATE_INFO_TYPE", |
| 708 154: "SIGNATURE_INFO_TYPE", | 706 154: "SIGNATURE_INFO_TYPE", |
| 709 155: "TYPE_SWITCH_INFO_TYPE", | 707 155: "TYPE_SWITCH_INFO_TYPE", |
| 710 156: "SCRIPT_TYPE", | 708 156: "SCRIPT_TYPE", |
| 711 157: "CODE_CACHE_TYPE", | 709 157: "CODE_CACHE_TYPE", |
| 712 158: "POLYMORPHIC_CODE_CACHE_TYPE", | 710 158: "POLYMORPHIC_CODE_CACHE_TYPE", |
| 713 161: "FIXED_ARRAY_TYPE", | 711 159: "TYPE_FEEDBACK_INFO_TYPE", |
| 712 160: "ALIASED_ARGUMENTS_ENTRY_TYPE", | |
| 713 163: "FIXED_ARRAY_TYPE", | |
| 714 145: "FIXED_DOUBLE_ARRAY_TYPE", | 714 145: "FIXED_DOUBLE_ARRAY_TYPE", |
| 715 162: "SHARED_FUNCTION_INFO_TYPE", | 715 164: "SHARED_FUNCTION_INFO_TYPE", |
| 716 163: "JS_MESSAGE_OBJECT_TYPE", | 716 165: "JS_MESSAGE_OBJECT_TYPE", |
| 717 166: "JS_VALUE_TYPE", | 717 168: "JS_VALUE_TYPE", |
| 718 167: "JS_OBJECT_TYPE", | 718 169: "JS_DATE_TYPE", |
| 719 168: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", | 719 170: "JS_OBJECT_TYPE", |
| 720 169: "JS_GLOBAL_OBJECT_TYPE", | 720 171: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", |
| 721 170: "JS_BUILTINS_OBJECT_TYPE", | 721 172: "JS_MODULE_TYPE", |
| 722 171: "JS_GLOBAL_PROXY_TYPE", | 722 173: "JS_GLOBAL_OBJECT_TYPE", |
| 723 172: "JS_ARRAY_TYPE", | 723 174: "JS_BUILTINS_OBJECT_TYPE", |
| 724 165: "JS_PROXY_TYPE", | 724 175: "JS_GLOBAL_PROXY_TYPE", |
| 725 175: "JS_WEAK_MAP_TYPE", | 725 176: "JS_ARRAY_TYPE", |
| 726 176: "JS_REGEXP_TYPE", | 726 167: "JS_PROXY_TYPE", |
| 727 177: "JS_FUNCTION_TYPE", | 727 179: "JS_WEAK_MAP_TYPE", |
| 728 164: "JS_FUNCTION_PROXY_TYPE", | 728 180: "JS_REGEXP_TYPE", |
| 729 159: "DEBUG_INFO_TYPE", | 729 181: "JS_FUNCTION_TYPE", |
| 730 160: "BREAK_POINT_INFO_TYPE", | 730 166: "JS_FUNCTION_PROXY_TYPE", |
| 731 161: "DEBUG_INFO_TYPE", | |
| 732 162: "BREAK_POINT_INFO_TYPE", | |
| 731 } | 733 } |
| 732 | 734 |
| 733 | 735 |
| 736 # List of known V8 maps. Used to determine the instance type and name | |
| 737 # for maps that are part of the root-set and hence on the first page of | |
| 738 # the map-space. Obtained by adding the code below to an IA32 release | |
| 739 # build with enabled snapshots to the end of the Isolate::Init method. | |
| 740 # | |
| 741 # #define ROOT_LIST_CASE(type, name, camel_name) \ | |
| 742 # if (o == heap_.name()) n = #camel_name; | |
| 743 # #define STRUCT_LIST_CASE(upper_name, camel_name, name) \ | |
| 744 # if (o == heap_.name##_map()) n = #camel_name "Map"; | |
| 745 # HeapObjectIterator it(heap_.map_space()); | |
| 746 # printf("KNOWN_MAPS = {\n"); | |
| 747 # for (Object* o = it.Next(); o != NULL; o = it.Next()) { | |
| 748 # Map* m = Map::cast(o); | |
| 749 # const char* n = ""; | |
| 750 # intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff; | |
| 751 # int t = m->instance_type(); | |
| 752 # ROOT_LIST(ROOT_LIST_CASE) | |
| 753 # STRUCT_LIST(STRUCT_LIST_CASE) | |
| 754 # printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n); | |
| 755 # } | |
| 756 # printf("}\n"); | |
| 757 KNOWN_MAPS = { | |
| 758 0x08081: (134, "ByteArrayMap"), | |
| 759 0x080a1: (128, "MetaMap"), | |
| 760 0x080c1: (130, "OddballMap"), | |
| 761 0x080e1: (163, "FixedArrayMap"), | |
| 762 0x08101: (68, "AsciiSymbolMap"), | |
| 763 0x08121: (132, "HeapNumberMap"), | |
| 764 0x08141: (135, "FreeSpaceMap"), | |
| 765 0x08161: (146, "OnePointerFillerMap"), | |
| 766 0x08181: (146, "TwoPointerFillerMap"), | |
| 767 0x081a1: (131, "GlobalPropertyCellMap"), | |
| 768 0x081c1: (164, "SharedFunctionInfoMap"), | |
| 769 0x081e1: (4, "AsciiStringMap"), | |
| 770 0x08201: (163, "GlobalContextMap"), | |
| 771 0x08221: (129, "CodeMap"), | |
| 772 0x08241: (163, "ScopeInfoMap"), | |
| 773 0x08261: (163, "FixedCOWArrayMap"), | |
| 774 0x08281: (145, "FixedDoubleArrayMap"), | |
| 775 0x082a1: (163, "HashTableMap"), | |
| 776 0x082c1: (0, "StringMap"), | |
| 777 0x082e1: (64, "SymbolMap"), | |
| 778 0x08301: (1, "ConsStringMap"), | |
| 779 0x08321: (5, "ConsAsciiStringMap"), | |
| 780 0x08341: (3, "SlicedStringMap"), | |
| 781 0x08361: (7, "SlicedAsciiStringMap"), | |
| 782 0x08381: (65, "ConsSymbolMap"), | |
| 783 0x083a1: (69, "ConsAsciiSymbolMap"), | |
| 784 0x083c1: (66, "ExternalSymbolMap"), | |
| 785 0x083e1: (74, "ExternalSymbolWithAsciiDataMap"), | |
| 786 0x08401: (70, "ExternalAsciiSymbolMap"), | |
| 787 0x08421: (2, "ExternalStringMap"), | |
| 788 0x08441: (10, "ExternalStringWithAsciiDataMap"), | |
| 789 0x08461: (6, "ExternalAsciiStringMap"), | |
| 790 0x08481: (82, "ShortExternalSymbolMap"), | |
| 791 0x084a1: (90, "ShortExternalSymbolWithAsciiDataMap"), | |
| 792 0x084c1: (86, "ShortExternalAsciiSymbolMap"), | |
| 793 0x084e1: (18, "ShortExternalStringMap"), | |
| 794 0x08501: (26, "ShortExternalStringWithAsciiDataMap"), | |
| 795 0x08521: (22, "ShortExternalAsciiStringMap"), | |
| 796 0x08541: (0, "UndetectableStringMap"), | |
| 797 0x08561: (4, "UndetectableAsciiStringMap"), | |
| 798 0x08581: (144, "ExternalPixelArrayMap"), | |
| 799 0x085a1: (136, "ExternalByteArrayMap"), | |
| 800 0x085c1: (137, "ExternalUnsignedByteArrayMap"), | |
| 801 0x085e1: (138, "ExternalShortArrayMap"), | |
| 802 0x08601: (139, "ExternalUnsignedShortArrayMap"), | |
| 803 0x08621: (140, "ExternalIntArrayMap"), | |
| 804 0x08641: (141, "ExternalUnsignedIntArrayMap"), | |
| 805 0x08661: (142, "ExternalFloatArrayMap"), | |
| 806 0x08681: (143, "ExternalDoubleArrayMap"), | |
| 807 0x086a1: (163, "NonStrictArgumentsElementsMap"), | |
| 808 0x086c1: (163, "FunctionContextMap"), | |
| 809 0x086e1: (163, "CatchContextMap"), | |
| 810 0x08701: (163, "WithContextMap"), | |
| 811 0x08721: (163, "BlockContextMap"), | |
| 812 0x08741: (163, "ModuleContextMap"), | |
| 813 0x08761: (165, "JSMessageObjectMap"), | |
| 814 0x08781: (133, "ForeignMap"), | |
| 815 0x087a1: (170, "NeanderMap"), | |
| 816 0x087c1: (158, "PolymorphicCodeCacheMap"), | |
| 817 0x087e1: (156, "ScriptMap"), | |
| 818 0x08801: (147, "AccessorInfoMap"), | |
| 819 0x08821: (148, "AccessorPairMap"), | |
| 820 0x08841: (149, "AccessCheckInfoMap"), | |
| 821 0x08861: (150, "InterceptorInfoMap"), | |
| 822 0x08881: (151, "CallHandlerInfoMap"), | |
| 823 0x088a1: (152, "FunctionTemplateInfoMap"), | |
| 824 0x088c1: (153, "ObjectTemplateInfoMap"), | |
| 825 0x088e1: (154, "SignatureInfoMap"), | |
| 826 0x08901: (155, "TypeSwitchInfoMap"), | |
| 827 0x08921: (157, "CodeCacheMap"), | |
| 828 0x08941: (159, "TypeFeedbackInfoMap"), | |
| 829 0x08961: (160, "AliasedArgumentsEntryMap"), | |
| 830 0x08981: (161, "DebugInfoMap"), | |
| 831 0x089a1: (162, "BreakPointInfoMap"), | |
| 832 } | |
| 833 | |
| 834 | |
| 835 # List of known V8 objects. Used to determine name for objects that are | |
| 836 # part of the root-set and hence on the first page of various old-space | |
| 837 # paged. Obtained by adding the code below to an IA32 release build with | |
| 838 # enabled snapshots to the end of the Isolate::Init method. | |
| 839 # | |
| 840 # #define ROOT_LIST_CASE(type, name, camel_name) \ | |
| 841 # if (o == heap_.name()) n = #camel_name; | |
| 842 # OldSpaces spit; | |
| 843 # printf("KNOWN_OBJECTS = {\n"); | |
| 844 # for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) { | |
| 845 # HeapObjectIterator it(s); | |
| 846 # const char* sname = AllocationSpaceName(s->identity()); | |
| 847 # for (Object* o = it.Next(); o != NULL; o = it.Next()) { | |
| 848 # const char* n = NULL; | |
| 849 # intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff; | |
| 850 # ROOT_LIST(ROOT_LIST_CASE) | |
| 851 # if (n != NULL) { | |
| 852 # printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n); | |
| 853 # } | |
| 854 # } | |
| 855 # } | |
| 856 # printf("}\n"); | |
| 857 KNOWN_OBJECTS = { | |
| 858 ("OLD_POINTER_SPACE", 0x08081): "NullValue", | |
| 859 ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue", | |
| 860 ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap", | |
| 861 ("OLD_POINTER_SPACE", 0x080b1): "TrueValue", | |
| 862 ("OLD_POINTER_SPACE", 0x080c1): "FalseValue", | |
| 863 ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel", | |
| 864 ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker", | |
| 865 ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache", | |
| 866 ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache", | |
| 867 ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache", | |
| 868 ("OLD_POINTER_SPACE", 0x08f09): "TerminationException", | |
| 869 ("OLD_POINTER_SPACE", 0x08f19): "MessageListeners", | |
| 870 ("OLD_POINTER_SPACE", 0x08f35): "CodeStubs", | |
| 871 ("OLD_POINTER_SPACE", 0x09b61): "NonMonomorphicCache", | |
| 872 ("OLD_POINTER_SPACE", 0x0a175): "PolymorphicCodeCache", | |
| 873 ("OLD_POINTER_SPACE", 0x0a17d): "NativesSourceCache", | |
| 874 ("OLD_POINTER_SPACE", 0x0a1bd): "EmptyScript", | |
| 875 ("OLD_POINTER_SPACE", 0x0a1f9): "IntrinsicFunctionNames", | |
| 876 ("OLD_POINTER_SPACE", 0x24a49): "SymbolTable", | |
| 877 ("OLD_DATA_SPACE", 0x08081): "EmptyFixedArray", | |
| 878 ("OLD_DATA_SPACE", 0x080a1): "NanValue", | |
| 879 ("OLD_DATA_SPACE", 0x0811d): "EmptyByteArray", | |
| 880 ("OLD_DATA_SPACE", 0x08125): "EmptyString", | |
| 881 ("OLD_DATA_SPACE", 0x08131): "EmptyDescriptorArray", | |
| 882 ("OLD_DATA_SPACE", 0x08259): "InfinityValue", | |
| 883 ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue", | |
| 884 ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors", | |
| 885 ("CODE_SPACE", 0x12b81): "JsEntryCode", | |
| 886 ("CODE_SPACE", 0x12c61): "JsConstructEntryCode", | |
| 887 } | |
| 888 | |
| 889 | |
| 734 class Printer(object): | 890 class Printer(object): |
| 735 """Printer with indentation support.""" | 891 """Printer with indentation support.""" |
| 736 | 892 |
| 737 def __init__(self): | 893 def __init__(self): |
| 738 self.indent = 0 | 894 self.indent = 0 |
| 739 | 895 |
| 740 def Indent(self): | 896 def Indent(self): |
| 741 self.indent += 2 | 897 self.indent += 2 |
| 742 | 898 |
| 743 def Dedent(self): | 899 def Dedent(self): |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 return self.heap.PointerSize() | 1055 return self.heap.PointerSize() |
| 900 | 1056 |
| 901 def __init__(self, heap, map, address): | 1057 def __init__(self, heap, map, address): |
| 902 HeapObject.__init__(self, heap, map, address) | 1058 HeapObject.__init__(self, heap, map, address) |
| 903 self.to_string = self.ObjectField(self.ToStringOffset()) | 1059 self.to_string = self.ObjectField(self.ToStringOffset()) |
| 904 | 1060 |
| 905 def Print(self, p): | 1061 def Print(self, p): |
| 906 p.Print(str(self)) | 1062 p.Print(str(self)) |
| 907 | 1063 |
| 908 def __str__(self): | 1064 def __str__(self): |
| 909 return "<%s>" % self.to_string.GetChars() | 1065 if self.to_string: |
| 1066 return "Oddball(%08x, <%s>)" % (self.address, self.to_string.GetChars()) | |
| 1067 else: | |
| 1068 return "Oddball(%08x, kind=%s)" % (self.address, "???") | |
| 910 | 1069 |
| 911 | 1070 |
| 912 class FixedArray(HeapObject): | 1071 class FixedArray(HeapObject): |
| 913 def LengthOffset(self): | 1072 def LengthOffset(self): |
| 914 return self.heap.PointerSize() | 1073 return self.heap.PointerSize() |
| 915 | 1074 |
| 916 def ElementsOffset(self): | 1075 def ElementsOffset(self): |
| 917 return self.heap.PointerSize() * 2 | 1076 return self.heap.PointerSize() * 2 |
| 918 | 1077 |
| 919 def __init__(self, heap, map, address): | 1078 def __init__(self, heap, map, address): |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1025 | 1184 |
| 1026 def NameOffset(self): | 1185 def NameOffset(self): |
| 1027 return self.SourceOffset() + self.heap.PointerSize() | 1186 return self.SourceOffset() + self.heap.PointerSize() |
| 1028 | 1187 |
| 1029 def __init__(self, heap, map, address): | 1188 def __init__(self, heap, map, address): |
| 1030 HeapObject.__init__(self, heap, map, address) | 1189 HeapObject.__init__(self, heap, map, address) |
| 1031 self.source = self.ObjectField(self.SourceOffset()) | 1190 self.source = self.ObjectField(self.SourceOffset()) |
| 1032 self.name = self.ObjectField(self.NameOffset()) | 1191 self.name = self.ObjectField(self.NameOffset()) |
| 1033 | 1192 |
| 1034 | 1193 |
| 1194 class CodeCache(HeapObject): | |
| 1195 def DefaultCacheOffset(self): | |
| 1196 return self.heap.PointerSize() | |
| 1197 | |
| 1198 def NormalTypeCacheOffset(self): | |
| 1199 return self.DefaultCacheOffset() + self.heap.PointerSize() | |
| 1200 | |
| 1201 def __init__(self, heap, map, address): | |
| 1202 HeapObject.__init__(self, heap, map, address) | |
| 1203 self.default_cache = self.ObjectField(self.DefaultCacheOffset()) | |
| 1204 self.normal_type_cache = self.ObjectField(self.NormalTypeCacheOffset()) | |
| 1205 | |
| 1206 def Print(self, p): | |
| 1207 p.Print("CodeCache(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | |
| 1208 p.Indent() | |
| 1209 p.Print("default cache: %s" % self.default_cache) | |
| 1210 p.Print("normal type cache: %s" % self.normal_type_cache) | |
| 1211 p.Dedent() | |
| 1212 p.Print("}") | |
| 1213 | |
| 1214 | |
| 1035 class Code(HeapObject): | 1215 class Code(HeapObject): |
| 1036 CODE_ALIGNMENT_MASK = (1 << 5) - 1 | 1216 CODE_ALIGNMENT_MASK = (1 << 5) - 1 |
| 1037 | 1217 |
| 1038 def InstructionSizeOffset(self): | 1218 def InstructionSizeOffset(self): |
| 1039 return self.heap.PointerSize() | 1219 return self.heap.PointerSize() |
| 1040 | 1220 |
| 1041 @staticmethod | 1221 @staticmethod |
| 1042 def HeaderSize(heap): | 1222 def HeaderSize(heap): |
| 1043 return (heap.PointerSize() + heap.IntSize() + \ | 1223 return (heap.PointerSize() + heap.IntSize() + \ |
| 1044 4 * heap.PointerSize() + 3 * heap.IntSize() + \ | 1224 4 * heap.PointerSize() + 3 * heap.IntSize() + \ |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1075 "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString, | 1255 "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString, |
| 1076 "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString, | 1256 "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString, |
| 1077 "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString, | 1257 "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString, |
| 1078 "STRING_TYPE": SeqString, | 1258 "STRING_TYPE": SeqString, |
| 1079 "ASCII_STRING_TYPE": SeqString, | 1259 "ASCII_STRING_TYPE": SeqString, |
| 1080 "CONS_STRING_TYPE": ConsString, | 1260 "CONS_STRING_TYPE": ConsString, |
| 1081 "CONS_ASCII_STRING_TYPE": ConsString, | 1261 "CONS_ASCII_STRING_TYPE": ConsString, |
| 1082 "EXTERNAL_STRING_TYPE": ExternalString, | 1262 "EXTERNAL_STRING_TYPE": ExternalString, |
| 1083 "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString, | 1263 "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString, |
| 1084 "EXTERNAL_ASCII_STRING_TYPE": ExternalString, | 1264 "EXTERNAL_ASCII_STRING_TYPE": ExternalString, |
| 1085 | |
| 1086 "MAP_TYPE": Map, | 1265 "MAP_TYPE": Map, |
| 1087 "ODDBALL_TYPE": Oddball, | 1266 "ODDBALL_TYPE": Oddball, |
| 1088 "FIXED_ARRAY_TYPE": FixedArray, | 1267 "FIXED_ARRAY_TYPE": FixedArray, |
| 1089 "JS_FUNCTION_TYPE": JSFunction, | 1268 "JS_FUNCTION_TYPE": JSFunction, |
| 1090 "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo, | 1269 "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo, |
| 1091 "SCRIPT_TYPE": Script, | 1270 "SCRIPT_TYPE": Script, |
| 1092 "CODE_TYPE": Code | 1271 "CODE_CACHE_TYPE": CodeCache, |
| 1272 "CODE_TYPE": Code, | |
| 1093 } | 1273 } |
| 1094 | 1274 |
| 1095 def __init__(self, reader, stack_map): | 1275 def __init__(self, reader, stack_map): |
| 1096 self.reader = reader | 1276 self.reader = reader |
| 1097 self.stack_map = stack_map | 1277 self.stack_map = stack_map |
| 1098 self.objects = {} | 1278 self.objects = {} |
| 1099 | 1279 |
| 1100 def FindObjectOrSmi(self, tagged_address): | 1280 def FindObjectOrSmi(self, tagged_address): |
| 1101 if (tagged_address & 1) == 0: return tagged_address / 2 | 1281 if (tagged_address & 1) == 0: return tagged_address / 2 |
| 1102 return self.FindObject(tagged_address) | 1282 return self.FindObject(tagged_address) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1140 | 1320 |
| 1141 def ObjectAlignmentMask(self): | 1321 def ObjectAlignmentMask(self): |
| 1142 return self.PointerSize() - 1 | 1322 return self.PointerSize() - 1 |
| 1143 | 1323 |
| 1144 def MapAlignmentMask(self): | 1324 def MapAlignmentMask(self): |
| 1145 if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64: | 1325 if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64: |
| 1146 return (1 << 4) - 1 | 1326 return (1 << 4) - 1 |
| 1147 elif self.reader.arch == MD_CPU_ARCHITECTURE_X86: | 1327 elif self.reader.arch == MD_CPU_ARCHITECTURE_X86: |
| 1148 return (1 << 5) - 1 | 1328 return (1 << 5) - 1 |
| 1149 | 1329 |
| 1330 def PageAlignmentMask(self): | |
| 1331 return (1 << 20) - 1 | |
| 1332 | |
| 1333 | |
| 1334 class KnownObject(HeapObject): | |
| 1335 def __init__(self, heap, known_name): | |
| 1336 HeapObject.__init__(self, heap, None, None) | |
| 1337 self.known_name = known_name | |
| 1338 | |
| 1339 def __str__(self): | |
| 1340 return "<%s>" % self.known_name | |
| 1341 | |
| 1342 | |
| 1343 class KnownMap(HeapObject): | |
| 1344 def __init__(self, heap, known_name, instance_type): | |
| 1345 HeapObject.__init__(self, heap, None, None) | |
| 1346 self.instance_type = instance_type | |
| 1347 self.known_name = known_name | |
| 1348 | |
| 1349 def __str__(self): | |
| 1350 return "<%s>" % self.known_name | |
| 1351 | |
| 1352 | |
| 1353 class InspectionPadawan(object): | |
| 1354 """The padawan can improve annotations by sensing well-known objects.""" | |
| 1355 def __init__(self, reader, heap): | |
| 1356 self.reader = reader | |
| 1357 self.heap = heap | |
| 1358 self.known_first_map_page = 0 | |
| 1359 self.known_first_data_page = 0 | |
| 1360 self.known_first_pointer_page = 0 | |
| 1361 | |
| 1362 def __getattr__(self, name): | |
| 1363 """An InspectionPadawan can be used instead of V8Heap, even though | |
| 1364 it does not inherit from V8Heap (aka. mixin).""" | |
| 1365 return getattr(self.heap, name) | |
| 1366 | |
| 1367 def GetPageOffset(self, tagged_address): | |
| 1368 return tagged_address & self.heap.PageAlignmentMask() | |
| 1369 | |
| 1370 def IsInKnownMapSpace(self, tagged_address): | |
| 1371 page_address = tagged_address & ~self.heap.PageAlignmentMask() | |
| 1372 return page_address == self.known_first_map_page | |
| 1373 | |
| 1374 def IsInKnownOldSpace(self, tagged_address): | |
| 1375 page_address = tagged_address & ~self.heap.PageAlignmentMask() | |
| 1376 return page_address in [self.known_first_data_page, | |
| 1377 self.known_first_pointer_page] | |
| 1378 | |
| 1379 def ContainingKnownOldSpaceName(self, tagged_address): | |
| 1380 page_address = tagged_address & ~self.heap.PageAlignmentMask() | |
| 1381 if page_address == self.known_first_data_page: return "OLD_DATA_SPACE" | |
| 1382 if page_address == self.known_first_pointer_page: return "OLD_POINTER_SPACE" | |
| 1383 return None | |
| 1384 | |
| 1385 def SenseObject(self, tagged_address): | |
| 1386 if self.IsInKnownOldSpace(tagged_address): | |
| 1387 offset = self.GetPageOffset(tagged_address) | |
| 1388 lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset) | |
| 1389 known_obj_name = KNOWN_OBJECTS.get(lookup_key) | |
| 1390 if known_obj_name: | |
| 1391 return KnownObject(self, known_obj_name) | |
| 1392 if self.IsInKnownMapSpace(tagged_address): | |
| 1393 known_map = self.SenseMap(tagged_address) | |
| 1394 if known_map: | |
| 1395 return known_map | |
| 1396 found_obj = self.heap.FindObject(tagged_address) | |
| 1397 if found_obj: return found_ob | |
| 1398 address = tagged_address - 1 | |
| 1399 if self.reader.IsValidAddress(address): | |
| 1400 map_tagged_address = self.reader.ReadUIntPtr(address) | |
| 1401 map = self.SenseMap(map_tagged_address) | |
| 1402 if map is None: return None | |
| 1403 instance_type_name = INSTANCE_TYPES.get(map.instance_type) | |
| 1404 if instance_type_name is None: return None | |
| 1405 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject) | |
| 1406 return cls(self, map, address) | |
| 1407 return None | |
| 1408 | |
| 1409 def SenseMap(self, tagged_address): | |
| 1410 if self.IsInKnownMapSpace(tagged_address): | |
| 1411 offset = self.GetPageOffset(tagged_address) | |
| 1412 known_map_info = KNOWN_MAPS.get(offset) | |
| 1413 if known_map_info: | |
| 1414 known_map_type, known_map_name = known_map_info | |
| 1415 return KnownMap(self, known_map_name, known_map_type) | |
| 1416 found_map = self.heap.FindMap(tagged_address) | |
| 1417 if found_map: return found_map | |
| 1418 return None | |
| 1419 | |
| 1420 def FindObjectOrSmi(self, tagged_address): | |
| 1421 """When used as a mixin in place of V8Heap.""" | |
| 1422 found_obj = self.SenseObject(tagged_address) | |
| 1423 if found_obj: return found_obj | |
| 1424 if (tagged_address & 1) == 0: | |
| 1425 return "Smi(%d)" % (tagged_address / 2) | |
| 1426 else: | |
| 1427 return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address) | |
| 1428 | |
| 1429 def FindObject(self, tagged_address): | |
| 1430 """When used as a mixin in place of V8Heap.""" | |
| 1431 raise NotImplementedError | |
| 1432 | |
| 1433 def FindMap(self, tagged_address): | |
| 1434 """When used as a mixin in place of V8Heap.""" | |
| 1435 raise NotImplementedError | |
| 1436 | |
| 1437 def PrintKnowledge(self): | |
| 1438 print " known_first_map_page = %s\n"\ | |
| 1439 " known_first_data_page = %s\n"\ | |
| 1440 " known_first_pointer_page = %s" % ( | |
| 1441 self.reader.FormatIntPtr(self.known_first_map_page), | |
| 1442 self.reader.FormatIntPtr(self.known_first_data_page), | |
| 1443 self.reader.FormatIntPtr(self.known_first_pointer_page)) | |
| 1444 | |
| 1445 | |
| 1446 class InspectionShell(cmd.Cmd): | |
| 1447 def __init__(self, reader, heap): | |
| 1448 cmd.Cmd.__init__(self) | |
| 1449 self.reader = reader | |
| 1450 self.heap = heap | |
| 1451 self.padawan = InspectionPadawan(reader, heap) | |
| 1452 self.prompt = "(grok) " | |
| 1453 | |
| 1454 def do_dd(self, address): | |
| 1455 """ | |
| 1456 Interpret memory at the given address (if available) as a sequence | |
| 1457 of words. Automatic alignment is NOT performed. | |
| 1458 """ | |
| 1459 start = int(address, 16) | |
| 1460 if (start & self.heap.ObjectAlignmentMask()) != 0: | |
| 1461 print "WARNING: Dumping un-aligned memory, is this what you had in mind?" | |
| 1462 for slot in xrange(start, | |
| 1463 start + self.reader.PointerSize() * 10, | |
| 1464 self.reader.PointerSize()): | |
| 1465 maybe_address = self.reader.ReadUIntPtr(slot) | |
| 1466 heap_object = self.padawan.SenseObject(maybe_address) | |
| 1467 print "%s: %s %s" % (self.reader.FormatIntPtr(slot), | |
| 1468 self.reader.FormatIntPtr(maybe_address), | |
| 1469 heap_object or '') | |
| 1470 | |
| 1471 def do_do(self, address): | |
| 1472 """ | |
| 1473 Interpret memory at the given address as a V8 object. Automatic | |
| 1474 alignment makes sure that you can pass tagged as well as un-tagged | |
| 1475 addresses. | |
| 1476 """ | |
| 1477 address = int(address, 16) | |
| 1478 if (address & self.heap.ObjectAlignmentMask()) == 0: | |
| 1479 address = address + 1 | |
| 1480 elif (address & self.heap.ObjectAlignmentMask()) != 1: | |
| 1481 print "Address doesn't look like a valid pointer!" | |
| 1482 return | |
| 1483 heap_object = self.padawan.SenseObject(address) | |
| 1484 if heap_object: | |
| 1485 heap_object.Print(Printer()) | |
| 1486 else: | |
| 1487 print "Address cannot be interpreted as object!" | |
| 1488 | |
| 1489 def do_dp(self, address): | |
| 1490 """ | |
| 1491 Interpret memory at the given address as being on a V8 heap page | |
| 1492 and print information about the page header (if available). | |
| 1493 """ | |
| 1494 address = int(address, 16) | |
| 1495 page_address = address & ~self.heap.PageAlignmentMask() | |
| 1496 if self.reader.IsValidAddress(page_address): | |
| 1497 raise NotImplementedError | |
| 1498 else: | |
| 1499 print "Page header is not available!" | |
| 1500 | |
| 1501 def do_k(self, arguments): | |
| 1502 """ | |
| 1503 Teach V8 heap layout information to the inspector. This increases | |
| 1504 the amount of annotations the inspector can produce while dumping | |
| 1505 data. The first page of each heap space is of particular interest | |
| 1506 because it contains known objects that do not move. | |
| 1507 """ | |
| 1508 self.padawan.PrintKnowledge() | |
| 1509 | |
| 1510 def do_km(self, address): | |
| 1511 """ | |
| 1512 Teach V8 heap layout information to the inspector. Set the first | |
| 1513 map-space page by passing any pointer into that page. | |
| 1514 """ | |
| 1515 address = int(address, 16) | |
| 1516 page_address = address & ~self.heap.PageAlignmentMask() | |
| 1517 self.padawan.known_first_map_page = page_address | |
| 1518 | |
| 1519 def do_kd(self, address): | |
| 1520 """ | |
| 1521 Teach V8 heap layout information to the inspector. Set the first | |
| 1522 data-space page by passing any pointer into that page. | |
| 1523 """ | |
| 1524 address = int(address, 16) | |
| 1525 page_address = address & ~self.heap.PageAlignmentMask() | |
| 1526 self.padawan.known_first_data_page = page_address | |
| 1527 | |
| 1528 def do_kp(self, address): | |
| 1529 """ | |
| 1530 Teach V8 heap layout information to the inspector. Set the first | |
| 1531 pointer-space page by passing any pointer into that page. | |
| 1532 """ | |
| 1533 address = int(address, 16) | |
| 1534 page_address = address & ~self.heap.PageAlignmentMask() | |
| 1535 self.padawan.known_first_pointer_page = page_address | |
| 1536 | |
| 1537 def do_s(self, word): | |
| 1538 """ | |
| 1539 Search for a given word in available memory regions. The given word | |
| 1540 is expanded to full pointer size and searched at aligned as well as | |
| 1541 un-aligned memory locations. Use 'sa' to search aligned locations | |
| 1542 only. | |
| 1543 """ | |
| 1544 try: | |
| 1545 word = int(word, 0) | |
| 1546 except ValueError: | |
| 1547 print "Malformed word, prefix with '0x' to use hexadecimal format." | |
| 1548 return | |
| 1549 print "Searching for word %d/0x%s:" % (word, self.reader.FormatIntPtr(word)) | |
| 1550 self.reader.FindWord(word) | |
| 1551 | |
| 1552 def do_sh(self, none): | |
| 1553 """ | |
| 1554 Search for the V8 Heap object in all available memory regions. You | |
| 1555 might get lucky and find this rare treasure full of invaluable | |
| 1556 information. | |
| 1557 """ | |
| 1558 raise NotImplementedError | |
| 1559 | |
| 1560 def do_list(self, smth): | |
| 1561 """ | |
| 1562 List all available memory regions. | |
| 1563 """ | |
| 1564 def print_region(reader, start, size, location): | |
| 1565 print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start), | |
| 1566 reader.FormatIntPtr(start + size), | |
| 1567 size) | |
| 1568 print "Available memory regions:" | |
| 1569 self.reader.ForEachMemoryRegion(print_region) | |
| 1570 | |
| 1150 | 1571 |
| 1151 EIP_PROXIMITY = 64 | 1572 EIP_PROXIMITY = 64 |
| 1152 | 1573 |
| 1153 CONTEXT_FOR_ARCH = { | 1574 CONTEXT_FOR_ARCH = { |
| 1154 MD_CPU_ARCHITECTURE_AMD64: | 1575 MD_CPU_ARCHITECTURE_AMD64: |
| 1155 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'], | 1576 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'], |
| 1156 MD_CPU_ARCHITECTURE_X86: | 1577 MD_CPU_ARCHITECTURE_X86: |
| 1157 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] | 1578 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] |
| 1158 } | 1579 } |
| 1159 | 1580 |
| 1160 class InspectionShell(cmd.Cmd): | |
| 1161 def __init__(self, reader, heap): | |
| 1162 cmd.Cmd.__init__(self) | |
| 1163 self.reader = reader | |
| 1164 self.heap = heap | |
| 1165 self.prompt = "(grok) " | |
| 1166 | |
| 1167 def do_dd(self, address): | |
| 1168 "Interpret memory at the given address (if available)"\ | |
| 1169 " as a sequence of words." | |
| 1170 start = int(address, 16) | |
| 1171 for slot in xrange(start, | |
| 1172 start + self.reader.PointerSize() * 10, | |
| 1173 self.reader.PointerSize()): | |
| 1174 maybe_address = self.reader.ReadUIntPtr(slot) | |
| 1175 heap_object = self.heap.FindObject(maybe_address) | |
| 1176 print "%s: %s" % (self.reader.FormatIntPtr(slot), | |
| 1177 self.reader.FormatIntPtr(maybe_address)) | |
| 1178 if heap_object: | |
| 1179 heap_object.Print(Printer()) | |
| 1180 print | |
| 1181 | |
| 1182 def do_s(self, word): | |
| 1183 "Search for a given word in available memory regions" | |
| 1184 word = int(word, 0) | |
| 1185 print "searching for word", word | |
| 1186 self.reader.FindWord(word) | |
| 1187 | |
| 1188 def do_list(self, smth): | |
| 1189 """List all available memory regions.""" | |
| 1190 def print_region(reader, start, size, location): | |
| 1191 print "%s - %s" % (reader.FormatIntPtr(start), | |
| 1192 reader.FormatIntPtr(start + size)) | |
| 1193 | |
| 1194 self.reader.ForEachMemoryRegion(print_region) | |
| 1195 | 1581 |
| 1196 def AnalyzeMinidump(options, minidump_name): | 1582 def AnalyzeMinidump(options, minidump_name): |
| 1197 reader = MinidumpReader(options, minidump_name) | 1583 reader = MinidumpReader(options, minidump_name) |
| 1198 heap = None | 1584 heap = None |
| 1199 DebugPrint("========================================") | 1585 DebugPrint("========================================") |
| 1200 if reader.exception is None: | 1586 if reader.exception is None: |
| 1201 print "Minidump has no exception info" | 1587 print "Minidump has no exception info" |
| 1202 else: | 1588 else: |
| 1203 print "Exception info:" | 1589 print "Exception info:" |
| 1204 exception_thread = reader.thread_map[reader.exception.thread_id] | 1590 exception_thread = reader.thread_map[reader.exception.thread_id] |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1233 lines = reader.GetDisasmLines(disasm_start, disasm_bytes) | 1619 lines = reader.GetDisasmLines(disasm_start, disasm_bytes) |
| 1234 | 1620 |
| 1235 for line in lines: | 1621 for line in lines: |
| 1236 print FormatDisasmLine(disasm_start, heap, line) | 1622 print FormatDisasmLine(disasm_start, heap, line) |
| 1237 print | 1623 print |
| 1238 | 1624 |
| 1239 if heap is None: | 1625 if heap is None: |
| 1240 heap = V8Heap(reader, None) | 1626 heap = V8Heap(reader, None) |
| 1241 | 1627 |
| 1242 if options.full: | 1628 if options.full: |
| 1243 do_dump(reader, heap) | 1629 FullDump(reader, heap) |
| 1244 | 1630 |
| 1245 if options.shell: | 1631 if options.shell: |
| 1246 InspectionShell(reader, heap).cmdloop("type help to get help") | 1632 InspectionShell(reader, heap).cmdloop("type help to get help") |
| 1247 else: | 1633 else: |
| 1248 if reader.exception is not None: | 1634 if reader.exception is not None: |
| 1249 print "Annotated stack (from exception.esp to bottom):" | 1635 print "Annotated stack (from exception.esp to bottom):" |
| 1250 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 1636 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): |
| 1251 maybe_address = reader.ReadUIntPtr(slot) | 1637 maybe_address = reader.ReadUIntPtr(slot) |
| 1252 heap_object = heap.FindObject(maybe_address) | 1638 heap_object = heap.FindObject(maybe_address) |
| 1253 print "%s: %s" % (reader.FormatIntPtr(slot), | 1639 print "%s: %s" % (reader.FormatIntPtr(slot), |
| 1254 reader.FormatIntPtr(maybe_address)) | 1640 reader.FormatIntPtr(maybe_address)) |
| 1255 if heap_object: | 1641 if heap_object: |
| 1256 heap_object.Print(Printer()) | 1642 heap_object.Print(Printer()) |
| 1257 print | 1643 print |
| 1258 | 1644 |
| 1259 reader.Dispose() | 1645 reader.Dispose() |
| 1260 | 1646 |
| 1261 | 1647 |
| 1262 if __name__ == "__main__": | 1648 if __name__ == "__main__": |
| 1263 parser = optparse.OptionParser(USAGE) | 1649 parser = optparse.OptionParser(USAGE) |
| 1264 parser.add_option("-s", "--shell", dest="shell", action="store_true") | 1650 parser.add_option("-s", "--shell", dest="shell", action="store_true", |
| 1265 parser.add_option("-f", "--full", dest="full", action="store_true") | 1651 help="start an interactive inspector shell") |
| 1652 parser.add_option("-f", "--full", dest="full", action="store_true", | |
| 1653 help="dump all information contained in the minidump") | |
| 1266 options, args = parser.parse_args() | 1654 options, args = parser.parse_args() |
| 1267 if len(args) != 1: | 1655 if len(args) != 1: |
| 1268 parser.print_help() | 1656 parser.print_help() |
| 1269 sys.exit(1) | 1657 sys.exit(1) |
| 1270 AnalyzeMinidump(options, args[0]) | 1658 AnalyzeMinidump(options, args[0]) |
| OLD | NEW |