@@ -387,7 +387,9 @@ extern int dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg);
#endif /* !UNW_REMOTE_ONLY */
extern int dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
- struct dl_phdr_info *info, unw_word_t ip);
+ unw_word_t ip, unw_word_t segbase,
+ const char* obj_name, unw_word_t start,
+ unw_word_t end);
extern int dwarf_search_unwind_table (unw_addr_space_t as,
unw_word_t ip,
unw_dyn_info_t *di,
@@ -26,7 +26,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* Locate an FDE via the ELF data-structures defined by LSB v1.3
(http://www.linuxbase.org/spec/). */
+#ifndef UNW_REMOTE_ONLY
#include <link.h>
+#endif /* !UNW_REMOTE_ONLY */
#include <stddef.h>
#include <stdio.h>
#include <limits.h>
@@ -269,17 +271,15 @@ find_binary_for_address (unw_word_t ip, char *name, size_t name_size)
pointer to debug frame descriptor, or zero if not found. */
static struct unw_debug_frame_list *
-locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
- unw_word_t addr, const char *dlname)
+locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
+ unw_word_t start, unw_word_t end)
{
struct unw_debug_frame_list *w, *fdesc = 0;
char path[PATH_MAX];
char *name = path;
int err;
- uint64_t start = 0, end = 0;
char *buf;
size_t bufsize;
- unsigned int i;
/* First, see if we loaded this frame already. */
@@ -306,29 +306,6 @@ locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
else
name = (char*) dlname;
- /* Find the start/end of the described region by parsing the
- dl_phdr_info structure. */
-
- start = info->dlpi_addr + info->dlpi_phdr[0].p_vaddr;
- end = start;
-
- for (i = 0; i < info->dlpi_phnum; i++)
- {
- Elf_W (Addr) hdrbase = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
- Elf_W (Addr) hdrlimit = hdrbase + info->dlpi_phdr[i].p_memsz;
-
- if (info->dlpi_phdr[i].p_type != PT_LOAD)
- continue;
-
- if (hdrbase < start)
- start = hdrbase;
- if (hdrlimit > end)
- end = hdrlimit;
- }
-
- Debug (4, "calculated bounds of %lx-%lx for '%s'\n", (long)start, (long)end,
- name);
-
err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
if (!err)
@@ -409,19 +386,19 @@ debug_frame_tab_compare (const void *a, const void *b)
}
PROTECTED int
-dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
- struct dl_phdr_info *info, unw_word_t ip)
+dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
+ unw_word_t segbase, const char* obj_name,
+ unw_word_t start, unw_word_t end)
{
unw_dyn_info_t *di;
struct unw_debug_frame_list *fdesc = 0;
unw_accessors_t *a;
unw_word_t addr;
- Debug (15, "Trying to find .debug_frame info->dlpi_name=%s\n",
- info->dlpi_name);
+ Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
di = di_debug;
- fdesc = locate_debug_info (unw_local_addr_space, info, ip, info->dlpi_name);
+ fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
if (!fdesc)
{
@@ -539,10 +516,10 @@ dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
di->format = UNW_INFO_FORMAT_TABLE;
di->start_ip = fdesc->start;
di->end_ip = fdesc->end;
- di->u.ti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
+ di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
di->u.ti.table_data = (unw_word_t *) fdesc;
di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
- di->u.ti.segbase = (unw_word_t) (uintptr_t) info->dlpi_addr;
+ di->u.ti.segbase = segbase;
found = 1;
Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
@@ -567,7 +544,7 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
struct dwarf_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;
- unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
+ unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip, start, end;
Elf_W(Addr) load_base, segbase = 0, max_load_addr = 0;
int ret, need_unwind_info = cb_data->need_unwind_info;
unw_proc_info_t *pi = cb_data->pi;
@@ -733,9 +710,29 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
}
#ifdef CONFIG_DEBUG_FRAME
- {
- found = dwarf_find_debug_frame (found, &cb_data->di_debug, info, ip);
- }
+ /* Find the start/end of the described region by parsing the phdr_info
+ structure. */
+ start = (unw_word_t) -1;
+ end = 0;
+
+ for (n = 0; n < info->dlpi_phnum; n++)
+ {
+ if (info->dlpi_phdr[n].p_type == PT_LOAD)
+ {
+ unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr;
+ unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz;
+
+ if (seg_start < start)
+ start = seg_start;
+
+ if (seg_end > end)
+ end = seg_end;
+ }
+ }
+
+ found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip,
+ info->dlpi_addr, info->dlpi_name, start,
+ end);
#endif /* CONFIG_DEBUG_FRAME */
return found;
@@ -172,6 +172,8 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL;
unw_word_t addr, eh_frame_start, fde_count, load_base;
unw_word_t max_load_addr = 0;
+ unw_word_t start_ip = (unw_word_t) -1;
+ unw_word_t end_ip = 0;
struct dwarf_eh_frame_hdr *hdr;
unw_proc_info_t pi;
unw_accessors_t *a;
@@ -194,6 +196,12 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
switch (phdr[i].p_type)
{
case PT_LOAD:
+ if (phdr[i].p_vaddr < start_ip)
+ start_ip = phdr[i].p_vaddr;
+
+ if (phdr[i].p_vaddr + phdr[i].p_memsz > end_ip)
+ end_ip = phdr[i].p_vaddr + phdr[i].p_memsz;
+
if (phdr[i].p_offset == mapoff)
ptxt = phdr + i;
if ((uintptr_t) ui->ei.image + phdr->p_filesz > max_load_addr)
@@ -222,6 +230,10 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
if (!ptxt)
return 0;
+ load_base = segbase - ptxt->p_vaddr;
+ start_ip += load_base;
+ end_ip += load_base;
+
if (peh_hdr)
{
if (pdyn)
@@ -305,10 +317,8 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
#endif
}
- load_base = segbase - ptxt->p_vaddr;
-
- ui->di_cache.start_ip = segbase;
- ui->di_cache.end_ip = ui->di_cache.start_ip + ptxt->p_memsz;
+ ui->di_cache.start_ip = start_ip;
+ ui->di_cache.end_ip = end_ip;
ui->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE;
ui->di_cache.u.rti.name_ptr = 0;
/* two 32-bit values (ip_offset/fde_offset) per table-entry: */
@@ -329,39 +339,19 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
if (parm_exidx)
{
ui->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX;
- ui->di_arm.start_ip = segbase;
- ui->di_arm.end_ip = ui->di_arm.start_ip + ptxt->p_memsz;
+ ui->di_arm.start_ip = start_ip;
+ ui->di_arm.end_ip = end_ip;
ui->di_arm.u.rti.name_ptr = (unw_word_t) path;
- ui->di_arm.u.rti.table_data = parm_exidx->p_vaddr + segbase -
- ptxt->p_vaddr;
+ ui->di_arm.u.rti.table_data = load_base + parm_exidx->p_vaddr;
ui->di_arm.u.rti.table_len = parm_exidx->p_memsz;
found = 1;
}
#endif
#ifdef CONFIG_DEBUG_FRAME
- {
- /* Try .debug_frame. */
- struct dl_phdr_info info;
-
- info.dlpi_name = path;
- info.dlpi_phdr = phdr;
- info.dlpi_phnum = ehdr->e_phnum;
-
- /* Fixup segbase to match correct base address. */
- for (i = 0; i < info.dlpi_phnum; i++)
- {
- if (info.dlpi_phdr[i].p_type == PT_LOAD &&
- info.dlpi_phdr[i].p_offset == 0)
- {
- segbase -= info.dlpi_phdr[i].p_vaddr;
- break;
- }
- }
- info.dlpi_addr = segbase;
-
- found = dwarf_find_debug_frame (found, &ui->di_debug, &info, ip);
- }
+ /* Try .debug_frame. */
+ found = dwarf_find_debug_frame (found, &ui->di_debug, ip, segbase, path,
+ start_ip, end_ip);
#endif
return found;
Since the dl_iterate_phdr is required for local unwinding only the use of struct dl_phdr_info can be eliminated in case libunwind gets compiled for remote unwinding. This enhances libunwinds portability to targets that don't provide any dl_iterate_phdr functionality. Signed-off-by: Ken Werner <ken.werner@linaro.org> --- include/dwarf.h | 4 ++- src/dwarf/Gfind_proc_info-lsb.c | 73 ++++++++++++++++++-------------------- src/ptrace/_UPT_find_proc_info.c | 50 ++++++++++--------------- 3 files changed, 58 insertions(+), 69 deletions(-)