1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-26 00:57:39 +01:00

Change libunwind-ptrace to also look for .debug_frame if nothing found in .eh_frame.

This changes the behavior of libunwind-ptrace to what we do for local
unwinding.

Signed-off-by: Ken Werner <ken.werner@linaro.org>
This commit is contained in:
Ken Werner 2011-07-20 07:18:50 +00:00
parent 545023c207
commit b317cb4829
3 changed files with 173 additions and 145 deletions

View file

@ -37,5 +37,10 @@ _UPT_create (pid_t pid)
memset (ui, 0, sizeof (*ui)); memset (ui, 0, sizeof (*ui));
ui->pid = pid; ui->pid = pid;
ui->di_cache.format = -1;
ui->di_debug.format = -1;
#if UNW_TARGET_IA64
ui->ktab.format = -1;;
#endif
return ui; return ui;
} }

View file

@ -164,7 +164,7 @@ dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a,
pi, valp, arg); pi, valp, arg);
} }
HIDDEN unw_dyn_info_t * HIDDEN int
_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as, _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff, char *path, unw_word_t segbase, unw_word_t mapoff,
unw_word_t ip) unw_word_t ip)
@ -176,12 +176,12 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
unw_proc_info_t pi; unw_proc_info_t pi;
unw_accessors_t *a; unw_accessors_t *a;
Elf_W(Ehdr) *ehdr; Elf_W(Ehdr) *ehdr;
int i, ret; int i, ret, found = 0;
/* XXX: Much of this code is Linux/LSB-specific. */ /* XXX: Much of this code is Linux/LSB-specific. */
if (!elf_w(valid_object) (&ui->ei)) if (!elf_w(valid_object) (&ui->ei))
return NULL; return -UNW_ENOINFO;
ehdr = ui->ei.image; ehdr = ui->ei.image;
phdr = (Elf_W(Phdr) *) ((char *) ui->ei.image + ehdr->e_phoff); phdr = (Elf_W(Phdr) *) ((char *) ui->ei.image + ehdr->e_phoff);
@ -209,37 +209,12 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
break; break;
} }
} }
if (!ptxt || !peh_hdr)
#ifdef CONFIG_DEBUG_FRAME if (!ptxt)
return 0;
if (peh_hdr)
{ {
/* No .eh_frame found, 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;
if (dwarf_find_debug_frame (0, &ui->di_cache, &info, ip))
return &ui->di_cache;
else
return NULL;
}
#else
return NULL;
#endif
if (pdyn) if (pdyn)
{ {
/* For dynamicly linked executables and shared libraries, /* For dynamicly linked executables and shared libraries,
@ -268,7 +243,7 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
{ {
Debug (1, "table `%s' has unexpected version %d\n", Debug (1, "table `%s' has unexpected version %d\n",
path, hdr->version); path, hdr->version);
return 0; return -UNW_ENOINFO;
} }
a = unw_get_accessors (unw_local_addr_space); a = unw_get_accessors (unw_local_addr_space);
@ -285,19 +260,19 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->eh_frame_ptr_enc, &pi, &addr, hdr->eh_frame_ptr_enc, &pi,
&eh_frame_start, NULL)) < 0) &eh_frame_start, NULL)) < 0)
return NULL; return -UNW_ENOINFO;
/* (Optionally) read fde_count: */ /* (Optionally) read fde_count: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->fde_count_enc, &pi, &addr, hdr->fde_count_enc, &pi,
&fde_count, NULL)) < 0) &fde_count, NULL)) < 0)
return NULL; return -UNW_ENOINFO;
if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
{ {
#if 1 #if 1
abort (); abort ();
#else #else
unw_word_t eh_frame_end; unw_word_t eh_frame_end;
/* If there is no search table or it has an unsupported /* If there is no search table or it has an unsupported
@ -318,7 +293,7 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
return linear_search (unw_local_addr_space, ip, return linear_search (unw_local_addr_space, ip,
eh_frame_start, eh_frame_end, fde_count, eh_frame_start, eh_frame_end, fde_count,
pi, need_unwind_info, NULL); pi, need_unwind_info, NULL);
#endif #endif
} }
load_base = segbase - ptxt->p_vaddr; load_base = segbase - ptxt->p_vaddr;
@ -338,29 +313,58 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
ui->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr) ui->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr)
+ ((unw_word_t) hdr - (unw_word_t) ui->ei.image + ((unw_word_t) hdr - (unw_word_t) ui->ei.image
- peh_hdr->p_offset)); - peh_hdr->p_offset));
found = 1;
}
return &ui->di_cache; #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);
}
#endif
return found;
} }
#endif /* UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_HPPA*/ #endif /* UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_HPPA*/
static unw_dyn_info_t * static int
get_unwind_info (struct UPT_info *ui, unw_addr_space_t as, unw_word_t ip) get_unwind_info (struct UPT_info *ui, unw_addr_space_t as, unw_word_t ip)
{ {
unsigned long segbase, mapoff; unsigned long segbase, mapoff;
char path[PATH_MAX]; char path[PATH_MAX];
unw_dyn_info_t *di;
#if UNW_TARGET_IA64 && defined(__linux) #if UNW_TARGET_IA64 && defined(__linux)
if (!ui->ktab.start_ip && _Uia64_get_kernel_table (&ui->ktab) < 0) if (!ui->ktab.start_ip && _Uia64_get_kernel_table (&ui->ktab) < 0)
return NULL; return -UNW_ENOINFO;
if (ip >= ui->ktab.start_ip && ip < ui->ktab.end_ip) if (ui->ktab.format != -1 && ip >= ui->ktab.start_ip && ip < ui->ktab.end_ip)
return &ui->ktab; return 0;
#endif #endif
if (ip >= ui->di_cache.start_ip && ip < ui->di_cache.end_ip) if ((ui->di_cache.format != -1
return &ui->di_cache; && ip >= ui->di_cache.start_ip && ip < ui->di_cache.end_ip)
|| (ui->di_debug.format != -1
&& ip >= ui->di_debug.start_ip && ip < ui->di_debug.end_ip))
return 0;
if (ui->ei.image) if (ui->ei.image)
{ {
@ -370,24 +374,36 @@ get_unwind_info (struct UPT_info *ui, unw_addr_space_t as, unw_word_t ip)
/* invalidate the cache: */ /* invalidate the cache: */
ui->di_cache.start_ip = ui->di_cache.end_ip = 0; ui->di_cache.start_ip = ui->di_cache.end_ip = 0;
ui->di_debug.start_ip = ui->di_debug.end_ip = 0;
ui->di_cache.format = -1;
ui->di_debug.format = -1;
} }
if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff, path, if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff, path,
sizeof(path)) < 0) sizeof(path)) < 0)
return NULL; return -UNW_ENOINFO;
/* Here, SEGBASE is the starting-address of the (mmap'ped) segment /* Here, SEGBASE is the starting-address of the (mmap'ped) segment
which covers the IP we're looking for. */ which covers the IP we're looking for. */
di = _UPTi_find_unwind_table (ui, as, path, segbase, mapoff, ip); if (_UPTi_find_unwind_table (ui, as, path, segbase, mapoff, ip) < 0)
if (!di return -UNW_ENOINFO;
/* This can happen in corner cases where dynamically generated /* This can happen in corner cases where dynamically generated
code falls into the same page that contains the data-segment code falls into the same page that contains the data-segment
and the page-offset of the code is within the first page of and the page-offset of the code is within the first page of
the executable. */ the executable. */
|| ip < di->start_ip || ip >= di->end_ip) if (ui->di_cache.format != -1
return NULL; && (ip < ui->di_cache.start_ip || ip >= ui->di_cache.end_ip))
ui->di_cache.format = -1;
return di; if (ui->di_debug.format != -1
&& (ip < ui->di_debug.start_ip || ip >= ui->di_debug.end_ip))
ui->di_debug.format = -1;
if (ui->di_cache.format == -1 && ui->di_debug.format == -1)
return -UNW_ENOINFO;
return 0;
} }
int int
@ -395,14 +411,13 @@ _UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
int need_unwind_info, void *arg) int need_unwind_info, void *arg)
{ {
struct UPT_info *ui = arg; struct UPT_info *ui = arg;
unw_dyn_info_t *di; int ret = -UNW_ENOINFO;
di = get_unwind_info (ui, as, ip); if (get_unwind_info (ui, as, ip) < 0)
if (!di)
return -UNW_ENOINFO; return -UNW_ENOINFO;
#if UNW_TARGET_IA64 #if UNW_TARGET_IA64
if (di == &ui->ktab) if (ui->ktab.format != -1)
{ {
/* The kernel unwind table resides in local memory, so we have /* The kernel unwind table resides in local memory, so we have
to use the local address space to search it. Since to use the local address space to search it. Since
@ -410,7 +425,7 @@ _UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
case, we simply make a copy of the unwind-info, so case, we simply make a copy of the unwind-info, so
_UPT_put_unwind_info() can always free() the unwind-info _UPT_put_unwind_info() can always free() the unwind-info
without ill effects. */ without ill effects. */
int ret = tdep_search_unwind_table (unw_local_addr_space, ip, di, pi, ret = tdep_search_unwind_table (unw_local_addr_space, ip, &ui->ktab, pi,
need_unwind_info, arg); need_unwind_info, arg);
if (ret >= 0) if (ret >= 0)
{ {
@ -426,9 +441,16 @@ _UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
pi->unwind_info = mem; pi->unwind_info = mem;
} }
} }
return ret;
} }
else
#endif #endif
return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
if (ret == -UNW_ENOINFO && ui->di_cache.format == -1)
ret = tdep_search_unwind_table (as, ip, &ui->di_cache,
pi, need_unwind_info, arg);
if (ret == -UNW_ENOINFO && ui->di_debug.format != -1)
ret = tdep_search_unwind_table (as, ip, &ui->di_debug, pi,
need_unwind_info, arg);
return ret;
} }

View file

@ -53,6 +53,7 @@ struct UPT_info
pid_t pid; /* the process-id of the child we're unwinding */ pid_t pid; /* the process-id of the child we're unwinding */
struct elf_image ei; struct elf_image ei;
unw_dyn_info_t di_cache; unw_dyn_info_t di_cache;
unw_dyn_info_t di_debug; /* additional table info for .debug_frame */
#if UNW_TARGET_IA64 #if UNW_TARGET_IA64
unw_dyn_info_t ktab; unw_dyn_info_t ktab;
#endif #endif
@ -60,7 +61,7 @@ struct UPT_info
extern int _UPT_reg_offset[UNW_REG_LAST + 1]; extern int _UPT_reg_offset[UNW_REG_LAST + 1];
extern unw_dyn_info_t *_UPTi_find_unwind_table (struct UPT_info *ui, extern int _UPTi_find_unwind_table (struct UPT_info *ui,
unw_addr_space_t as, unw_addr_space_t as,
char *path, char *path,
unw_word_t segbase, unw_word_t segbase,