From 872761f485e2b7d1a0c76fa7aab96b4c13ae941b Mon Sep 17 00:00:00 2001 From: Michael Snyder Date: Mon, 17 Aug 2009 18:23:45 +0000 Subject: [PATCH] 2009-08-17 Michael Snyder * amd64-tdep.c: Add a frame unwinder for function epilogues. (amd64_in_function_epilogue_p): New function. (amd64_epilogue_frame_sniffer): New function. (amd64_epilogue_frame_cache): New function. (amd64_epilogue_frame_this_id): New function. (amd64_epilogue_frame_unwind): New struct frame_unwind. (amd64_init_abi): Hook the new unwinder. * amd64-linux-tdep.c (amd64_linux_init_abi): Set gdbarch to use SVR4 method for skip_trampoline_code. --- gdb/ChangeLog | 13 ++++++ gdb/amd64-linux-tdep.c | 3 ++ gdb/amd64-tdep.c | 89 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3a02f7d6a54..d88dfca3752 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2009-08-17 Michael Snyder + + * amd64-tdep.c: Add a frame unwinder for function epilogues. + (amd64_in_function_epilogue_p): New function. + (amd64_epilogue_frame_sniffer): New function. + (amd64_epilogue_frame_cache): New function. + (amd64_epilogue_frame_this_id): New function. + (amd64_epilogue_frame_unwind): New struct frame_unwind. + (amd64_init_abi): Hook the new unwinder. + + * amd64-linux-tdep.c (amd64_linux_init_abi): Set gdbarch to use + SVR4 method for skip_trampoline_code. + 2009-08-17 Pedro Alves > * objfiles.c (objfile_relocate): Relocate the entry point before diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index e7f966b5cc2..dcfdb38fedf 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -1415,6 +1415,9 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + /* GNU/Linux uses SVR4-style shared libraries. */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + /* Displaced stepping. */ set_gdbarch_displaced_step_copy_insn (gdbarch, amd64_displaced_step_copy_insn); diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 187b9cefbfb..51560cf3382 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -1887,6 +1887,89 @@ static const struct frame_base amd64_frame_base = amd64_frame_base_address }; +/* Normal frames, but in a function epilogue. */ + +/* The epilogue is defined here as the 'ret' instruction, which will + follow any instruction such as 'leave' or 'pop %ebp' that destroys + the function's stack frame. */ + +static int +amd64_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + gdb_byte insn; + + if (target_read_memory (pc, &insn, 1)) + return 0; /* Can't read memory at pc. */ + + if (insn != 0xc3) /* 'ret' instruction. */ + return 0; + + return 1; +} + +static int +amd64_epilogue_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + if (frame_relative_level (this_frame) == 0) + return amd64_in_function_epilogue_p (get_frame_arch (this_frame), + get_frame_pc (this_frame)); + else + return 0; +} + +static struct amd64_frame_cache * +amd64_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct amd64_frame_cache *cache; + gdb_byte buf[4]; + + if (*this_cache) + return *this_cache; + + cache = amd64_alloc_frame_cache (); + *this_cache = cache; + + /* Cache base will be %esp plus cache->sp_offset (-8). */ + get_frame_register (this_frame, AMD64_RSP_REGNUM, buf); + cache->base = extract_unsigned_integer (buf, 8, + byte_order) + cache->sp_offset; + + /* Cache pc will be the frame func. */ + cache->pc = get_frame_pc (this_frame); + + /* The saved %esp will be at cache->base plus 16. */ + cache->saved_sp = cache->base + 16; + + /* The saved %eip will be at cache->base plus 8. */ + cache->saved_regs[AMD64_RIP_REGNUM] = cache->base + 8; + + return cache; +} + +static void +amd64_epilogue_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct amd64_frame_cache *cache = amd64_epilogue_frame_cache (this_frame, + this_cache); + + (*this_id) = frame_id_build (cache->base + 8, cache->pc); +} + +static const struct frame_unwind amd64_epilogue_frame_unwind = +{ + NORMAL_FRAME, + amd64_epilogue_frame_this_id, + amd64_frame_prev_register, + NULL, + amd64_epilogue_frame_sniffer +}; + static struct frame_id amd64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) { @@ -2065,6 +2148,12 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_dummy_id (gdbarch, amd64_dummy_id); + /* Hook the function epilogue frame unwinder. This unwinder is + appended to the list first, so that it supercedes the other + unwinders in function epilogues. */ + frame_unwind_prepend_unwinder (gdbarch, &amd64_epilogue_frame_unwind); + + /* Hook the prologue-based frame unwinders. */ frame_unwind_append_unwinder (gdbarch, &amd64_sigtramp_frame_unwind); frame_unwind_append_unwinder (gdbarch, &amd64_frame_unwind); frame_base_set_default (gdbarch, &amd64_frame_base); -- 2.30.2