 Chromium Code Reviews
 Chromium Code Reviews Issue 8957005:
  Add X64 minidumps support to tools/grokdump.py  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 8957005:
  Add X64 minidumps support to tools/grokdump.py  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| OLD | NEW | 
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python | 
| 2 # | 2 # | 
| 3 # Copyright 2011 the V8 project authors. All rights reserved. | 3 # Copyright 2011 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 Shows the processor state at the point of exception including the | 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 | 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 | 47 heap. Code objects are disassembled and the addresses linked from the | 
| 48 stack (pushed return addresses) are marked with "=>". | 48 stack (pushed return addresses) are marked with "=>". | 
| 49 | 49 | 
| 50 | 50 | 
| 51 Examples: | 51 Examples: | 
| 52 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp | 52 $ %prog 12345678-1234-1234-1234-123456789abcd-full.dmp | 
| 53 """ | 53 """ | 
| 54 | 54 | 
| 55 | |
| 55 DEBUG=False | 56 DEBUG=False | 
| 56 | 57 | 
| 57 | 58 | 
| 58 def DebugPrint(s): | 59 def DebugPrint(s): | 
| 59 if not DEBUG: return | 60 if not DEBUG: return | 
| 60 print s | 61 print s | 
| 61 | 62 | 
| 62 | 63 | 
| 63 class Descriptor(object): | 64 class Descriptor(object): | 
| 64 """Descriptor of a structure in a memory.""" | 65 """Descriptor of a structure in a memory.""" | 
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 226 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 227 ("cs", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
| 227 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 228 ("eflags", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
| 228 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 229 ("esp", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
| 229 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 230 ("ss", EnableOnFlag(ctypes.c_uint32, MD_CONTEXT_X86_CONTROL)), | 
| 230 # MD_CONTEXT_X86_EXTENDED_REGISTERS. | 231 # MD_CONTEXT_X86_EXTENDED_REGISTERS. | 
| 231 ("extended_registers", | 232 ("extended_registers", | 
| 232 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE, | 233 EnableOnFlag(ctypes.c_uint8 * MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE, | 
| 233 MD_CONTEXT_X86_EXTENDED_REGISTERS)) | 234 MD_CONTEXT_X86_EXTENDED_REGISTERS)) | 
| 234 ]) | 235 ]) | 
| 235 | 236 | 
| 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 | |
| 236 MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([ | 311 MINIDUMP_MEMORY_DESCRIPTOR = Descriptor([ | 
| 237 ("start", ctypes.c_uint64), | 312 ("start", ctypes.c_uint64), | 
| 238 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 313 ("memory", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 
| 239 ]) | 314 ]) | 
| 240 | 315 | 
| 241 MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([ | 316 MINIDUMP_MEMORY_DESCRIPTOR64 = Descriptor([ | 
| 242 ("start", ctypes.c_uint64), | 317 ("start", ctypes.c_uint64), | 
| 243 ("size", ctypes.c_uint64) | 318 ("size", ctypes.c_uint64) | 
| 244 ]) | 319 ]) | 
| 245 | 320 | 
| (...skipping 16 matching lines...) Expand all Loading... | |
| 262 ("ted", ctypes.c_uint64), | 337 ("ted", ctypes.c_uint64), | 
| 263 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), | 338 ("stack", MINIDUMP_MEMORY_DESCRIPTOR.ctype), | 
| 264 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 339 ("context", MINIDUMP_LOCATION_DESCRIPTOR.ctype) | 
| 265 ]) | 340 ]) | 
| 266 | 341 | 
| 267 MINIDUMP_THREAD_LIST = Descriptor([ | 342 MINIDUMP_THREAD_LIST = Descriptor([ | 
| 268 ("thread_count", ctypes.c_uint32), | 343 ("thread_count", ctypes.c_uint32), | 
| 269 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) | 344 ("threads", lambda t: MINIDUMP_THREAD.ctype * t.thread_count) | 
| 270 ]) | 345 ]) | 
| 271 | 346 | 
| 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 | |
| 272 | 353 | 
| 273 class MinidumpReader(object): | 354 class MinidumpReader(object): | 
| 274 """Minidump (.dmp) reader.""" | 355 """Minidump (.dmp) reader.""" | 
| 275 | 356 | 
| 276 _HEADER_MAGIC = 0x504d444d | 357 _HEADER_MAGIC = 0x504d444d | 
| 277 | 358 | 
| 278 def __init__(self, options, minidump_name): | 359 def __init__(self, options, minidump_name): | 
| 279 self.minidump_name = minidump_name | 360 self.minidump_name = minidump_name | 
| 280 self.minidump_file = open(minidump_name, "r") | 361 self.minidump_file = open(minidump_name, "r") | 
| 281 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) | 362 self.minidump = mmap.mmap(self.minidump_file.fileno(), 0, mmap.MAP_PRIVATE) | 
| 282 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) | 363 self.header = MINIDUMP_HEADER.Read(self.minidump, 0) | 
| 283 if self.header.signature != MinidumpReader._HEADER_MAGIC: | 364 if self.header.signature != MinidumpReader._HEADER_MAGIC: | 
| 284 print >>sys.stderr, "Warning: unsupported minidump header magic" | 365 print >>sys.stderr, "Warning: unsupported minidump header magic" | 
| 285 DebugPrint(self.header) | 366 DebugPrint(self.header) | 
| 286 directories = [] | 367 directories = [] | 
| 287 offset = self.header.stream_directories_rva | 368 offset = self.header.stream_directories_rva | 
| 288 for _ in xrange(self.header.stream_count): | 369 for _ in xrange(self.header.stream_count): | 
| 289 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) | 370 directories.append(MINIDUMP_DIRECTORY.Read(self.minidump, offset)) | 
| 290 offset += MINIDUMP_DIRECTORY.size | 371 offset += MINIDUMP_DIRECTORY.size | 
| 372 self.arch = None | |
| 291 self.exception = None | 373 self.exception = None | 
| 292 self.exception_context = None | 374 self.exception_context = None | 
| 293 self.memory_list = None | 375 self.memory_list = None | 
| 294 self.memory_list64 = None | 376 self.memory_list64 = None | 
| 295 self.thread_map = {} | 377 self.thread_map = {} | 
| 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 | |
| 296 for d in directories: | 388 for d in directories: | 
| 297 DebugPrint(d) | 389 DebugPrint(d) | 
| 298 # TODO(vitalyr): extract system info including CPU features. | |
| 299 if d.stream_type == MD_EXCEPTION_STREAM: | 390 if d.stream_type == MD_EXCEPTION_STREAM: | 
| 300 self.exception = MINIDUMP_EXCEPTION_STREAM.Read( | 391 self.exception = MINIDUMP_EXCEPTION_STREAM.Read( | 
| 301 self.minidump, d.location.rva) | 392 self.minidump, d.location.rva) | 
| 302 DebugPrint(self.exception) | 393 DebugPrint(self.exception) | 
| 303 self.exception_context = MINIDUMP_CONTEXT_X86.Read( | 394 if self.arch == MD_CPU_ARCHITECTURE_X86: | 
| 304 self.minidump, self.exception.thread_context.rva) | 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) | |
| 
Erik Corry
2011/12/15 12:09:11
Do we output an error message if it's not one of t
 | |
