struct gcc_pt_regs
{
unsigned long gpr[32];
unsigned long nip;
unsigned long msr;
unsigned long orig_gpr3;
unsigned long ctr;
unsigned long link;
unsigned long xer;
unsigned long ccr;
};
struct gcc_sigcontext
{
unsigned long pad[7];
struct gcc_pt_regs *regs;
};
struct gcc_ucontext
{
#ifdef __powerpc64__
unsigned long pad[21];
#else
unsigned long pad[5];
#endif
struct gcc_sigcontext uc_mcontext;
};
#ifdef __powerpc64__
enum { SIGNAL_FRAMESIZE = 128 };
#define MD_FROB_UPDATE_CONTEXT frob_update_context
static void
frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
{
if (fs->regs.reg[2].how == REG_UNSAVED)
{
unsigned int *insn
= (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
if (*insn == 0xE8410028)
_Unwind_SetGRPtr (context, 2, context->cfa + 40);
}
}
static struct gcc_sigcontext *
get_sigcontext (struct _Unwind_Context *context)
{
const unsigned char *pc = context->ra;
if (*(unsigned int *) (pc+0) != 0x38210000 + SIGNAL_FRAMESIZE
|| *(unsigned int *) (pc+8) != 0x44000002)
return NULL;
if (*(unsigned int *) (pc+4) == 0x38000077)
{
struct sigframe {
char gap[SIGNAL_FRAMESIZE];
struct gcc_sigcontext sigctx;
} *rt_ = context->cfa;
return &rt_->sigctx;
}
else if (*(unsigned int *) (pc+4) == 0x380000AC)
{
struct rt_sigframe {
int tramp[6];
void *pinfo;
struct gcc_ucontext *puc;
} *rt_ = (struct rt_sigframe *) pc;
return &rt_->puc->uc_mcontext;
}
return NULL;
}
#else
enum { SIGNAL_FRAMESIZE = 64 };
static struct gcc_sigcontext *
get_sigcontext (struct _Unwind_Context *context)
{
const unsigned char *pc = context->ra;
if (*(unsigned int *) (pc+4) != 0x44000002)
return NULL;
if (*(unsigned int *) (pc+0) == 0x38007777
|| *(unsigned int *) (pc+0) == 0x38000077)
{
struct sigframe {
char gap[SIGNAL_FRAMESIZE];
struct gcc_sigcontext sigctx;
} *rt_ = context->cfa;
return &rt_->sigctx;
}
else if (*(unsigned int *) (pc+0) == 0x38006666
|| *(unsigned int *) (pc+0) == 0x380000AC)
{
struct rt_sigframe {
char gap[SIGNAL_FRAMESIZE + 16];
char siginfo[128];
struct gcc_ucontext uc;
} *rt_ = context->cfa;
return &rt_->uc.uc_mcontext;
}
return NULL;
}
#endif
#define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
static _Unwind_Reason_Code
ppc_fallback_frame_state (struct _Unwind_Context *context,
_Unwind_FrameState *fs)
{
struct gcc_sigcontext *sc = get_sigcontext (context);
long new_cfa;
int i;
if (sc == NULL)
return _URC_END_OF_STACK;
new_cfa = sc->regs->gpr[STACK_POINTER_REGNUM];
fs->cfa_how = CFA_REG_OFFSET;
fs->cfa_reg = STACK_POINTER_REGNUM;
fs->cfa_offset = new_cfa - (long) context->cfa;
for (i = 0; i < 32; i++)
if (i != STACK_POINTER_REGNUM)
{
fs->regs.reg[i].how = REG_SAVED_OFFSET;
fs->regs.reg[i].loc.offset
= (long)&(sc->regs->gpr[i]) - new_cfa;
}
fs->regs.reg[CR2_REGNO].how = REG_SAVED_OFFSET;
fs->regs.reg[CR2_REGNO].loc.offset
= (long)&(sc->regs->ccr) - new_cfa;
fs->regs.reg[LINK_REGISTER_REGNUM].how = REG_SAVED_OFFSET;
fs->regs.reg[LINK_REGISTER_REGNUM].loc.offset
= (long)&(sc->regs->link) - new_cfa;
fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
fs->regs.reg[ARG_POINTER_REGNUM].loc.offset
= (long)&(sc->regs->nip) - new_cfa;
fs->retaddr_column = ARG_POINTER_REGNUM;
return _URC_NO_REASON;
}