From: Alan Modra Date: Mon, 31 Jan 2005 13:37:37 +0000 (+0000) Subject: linux-unwind.h (struct gcc_vregs): New. X-Git-Tag: releases/gcc-4.0.0~1167 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a7a52913cf19685b6b0e9cbc61015e41ec2f82b1;p=thirdparty%2Fgcc.git linux-unwind.h (struct gcc_vregs): New. * config/rs6000/linux-unwind.h (struct gcc_vregs): New. (struct gcc_regs): Rename from gcc_pt_regs. Add more regs. (struct gcc_sigcontext): Delete. Merge contents to.. (struct gcc_ucontext): ..here. (get_sigcontext): Delete. (get_regs): New function, like get_sigcontext but return regs ptr. 64-bit version finds regs from r1 to support vdso. (ppc_linux_aux_vector): New function. (ppc_fallback_frame_state): Modify for get_regs. Restore fprs and vector regs. From-SVN: r94481 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1a428646ce53..2a39cfd1727a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2005-01-31 Alan Modra + + * config/rs6000/linux-unwind.h (struct gcc_vregs): New. + (struct gcc_regs): Rename from gcc_pt_regs. Add more regs. + (struct gcc_sigcontext): Delete. Merge contents to.. + (struct gcc_ucontext): ..here. + (get_sigcontext): Delete. + (get_regs): New function, like get_sigcontext but return regs ptr. + 64-bit version finds regs from r1 to support vdso. + (ppc_linux_aux_vector): New function. + (ppc_fallback_frame_state): Modify for get_regs. Restore fprs + and vector regs. + 2005-01-31 Ira Rosen * tree-vectorizer.c (vect_analyze_offset_expr): Use ssizetype instead diff --git a/gcc/config/rs6000/linux-unwind.h b/gcc/config/rs6000/linux-unwind.h index 4212dfed9aa2..3e12cc691aec 100644 --- a/gcc/config/rs6000/linux-unwind.h +++ b/gcc/config/rs6000/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for PowerPC and PowerPC64 Linux. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -24,7 +24,22 @@ these structs elsewhere; Many fields are missing, particularly from the end of the structures. */ -struct gcc_pt_regs +struct gcc_vregs +{ + __attribute__ ((vector_size (16))) int vr[32]; +#ifdef __powerpc64__ + unsigned int pad1[3]; + unsigned int vscr; + unsigned int vsave; + unsigned int pad2[3]; +#else + unsigned int vsave; + unsigned int pad[2]; + unsigned int vscr; +#endif +}; + +struct gcc_regs { unsigned long gpr[32]; unsigned long nip; @@ -34,22 +49,32 @@ struct gcc_pt_regs unsigned long link; unsigned long xer; unsigned long ccr; -}; - -struct gcc_sigcontext -{ - unsigned long pad[7]; - struct gcc_pt_regs *regs; + unsigned long softe; + unsigned long trap; + unsigned long dar; + unsigned long dsisr; + unsigned long result; + unsigned long pad1[4]; + double fpr[32]; + unsigned int pad2; + unsigned int fpscr; +#ifdef __powerpc64__ + struct gcc_vregs *vp; +#else + unsigned int pad3[2]; +#endif + struct gcc_vregs vregs; }; struct gcc_ucontext { #ifdef __powerpc64__ - unsigned long pad[21]; + unsigned long pad[28]; #else - unsigned long pad[5]; + unsigned long pad[12]; #endif - struct gcc_sigcontext uc_mcontext; + struct gcc_regs *regs; + struct gcc_regs rsave; }; #ifdef __powerpc64__ @@ -77,34 +102,55 @@ frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) } /* If PC is at a sigreturn trampoline, return a pointer to the - sigcontext. Otherwise return NULL. */ + regs. Otherwise return NULL. */ -static struct gcc_sigcontext * -get_sigcontext (struct _Unwind_Context *context) +static struct gcc_regs * +get_regs (struct _Unwind_Context *context) { const unsigned char *pc = context->ra; /* addi r1, r1, 128; li r0, 0x0077; sc (sigreturn) */ /* addi r1, r1, 128; li r0, 0x00AC; sc (rt_sigreturn) */ - if (*(unsigned int *) (pc+0) != 0x38210000 + SIGNAL_FRAMESIZE - || *(unsigned int *) (pc+8) != 0x44000002) + if (*(unsigned int *) (pc + 0) != 0x38210000 + SIGNAL_FRAMESIZE + || *(unsigned int *) (pc + 8) != 0x44000002) return NULL; - if (*(unsigned int *) (pc+4) == 0x38000077) + if (*(unsigned int *) (pc + 4) == 0x38000077) { struct sigframe { char gap[SIGNAL_FRAMESIZE]; - struct gcc_sigcontext sigctx; - } *rt_ = context->cfa; - return &rt_->sigctx; + unsigned long pad[7]; + struct gcc_regs *regs; + } *frame = (struct sigframe *) context->cfa; + return frame->regs; } - else if (*(unsigned int *) (pc+4) == 0x380000AC) + else if (*(unsigned int *) (pc + 4) == 0x380000AC) { - struct rt_sigframe { + /* 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 + kernels released. */ + struct rt_sigframe_24 { int tramp[6]; void *pinfo; struct gcc_ucontext *puc; - } *rt_ = (struct rt_sigframe *) pc; - return &rt_->puc->uc_mcontext; + } *frame24 = (struct rt_sigframe_24 *) pc; + + /* Test for magic value in *puc of vdso. */ + if ((long) frame24->puc != -21 * 8) + return frame24->puc->regs; + else + { + /* This works for 2.4.21 and later kernels. */ + struct rt_sigframe { + char gap[SIGNAL_FRAMESIZE]; + struct gcc_ucontext uc; + unsigned long pad[2]; + int tramp[6]; + void *pinfo; + struct gcc_ucontext *puc; + } *frame = (struct rt_sigframe *) context->cfa; + return frame->uc.regs; + } } return NULL; } @@ -113,8 +159,8 @@ get_sigcontext (struct _Unwind_Context *context) enum { SIGNAL_FRAMESIZE = 64 }; -static struct gcc_sigcontext * -get_sigcontext (struct _Unwind_Context *context) +static struct gcc_regs * +get_regs (struct _Unwind_Context *context) { const unsigned char *pc = context->ra; @@ -122,31 +168,64 @@ get_sigcontext (struct _Unwind_Context *context) /* li r0, 0x0077; sc (sigreturn new) */ /* li r0, 0x6666; sc (rt_sigreturn old) */ /* li r0, 0x00AC; sc (rt_sigreturn new) */ - if (*(unsigned int *) (pc+4) != 0x44000002) + if (*(unsigned int *) (pc + 4) != 0x44000002) return NULL; - if (*(unsigned int *) (pc+0) == 0x38007777 - || *(unsigned int *) (pc+0) == 0x38000077) + 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; + unsigned long pad[7]; + struct gcc_regs *regs; + } *frame = (struct sigframe *) context->cfa; + return frame->regs; } - else if (*(unsigned int *) (pc+0) == 0x38006666 - || *(unsigned int *) (pc+0) == 0x380000AC) + 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; + } *frame = (struct rt_sigframe *) context->cfa; + return frame->uc.regs; } return NULL; } #endif +/* Find an entry in the process auxilliary vector. The canonical way to + test for VMX is to look at AT_HWCAP. */ + +static long +ppc_linux_aux_vector (long which) +{ + /* __libc_stack_end holds the original stack passed to a process. */ + extern long *__libc_stack_end; + long argc; + char **argv; + char **envp; + struct auxv + { + long a_type; + long a_val; + } *auxp; + + /* The Linux kernel puts argc first on the stack. */ + argc = __libc_stack_end[0]; + /* Followed by argv, NULL terminated. */ + argv = (char **) __libc_stack_end + 1; + /* Followed by environment string pointers, NULL terminated. */ + envp = argv + argc + 1; + while (*envp++) + continue; + /* Followed by the aux vector, zero terminated. */ + for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp) + if (auxp->a_type == which) + return auxp->a_val; + return 0; +} + /* Do code reading to identify a signal frame, and set the frame state data appropriately. See unwind-dw2.c for the structs. */ @@ -156,14 +235,15 @@ static _Unwind_Reason_Code ppc_fallback_frame_state (struct _Unwind_Context *context, _Unwind_FrameState *fs) { - struct gcc_sigcontext *sc = get_sigcontext (context); + static long hwcap = 0; + struct gcc_regs *regs = get_regs (context); long new_cfa; int i; - if (sc == NULL) + if (regs == NULL) return _URC_END_OF_STACK; - new_cfa = sc->regs->gpr[STACK_POINTER_REGNUM]; + new_cfa = 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; @@ -172,21 +252,65 @@ ppc_fallback_frame_state (struct _Unwind_Context *context, 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[i].loc.offset = (long) ®s->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[CR2_REGNO].loc.offset = (long) ®s->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[LINK_REGISTER_REGNUM].loc.offset = (long) ®s->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->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) ®s->nip - new_cfa; fs->retaddr_column = ARG_POINTER_REGNUM; + + if (hwcap == 0) + { + hwcap = ppc_linux_aux_vector (16); + /* These will already be set if we found AT_HWCAP. A non-zero + value stops us looking again if for some reason we couldn't + find AT_HWCAP. */ +#ifdef __powerpc64__ + hwcap |= 0xc0000000; +#else + hwcap |= 0x80000000; +#endif + } + + /* If we have a FPU... */ + if (hwcap & 0x08000000) + for (i = 0; i < 32; i++) + { + fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; + fs->regs.reg[i + 32].loc.offset = (long) ®s->fpr[i] - new_cfa; + } + + /* If we have a VMX unit... */ + if (hwcap & 0x10000000) + { + struct gcc_vregs *vregs; +#ifdef __powerpc64__ + vregs = regs->vp; +#else + vregs = ®s->vregs; +#endif + if (regs->msr & (1 << 25)) + { + for (i = 0; i < 32; i++) + { + fs->regs.reg[i + FIRST_ALTIVEC_REGNO].how = REG_SAVED_OFFSET; + fs->regs.reg[i + FIRST_ALTIVEC_REGNO].loc.offset + = (long) &vregs[i] - new_cfa; + } + + fs->regs.reg[VSCR_REGNO].how = REG_SAVED_OFFSET; + fs->regs.reg[VSCR_REGNO].loc.offset = (long) &vregs->vscr - new_cfa; + } + + fs->regs.reg[VRSAVE_REGNO].how = REG_SAVED_OFFSET; + fs->regs.reg[VRSAVE_REGNO].loc.offset = (long) &vregs->vsave - new_cfa; + } + return _URC_NO_REASON; }