Home | History | Annotate | Line # | Download | only in unwind
      1 /*	$NetBSD: stackframe.c,v 1.9 2016/07/31 19:33:18 dholland Exp $	*/
      2 
      3 /* Contributed to the NetBSD foundation by Cherry G. Mathew <cherry (at) mahiti.org>
      4  * This file contains routines to use decoded unwind descriptor entries
      5  * to build a stack configuration. The unwinder consults the stack
      6  * configuration to fetch registers used to unwind the frame.
      7  * References:
      8  *	[1] section. 11.4.2.6., Itanium Software Conventions and
      9  *			Runtime Architecture Guide.
     10  */
     11 
     12 #include <sys/cdefs.h>
     13 #include <sys/param.h>
     14 #include <sys/systm.h>
     15 
     16 
     17 #include <ia64/unwind/decode.h>
     18 #include <ia64/unwind/stackframe.h>
     19 
     20 //#define UNWIND_DIAGNOSTIC
     21 
     22 /*
     23  * Global variables:
     24  * array of struct recordchain
     25  * size of record chain array.
     26  */
     27 struct recordchain strc[MAXSTATERECS];
     28 int rec_cnt = 0;
     29 
     30 /*
     31  * Build a recordchain of a region, given the pointer to unwind table
     32  * entry, and the number of entries to decode.
     33  */
     34 void
     35 buildrecordchain(uint64_t unwind_infop, struct recordchain *xxx)
     36 {
     37 	uint64_t unwindstart, unwindend;
     38 	uint64_t unwindlen;
     39 	uint64_t region_len = 0;
     40 	bool region_type = false; /* Prologue */
     41 
     42 	struct unwind_hdr_t {
     43 		uint64_t uwh;
     44 	} *uwhp = (void *) unwind_infop;
     45 
     46 	char *nextrecp, *recptr = (char *) unwind_infop + sizeof(uint64_t);
     47 
     48 	unwindstart = (uint64_t) recptr;
     49 
     50 	if (UNW_VER(uwhp->uwh) != 1) {
     51 		printf("Wrong unwind version! \n");
     52 		return;
     53 	}
     54 
     55 	unwindlen = UNW_LENGTH(uwhp->uwh) * sizeof(uint64_t);
     56 	unwindend = unwindstart + unwindlen;
     57 
     58 #ifdef UNWIND_DIAGNOSTIC
     59 	printf("recptr = %p \n", recptr);
     60 	printf("unwindlen = %lx \n", unwindlen);
     61 	printf("unwindend = %lx \n", unwindend);
     62 #endif
     63 
     64 	/* XXX: Ignore zero length records. */
     65 
     66 
     67 	for (rec_cnt = 0;
     68 	    rec_cnt < MAXSTATERECS && (uint64_t)recptr < unwindend;
     69 	    rec_cnt++) {
     70 		nextrecp = unwind_decode_R1(recptr, &strc[rec_cnt].udesc);
     71 		if (nextrecp) {
     72 			region_len = strc[rec_cnt].udesc.R1.rlen;
     73 			region_type = strc[rec_cnt].udesc.R1.r;
     74 			strc[rec_cnt].type = R1;
     75 			recptr = nextrecp;
     76 			continue;
     77 		}
     78 
     79 		nextrecp = unwind_decode_R2(recptr, &strc[rec_cnt].udesc);
     80 		if (nextrecp) {
     81 			region_len = strc[rec_cnt].udesc.R2.rlen;
     82 			/* R2 regions are prologue regions */
     83 			region_type = false;
     84 			strc[rec_cnt].type = R2;
     85 			recptr = nextrecp;
     86 			continue;
     87 		}
     88 
     89 		nextrecp = unwind_decode_R3(recptr, &strc[rec_cnt].udesc);
     90 		if (nextrecp) {
     91 			region_len = strc[rec_cnt].udesc.R3.rlen;
     92 			region_type = strc[rec_cnt].udesc.R3.r;
     93 			strc[rec_cnt].type = R3;
     94 			recptr = nextrecp;
     95 			continue;
     96 		}
     97 
     98 		if (region_type == false) {
     99 			/* Prologue Region */
    100 			nextrecp = unwind_decode_P1(recptr,
    101 						    &strc[rec_cnt].udesc);
    102 			if (nextrecp) {
    103 				strc[rec_cnt].type = P1;
    104 				recptr = nextrecp;
    105 				continue;
    106 			}
    107 
    108 			nextrecp = unwind_decode_P2(recptr,
    109 						    &strc[rec_cnt].udesc);
    110 			if (nextrecp) {
    111 				strc[rec_cnt].type = P2;
    112 				recptr = nextrecp;
    113 				continue;
    114 			}
    115 
    116 			nextrecp = unwind_decode_P3(recptr,
    117 						    &strc[rec_cnt].udesc);
    118 			if (nextrecp) {
    119 				strc[rec_cnt].type = P3;
    120 				recptr = nextrecp;
    121 				continue;
    122 			}
    123 
    124 			nextrecp = unwind_decode_P4(recptr,
    125 						    &strc[rec_cnt].udesc,
    126 						    region_len);
    127 			if (nextrecp) {
    128 				strc[rec_cnt].type = P4;
    129 				recptr = nextrecp;
    130 				break;
    131 			}
    132 
    133 			nextrecp = unwind_decode_P5(recptr,
    134 						    &strc[rec_cnt].udesc);
    135 			if (nextrecp) {
    136 				strc[rec_cnt].type = P5;
    137 				recptr = nextrecp;
    138 				continue;
    139 			}
    140 
    141 			nextrecp = unwind_decode_P6(recptr,
    142 						    &strc[rec_cnt].udesc);
    143 			if (nextrecp) {
    144 				strc[rec_cnt].type = P6;
    145 				recptr = nextrecp;
    146 				continue;
    147 			}
    148 
    149 			nextrecp = unwind_decode_P7(recptr,
    150 						    &strc[rec_cnt].udesc);
    151 			if (nextrecp) {
    152 				strc[rec_cnt].type = P7;
    153 				recptr = nextrecp;
    154 				continue;
    155 			}
    156 
    157 			nextrecp = unwind_decode_P8(recptr,
    158 						    &strc[rec_cnt].udesc);
    159 			if (nextrecp) {
    160 				strc[rec_cnt].type = P8;
    161 				recptr = nextrecp;
    162 				continue;
    163 			}
    164 
    165 			nextrecp = unwind_decode_P9(recptr,
    166 						    &strc[rec_cnt].udesc);
    167 			if (nextrecp) {
    168 				strc[rec_cnt].type = P9;
    169 				recptr = nextrecp;
    170 				continue;
    171 			}
    172 
    173 			nextrecp = unwind_decode_P10(recptr,
    174 						     &strc[rec_cnt].udesc);
    175 			if (nextrecp) {
    176 				strc[rec_cnt].type = P10;
    177 				recptr = nextrecp;
    178 				continue;
    179 			}
    180 
    181 			printf("Skipping prologue desc slot :: %d \n", rec_cnt);
    182 		} else {
    183 
    184 			nextrecp = unwind_decode_B1(recptr,
    185 						    &strc[rec_cnt].udesc);
    186 			if (nextrecp) {
    187 				strc[rec_cnt].type = B1;
    188 				recptr = nextrecp;
    189 				continue;
    190 			}
    191 
    192 			nextrecp = unwind_decode_B2(recptr,
    193 						    &strc[rec_cnt].udesc);
    194 			if (nextrecp) {
    195 				strc[rec_cnt].type = B2;
    196 				recptr = nextrecp;
    197 				continue;
    198 			}
    199 
    200 			nextrecp = unwind_decode_B3(recptr,
    201 						    &strc[rec_cnt].udesc);
    202 			if (nextrecp) {
    203 				strc[rec_cnt].type = B3;
    204 				recptr = nextrecp;
    205 				continue;
    206 			}
    207 
    208 			nextrecp = unwind_decode_B4(recptr,
    209 						    &strc[rec_cnt].udesc);
    210 			if (nextrecp) {
    211 				strc[rec_cnt].type = B4;
    212 				recptr = nextrecp;
    213 				continue;
    214 			}
    215 
    216 			nextrecp = unwind_decode_X1(recptr,
    217 						    &strc[rec_cnt].udesc);
    218 			if (nextrecp) {
    219 				strc[rec_cnt].type = X1;
    220 				recptr = nextrecp;
    221 				continue;
    222 			}
    223 
    224 			nextrecp = unwind_decode_X2(recptr,
    225 						    &strc[rec_cnt].udesc);
    226 			if (nextrecp) {
    227 				strc[rec_cnt].type = X2;
    228 				recptr = nextrecp;
    229 				continue;
    230 			}
    231 
    232 
    233 			nextrecp = unwind_decode_X3(recptr,
    234 						    &strc[rec_cnt].udesc);
    235 			if (nextrecp) {
    236 				strc[rec_cnt].type = X3;
    237 				recptr = nextrecp;
    238 				continue;
    239 			}
    240 
    241 			nextrecp = unwind_decode_X4(recptr,
    242 						    &strc[rec_cnt].udesc);
    243 			if (nextrecp) {
    244 				strc[rec_cnt].type = X4;
    245 				recptr = nextrecp;
    246 				continue;
    247 			}
    248 
    249 			printf("Skipping body desc slot :: %d \n", rec_cnt);
    250 		}
    251 	}
    252 
    253 #ifdef UNWIND_DIAGNOSTIC
    254 	int i;
    255 	for(i = 0;i < rec_cnt;i++) {
    256 		dump_recordchain(&strc[i]);
    257 	}
    258 
    259 #endif /* UNWIND_DIAGNOSTIC */
    260 }
    261 
    262 
    263 
    264 
    265 /*
    266  * Debug support: dump a record chain entry
    267  */
    268 void
    269 dump_recordchain(struct recordchain *rchain)
    270 {
    271 
    272 	switch(rchain->type) {
    273 	case R1:
    274 		printf("\t R1:");
    275 		if(rchain->udesc.R1.r)
    276 			printf("body (");
    277 		else
    278 			printf("prologue (");
    279 		printf("rlen = %ld) \n", rchain->udesc.R1.rlen);
    280 		break;
    281 
    282 	case R2:
    283 		printf("\t R2:");
    284 		printf("prologue_gr (");
    285 		printf("mask = %x, ", rchain->udesc.R2.mask);
    286 		printf("grsave = %d, ", rchain->udesc.R2.grsave);
    287 		printf("rlen = %ld )\n", rchain->udesc.R2.rlen);
    288 		break;
    289 
    290 	case R3:
    291 		printf("\t R3:");
    292 		if(rchain->udesc.R3.r)
    293 			printf("body (");
    294 		else
    295 			printf("prologue (");
    296 		printf("rlen = %ld )\n", rchain->udesc.R3.rlen);
    297 		break;
    298 
    299 	case P1:
    300 		printf("\t\tP1:");
    301 		printf("br_mem (brmask = %x) \n", rchain->udesc.P1.brmask);
    302 		break;
    303 
    304 	case P2:
    305 		printf("\t\tP2:");
    306 		printf("br_gr(brmask = %x, ", rchain->udesc.P2.brmask);
    307 		printf("gr = %d ) \n", rchain->udesc.P2.gr);
    308 		break;
    309 
    310 	case P3:
    311 		printf("\t\tP3:");
    312 		switch(rchain->udesc.P3.r) {
    313 		case 0:
    314 			printf("psp_gr");
    315 			break;
    316 		case 1:
    317 			printf("rp_gr");
    318 			break;
    319 		case 2:
    320 			printf("pfs_gr");
    321 			break;
    322 		case 3:
    323 			printf("preds_gr");
    324 			break;
    325 		case 4:
    326 			printf("unat_gr");
    327 			break;
    328 		case 5:
    329 			printf("lc_gr");
    330 			break;
    331 		case 6:
    332 			printf("rp_br");
    333 			break;
    334 		case 7:
    335 			printf("rnat_gr");
    336 			break;
    337 		case 8:
    338 			printf("bsp_gr");
    339 			break;
    340 		case 9:
    341 			printf("bspstore_gr");
    342 			break;
    343 		case 10:
    344 			printf("fpsr_gr");
    345 			break;
    346 		case 11:
    347 			printf("priunat_gr");
    348 			break;
    349 		default:
    350 			printf("unknown desc: %d", rchain->udesc.P3.r);
    351 
    352 		}
    353 		printf("(gr/br = %d) \n", rchain->udesc.P3.grbr);
    354 
    355 		break;
    356 
    357 	case P4:
    358 		printf("P4: (unimplemented): \n");
    359 		break;
    360 
    361 	case P5:
    362 		printf("\t\tP5:");
    363 		printf("frgr_mem(grmask = %x, frmask = %x )\n",
    364 		       rchain->udesc.P5.grmask, rchain->udesc.P5.frmask);
    365 		break;
    366 
    367 	case P6:
    368 		printf("\t\tP6: ");
    369 		if(rchain->udesc.P6.r)
    370 			printf("gr_mem( ");
    371 		else
    372 			printf("fr_mem( ");
    373 		printf("rmask = %x) \n", rchain->udesc.P6.rmask);
    374 		break;
    375 
    376 	case P7:
    377 		printf("\t\tP7:");
    378 		switch(rchain->udesc.P7.r) {
    379 		case 0:
    380 			printf("memstack_f( ");
    381 			printf("t = %ld, ", rchain->udesc.P7.t);
    382 			printf("size = %ld) \n", rchain->udesc.P7.size);
    383 			break;
    384 		case 1:
    385 			printf("memstack_v( ");
    386 			printf("t = %ld) \n", rchain->udesc.P7.t);
    387 			break;
    388 		case 2:
    389 			printf("spillbase( ");
    390 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    391 			break;
    392 		case 3:
    393 			printf("psp_sprel( ");
    394 			printf("spoff = %ld) \n", rchain->udesc.P7.t);
    395 			break;
    396 		case 4:
    397 			printf("rp_when( ");
    398 			printf("t = %ld) \n", rchain->udesc.P7.t);
    399 			break;
    400 		case 5:
    401 			printf("rp_psprel( ");
    402 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    403 			break;
    404 		case 6:
    405 			printf("pfs_when( ");
    406 			printf("t = %ld) \n", rchain->udesc.P7.t);
    407 			break;
    408 		case 7:
    409 			printf("pfs_psprel( ");
    410 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    411 			break;
    412 		case 8:
    413 			printf("preds_when( ");
    414 			printf("t = %ld) \n", rchain->udesc.P7.t);
    415 			break;
    416 		case 9:
    417 			printf("preds_psprel( ");
    418 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    419 			break;
    420 		case 10:
    421 			printf("lc_when( ");
    422 			printf("t = %ld) \n", rchain->udesc.P7.t);
    423 			break;
    424 		case 11:
    425 			printf("lc_psprel( ");
    426 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    427 			break;
    428 		case 12:
    429 			printf("unat_when( ");
    430 			printf("t = %ld) \n", rchain->udesc.P7.t);
    431 			break;
    432 		case 13:
    433 			printf("unat_psprel( ");
    434 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    435 			break;
    436 		case 14:
    437 			printf("fpsr_when( ");
    438 			printf("t = %ld) \n", rchain->udesc.P7.t);
    439 			break;
    440 		case 15:
    441 			printf("fpsr_psprel( ");
    442 			printf("pspoff = %ld) \n", rchain->udesc.P7.t);
    443 			break;
    444 		default:
    445 			printf("unknown \n");
    446 		}
    447 
    448 		break;
    449 
    450 	case P8:
    451 		printf("\t\tP8:");
    452 		switch(rchain->udesc.P8.r) {
    453 		case 1:
    454 			printf("rp_sprel( ");
    455 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    456 			break;
    457 		case 2:
    458 			printf("pfs_sprel( ");
    459 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    460 			break;
    461 		case 3:
    462 			printf("preds_sprel( ");
    463 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    464 			break;
    465 		case 4:
    466 			printf("lc_sprel( ");
    467 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    468 			break;
    469 		case 5:
    470 			printf("unat_sprel( ");
    471 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    472 			break;
    473 		case 6:
    474 			printf("fpsr_sprel( ");
    475 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    476 			break;
    477 		case 7:
    478 			printf("bsp_when( ");
    479 			printf("t = %ld) \n", rchain->udesc.P8.t);
    480 			break;
    481 		case 8:
    482 			printf("bsp_psprel( ");
    483 			printf("pspoff = %ld) \n", rchain->udesc.P8.t);
    484 			break;
    485 		case 9:
    486 			printf("bsp_sprel( ");
    487 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    488 			break;
    489 		case 10:
    490 			printf("bspstore_when( ");
    491 			printf("t = %ld) \n", rchain->udesc.P8.t);
    492 			break;
    493 		case 11:
    494 			printf("bspstore_psprel( ");
    495 			printf("pspoff = %ld) \n", rchain->udesc.P8.t);
    496 			break;
    497 		case 12:
    498 			printf("bspstore_sprel( ");
    499 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    500 			break;
    501 		case 13:
    502 			printf("rnat_when( ");
    503 			printf("t = %ld) \n", rchain->udesc.P8.t);
    504 			break;
    505 		case 14:
    506 			printf("rnat_psprel( ");
    507 			printf("pspoff = %ld) \n", rchain->udesc.P8.t);
    508 			break;
    509 		case 15:
    510 			printf("rnat_sprel( ");
    511 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    512 			break;
    513 		case 16:
    514 			printf("priunat_when_gr( ");
    515 			printf("t = %ld) \n", rchain->udesc.P8.t);
    516 			break;
    517 		case 17:
    518 			printf("priunat_psprel( ");
    519 			printf("pspoff = %ld) \n", rchain->udesc.P8.t);
    520 			break;
    521 		case 18:
    522 			printf("priunat_sprel( ");
    523 			printf("spoff = %ld) \n", rchain->udesc.P8.t);
    524 			break;
    525 		case 19:
    526 			printf("priunat_when_mem( ");
    527 			printf("t = %ld) \n", rchain->udesc.P8.t);
    528 			break;
    529 
    530 		default:
    531 			printf("unknown \n");
    532 		}
    533 
    534 		break;
    535 
    536 	case P9:
    537 		printf("\t\tP9:");
    538 		printf("(grmask = %x, gr = %d) \n",
    539 		       rchain->udesc.P9.grmask, rchain->udesc.P9.gr);
    540 		break;
    541 
    542 	case P10:
    543 		printf("\t\tP10:");
    544 		printf("(abi: ");
    545 		switch(rchain->udesc.P10.abi) {
    546 		case 0:
    547 			printf("Unix SVR4) \n");
    548 			break;
    549 		case 1:
    550 			printf("HP-UX) \n");
    551 			break;
    552 		default:
    553 			printf("Other) \n");
    554 		}
    555 		break;
    556 
    557 	case B1:
    558 		printf("\t\tB1:");
    559 		if(rchain->udesc.B1.r)
    560 			printf("copy_state( ");
    561 		else
    562 			printf("label_state( ");
    563 		printf("label = %d) \n", rchain->udesc.B1.label);
    564 
    565 		break;
    566 
    567 	case B2:
    568 		printf("\t\tB2:");
    569 		printf("(ecount = %d, t = %ld)\n",
    570 		       rchain->udesc.B2.ecount, rchain->udesc.B2.t);
    571 
    572 		break;
    573 
    574 	case B3:
    575 		printf("\t\tB3:");
    576 		printf("(t = %ld, ecount = %ld) \n",
    577 		       rchain->udesc.B3.t, rchain->udesc.B3.ecount);
    578 
    579 		break;
    580 
    581 	case B4:
    582 		printf("\t\tB4:");
    583 		if(rchain->udesc.B4.r)
    584 			printf("copy_state( ");
    585 		else
    586 			printf("label_state( ");
    587 
    588 		printf("label = %ld) \n", rchain->udesc.B4.label);
    589 
    590 		break;
    591 
    592 
    593 	case X1:
    594 		printf("\tX1:\n ");
    595 		break;
    596 
    597 	case X2:
    598 		printf("\tX2:\n");
    599 		break;
    600 
    601 	case X3:
    602 		printf("\tX3:\n");
    603 		break;
    604 
    605 	case X4:
    606 		printf("\tX4:\n");
    607 		break;
    608 	default:
    609 		printf("\tunknow: \n");
    610 	}
    611 
    612 }
    613 
    614 /*
    615  * State record stuff..... based on section 11. and Appendix A. of the
    616  * "Itanium Software Conventions and Runtime Architecture Guide"
    617  */
    618 
    619 
    620 /*
    621  * Global variables:
    622  * 1. Two arrays of staterecords: recordstack[], recordstackcopy[]
    623  *	XXX:	Since we don't use malloc, we have two arbitrary sized arrays
    624  *		providing guaranteed memory from the BSS. See the TODO file
    625  *		for more details.
    626  * 2. Two head variables to hold the member index: unwind_rsp,unwind_rscp
    627  */
    628 
    629 struct staterecord recordstack[MAXSTATERECS];
    630 struct staterecord recordstackcopy[MAXSTATERECS];
    631 struct staterecord current_state;
    632 struct staterecord *unwind_rsp, *unwind_rscp;
    633 
    634 
    635 /* Base of spill area in memory stack frame as a psp relative offset */
    636 uint64_t spill_base = 0;
    637 
    638 /*
    639  * Initialises a staterecord from a given template,
    640  * with default values as described by the Runtime Spec.
    641  */
    642 void
    643 initrecord(struct staterecord *target)
    644 {
    645 	target->bsp.where = UNSAVED;
    646 	target->bsp.when = 0;
    647 	target->bsp.offset = INVALID;
    648 	target->psp.where = UNSAVED;
    649 	target->psp.when = 0;
    650 	target->psp.offset = INVALID;
    651 	target->rp.where = UNSAVED;
    652 	target->rp.when = 0;
    653 	target->rp.offset = INVALID;
    654 	target->pfs.where = UNSAVED;
    655 	target->pfs.when = 0;
    656 	target->pfs.offset = INVALID;
    657 }
    658 
    659 
    660 /*
    661  * Modifies a staterecord structure by parsing
    662  * a single record chain structure.
    663  * regionoffset is the offset within a (prologue) region
    664  * where the stack unwinding began.
    665  */
    666 void
    667 modifyrecord(struct staterecord *srec, struct recordchain *rchain,
    668 	uint64_t regionoffset)
    669 {
    670 	/*
    671 	 * Default start save GR for prologue_save GRs.
    672 	 */
    673 	uint64_t grno = 32;
    674 
    675 
    676 	switch (rchain->type) {
    677 
    678 	case R2:
    679 		/*
    680 		 * R2, prologue_gr is the only region encoding
    681 		 * with register save info.
    682 		 */
    683 
    684 		grno = rchain->udesc.R2.grsave;
    685 
    686 		if (rchain->udesc.R2.mask & R2MASKRP) {
    687 			srec->rp.when = 0;
    688 			srec->rp.where = GRREL;
    689 			srec->rp.offset = grno++;
    690 		}
    691 
    692 		if (rchain->udesc.R2.mask & R2MASKPFS) {
    693 			srec->pfs.when = 0;
    694 			srec->pfs.where = GRREL;
    695 			srec->pfs.offset = grno++;
    696 		}
    697 
    698 		if (rchain->udesc.R2.mask & R2MASKPSP) {
    699 			srec->psp.when = 0;
    700 			srec->psp.where = GRREL;
    701 			srec->psp.offset = grno++;
    702 		}
    703 		break;
    704 
    705 	case P3:
    706 		switch (rchain->udesc.P3.r) {
    707 		case 0: /* psp_gr */
    708 			if (srec->psp.when < regionoffset) {
    709 				srec->psp.where = GRREL;
    710 				srec->psp.offset = rchain->udesc.P3.grbr;
    711 			}
    712 			break;
    713 
    714 		case 1: /* rp_gr */
    715 			if (srec->rp.when < regionoffset) {
    716 				srec->rp.where = GRREL;
    717 				srec->rp.offset = rchain->udesc.P3.grbr;
    718 			}
    719 			break;
    720 
    721 		case 2: /* pfs_gr */
    722 			if (srec->pfs.when < regionoffset) {
    723 				srec->pfs.where = GRREL;
    724 				srec->pfs.offset = rchain->udesc.P3.grbr;
    725 			}
    726 			break;
    727 
    728 		}
    729 		break;
    730 
    731 
    732 	/*
    733 	 * XXX: P4 spill_mask and P7: spill_base are for GRs, FRs, and BRs.
    734 	 * We're not particularly worried about those right now.
    735 	 */
    736 
    737 	case P7:
    738 		switch (rchain->udesc.P7.r) {
    739 
    740 		case 0: /* mem_stack_f */
    741 			if (srec->psp.offset != INVALID) {
    742 				printf("!!!saw mem_stack_f more than once. \n");
    743 			}
    744 			srec->psp.when = rchain->udesc.P7.t;
    745 			if (srec->psp.when < regionoffset) {
    746 				srec->psp.where = IMMED;
    747 				/* spsz.offset is "overloaded" */
    748 				srec->psp.offset = rchain->udesc.P7.size;
    749 			}
    750 			break;
    751 
    752 		case 1: /* mem_stack_v */
    753 			srec->psp.when = rchain->udesc.P7.t;
    754 			break;
    755 
    756 		case 2: /* spill_base */
    757 			spill_base = rchain->udesc.P7.t;
    758 			break;
    759 
    760 		case 3: /* psp_sprel */
    761 			if (srec->psp.when < regionoffset) {
    762 				srec->psp.where = SPREL;
    763 				srec->psp.offset = rchain->udesc.P7.t;
    764 			}
    765 			break;
    766 
    767 		case 4: /* rp_when */
    768 			srec->rp.when = rchain->udesc.P7.t;
    769 			/*
    770 			 * XXX: Need to set to prologue_gr(grno) for
    771 			 *	the orphan case ie; _gr/_psprel/_sprel
    772 			 *	not set and therefore default to begin
    773 			 *	from the gr specified in prologue_gr.
    774 			 */
    775 			break;
    776 
    777 		case 5: /* rp_psprel */
    778 			if (srec->rp.when < regionoffset) {
    779 				srec->rp.where = PSPREL;
    780 				srec->rp.offset = rchain->udesc.P7.t;
    781 			}
    782 			break;
    783 
    784 		case 6: /* pfs_when */
    785 			srec->pfs.when = rchain->udesc.P7.t;
    786 			/*
    787 			 * XXX: Need to set to prologue_gr(grno) for
    788 			 *	the orphan case ie; _gr/_psprel/_sprel
    789 			 *	not set and therefore default to begin
    790 			 *	from the gr specified in prologue_gr.
    791 			 */
    792 			break;
    793 
    794 		case 7: /* pfs_psprel */
    795 			if (srec->pfs.when < regionoffset) {
    796 				srec->pfs.where = PSPREL;
    797 				srec->pfs.offset = rchain->udesc.P7.t;
    798 			}
    799 			break;
    800 
    801 		}
    802 		break;
    803 
    804 	case P8:
    805 		switch (rchain->udesc.P8.r) {
    806 		case 1: /* rp_sprel */
    807 			if (srec->rp.when < regionoffset) {
    808 				srec->rp.where = SPREL;
    809 				srec->rp.offset = rchain->udesc.P8.t;
    810 			}
    811 			break;
    812 		case 2: /* pfs_sprel */
    813 			if (srec->pfs.when < regionoffset) {
    814 				srec->pfs.where = SPREL;
    815 				srec->pfs.offset = rchain->udesc.P8.t;
    816 
    817 			}
    818 			break;
    819 		}
    820 		break;
    821 
    822 	case B1:
    823 
    824 		rchain->udesc.B1.r ? switchrecordstack(0) :
    825 			clonerecordstack(0);
    826 		break;
    827 
    828 	case B2:
    829 		if (regionoffset < rchain->udesc.B2.t) {
    830 		poprecord(&current_state, rchain->udesc.B2.ecount);
    831 		}
    832 		break;
    833 	case B3:
    834 		if (regionoffset < rchain->udesc.B3.t) {
    835 		poprecord(&current_state, rchain->udesc.B3.ecount);
    836 		}
    837 		break;
    838 	case B4:
    839 		rchain->udesc.B4.r ? switchrecordstack(0) :
    840 			clonerecordstack(0);
    841 		break;
    842 
    843 	case X1:
    844 	case X2:
    845 	case X3:
    846 		/* XXX: Todo */
    847 		break;
    848 
    849 
    850 	case R1:
    851 	case R3:
    852 	case P1:
    853 	case P2:
    854 	case P4:
    855 	case P5:
    856 	case P6:
    857 	case P9:
    858 	case P10:
    859 	default:
    860 		/* Ignore. */
    861 		printf("XXX: Ignored. \n");
    862 	}
    863 
    864 
    865 }
    866 
    867 void
    868 dump_staterecord(struct staterecord *srec)
    869 {
    870 	printf("rp.where: ");
    871 	switch(srec->rp.where) {
    872 	case UNSAVED:
    873 		printf("UNSAVED ");
    874 		break;
    875 	case BRREL:
    876 		printf("BRREL ");
    877 		break;
    878 	case GRREL:
    879 		printf("GRREL ");
    880 		break;
    881 	case SPREL:
    882 		printf("SPREL ");
    883 		break;
    884 	case PSPREL:
    885 		printf("PSPSREL ");
    886 		break;
    887 	default:
    888 		printf("unknown ");
    889 	}
    890 
    891 	printf(", rp.when = %lu, ", srec->rp.when);
    892 	printf("rp.offset = %lu \n", srec->rp.offset);
    893 
    894 
    895 	printf("pfs.where: ");
    896 	switch(srec->pfs.where) {
    897 	case UNSAVED:
    898 		printf("UNSAVED ");
    899 		break;
    900 	case BRREL:
    901 		printf("BRREL ");
    902 		break;
    903 	case GRREL:
    904 		printf("GRREL ");
    905 		break;
    906 	case SPREL:
    907 		printf("SPREL ");
    908 		break;
    909 	case PSPREL:
    910 		printf("PSPSREL ");
    911 		break;
    912 	default:
    913 		printf("unknown ");
    914 	}
    915 
    916 	printf(", pfs.when = %lu, ", srec->pfs.when);
    917 	printf("pfs.offset = %lu \n", srec->pfs.offset);
    918 }
    919 
    920 
    921 /*
    922  * Push a state record on the record stack.
    923  */
    924 void
    925 pushrecord(struct staterecord *srec)
    926 {
    927 	if(unwind_rsp >= recordstack + MAXSTATERECS) {
    928 		printf("Push exceeded array size!!! \n");
    929 		return;
    930 	}
    931 
    932 	memcpy(unwind_rsp, srec, sizeof(struct staterecord));
    933 	unwind_rsp++;
    934 
    935 }
    936 
    937 /*
    938  * Pop n state records off the record stack.
    939  */
    940 void
    941 poprecord(struct staterecord *srec, int n)
    942 {
    943 	if(unwind_rsp == recordstack) {
    944 		printf("Popped beyond end of Stack!!! \n");
    945 		return;
    946 	}
    947 	unwind_rsp -= n;
    948 	memcpy(srec, unwind_rsp, sizeof(struct staterecord));
    949 #ifdef DEBUG
    950 	memset(unwind_rsp, 0, sizeof(struct staterecord) * n);
    951 #endif
    952 
    953 }
    954 
    955 /*
    956  * Clone the whole record stack upto this one.
    957  */
    958 void
    959 clonerecordstack(u_int label)
    960 {
    961 	memcpy(recordstackcopy, recordstack,
    962 	       (unwind_rsp - recordstack) * sizeof(struct staterecord));
    963 	unwind_rscp = unwind_rsp;
    964 }
    965 
    966 /*
    967  * Discard the current stack, and adopt a clone.
    968  */
    969 void
    970 switchrecordstack(u_int label)
    971 {
    972 	memcpy((void *) recordstack, (void *) recordstackcopy,
    973 	       (unwind_rscp - recordstackcopy) * sizeof(struct staterecord));
    974 	unwind_rsp = unwind_rscp;
    975 
    976 }
    977 
    978 /*
    979  * In the context of a procedure:
    980  * Parses through a record chain, building, pushing and/or popping staterecords,
    981  * or cloning/destroying stacks of staterecords as required.
    982  * Parameters are:
    983  *	rchain: pointer to recordchain array.
    984  *	procoffset: offset of point of interest, in slots, within procedure
    985  *                  starting from slot 0
    986  * This routine obeys [1]
    987  */
    988 struct staterecord *
    989 buildrecordstack(struct recordchain *rchain, uint64_t procoffset)
    990 {
    991 	/* Current region length, defaults to zero if not specified */
    992 	uint64_t rlen = 0;
    993 	/* Accumulated region length */
    994 	uint64_t roffset = 0;
    995 	/* Offset within current region */
    996 	uint64_t rdepth = 0;
    997 
    998 	bool rtype;
    999 	int i;
   1000 
   1001 	/* Start with bottom of staterecord stack. */
   1002 	unwind_rsp = recordstack;
   1003 
   1004 	initrecord(&current_state);
   1005 
   1006 	for (i = 0;i < rec_cnt;i++) {
   1007 
   1008 		switch (rchain[i].type) {
   1009 		case R1:
   1010 			rlen = rchain[i].udesc.R1.rlen;
   1011 			if (procoffset < roffset) {
   1012 				/*
   1013 				 * Overshot Region containing
   1014 				 * procoffset. Bail out.
   1015 				 */
   1016 				goto out;
   1017 			}
   1018 			rdepth = procoffset - roffset;
   1019 			roffset += rlen;
   1020 			rtype = rchain[i].udesc.R1.r;
   1021 			if (!rtype) {
   1022 				pushrecord(&current_state);
   1023 			}
   1024 			break;
   1025 
   1026 		case R3:
   1027 			rlen = rchain[i].udesc.R3.rlen;
   1028 			if (procoffset < roffset) {
   1029 				/*
   1030 				 * Overshot Region containing
   1031 				 * procoffset. Bail out.
   1032 				 */
   1033 				goto out;
   1034 			}
   1035 			rdepth = procoffset - roffset;
   1036 			roffset += rlen;
   1037 			rtype = rchain[i].udesc.R3.r;
   1038 			if (!rtype) {
   1039 				pushrecord(&current_state);
   1040 			}
   1041 			break;
   1042 
   1043 		case R2:
   1044 			rlen = rchain[i].udesc.R2.rlen;
   1045 			if (procoffset < roffset) {
   1046 				/*
   1047 				 * Overshot Region containing
   1048 				 * procoffset. Bail out.
   1049 				 */
   1050 				goto out;
   1051 			}
   1052 			rdepth = procoffset - roffset;
   1053 			roffset += rlen;
   1054 			rtype = false; /* prologue region */
   1055 			pushrecord(&current_state);
   1056 
   1057 			/* R2 has save info. Continue down. */
   1058 			/* FALLTHROUGH */
   1059 		case P1:
   1060 		case P2:
   1061 		case P3:
   1062 		case P4:
   1063 		case P5:
   1064 		case P6:
   1065 		case P7:
   1066 		case P8:
   1067 		case P9:
   1068 		case P10:
   1069 			modifyrecord(&current_state, &rchain[i], rdepth);
   1070 			break;
   1071 
   1072 		case B1:
   1073 		case B2:
   1074 		case B3:
   1075 		case B4:
   1076 			modifyrecord(&current_state, &rchain[i],
   1077 				     rlen - 1 - rdepth);
   1078 			break;
   1079 
   1080 		case X1:
   1081 		case X2:
   1082 		case X3:
   1083 		case X4:
   1084 		default:
   1085 			printf("Error: Unknown descriptor type!!! \n");
   1086 
   1087 		}
   1088 
   1089 #if UNWIND_DIAGNOSTIC
   1090 		dump_staterecord(&current_state);
   1091 #endif
   1092 
   1093 
   1094 	}
   1095 
   1096 out:
   1097 
   1098 	return &current_state;
   1099 }
   1100 
   1101 void
   1102 updateregs(struct unwind_frame *uwf, struct staterecord *srec,
   1103 	uint64_t procoffset)
   1104 {
   1105 	/* XXX: Update uwf for regs other than rp and pfs*/
   1106 	uint64_t roffset = 0;
   1107 
   1108 	/* Uses shadow arrays to update uwf from srec in a loop. */
   1109 	/* Count of number of regstate elements in struct staterecord */
   1110 	int statecount = sizeof(struct staterecord)/sizeof(struct regstate);
   1111 	/* Pointer to current regstate. */
   1112 	struct regstate *stptr = (void *) srec;
   1113 	/* Pointer to current unwind_frame element */
   1114 	uint64_t *gr = (void *) uwf;
   1115 
   1116 	int i;
   1117 
   1118 #ifdef UNWIND_DIAGNOSTIC
   1119 	printf("updateregs(): \n");
   1120 	printf("procoffset (slots) = %lu \n", procoffset);
   1121 #endif
   1122 
   1123 	for(i = 0; i < statecount; i++) {
   1124 		switch (stptr[i].where) {
   1125 		case IMMED: /* currently only mem_stack_f */
   1126 			if (stptr[i].when >= procoffset) break;
   1127 			uwf->psp -= (stptr[i].offset << 4);
   1128 			break;
   1129 
   1130 		case GRREL:
   1131 			if (stptr[i].when >= procoffset) break;
   1132 
   1133 			roffset = stptr[i].offset;
   1134 			if (roffset == 0) {
   1135 				gr[i] = 0;
   1136 				break;
   1137 			}
   1138 
   1139 
   1140 			if (roffset < 32) {
   1141 				printf("GR%ld: static register save ??? \n",
   1142 				       roffset);
   1143 				break;
   1144 			}
   1145 
   1146 			/* Fetch from bsp + offset - 32 + Adjust for RNAT. */
   1147 			roffset -= 32;
   1148 			gr[i] = ia64_getrse_gr(uwf->bsp, roffset);
   1149 			break;
   1150 
   1151 		case SPREL:
   1152 			if (stptr[i].when >= procoffset) break;
   1153 
   1154 			/* Check if frame has been setup. */
   1155 			if (srec->psp.offset == INVALID) {
   1156 				printf("sprel used without setting up "
   1157 				       "stackframe!!! \n");
   1158 				break;
   1159 			}
   1160 
   1161 			roffset = stptr[i].offset;
   1162 
   1163 			/* Fetch from sp + offset */
   1164 			memcpy(&gr[i], (char *) uwf->sp + roffset * 4,
   1165 			       sizeof(uint64_t));
   1166 			break;
   1167 
   1168 
   1169 		case PSPREL:
   1170 			if (stptr[i].when >= procoffset) break;
   1171 
   1172 			/* Check if frame has been setup. */
   1173 			if (srec->psp.offset == INVALID) {
   1174 				printf("psprel used without setting up "
   1175 				       "stackframe!!! \n");
   1176 				break;
   1177 			}
   1178 
   1179 			roffset = stptr[i].offset;
   1180 
   1181 			/* Fetch from sp + offset */
   1182 			memcpy(&gr[i], (char *) uwf->psp + 16 - (roffset * 4),
   1183 			       sizeof(uint64_t));
   1184 			break;
   1185 
   1186 		case UNSAVED:
   1187 		case BRREL:
   1188 		default:
   1189 #ifdef UNWIND_DIAGNOSTIC
   1190 			printf ("updateregs: reg[%d] is UNSAVED \n", i);
   1191 #endif
   1192 			break;
   1193 			/* XXX: Not implemented yet. */
   1194 		}
   1195 
   1196 	}
   1197 
   1198 }
   1199 
   1200 
   1201 /*
   1202  * Locates unwind table entry, given unwind table entry info.
   1203  * Expects the variables ia64_unwindtab, and ia64_unwindtablen
   1204  * to be set appropriately.
   1205  */
   1206 struct uwtable_ent *
   1207 get_unwind_table_entry(uint64_t iprel)
   1208 {
   1209 
   1210 	extern uint64_t ia64_unwindtab, ia64_unwindtablen;
   1211 
   1212 	struct uwtable_ent *uwt;
   1213 	int tabent;
   1214 
   1215 
   1216 	for(uwt = (struct uwtable_ent *) ia64_unwindtab, tabent = 0;
   1217 	    /* The Runtime spec tells me the table entries are sorted. */
   1218 	    uwt->end <= iprel && tabent < ia64_unwindtablen;
   1219 	    uwt++, tabent += sizeof(struct uwtable_ent));
   1220 
   1221 
   1222 	if (!(uwt->start <= iprel && iprel < uwt->end)) {
   1223 #ifdef UNWIND_DIAGNOSTIC
   1224 		printf("Entry not found \n");
   1225 		printf("iprel = %lx \n", iprel);
   1226 		printf("uwt->start = %lx \nuwt->end = %lx \n",
   1227 		       uwt->start, uwt->end);
   1228 		printf("tabent = %d \n", tabent);
   1229 		printf("ia64_unwindtablen = %ld \n",
   1230 		       ia64_unwindtablen);
   1231 #endif
   1232 		return NULL;
   1233 	}
   1234 
   1235 #ifdef UNWIND_DIAGNOSTIC
   1236 	printf("uwt->start = %lx \nuwt->end = %lx \n"
   1237 	       "uwt->infoptr = %p\n", uwt->start, uwt->end, uwt->infoptr);
   1238 #endif
   1239 
   1240 	return uwt;
   1241 }
   1242 
   1243 
   1244 /*
   1245  * Reads unwind table info and updates register values.
   1246  */
   1247 void
   1248 patchunwindframe(struct unwind_frame *uwf, uint64_t iprel, uint64_t relocoffset)
   1249 {
   1250 
   1251 	extern struct recordchain strc[];
   1252 	struct staterecord *srec;
   1253 	struct uwtable_ent *uwt;
   1254 	uint64_t infoptr, procoffset, slotoffset;
   1255 
   1256 #if 0 /* does not work - moved to assertion at the call site */
   1257 	if (iprel < 0) {
   1258 		panic("unwind ip out of range!!! \n");
   1259 		return;
   1260 	}
   1261 #endif
   1262 
   1263 	uwt = get_unwind_table_entry(iprel);
   1264 
   1265 	if (uwt == NULL) return;
   1266 
   1267 	infoptr = (uint64_t) uwt->infoptr + relocoffset;
   1268 
   1269 	if (infoptr > relocoffset) {
   1270 		buildrecordchain(infoptr, NULL);
   1271 	} else {
   1272 		return;
   1273 	}
   1274 
   1275 	slotoffset = iprel & 3;
   1276 
   1277 	/* procoffset in Number of _slots_ , _not_ a byte offset. */
   1278 
   1279 	procoffset = (((iprel - slotoffset) - (uwt->start)) / 0x10 * 3)
   1280 		+ slotoffset;
   1281 	srec = buildrecordstack(strc, procoffset);
   1282 
   1283 	updateregs(uwf, srec, procoffset);
   1284 }
   1285