Add X64 minidumps support to tools/grokdump.py

R=erik.corry@gmail.com

Review URL: http://codereview.chromium.org/8957005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10263 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vegorov@chromium.org 2011-12-15 12:13:34 +00:00
parent 626b61f967
commit 7a93464ca0

View File

@ -52,6 +52,7 @@ Examples:
$ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp
""" """
DEBUG=False DEBUG=False
@ -233,6 +234,80 @@ MINIDUMP_CONTEXT_X86 = Descriptor([
MD_CONTEXT_X86_EXTENDED_REGISTERS)) MD_CONTEXT_X86_EXTENDED_REGISTERS))
]) ])
MD_CONTEXT_AMD64 = 0x00100000
MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001)
MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002)
MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004)
MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008)
MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010)
MINIDUMP_CONTEXT_AMD64 = Descriptor([
("p1_home", ctypes.c_uint64),
("p2_home", ctypes.c_uint64),
("p3_home", ctypes.c_uint64),
("p4_home", ctypes.c_uint64),
("p5_home", ctypes.c_uint64),
("p6_home", ctypes.c_uint64),
("context_flags", ctypes.c_uint32),
("mx_csr", ctypes.c_uint32),
# MD_CONTEXT_AMD64_CONTROL.
("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
# MD_CONTEXT_AMD64_SEGMENTS
("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)),
# MD_CONTEXT_AMD64_CONTROL.
("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)),
("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)),
# MD_CONTEXT_AMD64_DEBUG_REGISTERS.
("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
# MD_CONTEXT_AMD64_INTEGER.
("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
# MD_CONTEXT_AMD64_CONTROL.
("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
# MD_CONTEXT_AMD64_INTEGER.
("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)),
# MD_CONTEXT_AMD64_CONTROL.
("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)),
# MD_CONTEXT_AMD64_FLOATING_POINT
("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
MD_CONTEXT_AMD64_FLOATING_POINT)),
("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26),
MD_CONTEXT_AMD64_FLOATING_POINT)),
("vector_control", EnableOnFlag(ctypes.c_uint64,
MD_CONTEXT_AMD64_FLOATING_POINT)),
# MD_CONTEXT_AMD64_DEBUG_REGISTERS.
("debug_control", EnableOnFlag(ctypes.c_uint64,
MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64,
MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64,
MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64,
MD_CONTEXT_AMD64_DEBUG_REGISTERS)),
("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64,
MD_CONTEXT_AMD64_DEBUG_REGISTERS))
])
MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([ MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([
("start", ctypes.c_uint64), ("start", ctypes.c_uint64),
("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype) ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
@ -269,6 +344,12 @@ MINIDUMP_THREAD_LIST = Descriptor([
("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
]) ])
MINIDUMP_RAW_SYSTEM_INFO = Descriptor([
("processor_architecture", ctypes.c_uint16)
])
MD_CPU_ARCHITECTURE_X86 = 0
MD_CPU_ARCHITECTURE_AMD64 = 9
class MinidumpReader(object): class MinidumpReader(object):
"""Minidump (.dmp) reader.""" """Minidump (.dmp) reader."""
@ -288,20 +369,34 @@ class MinidumpReader(object):
for _ in xrange(self.header.stream_count): for _ in xrange(self.header.stream_count):
directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset))
offset += MINIDUMP_DIRECTORY.size offset += MINIDUMP_DIRECTORY.size
self.arch = None
self.exception = None self.exception = None
self.exception_context = None self.exception_context = None
self.memory_list = None self.memory_list = None
self.memory_list64 = None self.memory_list64 = None
self.thread_map = {} self.thread_map = {}
# Find MDRawSystemInfo stream and determine arch.
for d in directories:
if d.stream_type == MD_SYSTEM_INFO_STREAM:
system_info = MINIDUMP_RAW_SYSTEM_INFO.Read(
self.minidump, d.location.rva)
self.arch = system_info.processor_architecture
assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86]
assert not self.arch is None
for d in directories: for d in directories:
DebugPrint(d) DebugPrint(d)
# TODO(vitalyr): extract system info including CPU features.
if d.stream_type == MD_EXCEPTION_STREAM: if d.stream_type == MD_EXCEPTION_STREAM:
self.exception = MINIDUMP_EXCEPTION_STREAM.Read( self.exception = MINIDUMP_EXCEPTION_STREAM.Read(
self.minidump, d.location.rva) self.minidump, d.location.rva)
DebugPrint(self.exception) DebugPrint(self.exception)
self.exception_context = MINIDUMP_CONTEXT_X86.Read( if self.arch == MD_CPU_ARCHITECTURE_X86:
self.minidump, self.exception.thread_context.rva) 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)
DebugPrint(self.exception_context) DebugPrint(self.exception_context)
elif d.stream_type == MD_THREAD_LIST_STREAM: elif d.stream_type == MD_THREAD_LIST_STREAM:
thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva)
@ -335,6 +430,16 @@ class MinidumpReader(object):
location = self.FindLocation(address) location = self.FindLocation(address)
return ctypes.c_uint32.from_buffer(self.minidump, location).value return ctypes.c_uint32.from_buffer(self.minidump, location).value
def ReadU64(self, address):
location = self.FindLocation(address)
return ctypes.c_uint64.from_buffer(self.minidump, location).value
def ReadUIntPtr(self, address):
if self.arch == MD_CPU_ARCHITECTURE_AMD64:
return self.ReadU64(address)
elif self.arch == MD_CPU_ARCHITECTURE_X86:
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]
@ -355,10 +460,15 @@ class MinidumpReader(object):
def GetDisasmLines(self, address, size): def GetDisasmLines(self, address, size):
location = self.FindLocation(address) location = self.FindLocation(address)
if location is None: return [] if location is None: return []
arch = None
if self.arch == MD_CPU_ARCHITECTURE_X86:
arch = "ia32"
elif self.arch == MD_CPU_ARCHITECTURE_AMD64:
arch = "x64"
return disasm.GetDisasmLines(self.minidump_name, return disasm.GetDisasmLines(self.minidump_name,
location, location,
size, size,
"ia32", arch,
False) False)
@ -366,6 +476,33 @@ class MinidumpReader(object):
self.minidump.close() self.minidump.close()
self.minidump_file.close() self.minidump_file.close()
def ExceptionIP(self):
if self.arch == MD_CPU_ARCHITECTURE_AMD64:
return self.exception_context.rip
elif self.arch == MD_CPU_ARCHITECTURE_X86:
return self.exception_context.eip
def ExceptionSP(self):
if self.arch == MD_CPU_ARCHITECTURE_AMD64:
return self.exception_context.rsp
elif self.arch == MD_CPU_ARCHITECTURE_X86:
return self.exception_context.rbp
def FormatIntPtr(self, value):
if self.arch == MD_CPU_ARCHITECTURE_AMD64:
return "%016x" % value
elif self.arch == MD_CPU_ARCHITECTURE_X86:
return "%08x" % value
def PointerSize(self):
if self.arch == MD_CPU_ARCHITECTURE_AMD64:
return 8
elif self.arch == MD_CPU_ARCHITECTURE_X86:
return 4
def Register(self, name):
return self.exception_context.__getattribute__(name)
# List of V8 instance types. Obtained by adding the code below to any .cc file. # List of V8 instance types. Obtained by adding the code below to any .cc file.
# #
@ -501,34 +638,36 @@ class HeapObject(object):
p.Print(str(self)) p.Print(str(self))
def __str__(self): def __str__(self):
return "HeapObject(%08x, %s)" % (self.address, return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address),
INSTANCE_TYPES[self.map.instance_type]) INSTANCE_TYPES[self.map.instance_type])
def ObjectField(self, offset): def ObjectField(self, offset):
field_value = self.heap.reader.ReadU32(self.address + offset) field_value = self.heap.reader.ReadUIntPtr(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.ReadU32(self.address + offset) field_value = self.heap.reader.ReadUIntPtr(self.address + offset)
assert (field_value & 1) == 0 assert (field_value & 1) == 0
return field_value / 2 return field_value / 2
class Map(HeapObject): class Map(HeapObject):
INSTANCE_TYPE_OFFSET = 8 def InstanceTypeOffset():
return self.heap.PointerSize() + 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)
self.instance_type = \ self.instance_type = \
heap.reader.ReadU8(self.address + Map.INSTANCE_TYPE_OFFSET) heap.reader.ReadU8(self.address + self.InstanceTypeOffset())
class String(HeapObject): class String(HeapObject):
LENGTH_OFFSET = 4 def LengthOffset(self):
return self.heap.PointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
self.length = self.SmiField(String.LENGTH_OFFSET) self.length = self.SmiField(self.LengthOffset())
def GetChars(self): def GetChars(self):
return "?string?" return "?string?"
@ -541,11 +680,12 @@ class String(HeapObject):
class SeqString(String): class SeqString(String):
CHARS_OFFSET = 12 def CharsOffset(self):
return self.heap.PointerSize() * 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)
self.chars = heap.reader.ReadBytes(self.address + SeqString.CHARS_OFFSET, self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(),
self.length) self.length)
def GetChars(self): def GetChars(self):
@ -553,6 +693,7 @@ class SeqString(String):
class ExternalString(String): class ExternalString(String):
# TODO(vegorov) fix ExternalString for X64 architecture
RESOURCE_OFFSET = 12 RESOURCE_OFFSET = 12
WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4
@ -582,24 +723,28 @@ class ExternalString(String):
class ConsString(String): class ConsString(String):
LEFT_OFFSET = 12 def LeftOffset(self):
RIGHT_OFFSET = 16 return self.heap.PointerSize() * 3
def RightOffset(self):
return self.heap.PointerSize() * 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)
self.left = self.ObjectField(ConsString.LEFT_OFFSET) self.left = self.ObjectField(self.LeftOffset())
self.right = self.ObjectField(ConsString.RIGHT_OFFSET) self.right = self.ObjectField(self.RightOffset())
def GetChars(self): def GetChars(self):
return self.left.GetChars() + self.right.GetChars() return self.left.GetChars() + self.right.GetChars()
class Oddball(HeapObject): class Oddball(HeapObject):
TO_STRING_OFFSET = 4 def ToStringOffset(self):
return self.heap.PointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
self.to_string = self.ObjectField(Oddball.TO_STRING_OFFSET) self.to_string = self.ObjectField(self.ToStringOffset())
def Print(self, p): def Print(self, p):
p.Print(str(self)) p.Print(str(self))
@ -609,19 +754,23 @@ class Oddball(HeapObject):
class FixedArray(HeapObject): class FixedArray(HeapObject):
LENGTH_OFFSET = 4 def LengthOffset(self):
ELEMENTS_OFFSET = 8 return self.heap.PointerSize()
def ElementsOffset(self):
return self.heap.PointerSize() * 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)
self.length = self.SmiField(FixedArray.LENGTH_OFFSET) self.length = self.SmiField(self.LengthOffset())
def Print(self, p): def Print(self, p):
p.Print("FixedArray(%08x) {" % self.address) p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address))
p.Indent() p.Indent()
p.Print("length: %d" % self.length) p.Print("length: %d" % self.length)
base_offset = self.ElementsOffset()
for i in xrange(self.length): for i in xrange(self.length):
offset = FixedArray.ELEMENTS_OFFSET + 4 * i offset = base_offset + 4 * i
p.Print("[%08d] = %s" % (i, self.ObjectField(offset))) p.Print("[%08d] = %s" % (i, self.ObjectField(offset)))
p.Dedent() p.Dedent()
p.Print("}") p.Print("}")
@ -631,19 +780,22 @@ class FixedArray(HeapObject):
class JSFunction(HeapObject): class JSFunction(HeapObject):
CODE_ENTRY_OFFSET = 12 def CodeEntryOffset(self):
SHARED_OFFSET = 20 return 3 * self.heap.PointerSize()
def SharedOffset(self):
return 5 * self.heap.PointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
code_entry = \ code_entry = \
heap.reader.ReadU32(self.address + JSFunction.CODE_ENTRY_OFFSET) heap.reader.ReadU32(self.address + self.CodeEntryOffset())
self.code = heap.FindObject(code_entry - Code.ENTRY_OFFSET + 1) self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1)
self.shared = self.ObjectField(JSFunction.SHARED_OFFSET) self.shared = self.ObjectField(self.SharedOffset())
def Print(self, p): def Print(self, p):
source = "\n".join(" %s" % line for line in self._GetSource().split("\n")) source = "\n".join(" %s" % line for line in self._GetSource().split("\n"))
p.Print("JSFunction(%08x) {" % self.address) p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address))
p.Indent() p.Indent()
p.Print("inferred name: %s" % self.shared.inferred_name) p.Print("inferred name: %s" % self.shared.inferred_name)
if self.shared.script.Is(Script) and self.shared.script.name.Is(String): if self.shared.script.Is(Script) and self.shared.script.name.Is(String):
@ -662,7 +814,8 @@ class JSFunction(HeapObject):
inferred_name = "" inferred_name = ""
if self.shared.Is(SharedFunctionInfo): if self.shared.Is(SharedFunctionInfo):
inferred_name = self.shared.inferred_name inferred_name = self.shared.inferred_name
return "JSFunction(%08x, %s)" % (self.address, inferred_name) return "JSFunction(%s, %s)" % \
(self.heap.reader.FormatIntPtr(self.address), inferred_name)
def _GetSource(self): def _GetSource(self):
source = "?source?" source = "?source?"
@ -675,47 +828,75 @@ class JSFunction(HeapObject):
class SharedFunctionInfo(HeapObject): class SharedFunctionInfo(HeapObject):
CODE_OFFSET = 2 * 4 def CodeOffset(self):
SCRIPT_OFFSET = 7 * 4 return 2 * self.heap.PointerSize()
INFERRED_NAME_OFFSET = 9 * 4
START_POSITION_AND_TYPE_OFFSET = 17 * 4 def ScriptOffset(self):
END_POSITION_OFFSET = 18 * 4 return 7 * self.heap.PointerSize()
def InferredNameOffset(self):
return 9 * self.heap.PointerSize()
def EndPositionOffset(self):
return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize()
def StartPositionAndTypeOffset(self):
return 12 * self.heap.PointerSize() + 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)
self.code = self.ObjectField(SharedFunctionInfo.CODE_OFFSET) self.code = self.ObjectField(self.CodeOffset())
self.script = self.ObjectField(SharedFunctionInfo.SCRIPT_OFFSET) self.script = self.ObjectField(self.ScriptOffset())
self.inferred_name = \ self.inferred_name = self.ObjectField(self.InferredNameOffset())
self.ObjectField(SharedFunctionInfo.INFERRED_NAME_OFFSET) if heap.PointerSize() == 8:
start_position_and_type = \ start_position_and_type = \
self.SmiField(SharedFunctionInfo.START_POSITION_AND_TYPE_OFFSET) heap.reader.ReadU32(self.StartPositionAndTypeOffset())
self.start_position = start_position_and_type >> 2 self.start_position = start_position_and_type >> 2
self.end_position = self.SmiField(SharedFunctionInfo.END_POSITION_OFFSET) 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())
self.start_position = start_position_and_type >> 2
self.end_position = \
self.SmiField(self.EndPositionOffset())
class Script(HeapObject): class Script(HeapObject):
SOURCE_OFFSET = 4 def SourceOffset(self):
NAME_OFFSET = 8 return self.heap.PointerSize()
def NameOffset(self):
return self.SourceOffset() + self.heap.PointerSize()
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
self.source = self.ObjectField(Script.SOURCE_OFFSET) self.source = self.ObjectField(self.SourceOffset())
self.name = self.ObjectField(Script.NAME_OFFSET) self.name = self.ObjectField(self.NameOffset())
class Code(HeapObject): class Code(HeapObject):
INSTRUCTION_SIZE_OFFSET = 4 CODE_ALIGNMENT_MASK = (1 << 5) - 1
ENTRY_OFFSET = 32
def InstructionSizeOffset(self):
return self.heap.PointerSize()
@staticmethod
def HeaderSize(heap):
return (heap.PointerSize() + heap.IntSize() + \
4 * heap.PointerSize() + 3 * heap.IntSize() + \
CODE_ALIGNMENT_MASK) & ~CODE_ALIGNMENT_MASK
def __init__(self, heap, map, address): def __init__(self, heap, map, address):
HeapObject.__init__(self, heap, map, address) HeapObject.__init__(self, heap, map, address)
self.entry = self.address + Code.ENTRY_OFFSET self.entry = self.address + Code.HeaderSize(heap)
self.instruction_size = \ self.instruction_size = \
heap.reader.ReadU32(self.address + Code.INSTRUCTION_SIZE_OFFSET) heap.reader.ReadU32(self.address + self.InstructionSizeOffset())
def Print(self, p): def Print(self, p):
lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size) lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size)
p.Print("Code(%08x) {" % self.address) p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address))
p.Indent() p.Indent()
p.Print("instruction_size: %d" % self.instruction_size) p.Print("instruction_size: %d" % self.instruction_size)
p.PrintLines(self._FormatLine(line) for line in lines) p.PrintLines(self._FormatLine(line) for line in lines)
@ -767,7 +948,7 @@ class V8Heap(object):
if (tagged_address & 1) != 1: return None if (tagged_address & 1) != 1: 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.ReadU32(address) map_tagged_address = self.reader.ReadUIntPtr(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)
@ -785,9 +966,19 @@ class V8Heap(object):
self.objects[tagged_address] = object self.objects[tagged_address] = object
return object return object
def PointerSize(self):
return self.reader.PointerSize()
EIP_PROXIMITY = 64 EIP_PROXIMITY = 64
CONTEXT_FOR_ARCH = {
MD_CPU_ARCHITECTURE_AMD64:
['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'],
MD_CPU_ARCHITECTURE_X86:
['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
}
def AnalyzeMinidump(options, minidump_name): def AnalyzeMinidump(options, minidump_name):
reader = MinidumpReader(options, minidump_name) reader = MinidumpReader(options, minidump_name)
@ -800,40 +991,35 @@ def AnalyzeMinidump(options, minidump_name):
print " thread id: %d" % exception_thread.id print " thread id: %d" % exception_thread.id
print " code: %08X" % reader.exception.exception.code print " code: %08X" % reader.exception.exception.code
print " context:" print " context:"
print " eax: %08x" % reader.exception_context.eax for r in CONTEXT_FOR_ARCH[reader.arch]:
print " ebx: %08x" % reader.exception_context.ebx print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
print " ecx: %08x" % reader.exception_context.ecx
print " edx: %08x" % reader.exception_context.edx
print " edi: %08x" % reader.exception_context.edi
print " esi: %08x" % reader.exception_context.esi
print " ebp: %08x" % reader.exception_context.ebp
print " esp: %08x" % reader.exception_context.esp
print " eip: %08x" % reader.exception_context.eip
# TODO(vitalyr): decode eflags. # TODO(vitalyr): decode eflags.
print " eflags: %s" % bin(reader.exception_context.eflags)[2:] print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
print print
stack_top = reader.ExceptionSP()
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 = {reader.exception_context.eip: -1} stack_map = {reader.ExceptionIP(): -1}
for slot in xrange(reader.exception_context.esp, stack_bottom, 4): for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
maybe_address = reader.ReadU32(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
heap = V8Heap(reader, stack_map) heap = V8Heap(reader, stack_map)
print "Disassembly around exception.eip:" print "Disassembly around exception.eip:"
start = reader.exception_context.eip - EIP_PROXIMITY start = reader.ExceptionIP() - EIP_PROXIMITY
lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY) lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY)
for line in lines: for line in lines:
print FormatDisasmLine(start, heap, line) print FormatDisasmLine(start, heap, line)
print print
print "Annotated stack (from exception.esp to bottom):" print "Annotated stack (from exception.esp to bottom):"
for slot in xrange(reader.exception_context.esp, stack_bottom, 4): for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
maybe_address = reader.ReadU32(slot) maybe_address = reader.ReadUIntPtr(slot)
heap_object = heap.FindObject(maybe_address) heap_object = heap.FindObject(maybe_address)
print "%08x: %08x" % (slot, maybe_address) print "%s: %s" % (reader.FormatIntPtr(slot),
reader.FormatIntPtr(maybe_address))
if heap_object: if heap_object:
heap_object.Print(Printer()) heap_object.Print(Printer())
print print