| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python | 
|  | 2 | # | 
|  | 3 | # Copyright 2011 the V8 project authors. All rights reserved. | 
|  | 4 | # Redistribution and use in source and binary forms, with or without | 
|  | 5 | # modification, are permitted provided that the following conditions are | 
|  | 6 | # met: | 
|  | 7 | # | 
|  | 8 | #     * Redistributions of source code must retain the above copyright | 
|  | 9 | #       notice, this list of conditions and the following disclaimer. | 
|  | 10 | #     * Redistributions in binary form must reproduce the above | 
|  | 11 | #       copyright notice, this list of conditions and the following | 
|  | 12 | #       disclaimer in the documentation and/or other materials provided | 
|  | 13 | #       with the distribution. | 
|  | 14 | #     * Neither the name of Google Inc. nor the names of its | 
|  | 15 | #       contributors may be used to endorse or promote products derived | 
|  | 16 | #       from this software without specific prior written permission. | 
|  | 17 | # | 
|  | 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | 19 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | 20 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | 21 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | 22 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | 23 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | 24 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | 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. | 
|  | 29 |  | 
|  | 30 | import ctypes | 
|  | 31 | import mmap | 
|  | 32 | import optparse | 
|  | 33 | import os | 
|  | 34 | import disasm | 
|  | 35 | import sys | 
|  | 36 | import types | 
|  | 37 | import codecs | 
|  | 38 | import re | 
|  | 39 |  | 
|  | 40 |  | 
|  | 41 | USAGE="""usage: %prog [OPTION]... | 
|  | 42 |  | 
|  | 43 | Minidump analyzer. | 
|  | 44 |  | 
|  | 45 | Shows the processor state at the point of exception including the | 
|  | 46 | stack of the active thread and the referenced objects in the V8 | 
|  | 47 | heap. Code objects are disassembled and the addresses linked from the | 
|  | 48 | stack (pushed return addresses) are marked with "=>". | 
|  | 49 |  | 
|  | 50 |  | 
|  | 51 | Examples: | 
|  | 52 | $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp | 
|  | 53 | """ | 
|  | 54 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 55 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 56 | DEBUG=False | 
|  | 57 |  | 
|  | 58 |  | 
|  | 59 | def DebugPrint(s): | 
|  | 60 | if not DEBUG: return | 
|  | 61 | print s | 
|  | 62 |  | 
|  | 63 |  | 
|  | 64 | class Descriptor(object): | 
|  | 65 | """Descriptor of a structure in a memory.""" | 
|  | 66 |  | 
|  | 67 | def __init__(self, fields): | 
|  | 68 | self.fields = fields | 
|  | 69 | self.is_flexible = False | 
|  | 70 | for _, type_or_func in fields: | 
|  | 71 | if isinstance(type_or_func, types.FunctionType): | 
|  | 72 | self.is_flexible = True | 
|  | 73 | break | 
|  | 74 | if not self.is_flexible: | 
|  | 75 | self.ctype = Descriptor._GetCtype(fields) | 
|  | 76 | self.size = ctypes.sizeof(self.ctype) | 
|  | 77 |  | 
|  | 78 | def Read(self, memory, offset): | 
|  | 79 | if self.is_flexible: | 
|  | 80 | fields_copy = self.fields[:] | 
|  | 81 | last = 0 | 
|  | 82 | for name, type_or_func in fields_copy: | 
|  | 83 | if isinstance(type_or_func, types.FunctionType): | 
|  | 84 | partial_ctype = Descriptor._GetCtype(fields_copy[:last]) | 
|  | 85 | partial_object = partial_ctype.from_buffer(memory, offset) | 
|  | 86 | type = type_or_func(partial_object) | 
|  | 87 | if type is not None: | 
|  | 88 | fields_copy[last] = (name, type) | 
|  | 89 | last += 1 | 
|  | 90 | else: | 
|  | 91 | last += 1 | 
|  | 92 | complete_ctype = Descriptor._GetCtype(fields_copy[:last]) | 
|  | 93 | else: | 
|  | 94 | complete_ctype = self.ctype | 
|  | 95 | return complete_ctype.from_buffer(memory, offset) | 
|  | 96 |  | 
|  | 97 | @staticmethod | 
|  | 98 | def _GetCtype(fields): | 
|  | 99 | class Raw(ctypes.Structure): | 
|  | 100 | _fields_ = fields | 
|  | 101 | _pack_ = 1 | 
|  | 102 |  | 
|  | 103 | def __str__(self): | 
|  | 104 | return "{" + ", ".join("%s: %s" % (field, self.__getattribute__(field)) | 
|  | 105 | for field, _ in Raw._fields_) + "}" | 
|  | 106 | return Raw | 
|  | 107 |  | 
|  | 108 |  | 
|  | 109 | # Set of structures and constants that describe the layout of minidump | 
|  | 110 | # files. Based on MSDN and Google Breakpad. | 
|  | 111 |  | 
|  | 112 | MINIDUMP_HEADER = Descriptor([ | 
|  | 113 | ("signature", ctypes.c_uint32), | 
|  | 114 | ("version", ctypes.c_uint32), | 
|  | 115 | ("stream_count", ctypes.c_uint32), | 
|  | 116 | ("stream_directories_rva", ctypes.c_uint32), | 
|  | 117 | ("checksum", ctypes.c_uint32), | 
|  | 118 | ("time_date_stampt", ctypes.c_uint32), | 
|  | 119 | ("flags", ctypes.c_uint64) | 
|  | 120 | ]) | 
|  | 121 |  | 
|  | 122 | MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([ | 
|  | 123 | ("data_size", ctypes.c_uint32), | 
|  | 124 | ("rva", ctypes.c_uint32) | 
|  | 125 | ]) | 
|  | 126 |  | 
|  | 127 | MINIDUMP_DIRECTORY = Descriptor([ | 
|  | 128 | ("stream_type", ctypes.c_uint32), | 
|  | 129 | ("location", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 
|  | 130 | ]) | 
|  | 131 |  | 
|  | 132 | MD_EXCEPTION_MAXIMUM_PARAMETERS = 15 | 
|  | 133 |  | 
|  | 134 | MINIDUMP_EXCEPTION = Descriptor([ | 
|  | 135 | ("code", ctypes.c_uint32), | 
|  | 136 | ("flags", ctypes.c_uint32), | 
|  | 137 | ("record", ctypes.c_uint64), | 
|  | 138 | ("address", ctypes.c_uint64), | 
|  | 139 | ("parameter_count", ctypes.c_uint32), | 
|  | 140 | ("unused_alignment", ctypes.c_uint32), | 
|  | 141 | ("information", ctypes.c_uint64 * MD_EXCEPTION_MAXIMUM_PARAMETERS) | 
|  | 142 | ]) | 
|  | 143 |  | 
|  | 144 | MINIDUMP_EXCEPTION_STREAM = Descriptor([ | 
|  | 145 | ("thread_id", ctypes.c_uint32), | 
|  | 146 | ("unused_alignment", ctypes.c_uint32), | 
|  | 147 | ("exception", MINIDUMP_EXCEPTION.ctype), | 
|  | 148 | ("thread_context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 
|  | 149 | ]) | 
|  | 150 |  | 
|  | 151 | # Stream types. | 
|  | 152 | MD_UNUSED_STREAM = 0 | 
|  | 153 | MD_RESERVED_STREAM_0 = 1 | 
|  | 154 | MD_RESERVED_STREAM_1 = 2 | 
|  | 155 | MD_THREAD_LIST_STREAM = 3 | 
|  | 156 | MD_MODULE_LIST_STREAM = 4 | 
|  | 157 | MD_MEMORY_LIST_STREAM = 5 | 
|  | 158 | MD_EXCEPTION_STREAM = 6 | 
|  | 159 | MD_SYSTEM_INFO_STREAM = 7 | 
|  | 160 | MD_THREAD_EX_LIST_STREAM = 8 | 
|  | 161 | MD_MEMORY_64_LIST_STREAM = 9 | 
|  | 162 | MD_COMMENT_STREAM_A = 10 | 
|  | 163 | MD_COMMENT_STREAM_W = 11 | 
|  | 164 | MD_HANDLE_DATA_STREAM = 12 | 
|  | 165 | MD_FUNCTION_TABLE_STREAM = 13 | 
|  | 166 | MD_UNLOADED_MODULE_LIST_STREAM = 14 | 
|  | 167 | MD_MISC_INFO_STREAM = 15 | 
|  | 168 | MD_MEMORY_INFO_LIST_STREAM = 16 | 
|  | 169 | MD_THREAD_INFO_LIST_STREAM = 17 | 
|  | 170 | MD_HANDLE_OPERATION_LIST_STREAM = 18 | 
|  | 171 |  | 
|  | 172 | MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE = 80 | 
|  | 173 |  | 
|  | 174 | MINIDUMP_FLOATING_SAVE_AREA_X86 = Descriptor([ | 
|  | 175 | ("control_word", ctypes.c_uint32), | 
|  | 176 | ("status_word", ctypes.c_uint32), | 
|  | 177 | ("tag_word", ctypes.c_uint32), | 
|  | 178 | ("error_offset", ctypes.c_uint32), | 
|  | 179 | ("error_selector", ctypes.c_uint32), | 
|  | 180 | ("data_offset", ctypes.c_uint32), | 
|  | 181 | ("data_selector", ctypes.c_uint32), | 
|  | 182 | ("register_area", ctypes.c_uint8 * MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE), | 
|  | 183 | ("cr0_npx_state", ctypes.c_uint32) | 
|  | 184 | ]) | 
|  | 185 |  | 
|  | 186 | MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE = 512 | 
|  | 187 |  | 
|  | 188 | # Context flags. | 
|  | 189 | MD_CONTEXT_X86 = 0x00010000 | 
|  | 190 | MD_CONTEXT_X86_CONTROL = (MD_CONTEXT_X86 | 0x00000001) | 
|  | 191 | MD_CONTEXT_X86_INTEGER = (MD_CONTEXT_X86 | 0x00000002) | 
|  | 192 | MD_CONTEXT_X86_SEGMENTS = (MD_CONTEXT_X86 | 0x00000004) | 
|  | 193 | MD_CONTEXT_X86_FLOATING_POINT = (MD_CONTEXT_X86 | 0x00000008) | 
|  | 194 | MD_CONTEXT_X86_DEBUG_REGISTERS = (MD_CONTEXT_X86 | 0x00000010) | 
|  | 195 | MD_CONTEXT_X86_EXTENDED_REGISTERS = (MD_CONTEXT_X86 | 0x00000020) | 
|  | 196 |  | 
|  | 197 | def EnableOnFlag(type, flag): | 
|  | 198 | return lambda o: [None, type][int((o.context_flags & flag) != 0)] | 
|  | 199 |  | 
|  | 200 | MINIDUMP_CONTEXT_X86 = Descriptor([ | 
|  | 201 | ("context_flags", ctypes.c_uint32), | 
|  | 202 | # MD_CONTEXT_X86_DEBUG_REGISTERS. | 
|  | 203 | ("dr0", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), | 
|  | 204 | ("dr1", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), | 
|  | 205 | ("dr2", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), | 
|  | 206 | ("dr3", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), | 
|  | 207 | ("dr6", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), | 
|  | 208 | ("dr7", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_DEBUG_REGISTERS)), | 
|  | 209 | # MD_CONTEXT_X86_FLOATING_POINT. | 
|  | 210 | ("float_save", EnableOnFlag(MINIDUMP_FLOATING_SAVE_AREA_X86.ctype, | 
|  | 211 | MD_CONTEXT_X86_FLOATING_POINT)), | 
|  | 212 | # MD_CONTEXT_X86_SEGMENTS. | 
|  | 213 | ("gs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), | 
|  | 214 | ("fs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), | 
|  | 215 | ("es", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), | 
|  | 216 | ("ds", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_SEGMENTS)), | 
|  | 217 | # MD_CONTEXT_X86_INTEGER. | 
|  | 218 | ("edi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), | 
|  | 219 | ("esi", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), | 
|  | 220 | ("ebx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), | 
|  | 221 | ("edx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), | 
|  | 222 | ("ecx", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), | 
|  | 223 | ("eax", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_INTEGER)), | 
|  | 224 | # MD_CONTEXT_X86_CONTROL. | 
|  | 225 | ("ebp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
|  | 226 | ("eip", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
|  | 227 | ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
|  | 228 | ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
|  | 229 | ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
|  | 230 | ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
|  | 231 | # MD_CONTEXT_X86_EXTENDED_REGISTERS. | 
|  | 232 | ("extended_registers", | 
|  | 233 | EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE, | 
|  | 234 | MD_CONTEXT_X86_EXTENDED_REGISTERS)) | 
|  | 235 | ]) | 
|  | 236 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 237 | MD_CONTEXT_AMD64 = 0x00100000 | 
|  | 238 | MD_CONTEXT_AMD64_CONTROL = (MD_CONTEXT_AMD64 | 0x00000001) | 
|  | 239 | MD_CONTEXT_AMD64_INTEGER = (MD_CONTEXT_AMD64 | 0x00000002) | 
|  | 240 | MD_CONTEXT_AMD64_SEGMENTS = (MD_CONTEXT_AMD64 | 0x00000004) | 
|  | 241 | MD_CONTEXT_AMD64_FLOATING_POINT = (MD_CONTEXT_AMD64 | 0x00000008) | 
|  | 242 | MD_CONTEXT_AMD64_DEBUG_REGISTERS = (MD_CONTEXT_AMD64 | 0x00000010) | 
|  | 243 |  | 
|  | 244 | MINIDUMP_CONTEXT_AMD64 = Descriptor([ | 
|  | 245 | ("p1_home", ctypes.c_uint64), | 
|  | 246 | ("p2_home", ctypes.c_uint64), | 
|  | 247 | ("p3_home", ctypes.c_uint64), | 
|  | 248 | ("p4_home", ctypes.c_uint64), | 
|  | 249 | ("p5_home", ctypes.c_uint64), | 
|  | 250 | ("p6_home", ctypes.c_uint64), | 
|  | 251 | ("context_flags", ctypes.c_uint32), | 
|  | 252 | ("mx_csr", ctypes.c_uint32), | 
|  | 253 | # MD_CONTEXT_AMD64_CONTROL. | 
|  | 254 | ("cs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)), | 
|  | 255 | # MD_CONTEXT_AMD64_SEGMENTS | 
|  | 256 | ("ds", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), | 
|  | 257 | ("es", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), | 
|  | 258 | ("fs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), | 
|  | 259 | ("gs", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_SEGMENTS)), | 
|  | 260 | # MD_CONTEXT_AMD64_CONTROL. | 
|  | 261 | ("ss", EnableOnFlag(ctypes.c_uint16, MD_CONTEXT_AMD64_CONTROL)), | 
|  | 262 | ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_AMD64_CONTROL)), | 
|  | 263 | # MD_CONTEXT_AMD64_DEBUG_REGISTERS. | 
|  | 264 | ("dr0", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 265 | ("dr1", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 266 | ("dr2", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 267 | ("dr3", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 268 | ("dr6", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 269 | ("dr7", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 270 | # MD_CONTEXT_AMD64_INTEGER. | 
|  | 271 | ("rax", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 272 | ("rcx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 273 | ("rdx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 274 | ("rbx", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 275 | # MD_CONTEXT_AMD64_CONTROL. | 
|  | 276 | ("rsp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)), | 
|  | 277 | # MD_CONTEXT_AMD64_INTEGER. | 
|  | 278 | ("rbp", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 279 | ("rsi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 280 | ("rdi", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 281 | ("r8", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 282 | ("r9", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 283 | ("r10", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 284 | ("r11", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 285 | ("r12", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 286 | ("r13", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 287 | ("r14", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 288 | ("r15", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_INTEGER)), | 
|  | 289 | # MD_CONTEXT_AMD64_CONTROL. | 
|  | 290 | ("rip", EnableOnFlag(ctypes.c_uint64, MD_CONTEXT_AMD64_CONTROL)), | 
|  | 291 | # MD_CONTEXT_AMD64_FLOATING_POINT | 
|  | 292 | ("sse_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26), | 
|  | 293 | MD_CONTEXT_AMD64_FLOATING_POINT)), | 
|  | 294 | ("vector_registers", EnableOnFlag(ctypes.c_uint8 * (16 * 26), | 
|  | 295 | MD_CONTEXT_AMD64_FLOATING_POINT)), | 
|  | 296 | ("vector_control", EnableOnFlag(ctypes.c_uint64, | 
|  | 297 | MD_CONTEXT_AMD64_FLOATING_POINT)), | 
|  | 298 | # MD_CONTEXT_AMD64_DEBUG_REGISTERS. | 
|  | 299 | ("debug_control", EnableOnFlag(ctypes.c_uint64, | 
|  | 300 | MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 301 | ("last_branch_to_rip", EnableOnFlag(ctypes.c_uint64, | 
|  | 302 | MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 303 | ("last_branch_from_rip", EnableOnFlag(ctypes.c_uint64, | 
|  | 304 | MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 305 | ("last_exception_to_rip", EnableOnFlag(ctypes.c_uint64, | 
|  | 306 | MD_CONTEXT_AMD64_DEBUG_REGISTERS)), | 
|  | 307 | ("last_exception_from_rip", EnableOnFlag(ctypes.c_uint64, | 
|  | 308 | MD_CONTEXT_AMD64_DEBUG_REGISTERS)) | 
|  | 309 | ]) | 
|  | 310 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 311 | MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([ | 
|  | 312 | ("start", ctypes.c_uint64), | 
|  | 313 | ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 
|  | 314 | ]) | 
|  | 315 |  | 
|  | 316 | MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([ | 
|  | 317 | ("start", ctypes.c_uint64), | 
|  | 318 | ("size", ctypes.c_uint64) | 
|  | 319 | ]) | 
|  | 320 |  | 
|  | 321 | MINIDUMP_MEMORY_LIST = Descriptor([ | 
|  | 322 | ("range_count", ctypes.c_uint32), | 
|  | 323 | ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR.ctype * m.range_count) | 
|  | 324 | ]) | 
|  | 325 |  | 
|  | 326 | MINIDUMP_MEMORY_LIST64 = Descriptor([ | 
|  | 327 | ("range_count", ctypes.c_uint64), | 
|  | 328 | ("base_rva", ctypes.c_uint64), | 
|  | 329 | ("ranges", lambda m: MINIDUMP_MEMORY_DESCRIPTOR64.ctype * m.range_count) | 
|  | 330 | ]) | 
|  | 331 |  | 
|  | 332 | MINIDUMP_THREAD = Descriptor([ | 
|  | 333 | ("id", ctypes.c_uint32), | 
|  | 334 | ("suspend_count", ctypes.c_uint32), | 
|  | 335 | ("priority_class", ctypes.c_uint32), | 
|  | 336 | ("priority", ctypes.c_uint32), | 
|  | 337 | ("ted", ctypes.c_uint64), | 
|  | 338 | ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), | 
|  | 339 | ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 
|  | 340 | ]) | 
|  | 341 |  | 
|  | 342 | MINIDUMP_THREAD_LIST = Descriptor([ | 
|  | 343 | ("thread_count", ctypes.c_uint32), | 
|  | 344 | ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) | 
|  | 345 | ]) | 
|  | 346 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 347 | MINIDUMP_RAW_SYSTEM_INFO = Descriptor([ | 
|  | 348 | ("processor_architecture", ctypes.c_uint16) | 
|  | 349 | ]) | 
|  | 350 |  | 
|  | 351 | MD_CPU_ARCHITECTURE_X86 = 0 | 
|  | 352 | MD_CPU_ARCHITECTURE_AMD64 = 9 | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 353 |  | 
|  | 354 | class MinidumpReader(object): | 
|  | 355 | """Minidump (.dmp) reader.""" | 
|  | 356 |  | 
|  | 357 | _HEADER_MAGIC = 0x504d444d | 
|  | 358 |  | 
|  | 359 | def __init__(self, options, minidump_name): | 
|  | 360 | self.minidump_name = minidump_name | 
|  | 361 | self.minidump_file = open(minidump_name, "r") | 
|  | 362 | self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) | 
|  | 363 | self.header = MINIDUMP_HEADER.Read(self.minidump, 0) | 
|  | 364 | if self.header.signature != MinidumpReader._HEADER_MAGIC: | 
|  | 365 | print >>sys.stderr, "Warning: unsupported minidump header magic" | 
|  | 366 | DebugPrint(self.header) | 
|  | 367 | directories = [] | 
|  | 368 | offset = self.header.stream_directories_rva | 
|  | 369 | for _ in xrange(self.header.stream_count): | 
|  | 370 | directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) | 
|  | 371 | offset += MINIDUMP_DIRECTORY.size | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 372 | self.arch = None | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 373 | self.exception = None | 
|  | 374 | self.exception_context = None | 
|  | 375 | self.memory_list = None | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 376 | self.memory_list64 = None | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 377 | self.thread_map = {} | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 378 |  | 
|  | 379 | # Find MDRawSystemInfo stream and determine arch. | 
|  | 380 | for d in directories: | 
|  | 381 | if d.stream_type == MD_SYSTEM_INFO_STREAM: | 
|  | 382 | system_info = MINIDUMP_RAW_SYSTEM_INFO.Read( | 
|  | 383 | self.minidump, d.location.rva) | 
|  | 384 | self.arch = system_info.processor_architecture | 
|  | 385 | assert self.arch in [MD_CPU_ARCHITECTURE_AMD64, MD_CPU_ARCHITECTURE_X86] | 
|  | 386 | assert not self.arch is None | 
|  | 387 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 388 | for d in directories: | 
|  | 389 | DebugPrint(d) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 390 | if d.stream_type == MD_EXCEPTION_STREAM: | 
|  | 391 | self.exception = MINIDUMP_EXCEPTION_STREAM.Read( | 
|  | 392 | self.minidump, d.location.rva) | 
|  | 393 | DebugPrint(self.exception) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 394 | if self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 395 | self.exception_context = MINIDUMP_CONTEXT_X86.Read( | 
|  | 396 | self.minidump, self.exception.thread_context.rva) | 
|  | 397 | elif self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 398 | self.exception_context = MINIDUMP_CONTEXT_AMD64.Read( | 
|  | 399 | self.minidump, self.exception.thread_context.rva) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 400 | DebugPrint(self.exception_context) | 
|  | 401 | elif d.stream_type == MD_THREAD_LIST_STREAM: | 
|  | 402 | thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) | 
|  | 403 | assert ctypes.sizeof(thread_list) == d.location.data_size | 
|  | 404 | DebugPrint(thread_list) | 
|  | 405 | for thread in thread_list.threads: | 
|  | 406 | DebugPrint(thread) | 
|  | 407 | self.thread_map[thread.id] = thread | 
|  | 408 | elif d.stream_type == MD_MEMORY_LIST_STREAM: | 
|  | 409 | print >>sys.stderr, "Warning: not a full minidump" | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 410 | assert self.memory_list is None | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 411 | self.memory_list = MINIDUMP_MEMORY_LIST.Read( | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 412 | self.minidump, d.location.rva) | 
|  | 413 | assert ctypes.sizeof(self.memory_list) == d.location.data_size | 
|  | 414 | DebugPrint(self.memory_list) | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 415 | elif d.stream_type == MD_MEMORY_64_LIST_STREAM: | 
|  | 416 | assert self.memory_list64 is None | 
|  | 417 | self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( | 
|  | 418 | self.minidump, d.location.rva) | 
|  | 419 | assert ctypes.sizeof(self.memory_list64) == d.location.data_size | 
|  | 420 | DebugPrint(self.memory_list64) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 421 |  | 
|  | 422 | def IsValidAddress(self, address): | 
|  | 423 | return self.FindLocation(address) is not None | 
|  | 424 |  | 
|  | 425 | def ReadU8(self, address): | 
|  | 426 | location = self.FindLocation(address) | 
|  | 427 | return ctypes.c_uint8.from_buffer(self.minidump, location).value | 
|  | 428 |  | 
|  | 429 | def ReadU32(self, address): | 
|  | 430 | location = self.FindLocation(address) | 
|  | 431 | return ctypes.c_uint32.from_buffer(self.minidump, location).value | 
|  | 432 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 433 | def ReadU64(self, address): | 
|  | 434 | location = self.FindLocation(address) | 
|  | 435 | return ctypes.c_uint64.from_buffer(self.minidump, location).value | 
|  | 436 |  | 
|  | 437 | def ReadUIntPtr(self, address): | 
|  | 438 | if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 439 | return self.ReadU64(address) | 
|  | 440 | elif self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 441 | return self.ReadU32(address) | 
|  | 442 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 443 | def ReadBytes(self, address, size): | 
|  | 444 | location = self.FindLocation(address) | 
|  | 445 | return self.minidump[location:location + size] | 
|  | 446 |  | 
|  | 447 | def FindLocation(self, address): | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 448 | offset = 0 | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 449 | if self.memory_list64 is not None: | 
|  | 450 | for r in self.memory_list64.ranges: | 
|  | 451 | if r.start <= address < r.start + r.size: | 
|  | 452 | return self.memory_list64.base_rva + offset + address - r.start | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 453 | offset += r.size | 
| Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 454 | if self.memory_list is not None: | 
|  | 455 | for r in self.memory_list.ranges: | 
|  | 456 | if r.start <= address < r.start + r.memory.data_size: | 
|  | 457 | return r.memory.rva + address - r.start | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 458 | return None | 
|  | 459 |  | 
|  | 460 | def GetDisasmLines(self, address, size): | 
|  | 461 | location = self.FindLocation(address) | 
|  | 462 | if location is None: return [] | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 463 | arch = None | 
|  | 464 | if self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 465 | arch = "ia32" | 
|  | 466 | elif self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 467 | arch = "x64" | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 468 | return disasm.GetDisasmLines(self.minidump_name, | 
|  | 469 | location, | 
|  | 470 | size, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 471 | arch, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 472 | False) | 
|  | 473 |  | 
|  | 474 |  | 
|  | 475 | def Dispose(self): | 
|  | 476 | self.minidump.close() | 
|  | 477 | self.minidump_file.close() | 
|  | 478 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 479 | def ExceptionIP(self): | 
|  | 480 | if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 481 | return self.exception_context.rip | 
|  | 482 | elif self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 483 | return self.exception_context.eip | 
|  | 484 |  | 
|  | 485 | def ExceptionSP(self): | 
|  | 486 | if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 487 | return self.exception_context.rsp | 
|  | 488 | elif self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 489 | return self.exception_context.esp | 
|  | 490 |  | 
|  | 491 | def FormatIntPtr(self, value): | 
|  | 492 | if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 493 | return "%016x" % value | 
|  | 494 | elif self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 495 | return "%08x" % value | 
|  | 496 |  | 
|  | 497 | def PointerSize(self): | 
|  | 498 | if self.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 499 | return 8 | 
|  | 500 | elif self.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 501 | return 4 | 
|  | 502 |  | 
|  | 503 | def Register(self, name): | 
|  | 504 | return self.exception_context.__getattribute__(name) | 
|  | 505 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 506 |  | 
|  | 507 | # List of V8 instance types. Obtained by adding the code below to any .cc file. | 
|  | 508 | # | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 509 | # #define DUMP_TYPE(T) printf("  %d: \"%s\",\n", T, #T); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 510 | # struct P { | 
|  | 511 | #   P() { | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 512 | #     printf("INSTANCE_TYPES = {\n"); | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 513 | #     INSTANCE_TYPE_LIST(DUMP_TYPE) | 
|  | 514 | #     printf("}\n"); | 
|  | 515 | #   } | 
|  | 516 | # }; | 
|  | 517 | # static P p; | 
|  | 518 | INSTANCE_TYPES = { | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 519 | 64: "SYMBOL_TYPE", | 
|  | 520 | 68: "ASCII_SYMBOL_TYPE", | 
|  | 521 | 65: "CONS_SYMBOL_TYPE", | 
|  | 522 | 69: "CONS_ASCII_SYMBOL_TYPE", | 
|  | 523 | 66: "EXTERNAL_SYMBOL_TYPE", | 
|  | 524 | 74: "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE", | 
|  | 525 | 70: "EXTERNAL_ASCII_SYMBOL_TYPE", | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 526 | 82: "SHORT_EXTERNAL_SYMBOL_TYPE", | 
|  | 527 | 90: "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE", | 
|  | 528 | 86: "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE", | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 529 | 0: "STRING_TYPE", | 
|  | 530 | 4: "ASCII_STRING_TYPE", | 
|  | 531 | 1: "CONS_STRING_TYPE", | 
|  | 532 | 5: "CONS_ASCII_STRING_TYPE", | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 533 | 3: "SLICED_STRING_TYPE", | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 534 | 2: "EXTERNAL_STRING_TYPE", | 
|  | 535 | 10: "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", | 
|  | 536 | 6: "EXTERNAL_ASCII_STRING_TYPE", | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 537 | 18: "SHORT_EXTERNAL_STRING_TYPE", | 
|  | 538 | 26: "SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE", | 
|  | 539 | 22: "SHORT_EXTERNAL_ASCII_STRING_TYPE", | 
| Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 540 | 6: "PRIVATE_EXTERNAL_ASCII_STRING_TYPE", | 
|  | 541 | 128: "MAP_TYPE", | 
|  | 542 | 129: "CODE_TYPE", | 
|  | 543 | 130: "ODDBALL_TYPE", | 
|  | 544 | 131: "JS_GLOBAL_PROPERTY_CELL_TYPE", | 
|  | 545 | 132: "HEAP_NUMBER_TYPE", | 
|  | 546 | 133: "FOREIGN_TYPE", | 
|  | 547 | 134: "BYTE_ARRAY_TYPE", | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 548 | 135: "FREE_SPACE_TYPE", | 
|  | 549 | 136: "EXTERNAL_BYTE_ARRAY_TYPE", | 
|  | 550 | 137: "EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE", | 
|  | 551 | 138: "EXTERNAL_SHORT_ARRAY_TYPE", | 
|  | 552 | 139: "EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE", | 
|  | 553 | 140: "EXTERNAL_INT_ARRAY_TYPE", | 
|  | 554 | 141: "EXTERNAL_UNSIGNED_INT_ARRAY_TYPE", | 
|  | 555 | 142: "EXTERNAL_FLOAT_ARRAY_TYPE", | 
|  | 556 | 144: "EXTERNAL_PIXEL_ARRAY_TYPE", | 
|  | 557 | 146: "FILLER_TYPE", | 
|  | 558 | 147: "ACCESSOR_INFO_TYPE", | 
|  | 559 | 148: "ACCESSOR_PAIR_TYPE", | 
|  | 560 | 149: "ACCESS_CHECK_INFO_TYPE", | 
|  | 561 | 150: "INTERCEPTOR_INFO_TYPE", | 
|  | 562 | 151: "CALL_HANDLER_INFO_TYPE", | 
|  | 563 | 152: "FUNCTION_TEMPLATE_INFO_TYPE", | 
|  | 564 | 153: "OBJECT_TEMPLATE_INFO_TYPE", | 
|  | 565 | 154: "SIGNATURE_INFO_TYPE", | 
|  | 566 | 155: "TYPE_SWITCH_INFO_TYPE", | 
|  | 567 | 156: "SCRIPT_TYPE", | 
|  | 568 | 157: "CODE_CACHE_TYPE", | 
|  | 569 | 158: "POLYMORPHIC_CODE_CACHE_TYPE", | 
|  | 570 | 161: "FIXED_ARRAY_TYPE", | 
|  | 571 | 145: "FIXED_DOUBLE_ARRAY_TYPE", | 
|  | 572 | 162: "SHARED_FUNCTION_INFO_TYPE", | 
|  | 573 | 163: "JS_MESSAGE_OBJECT_TYPE", | 
|  | 574 | 166: "JS_VALUE_TYPE", | 
|  | 575 | 167: "JS_OBJECT_TYPE", | 
|  | 576 | 168: "JS_CONTEXT_EXTENSION_OBJECT_TYPE", | 
|  | 577 | 169: "JS_GLOBAL_OBJECT_TYPE", | 
|  | 578 | 170: "JS_BUILTINS_OBJECT_TYPE", | 
|  | 579 | 171: "JS_GLOBAL_PROXY_TYPE", | 
|  | 580 | 172: "JS_ARRAY_TYPE", | 
|  | 581 | 165: "JS_PROXY_TYPE", | 
|  | 582 | 175: "JS_WEAK_MAP_TYPE", | 
|  | 583 | 176: "JS_REGEXP_TYPE", | 
|  | 584 | 177: "JS_FUNCTION_TYPE", | 
|  | 585 | 164: "JS_FUNCTION_PROXY_TYPE", | 
|  | 586 | 159: "DEBUG_INFO_TYPE", | 
|  | 587 | 160: "BREAK_POINT_INFO_TYPE", | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 588 | } | 
|  | 589 |  | 
|  | 590 |  | 
|  | 591 | class Printer(object): | 
|  | 592 | """Printer with indentation support.""" | 
|  | 593 |  | 
|  | 594 | def __init__(self): | 
|  | 595 | self.indent = 0 | 
|  | 596 |  | 
|  | 597 | def Indent(self): | 
|  | 598 | self.indent += 2 | 
|  | 599 |  | 
|  | 600 | def Dedent(self): | 
|  | 601 | self.indent -= 2 | 
|  | 602 |  | 
|  | 603 | def Print(self, string): | 
|  | 604 | print "%s%s" % (self._IndentString(), string) | 
|  | 605 |  | 
|  | 606 | def PrintLines(self, lines): | 
|  | 607 | indent = self._IndentString() | 
|  | 608 | print "\n".join("%s%s" % (indent, line) for line in lines) | 
|  | 609 |  | 
|  | 610 | def _IndentString(self): | 
|  | 611 | return self.indent * " " | 
|  | 612 |  | 
|  | 613 |  | 
|  | 614 | ADDRESS_RE = re.compile(r"0x[0-9a-fA-F]+") | 
|  | 615 |  | 
|  | 616 |  | 
|  | 617 | def FormatDisasmLine(start, heap, line): | 
|  | 618 | line_address = start + line[0] | 
|  | 619 | stack_slot = heap.stack_map.get(line_address) | 
|  | 620 | marker = "  " | 
|  | 621 | if stack_slot: | 
|  | 622 | marker = "=>" | 
|  | 623 | code = AnnotateAddresses(heap, line[1]) | 
|  | 624 | return "%s%08x %08x: %s" % (marker, line_address, line[0], code) | 
|  | 625 |  | 
|  | 626 |  | 
|  | 627 | def AnnotateAddresses(heap, line): | 
|  | 628 | extra = [] | 
|  | 629 | for m in ADDRESS_RE.finditer(line): | 
|  | 630 | maybe_address = int(m.group(0), 16) | 
|  | 631 | object = heap.FindObject(maybe_address) | 
|  | 632 | if not object: continue | 
|  | 633 | extra.append(str(object)) | 
|  | 634 | if len(extra) == 0: return line | 
|  | 635 | return "%s  ;; %s" % (line, ", ".join(extra)) | 
|  | 636 |  | 
|  | 637 |  | 
|  | 638 | class HeapObject(object): | 
|  | 639 | def __init__(self, heap, map, address): | 
|  | 640 | self.heap = heap | 
|  | 641 | self.map = map | 
|  | 642 | self.address = address | 
|  | 643 |  | 
|  | 644 | def Is(self, cls): | 
|  | 645 | return isinstance(self, cls) | 
|  | 646 |  | 
|  | 647 | def Print(self, p): | 
|  | 648 | p.Print(str(self)) | 
|  | 649 |  | 
|  | 650 | def __str__(self): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 651 | return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address), | 
|  | 652 | INSTANCE_TYPES[self.map.instance_type]) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 653 |  | 
|  | 654 | def ObjectField(self, offset): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 655 | field_value = self.heap.reader.ReadUIntPtr(self.address + offset) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 656 | return self.heap.FindObjectOrSmi(field_value) | 
|  | 657 |  | 
|  | 658 | def SmiField(self, offset): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 659 | field_value = self.heap.reader.ReadUIntPtr(self.address + offset) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 660 | assert (field_value & 1) == 0 | 
|  | 661 | return field_value / 2 | 
|  | 662 |  | 
|  | 663 |  | 
|  | 664 | class Map(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 665 | def InstanceTypeOffset(self): | 
|  | 666 | return self.heap.PointerSize() + self.heap.IntSize() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 667 |  | 
|  | 668 | def __init__(self, heap, map, address): | 
|  | 669 | HeapObject.__init__(self, heap, map, address) | 
|  | 670 | self.instance_type = \ | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 671 | heap.reader.ReadU8(self.address + self.InstanceTypeOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 672 |  | 
|  | 673 |  | 
|  | 674 | class String(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 675 | def LengthOffset(self): | 
|  | 676 | return self.heap.PointerSize() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 677 |  | 
|  | 678 | def __init__(self, heap, map, address): | 
|  | 679 | HeapObject.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 680 | self.length = self.SmiField(self.LengthOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 681 |  | 
|  | 682 | def GetChars(self): | 
|  | 683 | return "?string?" | 
|  | 684 |  | 
|  | 685 | def Print(self, p): | 
|  | 686 | p.Print(str(self)) | 
|  | 687 |  | 
|  | 688 | def __str__(self): | 
|  | 689 | return "\"%s\"" % self.GetChars() | 
|  | 690 |  | 
|  | 691 |  | 
|  | 692 | class SeqString(String): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 693 | def CharsOffset(self): | 
|  | 694 | return self.heap.PointerSize() * 3 | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 695 |  | 
|  | 696 | def __init__(self, heap, map, address): | 
|  | 697 | String.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 698 | self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(), | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 699 | self.length) | 
|  | 700 |  | 
|  | 701 | def GetChars(self): | 
|  | 702 | return self.chars | 
|  | 703 |  | 
|  | 704 |  | 
|  | 705 | class ExternalString(String): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 706 | # TODO(vegorov) fix ExternalString for X64 architecture | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 707 | RESOURCE_OFFSET = 12 | 
|  | 708 |  | 
|  | 709 | WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4 | 
|  | 710 | WEBKIT_STRING_IMPL_CHARS_OFFSET = 8 | 
|  | 711 |  | 
|  | 712 | def __init__(self, heap, map, address): | 
|  | 713 | String.__init__(self, heap, map, address) | 
|  | 714 | reader = heap.reader | 
|  | 715 | self.resource = \ | 
|  | 716 | reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET) | 
|  | 717 | self.chars = "?external string?" | 
|  | 718 | if not reader.IsValidAddress(self.resource): return | 
|  | 719 | string_impl_address = self.resource + \ | 
|  | 720 | ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET | 
|  | 721 | if not reader.IsValidAddress(string_impl_address): return | 
|  | 722 | string_impl = reader.ReadU32(string_impl_address) | 
|  | 723 | chars_ptr_address = string_impl + \ | 
|  | 724 | ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET | 
|  | 725 | if not reader.IsValidAddress(chars_ptr_address): return | 
|  | 726 | chars_ptr = reader.ReadU32(chars_ptr_address) | 
|  | 727 | if not reader.IsValidAddress(chars_ptr): return | 
|  | 728 | raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length) | 
|  | 729 | self.chars = codecs.getdecoder("utf16")(raw_chars)[0] | 
|  | 730 |  | 
|  | 731 | def GetChars(self): | 
|  | 732 | return self.chars | 
|  | 733 |  | 
|  | 734 |  | 
|  | 735 | class ConsString(String): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 736 | def LeftOffset(self): | 
|  | 737 | return self.heap.PointerSize() * 3 | 
|  | 738 |  | 
|  | 739 | def RightOffset(self): | 
|  | 740 | return self.heap.PointerSize() * 4 | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 741 |  | 
|  | 742 | def __init__(self, heap, map, address): | 
|  | 743 | String.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 744 | self.left = self.ObjectField(self.LeftOffset()) | 
|  | 745 | self.right = self.ObjectField(self.RightOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 746 |  | 
|  | 747 | def GetChars(self): | 
|  | 748 | return self.left.GetChars() + self.right.GetChars() | 
|  | 749 |  | 
|  | 750 |  | 
|  | 751 | class Oddball(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 752 | def ToStringOffset(self): | 
|  | 753 | return self.heap.PointerSize() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 754 |  | 
|  | 755 | def __init__(self, heap, map, address): | 
|  | 756 | HeapObject.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 757 | self.to_string = self.ObjectField(self.ToStringOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 758 |  | 
|  | 759 | def Print(self, p): | 
|  | 760 | p.Print(str(self)) | 
|  | 761 |  | 
|  | 762 | def __str__(self): | 
|  | 763 | return "<%s>" % self.to_string.GetChars() | 
|  | 764 |  | 
|  | 765 |  | 
|  | 766 | class FixedArray(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 767 | def LengthOffset(self): | 
|  | 768 | return self.heap.PointerSize() | 
|  | 769 |  | 
|  | 770 | def ElementsOffset(self): | 
|  | 771 | return self.heap.PointerSize() * 2 | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 772 |  | 
|  | 773 | def __init__(self, heap, map, address): | 
|  | 774 | HeapObject.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 775 | self.length = self.SmiField(self.LengthOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 776 |  | 
|  | 777 | def Print(self, p): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 778 | p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 779 | p.Indent() | 
|  | 780 | p.Print("length: %d" % self.length) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 781 | base_offset = self.ElementsOffset() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 782 | for i in xrange(self.length): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 783 | offset = base_offset + 4 * i | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 784 | p.Print("[%08d] = %s" % (i, self.ObjectField(offset))) | 
|  | 785 | p.Dedent() | 
|  | 786 | p.Print("}") | 
|  | 787 |  | 
|  | 788 | def __str__(self): | 
|  | 789 | return "FixedArray(%08x, length=%d)" % (self.address, self.length) | 
|  | 790 |  | 
|  | 791 |  | 
|  | 792 | class JSFunction(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 793 | def CodeEntryOffset(self): | 
|  | 794 | return 3 * self.heap.PointerSize() | 
|  | 795 |  | 
|  | 796 | def SharedOffset(self): | 
|  | 797 | return 5 * self.heap.PointerSize() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 798 |  | 
|  | 799 | def __init__(self, heap, map, address): | 
|  | 800 | HeapObject.__init__(self, heap, map, address) | 
|  | 801 | code_entry = \ | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 802 | heap.reader.ReadU32(self.address + self.CodeEntryOffset()) | 
|  | 803 | self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1) | 
|  | 804 | self.shared = self.ObjectField(self.SharedOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 805 |  | 
|  | 806 | def Print(self, p): | 
|  | 807 | source = "\n".join("  %s" % line for line in self._GetSource().split("\n")) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 808 | p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 809 | p.Indent() | 
|  | 810 | p.Print("inferred name: %s" % self.shared.inferred_name) | 
|  | 811 | if self.shared.script.Is(Script) and self.shared.script.name.Is(String): | 
|  | 812 | p.Print("script name: %s" % self.shared.script.name) | 
|  | 813 | p.Print("source:") | 
|  | 814 | p.PrintLines(self._GetSource().split("\n")) | 
|  | 815 | p.Print("code:") | 
|  | 816 | self.code.Print(p) | 
|  | 817 | if self.code != self.shared.code: | 
|  | 818 | p.Print("unoptimized code:") | 
|  | 819 | self.shared.code.Print(p) | 
|  | 820 | p.Dedent() | 
|  | 821 | p.Print("}") | 
|  | 822 |  | 
|  | 823 | def __str__(self): | 
|  | 824 | inferred_name = "" | 
|  | 825 | if self.shared.Is(SharedFunctionInfo): | 
|  | 826 | inferred_name = self.shared.inferred_name | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 827 | return "JSFunction(%s, %s)" % \ | 
|  | 828 | (self.heap.reader.FormatIntPtr(self.address), inferred_name) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 829 |  | 
|  | 830 | def _GetSource(self): | 
|  | 831 | source = "?source?" | 
|  | 832 | start = self.shared.start_position | 
|  | 833 | end = self.shared.end_position | 
|  | 834 | if not self.shared.script.Is(Script): return source | 
|  | 835 | script_source = self.shared.script.source | 
|  | 836 | if not script_source.Is(String): return source | 
|  | 837 | return script_source.GetChars()[start:end] | 
|  | 838 |  | 
|  | 839 |  | 
|  | 840 | class SharedFunctionInfo(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 841 | def CodeOffset(self): | 
|  | 842 | return 2 * self.heap.PointerSize() | 
|  | 843 |  | 
|  | 844 | def ScriptOffset(self): | 
|  | 845 | return 7 * self.heap.PointerSize() | 
|  | 846 |  | 
|  | 847 | def InferredNameOffset(self): | 
|  | 848 | return 9 * self.heap.PointerSize() | 
|  | 849 |  | 
|  | 850 | def EndPositionOffset(self): | 
|  | 851 | return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize() | 
|  | 852 |  | 
|  | 853 | def StartPositionAndTypeOffset(self): | 
|  | 854 | return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 855 |  | 
|  | 856 | def __init__(self, heap, map, address): | 
|  | 857 | HeapObject.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 858 | self.code = self.ObjectField(self.CodeOffset()) | 
|  | 859 | self.script = self.ObjectField(self.ScriptOffset()) | 
|  | 860 | self.inferred_name = self.ObjectField(self.InferredNameOffset()) | 
|  | 861 | if heap.PointerSize() == 8: | 
|  | 862 | start_position_and_type = \ | 
|  | 863 | heap.reader.ReadU32(self.StartPositionAndTypeOffset()) | 
|  | 864 | self.start_position = start_position_and_type >> 2 | 
|  | 865 | pseudo_smi_end_position = \ | 
|  | 866 | heap.reader.ReadU32(self.EndPositionOffset()) | 
|  | 867 | self.end_position = pseudo_smi_end_position >> 2 | 
|  | 868 | else: | 
|  | 869 | start_position_and_type = \ | 
|  | 870 | self.SmiField(self.StartPositionAndTypeOffset()) | 
|  | 871 | self.start_position = start_position_and_type >> 2 | 
|  | 872 | self.end_position = \ | 
|  | 873 | self.SmiField(self.EndPositionOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 874 |  | 
|  | 875 |  | 
|  | 876 | class Script(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 877 | def SourceOffset(self): | 
|  | 878 | return self.heap.PointerSize() | 
|  | 879 |  | 
|  | 880 | def NameOffset(self): | 
|  | 881 | return self.SourceOffset() + self.heap.PointerSize() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 882 |  | 
|  | 883 | def __init__(self, heap, map, address): | 
|  | 884 | HeapObject.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 885 | self.source = self.ObjectField(self.SourceOffset()) | 
|  | 886 | self.name = self.ObjectField(self.NameOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 887 |  | 
|  | 888 |  | 
|  | 889 | class Code(HeapObject): | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 890 | CODE_ALIGNMENT_MASK = (1 << 5) - 1 | 
|  | 891 |  | 
|  | 892 | def InstructionSizeOffset(self): | 
|  | 893 | return self.heap.PointerSize() | 
|  | 894 |  | 
|  | 895 | @staticmethod | 
|  | 896 | def HeaderSize(heap): | 
|  | 897 | return (heap.PointerSize() + heap.IntSize() + \ | 
|  | 898 | 4 * heap.PointerSize() + 3 * heap.IntSize() + \ | 
|  | 899 | Code.CODE_ALIGNMENT_MASK) & ~Code.CODE_ALIGNMENT_MASK | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 900 |  | 
|  | 901 | def __init__(self, heap, map, address): | 
|  | 902 | HeapObject.__init__(self, heap, map, address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 903 | self.entry = self.address + Code.HeaderSize(heap) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 904 | self.instruction_size = \ | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 905 | heap.reader.ReadU32(self.address + self.InstructionSizeOffset()) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 906 |  | 
|  | 907 | def Print(self, p): | 
|  | 908 | lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 909 | p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 910 | p.Indent() | 
|  | 911 | p.Print("instruction_size: %d" % self.instruction_size) | 
|  | 912 | p.PrintLines(self._FormatLine(line) for line in lines) | 
|  | 913 | p.Dedent() | 
|  | 914 | p.Print("}") | 
|  | 915 |  | 
|  | 916 | def _FormatLine(self, line): | 
|  | 917 | return FormatDisasmLine(self.entry, self.heap, line) | 
|  | 918 |  | 
|  | 919 |  | 
|  | 920 | class V8Heap(object): | 
|  | 921 | CLASS_MAP = { | 
|  | 922 | "SYMBOL_TYPE": SeqString, | 
|  | 923 | "ASCII_SYMBOL_TYPE": SeqString, | 
|  | 924 | "CONS_SYMBOL_TYPE": ConsString, | 
|  | 925 | "CONS_ASCII_SYMBOL_TYPE": ConsString, | 
|  | 926 | "EXTERNAL_SYMBOL_TYPE": ExternalString, | 
|  | 927 | "EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString, | 
|  | 928 | "EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString, | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 929 | "SHORT_EXTERNAL_SYMBOL_TYPE": ExternalString, | 
|  | 930 | "SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE": ExternalString, | 
|  | 931 | "SHORT_EXTERNAL_ASCII_SYMBOL_TYPE": ExternalString, | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 932 | "STRING_TYPE": SeqString, | 
|  | 933 | "ASCII_STRING_TYPE": SeqString, | 
|  | 934 | "CONS_STRING_TYPE": ConsString, | 
|  | 935 | "CONS_ASCII_STRING_TYPE": ConsString, | 
|  | 936 | "EXTERNAL_STRING_TYPE": ExternalString, | 
|  | 937 | "EXTERNAL_STRING_WITH_ASCII_DATA_TYPE": ExternalString, | 
|  | 938 | "EXTERNAL_ASCII_STRING_TYPE": ExternalString, | 
|  | 939 |  | 
|  | 940 | "MAP_TYPE": Map, | 
|  | 941 | "ODDBALL_TYPE": Oddball, | 
|  | 942 | "FIXED_ARRAY_TYPE": FixedArray, | 
|  | 943 | "JS_FUNCTION_TYPE": JSFunction, | 
|  | 944 | "SHARED_FUNCTION_INFO_TYPE": SharedFunctionInfo, | 
|  | 945 | "SCRIPT_TYPE": Script, | 
|  | 946 | "CODE_TYPE": Code | 
|  | 947 | } | 
|  | 948 |  | 
|  | 949 | def __init__(self, reader, stack_map): | 
|  | 950 | self.reader = reader | 
|  | 951 | self.stack_map = stack_map | 
|  | 952 | self.objects = {} | 
|  | 953 |  | 
|  | 954 | def FindObjectOrSmi(self, tagged_address): | 
|  | 955 | if (tagged_address & 1) == 0: return tagged_address / 2 | 
|  | 956 | return self.FindObject(tagged_address) | 
|  | 957 |  | 
|  | 958 | def FindObject(self, tagged_address): | 
|  | 959 | if tagged_address in self.objects: | 
|  | 960 | return self.objects[tagged_address] | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 961 | if (tagged_address & self.ObjectAlignmentMask()) != 1: return None | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 962 | address = tagged_address - 1 | 
|  | 963 | if not self.reader.IsValidAddress(address): return None | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 964 | map_tagged_address = self.reader.ReadUIntPtr(address) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 965 | if tagged_address == map_tagged_address: | 
|  | 966 | # Meta map? | 
|  | 967 | meta_map = Map(self, None, address) | 
|  | 968 | instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type) | 
|  | 969 | if instance_type_name != "MAP_TYPE": return None | 
|  | 970 | meta_map.map = meta_map | 
|  | 971 | object = meta_map | 
|  | 972 | else: | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 973 | map = self.FindMap(map_tagged_address) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 974 | if map is None: return None | 
|  | 975 | instance_type_name = INSTANCE_TYPES.get(map.instance_type) | 
|  | 976 | if instance_type_name is None: return None | 
|  | 977 | cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject) | 
|  | 978 | object = cls(self, map, address) | 
|  | 979 | self.objects[tagged_address] = object | 
|  | 980 | return object | 
|  | 981 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 982 | def FindMap(self, tagged_address): | 
|  | 983 | if (tagged_address & self.MapAlignmentMask()) != 1: return None | 
|  | 984 | address = tagged_address - 1 | 
|  | 985 | if not self.reader.IsValidAddress(address): return None | 
|  | 986 | object = Map(self, None, address) | 
|  | 987 | return object | 
|  | 988 |  | 
|  | 989 | def IntSize(self): | 
|  | 990 | return 4 | 
|  | 991 |  | 
|  | 992 | def PointerSize(self): | 
|  | 993 | return self.reader.PointerSize() | 
|  | 994 |  | 
|  | 995 | def ObjectAlignmentMask(self): | 
|  | 996 | return self.PointerSize() - 1 | 
|  | 997 |  | 
|  | 998 | def MapAlignmentMask(self): | 
|  | 999 | if self.reader.arch == MD_CPU_ARCHITECTURE_AMD64: | 
|  | 1000 | return (1 << 4) - 1 | 
|  | 1001 | elif self.reader.arch == MD_CPU_ARCHITECTURE_X86: | 
|  | 1002 | return (1 << 5) - 1 | 
|  | 1003 |  | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1004 |  | 
|  | 1005 | EIP_PROXIMITY = 64 | 
|  | 1006 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1007 | CONTEXT_FOR_ARCH = { | 
|  | 1008 | MD_CPU_ARCHITECTURE_AMD64: | 
|  | 1009 | ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'], | 
|  | 1010 | MD_CPU_ARCHITECTURE_X86: | 
|  | 1011 | ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] | 
|  | 1012 | } | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1013 |  | 
|  | 1014 | def AnalyzeMinidump(options, minidump_name): | 
|  | 1015 | reader = MinidumpReader(options, minidump_name) | 
|  | 1016 | DebugPrint("========================================") | 
|  | 1017 | if reader.exception is None: | 
|  | 1018 | print "Minidump has no exception info" | 
|  | 1019 | return | 
|  | 1020 | print "Exception info:" | 
|  | 1021 | exception_thread = reader.thread_map[reader.exception.thread_id] | 
|  | 1022 | print "  thread id: %d" % exception_thread.id | 
|  | 1023 | print "  code: %08X" % reader.exception.exception.code | 
|  | 1024 | print "  context:" | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1025 | for r in CONTEXT_FOR_ARCH[reader.arch]: | 
|  | 1026 | print "    %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1027 | # TODO(vitalyr): decode eflags. | 
|  | 1028 | print "    eflags: %s" % bin(reader.exception_context.eflags)[2:] | 
|  | 1029 | print | 
|  | 1030 |  | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1031 | stack_top = reader.ExceptionSP() | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1032 | stack_bottom = exception_thread.stack.start + \ | 
|  | 1033 | exception_thread.stack.memory.data_size | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1034 | stack_map = {reader.ExceptionIP(): -1} | 
|  | 1035 | for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 
|  | 1036 | maybe_address = reader.ReadUIntPtr(slot) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1037 | if not maybe_address in stack_map: | 
|  | 1038 | stack_map[maybe_address] = slot | 
|  | 1039 | heap = V8Heap(reader, stack_map) | 
|  | 1040 |  | 
|  | 1041 | print "Disassembly around exception.eip:" | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1042 | start = reader.ExceptionIP() - EIP_PROXIMITY | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1043 | lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY) | 
|  | 1044 | for line in lines: | 
|  | 1045 | print FormatDisasmLine(start, heap, line) | 
|  | 1046 | print | 
|  | 1047 |  | 
|  | 1048 | print "Annotated stack (from exception.esp to bottom):" | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1049 | for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 
|  | 1050 | maybe_address = reader.ReadUIntPtr(slot) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1051 | heap_object = heap.FindObject(maybe_address) | 
| Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1052 | print "%s: %s" % (reader.FormatIntPtr(slot), | 
|  | 1053 | reader.FormatIntPtr(maybe_address)) | 
| Ben Murdoch | e0cee9b | 2011-05-25 10:26:03 +0100 | [diff] [blame] | 1054 | if heap_object: | 
|  | 1055 | heap_object.Print(Printer()) | 
|  | 1056 | print | 
|  | 1057 |  | 
|  | 1058 | reader.Dispose() | 
|  | 1059 |  | 
|  | 1060 |  | 
|  | 1061 | if __name__ == "__main__": | 
|  | 1062 | parser = optparse.OptionParser(USAGE) | 
|  | 1063 | options, args = parser.parse_args() | 
|  | 1064 | if len(args) != 1: | 
|  | 1065 | parser.print_help() | 
|  | 1066 | sys.exit(1) | 
|  | 1067 | AnalyzeMinidump(options, args[0]) |