diff --git a/include/libunwind-dynamic.h b/include/libunwind-dynamic.h index 8feb9de8..edb0bbd3 100644 --- a/include/libunwind-dynamic.h +++ b/include/libunwind-dynamic.h @@ -76,7 +76,11 @@ typedef enum UNW_INFO_FORMAT_DYNAMIC, /* unw_dyn_proc_info_t */ UNW_INFO_FORMAT_TABLE, /* unw_dyn_table_t */ UNW_INFO_FORMAT_REMOTE_TABLE, /* unw_dyn_remote_table_t */ - UNW_INFO_FORMAT_ARM_EXIDX /* ARM specific unwind info */ + UNW_INFO_FORMAT_ARM_EXIDX, /* ARM specific unwind info */ + UNW_INFO_FORMAT_IP_OFFSET, /* Like UNW_INFO_FORMAT_REMOTE_TABLE, but + table entries are considered + relative to di->start_ip, rather + than di->segbase */ } unw_dyn_info_format_t; diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c index af4546d4..6e1f4c3f 100644 --- a/src/dwarf/Gfind_proc_info-lsb.c +++ b/src/dwarf/Gfind_proc_info-lsb.c @@ -819,13 +819,19 @@ remote_lookup (unw_addr_space_t as, #endif /* !UNW_LOCAL_ONLY */ +static int is_remote_table(int format) +{ + return (format == UNW_INFO_FORMAT_REMOTE_TABLE || + format == UNW_INFO_FORMAT_IP_OFFSET); +} + PROTECTED int dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, unw_dyn_info_t *di, unw_proc_info_t *pi, int need_unwind_info, void *arg) { const struct table_entry *e = NULL, *table; - unw_word_t segbase = 0, fde_addr; + unw_word_t ip_base = 0, segbase = 0, fde_addr; unw_accessors_t *a; #ifndef UNW_LOCAL_ONLY struct table_entry ent; @@ -835,14 +841,14 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, size_t table_len; #ifdef UNW_REMOTE_ONLY - assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE); + assert (is_remote_table(di->format)); #else - assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE + assert (is_remote_table(di->format) || di->format == UNW_INFO_FORMAT_TABLE); #endif assert (ip >= di->start_ip && ip < di->end_ip); - if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE) + if (is_remote_table(di->format)) { table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data; table_len = di->u.rti.table_len * sizeof (unw_word_t); @@ -850,6 +856,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, } else { + assert(di->format == UNW_INFO_FORMAT_TABLE); #ifndef UNW_REMOTE_ONLY struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data; @@ -866,11 +873,17 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, a = unw_get_accessors (as); + segbase = di->u.rti.segbase; + if (di->format == UNW_INFO_FORMAT_IP_OFFSET) { + ip_base = di->start_ip; + } else { + ip_base = segbase; + } + #ifndef UNW_REMOTE_ONLY if (as == unw_local_addr_space) { - segbase = di->u.rti.segbase; - e = lookup (table, table_len, ip - segbase); + e = lookup (table, table_len, ip - ip_base); } else #endif @@ -878,7 +891,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, #ifndef UNW_LOCAL_ONLY segbase = di->u.rti.segbase; if ((ret = remote_lookup (as, (uintptr_t) table, table_len, - ip - segbase, &ent, arg)) < 0) + ip - ip_base, &ent, arg)) < 0) return ret; if (ret) e = &ent; diff --git a/src/mi/Gdyn-extract.c b/src/mi/Gdyn-extract.c index a0833509..c8ae7a03 100644 --- a/src/mi/Gdyn-extract.c +++ b/src/mi/Gdyn-extract.c @@ -49,6 +49,7 @@ unwi_extract_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip, case UNW_INFO_FORMAT_TABLE: case UNW_INFO_FORMAT_REMOTE_TABLE: + case UNW_INFO_FORMAT_IP_OFFSET: #ifdef tdep_search_unwind_table /* call platform-specific search routine: */ return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg); diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c index 480d470b..6e9d4fe9 100644 --- a/src/x86_64/Ginit.c +++ b/src/x86_64/Ginit.c @@ -168,8 +168,10 @@ access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, /* validate address */ const struct cursor *c = (const struct cursor *)arg; if (likely (c != NULL) && unlikely (c->validate) - && unlikely (validate_mem (addr))) + && unlikely (validate_mem (addr))) { + Debug (16, "mem[%016lx] -> invalid\n", addr); return -1; + } *val = *(unw_word_t *) addr; Debug (16, "mem[%016lx] -> %lx\n", addr, *val); }