Grokdump -f: Automatically detect memory that is x86/x64 instructions or text and dump appropriately.

Review URL: https://chromiumcodereview.appspot.com/10356150

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11621 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
erik.corry@gmail.com 2012-05-22 11:08:05 +00:00
parent 367757b794
commit 5cd40f740d

View File

@ -111,18 +111,56 @@ class Descriptor(object):
def do_dump(reader, heap):
"""Dump all available memory regions."""
def dump_region(reader, start, size, location):
print "%s - %s" % (reader.FormatIntPtr(start),
reader.FormatIntPtr(start + size))
for slot in xrange(start,
start + size,
reader.PointerSize()):
maybe_address = reader.ReadUIntPtr(slot)
heap_object = heap.FindObject(maybe_address)
print "%s: %s" % (reader.FormatIntPtr(slot),
reader.FormatIntPtr(maybe_address))
if heap_object:
heap_object.Print(Printer())
print
print
while start & 3 != 0:
start += 1
size -= 1
location += 1
is_executable = reader.IsProbableExecutableRegion(location, size)
is_ascii = reader.IsProbableASCIIRegion(location, size)
if is_executable is not False:
lines = reader.GetDisasmLines(start, size)
for line in lines:
print FormatDisasmLine(start, heap, line)
print
if is_ascii is not False:
# Output in the same format as the Unix hd command
addr = start
for slot in xrange(location, location + size, 16):
hex_line = ""
asc_line = ""
for i in xrange(0, 16):
if slot + i < location + size:
byte = ctypes.c_uint8.from_buffer(reader.minidump, slot + i).value
if byte >= 0x20 and byte < 0x7f:
asc_line += chr(byte)
else:
asc_line += "."
hex_line += " %02x" % (byte)
else:
hex_line += " "
if i == 7:
hex_line += " "
print "%s %s |%s|" % (reader.FormatIntPtr(addr),
hex_line,
asc_line)
addr += 16
if is_executable is not True and is_ascii is not True:
print "%s - %s" % (reader.FormatIntPtr(start),
reader.FormatIntPtr(start + size))
for slot in xrange(start,
start + size,
reader.PointerSize()):
maybe_address = reader.ReadUIntPtr(slot)
heap_object = heap.FindObject(maybe_address)
print "%s: %s" % (reader.FormatIntPtr(slot),
reader.FormatIntPtr(maybe_address))
if heap_object:
heap_object.Print(Printer())
print
reader.ForEachMemoryRegion(dump_region)
@ -470,6 +508,64 @@ class MinidumpReader(object):
elif self.arch == MD_CPU_ARCHITECTURE_X86:
return ctypes.c_uint32.from_buffer(self.minidump, location).value
def IsProbableASCIIRegion(self, location, length):
ascii_bytes = 0
non_ascii_bytes = 0
for loc in xrange(location, location + length):
byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
if byte >= 0x7f:
non_ascii_bytes += 1
if byte < 0x20 and byte != 0:
non_ascii_bytes += 1
if byte < 0x7f and byte >= 0x20:
ascii_bytes += 1
if byte == 0xa: # newline
ascii_bytes += 1
if ascii_bytes * 10 <= length:
return False
if length > 0 and ascii_bytes > non_ascii_bytes * 7:
return True
if ascii_bytes > non_ascii_bytes * 3:
return None # Maybe
return False
def IsProbableExecutableRegion(self, location, length):
opcode_bytes = 0
sixty_four = self.arch == MD_CPU_ARCHITECTURE_AMD64
for loc in xrange(location, location + length):
byte = ctypes.c_uint8.from_buffer(self.minidump, loc).value
if (byte == 0x8b or # mov
byte == 0x89 or # mov reg-reg
(byte & 0xf0) == 0x50 or # push/pop
(sixty_four and (byte & 0xf0) == 0x40) or # rex prefix
byte == 0xc3 or # return
byte == 0x74 or # jeq
byte == 0x84 or # jeq far
byte == 0x75 or # jne
byte == 0x85 or # jne far
byte == 0xe8 or # call
byte == 0xe9 or # jmp far
byte == 0xeb): # jmp near
opcode_bytes += 1
opcode_percent = (opcode_bytes * 100) / length
threshold = 20
if opcode_percent > threshold + 2:
return True
if opcode_percent > threshold - 2:
return None # Maybe
return False
def FindRegion(self, addr):
answer = [-1, -1]
def is_in(reader, start, size, location):
if addr >= start and addr < start + size:
answer[0] = start
answer[1] = size
self.ForEachMemoryRegion(is_in)
if answer[0] == -1:
return None
return answer
def ForEachMemoryRegion(self, cb):
if self.memory_list64 is not None:
for r in self.memory_list64.ranges:
@ -1099,37 +1195,49 @@ class InspectionShell(cmd.Cmd):
def AnalyzeMinidump(options, minidump_name):
reader = MinidumpReader(options, minidump_name)
heap = None
DebugPrint("========================================")
if reader.exception is None:
print "Minidump has no exception info"
return
print "Exception info:"
exception_thread = reader.thread_map[reader.exception.thread_id]
print " thread id: %d" % exception_thread.id
print " code: %08X" % reader.exception.exception.code
print " context:"
for r in CONTEXT_FOR_ARCH[reader.arch]:
print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
# TODO(vitalyr): decode eflags.
print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
print
else:
print "Exception info:"
exception_thread = reader.thread_map[reader.exception.thread_id]
print " thread id: %d" % exception_thread.id
print " code: %08X" % reader.exception.exception.code
print " context:"
for r in CONTEXT_FOR_ARCH[reader.arch]:
print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
# TODO(vitalyr): decode eflags.
print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
print
stack_top = reader.ExceptionSP()
stack_bottom = exception_thread.stack.start + \
exception_thread.stack.memory.data_size
stack_map = {reader.ExceptionIP(): -1}
for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
maybe_address = reader.ReadUIntPtr(slot)
if not maybe_address in stack_map:
stack_map[maybe_address] = slot
heap = V8Heap(reader, stack_map)
stack_top = reader.ExceptionSP()
stack_bottom = exception_thread.stack.start + \
exception_thread.stack.memory.data_size
stack_map = {reader.ExceptionIP(): -1}
for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
maybe_address = reader.ReadUIntPtr(slot)
if not maybe_address in stack_map:
stack_map[maybe_address] = slot
heap = V8Heap(reader, stack_map)
print "Disassembly around exception.eip:"
start = reader.ExceptionIP() - EIP_PROXIMITY
lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY)
for line in lines:
print FormatDisasmLine(start, heap, line)
print
print "Disassembly around exception.eip:"
disasm_start = reader.ExceptionIP() - EIP_PROXIMITY
disasm_bytes = 2 * EIP_PROXIMITY
if (options.full):
full_range = reader.FindRegion(reader.ExceptionIP())
if full_range is not None:
disasm_start = full_range[0]
disasm_bytes = full_range[1]
lines = reader.GetDisasmLines(disasm_start, disasm_bytes)
for line in lines:
print FormatDisasmLine(disasm_start, heap, line)
print
if heap is None:
heap = V8Heap(reader, None)
if options.full:
do_dump(reader, heap)
@ -1137,15 +1245,16 @@ def AnalyzeMinidump(options, minidump_name):
if options.shell:
InspectionShell(reader, heap).cmdloop("type help to get help")
else:
print "Annotated stack (from exception.esp to bottom):"
for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
maybe_address = reader.ReadUIntPtr(slot)
heap_object = heap.FindObject(maybe_address)
print "%s: %s" % (reader.FormatIntPtr(slot),
reader.FormatIntPtr(maybe_address))
if heap_object:
heap_object.Print(Printer())
print
if reader.exception is not None:
print "Annotated stack (from exception.esp to bottom):"
for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
maybe_address = reader.ReadUIntPtr(slot)
heap_object = heap.FindObject(maybe_address)
print "%s: %s" % (reader.FormatIntPtr(slot),
reader.FormatIntPtr(maybe_address))
if heap_object:
heap_object.Print(Printer())
print
reader.Dispose()