stackframe.c revision 1.2 1 /* $NetBSD: stackframe.c,v 1.2 2007/02/21 22:59:45 thorpej Exp $ */
2
3 /* Contributed to the NetBSD foundation by Cherry G. Mathew <cherry (at) mahiti.org>
4 * This file contains routines to use decoded unwind descriptor entries
5 * to build a stack configuration. The unwinder consults the stack
6 * configuration to fetch registers used to unwind the frame.
7 * References:
8 * [1] section. 11.4.2.6., Itanium Software Conventions and
9 * Runtime Architecture Guide.
10 */
11
12 #include <sys/cdefs.h>
13 #include <sys/param.h>
14 #include <sys/systm.h>
15
16
17 #include <ia64/unwind/decode.h>
18 #include <ia64/unwind/stackframe.h>
19
20 //#define UNWIND_DIAGNOSTIC
21
22 /* 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(¤t_state, rchain->udesc.B2.ecount);
783 }
784 break;
785 case B3:
786 if (regionoffset < rchain->udesc.B3.t) {
787 poprecord(¤t_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 bzero(unwind_rsp, 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(¤t_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(¤t_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(¤t_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(¤t_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(¤t_state, &rchain[i], rdepth);
995 break;
996
997 case B1:
998 case B2:
999 case B3:
1000 case B4:
1001 modifyrecord(¤t_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(¤t_state);
1015 #endif
1016
1017
1018 }
1019
1020 out:
1021
1022 return ¤t_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