diff options
author | Michael Snyder <msnyder@vmware.com> | 2009-08-17 18:23:45 +0000 |
---|---|---|
committer | Michael Snyder <msnyder@vmware.com> | 2009-08-17 18:23:45 +0000 |
commit | 872761f485e2b7d1a0c76fa7aab96b4c13ae941b (patch) | |
tree | d9471e9830d3632459efb2a6e42bb7d45bb2de77 | |
parent | 987499b2425ad953bf823e03b75e45381a4e0b4a (diff) | |
download | gdb-872761f485e2b7d1a0c76fa7aab96b4c13ae941b.zip gdb-872761f485e2b7d1a0c76fa7aab96b4c13ae941b.tar.gz gdb-872761f485e2b7d1a0c76fa7aab96b4c13ae941b.tar.bz2 |
2009-08-17 Michael Snyder <msnyder@vmware.com>
* 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.
-rw-r--r-- | gdb/ChangeLog | 13 | ||||
-rw-r--r-- | gdb/amd64-linux-tdep.c | 3 | ||||
-rw-r--r-- | gdb/amd64-tdep.c | 89 |
3 files changed, 105 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3a02f7d..d88dfca 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2009-08-17 Michael Snyder <msnyder@vmware.com> + + * 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 <pedro@codesourcery.com>> * objfiles.c (objfile_relocate): Relocate the entry point before diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index e7f966b..dcfdb38 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 187b9ce..51560cf 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); |