diff --git a/configure.in b/configure.in index 100df65d..f09a3230 100644 --- a/configure.in +++ b/configure.in @@ -169,6 +169,12 @@ if test x$enable_block_signals = xyes; then AC_DEFINE([CONFIG_BLOCK_SIGNALS], [], [Block signals before mutex operations]) fi +AC_ARG_ENABLE(conservative_checks, +[ --enable-conservative-checks Validate all memory addresses before use], +[enable_conservative_checks=$enableval], [enable_conservative_checks=yes]) +if test x$enable_conservative_checks = xyes; then + CPPFLAGS="${CPPFLAGS} -DCONSERVATIVE_CHECKS" +fi LIBUNWIND___THREAD diff --git a/include/dwarf.h b/include/dwarf.h index 37b5ec1c..5dcc6ec9 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; @@ -293,6 +295,7 @@ typedef struct dwarf_cursor dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS]; + unsigned int use_prev_instr :1; /* use previous (= call) or current (= signal) instruction? */ unsigned int pi_valid :1; /* is proc_info valid? */ unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */ unw_proc_info_t pi; /* info about current procedure */ diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h index 3424d86a..2e1c4285 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 553e97d8..d89cc65e 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 552c9498..4936d516 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 c2f756a1..298fae81 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 05dd1356..b963bca8 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 192a0343..799b511f 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 9af007d1..bed8cbf0 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 f6a02897..c0227251 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/arm/Ginit_local.c b/src/arm/Ginit_local.c index 7b2881e3..debf5bb5 100644 --- a/src/arm/Ginit_local.c +++ b/src/arm/Ginit_local.c @@ -47,7 +47,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c); + return common_init (c, 1); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/arm/Ginit_remote.c b/src/arm/Ginit_remote.c index 3baf3f60..854f3b62 100644 --- a/src/arm/Ginit_remote.c +++ b/src/arm/Ginit_remote.c @@ -40,6 +40,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as = as; c->dwarf.as_arg = as_arg; - return common_init (c); + return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ } diff --git a/src/arm/init.h b/src/arm/init.h index 5b3f927d..a3025698 100644 --- a/src/arm/init.h +++ b/src/arm/init.h @@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" static inline int -common_init (struct cursor *c) +common_init (struct cursor *c, unsigned use_prev_instr) { int ret, i; @@ -62,6 +62,7 @@ common_init (struct cursor *c) c->dwarf.args_size = 0; c->dwarf.ret_addr_column = 0; + c->dwarf.use_prev_instr = use_prev_instr; c->dwarf.pi_valid = 0; c->dwarf.pi_is_dynamic = 0; c->dwarf.hint = 0; diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c index 49e21db8..8659624b 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; @@ -293,7 +296,7 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); } - Debug (15, "looking for CIE at address %x\n", (int) cie_addr); + Debug (15, "looking for CIE at address %lx\n", (long) cie_addr); if ((ret = parse_cie (as, a, cie_addr, pi, &dci, base, arg)) < 0) return ret; diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c index d7405301..1b0a5292 100644 --- a/src/dwarf/Gfind_proc_info-lsb.c +++ b/src/dwarf/Gfind_proc_info-lsb.c @@ -275,7 +275,7 @@ locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info, for (w = as->debug_frames; w; w = w->next) { - Debug (4, "checking %p: %x-%x\n", w, (int)w->start, (int)w->end); + Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end); if (addr >= w->start && addr < w->end) return w; } @@ -316,7 +316,7 @@ locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info, end = hdrlimit; } - Debug (4, "calculated bounds of %x-%x for '%s'\n", (int)start, (int)end, + Debug (4, "calculated bounds of %lx-%lx for '%s'\n", (long)start, (long)end, name); err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space); @@ -667,8 +667,8 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr) NULL); if (err == 0) { - Debug (15, "start_ip = %x, end_ip = %x\n", - (int) this_pi.start_ip, (int) this_pi.end_ip); + Debug (15, "start_ip = %lx, end_ip = %lx\n", + (long) this_pi.start_ip, (long) this_pi.end_ip); debug_frame_tab_append (tab, item_start - (unw_word_t) (uintptr_t) buf, this_pi.start_ip); @@ -771,7 +771,7 @@ lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip) { mid = (lo + hi) / 2; e = table + mid; - Debug (1, "e->start_ip_offset = %x\n", (int) e->start_ip_offset); + Debug (1, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset); if (rel_ip < e->start_ip_offset) hi = mid; else @@ -897,8 +897,8 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, } if (!e) { - Debug (1, "IP %x inside range %x-%x, but no explicit unwind info found\n", - (int) ip, (int) di->start_ip, (int) di->end_ip); + Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n", + (long) ip, (long) di->start_ip, (long) di->end_ip); /* IP is inside this table's range, but there is no explicit unwind info. */ return -UNW_ENOINFO; @@ -909,9 +909,9 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, fde_addr = e->fde_offset + debug_frame_base; else fde_addr = e->fde_offset + segbase; - Debug (1, "e->fde_offset = %x, segbase = %x, debug_frame_base = %x, " - "fde_addr = %x\n", (int) e->fde_offset, (int) segbase, - (int) debug_frame_base, (int) fde_addr); + Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, " + "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase, + (long) debug_frame_base, (long) fde_addr); if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi, need_unwind_info, debug_frame_base, arg)) < 0) diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index db64b920..3b1a2b40 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -76,7 +76,10 @@ run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr, a = unw_get_accessors (as); curr_ip = c->pi.start_ip; - while (curr_ip < ip && *addr < end_addr) + /* Process everything up to and including the current 'ip', + including all the DW_CFA_advance_loc instructions. See + 'c->use_prev_instr' use in 'fetch_proc_info' for details. */ + while (curr_ip <= ip && *addr < end_addr) { if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0) return ret; @@ -381,7 +384,23 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info) { int ret, dynamic = 1; - --ip; + /* The 'ip' can point either to the previous or next instruction + depending on what type of frame we have: normal call or a place + to resume execution (e.g. after signal frame). + + For a normal call frame we need to back up so we point within the + call itself; this is important because a) the call might be the + very last instruction of the function and the edge of the FDE, + and b) so that run_cfi_program() runs locations up to the call + but not more. + + For execution resume, we need to do the exact opposite and look + up using the current 'ip' value. That is where execution will + continue, and it's important we get this right, as 'ip' could be + right at the function entry and hence FDE edge, or at instruction + that manipulates CFA (push/pop). */ + if (c->use_prev_instr) + --ip; if (c->pi_valid && !need_unwind_info) return 0; @@ -400,6 +419,19 @@ 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); + + /* Update use_prev_instr for the next frame. */ + if (need_unwind_info) + { + assert(c->pi.unwind_info); + struct dwarf_cie_info *dci = c->pi.unwind_info; + c->use_prev_instr = ! dci->signal_frame; + } + return ret; } @@ -604,6 +636,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; } @@ -743,13 +777,20 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) break; } } - c->cfa = cfa; - ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip); - if (ret < 0) - return ret; - c->ip = ip; - /* XXX: check for ip to be code_aligned */ + c->cfa = cfa; + /* DWARF spec says undefined return address location means end of stack. */ + if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column])) + c->ip = 0; + else + { + ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip); + if (ret < 0) + return ret; + c->ip = ip; + } + + /* XXX: check for ip to be code_aligned */ if (c->ip == prev_ip && c->cfa == prev_cfa) { Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n", @@ -796,7 +837,10 @@ dwarf_find_save_locs (struct dwarf_cursor *c) rs = rs_lookup(cache, c); if (rs) - c->ret_addr_column = rs->ret_addr_column; + { + c->ret_addr_column = rs->ret_addr_column; + c->use_prev_instr = ! rs->signal_frame; + } else { if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 || @@ -818,6 +862,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/hppa/Ginit_local.c b/src/hppa/Ginit_local.c index 243ffd49..6d4dd3df 100644 --- a/src/hppa/Ginit_local.c +++ b/src/hppa/Ginit_local.c @@ -48,7 +48,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c); + return common_init (c, 1); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/hppa/Ginit_remote.c b/src/hppa/Ginit_remote.c index 3d6606df..bd6093f1 100644 --- a/src/hppa/Ginit_remote.c +++ b/src/hppa/Ginit_remote.c @@ -41,6 +41,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as = as; c->dwarf.as_arg = as_arg; - return common_init (c); + return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ } diff --git a/src/hppa/init.h b/src/hppa/init.h index d5f900d4..d14354f6 100644 --- a/src/hppa/init.h +++ b/src/hppa/init.h @@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" static inline int -common_init (struct cursor *c) +common_init (struct cursor *c, unsigned use_prev_instr) { int ret; @@ -40,5 +40,7 @@ common_init (struct cursor *c) ret = hppa_get (c, HPPA_REG_LOC (c, UNW_HPPA_SP), &c->sp); if (ret < 0) return ret; + + c->dwarf.use_prev_instr = use_prev_instr; return 0; } diff --git a/src/mips/Ginit_local.c b/src/mips/Ginit_local.c index 7b2881e3..debf5bb5 100644 --- a/src/mips/Ginit_local.c +++ b/src/mips/Ginit_local.c @@ -47,7 +47,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c); + return common_init (c, 1); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/mips/Ginit_remote.c b/src/mips/Ginit_remote.c index 3baf3f60..854f3b62 100644 --- a/src/mips/Ginit_remote.c +++ b/src/mips/Ginit_remote.c @@ -40,6 +40,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as = as; c->dwarf.as_arg = as_arg; - return common_init (c); + return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ } diff --git a/src/mips/init.h b/src/mips/init.h index 98956d4a..e32e3c9e 100644 --- a/src/mips/init.h +++ b/src/mips/init.h @@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" static inline int -common_init (struct cursor *c) +common_init (struct cursor *c, unsigned use_prev_instr) { int ret, i; @@ -47,6 +47,7 @@ common_init (struct cursor *c) c->dwarf.args_size = 0; c->dwarf.ret_addr_column = 0; + c->dwarf.use_prev_instr = use_prev_instr; c->dwarf.pi_valid = 0; c->dwarf.pi_is_dynamic = 0; c->dwarf.hint = 0; diff --git a/src/ppc/Ginit_local.c b/src/ppc/Ginit_local.c index 2d9ab2ce..b931b5b6 100644 --- a/src/ppc/Ginit_local.c +++ b/src/ppc/Ginit_local.c @@ -56,9 +56,9 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; #ifdef UNW_TARGET_PPC64 - return common_init_ppc64 (c); + return common_init_ppc64 (c, 1); #else - return common_init_ppc32 (c); + return common_init_ppc32 (c, 1); #endif } diff --git a/src/ppc/Ginit_remote.c b/src/ppc/Ginit_remote.c index 66269d2c..0f4b0fdb 100644 --- a/src/ppc/Ginit_remote.c +++ b/src/ppc/Ginit_remote.c @@ -50,9 +50,9 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as_arg = as_arg; #ifdef UNW_TARGET_PPC64 - return common_init_ppc64(c); + return common_init_ppc64 (c, 0); #elif UNW_TARGET_PPC32 - return common_init_ppc32 (c); + return common_init_ppc32 (c, 0); #else #error init_remote :: NO VALID PPC ARCH! #endif diff --git a/src/ppc32/init.h b/src/ppc32/init.h index 8badb178..c2208ad9 100644 --- a/src/ppc32/init.h +++ b/src/ppc32/init.h @@ -30,7 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Here is the "common" init, for remote and local debuging" */ static inline int -common_init_ppc32 (struct cursor *c) +common_init_ppc32 (struct cursor *c, unsigned use_prev_instr) { int ret; int i; @@ -62,6 +62,7 @@ common_init_ppc32 (struct cursor *c) c->dwarf.args_size = 0; c->dwarf.ret_addr_column = 0; + c->dwarf.use_prev_instr = use_prev_instr; c->dwarf.pi_valid = 0; c->dwarf.pi_is_dynamic = 0; c->dwarf.hint = 0; diff --git a/src/ppc64/init.h b/src/ppc64/init.h index 886f14c4..64847b84 100644 --- a/src/ppc64/init.h +++ b/src/ppc64/init.h @@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" static inline int -common_init_ppc64 (struct cursor *c) +common_init_ppc64 (struct cursor *c, unsigned use_prev_instr) { int ret; int i; @@ -72,6 +72,7 @@ common_init_ppc64 (struct cursor *c) c->dwarf.args_size = 0; c->dwarf.ret_addr_column = 0; + c->dwarf.use_prev_instr = use_prev_instr; c->dwarf.pi_valid = 0; c->dwarf.pi_is_dynamic = 0; c->dwarf.hint = 0; diff --git a/src/x86/Ginit_local.c b/src/x86/Ginit_local.c index 55ab7490..5e8b6972 100644 --- a/src/x86/Ginit_local.c +++ b/src/x86/Ginit_local.c @@ -50,7 +50,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as_arg = c; c->uc = uc; c->validate = 0; - return common_init (c); + return common_init (c, 1); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/x86/Ginit_remote.c b/src/x86/Ginit_remote.c index 6949a73e..aa924052 100644 --- a/src/x86/Ginit_remote.c +++ b/src/x86/Ginit_remote.c @@ -51,6 +51,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as_arg = as_arg; c->uc = 0; } - return common_init (c); + return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ } diff --git a/src/x86/getcontext-freebsd.S b/src/x86/getcontext-freebsd.S index 17adade8..dfeb4328 100644 --- a/src/x86/getcontext-freebsd.S +++ b/src/x86/getcontext-freebsd.S @@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ .global _Ux86_getcontext .type _Ux86_getcontext, @function _Ux86_getcontext: + .cfi_startproc pushl %eax mov 8(%esp),%eax /* ucontext_t* */ popl FREEBSD_UC_MCONTEXT_EAX_OFF(%eax) @@ -97,6 +98,7 @@ _Ux86_getcontext: xorl %eax, %eax ret + .cfi_endproc .size _Ux86_getcontext, . - _Ux86_getcontext /* We do not need executable stack. */ diff --git a/src/x86/getcontext-linux.S b/src/x86/getcontext-linux.S index a0714cd1..c469dadb 100644 --- a/src/x86/getcontext-linux.S +++ b/src/x86/getcontext-linux.S @@ -36,6 +36,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ .global _Ux86_getcontext .type _Ux86_getcontext, @function _Ux86_getcontext: + .cfi_startproc mov 4(%esp),%eax /* ucontext_t* */ /* EAX is not preserved. */ @@ -66,6 +67,7 @@ _Ux86_getcontext: xor %eax, %eax ret + .cfi_endproc .size _Ux86_getcontext, . - _Ux86_getcontext /* We do not need executable stack. */ diff --git a/src/x86/init.h b/src/x86/init.h index 675b77e5..b59ad842 100644 --- a/src/x86/init.h +++ b/src/x86/init.h @@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" static inline int -common_init (struct cursor *c) +common_init (struct cursor *c, unsigned use_prev_instr) { int ret, i; @@ -59,6 +59,7 @@ common_init (struct cursor *c) c->dwarf.args_size = 0; c->dwarf.ret_addr_column = 0; + c->dwarf.use_prev_instr = use_prev_instr; c->dwarf.pi_valid = 0; c->dwarf.pi_is_dynamic = 0; c->dwarf.hint = 0; diff --git a/src/x86_64/Ginit_local.c b/src/x86_64/Ginit_local.c index 1e80cb85..18b3d989 100644 --- a/src/x86_64/Ginit_local.c +++ b/src/x86_64/Ginit_local.c @@ -51,8 +51,12 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = c; c->uc = uc; +#if CONSERVATIVE_CHECKS + c->validate = 1; +#else c->validate = 0; - return common_init (c); +#endif + return common_init (c, 1); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/x86_64/Ginit_remote.c b/src/x86_64/Ginit_remote.c index 8aa644d3..25dd6860 100644 --- a/src/x86_64/Ginit_remote.c +++ b/src/x86_64/Ginit_remote.c @@ -52,6 +52,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg) c->dwarf.as_arg = as_arg; c->uc = 0; } - return common_init (c); + return common_init (c, 0); #endif /* !UNW_LOCAL_ONLY */ } diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c index 1bf4ba2f..957f3e30 100644 --- a/src/x86_64/Gos-linux.c +++ b/src/x86_64/Gos-linux.c @@ -30,74 +30,76 @@ 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; - unw_word_t w0, w1, ip; - unw_addr_space_t as; - unw_accessors_t *a; - void *arg; - int ret; - - as = c->dwarf.as; - a = unw_get_accessors (as); - arg = c->dwarf.as_arg; - - /* Check if RIP points at sigreturn sequence. - on x86_64 Linux that is (see libc.so): - 48 c7 c0 0f 00 00 00 mov $0xf,%rax - 0f 05 syscall - 66 data16 - */ - - ip = c->dwarf.ip; - if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0 - || (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0) - return 0; - w1 &= 0xff; - return (w0 == 0x0f0000000fc0c748 && w1 == 0x05); + return c->sigcontext_format != X86_64_SCF_NONE; } PROTECTED int unw_handle_signal_frame (unw_cursor_t *cursor) { - 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; - - 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) - { - Debug (2, "returning %d\n", ret); - return ret; - } - - c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0); - c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0); - c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0); - c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0); - c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0); - c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0); - c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0); - c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0); - c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0); - c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0); - c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0); - c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0); - c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0); - c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0); - 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); - - return 0; +#if UNW_DEBUG /* To silence compiler warnings */ + /* 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. */ + 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); +#endif + return 1; } #ifndef UNW_REMOTE_ONLY diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index d23be8ea..237811ce 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) @@ -85,6 +86,11 @@ unw_step (unw_cursor_t *cursor) return 0; } } + else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) + { + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; + } else { unw_word_t rbp; @@ -92,7 +98,8 @@ unw_step (unw_cursor_t *cursor) ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp); if (ret < 0) { - Debug (2, "returning %d\n", ret); + Debug (2, "returning %d [RBP=0x%lx]\n", ret, + DWARF_GET_LOC (c->dwarf.loc[RBP])); return ret; } diff --git a/src/x86_64/getcontext.S b/src/x86_64/getcontext.S index a0df6f15..15fff283 100644 --- a/src/x86_64/getcontext.S +++ b/src/x86_64/getcontext.S @@ -37,6 +37,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ .global _Ux86_64_getcontext .type _Ux86_64_getcontext, @function _Ux86_64_getcontext: + .cfi_startproc /* Callee saved: RBX, RBP, R12-R15 */ movq %r12, UC_MCONTEXT_GREGS_R12(%rdi) @@ -70,7 +71,9 @@ _Ux86_64_getcontext: /* Save rflags and segment registers, so that sigreturn(2) does not complain. */ pushfq + .cfi_adjust_cfa_offset 8 popq UC_MCONTEXT_RFLAGS(%rdi) + .cfi_adjust_cfa_offset -8 movl $0, UC_MCONTEXT_FLAGS(%rdi) movw %cs, UC_MCONTEXT_CS(%rdi) movw %ss, UC_MCONTEXT_SS(%rdi) @@ -95,6 +98,7 @@ _Ux86_64_getcontext: xorq %rax, %rax retq + .cfi_endproc .size _Ux86_64_getcontext, . - _Ux86_64_getcontext /* We do not need executable stack. */ diff --git a/src/x86_64/init.h b/src/x86_64/init.h index ae108b24..dcd4aea2 100644 --- a/src/x86_64/init.h +++ b/src/x86_64/init.h @@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" static inline int -common_init (struct cursor *c) +common_init (struct cursor *c, unsigned use_prev_instr) { int ret; @@ -64,6 +64,7 @@ common_init (struct cursor *c) c->dwarf.args_size = 0; c->dwarf.ret_addr_column = RIP; + c->dwarf.use_prev_instr = use_prev_instr; c->dwarf.pi_valid = 0; c->dwarf.pi_is_dynamic = 0; c->dwarf.hint = 0; diff --git a/tests/run-ptrace-mapper b/tests/run-ptrace-mapper index f51cf9a1..dc3010d4 100755 --- a/tests/run-ptrace-mapper +++ b/tests/run-ptrace-mapper @@ -1,2 +1,2 @@ #!/bin/sh -./test-ptrace -c -n -t ./mapper +./test-ptrace -c -n -t ./mapper $*