Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(245)

Side by Side Diff: tools/grokdump.py

Issue 18310003: Grokdump: new shell command, "lm" (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fixed nits and enabled code behind a TODO Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2012 the V8 project authors. All rights reserved. 3 # Copyright 2012 the V8 project authors. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without 4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are 5 # modification, are permitted provided that the following conditions are
6 # met: 6 # met:
7 # 7 #
8 # * Redistributions of source code must retain the above copyright 8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer. 9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above 10 # * Redistributions in binary form must reproduce the above
(...skipping 13 matching lines...) Expand all
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 import bisect 30 import bisect
31 import cmd 31 import cmd
32 import codecs 32 import codecs
33 import ctypes 33 import ctypes
34 import datetime
34 import disasm 35 import disasm
35 import mmap 36 import mmap
36 import optparse 37 import optparse
37 import os 38 import os
38 import re 39 import re
39 import struct 40 import struct
40 import sys 41 import sys
41 import types 42 import types
42 43
43
44 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE] 44 USAGE="""usage: %prog [OPTIONS] [DUMP-FILE]
45 45
46 Minidump analyzer. 46 Minidump analyzer.
47 47
48 Shows the processor state at the point of exception including the 48 Shows the processor state at the point of exception including the
49 stack of the active thread and the referenced objects in the V8 49 stack of the active thread and the referenced objects in the V8
50 heap. Code objects are disassembled and the addresses linked from the 50 heap. Code objects are disassembled and the addresses linked from the
51 stack (e.g. pushed return addresses) are marked with "=>". 51 stack (e.g. pushed return addresses) are marked with "=>".
52 52
53 Examples: 53 Examples:
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 ("ted", ctypes.c_uint64), 435 ("ted", ctypes.c_uint64),
436 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), 436 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype),
437 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) 437 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype)
438 ]) 438 ])
439 439
440 MINIDUMP_THREAD_LIST = Descriptor([ 440 MINIDUMP_THREAD_LIST = Descriptor([
441 ("thread_count", ctypes.c_uint32), 441 ("thread_count", ctypes.c_uint32),
442 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) 442 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count)
443 ]) 443 ])
444 444
445 MINIDUMP_VS_FIXEDFILEINFO = Descriptor([
446 ("dwSignature", ctypes.c_uint32),
447 ("dwStrucVersion", ctypes.c_uint32),
448 ("dwFileVersionMS", ctypes.c_uint32),
449 ("dwFileVersionLS", ctypes.c_uint32),
450 ("dwProductVersionMS", ctypes.c_uint32),
451 ("dwProductVersionLS", ctypes.c_uint32),
452 ("dwFileFlagsMask", ctypes.c_uint32),
453 ("dwFileFlags", ctypes.c_uint32),
454 ("dwFileOS", ctypes.c_uint32),
455 ("dwFileType", ctypes.c_uint32),
456 ("dwFileSubtype", ctypes.c_uint32),
457 ("dwFileDateMS", ctypes.c_uint32),
458 ("dwFileDateLS", ctypes.c_uint32)
459 ])
460
445 MINIDUMP_RAW_MODULE = Descriptor([ 461 MINIDUMP_RAW_MODULE = Descriptor([
446 ("base_of_image", ctypes.c_uint64), 462 ("base_of_image", ctypes.c_uint64),
447 ("size_of_image", ctypes.c_uint32), 463 ("size_of_image", ctypes.c_uint32),
448 ("checksum", ctypes.c_uint32), 464 ("checksum", ctypes.c_uint32),
449 ("time_date_stamp", ctypes.c_uint32), 465 ("time_date_stamp", ctypes.c_uint32),
450 ("module_name_rva", ctypes.c_uint32), 466 ("module_name_rva", ctypes.c_uint32),
451 ("version_info", ctypes.c_uint32 * 13), 467 ("version_info", MINIDUMP_VS_FIXEDFILEINFO.ctype),
452 ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype), 468 ("cv_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
453 ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype), 469 ("misc_record", MINIDUMP_LOCATION_DESCRIPTOR.ctype),
454 ("reserved0", ctypes.c_uint32 * 2), 470 ("reserved0", ctypes.c_uint32 * 2),
455 ("reserved1", ctypes.c_uint32 * 2) 471 ("reserved1", ctypes.c_uint32 * 2)
456 ]) 472 ])
457 473
458 MINIDUMP_MODULE_LIST = Descriptor([ 474 MINIDUMP_MODULE_LIST = Descriptor([
459 ("number_of_modules", ctypes.c_uint32), 475 ("number_of_modules", ctypes.c_uint32),
460 ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules) 476 ("modules", lambda t: MINIDUMP_RAW_MODULE.ctype * t.number_of_modules)
461 ]) 477 ])
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 size = int(result.group(2), 16) 794 size = int(result.group(2), 16)
779 name = result.group(4).rstrip() 795 name = result.group(4).rstrip()
780 bisect.insort_left(self.symbols, 796 bisect.insort_left(self.symbols,
781 FuncSymbol(baseaddr + start, size, name)) 797 FuncSymbol(baseaddr + start, size, name))
782 print " ... done" 798 print " ... done"
783 799
784 def TryLoadSymbolsFor(self, modulename, module): 800 def TryLoadSymbolsFor(self, modulename, module):
785 try: 801 try:
786 symfile = os.path.join(self.symdir, 802 symfile = os.path.join(self.symdir,
787 modulename.replace('.', '_') + ".pdb.sym") 803 modulename.replace('.', '_') + ".pdb.sym")
788 self._LoadSymbolsFrom(symfile, module.base_of_image) 804 if os.path.isfile(symfile):
789 self.modules_with_symbols.append(module) 805 self._LoadSymbolsFrom(symfile, module.base_of_image)
806 self.modules_with_symbols.append(module)
790 except Exception as e: 807 except Exception as e:
791 print " ... failure (%s)" % (e) 808 print " ... failure (%s)" % (e)
792 809
793 # Returns true if address is covered by some module that has loaded symbols. 810 # Returns true if address is covered by some module that has loaded symbols.
794 def _IsInModuleWithSymbols(self, addr): 811 def _IsInModuleWithSymbols(self, addr):
795 for module in self.modules_with_symbols: 812 for module in self.modules_with_symbols:
796 start = module.base_of_image 813 start = module.base_of_image
797 end = start + module.size_of_image 814 end = start + module.size_of_image
798 if (start <= addr) and (addr < end): 815 if (start <= addr) and (addr < end):
799 return True 816 return True
(...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after
2004 """ 2021 """
2005 List all available memory regions. 2022 List all available memory regions.
2006 """ 2023 """
2007 def print_region(reader, start, size, location): 2024 def print_region(reader, start, size, location):
2008 print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start), 2025 print " %s - %s (%d bytes)" % (reader.FormatIntPtr(start),
2009 reader.FormatIntPtr(start + size), 2026 reader.FormatIntPtr(start + size),
2010 size) 2027 size)
2011 print "Available memory regions:" 2028 print "Available memory regions:"
2012 self.reader.ForEachMemoryRegion(print_region) 2029 self.reader.ForEachMemoryRegion(print_region)
2013 2030
2031 def do_lm(self, arg):
2032 """
2033 List details for all loaded modules in the minidump. An argument can
2034 be passed to limit the output to only those modules that contain the
2035 argument as a substring (case insensitive match).
2036 """
2037 for module in self.reader.module_list.modules:
2038 if arg:
2039 name = GetModuleName(self.reader, module).lower()
2040 if name.find(arg.lower()) >= 0:
2041 PrintModuleDetails(self.reader, module)
2042 else:
2043 PrintModuleDetails(self.reader, module)
2044 print
2045
2014 def do_s(self, word): 2046 def do_s(self, word):
2015 """ 2047 """
2016 Search for a given word in available memory regions. The given word 2048 Search for a given word in available memory regions. The given word
2017 is expanded to full pointer size and searched at aligned as well as 2049 is expanded to full pointer size and searched at aligned as well as
2018 un-aligned memory locations. Use 'sa' to search aligned locations 2050 un-aligned memory locations. Use 'sa' to search aligned locations
2019 only. 2051 only.
2020 """ 2052 """
2021 try: 2053 try:
2022 word = int(word, 0) 2054 word = int(word, 0)
2023 except ValueError: 2055 except ValueError:
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
2062 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'], 2094 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15'],
2063 MD_CPU_ARCHITECTURE_ARM: 2095 MD_CPU_ARCHITECTURE_ARM:
2064 ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 2096 ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9',
2065 'r10', 'r11', 'r12', 'sp', 'lr', 'pc'], 2097 'r10', 'r11', 'r12', 'sp', 'lr', 'pc'],
2066 MD_CPU_ARCHITECTURE_X86: 2098 MD_CPU_ARCHITECTURE_X86:
2067 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] 2099 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip']
2068 } 2100 }
2069 2101
2070 KNOWN_MODULES = {'chrome.exe', 'chrome.dll'} 2102 KNOWN_MODULES = {'chrome.exe', 'chrome.dll'}
2071 2103
2104 def GetVersionString(ms, ls):
2105 return "%d.%d.%d.%d" % (ms >> 16, ms & 0xffff, ls >> 16, ls & 0xffff)
2106
2107
2072 def GetModuleName(reader, module): 2108 def GetModuleName(reader, module):
2073 name = reader.ReadMinidumpString(module.module_name_rva) 2109 name = reader.ReadMinidumpString(module.module_name_rva)
2110 # simplify for path manipulation
2111 name = name.encode('utf-8')
2074 return str(os.path.basename(str(name).replace("\\", "/"))) 2112 return str(os.path.basename(str(name).replace("\\", "/")))
2075 2113
2114
2115 def PrintModuleDetails(reader, module):
2116 print "%s" % GetModuleName(reader, module)
2117 file_version = GetVersionString(module.version_info.dwFileVersionMS,
2118 module.version_info.dwFileVersionLS)
2119 product_version = GetVersionString(module.version_info.dwProductVersionMS,
2120 module.version_info.dwProductVersionLS)
2121 print " base: %s" % reader.FormatIntPtr(module.base_of_image)
2122 print " end: %s" % reader.FormatIntPtr(module.base_of_image +
2123 module.size_of_image)
2124 print " file version: %s" % file_version
2125 print " product version: %s" % product_version
2126 time_date_stamp = datetime.datetime.fromtimestamp(module.time_date_stamp)
2127 print " timestamp: %s" % time_date_stamp
2128
2129
2076 def AnalyzeMinidump(options, minidump_name): 2130 def AnalyzeMinidump(options, minidump_name):
2077 reader = MinidumpReader(options, minidump_name) 2131 reader = MinidumpReader(options, minidump_name)
2078 heap = None 2132 heap = None
2079 DebugPrint("========================================") 2133 DebugPrint("========================================")
2080 if reader.exception is None: 2134 if reader.exception is None:
2081 print "Minidump has no exception info" 2135 print "Minidump has no exception info"
2082 else: 2136 else:
2083 print "Exception info:" 2137 print "Exception info:"
2084 exception_thread = reader.thread_map[reader.exception.thread_id] 2138 exception_thread = reader.thread_map[reader.exception.thread_id]
2085 print " thread id: %d" % exception_thread.id 2139 print " thread id: %d" % exception_thread.id
2086 print " code: %08X" % reader.exception.exception.code 2140 print " code: %08X" % reader.exception.exception.code
2087 print " context:" 2141 print " context:"
2088 for r in CONTEXT_FOR_ARCH[reader.arch]: 2142 for r in CONTEXT_FOR_ARCH[reader.arch]:
2089 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) 2143 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r)))
2090 # TODO(vitalyr): decode eflags. 2144 # TODO(vitalyr): decode eflags.
2091 if reader.arch == MD_CPU_ARCHITECTURE_ARM: 2145 if reader.arch == MD_CPU_ARCHITECTURE_ARM:
2092 print " cpsr: %s" % bin(reader.exception_context.cpsr)[2:] 2146 print " cpsr: %s" % bin(reader.exception_context.cpsr)[2:]
2093 else: 2147 else:
2094 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] 2148 print " eflags: %s" % bin(reader.exception_context.eflags)[2:]
2095 2149
2096 # TODO(mstarzinger): Disabled because broken, needs investigation. 2150 print
2097 #print 2151 print " modules:"
2098 #print " modules:" 2152 for module in reader.module_list.modules:
2099 #for module in reader.module_list.modules: 2153 name = GetModuleName(reader, module)
2100 # name = GetModuleName(reader, module) 2154 if name in KNOWN_MODULES:
2101 # if name in KNOWN_MODULES: 2155 print " %s at %08X" % (name, module.base_of_image)
2102 # print " %s at %08X" % (name, module.base_of_image) 2156 reader.TryLoadSymbolsFor(name, module)
2103 # reader.TryLoadSymbolsFor(name, module)
2104 print 2157 print
2105 2158
2106 stack_top = reader.ExceptionSP() 2159 stack_top = reader.ExceptionSP()
2107 stack_bottom = exception_thread.stack.start + \ 2160 stack_bottom = exception_thread.stack.start + \
2108 exception_thread.stack.memory.data_size 2161 exception_thread.stack.memory.data_size
2109 stack_map = {reader.ExceptionIP(): -1} 2162 stack_map = {reader.ExceptionIP(): -1}
2110 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): 2163 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
2111 maybe_address = reader.ReadUIntPtr(slot) 2164 maybe_address = reader.ReadUIntPtr(slot)
2112 if not maybe_address in stack_map: 2165 if not maybe_address in stack_map:
2113 stack_map[maybe_address] = slot 2166 stack_map[maybe_address] = slot
(...skipping 16 matching lines...) Expand all
2130 for line in lines: 2183 for line in lines:
2131 print FormatDisasmLine(disasm_start, heap, line) 2184 print FormatDisasmLine(disasm_start, heap, line)
2132 print 2185 print
2133 2186
2134 if heap is None: 2187 if heap is None:
2135 heap = V8Heap(reader, None) 2188 heap = V8Heap(reader, None)
2136 2189
2137 if options.full: 2190 if options.full:
2138 FullDump(reader, heap) 2191 FullDump(reader, heap)
2139 2192
2193 if options.command:
2194 InspectionShell(reader, heap).onecmd(options.command)
2195
2140 if options.shell: 2196 if options.shell:
2141 try: 2197 try:
2142 InspectionShell(reader, heap).cmdloop("type help to get help") 2198 InspectionShell(reader, heap).cmdloop("type help to get help")
2143 except KeyboardInterrupt: 2199 except KeyboardInterrupt:
2144 print "Kthxbye." 2200 print "Kthxbye."
2145 else: 2201 elif not options.command:
2146 if reader.exception is not None: 2202 if reader.exception is not None:
2147 print "Annotated stack (from exception.esp to bottom):" 2203 print "Annotated stack (from exception.esp to bottom):"
2148 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): 2204 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()):
2149 maybe_address = reader.ReadUIntPtr(slot) 2205 maybe_address = reader.ReadUIntPtr(slot)
2150 heap_object = heap.FindObject(maybe_address) 2206 heap_object = heap.FindObject(maybe_address)
2151 maybe_symbol = reader.FindSymbol(maybe_address) 2207 maybe_symbol = reader.FindSymbol(maybe_address)
2152 print "%s: %s %s" % (reader.FormatIntPtr(slot), 2208 print "%s: %s %s" % (reader.FormatIntPtr(slot),
2153 reader.FormatIntPtr(maybe_address), 2209 reader.FormatIntPtr(maybe_address),
2154 maybe_symbol or "") 2210 maybe_symbol or "")
2155 if heap_object: 2211 if heap_object:
2156 heap_object.Print(Printer()) 2212 heap_object.Print(Printer())
2157 print 2213 print
2158 2214
2159 reader.Dispose() 2215 reader.Dispose()
2160 2216
2161 2217
2162 if __name__ == "__main__": 2218 if __name__ == "__main__":
2163 parser = optparse.OptionParser(USAGE) 2219 parser = optparse.OptionParser(USAGE)
2164 parser.add_option("-s", "--shell", dest="shell", action="store_true", 2220 parser.add_option("-s", "--shell", dest="shell", action="store_true",
2165 help="start an interactive inspector shell") 2221 help="start an interactive inspector shell")
2222 parser.add_option("-c", "--command", dest="command", default="",
2223 help="run an interactive inspector shell command and exit")
2166 parser.add_option("-f", "--full", dest="full", action="store_true", 2224 parser.add_option("-f", "--full", dest="full", action="store_true",
2167 help="dump all information contained in the minidump") 2225 help="dump all information contained in the minidump")
2168 parser.add_option("--symdir", dest="symdir", default=".", 2226 parser.add_option("--symdir", dest="symdir", default=".",
2169 help="directory containing *.pdb.sym file with symbols") 2227 help="directory containing *.pdb.sym file with symbols")
2170 parser.add_option("--objdump", 2228 parser.add_option("--objdump",
2171 default="/usr/bin/objdump", 2229 default="/usr/bin/objdump",
2172 help="objdump tool to use [default: %default]") 2230 help="objdump tool to use [default: %default]")
2173 options, args = parser.parse_args() 2231 options, args = parser.parse_args()
2174 if os.path.exists(options.objdump): 2232 if os.path.exists(options.objdump):
2175 disasm.OBJDUMP_BIN = options.objdump 2233 disasm.OBJDUMP_BIN = options.objdump
2176 OBJDUMP_BIN = options.objdump 2234 OBJDUMP_BIN = options.objdump
2177 else: 2235 else:
2178 print "Cannot find %s, falling back to default objdump" % options.objdump 2236 print "Cannot find %s, falling back to default objdump" % options.objdump
2179 if len(args) != 1: 2237 if len(args) != 1:
2180 parser.print_help() 2238 parser.print_help()
2181 sys.exit(1) 2239 sys.exit(1)
2182 AnalyzeMinidump(options, args[0]) 2240 AnalyzeMinidump(options, args[0])
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698