Chromium Code Reviews| Index: tools/grokdump.py |
| =================================================================== |
| --- tools/grokdump.py (revision 11561) |
| +++ tools/grokdump.py (working copy) |
| @@ -111,19 +111,57 @@ |
| 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()) |
| + while start & 3 != 0: |
| + start += 1 |
| + size -= 1 |
| + location += 1 |
| + is_executable = reader.IsExecutableRegion(location, size) |
| + is_ascii = reader.IsASCIIRegion(location, size) |
| + if is_executable is not False: |
| + lines = reader.GetDisasmLines(start, size) |
| + for line in lines: |
| + print FormatDisasmLine(start, heap, line) |
| + |
| + 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()) |
| + |
| reader.ForEachMemoryRegion(dump_region) |
| # Set of structures and constants that describe the layout of minidump |
| @@ -470,6 +508,64 @@ |
| elif self.arch == MD_CPU_ARCHITECTURE_X86: |
| return ctypes.c_uint32.from_buffer(self.minidump, location).value |
| + def IsASCIIRegion(self, location, length): |
|
Michael Starzinger
2012/05/21 12:03:13
Maybe we should rename this to IsProbableASCIIRegi
|
| + 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 IsExecutableRegion(self, location, length): |
|
Michael Starzinger
2012/05/21 12:03:13
Likewise.
|
| + 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,53 +1195,66 @@ |
| 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:] |
| + 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:] |
| - 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 "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) |
| + |
| + if heap is None: |
| + heap = V8Heap(reader, None) |
| + |
| if options.full: |
| do_dump(reader, heap) |
| 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()) |
| + 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()) |
| reader.Dispose() |