mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-27 01:27:39 +01:00
(ia64_scratch_loc): Split up into linux_scratch_loc() and hpux_scratch_loc().
(linux_scratch_loc): Add support for new pt_regs layout. (access_nat): Check last_abi_marker instead of sigcontext_addr and address-space ABI. (Logical change 1.91)
This commit is contained in:
parent
18626b8def
commit
3053ee9de1
1 changed files with 153 additions and 78 deletions
|
@ -30,84 +30,158 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|||
#include "rse.h"
|
||||
#include "unwind_i.h"
|
||||
|
||||
static inline ia64_loc_t
|
||||
linux_scratch_loc (struct cursor *c, unw_regnum_t reg)
|
||||
{
|
||||
#if !defined(UNW_LOCAL_ONLY) || defined(__linux)
|
||||
unw_word_t addr = c->sigcontext_addr, flags, tmp_addr;
|
||||
int i, ret;
|
||||
|
||||
switch (c->last_abi_marker)
|
||||
{
|
||||
case ABI_MARKER_OLD_LINUX_SIGTRAMP:
|
||||
case ABI_MARKER_LINUX_SIGTRAMP:
|
||||
switch (reg)
|
||||
{
|
||||
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
|
||||
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
|
||||
addr += LINUX_SC_NAT_OFF;
|
||||
break;
|
||||
|
||||
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
|
||||
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31:
|
||||
addr += LINUX_SC_GR_OFF + 8 * (reg - UNW_IA64_GR);
|
||||
break;
|
||||
|
||||
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
|
||||
addr += LINUX_SC_FR_OFF + 16 * (reg - UNW_IA64_FR);
|
||||
return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP);
|
||||
|
||||
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
|
||||
if ((ret = ia64_get (c, IA64_LOC_ADDR (addr + LINUX_SC_FLAGS_OFF, 0),
|
||||
&flags)) < 0)
|
||||
return IA64_NULL_LOC;
|
||||
|
||||
if (!(flags & IA64_SC_FLAG_FPH_VALID))
|
||||
{
|
||||
/* initialize fph partition: */
|
||||
tmp_addr = addr + LINUX_SC_FR_OFF + 32*16;
|
||||
for (i = 32; i < 128; ++i, tmp_addr += 16)
|
||||
if ((ret = ia64_putfp (c, IA64_LOC_ADDR (tmp_addr, 0), unw.f0))
|
||||
< 0)
|
||||
return IA64_NULL_LOC;
|
||||
/* mark fph partition as valid: */
|
||||
if ((ret = ia64_put (c, IA64_LOC_ADDR (addr + LINUX_SC_FLAGS_OFF,
|
||||
0),
|
||||
flags | IA64_SC_FLAG_FPH_VALID)) < 0)
|
||||
return IA64_NULL_LOC;
|
||||
}
|
||||
|
||||
addr += LINUX_SC_FR_OFF + 16 * (reg - UNW_IA64_FR);
|
||||
return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP);
|
||||
|
||||
case UNW_IA64_BR + 0: addr += LINUX_SC_BR_OFF + 0; break;
|
||||
case UNW_IA64_BR + 6: addr += LINUX_SC_BR_OFF + 6*8; break;
|
||||
case UNW_IA64_BR + 7: addr += LINUX_SC_BR_OFF + 7*8; break;
|
||||
case UNW_IA64_AR_RSC: addr += LINUX_SC_AR_RSC_OFF; break;
|
||||
case UNW_IA64_AR_CSD: addr += LINUX_SC_AR_CSD_OFF; break;
|
||||
case UNW_IA64_AR_SSD: addr += LINUX_SC_AR_SSD_OFF; break;
|
||||
case UNW_IA64_AR_CCV: addr += LINUX_SC_AR_CCV; break;
|
||||
}
|
||||
return IA64_LOC_ADDR (addr, 0);
|
||||
|
||||
case ABI_MARKER_LINUX_INTERRUPT:
|
||||
switch (reg)
|
||||
{
|
||||
case UNW_IA64_BR + 6 ... UNW_IA64_BR + 7:
|
||||
addr += LINUX_PT_B6_OFF + 8 * (reg - (UNW_IA64_BR + 6));
|
||||
break;
|
||||
|
||||
case UNW_IA64_AR_CSD: addr += LINUX_PT_CSD_OFF; break;
|
||||
case UNW_IA64_AR_SSD: addr += LINUX_PT_SSD_OFF; break;
|
||||
|
||||
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 11:
|
||||
addr += LINUX_PT_R8_OFF + 8 * (reg - (UNW_IA64_GR + 8));
|
||||
break;
|
||||
|
||||
case UNW_IA64_AR_RSC: addr += LINUX_PT_RSC_OFF; break;
|
||||
case UNW_IA64_BR + 0: addr += LINUX_PT_B0_OFF; break;
|
||||
case UNW_IA64_GR + 1: addr += LINUX_PT_R1_OFF; break;
|
||||
case UNW_IA64_GR + 2: addr += LINUX_PT_R2_OFF; break;
|
||||
case UNW_IA64_GR + 3: addr += LINUX_PT_R3_OFF; break;
|
||||
|
||||
case UNW_IA64_GR + 16 ... UNW_IA64_GR + 31:
|
||||
addr += LINUX_PT_R16_OFF + 8 * (reg - (UNW_IA64_GR + 16));
|
||||
break;
|
||||
|
||||
case UNW_IA64_AR_CCV: addr += LINUX_PT_CCV_OFF; break;
|
||||
|
||||
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 11:
|
||||
addr += LINUX_PT_F6_OFF + 16 * (reg - (UNW_IA64_FR + 6));
|
||||
return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP);
|
||||
}
|
||||
return IA64_LOC_ADDR (addr, 0);
|
||||
|
||||
case ABI_MARKER_OLD_LINUX_INTERRUPT:
|
||||
switch (reg)
|
||||
{
|
||||
case UNW_IA64_GR + 1 ... UNW_IA64_GR + 3:
|
||||
addr += LINUX_OLD_PT_R1_OFF + 8 * (reg - (UNW_IA64_GR + 1));
|
||||
break;
|
||||
|
||||
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 11:
|
||||
addr += LINUX_OLD_PT_R8_OFF + 8 * (reg - (UNW_IA64_GR + 8));
|
||||
break;
|
||||
|
||||
case UNW_IA64_GR + 16 ... UNW_IA64_GR + 31:
|
||||
addr += LINUX_OLD_PT_R16_OFF + 8 * (reg - (UNW_IA64_GR + 16));
|
||||
break;
|
||||
|
||||
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 9:
|
||||
addr += LINUX_OLD_PT_F6_OFF + 16 * (reg - (UNW_IA64_FR + 6));
|
||||
return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP);
|
||||
|
||||
case UNW_IA64_BR + 0: addr += LINUX_OLD_PT_B0_OFF; break;
|
||||
case UNW_IA64_BR + 6: addr += LINUX_OLD_PT_B6_OFF; break;
|
||||
case UNW_IA64_BR + 7: addr += LINUX_OLD_PT_B7_OFF; break;
|
||||
|
||||
case UNW_IA64_AR_RSC: addr += LINUX_OLD_PT_RSC_OFF; break;
|
||||
case UNW_IA64_AR_CCV: addr += LINUX_OLD_PT_CCV_OFF; break;
|
||||
}
|
||||
return IA64_LOC_ADDR (addr, 0);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return IA64_NULL_LOC;
|
||||
}
|
||||
|
||||
static inline ia64_loc_t
|
||||
hpux_scratch_loc (struct cursor *c, unw_regnum_t reg)
|
||||
{
|
||||
#if !defined(UNW_LOCAL_ONLY) || defined(__hpux)
|
||||
return IA64_LOC_UC_REG (reg, c->sigcontext_addr);
|
||||
#else
|
||||
return IA64_NULL_LOC;
|
||||
#endif
|
||||
}
|
||||
|
||||
HIDDEN ia64_loc_t
|
||||
ia64_scratch_loc (struct cursor *c, unw_regnum_t reg)
|
||||
{
|
||||
unw_word_t sc_addr = c->sigcontext_addr;
|
||||
if (c->sigcontext_addr)
|
||||
switch (c->as->abi)
|
||||
{
|
||||
case ABI_LINUX:
|
||||
return linux_scratch_loc (c, reg);
|
||||
|
||||
if (sc_addr)
|
||||
{
|
||||
switch (c->as->abi)
|
||||
{
|
||||
#if !defined(UNW_LOCAL_ONLY) || defined(__linux)
|
||||
case ABI_LINUX:
|
||||
{
|
||||
unw_word_t flags, tmp_addr;
|
||||
int i, ret;
|
||||
case ABI_HPUX:
|
||||
return hpux_scratch_loc (c, reg);
|
||||
|
||||
switch (reg)
|
||||
{
|
||||
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
|
||||
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
|
||||
sc_addr += LINUX_SC_NAT_OFF;
|
||||
break;
|
||||
|
||||
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
|
||||
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31:
|
||||
sc_addr += LINUX_SC_GR_OFF + 8*reg;
|
||||
break;
|
||||
|
||||
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
|
||||
sc_addr += LINUX_SC_FR_OFF + 16*(reg - UNW_IA64_FR);
|
||||
return IA64_LOC_ADDR (sc_addr, IA64_LOC_TYPE_FP);
|
||||
|
||||
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
|
||||
if ((ret = ia64_get (c, IA64_LOC_ADDR (sc_addr
|
||||
+ LINUX_SC_FLAGS_OFF,
|
||||
0), &flags)) < 0)
|
||||
return IA64_NULL_LOC;
|
||||
|
||||
if (!(flags & IA64_SC_FLAG_FPH_VALID))
|
||||
{
|
||||
/* initialize fph partition: */
|
||||
tmp_addr = sc_addr + LINUX_SC_FR_OFF + 32*16;
|
||||
for (i = 32; i < 128; ++i, tmp_addr += 16)
|
||||
if ((ret = ia64_putfp (c, IA64_LOC_ADDR (tmp_addr, 0),
|
||||
unw.f0)) < 0)
|
||||
return IA64_NULL_LOC;
|
||||
/* mark fph partition as valid: */
|
||||
if ((ret = ia64_put (c,
|
||||
IA64_LOC_ADDR (sc_addr
|
||||
+ LINUX_SC_FLAGS_OFF,
|
||||
0),
|
||||
flags | IA64_SC_FLAG_FPH_VALID)) < 0)
|
||||
return IA64_NULL_LOC;
|
||||
}
|
||||
|
||||
sc_addr += LINUX_SC_FR_OFF + 16*(reg - UNW_IA64_FR);
|
||||
return IA64_LOC_ADDR (sc_addr, IA64_LOC_TYPE_FP);
|
||||
|
||||
case UNW_IA64_BR + 0: sc_addr += LINUX_SC_BR_OFF + 0; break;
|
||||
case UNW_IA64_BR + 6: sc_addr += LINUX_SC_BR_OFF + 6*8; break;
|
||||
case UNW_IA64_BR + 7: sc_addr += LINUX_SC_BR_OFF + 7*8; break;
|
||||
case UNW_IA64_AR_RSC: sc_addr += LINUX_SC_AR_RSC_OFF; break;
|
||||
case UNW_IA64_AR_CSD: sc_addr += LINUX_SC_AR_CSD_OFF; break;
|
||||
case UNW_IA64_AR_26: sc_addr += LINUX_SC_AR_26_OFF; break;
|
||||
case UNW_IA64_AR_CCV: sc_addr += LINUX_SC_AR_CCV; break;
|
||||
}
|
||||
return IA64_LOC_ADDR (sc_addr, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(UNW_LOCAL_ONLY) || defined(__hpux)
|
||||
case ABI_HPUX:
|
||||
return IA64_LOC_UC_REG (reg, sc_addr);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return IA64_NULL_LOC;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return IA64_NULL_LOC;
|
||||
}
|
||||
else
|
||||
return IA64_REG_LOC (c, reg);
|
||||
}
|
||||
|
@ -140,7 +214,7 @@ static int
|
|||
access_nat (struct cursor *c, ia64_loc_t loc, ia64_loc_t reg_loc,
|
||||
unw_word_t *valp, int write)
|
||||
{
|
||||
unw_word_t mask = 0, sc_addr;
|
||||
unw_word_t mask = 0;
|
||||
ia64_loc_t nat_loc;
|
||||
unw_fpreg_t tmp;
|
||||
int ret, reg;
|
||||
|
@ -256,10 +330,11 @@ access_nat (struct cursor *c, ia64_loc_t loc, ia64_loc_t reg_loc,
|
|||
{
|
||||
/* NaT bit is saved in a scratch register. */
|
||||
#if !defined(UNW_LOCAL_ONLY) || defined(__linux)
|
||||
sc_addr = c->sigcontext_addr;
|
||||
if (sc_addr && c->as->abi == ABI_LINUX)
|
||||
if (c->last_abi_marker == ABI_MARKER_LINUX_SIGTRAMP
|
||||
|| c->last_abi_marker == ABI_MARKER_OLD_LINUX_SIGTRAMP)
|
||||
{
|
||||
nat_loc = IA64_LOC_ADDR (sc_addr + LINUX_SC_NAT_OFF, 0);
|
||||
nat_loc = IA64_LOC_ADDR (c->sigcontext_addr + LINUX_SC_NAT_OFF,
|
||||
0);
|
||||
mask = (unw_word_t) 1 << reg;
|
||||
}
|
||||
else
|
||||
|
@ -463,7 +538,7 @@ ia64_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
|
|||
case UNW_IA64_BR + 7:
|
||||
case UNW_IA64_AR_RSC:
|
||||
case UNW_IA64_AR_CSD:
|
||||
case UNW_IA64_AR_26:
|
||||
case UNW_IA64_AR_SSD:
|
||||
case UNW_IA64_AR_CCV:
|
||||
loc = ia64_scratch_loc (c, reg);
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue