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:
parent
626b61f967
commit
7a93464ca0
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user