aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/libgcc/config/rs6000/linux-unwind.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/libgcc/config/rs6000/linux-unwind.h')
-rw-r--r--gcc-4.8/libgcc/config/rs6000/linux-unwind.h51
1 files changed, 41 insertions, 10 deletions
diff --git a/gcc-4.8/libgcc/config/rs6000/linux-unwind.h b/gcc-4.8/libgcc/config/rs6000/linux-unwind.h
index c9273c404..a421b1582 100644
--- a/gcc-4.8/libgcc/config/rs6000/linux-unwind.h
+++ b/gcc-4.8/libgcc/config/rs6000/linux-unwind.h
@@ -24,9 +24,19 @@
#define R_LR 65
#define R_CR2 70
+#define R_CR3 71
+#define R_CR4 72
#define R_VR0 77
#define R_VRSAVE 109
+#ifdef __powerpc64__
+#if _CALL_ELF == 2
+#define TOC_SAVE_SLOT 24
+#else
+#define TOC_SAVE_SLOT 40
+#endif
+#endif
+
struct gcc_vregs
{
__attribute__ ((vector_size (16))) int vr[32];
@@ -107,6 +117,8 @@ get_regs (struct _Unwind_Context *context)
}
else if (pc[1] == 0x380000AC)
{
+#if _CALL_ELF != 2
+ /* These old kernel versions never supported ELFv2. */
/* This works for 2.4 kernels, but not for 2.6 kernels with vdso
because pc isn't pointing into the stack. Can be removed when
no one is running 2.4.19 or 2.4.20, the first two ppc64
@@ -121,6 +133,7 @@ get_regs (struct _Unwind_Context *context)
if ((long) frame24->puc != -21 * 8)
return frame24->puc->regs;
else
+#endif
{
/* This works for 2.4.21 and later kernels. */
struct rt_sigframe {
@@ -185,6 +198,7 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
{
struct gcc_regs *regs = get_regs (context);
struct gcc_vregs *vregs;
+ long cr_offset;
long new_cfa;
int i;
@@ -206,11 +220,21 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
}
+ /* The CR is saved in the low 32 bits of regs->ccr. */
+ cr_offset = (long) &regs->ccr - new_cfa;
+#ifndef __LITTLE_ENDIAN__
+ cr_offset += sizeof (long) - 4;
+#endif
+ /* In the ELFv1 ABI, CR2 stands in for the whole CR. */
fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
- /* CR? regs are always 32-bit and PPC is big-endian, so in 64-bit
- libgcc loc.offset needs to point to the low 32 bits of regs->ccr. */
- fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa
- + sizeof (long) - 4;
+ fs->regs.reg[R_CR2].loc.offset = cr_offset;
+#if _CALL_ELF == 2
+ /* In the ELFv2 ABI, every CR field has a separate CFI entry. */
+ fs->regs.reg[R_CR3].how = REG_SAVED_OFFSET;
+ fs->regs.reg[R_CR3].loc.offset = cr_offset;
+ fs->regs.reg[R_CR4].how = REG_SAVED_OFFSET;
+ fs->regs.reg[R_CR4].loc.offset = cr_offset;
+#endif
fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
@@ -294,9 +318,13 @@ frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATT
figure out if it was saved. The big problem here is that the
code that does the save/restore is generated by the linker, so
we have no good way to determine at compile time what to do. */
- if (pc[0] == 0xF8410028
+ if (pc[0] == 0xF8410000 + TOC_SAVE_SLOT
+#if _CALL_ELF != 2
+ /* The ELFv2 linker never generates the old PLT stub form. */
|| ((pc[0] & 0xFFFF0000) == 0x3D820000
- && pc[1] == 0xF8410028))
+ && pc[1] == 0xF8410000 + TOC_SAVE_SLOT)
+#endif
+ )
{
/* We are in a plt call stub or r2 adjusting long branch stub,
before r2 has been saved. Keep REG_UNSAVED. */
@@ -305,18 +333,21 @@ frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATT
{
unsigned int *insn
= (unsigned int *) _Unwind_GetGR (context, R_LR);
- if (insn && *insn == 0xE8410028)
- _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+ if (insn && *insn == 0xE8410000 + TOC_SAVE_SLOT)
+ _Unwind_SetGRPtr (context, 2, context->cfa + TOC_SAVE_SLOT);
+#if _CALL_ELF != 2
+ /* ELFv2 does not use this function pointer call sequence. */
else if (pc[0] == 0x4E800421
- && pc[1] == 0xE8410028)
+ && pc[1] == 0xE8410000 + TOC_SAVE_SLOT)
{
/* We are at the bctrl instruction in a call via function
pointer. gcc always emits the load of the new R2 just
before the bctrl so this is the first and only place
we need to use the stored R2. */
_Unwind_Word sp = _Unwind_GetGR (context, 1);
- _Unwind_SetGRPtr (context, 2, (void *)(sp + 40));
+ _Unwind_SetGRPtr (context, 2, (void *)(sp + TOC_SAVE_SLOT));
}
+#endif
}
}
#endif