Implement grokdump annotations for well-known objects.
R=ulan@chromium.org TEST=tools/grokdump.py Review URL: https://chromiumcodereview.appspot.com/10441088 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11684 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
75f35d3fe1
commit
dd81e9e29a
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2011 the V8 project authors. All rights reserved.
|
||||
# Copyright 2012 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
@ -40,19 +40,17 @@ import re
|
||||
import struct
|
||||
|
||||
|
||||
USAGE="""usage: %prog [OPTION]...
|
||||
USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
|
||||
|
||||
Minidump analyzer.
|
||||
|
||||
Shows the processor state at the point of exception including the
|
||||
stack of the active thread and the referenced objects in the V8
|
||||
heap. Code objects are disassembled and the addresses linked from the
|
||||
stack (pushed return addresses) are marked with "=>".
|
||||
|
||||
stack (e.g. pushed return addresses) are marked with "=>".
|
||||
|
||||
Examples:
|
||||
$ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp
|
||||
"""
|
||||
$ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp"""
|
||||
|
||||
|
||||
DEBUG=False
|
||||
@ -108,7 +106,7 @@ class Descriptor(object):
|
||||
return Raw
|
||||
|
||||
|
||||
def do_dump(reader, heap):
|
||||
def FullDump(reader, heap):
|
||||
"""Dump all available memory regions."""
|
||||
def dump_region(reader, start, size, location):
|
||||
print
|
||||
@ -420,7 +418,7 @@ class MinidumpReader(object):
|
||||
self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE)
|
||||
self.header = MINIDUMP_HEADER.Read(self.minidump, 0)
|
||||
if self.header.signature != MinidumpReader._HEADER_MAGIC:
|
||||
print >>sys.stderr, "Warning: unsupported minidump header magic"
|
||||
print >>sys.stderr, "Warning: Unsupported minidump header magic!"
|
||||
DebugPrint(self.header)
|
||||
directories = []
|
||||
offset = self.header.stream_directories_rva
|
||||
@ -464,7 +462,7 @@ class MinidumpReader(object):
|
||||
DebugPrint(thread)
|
||||
self.thread_map[thread.id] = thread
|
||||
elif d.stream_type == MD_MEMORY_LIST_STREAM:
|
||||
print >>sys.stderr, "Warning: not a full minidump"
|
||||
print >>sys.stderr, "Warning: This is not a full minidump!"
|
||||
assert self.memory_list is None
|
||||
self.memory_list = MINIDUMP_MEMORY_LIST.Read(
|
||||
self.minidump, d.location.rva)
|
||||
@ -577,14 +575,14 @@ class MinidumpReader(object):
|
||||
for r in self.memory_list.ranges:
|
||||
cb(self, r.start, r.memory.data_size, r.memory.rva)
|
||||
|
||||
def FindWord(self, word):
|
||||
def FindWord(self, word, alignment=0):
|
||||
def search_inside_region(reader, start, size, location):
|
||||
for loc in xrange(location, location + size):
|
||||
location = (location + alignment) & ~alignment
|
||||
for loc in xrange(location, location + size - self.PointerSize()):
|
||||
if reader._ReadWord(loc) == word:
|
||||
slot = start + (loc - location)
|
||||
print "%s: %s" % (reader.FormatIntPtr(slot),
|
||||
reader.FormatIntPtr(word))
|
||||
|
||||
self.ForEachMemoryRegion(search_inside_region)
|
||||
|
||||
def FindLocation(self, address):
|
||||
@ -710,24 +708,182 @@ INSTANCE_TYPES = {
|
||||
156: "SCRIPT_TYPE",
|
||||
157: "CODE_CACHE_TYPE",
|
||||
158: "POLYMORPHIC_CODE_CACHE_TYPE",
|
||||
161: "FIXED_ARRAY_TYPE",
|
||||
159: "TYPE_FEEDBACK_INFO_TYPE",
|
||||
160: "ALIASED_ARGUMENTS_ENTRY_TYPE",
|
||||
163: "FIXED_ARRAY_TYPE",
|
||||
145: "FIXED_DOUBLE_ARRAY_TYPE",
|
||||
162: "SHARED_FUNCTION_INFO_TYPE",
|
||||
163: "JS_MESSAGE_OBJECT_TYPE",
|
||||
166: "JS_VALUE_TYPE",
|
||||
167: "JS_OBJECT_TYPE",
|
||||
168: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
|
||||
169: "JS_GLOBAL_OBJECT_TYPE",
|
||||
170: "JS_BUILTINS_OBJECT_TYPE",
|
||||
171: "JS_GLOBAL_PROXY_TYPE",
|
||||
172: "JS_ARRAY_TYPE",
|
||||
165: "JS_PROXY_TYPE",
|
||||
175: "JS_WEAK_MAP_TYPE",
|
||||
176: "JS_REGEXP_TYPE",
|
||||
177: "JS_FUNCTION_TYPE",
|
||||
164: "JS_FUNCTION_PROXY_TYPE",
|
||||
159: "DEBUG_INFO_TYPE",
|
||||
160: "BREAK_POINT_INFO_TYPE",
|
||||
164: "SHARED_FUNCTION_INFO_TYPE",
|
||||
165: "JS_MESSAGE_OBJECT_TYPE",
|
||||
168: "JS_VALUE_TYPE",
|
||||
169: "JS_DATE_TYPE",
|
||||
170: "JS_OBJECT_TYPE",
|
||||
171: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
|
||||
172: "JS_MODULE_TYPE",
|
||||
173: "JS_GLOBAL_OBJECT_TYPE",
|
||||
174: "JS_BUILTINS_OBJECT_TYPE",
|
||||
175: "JS_GLOBAL_PROXY_TYPE",
|
||||
176: "JS_ARRAY_TYPE",
|
||||
167: "JS_PROXY_TYPE",
|
||||
179: "JS_WEAK_MAP_TYPE",
|
||||
180: "JS_REGEXP_TYPE",
|
||||
181: "JS_FUNCTION_TYPE",
|
||||
166: "JS_FUNCTION_PROXY_TYPE",
|
||||
161: "DEBUG_INFO_TYPE",
|
||||
162: "BREAK_POINT_INFO_TYPE",
|
||||
}
|
||||
|
||||
|
||||
# List of known V8 maps. Used to determine the instance type and name
|
||||
# for maps that are part of the root-set and hence on the first page of
|
||||
# the map-space. Obtained by adding the code below to an IA32 release
|
||||
# build with enabled snapshots to the end of the Isolate::Init method.
|
||||
#
|
||||
# #define ROOT_LIST_CASE(type, name, camel_name) \
|
||||
# if (o == heap_.name()) n = #camel_name;
|
||||
# #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
|
||||
# if (o == heap_.name##_map()) n = #camel_name "Map";
|
||||
# HeapObjectIterator it(heap_.map_space());
|
||||
# printf("KNOWN_MAPS = {\n");
|
||||
# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
|
||||
# Map* m = Map::cast(o);
|
||||
# const char* n = "";
|
||||
# intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
|
||||
# int t = m->instance_type();
|
||||
# ROOT_LIST(ROOT_LIST_CASE)
|
||||
# STRUCT_LIST(STRUCT_LIST_CASE)
|
||||
# printf(" 0x%05x: (%d, \"%s\"),\n", p, t, n);
|
||||
# }
|
||||
# printf("}\n");
|
||||
KNOWN_MAPS = {
|
||||
0x08081: (134, "ByteArrayMap"),
|
||||
0x080a1: (128, "MetaMap"),
|
||||
0x080c1: (130, "OddballMap"),
|
||||
0x080e1: (163, "FixedArrayMap"),
|
||||
0x08101: (68, "AsciiSymbolMap"),
|
||||
0x08121: (132, "HeapNumberMap"),
|
||||
0x08141: (135, "FreeSpaceMap"),
|
||||
0x08161: (146, "OnePointerFillerMap"),
|
||||
0x08181: (146, "TwoPointerFillerMap"),
|
||||
0x081a1: (131, "GlobalPropertyCellMap"),
|
||||
0x081c1: (164, "SharedFunctionInfoMap"),
|
||||
0x081e1: (4, "AsciiStringMap"),
|
||||
0x08201: (163, "GlobalContextMap"),
|
||||
0x08221: (129, "CodeMap"),
|
||||
0x08241: (163, "ScopeInfoMap"),
|
||||
0x08261: (163, "FixedCOWArrayMap"),
|
||||
0x08281: (145, "FixedDoubleArrayMap"),
|
||||
0x082a1: (163, "HashTableMap"),
|
||||
0x082c1: (0, "StringMap"),
|
||||
0x082e1: (64, "SymbolMap"),
|
||||
0x08301: (1, "ConsStringMap"),
|
||||
0x08321: (5, "ConsAsciiStringMap"),
|
||||
0x08341: (3, "SlicedStringMap"),
|
||||
0x08361: (7, "SlicedAsciiStringMap"),
|
||||
0x08381: (65, "ConsSymbolMap"),
|
||||
0x083a1: (69, "ConsAsciiSymbolMap"),
|
||||
0x083c1: (66, "ExternalSymbolMap"),
|
||||
0x083e1: (74, "ExternalSymbolWithAsciiDataMap"),
|
||||
0x08401: (70, "ExternalAsciiSymbolMap"),
|
||||
0x08421: (2, "ExternalStringMap"),
|
||||
0x08441: (10, "ExternalStringWithAsciiDataMap"),
|
||||
0x08461: (6, "ExternalAsciiStringMap"),
|
||||
0x08481: (82, "ShortExternalSymbolMap"),
|
||||
0x084a1: (90, "ShortExternalSymbolWithAsciiDataMap"),
|
||||
0x084c1: (86, "ShortExternalAsciiSymbolMap"),
|
||||
0x084e1: (18, "ShortExternalStringMap"),
|
||||
0x08501: (26, "ShortExternalStringWithAsciiDataMap"),
|
||||
0x08521: (22, "ShortExternalAsciiStringMap"),
|
||||
0x08541: (0, "UndetectableStringMap"),
|
||||
0x08561: (4, "UndetectableAsciiStringMap"),
|
||||
0x08581: (144, "ExternalPixelArrayMap"),
|
||||
0x085a1: (136, "ExternalByteArrayMap"),
|
||||
0x085c1: (137, "ExternalUnsignedByteArrayMap"),
|
||||
0x085e1: (138, "ExternalShortArrayMap"),
|
||||
0x08601: (139, "ExternalUnsignedShortArrayMap"),
|
||||
0x08621: (140, "ExternalIntArrayMap"),
|
||||
0x08641: (141, "ExternalUnsignedIntArrayMap"),
|
||||
0x08661: (142, "ExternalFloatArrayMap"),
|
||||
0x08681: (143, "ExternalDoubleArrayMap"),
|
||||
0x086a1: (163, "NonStrictArgumentsElementsMap"),
|
||||
0x086c1: (163, "FunctionContextMap"),
|
||||
0x086e1: (163, "CatchContextMap"),
|
||||
0x08701: (163, "WithContextMap"),
|
||||
0x08721: (163, "BlockContextMap"),
|
||||
0x08741: (163, "ModuleContextMap"),
|
||||
0x08761: (165, "JSMessageObjectMap"),
|
||||
0x08781: (133, "ForeignMap"),
|
||||
0x087a1: (170, "NeanderMap"),
|
||||
0x087c1: (158, "PolymorphicCodeCacheMap"),
|
||||
0x087e1: (156, "ScriptMap"),
|
||||
0x08801: (147, "AccessorInfoMap"),
|
||||
0x08821: (148, "AccessorPairMap"),
|
||||
0x08841: (149, "AccessCheckInfoMap"),
|
||||
0x08861: (150, "InterceptorInfoMap"),
|
||||
0x08881: (151, "CallHandlerInfoMap"),
|
||||
0x088a1: (152, "FunctionTemplateInfoMap"),
|
||||
0x088c1: (153, "ObjectTemplateInfoMap"),
|
||||
0x088e1: (154, "SignatureInfoMap"),
|
||||
0x08901: (155, "TypeSwitchInfoMap"),
|
||||
0x08921: (157, "CodeCacheMap"),
|
||||
0x08941: (159, "TypeFeedbackInfoMap"),
|
||||
0x08961: (160, "AliasedArgumentsEntryMap"),
|
||||
0x08981: (161, "DebugInfoMap"),
|
||||
0x089a1: (162, "BreakPointInfoMap"),
|
||||
}
|
||||
|
||||
|
||||
# List of known V8 objects. Used to determine name for objects that are
|
||||
# part of the root-set and hence on the first page of various old-space
|
||||
# paged. Obtained by adding the code below to an IA32 release build with
|
||||
# enabled snapshots to the end of the Isolate::Init method.
|
||||
#
|
||||
# #define ROOT_LIST_CASE(type, name, camel_name) \
|
||||
# if (o == heap_.name()) n = #camel_name;
|
||||
# OldSpaces spit;
|
||||
# printf("KNOWN_OBJECTS = {\n");
|
||||
# for (PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
|
||||
# HeapObjectIterator it(s);
|
||||
# const char* sname = AllocationSpaceName(s->identity());
|
||||
# for (Object* o = it.Next(); o != NULL; o = it.Next()) {
|
||||
# const char* n = NULL;
|
||||
# intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
|
||||
# ROOT_LIST(ROOT_LIST_CASE)
|
||||
# if (n != NULL) {
|
||||
# printf(" (\"%s\", 0x%05x): \"%s\",\n", sname, p, n);
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# printf("}\n");
|
||||
KNOWN_OBJECTS = {
|
||||
("OLD_POINTER_SPACE", 0x08081): "NullValue",
|
||||
("OLD_POINTER_SPACE", 0x08091): "UndefinedValue",
|
||||
("OLD_POINTER_SPACE", 0x080a1): "InstanceofCacheMap",
|
||||
("OLD_POINTER_SPACE", 0x080b1): "TrueValue",
|
||||
("OLD_POINTER_SPACE", 0x080c1): "FalseValue",
|
||||
("OLD_POINTER_SPACE", 0x080d1): "NoInterceptorResultSentinel",
|
||||
("OLD_POINTER_SPACE", 0x080e1): "ArgumentsMarker",
|
||||
("OLD_POINTER_SPACE", 0x080f1): "NumberStringCache",
|
||||
("OLD_POINTER_SPACE", 0x088f9): "SingleCharacterStringCache",
|
||||
("OLD_POINTER_SPACE", 0x08b01): "StringSplitCache",
|
||||
("OLD_POINTER_SPACE", 0x08f09): "TerminationException",
|
||||
("OLD_POINTER_SPACE", 0x08f19): "MessageListeners",
|
||||
("OLD_POINTER_SPACE", 0x08f35): "CodeStubs",
|
||||
("OLD_POINTER_SPACE", 0x09b61): "NonMonomorphicCache",
|
||||
("OLD_POINTER_SPACE", 0x0a175): "PolymorphicCodeCache",
|
||||
("OLD_POINTER_SPACE", 0x0a17d): "NativesSourceCache",
|
||||
("OLD_POINTER_SPACE", 0x0a1bd): "EmptyScript",
|
||||
("OLD_POINTER_SPACE", 0x0a1f9): "IntrinsicFunctionNames",
|
||||
("OLD_POINTER_SPACE", 0x24a49): "SymbolTable",
|
||||
("OLD_DATA_SPACE", 0x08081): "EmptyFixedArray",
|
||||
("OLD_DATA_SPACE", 0x080a1): "NanValue",
|
||||
("OLD_DATA_SPACE", 0x0811d): "EmptyByteArray",
|
||||
("OLD_DATA_SPACE", 0x08125): "EmptyString",
|
||||
("OLD_DATA_SPACE", 0x08131): "EmptyDescriptorArray",
|
||||
("OLD_DATA_SPACE", 0x08259): "InfinityValue",
|
||||
("OLD_DATA_SPACE", 0x08265): "MinusZeroValue",
|
||||
("OLD_DATA_SPACE", 0x08271): "PrototypeAccessors",
|
||||
("CODE_SPACE", 0x12b81): "JsEntryCode",
|
||||
("CODE_SPACE", 0x12c61): "JsConstructEntryCode",
|
||||
}
|
||||
|
||||
|
||||
@ -906,7 +1062,10 @@ class Oddball(HeapObject):
|
||||
p.Print(str(self))
|
||||
|
||||
def __str__(self):
|
||||
return "<%s>" % self.to_string.GetChars()
|
||||
if self.to_string:
|
||||
return "Oddball(%08x, <%s>)" % (self.address, self.to_string.GetChars())
|
||||
else:
|
||||
return "Oddball(%08x, kind=%s)" % (self.address, "???")
|
||||
|
||||
|
||||
class FixedArray(HeapObject):
|
||||
@ -1032,6 +1191,27 @@ class Script(HeapObject):
|
||||
self.name = self.ObjectField(self.NameOffset())
|
||||
|
||||
|
||||
class CodeCache(HeapObject):
|
||||
def DefaultCacheOffset(self):
|
||||
return self.heap.PointerSize()
|
||||
|
||||
def NormalTypeCacheOffset(self):
|
||||
return self.DefaultCacheOffset() + self.heap.PointerSize()
|
||||
|
||||
def __init__(self, heap, map, address):
|
||||
HeapObject.__init__(self, heap, map, address)
|
||||
self.default_cache = self.ObjectField(self.DefaultCacheOffset())
|
||||
self.normal_type_cache = self.ObjectField(self.NormalTypeCacheOffset())
|
||||
|
||||
def Print(self, p):
|
||||
p.Print("CodeCache(%s) {" % self.heap.reader.FormatIntPtr(self.address))
|
||||
p.Indent()
|
||||
p.Print("default cache: %s" % self.default_cache)
|
||||
p.Print("normal type cache: %s" % self.normal_type_cache)
|
||||
p.Dedent()
|
||||
p.Print("}")
|
||||
|
||||
|
||||
class Code(HeapObject):
|
||||
CODE_ALIGNMENT_MASK = (1 << 5) - 1
|
||||
|
||||
@ -1082,14 +1262,14 @@ class V8Heap(object):
|
||||
"EXTERNAL_STRING_TYPE": ExternalString,
|
||||
"EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString,
|
||||
"EXTERNAL_ASCII_STRING_TYPE": ExternalString,
|
||||
|
||||
"MAP_TYPE": Map,
|
||||
"ODDBALL_TYPE": Oddball,
|
||||
"FIXED_ARRAY_TYPE": FixedArray,
|
||||
"JS_FUNCTION_TYPE": JSFunction,
|
||||
"SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo,
|
||||
"SCRIPT_TYPE": Script,
|
||||
"CODE_TYPE": Code
|
||||
"CODE_CACHE_TYPE": CodeCache,
|
||||
"CODE_TYPE": Code,
|
||||
}
|
||||
|
||||
def __init__(self, reader, stack_map):
|
||||
@ -1147,6 +1327,247 @@ class V8Heap(object):
|
||||
elif self.reader.arch == MD_CPU_ARCHITECTURE_X86:
|
||||
return (1 << 5) - 1
|
||||
|
||||
def PageAlignmentMask(self):
|
||||
return (1 << 20) - 1
|
||||
|
||||
|
||||
class KnownObject(HeapObject):
|
||||
def __init__(self, heap, known_name):
|
||||
HeapObject.__init__(self, heap, None, None)
|
||||
self.known_name = known_name
|
||||
|
||||
def __str__(self):
|
||||
return "<%s>" % self.known_name
|
||||
|
||||
|
||||
class KnownMap(HeapObject):
|
||||
def __init__(self, heap, known_name, instance_type):
|
||||
HeapObject.__init__(self, heap, None, None)
|
||||
self.instance_type = instance_type
|
||||
self.known_name = known_name
|
||||
|
||||
def __str__(self):
|
||||
return "<%s>" % self.known_name
|
||||
|
||||
|
||||
class InspectionPadawan(object):
|
||||
"""The padawan can improve annotations by sensing well-known objects."""
|
||||
def __init__(self, reader, heap):
|
||||
self.reader = reader
|
||||
self.heap = heap
|
||||
self.known_first_map_page = 0
|
||||
self.known_first_data_page = 0
|
||||
self.known_first_pointer_page = 0
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""An InspectionPadawan can be used instead of V8Heap, even though
|
||||
it does not inherit from V8Heap (aka. mixin)."""
|
||||
return getattr(self.heap, name)
|
||||
|
||||
def GetPageOffset(self, tagged_address):
|
||||
return tagged_address & self.heap.PageAlignmentMask()
|
||||
|
||||
def IsInKnownMapSpace(self, tagged_address):
|
||||
page_address = tagged_address & ~self.heap.PageAlignmentMask()
|
||||
return page_address == self.known_first_map_page
|
||||
|
||||
def IsInKnownOldSpace(self, tagged_address):
|
||||
page_address = tagged_address & ~self.heap.PageAlignmentMask()
|
||||
return page_address in [self.known_first_data_page,
|
||||
self.known_first_pointer_page]
|
||||
|
||||
def ContainingKnownOldSpaceName(self, tagged_address):
|
||||
page_address = tagged_address & ~self.heap.PageAlignmentMask()
|
||||
if page_address == self.known_first_data_page: return "OLD_DATA_SPACE"
|
||||
if page_address == self.known_first_pointer_page: return "OLD_POINTER_SPACE"
|
||||
return None
|
||||
|
||||
def SenseObject(self, tagged_address):
|
||||
if self.IsInKnownOldSpace(tagged_address):
|
||||
offset = self.GetPageOffset(tagged_address)
|
||||
lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset)
|
||||
known_obj_name = KNOWN_OBJECTS.get(lookup_key)
|
||||
if known_obj_name:
|
||||
return KnownObject(self, known_obj_name)
|
||||
if self.IsInKnownMapSpace(tagged_address):
|
||||
known_map = self.SenseMap(tagged_address)
|
||||
if known_map:
|
||||
return known_map
|
||||
found_obj = self.heap.FindObject(tagged_address)
|
||||
if found_obj: return found_ob
|
||||
address = tagged_address - 1
|
||||
if self.reader.IsValidAddress(address):
|
||||
map_tagged_address = self.reader.ReadUIntPtr(address)
|
||||
map = self.SenseMap(map_tagged_address)
|
||||
if map is None: return None
|
||||
instance_type_name = INSTANCE_TYPES.get(map.instance_type)
|
||||
if instance_type_name is None: return None
|
||||
cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject)
|
||||
return cls(self, map, address)
|
||||
return None
|
||||
|
||||
def SenseMap(self, tagged_address):
|
||||
if self.IsInKnownMapSpace(tagged_address):
|
||||
offset = self.GetPageOffset(tagged_address)
|
||||
known_map_info = KNOWN_MAPS.get(offset)
|
||||
if known_map_info:
|
||||
known_map_type, known_map_name = known_map_info
|
||||
return KnownMap(self, known_map_name, known_map_type)
|
||||
found_map = self.heap.FindMap(tagged_address)
|
||||
if found_map: return found_map
|
||||
return None
|
||||
|
||||
def FindObjectOrSmi(self, tagged_address):
|
||||
"""When used as a mixin in place of V8Heap."""
|
||||
found_obj = self.SenseObject(tagged_address)
|
||||
if found_obj: return found_obj
|
||||
if (tagged_address & 1) == 0:
|
||||
return "Smi(%d)" % (tagged_address / 2)
|
||||
else:
|
||||
return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address)
|
||||
|
||||
def FindObject(self, tagged_address):
|
||||
"""When used as a mixin in place of V8Heap."""
|
||||
raise NotImplementedError
|
||||
|
||||
def FindMap(self, tagged_address):
|
||||
"""When used as a mixin in place of V8Heap."""
|
||||
raise NotImplementedError
|
||||
|
||||
def PrintKnowledge(self):
|
||||
print " known_first_map_page = %s\n"\
|
||||
" known_first_data_page = %s\n"\
|
||||
" known_first_pointer_page = %s" % (
|
||||
self.reader.FormatIntPtr(self.known_first_map_page),
|
||||
self.reader.FormatIntPtr(self.known_first_data_page),
|
||||
self.reader.FormatIntPtr(self.known_first_pointer_page))
|
||||
|
||||
|
||||
class InspectionShell(cmd.Cmd):
|
||||
def __init__(self, reader, heap):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.reader = reader
|
||||
self.heap = heap
|
||||
self.padawan = InspectionPadawan(reader, heap)
|
||||
self.prompt = "(grok) "
|
||||
|
||||
def do_dd(self, address):
|
||||
"""
|
||||
Interpret memory at the given address (if available) as a sequence
|
||||
of words. Automatic alignment is not performed.
|
||||
"""
|
||||
start = int(address, 16)
|
||||
if (start & self.heap.ObjectAlignmentMask()) != 0:
|
||||
print "Warning: Dumping un-aligned memory, is this what you had in mind?"
|
||||
for slot in xrange(start,
|
||||
start + self.reader.PointerSize() * 10,
|
||||
self.reader.PointerSize()):
|
||||
maybe_address = self.reader.ReadUIntPtr(slot)
|
||||
heap_object = self.padawan.SenseObject(maybe_address)
|
||||
print "%s: %s %s" % (self.reader.FormatIntPtr(slot),
|
||||
self.reader.FormatIntPtr(maybe_address),
|
||||
heap_object or '')
|
||||
|
||||
def do_do(self, address):
|
||||
"""
|
||||
Interpret memory at the given address as a V8 object. Automatic
|
||||
alignment makes sure that you can pass tagged as well as un-tagged
|
||||
addresses.
|
||||
"""
|
||||
address = int(address, 16)
|
||||
if (address & self.heap.ObjectAlignmentMask()) == 0:
|
||||
address = address + 1
|
||||
elif (address & self.heap.ObjectAlignmentMask()) != 1:
|
||||
print "Address doesn't look like a valid pointer!"
|
||||
return
|
||||
heap_object = self.padawan.SenseObject(address)
|
||||
if heap_object:
|
||||
heap_object.Print(Printer())
|
||||
else:
|
||||
print "Address cannot be interpreted as object!"
|
||||
|
||||
def do_dp(self, address):
|
||||
"""
|
||||
Interpret memory at the given address as being on a V8 heap page
|
||||
and print information about the page header (if available).
|
||||
"""
|
||||
address = int(address, 16)
|
||||
page_address = address & ~self.heap.PageAlignmentMask()
|
||||
if self.reader.IsValidAddress(page_address):
|
||||
raise NotImplementedError
|
||||
else:
|
||||
print "Page header is not available!"
|
||||
|
||||
def do_k(self, arguments):
|
||||
"""
|
||||
Teach V8 heap layout information to the inspector. This increases
|
||||
the amount of annotations the inspector can produce while dumping
|
||||
data. The first page of each heap space is of particular interest
|
||||
because it contains known objects that do not move.
|
||||
"""
|
||||
self.padawan.PrintKnowledge()
|
||||
|
||||
def do_km(self, address):
|
||||
"""
|
||||
Teach V8 heap layout information to the inspector. Set the first
|
||||
map-space page by passing any pointer into that page.
|
||||
"""
|
||||
address = int(address, 16)
|
||||
page_address = address & ~self.heap.PageAlignmentMask()
|
||||
self.padawan.known_first_map_page = page_address
|
||||
|
||||
def do_kd(self, address):
|
||||
"""
|
||||
Teach V8 heap layout information to the inspector. Set the first
|
||||
data-space page by passing any pointer into that page.
|
||||
"""
|
||||
address = int(address, 16)
|
||||
page_address = address & ~self.heap.PageAlignmentMask()
|
||||
self.padawan.known_first_data_page = page_address
|
||||
|
||||
def do_kp(self, address):
|
||||
"""
|
||||
Teach V8 heap layout information to the inspector. Set the first
|
||||
pointer-space page by passing any pointer into that page.
|
||||
"""
|
||||
address = int(address, 16)
|
||||
page_address = address & ~self.heap.PageAlignmentMask()
|
||||
self.padawan.known_first_pointer_page = page_address
|
||||
|
||||
def do_s(self, word):
|
||||
"""
|
||||
Search for a given word in available memory regions. The given word
|
||||
is expanded to full pointer size and searched at aligned as well as
|
||||
un-aligned memory locations. Use 'sa' to search aligned locations
|
||||
only.
|
||||
"""
|
||||
try:
|
||||
word = int(word, 0)
|
||||
except ValueError:
|
||||
print "Malformed word, prefix with '0x' to use hexadecimal format."
|
||||
return
|
||||
print "Searching for word %d/0x%s:" % (word, self.reader.FormatIntPtr(word))
|
||||
self.reader.FindWord(word)
|
||||
|
||||
def do_sh(self, none):
|
||||
"""
|
||||
Search for the V8 Heap object in all available memory regions. You
|
||||
might get lucky and find this rare treasure full of invaluable
|
||||
information.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def do_list(self, smth):
|
||||
"""
|
||||
List all available memory regions.
|
||||
"""
|
||||
def print_region(reader, start, size, location):
|
||||
print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start),
|
||||
reader.FormatIntPtr(start + size),
|
||||
size)
|
||||
print "Available memory regions:"
|
||||
self.reader.ForEachMemoryRegion(print_region)
|
||||
|
||||
|
||||
EIP_PROXIMITY = 64
|
||||
|
||||
@ -1157,41 +1578,6 @@ CONTEXT_FOR_ARCH = {
|
||||
['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
|
||||
}
|
||||
|
||||
class InspectionShell(cmd.Cmd):
|
||||
def __init__(self, reader, heap):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.reader = reader
|
||||
self.heap = heap
|
||||
self.prompt = "(grok) "
|
||||
|
||||
def do_dd(self, address):
|
||||
"Interpret memory at the given address (if available)"\
|
||||
" as a sequence of words."
|
||||
start = int(address, 16)
|
||||
for slot in xrange(start,
|
||||
start + self.reader.PointerSize() * 10,
|
||||
self.reader.PointerSize()):
|
||||
maybe_address = self.reader.ReadUIntPtr(slot)
|
||||
heap_object = self.heap.FindObject(maybe_address)
|
||||
print "%s: %s" % (self.reader.FormatIntPtr(slot),
|
||||
self.reader.FormatIntPtr(maybe_address))
|
||||
if heap_object:
|
||||
heap_object.Print(Printer())
|
||||
print
|
||||
|
||||
def do_s(self, word):
|
||||
"Search for a given word in available memory regions"
|
||||
word = int(word, 0)
|
||||
print "searching for word", word
|
||||
self.reader.FindWord(word)
|
||||
|
||||
def do_list(self, smth):
|
||||
"""List all available memory regions."""
|
||||
def print_region(reader, start, size, location):
|
||||
print "%s - %s" % (reader.FormatIntPtr(start),
|
||||
reader.FormatIntPtr(start + size))
|
||||
|
||||
self.reader.ForEachMemoryRegion(print_region)
|
||||
|
||||
def AnalyzeMinidump(options, minidump_name):
|
||||
reader = MinidumpReader(options, minidump_name)
|
||||
@ -1240,7 +1626,7 @@ def AnalyzeMinidump(options, minidump_name):
|
||||
heap = V8Heap(reader, None)
|
||||
|
||||
if options.full:
|
||||
do_dump(reader, heap)
|
||||
FullDump(reader, heap)
|
||||
|
||||
if options.shell:
|
||||
InspectionShell(reader, heap).cmdloop("type help to get help")
|
||||
@ -1261,8 +1647,10 @@ def AnalyzeMinidump(options, minidump_name):
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = optparse.OptionParser(USAGE)
|
||||
parser.add_option("-s", "--shell", dest="shell", action="store_true")
|
||||
parser.add_option("-f", "--full", dest="full", action="store_true")
|
||||
parser.add_option("-s", "--shell", dest="shell", action="store_true",
|
||||
help="start an interactive inspector shell")
|
||||
parser.add_option("-f", "--full", dest="full", action="store_true",
|
||||
help="dump all information contained in the minidump")
|
||||
options, args = parser.parse_args()
|
||||
if len(args) != 1:
|
||||
parser.print_help()
|
||||
|
Loading…
Reference in New Issue
Block a user