1115013Smarcel/*
2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3121642SmarcelPermission is hereby granted, free of charge, to any person
4121642Smarcelobtaining a copy of this software and associated documentation
5121642Smarcelfiles (the "Software"), to deal in the Software without
6121642Smarcelrestriction, including without limitation the rights to use,
7121642Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell
8121642Smarcelcopies of the Software, and to permit persons to whom the
9121642SmarcelSoftware is furnished to do so, subject to the following
10121642Smarcelconditions:
11115013Smarcel
12121642SmarcelThe above copyright notice and this permission notice shall be
13121642Smarcelincluded in all copies or substantial portions of the Software.
14121642Smarcel
15121642SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16121642SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17121642SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18121642SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19121642SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20121642SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21121642SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22121642SmarcelOTHER DEALINGS IN THE SOFTWARE.
23121642Smarcel*/
24121642Smarcel
25115013Smarcel#include "uwx_env.h"
26115013Smarcel#include "uwx_uinfo.h"
27115013Smarcel#include "uwx_utable.h"
28115013Smarcel#include "uwx_scoreboard.h"
29115013Smarcel#include "uwx_bstream.h"
30115013Smarcel#include "uwx_trace.h"
31160163Smarcel#include "uwx_swap.h"
32115013Smarcel
33115013Smarcelint uwx_count_ones(unsigned int mask);
34115013Smarcel
35115013Smarcel/*
36115013Smarcel *  uwx_uinfo.c
37115013Smarcel *
38115013Smarcel *  This file contains the routines for reading and decoding
39115013Smarcel *  the unwind information block.
40115013Smarcel *
41115013Smarcel *  The main entry point, uwx_decode_uinfo(), is given a pointer
42115013Smarcel *  to an unwind table entry and a pointer (passed by reference)
43115013Smarcel *  to be filled in with a pointer to an update vector. It will
44115013Smarcel *  read and decode the unwind descriptors contained in the
45115013Smarcel *  unwind information block, then build the register state array,
46115013Smarcel *  which describes the actions necessary to step from the current
47115013Smarcel *  frame to the previous one.
48115013Smarcel */
49115013Smarcel
50115013Smarcel#define COPYIN_UINFO_4(dest, src) \
51115013Smarcel    (env->remote? \
52160157Smarcel      (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
53115013Smarcel						WORDSZ, env->cb_token) : \
54160157Smarcel      (*(uint32_t *)(intptr_t)(dest) = *(uint32_t *)(intptr_t)(src), WORDSZ) )
55115013Smarcel
56115013Smarcel#define COPYIN_UINFO_8(dest, src) \
57115013Smarcel    (env->remote? \
58160157Smarcel      (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
59115013Smarcel						DWORDSZ, env->cb_token) : \
60160157Smarcel      (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), DWORDSZ) )
61115013Smarcel
62115013Smarcel
63115013Smarcel/* uwx_default_rstate: Returns the default register state for a leaf routine */
64115013Smarcel
65115013Smarcelint uwx_default_rstate(struct uwx_env *env, uint64_t **rstatep)
66115013Smarcel{
67115013Smarcel    struct uwx_scoreboard *sb;
68115013Smarcel
69115013Smarcel    sb = uwx_init_scoreboards(env);
70115013Smarcel    *rstatep = sb->rstate;
71115013Smarcel    return UWX_OK;
72115013Smarcel}
73115013Smarcel
74115013Smarcel
75115013Smarcel/* uwx_decode_uinfo: Decodes unwind info region */
76115013Smarcel
77115013Smarcelint uwx_decode_uinfo(
78115013Smarcel    struct uwx_env *env,
79115013Smarcel    struct uwx_utable_entry *uentry,
80115013Smarcel    uint64_t **rstatep)
81115013Smarcel{
82115013Smarcel    uint64_t uinfohdr;
83115013Smarcel    unsigned int ulen;
84115013Smarcel    int len;
85115013Smarcel    struct uwx_bstream bstream;
86115013Smarcel    struct uwx_scoreboard *scoreboard;
87115013Smarcel    int ip_slot;
88115013Smarcel    int cur_slot;
89115013Smarcel    int status;
90115013Smarcel    struct uwx_rhdr rhdr;
91115013Smarcel
92115013Smarcel    /* Remember the offset from the start of the function */
93115013Smarcel    /* to the current IP. This helps the client find */
94115013Smarcel    /* the symbolic information. */
95115013Smarcel
96129059Smarcel    env->function_offset = env->remapped_ip - uentry->code_start;
97115013Smarcel
98115013Smarcel    /* Read the unwind info header using the copyin callback. */
99115013Smarcel    /* (If we're reading a 32-bit unwind table, we need to */
100115013Smarcel    /* read the header as two 32-bit pieces to preserve the */
101115013Smarcel    /* guarantee that we always call copyin for aligned */
102115013Smarcel    /* 4-byte or 8-byte chunks.) */
103115013Smarcel    /* Then compute the length of the unwind descriptor */
104115013Smarcel    /* region and initialize a byte stream to read it. */
105115013Smarcel
106115013Smarcel    if (uentry->unwind_flags & UNWIND_TBL_32BIT) {
107115013Smarcel	len = COPYIN_UINFO_4((char *)&uinfohdr, uentry->unwind_info);
108115013Smarcel	len += COPYIN_UINFO_4((char *)&uinfohdr + WORDSZ,
109115013Smarcel					uentry->unwind_info + WORDSZ);
110115013Smarcel	}
111115013Smarcel    else
112115013Smarcel	len = COPYIN_UINFO_8((char *)&uinfohdr, uentry->unwind_info);
113115013Smarcel    if (len != DWORDSZ)
114115013Smarcel	return UWX_ERR_COPYIN_UINFO;
115115013Smarcel    if (env->byte_swap)
116115013Smarcel	uwx_swap8(&uinfohdr);
117115013Smarcel    if (uentry->unwind_flags & UNWIND_TBL_32BIT)
118115013Smarcel	ulen = UNW_LENGTH(uinfohdr) * WORDSZ;
119115013Smarcel    else
120115013Smarcel	ulen = UNW_LENGTH(uinfohdr) * DWORDSZ;
121115013Smarcel    uwx_init_bstream(&bstream, env,
122115013Smarcel		uentry->unwind_info + DWORDSZ, ulen, UWX_COPYIN_UINFO);
123115013Smarcel
124160157Smarcel    /* Save the header and a pointer to the personality routine ptr */
125160157Smarcel    /* for later use in exception handling. */
126160157Smarcel
127160157Smarcel    env->uinfo_hdr = uinfohdr;
128160157Smarcel    env->uinfo_end = uentry->unwind_info + DWORDSZ + ulen;
129160157Smarcel
130115013Smarcel    TRACE_R_UIB(uentry, ulen)
131115013Smarcel
132115013Smarcel    /* Create an initial scoreboard for tracking the unwind state. */
133115013Smarcel
134115013Smarcel    scoreboard = uwx_init_scoreboards(env);
135115013Smarcel
136115013Smarcel    /* Prepare to read and decode the unwind regions described */
137115013Smarcel    /* by the unwind info block. Find the target "ip" slot */
138115013Smarcel    /* relative to the beginning of the region. The lower 4 bits */
139115013Smarcel    /* of the actual IP encode the slot number within a bundle. */
140115013Smarcel
141115013Smarcel    cur_slot = 0;
142115013Smarcel    ip_slot = (int) ((env->context.special[UWX_REG_IP] & ~0x0fLL)
143115013Smarcel							- uentry->code_start)
144115013Smarcel		/ BUNDLESZ * SLOTSPERBUNDLE
145115013Smarcel		+ (unsigned int) (env->context.special[UWX_REG_IP] & 0x0f);
146115013Smarcel
147115013Smarcel    /* Loop over the regions in the unwind info block. */
148115013Smarcel
149115013Smarcel    for (;;) {
150115013Smarcel
151115013Smarcel	/* Decode the next region header. */
152115013Smarcel	/* We have an error if we reach the end of the info block, */
153115013Smarcel	/* since we should have found our target ip slot by then. */
154115013Smarcel	/* We also have an error if the next byte isn't a region */
155115013Smarcel	/* header record. */
156115013Smarcel
157115013Smarcel	status = uwx_decode_rhdr(env, &bstream, &rhdr);
158115013Smarcel	if (status != UWX_OK)
159115013Smarcel	    return status;
160115013Smarcel
161115013Smarcel	/* If a prologue region, get a new scoreboard, pushing */
162115013Smarcel	/* the previous one onto the prologue stack. Then read */
163115013Smarcel	/* and decode the prologue region records. */
164115013Smarcel
165115013Smarcel	if (rhdr.is_prologue) {
166115013Smarcel	    scoreboard = uwx_new_scoreboard(env, scoreboard);
167115013Smarcel	    if (scoreboard == 0)
168115013Smarcel		return UWX_ERR_NOMEM;
169115013Smarcel	    status = uwx_decode_prologue(env, &bstream,
170115013Smarcel					    scoreboard, &rhdr, ip_slot);
171115013Smarcel	}
172115013Smarcel
173115013Smarcel	/* If a body region, read and decode the body region */
174115013Smarcel	/* records. If the body has an epilogue count, */
175115013Smarcel	/* uwx_decode_body will note that in the region header */
176115013Smarcel	/* record for use at the bottom of the loop. */
177115013Smarcel
178115013Smarcel	else {
179115013Smarcel	    status = uwx_decode_body(env, &bstream, scoreboard, &rhdr, ip_slot);
180115013Smarcel	}
181115013Smarcel
182115013Smarcel	if (status != UWX_OK)
183115013Smarcel	    return status;
184115013Smarcel
185115013Smarcel	TRACE_R_DUMP_SB(scoreboard, rhdr, cur_slot, ip_slot)
186115013Smarcel
187115013Smarcel	/* If the target ip slot is within this region, we're done. */
188115013Smarcel	/* Return the scoreboard's register state array. */
189115013Smarcel
190115013Smarcel	if (ip_slot < rhdr.rlen) {
191115013Smarcel	    *rstatep = scoreboard->rstate;
192115013Smarcel	    return UWX_OK;
193115013Smarcel	}
194115013Smarcel
195115013Smarcel	/* Otherwise, update the current ip slot, pop the */
196115013Smarcel	/* scoreboard stack based on the epilogue count, */
197115013Smarcel	/* and loop back around for the next region. */
198115013Smarcel
199115013Smarcel	cur_slot += rhdr.rlen;
200115013Smarcel	ip_slot -= rhdr.rlen;
201115013Smarcel	if (rhdr.ecount > 0) {
202115013Smarcel	    scoreboard = uwx_pop_scoreboards(env, scoreboard, rhdr.ecount);
203115013Smarcel	    if (scoreboard == 0)
204115013Smarcel		return UWX_ERR_PROLOG_UF;
205115013Smarcel	}
206115013Smarcel    }
207115013Smarcel    /*NOTREACHED*/
208115013Smarcel}
209115013Smarcel
210115013Smarcel
211115013Smarcel/* uwx_decode_rhdr: Decodes a region header record */
212115013Smarcel
213115013Smarcelint uwx_decode_rhdr(
214115013Smarcel    struct uwx_env *env,
215115013Smarcel    struct uwx_bstream *bstream,
216115013Smarcel    struct uwx_rhdr *rhdr)
217115013Smarcel{
218115013Smarcel    int b0;
219115013Smarcel    int b1;
220115013Smarcel    uint64_t val;
221115013Smarcel    int status;
222115013Smarcel
223115013Smarcel    /* Get the first byte of the next descriptor record. */
224115013Smarcel    b0 = uwx_get_byte(bstream);
225115013Smarcel    if (b0 < 0)
226115013Smarcel	return UWX_ERR_NOUDESC;
227115013Smarcel
228115013Smarcel    /* Initialize region header record. */
229115013Smarcel
230115013Smarcel    rhdr->is_prologue = 0;
231115013Smarcel    rhdr->rlen = 0;
232115013Smarcel    rhdr->mask = 0;
233115013Smarcel    rhdr->grsave = 0;
234115013Smarcel    rhdr->ecount = 0;
235115013Smarcel
236115013Smarcel    /* Format R1 */
237115013Smarcel
238115013Smarcel    if (b0 < 0x40) {
239115013Smarcel	if ((b0 & 0x20) == 0) {
240115013Smarcel	    TRACE_I_DECODE_RHDR_1("(R1) prologue", b0)
241115013Smarcel	    rhdr->is_prologue = 1;
242120925Smarcel	}
243120925Smarcel	else {
244117465Smarcel	    TRACE_I_DECODE_RHDR_1("(R1) body", b0)
245115013Smarcel	}
246115013Smarcel	rhdr->rlen = b0 & 0x1f;
247115013Smarcel    }
248115013Smarcel
249115013Smarcel    /* Format R2 */
250115013Smarcel
251115013Smarcel    else if (b0 < 0x60) {
252115013Smarcel	b1 = uwx_get_byte(bstream);
253115013Smarcel	if (b1 < 0)
254115013Smarcel	    return UWX_ERR_BADUDESC;
255115013Smarcel	status = uwx_get_uleb128(bstream, &val);
256115013Smarcel	if (status != 0)
257115013Smarcel	    return UWX_ERR_BADUDESC;
258115013Smarcel	TRACE_I_DECODE_RHDR_2L("(R2) prologue_gr", b0, b1, val)
259115013Smarcel	rhdr->is_prologue = 1;
260115013Smarcel	rhdr->rlen = (unsigned int) val;
261115013Smarcel	rhdr->mask = ((b0 & 0x07) << 1) | (b1 >> 7);
262115013Smarcel	rhdr->grsave = b1 & 0x7f;
263115013Smarcel    }
264115013Smarcel
265115013Smarcel    /* Format R3 */
266115013Smarcel
267115013Smarcel    else if (b0 < 0x80) {
268115013Smarcel	status = uwx_get_uleb128(bstream, &val);
269115013Smarcel	if (status != 0)
270115013Smarcel	    return UWX_ERR_BADUDESC;
271115013Smarcel	if ((b0 & 0x03) == 0) {
272115013Smarcel	    TRACE_I_DECODE_RHDR_1L("(R3) prologue", b0, val)
273115013Smarcel	    rhdr->is_prologue = 1;
274120925Smarcel	}
275120925Smarcel	else {
276117465Smarcel	    TRACE_I_DECODE_RHDR_1L("(R3) body", b0, val)
277115013Smarcel	}
278115013Smarcel	rhdr->rlen = (unsigned int) val;
279115013Smarcel    }
280115013Smarcel
281115013Smarcel    /* Otherwise, not a region header record. */
282115013Smarcel
283115013Smarcel    else {
284115013Smarcel	TRACE_I_DECODE_RHDR_1("(?)", b0)
285115013Smarcel	return UWX_ERR_BADUDESC;
286115013Smarcel    }
287115013Smarcel
288115013Smarcel    return UWX_OK;
289115013Smarcel}
290115013Smarcel
291115013Smarcel
292115013Smarcel/* uwx_decode_prologue: Decodes a prologue region */
293115013Smarcel
294115013Smarcelint uwx_decode_prologue(
295115013Smarcel    struct uwx_env *env,
296115013Smarcel    struct uwx_bstream *bstream,
297115013Smarcel    struct uwx_scoreboard *scoreboard,
298115013Smarcel    struct uwx_rhdr *rhdr,
299115013Smarcel    int ip_slot)
300115013Smarcel{
301115013Smarcel    int status;
302115013Smarcel    int reg;
303115013Smarcel    int mask;
304115013Smarcel    int b0;
305115013Smarcel    int b1;
306115013Smarcel    int b2;
307115013Smarcel    int b3;
308115013Smarcel    int r;
309115013Smarcel    int t;
310115013Smarcel    int i;
311115013Smarcel    uint64_t parm1;
312115013Smarcel    uint64_t parm2;
313115013Smarcel    uint64_t newrstate[NSBREG];
314115013Smarcel    int tspill[NSBREG];
315115013Smarcel    int priunat_mem_rstate;
316115013Smarcel    int t_priunat_mem;
317115013Smarcel    unsigned int gr_mem_mask;
318115013Smarcel    unsigned int br_mem_mask;
319115013Smarcel    unsigned int fr_mem_mask;
320115013Smarcel    unsigned int gr_gr_mask;
321115013Smarcel    unsigned int br_gr_mask;
322115013Smarcel    int ngr;
323115013Smarcel    int nbr;
324115013Smarcel    int nfr;
325115013Smarcel    unsigned int spill_base;
326115013Smarcel    unsigned int gr_base;
327115013Smarcel    unsigned int br_base;
328115013Smarcel    unsigned int fr_base;
329115013Smarcel
330115013Smarcel    /* Initialize an array of register states from the current */
331115013Smarcel    /* scoreboard, along with a parallel array of spill times. */
332115013Smarcel    /* We use this as a temporary scoreboard, then update the */
333115013Smarcel    /* real scoreboard at the end of the procedure. */
334115013Smarcel    /* We initialize the spill time to (rhdr.rlen - 1) so that */
335115013Smarcel    /* spills without a "when" descriptor will take effect */
336115013Smarcel    /* at the end of the prologue region. */
337115013Smarcel    /* (Boundary condition: all actions in a zero-length prologue */
338115013Smarcel    /* will appear to have happened in the instruction slot */
339115013Smarcel    /* immediately preceding the prologue.) */
340115013Smarcel
341115013Smarcel    for (i = 0; i < env->nsbreg; i++) {
342115013Smarcel	newrstate[i] = scoreboard->rstate[i];
343115013Smarcel	tspill[i] = rhdr->rlen - 1;
344115013Smarcel    }
345115013Smarcel    priunat_mem_rstate = UWX_DISP_NONE;
346115013Smarcel    t_priunat_mem = rhdr->rlen - 1;
347115013Smarcel
348115013Smarcel    fr_mem_mask = 0;
349115013Smarcel    gr_mem_mask = 0;
350115013Smarcel    br_mem_mask = 0;
351115013Smarcel    gr_gr_mask = 0;
352115013Smarcel    br_gr_mask = 0;
353160157Smarcel    nfr = 127;
354160157Smarcel    ngr = 127;
355160157Smarcel    nbr = 127;
356115013Smarcel    spill_base = 0;
357115013Smarcel
358115013Smarcel    /* If prologue_gr header record supplied mask and grsave, */
359115013Smarcel    /* record these in the scoreboard. */
360115013Smarcel
361115013Smarcel    reg = rhdr->grsave;
362115013Smarcel    mask = rhdr->mask;
363115013Smarcel    if (mask & 0x8) {
364115013Smarcel	newrstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_GR(reg));
365115013Smarcel	reg++;
366115013Smarcel    }
367115013Smarcel    if (mask & 0x4) {
368115013Smarcel	newrstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_GR(reg));
369115013Smarcel	reg++;
370115013Smarcel    }
371115013Smarcel    if (mask & 0x2) {
372115013Smarcel	newrstate[SBREG_PSP] = UWX_DISP_REG(UWX_REG_GR(reg));
373115013Smarcel	reg++;
374115013Smarcel    }
375115013Smarcel    if (mask & 0x1) {
376115013Smarcel	newrstate[SBREG_PREDS] = UWX_DISP_REG(UWX_REG_GR(reg));
377115013Smarcel	reg++;
378115013Smarcel    }
379115013Smarcel
380115013Smarcel    /* Read prologue descriptor records until */
381115013Smarcel    /* we hit another region header. */
382115013Smarcel
383115013Smarcel    for (;;) {
384115013Smarcel
385115013Smarcel	b0 = uwx_get_byte(bstream);
386115013Smarcel
387115013Smarcel	if (b0 < 0x80) {
388115013Smarcel	    /* Return the last byte read to the byte stream, since it's */
389115013Smarcel	    /* really the first byte of the next region header record. */
390115013Smarcel	    if (b0 >= 0)
391115013Smarcel		(void) uwx_unget_byte(bstream, b0);
392115013Smarcel	    break;
393115013Smarcel	}
394115013Smarcel
395115013Smarcel	switch ((b0 & 0x70) >> 4) {
396115013Smarcel
397115013Smarcel	    case 0:			/* 1000 xxxx */
398115013Smarcel	    case 1:			/* 1001 xxxx */
399115013Smarcel		/* Format P1 (br_mem) */
400115013Smarcel		TRACE_I_DECODE_PROLOGUE_1("(P1) br_mem", b0)
401115013Smarcel		br_mem_mask = b0 & 0x1f;
402115013Smarcel		break;
403115013Smarcel
404115013Smarcel	    case 2:			/* 1010 xxxx */
405115013Smarcel		/* Format P2 (br_gr) */
406115013Smarcel		b1 = uwx_get_byte(bstream);
407115013Smarcel		if (b1 < 0)
408115013Smarcel		    return UWX_ERR_BADUDESC;
409115013Smarcel		TRACE_I_DECODE_PROLOGUE_2("(P2) br_gr", b0, b1)
410115013Smarcel		mask = ((b0 & 0x0f) << 1) | (b1 >> 7);
411115013Smarcel		reg = b1 & 0x7f;
412115013Smarcel		br_gr_mask = mask;
413115013Smarcel		for (i = 0; i < NSB_BR && mask != 0; i++) {
414115013Smarcel		    if (mask & 0x01) {
415115013Smarcel			newrstate[SBREG_BR + i] = UWX_DISP_REG(UWX_REG_GR(reg));
416115013Smarcel			reg++;
417115013Smarcel		    }
418115013Smarcel		    mask = mask >> 1;
419115013Smarcel		}
420115013Smarcel		break;
421115013Smarcel
422115013Smarcel	    case 3:			/* 1011 xxxx */
423115013Smarcel		/* Format P3 */
424115013Smarcel		if (b0 < 0xb8) {
425115013Smarcel		    b1 = uwx_get_byte(bstream);
426115013Smarcel		    if (b1 < 0)
427115013Smarcel			return UWX_ERR_BADUDESC;
428129059Smarcel		    r = ((b0 & 0x7) << 1) | (b1 >> 7);
429115013Smarcel		    reg = b1 & 0x7f;
430115013Smarcel		    switch (r) {
431115013Smarcel			case 0:		/* psp_gr */
432115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) psp_gr", b0, b1)
433115013Smarcel			    newrstate[SBREG_PSP] = UWX_DISP_REG(UWX_REG_GR(reg));
434115013Smarcel			    break;
435115013Smarcel			case 1:		/* rp_gr */
436115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) rp_gr", b0, b1)
437115013Smarcel			    newrstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_GR(reg));
438115013Smarcel			    break;
439115013Smarcel			case 2:		/* pfs_gr */
440115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) pfs_gr", b0, b1)
441115013Smarcel			    newrstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_GR(reg));
442115013Smarcel			    break;
443115013Smarcel			case 3:		/* preds_gr */
444115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) preds_gr", b0, b1)
445115013Smarcel			    newrstate[SBREG_PREDS] =
446115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
447115013Smarcel			    break;
448115013Smarcel			case 4:		/* unat_gr */
449115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) unat_gr", b0, b1)
450115013Smarcel			    newrstate[SBREG_UNAT] =
451115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
452115013Smarcel			    break;
453115013Smarcel			case 5:		/* lc_gr */
454115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) lc_gr", b0, b1)
455115013Smarcel			    newrstate[SBREG_LC] =
456115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
457115013Smarcel			    break;
458115013Smarcel			case 6:		/* rp_br */
459115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) rp_br", b0, b1)
460115013Smarcel			    scoreboard->rstate[SBREG_RP] =
461115013Smarcel					UWX_DISP_REG(UWX_REG_BR(reg));
462160157Smarcel			    if (newrstate[SBREG_RP] ==
463160157Smarcel						UWX_DISP_REG(UWX_REG_BR(0)))
464160157Smarcel				newrstate[SBREG_RP] =
465160157Smarcel					UWX_DISP_REG(UWX_REG_BR(reg));
466115013Smarcel			    break;
467115013Smarcel			case 7:		/* rnat_gr */
468115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) rnat_gr", b0, b1)
469115013Smarcel			    newrstate[SBREG_RNAT] =
470115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
471115013Smarcel			    break;
472115013Smarcel			case 8:		/* bsp_gr */
473115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) bsp_gr", b0, b1)
474115013Smarcel			    /* Don't track BSP yet */
475115013Smarcel			    return UWX_ERR_CANTUNWIND;
476160157Smarcel			    /* break; */
477115013Smarcel			case 9:		/* bspstore_gr */
478115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) bspstore_gr", b0, b1)
479115013Smarcel			    /* Don't track BSPSTORE yet */
480115013Smarcel			    return UWX_ERR_CANTUNWIND;
481160157Smarcel			    /* break; */
482115013Smarcel			case 10:	/* fpsr_gr */
483115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) fpsr_gr", b0, b1)
484115013Smarcel			    newrstate[SBREG_FPSR] =
485115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
486115013Smarcel			    break;
487115013Smarcel			case 11:	/* priunat_gr */
488115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) priunat_gr", b0, b1)
489115013Smarcel			    newrstate[SBREG_PRIUNAT] =
490115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
491115013Smarcel			    break;
492115013Smarcel			default:
493115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2("(P3) ??", b0, b1)
494115013Smarcel			    return UWX_ERR_BADUDESC;
495115013Smarcel		    }
496115013Smarcel		}
497115013Smarcel
498115013Smarcel		/* Format P4 (spill_mask) */
499115013Smarcel		else if (b0 == 0xb8) {
500115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(P4) spill_mask", b0)
501115013Smarcel		    /* The spill_mask descriptor is followed by */
502115013Smarcel		    /* an imask field whose length is determined */
503115013Smarcel		    /* by the region length: there are two mask */
504115013Smarcel		    /* bits per instruction slot in the region. */
505115013Smarcel		    /* We decode these bits two at a time, counting */
506115013Smarcel		    /* the number of FRs, GRs, and BRs that are */
507115013Smarcel		    /* saved up to the slot of interest. Other */
508115013Smarcel		    /* descriptors describe which sets of these */
509115013Smarcel		    /* registers are spilled, and we put those */
510115013Smarcel		    /* two pieces of information together at the */
511115013Smarcel		    /* end of the main loop. */
512115013Smarcel		    t = 0;
513160157Smarcel		    nfr = 0;
514160157Smarcel		    ngr = 0;
515160157Smarcel		    nbr = 0;
516115013Smarcel		    while (t < rhdr->rlen) {
517115013Smarcel			b1 = uwx_get_byte(bstream);
518115013Smarcel			if (b1 < 0)
519115013Smarcel			    return UWX_ERR_BADUDESC;
520115013Smarcel			for (i = 0; i < 4 && (t + i) < ip_slot; i++) {
521115013Smarcel			    switch (b1 & 0xc0) {
522115013Smarcel				case 0x00: break;
523115013Smarcel				case 0x40: nfr++; break;
524115013Smarcel				case 0x80: ngr++; break;
525115013Smarcel				case 0xc0: nbr++; break;
526115013Smarcel			    }
527115013Smarcel			    b1 = b1 << 2;
528115013Smarcel			}
529115013Smarcel			t += 4;
530115013Smarcel		    }
531115013Smarcel		}
532115013Smarcel
533115013Smarcel		/* Format P5 (frgr_mem) */
534115013Smarcel		else if (b0 == 0xb9) {
535115013Smarcel		    b1 = uwx_get_byte(bstream);
536115013Smarcel		    if (b1 < 0)
537115013Smarcel			return UWX_ERR_BADUDESC;
538115013Smarcel		    b2 = uwx_get_byte(bstream);
539115013Smarcel		    if (b2 < 0)
540115013Smarcel			return UWX_ERR_BADUDESC;
541115013Smarcel		    b3 = uwx_get_byte(bstream);
542115013Smarcel		    if (b3 < 0)
543115013Smarcel			return UWX_ERR_BADUDESC;
544115013Smarcel		    TRACE_I_DECODE_PROLOGUE_4("(P5) frgr_mem", b0, b1, b2, b3)
545115013Smarcel		    gr_mem_mask = b1 >> 4;
546115013Smarcel		    fr_mem_mask = ((b1 & 0x0f) << 16) | (b2 << 8) | b3;
547115013Smarcel		}
548115013Smarcel
549115013Smarcel		/* Invalid descriptor record */
550115013Smarcel		else {
551115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(?)", b0)
552115013Smarcel		    return UWX_ERR_BADUDESC;
553115013Smarcel		}
554115013Smarcel
555115013Smarcel		break;
556115013Smarcel
557115013Smarcel	    case 4:			/* 1100 xxxx */
558115013Smarcel		/* Format P6 (fr_mem) */
559115013Smarcel		TRACE_I_DECODE_PROLOGUE_1("(P6) fr_mem", b0)
560115013Smarcel		fr_mem_mask = b0 & 0x0f;
561115013Smarcel		break;
562115013Smarcel
563115013Smarcel	    case 5:			/* 1101 xxxx */
564115013Smarcel		/* Format P6 (gr_mem) */
565115013Smarcel		TRACE_I_DECODE_PROLOGUE_1("(P6) gr_mem", b0)
566115013Smarcel		gr_mem_mask = b0 & 0x0f;
567115013Smarcel		break;
568115013Smarcel
569115013Smarcel	    case 6:			/* 1110 xxxx */
570115013Smarcel		/* Format P7 */
571115013Smarcel		r = b0 & 0xf;
572115013Smarcel		status = uwx_get_uleb128(bstream, &parm1);
573115013Smarcel		if (status != 0)
574115013Smarcel		    return UWX_ERR_BADUDESC;
575115013Smarcel		switch (r) {
576115013Smarcel		    case 0:		/* mem_stack_f */
577115013Smarcel			status = uwx_get_uleb128(bstream, &parm2);
578115013Smarcel			if (status != 0)
579115013Smarcel			    return UWX_ERR_BADUDESC;
580115013Smarcel			TRACE_I_DECODE_PROLOGUE_1LL("(P7) mem_stack_f", b0, parm1, parm2)
581115013Smarcel			newrstate[SBREG_PSP] = UWX_DISP_SPPLUS(parm2 * 16);
582115013Smarcel			tspill[SBREG_PSP] = (int) parm1;
583115013Smarcel			break;
584115013Smarcel		    case 1:		/* mem_stack_v */
585115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) mem_stack_v", b0, parm1)
586115013Smarcel			tspill[SBREG_PSP] = (int) parm1;
587115013Smarcel			break;
588115013Smarcel		    case 2:		/* spill_base */
589115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) spill_base", b0, parm1)
590115013Smarcel			spill_base = 4 * (unsigned int) parm1;
591115013Smarcel			break;
592115013Smarcel		    case 3:		/* psp_sprel */
593115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) psp_sprel", b0, parm1)
594115013Smarcel			newrstate[SBREG_PSP] = UWX_DISP_SPREL(parm1 * 4);
595115013Smarcel			break;
596115013Smarcel		    case 4:		/* rp_when */
597115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) rp_when", b0, parm1)
598115013Smarcel			tspill[SBREG_RP] = (int) parm1;
599115013Smarcel			break;
600115013Smarcel		    case 5:		/* rp_psprel */
601115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) rp_psprel", b0, parm1)
602115013Smarcel			newrstate[SBREG_RP] = UWX_DISP_PSPREL(parm1 * 4);
603115013Smarcel			break;
604115013Smarcel		    case 6:		/* pfs_when */
605115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) pfs_when", b0, parm1)
606115013Smarcel			tspill[SBREG_PFS] = (int) parm1;
607115013Smarcel			break;
608115013Smarcel		    case 7:		/* pfs_psprel */
609115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) pfs_psprel", b0, parm1)
610115013Smarcel			newrstate[SBREG_PFS] = UWX_DISP_PSPREL(parm1 * 4);
611115013Smarcel			break;
612115013Smarcel		    case 8:		/* preds_when */
613115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) preds_when", b0, parm1)
614115013Smarcel			tspill[SBREG_PREDS] = (int) parm1;
615115013Smarcel			break;
616115013Smarcel		    case 9:		/* preds_psprel */
617115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) preds_psprel", b0, parm1)
618115013Smarcel			newrstate[SBREG_PREDS] = UWX_DISP_PSPREL(parm1 * 4);
619115013Smarcel			break;
620115013Smarcel		    case 10:	/* lc_when */
621115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) lc_when", b0, parm1)
622115013Smarcel			tspill[SBREG_LC] = (int) parm1;
623115013Smarcel			break;
624115013Smarcel		    case 11:	/* lc_psprel */
625115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) lc_psprel", b0, parm1)
626115013Smarcel			newrstate[SBREG_LC] = UWX_DISP_PSPREL(parm1 * 4);
627115013Smarcel			break;
628115013Smarcel		    case 12:	/* unat_when */
629115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) unat_when", b0, parm1)
630115013Smarcel			tspill[SBREG_UNAT] = (int) parm1;
631115013Smarcel			break;
632115013Smarcel		    case 13:	/* unat_psprel */
633115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) unat_psprel", b0, parm1)
634115013Smarcel			newrstate[SBREG_UNAT] = UWX_DISP_PSPREL(parm1 * 4);
635115013Smarcel			break;
636115013Smarcel		    case 14:	/* fpsr_when */
637115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) fpsr_when", b0, parm1)
638115013Smarcel			tspill[SBREG_FPSR] = (int) parm1;
639115013Smarcel			break;
640115013Smarcel		    case 15:	/* fpsr_psprel */
641115013Smarcel			TRACE_I_DECODE_PROLOGUE_1L("(P7) fpsr_psprel", b0, parm1)
642115013Smarcel			newrstate[SBREG_FPSR] = UWX_DISP_PSPREL(parm1 * 4);
643115013Smarcel			break;
644115013Smarcel		}
645115013Smarcel		break;
646115013Smarcel
647115013Smarcel	    case 7:			/* 1111 xxxx */
648115013Smarcel		/* Format P8 */
649115013Smarcel		if (b0 == 0xf0) {
650115013Smarcel		    b1 = uwx_get_byte(bstream);
651115013Smarcel		    if (b1 < 0)
652115013Smarcel			return UWX_ERR_BADUDESC;
653115013Smarcel		    status = uwx_get_uleb128(bstream, &parm1);
654115013Smarcel		    if (status != 0)
655115013Smarcel			return UWX_ERR_BADUDESC;
656115013Smarcel		    switch (b1) {
657115013Smarcel			case 1:		/* rp_sprel */
658115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rp_sprel", b0, b1, parm1)
659115013Smarcel			    newrstate[SBREG_RP] = UWX_DISP_SPREL(parm1 * 4);
660115013Smarcel			    break;
661115013Smarcel			case 2:		/* pfs_sprel */
662115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) pfs_sprel", b0, b1, parm1)
663115013Smarcel			    newrstate[SBREG_PFS] = UWX_DISP_SPREL(parm1 * 4);
664115013Smarcel			    break;
665115013Smarcel			case 3:		/* preds_sprel */
666115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) preds_sprel", b0, b1, parm1)
667115013Smarcel			    newrstate[SBREG_PREDS] = UWX_DISP_SPREL(parm1 * 4);
668115013Smarcel			    break;
669115013Smarcel			case 4:		/* lc_sprel */
670115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) lc_sprel", b0, b1, parm1)
671115013Smarcel			    newrstate[SBREG_LC] = UWX_DISP_SPREL(parm1 * 4);
672115013Smarcel			    break;
673115013Smarcel			case 5:		/* unat_sprel */
674115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) unat_sprel", b0, b1, parm1)
675115013Smarcel			    newrstate[SBREG_UNAT] = UWX_DISP_SPREL(parm1 * 4);
676115013Smarcel			    break;
677115013Smarcel			case 6:		/* fpsr_sprel */
678115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) fpsr_sprel", b0, b1, parm1)
679115013Smarcel			    newrstate[SBREG_FPSR] = UWX_DISP_SPREL(parm1 * 4);
680115013Smarcel			    break;
681115013Smarcel			case 7:		/* bsp_when */
682115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_when", b0, b1, parm1)
683115013Smarcel			    /* Don't track BSP yet */
684115013Smarcel			    return UWX_ERR_CANTUNWIND;
685160157Smarcel			    /* break; */
686115013Smarcel			case 8:		/* bsp_psprel */
687115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_psprel", b0, b1, parm1)
688115013Smarcel			    /* Don't track BSP yet */
689115013Smarcel			    return UWX_ERR_CANTUNWIND;
690160157Smarcel			    /* break; */
691115013Smarcel			case 9:		/* bsp_sprel */
692115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_sprel", b0, b1, parm1)
693115013Smarcel			    /* Don't track BSP yet */
694115013Smarcel			    return UWX_ERR_CANTUNWIND;
695160157Smarcel			    /* break; */
696115013Smarcel			case 10:	/* bspstore_when */
697115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_when", b0, b1, parm1)
698115013Smarcel			    /* Don't track BSP yet */
699115013Smarcel			    return UWX_ERR_CANTUNWIND;
700160157Smarcel			    /* break; */
701115013Smarcel			case 11:	/* bspstore_psprel */
702115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_psprel", b0, b1, parm1)
703115013Smarcel			    /* Don't track BSP yet */
704115013Smarcel			    return UWX_ERR_CANTUNWIND;
705160157Smarcel			    /* break; */
706115013Smarcel			case 12:	/* bspstore_sprel */
707115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_sprel", b0, b1, parm1)
708115013Smarcel			    /* Don't track BSP yet */
709115013Smarcel			    return UWX_ERR_CANTUNWIND;
710160157Smarcel			    /* break; */
711115013Smarcel			case 13:	/* rnat_when */
712115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_when", b0, b1, parm1)
713115013Smarcel			    tspill[SBREG_RNAT] = (int) parm1;
714115013Smarcel			    break;
715115013Smarcel			case 14:	/* rnat_psprel */
716115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_psprel", b0, b1, parm1)
717115013Smarcel			    newrstate[SBREG_RNAT] = UWX_DISP_PSPREL(parm1 * 4);
718115013Smarcel			    break;
719115013Smarcel			case 15:	/* rnat_sprel */
720115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_sprel", b0, b1, parm1)
721115013Smarcel			    newrstate[SBREG_RNAT] = UWX_DISP_SPREL(parm1 * 4);
722115013Smarcel			    break;
723115013Smarcel			case 16:	/* priunat_when_gr */
724115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_when_gr", b0, b1, parm1)
725115013Smarcel			    tspill[SBREG_PRIUNAT] = (int) parm1;
726115013Smarcel			    break;
727115013Smarcel			case 17:	/* priunat_psprel */
728115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_psprel", b0, b1, parm1)
729115013Smarcel			    priunat_mem_rstate = UWX_DISP_PSPREL(parm1 * 4);
730115013Smarcel			    break;
731115013Smarcel			case 18:	/* priunat_sprel */
732115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_sprel", b0, b1, parm1)
733115013Smarcel			    priunat_mem_rstate = UWX_DISP_SPREL(parm1 * 4);
734115013Smarcel			    break;
735115013Smarcel			case 19:	/* priunat_when_mem */
736115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_when_mem", b0, b1, parm1)
737115013Smarcel			    t_priunat_mem = (int) parm1;
738115013Smarcel			    break;
739115013Smarcel			default:
740115013Smarcel			    TRACE_I_DECODE_PROLOGUE_2L("(P8) ??", b0, b1, parm1)
741115013Smarcel			    return UWX_ERR_BADUDESC;
742115013Smarcel		    }
743115013Smarcel		}
744115013Smarcel
745115013Smarcel		/* Format P9 (gr_gr) */
746115013Smarcel		else if (b0 == 0xf1) {
747115013Smarcel		    b1 = uwx_get_byte(bstream);
748115013Smarcel		    if (b1 < 0)
749115013Smarcel			return UWX_ERR_BADUDESC;
750115013Smarcel		    b2 = uwx_get_byte(bstream);
751115013Smarcel		    if (b2 < 0)
752115013Smarcel			return UWX_ERR_BADUDESC;
753115013Smarcel		    TRACE_I_DECODE_PROLOGUE_3("(P9) gr_gr", b0, b1, b2)
754115013Smarcel		    mask = b1 & 0x0f;
755115013Smarcel		    reg = b2 & 0x7f;
756115013Smarcel		    gr_gr_mask = mask;
757115013Smarcel		    for (i = 0; i < NSB_GR && mask != 0; i++) {
758115013Smarcel			if (mask & 0x01) {
759115013Smarcel			    newrstate[SBREG_GR + i] =
760115013Smarcel					UWX_DISP_REG(UWX_REG_GR(reg));
761115013Smarcel			    reg++;
762115013Smarcel			}
763115013Smarcel			mask = mask >> 1;
764115013Smarcel		    }
765115013Smarcel		}
766115013Smarcel
767115013Smarcel		/* Format X1 */
768115013Smarcel		else if (b0 == 0xf9) {
769115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(X1)", b0)
770115013Smarcel		    b1 = uwx_get_byte(bstream);
771115013Smarcel		    if (b1 < 0)
772115013Smarcel			return UWX_ERR_BADUDESC;
773115013Smarcel		    /* Don't support X-format descriptors yet */
774115013Smarcel		    return UWX_ERR_CANTUNWIND;
775115013Smarcel		}
776115013Smarcel
777115013Smarcel		/* Format X2 */
778115013Smarcel		else if (b0 == 0xfa) {
779115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(X2)", b0)
780115013Smarcel		    b1 = uwx_get_byte(bstream);
781115013Smarcel		    if (b1 < 0)
782115013Smarcel			return UWX_ERR_BADUDESC;
783115013Smarcel		    b2 = uwx_get_byte(bstream);
784115013Smarcel		    if (b2 < 0)
785115013Smarcel			return UWX_ERR_BADUDESC;
786115013Smarcel		    /* Don't support X-format descriptors yet */
787115013Smarcel		    return UWX_ERR_CANTUNWIND;
788115013Smarcel		}
789115013Smarcel
790115013Smarcel		/* Format X3 */
791115013Smarcel		else if (b0 == 0xfb) {
792115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(X3)", b0)
793115013Smarcel		    b1 = uwx_get_byte(bstream);
794115013Smarcel		    if (b1 < 0)
795115013Smarcel			return UWX_ERR_BADUDESC;
796115013Smarcel		    b2 = uwx_get_byte(bstream);
797115013Smarcel		    if (b2 < 0)
798115013Smarcel			return UWX_ERR_BADUDESC;
799115013Smarcel		    /* Don't support X-format descriptors yet */
800115013Smarcel		    return UWX_ERR_CANTUNWIND;
801115013Smarcel		}
802115013Smarcel
803115013Smarcel		/* Format X4 */
804115013Smarcel		else if (b0 == 0xfc) {
805115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(X4)", b0)
806115013Smarcel		    b1 = uwx_get_byte(bstream);
807115013Smarcel		    if (b1 < 0)
808115013Smarcel			return UWX_ERR_BADUDESC;
809115013Smarcel		    b2 = uwx_get_byte(bstream);
810115013Smarcel		    if (b2 < 0)
811115013Smarcel			return UWX_ERR_BADUDESC;
812115013Smarcel		    b3 = uwx_get_byte(bstream);
813115013Smarcel		    if (b3 < 0)
814115013Smarcel			return UWX_ERR_BADUDESC;
815115013Smarcel		    /* Don't support X-format descriptors yet */
816115013Smarcel		    return UWX_ERR_CANTUNWIND;
817115013Smarcel		}
818115013Smarcel
819115013Smarcel		/* Format P10 */
820115013Smarcel		else if (b0 == 0xff) {
821115013Smarcel		    b1 = uwx_get_byte(bstream);
822115013Smarcel		    if (b1 < 0)
823115013Smarcel			return UWX_ERR_BADUDESC;
824115013Smarcel		    b2 = uwx_get_byte(bstream);
825115013Smarcel		    if (b2 < 0)
826115013Smarcel			return UWX_ERR_BADUDESC;
827115013Smarcel		    TRACE_I_DECODE_PROLOGUE_3("(P10) abi", b0, b1, b2)
828115013Smarcel		    env->abi_context = (b1 << 8) | b2;
829115013Smarcel		    return UWX_ABI_FRAME;
830115013Smarcel		}
831115013Smarcel
832115013Smarcel		/* Invalid descriptor record */
833115013Smarcel		else {
834115013Smarcel		    TRACE_I_DECODE_PROLOGUE_1("(?)", b0)
835115013Smarcel		    return UWX_ERR_BADUDESC;
836115013Smarcel		}
837115013Smarcel		break;
838115013Smarcel	}
839115013Smarcel    }
840115013Smarcel
841115013Smarcel    /* Process the masks of spilled GRs, FRs, and BRs to */
842115013Smarcel    /* determine when and where each register was saved. */
843115013Smarcel
844115013Smarcel    fr_base = spill_base + 16 * uwx_count_ones(fr_mem_mask);
845115013Smarcel    br_base = fr_base + 8 * uwx_count_ones(br_mem_mask);
846115013Smarcel    gr_base = br_base + 8 * uwx_count_ones(gr_mem_mask);
847115013Smarcel    TRACE_I_DECODE_PROLOGUE_SPILL_BASE(spill_base)
848115013Smarcel    TRACE_I_DECODE_PROLOGUE_MASKS(gr_mem_mask, gr_gr_mask)
849115013Smarcel    TRACE_I_DECODE_PROLOGUE_NSPILL(ngr)
850115013Smarcel    for (i = 0; ngr > 0 && i <= NSB_GR; i++) {
851115013Smarcel	if (gr_mem_mask & 1) {
852115013Smarcel	    newrstate[SBREG_GR + i] = UWX_DISP_PSPREL(gr_base);
853115013Smarcel	    tspill[SBREG_GR + i] = 0;
854115013Smarcel	    gr_base -= 8;
855115013Smarcel	    ngr--;
856115013Smarcel	}
857115013Smarcel	else if (gr_gr_mask & 1) {
858115013Smarcel	    tspill[SBREG_GR + i] = 0;
859115013Smarcel	    ngr--;
860115013Smarcel	}
861115013Smarcel	gr_gr_mask = gr_gr_mask >> 1;
862115013Smarcel	gr_mem_mask = gr_mem_mask >> 1;
863115013Smarcel    }
864115013Smarcel    for (i = 0; nbr > 0 && i <= NSB_BR; i++) {
865115013Smarcel	if (br_mem_mask & 1) {
866115013Smarcel	    newrstate[SBREG_BR + i] = UWX_DISP_PSPREL(br_base);
867115013Smarcel	    tspill[SBREG_BR + i] = 0;
868115013Smarcel	    br_base -= 8;
869115013Smarcel	    nbr--;
870115013Smarcel	}
871115013Smarcel	else if (br_gr_mask & 1) {
872115013Smarcel	    tspill[SBREG_BR + i] = 0;
873115013Smarcel	    nbr--;
874115013Smarcel	}
875115013Smarcel	br_gr_mask = br_gr_mask >> 1;
876115013Smarcel	br_mem_mask = br_mem_mask >> 1;
877115013Smarcel    }
878115013Smarcel    for (i = 0; nfr > 0 && i <= NSB_FR; i++) {
879115013Smarcel	if (fr_mem_mask & 1) {
880115013Smarcel	    newrstate[SBREG_FR + i] = UWX_DISP_PSPREL(fr_base);
881115013Smarcel	    tspill[SBREG_FR + i] = 0;
882120925Smarcel	    fr_base -= 16;
883115013Smarcel	    nfr--;
884115013Smarcel	}
885115013Smarcel	fr_mem_mask = fr_mem_mask >> 1;
886115013Smarcel    }
887115013Smarcel
888115013Smarcel    /* Update the scoreboard. */
889115013Smarcel
890115013Smarcel    for (i = 0; i < env->nsbreg; i++) {
891121642Smarcel	if (ip_slot >= rhdr->rlen || ip_slot > tspill[i])
892115013Smarcel	    scoreboard->rstate[i] = newrstate[i];
893115013Smarcel    }
894115013Smarcel    if (priunat_mem_rstate != UWX_DISP_NONE && ip_slot > t_priunat_mem)
895115013Smarcel	scoreboard->rstate[SBREG_PRIUNAT] = priunat_mem_rstate;
896115013Smarcel
897115013Smarcel    return UWX_OK;
898115013Smarcel}
899115013Smarcel
900115013Smarcelint uwx_count_ones(unsigned int mask)
901115013Smarcel{
902115013Smarcel    mask = (mask & 0x55555555) + ((mask & 0xaaaaaaaa) >> 1);
903115013Smarcel    mask = (mask & 0x33333333) + ((mask & 0xcccccccc) >> 2);
904115013Smarcel    mask = (mask & 0x0f0f0f0f) + ((mask & 0xf0f0f0f0) >> 4);
905115013Smarcel    mask = (mask & 0x00ff00ff) + ((mask & 0xff00ff00) >> 8);
906115013Smarcel    return (mask & 0x0000ffff) + ((mask & 0xffff0000) >> 16);
907115013Smarcel}
908115013Smarcel
909115013Smarcel/* uwx_decode_body: Decodes a body region */
910115013Smarcel
911115013Smarcelint uwx_decode_body(
912115013Smarcel    struct uwx_env *env,
913115013Smarcel    struct uwx_bstream *bstream,
914115013Smarcel    struct uwx_scoreboard *scoreboard,
915115013Smarcel    struct uwx_rhdr *rhdr,
916115013Smarcel    int ip_slot)
917115013Smarcel{
918115013Smarcel    int status;
919115013Smarcel    int b0;
920115013Smarcel    int b1;
921115013Smarcel    int b2;
922115013Smarcel    int b3;
923115013Smarcel    int label;
924115013Smarcel    int ecount;
925115013Smarcel    int i;
926115013Smarcel    uint64_t parm1;
927115013Smarcel    uint64_t parm2;
928115013Smarcel    uint64_t newrstate[NSBREG];
929115013Smarcel    int tspill[NSBREG];
930115013Smarcel    int t_sp_restore;
931115013Smarcel
932115013Smarcel    /* Initialize an array of register states from the current */
933115013Smarcel    /* scoreboard, along with a parallel array of spill times. */
934115013Smarcel    /* We use this as a temporary scoreboard, then update the */
935115013Smarcel    /* real scoreboard at the end of the procedure. */
936115013Smarcel    /* We initialize the spill time to (rhdr.rlen - 1) so that */
937115013Smarcel    /* spills without a "when" descriptor will take effect */
938115013Smarcel    /* at the end of the prologue region. */
939115013Smarcel    /* (Boundary condition: all actions in a zero-length prologue */
940115013Smarcel    /* will appear to have happened in the instruction slot */
941115013Smarcel    /* immediately preceding the prologue.) */
942115013Smarcel
943115013Smarcel    for (i = 0; i < env->nsbreg; i++) {
944115013Smarcel	newrstate[i] = scoreboard->rstate[i];
945115013Smarcel	tspill[i] = rhdr->rlen - 1;
946115013Smarcel    }
947115013Smarcel    t_sp_restore = rhdr->rlen - 1;
948115013Smarcel
949115013Smarcel    /* Read body descriptor records until */
950115013Smarcel    /* we hit another region header. */
951115013Smarcel
952115013Smarcel    for (;;) {
953115013Smarcel
954115013Smarcel	b0 = uwx_get_byte(bstream);
955115013Smarcel
956115013Smarcel	if (b0 < 0x80) {
957115013Smarcel	    /* Return the last byte read to the byte stream, since it's */
958115013Smarcel	    /* really the first byte of the next region header record. */
959115013Smarcel	    if (b0 >= 0)
960115013Smarcel		(void) uwx_unget_byte(bstream, b0);
961115013Smarcel	    break;
962115013Smarcel	}
963115013Smarcel
964115013Smarcel	/* Format B1 (label_state) */
965115013Smarcel	if (b0 < 0xa0) {
966115013Smarcel	    TRACE_I_DECODE_BODY_1("(B1) label_state", b0)
967115013Smarcel	    label = b0 & 0x1f;
968115013Smarcel	    status = uwx_label_scoreboard(env, scoreboard, label);
969115013Smarcel	    if (status != UWX_OK)
970115013Smarcel		return (status);
971115013Smarcel	}
972115013Smarcel
973115013Smarcel	/* Format B1 (copy_state)  */
974115013Smarcel	else if (b0 < 0xc0) {
975115013Smarcel	    TRACE_I_DECODE_BODY_1("(B1) copy_state", b0)
976115013Smarcel	    label = b0 & 0x1f;
977115013Smarcel	    status = uwx_copy_scoreboard(env, scoreboard, label);
978115013Smarcel	    if (status != UWX_OK)
979115013Smarcel		return (status);
980115013Smarcel	    for (i = 0; i < env->nsbreg; i++) {
981115013Smarcel		newrstate[i] = scoreboard->rstate[i];
982115013Smarcel		tspill[i] = rhdr->rlen;
983115013Smarcel	    }
984115013Smarcel	}
985115013Smarcel
986115013Smarcel	/* Format B2 (epilogue) */
987115013Smarcel	else if (b0 < 0xe0) {
988115013Smarcel	    ecount = b0 & 0x1f;
989115013Smarcel	    status = uwx_get_uleb128(bstream, &parm1);
990115013Smarcel	    if (status != 0)
991115013Smarcel		return UWX_ERR_BADUDESC;
992115013Smarcel	    TRACE_I_DECODE_BODY_1L("(B2) epilogue", b0, parm1)
993115013Smarcel	    rhdr->ecount = ecount + 1;
994115013Smarcel	    t_sp_restore = rhdr->rlen - (unsigned int) parm1;
995115013Smarcel	}
996115013Smarcel
997115013Smarcel	/* Format B3 (epilogue) */
998115013Smarcel	else if (b0 == 0xe0) {
999115013Smarcel	    status = uwx_get_uleb128(bstream, &parm1);
1000115013Smarcel	    if (status != 0)
1001115013Smarcel		return UWX_ERR_BADUDESC;
1002115013Smarcel	    status = uwx_get_uleb128(bstream, &parm2);
1003115013Smarcel	    if (status != 0)
1004115013Smarcel		return UWX_ERR_BADUDESC;
1005115013Smarcel	    TRACE_I_DECODE_BODY_1LL("(B3) epilogue", b0, parm1, parm2)
1006115013Smarcel	    t_sp_restore = rhdr->rlen - (unsigned int) parm1;
1007115013Smarcel	    rhdr->ecount = (unsigned int) parm2 + 1;
1008115013Smarcel	}
1009115013Smarcel
1010115013Smarcel	/* Format B4 (label_state) */
1011115013Smarcel	else if (b0 == 0xf0) {
1012115013Smarcel	    status = uwx_get_uleb128(bstream, &parm1);
1013115013Smarcel	    if (status != 0)
1014115013Smarcel		return UWX_ERR_BADUDESC;
1015115013Smarcel	    TRACE_I_DECODE_BODY_1L("(B4) label_state", b0, parm1)
1016115013Smarcel	    label = (int) parm1;
1017115013Smarcel	    status = uwx_label_scoreboard(env, scoreboard, label);
1018115013Smarcel	    if (status != UWX_OK)
1019115013Smarcel		return (status);
1020115013Smarcel	}
1021115013Smarcel
1022115013Smarcel	/* Format B4 (copy_state) */
1023115013Smarcel	else if (b0 == 0xf8) {
1024115013Smarcel	    status = uwx_get_uleb128(bstream, &parm1);
1025115013Smarcel	    if (status != 0)
1026115013Smarcel		return UWX_ERR_BADUDESC;
1027115013Smarcel	    TRACE_I_DECODE_BODY_1L("(B4) copy_state", b0, parm1)
1028115013Smarcel	    label = (int) parm1;
1029115013Smarcel	    status = uwx_copy_scoreboard(env, scoreboard, label);
1030115013Smarcel	    if (status != UWX_OK)
1031115013Smarcel		return (status);
1032115013Smarcel	    for (i = 0; i < env->nsbreg; i++) {
1033115013Smarcel		newrstate[i] = scoreboard->rstate[i];
1034115013Smarcel		tspill[i] = rhdr->rlen;
1035115013Smarcel	    }
1036115013Smarcel	}
1037115013Smarcel
1038115013Smarcel	/* Format X1 */
1039115013Smarcel	else if (b0 == 0xf9) {
1040115013Smarcel	    TRACE_I_DECODE_BODY_1("(X1)", b0)
1041115013Smarcel	    b1 = uwx_get_byte(bstream);
1042115013Smarcel	    if (b1 < 0)
1043115013Smarcel		return UWX_ERR_BADUDESC;
1044115013Smarcel	    /* Don't support X-format descriptors yet */
1045115013Smarcel	    return UWX_ERR_CANTUNWIND;
1046115013Smarcel	}
1047115013Smarcel
1048115013Smarcel	/* Format X2 */
1049115013Smarcel	else if (b0 == 0xfa) {
1050115013Smarcel	    TRACE_I_DECODE_BODY_1("(X2)", b0)
1051115013Smarcel	    b1 = uwx_get_byte(bstream);
1052115013Smarcel	    if (b1 < 0)
1053115013Smarcel		return UWX_ERR_BADUDESC;
1054115013Smarcel	    b2 = uwx_get_byte(bstream);
1055115013Smarcel	    if (b2 < 0)
1056115013Smarcel		return UWX_ERR_BADUDESC;
1057115013Smarcel	    /* Don't support X-format descriptors yet */
1058115013Smarcel	    return UWX_ERR_CANTUNWIND;
1059115013Smarcel	}
1060115013Smarcel
1061115013Smarcel	/* Format X3 */
1062115013Smarcel	else if (b0 == 0xfb) {
1063115013Smarcel	    TRACE_I_DECODE_BODY_1("(X3)", b0)
1064115013Smarcel	    b1 = uwx_get_byte(bstream);
1065115013Smarcel	    if (b1 < 0)
1066115013Smarcel		return UWX_ERR_BADUDESC;
1067115013Smarcel	    b2 = uwx_get_byte(bstream);
1068115013Smarcel	    if (b2 < 0)
1069115013Smarcel		return UWX_ERR_BADUDESC;
1070115013Smarcel	    /* Don't support X-format descriptors yet */
1071115013Smarcel	    return UWX_ERR_CANTUNWIND;
1072115013Smarcel	}
1073115013Smarcel
1074115013Smarcel	/* Format X4 */
1075115013Smarcel	else if (b0 == 0xfc) {
1076115013Smarcel	    TRACE_I_DECODE_BODY_1("(X4)", b0)
1077115013Smarcel	    b1 = uwx_get_byte(bstream);
1078115013Smarcel	    if (b1 < 0)
1079115013Smarcel		return UWX_ERR_BADUDESC;
1080115013Smarcel	    b2 = uwx_get_byte(bstream);
1081115013Smarcel	    if (b2 < 0)
1082115013Smarcel		return UWX_ERR_BADUDESC;
1083115013Smarcel	    b3 = uwx_get_byte(bstream);
1084115013Smarcel	    if (b3 < 0)
1085115013Smarcel		return UWX_ERR_BADUDESC;
1086115013Smarcel	    /* Don't support X-format descriptors yet */
1087115013Smarcel	    return UWX_ERR_CANTUNWIND;
1088115013Smarcel	}
1089115013Smarcel
1090115013Smarcel	/* Invalid descriptor record */
1091115013Smarcel	else {
1092115013Smarcel	    TRACE_I_DECODE_BODY_1("(?)", b0)
1093115013Smarcel	    return UWX_ERR_BADUDESC;
1094115013Smarcel	}
1095115013Smarcel    }
1096115013Smarcel
1097115013Smarcel    /* Update the scoreboard. */
1098115013Smarcel
1099115013Smarcel    for (i = 0; i < env->nsbreg; i++) {
1100115013Smarcel	if (ip_slot > tspill[i])
1101115013Smarcel	    scoreboard->rstate[i] = newrstate[i];
1102115013Smarcel    }
1103115013Smarcel
1104115013Smarcel    /* If we've passed the point in the epilogue where sp */
1105115013Smarcel    /* is restored, update the scoreboard entry for PSP */
1106115013Smarcel    /* and reset any entries for registers saved in memory. */
1107115013Smarcel
1108160157Smarcel    if (rhdr->ecount > 0 && ip_slot > t_sp_restore) {
1109115013Smarcel	scoreboard->rstate[SBREG_PSP] = UWX_DISP_SPPLUS(0);
1110115013Smarcel	for (i = 0; i < env->nsbreg; i++) {
1111115013Smarcel	    if (UWX_GET_DISP_CODE(scoreboard->rstate[i]) == UWX_DISP_SPREL(0) ||
1112115013Smarcel		UWX_GET_DISP_CODE(scoreboard->rstate[i]) == UWX_DISP_PSPREL(0))
1113115013Smarcel		scoreboard->rstate[i] = UWX_DISP_NONE;
1114115013Smarcel	}
1115115013Smarcel    }
1116115013Smarcel
1117115013Smarcel    return UWX_OK;
1118115013Smarcel}
1119115013Smarcel
1120