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