/* $NetBSD: stackframe.c,v 1.9 2016/07/31 19:33:18 dholland Exp $ */ /* Contributed to the NetBSD foundation by Cherry G. Mathew * This file contains routines to use decoded unwind descriptor entries * to build a stack configuration. The unwinder consults the stack * configuration to fetch registers used to unwind the frame. * References: * [1] section. 11.4.2.6., Itanium Software Conventions and * Runtime Architecture Guide. */ #include #include #include #include #include //#define UNWIND_DIAGNOSTIC /* * Global variables: * array of struct recordchain * size of record chain array. */ struct recordchain strc[MAXSTATERECS]; int rec_cnt = 0; /* * Build a recordchain of a region, given the pointer to unwind table * entry, and the number of entries to decode. */ void buildrecordchain(uint64_t unwind_infop, struct recordchain *xxx) { uint64_t unwindstart, unwindend; uint64_t unwindlen; uint64_t region_len = 0; bool region_type = false; /* Prologue */ struct unwind_hdr_t { uint64_t uwh; } *uwhp = (void *) unwind_infop; char *nextrecp, *recptr = (char *) unwind_infop + sizeof(uint64_t); unwindstart = (uint64_t) recptr; if (UNW_VER(uwhp->uwh) != 1) { printf("Wrong unwind version! \n"); return; } unwindlen = UNW_LENGTH(uwhp->uwh) * sizeof(uint64_t); unwindend = unwindstart + unwindlen; #ifdef UNWIND_DIAGNOSTIC printf("recptr = %p \n", recptr); printf("unwindlen = %lx \n", unwindlen); printf("unwindend = %lx \n", unwindend); #endif /* XXX: Ignore zero length records. */ for (rec_cnt = 0; rec_cnt < MAXSTATERECS && (uint64_t)recptr < unwindend; rec_cnt++) { nextrecp = unwind_decode_R1(recptr, &strc[rec_cnt].udesc); if (nextrecp) { region_len = strc[rec_cnt].udesc.R1.rlen; region_type = strc[rec_cnt].udesc.R1.r; strc[rec_cnt].type = R1; recptr = nextrecp; continue; } nextrecp = unwind_decode_R2(recptr, &strc[rec_cnt].udesc); if (nextrecp) { region_len = strc[rec_cnt].udesc.R2.rlen; /* R2 regions are prologue regions */ region_type = false; strc[rec_cnt].type = R2; recptr = nextrecp; continue; } nextrecp = unwind_decode_R3(recptr, &strc[rec_cnt].udesc); if (nextrecp) { region_len = strc[rec_cnt].udesc.R3.rlen; region_type = strc[rec_cnt].udesc.R3.r; strc[rec_cnt].type = R3; recptr = nextrecp; continue; } if (region_type == false) { /* Prologue Region */ nextrecp = unwind_decode_P1(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P1; recptr = nextrecp; continue; } nextrecp = unwind_decode_P2(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P2; recptr = nextrecp; continue; } nextrecp = unwind_decode_P3(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P3; recptr = nextrecp; continue; } nextrecp = unwind_decode_P4(recptr, &strc[rec_cnt].udesc, region_len); if (nextrecp) { strc[rec_cnt].type = P4; recptr = nextrecp; break; } nextrecp = unwind_decode_P5(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P5; recptr = nextrecp; continue; } nextrecp = unwind_decode_P6(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P6; recptr = nextrecp; continue; } nextrecp = unwind_decode_P7(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P7; recptr = nextrecp; continue; } nextrecp = unwind_decode_P8(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P8; recptr = nextrecp; continue; } nextrecp = unwind_decode_P9(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P9; recptr = nextrecp; continue; } nextrecp = unwind_decode_P10(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = P10; recptr = nextrecp; continue; } printf("Skipping prologue desc slot :: %d \n", rec_cnt); } else { nextrecp = unwind_decode_B1(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = B1; recptr = nextrecp; continue; } nextrecp = unwind_decode_B2(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = B2; recptr = nextrecp; continue; } nextrecp = unwind_decode_B3(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = B3; recptr = nextrecp; continue; } nextrecp = unwind_decode_B4(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = B4; recptr = nextrecp; continue; } nextrecp = unwind_decode_X1(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = X1; recptr = nextrecp; continue; } nextrecp = unwind_decode_X2(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = X2; recptr = nextrecp; continue; } nextrecp = unwind_decode_X3(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = X3; recptr = nextrecp; continue; } nextrecp = unwind_decode_X4(recptr, &strc[rec_cnt].udesc); if (nextrecp) { strc[rec_cnt].type = X4; recptr = nextrecp; continue; } printf("Skipping body desc slot :: %d \n", rec_cnt); } } #ifdef UNWIND_DIAGNOSTIC int i; for(i = 0;i < rec_cnt;i++) { dump_recordchain(&strc[i]); } #endif /* UNWIND_DIAGNOSTIC */ } /* * Debug support: dump a record chain entry */ void dump_recordchain(struct recordchain *rchain) { switch(rchain->type) { case R1: printf("\t R1:"); if(rchain->udesc.R1.r) printf("body ("); else printf("prologue ("); printf("rlen = %ld) \n", rchain->udesc.R1.rlen); break; case R2: printf("\t R2:"); printf("prologue_gr ("); printf("mask = %x, ", rchain->udesc.R2.mask); printf("grsave = %d, ", rchain->udesc.R2.grsave); printf("rlen = %ld )\n", rchain->udesc.R2.rlen); break; case R3: printf("\t R3:"); if(rchain->udesc.R3.r) printf("body ("); else printf("prologue ("); printf("rlen = %ld )\n", rchain->udesc.R3.rlen); break; case P1: printf("\t\tP1:"); printf("br_mem (brmask = %x) \n", rchain->udesc.P1.brmask); break; case P2: printf("\t\tP2:"); printf("br_gr(brmask = %x, ", rchain->udesc.P2.brmask); printf("gr = %d ) \n", rchain->udesc.P2.gr); break; case P3: printf("\t\tP3:"); switch(rchain->udesc.P3.r) { case 0: printf("psp_gr"); break; case 1: printf("rp_gr"); break; case 2: printf("pfs_gr"); break; case 3: printf("preds_gr"); break; case 4: printf("unat_gr"); break; case 5: printf("lc_gr"); break; case 6: printf("rp_br"); break; case 7: printf("rnat_gr"); break; case 8: printf("bsp_gr"); break; case 9: printf("bspstore_gr"); break; case 10: printf("fpsr_gr"); break; case 11: printf("priunat_gr"); break; default: printf("unknown desc: %d", rchain->udesc.P3.r); } printf("(gr/br = %d) \n", rchain->udesc.P3.grbr); break; case P4: printf("P4: (unimplemented): \n"); break; case P5: printf("\t\tP5:"); printf("frgr_mem(grmask = %x, frmask = %x )\n", rchain->udesc.P5.grmask, rchain->udesc.P5.frmask); break; case P6: printf("\t\tP6: "); if(rchain->udesc.P6.r) printf("gr_mem( "); else printf("fr_mem( "); printf("rmask = %x) \n", rchain->udesc.P6.rmask); break; case P7: printf("\t\tP7:"); switch(rchain->udesc.P7.r) { case 0: printf("memstack_f( "); printf("t = %ld, ", rchain->udesc.P7.t); printf("size = %ld) \n", rchain->udesc.P7.size); break; case 1: printf("memstack_v( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 2: printf("spillbase( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; case 3: printf("psp_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P7.t); break; case 4: printf("rp_when( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 5: printf("rp_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; case 6: printf("pfs_when( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 7: printf("pfs_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; case 8: printf("preds_when( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 9: printf("preds_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; case 10: printf("lc_when( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 11: printf("lc_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; case 12: printf("unat_when( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 13: printf("unat_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; case 14: printf("fpsr_when( "); printf("t = %ld) \n", rchain->udesc.P7.t); break; case 15: printf("fpsr_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P7.t); break; default: printf("unknown \n"); } break; case P8: printf("\t\tP8:"); switch(rchain->udesc.P8.r) { case 1: printf("rp_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 2: printf("pfs_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 3: printf("preds_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 4: printf("lc_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 5: printf("unat_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 6: printf("fpsr_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 7: printf("bsp_when( "); printf("t = %ld) \n", rchain->udesc.P8.t); break; case 8: printf("bsp_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P8.t); break; case 9: printf("bsp_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 10: printf("bspstore_when( "); printf("t = %ld) \n", rchain->udesc.P8.t); break; case 11: printf("bspstore_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P8.t); break; case 12: printf("bspstore_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 13: printf("rnat_when( "); printf("t = %ld) \n", rchain->udesc.P8.t); break; case 14: printf("rnat_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P8.t); break; case 15: printf("rnat_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 16: printf("priunat_when_gr( "); printf("t = %ld) \n", rchain->udesc.P8.t); break; case 17: printf("priunat_psprel( "); printf("pspoff = %ld) \n", rchain->udesc.P8.t); break; case 18: printf("priunat_sprel( "); printf("spoff = %ld) \n", rchain->udesc.P8.t); break; case 19: printf("priunat_when_mem( "); printf("t = %ld) \n", rchain->udesc.P8.t); break; default: printf("unknown \n"); } break; case P9: printf("\t\tP9:"); printf("(grmask = %x, gr = %d) \n", rchain->udesc.P9.grmask, rchain->udesc.P9.gr); break; case P10: printf("\t\tP10:"); printf("(abi: "); switch(rchain->udesc.P10.abi) { case 0: printf("Unix SVR4) \n"); break; case 1: printf("HP-UX) \n"); break; default: printf("Other) \n"); } break; case B1: printf("\t\tB1:"); if(rchain->udesc.B1.r) printf("copy_state( "); else printf("label_state( "); printf("label = %d) \n", rchain->udesc.B1.label); break; case B2: printf("\t\tB2:"); printf("(ecount = %d, t = %ld)\n", rchain->udesc.B2.ecount, rchain->udesc.B2.t); break; case B3: printf("\t\tB3:"); printf("(t = %ld, ecount = %ld) \n", rchain->udesc.B3.t, rchain->udesc.B3.ecount); break; case B4: printf("\t\tB4:"); if(rchain->udesc.B4.r) printf("copy_state( "); else printf("label_state( "); printf("label = %ld) \n", rchain->udesc.B4.label); break; case X1: printf("\tX1:\n "); break; case X2: printf("\tX2:\n"); break; case X3: printf("\tX3:\n"); break; case X4: printf("\tX4:\n"); break; default: printf("\tunknow: \n"); } } /* * State record stuff..... based on section 11. and Appendix A. of the * "Itanium Software Conventions and Runtime Architecture Guide" */ /* * Global variables: * 1. Two arrays of staterecords: recordstack[], recordstackcopy[] * XXX: Since we don't use malloc, we have two arbitrary sized arrays * providing guaranteed memory from the BSS. See the TODO file * for more details. * 2. Two head variables to hold the member index: unwind_rsp,unwind_rscp */ struct staterecord recordstack[MAXSTATERECS]; struct staterecord recordstackcopy[MAXSTATERECS]; struct staterecord current_state; struct staterecord *unwind_rsp, *unwind_rscp; /* Base of spill area in memory stack frame as a psp relative offset */ uint64_t spill_base = 0; /* * Initialises a staterecord from a given template, * with default values as described by the Runtime Spec. */ void initrecord(struct staterecord *target) { target->bsp.where = UNSAVED; target->bsp.when = 0; target->bsp.offset = INVALID; target->psp.where = UNSAVED; target->psp.when = 0; target->psp.offset = INVALID; target->rp.where = UNSAVED; target->rp.when = 0; target->rp.offset = INVALID; target->pfs.where = UNSAVED; target->pfs.when = 0; target->pfs.offset = INVALID; } /* * Modifies a staterecord structure by parsing * a single record chain structure. * regionoffset is the offset within a (prologue) region * where the stack unwinding began. */ void modifyrecord(struct staterecord *srec, struct recordchain *rchain, uint64_t regionoffset) { /* * Default start save GR for prologue_save GRs. */ uint64_t grno = 32; switch (rchain->type) { case R2: /* * R2, prologue_gr is the only region encoding * with register save info. */ grno = rchain->udesc.R2.grsave; if (rchain->udesc.R2.mask & R2MASKRP) { srec->rp.when = 0; srec->rp.where = GRREL; srec->rp.offset = grno++; } if (rchain->udesc.R2.mask & R2MASKPFS) { srec->pfs.when = 0; srec->pfs.where = GRREL; srec->pfs.offset = grno++; } if (rchain->udesc.R2.mask & R2MASKPSP) { srec->psp.when = 0; srec->psp.where = GRREL; srec->psp.offset = grno++; } break; case P3: switch (rchain->udesc.P3.r) { case 0: /* psp_gr */ if (srec->psp.when < regionoffset) { srec->psp.where = GRREL; srec->psp.offset = rchain->udesc.P3.grbr; } break; case 1: /* rp_gr */ if (srec->rp.when < regionoffset) { srec->rp.where = GRREL; srec->rp.offset = rchain->udesc.P3.grbr; } break; case 2: /* pfs_gr */ if (srec->pfs.when < regionoffset) { srec->pfs.where = GRREL; srec->pfs.offset = rchain->udesc.P3.grbr; } break; } break; /* * XXX: P4 spill_mask and P7: spill_base are for GRs, FRs, and BRs. * We're not particularly worried about those right now. */ case P7: switch (rchain->udesc.P7.r) { case 0: /* mem_stack_f */ if (srec->psp.offset != INVALID) { printf("!!!saw mem_stack_f more than once. \n"); } srec->psp.when = rchain->udesc.P7.t; if (srec->psp.when < regionoffset) { srec->psp.where = IMMED; /* spsz.offset is "overloaded" */ srec->psp.offset = rchain->udesc.P7.size; } break; case 1: /* mem_stack_v */ srec->psp.when = rchain->udesc.P7.t; break; case 2: /* spill_base */ spill_base = rchain->udesc.P7.t; break; case 3: /* psp_sprel */ if (srec->psp.when < regionoffset) { srec->psp.where = SPREL; srec->psp.offset = rchain->udesc.P7.t; } break; case 4: /* rp_when */ srec->rp.when = rchain->udesc.P7.t; /* * XXX: Need to set to prologue_gr(grno) for * the orphan case ie; _gr/_psprel/_sprel * not set and therefore default to begin * from the gr specified in prologue_gr. */ break; case 5: /* rp_psprel */ if (srec->rp.when < regionoffset) { srec->rp.where = PSPREL; srec->rp.offset = rchain->udesc.P7.t; } break; case 6: /* pfs_when */ srec->pfs.when = rchain->udesc.P7.t; /* * XXX: Need to set to prologue_gr(grno) for * the orphan case ie; _gr/_psprel/_sprel * not set and therefore default to begin * from the gr specified in prologue_gr. */ break; case 7: /* pfs_psprel */ if (srec->pfs.when < regionoffset) { srec->pfs.where = PSPREL; srec->pfs.offset = rchain->udesc.P7.t; } break; } break; case P8: switch (rchain->udesc.P8.r) { case 1: /* rp_sprel */ if (srec->rp.when < regionoffset) { srec->rp.where = SPREL; srec->rp.offset = rchain->udesc.P8.t; } break; case 2: /* pfs_sprel */ if (srec->pfs.when < regionoffset) { srec->pfs.where = SPREL; srec->pfs.offset = rchain->udesc.P8.t; } break; } break; case B1: rchain->udesc.B1.r ? switchrecordstack(0) : clonerecordstack(0); break; case B2: if (regionoffset < rchain->udesc.B2.t) { poprecord(¤t_state, rchain->udesc.B2.ecount); } break; case B3: if (regionoffset < rchain->udesc.B3.t) { poprecord(¤t_state, rchain->udesc.B3.ecount); } break; case B4: rchain->udesc.B4.r ? switchrecordstack(0) : clonerecordstack(0); break; case X1: case X2: case X3: /* XXX: Todo */ break; case R1: case R3: case P1: case P2: case P4: case P5: case P6: case P9: case P10: default: /* Ignore. */ printf("XXX: Ignored. \n"); } } void dump_staterecord(struct staterecord *srec) { printf("rp.where: "); switch(srec->rp.where) { case UNSAVED: printf("UNSAVED "); break; case BRREL: printf("BRREL "); break; case GRREL: printf("GRREL "); break; case SPREL: printf("SPREL "); break; case PSPREL: printf("PSPSREL "); break; default: printf("unknown "); } printf(", rp.when = %lu, ", srec->rp.when); printf("rp.offset = %lu \n", srec->rp.offset); printf("pfs.where: "); switch(srec->pfs.where) { case UNSAVED: printf("UNSAVED "); break; case BRREL: printf("BRREL "); break; case GRREL: printf("GRREL "); break; case SPREL: printf("SPREL "); break; case PSPREL: printf("PSPSREL "); break; default: printf("unknown "); } printf(", pfs.when = %lu, ", srec->pfs.when); printf("pfs.offset = %lu \n", srec->pfs.offset); } /* * Push a state record on the record stack. */ void pushrecord(struct staterecord *srec) { if(unwind_rsp >= recordstack + MAXSTATERECS) { printf("Push exceeded array size!!! \n"); return; } memcpy(unwind_rsp, srec, sizeof(struct staterecord)); unwind_rsp++; } /* * Pop n state records off the record stack. */ void poprecord(struct staterecord *srec, int n) { if(unwind_rsp == recordstack) { printf("Popped beyond end of Stack!!! \n"); return; } unwind_rsp -= n; memcpy(srec, unwind_rsp, sizeof(struct staterecord)); #ifdef DEBUG memset(unwind_rsp, 0, sizeof(struct staterecord) * n); #endif } /* * Clone the whole record stack upto this one. */ void clonerecordstack(u_int label) { memcpy(recordstackcopy, recordstack, (unwind_rsp - recordstack) * sizeof(struct staterecord)); unwind_rscp = unwind_rsp; } /* * Discard the current stack, and adopt a clone. */ void switchrecordstack(u_int label) { memcpy((void *) recordstack, (void *) recordstackcopy, (unwind_rscp - recordstackcopy) * sizeof(struct staterecord)); unwind_rsp = unwind_rscp; } /* * In the context of a procedure: * Parses through a record chain, building, pushing and/or popping staterecords, * or cloning/destroying stacks of staterecords as required. * Parameters are: * rchain: pointer to recordchain array. * procoffset: offset of point of interest, in slots, within procedure * starting from slot 0 * This routine obeys [1] */ struct staterecord * buildrecordstack(struct recordchain *rchain, uint64_t procoffset) { /* Current region length, defaults to zero if not specified */ uint64_t rlen = 0; /* Accumulated region length */ uint64_t roffset = 0; /* Offset within current region */ uint64_t rdepth = 0; bool rtype; int i; /* Start with bottom of staterecord stack. */ unwind_rsp = recordstack; initrecord(¤t_state); for (i = 0;i < rec_cnt;i++) { switch (rchain[i].type) { case R1: rlen = rchain[i].udesc.R1.rlen; if (procoffset < roffset) { /* * Overshot Region containing * procoffset. Bail out. */ goto out; } rdepth = procoffset - roffset; roffset += rlen; rtype = rchain[i].udesc.R1.r; if (!rtype) { pushrecord(¤t_state); } break; case R3: rlen = rchain[i].udesc.R3.rlen; if (procoffset < roffset) { /* * Overshot Region containing * procoffset. Bail out. */ goto out; } rdepth = procoffset - roffset; roffset += rlen; rtype = rchain[i].udesc.R3.r; if (!rtype) { pushrecord(¤t_state); } break; case R2: rlen = rchain[i].udesc.R2.rlen; if (procoffset < roffset) { /* * Overshot Region containing * procoffset. Bail out. */ goto out; } rdepth = procoffset - roffset; roffset += rlen; rtype = false; /* prologue region */ pushrecord(¤t_state); /* R2 has save info. Continue down. */ /* FALLTHROUGH */ case P1: case P2: case P3: case P4: case P5: case P6: case P7: case P8: case P9: case P10: modifyrecord(¤t_state, &rchain[i], rdepth); break; case B1: case B2: case B3: case B4: modifyrecord(¤t_state, &rchain[i], rlen - 1 - rdepth); break; case X1: case X2: case X3: case X4: default: printf("Error: Unknown descriptor type!!! \n"); } #if UNWIND_DIAGNOSTIC dump_staterecord(¤t_state); #endif } out: return ¤t_state; } void updateregs(struct unwind_frame *uwf, struct staterecord *srec, uint64_t procoffset) { /* XXX: Update uwf for regs other than rp and pfs*/ uint64_t roffset = 0; /* Uses shadow arrays to update uwf from srec in a loop. */ /* Count of number of regstate elements in struct staterecord */ int statecount = sizeof(struct staterecord)/sizeof(struct regstate); /* Pointer to current regstate. */ struct regstate *stptr = (void *) srec; /* Pointer to current unwind_frame element */ uint64_t *gr = (void *) uwf; int i; #ifdef UNWIND_DIAGNOSTIC printf("updateregs(): \n"); printf("procoffset (slots) = %lu \n", procoffset); #endif for(i = 0; i < statecount; i++) { switch (stptr[i].where) { case IMMED: /* currently only mem_stack_f */ if (stptr[i].when >= procoffset) break; uwf->psp -= (stptr[i].offset << 4); break; case GRREL: if (stptr[i].when >= procoffset) break; roffset = stptr[i].offset; if (roffset == 0) { gr[i] = 0; break; } if (roffset < 32) { printf("GR%ld: static register save ??? \n", roffset); break; } /* Fetch from bsp + offset - 32 + Adjust for RNAT. */ roffset -= 32; gr[i] = ia64_getrse_gr(uwf->bsp, roffset); break; case SPREL: if (stptr[i].when >= procoffset) break; /* Check if frame has been setup. */ if (srec->psp.offset == INVALID) { printf("sprel used without setting up " "stackframe!!! \n"); break; } roffset = stptr[i].offset; /* Fetch from sp + offset */ memcpy(&gr[i], (char *) uwf->sp + roffset * 4, sizeof(uint64_t)); break; case PSPREL: if (stptr[i].when >= procoffset) break; /* Check if frame has been setup. */ if (srec->psp.offset == INVALID) { printf("psprel used without setting up " "stackframe!!! \n"); break; } roffset = stptr[i].offset; /* Fetch from sp + offset */ memcpy(&gr[i], (char *) uwf->psp + 16 - (roffset * 4), sizeof(uint64_t)); break; case UNSAVED: case BRREL: default: #ifdef UNWIND_DIAGNOSTIC printf ("updateregs: reg[%d] is UNSAVED \n", i); #endif break; /* XXX: Not implemented yet. */ } } } /* * Locates unwind table entry, given unwind table entry info. * Expects the variables ia64_unwindtab, and ia64_unwindtablen * to be set appropriately. */ struct uwtable_ent * get_unwind_table_entry(uint64_t iprel) { extern uint64_t ia64_unwindtab, ia64_unwindtablen; struct uwtable_ent *uwt; int tabent; for(uwt = (struct uwtable_ent *) ia64_unwindtab, tabent = 0; /* The Runtime spec tells me the table entries are sorted. */ uwt->end <= iprel && tabent < ia64_unwindtablen; uwt++, tabent += sizeof(struct uwtable_ent)); if (!(uwt->start <= iprel && iprel < uwt->end)) { #ifdef UNWIND_DIAGNOSTIC printf("Entry not found \n"); printf("iprel = %lx \n", iprel); printf("uwt->start = %lx \nuwt->end = %lx \n", uwt->start, uwt->end); printf("tabent = %d \n", tabent); printf("ia64_unwindtablen = %ld \n", ia64_unwindtablen); #endif return NULL; } #ifdef UNWIND_DIAGNOSTIC printf("uwt->start = %lx \nuwt->end = %lx \n" "uwt->infoptr = %p\n", uwt->start, uwt->end, uwt->infoptr); #endif return uwt; } /* * Reads unwind table info and updates register values. */ void patchunwindframe(struct unwind_frame *uwf, uint64_t iprel, uint64_t relocoffset) { extern struct recordchain strc[]; struct staterecord *srec; struct uwtable_ent *uwt; uint64_t infoptr, procoffset, slotoffset; #if 0 /* does not work - moved to assertion at the call site */ if (iprel < 0) { panic("unwind ip out of range!!! \n"); return; } #endif uwt = get_unwind_table_entry(iprel); if (uwt == NULL) return; infoptr = (uint64_t) uwt->infoptr + relocoffset; if (infoptr > relocoffset) { buildrecordchain(infoptr, NULL); } else { return; } slotoffset = iprel & 3; /* procoffset in Number of _slots_ , _not_ a byte offset. */ procoffset = (((iprel - slotoffset) - (uwt->start)) / 0x10 * 3) + slotoffset; srec = buildrecordstack(strc, procoffset); updateregs(uwf, srec, procoffset); }