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(¤t_state, rchain->udesc.B2.ecount);
831 }
832 break;
833 case B3:
834 if (regionoffset < rchain->udesc.B3.t) {
835 poprecord(¤t_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(¤t_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(¤t_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(¤t_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(¤t_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(¤t_state, &rchain[i], rdepth);
1070 break;
1071
1072 case B1:
1073 case B2:
1074 case B3:
1075 case B4:
1076 modifyrecord(¤t_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(¤t_state);
1091 #endif
1092
1093
1094 }
1095
1096 out:
1097
1098 return ¤t_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