OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 22 matching lines...) Expand all Loading... |
33 import ctypes | 33 import ctypes |
34 import datetime | 34 import datetime |
35 import disasm | 35 import disasm |
36 import mmap | 36 import mmap |
37 import optparse | 37 import optparse |
38 import os | 38 import os |
39 import re | 39 import re |
40 import struct | 40 import struct |
41 import sys | 41 import sys |
42 import types | 42 import types |
| 43 import v8heapconst |
43 | 44 |
44 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] | 45 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] |
45 | 46 |
46 Minidump analyzer. | 47 Minidump analyzer. |
47 | 48 |
48 Shows the processor state at the point of exception including the | 49 Shows the processor state at the point of exception including the |
49 stack of the active thread and the referenced objects in the V8 | 50 stack of the active thread and the referenced objects in the V8 |
50 heap. Code objects are disassembled and the addresses linked from the | 51 heap. Code objects are disassembled and the addresses linked from the |
51 stack (e.g. pushed return addresses) are marked with "=>". | 52 stack (e.g. pushed return addresses) are marked with "=>". |
52 | 53 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 maybe_address = reader.ReadUIntPtr(slot) | 157 maybe_address = reader.ReadUIntPtr(slot) |
157 heap_object = heap.FindObject(maybe_address) | 158 heap_object = heap.FindObject(maybe_address) |
158 print "%s: %s" % (reader.FormatIntPtr(slot), | 159 print "%s: %s" % (reader.FormatIntPtr(slot), |
159 reader.FormatIntPtr(maybe_address)) | 160 reader.FormatIntPtr(maybe_address)) |
160 if heap_object: | 161 if heap_object: |
161 heap_object.Print(Printer()) | 162 heap_object.Print(Printer()) |
162 print | 163 print |
163 | 164 |
164 reader.ForEachMemoryRegion(dump_region) | 165 reader.ForEachMemoryRegion(dump_region) |
165 | 166 |
| 167 # Heap constants generated by 'make grokdump' in v8heapconst module. |
| 168 INSTANCE_TYPES = v8heapconst.INSTANCE_TYPES |
| 169 KNOWN_MAPS = v8heapconst.KNOWN_MAPS |
| 170 KNOWN_OBJECTS = v8heapconst.KNOWN_OBJECTS |
| 171 |
166 # Set of structures and constants that describe the layout of minidump | 172 # Set of structures and constants that describe the layout of minidump |
167 # files. Based on MSDN and Google Breakpad. | 173 # files. Based on MSDN and Google Breakpad. |
168 | 174 |
169 MINIDUMP_HEADER = Descriptor([ | 175 MINIDUMP_HEADER = Descriptor([ |
170 ("signature", ctypes.c_uint32), | 176 ("signature", ctypes.c_uint32), |
171 ("version", ctypes.c_uint32), | 177 ("version", ctypes.c_uint32), |
172 ("stream_count", ctypes.c_uint32), | 178 ("stream_count", ctypes.c_uint32), |
173 ("stream_directories_rva", ctypes.c_uint32), | 179 ("stream_directories_rva", ctypes.c_uint32), |
174 ("checksum", ctypes.c_uint32), | 180 ("checksum", ctypes.c_uint32), |
175 ("time_date_stampt", ctypes.c_uint32), | 181 ("time_date_stampt", ctypes.c_uint32), |
(...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 if (0 < i) and self.symbols[i - 1].Covers(addr): | 833 if (0 < i) and self.symbols[i - 1].Covers(addr): |
828 symbol = self.symbols[i - 1] | 834 symbol = self.symbols[i - 1] |
829 elif (i < len(self.symbols)) and self.symbols[i].Covers(addr): | 835 elif (i < len(self.symbols)) and self.symbols[i].Covers(addr): |
830 symbol = self.symbols[i] | 836 symbol = self.symbols[i] |
831 else: | 837 else: |
832 return None | 838 return None |
833 diff = addr - symbol.start | 839 diff = addr - symbol.start |
834 return "%s+0x%x" % (symbol.name, diff) | 840 return "%s+0x%x" % (symbol.name, diff) |
835 | 841 |
836 | 842 |
837 | |
838 # List of V8 instance types. Obtained by adding the code below to any .cc file. | |
839 # | |
840 # #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", T, #T); | |
841 # struct P { | |
842 # P() { | |
843 # printf("INSTANCE_TYPES = {\n"); | |
844 # INSTANCE_TYPE_LIST(DUMP_TYPE) | |
845 # printf("}\n"); | |
846 # } | |
847 # }; | |
848 # static P p; | |
849 INSTANCE_TYPES = { | |
850 0: "STRING_TYPE", | |
851 4: "ASCII_STRING_TYPE", | |
852 1: "CONS_STRING_TYPE", | |
853 5: "CONS_ASCII_STRING_TYPE", | |
854 3: "SLICED_STRING_TYPE", | |
855 2: "EXTERNAL_STRING_TYPE", | |
856 6: "EXTERNAL_ASCII_STRING_TYPE", | |
857 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", | |
858 18: "SHORT_EXTERNAL_STRING_TYPE", | |
859 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE", | |
860 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", | |
861 64: "INTERNALIZED_STRING_TYPE", | |
862 68: "ASCII_INTERNALIZED_STRING_TYPE", | |
863 65: "CONS_INTERNALIZED_STRING_TYPE", | |
864 69: "CONS_ASCII_INTERNALIZED_STRING_TYPE", | |
865 66: "EXTERNAL_INTERNALIZED_STRING_TYPE", | |
866 70: "EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE", | |
867 74: "EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE", | |
868 82: "SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE", | |
869 86: "SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE", | |
870 90: "SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE", | |
871 128: "SYMBOL_TYPE", | |
872 129: "MAP_TYPE", | |
873 130: "CODE_TYPE", | |
874 131: "ODDBALL_TYPE", | |
875 132: "JS_GLOBAL_PROPERTY_CELL_TYPE", | |
876 133: "HEAP_NUMBER_TYPE", | |
877 134: "FOREIGN_TYPE", | |
878 135: "BYTE_ARRAY_TYPE", | |
879 136: "FREE_SPACE_TYPE", | |
880 137: "EXTERNAL_BYTE_ARRAY_TYPE", | |
881 138: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", | |
882 139: "EXTERNAL_SHORT_ARRAY_TYPE", | |
883 140: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", | |
884 141: "EXTERNAL_INT_ARRAY_TYPE", | |
885 142: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", | |
886 143: "EXTERNAL_FLOAT_ARRAY_TYPE", | |
887 145: "EXTERNAL_PIXEL_ARRAY_TYPE", | |
888 147: "FILLER_TYPE", | |
889 148: "DECLARED_ACCESSOR_DESCRIPTOR_TYPE", | |
890 149: "DECLARED_ACCESSOR_INFO_TYPE", | |
891 150: "EXECUTABLE_ACCESSOR_INFO_TYPE", | |
892 151: "ACCESSOR_PAIR_TYPE", | |
893 152: "ACCESS_CHECK_INFO_TYPE", | |
894 153: "INTERCEPTOR_INFO_TYPE", | |
895 154: "CALL_HANDLER_INFO_TYPE", | |
896 155: "FUNCTION_TEMPLATE_INFO_TYPE", | |
897 156: "OBJECT_TEMPLATE_INFO_TYPE", | |
898 157: "SIGNATURE_INFO_TYPE", | |
899 158: "TYPE_SWITCH_INFO_TYPE", | |
900 159: "ALLOCATION_SITE_INFO_TYPE", | |
901 160: "SCRIPT_TYPE", | |
902 161: "CODE_CACHE_TYPE", | |
903 162: "POLYMORPHIC_CODE_CACHE_TYPE", | |
904 163: "TYPE_FEEDBACK_INFO_TYPE", | |
905 164: "ALIASED_ARGUMENTS_ENTRY_TYPE", | |
906 167: "FIXED_ARRAY_TYPE", | |
907 146: "FIXED_DOUBLE_ARRAY_TYPE", | |
908 168: "SHARED_FUNCTION_INFO_TYPE", | |
909 169: "JS_MESSAGE_OBJECT_TYPE", | |
910 172: "JS_VALUE_TYPE", | |
911 173: "JS_DATE_TYPE", | |
912 174: "JS_OBJECT_TYPE", | |
913 175: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", | |
914 176: "JS_MODULE_TYPE", | |
915 177: "JS_GLOBAL_OBJECT_TYPE", | |
916 178: "JS_BUILTINS_OBJECT_TYPE", | |
917 179: "JS_GLOBAL_PROXY_TYPE", | |
918 180: "JS_ARRAY_TYPE", | |
919 171: "JS_PROXY_TYPE", | |
920 183: "JS_WEAK_MAP_TYPE", | |
921 184: "JS_WEAK_SET_TYPE", | |
922 185: "JS_REGEXP_TYPE", | |
923 186: "JS_FUNCTION_TYPE", | |
924 170: "JS_FUNCTION_PROXY_TYPE", | |
925 165: "DEBUG_INFO_TYPE", | |
926 166: "BREAK_POINT_INFO_TYPE", | |
927 } | |
928 | |
929 | |
930 # List of known V8 maps. Used to determine the instance type and name | |
931 # for maps that are part of the root-set and hence on the first page of | |
932 # the map-space. Obtained by adding the code below to an IA32 release | |
933 # build with enabled snapshots to the end of the Isolate::Init method. | |
934 # | |
935 # #define ROOT_LIST_CASE(type, name, camel_name) \ | |
936 # if (o == heap_.name()) n = #camel_name; | |
937 # #define STRUCT_LIST_CASE(upper_name, camel_name, name) \ | |
938 # if (o == heap_.name##_map()) n = #camel_name "Map"; | |
939 # HeapObjectIterator it(heap_.map_space()); | |
940 # printf("KNOWN_MAPS = {\n"); | |
941 # for (Object* o = it.Next(); o != NULL; o = it.Next()) { | |
942 # Map* m = Map::cast(o); | |
943 # const char* n = ""; | |
944 # intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff; | |
945 # int t = m->instance_type(); | |
946 # ROOT_LIST(ROOT_LIST_CASE) | |
947 # STRUCT_LIST(STRUCT_LIST_CASE) | |
948 # printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n); | |
949 # } | |
950 # printf("}\n"); | |
951 KNOWN_MAPS = { | |
952 0x08081: (135, "ByteArrayMap"), | |
953 0x080a9: (129, "MetaMap"), | |
954 0x080d1: (131, "OddballMap"), | |
955 0x080f9: (68, "AsciiInternalizedStringMap"), | |
956 0x08121: (167, "FixedArrayMap"), | |
957 0x08149: (133, "HeapNumberMap"), | |
958 0x08171: (136, "FreeSpaceMap"), | |
959 0x08199: (147, "OnePointerFillerMap"), | |
960 0x081c1: (147, "TwoPointerFillerMap"), | |
961 0x081e9: (132, "GlobalPropertyCellMap"), | |
962 0x08211: (168, "SharedFunctionInfoMap"), | |
963 0x08239: (167, "NativeContextMap"), | |
964 0x08261: (130, "CodeMap"), | |
965 0x08289: (167, "ScopeInfoMap"), | |
966 0x082b1: (167, "FixedCOWArrayMap"), | |
967 0x082d9: (146, "FixedDoubleArrayMap"), | |
968 0x08301: (167, "HashTableMap"), | |
969 0x08329: (128, "SymbolMap"), | |
970 0x08351: (0, "StringMap"), | |
971 0x08379: (4, "AsciiStringMap"), | |
972 0x083a1: (1, "ConsStringMap"), | |
973 0x083c9: (5, "ConsAsciiStringMap"), | |
974 0x083f1: (3, "SlicedStringMap"), | |
975 0x08419: (7, "SlicedAsciiStringMap"), | |
976 0x08441: (2, "ExternalStringMap"), | |
977 0x08469: (10, "ExternalStringWithAsciiDataMap"), | |
978 0x08491: (6, "ExternalAsciiStringMap"), | |
979 0x084b9: (18, "ShortExternalStringMap"), | |
980 0x084e1: (26, "ShortExternalStringWithAsciiDataMap"), | |
981 0x08509: (64, "InternalizedStringMap"), | |
982 0x08531: (65, "ConsInternalizedStringMap"), | |
983 0x08559: (69, "ConsAsciiInternalizedStringMap"), | |
984 0x08581: (66, "ExternalInternalizedStringMap"), | |
985 0x085a9: (74, "ExternalInternalizedStringWithAsciiDataMap"), | |
986 0x085d1: (70, "ExternalAsciiInternalizedStringMap"), | |
987 0x085f9: (82, "ShortExternalInternalizedStringMap"), | |
988 0x08621: (90, "ShortExternalInternalizedStringWithAsciiDataMap"), | |
989 0x08649: (86, "ShortExternalAsciiInternalizedStringMap"), | |
990 0x08671: (22, "ShortExternalAsciiStringMap"), | |
991 0x08699: (0, "UndetectableStringMap"), | |
992 0x086c1: (4, "UndetectableAsciiStringMap"), | |
993 0x086e9: (145, "ExternalPixelArrayMap"), | |
994 0x08711: (137, "ExternalByteArrayMap"), | |
995 0x08739: (138, "ExternalUnsignedByteArrayMap"), | |
996 0x08761: (139, "ExternalShortArrayMap"), | |
997 0x08789: (140, "ExternalUnsignedShortArrayMap"), | |
998 0x087b1: (141, "ExternalIntArrayMap"), | |
999 0x087d9: (142, "ExternalUnsignedIntArrayMap"), | |
1000 0x08801: (143, "ExternalFloatArrayMap"), | |
1001 0x08829: (144, "ExternalDoubleArrayMap"), | |
1002 0x08851: (167, "NonStrictArgumentsElementsMap"), | |
1003 0x08879: (167, "FunctionContextMap"), | |
1004 0x088a1: (167, "CatchContextMap"), | |
1005 0x088c9: (167, "WithContextMap"), | |
1006 0x088f1: (167, "BlockContextMap"), | |
1007 0x08919: (167, "ModuleContextMap"), | |
1008 0x08941: (167, "GlobalContextMap"), | |
1009 0x08969: (169, "JSMessageObjectMap"), | |
1010 0x08991: (134, "ForeignMap"), | |
1011 0x089b9: (174, "NeanderMap"), | |
1012 0x089e1: (159, "AllocationSiteInfoMap"), | |
1013 0x08a09: (162, "PolymorphicCodeCacheMap"), | |
1014 0x08a31: (160, "ScriptMap"), | |
1015 0x08a59: (174, ""), | |
1016 0x08a81: (174, "ExternalMap"), | |
1017 0x08aa9: (148, "DeclaredAccessorDescriptorMap"), | |
1018 0x08ad1: (149, "DeclaredAccessorInfoMap"), | |
1019 0x08af9: (150, "ExecutableAccessorInfoMap"), | |
1020 0x08b21: (151, "AccessorPairMap"), | |
1021 0x08b49: (152, "AccessCheckInfoMap"), | |
1022 0x08b71: (153, "InterceptorInfoMap"), | |
1023 0x08b99: (154, "CallHandlerInfoMap"), | |
1024 0x08bc1: (155, "FunctionTemplateInfoMap"), | |
1025 0x08be9: (156, "ObjectTemplateInfoMap"), | |
1026 0x08c11: (157, "SignatureInfoMap"), | |
1027 0x08c39: (158, "TypeSwitchInfoMap"), | |
1028 0x08c61: (161, "CodeCacheMap"), | |
1029 0x08c89: (163, "TypeFeedbackInfoMap"), | |
1030 0x08cb1: (164, "AliasedArgumentsEntryMap"), | |
1031 0x08cd9: (165, "DebugInfoMap"), | |
1032 0x08d01: (166, "BreakPointInfoMap"), | |
1033 } | |
1034 | |
1035 | |
1036 # List of known V8 objects. Used to determine name for objects that are | |
1037 # part of the root-set and hence on the first page of various old-space | |
1038 # paged. Obtained by adding the code below to an IA32 release build with | |
1039 # enabled snapshots to the end of the Isolate::Init method. | |
1040 # | |
1041 # #define ROOT_LIST_CASE(type, name, camel_name) \ | |
1042 # if (o == heap_.name()) n = #camel_name; | |
1043 # OldSpaces spit(heap()); | |
1044 # printf("KNOWN_OBJECTS = {\n"); | |
1045 # for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) { | |
1046 # HeapObjectIterator it(s); | |
1047 # const char* sname = AllocationSpaceName(s->identity()); | |
1048 # for (Object* o = it.Next(); o != NULL; o = it.Next()) { | |
1049 # const char* n = NULL; | |
1050 # intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff; | |
1051 # ROOT_LIST(ROOT_LIST_CASE) | |
1052 # if (n != NULL) { | |
1053 # printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n); | |
1054 # } | |
1055 # } | |
1056 # } | |
1057 # printf("}\n"); | |
1058 KNOWN_OBJECTS = { | |
1059 ("OLD_POINTER_SPACE", 0x08081): "NullValue", | |
1060 ("OLD_POINTER_SPACE", 0x08091): "UndefinedValue", | |
1061 ("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap", | |
1062 ("OLD_POINTER_SPACE", 0x080b1): "TrueValue", | |
1063 ("OLD_POINTER_SPACE", 0x080c1): "FalseValue", | |
1064 ("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel", | |
1065 ("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker", | |
1066 ("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache", | |
1067 ("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache", | |
1068 ("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache", | |
1069 ("OLD_POINTER_SPACE", 0x08f09): "RegExpMultipleCache", | |
1070 ("OLD_POINTER_SPACE", 0x09311): "TerminationException", | |
1071 ("OLD_POINTER_SPACE", 0x09321): "MessageListeners", | |
1072 ("OLD_POINTER_SPACE", 0x0933d): "CodeStubs", | |
1073 ("OLD_POINTER_SPACE", 0x09fa5): "NonMonomorphicCache", | |
1074 ("OLD_POINTER_SPACE", 0x0a5b9): "PolymorphicCodeCache", | |
1075 ("OLD_POINTER_SPACE", 0x0a5c1): "NativesSourceCache", | |
1076 ("OLD_POINTER_SPACE", 0x0a601): "EmptyScript", | |
1077 ("OLD_POINTER_SPACE", 0x0a63d): "IntrinsicFunctionNames", | |
1078 ("OLD_POINTER_SPACE", 0x0d659): "ObservationState", | |
1079 ("OLD_POINTER_SPACE", 0x27415): "SymbolTable", | |
1080 ("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray", | |
1081 ("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray", | |
1082 ("OLD_DATA_SPACE", 0x080a9): "NanValue", | |
1083 ("OLD_DATA_SPACE", 0x08125): "EmptyByteArray", | |
1084 ("OLD_DATA_SPACE", 0x0812d): "EmptyString", | |
1085 ("OLD_DATA_SPACE", 0x08259): "InfinityValue", | |
1086 ("OLD_DATA_SPACE", 0x08265): "MinusZeroValue", | |
1087 ("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors", | |
1088 ("CODE_SPACE", 0x0aea1): "JsEntryCode", | |
1089 ("CODE_SPACE", 0x0b5c1): "JsConstructEntryCode", | |
1090 } | |
1091 | |
1092 | |
1093 class Printer(object): | 843 class Printer(object): |
1094 """Printer with indentation support.""" | 844 """Printer with indentation support.""" |
1095 | 845 |
1096 def __init__(self): | 846 def __init__(self): |
1097 self.indent = 0 | 847 self.indent = 0 |
1098 | 848 |
1099 def Indent(self): | 849 def Indent(self): |
1100 self.indent += 2 | 850 self.indent += 2 |
1101 | 851 |
1102 def Dedent(self): | 852 def Dedent(self): |
(...skipping 1129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2232 options, args = parser.parse_args() | 1982 options, args = parser.parse_args() |
2233 if os.path.exists(options.objdump): | 1983 if os.path.exists(options.objdump): |
2234 disasm.OBJDUMP_BIN = options.objdump | 1984 disasm.OBJDUMP_BIN = options.objdump |
2235 OBJDUMP_BIN = options.objdump | 1985 OBJDUMP_BIN = options.objdump |
2236 else: | 1986 else: |
2237 print "Cannot find %s, falling back to default objdump" % options.objdump | 1987 print "Cannot find %s, falling back to default objdump" % options.objdump |
2238 if len(args) != 1: | 1988 if len(args) != 1: |
2239 parser.print_help() | 1989 parser.print_help() |
2240 sys.exit(1) | 1990 sys.exit(1) |
2241 AnalyzeMinidump(options, args[0]) | 1991 AnalyzeMinidump(options, args[0]) |
OLD | NEW |