#include "tconfig.h"
#ifndef inhibit_libc
#include <stdlib.h>
#include <unistd.h>
#endif
#include "defaults.h"
#ifdef DWARF2_UNWIND_INFO
#include "dwarf2.h"
#include <stddef.h>
#include "frame.h"
#include "gthr.h"
#ifdef __DEBUG_EH__
#include <stdio.h>
#endif
#ifdef TRACE_EXCEPTIONS
int __trace_exceptions = 0;
#else
#define TRACE_EXCEPTIONS(MASK,ARG0,ARG1)
#endif
#ifndef GET_AND_LOCK_TARGET_OBJECT_LIST
#ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
#else
static __gthread_mutex_t object_mutex;
#endif
#endif
#ifdef abort
#undef abort
#endif
typedef int sword __attribute__ ((mode (SI)));
typedef unsigned int uword __attribute__ ((mode (SI)));
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
typedef int saddr __attribute__ ((mode (pointer)));
typedef unsigned char ubyte;
struct dwarf_cie {
uword length;
sword CIE_id;
ubyte version;
char augmentation[0];
} __attribute__ ((packed, aligned (__alignof__ (void *))));
struct dwarf_fde {
uword length;
sword CIE_delta;
void* pc_begin;
uaddr pc_range;
} __attribute__ ((packed, aligned (__alignof__ (void *))));
typedef struct dwarf_fde fde;
#ifndef GET_AND_LOCK_TARGET_OBJECT_LIST
static struct object *objects;
#define GET_AND_LOCK_TARGET_OBJECT_LIST(OB) \
do { \
OB = objects; \
init_object_mutex_once (); \
__gthread_mutex_lock (&object_mutex); \
} while (0)
#define UNLOCK_TARGET_OBJECT_LIST() __gthread_mutex_unlock (&object_mutex)
#endif
struct cie_info {
char *augmentation;
void *eh_ptr;
int code_align;
int data_align;
unsigned ra_regno;
};
struct frame_state_internal
{
struct frame_state s;
struct frame_state_internal *saved_state;
};
#ifndef GET_DWARF2_FDE_INITIAL_PC
#define GET_DWARF2_FDE_INITIAL_PC(fde_ptr) (fde_ptr->pc_begin)
#endif
#define init_object_mutex_once()
#if __GTHREADS
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
static void
init_object_mutex (void)
{
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
}
#undef init_object_mutex_once
static void
init_object_mutex_once (void)
{
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
__gthread_once (&once, init_object_mutex);
}
#endif
#endif
static void *
decode_uleb128 (unsigned char *buf, unsigned *r)
{
unsigned shift = 0;
unsigned result = 0;
while (1)
{
unsigned byte = *buf++;
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
*r = result;
return buf;
}
static void *
decode_sleb128 (unsigned char *buf, int *r)
{
unsigned shift = 0;
unsigned result = 0;
unsigned byte;
while (1)
{
byte = *buf++;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
break;
}
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
result |= - (1 << shift);
*r = result;
return buf;
}
union unaligned {
void *p;
unsigned b2 __attribute__ ((mode (HI)));
unsigned b4 __attribute__ ((mode (SI)));
unsigned b8 __attribute__ ((mode (DI)));
} __attribute__ ((packed));
static inline void *
read_pointer (void *p)
{ union unaligned *up = p; return up->p; }
static inline unsigned
read_1byte (void *p)
{ return *(unsigned char *)p; }
static inline unsigned
read_2byte (void *p)
{ union unaligned *up = p; return up->b2; }
static inline unsigned
read_4byte (void *p)
{ union unaligned *up = p; return up->b4; }
static inline unsigned long
read_8byte (void *p)
{ union unaligned *up = p; return up->b8; }
#ifndef READ_DWARF2_UNALIGNED_POINTER
#define READ_DWARF2_UNALIGNED_POINTER(p) read_pointer ((p))
#endif
static inline saddr
fde_compare (const fde *x, const fde *y)
{
return (saddr)GET_DWARF2_FDE_INITIAL_PC (x)
- (saddr)GET_DWARF2_FDE_INITIAL_PC (y);
}
static inline fde *
next_fde (fde *p)
{
return (fde *)(((char *)p) + p->length + sizeof (p->length));
}
typedef struct fde_vector
{
fde **array;
size_t count;
} fde_vector;
typedef struct fde_accumulator
{
fde_vector linear;
fde_vector erratic;
} fde_accumulator;
static inline void
start_fde_sort (fde_accumulator *accu, size_t count)
{
accu->linear.array = (fde **) malloc (sizeof (fde *) * count);
accu->erratic.array = (fde **) malloc (sizeof (fde *) * count);
accu->linear.count = 0;
accu->erratic.count = 0;
}
static inline void
fde_insert (fde_accumulator *accu, fde *this_fde)
{
accu->linear.array[accu->linear.count++] = this_fde;
}
static inline void
fde_split (fde_vector *linear, fde_vector *erratic)
{
size_t count = linear->count;
size_t linear_max = (size_t) -1;
size_t previous_max[count];
size_t i, j;
for (i = 0; i < count; i++)
{
for (j = linear_max;
j != (size_t) -1
&& fde_compare (linear->array[i], linear->array[j]) < 0;
j = previous_max[j])
{
erratic->array[erratic->count++] = linear->array[j];
linear->array[j] = (fde *) NULL;
}
previous_max[i] = j;
linear_max = i;
}
for (i = 0, j = 0; i < count; i++)
if (linear->array[i] != (fde *) NULL)
linear->array[j++] = linear->array[i];
linear->count = j;
}
static inline void
frame_heapsort (fde_vector *erratic)
{
fde ** a = erratic->array;
#define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0)
size_t n = erratic->count;
size_t m = n;
size_t i;
while (m > 0)
{
m--;
for (i = m; 2*i+1 < n; )
{
if (2*i+2 < n
&& fde_compare (a[2*i+2], a[2*i+1]) > 0
&& fde_compare (a[2*i+2], a[i]) > 0)
{
SWAP (a[i], a[2*i+2]);
i = 2*i+2;
}
else if (fde_compare (a[2*i+1], a[i]) > 0)
{
SWAP (a[i], a[2*i+1]);
i = 2*i+1;
}
else
break;
}
}
while (n > 1)
{
n--;
SWAP (a[0], a[n]);
for (i = 0; 2*i+1 < n; )
{
if (2*i+2 < n
&& fde_compare (a[2*i+2], a[2*i+1]) > 0
&& fde_compare (a[2*i+2], a[i]) > 0)
{
SWAP (a[i], a[2*i+2]);
i = 2*i+2;
}
else if (fde_compare (a[2*i+1], a[i]) > 0)
{
SWAP (a[i], a[2*i+1]);
i = 2*i+1;
}
else
break;
}
}
#undef SWAP
}
static void
fde_merge (fde_vector *v1, const fde_vector *v2)
{
size_t i1, i2;
fde * fde2;
i2 = v2->count;
if (i2 > 0)
{
i1 = v1->count;
do {
i2--;
fde2 = v2->array[i2];
while (i1 > 0 && fde_compare (v1->array[i1-1], fde2) > 0)
{
v1->array[i1+i2] = v1->array[i1-1];
i1--;
}
v1->array[i1+i2] = fde2;
} while (i2 > 0);
v1->count += v2->count;
}
}
static
void prune_duplicate_fdes (fde_vector *v)
{
size_t ix, num, dupcount;
num = v->count;
if (num <= 1)
return;
dupcount = 0;
for (ix = 0; ix < num - 1; ++ix)
{
if (fde_compare (v->array[ix], v->array[ix+1]) == 0)
{
if (v->array[ix]->pc_range != v->array[ix+1]->pc_range)
{
#ifdef __DEBUG_EH__
fprintf (stderr, "####"
" index %d,%d compare equal (PC=%08x), but pc_ranges differ"
" (%d != %d)\n####\n", ix, ix+1,
GET_DWARF2_FDE_INITIAL_PC (v->array[ix]),
v->array[ix]->pc_range,
v->array[ix+1]->pc_range);
#endif
#ifdef PLAUSIBLE_PC_RANGE
if (PLAUSIBLE_PC_RANGE (GET_DWARF2_FDE_INITIAL_PC (v->array[ix]),
v->array[ix]->pc_range))
{
#ifdef __DEBUG_EH__
fprintf (stderr, "1st item (len %d) deemed more plausible\n",
v->array[ix]->pc_range);
#endif
v->array[ix+1] = v->array[ix];
}
#else
__terminate ();
#endif
}
++dupcount;
#ifdef __DEBUG_EH__
if (__trace_exceptions)
fprintf (stderr, "## %d-th duplicate (index %d) removed (pc=%x)\n",
dupcount, ix, GET_DWARF2_FDE_INITIAL_PC (v->array[ix]));
#endif
v->array[ix] = 0;
v->count--;
}
}
if (dupcount != 0)
{
int w;
for (w = ix = 0; ix < num; ++ix)
if (v->array[ix])
v->array[w++] = v->array[ix];
}
}
static fde **
end_fde_sort (fde_accumulator *accu, size_t count, size_t *final_count)
{
if (accu->linear.count != count)
abort ();
fde_split (&accu->linear, &accu->erratic);
if (accu->linear.count + accu->erratic.count != count)
abort ();
frame_heapsort (&accu->erratic);
prune_duplicate_fdes (&accu->erratic);
fde_merge (&accu->linear, &accu->erratic);
free (accu->erratic.array);
#ifdef __DEBUG_EH__
if (accu->linear.count > 1) {
const fde_vector *v = &accu->linear;
size_t ix, count = v->count;
for (ix = 0; ix < count - 1; ++ix)
{
const fde *f = v->array[ix];
const fde *g = v->array[ix+1];
int cmp = fde_compare (f, g);
if (cmp > 0)
{
fprintf (stderr, (cmp) ? "## NOT SORTED!! " : " Duplicated ");
fprintf (stderr, "(index %d) PC %08x, len %08x (%6d)\n", ix,
GET_DWARF2_FDE_INITIAL_PC (f), f->pc_range, f->pc_range);
fprintf (stderr, "\t(index %d) PC %08x, len %08x (%6d)\n", ix+1,
GET_DWARF2_FDE_INITIAL_PC (g), g->pc_range, g->pc_range);
if (__trace_exceptions & 0x1000) __terminate ();
}
}
}
#endif
*final_count = accu->linear.count;
return accu->linear.array;
}
static size_t
count_fdes (fde *this_fde, long section_size)
{
size_t count;
for (count = 0; (section_size > 0) && (this_fde->length != 0);
this_fde = next_fde (this_fde))
{
section_size -= (this_fde->length + 4);
if (this_fde->CIE_delta == 0 || GET_DWARF2_FDE_INITIAL_PC (this_fde) == 0)
{
TRACE_EXCEPTIONS (TR_FDE, "count_fdes: Skipping CIE address=0x%08x\n",
this_fde);
TRACE_EXCEPTIONS (TR_FDE, " (initial pc was 0x%08x)\n",
GET_DWARF2_FDE_INITIAL_PC (this_fde));
continue;
}
if (((signed long)this_fde->pc_range) <= 0)
{
#ifdef __DEBUG_EH__
fprintf (stderr, "\n### FUNCTION 0x%08x HAS ILLEGAL LENGTH %d, skipping", GET_DWARF2_FDE_INITIAL_PC (this_fde), this_fde->pc_range);
#endif
continue;
}
TRACE_EXCEPTIONS (TR_FDE, "count_fdes: FDE addr=0x%08x\n", this_fde);
TRACE_EXCEPTIONS (TR_FDE, " FDE size=0x%x\n",
this_fde->length);
TRACE_EXCEPTIONS (TR_FDE, " FDE initial PC=0x%08x\n",
GET_DWARF2_FDE_INITIAL_PC (this_fde));
TRACE_EXCEPTIONS (TR_FDE, " FDE func size(pc_range)=0x%08x\n",
this_fde->pc_range);
++count;
}
TRACE_EXCEPTIONS (TR_FDE, "count_fdes: #unused bytes in section=%d\n",section_size);
return count;
}
static void
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr, long section_size)
{
void *pc_begin = *beg_ptr;
void *pc_end = *end_ptr;
for (; (section_size > 0) && (this_fde->length != 0); this_fde = next_fde (this_fde))
{
section_size -= (this_fde->length + 4);
if (this_fde->CIE_delta == 0 || GET_DWARF2_FDE_INITIAL_PC (this_fde) == 0)
continue;
if (((signed long)this_fde->pc_range) <= 0)
continue;
fde_insert (accu, this_fde);
if (GET_DWARF2_FDE_INITIAL_PC (this_fde) < pc_begin)
pc_begin = GET_DWARF2_FDE_INITIAL_PC (this_fde);
if (GET_DWARF2_FDE_INITIAL_PC (this_fde) + this_fde->pc_range > pc_end)
pc_end = GET_DWARF2_FDE_INITIAL_PC (this_fde) + this_fde->pc_range;
}
*beg_ptr = pc_begin;
*end_ptr = pc_end;
}
#define NO_FRAME_SECTION_SIZE 0x7FFFFFFF
#ifndef FRAME_SECTION_SIZE
#define FRAME_SECTION_SIZE(OB) NO_FRAME_SECTION_SIZE
#endif
static void
frame_init (struct object* ob)
{
size_t count, final_count;
fde_accumulator accu;
void *pc_begin, *pc_end;
if (ob->fde_array)
{
fde **p = ob->fde_array;
for (count = 0; *p; ++p)
count += count_fdes (*p, NO_FRAME_SECTION_SIZE);
}
else
count = count_fdes (ob->fde_begin, FRAME_SECTION_SIZE(ob));
#ifdef __DEBUG_EH__
if (count == 0)
abort ();
#endif
ob->count = final_count = count;
start_fde_sort (&accu, count);
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
if (ob->fde_array)
{
fde **p = ob->fde_array;
for (; *p; ++p)
add_fdes (*p, &accu, &pc_begin, &pc_end, NO_FRAME_SECTION_SIZE);
}
else
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end, FRAME_SECTION_SIZE(ob));
ob->fde_array = end_fde_sort (&accu, count, &final_count);
ob->pc_begin = pc_begin;
ob->pc_end = pc_end;
TRACE_EXCEPTIONS (TR_ALL, "frame_init: image starting pc=0x%08x\n", pc_begin);
TRACE_EXCEPTIONS (TR_ALL, "frame_init: image ending pc=0x%08x\n", pc_end);
#ifdef __DEBUG_EH__
if (count != final_count && __trace_exceptions)
fprintf (stderr, "### Discarded %d duplicates (orig %d, now %d)\n",
count - final_count, count, final_count);
#endif
ob->count = final_count;
}
static fde *
find_fde (void *pc)
{
struct object *ob;
size_t lo, hi;
TRACE_EXCEPTIONS (TR_ALL, "find_fde: ------Stack Frame---- pc = 0x%08x\n",pc);
GET_AND_LOCK_TARGET_OBJECT_LIST (ob);
for ( ; ob; ob = ob->next)
{
if (ob->pc_begin == 0)
frame_init (ob);
if (pc >= ob->pc_begin && pc < ob->pc_end)
{
TRACE_EXCEPTIONS (TR_ALL, "find_fde: image MATCH: sect addr=0x%08x\n",
ob->fde_begin);
TRACE_EXCEPTIONS (TR_ALL, " section size: %d bytes\n",
FRAME_SECTION_SIZE(ob));
TRACE_EXCEPTIONS (TR_ALL, " section pc_begin: 0x%08x\n",
ob->pc_begin);
TRACE_EXCEPTIONS (TR_ALL, " section pc_end: 0x%08x\n",
ob->pc_end);
break;
}
}
UNLOCK_TARGET_OBJECT_LIST();
if (ob == 0)
{
TRACE_EXCEPTIONS (TR_ALL, "--> NO OBJECT MATCHING PC=0x%08x\n", pc);
return 0;
}
for (lo = 0, hi = ob->count; lo < hi; )
{
size_t i = (lo + hi) / 2;
fde *f = ob->fde_array[i];
if (pc < GET_DWARF2_FDE_INITIAL_PC (f))
hi = i;
else if (pc >= GET_DWARF2_FDE_INITIAL_PC (f) + f->pc_range)
lo = i + 1;
else
{
TRACE_EXCEPTIONS (TR_ALL, "find_fde: fde matched=0x%08x\n", f);
#ifdef __DEBUG_EH__
{
fde *n_fde, *best_fit = f;
size_t next_ix = i;
while (++next_ix < ob->count
&& (n_fde = ob->fde_array[next_ix]) != NULL
&& pc >= GET_DWARF2_FDE_INITIAL_PC (n_fde)
&& n_fde->pc_range < ob->fde_array[next_ix-1]->pc_range
&& pc < GET_DWARF2_FDE_INITIAL_PC (n_fde) + n_fde->pc_range)
best_fit = n_fde;
if (best_fit != f)
{
fprintf (stderr, "## Broken FDE index, was %d, "
"fixed to %d, fde now 0x%x (for pc=%x)\n",
i, next_ix-1, best_fit, pc);
return best_fit;
}
}
#endif
return f;
}
}
TRACE_EXCEPTIONS (TR_ALL, "find_fde: No fde matches pc 0x%08x\n", pc);
return 0;
}
static inline struct dwarf_cie *
get_cie (fde *f)
{
TRACE_EXCEPTIONS (TR_CIE, "get_cie: from fde=0x%08x\n", f);
TRACE_EXCEPTIONS (TR_CIE, "get_cie: CIE referenced=0x%08x\n",
(((void *)&f->CIE_delta) - f->CIE_delta));
return ((void *)&f->CIE_delta) - f->CIE_delta;
}
static void *
extract_cie_info (fde *f, struct cie_info *c)
{
void *p;
int i;
c->augmentation = get_cie (f)->augmentation;
TRACE_EXCEPTIONS (TR_CIE, "extract_cie_info: augmentation string [%s]\n",
c->augmentation);
if (strcmp (c->augmentation, "") != 0
&& strcmp (c->augmentation, "eh") != 0
&& c->augmentation[0] != 'z')
{
TRACE_EXCEPTIONS (TR_CIE, "Invalid augmentation (0x%08x)!!\n",
c->augmentation);
return 0;
}
p = c->augmentation + strlen (c->augmentation) + 1;
if (strcmp (c->augmentation, "eh") == 0)
{
c->eh_ptr = READ_DWARF2_UNALIGNED_POINTER (p);
TRACE_EXCEPTIONS (TR_CIE, "extract_cie_info: exception table at 0x%08x\n",
c->eh_ptr);
p += sizeof (void *);
}
else {
TRACE_EXCEPTIONS (TR_ALL, "*NO* exception table in CIE referenced from FDE 0x%08x!\n", f);
c->eh_ptr = 0;
}
p = decode_uleb128 (p, &c->code_align);
p = decode_sleb128 (p, &c->data_align);
c->ra_regno = *(unsigned char *)p++;
TRACE_EXCEPTIONS (TR_CIE, "extract_cie_info: code alignment=%d\n",
c->code_align);
TRACE_EXCEPTIONS (TR_CIE, " data alignment=%d\n",
c->data_align);
TRACE_EXCEPTIONS (TR_CIE, " return address reg=%d\n",
c->ra_regno);
if (c->augmentation[0] == 'z')
{
p = decode_uleb128 (p, &i);
p += i;
}
TRACE_EXCEPTIONS (TR_CIE, "extract_cie_info: Instructions starting addr=0x%08x\n", p);
return p;
}
static void *
execute_cfa_insn (void *p, struct frame_state_internal *state,
struct cie_info *info, void **pc)
{
unsigned insn = *(unsigned char *)p++;
unsigned reg;
int offset;
if (insn & DW_CFA_advance_loc)
{
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_advance_loc(%d)\n", ((insn & 0x3f) * info->code_align));
*pc += ((insn & 0x3f) * info->code_align);
}
else if (insn & DW_CFA_offset)
{
reg = (insn & 0x3f);
p = decode_uleb128 (p, &offset);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_offset(reg=%d,\n",reg);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: offset=%d)\n",offset);
offset *= info->data_align;
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = offset;
}
else if (insn & DW_CFA_restore)
{
reg = (insn & 0x3f);
state->s.saved[reg] = REG_UNSAVED;
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_restore(%d)\n",reg);
}
else switch (insn)
{
case DW_CFA_set_loc:
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_set_loc(0x%08x)\n",
READ_DWARF2_UNALIGNED_POINTER (p));
*pc = READ_DWARF2_UNALIGNED_POINTER (p);
p += sizeof (void *);
break;
case DW_CFA_advance_loc1:
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_advance_loc1(0x%08x)\n",
read_1byte (p));
*pc += read_1byte (p);
p += 1;
break;
case DW_CFA_advance_loc2:
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_advance_loc2(0x%08x)\n",
read_2byte (p));
*pc += read_2byte (p);
p += 2;
break;
case DW_CFA_advance_loc4:
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_advance_loc4(0x%08x)\n",
read_4byte (p));
*pc += read_4byte (p);
p += 4;
break;
case DW_CFA_offset_extended:
p = decode_uleb128 (p, ®);
p = decode_uleb128 (p, &offset);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_offset_extended(reg=%d,\n",reg);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: offset=%d)\n",offset);
offset *= info->data_align;
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = offset;
break;
case DW_CFA_restore_extended:
p = decode_uleb128 (p, ®);
state->s.saved[reg] = REG_UNSAVED;
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_restore_extended(%d)\n",reg);
break;
case DW_CFA_undefined:
p = decode_uleb128 (p, ®);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_undefined(%d)\n",reg);
break;
case DW_CFA_same_value:
p = decode_uleb128 (p, ®);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_same_value(%d)\n",reg);
break;
case DW_CFA_nop:
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_nop\n",0);
break;
case DW_CFA_register:
{
unsigned reg2;
p = decode_uleb128 (p, ®);
p = decode_uleb128 (p, ®2);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_register(reg1=%d,\n",reg);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: reg2=%d)\n",reg2);
state->s.saved[reg] = REG_SAVED_REG;
state->s.reg_or_offset[reg] = reg2;
}
break;
case DW_CFA_def_cfa:
p = decode_uleb128 (p, ®);
p = decode_uleb128 (p, &offset);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_def_cfa(reg=%d,\n",reg);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: offset=%d)\n",offset);
state->s.cfa_reg = reg;
state->s.cfa_offset = offset;
break;
case DW_CFA_def_cfa_register:
p = decode_uleb128 (p, ®);
state->s.cfa_reg = reg;
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_def_cfa_register(%d)\n",reg);
break;
case DW_CFA_def_cfa_offset:
p = decode_uleb128 (p, &offset);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_def_cfa_offset(%d)\n",offset);
state->s.cfa_offset = offset;
break;
case DW_CFA_remember_state:
{
struct frame_state_internal *save =
(struct frame_state_internal *)
malloc (sizeof (struct frame_state_internal));
memcpy (save, state, sizeof (struct frame_state_internal));
state->saved_state = save;
}
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_remember_state\n",0);
break;
case DW_CFA_restore_state:
{
struct frame_state_internal *save = state->saved_state;
memcpy (state, save, sizeof (struct frame_state_internal));
free (save);
}
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_restore_state\n",0);
break;
case DW_CFA_GNU_window_save:
for (reg = 16; reg < 32; ++reg)
{
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
}
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_GNU_window_save\n",0);
break;
case DW_CFA_GNU_args_size:
p = decode_uleb128 (p, &offset);
state->s.args_size = offset;
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: DW_CFA_GNU_args_size(%d)\n",offset);
break;
case DW_CFA_GNU_negative_offset_extended:
p = decode_uleb128 (p, ®);
p = decode_uleb128 (p, &offset);
offset *= info->data_align;
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = -offset;
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: "
"DW_CFA_GNU_negative_offset_extended reg=%d,\n",
reg);
TRACE_EXCEPTIONS (TR_EXE, "execute_cfa_insn: "
" offs=%d)\n",
-offset);
break;
default:
TRACE_EXCEPTIONS (TR_ALL, "execute_cfa_insn: ILLEGAL INSTRUCTION\n",0);
abort ();
}
return p;
}
#ifdef TARGET_SPECIFIC_OBJECT_REGISTER_FUNCS
TARGET_SPECIFIC_OBJECT_REGISTER_FUNCS
#else
void
__register_frame_info (void *begin, struct object *ob)
{
ob->fde_begin = begin;
ob->pc_begin = ob->pc_end = 0;
ob->fde_array = 0;
ob->count = 0;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
ob->next = objects;
objects = ob;
__gthread_mutex_unlock (&object_mutex);
}
void
__register_frame (void *begin)
{
struct object *ob = (struct object *) malloc (sizeof (struct object));
__register_frame_info (begin, ob);
}
void
__register_frame_info_table (void *begin, struct object *ob)
{
ob->fde_begin = begin;
ob->fde_array = begin;
ob->pc_begin = ob->pc_end = 0;
ob->count = 0;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
ob->next = objects;
objects = ob;
__gthread_mutex_unlock (&object_mutex);
}
void
__register_frame_table (void *begin)
{
struct object *ob = (struct object *) malloc (sizeof (struct object));
__register_frame_info_table (begin, ob);
}
void *
__deregister_frame_info (void *begin)
{
struct object **p;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
p = &objects;
while (*p)
{
if ((*p)->fde_begin == begin)
{
struct object *ob = *p;
*p = (*p)->next;
if (ob->pc_begin)
free (ob->fde_array);
__gthread_mutex_unlock (&object_mutex);
return (void *) ob;
}
p = &((*p)->next);
}
__gthread_mutex_unlock (&object_mutex);
abort ();
}
void
__deregister_frame (void *begin)
{
free (__deregister_frame_info (begin));
}
#endif
struct frame_state *
__frame_state_for (void *pc_target, struct frame_state *state_in)
{
fde *f;
void *insn, *end, *pc;
struct cie_info info;
struct frame_state_internal state;
f = find_fde (pc_target);
if (f == 0)
return 0;
insn = extract_cie_info (f, &info);
if (insn == 0)
return 0;
memset (&state, 0, sizeof (state));
state.s.retaddr_column = info.ra_regno;
state.s.eh_ptr = info.eh_ptr;
end = next_fde ((fde*) get_cie (f));
TRACE_EXCEPTIONS (TR_ALL, "frame_state_for: Executing CIE Instructions starting at: 0x%08x\n",insn);
TRACE_EXCEPTIONS (TR_ALL, "frame_state_for: Execution will end before FDE: 0x%08x\n",end);
while (insn < end)
insn = execute_cfa_insn (insn, &state, &info, 0);
insn = ((fde *)f) + 1;
if (info.augmentation[0] == 'z')
{
int i;
insn = decode_uleb128 (insn, &i);
insn += i;
}
end = next_fde (f);
pc = GET_DWARF2_FDE_INITIAL_PC (f);
TRACE_EXCEPTIONS (TR_ALL, "frame_state_for: Executing instructions for FDE: 0x%08x\n", f);
TRACE_EXCEPTIONS (TR_ALL, "frame_state_for: Execute up to state PC=0x%08x\n",pc_target);
TRACE_EXCEPTIONS (TR_ALL, "Start PC at: 0x%08x, ", pc);
TRACE_EXCEPTIONS (TR_ALL, "length (range) of FDE is %d\n", f->pc_range);
TRACE_EXCEPTIONS (TR_ALL, "frame_state_for: Stop at next FDE: 0x%08x\n",end);
while (insn < end && pc <= pc_target)
insn = execute_cfa_insn (insn, &state, &info, &pc);
memcpy (state_in, &state.s, sizeof (state.s));
TRACE_EXCEPTIONS (TR_ALL, "Returning state in: 0x%08x\n",&state_in);
return state_in;
}
#endif