1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-07-02 21:51:45 +02:00

(finish_prologue): Iterate over "mask" only if it is non-zero.

(lookup_preg): New function.
(parse_dynamic): Ditto.
(get_proc_info): Take explicit IP argument.
(create_state_record_for): New function, containing most of the code originally
	in ia64_create_state_record().  Don't forget to initialize
	sr->first_region.  Check c->pi.format and parse unwind descriptors or
	dynamically registered unwind info accordingly.
(ia64_get_proc_info): Adjust for extra argument expected by get_proc_info().
(ia64_create_state_record): Do interesting work by calling create_state_record_for().

(Logical change 1.29)
This commit is contained in:
mostang.com!davidm 2002-12-03 08:19:58 +00:00
parent 15eec54cc8
commit b8802b5c11

View file

@ -30,6 +30,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
/* forward declaration: */
static int create_state_record_for (struct ia64_cursor *c,
struct ia64_state_record *sr,
unw_word_t ip);
typedef unsigned long unw_word; typedef unsigned long unw_word;
#define alloc_reg_state() (mempool_alloc (&unw.state_record_pool)) #define alloc_reg_state() (mempool_alloc (&unw.state_record_pool))
@ -292,6 +297,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask,
if (!body) if (!body)
{ {
if (mask)
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
{ {
if (mask & 0x8) if (mask & 0x8)
@ -689,136 +695,235 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg,
#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg) #define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg)
#include "unwind_decoder.h" #include "unwind_decoder.h"
/* parse dynamic unwind info */
static inline const struct ia64_unwind_table_entry * static struct ia64_reg_info *
lookup (struct ia64_unwind_table *table, unw_word_t rel_ip) lookup_preg (int regnum, int memory, struct ia64_state_record *sr)
{ {
const struct ia64_unwind_table_entry *e = 0; int preg;
unsigned long lo, hi, mid;
/* do a binary search for right entry: */ switch (regnum)
for (lo = 0, hi = table->info.length; lo < hi;)
{ {
mid = (lo + hi) / 2; case UNW_IA64_AR_BSP: preg = IA64_REG_BSP; break;
e = (struct ia64_unwind_table_entry *) table->info.array + mid; case UNW_IA64_AR_BSPSTORE: preg = IA64_REG_BSPSTORE; break;
if (rel_ip < e->start_offset) case UNW_IA64_AR_FPSR: preg = IA64_REG_FPSR; break;
hi = mid; case UNW_IA64_AR_LC: preg = IA64_REG_LC; break;
else if (rel_ip >= e->end_offset) case UNW_IA64_AR_PFS: preg = IA64_REG_PFS; break;
lo = mid + 1; case UNW_IA64_AR_RNAT: preg = IA64_REG_RNAT; break;
case UNW_IA64_AR_UNAT: preg = IA64_REG_UNAT; break;
case UNW_IA64_BR + 0: preg = IA64_REG_RP; break;
case UNW_IA64_PR: preg = IA64_REG_PR; break;
case UNW_IA64_SP: preg = IA64_REG_PSP; break;
case UNW_IA64_NAT:
if (memory)
preg = IA64_REG_PRI_UNAT_MEM;
else else
preg = IA64_REG_PRI_UNAT_GR;
break; break;
}
if (rel_ip < e->start_offset || rel_ip >= e->end_offset) case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
preg = IA64_REG_R4 + (regnum - (UNW_IA64_GR + 4));
break;
case UNW_IA64_BR + 1 ... UNW_IA64_BR + 5:
preg = IA64_REG_B1 + (regnum - UNW_IA64_BR);
break;
case UNW_IA64_FR + 2 ... UNW_IA64_FR + 5:
preg = IA64_REG_F2 + (regnum - (UNW_IA64_FR + 2));
break;
case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31:
preg = IA64_REG_F16 + (regnum - (UNW_IA64_FR + 16));
break;
default:
dprintf ("unwind.%s: invalid register number %d\n",
__FUNCTION__, regnum);
return NULL; return NULL;
return e; }
return sr->curr.reg + preg;
} }
static int static int
get_proc_info (struct ia64_cursor *c) parse_dynamic (struct ia64_cursor *c, struct ia64_state_record *sr)
{ {
const struct ia64_unwind_table_entry *e = 0; unw_dyn_info_t *di = c->pi.unwind_info;
struct ia64_unwind_table *table; unw_dyn_proc_info_t *proc = &di->u.pi;
unw_word_t segbase, len; unw_dyn_region_info_t *r;
uint8_t *dp, *desc_end; struct ia64_reg_info *ri;
unw_ia64_table_t info; unw_word_t val, new_ip;
unw_word_t ip = c->ip; enum ia64_where where;
uint64_t hdr; unw_dyn_op_t *op;
int ret; int32_t when;
int16_t qp;
int memory;
/* search the unwind tables for IP: */ for (r = proc->regions; r; r = r->next)
{
/* all regions are treated as prologue regions: */
desc_prologue (0, r->insn_count, 0, 0, sr);
for (table = c->as->tables; table; table = table->next) for (op = r->op; 1; ++op)
if (ip >= table->info.start && ip < table->info.end) {
when = op->when;
val = op->val;
qp = op->qp;
if (!desc_is_active (qp, when, sr))
continue;
switch (op->tag)
{
case UNW_DYN_SAVE_REG:
memory = 0;
if ((unsigned) (val - UNW_IA64_GR) < 128)
where = IA64_WHERE_GR;
else if ((unsigned) (val - UNW_IA64_FR) < 128)
where = IA64_WHERE_FR;
else if ((unsigned) (val - UNW_IA64_BR) < 8)
where = IA64_WHERE_BR;
else
{
dprintf ("unwind.%s: can't save to register number %d\n",
__FUNCTION__, (int) op->reg);
return -UNW_EBADREG;
}
/* fall through */
update_reg_info:
ri = lookup_preg (op->reg, memory, sr);
if (!ri)
return -UNW_EBADREG;
ri->where = where;
ri->when = when;
ri->val = val;
break; break;
if (!table) case UNW_DYN_SPILL_FP_REL:
memory = 1;
where = IA64_WHERE_PSPREL;
goto update_reg_info;
case UNW_DYN_SPILL_SP_REL:
memory = 1;
where = IA64_WHERE_SPREL;
goto update_reg_info;
case UNW_DYN_ADD:
if (op->reg == UNW_IA64_SP)
{ {
ret = ia64_acquire_unwind_info (c, ip, &info); if (val & 0xf)
if (ret < 0)
return ret;
segbase = info.segbase;
len = info.length;
table = mempool_alloc (&unw.unwind_table_pool);
if (!table)
{ {
dprintf ("%s: out of memory\n", __FUNCTION__); dprintf ("unwind.%s: frame-size %ld not an integer "
return -UNW_ENOMEM; "multiple of 16\n",
__FUNCTION__, (long) op->val);
return -UNW_EINVAL;
} }
table->info = info;
/* XXX LOCK { */
table->next = c->as->tables;
c->as->tables = table;
/* XXX LOCK } */
} }
else
assert (ip >= table->info.start && ip < table->info.end);
e = lookup (table, ip - table->info.segbase);
if (!e)
{ {
memset (&c->pi, 0, sizeof (c->pi)); dprintf ("unwind.%s: can only ADD to stack-pointer\n",
return 0; __FUNCTION__);
return -UNW_EBADREG;
} }
break;
hdr = *(uint64_t *) (table->info.unwind_info_base + e->info_offset); case UNW_DYN_POP_FRAMES:
dp = (uint8_t *) (table->info.unwind_info_base + e->info_offset + 8); sr->epilogue_start
desc_end = dp + 8 * IA64_UNW_LENGTH (hdr); = sr->region_start + sr->region_len - 1 - op->when;
sr->epilogue_count = op->val;
break;
c->pi.flags = 0; case UNW_DYN_LABEL_STATE:
c->pi.gp = table->info.gp; desc_label_state(op->val, sr);
c->pi.proc_start = table->info.segbase + e->start_offset; break;
c->pi.pers_addr = (uint64_t *) desc_end;
c->pi.desc = dp;
if (IA64_UNW_VER (hdr) != 1) case UNW_DYN_COPY_STATE:
return -UNW_EBADVERSION; desc_copy_state(op->val, sr);
break;
if (IA64_UNW_FLAG_EHANDLER (hdr) | IA64_UNW_FLAG_UHANDLER (hdr)) case UNW_DYN_ALIAS:
c->pi.flags |= IA64_FLAG_HAS_HANDLER; while (sr->curr.next)
pop (sr);
new_ip = op->val + ((sr->when_target / 3) * 16
+ (sr->when_target % 3));
return create_state_record_for (c, sr, new_ip);
case UNW_DYN_STOP:
goto end_of_ops;
}
}
}
while (!sr->done);
end_of_ops:
return 0; return 0;
} }
int static int
ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr) get_proc_info (struct ia64_cursor *c, unw_word_t ip)
{ {
unw_word_t ip = c->ip, predicates = c->pr; int ret;
/* check dynamic info first --- it overrides everything else */
ret = unw_find_dynamic_proc_info (c->as, ip, &c->pi, c->as_arg);
if (ret != -UNW_ENOINFO)
return ret;
return ia64_find_proc_info (c, ip);
}
static int
create_state_record_for (struct ia64_cursor *c, struct ia64_state_record *sr,
unw_word_t ip)
{
unw_word_t predicates = c->pr;
struct ia64_reg_info *r; struct ia64_reg_info *r;
uint8_t *dp, *desc_end; uint8_t *dp, *desc_end;
int ret; int ret;
STAT(unsigned long start;)
STAT(++unw.stat.parse.calls; start = ia64_get_itc ());
/* build state record */ /* build state record */
memset (sr, 0, sizeof (*sr)); memset (sr, 0, sizeof (*sr));
for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r) for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
r->when = IA64_WHEN_NEVER; r->when = IA64_WHEN_NEVER;
sr->pr_val = predicates; sr->pr_val = predicates;
sr->first_region = 1;
ret = get_proc_info (c); ret = get_proc_info (c, ip);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!c->pi.desc) if (!c->pi.unwind_info)
{ {
/* No info, return default unwinder (leaf proc, no mem stack, no /* No info, return default unwinder (leaf proc, no mem stack, no
saved regs), rp in b0, pfs in ar.pfs. */ saved regs), rp in b0, pfs in ar.pfs. */
dprintf ("unwind: no unwind info for ip=0x%lx\n", (long) ip); dprintf ("unwind.parser: no unwind info for ip=0x%lx\n", (long) ip);
sr->curr.reg[IA64_REG_RP].where = IA64_WHERE_BR; sr->curr.reg[IA64_REG_RP].where = IA64_WHERE_BR;
sr->curr.reg[IA64_REG_RP].when = -1; sr->curr.reg[IA64_REG_RP].when = -1;
sr->curr.reg[IA64_REG_RP].val = 0; sr->curr.reg[IA64_REG_RP].val = 0;
goto out; goto out;
} }
sr->when_target = (3 * ((ip & ~0xfUL) - c->pi.proc_start) sr->when_target = (3 * ((ip & ~0xfUL) - c->pi.start_ip) / 16 + (ip & 0xfUL));
/ 16 + (ip & 0xfUL));
dp = c->pi.desc; c->pi.flags &= ~IA64_FLAG_SIGTRAMP;
desc_end = (uint8_t *) c->pi.pers_addr;
if (c->pi.format == UNW_INFO_FORMAT_TABLE)
{
dp = c->pi.unwind_info;
desc_end = dp + c->pi.unwind_info_size;
while (!sr->done && dp < desc_end) while (!sr->done && dp < desc_end)
dp = unw_decode (dp, sr->in_body, sr); dp = unw_decode (dp, sr->in_body, sr);
}
else
{
ret = parse_dynamic (c, sr);
if (ret < 0)
return ret;
}
c->pi.flags |= sr->flags; c->pi.flags |= sr->flags;
@ -852,8 +957,8 @@ ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
#if IA64_UNW_DEBUG #if IA64_UNW_DEBUG
if (unw.debug_level > 0) if (unw.debug_level > 0)
{ {
printf ("unwind: state record for func 0x%lx, t=%u:\n", printf ("unwind: state record for func 0x%lx, t=%u (flags=0x%lx):\n",
(long) c->pi.proc_start, sr->when_target); (long) c->pi.start_ip, sr->when_target, (long) c->pi.flags);
for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r) for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
{ {
if (r->where != IA64_WHERE_NONE || r->when != IA64_WHEN_NEVER) if (r->where != IA64_WHERE_NONE || r->when != IA64_WHEN_NEVER)
@ -892,6 +997,12 @@ ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
return 0; return 0;
} }
int
ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
{
return create_state_record_for(c, sr, c->ip);
}
int int
ia64_free_state_record (struct ia64_state_record *sr) ia64_free_state_record (struct ia64_state_record *sr)
{ {
@ -899,7 +1010,6 @@ ia64_free_state_record (struct ia64_state_record *sr)
/* free labeled register states & stack: */ /* free labeled register states & stack: */
STAT(parse_start = ia64_get_itc ());
for (ls = sr->labeled_states; ls; ls = next) for (ls = sr->labeled_states; ls; ls = next)
{ {
next = ls->next; next = ls->next;
@ -908,12 +1018,11 @@ ia64_free_state_record (struct ia64_state_record *sr)
} }
free_state_stack (&sr->curr); free_state_stack (&sr->curr);
STAT(unw.stat.script.parse_time += ia64_get_itc () - parse_start);
return 0; return 0;
} }
int int
ia64_get_proc_info (struct ia64_cursor *c) ia64_make_proc_info (struct ia64_cursor *c)
{ {
if (c->as->caching_policy != UNW_CACHE_NONE) if (c->as->caching_policy != UNW_CACHE_NONE)
{ {
@ -925,5 +1034,6 @@ ia64_get_proc_info (struct ia64_cursor *c)
return 0; return 0;
} }
} }
return get_proc_info (c);
return get_proc_info (c, c->ip);
} }