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 |