summaryrefslogtreecommitdiff
path: root/chromium/v8/tools/grokdump.py
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/v8/tools/grokdump.py
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/v8/tools/grokdump.py')
-rwxr-xr-xchromium/v8/tools/grokdump.py875
1 files changed, 675 insertions, 200 deletions
diff --git a/chromium/v8/tools/grokdump.py b/chromium/v8/tools/grokdump.py
index 4525e7ef33e..4a3cc7c6f50 100755
--- a/chromium/v8/tools/grokdump.py
+++ b/chromium/v8/tools/grokdump.py
@@ -177,6 +177,13 @@ def FullDump(reader, heap):
INSTANCE_TYPES = v8heapconst.INSTANCE_TYPES
KNOWN_MAPS = v8heapconst.KNOWN_MAPS
KNOWN_OBJECTS = v8heapconst.KNOWN_OBJECTS
+FRAME_MARKERS = v8heapconst.FRAME_MARKERS
+
+# Markers pushed on the stack by PushStackTraceAndDie
+MAGIC_MARKER_PAIRS = (
+ (0xbbbbbbbb, 0xbbbbbbbb),
+ (0xfefefefe, 0xfefefeff),
+)
# Set of structures and constants that describe the layout of minidump
# files. Based on MSDN and Google Breakpad.
@@ -633,18 +640,8 @@ class MinidumpReader(object):
self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
self.minidump, d.location.rva)
DebugPrint(self.exception)
- if self.arch == MD_CPU_ARCHITECTURE_X86:
- self.exception_context = MINIDUMP_CONTEXT_X86.Read(
- self.minidump, self.exception.thread_context.rva)
- elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
- self.exception_context = MINIDUMP_CONTEXT_AMD64.Read(
- self.minidump, self.exception.thread_context.rva)
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- self.exception_context = MINIDUMP_CONTEXT_ARM.Read(
- self.minidump, self.exception.thread_context.rva)
- elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
- self.exception_context = MINIDUMP_CONTEXT_ARM64.Read(
- self.minidump, self.exception.thread_context.rva)
+ self.exception_context = self.ContextDescriptor().Read(
+ self.minidump, self.exception.thread_context.rva)
DebugPrint(self.exception_context)
elif d.stream_type == MD_THREAD_LIST_STREAM:
thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
@@ -682,9 +679,48 @@ class MinidumpReader(object):
assert ctypes.sizeof(self.memory_list64) == d.location.data_size
DebugPrint(self.memory_list64)
+ def ContextDescriptor(self):
+ if self.arch == MD_CPU_ARCHITECTURE_X86:
+ return MINIDUMP_CONTEXT_X86
+ elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
+ return MINIDUMP_CONTEXT_AMD64
+ elif self.arch == MD_CPU_ARCHITECTURE_ARM:
+ return MINIDUMP_CONTEXT_ARM
+ elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
+ return MINIDUMP_CONTEXT_ARM64
+ else:
+ return None
+
+ def IsValidAlignedAddress(self, address):
+ return self.IsAlignedAddress(address) and self.IsValidAddress(address)
+
def IsValidAddress(self, address):
return self.FindLocation(address) is not None
+ def IsAlignedAddress(self, address):
+ return (address % self.PointerSize()) == 0
+
+ def IsExceptionStackAddress(self, address):
+ if not self.IsAlignedAddress(address): return False
+ return self.IsAnyExceptionStackAddress(address)
+
+ def IsAnyExceptionStackAddress(self, address):
+ return self.StackTop() <= address <= self.StackBottom()
+
+ def IsValidExceptionStackAddress(self, address):
+ if not self.IsValidAddress(address): return False
+ return self.isExceptionStackAddress(address)
+
+ def IsModuleAddress(self, address):
+ return self.GetModuleForAddress(address) != None
+
+ def GetModuleForAddress(self, address):
+ for module in self.module_list.modules:
+ start = module.base_of_image
+ end = start + module.size_of_image
+ if start <= address < end: return module
+ return None
+
def ReadU8(self, address):
location = self.FindLocation(address)
return ctypes.c_uint8.from_buffer(self.minidump, location).value
@@ -697,29 +733,39 @@ class MinidumpReader(object):
location = self.FindLocation(address)
return ctypes.c_uint64.from_buffer(self.minidump, location).value
+ def Is64(self):
+ return (self.arch == MD_CPU_ARCHITECTURE_ARM64 or
+ self.arch == MD_CPU_ARCHITECTURE_AMD64)
+
def ReadUIntPtr(self, address):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return self.ReadU64(address)
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return self.ReadU32(address)
- elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
+ if self.Is64():
return self.ReadU64(address)
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return self.ReadU32(address)
+ return self.ReadU32(address)
def ReadBytes(self, address, size):
location = self.FindLocation(address)
return self.minidump[location:location + size]
def _ReadWord(self, location):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return ctypes.c_uint64.from_buffer(self.minidump, location).value
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return ctypes.c_uint32.from_buffer(self.minidump, location).value
- elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
+ if self.Is64():
return ctypes.c_uint64.from_buffer(self.minidump, location).value
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return ctypes.c_uint32.from_buffer(self.minidump, location).value
+ return ctypes.c_uint32.from_buffer(self.minidump, location).value
+
+ def ReadAsciiPtr(self, address):
+ ascii_content = [c if c >= '\x20' and c < '\x7f' else '.'
+ for c in self.ReadBytes(address, self.PointerSize())]
+ return ''.join(ascii_content)
+
+ def ReadAsciiString(self, address):
+ string = ""
+ while self.IsValidAddress(address):
+ code = self.ReadU8(address)
+ if 0 < code < 128:
+ string += chr(code)
+ else:
+ break
+ address += 1
+ return string
def IsProbableASCIIRegion(self, location, length):
ascii_bytes = 0
@@ -745,7 +791,7 @@ class MinidumpReader(object):
def IsProbableExecutableRegion(self, location, length):
opcode_bytes = 0
- sixty_four = self.arch == MD_CPU_ARCHITECTURE_AMD64
+ sixty_four = self.Is64()
for i in xrange(length):
loc = location + i
byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
@@ -811,7 +857,7 @@ class MinidumpReader(object):
loc = location + i
if reader._ReadWord(loc) == word:
slot = start + (loc - location)
- if slot % self.PointerSize() == 0:
+ if self.IsAlignedAddress(slot):
aligned_res.append(slot)
else:
unaligned_res.append(slot)
@@ -894,25 +940,26 @@ class MinidumpReader(object):
elif self.arch == MD_CPU_ARCHITECTURE_X86:
return self.exception_context.ebp
+ def ExceptionThread(self):
+ return self.thread_map[self.exception.thread_id]
+
+ def StackTop(self):
+ return self.ExceptionSP()
+
+ def StackBottom(self):
+ exception_thread = self.ExceptionThread()
+ return exception_thread.stack.start + \
+ exception_thread.stack.memory.data_size
+
def FormatIntPtr(self, value):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return "%016x" % value
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return "%08x" % value
- elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
+ if self.Is64():
return "%016x" % value
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return "%08x" % value
+ return "%08x" % value
def PointerSize(self):
- if self.arch == MD_CPU_ARCHITECTURE_AMD64:
- return 8
- elif self.arch == MD_CPU_ARCHITECTURE_ARM:
- return 4
- elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
+ if self.Is64():
return 8
- elif self.arch == MD_CPU_ARCHITECTURE_X86:
- return 4
+ return 4
def Register(self, name):
return self.exception_context.__getattribute__(name)
@@ -1054,8 +1101,9 @@ class HeapObject(object):
instance_type = "???"
if self.map is not None:
instance_type = INSTANCE_TYPES[self.map.instance_type]
- return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
- instance_type)
+ return "%s(%s, %s)" % (self.__class__.__name__,
+ self.heap.reader.FormatIntPtr(self.address),
+ instance_type)
def ObjectField(self, offset):
field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
@@ -1063,8 +1111,8 @@ class HeapObject(object):
def SmiField(self, offset):
field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
- if (field_value & 1) == 0:
- return field_value / 2
+ if self.heap.IsSmi(field_value):
+ return self.heap.SmiUntag(field_value)
return None
@@ -1082,11 +1130,11 @@ class Map(HeapObject):
def InObjectProperties(self):
return self.InstanceSizeOffset() + 1
- def PreAllocatedPropertyFields(self):
+ def UnusedByte(self):
return self.InObjectProperties() + 1
def VisitorId(self):
- return self.PreAllocatedPropertyFields() + 1
+ return self.UnusedByte() + 1
# Instance Attributes
def InstanceAttributesOffset(self):
@@ -1095,78 +1143,93 @@ class Map(HeapObject):
def InstanceTypeOffset(self):
return self.InstanceAttributesOffset()
- def UnusedPropertyFieldsOffset(self):
- return self.InstanceTypeOffset() + 1
-
def BitFieldOffset(self):
- return self.UnusedPropertyFieldsOffset() + 1
+ return self.InstanceTypeOffset() + 1
def BitField2Offset(self):
return self.BitFieldOffset() + 1
+ def UnusedPropertyFieldsOffset(self):
+ return self.BitField2Offset() + 1
+
# Other fields
- def PrototypeOffset(self):
+ def BitField3Offset(self):
return self.InstanceAttributesOffset() + self.heap.IntSize()
- def ConstructorOffset(self):
+ def PrototypeOffset(self):
+ return self.BitField3Offset() + self.heap.PointerSize()
+
+ def ConstructorOrBackPointerOffset(self):
return self.PrototypeOffset() + self.heap.PointerSize()
- def TransitionsOrBackPointerOffset(self):
- return self.ConstructorOffset() + self.heap.PointerSize()
+ def TransitionsOrPrototypeInfoOffset(self):
+ return self.ConstructorOrBackPointerOffset() + self.heap.PointerSize()
def DescriptorsOffset(self):
- return self.TransitionsOrBackPointerOffset() + self.heap.PointerSize()
+ return self.TransitionsOrPrototypeInfoOffset() + self.heap.PointerSize()
+
+ def LayoutDescriptorOffset(self):
+ return self.DescriptorsOffset() + self.heap.PointerSize()
def CodeCacheOffset(self):
+ if (self.heap.reader.Is64()):
+ return self.LayoutDescriptorOffset() + self.heap.PointerSize()
return self.DescriptorsOffset() + self.heap.PointerSize()
def DependentCodeOffset(self):
return self.CodeCacheOffset() + self.heap.PointerSize()
- def BitField3Offset(self):
+ def WeakCellCacheOffset(self):
return self.DependentCodeOffset() + self.heap.PointerSize()
def ReadByte(self, offset):
return self.heap.reader.ReadU8(self.address + offset)
+ def ReadWord(self, offset):
+ return self.heap.reader.ReadUIntPtr(self.address + offset)
+
def Print(self, p):
p.Print("Map(%08x)" % (self.address))
- p.Print("- size: %d, inobject: %d, preallocated: %d, visitor: %d" % (
+ p.Print(" - size: %d, inobject: %d, (unused: %d), visitor: %d" % (
self.ReadByte(self.InstanceSizeOffset()),
self.ReadByte(self.InObjectProperties()),
- self.ReadByte(self.PreAllocatedPropertyFields()),
+ self.ReadByte(self.UnusedByte()),
self.VisitorId()))
+ instance_type = INSTANCE_TYPES[self.ReadByte(self.InstanceTypeOffset())]
bitfield = self.ReadByte(self.BitFieldOffset())
bitfield2 = self.ReadByte(self.BitField2Offset())
- p.Print("- %s, unused: %d, bf: %d, bf2: %d" % (
- INSTANCE_TYPES[self.ReadByte(self.InstanceTypeOffset())],
- self.ReadByte(self.UnusedPropertyFieldsOffset()),
- bitfield, bitfield2))
+ unused = self.ReadByte(self.UnusedPropertyFieldsOffset())
+ p.Print(" - %s, bf: %d, bf2: %d, unused: %d" % (
+ instance_type, bitfield, bitfield2, unused))
- p.Print("- kind: %s" % (self.Decode(3, 5, bitfield2)))
+ p.Print(" - kind: %s" % (self.Decode(3, 5, bitfield2)))
+
+ bitfield3 = self.ReadWord(self.BitField3Offset())
- bitfield3 = self.ObjectField(self.BitField3Offset())
p.Print(
- "- EnumLength: %d NumberOfOwnDescriptors: %d OwnsDescriptors: %s" % (
- self.Decode(0, 11, bitfield3),
- self.Decode(11, 11, bitfield3),
- self.Decode(25, 1, bitfield3)))
- p.Print("- IsShared: %s" % (self.Decode(22, 1, bitfield3)))
- p.Print("- FunctionWithPrototype: %s" % (self.Decode(23, 1, bitfield3)))
- p.Print("- DictionaryMap: %s" % (self.Decode(24, 1, bitfield3)))
+ " - EnumLength: %d NumberOfOwnDescriptors: %d OwnsDescriptors: %s" % (
+ self.Decode(0, 10, bitfield3),
+ self.Decode(10, 10, bitfield3),
+ self.Decode(21, 1, bitfield3)))
+ p.Print(" - DictionaryMap: %s" % (self.Decode(20, 1, bitfield3)))
+ p.Print(" - Deprecated: %s" % (self.Decode(23, 1, bitfield3)))
+ p.Print(" - IsUnstable: %s" % (self.Decode(24, 1, bitfield3)))
+ p.Print(" - NewTargetIsBase: %s" % (self.Decode(27, 1, bitfield3)))
descriptors = self.ObjectField(self.DescriptorsOffset())
if descriptors.__class__ == FixedArray:
DescriptorArray(descriptors).Print(p)
else:
- p.Print("Descriptors: %s" % (descriptors))
+ p.Print(" - Descriptors: %s" % (descriptors))
- transitions = self.ObjectField(self.TransitionsOrBackPointerOffset())
+ transitions = self.ObjectField(self.TransitionsOrPrototypeInfoOffset())
if transitions.__class__ == FixedArray:
TransitionArray(transitions).Print(p)
else:
- p.Print("TransitionsOrBackPointer: %s" % (transitions))
+ p.Print(" - TransitionsOrPrototypeInfo: %s" % (transitions))
+
+ p.Print(" - Prototype: %s" % self.ObjectField(self.PrototypeOffset()))
def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address)
@@ -1256,7 +1319,7 @@ class ConsString(String):
class Oddball(HeapObject):
- # Should match declarations in objects.h
+ #Should match declarations in objects.h
KINDS = [
"False",
"True",
@@ -1505,25 +1568,28 @@ class SharedFunctionInfo(HeapObject):
def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address)
- self.code = self.ObjectField(self.CodeOffset())
- self.script = self.ObjectField(self.ScriptOffset())
- self.inferred_name = self.ObjectField(self.InferredNameOffset())
- if heap.PointerSize() == 8:
- start_position_and_type = \
- heap.reader.ReadU32(self.StartPositionAndTypeOffset())
- self.start_position = start_position_and_type >> 2
- pseudo_smi_end_position = \
- heap.reader.ReadU32(self.EndPositionOffset())
- self.end_position = pseudo_smi_end_position >> 2
- else:
- start_position_and_type = \
- self.SmiField(self.StartPositionAndTypeOffset())
- if start_position_and_type:
+ try:
+ self.code = self.ObjectField(self.CodeOffset())
+ self.script = self.ObjectField(self.ScriptOffset())
+ self.inferred_name = self.ObjectField(self.InferredNameOffset())
+ if heap.PointerSize() == 8:
+ start_position_and_type = \
+ heap.reader.ReadU32(self.StartPositionAndTypeOffset())
self.start_position = start_position_and_type >> 2
+ pseudo_smi_end_position = \
+ heap.reader.ReadU32(self.EndPositionOffset())
+ self.end_position = pseudo_smi_end_position >> 2
else:
- self.start_position = None
- self.end_position = \
- self.SmiField(self.EndPositionOffset())
+ start_position_and_type = \
+ self.SmiField(self.StartPositionAndTypeOffset())
+ if start_position_and_type:
+ self.start_position = start_position_and_type >> 2
+ else:
+ self.start_position = None
+ self.end_position = \
+ self.SmiField(self.EndPositionOffset())
+ except:
+ print("*** Error while reading SharedFunctionInfo")
class Script(HeapObject):
@@ -1626,13 +1692,13 @@ class V8Heap(object):
self.objects = {}
def FindObjectOrSmi(self, tagged_address):
- if (tagged_address & 1) == 0: return tagged_address / 2
+ if self.IsSmi(tagged_address): return self.SmiUntag(tagged_address)
return self.FindObject(tagged_address)
def FindObject(self, tagged_address):
if tagged_address in self.objects:
return self.objects[tagged_address]
- if (tagged_address & self.ObjectAlignmentMask()) != 1: return None
+ if not self.IsTaggedObjectAddress(tagged_address): return None
address = tagged_address - 1
if not self.reader.IsValidAddress(address): return None
map_tagged_address = self.reader.ReadUIntPtr(address)
@@ -1654,12 +1720,17 @@ class V8Heap(object):
return object
def FindMap(self, tagged_address):
- if (tagged_address & self.MapAlignmentMask()) != 1: return None
- address = tagged_address - 1
- if not self.reader.IsValidAddress(address): return None
+ address = self.FindMapAddress(tagged_address)
+ if not address: return None
object = Map(self, None, address)
return object
+ def FindMapAddress(self, tagged_address):
+ if not self.IsTaggedMapAddress(tagged_address): return None
+ address = tagged_address - 1
+ if not self.reader.IsValidAddress(address): return None
+ return address
+
def IntSize(self):
return 4
@@ -1669,6 +1740,16 @@ class V8Heap(object):
def ObjectAlignmentMask(self):
return self.PointerSize() - 1
+ def IsTaggedObjectAddress(self, address):
+ return (address & self.ObjectAlignmentMask()) == 1
+
+ def IsValidTaggedObjectAddress(self, address):
+ if not self.IsTaggedObjectAddress(address): return False
+ return self.reader.IsValidAddress(address)
+
+ def IsTaggedMapAddress(self, address):
+ return (address & self.MapAlignmentMask()) == 1
+
def MapAlignmentMask(self):
if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64:
return (1 << 4) - 1
@@ -1680,8 +1761,71 @@ class V8Heap(object):
return (1 << 5) - 1
def PageAlignmentMask(self):
- return (1 << 20) - 1
+ return (1 << 19) - 1
+
+ def IsTaggedAddress(self, address):
+ return (address & self.ObjectAlignmentMask()) == 1
+
+ def IsSmi(self, tagged_address):
+ if self.reader.Is64():
+ return (tagged_address & 0xFFFFFFFF) == 0
+ return not self.IsTaggedAddress(tagged_address)
+
+ def SmiUntag(self, tagged_address):
+ if self.reader.Is64(): return tagged_address >> 32
+ return tagged_address >> 1
+
+ def AddressTypeMarker(self, address):
+ if not self.reader.IsValidAddress(address): return " "
+ if self.reader.IsExceptionStackAddress(address): return "S"
+ if self.reader.IsModuleAddress(address): return "C"
+ if self.IsTaggedAddress(address):
+ # Cannot have an tagged pointer into the stack
+ if self.reader.IsAnyExceptionStackAddress(address): return "s"
+ return "T"
+ return "*"
+
+ def FormatIntPtr(self, address):
+ marker = self.AddressTypeMarker(address)
+ address = self.reader.FormatIntPtr(address)
+ if marker == " ": return address
+ return "%s %s" % (address, marker)
+
+ def RelativeOffset(self, slot, address):
+ if not self.reader.IsValidAlignedAddress(slot): return None
+ if self.IsTaggedObjectAddress(address):
+ address -= 1
+ if not self.reader.IsValidAlignedAddress(address): return None
+ offset = (address - slot) / self.PointerSize()
+
+ lower_limit = -32
+ upper_limit = 128
+ if self.reader.IsExceptionStackAddress(address):
+ upper_limit = 0xFFFFFF
+
+ if offset < lower_limit or upper_limit < offset: return None
+ target_address = self.reader.ReadUIntPtr(address)
+ return "[%+02d]=%s %s" % (offset, self.reader.FormatIntPtr(target_address),
+ self.AddressTypeMarker(target_address))
+
+ def FindObjectPointers(self, start=0, end=0):
+ objects = set()
+ def find_object_in_region(reader, start, size, location):
+ for slot in range(start, start+size, self.reader.PointerSize()):
+ if not self.reader.IsValidAddress(slot): break
+ # Collect only tagged pointers (object) to tagged pointers (map)
+ tagged_address = self.reader.ReadUIntPtr(slot)
+ if not self.IsValidTaggedObjectAddress(tagged_address): continue
+ map_address = self.reader.ReadUIntPtr(tagged_address - 1)
+ if not self.IsTaggedMapAddress(map_address): continue
+ objects.add(tagged_address)
+
+ if not start and not end:
+ self.reader.ForEachMemoryRegion(find_object_in_region)
+ else:
+ find_object_in_region(self.reader, start, end-start, None)
+ return objects
class KnownObject(HeapObject):
def __init__(self, heap, known_name):
@@ -1784,6 +1928,7 @@ class InspectionPadawan(object):
self.heap = heap
self.known_first_map_page = 0
self.known_first_old_page = 0
+ self.context = None
def __getattr__(self, name):
"""An InspectionPadawan can be used instead of V8Heap, even though
@@ -1806,7 +1951,33 @@ class InspectionPadawan(object):
if page_address == self.known_first_old_page: return "OLD_SPACE"
return None
- def SenseObject(self, tagged_address):
+ def FrameMarkerName(self, value):
+ if 0 < value <= len(FRAME_MARKERS):
+ return "Possibly %s frame marker" % FRAME_MARKERS[value-1]
+ return ""
+
+ def IsFrameMarker(self, slot, address):
+ if not slot: return False
+ # Frame markers only occur directly after a frame pointer and only on the
+ # stack.
+ if not self.reader.IsExceptionStackAddress(slot): return False
+ next_address = self.reader.ReadUIntPtr(slot + self.reader.PointerSize())
+ return self.reader.IsExceptionStackAddress(next_address)
+
+ def FormatSmi(self, address, slot=None):
+ value = self.heap.SmiUntag(address)
+ marker = ""
+ if self.IsFrameMarker(slot, address):
+ marker = self.FrameMarkerName(value)
+ # On 32-bit systems almost everything looks like a Smi.
+ if not self.reader.Is64() or value == 0: return marker
+ return "Smi(%d) %s" % (value, marker)
+
+ def SenseObject(self, address, slot=None):
+ if self.heap.IsSmi(address):
+ return self.FormatSmi(address, slot)
+ if not self.heap.IsTaggedAddress(address): return None
+ tagged_address = address
if self.IsInKnownOldSpace(tagged_address):
offset = self.GetPageOffset(tagged_address)
lookup_key = (self.ContainingKnownOldSpaceName(tagged_address), offset)
@@ -1845,8 +2016,8 @@ class InspectionPadawan(object):
"""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)
+ if self.IsSmi(tagged_address):
+ return self.FormatSmi(tagged_address)
else:
return "Unknown(%s)" % self.reader.FormatIntPtr(tagged_address)
@@ -1864,6 +2035,202 @@ class InspectionPadawan(object):
self.reader.FormatIntPtr(self.known_first_map_page),
self.reader.FormatIntPtr(self.known_first_old_page))
+ def FindFirstAsciiString(self, start, end=None, min_length=32):
+ """ Walk the memory until we find a large string """
+ if not end: end = start + 64
+ for slot in xrange(start, end):
+ if not self.reader.IsValidAddress(slot): break
+ message = self.reader.ReadAsciiString(slot)
+ if len(message) > min_length:
+ return (slot, message)
+ return (None,None)
+
+ def PrintStackTraceMessage(self, start=None, print_message=True):
+ """
+ Try to print a possible message from PushStackTraceAndDie.
+ Returns the first address where the normal stack starts again.
+ """
+ # Only look at the first 1k words on the stack
+ ptr_size = self.reader.PointerSize()
+ if start is None:
+ start = self.reader.ExceptionSP()
+ end = start + ptr_size * 1024
+ message_start = 0
+ magic1 = None
+ for slot in xrange(start, end, ptr_size):
+ magic1 = self.reader.ReadUIntPtr(slot)
+ magic2 = self.reader.ReadUIntPtr(slot + ptr_size)
+ pair = (magic1 & 0xFFFFFFFF, magic2 & 0xFFFFFFFF)
+ if pair in MAGIC_MARKER_PAIRS:
+ message_slot = slot + ptr_size * 4
+ message_start = self.reader.ReadUIntPtr(message_slot)
+ break
+ if message_start == 0:
+ """
+ On Mac we don't always get proper magic markers, so just try printing
+ the first long ascii string found on the stack.
+ """
+ message_start, message = self.FindFirstAsciiString(start)
+ if message_start is None: return start
+ else:
+ message = self.reader.ReadAsciiString(message_start)
+ stack_start = message_start + len(message) + 1
+ # Make sure the address is word aligned
+ stack_start = stack_start - (stack_start % ptr_size)
+ if magic1 is None:
+ print "Stack Message:"
+ print " message start: %s" % self.heap.FormatIntPtr(message_start)
+ print " stack_start: %s" % self.heap.FormatIntPtr(stack_start )
+ else:
+ ptr1 = self.reader.ReadUIntPtr(slot + ptr_size * 2)
+ ptr2 = self.reader.ReadUIntPtr(slot + ptr_size * 3)
+ print "Stack Message:"
+ print " magic1: %s" % self.heap.FormatIntPtr(magic1)
+ print " magic2: %s" % self.heap.FormatIntPtr(magic2)
+ print " ptr1: %s" % self.heap.FormatIntPtr(ptr1)
+ print " ptr2: %s" % self.heap.FormatIntPtr(ptr2)
+ print " message start: %s" % self.heap.FormatIntPtr(message_start)
+ print " stack_start: %s" % self.heap.FormatIntPtr(stack_start )
+ print ""
+ if not print_message:
+ print " Use `dsa` to print the message with annotated addresses."
+ print ""
+ return stack_start
+ # Annotate all addresses in the dumped message
+ prog = re.compile("[0-9a-fA-F]{%s}" % ptr_size*2)
+ addresses = list(set(prog.findall(message)))
+ for i in range(len(addresses)):
+ address_org = addresses[i]
+ address = self.heap.FormatIntPtr(int(address_org, 16))
+ if address_org != address:
+ message = message.replace(address_org, address)
+ print "Message:"
+ print "="*80
+ print message
+ print "="*80
+ print ""
+ return stack_start
+
+ def TryInferFramePointer(self, slot, address):
+ """ Assume we have a framepointer if we find 4 consecutive links """
+ for i in range(0, 4):
+ if not self.reader.IsExceptionStackAddress(address): return 0
+ next_address = self.reader.ReadUIntPtr(address)
+ if next_address == address: return 0
+ address = next_address
+ return slot
+
+ def TryInferContext(self, address):
+ if self.context: return
+ ptr_size = self.reader.PointerSize()
+ possible_context = dict()
+ count = 0
+ while self.reader.IsExceptionStackAddress(address):
+ prev_addr = self.reader.ReadUIntPtr(address-ptr_size)
+ if self.heap.IsTaggedObjectAddress(prev_addr):
+ if prev_addr in possible_context:
+ possible_context[prev_addr] += 1
+ else:
+ possible_context[prev_addr] = 1
+ address = self.reader.ReadUIntPtr(address)
+ count += 1
+ if count <= 5 or len(possible_context) == 0: return
+ # Find entry with highest count
+ possible_context = possible_context.items()
+ possible_context.sort(key=lambda pair: pair[1])
+ address,count = possible_context[-1]
+ if count <= 4: return
+ self.context = address
+
+ def InterpretMemory(self, start, end):
+ # On 64 bit we omit frame pointers, so we have to do some more guesswork.
+ frame_pointer = 0
+ if not self.reader.Is64():
+ frame_pointer = self.reader.ExceptionFP()
+ # Follow the framepointer into the address range
+ while frame_pointer and frame_pointer < start:
+ frame_pointer = self.reader.ReadUIntPtr(frame_pointer)
+ if not self.reader.IsExceptionStackAddress(frame_pointer) or \
+ not frame_pointer:
+ frame_pointer = 0
+ break
+ in_oom_dump_area = False
+ is_stack = self.reader.IsExceptionStackAddress(start)
+ free_space_end = 0
+ ptr_size = self.reader.PointerSize()
+
+ for slot in xrange(start, end, ptr_size):
+ if not self.reader.IsValidAddress(slot):
+ print "%s: Address is not contained within the minidump!" % slot
+ return
+ maybe_address = self.reader.ReadUIntPtr(slot)
+ address_info = []
+ # Mark continuous free space objects
+ if slot == free_space_end:
+ address_info.append("+")
+ elif slot <= free_space_end:
+ address_info.append("|")
+ else:
+ free_space_end = 0
+
+ heap_object = self.SenseObject(maybe_address, slot)
+ if heap_object:
+ # Detect Free-space ranges
+ if isinstance(heap_object, KnownMap) and \
+ heap_object.known_name == "FreeSpaceMap":
+ # The free-space length is is stored as a Smi in the next slot.
+ length = self.reader.ReadUIntPtr(slot + ptr_size)
+ if self.heap.IsSmi(length):
+ length = self.heap.SmiUntag(length)
+ free_space_end = slot + length - ptr_size
+ address_info.append(str(heap_object))
+ relative_offset = self.heap.RelativeOffset(slot, maybe_address)
+ if relative_offset:
+ address_info.append(relative_offset)
+ if maybe_address == self.context:
+ address_info.append("CONTEXT")
+
+ maybe_address_contents = None
+ if is_stack:
+ if self.reader.IsExceptionStackAddress(maybe_address):
+ maybe_address_contents = \
+ self.reader.ReadUIntPtr(maybe_address) & 0xFFFFFFFF
+ if maybe_address_contents == 0xdecade00:
+ in_oom_dump_area = True
+ if frame_pointer == 0:
+ frame_pointer = self.TryInferFramePointer(slot, maybe_address)
+ if frame_pointer != 0:
+ self.TryInferContext(slot)
+ maybe_symbol = self.reader.FindSymbol(maybe_address)
+ if in_oom_dump_area:
+ if maybe_address_contents == 0xdecade00:
+ address_info = ["<==== HeapStats start marker"]
+ elif maybe_address_contents == 0xdecade01:
+ address_info = ["<==== HeapStats end marker"]
+ elif maybe_address_contents is not None:
+ address_info = [" %d (%d Mbytes)" % (maybe_address_contents,
+ maybe_address_contents >> 20)]
+ if slot == frame_pointer:
+ if not self.reader.IsExceptionStackAddress(maybe_address):
+ address_info.append("<==== BAD frame pointer")
+ frame_pointer = 0
+ else:
+ address_info.append("<==== Frame pointer")
+ frame_pointer = maybe_address
+ address_type_marker = self.heap.AddressTypeMarker(maybe_address)
+ string_value = self.reader.ReadAsciiPtr(slot)
+ print "%s: %s %s %s %s" % (self.reader.FormatIntPtr(slot),
+ self.reader.FormatIntPtr(maybe_address),
+ address_type_marker,
+ string_value,
+ ' | '.join(address_info))
+ if maybe_address_contents == 0xdecade01:
+ in_oom_dump_area = False
+ heap_object = self.heap.FindObject(maybe_address)
+ if heap_object:
+ heap_object.Print(Printer())
+ print ""
+
WEB_HEADER = """
<!DOCTYPE html>
<html>
@@ -2045,7 +2412,7 @@ function onpage(kind, address) {
<body>
<div class="header">
- <form class="navigation" action=/search.html">
+ <form class="navigation" action="search.html">
<a href="summary.html?%(query_dump)s">Context info</a>&nbsp;&nbsp;&nbsp;
<a href="info.html?%(query_dump)s">Dump info</a>&nbsp;&nbsp;&nbsp;
<a href="modules.html?%(query_dump)s">Modules</a>&nbsp;&nbsp;&nbsp;
@@ -2916,59 +3283,121 @@ class InspectionShell(cmd.Cmd):
self.padawan = InspectionPadawan(reader, heap)
self.prompt = "(grok) "
+ self.dd_start = 0
+ self.dd_num = 0x10
+ self.u_start = 0
+ self.u_num = 0
+
+ def EvalExpression(self, expr):
+ # Auto convert hex numbers to a python compatible format
+ if expr[:2] == "00":
+ expr = "0x"+expr
+ result = None
+ try:
+ # Ugly hack to patch in register values.
+ registers = [register
+ for register,value in self.reader.ContextDescriptor().fields]
+ registers.sort(key=lambda r: len(r))
+ registers.reverse()
+ for register in registers:
+ expr = expr.replace("$"+register, str(self.reader.Register(register)))
+ result = eval(expr)
+ except Exception as e:
+ print("**** Could not evaluate '%s': %s" % (expr, e))
+ raise e
+ return result
+
+ def ParseAddressExpr(self, expr):
+ address = 0;
+ try:
+ result = self.EvalExpression(expr)
+ except:
+ return 0
+ try:
+ address = int(result)
+ except Exception as e:
+ print("**** Could not convert '%s' => %s to valid address: %s" % (
+ expr, result , e))
+ return address
+
+ def do_p(self, cmd):
+ """ see print """
+ return self.do_print(cmd)
+
+ def do_print(self, cmd):
+ """
+ Evaluate an arbitrary python command.
+ """
+ try:
+ print(self.EvalExpression(cmd))
+ except:
+ pass
+
def do_da(self, address):
+ """ see display_ascii"""
+ return self.do_display_ascii(address)
+
+ def do_display_ascii(self, address):
"""
Print ASCII string starting at specified address.
"""
- address = int(address, 16)
- string = ""
- while self.reader.IsValidAddress(address):
- code = self.reader.ReadU8(address)
- if code < 128:
- string += chr(code)
- else:
- break
- address += 1
+ address = self.ParseAddressExpr(address)
+ string = self.reader.ReadAsciiString(address)
if string == "":
print "Not an ASCII string at %s" % self.reader.FormatIntPtr(address)
else:
print "%s\n" % string
+ def do_dsa(self, address):
+ """ see display_stack_ascii"""
+ return self.do_display_stack_ascii(address)
+
+ def do_display_stack_ascii(self, address):
+ """
+ Print ASCII stack error message.
+ """
+ if self.reader.exception is None:
+ print "Minidump has no exception info"
+ return
+ if len(address) == 0:
+ address = None
+ else:
+ address = self.ParseAddressExpr(address)
+ self.padawan.PrintStackTraceMessage(address)
+
def do_dd(self, args):
"""
Interpret memory in the given region [address, address + num * word_size)
(if available) as a sequence of words. Automatic alignment is not performed.
- If the num is not specified, a default value of 16 words is used.
- Synopsis: dd 0x<address> 0x<num>
+ If the num is not specified, a default value of 16 words is usif not self.Is
+ If no address is given, dd continues printing at the next word.
+ Synopsis: dd 0x<address>|$register [0x<num>]
"""
- args = args.split(' ')
- start = int(args[0], 16)
- num = int(args[1], 16) if len(args) > 1 else 0x10
- if (start & self.heap.ObjectAlignmentMask()) != 0:
+ if len(args) != 0:
+ args = args.split(' ')
+ self.dd_start = self.ParseAddressExpr(args[0])
+ self.dd_num = int(args[1], 16) if len(args) > 1 else 0x10
+ else:
+ self.dd_start += self.dd_num * self.reader.PointerSize()
+ if not self.reader.IsAlignedAddress(self.dd_start):
print "Warning: Dumping un-aligned memory, is this what you had in mind?"
- for i in xrange(0,
- self.reader.PointerSize() * num,
- self.reader.PointerSize()):
- slot = start + i
- if not self.reader.IsValidAddress(slot):
- print "Address is not contained within the minidump!"
- return
- 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 '')
+ end = self.dd_start + self.reader.PointerSize() * self.dd_num
+ self.padawan.InterpretMemory(self.dd_start, end)
def do_do(self, address):
+ """ see display_object """
+ return self.do_display_object(address)
+
+ def do_display_object(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 = self.ParseAddressExpr(address)
+ if self.reader.IsAlignedAddress(address):
address = address + 1
- elif (address & self.heap.ObjectAlignmentMask()) != 1:
+ elif not self.heap.IsTaggedObjectAddress(address):
print "Address doesn't look like a valid pointer!"
return
heap_object = self.padawan.SenseObject(address)
@@ -2977,11 +3406,35 @@ class InspectionShell(cmd.Cmd):
else:
print "Address cannot be interpreted as object!"
+ def do_dso(self, args):
+ """ see display_stack_objects """
+ return self.do_display_stack_objects(args)
+
+ def do_display_stack_objects(self, args):
+ """
+ Print all possible object pointers that are on the stack or in the given
+ address range.
+ Usage: dso [START_ADDR,[END_ADDR]]
+ """
+ start = self.reader.StackTop()
+ end = self.reader.StackBottom()
+ if len(args) != 0:
+ args = args.split(' ')
+ start = self.ParseAddressExpr(args[0])
+ end = self.ParseAddressExpr(args[1]) if len(args) > 1 else end
+ objects = self.heap.FindObjectPointers(start, end)
+ for address in objects:
+ heap_object = self.padawan.SenseObject(address)
+ info = ""
+ if heap_object:
+ info = str(heap_object)
+ print("%s %s" % (self.padawan.FormatIntPtr(address), info))
+
def do_do_desc(self, address):
"""
Print a descriptor array in a readable format.
"""
- start = int(address, 16)
+ start = self.ParseAddressExpr(address)
if ((start & 1) == 1): start = start - 1
DescriptorArray(FixedArray(self.heap, None, start)).Print(Printer())
@@ -2989,7 +3442,7 @@ class InspectionShell(cmd.Cmd):
"""
Print a descriptor array in a readable format.
"""
- start = int(address, 16)
+ start = self.ParseAddressExpr(address)
if ((start & 1) == 1): start = start - 1
Map(self.heap, None, start).Print(Printer())
@@ -2997,19 +3450,24 @@ class InspectionShell(cmd.Cmd):
"""
Print a transition array in a readable format.
"""
- start = int(address, 16)
+ start = self.ParseAddressExpr(address)
if ((start & 1) == 1): start = start - 1
TransitionArray(FixedArray(self.heap, None, start)).Print(Printer())
def do_dp(self, address):
+ """ see display_page """
+ return self.do_display_page(address)
+
+ def do_display_page(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)
+ address = self.ParseAddressExpr(address)
page_address = address & ~self.heap.PageAlignmentMask()
if self.reader.IsValidAddress(page_address):
- raise NotImplementedError
+ print "**** Not Implemented"
+ return
else:
print "Page header is not available!"
@@ -3023,20 +3481,28 @@ class InspectionShell(cmd.Cmd):
self.padawan.PrintKnowledge()
def do_ko(self, address):
+ """ see known_oldspace """
+ return self.do_known_oldspace(address)
+
+ def do_known_oldspace(self, address):
"""
Teach V8 heap layout information to the inspector. Set the first
old space page by passing any pointer into that page.
"""
- address = int(address, 16)
+ address = self.ParseAddressExpr(address)
page_address = address & ~self.heap.PageAlignmentMask()
self.padawan.known_first_old_page = page_address
def do_km(self, address):
+ """ see known_map """
+ return self.do_known_map(address)
+
+ def do_known_map(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)
+ address = self.ParseAddressExpr(address)
page_address = address & ~self.heap.PageAlignmentMask()
self.padawan.known_first_map_page = page_address
@@ -3052,6 +3518,10 @@ class InspectionShell(cmd.Cmd):
self.reader.ForEachMemoryRegion(print_region)
def do_lm(self, arg):
+ """ see list_modules """
+ return self.do_list_modules(arg)
+
+ def do_list_modules(self, arg):
"""
List details for all loaded modules in the minidump. An argument can
be passed to limit the output to only those modules that contain the
@@ -3067,6 +3537,10 @@ class InspectionShell(cmd.Cmd):
print
def do_s(self, word):
+ """ see search """
+ return self.do_search(word)
+
+ def do_search(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
@@ -3074,7 +3548,7 @@ class InspectionShell(cmd.Cmd):
only.
"""
try:
- word = int(word, 0)
+ word = self.ParseAddressExpr(word)
except ValueError:
print "Malformed word, prefix with '0x' to use hexadecimal format."
return
@@ -3087,23 +3561,39 @@ class InspectionShell(cmd.Cmd):
might get lucky and find this rare treasure full of invaluable
information.
"""
- raise NotImplementedError
+ print "**** Not Implemented"
def do_u(self, args):
+ """ see disassemble """
+ return self.do_disassemble(args)
+
+ def do_disassemble(self, args):
"""
Unassemble memory in the region [address, address + size). If the
size is not specified, a default value of 32 bytes is used.
Synopsis: u 0x<address> 0x<size>
"""
- args = args.split(' ')
- start = int(args[0], 16)
- size = int(args[1], 16) if len(args) > 1 else 0x20
- if not self.reader.IsValidAddress(start):
- print "Address is not contained within the minidump!"
+ if len(args) != 0:
+ args = args.split(' ')
+ self.u_start = self.ParseAddressExpr(args[0])
+ self.u_size = self.ParseAddressExpr(args[1]) if len(args) > 1 else 0x20
+ skip = False
+ else:
+ # Skip the first instruction if we reuse the last address.
+ skip = True
+
+ if not self.reader.IsValidAddress(self.u_start):
+ print "Address %s is not contained within the minidump!" % (
+ self.reader.FormatIntPtr(self.u_start))
return
- lines = self.reader.GetDisasmLines(start, size)
+ lines = self.reader.GetDisasmLines(self.u_start, self.u_size)
for line in lines:
- print FormatDisasmLine(start, self.heap, line)
+ if skip:
+ skip = False
+ continue
+ print FormatDisasmLine(self.u_start, self.heap, line)
+ # Set the next start address = last line
+ self.u_start += lines[-1][0]
print
def do_EOF(self, none):
@@ -3143,7 +3633,7 @@ def GetModuleName(reader, module):
def PrintModuleDetails(reader, module):
print "%s" % GetModuleName(reader, module)
file_version = GetVersionString(module.version_info.dwFileVersionMS,
- module.version_info.dwFileVersionLS)
+ module.version_info.dwFileVersionLS);
product_version = GetVersionString(module.version_info.dwProductVersionMS,
module.version_info.dwProductVersionLS)
print " base: %s" % reader.FormatIntPtr(module.base_of_image)
@@ -3158,17 +3648,39 @@ def PrintModuleDetails(reader, module):
def AnalyzeMinidump(options, minidump_name):
reader = MinidumpReader(options, minidump_name)
heap = None
+
+ stack_top = reader.ExceptionSP()
+ stack_bottom = reader.StackBottom()
+ stack_map = {reader.ExceptionIP(): -1}
+ for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
+ maybe_address = reader.ReadUIntPtr(slot)
+ if not maybe_address in stack_map:
+ stack_map[maybe_address] = slot
+
+ heap = V8Heap(reader, stack_map)
+ padawan = InspectionPadawan(reader, heap)
+
DebugPrint("========================================")
if reader.exception is None:
print "Minidump has no exception info"
else:
+ print "Address markers:"
+ print " T = valid tagged pointer in the minidump"
+ print " S = address on the exception stack"
+ print " C = address in loaded C/C++ module"
+ print " * = address in the minidump"
+ print ""
print "Exception info:"
- exception_thread = reader.thread_map[reader.exception.thread_id]
+ exception_thread = reader.ExceptionThread()
print " thread id: %d" % exception_thread.id
- print " code: %08X" % reader.exception.exception.code
+ print " code: %08X" % reader.exception.exception.code
print " context:"
- for r in CONTEXT_FOR_ARCH[reader.arch]:
- print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
+ context = CONTEXT_FOR_ARCH[reader.arch]
+ maxWidth = max(map(lambda s: len(s), context))
+ for r in context:
+ register_value = reader.Register(r)
+ print " %s: %s" % (r.rjust(maxWidth),
+ heap.FormatIntPtr(register_value))
# TODO(vitalyr): decode eflags.
if reader.arch in [MD_CPU_ARCHITECTURE_ARM, MD_CPU_ARCHITECTURE_ARM64]:
print " cpsr: %s" % bin(reader.exception_context.cpsr)[2:]
@@ -3184,15 +3696,12 @@ def AnalyzeMinidump(options, minidump_name):
reader.TryLoadSymbolsFor(name, module)
print
- stack_top = reader.ExceptionSP()
- stack_bottom = exception_thread.stack.start + \
- exception_thread.stack.memory.data_size
- stack_map = {reader.ExceptionIP(): -1}
- for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
- maybe_address = reader.ReadUIntPtr(slot)
- if not maybe_address in stack_map:
- stack_map[maybe_address] = slot
- heap = V8Heap(reader, stack_map)
+ print " stack-top: %s" % heap.FormatIntPtr(reader.StackTop())
+ print " stack-bottom: %s" % heap.FormatIntPtr(reader.StackBottom())
+ print ""
+
+ if options.shell:
+ padawan.PrintStackTraceMessage(print_message=False)
print "Disassembly around exception.eip:"
eip_symbol = reader.FindSymbol(reader.ExceptionIP())
@@ -3232,43 +3741,9 @@ def AnalyzeMinidump(options, minidump_name):
print "Kthxbye."
elif not options.command:
if reader.exception is not None:
- frame_pointer = reader.ExceptionFP()
- in_oom_dump_area = False
print "Annotated stack (from exception.esp to bottom):"
- for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
- ascii_content = [c if c >= '\x20' and c < '\x7f' else '.'
- for c in reader.ReadBytes(slot, reader.PointerSize())]
- maybe_address = reader.ReadUIntPtr(slot)
- maybe_address_contents = None
- if maybe_address >= stack_top and maybe_address <= stack_bottom:
- maybe_address_contents = reader.ReadUIntPtr(maybe_address)
- if maybe_address_contents == 0xdecade00:
- in_oom_dump_area = True
- heap_object = heap.FindObject(maybe_address)
- maybe_symbol = reader.FindSymbol(maybe_address)
- oom_comment = ""
- if in_oom_dump_area:
- if maybe_address_contents == 0xdecade00:
- oom_comment = " <----- HeapStats start marker"
- elif maybe_address_contents == 0xdecade01:
- oom_comment = " <----- HeapStats end marker"
- elif maybe_address_contents is not None:
- oom_comment = " %d (%d Mbytes)" % (maybe_address_contents,
- maybe_address_contents >> 20)
- if slot == frame_pointer:
- maybe_symbol = "<---- frame pointer"
- frame_pointer = maybe_address
- print "%s: %s %s %s%s" % (reader.FormatIntPtr(slot),
- reader.FormatIntPtr(maybe_address),
- "".join(ascii_content),
- maybe_symbol or "",
- oom_comment)
- if maybe_address_contents == 0xdecade01:
- in_oom_dump_area = False
- if heap_object:
- heap_object.Print(Printer())
- print
-
+ stack_start = padawan.PrintStackTraceMessage()
+ padawan.InterpretMemory(stack_start, stack_bottom)
reader.Dispose()