uwx_uinfo.c revision 160157
1/*
2Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3Permission is hereby granted, free of charge, to any person
4obtaining a copy of this software and associated documentation
5files (the "Software"), to deal in the Software without
6restriction, including without limitation the rights to use,
7copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following
10conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23*/
24
25#include "uwx_env.h"
26#include "uwx_uinfo.h"
27#include "uwx_utable.h"
28#include "uwx_scoreboard.h"
29#include "uwx_bstream.h"
30#include "uwx_trace.h"
31
32int uwx_count_ones(unsigned int mask);
33
34/*
35 *  uwx_uinfo.c
36 *
37 *  This file contains the routines for reading and decoding
38 *  the unwind information block.
39 *
40 *  The main entry point, uwx_decode_uinfo(), is given a pointer
41 *  to an unwind table entry and a pointer (passed by reference)
42 *  to be filled in with a pointer to an update vector. It will
43 *  read and decode the unwind descriptors contained in the
44 *  unwind information block, then build the register state array,
45 *  which describes the actions necessary to step from the current
46 *  frame to the previous one.
47 */
48
49#define COPYIN_UINFO_4(dest, src) \
50    (env->remote? \
51      (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
52						WORDSZ, env->cb_token) : \
53      (*(uint32_t *)(intptr_t)(dest) = *(uint32_t *)(intptr_t)(src), WORDSZ) )
54
55#define COPYIN_UINFO_8(dest, src) \
56    (env->remote? \
57      (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
58						DWORDSZ, env->cb_token) : \
59      (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), DWORDSZ) )
60
61
62/* uwx_default_rstate: Returns the default register state for a leaf routine */
63
64int uwx_default_rstate(struct uwx_env *env, uint64_t **rstatep)
65{
66    struct uwx_scoreboard *sb;
67
68    sb = uwx_init_scoreboards(env);
69    *rstatep = sb->rstate;
70    return UWX_OK;
71}
72
73
74/* uwx_decode_uinfo: Decodes unwind info region */
75
76int uwx_decode_uinfo(
77    struct uwx_env *env,
78    struct uwx_utable_entry *uentry,
79    uint64_t **rstatep)
80{
81    uint64_t uinfohdr;
82    unsigned int ulen;
83    int len;
84    struct uwx_bstream bstream;
85    struct uwx_scoreboard *scoreboard;
86    int ip_slot;
87    int cur_slot;
88    int status;
89    struct uwx_rhdr rhdr;
90
91    /* Remember the offset from the start of the function */
92    /* to the current IP. This helps the client find */
93    /* the symbolic information. */
94
95    env->function_offset = env->remapped_ip - uentry->code_start;
96
97    /* Read the unwind info header using the copyin callback. */
98    /* (If we're reading a 32-bit unwind table, we need to */
99    /* read the header as two 32-bit pieces to preserve the */
100    /* guarantee that we always call copyin for aligned */
101    /* 4-byte or 8-byte chunks.) */
102    /* Then compute the length of the unwind descriptor */
103    /* region and initialize a byte stream to read it. */
104
105    if (uentry->unwind_flags & UNWIND_TBL_32BIT) {
106	len = COPYIN_UINFO_4((char *)&uinfohdr, uentry->unwind_info);
107	len += COPYIN_UINFO_4((char *)&uinfohdr + WORDSZ,
108					uentry->unwind_info + WORDSZ);
109	}
110    else
111	len = COPYIN_UINFO_8((char *)&uinfohdr, uentry->unwind_info);
112    if (len != DWORDSZ)
113	return UWX_ERR_COPYIN_UINFO;
114    if (env->byte_swap)
115	uwx_swap8(&uinfohdr);
116    if (uentry->unwind_flags & UNWIND_TBL_32BIT)
117	ulen = UNW_LENGTH(uinfohdr) * WORDSZ;
118    else
119	ulen = UNW_LENGTH(uinfohdr) * DWORDSZ;
120    uwx_init_bstream(&bstream, env,
121		uentry->unwind_info + DWORDSZ, ulen, UWX_COPYIN_UINFO);
122
123    /* Save the header and a pointer to the personality routine ptr */
124    /* for later use in exception handling. */
125
126    env->uinfo_hdr = uinfohdr;
127    env->uinfo_end = uentry->unwind_info + DWORDSZ + ulen;
128
129    TRACE_R_UIB(uentry, ulen)
130
131    /* Create an initial scoreboard for tracking the unwind state. */
132
133    scoreboard = uwx_init_scoreboards(env);
134
135    /* Prepare to read and decode the unwind regions described */
136    /* by the unwind info block. Find the target "ip" slot */
137    /* relative to the beginning of the region. The lower 4 bits */
138    /* of the actual IP encode the slot number within a bundle. */
139
140    cur_slot = 0;
141    ip_slot = (int) ((env->context.special[UWX_REG_IP] & ~0x0fLL)
142							- uentry->code_start)
143		/ BUNDLESZ * SLOTSPERBUNDLE
144		+ (unsigned int) (env->context.special[UWX_REG_IP] & 0x0f);
145
146    /* Loop over the regions in the unwind info block. */
147
148    for (;;) {
149
150	/* Decode the next region header. */
151	/* We have an error if we reach the end of the info block, */
152	/* since we should have found our target ip slot by then. */
153	/* We also have an error if the next byte isn't a region */
154	/* header record. */
155
156	status = uwx_decode_rhdr(env, &bstream, &rhdr);
157	if (status != UWX_OK)
158	    return status;
159
160	/* If a prologue region, get a new scoreboard, pushing */
161	/* the previous one onto the prologue stack. Then read */
162	/* and decode the prologue region records. */
163
164	if (rhdr.is_prologue) {
165	    scoreboard = uwx_new_scoreboard(env, scoreboard);
166	    if (scoreboard == 0)
167		return UWX_ERR_NOMEM;
168	    status = uwx_decode_prologue(env, &bstream,
169					    scoreboard, &rhdr, ip_slot);
170	}
171
172	/* If a body region, read and decode the body region */
173	/* records. If the body has an epilogue count, */
174	/* uwx_decode_body will note that in the region header */
175	/* record for use at the bottom of the loop. */
176
177	else {
178	    status = uwx_decode_body(env, &bstream, scoreboard, &rhdr, ip_slot);
179	}
180
181	if (status != UWX_OK)
182	    return status;
183
184	TRACE_R_DUMP_SB(scoreboard, rhdr, cur_slot, ip_slot)
185
186	/* If the target ip slot is within this region, we're done. */
187	/* Return the scoreboard's register state array. */
188
189	if (ip_slot < rhdr.rlen) {
190	    *rstatep = scoreboard->rstate;
191	    return UWX_OK;
192	}
193
194	/* Otherwise, update the current ip slot, pop the */
195	/* scoreboard stack based on the epilogue count, */
196	/* and loop back around for the next region. */
197
198	cur_slot += rhdr.rlen;
199	ip_slot -= rhdr.rlen;
200	if (rhdr.ecount > 0) {
201	    scoreboard = uwx_pop_scoreboards(env, scoreboard, rhdr.ecount);
202	    if (scoreboard == 0)
203		return UWX_ERR_PROLOG_UF;
204	}
205    }
206    /*NOTREACHED*/
207}
208
209
210/* uwx_decode_rhdr: Decodes a region header record */
211
212int uwx_decode_rhdr(
213    struct uwx_env *env,
214    struct uwx_bstream *bstream,
215    struct uwx_rhdr *rhdr)
216{
217    int b0;
218    int b1;
219    uint64_t val;
220    int status;
221
222    /* Get the first byte of the next descriptor record. */
223    b0 = uwx_get_byte(bstream);
224    if (b0 < 0)
225	return UWX_ERR_NOUDESC;
226
227    /* Initialize region header record. */
228
229    rhdr->is_prologue = 0;
230    rhdr->rlen = 0;
231    rhdr->mask = 0;
232    rhdr->grsave = 0;
233    rhdr->ecount = 0;
234
235    /* Format R1 */
236
237    if (b0 < 0x40) {
238	if ((b0 & 0x20) == 0) {
239	    TRACE_I_DECODE_RHDR_1("(R1) prologue", b0)
240	    rhdr->is_prologue = 1;
241	}
242	else {
243	    TRACE_I_DECODE_RHDR_1("(R1) body", b0)
244	}
245	rhdr->rlen = b0 & 0x1f;
246    }
247
248    /* Format R2 */
249
250    else if (b0 < 0x60) {
251	b1 = uwx_get_byte(bstream);
252	if (b1 < 0)
253	    return UWX_ERR_BADUDESC;
254	status = uwx_get_uleb128(bstream, &val);
255	if (status != 0)
256	    return UWX_ERR_BADUDESC;
257	TRACE_I_DECODE_RHDR_2L("(R2) prologue_gr", b0, b1, val)
258	rhdr->is_prologue = 1;
259	rhdr->rlen = (unsigned int) val;
260	rhdr->mask = ((b0 & 0x07) << 1) | (b1 >> 7);
261	rhdr->grsave = b1 & 0x7f;
262    }
263
264    /* Format R3 */
265
266    else if (b0 < 0x80) {
267	status = uwx_get_uleb128(bstream, &val);
268	if (status != 0)
269	    return UWX_ERR_BADUDESC;
270	if ((b0 & 0x03) == 0) {
271	    TRACE_I_DECODE_RHDR_1L("(R3) prologue", b0, val)
272	    rhdr->is_prologue = 1;
273	}
274	else {
275	    TRACE_I_DECODE_RHDR_1L("(R3) body", b0, val)
276	}
277	rhdr->rlen = (unsigned int) val;
278    }
279
280    /* Otherwise, not a region header record. */
281
282    else {
283	TRACE_I_DECODE_RHDR_1("(?)", b0)
284	return UWX_ERR_BADUDESC;
285    }
286
287    return UWX_OK;
288}
289
290
291/* uwx_decode_prologue: Decodes a prologue region */
292
293int uwx_decode_prologue(
294    struct uwx_env *env,
295    struct uwx_bstream *bstream,
296    struct uwx_scoreboard *scoreboard,
297    struct uwx_rhdr *rhdr,
298    int ip_slot)
299{
300    int status;
301    int reg;
302    int mask;
303    int b0;
304    int b1;
305    int b2;
306    int b3;
307    int r;
308    int t;
309    int i;
310    uint64_t parm1;
311    uint64_t parm2;
312    uint64_t newrstate[NSBREG];
313    int tspill[NSBREG];
314    int priunat_mem_rstate;
315    int t_priunat_mem;
316    unsigned int gr_mem_mask;
317    unsigned int br_mem_mask;
318    unsigned int fr_mem_mask;
319    unsigned int gr_gr_mask;
320    unsigned int br_gr_mask;
321    int ngr;
322    int nbr;
323    int nfr;
324    unsigned int spill_base;
325    unsigned int gr_base;
326    unsigned int br_base;
327    unsigned int fr_base;
328
329    /* Initialize an array of register states from the current */
330    /* scoreboard, along with a parallel array of spill times. */
331    /* We use this as a temporary scoreboard, then update the */
332    /* real scoreboard at the end of the procedure. */
333    /* We initialize the spill time to (rhdr.rlen - 1) so that */
334    /* spills without a "when" descriptor will take effect */
335    /* at the end of the prologue region. */
336    /* (Boundary condition: all actions in a zero-length prologue */
337    /* will appear to have happened in the instruction slot */
338    /* immediately preceding the prologue.) */
339
340    for (i = 0; i < env->nsbreg; i++) {
341	newrstate[i] = scoreboard->rstate[i];
342	tspill[i] = rhdr->rlen - 1;
343    }
344    priunat_mem_rstate = UWX_DISP_NONE;
345    t_priunat_mem = rhdr->rlen - 1;
346
347    fr_mem_mask = 0;
348    gr_mem_mask = 0;
349    br_mem_mask = 0;
350    gr_gr_mask = 0;
351    br_gr_mask = 0;
352    nfr = 127;
353    ngr = 127;
354    nbr = 127;
355    spill_base = 0;
356
357    /* If prologue_gr header record supplied mask and grsave, */
358    /* record these in the scoreboard. */
359
360    reg = rhdr->grsave;
361    mask = rhdr->mask;
362    if (mask & 0x8) {
363	newrstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_GR(reg));
364	reg++;
365    }
366    if (mask & 0x4) {
367	newrstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_GR(reg));
368	reg++;
369    }
370    if (mask & 0x2) {
371	newrstate[SBREG_PSP] = UWX_DISP_REG(UWX_REG_GR(reg));
372	reg++;
373    }
374    if (mask & 0x1) {
375	newrstate[SBREG_PREDS] = UWX_DISP_REG(UWX_REG_GR(reg));
376	reg++;
377    }
378
379    /* Read prologue descriptor records until */
380    /* we hit another region header. */
381
382    for (;;) {
383
384	b0 = uwx_get_byte(bstream);
385
386	if (b0 < 0x80) {
387	    /* Return the last byte read to the byte stream, since it's */
388	    /* really the first byte of the next region header record. */
389	    if (b0 >= 0)
390		(void) uwx_unget_byte(bstream, b0);
391	    break;
392	}
393
394	switch ((b0 & 0x70) >> 4) {
395
396	    case 0:			/* 1000 xxxx */
397	    case 1:			/* 1001 xxxx */
398		/* Format P1 (br_mem) */
399		TRACE_I_DECODE_PROLOGUE_1("(P1) br_mem", b0)
400		br_mem_mask = b0 & 0x1f;
401		break;
402
403	    case 2:			/* 1010 xxxx */
404		/* Format P2 (br_gr) */
405		b1 = uwx_get_byte(bstream);
406		if (b1 < 0)
407		    return UWX_ERR_BADUDESC;
408		TRACE_I_DECODE_PROLOGUE_2("(P2) br_gr", b0, b1)
409		mask = ((b0 & 0x0f) << 1) | (b1 >> 7);
410		reg = b1 & 0x7f;
411		br_gr_mask = mask;
412		for (i = 0; i < NSB_BR && mask != 0; i++) {
413		    if (mask & 0x01) {
414			newrstate[SBREG_BR + i] = UWX_DISP_REG(UWX_REG_GR(reg));
415			reg++;
416		    }
417		    mask = mask >> 1;
418		}
419		break;
420
421	    case 3:			/* 1011 xxxx */
422		/* Format P3 */
423		if (b0 < 0xb8) {
424		    b1 = uwx_get_byte(bstream);
425		    if (b1 < 0)
426			return UWX_ERR_BADUDESC;
427		    r = ((b0 & 0x7) << 1) | (b1 >> 7);
428		    reg = b1 & 0x7f;
429		    switch (r) {
430			case 0:		/* psp_gr */
431			    TRACE_I_DECODE_PROLOGUE_2("(P3) psp_gr", b0, b1)
432			    newrstate[SBREG_PSP] = UWX_DISP_REG(UWX_REG_GR(reg));
433			    break;
434			case 1:		/* rp_gr */
435			    TRACE_I_DECODE_PROLOGUE_2("(P3) rp_gr", b0, b1)
436			    newrstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_GR(reg));
437			    break;
438			case 2:		/* pfs_gr */
439			    TRACE_I_DECODE_PROLOGUE_2("(P3) pfs_gr", b0, b1)
440			    newrstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_GR(reg));
441			    break;
442			case 3:		/* preds_gr */
443			    TRACE_I_DECODE_PROLOGUE_2("(P3) preds_gr", b0, b1)
444			    newrstate[SBREG_PREDS] =
445					UWX_DISP_REG(UWX_REG_GR(reg));
446			    break;
447			case 4:		/* unat_gr */
448			    TRACE_I_DECODE_PROLOGUE_2("(P3) unat_gr", b0, b1)
449			    newrstate[SBREG_UNAT] =
450					UWX_DISP_REG(UWX_REG_GR(reg));
451			    break;
452			case 5:		/* lc_gr */
453			    TRACE_I_DECODE_PROLOGUE_2("(P3) lc_gr", b0, b1)
454			    newrstate[SBREG_LC] =
455					UWX_DISP_REG(UWX_REG_GR(reg));
456			    break;
457			case 6:		/* rp_br */
458			    TRACE_I_DECODE_PROLOGUE_2("(P3) rp_br", b0, b1)
459			    scoreboard->rstate[SBREG_RP] =
460					UWX_DISP_REG(UWX_REG_BR(reg));
461			    if (newrstate[SBREG_RP] ==
462						UWX_DISP_REG(UWX_REG_BR(0)))
463				newrstate[SBREG_RP] =
464					UWX_DISP_REG(UWX_REG_BR(reg));
465			    break;
466			case 7:		/* rnat_gr */
467			    TRACE_I_DECODE_PROLOGUE_2("(P3) rnat_gr", b0, b1)
468			    newrstate[SBREG_RNAT] =
469					UWX_DISP_REG(UWX_REG_GR(reg));
470			    break;
471			case 8:		/* bsp_gr */
472			    TRACE_I_DECODE_PROLOGUE_2("(P3) bsp_gr", b0, b1)
473			    /* Don't track BSP yet */
474			    return UWX_ERR_CANTUNWIND;
475			    /* break; */
476			case 9:		/* bspstore_gr */
477			    TRACE_I_DECODE_PROLOGUE_2("(P3) bspstore_gr", b0, b1)
478			    /* Don't track BSPSTORE yet */
479			    return UWX_ERR_CANTUNWIND;
480			    /* break; */
481			case 10:	/* fpsr_gr */
482			    TRACE_I_DECODE_PROLOGUE_2("(P3) fpsr_gr", b0, b1)
483			    newrstate[SBREG_FPSR] =
484					UWX_DISP_REG(UWX_REG_GR(reg));
485			    break;
486			case 11:	/* priunat_gr */
487			    TRACE_I_DECODE_PROLOGUE_2("(P3) priunat_gr", b0, b1)
488			    newrstate[SBREG_PRIUNAT] =
489					UWX_DISP_REG(UWX_REG_GR(reg));
490			    break;
491			default:
492			    TRACE_I_DECODE_PROLOGUE_2("(P3) ??", b0, b1)
493			    return UWX_ERR_BADUDESC;
494		    }
495		}
496
497		/* Format P4 (spill_mask) */
498		else if (b0 == 0xb8) {
499		    TRACE_I_DECODE_PROLOGUE_1("(P4) spill_mask", b0)
500		    /* The spill_mask descriptor is followed by */
501		    /* an imask field whose length is determined */
502		    /* by the region length: there are two mask */
503		    /* bits per instruction slot in the region. */
504		    /* We decode these bits two at a time, counting */
505		    /* the number of FRs, GRs, and BRs that are */
506		    /* saved up to the slot of interest. Other */
507		    /* descriptors describe which sets of these */
508		    /* registers are spilled, and we put those */
509		    /* two pieces of information together at the */
510		    /* end of the main loop. */
511		    t = 0;
512		    nfr = 0;
513		    ngr = 0;
514		    nbr = 0;
515		    while (t < rhdr->rlen) {
516			b1 = uwx_get_byte(bstream);
517			if (b1 < 0)
518			    return UWX_ERR_BADUDESC;
519			for (i = 0; i < 4 && (t + i) < ip_slot; i++) {
520			    switch (b1 & 0xc0) {
521				case 0x00: break;
522				case 0x40: nfr++; break;
523				case 0x80: ngr++; break;
524				case 0xc0: nbr++; break;
525			    }
526			    b1 = b1 << 2;
527			}
528			t += 4;
529		    }
530		}
531
532		/* Format P5 (frgr_mem) */
533		else if (b0 == 0xb9) {
534		    b1 = uwx_get_byte(bstream);
535		    if (b1 < 0)
536			return UWX_ERR_BADUDESC;
537		    b2 = uwx_get_byte(bstream);
538		    if (b2 < 0)
539			return UWX_ERR_BADUDESC;
540		    b3 = uwx_get_byte(bstream);
541		    if (b3 < 0)
542			return UWX_ERR_BADUDESC;
543		    TRACE_I_DECODE_PROLOGUE_4("(P5) frgr_mem", b0, b1, b2, b3)
544		    gr_mem_mask = b1 >> 4;
545		    fr_mem_mask = ((b1 & 0x0f) << 16) | (b2 << 8) | b3;
546		}
547
548		/* Invalid descriptor record */
549		else {
550		    TRACE_I_DECODE_PROLOGUE_1("(?)", b0)
551		    return UWX_ERR_BADUDESC;
552		}
553
554		break;
555
556	    case 4:			/* 1100 xxxx */
557		/* Format P6 (fr_mem) */
558		TRACE_I_DECODE_PROLOGUE_1("(P6) fr_mem", b0)
559		fr_mem_mask = b0 & 0x0f;
560		break;
561
562	    case 5:			/* 1101 xxxx */
563		/* Format P6 (gr_mem) */
564		TRACE_I_DECODE_PROLOGUE_1("(P6) gr_mem", b0)
565		gr_mem_mask = b0 & 0x0f;
566		break;
567
568	    case 6:			/* 1110 xxxx */
569		/* Format P7 */
570		r = b0 & 0xf;
571		status = uwx_get_uleb128(bstream, &parm1);
572		if (status != 0)
573		    return UWX_ERR_BADUDESC;
574		switch (r) {
575		    case 0:		/* mem_stack_f */
576			status = uwx_get_uleb128(bstream, &parm2);
577			if (status != 0)
578			    return UWX_ERR_BADUDESC;
579			TRACE_I_DECODE_PROLOGUE_1LL("(P7) mem_stack_f", b0, parm1, parm2)
580			newrstate[SBREG_PSP] = UWX_DISP_SPPLUS(parm2 * 16);
581			tspill[SBREG_PSP] = (int) parm1;
582			break;
583		    case 1:		/* mem_stack_v */
584			TRACE_I_DECODE_PROLOGUE_1L("(P7) mem_stack_v", b0, parm1)
585			tspill[SBREG_PSP] = (int) parm1;
586			break;
587		    case 2:		/* spill_base */
588			TRACE_I_DECODE_PROLOGUE_1L("(P7) spill_base", b0, parm1)
589			spill_base = 4 * (unsigned int) parm1;
590			break;
591		    case 3:		/* psp_sprel */
592			TRACE_I_DECODE_PROLOGUE_1L("(P7) psp_sprel", b0, parm1)
593			newrstate[SBREG_PSP] = UWX_DISP_SPREL(parm1 * 4);
594			break;
595		    case 4:		/* rp_when */
596			TRACE_I_DECODE_PROLOGUE_1L("(P7) rp_when", b0, parm1)
597			tspill[SBREG_RP] = (int) parm1;
598			break;
599		    case 5:		/* rp_psprel */
600			TRACE_I_DECODE_PROLOGUE_1L("(P7) rp_psprel", b0, parm1)
601			newrstate[SBREG_RP] = UWX_DISP_PSPREL(parm1 * 4);
602			break;
603		    case 6:		/* pfs_when */
604			TRACE_I_DECODE_PROLOGUE_1L("(P7) pfs_when", b0, parm1)
605			tspill[SBREG_PFS] = (int) parm1;
606			break;
607		    case 7:		/* pfs_psprel */
608			TRACE_I_DECODE_PROLOGUE_1L("(P7) pfs_psprel", b0, parm1)
609			newrstate[SBREG_PFS] = UWX_DISP_PSPREL(parm1 * 4);
610			break;
611		    case 8:		/* preds_when */
612			TRACE_I_DECODE_PROLOGUE_1L("(P7) preds_when", b0, parm1)
613			tspill[SBREG_PREDS] = (int) parm1;
614			break;
615		    case 9:		/* preds_psprel */
616			TRACE_I_DECODE_PROLOGUE_1L("(P7) preds_psprel", b0, parm1)
617			newrstate[SBREG_PREDS] = UWX_DISP_PSPREL(parm1 * 4);
618			break;
619		    case 10:	/* lc_when */
620			TRACE_I_DECODE_PROLOGUE_1L("(P7) lc_when", b0, parm1)
621			tspill[SBREG_LC] = (int) parm1;
622			break;
623		    case 11:	/* lc_psprel */
624			TRACE_I_DECODE_PROLOGUE_1L("(P7) lc_psprel", b0, parm1)
625			newrstate[SBREG_LC] = UWX_DISP_PSPREL(parm1 * 4);
626			break;
627		    case 12:	/* unat_when */
628			TRACE_I_DECODE_PROLOGUE_1L("(P7) unat_when", b0, parm1)
629			tspill[SBREG_UNAT] = (int) parm1;
630			break;
631		    case 13:	/* unat_psprel */
632			TRACE_I_DECODE_PROLOGUE_1L("(P7) unat_psprel", b0, parm1)
633			newrstate[SBREG_UNAT] = UWX_DISP_PSPREL(parm1 * 4);
634			break;
635		    case 14:	/* fpsr_when */
636			TRACE_I_DECODE_PROLOGUE_1L("(P7) fpsr_when", b0, parm1)
637			tspill[SBREG_FPSR] = (int) parm1;
638			break;
639		    case 15:	/* fpsr_psprel */
640			TRACE_I_DECODE_PROLOGUE_1L("(P7) fpsr_psprel", b0, parm1)
641			newrstate[SBREG_FPSR] = UWX_DISP_PSPREL(parm1 * 4);
642			break;
643		}
644		break;
645
646	    case 7:			/* 1111 xxxx */
647		/* Format P8 */
648		if (b0 == 0xf0) {
649		    b1 = uwx_get_byte(bstream);
650		    if (b1 < 0)
651			return UWX_ERR_BADUDESC;
652		    status = uwx_get_uleb128(bstream, &parm1);
653		    if (status != 0)
654			return UWX_ERR_BADUDESC;
655		    switch (b1) {
656			case 1:		/* rp_sprel */
657			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rp_sprel", b0, b1, parm1)
658			    newrstate[SBREG_RP] = UWX_DISP_SPREL(parm1 * 4);
659			    break;
660			case 2:		/* pfs_sprel */
661			    TRACE_I_DECODE_PROLOGUE_2L("(P8) pfs_sprel", b0, b1, parm1)
662			    newrstate[SBREG_PFS] = UWX_DISP_SPREL(parm1 * 4);
663			    break;
664			case 3:		/* preds_sprel */
665			    TRACE_I_DECODE_PROLOGUE_2L("(P8) preds_sprel", b0, b1, parm1)
666			    newrstate[SBREG_PREDS] = UWX_DISP_SPREL(parm1 * 4);
667			    break;
668			case 4:		/* lc_sprel */
669			    TRACE_I_DECODE_PROLOGUE_2L("(P8) lc_sprel", b0, b1, parm1)
670			    newrstate[SBREG_LC] = UWX_DISP_SPREL(parm1 * 4);
671			    break;
672			case 5:		/* unat_sprel */
673			    TRACE_I_DECODE_PROLOGUE_2L("(P8) unat_sprel", b0, b1, parm1)
674			    newrstate[SBREG_UNAT] = UWX_DISP_SPREL(parm1 * 4);
675			    break;
676			case 6:		/* fpsr_sprel */
677			    TRACE_I_DECODE_PROLOGUE_2L("(P8) fpsr_sprel", b0, b1, parm1)
678			    newrstate[SBREG_FPSR] = UWX_DISP_SPREL(parm1 * 4);
679			    break;
680			case 7:		/* bsp_when */
681			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_when", b0, b1, parm1)
682			    /* Don't track BSP yet */
683			    return UWX_ERR_CANTUNWIND;
684			    /* break; */
685			case 8:		/* bsp_psprel */
686			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_psprel", b0, b1, parm1)
687			    /* Don't track BSP yet */
688			    return UWX_ERR_CANTUNWIND;
689			    /* break; */
690			case 9:		/* bsp_sprel */
691			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_sprel", b0, b1, parm1)
692			    /* Don't track BSP yet */
693			    return UWX_ERR_CANTUNWIND;
694			    /* break; */
695			case 10:	/* bspstore_when */
696			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_when", b0, b1, parm1)
697			    /* Don't track BSP yet */
698			    return UWX_ERR_CANTUNWIND;
699			    /* break; */
700			case 11:	/* bspstore_psprel */
701			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_psprel", b0, b1, parm1)
702			    /* Don't track BSP yet */
703			    return UWX_ERR_CANTUNWIND;
704			    /* break; */
705			case 12:	/* bspstore_sprel */
706			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_sprel", b0, b1, parm1)
707			    /* Don't track BSP yet */
708			    return UWX_ERR_CANTUNWIND;
709			    /* break; */
710			case 13:	/* rnat_when */
711			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_when", b0, b1, parm1)
712			    tspill[SBREG_RNAT] = (int) parm1;
713			    break;
714			case 14:	/* rnat_psprel */
715			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_psprel", b0, b1, parm1)
716			    newrstate[SBREG_RNAT] = UWX_DISP_PSPREL(parm1 * 4);
717			    break;
718			case 15:	/* rnat_sprel */
719			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_sprel", b0, b1, parm1)
720			    newrstate[SBREG_RNAT] = UWX_DISP_SPREL(parm1 * 4);
721			    break;
722			case 16:	/* priunat_when_gr */
723			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_when_gr", b0, b1, parm1)
724			    tspill[SBREG_PRIUNAT] = (int) parm1;
725			    break;
726			case 17:	/* priunat_psprel */
727			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_psprel", b0, b1, parm1)
728			    priunat_mem_rstate = UWX_DISP_PSPREL(parm1 * 4);
729			    break;
730			case 18:	/* priunat_sprel */
731			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_sprel", b0, b1, parm1)
732			    priunat_mem_rstate = UWX_DISP_SPREL(parm1 * 4);
733			    break;
734			case 19:	/* priunat_when_mem */
735			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_when_mem", b0, b1, parm1)
736			    t_priunat_mem = (int) parm1;
737			    break;
738			default:
739			    TRACE_I_DECODE_PROLOGUE_2L("(P8) ??", b0, b1, parm1)
740			    return UWX_ERR_BADUDESC;
741		    }
742		}
743
744		/* Format P9 (gr_gr) */
745		else if (b0 == 0xf1) {
746		    b1 = uwx_get_byte(bstream);
747		    if (b1 < 0)
748			return UWX_ERR_BADUDESC;
749		    b2 = uwx_get_byte(bstream);
750		    if (b2 < 0)
751			return UWX_ERR_BADUDESC;
752		    TRACE_I_DECODE_PROLOGUE_3("(P9) gr_gr", b0, b1, b2)
753		    mask = b1 & 0x0f;
754		    reg = b2 & 0x7f;
755		    gr_gr_mask = mask;
756		    for (i = 0; i < NSB_GR && mask != 0; i++) {
757			if (mask & 0x01) {
758			    newrstate[SBREG_GR + i] =
759					UWX_DISP_REG(UWX_REG_GR(reg));
760			    reg++;
761			}
762			mask = mask >> 1;
763		    }
764		}
765
766		/* Format X1 */
767		else if (b0 == 0xf9) {
768		    TRACE_I_DECODE_PROLOGUE_1("(X1)", b0)
769		    b1 = uwx_get_byte(bstream);
770		    if (b1 < 0)
771			return UWX_ERR_BADUDESC;
772		    /* Don't support X-format descriptors yet */
773		    return UWX_ERR_CANTUNWIND;
774		}
775
776		/* Format X2 */
777		else if (b0 == 0xfa) {
778		    TRACE_I_DECODE_PROLOGUE_1("(X2)", b0)
779		    b1 = uwx_get_byte(bstream);
780		    if (b1 < 0)
781			return UWX_ERR_BADUDESC;
782		    b2 = uwx_get_byte(bstream);
783		    if (b2 < 0)
784			return UWX_ERR_BADUDESC;
785		    /* Don't support X-format descriptors yet */
786		    return UWX_ERR_CANTUNWIND;
787		}
788
789		/* Format X3 */
790		else if (b0 == 0xfb) {
791		    TRACE_I_DECODE_PROLOGUE_1("(X3)", b0)
792		    b1 = uwx_get_byte(bstream);
793		    if (b1 < 0)
794			return UWX_ERR_BADUDESC;
795		    b2 = uwx_get_byte(bstream);
796		    if (b2 < 0)
797			return UWX_ERR_BADUDESC;
798		    /* Don't support X-format descriptors yet */
799		    return UWX_ERR_CANTUNWIND;
800		}
801
802		/* Format X4 */
803		else if (b0 == 0xfc) {
804		    TRACE_I_DECODE_PROLOGUE_1("(X4)", b0)
805		    b1 = uwx_get_byte(bstream);
806		    if (b1 < 0)
807			return UWX_ERR_BADUDESC;
808		    b2 = uwx_get_byte(bstream);
809		    if (b2 < 0)
810			return UWX_ERR_BADUDESC;
811		    b3 = uwx_get_byte(bstream);
812		    if (b3 < 0)
813			return UWX_ERR_BADUDESC;
814		    /* Don't support X-format descriptors yet */
815		    return UWX_ERR_CANTUNWIND;
816		}
817
818		/* Format P10 */
819		else if (b0 == 0xff) {
820		    b1 = uwx_get_byte(bstream);
821		    if (b1 < 0)
822			return UWX_ERR_BADUDESC;
823		    b2 = uwx_get_byte(bstream);
824		    if (b2 < 0)
825			return UWX_ERR_BADUDESC;
826		    TRACE_I_DECODE_PROLOGUE_3("(P10) abi", b0, b1, b2)
827		    env->abi_context = (b1 << 8) | b2;
828		    return UWX_ABI_FRAME;
829		}
830
831		/* Invalid descriptor record */
832		else {
833		    TRACE_I_DECODE_PROLOGUE_1("(?)", b0)
834		    return UWX_ERR_BADUDESC;
835		}
836		break;
837	}
838    }
839
840    /* Process the masks of spilled GRs, FRs, and BRs to */
841    /* determine when and where each register was saved. */
842
843    fr_base = spill_base + 16 * uwx_count_ones(fr_mem_mask);
844    br_base = fr_base + 8 * uwx_count_ones(br_mem_mask);
845    gr_base = br_base + 8 * uwx_count_ones(gr_mem_mask);
846    TRACE_I_DECODE_PROLOGUE_SPILL_BASE(spill_base)
847    TRACE_I_DECODE_PROLOGUE_MASKS(gr_mem_mask, gr_gr_mask)
848    TRACE_I_DECODE_PROLOGUE_NSPILL(ngr)
849    for (i = 0; ngr > 0 && i <= NSB_GR; i++) {
850	if (gr_mem_mask & 1) {
851	    newrstate[SBREG_GR + i] = UWX_DISP_PSPREL(gr_base);
852	    tspill[SBREG_GR + i] = 0;
853	    gr_base -= 8;
854	    ngr--;
855	}
856	else if (gr_gr_mask & 1) {
857	    tspill[SBREG_GR + i] = 0;
858	    ngr--;
859	}
860	gr_gr_mask = gr_gr_mask >> 1;
861	gr_mem_mask = gr_mem_mask >> 1;
862    }
863    for (i = 0; nbr > 0 && i <= NSB_BR; i++) {
864	if (br_mem_mask & 1) {
865	    newrstate[SBREG_BR + i] = UWX_DISP_PSPREL(br_base);
866	    tspill[SBREG_BR + i] = 0;
867	    br_base -= 8;
868	    nbr--;
869	}
870	else if (br_gr_mask & 1) {
871	    tspill[SBREG_BR + i] = 0;
872	    nbr--;
873	}
874	br_gr_mask = br_gr_mask >> 1;
875	br_mem_mask = br_mem_mask >> 1;
876    }
877    for (i = 0; nfr > 0 && i <= NSB_FR; i++) {
878	if (fr_mem_mask & 1) {
879	    newrstate[SBREG_FR + i] = UWX_DISP_PSPREL(fr_base);
880	    tspill[SBREG_FR + i] = 0;
881	    fr_base -= 16;
882	    nfr--;
883	}
884	fr_mem_mask = fr_mem_mask >> 1;
885    }
886
887    /* Update the scoreboard. */
888
889    for (i = 0; i < env->nsbreg; i++) {
890	if (ip_slot >= rhdr->rlen || ip_slot > tspill[i])
891	    scoreboard->rstate[i] = newrstate[i];
892    }
893    if (priunat_mem_rstate != UWX_DISP_NONE && ip_slot > t_priunat_mem)
894	scoreboard->rstate[SBREG_PRIUNAT] = priunat_mem_rstate;
895
896    return UWX_OK;
897}
898
899int uwx_count_ones(unsigned int mask)
900{
901    mask = (mask & 0x55555555) + ((mask & 0xaaaaaaaa) >> 1);
902    mask = (mask & 0x33333333) + ((mask & 0xcccccccc) >> 2);
903    mask = (mask & 0x0f0f0f0f) + ((mask & 0xf0f0f0f0) >> 4);
904    mask = (mask & 0x00ff00ff) + ((mask & 0xff00ff00) >> 8);
905    return (mask & 0x0000ffff) + ((mask & 0xffff0000) >> 16);
906}
907
908/* uwx_decode_body: Decodes a body region */
909
910int uwx_decode_body(
911    struct uwx_env *env,
912    struct uwx_bstream *bstream,
913    struct uwx_scoreboard *scoreboard,
914    struct uwx_rhdr *rhdr,
915    int ip_slot)
916{
917    int status;
918    int b0;
919    int b1;
920    int b2;
921    int b3;
922    int label;
923    int ecount;
924    int i;
925    uint64_t parm1;
926    uint64_t parm2;
927    uint64_t newrstate[NSBREG];
928    int tspill[NSBREG];
929    int t_sp_restore;
930
931    /* Initialize an array of register states from the current */
932    /* scoreboard, along with a parallel array of spill times. */
933    /* We use this as a temporary scoreboard, then update the */
934    /* real scoreboard at the end of the procedure. */
935    /* We initialize the spill time to (rhdr.rlen - 1) so that */
936    /* spills without a "when" descriptor will take effect */
937    /* at the end of the prologue region. */
938    /* (Boundary condition: all actions in a zero-length prologue */
939    /* will appear to have happened in the instruction slot */
940    /* immediately preceding the prologue.) */
941
942    for (i = 0; i < env->nsbreg; i++) {
943	newrstate[i] = scoreboard->rstate[i];
944	tspill[i] = rhdr->rlen - 1;
945    }
946    t_sp_restore = rhdr->rlen - 1;
947
948    /* Read body descriptor records until */
949    /* we hit another region header. */
950
951    for (;;) {
952
953	b0 = uwx_get_byte(bstream);
954
955	if (b0 < 0x80) {
956	    /* Return the last byte read to the byte stream, since it's */
957	    /* really the first byte of the next region header record. */
958	    if (b0 >= 0)
959		(void) uwx_unget_byte(bstream, b0);
960	    break;
961	}
962
963	/* Format B1 (label_state) */
964	if (b0 < 0xa0) {
965	    TRACE_I_DECODE_BODY_1("(B1) label_state", b0)
966	    label = b0 & 0x1f;
967	    status = uwx_label_scoreboard(env, scoreboard, label);
968	    if (status != UWX_OK)
969		return (status);
970	}
971
972	/* Format B1 (copy_state)  */
973	else if (b0 < 0xc0) {
974	    TRACE_I_DECODE_BODY_1("(B1) copy_state", b0)
975	    label = b0 & 0x1f;
976	    status = uwx_copy_scoreboard(env, scoreboard, label);
977	    if (status != UWX_OK)
978		return (status);
979	    for (i = 0; i < env->nsbreg; i++) {
980		newrstate[i] = scoreboard->rstate[i];
981		tspill[i] = rhdr->rlen;
982	    }
983	}
984
985	/* Format B2 (epilogue) */
986	else if (b0 < 0xe0) {
987	    ecount = b0 & 0x1f;
988	    status = uwx_get_uleb128(bstream, &parm1);
989	    if (status != 0)
990		return UWX_ERR_BADUDESC;
991	    TRACE_I_DECODE_BODY_1L("(B2) epilogue", b0, parm1)
992	    rhdr->ecount = ecount + 1;
993	    t_sp_restore = rhdr->rlen - (unsigned int) parm1;
994	}
995
996	/* Format B3 (epilogue) */
997	else if (b0 == 0xe0) {
998	    status = uwx_get_uleb128(bstream, &parm1);
999	    if (status != 0)
1000		return UWX_ERR_BADUDESC;
1001	    status = uwx_get_uleb128(bstream, &parm2);
1002	    if (status != 0)
1003		return UWX_ERR_BADUDESC;
1004	    TRACE_I_DECODE_BODY_1LL("(B3) epilogue", b0, parm1, parm2)
1005	    t_sp_restore = rhdr->rlen - (unsigned int) parm1;
1006	    rhdr->ecount = (unsigned int) parm2 + 1;
1007	}
1008
1009	/* Format B4 (label_state) */
1010	else if (b0 == 0xf0) {
1011	    status = uwx_get_uleb128(bstream, &parm1);
1012	    if (status != 0)
1013		return UWX_ERR_BADUDESC;
1014	    TRACE_I_DECODE_BODY_1L("(B4) label_state", b0, parm1)
1015	    label = (int) parm1;
1016	    status = uwx_label_scoreboard(env, scoreboard, label);
1017	    if (status != UWX_OK)
1018		return (status);
1019	}
1020
1021	/* Format B4 (copy_state) */
1022	else if (b0 == 0xf8) {
1023	    status = uwx_get_uleb128(bstream, &parm1);
1024	    if (status != 0)
1025		return UWX_ERR_BADUDESC;
1026	    TRACE_I_DECODE_BODY_1L("(B4) copy_state", b0, parm1)
1027	    label = (int) parm1;
1028	    status = uwx_copy_scoreboard(env, scoreboard, label);
1029	    if (status != UWX_OK)
1030		return (status);
1031	    for (i = 0; i < env->nsbreg; i++) {
1032		newrstate[i] = scoreboard->rstate[i];
1033		tspill[i] = rhdr->rlen;
1034	    }
1035	}
1036
1037	/* Format X1 */
1038	else if (b0 == 0xf9) {
1039	    TRACE_I_DECODE_BODY_1("(X1)", b0)
1040	    b1 = uwx_get_byte(bstream);
1041	    if (b1 < 0)
1042		return UWX_ERR_BADUDESC;
1043	    /* Don't support X-format descriptors yet */
1044	    return UWX_ERR_CANTUNWIND;
1045	}
1046
1047	/* Format X2 */
1048	else if (b0 == 0xfa) {
1049	    TRACE_I_DECODE_BODY_1("(X2)", b0)
1050	    b1 = uwx_get_byte(bstream);
1051	    if (b1 < 0)
1052		return UWX_ERR_BADUDESC;
1053	    b2 = uwx_get_byte(bstream);
1054	    if (b2 < 0)
1055		return UWX_ERR_BADUDESC;
1056	    /* Don't support X-format descriptors yet */
1057	    return UWX_ERR_CANTUNWIND;
1058	}
1059
1060	/* Format X3 */
1061	else if (b0 == 0xfb) {
1062	    TRACE_I_DECODE_BODY_1("(X3)", b0)
1063	    b1 = uwx_get_byte(bstream);
1064	    if (b1 < 0)
1065		return UWX_ERR_BADUDESC;
1066	    b2 = uwx_get_byte(bstream);
1067	    if (b2 < 0)
1068		return UWX_ERR_BADUDESC;
1069	    /* Don't support X-format descriptors yet */
1070	    return UWX_ERR_CANTUNWIND;
1071	}
1072
1073	/* Format X4 */
1074	else if (b0 == 0xfc) {
1075	    TRACE_I_DECODE_BODY_1("(X4)", b0)
1076	    b1 = uwx_get_byte(bstream);
1077	    if (b1 < 0)
1078		return UWX_ERR_BADUDESC;
1079	    b2 = uwx_get_byte(bstream);
1080	    if (b2 < 0)
1081		return UWX_ERR_BADUDESC;
1082	    b3 = uwx_get_byte(bstream);
1083	    if (b3 < 0)
1084		return UWX_ERR_BADUDESC;
1085	    /* Don't support X-format descriptors yet */
1086	    return UWX_ERR_CANTUNWIND;
1087	}
1088
1089	/* Invalid descriptor record */
1090	else {
1091	    TRACE_I_DECODE_BODY_1("(?)", b0)
1092	    return UWX_ERR_BADUDESC;
1093	}
1094    }
1095
1096    /* Update the scoreboard. */
1097
1098    for (i = 0; i < env->nsbreg; i++) {
1099	if (ip_slot > tspill[i])
1100	    scoreboard->rstate[i] = newrstate[i];
1101    }
1102
1103    /* If we've passed the point in the epilogue where sp */
1104    /* is restored, update the scoreboard entry for PSP */
1105    /* and reset any entries for registers saved in memory. */
1106
1107    if (rhdr->ecount > 0 && ip_slot > t_sp_restore) {
1108	scoreboard->rstate[SBREG_PSP] = UWX_DISP_SPPLUS(0);
1109	for (i = 0; i < env->nsbreg; i++) {
1110	    if (UWX_GET_DISP_CODE(scoreboard->rstate[i]) == UWX_DISP_SPREL(0) ||
1111		UWX_GET_DISP_CODE(scoreboard->rstate[i]) == UWX_DISP_PSPREL(0))
1112		scoreboard->rstate[i] = UWX_DISP_NONE;
1113	}
1114    }
1115
1116    return UWX_OK;
1117}
1118
1119