mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-10-03 20:09:30 +02:00
(_Uia64_search_unwind_table): Correct off-by-8 error in calculating
personality-routine and LSDA address and dont' forget to dereference the personality-routine function-pointer, so we really get the address of the function-descriptor of the personality routine. (callback): Set the segment-base based on the segment that contains the unwind-table. Normally, that the text segment but in special cases, such as the kernel's gate DSO, it will be in a different segment. (Logical change 1.108)
This commit is contained in:
parent
5c9fea2476
commit
656e9d6e7d
1 changed files with 32 additions and 6 deletions
|
@ -142,12 +142,17 @@ _Uia64_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
|
||||||
if (IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
|
if (IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
|
||||||
{
|
{
|
||||||
/* read the personality routine address (address is gp-relative): */
|
/* read the personality routine address (address is gp-relative): */
|
||||||
ret = (*a->access_mem) (as, info_end_addr + 8, &handler_offset, 0, arg);
|
ret = (*a->access_mem) (as, info_end_addr, &handler_offset, 0, arg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
debug (50, "%s: handler ptr @ offset=%lx, gp=%lx\n",
|
||||||
|
__FUNCTION__, handler_offset, di->gp);
|
||||||
|
ret = (*a->access_mem) (as, handler_offset + di->gp, &pi->handler,
|
||||||
|
0, arg);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
pi->handler = handler_offset + di->gp;
|
|
||||||
}
|
}
|
||||||
pi->lsda = info_end_addr + 16;
|
pi->lsda = info_end_addr + 8;
|
||||||
pi->gp = di->gp;
|
pi->gp = di->gp;
|
||||||
pi->format = di->format;
|
pi->format = di->format;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -312,14 +317,15 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||||
unw_dyn_info_t *di = ptr;
|
unw_dyn_info_t *di = ptr;
|
||||||
const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text;
|
const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text;
|
||||||
long n;
|
long n;
|
||||||
Elf64_Addr load_base;
|
Elf64_Addr load_base, segbase = 0;
|
||||||
|
|
||||||
/* Make sure struct dl_phdr_info is at least as big as we need. */
|
/* Make sure struct dl_phdr_info is at least as big as we need. */
|
||||||
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
|
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
|
||||||
+ sizeof (info->dlpi_phnum))
|
+ sizeof (info->dlpi_phnum))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
debug (100, "unwind: checking `%s'\n", info->dlpi_name);
|
debug (100, "unwind: checking `%s' (load_base=%lx)\n",
|
||||||
|
info->dlpi_name, info->dlpi_addr);
|
||||||
|
|
||||||
phdr = info->dlpi_phdr;
|
phdr = info->dlpi_phdr;
|
||||||
load_base = info->dlpi_addr;
|
load_base = info->dlpi_addr;
|
||||||
|
@ -346,6 +352,26 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||||
if (!p_text || !p_unwind)
|
if (!p_text || !p_unwind)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (likely (p_unwind->p_vaddr >= p_text->p_vaddr
|
||||||
|
&& p_unwind->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
|
||||||
|
/* normal case: unwind table is inside text segment */
|
||||||
|
segbase = p_text->p_vaddr + load_base;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Special case: unwind table is in some other segment; this
|
||||||
|
happens for the Linux kernel's gate DSO, for example. */
|
||||||
|
phdr = info->dlpi_phdr;
|
||||||
|
for (n = info->dlpi_phnum; --n >= 0; phdr++)
|
||||||
|
{
|
||||||
|
if (phdr->p_type == PT_LOAD && p_unwind->p_vaddr >= phdr->p_vaddr
|
||||||
|
&& p_unwind->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
|
||||||
|
{
|
||||||
|
segbase = phdr->p_vaddr + load_base;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (p_dynamic)
|
if (p_dynamic)
|
||||||
{
|
{
|
||||||
/* For dynamicly linked executables and shared libraries,
|
/* For dynamicly linked executables and shared libraries,
|
||||||
|
@ -369,7 +395,7 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||||
di->u.ti.name_ptr = (unw_word_t) info->dlpi_name;
|
di->u.ti.name_ptr = (unw_word_t) info->dlpi_name;
|
||||||
di->u.ti.table_data = (void *) (p_unwind->p_vaddr + load_base);
|
di->u.ti.table_data = (void *) (p_unwind->p_vaddr + load_base);
|
||||||
di->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
|
di->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
|
||||||
di->u.ti.segbase = p_text->p_vaddr + load_base;
|
di->u.ti.segbase = segbase;
|
||||||
|
|
||||||
debug (100, "unwind: found table `%s': segbase=%lx, len=%lu, gp=%lx, "
|
debug (100, "unwind: found table `%s': segbase=%lx, len=%lu, gp=%lx, "
|
||||||
"table_data=%p\n", (char *) di->u.ti.name_ptr, di->u.ti.segbase,
|
"table_data=%p\n", (char *) di->u.ti.name_ptr, di->u.ti.segbase,
|
||||||
|
|
Loading…
Reference in a new issue