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
00096
00097
00098 #define MD_FROB_UPDATE_CONTEXT frob_update_context
00099
00100 static void
00101 frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
00102 {
00103 if (fs->regs.reg[2].how == REG_UNSAVED)
00104 {
00105 unsigned int *insn
00106 = (unsigned int *) _Unwind_GetGR (context, LINK_REGISTER_REGNUM);
00107 if (*insn == 0xE8410028)
00108 _Unwind_SetGRPtr (context, 2, context->cfa + 40);
00109 }
00110 }
00111
00112
00113
00114
00115 static struct gcc_regs *
00116 get_regs (struct _Unwind_Context *context)
00117 {
00118 const unsigned char *pc = context->ra;
00119
00120
00121
00122 if (*(unsigned int *) (pc + 0) != 0x38210000 + SIGNAL_FRAMESIZE
00123 || *(unsigned int *) (pc + 8) != 0x44000002)
00124 return NULL;
00125 if (*(unsigned int *) (pc + 4) == 0x38000077)
00126 {
00127 struct sigframe {
00128 char gap[SIGNAL_FRAMESIZE];
00129 unsigned long pad[7];
00130 struct gcc_regs *regs;
00131 } *frame = (struct sigframe *) context->cfa;
00132 return frame->regs;
00133 }
00134 else if (*(unsigned int *) (pc + 4) == 0x380000AC)
00135 {
00136
00137
00138
00139
00140 struct rt_sigframe_24 {
00141 int tramp[6];
00142 void *pinfo;
00143 struct gcc_ucontext *puc;
00144 } *frame24 = (struct rt_sigframe_24 *) pc;
00145
00146
00147 if ((long) frame24->puc != -21 * 8)
00148 return frame24->puc->regs;
00149 else
00150 {
00151
00152 struct rt_sigframe {
00153 char gap[SIGNAL_FRAMESIZE];
00154 struct gcc_ucontext uc;
00155 unsigned long pad[2];
00156 int tramp[6];
00157 void *pinfo;
00158 struct gcc_ucontext *puc;
00159 } *frame = (struct rt_sigframe *) context->cfa;
00160 return frame->uc.regs;
00161 }
00162 }
00163 return NULL;
00164 }
00165
00166 #else
00167
00168 enum { SIGNAL_FRAMESIZE = 64 };
00169
00170 static struct gcc_regs *
00171 get_regs (struct _Unwind_Context *context)
00172 {
00173 const unsigned char *pc = context->ra;
00174
00175
00176
00177
00178
00179 if (*(unsigned int *) (pc + 4) != 0x44000002)
00180 return NULL;
00181 if (*(unsigned int *) (pc + 0) == 0x38007777
00182 || *(unsigned int *) (pc + 0) == 0x38000077)
00183 {
00184 struct sigframe {
00185 char gap[SIGNAL_FRAMESIZE];
00186 unsigned long pad[7];
00187 struct gcc_regs *regs;
00188 } *frame = (struct sigframe *) context->cfa;
00189 return frame->regs;
00190 }
00191 else if (*(unsigned int *) (pc + 0) == 0x38006666
00192 || *(unsigned int *) (pc + 0) == 0x380000AC)
00193 {
00194 struct rt_sigframe {
00195 char gap[SIGNAL_FRAMESIZE + 16];
00196 char siginfo[128];
00197 struct gcc_ucontext uc;
00198 } *frame = (struct rt_sigframe *) context->cfa;
00199 return frame->uc.regs;
00200 }
00201 return NULL;
00202 }
00203 #endif
00204
00205
00206
00207
00208 static long
00209 ppc_linux_aux_vector (long which)
00210 {
00211
00212 extern long *__libc_stack_end;
00213 long argc;
00214 char **argv;
00215 char **envp;
00216 struct auxv
00217 {
00218 long a_type;
00219 long a_val;
00220 } *auxp;
00221
00222
00223 argc = __libc_stack_end[0];
00224
00225 argv = (char **) __libc_stack_end + 1;
00226
00227 envp = argv + argc + 1;
00228 while (*envp++)
00229 continue;
00230
00231 for (auxp = (struct auxv *) envp; auxp->a_type != 0; ++auxp)
00232 if (auxp->a_type == which)
00233 return auxp->a_val;
00234 return 0;
00235 }
00236
00237
00238
00239
00240 #define MD_FALLBACK_FRAME_STATE_FOR ppc_fallback_frame_state
00241
00242 static _Unwind_Reason_Code
00243 ppc_fallback_frame_state (struct _Unwind_Context *context,
00244 _Unwind_FrameState *fs)
00245 {
00246 static long hwcap = 0;
00247 struct gcc_regs *regs = get_regs (context);
00248 long new_cfa;
00249 int i;
00250
00251 if (regs == NULL)
00252 return _URC_END_OF_STACK;
00253
00254 new_cfa = regs->gpr[STACK_POINTER_REGNUM];
00255 fs->cfa_how = CFA_REG_OFFSET;
00256 fs->cfa_reg = STACK_POINTER_REGNUM;
00257 fs->cfa_offset = new_cfa - (long) context->cfa;
00258
00259 for (i = 0; i < 32; i++)
00260 if (i != STACK_POINTER_REGNUM)
00261 {
00262 fs->regs.reg[i].how = REG_SAVED_OFFSET;
00263 fs->regs.reg[i].loc.offset = (long) ®s->gpr[i] - new_cfa;
00264 }
00265
00266 fs->regs.reg[CR2_REGNO].how = REG_SAVED_OFFSET;
00267 fs->regs.reg[CR2_REGNO].loc.offset = (long) ®s->ccr - new_cfa;
00268
00269 fs->regs.reg[LINK_REGISTER_REGNUM].how = REG_SAVED_OFFSET;
00270 fs->regs.reg[LINK_REGISTER_REGNUM].loc.offset = (long) ®s->link - new_cfa;
00271
00272 fs->regs.reg[ARG_POINTER_REGNUM].how = REG_SAVED_OFFSET;
00273 fs->regs.reg[ARG_POINTER_REGNUM].loc.offset = (long) ®s->nip - new_cfa;
00274 fs->retaddr_column = ARG_POINTER_REGNUM;
00275
00276 if (hwcap == 0)
00277 {
00278 hwcap = ppc_linux_aux_vector (16);
00279
00280
00281
00282 #ifdef __powerpc64__
00283 hwcap |= 0xc0000000;
00284 #else
00285 hwcap |= 0x80000000;
00286 #endif
00287 }
00288
00289
00290 if (hwcap & 0x08000000)
00291 for (i = 0; i < 32; i++)
00292 {
00293 fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
00294 fs->regs.reg[i + 32].loc.offset = (long) ®s->fpr[i] - new_cfa;
00295 }
00296
00297
00298 if (hwcap & 0x10000000)
00299 {
00300 struct gcc_vregs *vregs;
00301 #ifdef __powerpc64__
00302 vregs = regs->vp;
00303 #else
00304 vregs = ®s->vregs;
00305 #endif
00306 if (regs->msr & (1 << 25))
00307 {
00308 for (i = 0; i < 32; i++)
00309 {
00310 fs->regs.reg[i + FIRST_ALTIVEC_REGNO].how = REG_SAVED_OFFSET;
00311 fs->regs.reg[i + FIRST_ALTIVEC_REGNO].loc.offset
00312 = (long) &vregs[i] - new_cfa;
00313 }
00314
00315 fs->regs.reg[VSCR_REGNO].how = REG_SAVED_OFFSET;
00316 fs->regs.reg[VSCR_REGNO].loc.offset = (long) &vregs->vscr - new_cfa;
00317 }
00318
00319 fs->regs.reg[VRSAVE_REGNO].how = REG_SAVED_OFFSET;
00320 fs->regs.reg[VRSAVE_REGNO].loc.offset = (long) &vregs->vsave - new_cfa;
00321 }
00322
00323 return _URC_NO_REASON;
00324 }