mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-02-17 02:31:41 +01:00
(remote_read): New macro.
(remote_lookup): New function. (_Uia64_search_unwind_table): Handle UNW_INFO_FORMAT_REMOTE_TABLE. (_Uia64_find_dyn_list): Take unw_dyn_info_t pointer argument instead of its members and handle UNW_INFO_FORMAT_REMOTE_TABLE. (Logical change 1.126)
This commit is contained in:
parent
13147e5e9c
commit
7cec620ea8
1 changed files with 115 additions and 15 deletions
|
@ -10,6 +10,7 @@ This file is part of libunwind. */
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#ifdef HAVE_IA64INTRIN_H
|
||||
# include <ia64intrin.h>
|
||||
#endif
|
||||
|
@ -48,6 +49,56 @@ lookup (struct ia64_table_entry *table, size_t table_size, unw_word_t rel_ip)
|
|||
return e;
|
||||
}
|
||||
|
||||
/* Helper macro for reading an ia64_table_entry from remote memory. */
|
||||
#define remote_read(addr, member) \
|
||||
(*a->access_mem) (as, (addr) + offsetof (struct ia64_table_entry, \
|
||||
member), &member, 0, arg)
|
||||
|
||||
/* Lookup an unwind-table entry in remote memory. Returns 1 if an
|
||||
entry is found, 0 if no entry is found, negative if an error
|
||||
occurred reading remote memory. */
|
||||
static int
|
||||
remote_lookup (unw_addr_space_t as,
|
||||
unw_word_t table, size_t table_size, unw_word_t rel_ip,
|
||||
struct ia64_table_entry *e, void *arg)
|
||||
{
|
||||
unw_word_t e_addr = 0, start_offset, end_offset, info_offset;
|
||||
unw_accessors_t *a = unw_get_accessors (as);
|
||||
unsigned long lo, hi, mid;
|
||||
int ret;
|
||||
|
||||
/* do a binary search for right entry: */
|
||||
for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
e_addr = table + mid * sizeof (struct ia64_table_entry);
|
||||
if ((ret = remote_read (e_addr, start_offset)) < 0)
|
||||
return ret;
|
||||
|
||||
if (rel_ip < start_offset)
|
||||
hi = mid;
|
||||
else
|
||||
{
|
||||
if ((ret = remote_read (e_addr, end_offset)) < 0)
|
||||
return ret;
|
||||
|
||||
if (rel_ip >= end_offset)
|
||||
lo = mid + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rel_ip < start_offset || rel_ip >= end_offset)
|
||||
return 0;
|
||||
e->start_offset = start_offset;
|
||||
e->end_offset = end_offset;
|
||||
|
||||
if ((ret = remote_read (e_addr, info_offset)) < 0)
|
||||
return ret;
|
||||
e->info_offset = info_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_local_addr_space (unw_addr_space_t as)
|
||||
{
|
||||
|
@ -68,20 +119,39 @@ _Uia64_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
|
|||
int need_unwind_info, void *arg)
|
||||
{
|
||||
unw_word_t addr, hdr_addr, info_addr, info_end_addr, hdr, *wp;
|
||||
unw_word_t handler_offset;
|
||||
unw_word_t handler_offset, segbase;
|
||||
const struct ia64_table_entry *e;
|
||||
struct ia64_table_entry ent;
|
||||
unw_accessors_t *a = unw_get_accessors (as);
|
||||
int ret;
|
||||
|
||||
assert (di->format == UNW_INFO_FORMAT_TABLE
|
||||
assert ((di->format == UNW_INFO_FORMAT_TABLE
|
||||
|| di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
|
||||
&& (ip >= di->start_ip && ip < di->end_ip));
|
||||
|
||||
pi->flags = 0;
|
||||
pi->unwind_info = 0;
|
||||
pi->handler = 0;
|
||||
|
||||
e = lookup ((struct ia64_table_entry *) di->u.ti.table_data,
|
||||
di->u.ti.table_len * sizeof (unw_word_t), ip - di->u.ti.segbase);
|
||||
if (likely (di->format == UNW_INFO_FORMAT_TABLE))
|
||||
{
|
||||
segbase = di->u.ti.segbase;
|
||||
e = lookup ((struct ia64_table_entry *) di->u.ti.table_data,
|
||||
di->u.ti.table_len * sizeof (unw_word_t),
|
||||
ip - segbase);
|
||||
}
|
||||
else
|
||||
{
|
||||
segbase = di->u.rti.segbase;
|
||||
if ((ret = remote_lookup (as, di->u.rti.table_data,
|
||||
di->u.rti.table_len * sizeof (unw_word_t),
|
||||
ip - segbase, &ent, arg)) < 0)
|
||||
return ret;
|
||||
if (ret)
|
||||
e = &ent;
|
||||
else
|
||||
e = NULL; /* no info found */
|
||||
}
|
||||
if (!e)
|
||||
{
|
||||
/* IP is inside this table's range, but there is no explicit
|
||||
|
@ -95,10 +165,10 @@ _Uia64_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
pi->start_ip = e->start_offset + di->u.ti.segbase;
|
||||
pi->end_ip = e->end_offset + di->u.ti.segbase;
|
||||
pi->start_ip = e->start_offset + segbase;
|
||||
pi->end_ip = e->end_offset + segbase;
|
||||
|
||||
hdr_addr = e->info_offset + di->u.ti.segbase;
|
||||
hdr_addr = e->info_offset + segbase;
|
||||
info_addr = hdr_addr + 8;
|
||||
|
||||
/* read the header word: */
|
||||
|
@ -172,18 +242,49 @@ tdep_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
|
|||
}
|
||||
|
||||
unw_word_t
|
||||
_Uia64_find_dyn_list (unw_addr_space_t as, void *table, size_t table_size,
|
||||
unw_word_t segbase, unw_word_t gp, void *arg)
|
||||
_Uia64_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg)
|
||||
{
|
||||
unw_word_t hdr_addr, info_addr, hdr, directives, pers, cookie, off;
|
||||
unw_word_t start_offset, end_offset, info_offset, e_addr, segbase;
|
||||
unw_accessors_t *a = unw_get_accessors (as);
|
||||
struct ia64_table_entry *tab = table;
|
||||
struct ia64_table_entry *e;
|
||||
size_t table_size;
|
||||
unw_word_t gp = di->gp;
|
||||
int ret;
|
||||
|
||||
if (table_size < sizeof (struct ia64_table_entry))
|
||||
return 0;
|
||||
switch (di->format)
|
||||
{
|
||||
case UNW_INFO_FORMAT_DYNAMIC:
|
||||
default:
|
||||
return 0;
|
||||
|
||||
if (tab[0].start_offset != tab[0].end_offset)
|
||||
case UNW_INFO_FORMAT_TABLE:
|
||||
e = (struct ia64_table_entry *) di->u.ti.table_data;
|
||||
table_size = di->u.ti.table_len * sizeof (di->u.ti.table_data[0]);
|
||||
segbase = di->u.ti.segbase;
|
||||
if (table_size < sizeof (struct ia64_table_entry))
|
||||
return 0;
|
||||
start_offset = e[0].start_offset;
|
||||
end_offset = e[0].end_offset;
|
||||
info_offset = e[0].info_offset;
|
||||
break;
|
||||
|
||||
case UNW_INFO_FORMAT_REMOTE_TABLE:
|
||||
e_addr = di->u.rti.table_data;
|
||||
table_size = di->u.rti.table_len * sizeof (unw_word_t);
|
||||
segbase = di->u.rti.segbase;
|
||||
if (table_size < sizeof (struct ia64_table_entry))
|
||||
return 0;
|
||||
|
||||
if ((ret = remote_read (e_addr, start_offset) < 0)
|
||||
|| (ret = remote_read (e_addr, end_offset) < 0)
|
||||
|| (ret = remote_read (e_addr, info_offset) < 0))
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (start_offset != end_offset)
|
||||
/* dyn-list entry cover a zero-length "procedure" and should be
|
||||
first entry (note: technically a binary could contain code
|
||||
below the segment base, but this doesn't happen for normal
|
||||
|
@ -192,7 +293,7 @@ _Uia64_find_dyn_list (unw_addr_space_t as, void *table, size_t table_size,
|
|||
have to provide its own (slower) version of this routine. */
|
||||
return 0;
|
||||
|
||||
hdr_addr = tab[0].info_offset + segbase;
|
||||
hdr_addr = info_offset + segbase;
|
||||
info_addr = hdr_addr + 8;
|
||||
|
||||
/* read the header word: */
|
||||
|
@ -230,7 +331,6 @@ _Uia64_find_dyn_list (unw_addr_space_t as, void *table, size_t table_size,
|
|||
#if defined(HAVE_DL_ITERATE_PHDR)
|
||||
|
||||
#include <link.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
|
||||
|
|
Loading…
Add table
Reference in a new issue