Grokdump: new shell command, "lm"
lm - list matching modules and details such as product version number found in the minidump. Also, enabled a mode to execute one command and exit. BUG= R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/18310003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15410 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6a19aca501
commit
d594fd5de3
@ -31,6 +31,7 @@ import bisect
|
|||||||
import cmd
|
import cmd
|
||||||
import codecs
|
import codecs
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import datetime
|
||||||
import disasm
|
import disasm
|
||||||
import mmap
|
import mmap
|
||||||
import optparse
|
import optparse
|
||||||
@ -40,7 +41,6 @@ import struct
|
|||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
|
||||||
USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
|
USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
|
||||||
|
|
||||||
Minidump analyzer.
|
Minidump analyzer.
|
||||||
@ -442,13 +442,29 @@ MINIDUMP_THREAD_LIST = Descriptor([
|
|||||||
("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
|
("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
MINIDUMP_VS_FIXEDFILEINFO = Descriptor([
|
||||||
|
("dwSignature", ctypes.c_uint32),
|
||||||
|
("dwStrucVersion", ctypes.c_uint32),
|
||||||
|
("dwFileVersionMS", ctypes.c_uint32),
|
||||||
|
("dwFileVersionLS", ctypes.c_uint32),
|
||||||
|
("dwProductVersionMS", ctypes.c_uint32),
|
||||||
|
("dwProductVersionLS", ctypes.c_uint32),
|
||||||
|
("dwFileFlagsMask", ctypes.c_uint32),
|
||||||
|
("dwFileFlags", ctypes.c_uint32),
|
||||||
|
("dwFileOS", ctypes.c_uint32),
|
||||||
|
("dwFileType", ctypes.c_uint32),
|
||||||
|
("dwFileSubtype", ctypes.c_uint32),
|
||||||
|
("dwFileDateMS", ctypes.c_uint32),
|
||||||
|
("dwFileDateLS", ctypes.c_uint32)
|
||||||
|
])
|
||||||
|
|
||||||
MINIDUMP_RAW_MODULE = Descriptor([
|
MINIDUMP_RAW_MODULE = Descriptor([
|
||||||
("base_of_image", ctypes.c_uint64),
|
("base_of_image", ctypes.c_uint64),
|
||||||
("size_of_image", ctypes.c_uint32),
|
("size_of_image", ctypes.c_uint32),
|
||||||
("checksum", ctypes.c_uint32),
|
("checksum", ctypes.c_uint32),
|
||||||
("time_date_stamp", ctypes.c_uint32),
|
("time_date_stamp", ctypes.c_uint32),
|
||||||
("module_name_rva", ctypes.c_uint32),
|
("module_name_rva", ctypes.c_uint32),
|
||||||
("version_info", ctypes.c_uint32 * 13),
|
("version_info", MINIDUMP_VS_FIXEDFILEINFO.ctype),
|
||||||
("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
|
("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
|
||||||
("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
|
("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
|
||||||
("reserved0", ctypes.c_uint32 * 2),
|
("reserved0", ctypes.c_uint32 * 2),
|
||||||
@ -785,6 +801,7 @@ class MinidumpReader(object):
|
|||||||
try:
|
try:
|
||||||
symfile = os.path.join(self.symdir,
|
symfile = os.path.join(self.symdir,
|
||||||
modulename.replace('.', '_') + ".pdb.sym")
|
modulename.replace('.', '_') + ".pdb.sym")
|
||||||
|
if os.path.isfile(symfile):
|
||||||
self._LoadSymbolsFrom(symfile, module.base_of_image)
|
self._LoadSymbolsFrom(symfile, module.base_of_image)
|
||||||
self.modules_with_symbols.append(module)
|
self.modules_with_symbols.append(module)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -2011,6 +2028,21 @@ class InspectionShell(cmd.Cmd):
|
|||||||
print "Available memory regions:"
|
print "Available memory regions:"
|
||||||
self.reader.ForEachMemoryRegion(print_region)
|
self.reader.ForEachMemoryRegion(print_region)
|
||||||
|
|
||||||
|
def do_lm(self, arg):
|
||||||
|
"""
|
||||||
|
List details for all loaded modules in the minidump. An argument can
|
||||||
|
be passed to limit the output to only those modules that contain the
|
||||||
|
argument as a substring (case insensitive match).
|
||||||
|
"""
|
||||||
|
for module in self.reader.module_list.modules:
|
||||||
|
if arg:
|
||||||
|
name = GetModuleName(self.reader, module).lower()
|
||||||
|
if name.find(arg.lower()) >= 0:
|
||||||
|
PrintModuleDetails(self.reader, module)
|
||||||
|
else:
|
||||||
|
PrintModuleDetails(self.reader, module)
|
||||||
|
print
|
||||||
|
|
||||||
def do_s(self, word):
|
def do_s(self, word):
|
||||||
"""
|
"""
|
||||||
Search for a given word in available memory regions. The given word
|
Search for a given word in available memory regions. The given word
|
||||||
@ -2069,10 +2101,32 @@ CONTEXT_FOR_ARCH = {
|
|||||||
|
|
||||||
KNOWN_MODULES = {'chrome.exe', 'chrome.dll'}
|
KNOWN_MODULES = {'chrome.exe', 'chrome.dll'}
|
||||||
|
|
||||||
|
def GetVersionString(ms, ls):
|
||||||
|
return "%d.%d.%d.%d" % (ms >> 16, ms & 0xffff, ls >> 16, ls & 0xffff)
|
||||||
|
|
||||||
|
|
||||||
def GetModuleName(reader, module):
|
def GetModuleName(reader, module):
|
||||||
name = reader.ReadMinidumpString(module.module_name_rva)
|
name = reader.ReadMinidumpString(module.module_name_rva)
|
||||||
|
# simplify for path manipulation
|
||||||
|
name = name.encode('utf-8')
|
||||||
return str(os.path.basename(str(name).replace("\\", "/")))
|
return str(os.path.basename(str(name).replace("\\", "/")))
|
||||||
|
|
||||||
|
|
||||||
|
def PrintModuleDetails(reader, module):
|
||||||
|
print "%s" % GetModuleName(reader, module)
|
||||||
|
file_version = GetVersionString(module.version_info.dwFileVersionMS,
|
||||||
|
module.version_info.dwFileVersionLS)
|
||||||
|
product_version = GetVersionString(module.version_info.dwProductVersionMS,
|
||||||
|
module.version_info.dwProductVersionLS)
|
||||||
|
print " base: %s" % reader.FormatIntPtr(module.base_of_image)
|
||||||
|
print " end: %s" % reader.FormatIntPtr(module.base_of_image +
|
||||||
|
module.size_of_image)
|
||||||
|
print " file version: %s" % file_version
|
||||||
|
print " product version: %s" % product_version
|
||||||
|
time_date_stamp = datetime.datetime.fromtimestamp(module.time_date_stamp)
|
||||||
|
print " timestamp: %s" % time_date_stamp
|
||||||
|
|
||||||
|
|
||||||
def AnalyzeMinidump(options, minidump_name):
|
def AnalyzeMinidump(options, minidump_name):
|
||||||
reader = MinidumpReader(options, minidump_name)
|
reader = MinidumpReader(options, minidump_name)
|
||||||
heap = None
|
heap = None
|
||||||
@ -2093,14 +2147,13 @@ def AnalyzeMinidump(options, minidump_name):
|
|||||||
else:
|
else:
|
||||||
print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
|
print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
|
||||||
|
|
||||||
# TODO(mstarzinger): Disabled because broken, needs investigation.
|
print
|
||||||
#print
|
print " modules:"
|
||||||
#print " modules:"
|
for module in reader.module_list.modules:
|
||||||
#for module in reader.module_list.modules:
|
name = GetModuleName(reader, module)
|
||||||
# name = GetModuleName(reader, module)
|
if name in KNOWN_MODULES:
|
||||||
# if name in KNOWN_MODULES:
|
print " %s at %08X" % (name, module.base_of_image)
|
||||||
# print " %s at %08X" % (name, module.base_of_image)
|
reader.TryLoadSymbolsFor(name, module)
|
||||||
# reader.TryLoadSymbolsFor(name, module)
|
|
||||||
print
|
print
|
||||||
|
|
||||||
stack_top = reader.ExceptionSP()
|
stack_top = reader.ExceptionSP()
|
||||||
@ -2137,12 +2190,15 @@ def AnalyzeMinidump(options, minidump_name):
|
|||||||
if options.full:
|
if options.full:
|
||||||
FullDump(reader, heap)
|
FullDump(reader, heap)
|
||||||
|
|
||||||
|
if options.command:
|
||||||
|
InspectionShell(reader, heap).onecmd(options.command)
|
||||||
|
|
||||||
if options.shell:
|
if options.shell:
|
||||||
try:
|
try:
|
||||||
InspectionShell(reader, heap).cmdloop("type help to get help")
|
InspectionShell(reader, heap).cmdloop("type help to get help")
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print "Kthxbye."
|
print "Kthxbye."
|
||||||
else:
|
elif not options.command:
|
||||||
if reader.exception is not None:
|
if reader.exception is not None:
|
||||||
print "Annotated stack (from exception.esp to bottom):"
|
print "Annotated stack (from exception.esp to bottom):"
|
||||||
for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
|
for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
|
||||||
@ -2163,6 +2219,8 @@ if __name__ == "__main__":
|
|||||||
parser = optparse.OptionParser(USAGE)
|
parser = optparse.OptionParser(USAGE)
|
||||||
parser.add_option("-s", "--shell", dest="shell", action="store_true",
|
parser.add_option("-s", "--shell", dest="shell", action="store_true",
|
||||||
help="start an interactive inspector shell")
|
help="start an interactive inspector shell")
|
||||||
|
parser.add_option("-c", "--command", dest="command", default="",
|
||||||
|
help="run an interactive inspector shell command and exit")
|
||||||
parser.add_option("-f", "--full", dest="full", action="store_true",
|
parser.add_option("-f", "--full", dest="full", action="store_true",
|
||||||
help="dump all information contained in the minidump")
|
help="dump all information contained in the minidump")
|
||||||
parser.add_option("--symdir", dest="symdir", default=".",
|
parser.add_option("--symdir", dest="symdir", default=".",
|
||||||
|
Loading…
Reference in New Issue
Block a user