[tools] Add basic pointer compression to grokdump

Distinguish between tagged and machine pointer sizes in grokdump, and
dump a tagged memory view in addition to the machine-word dump when they
don't match.

This tagged view tries to decompress pointers for link targets, by
masking the slot they're in to get the cage root.

Drive-by: Add a .style.yapf to opt in to python formatting using
git cl format.

Change-Id: Ic5272cd865f995fc670ab2fb7d5e464f317af1bf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3439906
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78948}
This commit is contained in:
Leszek Swirski 2022-02-04 14:33:39 +01:00 committed by V8 LUCI CQ
parent 6bb35b8c83
commit c97337ff5e
2 changed files with 187 additions and 112 deletions

2
.style.yapf Normal file
View File

@ -0,0 +1,2 @@
[style]
based_on_style = chromium

View File

@ -168,7 +168,7 @@ def FullDump(reader, heap):
print("%s - %s" % (reader.FormatIntPtr(start), print("%s - %s" % (reader.FormatIntPtr(start),
reader.FormatIntPtr(start + size))) reader.FormatIntPtr(start + size)))
print(start + size + 1); print(start + size + 1);
for i in range(0, size, reader.PointerSize()): for i in range(0, size, reader.MachinePointerSize()):
slot = start + i slot = start + i
maybe_address = reader.ReadUIntPtr(slot) maybe_address = reader.ReadUIntPtr(slot)
heap_object = heap.FindObject(maybe_address) heap_object = heap.FindObject(maybe_address)
@ -710,7 +710,7 @@ class MinidumpReader(object):
def _FindObjdump(self, options): def _FindObjdump(self, options):
if options.objdump: if options.objdump:
objdump_bin = options.objdump objdump_bin = options.objdump
else: else:
objdump_bin = self._FindThirdPartyObjdump() objdump_bin = self._FindThirdPartyObjdump()
if not objdump_bin or not os.path.exists(objdump_bin): if not objdump_bin or not os.path.exists(objdump_bin):
@ -722,29 +722,29 @@ class MinidumpReader(object):
disasm.OBJDUMP_BIN = objdump_bin disasm.OBJDUMP_BIN = objdump_bin
def _FindThirdPartyObjdump(self): def _FindThirdPartyObjdump(self):
# Try to find the platform specific objdump # Try to find the platform specific objdump
third_party_dir = os.path.join( third_party_dir = os.path.join(
os.path.dirname(os.path.dirname(__file__)), 'third_party') os.path.dirname(os.path.dirname(__file__)), 'third_party')
objdumps = [] objdumps = []
for root, dirs, files in os.walk(third_party_dir): for root, dirs, files in os.walk(third_party_dir):
for file in files: for file in files:
if file.endswith("objdump"): if file.endswith("objdump"):
objdumps.append(os.path.join(root, file)) objdumps.append(os.path.join(root, file))
if self.arch == MD_CPU_ARCHITECTURE_ARM: if self.arch == MD_CPU_ARCHITECTURE_ARM:
platform_filter = 'arm-linux' platform_filter = 'arm-linux'
elif self.arch == MD_CPU_ARCHITECTURE_ARM64: elif self.arch == MD_CPU_ARCHITECTURE_ARM64:
platform_filter = 'aarch64' platform_filter = 'aarch64'
else: else:
# use default otherwise # use default otherwise
return None return None
print(("# Looking for platform specific (%s) objdump in " print(("# Looking for platform specific (%s) objdump in "
"third_party directory.") % platform_filter) "third_party directory.") % platform_filter)
objdumps = filter(lambda file: platform_filter in file >= 0, objdumps) objdumps = filter(lambda file: platform_filter in file >= 0, objdumps)
if len(objdumps) == 0: if len(objdumps) == 0:
print("# Could not find platform specific objdump in third_party.") print("# Could not find platform specific objdump in third_party.")
print("# Make sure you installed the correct SDK.") print("# Make sure you installed the correct SDK.")
return None return None
return objdumps[0] return objdumps[0]
def ContextDescriptor(self): def ContextDescriptor(self):
if self.arch == MD_CPU_ARCHITECTURE_X86: if self.arch == MD_CPU_ARCHITECTURE_X86:
@ -765,7 +765,7 @@ class MinidumpReader(object):
return self.FindLocation(address) is not None return self.FindLocation(address) is not None
def IsAlignedAddress(self, address): def IsAlignedAddress(self, address):
return (address % self.PointerSize()) == 0 return (address % self.MachinePointerSize()) == 0
def IsExceptionStackAddress(self, address): def IsExceptionStackAddress(self, address):
if not self.IsAlignedAddress(address): return False if not self.IsAlignedAddress(address): return False
@ -804,11 +804,29 @@ class MinidumpReader(object):
return (self.arch == MD_CPU_ARCHITECTURE_ARM64 or return (self.arch == MD_CPU_ARCHITECTURE_ARM64 or
self.arch == MD_CPU_ARCHITECTURE_AMD64) self.arch == MD_CPU_ARCHITECTURE_AMD64)
def IsPointerCompressed(self):
# Assume all 64-bit builds are pointer compressed.
return self.Is64()
def Is32BitTagged(self):
return not self.Is64() or self.IsPointerCompressed()
def ReadTagged(self, address):
if self.Is32BitTagged():
return self.ReadU32(address)
return self.ReadU64(address)
def ReadUIntPtr(self, address): def ReadUIntPtr(self, address):
if self.Is64(): if self.Is64():
return self.ReadU64(address) return self.ReadU64(address)
return self.ReadU32(address) return self.ReadU32(address)
def ReadSized(self, address, size):
if size == 8:
return self.ReadU64(address)
assert (size == 4)
return self.ReadU32(address)
def ReadBytes(self, address, size): def ReadBytes(self, address, size):
location = self.FindLocation(address) location = self.FindLocation(address)
return self.minidump[location:location + size] return self.minidump[location:location + size]
@ -819,8 +837,10 @@ class MinidumpReader(object):
return ctypes.c_uint32.from_buffer(self.minidump, location).value return ctypes.c_uint32.from_buffer(self.minidump, location).value
def ReadAsciiPtr(self, address): def ReadAsciiPtr(self, address):
ascii_content = [c if c >= '\x20' and c < '\x7f' else '.' ascii_content = [
for c in self.ReadBytes(address, self.PointerSize())] c if c >= '\x20' and c < '\x7f' else '.'
for c in self.ReadBytes(address, self.MachinePointerSize())
]
return ''.join(ascii_content) return ''.join(ascii_content)
def ReadAsciiString(self, address): def ReadAsciiString(self, address):
@ -908,7 +928,7 @@ class MinidumpReader(object):
def FindWord(self, word, alignment=0): def FindWord(self, word, alignment=0):
def search_inside_region(reader, start, size, location): def search_inside_region(reader, start, size, location):
location = (location + alignment) & ~alignment location = (location + alignment) & ~alignment
for i in range(size - self.PointerSize()): for i in range(size - self.MachinePointerSize()):
loc = location + i loc = location + i
if reader._ReadWord(loc) == word: if reader._ReadWord(loc) == word:
slot = start + (loc - location) slot = start + (loc - location)
@ -920,7 +940,7 @@ class MinidumpReader(object):
aligned_res = [] aligned_res = []
unaligned_res = [] unaligned_res = []
def search_inside_region(reader, start, size, location): def search_inside_region(reader, start, size, location):
for i in range(size - self.PointerSize()): for i in range(size - self.MachinePointerSize()):
loc = location + i loc = location + i
if reader._ReadWord(loc) == word: if reader._ReadWord(loc) == word:
slot = start + (loc - location) slot = start + (loc - location)
@ -1023,11 +1043,21 @@ class MinidumpReader(object):
return "%016x" % value return "%016x" % value
return "%08x" % value return "%08x" % value
def PointerSize(self): def FormatTagged(self, value):
if self.Is64() and not self.IsPointerCompressed():
return "%016x" % value
return "%08x" % value
def MachinePointerSize(self):
if self.Is64(): if self.Is64():
return 8 return 8
return 4 return 4
def TaggedPointerSize(self):
if self.IsPointerCompressed():
return 4
return self.MachinePointerSize()
def Register(self, name): def Register(self, name):
return self.exception_context.__getattribute__(name) return self.exception_context.__getattribute__(name)
@ -1173,11 +1203,11 @@ class HeapObject(object):
instance_type) instance_type)
def ObjectField(self, offset): def ObjectField(self, offset):
field_value = self.heap.reader.ReadUIntPtr(self.address + offset) field_value = self.heap.reader.ReadTagged(self.address + offset)
return self.heap.FindObjectOrSmi(field_value) return self.heap.FindObjectOrSmi(field_value)
def SmiField(self, offset): def SmiField(self, offset):
field_value = self.heap.reader.ReadUIntPtr(self.address + offset) field_value = self.heap.reader.ReadTagged(self.address + offset)
if self.heap.IsSmi(field_value): if self.heap.IsSmi(field_value):
return self.heap.SmiUntag(field_value) return self.heap.SmiUntag(field_value)
return None return None
@ -1189,7 +1219,7 @@ class Map(HeapObject):
# Instance Sizes # Instance Sizes
def InstanceSizesOffset(self): def InstanceSizesOffset(self):
return self.heap.PointerSize() return self.heap.TaggedPointerSize()
def InstanceSizeOffset(self): def InstanceSizeOffset(self):
return self.InstanceSizesOffset() return self.InstanceSizesOffset()
@ -1224,28 +1254,29 @@ class Map(HeapObject):
return self.InstanceAttributesOffset() + self.heap.IntSize() return self.InstanceAttributesOffset() + self.heap.IntSize()
def PrototypeOffset(self): def PrototypeOffset(self):
return self.BitField3Offset() + self.heap.PointerSize() return self.BitField3Offset() + self.heap.TaggedPointerSize()
def ConstructorOrBackPointerOffset(self): def ConstructorOrBackPointerOffset(self):
return self.PrototypeOffset() + self.heap.PointerSize() return self.PrototypeOffset() + self.heap.TaggedPointerSize()
def TransitionsOrPrototypeInfoOffset(self): def TransitionsOrPrototypeInfoOffset(self):
return self.ConstructorOrBackPointerOffset() + self.heap.PointerSize() return self.ConstructorOrBackPointerOffset() + self.heap.TaggedPointerSize()
def DescriptorsOffset(self): def DescriptorsOffset(self):
return self.TransitionsOrPrototypeInfoOffset() + self.heap.PointerSize() return (self.TransitionsOrPrototypeInfoOffset() +
self.heap.TaggedPointerSize())
def CodeCacheOffset(self): def CodeCacheOffset(self):
return self.DescriptorsOffset() + self.heap.PointerSize() return self.DescriptorsOffset() + self.heap.TaggedPointerSize()
def DependentCodeOffset(self): def DependentCodeOffset(self):
return self.CodeCacheOffset() + self.heap.PointerSize() return self.CodeCacheOffset() + self.heap.TaggedPointerSize()
def ReadByte(self, offset): def ReadByte(self, offset):
return self.heap.reader.ReadU8(self.address + offset) return self.heap.reader.ReadU8(self.address + offset)
def ReadWord(self, offset): def ReadSlot(self, offset):
return self.heap.reader.ReadUIntPtr(self.address + offset) return self.heap.reader.ReadTagged(self.address + offset)
def Print(self, p): def Print(self, p):
p.Print("Map(%08x)" % (self.address)) p.Print("Map(%08x)" % (self.address))
@ -1264,7 +1295,7 @@ class Map(HeapObject):
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.ReadSlot(self.BitField3Offset())
p.Print( p.Print(
" - EnumLength: %d NumberOfOwnDescriptors: %d OwnsDescriptors: %s" % ( " - EnumLength: %d NumberOfOwnDescriptors: %d OwnsDescriptors: %s" % (
@ -1299,7 +1330,7 @@ class Map(HeapObject):
class String(HeapObject): class String(HeapObject):
def LengthOffset(self): def LengthOffset(self):
# First word after the map is the hash, the second is the length. # First word after the map is the hash, the second is the length.
return self.heap.PointerSize() * 2 return self.heap.TaggedPointerSize() * 2
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
@ -1317,7 +1348,7 @@ class String(HeapObject):
class SeqString(String): class SeqString(String):
def CharsOffset(self): def CharsOffset(self):
return self.heap.PointerSize() * 3 return self.heap.TaggedPointerSize() * 3
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
String.__init__(self, heap, map, address) String.__init__(self, heap, map, address)
@ -1360,10 +1391,10 @@ class ExternalString(String):
class ConsString(String): class ConsString(String):
def LeftOffset(self): def LeftOffset(self):
return self.heap.PointerSize() * 3 return self.heap.TaggedPointerSize() * 3
def RightOffset(self): def RightOffset(self):
return self.heap.PointerSize() * 4 return self.heap.TaggedPointerSize() * 4
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
String.__init__(self, heap, map, address) String.__init__(self, heap, map, address)
@ -1390,13 +1421,13 @@ class Oddball(HeapObject):
] ]
def ToStringOffset(self): def ToStringOffset(self):
return self.heap.PointerSize() return self.heap.TaggedPointerSize()
def ToNumberOffset(self): def ToNumberOffset(self):
return self.ToStringOffset() + self.heap.PointerSize() return self.ToStringOffset() + self.heap.TaggedPointerSize()
def KindOffset(self): def KindOffset(self):
return self.ToNumberOffset() + self.heap.PointerSize() return self.ToNumberOffset() + self.heap.TaggedPointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
@ -1418,13 +1449,13 @@ class Oddball(HeapObject):
class FixedArray(HeapObject): class FixedArray(HeapObject):
def LengthOffset(self): def LengthOffset(self):
return self.heap.PointerSize() return self.heap.TaggedPointerSize()
def ElementsOffset(self): def ElementsOffset(self):
return self.heap.PointerSize() * 2 return self.heap.TaggedPointerSize() * 2
def MemberOffset(self, i): def MemberOffset(self, i):
return self.ElementsOffset() + self.heap.PointerSize() * i return self.ElementsOffset() + self.heap.TaggedPointerSize() * i
def Get(self, i): def Get(self, i):
return self.ObjectField(self.MemberOffset(i)) return self.ObjectField(self.MemberOffset(i))
@ -1561,10 +1592,10 @@ class TransitionArray(object):
class JSFunction(HeapObject): class JSFunction(HeapObject):
def CodeEntryOffset(self): def CodeEntryOffset(self):
return 3 * self.heap.PointerSize() return 3 * self.heap.TaggedPointerSize()
def SharedOffset(self): def SharedOffset(self):
return 5 * self.heap.PointerSize() return 5 * self.heap.TaggedPointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
@ -1611,19 +1642,19 @@ class JSFunction(HeapObject):
class SharedFunctionInfo(HeapObject): class SharedFunctionInfo(HeapObject):
def CodeOffset(self): def CodeOffset(self):
return 2 * self.heap.PointerSize() return 2 * self.heap.TaggedPointerSize()
def ScriptOffset(self): def ScriptOffset(self):
return 7 * self.heap.PointerSize() return 7 * self.heap.TaggedPointerSize()
def InferredNameOffset(self): def InferredNameOffset(self):
return 9 * self.heap.PointerSize() return 9 * self.heap.TaggedPointerSize()
def EndPositionOffset(self): def EndPositionOffset(self):
return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize() return 12 * self.heap.TaggedPointerSize() + 4 * self.heap.IntSize()
def StartPositionAndTypeOffset(self): def StartPositionAndTypeOffset(self):
return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize() return 12 * self.heap.TaggedPointerSize() + 5 * self.heap.IntSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
@ -1631,7 +1662,7 @@ class SharedFunctionInfo(HeapObject):
self.code = self.ObjectField(self.CodeOffset()) self.code = self.ObjectField(self.CodeOffset())
self.script = self.ObjectField(self.ScriptOffset()) self.script = self.ObjectField(self.ScriptOffset())
self.inferred_name = self.ObjectField(self.InferredNameOffset()) self.inferred_name = self.ObjectField(self.InferredNameOffset())
if heap.PointerSize() == 8: if heap.TaggedPointerSize() == 8:
start_position_and_type = \ start_position_and_type = \
heap.reader.ReadU32(self.StartPositionAndTypeOffset()) heap.reader.ReadU32(self.StartPositionAndTypeOffset())
self.start_position = start_position_and_type >> 2 self.start_position = start_position_and_type >> 2
@ -1653,10 +1684,10 @@ class SharedFunctionInfo(HeapObject):
class Script(HeapObject): class Script(HeapObject):
def SourceOffset(self): def SourceOffset(self):
return self.heap.PointerSize() return self.heap.TaggedPointerSize()
def NameOffset(self): def NameOffset(self):
return self.SourceOffset() + self.heap.PointerSize() return self.SourceOffset() + self.heap.TaggedPointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
@ -1666,10 +1697,10 @@ class Script(HeapObject):
class CodeCache(HeapObject): class CodeCache(HeapObject):
def DefaultCacheOffset(self): def DefaultCacheOffset(self):
return self.heap.PointerSize() return self.heap.TaggedPointerSize()
def NormalTypeCacheOffset(self): def NormalTypeCacheOffset(self):
return self.DefaultCacheOffset() + self.heap.PointerSize() return self.DefaultCacheOffset() + self.heap.TaggedPointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
@ -1689,12 +1720,12 @@ class Code(HeapObject):
CODE_ALIGNMENT_MASK = (1 << 5) - 1 CODE_ALIGNMENT_MASK = (1 << 5) - 1
def InstructionSizeOffset(self): def InstructionSizeOffset(self):
return self.heap.PointerSize() return self.heap.TaggedPointerSize()
@staticmethod @staticmethod
def HeaderSize(heap): def HeaderSize(heap):
return (heap.PointerSize() + heap.IntSize() + \ return (heap.TaggedPointerSize() + heap.IntSize() + \
4 * heap.PointerSize() + 3 * heap.IntSize() + \ 4 * heap.TaggedPointerSize() + 3 * heap.IntSize() + \
Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
@ -1763,7 +1794,7 @@ class V8Heap(object):
if not self.IsTaggedObjectAddress(tagged_address): return None if not self.IsTaggedObjectAddress(tagged_address): return None
address = tagged_address - 1 address = tagged_address - 1
if not self.reader.IsValidAddress(address): return None if not self.reader.IsValidAddress(address): return None
map_tagged_address = self.reader.ReadUIntPtr(address) map_tagged_address = self.reader.ReadTagged(address)
if tagged_address == map_tagged_address: if tagged_address == map_tagged_address:
# Meta map? # Meta map?
meta_map = Map(self, None, address) meta_map = Map(self, None, address)
@ -1796,11 +1827,17 @@ class V8Heap(object):
def IntSize(self): def IntSize(self):
return 4 return 4
def PointerSize(self): def MachinePointerSize(self):
return self.reader.PointerSize() return self.reader.MachinePointerSize()
def TaggedPointerSize(self):
return self.reader.TaggedPointerSize()
def IsPointerCompressed(self):
return self.reader.IsPointerCompressed()
def ObjectAlignmentMask(self): def ObjectAlignmentMask(self):
return self.PointerSize() - 1 return self.TaggedPointerSize() - 1
def IsTaggedObjectAddress(self, address): def IsTaggedObjectAddress(self, address):
return (address & self.ObjectAlignmentMask()) == 1 return (address & self.ObjectAlignmentMask()) == 1
@ -1829,13 +1866,14 @@ class V8Heap(object):
return (address & self.ObjectAlignmentMask()) == 1 return (address & self.ObjectAlignmentMask()) == 1
def IsSmi(self, tagged_address): def IsSmi(self, tagged_address):
if self.reader.Is64(): if self.reader.Is64() and not self.reader.IsPointerCompressed():
return (tagged_address & 0xFFFFFFFF) == 0 return (tagged_address & 0xFFFFFFFF) == 0
return not self.IsTaggedAddress(tagged_address) return not self.IsTaggedAddress(tagged_address)
def SmiUntag(self, tagged_address): def SmiUntag(self, tagged_address):
if self.reader.Is64(): return tagged_address >> 32 if self.reader.Is64() and not self.reader.IsPointerCompressed():
return tagged_address >> 1 return tagged_address >> 32
return (tagged_address >> 1) & 0xFFFFFFFF
def AddressTypeMarker(self, address): def AddressTypeMarker(self, address):
if not self.reader.IsValidAddress(address): return " " if not self.reader.IsValidAddress(address): return " "
@ -1858,7 +1896,7 @@ class V8Heap(object):
if self.IsTaggedObjectAddress(address): if self.IsTaggedObjectAddress(address):
address -= 1 address -= 1
if not self.reader.IsValidAlignedAddress(address): return None if not self.reader.IsValidAlignedAddress(address): return None
offset = (address - slot) / self.PointerSize() offset = (address - slot) / self.MachinePointerSize()
lower_limit = -32 lower_limit = -32
upper_limit = 128 upper_limit = 128
@ -1873,12 +1911,12 @@ class V8Heap(object):
def FindObjectPointers(self, start=0, end=0): def FindObjectPointers(self, start=0, end=0):
objects = set() objects = set()
def find_object_in_region(reader, start, size, location): def find_object_in_region(reader, start, size, location):
for slot in range(start, start+size, self.reader.PointerSize()): for slot in range(start, start + size, self.reader.TaggedPointerSize()):
if not self.reader.IsValidAddress(slot): break if not self.reader.IsValidAddress(slot): break
# Collect only tagged pointers (object) to tagged pointers (map) # Collect only tagged pointers (object) to tagged pointers (map)
tagged_address = self.reader.ReadUIntPtr(slot) tagged_address = self.reader.ReadTagged(slot)
if not self.IsValidTaggedObjectAddress(tagged_address): continue if not self.IsValidTaggedObjectAddress(tagged_address): continue
map_address = self.reader.ReadUIntPtr(tagged_address - 1) map_address = self.reader.ReadTagged(tagged_address - 1)
if not self.IsTaggedMapAddress(map_address): continue if not self.IsTaggedMapAddress(map_address): continue
objects.add(tagged_address) objects.add(tagged_address)
@ -1951,10 +1989,12 @@ class InspectionInfo(object):
exception_thread.stack.memory.data_size exception_thread.stack.memory.data_size
frame_pointer = self.reader.ExceptionFP() frame_pointer = self.reader.ExceptionFP()
self.styles[frame_pointer] = "frame" self.styles[frame_pointer] = "frame"
for slot in range(stack_top, stack_bottom, self.reader.PointerSize()): for slot in range(stack_top, stack_bottom,
self.reader.MachinePointerSize()):
# stack address # stack address
self.styles[slot] = "sa" self.styles[slot] = "sa"
for slot in range(stack_top, stack_bottom, self.reader.PointerSize()): for slot in range(stack_top, stack_bottom,
self.reader.MachinePointerSize()):
maybe_address = self.reader.ReadUIntPtr(slot) maybe_address = self.reader.ReadUIntPtr(slot)
# stack value # stack value
self.styles[maybe_address] = "sv" self.styles[maybe_address] = "sv"
@ -2026,7 +2066,7 @@ class InspectionPadawan(object):
# Frame markers only occur directly after a frame pointer and only on the # Frame markers only occur directly after a frame pointer and only on the
# stack. # stack.
if not self.reader.IsExceptionStackAddress(slot): return False if not self.reader.IsExceptionStackAddress(slot): return False
next_slot = slot + self.reader.PointerSize() next_slot = slot + self.reader.MachinePointerSize()
if not self.reader.IsValidAddress(next_slot): return False if not self.reader.IsValidAddress(next_slot): return False
next_address = self.reader.ReadUIntPtr(next_slot) next_address = self.reader.ReadUIntPtr(next_slot)
return self.reader.IsExceptionStackAddress(next_address) return self.reader.IsExceptionStackAddress(next_address)
@ -2058,7 +2098,7 @@ class InspectionPadawan(object):
if found_obj: return found_obj if found_obj: return found_obj
address = tagged_address - 1 address = tagged_address - 1
if self.reader.IsValidAddress(address): if self.reader.IsValidAddress(address):
map_tagged_address = self.reader.ReadUIntPtr(address) map_tagged_address = self.reader.ReadTagged(address)
map = self.SenseMap(map_tagged_address) map = self.SenseMap(map_tagged_address)
if map is None: return None if map is None: return None
instance_type_name = INSTANCE_TYPES.get(map.instance_type) instance_type_name = INSTANCE_TYPES.get(map.instance_type)
@ -2118,7 +2158,7 @@ class InspectionPadawan(object):
Returns the first address where the normal stack starts again. Returns the first address where the normal stack starts again.
""" """
# Only look at the first 1k words on the stack # Only look at the first 1k words on the stack
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
if start is None: start = self.reader.ExceptionSP() if start is None: start = self.reader.ExceptionSP()
if not self.reader.IsValidAddress(start): return start if not self.reader.IsValidAddress(start): return start
end = start + ptr_size * 1024 * 4 end = start + ptr_size * 1024 * 4
@ -2140,7 +2180,7 @@ class InspectionPadawan(object):
print_message) print_message)
def TryExtractStackTrace(self, slot, start, end, print_message): def TryExtractStackTrace(self, slot, start, end, print_message):
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
assert self.reader.ReadUIntPtr(slot) & 0xFFFFFFFF == STACK_TRACE_MARKER assert self.reader.ReadUIntPtr(slot) & 0xFFFFFFFF == STACK_TRACE_MARKER
end_marker = STACK_TRACE_MARKER + 1; end_marker = STACK_TRACE_MARKER + 1;
header_size = 10 header_size = 10
@ -2163,7 +2203,7 @@ class InspectionPadawan(object):
return stack_start return stack_start
def FindPtr(self, expected_value, start, end): def FindPtr(self, expected_value, start, end):
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
for slot in range(start, end, ptr_size): for slot in range(start, end, ptr_size):
if not self.reader.IsValidAddress(slot): return None if not self.reader.IsValidAddress(slot): return None
value = self.reader.ReadUIntPtr(slot) value = self.reader.ReadUIntPtr(slot)
@ -2171,7 +2211,7 @@ class InspectionPadawan(object):
return None return None
def TryExtractErrorMessage(self, slot, start, end, print_message): def TryExtractErrorMessage(self, slot, start, end, print_message):
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
end_marker = ERROR_MESSAGE_MARKER + 1; end_marker = ERROR_MESSAGE_MARKER + 1;
header_size = 1 header_size = 1
end_search = start + 1024 + (header_size * ptr_size); end_search = start + 1024 + (header_size * ptr_size);
@ -2186,7 +2226,7 @@ class InspectionPadawan(object):
def TryExtractOldStyleStackTrace(self, message_slot, start, end, def TryExtractOldStyleStackTrace(self, message_slot, start, end,
print_message): print_message):
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
if message_slot == 0: if message_slot == 0:
""" """
On Mac we don't always get proper magic markers, so just try printing On Mac we don't always get proper magic markers, so just try printing
@ -2225,7 +2265,7 @@ class InspectionPadawan(object):
print(" Use `dsa` to print the message with annotated addresses.") print(" Use `dsa` to print the message with annotated addresses.")
print("") print("")
return return
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
# Annotate all addresses in the dumped message # Annotate all addresses in the dumped message
prog = re.compile("[0-9a-fA-F]{%s}" % ptr_size*2) prog = re.compile("[0-9a-fA-F]{%s}" % ptr_size*2)
addresses = list(set(prog.findall(message))) addresses = list(set(prog.findall(message)))
@ -2252,7 +2292,7 @@ class InspectionPadawan(object):
def TryInferContext(self, address): def TryInferContext(self, address):
if self.context: return if self.context: return
ptr_size = self.reader.PointerSize() ptr_size = self.reader.MachinePointerSize()
possible_context = dict() possible_context = dict()
count = 0 count = 0
while self.reader.IsExceptionStackAddress(address): while self.reader.IsExceptionStackAddress(address):
@ -2287,7 +2327,7 @@ class InspectionPadawan(object):
in_oom_dump_area = False in_oom_dump_area = False
is_stack = self.reader.IsExceptionStackAddress(start) is_stack = self.reader.IsExceptionStackAddress(start)
free_space_end = 0 free_space_end = 0
ptr_size = self.reader.PointerSize() ptr_size = self.reader.TaggedPointerSize()
for slot in range(start, end, ptr_size): for slot in range(start, end, ptr_size):
if not self.reader.IsValidAddress(slot): if not self.reader.IsValidAddress(slot):
@ -2309,7 +2349,7 @@ class InspectionPadawan(object):
if isinstance(heap_object, KnownMap) and \ if isinstance(heap_object, KnownMap) and \
heap_object.known_name == "FreeSpaceMap": heap_object.known_name == "FreeSpaceMap":
# The free-space length is is stored as a Smi in the next slot. # The free-space length is is stored as a Smi in the next slot.
length = self.reader.ReadUIntPtr(slot + ptr_size) length = self.reader.ReadTagged(slot + ptr_size)
if self.heap.IsSmi(length): if self.heap.IsSmi(length):
length = self.heap.SmiUntag(length) length = self.heap.SmiUntag(length)
free_space_end = slot + length - ptr_size free_space_end = slot + length - ptr_size
@ -2711,7 +2751,8 @@ class InspectionWebFormatter(object):
stack_bottom = exception_thread.stack.start + \ stack_bottom = exception_thread.stack.start + \
exception_thread.stack.memory.data_size exception_thread.stack.memory.data_size
stack_map = {self.reader.ExceptionIP(): -1} stack_map = {self.reader.ExceptionIP(): -1}
for slot in range(stack_top, stack_bottom, self.reader.PointerSize()): for slot in range(stack_top, stack_bottom,
self.reader.MachinePointerSize()):
maybe_address = self.reader.ReadUIntPtr(slot) maybe_address = self.reader.ReadUIntPtr(slot)
if not maybe_address in stack_map: if not maybe_address in stack_map:
stack_map[maybe_address] = slot stack_map[maybe_address] = slot
@ -2757,6 +2798,18 @@ class InspectionWebFormatter(object):
return ("<a %s href=s?%s&amp;val=%s>%s</a>" % return ("<a %s href=s?%s&amp;val=%s>%s</a>" %
(style_class, self.encfilename, straddress, straddress)) (style_class, self.encfilename, straddress, straddress))
def format_onheap_address(self, size, maybeaddress, uncompressed):
if maybeaddress is None:
return "not in dump"
else:
straddress = "0x" + self.reader.FormatTagged(maybeaddress)
struncompressed = "0x" + self.reader.FormatIntPtr(uncompressed)
style_class = ""
if not self.reader.IsValidAddress(maybeaddress):
style_class = "class=nd"
return ("<a %s href=s?%s&amp;val=%s>%s</a>" %
(style_class, self.encfilename, struncompressed, straddress))
def output_header(self, f): def output_header(self, f):
f.write(WEB_HEADER % f.write(WEB_HEADER %
{ "query_dump" : self.encfilename, { "query_dump" : self.encfilename,
@ -2779,7 +2832,8 @@ class InspectionWebFormatter(object):
stack_bottom = min(exception_thread.stack.start + \ stack_bottom = min(exception_thread.stack.start + \
exception_thread.stack.memory.data_size, exception_thread.stack.memory.data_size,
stack_top + self.MAX_CONTEXT_STACK) stack_top + self.MAX_CONTEXT_STACK)
self.output_words(f, stack_top - 16, stack_bottom, stack_top, "Stack") self.output_words(f, stack_top - 16, stack_bottom, stack_top, "Stack",
self.heap.MachinePointerSize())
f.write('</div>') f.write('</div>')
self.output_footer(f) self.output_footer(f)
@ -2900,7 +2954,11 @@ class InspectionWebFormatter(object):
return return
region = self.reader.FindRegion(address) region = self.reader.FindRegion(address)
if datakind == "address": if datakind == "address":
self.output_words(f, region[0], region[0] + region[1], address, "Dump") self.output_words(f, region[0], region[0] + region[1], address, "Dump",
self.heap.MachinePointerSize())
if datakind == "tagged":
self.output_words(f, region[0], region[0] + region[1], address,
"Tagged Dump", self.heap.TaggedPointerSize())
elif datakind == "ascii": elif datakind == "ascii":
self.output_ascii(f, region[0], region[0] + region[1], address) self.output_ascii(f, region[0], region[0] + region[1], address)
self.output_footer(f) self.output_footer(f)
@ -2909,14 +2967,13 @@ class InspectionWebFormatter(object):
f.write("<h3>Unrecognized address format \"%s\".</h3>" % straddress) f.write("<h3>Unrecognized address format \"%s\".</h3>" % straddress)
return return
def output_words(self, f, start_address, end_address, def output_words(self, f, start_address, end_address, highlight_address, desc,
highlight_address, desc): size):
region = self.reader.FindRegion(highlight_address) region = self.reader.FindRegion(highlight_address)
if region is None: if region is None:
f.write("<h3>Address 0x%x not found in the dump.</h3>" % f.write("<h3>Address 0x%x not found in the dump.</h3>" %
(highlight_address)) (highlight_address))
return return
size = self.heap.PointerSize()
start_address = self.align_down(start_address, size) start_address = self.align_down(start_address, size)
low = self.align_down(region[0], size) low = self.align_down(region[0], size)
high = self.align_up(region[0] + region[1], size) high = self.align_up(region[0] + region[1], size)
@ -2943,6 +3000,7 @@ class InspectionWebFormatter(object):
slot = start_address + j slot = start_address + j
heap_object = "" heap_object = ""
maybe_address = None maybe_address = None
maybe_uncompressed_address = None
end_region = region[0] + region[1] end_region = region[0] + region[1]
if slot < region[0] or slot + size > end_region: if slot < region[0] or slot + size > end_region:
straddress = "0x" straddress = "0x"
@ -2954,10 +3012,20 @@ class InspectionWebFormatter(object):
for i in range(slot, region[0]): for i in range(slot, region[0]):
straddress += "??" straddress += "??"
else: else:
maybe_address = self.reader.ReadUIntPtr(slot) maybe_address = self.reader.ReadSized(slot, size)
straddress = self.format_address(maybe_address) if size == self.reader.MachinePointerSize():
if maybe_address: maybe_uncompressed_address = maybe_address
heap_object = self.format_object(maybe_address) else:
maybe_uncompressed_address = (slot & (0xFFFFFF << 32)) | (
maybe_address & 0xFFFFFF)
if size == self.reader.TaggedPointerSize():
straddress = self.format_onheap_address(size, maybe_address,
maybe_uncompressed_address)
if maybe_address:
heap_object = self.format_object(maybe_address)
else:
straddress = self.format_address(maybe_address)
address_fmt = "%s&nbsp;</td>" address_fmt = "%s&nbsp;</td>"
if slot == highlight_address: if slot == highlight_address:
@ -2974,12 +3042,12 @@ class InspectionWebFormatter(object):
f.write("</td>") f.write("</td>")
self.td_from_address(f, slot) self.td_from_address(f, slot)
f.write(address_fmt % self.format_address(slot)) f.write(address_fmt % self.format_address(slot))
self.td_from_address(f, maybe_address) self.td_from_address(f, maybe_uncompressed_address)
f.write(":&nbsp;%s&nbsp;</td>" % straddress) f.write(":&nbsp;%s&nbsp;</td>" % straddress)
f.write("<td>") f.write("<td>")
if maybe_address != None: if maybe_uncompressed_address != None:
self.output_comment_box( self.output_comment_box(f, "sv-" + self.reader.FormatIntPtr(slot),
f, "sv-" + self.reader.FormatIntPtr(slot), maybe_address) maybe_uncompressed_address)
f.write("</td>") f.write("</td>")
f.write("<td>%s</td>" % (heap_object or '')) f.write("<td>%s</td>" % (heap_object or ''))
f.write("</tr>") f.write("</tr>")
@ -3134,9 +3202,9 @@ class InspectionWebFormatter(object):
# Some disassemblers insert spaces between each byte, # Some disassemblers insert spaces between each byte,
# while some do not. # while some do not.
if code[2] == " ": if code[2] == " ":
op_offset = 3 * num_bytes - 1 op_offset = 3 * num_bytes - 1
else: else:
op_offset = 2 * num_bytes op_offset = 2 * num_bytes
# Compute the actual call target which the disassembler is too stupid # Compute the actual call target which the disassembler is too stupid
# to figure out (it adds the call offset to the disassembly offset rather # to figure out (it adds the call offset to the disassembly offset rather
@ -3230,7 +3298,12 @@ class InspectionWebFormatter(object):
straddress) straddress)
else: else:
# Print as words # Print as words
self.output_words(f, address - 8, address + 32, address, "Dump") self.output_words(f, address - 8, address + 32, address, "Dump",
self.heap.MachinePointerSize())
if self.heap.IsPointerCompressed():
self.output_words(f, address - 8, address + 32, address,
"Tagged Dump", self.heap.TaggedPointerSize())
# Print as ASCII # Print as ASCII
f.write("<hr>") f.write("<hr>")
@ -3534,10 +3607,10 @@ class InspectionShell(cmd.Cmd):
self.dd_start = self.ParseAddressExpr(args[0]) self.dd_start = self.ParseAddressExpr(args[0])
self.dd_num = int(args[1], 16) if len(args) > 1 else 0x10 self.dd_num = int(args[1], 16) if len(args) > 1 else 0x10
else: else:
self.dd_start += self.dd_num * self.reader.PointerSize() self.dd_start += self.dd_num * self.reader.MachinePointerSize()
if not self.reader.IsAlignedAddress(self.dd_start): if not self.reader.IsAlignedAddress(self.dd_start):
print("Warning: Dumping un-aligned memory, is this what you had in mind?") print("Warning: Dumping un-aligned memory, is this what you had in mind?")
end = self.dd_start + self.reader.PointerSize() * self.dd_num end = self.dd_start + self.reader.MachinePointerSize() * self.dd_num
self.padawan.InterpretMemory(self.dd_start, end) self.padawan.InterpretMemory(self.dd_start, end)
def do_do(self, address): def do_do(self, address):
@ -3828,7 +3901,7 @@ def AnalyzeMinidump(options, minidump_name):
stack_top = reader.ExceptionSP() stack_top = reader.ExceptionSP()
stack_bottom = reader.StackBottom() stack_bottom = reader.StackBottom()
stack_map = {reader.ExceptionIP(): -1} stack_map = {reader.ExceptionIP(): -1}
for slot in range(stack_top, stack_bottom, reader.PointerSize()): for slot in range(stack_top, stack_bottom, reader.MachinePointerSize()):
maybe_address = reader.ReadUIntPtr(slot) maybe_address = reader.ReadUIntPtr(slot)
if not maybe_address in stack_map: if not maybe_address in stack_map:
stack_map[maybe_address] = slot stack_map[maybe_address] = slot