1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-25 16:47:38 +01:00

When printing a value of type unw_word_t, use the %lu format and

cast the value to (long).

(struct ia64_labeled_state): New type.
(alloc_labeled_state): New macro.
(free_labeled_state): Ditto.
(push, pop): Update for new ia64_state_record layout.
(dup_state_stack): New function.
(free_state_stack): Ditto.
(desc_copy_state): Make it restore the entire stack of states, not
	just the current one.
(desc_label_state): Make it save the entire stack of states, not
	just the current one.
(ia64_free_state_record): Free the list of labeled states.

(desc_prologue): Terminate parsing at end of region regardless of
	whether the next region is a body or a prologue.

(lookup): Verify that unwind table entry found by binary search
	really includes the desired IP.  If not, return NULL.
(get_proc_info): Adjust for move of start/end from unwind table
	to the unwind table info.  Return -UNW_ENOMEM if unable
	to allocate a new table.  If unwind entry does not exist
	for desired IP, clear the procedure info to zero.  Check
	the unwind version number and return -UNW_EBADVERSION if
	it is not 1.

(Logical change 1.5)
This commit is contained in:
(none)!davidm 2002-02-22 21:58:53 +00:00
parent 8dbd577e05
commit 68ffdc1fce

View file

@ -28,12 +28,21 @@ License. */
#include "unwind_i.h" #include "unwind_i.h"
struct ia64_labeled_state {
struct ia64_labeled_state *next; /* next label (or NULL) */
unsigned long label; /* label for this state */
struct ia64_reg_state saved_state;
};
typedef unsigned long unw_word; typedef unsigned long unw_word;
/* XXX fix these to use private allocator: */
#define alloc_reg_state() (malloc (sizeof(struct ia64_state_record))) #define alloc_reg_state() (malloc (sizeof(struct ia64_state_record)))
#define free_reg_state(usr) (free (usr)) #define free_reg_state(usr) (free (usr))
#define alloc_labeled_state() (malloc (sizeof(struct ia64_labeled_state)))
#define free_labeled_state(usr) (free (usr))
/* Unwind decoder routines */ /* Routines to manipulate the state stack. */
static inline void static inline void
push (struct ia64_state_record *sr) push (struct ia64_state_record *sr)
@ -47,25 +56,64 @@ push (struct ia64_state_record *sr)
return; return;
} }
memcpy (rs, &sr->curr, sizeof (*rs)); memcpy (rs, &sr->curr, sizeof (*rs));
rs->next = sr->stack; sr->curr.next = rs;
sr->stack = rs;
} }
static void static void
pop (struct ia64_state_record *sr) pop (struct ia64_state_record *sr)
{ {
struct ia64_reg_state *rs; struct ia64_reg_state *rs = sr->curr.next;
if (!sr->stack) if (!rs)
{ {
fprintf (stderr, "unwind: stack underflow!\n"); fprintf (stderr, "unwind: stack underflow!\n");
return; return;
} }
rs = sr->stack; memcpy (&sr->curr, rs, sizeof (*rs));
sr->stack = rs->next;
free_reg_state (rs); free_reg_state (rs);
} }
/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */
static struct ia64_reg_state *
dup_state_stack (struct ia64_reg_state *rs)
{
struct ia64_reg_state *copy, *prev = NULL, *first = NULL;
while (rs)
{
copy = alloc_reg_state ();
if (!copy)
{
fprintf (stderr, "unwind.dup_state_stack: out of memory\n");
return NULL;
}
memcpy (copy, rs, sizeof (*copy));
if (first)
prev->next = copy;
else
first = copy;
rs = rs->next;
prev = copy;
}
return first;
}
/* Free all stacked register states (but not RS itself). */
static void
free_state_stack (struct ia64_reg_state *rs)
{
struct ia64_reg_state *p, *next;
for (p = rs->next; p != NULL; p = next)
{
next = p->next;
free_reg_state (p);
}
rs->next = NULL;
}
/* Unwind decoder routines */
static enum ia64_pregnum __attribute__ ((const)) static enum ia64_pregnum __attribute__ ((const))
decode_abreg (unsigned char abreg, int memory) decode_abreg (unsigned char abreg, int memory)
{ {
@ -229,7 +277,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask,
sr->first_region = 0; sr->first_region = 0;
/* check if we're done: */ /* check if we're done: */
if (body && sr->when_target < sr->region_start + sr->region_len) if (sr->when_target < sr->region_start + sr->region_len)
{ {
sr->done = 1; sr->done = 1;
return; return;
@ -463,37 +511,42 @@ desc_epilogue (unw_word t, unw_word ecount, struct ia64_state_record *sr)
static inline void static inline void
desc_copy_state (unw_word label, struct ia64_state_record *sr) desc_copy_state (unw_word label, struct ia64_state_record *sr)
{ {
struct ia64_reg_state *rs; struct ia64_labeled_state *ls;
for (rs = sr->reg_state_list; rs; rs = rs->next) for (ls = sr->labeled_states; ls; ls = ls->next)
{ {
if (rs->label == label) if (ls->label == label)
{ {
memcpy (&sr->curr, rs, sizeof (sr->curr)); free_state_stack (&sr->curr);
memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
sr->curr.next = dup_state_stack (ls->saved_state.next);
return; return;
} }
} }
fprintf (stderr, "unwind: failed to find state labelled 0x%lx\n", label); fprintf (stderr, "unwind: failed to find state labeled 0x%lx\n", label);
} }
static inline void static inline void
desc_label_state (unw_word label, struct ia64_state_record *sr) desc_label_state (unw_word label, struct ia64_state_record *sr)
{ {
struct ia64_reg_state *rs; struct ia64_labeled_state *ls;
rs = alloc_reg_state (); ls = alloc_labeled_state ();
if (!rs) if (!ls)
{ {
fprintf (stderr, "unwind: cannot stack!\n"); fprintf (stderr, "unwind.desc_label_state(): out of memory\n");
return; return;
} }
memcpy (rs, &sr->curr, sizeof (*rs)); ls->label = label;
rs->label = label; memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
rs->next = sr->reg_state_list; ls->saved_state.next = dup_state_stack (sr->curr.next);
sr->reg_state_list = rs;
/* insert into list of labeled states: */
ls->next = sr->labeled_states;
sr->labeled_states = ls;
} }
/** General descriptors. */ /* General descriptors. */
static inline int static inline int
desc_is_active (unsigned char qp, unw_word t, struct ia64_state_record *sr) desc_is_active (unsigned char qp, unw_word t, struct ia64_state_record *sr)
@ -651,7 +704,7 @@ lookup (struct ia64_unwind_table *table, unw_word_t rel_ip)
for (lo = 0, hi = table->info.length; lo < hi;) for (lo = 0, hi = table->info.length; lo < hi;)
{ {
mid = (lo + hi) / 2; mid = (lo + hi) / 2;
e = &table->info.array[mid]; e = (struct ia64_unwind_table_entry *) table->info.array + mid;
if (rel_ip < e->start_offset) if (rel_ip < e->start_offset)
hi = mid; hi = mid;
else if (rel_ip >= e->end_offset) else if (rel_ip >= e->end_offset)
@ -659,6 +712,8 @@ lookup (struct ia64_unwind_table *table, unw_word_t rel_ip)
else else
break; break;
} }
if (rel_ip < e->start_offset || rel_ip >= e->end_offset)
return NULL;
return e; return e;
} }
@ -677,7 +732,7 @@ get_proc_info (struct ia64_cursor *c)
/* search the kernels and the modules' unwind tables for IP: */ /* search the kernels and the modules' unwind tables for IP: */
for (table = unw.tables; table; table = table->next) for (table = unw.tables; table; table = table->next)
if (ip >= table->start && ip < table->end) if (ip >= table->info.start && ip < table->info.end)
break; break;
if (!table) if (!table)
@ -694,22 +749,23 @@ get_proc_info (struct ia64_cursor *c)
if (!table) if (!table)
{ {
dprintf ("%s: out of memory\n", __FUNCTION__); dprintf ("%s: out of memory\n", __FUNCTION__);
return -1; return -UNW_ENOMEM;
} }
memset (table, 0, sizeof (*table));
table->info = info; table->info = info;
table->start = segbase + table->info.array[0].start_offset;
table->end = segbase + table->info.array[len - 1].end_offset;
/* XXX LOCK { */ /* XXX LOCK { */
table->next = unw.tables; table->next = unw.tables;
unw.tables = table; unw.tables = table;
/* XXX LOCK } */ /* XXX LOCK } */
} }
assert (ip >= table->start && ip < table->end); assert (ip >= table->info.start && ip < table->info.end);
e = lookup (table, ip - table->info.segbase); e = lookup (table, ip - table->info.segbase);
if (!e)
{
memset (&c->pi, 0, sizeof (c->pi));
return 0;
}
hdr = *(uint64_t *) (table->info.unwind_info_base + e->info_offset); hdr = *(uint64_t *) (table->info.unwind_info_base + e->info_offset);
dp = (uint8_t *) (table->info.unwind_info_base + e->info_offset + 8); dp = (uint8_t *) (table->info.unwind_info_base + e->info_offset + 8);
@ -721,7 +777,9 @@ get_proc_info (struct ia64_cursor *c)
c->pi.pers_addr = (uint64_t *) desc_end; c->pi.pers_addr = (uint64_t *) desc_end;
c->pi.desc = dp; c->pi.desc = dp;
/* XXX Perhaps check UNW_VER / UNW_FLAG_OSMASK ? */ if (IA64_UNW_VER (hdr) != 1)
return -UNW_EBADVERSION;
if (IA64_UNW_FLAG_EHANDLER (hdr) | IA64_UNW_FLAG_UHANDLER (hdr)) if (IA64_UNW_FLAG_EHANDLER (hdr) | IA64_UNW_FLAG_UHANDLER (hdr))
c->pi.flags |= IA64_FLAG_HAS_HANDLER; c->pi.flags |= IA64_FLAG_HAS_HANDLER;
@ -752,7 +810,7 @@ ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
{ {
/* No info, return default unwinder (leaf proc, no mem stack, no /* No info, return default unwinder (leaf proc, no mem stack, no
saved regs). */ saved regs). */
dprintf ("unwind: no unwind info for ip=0x%lx\n", ip); dprintf ("unwind: 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;
@ -800,7 +858,7 @@ ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
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:\n",
c->pi.proc_start, sr->when_target); (long) c->pi.proc_start, sr->when_target);
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)
@ -809,22 +867,23 @@ ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
switch (r->where) switch (r->where)
{ {
case IA64_WHERE_GR: case IA64_WHERE_GR:
printf ("r%lu", r->val); printf ("r%lu", (long) r->val);
break; break;
case IA64_WHERE_FR: case IA64_WHERE_FR:
printf ("f%lu", r->val); printf ("f%lu", (long) r->val);
break; break;
case IA64_WHERE_BR: case IA64_WHERE_BR:
printf ("b%lu", r->val); printf ("b%lu", (long) r->val);
break; break;
case IA64_WHERE_SPREL: case IA64_WHERE_SPREL:
printf ("[sp+0x%lx]", r->val); printf ("[sp+0x%lx]", (long) r->val);
break; break;
case IA64_WHERE_PSPREL: case IA64_WHERE_PSPREL:
printf ("[psp+0x%lx]", r->val); printf ("[psp+0x%lx]", (long) r->val);
break; break;
case IA64_WHERE_NONE: case IA64_WHERE_NONE:
printf ("%s+0x%lx", unw.preg_name[r - sr->curr.reg], r->val); printf ("%s+0x%lx",
unw.preg_name[r - sr->curr.reg], (long) r->val);
break; break;
default: default:
printf ("BADWHERE(%d)", r->where); printf ("BADWHERE(%d)", r->where);
@ -841,18 +900,18 @@ ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
int int
ia64_free_state_record (struct ia64_state_record *sr) ia64_free_state_record (struct ia64_state_record *sr)
{ {
struct ia64_reg_state *rs, *next; struct ia64_labeled_state *ls, *next;
/* free labelled register states & stack: */ /* free labeled register states & stack: */
STAT(parse_start = ia64_get_itc ()); STAT(parse_start = ia64_get_itc ());
for (rs = sr->reg_state_list; rs; rs = next) for (ls = sr->labeled_states; ls; ls = next)
{ {
next = rs->next; next = ls->next;
free_reg_state (rs); free_state_stack (&ls->saved_state);
free_labeled_state (ls);
} }
while (sr->stack) free_state_stack (&sr->curr);
pop (sr);
STAT(unw.stat.script.parse_time += ia64_get_itc () - parse_start); STAT(unw.stat.script.parse_time += ia64_get_itc () - parse_start);
return 0; return 0;