From 250382c56d2c84fc3976cf8a4c834433bb68990d Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Tue, 20 Apr 2010 23:13:05 +0200 Subject: [PATCH 01/12] Use wider format when printing addresses in debug format. --- src/dwarf/Gfde.c | 2 +- src/dwarf/Gfind_proc_info-lsb.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c index 49e21db8..16e36ee2 100644 --- a/src/dwarf/Gfde.c +++ b/src/dwarf/Gfde.c @@ -293,7 +293,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) From dac2d001afb1fa7040ca7d8ae57032f684d7023e Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Tue, 20 Apr 2010 23:13:09 +0200 Subject: [PATCH 02/12] Identify signal frames by augmentation attribute. --- include/dwarf.h | 2 + include/tdep-arm/libunwind_i.h | 3 ++ include/tdep-hppa/libunwind_i.h | 3 ++ include/tdep-ia64/libunwind_i.h | 3 ++ include/tdep-mips/libunwind_i.h | 3 ++ include/tdep-ppc32/libunwind_i.h | 3 ++ include/tdep-ppc64/libunwind_i.h | 3 ++ include/tdep-x86/libunwind_i.h | 3 ++ include/tdep-x86_64/libunwind_i.h | 18 ++++++++ src/dwarf/Gfde.c | 3 ++ src/dwarf/Gparser.c | 9 ++++ src/x86_64/Gos-linux.c | 72 +++++++++++++++++++++++++++---- src/x86_64/Gstep.c | 1 + 13 files changed, 117 insertions(+), 9 deletions(-) diff --git a/include/dwarf.h b/include/dwarf.h index 37b5ec1c..53c803b2 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 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/dwarf/Gfde.c b/src/dwarf/Gfde.c index 16e36ee2..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; diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index db64b920..ccb710a3 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 1bf4ba2f..8337fa55 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 d23be8ea..01022a19 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) From 4c553ceb2c3fcde6248b05953abc34e162917c4a Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Tue, 20 Apr 2010 23:13:11 +0200 Subject: [PATCH 03/12] Identify end-of-stack by undefined return address location. --- src/dwarf/Gparser.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index ccb710a3..21b042c4 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -750,13 +750,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", From a9dce3c06e6ffcb83957e734d960505415118f00 Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Sat, 24 Apr 2010 19:16:09 -0700 Subject: [PATCH 04/12] During the stack unwinding process, the return address points to the instruction after the call for a normal frame. libunwind uses IP-1 to lookup unwind information. However, this is not necessary for interrupted frames such as signal frames (or interrupt frames) in the kernel context. This patch handles both cases correctly. Based on work by Mark Wielaard --- include/dwarf.h | 1 + src/arm/Ginit_local.c | 2 +- src/arm/Ginit_remote.c | 2 +- src/arm/init.h | 3 ++- src/dwarf/Gparser.c | 36 +++++++++++++++++++++++++++++++++--- src/hppa/Ginit_local.c | 2 +- src/hppa/Ginit_remote.c | 2 +- src/hppa/init.h | 4 +++- src/mips/Ginit_local.c | 2 +- src/mips/Ginit_remote.c | 2 +- src/mips/init.h | 3 ++- src/ppc/Ginit_local.c | 4 ++-- src/ppc/Ginit_remote.c | 4 ++-- src/ppc32/init.h | 3 ++- src/ppc64/init.h | 3 ++- src/x86/Ginit_local.c | 2 +- src/x86/Ginit_remote.c | 2 +- src/x86/init.h | 3 ++- src/x86_64/Ginit_local.c | 2 +- src/x86_64/Ginit_remote.c | 2 +- src/x86_64/init.h | 3 ++- 21 files changed, 63 insertions(+), 24 deletions(-) diff --git a/include/dwarf.h b/include/dwarf.h index 53c803b2..5dcc6ec9 100644 --- a/include/dwarf.h +++ b/include/dwarf.h @@ -295,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/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/Gparser.c b/src/dwarf/Gparser.c index 21b042c4..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; @@ -405,6 +424,14 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info) 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; } @@ -810,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 || 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/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..70bef3e1 100644 --- a/src/x86_64/Ginit_local.c +++ b/src/x86_64/Ginit_local.c @@ -52,7 +52,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_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/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; From f252f5ff4e51af90fd6629f122f72556db94ccb7 Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Tue, 20 Apr 2010 23:13:14 +0200 Subject: [PATCH 05/12] Recognise and unwind through PLT. --- src/x86_64/Gstep.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 01022a19..d691aa6e 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -28,14 +28,38 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" #include +/* Recognise PLT entries such as: + 3bdf0: ff 25 e2 49 13 00 jmpq *0x1349e2(%rip) + 3bdf6: 68 ae 03 00 00 pushq $0x3ae + 3bdfb: e9 00 c5 ff ff jmpq 38300 <_init+0x18> */ +static int +is_plt_entry (struct dwarf_cursor *c) +{ + unw_word_t w0, w1; + unw_accessors_t *a; + int ret; + + a = unw_get_accessors (c->as); + if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0 + || (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0) + return 0; + + ret = (((w0 & 0xffff) == 0x25ff) + && (((w0 >> 48) & 0xff) == 0x68) + && (((w1 >> 24) & 0xff) == 0xe9)); + + Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret); + return ret; +} + PROTECTED int unw_step (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; int ret, i; - Debug (1, "(cursor=%p, ip=0x%016llx)\n", - c, (unsigned long long) c->dwarf.ip); + Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n", + c, c->dwarf.ip, c->dwarf.cfa); /* Try DWARF-based unwinding... */ c->sigcontext_format = X86_64_SCF_NONE; @@ -86,6 +110,12 @@ unw_step (unw_cursor_t *cursor) return 0; } } + else if (is_plt_entry (&c->dwarf)) + { + Debug (2, "found plt entry\n"); + c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); + c->dwarf.cfa += 8; + } else { unw_word_t rbp; @@ -133,7 +163,7 @@ unw_step (unw_cursor_t *cursor) c->dwarf.ret_addr_column = RIP; - if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) + if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP])) { ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", From 92cc7fd78a5a79c4bb5f85bfb7d7fb025df9cd5a Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Tue, 20 Apr 2010 23:13:16 +0200 Subject: [PATCH 06/12] Remove obsolete code for 'old way' of handling x86-64 signal frames. --- src/x86_64/Gos-linux.c | 53 ------------------------------------------ 1 file changed, 53 deletions(-) diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c index 8337fa55..e2929beb 100644 --- a/src/x86_64/Gos-linux.c +++ b/src/x86_64/Gos-linux.c @@ -82,31 +82,6 @@ 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; - 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); -#endif } PROTECTED int @@ -123,34 +98,6 @@ unw_handle_signal_frame (unw_cursor_t *cursor) 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) - { - 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); -#endif - return 1; } From d4fbc8326a91d246af29ff17131a12ed7ae87140 Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Tue, 20 Apr 2010 23:13:18 +0200 Subject: [PATCH 07/12] Detect end of stack in x86-64 rbp-based walk. --- src/x86_64/Gstep.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index d691aa6e..85e3989a 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -116,6 +116,11 @@ unw_step (unw_cursor_t *cursor) c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); c->dwarf.cfa += 8; } + 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; @@ -123,7 +128,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; } From 045c55b2a296988c16a4c1b90f3d8b7e8b78752b Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Sat, 24 Apr 2010 19:24:49 -0700 Subject: [PATCH 08/12] Be conservative in all pointer derefrences by default. Since most people can't completely control their compile or runtime environment, it becomes hard to ensure that unwind data is perfect. --- configure.in | 6 ++++++ src/x86_64/Ginit_local.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/configure.in b/configure.in index fcc88137..e42445b2 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/src/x86_64/Ginit_local.c b/src/x86_64/Ginit_local.c index 70bef3e1..18b3d989 100644 --- a/src/x86_64/Ginit_local.c +++ b/src/x86_64/Ginit_local.c @@ -51,7 +51,11 @@ 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; +#endif return common_init (c, 1); } From d3c4bc42952a1aad0297b6f86569178814275a83 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Sun, 25 Apr 2010 09:24:40 -0700 Subject: [PATCH 09/12] Fix a compiler warning --- src/x86_64/Gos-linux.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c index e2929beb..826489f0 100644 --- a/src/x86_64/Gos-linux.c +++ b/src/x86_64/Gos-linux.c @@ -92,7 +92,6 @@ unw_handle_signal_frame (unw_cursor_t *cursor) 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; 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); From c140d8598d86c699ec619f3652aedbbddb142b69 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Sun, 25 Apr 2010 09:44:59 -0700 Subject: [PATCH 10/12] Undo commit f252f5ff4e51af90fd6629f122f72556db94ccb7 for now. Seems to introduce a couple of test breakages. --- src/x86_64/Gstep.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 85e3989a..237811ce 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -28,38 +28,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" #include -/* Recognise PLT entries such as: - 3bdf0: ff 25 e2 49 13 00 jmpq *0x1349e2(%rip) - 3bdf6: 68 ae 03 00 00 pushq $0x3ae - 3bdfb: e9 00 c5 ff ff jmpq 38300 <_init+0x18> */ -static int -is_plt_entry (struct dwarf_cursor *c) -{ - unw_word_t w0, w1; - unw_accessors_t *a; - int ret; - - a = unw_get_accessors (c->as); - if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0 - || (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0) - return 0; - - ret = (((w0 & 0xffff) == 0x25ff) - && (((w0 >> 48) & 0xff) == 0x68) - && (((w1 >> 24) & 0xff) == 0xe9)); - - Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret); - return ret; -} - PROTECTED int unw_step (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; int ret, i; - Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n", - c, c->dwarf.ip, c->dwarf.cfa); + Debug (1, "(cursor=%p, ip=0x%016llx)\n", + c, (unsigned long long) c->dwarf.ip); /* Try DWARF-based unwinding... */ c->sigcontext_format = X86_64_SCF_NONE; @@ -110,12 +86,6 @@ unw_step (unw_cursor_t *cursor) return 0; } } - else if (is_plt_entry (&c->dwarf)) - { - Debug (2, "found plt entry\n"); - c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); - c->dwarf.cfa += 8; - } else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) { for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) @@ -169,7 +139,7 @@ unw_step (unw_cursor_t *cursor) c->dwarf.ret_addr_column = RIP; - if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP])) + if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) { ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", From 215afa30b782970479e956b7bb96dca7cd9325ea Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Wed, 28 Apr 2010 16:32:30 -0700 Subject: [PATCH 11/12] Add unwind descriptors to getcontext.S --- src/x86/getcontext-freebsd.S | 2 ++ src/x86/getcontext-linux.S | 2 ++ src/x86_64/getcontext.S | 4 ++++ tests/run-ptrace-mapper | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/x86/getcontext-freebsd.S b/src/x86/getcontext-freebsd.S index 92ae26f4..eb435394 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) @@ -81,6 +82,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_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/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 $* From fdc534ccb05d1e6c0438345d292203343a811701 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Wed, 28 Apr 2010 16:38:27 -0700 Subject: [PATCH 12/12] Silence a compiler warning --- src/x86_64/Gos-linux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c index e2929beb..b7f832ca 100644 --- a/src/x86_64/Gos-linux.c +++ b/src/x86_64/Gos-linux.c @@ -87,6 +87,7 @@ unw_is_signal_frame (unw_cursor_t *cursor) PROTECTED int unw_handle_signal_frame (unw_cursor_t *cursor) { +#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 @@ -98,6 +99,7 @@ unw_handle_signal_frame (unw_cursor_t *cursor) assert(c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME); assert(c->sigcontext_addr == c->dwarf.cfa); assert(0); +#endif return 1; }