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. Index: gdb-6.7/gdb/libunwind-frame.c =================================================================== --- gdb-6.7.orig/gdb/libunwind-frame.c 2007-10-15 00:08:30.000000000 +0200 +++ gdb-6.7/gdb/libunwind-frame.c 2007-10-15 00:13:29.000000000 +0200 @@ -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; @@ -134,7 +135,7 @@ libunwind_frame_cache (struct frame_info unw_accessors_t *acc; unw_addr_space_t as; unw_cursor_t *cursor_addr; - unw_word_t fp; + unw_word_t fp, sp; unw_regnum_t uw_sp_regnum; struct libunwind_frame_cache *cache; struct libunwind_descr *descr; @@ -183,14 +184,29 @@ libunwind_frame_cache (struct frame_info else /* make copy */ cache->cursor = *cursor_addr; + /* 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 (current_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 (current_gdbarch)); ret = unw_get_reg_p (&cache->cursor, uw_sp_regnum, &fp); if (ret < 0) { @@ -198,6 +214,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; @@ -402,6 +419,31 @@ libunwind_search_unwind_table (void *as, di, pi, need_unwind_info, args); } +void +libunwind_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct libunwind_frame_cache *cache = + libunwind_frame_cache (next_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. */ const struct frame_unwind * libunwind_sigtramp_frame_sniffer (struct frame_info *next_frame) @@ -439,7 +481,7 @@ libunwind_sigtramp_frame_sniffer (struct ret = unw_is_signal_frame_p (&cursor); unw_destroy_addr_space_p (as); if (ret > 0) - return &libunwind_frame_unwind; + return &libunwind_sigtramp_frame_unwind; return NULL; } Index: gdb-6.7/gdb/libunwind-frame.h =================================================================== --- gdb-6.7.orig/gdb/libunwind-frame.h 2007-10-15 00:05:20.000000000 +0200 +++ gdb-6.7/gdb/libunwind-frame.h 2007-10-15 00:08:36.000000000 +0200 @@ -48,6 +48,9 @@ void libunwind_frame_set_descr (struct g void libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache, struct frame_id *this_id); +void libunwind_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id); void libunwind_frame_prev_register (struct frame_info *next_frame, void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp, CORE_ADDR *addrp, Index: gdb-6.7/gdb/ia64-tdep.c =================================================================== --- gdb-6.7.orig/gdb/ia64-tdep.c 2007-10-15 00:05:20.000000000 +0200 +++ gdb-6.7/gdb/ia64-tdep.c 2007-10-15 00:08:36.000000000 +0200 @@ -2968,7 +2968,7 @@ ia64_libunwind_sigtramp_frame_this_id (s struct frame_id id; CORE_ADDR prev_ip; - libunwind_frame_this_id (next_frame, this_cache, &id); + libunwind_sigtramp_frame_this_id (next_frame, this_cache, &id); if (frame_id_eq (id, null_frame_id)) { (*this_id) = null_frame_id; @@ -2980,8 +2980,14 @@ ia64_libunwind_sigtramp_frame_this_id (s frame_unwind_register (next_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,