summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kostik@pooma.home>2010-05-02 16:29:02 +0300
committerKonstantin Belousov <kostik@pooma.home>2010-05-02 16:29:02 +0300
commitb73c618a3135e2e98a279c957240d6d00a192166 (patch)
tree92eeecbc084ac95d0ba62a41b1affed7c1185a20
parent58f290e1ce5950beac3767acbde08fcb0e1ca03f (diff)
parent0176c4f723f1ea90eb20018091ca58eedf28a4a8 (diff)
downloadlibunwind-b73c618a3135e2e98a279c957240d6d00a192166.tar.gz
Merge branch 'master' into freebsd
-rw-r--r--configure.in6
-rw-r--r--include/dwarf.h3
-rw-r--r--include/tdep-arm/libunwind_i.h3
-rw-r--r--include/tdep-hppa/libunwind_i.h3
-rw-r--r--include/tdep-ia64/libunwind_i.h3
-rw-r--r--include/tdep-mips/libunwind_i.h3
-rw-r--r--include/tdep-ppc32/libunwind_i.h3
-rw-r--r--include/tdep-ppc64/libunwind_i.h3
-rw-r--r--include/tdep-x86/libunwind_i.h3
-rw-r--r--include/tdep-x86_64/libunwind_i.h18
-rw-r--r--src/arm/Ginit_local.c2
-rw-r--r--src/arm/Ginit_remote.c2
-rw-r--r--src/arm/init.h3
-rw-r--r--src/dwarf/Gfde.c5
-rw-r--r--src/dwarf/Gfind_proc_info-lsb.c20
-rw-r--r--src/dwarf/Gparser.c62
-rw-r--r--src/hppa/Ginit_local.c2
-rw-r--r--src/hppa/Ginit_remote.c2
-rw-r--r--src/hppa/init.h4
-rw-r--r--src/mips/Ginit_local.c2
-rw-r--r--src/mips/Ginit_remote.c2
-rw-r--r--src/mips/init.h3
-rw-r--r--src/ppc/Ginit_local.c4
-rw-r--r--src/ppc/Ginit_remote.c4
-rw-r--r--src/ppc32/init.h3
-rw-r--r--src/ppc64/init.h3
-rw-r--r--src/x86/Ginit_local.c2
-rw-r--r--src/x86/Ginit_remote.c2
-rw-r--r--src/x86/getcontext-freebsd.S2
-rw-r--r--src/x86/getcontext-linux.S2
-rw-r--r--src/x86/init.h3
-rw-r--r--src/x86_64/Ginit_local.c6
-rw-r--r--src/x86_64/Ginit_remote.c2
-rw-r--r--src/x86_64/Gos-linux.c120
-rw-r--r--src/x86_64/Gstep.c9
-rw-r--r--src/x86_64/getcontext.S4
-rw-r--r--src/x86_64/init.h3
-rwxr-xr-xtests/run-ptrace-mapper2
38 files changed, 227 insertions, 101 deletions
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 */
+ /* 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 <sys/syscall.h>
+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 $*