1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-06-18 15:51:44 +02:00

[X86-64] For local unwinding, we have a defence mechanism against

bad/missing unwind information, which could result in libunwind
dereferencing bad pointers. This mechanism is based on msync(2) system
call and significantly reduces the chances of a bad pointer
dereference in libunwind.

The original idea was to turn this mechanism on only when necessary
i.e. libunwind didn't find proper unwind information for a IP.

There are a couple of problems in the current implementation.

* The flag is global and is modified without locking
* The flag isn't reset when starting a new unwind

The attached patch makes ->validate a per-thread setting by moving it
into struct cursor from unw_local_addr_space and resets it to false
when starting a new unwind. As a result, cursor->as_arg points to the
cursor itself instead of the ucontext (for the local case).

This was found to reduce the number of msync() system calls from an
application using libunwind significantly.

Signed-off-by: Paul Pluzhnikov <ppluzhnikov@google.com>
Signed-off-by: Arun Sharma <arun.sharma@google.com>
This commit is contained in:
Arun Sharma 2008-06-16 14:35:53 -06:00 committed by David Mosberger-Tang
parent 183d28a066
commit 649f1fb344
7 changed files with 33 additions and 11 deletions

View file

@ -51,7 +51,6 @@ struct unw_addr_space
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
int validate;
};
struct cursor
@ -67,8 +66,17 @@ struct cursor
}
sigcontext_format;
unw_word_t sigcontext_addr;
int validate;
ucontext_t *uc;
};
static inline ucontext_t *
dwarf_get_uc(const struct dwarf_cursor *cursor)
{
const struct cursor *c = (struct cursor *) cursor->as_arg;
return c->uc;
}
#define DWARF_GET_LOC(l) ((l).val)
#ifdef UNW_LOCAL_ONLY
@ -77,10 +85,10 @@ struct cursor
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) })
# define DWARF_IS_REG_LOC(l) 0
# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
tdep_uc_addr(dwarf_get_uc(c), (r)), 0))
#else /* !UNW_LOCAL_ONLY */
# define DWARF_LOC_TYPE_FP (1 << 0)

View file

@ -158,7 +158,8 @@ access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
else
{
/* validate address */
if (as->validate && validate_mem(addr))
const struct cursor *c = (const struct cursor *)arg;
if (c && c->validate && validate_mem(addr))
return -1;
*val = *(unw_word_t *) addr;
Debug (16, "mem[%016lx] -> %lx\n", addr, *val);
@ -171,7 +172,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
void *arg)
{
unw_word_t *addr;
ucontext_t *uc = arg;
ucontext_t *uc = ((struct cursor *)arg)->uc;
if (unw_is_fpreg (reg))
goto badreg;
@ -200,7 +201,7 @@ static int
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg)
{
ucontext_t *uc = arg;
ucontext_t *uc = ((struct cursor *)arg)->uc;
unw_fpreg_t *addr;
if (!unw_is_fpreg (reg))
@ -252,7 +253,6 @@ x86_64_local_addr_space_init (void)
local_addr_space.acc.get_proc_name = get_static_proc_name;
unw_flush_cache (&local_addr_space, 0, 0);
local_addr_space.validate = 0;
memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA);
lga_victim = 0;
}

View file

@ -49,7 +49,9 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
c->dwarf.as_arg = c;
c->uc = uc;
c->validate = 0;
return common_init (c);
}

View file

@ -42,7 +42,16 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = as;
c->dwarf.as_arg = as_arg;
if (as == unw_local_addr_space)
{
c->dwarf.as_arg = c;
c->uc = as_arg;
}
else
{
c->dwarf.as_arg = as_arg;
c->uc = 0;
}
return common_init (c);
#endif /* !UNW_LOCAL_ONLY */
}

View file

@ -40,7 +40,6 @@ unw_is_signal_frame (unw_cursor_t *cursor)
as = c->dwarf.as;
a = unw_get_accessors (as);
as->validate = 1; /* Don't trust the ip */
arg = c->dwarf.as_arg;
/* Check if RIP points at sigreturn sequence.

View file

@ -51,7 +51,7 @@ x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
#if defined(__linux)
struct cursor *c = (struct cursor *) cursor;
ucontext_t *uc = c->dwarf.as_arg;
ucontext_t *uc = c->uc;
/* Ensure c->pi is up-to-date. On x86-64, it's relatively common to
be missing DWARF unwind info. We don't want to fail in that

View file

@ -71,6 +71,10 @@ unw_step (unw_cursor_t *cursor)
unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
/* We could get here because of missing/bad unwind information.
Validate all addresses before dereferencing. */
c->validate = 1;
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
if (unw_is_signal_frame (cursor))