xref: /netbsd/sys/arch/ia64/unwind/stackframe.c (revision ffbc4147)
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@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
buildrecordchain(uint64_t unwind_infop,struct recordchain * xxx)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
dump_recordchain(struct recordchain * rchain)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
initrecord(struct staterecord * target)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
modifyrecord(struct staterecord * srec,struct recordchain * rchain,uint64_t regionoffset)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
dump_staterecord(struct staterecord * srec)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
pushrecord(struct staterecord * srec)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
poprecord(struct staterecord * srec,int n)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
clonerecordstack(u_int label)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
switchrecordstack(u_int label)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 *
buildrecordstack(struct recordchain * rchain,uint64_t procoffset)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
updateregs(struct unwind_frame * uwf,struct staterecord * srec,uint64_t procoffset)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 *
get_unwind_table_entry(uint64_t iprel)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
patchunwindframe(struct unwind_frame * uwf,uint64_t iprel,uint64_t relocoffset)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