1/*	$NetBSD: stackframe.c,v 1.3 2007/02/28 04:21:51 thorpej 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*/
26struct recordchain strc[MAXSTATERECS];
27int 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
33void 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 */
230void 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
590struct staterecord recordstack[MAXSTATERECS];
591struct staterecord recordstackcopy[MAXSTATERECS];
592struct staterecord current_state;
593struct staterecord *unwind_rsp, *unwind_rscp;
594
595
596uint64_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
602void
603initrecord(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
626void 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
819void 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
876void 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
890void 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. */
905void 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. */
913void 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 */
929struct 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
1020out:
1021
1022	return &current_state;
1023}
1024
1025void 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
1125struct uwtable_ent *
1126get_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
1168void
1169patchunwindframe(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