Chromium Code Reviews| 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 |