summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ia64/libuwx/src/uwx_uinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ia64/libuwx/src/uwx_uinfo.c')
-rw-r--r--sys/contrib/ia64/libuwx/src/uwx_uinfo.c1119
1 files changed, 1119 insertions, 0 deletions
diff --git a/sys/contrib/ia64/libuwx/src/uwx_uinfo.c b/sys/contrib/ia64/libuwx/src/uwx_uinfo.c
new file mode 100644
index 0000000..5f63b7e
--- /dev/null
+++ b/sys/contrib/ia64/libuwx/src/uwx_uinfo.c
@@ -0,0 +1,1119 @@
+/*
+Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "uwx_env.h"
+#include "uwx_uinfo.h"
+#include "uwx_utable.h"
+#include "uwx_scoreboard.h"
+#include "uwx_bstream.h"
+#include "uwx_trace.h"
+#include "uwx_swap.h"
+
+int uwx_count_ones(unsigned int mask);
+
+/*
+ * uwx_uinfo.c
+ *
+ * This file contains the routines for reading and decoding
+ * the unwind information block.
+ *
+ * The main entry point, uwx_decode_uinfo(), is given a pointer
+ * to an unwind table entry and a pointer (passed by reference)
+ * to be filled in with a pointer to an update vector. It will
+ * read and decode the unwind descriptors contained in the
+ * unwind information block, then build the register state array,
+ * which describes the actions necessary to step from the current
+ * frame to the previous one.
+ */
+
+#define COPYIN_UINFO_4(dest, src) \
+ (env->remote? \
+ (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
+ WORDSZ, env->cb_token) : \
+ (*(uint32_t *)(intptr_t)(dest) = *(uint32_t *)(intptr_t)(src), WORDSZ) )
+
+#define COPYIN_UINFO_8(dest, src) \
+ (env->remote? \
+ (*env->copyin)(UWX_COPYIN_UINFO, (dest), (src), \
+ DWORDSZ, env->cb_token) : \
+ (*(uint64_t *)(intptr_t)(dest) = *(uint64_t *)(intptr_t)(src), DWORDSZ) )
+
+
+/* uwx_default_rstate: Returns the default register state for a leaf routine */
+
+int uwx_default_rstate(struct uwx_env *env, uint64_t **rstatep)
+{
+ struct uwx_scoreboard *sb;
+
+ sb = uwx_init_scoreboards(env);
+ *rstatep = sb->rstate;
+ return UWX_OK;
+}
+
+
+/* uwx_decode_uinfo: Decodes unwind info region */
+
+int uwx_decode_uinfo(
+ struct uwx_env *env,
+ struct uwx_utable_entry *uentry,
+ uint64_t **rstatep)
+{
+ uint64_t uinfohdr;
+ unsigned int ulen;
+ int len;
+ struct uwx_bstream bstream;
+ struct uwx_scoreboard *scoreboard;
+ int ip_slot;
+ int cur_slot;
+ int status;
+ struct uwx_rhdr rhdr;
+
+ /* Remember the offset from the start of the function */
+ /* to the current IP. This helps the client find */
+ /* the symbolic information. */
+
+ env->function_offset = env->remapped_ip - uentry->code_start;
+
+ /* Read the unwind info header using the copyin callback. */
+ /* (If we're reading a 32-bit unwind table, we need to */
+ /* read the header as two 32-bit pieces to preserve the */
+ /* guarantee that we always call copyin for aligned */
+ /* 4-byte or 8-byte chunks.) */
+ /* Then compute the length of the unwind descriptor */
+ /* region and initialize a byte stream to read it. */
+
+ if (uentry->unwind_flags & UNWIND_TBL_32BIT) {
+ len = COPYIN_UINFO_4((char *)&uinfohdr, uentry->unwind_info);
+ len += COPYIN_UINFO_4((char *)&uinfohdr + WORDSZ,
+ uentry->unwind_info + WORDSZ);
+ }
+ else
+ len = COPYIN_UINFO_8((char *)&uinfohdr, uentry->unwind_info);
+ if (len != DWORDSZ)
+ return UWX_ERR_COPYIN_UINFO;
+ if (env->byte_swap)
+ uwx_swap8(&uinfohdr);
+ if (uentry->unwind_flags & UNWIND_TBL_32BIT)
+ ulen = UNW_LENGTH(uinfohdr) * WORDSZ;
+ else
+ ulen = UNW_LENGTH(uinfohdr) * DWORDSZ;
+ uwx_init_bstream(&bstream, env,
+ uentry->unwind_info + DWORDSZ, ulen, UWX_COPYIN_UINFO);
+
+ /* Save the header and a pointer to the personality routine ptr */
+ /* for later use in exception handling. */
+
+ env->uinfo_hdr = uinfohdr;
+ env->uinfo_end = uentry->unwind_info + DWORDSZ + ulen;
+
+ TRACE_R_UIB(uentry, ulen)
+
+ /* Create an initial scoreboard for tracking the unwind state. */
+
+ scoreboard = uwx_init_scoreboards(env);
+
+ /* Prepare to read and decode the unwind regions described */
+ /* by the unwind info block. Find the target "ip" slot */
+ /* relative to the beginning of the region. The lower 4 bits */
+ /* of the actual IP encode the slot number within a bundle. */
+
+ cur_slot = 0;
+ ip_slot = (int) ((env->context.special[UWX_REG_IP] & ~0x0fLL)
+ - uentry->code_start)
+ / BUNDLESZ * SLOTSPERBUNDLE
+ + (unsigned int) (env->context.special[UWX_REG_IP] & 0x0f);
+
+ /* Loop over the regions in the unwind info block. */
+
+ for (;;) {
+
+ /* Decode the next region header. */
+ /* We have an error if we reach the end of the info block, */
+ /* since we should have found our target ip slot by then. */
+ /* We also have an error if the next byte isn't a region */
+ /* header record. */
+
+ status = uwx_decode_rhdr(env, &bstream, &rhdr);
+ if (status != UWX_OK)
+ return status;
+
+ /* If a prologue region, get a new scoreboard, pushing */
+ /* the previous one onto the prologue stack. Then read */
+ /* and decode the prologue region records. */
+
+ if (rhdr.is_prologue) {
+ scoreboard = uwx_new_scoreboard(env, scoreboard);
+ if (scoreboard == 0)
+ return UWX_ERR_NOMEM;
+ status = uwx_decode_prologue(env, &bstream,
+ scoreboard, &rhdr, ip_slot);
+ }
+
+ /* If a body region, read and decode the body region */
+ /* records. If the body has an epilogue count, */
+ /* uwx_decode_body will note that in the region header */
+ /* record for use at the bottom of the loop. */
+
+ else {
+ status = uwx_decode_body(env, &bstream, scoreboard, &rhdr, ip_slot);
+ }
+
+ if (status != UWX_OK)
+ return status;
+
+ TRACE_R_DUMP_SB(scoreboard, rhdr, cur_slot, ip_slot)
+
+ /* If the target ip slot is within this region, we're done. */
+ /* Return the scoreboard's register state array. */
+
+ if (ip_slot < rhdr.rlen) {
+ *rstatep = scoreboard->rstate;
+ return UWX_OK;
+ }
+
+ /* Otherwise, update the current ip slot, pop the */
+ /* scoreboard stack based on the epilogue count, */
+ /* and loop back around for the next region. */
+
+ cur_slot += rhdr.rlen;
+ ip_slot -= rhdr.rlen;
+ if (rhdr.ecount > 0) {
+ scoreboard = uwx_pop_scoreboards(env, scoreboard, rhdr.ecount);
+ if (scoreboard == 0)
+ return UWX_ERR_PROLOG_UF;
+ }
+ }
+ /*NOTREACHED*/
+}
+
+
+/* uwx_decode_rhdr: Decodes a region header record */
+
+int uwx_decode_rhdr(
+ struct uwx_env *env,
+ struct uwx_bstream *bstream,
+ struct uwx_rhdr *rhdr)
+{
+ int b0;
+ int b1;
+ uint64_t val;
+ int status;
+
+ /* Get the first byte of the next descriptor record. */
+ b0 = uwx_get_byte(bstream);
+ if (b0 < 0)
+ return UWX_ERR_NOUDESC;
+
+ /* Initialize region header record. */
+
+ rhdr->is_prologue = 0;
+ rhdr->rlen = 0;
+ rhdr->mask = 0;
+ rhdr->grsave = 0;
+ rhdr->ecount = 0;
+
+ /* Format R1 */
+
+ if (b0 < 0x40) {
+ if ((b0 & 0x20) == 0) {
+ TRACE_I_DECODE_RHDR_1("(R1) prologue", b0)
+ rhdr->is_prologue = 1;
+ }
+ else {
+ TRACE_I_DECODE_RHDR_1("(R1) body", b0)
+ }
+ rhdr->rlen = b0 & 0x1f;
+ }
+
+ /* Format R2 */
+
+ else if (b0 < 0x60) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ status = uwx_get_uleb128(bstream, &val);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_RHDR_2L("(R2) prologue_gr", b0, b1, val)
+ rhdr->is_prologue = 1;
+ rhdr->rlen = (unsigned int) val;
+ rhdr->mask = ((b0 & 0x07) << 1) | (b1 >> 7);
+ rhdr->grsave = b1 & 0x7f;
+ }
+
+ /* Format R3 */
+
+ else if (b0 < 0x80) {
+ status = uwx_get_uleb128(bstream, &val);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ if ((b0 & 0x03) == 0) {
+ TRACE_I_DECODE_RHDR_1L("(R3) prologue", b0, val)
+ rhdr->is_prologue = 1;
+ }
+ else {
+ TRACE_I_DECODE_RHDR_1L("(R3) body", b0, val)
+ }
+ rhdr->rlen = (unsigned int) val;
+ }
+
+ /* Otherwise, not a region header record. */
+
+ else {
+ TRACE_I_DECODE_RHDR_1("(?)", b0)
+ return UWX_ERR_BADUDESC;
+ }
+
+ return UWX_OK;
+}
+
+
+/* uwx_decode_prologue: Decodes a prologue region */
+
+int uwx_decode_prologue(
+ struct uwx_env *env,
+ struct uwx_bstream *bstream,
+ struct uwx_scoreboard *scoreboard,
+ struct uwx_rhdr *rhdr,
+ int ip_slot)
+{
+ int status;
+ int reg;
+ int mask;
+ int b0;
+ int b1;
+ int b2;
+ int b3;
+ int r;
+ int t;
+ int i;
+ uint64_t parm1;
+ uint64_t parm2;
+ uint64_t newrstate[NSBREG];
+ int tspill[NSBREG];
+ int priunat_mem_rstate;
+ int t_priunat_mem;
+ unsigned int gr_mem_mask;
+ unsigned int br_mem_mask;
+ unsigned int fr_mem_mask;
+ unsigned int gr_gr_mask;
+ unsigned int br_gr_mask;
+ int ngr;
+ int nbr;
+ int nfr;
+ unsigned int spill_base;
+ unsigned int gr_base;
+ unsigned int br_base;
+ unsigned int fr_base;
+
+ /* Initialize an array of register states from the current */
+ /* scoreboard, along with a parallel array of spill times. */
+ /* We use this as a temporary scoreboard, then update the */
+ /* real scoreboard at the end of the procedure. */
+ /* We initialize the spill time to (rhdr.rlen - 1) so that */
+ /* spills without a "when" descriptor will take effect */
+ /* at the end of the prologue region. */
+ /* (Boundary condition: all actions in a zero-length prologue */
+ /* will appear to have happened in the instruction slot */
+ /* immediately preceding the prologue.) */
+
+ for (i = 0; i < env->nsbreg; i++) {
+ newrstate[i] = scoreboard->rstate[i];
+ tspill[i] = rhdr->rlen - 1;
+ }
+ priunat_mem_rstate = UWX_DISP_NONE;
+ t_priunat_mem = rhdr->rlen - 1;
+
+ fr_mem_mask = 0;
+ gr_mem_mask = 0;
+ br_mem_mask = 0;
+ gr_gr_mask = 0;
+ br_gr_mask = 0;
+ nfr = 127;
+ ngr = 127;
+ nbr = 127;
+ spill_base = 0;
+
+ /* If prologue_gr header record supplied mask and grsave, */
+ /* record these in the scoreboard. */
+
+ reg = rhdr->grsave;
+ mask = rhdr->mask;
+ if (mask & 0x8) {
+ newrstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_GR(reg));
+ reg++;
+ }
+ if (mask & 0x4) {
+ newrstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_GR(reg));
+ reg++;
+ }
+ if (mask & 0x2) {
+ newrstate[SBREG_PSP] = UWX_DISP_REG(UWX_REG_GR(reg));
+ reg++;
+ }
+ if (mask & 0x1) {
+ newrstate[SBREG_PREDS] = UWX_DISP_REG(UWX_REG_GR(reg));
+ reg++;
+ }
+
+ /* Read prologue descriptor records until */
+ /* we hit another region header. */
+
+ for (;;) {
+
+ b0 = uwx_get_byte(bstream);
+
+ if (b0 < 0x80) {
+ /* Return the last byte read to the byte stream, since it's */
+ /* really the first byte of the next region header record. */
+ if (b0 >= 0)
+ (void) uwx_unget_byte(bstream, b0);
+ break;
+ }
+
+ switch ((b0 & 0x70) >> 4) {
+
+ case 0: /* 1000 xxxx */
+ case 1: /* 1001 xxxx */
+ /* Format P1 (br_mem) */
+ TRACE_I_DECODE_PROLOGUE_1("(P1) br_mem", b0)
+ br_mem_mask = b0 & 0x1f;
+ break;
+
+ case 2: /* 1010 xxxx */
+ /* Format P2 (br_gr) */
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_PROLOGUE_2("(P2) br_gr", b0, b1)
+ mask = ((b0 & 0x0f) << 1) | (b1 >> 7);
+ reg = b1 & 0x7f;
+ br_gr_mask = mask;
+ for (i = 0; i < NSB_BR && mask != 0; i++) {
+ if (mask & 0x01) {
+ newrstate[SBREG_BR + i] = UWX_DISP_REG(UWX_REG_GR(reg));
+ reg++;
+ }
+ mask = mask >> 1;
+ }
+ break;
+
+ case 3: /* 1011 xxxx */
+ /* Format P3 */
+ if (b0 < 0xb8) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ r = ((b0 & 0x7) << 1) | (b1 >> 7);
+ reg = b1 & 0x7f;
+ switch (r) {
+ case 0: /* psp_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) psp_gr", b0, b1)
+ newrstate[SBREG_PSP] = UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 1: /* rp_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) rp_gr", b0, b1)
+ newrstate[SBREG_RP] = UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 2: /* pfs_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) pfs_gr", b0, b1)
+ newrstate[SBREG_PFS] = UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 3: /* preds_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) preds_gr", b0, b1)
+ newrstate[SBREG_PREDS] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 4: /* unat_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) unat_gr", b0, b1)
+ newrstate[SBREG_UNAT] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 5: /* lc_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) lc_gr", b0, b1)
+ newrstate[SBREG_LC] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 6: /* rp_br */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) rp_br", b0, b1)
+ scoreboard->rstate[SBREG_RP] =
+ UWX_DISP_REG(UWX_REG_BR(reg));
+ if (newrstate[SBREG_RP] ==
+ UWX_DISP_REG(UWX_REG_BR(0)))
+ newrstate[SBREG_RP] =
+ UWX_DISP_REG(UWX_REG_BR(reg));
+ break;
+ case 7: /* rnat_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) rnat_gr", b0, b1)
+ newrstate[SBREG_RNAT] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 8: /* bsp_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) bsp_gr", b0, b1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 9: /* bspstore_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) bspstore_gr", b0, b1)
+ /* Don't track BSPSTORE yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 10: /* fpsr_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) fpsr_gr", b0, b1)
+ newrstate[SBREG_FPSR] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ case 11: /* priunat_gr */
+ TRACE_I_DECODE_PROLOGUE_2("(P3) priunat_gr", b0, b1)
+ newrstate[SBREG_PRIUNAT] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ break;
+ default:
+ TRACE_I_DECODE_PROLOGUE_2("(P3) ??", b0, b1)
+ return UWX_ERR_BADUDESC;
+ }
+ }
+
+ /* Format P4 (spill_mask) */
+ else if (b0 == 0xb8) {
+ TRACE_I_DECODE_PROLOGUE_1("(P4) spill_mask", b0)
+ /* The spill_mask descriptor is followed by */
+ /* an imask field whose length is determined */
+ /* by the region length: there are two mask */
+ /* bits per instruction slot in the region. */
+ /* We decode these bits two at a time, counting */
+ /* the number of FRs, GRs, and BRs that are */
+ /* saved up to the slot of interest. Other */
+ /* descriptors describe which sets of these */
+ /* registers are spilled, and we put those */
+ /* two pieces of information together at the */
+ /* end of the main loop. */
+ t = 0;
+ nfr = 0;
+ ngr = 0;
+ nbr = 0;
+ while (t < rhdr->rlen) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ for (i = 0; i < 4 && (t + i) < ip_slot; i++) {
+ switch (b1 & 0xc0) {
+ case 0x00: break;
+ case 0x40: nfr++; break;
+ case 0x80: ngr++; break;
+ case 0xc0: nbr++; break;
+ }
+ b1 = b1 << 2;
+ }
+ t += 4;
+ }
+ }
+
+ /* Format P5 (frgr_mem) */
+ else if (b0 == 0xb9) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ b3 = uwx_get_byte(bstream);
+ if (b3 < 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_PROLOGUE_4("(P5) frgr_mem", b0, b1, b2, b3)
+ gr_mem_mask = b1 >> 4;
+ fr_mem_mask = ((b1 & 0x0f) << 16) | (b2 << 8) | b3;
+ }
+
+ /* Invalid descriptor record */
+ else {
+ TRACE_I_DECODE_PROLOGUE_1("(?)", b0)
+ return UWX_ERR_BADUDESC;
+ }
+
+ break;
+
+ case 4: /* 1100 xxxx */
+ /* Format P6 (fr_mem) */
+ TRACE_I_DECODE_PROLOGUE_1("(P6) fr_mem", b0)
+ fr_mem_mask = b0 & 0x0f;
+ break;
+
+ case 5: /* 1101 xxxx */
+ /* Format P6 (gr_mem) */
+ TRACE_I_DECODE_PROLOGUE_1("(P6) gr_mem", b0)
+ gr_mem_mask = b0 & 0x0f;
+ break;
+
+ case 6: /* 1110 xxxx */
+ /* Format P7 */
+ r = b0 & 0xf;
+ status = uwx_get_uleb128(bstream, &parm1);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ switch (r) {
+ case 0: /* mem_stack_f */
+ status = uwx_get_uleb128(bstream, &parm2);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_PROLOGUE_1LL("(P7) mem_stack_f", b0, parm1, parm2)
+ newrstate[SBREG_PSP] = UWX_DISP_SPPLUS(parm2 * 16);
+ tspill[SBREG_PSP] = (int) parm1;
+ break;
+ case 1: /* mem_stack_v */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) mem_stack_v", b0, parm1)
+ tspill[SBREG_PSP] = (int) parm1;
+ break;
+ case 2: /* spill_base */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) spill_base", b0, parm1)
+ spill_base = 4 * (unsigned int) parm1;
+ break;
+ case 3: /* psp_sprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) psp_sprel", b0, parm1)
+ newrstate[SBREG_PSP] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 4: /* rp_when */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) rp_when", b0, parm1)
+ tspill[SBREG_RP] = (int) parm1;
+ break;
+ case 5: /* rp_psprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) rp_psprel", b0, parm1)
+ newrstate[SBREG_RP] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 6: /* pfs_when */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) pfs_when", b0, parm1)
+ tspill[SBREG_PFS] = (int) parm1;
+ break;
+ case 7: /* pfs_psprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) pfs_psprel", b0, parm1)
+ newrstate[SBREG_PFS] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 8: /* preds_when */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) preds_when", b0, parm1)
+ tspill[SBREG_PREDS] = (int) parm1;
+ break;
+ case 9: /* preds_psprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) preds_psprel", b0, parm1)
+ newrstate[SBREG_PREDS] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 10: /* lc_when */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) lc_when", b0, parm1)
+ tspill[SBREG_LC] = (int) parm1;
+ break;
+ case 11: /* lc_psprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) lc_psprel", b0, parm1)
+ newrstate[SBREG_LC] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 12: /* unat_when */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) unat_when", b0, parm1)
+ tspill[SBREG_UNAT] = (int) parm1;
+ break;
+ case 13: /* unat_psprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) unat_psprel", b0, parm1)
+ newrstate[SBREG_UNAT] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 14: /* fpsr_when */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) fpsr_when", b0, parm1)
+ tspill[SBREG_FPSR] = (int) parm1;
+ break;
+ case 15: /* fpsr_psprel */
+ TRACE_I_DECODE_PROLOGUE_1L("(P7) fpsr_psprel", b0, parm1)
+ newrstate[SBREG_FPSR] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ }
+ break;
+
+ case 7: /* 1111 xxxx */
+ /* Format P8 */
+ if (b0 == 0xf0) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ status = uwx_get_uleb128(bstream, &parm1);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ switch (b1) {
+ case 1: /* rp_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) rp_sprel", b0, b1, parm1)
+ newrstate[SBREG_RP] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 2: /* pfs_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) pfs_sprel", b0, b1, parm1)
+ newrstate[SBREG_PFS] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 3: /* preds_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) preds_sprel", b0, b1, parm1)
+ newrstate[SBREG_PREDS] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 4: /* lc_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) lc_sprel", b0, b1, parm1)
+ newrstate[SBREG_LC] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 5: /* unat_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) unat_sprel", b0, b1, parm1)
+ newrstate[SBREG_UNAT] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 6: /* fpsr_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) fpsr_sprel", b0, b1, parm1)
+ newrstate[SBREG_FPSR] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 7: /* bsp_when */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_when", b0, b1, parm1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 8: /* bsp_psprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_psprel", b0, b1, parm1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 9: /* bsp_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) bsp_sprel", b0, b1, parm1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 10: /* bspstore_when */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_when", b0, b1, parm1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 11: /* bspstore_psprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_psprel", b0, b1, parm1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 12: /* bspstore_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) bspstore_sprel", b0, b1, parm1)
+ /* Don't track BSP yet */
+ return UWX_ERR_CANTUNWIND;
+ /* break; */
+ case 13: /* rnat_when */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_when", b0, b1, parm1)
+ tspill[SBREG_RNAT] = (int) parm1;
+ break;
+ case 14: /* rnat_psprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_psprel", b0, b1, parm1)
+ newrstate[SBREG_RNAT] = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 15: /* rnat_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) rnat_sprel", b0, b1, parm1)
+ newrstate[SBREG_RNAT] = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 16: /* priunat_when_gr */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_when_gr", b0, b1, parm1)
+ tspill[SBREG_PRIUNAT] = (int) parm1;
+ break;
+ case 17: /* priunat_psprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_psprel", b0, b1, parm1)
+ priunat_mem_rstate = UWX_DISP_PSPREL(parm1 * 4);
+ break;
+ case 18: /* priunat_sprel */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_sprel", b0, b1, parm1)
+ priunat_mem_rstate = UWX_DISP_SPREL(parm1 * 4);
+ break;
+ case 19: /* priunat_when_mem */
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) priunat_when_mem", b0, b1, parm1)
+ t_priunat_mem = (int) parm1;
+ break;
+ default:
+ TRACE_I_DECODE_PROLOGUE_2L("(P8) ??", b0, b1, parm1)
+ return UWX_ERR_BADUDESC;
+ }
+ }
+
+ /* Format P9 (gr_gr) */
+ else if (b0 == 0xf1) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_PROLOGUE_3("(P9) gr_gr", b0, b1, b2)
+ mask = b1 & 0x0f;
+ reg = b2 & 0x7f;
+ gr_gr_mask = mask;
+ for (i = 0; i < NSB_GR && mask != 0; i++) {
+ if (mask & 0x01) {
+ newrstate[SBREG_GR + i] =
+ UWX_DISP_REG(UWX_REG_GR(reg));
+ reg++;
+ }
+ mask = mask >> 1;
+ }
+ }
+
+ /* Format X1 */
+ else if (b0 == 0xf9) {
+ TRACE_I_DECODE_PROLOGUE_1("(X1)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format X2 */
+ else if (b0 == 0xfa) {
+ TRACE_I_DECODE_PROLOGUE_1("(X2)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format X3 */
+ else if (b0 == 0xfb) {
+ TRACE_I_DECODE_PROLOGUE_1("(X3)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format X4 */
+ else if (b0 == 0xfc) {
+ TRACE_I_DECODE_PROLOGUE_1("(X4)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ b3 = uwx_get_byte(bstream);
+ if (b3 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format P10 */
+ else if (b0 == 0xff) {
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_PROLOGUE_3("(P10) abi", b0, b1, b2)
+ env->abi_context = (b1 << 8) | b2;
+ return UWX_ABI_FRAME;
+ }
+
+ /* Invalid descriptor record */
+ else {
+ TRACE_I_DECODE_PROLOGUE_1("(?)", b0)
+ return UWX_ERR_BADUDESC;
+ }
+ break;
+ }
+ }
+
+ /* Process the masks of spilled GRs, FRs, and BRs to */
+ /* determine when and where each register was saved. */
+
+ fr_base = spill_base + 16 * uwx_count_ones(fr_mem_mask);
+ br_base = fr_base + 8 * uwx_count_ones(br_mem_mask);
+ gr_base = br_base + 8 * uwx_count_ones(gr_mem_mask);
+ TRACE_I_DECODE_PROLOGUE_SPILL_BASE(spill_base)
+ TRACE_I_DECODE_PROLOGUE_MASKS(gr_mem_mask, gr_gr_mask)
+ TRACE_I_DECODE_PROLOGUE_NSPILL(ngr)
+ for (i = 0; ngr > 0 && i <= NSB_GR; i++) {
+ if (gr_mem_mask & 1) {
+ newrstate[SBREG_GR + i] = UWX_DISP_PSPREL(gr_base);
+ tspill[SBREG_GR + i] = 0;
+ gr_base -= 8;
+ ngr--;
+ }
+ else if (gr_gr_mask & 1) {
+ tspill[SBREG_GR + i] = 0;
+ ngr--;
+ }
+ gr_gr_mask = gr_gr_mask >> 1;
+ gr_mem_mask = gr_mem_mask >> 1;
+ }
+ for (i = 0; nbr > 0 && i <= NSB_BR; i++) {
+ if (br_mem_mask & 1) {
+ newrstate[SBREG_BR + i] = UWX_DISP_PSPREL(br_base);
+ tspill[SBREG_BR + i] = 0;
+ br_base -= 8;
+ nbr--;
+ }
+ else if (br_gr_mask & 1) {
+ tspill[SBREG_BR + i] = 0;
+ nbr--;
+ }
+ br_gr_mask = br_gr_mask >> 1;
+ br_mem_mask = br_mem_mask >> 1;
+ }
+ for (i = 0; nfr > 0 && i <= NSB_FR; i++) {
+ if (fr_mem_mask & 1) {
+ newrstate[SBREG_FR + i] = UWX_DISP_PSPREL(fr_base);
+ tspill[SBREG_FR + i] = 0;
+ fr_base -= 16;
+ nfr--;
+ }
+ fr_mem_mask = fr_mem_mask >> 1;
+ }
+
+ /* Update the scoreboard. */
+
+ for (i = 0; i < env->nsbreg; i++) {
+ if (ip_slot >= rhdr->rlen || ip_slot > tspill[i])
+ scoreboard->rstate[i] = newrstate[i];
+ }
+ if (priunat_mem_rstate != UWX_DISP_NONE && ip_slot > t_priunat_mem)
+ scoreboard->rstate[SBREG_PRIUNAT] = priunat_mem_rstate;
+
+ return UWX_OK;
+}
+
+int uwx_count_ones(unsigned int mask)
+{
+ mask = (mask & 0x55555555) + ((mask & 0xaaaaaaaa) >> 1);
+ mask = (mask & 0x33333333) + ((mask & 0xcccccccc) >> 2);
+ mask = (mask & 0x0f0f0f0f) + ((mask & 0xf0f0f0f0) >> 4);
+ mask = (mask & 0x00ff00ff) + ((mask & 0xff00ff00) >> 8);
+ return (mask & 0x0000ffff) + ((mask & 0xffff0000) >> 16);
+}
+
+/* uwx_decode_body: Decodes a body region */
+
+int uwx_decode_body(
+ struct uwx_env *env,
+ struct uwx_bstream *bstream,
+ struct uwx_scoreboard *scoreboard,
+ struct uwx_rhdr *rhdr,
+ int ip_slot)
+{
+ int status;
+ int b0;
+ int b1;
+ int b2;
+ int b3;
+ int label;
+ int ecount;
+ int i;
+ uint64_t parm1;
+ uint64_t parm2;
+ uint64_t newrstate[NSBREG];
+ int tspill[NSBREG];
+ int t_sp_restore;
+
+ /* Initialize an array of register states from the current */
+ /* scoreboard, along with a parallel array of spill times. */
+ /* We use this as a temporary scoreboard, then update the */
+ /* real scoreboard at the end of the procedure. */
+ /* We initialize the spill time to (rhdr.rlen - 1) so that */
+ /* spills without a "when" descriptor will take effect */
+ /* at the end of the prologue region. */
+ /* (Boundary condition: all actions in a zero-length prologue */
+ /* will appear to have happened in the instruction slot */
+ /* immediately preceding the prologue.) */
+
+ for (i = 0; i < env->nsbreg; i++) {
+ newrstate[i] = scoreboard->rstate[i];
+ tspill[i] = rhdr->rlen - 1;
+ }
+ t_sp_restore = rhdr->rlen - 1;
+
+ /* Read body descriptor records until */
+ /* we hit another region header. */
+
+ for (;;) {
+
+ b0 = uwx_get_byte(bstream);
+
+ if (b0 < 0x80) {
+ /* Return the last byte read to the byte stream, since it's */
+ /* really the first byte of the next region header record. */
+ if (b0 >= 0)
+ (void) uwx_unget_byte(bstream, b0);
+ break;
+ }
+
+ /* Format B1 (label_state) */
+ if (b0 < 0xa0) {
+ TRACE_I_DECODE_BODY_1("(B1) label_state", b0)
+ label = b0 & 0x1f;
+ status = uwx_label_scoreboard(env, scoreboard, label);
+ if (status != UWX_OK)
+ return (status);
+ }
+
+ /* Format B1 (copy_state) */
+ else if (b0 < 0xc0) {
+ TRACE_I_DECODE_BODY_1("(B1) copy_state", b0)
+ label = b0 & 0x1f;
+ status = uwx_copy_scoreboard(env, scoreboard, label);
+ if (status != UWX_OK)
+ return (status);
+ for (i = 0; i < env->nsbreg; i++) {
+ newrstate[i] = scoreboard->rstate[i];
+ tspill[i] = rhdr->rlen;
+ }
+ }
+
+ /* Format B2 (epilogue) */
+ else if (b0 < 0xe0) {
+ ecount = b0 & 0x1f;
+ status = uwx_get_uleb128(bstream, &parm1);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_BODY_1L("(B2) epilogue", b0, parm1)
+ rhdr->ecount = ecount + 1;
+ t_sp_restore = rhdr->rlen - (unsigned int) parm1;
+ }
+
+ /* Format B3 (epilogue) */
+ else if (b0 == 0xe0) {
+ status = uwx_get_uleb128(bstream, &parm1);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ status = uwx_get_uleb128(bstream, &parm2);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_BODY_1LL("(B3) epilogue", b0, parm1, parm2)
+ t_sp_restore = rhdr->rlen - (unsigned int) parm1;
+ rhdr->ecount = (unsigned int) parm2 + 1;
+ }
+
+ /* Format B4 (label_state) */
+ else if (b0 == 0xf0) {
+ status = uwx_get_uleb128(bstream, &parm1);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_BODY_1L("(B4) label_state", b0, parm1)
+ label = (int) parm1;
+ status = uwx_label_scoreboard(env, scoreboard, label);
+ if (status != UWX_OK)
+ return (status);
+ }
+
+ /* Format B4 (copy_state) */
+ else if (b0 == 0xf8) {
+ status = uwx_get_uleb128(bstream, &parm1);
+ if (status != 0)
+ return UWX_ERR_BADUDESC;
+ TRACE_I_DECODE_BODY_1L("(B4) copy_state", b0, parm1)
+ label = (int) parm1;
+ status = uwx_copy_scoreboard(env, scoreboard, label);
+ if (status != UWX_OK)
+ return (status);
+ for (i = 0; i < env->nsbreg; i++) {
+ newrstate[i] = scoreboard->rstate[i];
+ tspill[i] = rhdr->rlen;
+ }
+ }
+
+ /* Format X1 */
+ else if (b0 == 0xf9) {
+ TRACE_I_DECODE_BODY_1("(X1)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format X2 */
+ else if (b0 == 0xfa) {
+ TRACE_I_DECODE_BODY_1("(X2)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format X3 */
+ else if (b0 == 0xfb) {
+ TRACE_I_DECODE_BODY_1("(X3)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Format X4 */
+ else if (b0 == 0xfc) {
+ TRACE_I_DECODE_BODY_1("(X4)", b0)
+ b1 = uwx_get_byte(bstream);
+ if (b1 < 0)
+ return UWX_ERR_BADUDESC;
+ b2 = uwx_get_byte(bstream);
+ if (b2 < 0)
+ return UWX_ERR_BADUDESC;
+ b3 = uwx_get_byte(bstream);
+ if (b3 < 0)
+ return UWX_ERR_BADUDESC;
+ /* Don't support X-format descriptors yet */
+ return UWX_ERR_CANTUNWIND;
+ }
+
+ /* Invalid descriptor record */
+ else {
+ TRACE_I_DECODE_BODY_1("(?)", b0)
+ return UWX_ERR_BADUDESC;
+ }
+ }
+
+ /* Update the scoreboard. */
+
+ for (i = 0; i < env->nsbreg; i++) {
+ if (ip_slot > tspill[i])
+ scoreboard->rstate[i] = newrstate[i];
+ }
+
+ /* If we've passed the point in the epilogue where sp */
+ /* is restored, update the scoreboard entry for PSP */
+ /* and reset any entries for registers saved in memory. */
+
+ if (rhdr->ecount > 0 && ip_slot > t_sp_restore) {
+ scoreboard->rstate[SBREG_PSP] = UWX_DISP_SPPLUS(0);
+ for (i = 0; i < env->nsbreg; i++) {
+ if (UWX_GET_DISP_CODE(scoreboard->rstate[i]) == UWX_DISP_SPREL(0) ||
+ UWX_GET_DISP_CODE(scoreboard->rstate[i]) == UWX_DISP_PSPREL(0))
+ scoreboard->rstate[i] = UWX_DISP_NONE;
+ }
+ }
+
+ return UWX_OK;
+}
+
OpenPOWER on IntegriCloud