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