| 305 DebugPrint(self.exception_context) | 400 DebugPrint(self.exception_context) | 
| 306 elif d.stream_type == MD_THREAD_LIST_STREAM: | 401 elif d.stream_type == MD_THREAD_LIST_STREAM: | 
| 307 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) | 402 thread_list = MINIDUMP_THREAD_LIST.Read(self.minidump, d.location.rva) | 
| 308 assert ctypes.sizeof(thread_list) == d.location.data_size | 403 assert ctypes.sizeof(thread_list) == d.location.data_size | 
| 309 DebugPrint(thread_list) | 404 DebugPrint(thread_list) | 
| 310 for thread in thread_list.threads: | 405 for thread in thread_list.threads: | 
| 311 DebugPrint(thread) | 406 DebugPrint(thread) | 
| 312 self.thread_map[thread.id] = thread | 407 self.thread_map[thread.id] = thread | 
| 313 elif d.stream_type == MD_MEMORY_LIST_STREAM: | 408 elif d.stream_type == MD_MEMORY_LIST_STREAM: | 
| 314 print >>sys.stderr, "Warning: not a full minidump" | 409 print >>sys.stderr, "Warning: not a full minidump" | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 328 return self.FindLocation(address) is not None | 423 return self.FindLocation(address) is not None | 
| 329 | 424 | 
| 330 def ReadU8(self, address): | 425 def ReadU8(self, address): | 
| 331 location = self.FindLocation(address) | 426 location = self.FindLocation(address) | 
| 332 return ctypes.c_uint8.from_buffer(self.minidump, location).value | 427 return ctypes.c_uint8.from_buffer(self.minidump, location).value | 
| 333 | 428 | 
| 334 def ReadU32(self, address): | 429 def ReadU32(self, address): | 
| 335 location = self.FindLocation(address) | 430 location = self.FindLocation(address) | 
| 336 return ctypes.c_uint32.from_buffer(self.minidump, location).value | 431 return ctypes.c_uint32.from_buffer(self.minidump, location).value | 
| 337 | 432 | 
| 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 | |
| 338 def ReadBytes(self, address, size): | 443 def ReadBytes(self, address, size): | 
| 339 location = self.FindLocation(address) | 444 location = self.FindLocation(address) | 
| 340 return self.minidump[location:location + size] | 445 return self.minidump[location:location + size] | 
| 341 | 446 | 
| 342 def FindLocation(self, address): | 447 def FindLocation(self, address): | 
| 343 offset = 0 | 448 offset = 0 | 
| 344 if self.memory_list64 is not None: | 449 if self.memory_list64 is not None: | 
| 345 for r in self.memory_list64.ranges: | 450 for r in self.memory_list64.ranges: | 
| 346 if r.start <= address < r.start + r.size: | 451 if r.start <= address < r.start + r.size: | 
| 347 return self.memory_list64.base_rva + offset + address - r.start | 452 return self.memory_list64.base_rva + offset + address - r.start | 
| 348 offset += r.size | 453 offset += r.size | 
| 349 if self.memory_list is not None: | 454 if self.memory_list is not None: | 
| 350 for r in self.memory_list.ranges: | 455 for r in self.memory_list.ranges: | 
| 351 if r.start <= address < r.start + r.memory.data_size: | 456 if r.start <= address < r.start + r.memory.data_size: | 
| 352 return r.memory.rva + address - r.start | 457 return r.memory.rva + address - r.start | 
| 353 return None | 458 return None | 
| 354 | 459 | 
| 355 def GetDisasmLines(self, address, size): | 460 def GetDisasmLines(self, address, size): | 
| 356 location = self.FindLocation(address) | 461 location = self.FindLocation(address) | 
| 357 if location is None: return [] | 462 if location is None: return [] | 
| 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" | |
| 358 return disasm.GetDisasmLines(self.minidump_name, | 468 return disasm.GetDisasmLines(self.minidump_name, | 
| 359 location, | 469 location, | 
| 360 size, | 470 size, | 
| 361 "ia32", | 471 arch, | 
| 362 False) | 472 False) | 
| 363 | 473 | 
| 364 | 474 | 
| 365 def Dispose(self): | 475 def Dispose(self): | 
| 366 self.minidump.close() | 476 self.minidump.close() | 
| 367 self.minidump_file.close() | 477 self.minidump_file.close() | 
| 368 | 478 | 
| 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.rbp | |
| 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 | |
| 369 | 506 | 
| 370 # List of V8 instance types. Obtained by adding the code below to any .cc file. | 507 # List of V8 instance types. Obtained by adding the code below to any .cc file. | 
| 371 # | 508 # | 
| 372 # #define DUMP_TYPE(T) printf("%d: \"%s\",\n", T, #T); | 509 # #define DUMP_TYPE(T) printf("%d: \"%s\",\n", T, #T); | 
| 373 # struct P { | 510 # struct P { | 
| 374 # P() { | 511 # P() { | 
| 375 # printf("{\n"); | 512 # printf("{\n"); | 
| 376 # INSTANCE_TYPE_LIST(DUMP_TYPE) | 513 # INSTANCE_TYPE_LIST(DUMP_TYPE) | 
| 377 # printf("}\n"); | 514 # printf("}\n"); | 
| 378 # } | 515 # } | 
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 494 self.map = map | 631 self.map = map | 
| 495 self.address = address | 632 self.address = address | 
| 496 | 633 | 
| 497 def Is(self, cls): | 634 def Is(self, cls): | 
| 498 return isinstance(self, cls) | 635 return isinstance(self, cls) | 
| 499 | 636 | 
| 500 def Print(self, p): | 637 def Print(self, p): | 
| 501 p.Print(str(self)) | 638 p.Print(str(self)) | 
| 502 | 639 | 
| 503 def __str__(self): | 640 def __str__(self): | 
| 504 return "HeapObject(%08x, %s)" % (self.address, | 641 return "HeapObject(%s, %s)" % (self.heap.reader.FormatIntPtr(self.address), | 
| 505 INSTANCE_TYPES[self.map.instance_type]) | 642 INSTANCE_TYPES[self.map.instance_type]) | 
| 506 | 643 | 
| 507 def ObjectField(self, offset): | 644 def ObjectField(self, offset): | 
| 508 field_value = self.heap.reader.ReadU32(self.address + offset) | 645 field_value = self.heap.reader.ReadUIntPtr(self.address + offset) | 
| 509 return self.heap.FindObjectOrSmi(field_value) | 646 return self.heap.FindObjectOrSmi(field_value) | 
| 510 | 647 | 
| 511 def SmiField(self, offset): | 648 def SmiField(self, offset): | 
| 512 field_value = self.heap.reader.ReadU32(self.address + offset) | 649 field_value = self.heap.reader.ReadUIntPtr(self.address + offset) | 
| 513 assert (field_value & 1) == 0 | 650 assert (field_value & 1) == 0 | 
| 514 return field_value / 2 | 651 return field_value / 2 | 
| 515 | 652 | 
| 516 | 653 | 
| 517 class Map(HeapObject): | 654 class Map(HeapObject): | 
| 518 INSTANCE_TYPE_OFFSET = 8 | 655 def InstanceTypeOffset(): | 
| 656 return self.heap.PointerSize() + self.heap.IntSize() | |
| 519 | 657 | 
| 520 def __init__(self, heap, map, address): | 658 def __init__(self, heap, map, address): | 
| 521 HeapObject.__init__(self, heap, map, address) | 659 HeapObject.__init__(self, heap, map, address) | 
| 522 self.instance_type = \ | 660 self.instance_type = \ | 
| 523 heap.reader.ReadU8(self.address + Map.INSTANCE_TYPE_OFFSET) | 661 heap.reader.ReadU8(self.address + self.InstanceTypeOffset()) | 
| 524 | 662 | 
| 525 | 663 | 
| 526 class String(HeapObject): | 664 class String(HeapObject): | 
| 527 LENGTH_OFFSET = 4 | 665 def LengthOffset(self): | 
| 666 return self.heap.PointerSize() | |
| 528 | 667 | 
| 529 def __init__(self, heap, map, address): | 668 def __init__(self, heap, map, address): | 
| 530 HeapObject.__init__(self, heap, map, address) | 669 HeapObject.__init__(self, heap, map, address) | 
| 531 self.length = self.SmiField(String.LENGTH_OFFSET) | 670 self.length = self.SmiField(self.LengthOffset()) | 
| 532 | 671 | 
| 533 def GetChars(self): | 672 def GetChars(self): | 
| 534 return "?string?" | 673 return "?string?" | 
| 535 | 674 | 
| 536 def Print(self, p): | 675 def Print(self, p): | 
| 537 p.Print(str(self)) | 676 p.Print(str(self)) | 
| 538 | 677 | 
| 539 def __str__(self): | 678 def __str__(self): | 
| 540 return "\"%s\"" % self.GetChars() | 679 return "\"%s\"" % self.GetChars() | 
| 541 | 680 | 
| 542 | 681 | 
| 543 class SeqString(String): | 682 class SeqString(String): | 
| 544 CHARS_OFFSET = 12 | 683 def CharsOffset(self): | 
| 684 return self.heap.PointerSize() * 3 | |
| 545 | 685 | 
| 546 def __init__(self, heap, map, address): | 686 def __init__(self, heap, map, address): | 
| 547 String.__init__(self, heap, map, address) | 687 String.__init__(self, heap, map, address) | 
| 548 self.chars = heap.reader.ReadBytes(self.address + SeqString.CHARS_OFFSET, | 688 self.chars = heap.reader.ReadBytes(self.address + self.CharsOffset(), | 
| 549 self.length) | 689 self.length) | 
| 550 | 690 | 
| 551 def GetChars(self): | 691 def GetChars(self): | 
| 552 return self.chars | 692 return self.chars | 
| 553 | 693 | 
| 554 | 694 | 
| 555 class ExternalString(String): | 695 class ExternalString(String): | 
| 696 # TODO(vegorov) fix ExternalString for X64 architecture | |
| 556 RESOURCE_OFFSET = 12 | 697 RESOURCE_OFFSET = 12 | 
| 557 | 698 | 
| 558 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4 | 699 WEBKIT_RESOUCE_STRING_IMPL_OFFSET = 4 | 
| 559 WEBKIT_STRING_IMPL_CHARS_OFFSET = 8 | 700 WEBKIT_STRING_IMPL_CHARS_OFFSET = 8 | 
| 560 | 701 | 
| 561 def __init__(self, heap, map, address): | 702 def __init__(self, heap, map, address): | 
| 562 String.__init__(self, heap, map, address) | 703 String.__init__(self, heap, map, address) | 
| 563 reader = heap.reader | 704 reader = heap.reader | 
| 564 self.resource = \ | 705 self.resource = \ | 
| 565 reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET) | 706 reader.ReadU32(self.address + ExternalString.RESOURCE_OFFSET) | 
| 566 self.chars = "?external string?" | 707 self.chars = "?external string?" | 
| 567 if not reader.IsValidAddress(self.resource): return | 708 if not reader.IsValidAddress(self.resource): return | 
| 568 string_impl_address = self.resource + \ | 709 string_impl_address = self.resource + \ | 
| 569 ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET | 710 ExternalString.WEBKIT_RESOUCE_STRING_IMPL_OFFSET | 
| 570 if not reader.IsValidAddress(string_impl_address): return | 711 if not reader.IsValidAddress(string_impl_address): return | 
| 571 string_impl = reader.ReadU32(string_impl_address) | 712 string_impl = reader.ReadU32(string_impl_address) | 
| 572 chars_ptr_address = string_impl + \ | 713 chars_ptr_address = string_impl + \ | 
| 573 ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET | 714 ExternalString.WEBKIT_STRING_IMPL_CHARS_OFFSET | 
| 574 if not reader.IsValidAddress(chars_ptr_address): return | 715 if not reader.IsValidAddress(chars_ptr_address): return | 
| 575 chars_ptr = reader.ReadU32(chars_ptr_address) | 716 chars_ptr = reader.ReadU32(chars_ptr_address) | 
| 576 if not reader.IsValidAddress(chars_ptr): return | 717 if not reader.IsValidAddress(chars_ptr): return | 
| 577 raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length) | 718 raw_chars = reader.ReadBytes(chars_ptr, 2 * self.length) | 
| 578 self.chars = codecs.getdecoder("utf16")(raw_chars)[0] | 719 self.chars = codecs.getdecoder("utf16")(raw_chars)[0] | 
| 579 | 720 | 
| 580 def GetChars(self): | 721 def GetChars(self): | 
| 581 return self.chars | 722 return self.chars | 
| 582 | 723 | 
| 583 | 724 | 
| 584 class ConsString(String): | 725 class ConsString(String): | 
| 585 LEFT_OFFSET = 12 | 726 def LeftOffset(self): | 
| 586 RIGHT_OFFSET = 16 | 727 return self.heap.PointerSize() * 3 | 
| 728 | |
| 729 def RightOffset(self): | |
| 730 return self.heap.PointerSize() * 4 | |
| 587 | 731 | 
| 588 def __init__(self, heap, map, address): | 732 def __init__(self, heap, map, address): | 
| 589 String.__init__(self, heap, map, address) | 733 String.__init__(self, heap, map, address) | 
| 590 self.left = self.ObjectField(ConsString.LEFT_OFFSET) | 734 self.left = self.ObjectField(self.LeftOffset()) | 
| 591 self.right = self.ObjectField(ConsString.RIGHT_OFFSET) | 735 self.right = self.ObjectField(self.RightOffset()) | 
| 592 | 736 | 
| 593 def GetChars(self): | 737 def GetChars(self): | 
| 594 return self.left.GetChars() + self.right.GetChars() | 738 return self.left.GetChars() + self.right.GetChars() | 
| 595 | 739 | 
| 596 | 740 | 
| 597 class Oddball(HeapObject): | 741 class Oddball(HeapObject): | 
| 598 TO_STRING_OFFSET = 4 | 742 def ToStringOffset(self): | 
| 743 return self.heap.PointerSize() | |
| 599 | 744 | 
| 600 def __init__(self, heap, map, address): | 745 def __init__(self, heap, map, address): | 
| 601 HeapObject.__init__(self, heap, map, address) | 746 HeapObject.__init__(self, heap, map, address) | 
| 602 self.to_string = self.ObjectField(Oddball.TO_STRING_OFFSET) | 747 self.to_string = self.ObjectField(self.ToStringOffset()) | 
| 603 | 748 | 
| 604 def Print(self, p): | 749 def Print(self, p): | 
| 605 p.Print(str(self)) | 750 p.Print(str(self)) | 
| 606 | 751 | 
| 607 def __str__(self): | 752 def __str__(self): | 
| 608 return "<%s>" % self.to_string.GetChars() | 753 return "<%s>" % self.to_string.GetChars() | 
| 609 | 754 | 
| 610 | 755 | 
| 611 class FixedArray(HeapObject): | 756 class FixedArray(HeapObject): | 
| 612 LENGTH_OFFSET = 4 | 757 def LengthOffset(self): | 
| 613 ELEMENTS_OFFSET = 8 | 758 return self.heap.PointerSize() | 
| 759 | |
| 760 def ElementsOffset(self): | |
| 761 return self.heap.PointerSize() * 2 | |
| 614 | 762 | 
| 615 def __init__(self, heap, map, address): | 763 def __init__(self, heap, map, address): | 
| 616 HeapObject.__init__(self, heap, map, address) | 764 HeapObject.__init__(self, heap, map, address) | 
| 617 self.length = self.SmiField(FixedArray.LENGTH_OFFSET) | 765 self.length = self.SmiField(self.LengthOffset()) | 
| 618 | 766 | 
| 619 def Print(self, p): | 767 def Print(self, p): | 
| 620 p.Print("FixedArray(%08x) {" % self.address) | 768 p.Print("FixedArray(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 
| 621 p.Indent() | 769 p.Indent() | 
| 622 p.Print("length: %d" % self.length) | 770 p.Print("length: %d" % self.length) | 
| 771 base_offset = self.ElementsOffset() | |
| 623 for i in xrange(self.length): | 772 for i in xrange(self.length): | 
| 624 offset = FixedArray.ELEMENTS_OFFSET + 4 * i | 773 offset = base_offset + 4 * i | 
| 625 p.Print("[%08d] = %s" % (i, self.ObjectField(offset))) | 774 p.Print("[%08d] = %s" % (i, self.ObjectField(offset))) | 
| 626 p.Dedent() | 775 p.Dedent() | 
| 627 p.Print("}") | 776 p.Print("}") | 
| 628 | 777 | 
| 629 def __str__(self): | 778 def __str__(self): | 
| 630 return "FixedArray(%08x, length=%d)" % (self.address, self.length) | 779 return "FixedArray(%08x, length=%d)" % (self.address, self.length) | 
| 631 | 780 | 
| 632 | 781 | 
| 633 class JSFunction(HeapObject): | 782 class JSFunction(HeapObject): | 
| 634 CODE_ENTRY_OFFSET = 12 | 783 def CodeEntryOffset(self): | 
| 635 SHARED_OFFSET = 20 | 784 return 3 * self.heap.PointerSize() | 
| 785 | |
| 786 def SharedOffset(self): | |
| 787 return 5 * self.heap.PointerSize() | |
| 636 | 788 | 
| 637 def __init__(self, heap, map, address): | 789 def __init__(self, heap, map, address): | 
| 638 HeapObject.__init__(self, heap, map, address) | 790 HeapObject.__init__(self, heap, map, address) | 
| 639 code_entry = \ | 791 code_entry = \ | 
| 640 heap.reader.ReadU32(self.address + JSFunction.CODE_ENTRY_OFFSET) | 792 heap.reader.ReadU32(self.address + self.CodeEntryOffset()) | 
| 641 self.code = heap.FindObject(code_entry - Code.ENTRY_OFFSET + 1) | 793 self.code = heap.FindObject(code_entry - Code.HeaderSize(heap) + 1) | 
| 642 self.shared = self.ObjectField(JSFunction.SHARED_OFFSET) | 794 self.shared = self.ObjectField(self.SharedOffset()) | 
| 643 | 795 | 
| 644 def Print(self, p): | 796 def Print(self, p): | 
| 645 source = "\n".join(" %s" % line for line in self._GetSource().split("\n")) | 797 source = "\n".join(" %s" % line for line in self._GetSource().split("\n")) | 
| 646 p.Print("JSFunction(%08x) {" % self.address) | 798 p.Print("JSFunction(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 
| 647 p.Indent() | 799 p.Indent() | 
| 648 p.Print("inferred name: %s" % self.shared.inferred_name) | 800 p.Print("inferred name: %s" % self.shared.inferred_name) | 
| 649 if self.shared.script.Is(Script) and self.shared.script.name.Is(String): | 801 if self.shared.script.Is(Script) and self.shared.script.name.Is(String): | 
| 650 p.Print("script name: %s" % self.shared.script.name) | 802 p.Print("script name: %s" % self.shared.script.name) | 
| 651 p.Print("source:") | 803 p.Print("source:") | 
| 652 p.PrintLines(self._GetSource().split("\n")) | 804 p.PrintLines(self._GetSource().split("\n")) | 
| 653 p.Print("code:") | 805 p.Print("code:") | 
| 654 self.code.Print(p) | 806 self.code.Print(p) | 
| 655 if self.code != self.shared.code: | 807 if self.code != self.shared.code: | 
| 656 p.Print("unoptimized code:") | 808 p.Print("unoptimized code:") | 
| 657 self.shared.code.Print(p) | 809 self.shared.code.Print(p) | 
| 658 p.Dedent() | 810 p.Dedent() | 
| 659 p.Print("}") | 811 p.Print("}") | 
| 660 | 812 | 
| 661 def __str__(self): | 813 def __str__(self): | 
| 662 inferred_name = "" | 814 inferred_name = "" | 
| 663 if self.shared.Is(SharedFunctionInfo): | 815 if self.shared.Is(SharedFunctionInfo): | 
| 664 inferred_name = self.shared.inferred_name | 816 inferred_name = self.shared.inferred_name | 
| 665 return "JSFunction(%08x, %s)" % (self.address, inferred_name) | 817 return "JSFunction(%s, %s)" % \ | 
| 818 (self.heap.reader.FormatIntPtr(self.address), inferred_name) | |
| 666 | 819 | 
| 667 def _GetSource(self): | 820 def _GetSource(self): | 
| 668 source = "?source?" | 821 source = "?source?" | 
| 669 start = self.shared.start_position | 822 start = self.shared.start_position | 
| 670 end = self.shared.end_position | 823 end = self.shared.end_position | 
| 671 if not self.shared.script.Is(Script): return source | 824 if not self.shared.script.Is(Script): return source | 
| 672 script_source = self.shared.script.source | 825 script_source = self.shared.script.source | 
| 673 if not script_source.Is(String): return source | 826 if not script_source.Is(String): return source | 
| 674 return script_source.GetChars()[start:end] | 827 return script_source.GetChars()[start:end] | 
| 675 | 828 | 
| 676 | 829 | 
| 677 class SharedFunctionInfo(HeapObject): | 830 class SharedFunctionInfo(HeapObject): | 
| 678 CODE_OFFSET = 2 * 4 | 831 def CodeOffset(self): | 
| 679 SCRIPT_OFFSET = 7 * 4 | 832 return 2 * self.heap.PointerSize() | 
| 680 INFERRED_NAME_OFFSET = 9 * 4 | 833 | 
| 681 START_POSITION_AND_TYPE_OFFSET = 17 * 4 | 834 def ScriptOffset(self): | 
| 682 END_POSITION_OFFSET = 18 * 4 | 835 return 7 * self.heap.PointerSize() | 
| 836 | |
| 837 def InferredNameOffset(self): | |
| 838 return 9 * self.heap.PointerSize() | |
| 839 | |
| 840 def EndPositionOffset(self): | |
| 841 return 12 * self.heap.PointerSize() + 4 * self.heap.IntSize() | |
| 842 | |
| 843 def StartPositionAndTypeOffset(self): | |
| 844 return 12 * self.heap.PointerSize() + 5 * self.heap.IntSize() | |
| 683 | 845 | 
| 684 def __init__(self, heap, map, address): | 846 def __init__(self, heap, map, address): | 
| 685 HeapObject.__init__(self, heap, map, address) | 847 HeapObject.__init__(self, heap, map, address) | 
| 686 self.code = self.ObjectField(SharedFunctionInfo.CODE_OFFSET) | 848 self.code = self.ObjectField(self.CodeOffset()) | 
| 687 self.script = self.ObjectField(SharedFunctionInfo.SCRIPT_OFFSET) | 849 self.script = self.ObjectField(self.ScriptOffset()) | 
| 688 self.inferred_name = \ | 850 self.inferred_name = self.ObjectField(self.InferredNameOffset()) | 
| 689 self.ObjectField(SharedFunctionInfo.INFERRED_NAME_OFFSET) | 851 if heap.PointerSize() == 8: | 
| 690 start_position_and_type = \ | 852 start_position_and_type = \ | 
| 691 self.SmiField(SharedFunctionInfo.START_POSITION_AND_TYPE_OFFSET) | 853 heap.reader.ReadU32(self.StartPositionAndTypeOffset()) | 
| 692 self.start_position = start_position_and_type >> 2 | 854 self.start_position = start_position_and_type >> 2 | 
| 693 self.end_position = self.SmiField(SharedFunctionInfo.END_POSITION_OFFSET) | 855 pseudo_smi_end_position = \ | 
| 856 heap.reader.ReadU32(self.EndPositionOffset()) | |
| 857 self.end_position = pseudo_smi_end_position >> 2 | |
| 858 else: | |
| 859 start_position_and_type = \ | |
| 860 self.SmiField(self.StartPositionAndTypeOffset()) | |
| 861 self.start_position = start_position_and_type >> 2 | |
| 862 self.end_position = \ | |
| 863 self.SmiField(self.EndPositionOffset()) | |
| 694 | 864 | 
| 695 | 865 | 
| 696 class Script(HeapObject): | 866 class Script(HeapObject): | 
| 697 SOURCE_OFFSET = 4 | 867 def SourceOffset(self): | 
| 698 NAME_OFFSET = 8 | 868 return self.heap.PointerSize() | 
| 869 | |
| 870 def NameOffset(self): | |
| 871 return self.SourceOffset() + self.heap.PointerSize() | |
| 699 | 872 | 
| 700 def __init__(self, heap, map, address): | 873 def __init__(self, heap, map, address): | 
| 701 HeapObject.__init__(self, heap, map, address) | 874 HeapObject.__init__(self, heap, map, address) | 
| 702 self.source = self.ObjectField(Script.SOURCE_OFFSET) | 875 self.source = self.ObjectField(self.SourceOffset()) | 
| 703 self.name = self.ObjectField(Script.NAME_OFFSET) | 876 self.name = self.ObjectField(self.NameOffset()) | 
| 704 | 877 | 
| 705 | 878 | 
| 706 class Code(HeapObject): | 879 class Code(HeapObject): | 
| 707 INSTRUCTION_SIZE_OFFSET = 4 | 880 CODE_ALIGNMENT_MASK = (1 << 5) - 1 | 
| 708 ENTRY_OFFSET = 32 | 881 | 
| 882 def InstructionSizeOffset(self): | |
| 883 return self.heap.PointerSize() | |
| 884 | |
| 885 @staticmethod | |
| 886 def HeaderSize(heap): | |
| 887 return (heap.PointerSize() + heap.IntSize() + \ | |
| 888 4 * heap.PointerSize() + 3 * heap.IntSize() + \ | |
| 889 CODE_ALIGNMENT_MASK) & ~CODE_ALIGNMENT_MASK | |
| 709 | 890 | 
| 710 def __init__(self, heap, map, address): | 891 def __init__(self, heap, map, address): | 
| 711 HeapObject.__init__(self, heap, map, address) | 892 HeapObject.__init__(self, heap, map, address) | 
| 712 self.entry = self.address + Code.ENTRY_OFFSET | 893 self.entry = self.address + Code.HeaderSize(heap) | 
| 713 self.instruction_size = \ | 894 self.instruction_size = \ | 
| 714 heap.reader.ReadU32(self.address + Code.INSTRUCTION_SIZE_OFFSET) | 895 heap.reader.ReadU32(self.address + self.InstructionSizeOffset()) | 
| 715 | 896 | 
| 716 def Print(self, p): | 897 def Print(self, p): | 
| 717 lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size) | 898 lines = self.heap.reader.GetDisasmLines(self.entry, self.instruction_size) | 
| 718 p.Print("Code(%08x) {" % self.address) | 899 p.Print("Code(%s) {" % self.heap.reader.FormatIntPtr(self.address)) | 
| 719 p.Indent() | 900 p.Indent() | 
| 720 p.Print("instruction_size: %d" % self.instruction_size) | 901 p.Print("instruction_size: %d" % self.instruction_size) | 
| 721 p.PrintLines(self._FormatLine(line) for line in lines) | 902 p.PrintLines(self._FormatLine(line) for line in lines) | 
| 722 p.Dedent() | 903 p.Dedent() | 
| 723 p.Print("}") | 904 p.Print("}") | 
| 724 | 905 | 
| 725 def _FormatLine(self, line): | 906 def _FormatLine(self, line): | 
| 726 return FormatDisasmLine(self.entry, self.heap, line) | 907 return FormatDisasmLine(self.entry, self.heap, line) | 
| 727 | 908 | 
| 728 | 909 | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 760 def FindObjectOrSmi(self, tagged_address): | 941 def FindObjectOrSmi(self, tagged_address): | 
| 761 if (tagged_address & 1) == 0: return tagged_address / 2 | 942 if (tagged_address & 1) == 0: return tagged_address / 2 | 
| 762 return self.FindObject(tagged_address) | 943 return self.FindObject(tagged_address) | 
| 763 | 944 | 
| 764 def FindObject(self, tagged_address): | 945 def FindObject(self, tagged_address): | 
| 765 if tagged_address in self.objects: | 946 if tagged_address in self.objects: | 
| 766 return self.objects[tagged_address] | 947 return self.objects[tagged_address] | 
| 767 if (tagged_address & 1) != 1: return None | 948 if (tagged_address & 1) != 1: return None | 
| 768 address = tagged_address - 1 | 949 address = tagged_address - 1 | 
| 769 if not self.reader.IsValidAddress(address): return None | 950 if not self.reader.IsValidAddress(address): return None | 
| 770 map_tagged_address = self.reader.ReadU32(address) | 951 map_tagged_address = self.reader.ReadUIntPtr(address) | 
| 771 if tagged_address == map_tagged_address: | 952 if tagged_address == map_tagged_address: | 
| 772 # Meta map? | 953 # Meta map? | 
| 773 meta_map = Map(self, None, address) | 954 meta_map = Map(self, None, address) | 
| 774 instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type) | 955 instance_type_name = INSTANCE_TYPES.get(meta_map.instance_type) | 
| 775 if instance_type_name != "MAP_TYPE": return None | 956 if instance_type_name != "MAP_TYPE": return None | 
| 776 meta_map.map = meta_map | 957 meta_map.map = meta_map | 
| 777 object = meta_map | 958 object = meta_map | 
| 778 else: | 959 else: | 
| 779 map = self.FindObject(map_tagged_address) | 960 map = self.FindObject(map_tagged_address) | 
| 780 if map is None: return None | 961 if map is None: return None | 
| 781 instance_type_name = INSTANCE_TYPES.get(map.instance_type) | 962 instance_type_name = INSTANCE_TYPES.get(map.instance_type) | 
| 782 if instance_type_name is None: return None | 963 if instance_type_name is None: return None | 
| 783 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject) | 964 cls = V8Heap.CLASS_MAP.get(instance_type_name, HeapObject) | 
| 784 object = cls(self, map, address) | 965 object = cls(self, map, address) | 
| 785 self.objects[tagged_address] = object | 966 self.objects[tagged_address] = object | 
| 786 return object | 967 return object | 
| 787 | 968 | 
| 969 def PointerSize(self): | |
| 970 return self.reader.PointerSize() | |
| 971 | |
| 972 | |
| 788 | 973 | 
| 789 EIP_PROXIMITY = 64 | 974 EIP_PROXIMITY = 64 | 
| 790 | 975 | 
| 976 CONTEXT_FOR_ARCH = { | |
| 977 MD_CPU_ARCHITECTURE_AMD64: | |
| 978 ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp', 'rip'], | |
| 979 MD_CPU_ARCHITECTURE_X86: | |
| 980 ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'eip'] | |
| 981 } | |
| 791 | 982 | 
| 792 def AnalyzeMinidump(options, minidump_name): | 983 def AnalyzeMinidump(options, minidump_name): | 
| 793 reader = MinidumpReader(options, minidump_name) | 984 reader = MinidumpReader(options, minidump_name) | 
| 794 DebugPrint("========================================") | 985 DebugPrint("========================================") | 
| 795 if reader.exception is None: | 986 if reader.exception is None: | 
| 796 print "Minidump has no exception info" | 987 print "Minidump has no exception info" | 
| 797 return | 988 return | 
| 798 print "Exception info:" | 989 print "Exception info:" | 
| 799 exception_thread = reader.thread_map[reader.exception.thread_id] | 990 exception_thread = reader.thread_map[reader.exception.thread_id] | 
| 800 print " thread id: %d" % exception_thread.id | 991 print " thread id: %d" % exception_thread.id | 
| 801 print " code: %08X" % reader.exception.exception.code | 992 print " code: %08X" % reader.exception.exception.code | 
| 802 print " context:" | 993 print " context:" | 
| 803 print " eax: %08x" % reader.exception_context.eax | 994 for r in CONTEXT_FOR_ARCH[reader.arch]: | 
| 804 print " ebx: %08x" % reader.exception_context.ebx | 995 print " %s: %s" % (r, reader.FormatIntPtr(reader.Register(r))) | 
| 805 print " ecx: %08x" % reader.exception_context.ecx | |
| 806 print " edx: %08x" % reader.exception_context.edx | |
| 807 print " edi: %08x" % reader.exception_context.edi | |
| 808 print " esi: %08x" % reader.exception_context.esi | |
| 809 print " ebp: %08x" % reader.exception_context.ebp | |
| 810 print " esp: %08x" % reader.exception_context.esp | |
| 811 print " eip: %08x" % reader.exception_context.eip | |
| 812 # TODO(vitalyr): decode eflags. | 996 # TODO(vitalyr): decode eflags. | 
| 813 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] | 997 print " eflags: %s" % bin(reader.exception_context.eflags)[2:] | 
| 814 print | 998 print | 
| 815 | 999 | 
| 1000 stack_top = reader.ExceptionSP() | |
| 816 stack_bottom = exception_thread.stack.start + \ | 1001 stack_bottom = exception_thread.stack.start + \ | 
| 817 exception_thread.stack.memory.data_size | 1002 exception_thread.stack.memory.data_size | 
| 818 stack_map = {reader.exception_context.eip: -1} | 1003 stack_map = {reader.ExceptionIP(): -1} | 
| 819 for slot in xrange(reader.exception_context.esp, stack_bottom, 4): | 1004 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 
| 820 maybe_address = reader.ReadU32(slot) | 1005 maybe_address = reader.ReadUIntPtr(slot) | 
| 821 if not maybe_address in stack_map: | 1006 if not maybe_address in stack_map: | 
| 822 stack_map[maybe_address] = slot | 1007 stack_map[maybe_address] = slot | 
| 823 heap = V8Heap(reader, stack_map) | 1008 heap = V8Heap(reader, stack_map) | 
| 824 | 1009 | 
| 825 print "Disassembly around exception.eip:" | 1010 print "Disassembly around exception.eip:" | 
| 826 start = reader.exception_context.eip - EIP_PROXIMITY | 1011 start = reader.ExceptionIP() - EIP_PROXIMITY | 
| 827 lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY) | 1012 lines = reader.GetDisasmLines(start, 2 * EIP_PROXIMITY) | 
| 828 for line in lines: | 1013 for line in lines: | 
| 829 print FormatDisasmLine(start, heap, line) | 1014 print FormatDisasmLine(start, heap, line) | 
| 830 print | 1015 print | 
| 831 | 1016 | 
| 832 print "Annotated stack (from exception.esp to bottom):" | 1017 print "Annotated stack (from exception.esp to bottom):" | 
| 833 for slot in xrange(reader.exception_context.esp, stack_bottom, 4): | 1018 for slot in xrange(stack_top, stack_bottom, reader.PointerSize()): | 
| 834 maybe_address = reader.ReadU32(slot) | 1019 maybe_address = reader.ReadUIntPtr(slot) | 
| 835 heap_object = heap.FindObject(maybe_address) | 1020 heap_object = heap.FindObject(maybe_address) | 
| 836 print "%08x: %08x" % (slot, maybe_address) | 1021 print "%s: %s" % (reader.FormatIntPtr(slot), | 
| 1022 reader.FormatIntPtr(maybe_address)) | |
| 837 if heap_object: | 1023 if heap_object: | 
| 838 heap_object.Print(Printer()) | 1024 heap_object.Print(Printer()) | 
| 839 print | 1025 print | 
| 840 | 1026 | 
| 841 reader.Dispose() | 1027 reader.Dispose() | 
| 842 | 1028 | 
| 843 | 1029 | 
| 844 if __name__ == "__main__": | 1030 if __name__ == "__main__": | 
| 845 parser = optparse.OptionParser(USAGE) | 1031 parser = optparse.OptionParser(USAGE) | 
| 846 options, args = parser.parse_args() | 1032 options, args = parser.parse_args() | 
| 847 if len(args) != 1: | 1033 if len(args) != 1: | 
| 848 parser.print_help() | 1034 parser.print_help() | 
| 849 sys.exit(1) | 1035 sys.exit(1) | 
| 850 AnalyzeMinidump(options, args[0]) | 1036 AnalyzeMinidump(options, args[0]) | 
| OLD | NEW |