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 |