|
| 1 | +# Add a simple unwinder which, on x64, walks frame pointers when there |
| 2 | +# is no source information available. |
| 3 | + |
| 4 | +python |
| 5 | + |
| 6 | +from gdb.unwinder import Unwinder |
| 7 | + |
| 8 | +class V8UnwinderFrameId(object): |
| 9 | + def __init__(self, sp, pc): |
| 10 | + self.sp = sp |
| 11 | + self.pc = pc |
| 12 | + |
| 13 | +class V8Unwinder(Unwinder): |
| 14 | + def __init__(self): |
| 15 | + super(V8Unwinder, self).__init__("V8Unwinder") |
| 16 | + self.enabled = True |
| 17 | + |
| 18 | + def __call__(self, pending_frame): |
| 19 | + try: |
| 20 | + # Only supported on x64. |
| 21 | + if gdb.selected_inferior().architecture().name() != "i386:x86-64": |
| 22 | + return None |
| 23 | + |
| 24 | + pc = pending_frame.read_register("rip") |
| 25 | + sym_and_line = gdb.current_progspace().find_pc_line(int(pc)) |
| 26 | + |
| 27 | + if sym_and_line.symtab is not None: |
| 28 | + return None |
| 29 | + fp = pending_frame.read_register("rbp").reinterpret_cast( |
| 30 | + gdb.lookup_type("void").pointer().pointer()) |
| 31 | + |
| 32 | + next_sp = fp |
| 33 | + next_fp = fp.dereference() |
| 34 | + next_pc = (fp+1).dereference() |
| 35 | + |
| 36 | + frame_info = V8UnwinderFrameId(next_sp, next_pc) |
| 37 | + |
| 38 | + # create_unwind_info seems to sometimes have issues accessing |
| 39 | + # the frame_info if it's not first accessed in Python. |
| 40 | + _lol_gdb_workaround = frame_info.pc + 1 |
| 41 | + |
| 42 | + unwind_info = pending_frame.create_unwind_info(frame_info) |
| 43 | + unwind_info.add_saved_register("rsp", next_sp) |
| 44 | + unwind_info.add_saved_register("rip", next_pc) |
| 45 | + unwind_info.add_saved_register("rbp", next_fp) |
| 46 | + return unwind_info |
| 47 | + except Exception as e: |
| 48 | + return None |
| 49 | + |
| 50 | +gdb.unwinder.register_unwinder(None, V8Unwinder(), replace=True) |
| 51 | + |
| 52 | +end |
0 commit comments