2005-09-27 Jeff Johnston * libunwind-frame.c (libunwind_frame_cache): Save the current stack pointer in the cache. (libunwind_sigtramp_frame_this_id): New function. (libunwind_sigtramp_frame_unwind): New unwinder. (libunwind_sigtramp_frame_sniffer): Return libunwind_sigtramp_frame_unwind address. * libunwind-frame.h (libunwind_sigtramp_frame_this_id): New prototype. * ia64-tdep.c (ia64_libunwind_sigtramp_frame_this_id): Calculate the base address using the current stack pointer plus a fixed offset. 2007-10-14 Jan Kratochvil Port to GDB-6.7. 2008-02-24 Jan Kratochvil Port to GDB-6.8pre. 2008-04-16 Yi Zhan Fix a compilation error on a typo. Index: gdb-6.8.50.20081128/gdb/libunwind-frame.c =================================================================== --- gdb-6.8.50.20081128.orig/gdb/libunwind-frame.c 2008-05-06 20:37:46.000000000 +0200 +++ gdb-6.8.50.20081128/gdb/libunwind-frame.c 2008-12-02 19:46:26.000000000 +0100 @@ -61,6 +61,7 @@ static unw_word_t (*unw_find_dyn_list_p) struct libunwind_frame_cache { CORE_ADDR base; + CORE_ADDR sp; CORE_ADDR func_addr; unw_cursor_t cursor; unw_addr_space_t as; @@ -133,6 +134,7 @@ libunwind_frame_cache (struct frame_info unw_accessors_t *acc; unw_addr_space_t as; unw_word_t fp; + unw_word_t sp; unw_regnum_t uw_sp_regnum; struct libunwind_frame_cache *cache; struct libunwind_descr *descr; @@ -174,14 +176,30 @@ libunwind_frame_cache (struct frame_info : __LITTLE_ENDIAN); unw_init_remote_p (&cache->cursor, as, this_frame); + + /* For the base address, we have a small problem. The majority + of the time, we can get the stack pointer of the previous + frame to use as a frame pointer. In the case where we have + a signal trampoline, the stack may change due to a sigaltstack + being set up. In that case, the normal mechanism will give us + an address in the regular stack which is not at the end of the + sigaltstack as we want. To handle this, we record the stack + address so the caller may calculate a more correct base address + to use. */ + uw_sp_regnum = descr->gdb2uw (gdbarch_sp_regnum (gdbarch)); + ret = unw_get_reg_p (&cache->cursor, uw_sp_regnum, &sp); + if (ret < 0) + { + unw_destroy_addr_space_p (as); + error (_("Can't get libunwind sp register.")); + } + if (unw_step_p (&cache->cursor) < 0) { unw_destroy_addr_space_p (as); return NULL; } - /* To get base address, get sp from previous frame. */ - uw_sp_regnum = descr->gdb2uw (gdbarch_sp_regnum (gdbarch)); ret = unw_get_reg_p (&cache->cursor, uw_sp_regnum, &fp); if (ret < 0) { @@ -189,6 +207,7 @@ libunwind_frame_cache (struct frame_info error (_("Can't get libunwind sp register.")); } + cache->sp = (CORE_ADDR)sp; cache->base = (CORE_ADDR)fp; cache->as = as; @@ -376,6 +395,31 @@ libunwind_search_unwind_table (void *as, di, pi, need_unwind_info, args); } +void +libunwind_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct libunwind_frame_cache *cache = + libunwind_frame_cache (this_frame, this_cache); + + /* Unlike a regular frame, we can't use the normal frame pointer + mechanism because a sigaltstack may have been used. Instead, + we return the current stack pointer for the caller to use + to calculate the base address. */ + if (cache != NULL) + (*this_id) = frame_id_build (cache->sp, cache->func_addr); + else + (*this_id) = null_frame_id; +} + +static const struct frame_unwind libunwind_sigtramp_frame_unwind = +{ + SIGTRAMP_FRAME, + libunwind_sigtramp_frame_this_id, + libunwind_frame_prev_register +}; + /* Verify if we are in a sigtramp frame and we can use libunwind to unwind. */ int libunwind_sigtramp_frame_sniffer (const struct frame_unwind *self, Index: gdb-6.8.50.20081128/gdb/libunwind-frame.h =================================================================== --- gdb-6.8.50.20081128.orig/gdb/libunwind-frame.h 2008-05-06 20:37:46.000000000 +0200 +++ gdb-6.8.50.20081128/gdb/libunwind-frame.h 2008-12-02 19:38:55.000000000 +0100 @@ -52,6 +52,9 @@ void libunwind_frame_set_descr (struct g void libunwind_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id); +void libunwind_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id); struct value *libunwind_frame_prev_register (struct frame_info *this_frame, void **this_cache, int regnum); void libunwind_frame_dealloc_cache (struct frame_info *self, void *cache); Index: gdb-6.8.50.20081128/gdb/ia64-tdep.c =================================================================== --- gdb-6.8.50.20081128.orig/gdb/ia64-tdep.c 2008-12-02 19:04:32.000000000 +0100 +++ gdb-6.8.50.20081128/gdb/ia64-tdep.c 2008-12-02 21:09:46.000000000 +0100 @@ -2964,7 +2964,7 @@ ia64_libunwind_sigtramp_frame_this_id (s struct frame_id id; CORE_ADDR prev_ip; - libunwind_frame_this_id (this_frame, this_cache, &id); + libunwind_sigtramp_frame_this_id (this_frame, this_cache, &id); if (frame_id_eq (id, null_frame_id)) { (*this_id) = null_frame_id; @@ -2976,8 +2976,14 @@ ia64_libunwind_sigtramp_frame_this_id (s get_frame_register (this_frame, IA64_BSP_REGNUM, buf); bsp = extract_unsigned_integer (buf, 8); - /* For a sigtramp frame, we don't make the check for previous ip being 0. */ - (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp); + /* For a sigtramp frame, we don't make the check for previous ip being 0. + We also must calculate the frame pointer because libunwind will give + us back the current stack pointer instead of the frame pointer since + it cannot figure this out when in a sigaltstack. We make a basic + assumption of 16 (default size) + 8 bytes for sigcontext address. + FIXME: if libunwind were to export the frame pointer address, we + could eliminate the assumption and get the actual value. */ + (*this_id) = frame_id_build_special (id.stack_addr + 24, id.code_addr, bsp); if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog,