@@ -285,14 +285,6 @@ struct arm_exidx_entry {
uint32_t data;
};
-struct arm_exidx_table {
- const char *name;
- struct arm_exidx_entry *start;
- struct arm_exidx_entry *end;
- unw_word_t start_addr;
- unw_word_t end_addr;
-};
-
typedef struct
{
/* no arm-specific auxiliary proc-info */
@@ -304,6 +296,11 @@ unw_tdep_proc_info_t;
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_is_fpreg (int);
+#define unw_search_arm_unwind_table UNW_OBJ(search_unwind_table)
+extern int unw_search_arm_unwind_table (unw_addr_space_t, unw_word_t,
+ unw_dyn_info_t *, unw_proc_info_t *,
+ int, void *);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
@@ -75,7 +75,8 @@ 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_REMOTE_TABLE, /* unw_dyn_remote_table_t */
+ UNW_INFO_FORMAT_ARM_EXIDX /* ARM specific unwind info */
}
unw_dyn_info_format_t;
@@ -44,20 +44,10 @@ struct arm_exbuf_data
uint32_t data;
};
-#define arm_exidx_init_local UNW_OBJ(arm_exidx_init_local)
-#define arm_exidx_table_add UNW_OBJ(arm_exidx_table_add)
-#define arm_exidx_table_find UNW_OBJ(arm_exidx_table_find)
-#define arm_exidx_table_lookup UNW_OBJ(arm_exidx_table_lookup)
#define arm_exidx_extract UNW_OBJ(arm_exidx_extract)
#define arm_exidx_decode UNW_OBJ(arm_exidx_decode)
#define arm_exidx_apply_cmd UNW_OBJ(arm_exidx_apply_cmd)
-int arm_exidx_init_local (void);
-int arm_exidx_table_add (const char *name, struct arm_exidx_entry *start,
- struct arm_exidx_entry *end);
-struct arm_exidx_table *arm_exidx_table_find (unw_word_t pc);
-struct arm_exidx_entry *arm_exidx_table_lookup (struct arm_exidx_table *table,
- unw_word_t pc);
int arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf);
int arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c);
int arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c);
@@ -231,7 +231,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_init UNW_OBJ(init)
/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
tdep_search_unwind_table. */
-#define tdep_search_unwind_table dwarf_search_unwind_table
+#define tdep_search_unwind_table unw_search_arm_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg)
@@ -264,9 +264,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
extern int tdep_needs_initialization;
extern void tdep_init (void);
-extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
+/*extern int tdep_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);
+ int need_unwind_info, void *arg);*/
extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff,
@@ -33,22 +33,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#define ARM_EXTBL_OP_FINISH 0xb0
-#define ARM_EXIDX_TABLE_LIMIT 32
-
-#define arm_exidx_tables UNW_OBJ(arm_exidx_tables)
-#define arm_exidx_table_count UNW_OBJ(arm_exidx_table_count)
-#define arm_exidx_table_find UNW_OBJ(arm_exidx_table_find)
-#define arm_exidx_table_reset_all UNW_OBJ(arm_exidx_table_reset_all)
-#define arm_exidx_init_local_cb UNW_OBJ(arm_exidx_init_local_cb)
-
enum arm_exbuf_cmd_flags {
ARM_EXIDX_VFP_SHIFT_16 = 1 << 16,
ARM_EXIDX_VFP_DOUBLE = 1 << 17,
};
-static struct arm_exidx_table arm_exidx_tables[ARM_EXIDX_TABLE_LIMIT];
-static unsigned arm_exidx_table_count = 0;
-
static inline uint32_t
prel31_read (uint32_t prel31)
{
@@ -62,68 +51,6 @@ prel31_to_addr (uint32_t *addr)
return (uint32_t)addr + offset;
}
-static void
-arm_exidx_table_reset_all (void)
-{
- arm_exidx_table_count = 0;
-}
-
-HIDDEN int
-arm_exidx_table_add (const char *name,
- struct arm_exidx_entry *start, struct arm_exidx_entry *end)
-{
- if (arm_exidx_table_count >= ARM_EXIDX_TABLE_LIMIT)
- return -1;
- struct arm_exidx_table *table = &arm_exidx_tables[arm_exidx_table_count++];
- table->name = name;
- table->start = start;
- table->end = end;
- table->start_addr = prel31_to_addr (&start->addr);
- table->end_addr = prel31_to_addr (&(end - 1)->addr);
- Debug (2, "name=%s, range=%p-%p, addr=%p-%p\n",
- name, start, end, (void *)table->start_addr, (void *)table->end_addr);
- return 0;
-}
-
-/**
- * Locate the appropriate unwind table from the given PC.
- */
-HIDDEN struct arm_exidx_table *
-arm_exidx_table_find (unw_word_t pc)
-{
- struct arm_exidx_table *table;
- unsigned i;
- for (i = 0; i < arm_exidx_table_count; i++)
- {
- table = &arm_exidx_tables[i];
- if (pc >= table->start_addr && pc < table->end_addr)
- return table;
- }
- return NULL;
-}
-
-/**
- * Finds the corresponding arm_exidx_entry from a given index table and PC.
- */
-HIDDEN struct arm_exidx_entry *
-arm_exidx_table_lookup (struct arm_exidx_table *table, unw_word_t pc)
-{
- struct arm_exidx_entry *first = table->start, *last = table->end - 1;
- if (pc < prel31_to_addr (&first->addr))
- return NULL;
- else if (pc >= prel31_to_addr (&last->addr))
- return last;
- while (first < last - 1)
- {
- struct arm_exidx_entry *mid = first + ((last - first + 1) >> 1);
- if (pc < prel31_to_addr (&mid->addr))
- last = mid;
- else
- first = mid;
- }
- return first;
-}
-
/**
* Applies the given command onto the new state to the given dwarf_cursor.
*/
@@ -401,39 +328,56 @@ arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf)
return nbuf;
}
-/**
- * Callback to dl_iterate_phdr to find the unwind tables.
- * If found, calls arm_exidx_table_add to remember it for later lookups.
- */
-static int
-arm_exidx_init_local_cb (struct dl_phdr_info *info, size_t size, void *data)
+PROTECTED int
+unw_search_arm_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)
{
- unsigned i;
-
- for (i = 0; i < info->dlpi_phnum; i++)
+ if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)
+ && di->format == UNW_INFO_FORMAT_ARM_EXIDX)
{
- const ElfW (Phdr) *phdr = info->dlpi_phdr + i;
- if (phdr->p_type != PT_ARM_EXIDX)
- continue;
+ struct arm_exidx_entry *first =
+ (struct arm_exidx_entry *) di->u.rti.table_data;
+ struct arm_exidx_entry *last =
+ ((struct arm_exidx_entry *) (di->u.rti.table_data +
+ di->u.rti.table_len)) - 1;
+ struct arm_exidx_entry *entry;
+
+ if (ip < prel31_to_addr (&first->addr))
+ return -UNW_ENOINFO;
+ else if (ip >= prel31_to_addr (&last->addr))
+ {
+ entry = last;
+ pi->start_ip = prel31_to_addr (&last->addr);
+ pi->end_ip = di->end_ip - 1;
+ }
+ else
+ {
+ while (first < last - 1)
+ {
+ entry = first + ((last - first + 1) >> 1);
+ if (ip < prel31_to_addr (&entry->addr))
+ last = entry;
+ else
+ first = entry;
+ }
- ElfW (Addr) addr = info->dlpi_addr + phdr->p_vaddr;
- ElfW (Word) size = phdr->p_filesz;
+ entry = first;
+ pi->start_ip = prel31_to_addr (&entry->addr);
+ pi->end_ip = prel31_to_addr (&(entry + 1)->addr) - 1;
+ }
- arm_exidx_table_add (info->dlpi_name,
- (struct arm_exidx_entry *)addr,
- (struct arm_exidx_entry *)(addr + size));
- break;
+ if (need_unwind_info)
+ {
+ pi->unwind_info_size = 8;
+ pi->unwind_info = entry;
+ pi->format = UNW_INFO_FORMAT_ARM_EXIDX;
+ }
+ return 0;
}
- return 0;
-}
+ else if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF
+ && di->format != UNW_INFO_FORMAT_ARM_EXIDX))
+ return dwarf_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
-/**
- * Traverse the program headers of the executable and its loaded
- * shared objects to collect the unwind tables.
- */
-HIDDEN int
-arm_exidx_init_local (void)
-{
- arm_exidx_table_reset_all();
- return dl_iterate_phdr (&arm_exidx_init_local_cb, NULL);
+ return -UNW_ENOINFO;
}
@@ -49,9 +49,6 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
- arm_exidx_init_local ();
-
return common_init (c, 1);
}
@@ -35,7 +35,6 @@ static inline int
arm_exidx_step (struct cursor *c)
{
unw_word_t old_ip, old_cfa;
- struct arm_exidx_table *table;
struct arm_exidx_entry *entry;
uint8_t buf[32];
int ret;
@@ -46,14 +45,13 @@ arm_exidx_step (struct cursor *c)
/* mark PC unsaved */
c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
- table = arm_exidx_table_find (c->dwarf.ip);
- if (NULL == table)
- return -UNW_ENOINFO;
+ if ((ret = tdep_find_proc_info (&c->dwarf, c->dwarf.ip, 1)) < 0)
+ return -UNW_ENOINFO;
- entry = arm_exidx_table_lookup (table, c->dwarf.ip);
- if (NULL == entry)
+ if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
return -UNW_ENOINFO;
+ entry = (struct arm_exidx_entry *)c->dwarf.pi.unwind_info;
ret = arm_exidx_extract (entry, buf);
if (ret < 0)
return ret;
@@ -57,6 +57,9 @@ struct callback_data
int single_fde; /* did we find a single FDE? (vs. a table) */
unw_dyn_info_t di; /* table info (if single_fde is false) */
unw_dyn_info_t di_debug; /* additional table info for .debug_frame */
+#if UNW_TARGET_ARM
+ unw_dyn_info_t di_arm; /* additional table info for .ARM.exidx */
+#endif
};
static int
@@ -576,6 +579,9 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
struct callback_data *cb_data = ptr;
unw_dyn_info_t *di = &cb_data->di;
const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
+#if UNW_TARGET_ARM
+ const Elf_W(Phdr) *p_arm_exidx = NULL;
+#endif
unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
Elf_W(Addr) load_base, segbase = 0, max_load_addr = 0;
int ret, need_unwind_info = cb_data->need_unwind_info;
@@ -619,6 +625,10 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
p_eh_hdr = phdr;
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
+#if UNW_TARGET_ARM
+ else if (phdr->p_type == PT_ARM_EXIDX)
+ p_arm_exidx = phdr;
+#endif
}
if (!p_text)
@@ -747,6 +757,19 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
}
#endif /* CONFIG_DEBUG_FRAME */
+#if UNW_TARGET_ARM
+ if (p_arm_exidx)
+ {
+ cb_data->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX;
+ cb_data->di_arm.start_ip = p_text->p_vaddr + load_base;
+ cb_data->di_arm.end_ip = cb_data->di_arm.start_ip + p_text->p_memsz;
+ cb_data->di_arm.u.rti.name_ptr = (unw_word_t) info->dlpi_name;
+ cb_data->di_arm.u.rti.table_data = p_arm_exidx->p_vaddr + load_base;
+ cb_data->di_arm.u.rti.table_len = p_arm_exidx->p_memsz;
+ found = 1;
+ }
+#endif
+
return found;
}
@@ -766,6 +789,9 @@ dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
cb_data.need_unwind_info = need_unwind_info;
cb_data.di.format = -1;
cb_data.di_debug.format = -1;
+#if UNW_TARGET_ARM
+ cb_data.di_arm.format = -1;
+#endif
SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
ret = dl_iterate_phdr (callback, &cb_data);
@@ -783,14 +809,21 @@ dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
/* search the table: */
if (cb_data.di.format != -1)
- ret = dwarf_search_unwind_table (as, ip, &cb_data.di,
- pi, need_unwind_info, arg);
+ ret = tdep_search_unwind_table (as, ip, &cb_data.di,
+ pi, need_unwind_info, arg);
else
ret = -UNW_ENOINFO;
+#if UNW_TARGET_ARM
+ if (ret == -UNW_ENOINFO && cb_data.di_arm.format != -1)
+ ret = tdep_search_unwind_table (as, ip, &cb_data.di_arm, pi,
+ need_unwind_info, arg);
+#endif
+
if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
- ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi,
- need_unwind_info, arg);
+ ret = tdep_search_unwind_table (as, ip, &cb_data.di_debug, pi,
+ need_unwind_info, arg);
+
return ret;
}
@@ -423,6 +423,11 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
return ret;
}
+ if (c->pi.format != UNW_INFO_FORMAT_DYNAMIC
+ && c->pi.format != UNW_INFO_FORMAT_TABLE
+ && c->pi.format != UNW_INFO_FORMAT_REMOTE_TABLE)
+ return -UNW_ENOINFO;
+
c->pi_valid = 1;
c->pi_is_dynamic = dynamic;
Use the dh_iterate_phdr callback in Gfind_proc_info-lsb.c to find the ARM specific unwind tables rather than doing it on our own at the unw_init_local. Signed-off-by: Ken Werner <ken.werner@linaro.org> --- include/libunwind-arm.h | 13 ++-- include/libunwind-dynamic.h | 3 +- include/tdep-arm/ex_tables.h | 10 --- include/tdep-arm/libunwind_i.h | 6 +- src/arm/Gex_tables.c | 148 ++++++++++++--------------------------- src/arm/Ginit_local.c | 3 - src/arm/Gstep.c | 10 +-- src/dwarf/Gfind_proc_info-lsb.c | 41 ++++++++++- src/dwarf/Gparser.c | 5 ++ 9 files changed, 102 insertions(+), 137 deletions(-)