fix x86_64 DWARF-based stack trace

Commit 5917d4c added a guard on some pointer dereferences, but
the guard is too strict for DWARF. Allow reading of TEXT segments,
etc.
This commit is contained in:
Matthew Flatt 2013-07-23 17:20:20 -06:00
parent b27f2217c9
commit 9f0c5b1487
4 changed files with 136 additions and 40 deletions

View File

@ -197,14 +197,10 @@ Scheme_Object *scheme_native_stack_trace(void)
tail = scheme_null;
}
#ifdef MZ_USE_DWARF_LIBUNWIND
unw_set_safe_pointer_range(stack_start, stack_end);
unw_reset_bad_ptr_flag();
#endif
#ifdef MZ_USE_DWARF_LIBUNWIND
unw_getcontext(&cx);
unw_init_local(&c, &cx);
unw_set_safe_pointer_range(&c, stack_start, stack_end);
use_unw = 1;
p = NULL;
#else
@ -473,7 +469,7 @@ Scheme_Object *scheme_native_stack_trace(void)
unw_step(&c);
q = (void *)unw_get_ip(&c);
if ((q == prev_q)
|| unw_reset_bad_ptr_flag())
|| unw_reset_bad_ptr_flag(&c))
break;
}
}

View File

@ -2545,6 +2545,91 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
return 1;
}
struct addrs_callback_data {
long size, count;
unw_word_t *starts, *ends;
};
static void add_address_range(struct addrs_callback_data *cb_data,
unw_word_t start,
unw_word_t end) {
if (cb_data->count == cb_data->size) {
long size = (cb_data->size ? (cb_data->size * 2) : 32);
unw_word_t *n;
n = (unw_word_t *)malloc(sizeof(unw_word_t) * size);
memcpy(n, cb_data->starts, sizeof(unw_word_t) * cb_data->size);
if (cb_data->starts) free(cb_data->starts);
cb_data->starts = n;
n = (unw_word_t *)malloc(sizeof(unw_word_t) * size);
memcpy(n, cb_data->ends, sizeof(unw_word_t) * cb_data->size);
if (cb_data->ends) free(cb_data->ends);
cb_data->ends = n;
cb_data->size = size;
}
cb_data->starts[cb_data->count] = start;
cb_data->ends[cb_data->count] = end;
cb_data->count++;
}
static int
safe_addrs_callback (struct dl_phdr_info *info, size_t size, void *ptr)
{
struct addrs_callback_data *cb_data = ptr;
const Elf_W(Phdr) *phdr;
Elf_W(Addr) load_base;
long n;
/* Make sure struct dl_phdr_info is at least as big as we need. */
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
+ sizeof (info->dlpi_phnum))
return -1;
phdr = info->dlpi_phdr;
load_base = info->dlpi_addr;
/* See if PC falls into one of the loaded segments. Find the
eh-header segment at the same time. */
for (n = info->dlpi_phnum; --n >= 0; phdr++)
{
if (phdr->p_type == PT_LOAD)
{
Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
add_address_range(cb_data, (unw_word_t)vaddr, (unw_word_t)(vaddr + phdr->p_memsz));
}
}
return 0;
}
static struct addrs_callback_data safe_addrs;
HIDDEN int
initialize_safe_addresses (unw_addr_space_t as)
{
if (!safe_addrs.count) {
struct addrs_callback_data cb_data;
memset(&cb_data, 0, sizeof(cb_data));
#ifndef UW_NO_SYNC
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask);
#endif
(void)dl_iterate_phdr (safe_addrs_callback, &cb_data);
#ifndef UW_NO_SYNC
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
#endif
memcpy(&safe_addrs, &cb_data, sizeof(cb_data));
}
as->num_safe_addresses = safe_addrs.count;
as->safe_start_addresses = safe_addrs.starts;
as->safe_end_addresses = safe_addrs.ends;
return 0;
}
HIDDEN int
dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, int need_unwind_info, void *arg)
@ -3161,6 +3246,8 @@ int unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
as->debug_frames = shared_debug_frames;
#endif
initialize_safe_addresses(as);
c->dwarf.as = as;
c->dwarf.as_arg = uc;
return common_init (c);
@ -3183,29 +3270,37 @@ int unw_step (unw_cursor_t *c)
return dwarf_step(&((struct cursor *)c)->dwarf);
}
static int saw_bad_ptr = 0;
static char safe_space[8];
static unw_word_t safe_start_address, safe_end_address;
void unw_set_safe_pointer_range(unw_word_t s, unw_word_t e)
void unw_set_safe_pointer_range(unw_cursor_t *c, unw_word_t s, unw_word_t e)
{
safe_start_address = s;
safe_end_address = e;
unw_addr_space_t as = ((struct dwarf_cursor *)c)->as;
as->safe_start_address = s;
as->safe_end_address = e;
}
int unw_reset_bad_ptr_flag()
int unw_reset_bad_ptr_flag(unw_cursor_t *c)
{
int v = saw_bad_ptr;
saw_bad_ptr = 0;
unw_addr_space_t as = ((struct dwarf_cursor *)c)->as;
int v = as->saw_bad_ptr;
as->saw_bad_ptr = 0;
return v;
}
static void *safe_pointer(unw_word_t p)
static void *safe_pointer(unw_addr_space_t as, unw_word_t p)
{
if (safe_start_address != safe_end_address)
if ((p < safe_start_address)
|| (p >= safe_end_address)) {
saw_bad_ptr = 1;
int i;
for (i = as->num_safe_addresses; i--; ) {
if ((p >= as->safe_start_addresses[i])
&& (p <= as->safe_end_addresses[i]))
return (void *)p;
}
if (as->safe_start_address != as->safe_end_address)
if ((p < as->safe_start_address)
|| (p >= as->safe_end_address)) {
as->saw_bad_ptr = 1;
return safe_space;
}
@ -3228,7 +3323,8 @@ unw_word_t unw_get_frame_pointer(unw_cursor_t *c)
#else
# define JIT_FRAME_POINTER_ID 6 /* = BP */
#endif
return *(unw_word_t *)safe_pointer(((struct cursor *)c)->dwarf.loc[JIT_FRAME_POINTER_ID].val);
return *(unw_word_t *)safe_pointer(((struct cursor *)c)->dwarf.as,
((struct cursor *)c)->dwarf.loc[JIT_FRAME_POINTER_ID].val);
}
#ifdef UNW_X86_64
@ -3249,8 +3345,8 @@ void unw_manual_step(unw_cursor_t *_c,
c->dwarf.loc[13].val = (unw_word_t)r13_addr;
c->dwarf.loc[16].val = (unw_word_t)ip_addr;
c->dwarf.ip = *(unw_word_t *)safe_pointer((unw_word_t)ip_addr);
c->dwarf.cfa = *(unw_word_t *)safe_pointer((unw_word_t)sp_addr);
c->dwarf.ip = *(unw_word_t *)safe_pointer(c->dwarf.as, (unw_word_t)ip_addr);
c->dwarf.cfa = *(unw_word_t *)safe_pointer(c->dwarf.as, (unw_word_t)sp_addr);
c->dwarf.ret_addr_column = UNW_TDEP_IP;
c->dwarf.pi_valid = 0;
c->dwarf.hint = 0;
@ -3280,8 +3376,8 @@ void unw_manual_step(unw_cursor_t *_c,
c->dwarf.loc[UNW_ARM_RSP].val = (unw_word_t)sp_addr;
c->dwarf.loc[UNW_ARM_R11].val = (unw_word_t)fp_addr;
c->dwarf.ip = *(unw_word_t *)safe_pointer((unw_word_t)ip_addr);
c->dwarf.cfa = *(unw_word_t *)safe_pointer((unw_word_t)sp_addr);
c->dwarf.ip = *(unw_word_t *)safe_pointer(c->dwarf.as, (unw_word_t)ip_addr);
c->dwarf.cfa = *(unw_word_t *)safe_pointer(c->dwarf.as, (unw_word_t)sp_addr);
c->dwarf.ret_addr_column = UNW_TDEP_IP;
c->dwarf.pi_valid = 0;
c->dwarf.hint = 0;

View File

@ -585,8 +585,8 @@ void unw_manual_step(unw_cursor_t *_c,
extern unw_addr_space_t unw_local_addr_space;
extern int unw_reset_bad_ptr_flag();
extern void unw_set_safe_pointer_range(unw_word_t s, unw_word_t e);
extern int unw_reset_bad_ptr_flag(unw_cursor_t *c);
extern void unw_set_safe_pointer_range(unw_cursor_t *c, unw_word_t s, unw_word_t e);
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_is_fpreg (int);

View File

@ -692,6 +692,10 @@ struct unw_addr_space
#ifdef CONFIG_DEBUG_FRAME
struct unw_debug_frame_list *debug_frames;
#endif
unw_word_t safe_start_address, safe_end_address;
long num_safe_addresses;
unw_word_t *safe_start_addresses, *safe_end_addresses;
int saw_bad_ptr;
};
struct cursor
@ -723,14 +727,14 @@ struct cursor
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
static void *safe_pointer(unw_word_t);
static void *safe_pointer(unw_addr_space_t, unw_word_t);
static inline int
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*val = *(unw_fpreg_t *) safe_pointer(DWARF_GET_LOC (loc));
*val = *(unw_fpreg_t *) safe_pointer(c->as, DWARF_GET_LOC (loc));
return 0;
}
@ -739,7 +743,7 @@ dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*(unw_fpreg_t *) safe_pointer(DWARF_GET_LOC (loc)) = val;
*(unw_fpreg_t *) safe_pointer(c->as, DWARF_GET_LOC (loc)) = val;
return 0;
}
@ -748,7 +752,7 @@ dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*val = *(unw_word_t *) safe_pointer(DWARF_GET_LOC (loc));
*val = *(unw_word_t *) safe_pointer(c->as, DWARF_GET_LOC (loc));
return 0;
}
@ -757,7 +761,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*(unw_word_t *) safe_pointer(DWARF_GET_LOC (loc)) = val;
*(unw_word_t *) safe_pointer(c->as, DWARF_GET_LOC (loc)) = val;
return 0;
}
@ -826,7 +830,7 @@ static inline int
dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->s8;
*addr += sizeof (mvp->s8);
@ -837,7 +841,7 @@ static inline int
dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->s16;
*addr += sizeof (mvp->s16);
@ -848,7 +852,7 @@ static inline int
dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->s32;
*addr += sizeof (mvp->s32);
@ -859,7 +863,7 @@ static inline int
dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->s64;
*addr += sizeof (mvp->s64);
@ -870,7 +874,7 @@ static inline int
dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->u8;
*addr += sizeof (mvp->u8);
@ -881,7 +885,7 @@ static inline int
dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->u16;
*addr += sizeof (mvp->u16);
@ -892,7 +896,7 @@ static inline int
dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->u32;
*addr += sizeof (mvp->u32);
@ -903,7 +907,7 @@ static inline int
dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->u64;
*addr += sizeof (mvp->u64);
@ -914,7 +918,7 @@ static inline int
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(*addr);
dwarf_misaligned_value_t *mvp = (void *)safe_pointer(as, *addr);
*val = mvp->w;
*addr += sizeof (mvp->w);