00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 struct gcc_vregs
00036 {
00037 __attribute__ ((vector_size (16))) int vr[32];
00038 #ifdef __powerpc64__
00039 unsigned int pad1[3];
00040 unsigned int vscr;
00041 unsigned int vsave;
00042 unsigned int pad2[3];
00043 #else
00044 unsigned int vsave;
00045 unsigned int pad[2];
00046 unsigned int vscr;
00047 #endif
00048 };
00049
00050 struct gcc_regs
00051 {
00052 unsigned long gpr[32];
00053 unsigned long nip;
00054 unsigned long msr;
00055 unsigned long orig_gpr3;
00056 unsigned long ctr;
00057 unsigned long link;
00058 unsigned long xer;
00059 unsigned long ccr;
00060 unsigned long softe;
00061 unsigned long trap;
00062 unsigned long dar;
00063 unsigned long dsisr;
00064 unsigned long result;
00065 unsigned long pad1[4];
00066 double fpr[32];
00067 unsigned int pad2;
00068 unsigned int fpscr;
00069 #ifdef __powerpc64__
00070 struct gcc_vregs *vp;
00071 #else
00072 unsigned int pad3[2];
00073 #endif
00074 struct gcc_vregs vregs;
00075 };
00076
00077 struct gcc_ucontext
00078 {
00079 #ifdef __powerpc64__
00080 unsigned long pad[28];
00081 #else
00082 unsigned long pad[12];
00083 #endif
00084 struct gcc_regs *regs;
00085 struct gcc_regs rsave;
00086 };
00087
00088 #ifdef __powerpc64__
00089
00090 enum { SIGNAL_FRAMESIZE = 128 };
00091
00092
00093
00094
00095 static struct gcc_regs *
00096 get_regs (struct _Unwind_Context *context)
00097 {
00098 const unsigned char *pc = context->ra;
00099
00100
00101
00102 if (*(unsigned int *) (pc + 0) != 0x38210000 + SIGNAL_FRAMESIZE
00103 || *(unsigned int *) (pc + 8) != 0x44000002)
00104 return NULL;
00105 if (*(unsigned int *) (pc + 4) == 0x38000077)
00106 {
00107 struct sigframe {
00108 char gap[SIGNAL_FRAMESIZE];
00109 unsigned long pad[7];
00110 struct gcc_regs *regs;
00111 } *frame = (struct sigframe *) context->cfa;
00112 return frame->regs;
00113 }
00114 else if (*(unsigned int *) (pc + 4) == 0x380000AC)
00115 {
00116
00117
00118
00119
00120 struct rt_sigframe_24 {
00121 int tramp[6];
00122 void *pinfo;
00123 struct gcc_ucontext *puc;
00124 } *frame24 = (struct rt_sigframe_24 *) pc;
00125
00126
00127 if ((long) frame24->puc != -21 * 8)
00128 return frame24->puc->regs;
00129 else
00130 {
00131
00132 struct rt_sigframe {
00133 char gap[SIGNAL_FRAMESIZE];
00134 struct gcc_ucontext uc;
00135 unsigned long pad[2];
00136 int tramp[6];
00137 void *pinfo;
00138 struct gcc_ucontext *puc;
00139 } *frame = (struct rt_sigframe *) context->cfa;
00140 return frame->uc.regs;
00141 }
00142 }
00143 return NULL;
00144 }
00145
00146 #else
00147
00148 enum { SIGNAL_FRAMESIZE = 64 };
00149
00150 static struct gcc_regs *
00151 get_regs (struct _Unwind_Context *context)
00152 {
00153 const unsigned char *pc = context->ra;
00154
00155
00156
00157
00158
00159 if (*(unsigned int *) (pc + 4) != 0x44000002)
00160 return NULL;
00161 if (*(unsigned int *) (pc + 0) == 0x38007777
00162 || *(unsigned int *) (pc + 0) == 0x38000077)
00163 {
00164 struct sigframe {
00165 char gap[SIGNAL_FRAMESIZE];
00166 unsigned long pad[7];
00167 struct gcc_regs *regs;
00168 } *frame = (struct sigframe *) context->cfa;
00169 return frame->regs;
00170 }
00171 else if (*(unsigned int *) (pc + 0) == 0x38006666
00172 || *(unsigned int *) (pc + 0) == 0x380000AC)
00173 {
00174 struct rt_sigframe {
00175 char gap[SIGNAL_FRAMESIZE + 16];
00176 char siginfo[128];
00177 struct gcc_ucontext uc;
00178 } *frame = (struct rt_sigframe *) context->cfa;
00179 return frame->uc.regs;
00180 }
00181 return NULL;
00182 }
00183 #endif
00184
00185
00186
00187
00188 static long
00189 ppc_linux_aux_vector (long which)
00190 {
00191
00192 extern long *__libc_stack_end;
00193 long argc;
00194 char **argv;
00195 char **envp;
00196 struct auxv
00197 {
00198 long a_type;
00199 long a_val;
00200 } *auxp;
00201
00202
00203 argc = __libc_stack_end[0];
00204
00205 argv = (char **) __libc_stack_end + 1;
00206
00207 envp = argv + argc + 1;
00208 while (*envp++)
00209 continue;
00210
00211 for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp)
00212 if (auxp->a_type == which)
00213 return auxp->a_val;
00214 return 0;
00215 }
00216
00217
00218
00219
00220 #define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
00221
00222 static _Unwind_Reason_Code
00223 ppc_fallback_frame_state (struct _Unwind_Context *context,
00224 _Unwind_FrameState *fs)
00225 {
00226 static long hwcap = 0;
00227 struct gcc_regs *regs = get_regs (context);
00228 long new_cfa;
00229 int i;
00230
00231 if (regs == NULL)
00232 return _URC_END_OF_STACK;
00233
00234 new_cfa = regs->gpr[STACK_POINTER_REGNUM];
00235 fs->cfa_how = CFA_REG_OFFSET;
00236 fs->cfa_reg = STACK_POINTER_REGNUM;
00237 fs->cfa_offset = new_cfa - (long) context->cfa;
00238
00239 for (i = 0; i < 32; i++)
00240 if (i != STACK_POINTER_REGNUM)
00241 {
00242 fs->regs.reg[i].how = REG_SAVED_OFFSET;
00243 fs->regs.reg[i].loc.offset = (long) ®s->gpr[i] - new_cfa;
00244 }
00245
00246 fs->regs.reg[CR2_REGNO].how = REG_SAVED_OFFSET;
00247 fs->regs.reg[CR2_REGNO].loc.offset = (long) ®s->ccr - new_cfa;
00248
00249 fs->regs.reg[LINK_REGISTER_REGNUM].how = REG_SAVED_OFFSET;
00250 fs->regs.reg[LINK_REGISTER_REGNUM].loc.offset = (long) ®s->link - new_cfa;
00251
00252 fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
00253 fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) ®s->nip - new_cfa;
00254 fs->retaddr_column = ARG_POINTER_REGNUM;
00255 fs->signal_frame = 1;
00256
00257 if (hwcap == 0)
00258 {
00259 hwcap = ppc_linux_aux_vector (16);
00260
00261
00262
00263 #ifdef __powerpc64__
00264 hwcap |= 0xc0000000;
00265 #else
00266 hwcap |= 0x80000000;
00267 #endif
00268 }
00269
00270
00271 if (hwcap & 0x08000000)
00272 for (i = 0; i < 32; i++)
00273 {
00274 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
00275 fs->regs.reg[i + 32].loc.offset = (long) ®s->fpr[i] - new_cfa;
00276 }
00277
00278
00279 if (hwcap & 0x10000000)
00280 {
00281 struct gcc_vregs *vregs;
00282 #ifdef __powerpc64__
00283 vregs = regs->vp;
00284 #else
00285 vregs = ®s->vregs;
00286 #endif
00287 if (regs->msr & (1 << 25))
00288 {
00289 for (i = 0; i < 32; i++)
00290 {
00291 fs->regs.reg[i + FIRST_ALTIVEC_REGNO].how = REG_SAVED_OFFSET;
00292 fs->regs.reg[i + FIRST_ALTIVEC_REGNO].loc.offset
00293 = (long) &vregs[i] - new_cfa;
00294 }
00295
00296 fs->regs.reg[VSCR_REGNO].how = REG_SAVED_OFFSET;
00297 fs->regs.reg[VSCR_REGNO].loc.offset = (long) &vregs->vscr - new_cfa;
00298 }
00299
00300 fs->regs.reg[VRSAVE_REGNO].how = REG_SAVED_OFFSET;
00301 fs->regs.reg[VRSAVE_REGNO].loc.offset = (long) &vregs->vsave - new_cfa;
00302 }
00303
00304 return _URC_NO_REASON;
00305 }
00306
00307 #define MD_FROB_UPDATE_CONTEXT frob_update_context
00308
00309 static void
00310 frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATTRIBUTE_UNUSED)
00311 {
00312 const unsigned int *pc = (const unsigned int *) context->ra;
00313
00314
00315
00316 #ifdef __powerpc64__
00317
00318
00319 if (pc[0] == 0x38210000 + SIGNAL_FRAMESIZE
00320 && (pc[1] == 0x38000077 || pc[1] == 0x380000AC)
00321 && pc[2] == 0x44000002)
00322 _Unwind_SetSignalFrame (context, 1);
00323 #else
00324
00325
00326
00327
00328 if ((pc[0] == 0x38007777 || pc[0] == 0x38000077
00329 || pc[0] == 0x38006666 || pc[0] == 0x380000AC)
00330 && pc[1] == 0x44000002)
00331 _Unwind_SetSignalFrame (context, 1);
00332 #endif
00333
00334 #ifdef __powerpc64__
00335 if (fs->regs.reg[2].how == REG_UNSAVED)
00336 {
00337
00338
00339
00340
00341
00342 unsigned int *insn
00343 = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
00344 if (*insn == 0xE8410028)
00345 _Unwind_SetGRPtr (context, 2, context->cfa + 40);
00346 }
00347 #endif
00348 }