1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-22 15:47:37 +01:00

Include "offsets.h" to get offsets for various structures (such

as sigcontext).  Adjust for the fact that the RSE arithmetic
is now done on values of type unw_word_t rather than long pointers.

(ia64_scratch_loc): Rename from ia64_get_sigcontext() and expand
	it such that it returns a scratch register location if
	the current frame is not a sigcontext frame.
(ia64_access_reg): Read the address of the personality routine with
	ia64_get() rather than trying to dereference the address
	directly.  When writing the IP or the PR, update the cached
	values, too.

(Logical change 1.5)
This commit is contained in:
(none)!davidm 2002-02-22 21:58:53 +00:00
parent 3790561497
commit 7820abd977

View file

@ -21,29 +21,54 @@ This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public executable file might be covered by the GNU General Public
License. */ License. */
#include "config.h"
#include <assert.h> #include <assert.h>
#include "unwind_i.h"
#include "rse.h"
/* The first three 64-bit words in a signal frame contain the signal #include "offsets.h"
number, siginfo pointer, and sigcontext pointer passed to the #include "rse.h"
signal handler. We use this to locate the sigcontext pointer. */ #include "unwind_i.h"
#define SIGFRAME_ARG2_OFF 0x10
unw_word_t unw_word_t
ia64_get_sigcontext_addr (struct ia64_cursor *c) ia64_scratch_loc (struct ia64_cursor *c, unw_regnum_t reg)
{ {
unw_word_t addr; unw_word_t loc;
if (!(c->pi.flags & IA64_FLAG_SIGTRAMP)) if (c->pi.flags & IA64_FLAG_SIGTRAMP)
return 0; {
if (ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &loc) < 0)
return 0;
if (ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &addr) < 0) switch (reg)
return 0; {
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
loc += SIGCONTEXT_NAT_OFF;
break;
return addr; case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31:
loc += SIGCONTEXT_GR_OFF + 8*reg;
break;
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
loc += SIGCONTEXT_FR_OFF + 16*(reg - UNW_IA64_FR);
break;
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
loc += SIGCONTEXT_FR_OFF + 16*(reg - UNW_IA64_FR);
break;
case UNW_IA64_BR + 0: loc += SIGCONTEXT_BR_OFF + 0; break;
case UNW_IA64_BR + 7: loc += SIGCONTEXT_BR_OFF + 7*8; break;
case UNW_IA64_AR_RSC: loc += SIGCONTEXT_AR_RSC_OFF; break;
case UNW_IA64_AR_25: loc += SIGCONTEXT_AR_25_OFF; break;
case UNW_IA64_AR_26: loc += SIGCONTEXT_AR_26_OFF; break;
case UNW_IA64_AR_CCV: loc += SIGCONTEXT_AR_CCV; break;
}
return loc;
}
else
return IA64_REG_LOC (reg);
} }
/* Apply rotation to a general register. The number REG must be in /* Apply rotation to a general register. The number REG must be in
@ -171,7 +196,7 @@ access_nat (struct ia64_cursor *c, unw_word_t loc, unw_word_t reg_loc,
{ {
unw_word_t nat_loc = -8, mask = 0, sc_addr; unw_word_t nat_loc = -8, mask = 0, sc_addr;
unw_fpreg_t tmp; unw_fpreg_t tmp;
int ret; int ret, reg;
if (IA64_IS_FP_LOC (reg_loc)) if (IA64_IS_FP_LOC (reg_loc))
{ {
@ -221,13 +246,13 @@ access_nat (struct ia64_cursor *c, unw_word_t loc, unw_word_t reg_loc,
if (IA64_IS_MEMSTK_NAT (loc)) if (IA64_IS_MEMSTK_NAT (loc))
{ {
nat_loc = IA64_GET_LOC (loc) << 3; nat_loc = IA64_GET_LOC (loc) << 3;
mask = (unw_word_t) 1 << ia64_rse_slot_num ((unsigned long *) reg_loc); mask = (unw_word_t) 1 << ia64_rse_slot_num (reg_loc);
} }
else else
{ {
loc = IA64_GET_LOC (loc); reg = IA64_GET_LOC (loc);
assert (loc >= 0 && loc < 128); assert (reg >= 0 && reg < 128);
if (!loc) if (!reg)
{ {
/* NaT bit is not saved. This happens if a general register /* NaT bit is not saved. This happens if a general register
is saved to a branch register. Since the NaT bit gets is saved to a branch register. Since the NaT bit gets
@ -244,39 +269,44 @@ access_nat (struct ia64_cursor *c, unw_word_t loc, unw_word_t reg_loc,
return 0; return 0;
} }
if (loc >= 4 && loc <= 7) if (reg >= 4 && reg <= 7)
{ {
/* NaT bit is saved in a NaT register. This happens when a /* NaT bit is saved in a NaT register. This happens when a
general register is saved to another general general register is saved to another general
register. */ register. */
if (write) if (write)
ret = ia64_put (c, UNW_IA64_NAT + loc, *valp); ret = ia64_put (c, UNW_IA64_NAT + reg, *valp);
else else
ret = ia64_get (c, UNW_IA64_NAT + loc, valp); ret = ia64_get (c, UNW_IA64_NAT + reg, valp);
return ret; return ret;
} }
else if (loc >= 32) else if (reg >= 32)
{ {
/* NaT bit is saved in a stacked register. */ /* NaT bit is saved in a stacked register. */
nat_loc = (unw_word_t) ia64_rse_rnat_addr ((unsigned long *) nat_loc = (intptr_t) ia64_rse_rnat_addr (reg_loc);
reg_loc);
if (nat_loc > c->rbs_top) if (nat_loc > c->rbs_top)
nat_loc = c->top_rnat_loc; nat_loc = c->top_rnat_loc;
mask = (unw_word_t) 1 << ia64_rse_slot_num ((unsigned long *) mask = (intptr_t) 1 << ia64_rse_slot_num (reg_loc);
reg_loc);
} }
else else
{ {
/* NaT bit is saved in a scratch register. */ /* NaT bit is saved in a scratch register. */
if (!(c->pi.flags & IA64_FLAG_SIGTRAMP)) if (c->pi.flags & IA64_FLAG_SIGTRAMP)
return -UNW_EBADREG; {
ret = ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &sc_addr);
if (ret < 0)
return ret;
sc_addr = ia64_get_sigcontext_addr (c); nat_loc = sc_addr + SIGCONTEXT_NAT_OFF;
if (!sc_addr) mask = (unw_word_t) 1 << reg;
return -UNW_EBADREG; }
else
nat_loc = sc_addr + struct_offset (struct sigcontext, sc_nat); {
mask = (unw_word_t) 1 << loc; if (write)
return ia64_put (c, loc, *valp);
else
return ia64_get (c, loc, valp);
}
} }
} }
return update_nat (c, nat_loc, mask, valp, write); return update_nat (c, nat_loc, mask, valp, write);
@ -286,7 +316,7 @@ int
ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp, ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
int write) int write)
{ {
unw_word_t loc = -8, reg_loc, sc_off = 0, nat, nat_loc, cfm, mask, pr; unw_word_t loc = -8, reg_loc, nat, nat_loc, cfm, mask, pr;
int ret, readonly = 0; int ret, readonly = 0;
switch (reg) switch (reg)
@ -310,14 +340,14 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
case UNW_REG_SP: *valp = c->sp; break; case UNW_REG_SP: *valp = c->sp; break;
case UNW_REG_PROC_START:*valp = c->pi.proc_start; break; case UNW_REG_PROC_START:*valp = c->pi.proc_start; break;
case UNW_REG_LSDA: case UNW_REG_LSDA:
*valp = (unw_word_t) (c->pi.pers_addr + 1); *valp = (intptr_t) (c->pi.pers_addr + 1);
break; break;
case UNW_REG_HANDLER: case UNW_REG_HANDLER:
if (c->pi.flags & IA64_FLAG_HAS_HANDLER) if (c->pi.flags & IA64_FLAG_HAS_HANDLER)
/* *c->pers_addr is the linkage-table offset of the word /* *c->pers_addr is the linkage-table offset of the word
that stores the address of the personality routine's that stores the address of the personality routine's
function descriptor. */ function descriptor. */
*valp = *(unw_word_t *) (*c->pi.pers_addr + c->pi.gp); return ia64_get (c, *c->pi.pers_addr + c->pi.gp, valp);
else else
*valp = 0; *valp = 0;
break; break;
@ -325,15 +355,23 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
return 0; return 0;
case UNW_REG_IP: case UNW_REG_IP:
loc = c->rp_loc; if (write)
c->ip = *valp; /* also update the IP cache */
loc = c->ip_loc;
break; break;
/* preserved registers: */ /* preserved registers: */
case UNW_IA64_GR + 4: loc = c->r4_loc; break; case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
case UNW_IA64_GR + 5: loc = c->r5_loc; break; loc = (&c->r4_loc)[reg - (UNW_IA64_GR + 4)];
case UNW_IA64_GR + 6: loc = c->r6_loc; break; break;
case UNW_IA64_GR + 7: loc = c->r7_loc; break;
case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7:
loc = (&c->nat4_loc)[reg - (UNW_IA64_NAT + 4)];
reg_loc = (&c->r4_loc)[reg - (UNW_IA64_NAT + 4)];
return access_nat (c, loc, reg_loc, valp, write);
case UNW_IA64_AR_BSP: loc = c->bsp_loc; break; case UNW_IA64_AR_BSP: loc = c->bsp_loc; break;
case UNW_IA64_AR_BSPSTORE: loc = c->bspstore_loc; break; case UNW_IA64_AR_BSPSTORE: loc = c->bspstore_loc; break;
case UNW_IA64_AR_PFS: loc = c->pfs_loc; break; case UNW_IA64_AR_PFS: loc = c->pfs_loc; break;
@ -351,6 +389,7 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
case UNW_IA64_PR: case UNW_IA64_PR:
if (write) if (write)
{ {
c->pr = *valp; /* update the predicate cache */
pr = pr_ltop (c, *valp); pr = pr_ltop (c, *valp);
return ia64_put (c, c->pr_loc, pr); return ia64_put (c, c->pr_loc, pr);
} }
@ -365,18 +404,16 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */ case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */
reg = rotate_gr (c, reg - UNW_IA64_GR) + UNW_IA64_GR; reg = rotate_gr (c, reg - UNW_IA64_GR) + UNW_IA64_GR;
loc = (unw_word_t) ia64_rse_skip_regs ((unsigned long *) c->bsp, loc = ia64_rse_skip_regs (c->bsp, reg - (UNW_IA64_GR + 32));
reg - (UNW_IA64_GR + 32));
break; break;
case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */ case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */
reg = rotate_gr (c, reg - UNW_IA64_NAT) + UNW_IA64_NAT; reg = rotate_gr (c, reg - UNW_IA64_NAT) + UNW_IA64_NAT;
loc = (unw_word_t) ia64_rse_skip_regs ((unsigned long *) c->bsp, loc = ia64_rse_skip_regs (c->bsp, reg - (UNW_IA64_NAT + 32));
reg - (UNW_IA64_NAT + 32)); nat_loc = ia64_rse_rnat_addr (loc);
nat_loc = (unw_word_t) ia64_rse_rnat_addr ((unsigned long *) loc);
if (nat_loc > c->rbs_top) if (nat_loc > c->rbs_top)
nat_loc = c->top_rnat_loc; nat_loc = c->top_rnat_loc;
mask = (unw_word_t) 1 << ia64_rse_slot_num ((unsigned long *) loc); mask = (unw_word_t) 1 << ia64_rse_slot_num (loc);
return update_nat (c, nat_loc, mask, valp, write); return update_nat (c, nat_loc, mask, valp, write);
case UNW_IA64_AR_EC: case UNW_IA64_AR_EC:
@ -405,25 +442,6 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
*valp = c->pi.gp; *valp = c->pi.gp;
return 0; return 0;
case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18:
if (!(c->pi.flags & IA64_FLAG_SIGTRAMP))
{
if (write)
c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
else
*valp = c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
return 0;
}
else
sc_off = struct_offset (struct sigcontext, sc_gr[reg]);
break;
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 14:
case UNW_IA64_GR + 19 ... UNW_IA64_GR + 31:
sc_off = struct_offset (struct sigcontext, sc_gr[reg]);
break;
case UNW_IA64_NAT + 0: case UNW_IA64_NAT + 0:
case UNW_IA64_NAT + 1: /* global pointer */ case UNW_IA64_NAT + 1: /* global pointer */
if (write) if (write)
@ -433,50 +451,52 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
mask = (unw_word_t) 1 << (reg - UNW_IA64_NAT); loc = ia64_scratch_loc (c, reg);
loc = ia64_get_sigcontext_addr (c); if (c->pi.flags & IA64_FLAG_SIGTRAMP)
if (!loc)
return -UNW_EBADREG;
loc += struct_offset (struct sigcontext, sc_nat);
ret = ia64_get (c, loc, &nat);
if (ret < 0)
return ret;
if (write)
{ {
if (*valp) mask = (unw_word_t) 1 << (reg - UNW_IA64_NAT);
nat |= mask;
ret = ia64_get (c, loc, &nat);
if (ret < 0)
return ret;
if (write)
{
if (*valp)
nat |= mask;
else
nat &= ~mask;
ret = ia64_put (c, loc, nat);
}
else else
nat &= ~mask; *valp = (nat & mask) != 0;
ret = ia64_put (c, loc, nat); return ret;
} }
break;
case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18:
if (c->pi.flags & IA64_FLAG_SIGTRAMP)
loc = ia64_scratch_loc (c, reg);
else else
*valp = (nat & mask) != 0; {
return ret; if (write)
c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7: else
loc = (&c->nat4_loc)[reg - (UNW_IA64_NAT + 4)]; *valp = c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
reg_loc = (&c->r4_loc)[reg - (UNW_IA64_NAT + 4)]; return 0;
return access_nat (c, loc, reg_loc, valp, write); }
break;
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 14:
case UNW_IA64_GR + 19 ... UNW_IA64_GR + 31:
case UNW_IA64_BR + 0:
case UNW_IA64_BR + 7:
case UNW_IA64_AR_RSC: case UNW_IA64_AR_RSC:
sc_off = struct_offset (struct sigcontext, sc_ar_rsc);
break;
#ifdef SIGCONTEXT_HAS_AR25_AND_AR26
case UNW_IA64_AR_25: case UNW_IA64_AR_25:
sc_off = struct_offset (struct sigcontext, sc_ar25);
break;
case UNW_IA64_AR_26: case UNW_IA64_AR_26:
sc_off = struct_offset (struct sigcontext, sc_ar26);
break;
#endif
case UNW_IA64_AR_CCV: case UNW_IA64_AR_CCV:
sc_off = struct_offset (struct sigcontext, sc_ar_ccv); loc = ia64_scratch_loc (c, reg);
break; break;
default: default:
@ -484,15 +504,6 @@ ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
return -UNW_EBADREG; return -UNW_EBADREG;
} }
if (sc_off)
{
loc = ia64_get_sigcontext_addr (c);
if (!loc)
return -UNW_EBADREG;
loc += sc_off;
}
if (write) if (write)
{ {
if (readonly) if (readonly)
@ -537,49 +548,46 @@ ia64_access_fpreg (struct ia64_cursor *c, int reg, unw_fpreg_t *valp,
break; break;
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
loc = ia64_get_sigcontext_addr (c); loc = ia64_scratch_loc (c, reg);
if (!loc)
return -UNW_EBADREG;
loc += struct_offset (struct sigcontext, sc_fr[reg - UNW_IA64_FR]);
break; break;
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR; if (c->pi.flags & IA64_FLAG_SIGTRAMP)
loc = ia64_get_sigcontext_addr (c);
if (!loc)
return -UNW_EBADREG;
ret = ia64_get (c, loc + struct_offset (struct sigcontext, sc_flags),
&flags);
if (ret < 0)
return ret;
if (!(flags & IA64_SC_FLAG_FPH_VALID))
{ {
if (write) ret = ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &loc);
if (ret < 0)
return ret;
ret = ia64_get (c, loc + SIGCONTEXT_FLAGS_OFF, &flags);
if (ret < 0)
return ret;
if (!(flags & IA64_SC_FLAG_FPH_VALID))
{ {
/* initialize fph partition: */ if (write)
tmp_loc = loc + struct_offset (struct sigcontext, sc_fr[32]);
for (i = 32; i < 128; ++i, tmp_loc += 16)
{ {
ret = ia64_putfp (c, tmp_loc, unw.f0); /* initialize fph partition: */
tmp_loc = loc + SIGCONTEXT_FR_OFF + 32*16;
for (i = 32; i < 128; ++i, tmp_loc += 16)
{
ret = ia64_putfp (c, tmp_loc, unw.f0);
if (ret < 0)
return ret;
}
/* mark fph partition as valid: */
ret = ia64_put (c, loc + SIGCONTEXT_FLAGS_OFF,
flags | IA64_SC_FLAG_FPH_VALID);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
/* mark fph partition as being valid: */ else
ret = ia64_put (c, loc + struct_offset (struct sigcontext, {
sc_flags), *valp = unw.f0;
flags | IA64_SC_FLAG_FPH_VALID); return 0;
if (ret < 0) }
return ret;
}
else
{
*valp = unw.f0;
return 0;
} }
} }
loc += struct_offset (struct sigcontext, sc_fr[reg - UNW_IA64_FR]); reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR;
loc = ia64_scratch_loc (c, reg);
break; break;
} }