mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-12-23 03:53:43 +01:00
Prevent the use of struct dl_phdr_info outside of dl_iterate_phdr
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>
This commit is contained in:
parent
0fed502a81
commit
059676cb00
3 changed files with 58 additions and 69 deletions
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue