Hi,
>> Force address validation on x86-64 to avoid frequent crashes, caused
>> both by .eh_frame info inaccuracies and current libunwind limitations.
>> It is not sufficient to validate only in or after signal frames.
>>>
>>
>
> Could you make this a compile time option?
Like this? Updated patch + knock-on update in another patch in the series.
Subject: [PATCH 1/2] Always validate all addresses.
From: Lassi Tuura <[email protected]>
Date: Thu, 22 Apr 2010 16:38:13 +0200
Force address validation on x86-64 to avoid frequent crashes, caused
both by .eh_frame info inaccuracies and current libunwind limitations.
It is not sufficient to validate only in or after signal frames.
---
configure.in | 6 ++++++
src/x86_64/Ginit_local.c | 4 ++++
2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/configure.in b/configure.in
index fcc8813..a116104 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=no])
+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 1e80cb8..37fe0bd 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);
}
Subject: [PATCH 2/2] Correct choice of next or previous instruction.
From: Lassi Tuura <[email protected]>
Date: Thu, 22 Apr 2010 16:38:18 +0200
---
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 53c803b..5dcc6ec 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 7b2881e..debf5bb 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 3baf3f6..854f3b6 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 5b3f927..a302569 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 22dc01e..efaa1ad 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 243ffd4..6d4dd3d 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 3d6606d..bd6093f 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 d5f900d..d14354f 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 7b2881e..debf5bb 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 3baf3f6..854f3b6 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 98956d4..e32e3c9 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 2d9ab2c..b931b5b 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 66269d2..0f4b0fd 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 8badb17..c2208ad 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 886f14c..64847b8 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 55ab749..5e8b697 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 6949a73..aa92405 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 675b77e..b59ad84 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 37fe0bd..18b3d98 100644
--- a/src/x86_64/Ginit_local.c
+++ b/src/x86_64/Ginit_local.c
@@ -56,7 +56,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
#else
c->validate = 0;
#endif
- 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 8aa644d..25dd686 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 ae108b2..dcd4aea 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;
_______________________________________________
Libunwind-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/libunwind-devel