diff --git a/include/dwarf.h b/include/dwarf.h index 37b5ec1..53c803b 100644 --- a/include/dwarf.h +++ b/include/dwarf.h @@ -247,6 +247,7 @@ typedef struct dwarf_reg_state unsigned short lru_chain; /* used for least-recently-used chain */ unsigned short coll_chain; /* used for hash collisions */ unsigned short hint; /* hint for next rs to try (or -1) */ + unsigned short signal_frame; /* optional machine-dependent signal info */ } dwarf_reg_state_t; @@ -266,6 +267,7 @@ typedef struct dwarf_cie_info uint8_t lsda_encoding; unsigned int sized_augmentation : 1; unsigned int have_abi_marker : 1; + unsigned int signal_frame : 1; } dwarf_cie_info_t; diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h index 3424d86..2e1c428 100644 --- a/include/tdep-arm/libunwind_i.h +++ b/include/tdep-arm/libunwind_i.h @@ -217,6 +217,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-hppa/libunwind_i.h b/include/tdep-hppa/libunwind_i.h index 553e97d..d89cc65 100644 --- a/include/tdep-hppa/libunwind_i.h +++ b/include/tdep-hppa/libunwind_i.h @@ -224,6 +224,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-ia64/libunwind_i.h b/include/tdep-ia64/libunwind_i.h index 552c949..4936d51 100644 --- a/include/tdep-ia64/libunwind_i.h +++ b/include/tdep-ia64/libunwind_i.h @@ -220,6 +220,9 @@ struct ia64_global_unwind_state #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_get_as(c) ((c)->as) #define tdep_get_as_arg(c) ((c)->as_arg) #define tdep_get_ip(c) ((c)->ip) diff --git a/include/tdep-mips/libunwind_i.h b/include/tdep-mips/libunwind_i.h index c2f756a..298fae8 100644 --- a/include/tdep-mips/libunwind_i.h +++ b/include/tdep-mips/libunwind_i.h @@ -279,6 +279,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-ppc32/libunwind_i.h b/include/tdep-ppc32/libunwind_i.h index 05dd135..b963bca 100644 --- a/include/tdep-ppc32/libunwind_i.h +++ b/include/tdep-ppc32/libunwind_i.h @@ -256,6 +256,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_get_func_addr UNW_OBJ(get_func_addr) #ifdef UNW_LOCAL_ONLY diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h index 192a034..799b511 100644 --- a/include/tdep-ppc64/libunwind_i.h +++ b/include/tdep-ppc64/libunwind_i.h @@ -256,6 +256,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_get_func_addr UNW_OBJ(get_func_addr) #ifdef UNW_LOCAL_ONLY diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h index 9af007d..bed8cbf 100644 --- a/include/tdep-x86/libunwind_i.h +++ b/include/tdep-x86/libunwind_i.h @@ -240,6 +240,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#define tdep_fetch_frame(c,ip,n) do {} while(0) +#define tdep_cache_frame(c,rs) do {} while(0) +#define tdep_reuse_frame(c,rs) do {} while(0) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h index f6a0289..c022725 100644 --- a/include/tdep-x86_64/libunwind_i.h +++ b/include/tdep-x86_64/libunwind_i.h @@ -163,6 +163,15 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_fpreg UNW_OBJ(access_fpreg) +#if __linux__ +# define tdep_fetch_frame UNW_OBJ(fetch_frame) +# define tdep_cache_frame UNW_OBJ(cache_frame) +# define tdep_reuse_frame UNW_OBJ(reuse_frame) +#else +# define tdep_fetch_frame(c,ip,n) do {} while(0) +# define tdep_cache_frame(c,rs) do {} while(0) +# define tdep_reuse_frame(c,rs) do {} while(0) +#endif #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ @@ -196,5 +205,14 @@ extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, int write); extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, int write); +#if __linux__ +extern void tdep_fetch_frame (struct dwarf_cursor *c, unw_word_t ip, + int need_unwind_info); +extern void tdep_cache_frame (struct dwarf_cursor *c, + struct dwarf_reg_state *rs); +extern void tdep_reuse_frame (struct dwarf_cursor *c, + struct dwarf_reg_state *rs); +#endif + #endif /* X86_64_LIBUNWIND_I_H */ diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c index 16e36ee..8659624 100644 --- a/src/dwarf/Gfde.c +++ b/src/dwarf/Gfde.c @@ -187,6 +187,9 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, break; case 'S': + /* This is a signal frame. */ + dci->signal_frame = 1; + /* Temporarily set it to one so dwarf_parse_fde() knows that it should fetch the actual ABI/TAG pair from the FDE. */ dci->have_abi_marker = 1; diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index db64b92..ccb710a 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -400,6 +400,11 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info) c->pi_valid = 1; c->pi_is_dynamic = dynamic; + + /* Let system/machine-dependent code determine frame-specific attributes. */ + if (ret >= 0) + tdep_fetch_frame (c, ip, need_unwind_info); + return ret; } @@ -604,6 +609,8 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c) rs->hint = 0; rs->ip = c->ip; rs->ret_addr_column = c->ret_addr_column; + rs->signal_frame = 0; + tdep_cache_frame (c, rs); return rs; } @@ -818,6 +825,8 @@ dwarf_find_save_locs (struct dwarf_cursor *c) memcpy (&rs_copy, rs, sizeof (rs_copy)); put_rs_cache (c->as, cache, &saved_mask); + + tdep_reuse_frame (c, &rs_copy); if ((ret = apply_reg_state (c, &rs_copy)) < 0) return ret; diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c index 1bf4ba2..8337fa5 100644 --- a/src/x86_64/Gos-linux.c +++ b/src/x86_64/Gos-linux.c @@ -30,10 +30,59 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +HIDDEN void +tdep_fetch_frame (struct dwarf_cursor *dw, unw_word_t ip, int need_unwind_info) +{ + struct cursor *c = (struct cursor *) dw; + assert(! need_unwind_info || dw->pi_valid); + assert(! need_unwind_info || dw->pi.unwind_info); + if (dw->pi_valid + && dw->pi.unwind_info + && ((struct dwarf_cie_info *) dw->pi.unwind_info)->signal_frame) + { + c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = dw->cfa; + } + else + { + c->sigcontext_format = X86_64_SCF_NONE; + c->sigcontext_addr = 0; + } + + Debug(15, "fetch frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx\n", + dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr); +} + +HIDDEN void +tdep_cache_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs) +{ + struct cursor *c = (struct cursor *) dw; + rs->signal_frame = c->sigcontext_format; + + Debug(15, "cache frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx\n", + dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr); +} + +HIDDEN void +tdep_reuse_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs) +{ + struct cursor *c = (struct cursor *) dw; + c->sigcontext_format = rs->signal_frame; + if (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME) + c->sigcontext_addr = dw->cfa; + else + c->sigcontext_addr = 0; + + Debug(15, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx\n", + dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr); +} + PROTECTED int unw_is_signal_frame (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; + return c->sigcontext_format != X86_64_SCF_NONE; +#if 0 unw_word_t w0, w1, ip; unw_addr_space_t as; unw_accessors_t *a; @@ -57,20 +106,24 @@ unw_is_signal_frame (unw_cursor_t *cursor) return 0; w1 &= 0xff; return (w0 == 0x0f0000000fc0c748 && w1 == 0x05); +#endif } PROTECTED int unw_handle_signal_frame (unw_cursor_t *cursor) { + /* Should not get here because we now use kernel-provided dwarf + information for the signal trampoline and dwarf_step() works. + Hence dwarf_step() should never call this function. Maybe + restore old non-dwarf signal handling here, but then the + gating on unw_is_signal_frame() needs to be removed. */ struct cursor *c = (struct cursor *) cursor; - int ret; - unw_word_t ucontext = c->dwarf.cfa; - - Debug(1, "signal frame, skip over trampoline\n"); - - c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME; - c->sigcontext_addr = c->dwarf.cfa; - + Debug(1, "old format signal frame? format=%d addr=0x%lx cfa=0x%lx\n", + c->sigcontext_format, c->sigcontext_addr, c->dwarf.cfa); + assert(c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME); + assert(c->sigcontext_addr == c->dwarf.cfa); + assert(0); +#if 0 struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0); ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa); if (ret < 0) @@ -96,8 +149,9 @@ unw_handle_signal_frame (unw_cursor_t *cursor) c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0); c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0); c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0); +#endif - return 0; + return 1; } #ifndef UNW_REMOTE_ONLY diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index d23be8e..01022a1 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -38,6 +38,7 @@ unw_step (unw_cursor_t *cursor) c, (unsigned long long) c->dwarf.ip); /* Try DWARF-based unwinding... */ + c->sigcontext_format = X86_64_SCF_NONE; ret = dwarf_step (&c->dwarf); if (ret < 0 && ret != -UNW_ENOINFO)