+ stackframeinfo sfi;
+ ucontext_t *_uc;
+ mcontext_t *_mc;
+ greg_t *_gregs;
+ u1 *pv;
+ u1 *sp;
+ u1 *ra;
+ u1 *xpc;
+ unsigned int cause;
+ u4 mcode;
+ int d;
+ int s1;
+ int16_t disp;
+ intptr_t val;
+ intptr_t addr;
+ int type;
+ void *p;
+
+ _uc = (struct ucontext *) _p;
+ _mc = &_uc->uc_mcontext;
+
+#if defined(__UCLIBC__)
+ _gregs = _mc->gpregs;
+#else
+ _gregs = _mc->gregs;
+#endif
+
+ /* In glibc's ucontext.h the registers are defined as long long,
+ even for MIPS32, so we cast them. This is not the case for
+ uClibc. */
+
+ pv = (u1 *) (ptrint) _gregs[REG_PV];
+ sp = (u1 *) (ptrint) _gregs[REG_SP];
+ ra = (u1 *) (ptrint) _gregs[REG_RA]; /* this is correct for leafs */
+
+#if !defined(__UCLIBC__) && ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 5))
+ /* NOTE: We only need this for pre glibc-2.5. */
+
+ xpc = (u1 *) (ptrint) _mc->pc;
+
+ /* get the cause of this exception */
+
+ cause = _mc->cause;
+
+ /* check the cause to find the faulting instruction */
+
+ /* TODO: use defines for that stuff */
+
+ switch (cause & 0x0000003c) {
+ case 0x00000008:
+ /* TLBL: XPC is ok */
+ break;
+
+ case 0x00000010:
+ /* AdEL: XPC is of the following instruction */
+ xpc = xpc - 4;
+ break;
+ }
+#else
+ xpc = (u1 *) (ptrint) _gregs[CTX_EPC];
+#endif
+
+ /* get exception-throwing instruction */
+
+ mcode = *((u4 *) xpc);
+
+ d = M_ITYPE_GET_RT(mcode);
+ s1 = M_ITYPE_GET_RS(mcode);
+ disp = M_ITYPE_GET_IMM(mcode);
+
+ /* check for special-load */
+
+ if (s1 == REG_ZERO) {
+ /* we use the exception type as load displacement */