summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c')
-rw-r--r--usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c2422
1 files changed, 2422 insertions, 0 deletions
diff --git a/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c b/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c
new file mode 100644
index 0000000000..b49c381d96
--- /dev/null
+++ b/usr/src/lib/libdisasm/sparc/dis_sparc_fmt.c
@@ -0,0 +1,2422 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2007 Jason King. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/byteorder.h>
+#include <stdarg.h>
+
+#if !defined(DIS_STANDALONE)
+#include <stdio.h>
+#endif /* DIS_STANDALONE */
+
+#include "libdisasm.h"
+#include "libdisasm_impl.h"
+#include "dis_sparc.h"
+#include "dis_sparc_fmt.h"
+
+extern char *strncpy(char *, const char *, size_t);
+extern size_t strlen(const char *);
+extern int strcmp(const char *, const char *);
+extern int strncmp(const char *, const char *, size_t);
+extern size_t strlcat(char *, const char *, size_t);
+extern size_t strlcpy(char *, const char *, size_t);
+extern int snprintf(char *, size_t, const char *, ...);
+extern int vsnprintf(char *, size_t, const char *, va_list);
+
+/*
+ * This file has the functions that do all the dirty work of outputting the
+ * disassembled instruction
+ *
+ * All the non-static functions follow the format_fcn (in dis_sparc.h):
+ * Input:
+ * disassembler handle/context
+ * instruction to disassemble
+ * instruction definition pointer (inst_t *)
+ * index in the table of the instruction
+ * Return:
+ * 0 Success
+ * !0 Invalid instruction
+ *
+ * Generally, instructions found in the same table use the same output format
+ * or have a few minor differences (which are described in the 'flags' field
+ * of the instruction definition. In some cases, certain instructions differ
+ * radically enough from those in the same table, that their own format
+ * function is used.
+ *
+ * Typically each table has a unique format function defined in this file. In
+ * some cases (such as branches) a common one for all the tables is used.
+ *
+ * When adding support for new instructions, it is largely a judgement call
+ * as to when a new format function is defined.
+ */
+
+/* The various instruction formats of a sparc instruction */
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format1 {
+ uint32_t op:2;
+ uint32_t disp30:30;
+} format1_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format1 {
+ uint32_t disp30:30;
+ uint32_t op:2;
+} format1_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format2 {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op2:3;
+ uint32_t imm22:22;
+} format2_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format2 {
+ uint32_t imm22:22;
+ uint32_t op2:3;
+ uint32_t rd:5;
+ uint32_t op:2;
+} format2_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format2a {
+ uint32_t op:2;
+ uint32_t a:1;
+ uint32_t cond:4;
+ uint32_t op2:3;
+ uint32_t disp22:22;
+} format2a_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format2a {
+ uint32_t disp22:22;
+ uint32_t op2:3;
+ uint32_t cond:4;
+ uint32_t a:1;
+ uint32_t op:2;
+} format2a_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format2b {
+ uint32_t op:2;
+ uint32_t a:1;
+ uint32_t cond:4;
+ uint32_t op2:3;
+ uint32_t cc:2;
+ uint32_t p:1;
+ uint32_t disp19:19;
+} format2b_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format2b {
+ uint32_t disp19:19;
+ uint32_t p:1;
+ uint32_t cc:2;
+ uint32_t op2:3;
+ uint32_t cond:4;
+ uint32_t a:1;
+ uint32_t op:2;
+} format2b_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format2c {
+ uint32_t op:2;
+ uint32_t a:1;
+ uint32_t cond:4;
+ uint32_t op2:3;
+ uint32_t d16hi:2;
+ uint32_t p:1;
+ uint32_t rs1:5;
+ uint32_t d16lo:14;
+} format2c_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format2c {
+ uint32_t d16lo:14;
+ uint32_t rs1:5;
+ uint32_t p:1;
+ uint32_t d16hi:2;
+ uint32_t op2:3;
+ uint32_t cond:4;
+ uint32_t a:1;
+ uint32_t op:2;
+} format2c_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format3 {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t asi:8;
+ uint32_t rs2:5;
+} format3_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format3 {
+ uint32_t rs2:5;
+ uint32_t asi:8;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} format3_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format3a {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t simm13:13;
+} format3a_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format3a {
+ uint32_t simm13:13;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} format3a_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format3b {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t x:1;
+ uint32_t undef:6;
+ uint32_t shcnt:6;
+} format3b_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format3b {
+ uint32_t shcnt:6;
+ uint32_t undef:6;
+ uint32_t x:1;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} format3b_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format3c {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t cc2:1;
+ uint32_t cond:4;
+ uint32_t i:1;
+ uint32_t cc:2;
+ uint32_t simm11:11;
+} format3c_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format3c {
+ uint32_t simm11:11;
+ uint32_t cc:2;
+ uint32_t i:1;
+ uint32_t cond:4;
+ uint32_t cc2:1;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} format3c_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct format3d {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t rcond:3;
+ uint32_t simm10:10;
+} format3d_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct format3d {
+ uint32_t simm10:10;
+ uint32_t rcond:3;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} format3d_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formatcp {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t opc:9;
+ uint32_t rs2:5;
+} formatcp_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formatcp {
+ uint32_t rs2:5;
+ uint32_t opc:9;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} formatcp_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formattcc {
+ uint32_t op:2;
+ uint32_t undef:1;
+ uint32_t cond:4;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t cc:2;
+ uint32_t undef2:3;
+ uint32_t immtrap:8;
+} formattcc_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formattcc {
+ uint32_t immtrap:8;
+ uint32_t undef2:3;
+ uint32_t cc:2;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t cond:4;
+ uint32_t undef:1;
+ uint32_t op:2;
+} formattcc_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formattcc2 {
+ uint32_t op:2;
+ uint32_t undef:1;
+ uint32_t cond:4;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t cc:2;
+ uint32_t undef2:6;
+ uint32_t rs2:5;
+} formattcc2_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formattcc2 {
+ uint32_t rs2:5;
+ uint32_t undef2:6;
+ uint32_t cc:2;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t cond:4;
+ uint32_t undef:1;
+ uint32_t op:2;
+} formattcc2_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formatmbr {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t i:1;
+ uint32_t undef:6;
+ uint32_t cmask:3;
+ uint32_t mmask:4;
+} formatmbr_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formatmbr {
+ uint32_t mmask:4;
+ uint32_t cmask:3;
+ uint32_t undef:6;
+ uint32_t i:1;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} formatmbr_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formatfcmp {
+ uint32_t op:2;
+ uint32_t undef:3;
+ uint32_t cc:2;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t opf:9;
+ uint32_t rs2:5;
+} formatfcmp_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formatfcmp {
+ uint32_t rs2:5;
+ uint32_t opf:9;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t cc:2;
+ uint32_t undef:3;
+ uint32_t op:2;
+} formatfcmp_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formatfmov {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t undef:1;
+ uint32_t cond:4;
+ uint32_t cc:3;
+ uint32_t opf:6;
+ uint32_t rs2:5;
+} formatfmov_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formatfmov {
+ uint32_t rs2:5;
+ uint32_t opf:6;
+ uint32_t cc:3;
+ uint32_t cond:4;
+ uint32_t undef:1;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} formatfmov_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#if defined(_BIT_FIELDS_HTOL)
+typedef struct formatfused {
+ uint32_t op:2;
+ uint32_t rd:5;
+ uint32_t op3:6;
+ uint32_t rs1:5;
+ uint32_t rs3:5;
+ uint32_t op5:4;
+ uint32_t rs2:5;
+} formatfused_t;
+#elif defined(_BIT_FIELDS_LTOH)
+typedef struct formatfused {
+ uint32_t rs2:5;
+ uint32_t op5:4;
+ uint32_t rs3:5;
+ uint32_t rs1:5;
+ uint32_t op3:6;
+ uint32_t rd:5;
+ uint32_t op:2;
+} formatfused_t;
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+typedef union ifmt {
+ uint32_t i;
+ format1_t f1;
+ format2_t f2;
+ format2a_t f2a;
+ format2b_t f2b;
+ format2c_t f2c;
+ format3_t f3;
+ format3a_t f3a;
+ format3b_t f3b;
+ format3c_t f3c;
+ format3d_t f3d;
+ formatcp_t fcp;
+ formattcc_t ftcc;
+ formattcc2_t ftcc2;
+ formatfcmp_t fcmp;
+ formatmbr_t fmb;
+ formatfmov_t fmv;
+ formatfused_t fused;
+} ifmt_t;
+
+/* integer register names */
+static const char *reg_names[32] = {
+ "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+ "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
+ "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
+ "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7"
+};
+
+/* floating point register names */
+static const char *freg_names[32] = {
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+ "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31"
+};
+
+/* double precision register names */
+static const char *fdreg_names[32] = {
+ "%d0", "%d32", "%d2", "%d34", "%d4", "%d36", "%d6", "%d38",
+ "%d8", "%d40", "%d10", "%d42", "%d12", "%d44", "%d14", "%d46",
+ "%d16", "%d48", "%d18", "%d50", "%d20", "%d52", "%d22", "%d54",
+ "%d24", "%d56", "%d26", "%d58", "%d28", "%d60", "%d30", "%d62"
+};
+
+static const char *compat_fdreg_names[32] = {
+ "%f0", "%f32", "%f2", "%f34", "%f4", "%f36", "%f6", "%f38",
+ "%f8", "%f40", "%f10", "%f42", "%f12", "%f44", "%f14", "%f46",
+ "%f16", "%f48", "%f18", "%f50", "%f20", "%f52", "%f22", "%f54",
+ "%f24", "%f56", "%f26", "%f58", "%f28", "%f60", "%f30", "%f62"
+};
+
+
+static const char *fqreg_names[32] = {
+ "%q0", "%q32", "%f2", "%f3", "%f4", "%q4", "%q36", "%f6",
+ "%f7", "%q8", "%q40", "%f10", "%f11", "%q12", "%q44", "%f14",
+ "%f15", "%q16", "%q48", "%f18", "%f19", "%q20", "%q52", "%f22",
+ "%f23", "%q24", "%q56", "%f26", "%f27", "%q28", "%q60", "%f30",
+};
+
+
+/* coprocessor register names -- sparcv8 only */
+static const char *cpreg_names[32] = {
+ "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
+ "%c8", "%c9", "%c10", "%c11", "%c12", "%c13", "%c14", "%c15",
+ "%c16", "%c17", "%c18", "%c19", "%c20", "%c21", "%c22", "%c23",
+ "%c24", "%c25", "%c26", "%c27", "%c28", "%c29", "%c30", "%c31",
+};
+
+/* floating point condition code names */
+static const char *fcc_names[4] = {
+ "%fcc0", "%fcc1", "%fcc2", "%fcc3"
+};
+
+/* condition code names */
+static const char *icc_names[4] = {
+ "%icc", NULL, "%xcc", NULL
+};
+
+/* bitmask values for membar */
+static const char *membar_mmask[4] = {
+ "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore"
+};
+
+static const char *membar_cmask[3] = {
+ "#Lookaside", "#MemIssue", "#Sync"
+};
+
+/* v8 ancillary state register names */
+static const char *asr_names[32] = {
+ "%y", "%asr1", "%asr2", "%asr3",
+ "%asr4", "%asr5", "%asr6", "%asr7",
+ "%asr8", "%asr9", "%asr10", "%asr11",
+ "%asr12", "%asr13", "%asr14", "%asr15",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+static const uint32_t asr_rdmask = 0x0000ffffL;
+static const uint32_t asr_wrmask = 0x0000ffffL;
+
+static const char *v9_asr_names[32] = {
+ "%y", NULL, "%ccr", "%asi",
+ "%tick", "%pc", "%fprs", NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "%pcr", "%pic", NULL, "%gsr",
+ "%softint_set", "%softint_clr", "%softint", "%tick_cmpr",
+ "%stick", "%stick_cmpr", NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+/*
+ * on v9, only certain registers are valid for read or writing
+ * these are bitmasks corresponding to which registers are valid in which
+ * case
+ */
+static const uint32_t v9_asr_rdmask = 0x03cb007d;
+static const uint32_t v9_asr_wrmask = 0x02fb004d;
+
+/* privledged register names on v9 */
+/* TODO: compat - NULL to %priv_nn */
+static const char *v9_privreg_names[32] = {
+ "%tpc", "%tnpc", "%tstate", "%tt",
+ "%tick", "%tba", "%pstate", "%tl",
+ "%pil", "%cwp", "%cansave", "%canrestore",
+ "%cleanwin", "%otherwin", "%wstate", "%fq",
+ "%gl", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "%ver"
+};
+
+static const uint32_t v9_pr_rdmask = 0x80017fff;
+static const uint32_t v9_pr_wrmask = 0x00017fef;
+
+static const char *prefetch_str[32] = {
+ "#n_reads", "#one_read",
+ "#n_writes", "#one_write",
+ "#page", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, "#unified", NULL, NULL,
+ "#n_reads_strong", "#one_read_strong",
+ "#n_writes_strong", "#one_write_strong",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static void prt_field(const char *, uint32_t, int);
+
+static const char *get_regname(dis_handle_t *, int, uint32_t);
+static int32_t sign_extend(int32_t, int32_t);
+
+static void prt_name(dis_handle_t *, const char *, int);
+
+#define IMM_SIGNED 0x01 /* Is immediate value signed */
+#define IMM_ADDR 0x02 /* Is immediate value part of an address */
+static void prt_imm(dis_handle_t *, uint32_t, int);
+
+static void prt_asi(dis_handle_t *, uint32_t);
+static void prt_address(dis_handle_t *, uint32_t, int);
+static void prt_aluargs(dis_handle_t *, uint32_t, uint32_t);
+static void bprintf(dis_handle_t *, const char *, ...);
+
+/*
+ * print out val (which is 'bitlen' bits long) in binary
+ */
+#if defined(DIS_STANDALONE)
+/* ARGSUSED */
+void
+prt_binary(uint32_t val, int bitlen)
+{
+
+}
+
+#else
+
+void
+prt_binary(uint32_t val, int bitlen)
+{
+ int i;
+
+ for (i = bitlen - 1; i >= 0; --i) {
+ (void) fprintf(stderr, ((val & (1L << i)) != 0) ? "1" : "0");
+
+ if (i % 4 == 0 && i != 0)
+ (void) fprintf(stderr, " ");
+ }
+}
+#endif /* DIS_STANDALONE */
+
+
+/*
+ * print out a call instruction
+ * format: call address <name>
+ */
+/* ARGSUSED1 */
+int
+fmt_call(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ int32_t disp;
+ size_t curlen;
+
+ int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f1.op, 2);
+ prt_field("disp30", f->f1.disp30, 30);
+ }
+
+ disp = sign_extend(f->f1.disp30, 30) * 4;
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+
+ bprintf(dhp, (octal != 0) ? "%s0%-11lo" : "%s0x%-10lx",
+ (disp < 0) ? "-" : "+",
+ (disp < 0) ? (-disp) : disp);
+
+ (void) strlcat(dhp->dh_buf, " <", dhp->dh_buflen);
+
+ curlen = strlen(dhp->dh_buf);
+ dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
+ dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL,
+ NULL);
+ (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
+
+
+ return (0);
+}
+
+int
+fmt_sethi(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f2.op, 2);
+ prt_field("op2", f->f2.op2, 3);
+ prt_field("rd", f->f2.rd, 5);
+ prt_field("imm22", f->f2.imm22, 22);
+ }
+
+ if (idx == 0) {
+ /* unimp / illtrap */
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+ prt_imm(dhp, f->f2.imm22, 0);
+ return (0);
+ }
+
+ if (f->f2.imm22 == 0 && f->f2.rd == 0) {
+ prt_name(dhp, "nop", 0);
+ return (0);
+ }
+
+ /* ?? Should we return -1 if rd == 0 && disp != 0 */
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+
+ bprintf(dhp,
+ ((dhp->dh_flags & DIS_OCTAL) != 0) ?
+ "%%hi(0%lo), %s" : "%%hi(0x%lx), %s",
+ f->f2.imm22 << 10,
+ reg_names[f->f2.rd]);
+
+ return (0);
+}
+
+/* ARGSUSED3 */
+int
+fmt_branch(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ const char *name = inp->in_data.in_def.in_name;
+ const char *r = NULL;
+ const char *annul = "";
+ const char *pred = "";
+
+ char buf[15];
+
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ size_t curlen;
+ int32_t disp;
+ uint32_t flags = inp->in_data.in_def.in_flags;
+ int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f2.op, 2);
+ prt_field("op2", f->f2.op2, 3);
+
+ switch (FLG_DISP_VAL(flags)) {
+ case DISP22:
+ prt_field("cond", f->f2a.cond, 4);
+ prt_field("a", f->f2a.a, 1);
+ prt_field("disp22", f->f2a.disp22, 22);
+ break;
+
+ case DISP19:
+ prt_field("cond", f->f2a.cond, 4);
+ prt_field("a", f->f2a.a, 1);
+ prt_field("p", f->f2b.p, 1);
+ prt_field("cc", f->f2b.cc, 2);
+ prt_field("disp19", f->f2b.disp19, 19);
+ break;
+
+ case DISP16:
+ prt_field("bit 28", ((instr & (1L << 28)) >> 28), 1);
+ prt_field("rcond", f->f2c.cond, 3);
+ prt_field("p", f->f2c.p, 1);
+ prt_field("rs1", f->f2c.rs1, 5);
+ prt_field("d16hi", f->f2c.d16hi, 2);
+ prt_field("d16lo", f->f2c.d16lo, 14);
+ break;
+ }
+ }
+
+ if (f->f2b.op2 == 0x01 && idx == 0x00 && f->f2b.p == 1 &&
+ f->f2b.cc == 0x02 && ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0)) {
+ name = "iprefetch";
+ flags = FLG_RS1(REG_NONE)|FLG_DISP(DISP19);
+ }
+
+ switch (FLG_DISP_VAL(flags)) {
+ case DISP22:
+ disp = sign_extend(f->f2a.disp22, 22);
+ break;
+
+ case DISP19:
+ disp = sign_extend(f->f2b.disp19, 19);
+ break;
+
+ case DISP16:
+ disp = sign_extend((f->f2c.d16hi << 14)|f->f2c.d16lo, 16);
+ break;
+
+ }
+
+ disp *= 4;
+
+ if ((FLG_RS1_VAL(flags) == REG_ICC) || (FLG_RS1_VAL(flags) == REG_FCC))
+ r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2b.cc);
+ else
+ r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2c.rs1);
+
+ if (r == NULL)
+ return (-1);
+
+ if (f->f2a.a == 1)
+ annul = ",a";
+
+ if ((flags & FLG_PRED) != 0) {
+ if (f->f2b.p == 0) {
+ pred = ",pn";
+ } else {
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)
+ pred = ",pt";
+ }
+ }
+
+ (void) snprintf(buf, sizeof (buf), "%s%s%s", name, annul, pred);
+ prt_name(dhp, buf, 1);
+
+
+ switch (FLG_DISP_VAL(flags)) {
+ case DISP22:
+ bprintf(dhp,
+ (octal != 0) ? "%s0%-11lo <" : "%s0x%-10lx <",
+ (disp < 0) ? "-" : "+",
+ (disp < 0) ? (-disp) : disp);
+ break;
+
+ case DISP19:
+ bprintf(dhp,
+ (octal != 0) ? "%s, %s0%-5lo <" : "%s, %s0x%-04lx <",
+ r,
+ (disp < 0) ? "-" : "+",
+ (disp < 0) ? (-disp) : disp);
+ break;
+
+ case DISP16:
+ bprintf(dhp,
+ (octal != 0) ? "%s, %s0%-6lo <" : "%s, %s0x%-5lx <",
+ r,
+ (disp < 0) ? "-" : "+",
+ (disp < 0) ? (-disp) : disp);
+ break;
+ }
+
+ curlen = strlen(dhp->dh_buf);
+ dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
+ dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL, NULL);
+
+ (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
+
+ return (0);
+}
+
+
+
+/*
+ * print out the compare and swap instructions (casa/casxa)
+ * format: casa/casxa [%rs1] imm_asi, %rs2, %rd
+ * casa/casxa [%rs1] %asi, %rs2, %rd
+ *
+ * If DIS_DEBUG_SYN_ALL is set, synthetic instructions are emitted
+ * when an immediate ASI value is given as follows:
+ *
+ * casa [%rs1]#ASI_P, %rs2, %rd -> cas [%rs1], %rs2, %rd
+ * casa [%rs1]#ASI_P_L, %rs2, %rd -> casl [%rs1], %rs2, %rd
+ * casxa [%rs1]#ASI_P, %rs2, %rd -> casx [%rs1], %rs2, %rd
+ * casxa [%rs1]#ASI_P_L, %rs2, %rd -> casxl [%rs1], %rs2, %rd
+ */
+static int
+fmt_cas(dis_handle_t *dhp, uint32_t instr, const char *name)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int noasi = 0;
+
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) != 0) {
+ if (f->f3.op3 == 0x3c && f->f3.i == 0) {
+ if (f->f3.asi == 0x80) {
+ noasi = 1;
+ name = "cas";
+ }
+
+ if (f->f3.asi == 0x88) {
+ noasi = 1;
+ name = "casl";
+ }
+ }
+
+ if (f->f3.op3 == 0x3e && f->f3.i == 0) {
+ if (f->f3.asi == 0x80) {
+ noasi = 1;
+ name = "casx";
+ }
+
+ if (f->f3.asi == 0x88) {
+ noasi = 1;
+ name = "casxl";
+ }
+ }
+ }
+
+ prt_name(dhp, name, 1);
+
+ bprintf(dhp, "[%s]", reg_names[f->f3.rs1]);
+
+ if (noasi == 0) {
+ (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
+ prt_asi(dhp, instr);
+ }
+
+ bprintf(dhp, ", %s, %s", reg_names[f->f3.rs2], reg_names[f->f3.rd]);
+
+ return (0);
+}
+
+/*
+ * format a load/store instruction
+ * format: ldXX [%rs1 + %rs2], %rd load, i==0
+ * ldXX [%rs1 +/- nn], %rd load, i==1
+ * ldXX [%rs1 + %rs2] #XX, %rd load w/ imm_asi, i==0
+ * ldXX [%rs1 +/- nn] %asi, %rd load from asi[%asi], i==1
+ *
+ * stXX %rd, [%rs1 + %rs2] store, i==0
+ * stXX %rd, [%rs1 +/- nn] store, i==1
+ * stXX %rd, [%rs1 + %rs1] #XX store to imm_asi, i==0
+ * stXX %rd, [%rs1 +/-nn] %asi store to asi[%asi], i==1
+ *
+ * The register sets used for %rd are set in the instructions flags field
+ * The asi variants are used if FLG_ASI is set in the instructions flags field
+ *
+ * If DIS_DEBUG_SYNTH_ALL or DIS_DEBUG_COMPAT are set,
+ * When %rs1, %rs2 or nn are 0, they are not printed, i.e.
+ * [ %rs1 + 0x0 ], %rd -> [%rs1], %rd for example
+ *
+ * The following synthetic instructions are also implemented:
+ *
+ * stb %g0, [addr] -> clrb [addr] DIS_DEBUG_SYNTH_ALL
+ * sth %g0, [addr] -> crlh [addr] DIS_DEBUG_SYNTH_ALL
+ * stw %g0, [addr] -> clr [addr] DIS_DEBUG_SYNTH_ALL|DIS_DEBUG_COMPAT
+ * stx %g0, [addr] -> clrx [addr] DIS_DEBUG_SYNTH_ALL
+ *
+ * If DIS_DEBUG_COMPAT is set, the following substitutions also take place
+ * lduw -> ld
+ * ldtw -> ld
+ * stuw -> st
+ * sttw -> st
+ */
+int
+fmt_ls(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ const char *regstr = NULL;
+
+ const char *iname = inp->in_data.in_def.in_name;
+ uint32_t flags = inp->in_data.in_def.in_flags;
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f3.op, 2);
+ prt_field("op3", f->f3.op3, 6);
+ prt_field("rs1", f->f3.rs1, 5);
+ prt_field("i", f->f3.i, 1);
+ if (f->f3.i != 0) {
+ prt_field("simm13", f->f3a.simm13, 13);
+ } else {
+ if ((flags & FLG_ASI) != 0)
+ prt_field("imm_asi", f->f3.asi, 8);
+ prt_field("rs2", f->f3.rs2, 5);
+ }
+ prt_field("rd", f->f3.rd, 5);
+ }
+
+ if (idx == 0x2d || idx == 0x3d) {
+ /* prefetch / prefetcha */
+
+ prt_name(dhp, iname, 1);
+
+ prt_address(dhp, instr, 0);
+
+ if (idx == 0x3d) {
+ (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
+ prt_asi(dhp, instr);
+ }
+
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+
+ /* fcn field is the same as rd */
+ if (prefetch_str[f->f3.rd] != NULL)
+ (void) strlcat(dhp->dh_buf, prefetch_str[f->f3.rd],
+ dhp->dh_buflen);
+ else
+ prt_imm(dhp, f->f3.rd, 0);
+
+ return (0);
+ }
+
+ /* casa / casxa */
+ if (idx == 0x3c || idx == 0x3e)
+ return (fmt_cas(dhp, instr, iname));
+
+ /* synthetic instructions & special cases */
+ switch (idx) {
+ case 0x00:
+ /* ld */
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
+ iname = "lduw";
+ break;
+
+ case 0x03:
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
+ iname = "ldtw";
+ break;
+
+ case 0x04:
+ /* stw */
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
+ iname = "stuw";
+
+ if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
+ == 0)
+ break;
+
+ if (f->f3.rd == 0) {
+ iname = "clr";
+ flags = FLG_RD(REG_NONE);
+ }
+ break;
+
+ case 0x05:
+ /* stb */
+ if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
+ == 0)
+ break;
+
+ if (f->f3.rd == 0) {
+ iname = "clrb";
+ flags = FLG_RD(REG_NONE);
+ }
+ break;
+
+ case 0x06:
+ /* sth */
+ if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
+ == 0)
+ break;
+
+ if (f->f3.rd == 0) {
+ iname = "clrh";
+ flags = FLG_RD(REG_NONE);
+ }
+ break;
+
+ case 0x07:
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
+ iname = "sttw";
+ break;
+
+ case 0x0e:
+ /* stx */
+
+ if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
+ == 0)
+ break;
+
+ if (f->f3.rd == 0) {
+ iname = "clrx";
+ flags = FLG_RD(REG_NONE);
+ }
+ break;
+
+ case 0x13:
+ /* ldtwa */
+ if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) &&
+ ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
+ iname = "ldtwa";
+ break;
+
+ case 0x17:
+ /* sttwa */
+ if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) &&
+ ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
+ iname = "sttwa";
+ break;
+
+ case 0x21:
+ case 0x25:
+ /*
+ * on sparcv8 it merely says that rd != 1 should generate an
+ * exception, on v9, it is illegal
+ */
+ if ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0)
+ break;
+
+ iname = (idx == 0x21) ? "ldx" : "stx";
+
+ if (f->f3.rd > 1)
+ return (-1);
+
+ break;
+
+ case 0x31:
+ /* stda */
+ switch (f->f3.asi) {
+ case 0xc0:
+ case 0xc1:
+ case 0xc8:
+ case 0xc9:
+ case 0xc2:
+ case 0xc3:
+ case 0xca:
+ case 0xcb:
+ case 0xc4:
+ case 0xc5:
+ case 0xcc:
+ case 0xcd:
+ /*
+ * store partial floating point, only valid w/
+ * vis
+ *
+ * Somewhat confusingly, it uses the same op
+ * code as 'stda' -- store double to alternate
+ * space. It is distinguised by specific
+ * imm_asi values (as seen above), and
+ * has a slightly different output syntax
+ */
+
+ if ((dhp->dh_flags & DIS_SPARC_V9_SGI) == 0)
+ break;
+ if (f->f3.i != 0)
+ break;
+ prt_name(dhp, iname, 1);
+ bprintf(dhp, "%s, %s, [%s] ",
+ get_regname(dhp, REG_FPD, f->f3.rd),
+ get_regname(dhp, REG_FPD, f->f3.rs2),
+ get_regname(dhp, REG_FPD, f->f3.rs1));
+ prt_asi(dhp, instr);
+ return (0);
+
+ default:
+ break;
+ }
+
+ }
+
+ regstr = get_regname(dhp, FLG_RD_VAL(flags), f->f3.rd);
+
+ prt_name(dhp, iname, 1);
+
+ if ((flags & FLG_STORE) != 0) {
+ if (regstr[0] != '\0') {
+ (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+ }
+
+ prt_address(dhp, instr, 0);
+ if ((flags & FLG_ASI) != 0) {
+ (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
+ prt_asi(dhp, instr);
+ }
+ } else {
+ prt_address(dhp, instr, 0);
+ if ((flags & FLG_ASI) != 0) {
+ (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
+ prt_asi(dhp, instr);
+ }
+
+ if (regstr[0] != '\0') {
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+ (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
+ }
+ }
+
+ return (0);
+}
+
+static int
+fmt_cpop(dis_handle_t *dhp, uint32_t instr, const inst_t *inp)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int flags = FLG_P1(REG_CP)|FLG_P2(REG_CP)|FLG_NOIMM|FLG_P3(REG_CP);
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->fcp.op, 2);
+ prt_field("op3", f->fcp.op3, 6);
+ prt_field("opc", f->fcp.opc, 9);
+ prt_field("rs1", f->fcp.rs1, 5);
+ prt_field("rs2", f->fcp.rs2, 5);
+ prt_field("rd", f->fcp.rd, 5);
+ }
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+ prt_imm(dhp, f->fcp.opc, 0);
+
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+ (void) prt_aluargs(dhp, instr, flags);
+
+ return (0);
+}
+
+static int
+dis_fmt_rdwr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ const char *psr_str = "%psr";
+ const char *wim_str = "%wim";
+ const char *tbr_str = "%tbr";
+
+ const char *name = inp->in_data.in_def.in_name;
+ const char *regstr = NULL;
+
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ int rd = (idx < 0x30);
+ int v9 = (dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI));
+ int ridx = f->f3.rs1;
+ int i, first;
+ int pr_rs1 = 1;
+ int pr_rs2 = 1;
+
+ int use_mask = 1;
+ uint32_t mask;
+
+ if (rd == 0)
+ ridx = f->f3.rd;
+
+ switch (idx) {
+ case 0x28:
+ /* rd */
+
+ /* stbar */
+ if ((f->f3.rd == 0) && (f->f3.rs1 == 15) && (f->f3.i == 0)) {
+ prt_name(dhp, "stbar", 0);
+ return (0);
+ }
+
+ /* membar */
+ if ((v9 != 0) && (f->f3.rd == 0) && (f->f3.rs1 == 15) &&
+ (f->f3.i == 1) && ((f->i & (1L << 12)) == 0)) {
+
+ prt_name(dhp, "membar",
+ ((f->fmb.cmask != 0) || (f->fmb.mmask != 0)));
+
+ first = 0;
+
+ for (i = 0; i < 4; ++i) {
+ if ((f->fmb.cmask & (1L << i)) != 0) {
+ bprintf(dhp, "%s%s",
+ (first != 0) ? "|" : "",
+ membar_cmask[i]);
+ first = 1;
+ }
+ }
+
+ for (i = 0; i < 5; ++i) {
+ if ((f->fmb.mmask & (1L << i)) != 0) {
+ bprintf(dhp, "%s%s",
+ (first != 0) ? "|" : "",
+ membar_mmask[i]);
+ first = 1;
+ }
+ }
+
+ return (0);
+ }
+
+ if (v9 != 0) {
+ regstr = v9_asr_names[ridx];
+ mask = v9_asr_rdmask;
+ } else {
+ regstr = asr_names[ridx];
+ mask = asr_rdmask;
+ }
+ break;
+
+ case 0x29:
+ /*
+ * NOTE: due to an overlay entry, this only gets executed when
+ * disassembling v8 instructions
+ */
+ regstr = psr_str;
+ use_mask = 0;
+ break;
+
+ case 0x2a:
+ if (v9 != 0) {
+ regstr = v9_privreg_names[ridx];
+ mask = v9_pr_rdmask;
+ } else {
+ regstr = wim_str;
+ use_mask = 0;
+ }
+ break;
+
+ case 0x2b:
+ if (v9 != 0) {
+ /* flushw */
+ prt_name(dhp, name, 0);
+ return (0);
+ }
+
+ regstr = tbr_str;
+ use_mask = 0;
+ break;
+
+ case 0x30:
+ if (v9 != 0) {
+ regstr = v9_asr_names[ridx];
+ mask = v9_asr_wrmask;
+ } else {
+ regstr = asr_names[ridx];
+ mask = asr_wrmask;
+ }
+
+ /* synth: mov */
+ if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
+ == 0)
+ break;
+
+ if (f->f3.rs1 == 0) {
+ name = "mov";
+ pr_rs1 = 0;
+ }
+
+ if ((f->f3.i == 0 && f->f3.rs2 == 0) ||
+ (f->f3.i == 1 && f->f3a.simm13 == 0)) {
+ name = "mov";
+ pr_rs2 = 0;
+ }
+
+ if (pr_rs1 == 0)
+ pr_rs2 = 1;
+
+ break;
+
+ case 0x31:
+ /*
+ * NOTE: due to the presence of an overlay entry for another
+ * table, this case only happens when doing v8 instructions
+ * only
+ */
+ regstr = psr_str;
+ use_mask = 0;
+ break;
+
+ case 0x32:
+ if (v9 != 0) {
+ regstr = v9_privreg_names[ridx];
+ mask = v9_pr_wrmask;
+ } else {
+ regstr = wim_str;
+ use_mask = 0;
+ }
+ break;
+
+ case 0x33:
+ /* NOTE: due to an overlay entry, this is v8 only */
+ regstr = tbr_str;
+ use_mask = 0;
+ break;
+ }
+
+ if (regstr == NULL)
+ return (-1);
+
+ if (use_mask != 0 && ((1L << ridx) & mask) == 0)
+ return (-1);
+
+ prt_name(dhp, name, 1);
+
+ if (rd != 0) {
+ bprintf(dhp, "%s, %s", regstr, reg_names[f->f3.rd]);
+ } else {
+ if (pr_rs1 == 1)
+ bprintf(dhp, "%s, ", reg_names[f->f3.rs1]);
+
+ if (pr_rs2 != 0) {
+ if (f->f3.i == 1)
+ prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
+ IMM_SIGNED);
+ else
+ (void) strlcat(dhp->dh_buf,
+ reg_names[f->f3.rs2], dhp->dh_buflen);
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+ }
+
+ (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED3 */
+int
+fmt_trap(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ int v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
+ int p_rs1, p_t;
+
+ if (f->ftcc.undef != 0)
+ return (-1);
+
+ if (icc_names[f->ftcc.cc] == NULL)
+ return (-1);
+
+ if (f->ftcc.i == 1 && f->ftcc.undef2 != 0)
+ return (-1);
+
+ if (f->ftcc2.i == 0 && f->ftcc2.undef2 != 0)
+ return (-1);
+
+ p_rs1 = ((f->ftcc.rs1 != 0) ||
+ ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0));
+
+ if (f->ftcc.i == 0) {
+ p_t = (f->f3.rs2 != 0 || p_rs1 == 0);
+
+ bprintf(dhp, "%-9s %s%s%s%s%s", inp->in_data.in_def.in_name,
+ (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
+ (v9 != 0) ? ", " : "",
+ (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
+ (p_rs1 != 0) ? " + " : "",
+ (p_t != 0) ? reg_names[f->f3.rs2] : "");
+ } else {
+ bprintf(dhp, "%-9s %s%s%s%s0x%x", inp->in_data.in_def.in_name,
+ (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
+ (v9 != 0) ? ", " : "",
+ (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
+ (p_rs1 != 0) ? " + " : "",
+ f->ftcc.immtrap);
+ }
+
+ return (0);
+}
+
+static int
+prt_shift(dis_handle_t *dhp, uint32_t instr, const inst_t *inp)
+{
+ char name[5];
+ uint32_t cnt;
+
+ ifmt_t *f = (ifmt_t *)&instr;
+ int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
+
+ name[0] = '\0';
+ (void) strlcat(name, inp->in_data.in_def.in_name, sizeof (name));
+
+ if (f->f3b.i == 1)
+ cnt = f->f3.rs2;
+
+ if (f->f3b.x == 1 && ((dhp->dh_flags & DIS_SPARC_V8) == 0)) {
+ cnt = f->f3b.shcnt;
+ (void) strlcat(name, "x", sizeof (name));
+ }
+
+ prt_name(dhp, name, 1);
+
+ if (f->f3b.i == 1)
+ bprintf(dhp, (octal != 0) ? "%s, 0%lo, %s" : "%s, 0x%lx, %s",
+ reg_names[f->f3.rs1], cnt, reg_names[f->f3.rd]);
+ else
+ bprintf(dhp, "%s, %s, %s", reg_names[f->f3.rs1],
+ reg_names[f->f3.rs2], reg_names[f->f3.rd]);
+
+ return (0);
+}
+
+/* ARGSUSED3 */
+static int
+prt_jmpl(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ const char *name = inp->in_data.in_def.in_name;
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0))
+ name = "call";
+
+ if (f->f3.rd == 0) {
+ if (f->f3.i == 1 && f->f3a.simm13 == 8) {
+ if (f->f3.rs1 == 15) {
+ prt_name(dhp, "retl", 0);
+ return (0);
+ }
+
+ if (f->f3.rs1 == 31) {
+ prt_name(dhp, "ret", 0);
+ return (0);
+ }
+ }
+
+ name = "jmp";
+ }
+
+ prt_name(dhp, name, 1);
+ prt_address(dhp, instr, 1);
+
+ if (f->f3.rd == 0)
+ return (0);
+
+ if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0))
+ return (0);
+
+ bprintf(dhp, ", %s", reg_names[f->f3.rd]);
+
+ return (0);
+}
+
+int
+fmt_alu(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ const char *name = inp->in_data.in_def.in_name;
+ int flags = inp->in_data.in_def.in_flags;
+ int arg = 0;
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f3.op, 2);
+ prt_field("op3", f->f3.op3, 6);
+ prt_field("rs1", f->f3.rs1, 5);
+
+ switch (idx) {
+ /* TODO: more formats */
+
+ default:
+ if (f->f3.i == 0)
+ prt_field("rs2", f->f3.rs2, 5);
+ else
+ prt_field("simm13", f->f3a.simm13, 13);
+
+ prt_field("rd", f->f3.rd, 5);
+ }
+
+ }
+
+ switch (idx) {
+ case 0x00:
+ /* add */
+
+ if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
+ break;
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 == 1) {
+ name = "inc";
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
+ break;
+ }
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 != 1) {
+ name = "inc";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+ break;
+
+ case 0x02:
+ /* or */
+
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
+ == 0)
+ break;
+
+ if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0) {
+ if (f->f3.rs1 == f->f3.rd) {
+ name = "bset";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+ }
+
+ if (((f->f3.i == 0 && f->f3.rs2 == 0) ||
+ (f->f3.i == 1 && f->f3a.simm13 == 0)) &&
+ (f->f3.rs1 == 0)) {
+ name = "clr";
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
+ break;
+ }
+
+ if (f->f3.rs1 == 0) {
+ name = "mov";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+ break;
+
+ case 0x04:
+ /* sub */
+
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
+ == 0)
+ break;
+
+ if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 == f->f3.rd) {
+ name = "neg";
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE);
+ break;
+ }
+
+ if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 != f->f3.rd) {
+ name = "neg";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+
+ if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
+ break;
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 == 1) {
+ name = "dec";
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
+ break;
+ }
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 != 1) {
+ name = "dec";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+ break;
+
+ case 0x07:
+ /* xnor */
+
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
+ == 0)
+ break;
+
+ /*
+ * xnor -> not when you have:
+ * xnor %rs1, 0x0 or %g0, %rd
+ */
+ if ((f->f3.i == 0 && f->f3.rs2 != 0) ||
+ (f->f3.i == 1 && f->f3a.simm13 != 0))
+ break;
+
+ name = "not";
+
+ if (f->f3.rs1 == f->f3.rd)
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM|
+ FLG_P3(REG_INT);
+ else
+ flags = FLG_P1(REG_INT)|FLG_P2(REG_NONE)|FLG_NOIMM|
+ FLG_P3(REG_INT);
+
+ break;
+
+ case 0x10:
+ /* addcc */
+
+ if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
+ break;
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 == 1) {
+ name = "inccc";
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
+ break;
+ }
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 != 1) {
+ name = "inccc";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+ break;
+
+ case 0x11:
+ /* andcc */
+
+ if (f->f3.rd != 0)
+ break;
+
+ if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
+ == 0)
+ break;
+
+ if (((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0) &&
+ ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0))
+ break;
+
+ name = "btst";
+ flags = FLG_P1(REG_NONE);
+ f->f3.rd = f->f3.rs1;
+ break;
+
+ case 0x12:
+ /* orcc */
+
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
+ == 0)
+ break;
+
+ if (f->f3.rs1 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
+ name = "tst";
+ flags = FLG_P1(REG_NONE)|FLG_P3(REG_NONE);
+ break;
+ }
+
+ if (f->f3.rs2 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
+ name = "tst";
+ flags = FLG_P2(REG_NONE)|FLG_P3(REG_NONE);
+ break;
+ }
+
+ break;
+
+ case 0x14:
+ /* subcc */
+
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
+ == 0)
+ break;
+
+ if (f->f3.rd == 0) {
+ name = "cmp";
+ flags = FLG_P3(REG_NONE);
+ break;
+ }
+
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)
+ break;
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 == 1) {
+ name = "deccc";
+ flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
+ break;
+ }
+
+ if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
+ f->f3a.simm13 != 1) {
+ name = "deccc";
+ flags = FLG_P1(REG_NONE);
+ break;
+ }
+
+ break;
+
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ return (prt_shift(dhp, instr, inp));
+
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ return (dis_fmt_rdwr(dhp, instr, inp, idx));
+
+ case 0x36:
+ case 0x37:
+ /* NOTE: overlayed on v9 */
+ if ((dhp->dh_flags & DIS_SPARC_V8) != 0)
+ return (fmt_cpop(dhp, instr, inp));
+ break;
+
+ case 0x38:
+ /* jmpl */
+ return (prt_jmpl(dhp, instr, inp, idx));
+
+ case 0x39:
+ /* rett / return */
+ prt_name(dhp, name, 1);
+ prt_address(dhp, instr, 1);
+ return (0);
+
+ case 0x3b:
+ /* flush */
+ prt_name(dhp, name, 1);
+ prt_address(dhp, instr, 0);
+ return (0);
+
+ case 0x3c:
+ case 0x3d:
+ /* save / restore */
+ if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
+ == 0)
+ break;
+
+ if (f->f3.rs1 != 0 || f->f3.rs2 != 0 || f->f3.rd != 0)
+ break;
+
+ if (f->f3.i != 0 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0))
+ break;
+
+ prt_name(dhp, name, 0);
+ return (0);
+ }
+
+ if (FLG_P1_VAL(flags) != REG_NONE || FLG_P2_VAL(flags) != REG_NONE ||
+ FLG_P3_VAL(flags) != REG_NONE)
+ arg = 1;
+
+ prt_name(dhp, name, (arg != 0));
+ prt_aluargs(dhp, instr, flags);
+
+ return (0);
+}
+
+/* ARGSUSED1 */
+int
+fmt_regwin(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ prt_name(dhp, inp->in_data.in_def.in_name, 0);
+ return (0);
+}
+
+/* ARGSUSED1 */
+int
+fmt_trap_ret(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ prt_name(dhp, inp->in_data.in_def.in_name, 0);
+ return (0);
+}
+
+/* ARGSUSED3 */
+int
+fmt_movcc(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ const char **regs = NULL;
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f3c.op, 2);
+ prt_field("op3", f->f3c.op3, 6);
+ prt_field("cond", f->f3c.cond, 4);
+ prt_field("cc2", f->f3c.cc2, 1);
+ prt_field("cc", f->f3c.cc, 2);
+ prt_field("i", f->f3c.i, 1);
+
+ if (f->f3c.i == 0)
+ prt_field("rs2", f->f3.rs2, 5);
+ else
+ prt_field("simm11", f->f3c.simm11, 11);
+
+ prt_field("rd", f->f3.rd, 5);
+ }
+
+ if (f->f3c.cc2 == 0) {
+ regs = fcc_names;
+ } else {
+ regs = icc_names;
+ if (regs[f->f3c.cc] == NULL)
+ return (-1);
+ }
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+
+ bprintf(dhp, "%s, ", regs[f->f3c.cc]);
+
+ if (f->f3c.i == 1)
+ prt_imm(dhp, sign_extend(f->f3c.simm11, 11), IMM_SIGNED);
+ else
+ (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2],
+ dhp->dh_buflen);
+
+ bprintf(dhp, ", %s", reg_names[f->f3.rd]);
+
+ return (0);
+}
+
+/* ARGSUSED3 */
+int
+fmt_movr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+
+ bprintf(dhp, "%s, ", reg_names[f->f3d.rs1]);
+
+ if (f->f3d.i == 1)
+ prt_imm(dhp, sign_extend(f->f3d.simm10, 10), IMM_SIGNED);
+ else
+ (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2],
+ dhp->dh_buflen);
+
+ bprintf(dhp, ", %s", reg_names[f->f3.rd]);
+
+ return (0);
+}
+
+/* ARGSUSED3 */
+int
+fmt_fpop1(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int flags = inp->in_data.in_def.in_flags;
+
+ flags |= FLG_NOIMM;
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f3.op, 2);
+ prt_field("op3", f->f3.op3, 6);
+ prt_field("opf", f->fcmp.opf, 9);
+ prt_field("rs1", f->f3.rs1, 5);
+ prt_field("rs2", f->f3.rs2, 5);
+ prt_field("rd", f->f3.rd, 5);
+ }
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+ prt_aluargs(dhp, instr, flags);
+
+ return (0);
+}
+
+int
+fmt_fpop2(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ static const char *condstr_icc[16] = {
+ "n", "e", "le", "l", "leu", "lu", "neg", "vs",
+ "a", "nz", "g", "ge", "gu", "geu", "pos", "vc"
+ };
+
+ static const char *condstr_fcc[16] = {
+ "n", "nz", "lg", "ul", "l", "ug", "g", "u",
+ "a", "e", "ue", "ge", "uge", "le", "ule", "o"
+ };
+
+ ifmt_t *f = (ifmt_t *)&instr;
+ const char *ccstr = "";
+ char name[15];
+
+ int flags = inp->in_data.in_def.in_flags;
+ int is_cmp = (idx == 0x51 || idx == 0x52 || idx == 0x53 ||
+ idx == 0x55 || idx == 0x56 || idx == 0x57);
+ int is_fmov = (idx & 0x3f);
+ int is_v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
+ int is_compat = ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0);
+
+ int p_cc = 0;
+
+ is_fmov = (is_fmov == 0x1 || is_fmov == 0x2 || is_fmov == 0x3);
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f3.op, 2);
+ prt_field("op3", f->f3.op3, 6);
+ prt_field("opf", f->fcmp.opf, 9);
+
+ switch (idx & 0x3f) {
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ prt_field("cc", f->fcmp.cc, 2);
+ prt_field("rs1", f->f3.rs1, 5);
+ prt_field("rs2", f->f3.rs2, 5);
+ break;
+
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ prt_field("opf_low", f->fmv.opf, 6);
+ prt_field("cond", f->fmv.cond, 4);
+ prt_field("opf_cc", f->fmv.cc, 3);
+ prt_field("rs2", f->fmv.rs2, 5);
+ break;
+
+ default:
+ prt_field("rs1", f->f3.rs1, 5);
+ prt_field("rs2", f->f3.rs2, 5);
+ prt_field("rd", f->f3.rd, 5);
+ }
+ }
+
+ name[0] = '\0';
+ (void) strlcat(name, inp->in_data.in_def.in_name, sizeof (name));
+
+ if (is_fmov != 0) {
+ (void) strlcat(name,
+ (f->fmv.cc < 4) ? condstr_fcc[f->fmv.cond]
+ : condstr_icc[f->fmv.cond],
+ sizeof (name));
+ }
+
+ prt_name(dhp, name, 1);
+
+ if (is_cmp != 0)
+ ccstr = fcc_names[f->fcmp.cc];
+
+ if (is_fmov != 0)
+ ccstr = (f->fmv.cc < 4) ? fcc_names[f->fmv.cc & 0x3]
+ : icc_names[f->fmv.cc & 0x3];
+
+ if (ccstr == NULL)
+ return (-1);
+
+ p_cc = (is_compat == 0 || is_v9 != 0 ||
+ (is_cmp != 0 && f->fcmp.cc != 0) ||
+ (is_fmov != 0 && f->fmv.cc != 0));
+
+ if (p_cc != 0)
+ bprintf(dhp, "%s, ", ccstr);
+
+ prt_aluargs(dhp, instr, flags);
+
+ return (0);
+}
+
+int
+fmt_vis(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int flags = inp->in_data.in_def.in_flags;
+
+ if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
+ prt_field("op", f->f3.op, 2);
+ prt_field("op3", f->f3.op3, 6);
+ prt_field("opf", f->fcmp.opf, 9);
+
+ if (idx == 0x081) {
+ prt_field("mode", instr & 02L, 2);
+ } else {
+ prt_field("rs1", f->f3.rs1, 5);
+ prt_field("rs2", f->f3.rs2, 5);
+ prt_field("rd", f->f3.rd, 5);
+ }
+ }
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+
+ if (idx == 0x081) {
+ /* siam */
+ bprintf(dhp, "%d", instr & 0x7L);
+ return (0);
+ }
+
+ prt_aluargs(dhp, instr, flags);
+
+ return (0);
+}
+
+/* ARGSUSED3 */
+int
+fmt_fused(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int flags = inp->in_data.in_def.in_flags;
+
+ prt_name(dhp, inp->in_data.in_def.in_name, 1);
+ bprintf(dhp, "%s, %s, %s, %s",
+ get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs1),
+ get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs2),
+ get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs3),
+ get_regname(dhp, FLG_P1_VAL(flags), f->fused.rd));
+
+ return (0);
+}
+/*
+ * put name into the output buffer
+ * if add_space !=0, append a space after it
+ */
+static void
+prt_name(dis_handle_t *dhp, const char *name, int add_space)
+{
+ bprintf(dhp, (add_space == 0) ? "%s" : "%-9s ", name);
+}
+
+/*
+ * For debugging, print out a field of the instruction
+ * field is the name of the field
+ * val is the value of the field
+ * len is the length of the field (in bits)
+ */
+#if defined(DIS_STANDALONE)
+/* ARGSUSED */
+static void
+prt_field(const char *field, uint32_t val, int len)
+{
+
+}
+
+#else
+static void
+prt_field(const char *field, uint32_t val, int len)
+{
+ (void) fprintf(stderr, "DISASM: %8s = 0x%-8ulx (", field, val);
+ prt_binary(val, len);
+ (void) fprintf(stderr, ")\n");
+}
+#endif /* DIS_STANDALONE */
+
+/*
+ * sign extend a val (that is 'bits' bits in length) to a 32-bit signed
+ * integer
+ */
+static int32_t
+sign_extend(int32_t val, int32_t bits)
+{
+ if ((val & (1L << (bits - 1))) == 0)
+ return (val);
+
+ return ((-1L << bits) | val);
+}
+
+/*
+ * print out an immediate (i.e. constant) value
+ * val is the value
+ * format indicates if it is:
+ * 0 Unsigned
+ * IMM_SIGNED A signed value (prepend +/- to the value)
+ * IMM_ADDR Part of an address expression (prepend +/- but with a space
+ * between the sign and the value for things like [%i1 + 0x55]
+ */
+static void
+prt_imm(dis_handle_t *dhp, uint32_t val, int format)
+{
+ const char *fmtstr = NULL;
+ int32_t sv = (int32_t)val;
+ int octal = dhp->dh_flags & DIS_OCTAL;
+
+ switch (format) {
+ case IMM_ADDR:
+ if (sv < 0) {
+ sv = -sv;
+ fmtstr = (octal != 0) ? "- 0%lo" : "- 0x%lx";
+ } else {
+ fmtstr = (octal != 0) ? "+ 0%lo" : "+ 0x%lx";
+ }
+ break;
+
+ case IMM_SIGNED:
+ if (sv < 0) {
+ sv = -sv;
+ fmtstr = (octal != 0) ? "-0%lo" : "-0x%lx";
+ break;
+ }
+ /* fall through */
+
+ default:
+ fmtstr = (octal != 0) ? "0%lo" : "0x%lx";
+ }
+
+ bprintf(dhp, fmtstr, sv);
+}
+
+/*
+ * return the symbolic name of a register
+ * regset is one of the REG_* values indicating which type of register it is
+ * such as integer, floating point, etc.
+ * idx is the numeric value of the register
+ *
+ * If regset is REG_NONE, an empty, but non-NULL string is returned
+ * NULL may be returned if the index indicates an invalid register value
+ * such as with the %icc/%xcc sets
+ */
+static const char *
+get_regname(dis_handle_t *dhp, int regset, uint32_t idx)
+{
+ const char *regname = NULL;
+
+ switch (regset) {
+ case REG_INT:
+ regname = reg_names[idx];
+ break;
+
+ case REG_FP:
+ regname = freg_names[idx];
+ break;
+
+ case REG_FPD:
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
+ regname = fdreg_names[idx];
+ else
+ regname = compat_fdreg_names[idx];
+
+ break;
+
+ case REG_FPQ:
+ if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
+ regname = fqreg_names[idx];
+ else
+ regname = freg_names[idx];
+
+ break;
+
+ case REG_CP:
+ regname = cpreg_names[idx];
+ break;
+
+ case REG_ICC:
+ regname = icc_names[idx];
+ break;
+
+ case REG_FCC:
+ regname = fcc_names[idx];
+ break;
+
+ case REG_FSR:
+ regname = "%fsr";
+ break;
+
+ case REG_CSR:
+ regname = "%csr";
+ break;
+
+ case REG_CQ:
+ regname = "%cq";
+ break;
+
+ case REG_NONE:
+ regname = "";
+ break;
+ }
+
+ return (regname);
+}
+
+/*
+ * output the asi value from the instruction
+ *
+ * TODO: investigate if this should perhaps have a mask -- are undefined ASI
+ * values for an instruction still disassembled??
+ */
+static void
+prt_asi(dis_handle_t *dhp, uint32_t instr)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
+
+ if (f->f3.i != 0)
+ bprintf(dhp, "%%asi");
+ else
+ bprintf(dhp, (octal != 0) ? "0%03o" : "0x%02x", f->f3.asi);
+
+}
+
+/*
+ * put an address expression into the output buffer
+ *
+ * instr is the instruction to use
+ * if nobrackets != 0, [] are not added around the instruction
+ *
+ * Currently this option is set when printing out the address portion
+ * of a jmpl instruction, but otherwise 0 for load/stores
+ *
+ * If no debug flags are set, the full expression is output, even when
+ * %g0 or 0x0 appears in the address
+ *
+ * If DIS_DEBUG_SYN_ALL or DIS_DEBUG_COMPAT are set, when %g0 or 0x0
+ * appear in the address, they are not output. If the wierd (and probably
+ * shouldn't happen) address of [%g0 + %g0] or [%g0 + 0x0] is encountered,
+ * [%g0] is output
+ */
+static void
+prt_address(dis_handle_t *dhp, uint32_t instr, int nobrackets)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ int32_t simm13;
+ int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
+ int p1 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
+ int p2 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
+
+ if (f->f3a.i == 0) {
+ p1 |= ((f->f3a.rs1 != 0) || f->f3.rs2 == 0);
+ p2 |= (f->f3.rs2 != 0);
+
+ bprintf(dhp, "%s%s%s%s%s",
+ (nobrackets == 0) ? "[" : "",
+ (p1 != 0) ? reg_names[f->f3a.rs1] : "",
+ (p1 != 0 && p2 != 0) ? " + " : "",
+ (p2 != 0) ? reg_names[f->f3.rs2] : "",
+ (nobrackets == 0) ? "]" : "");
+ } else {
+ const char *sign;
+
+ simm13 = sign_extend(f->f3a.simm13, 13);
+ sign = (simm13 < 0) ? "-" : "+";
+
+ p1 |= (f->f3a.rs1 != 0);
+ p2 |= (p1 == 0 || simm13 != 0);
+
+ if (p1 == 0 && simm13 == 0)
+ p2 = 1;
+
+ if (p1 == 0 && simm13 >= 0)
+ sign = "";
+
+ if (p2 != 0)
+ bprintf(dhp,
+ (octal != 0) ? "%s%s%s%s%s0%lo%s" :
+ "%s%s%s%s%s0x%lx%s",
+ (nobrackets == 0) ? "[" : "",
+ (p1 != 0) ? reg_names[f->f3a.rs1] : "",
+ (p1 != 0) ? " " : "",
+ sign,
+ (p1 != 0) ? " " : "",
+ (simm13 < 0) ? -(simm13) : simm13,
+ (nobrackets == 0) ? "]" : "");
+ else
+ bprintf(dhp, "%s%s%s",
+ (nobrackets == 0) ? "[" : "",
+ reg_names[f->f3a.rs1],
+ (nobrackets == 0) ? "]" : "");
+ }
+}
+
+/*
+ * print out the arguments to an alu operation (add, sub, etc.)
+ * conatined in 'instr'
+ *
+ * alu instructions have the following format:
+ * %rs1, %rs2, %rd (i == 0)
+ * %rs1, 0xnnn, %rd (i == 1)
+ * ^ ^ ^
+ * | | |
+ * p1 p2 p3
+ *
+ * flags indicates the register set to use for each position (p1, p2, p3)
+ * as well as if immediate values (i == 1) are allowed
+ *
+ * if flags indicates a specific position has REG_NONE set as it's register
+ * set, it is omitted from the output. This is primarly used for certain
+ * floating point operations
+ */
+static void
+prt_aluargs(dis_handle_t *dhp, uint32_t instr, uint32_t flags)
+{
+ ifmt_t *f = (ifmt_t *)&instr;
+ const char *r1, *r2, *r3;
+ int p1, p2, p3;
+
+ r1 = get_regname(dhp, FLG_P1_VAL(flags), f->f3.rs1);
+ r2 = get_regname(dhp, FLG_P2_VAL(flags), f->f3.rs2);
+ r3 = get_regname(dhp, FLG_P3_VAL(flags), f->f3.rd);
+
+ p1 = (FLG_P1_VAL(flags) != REG_NONE);
+ p2 = (((flags & FLG_NOIMM) == 0) || (FLG_P2_VAL(flags) != REG_NONE));
+ p3 = (FLG_RD_VAL(flags) != REG_NONE);
+
+ if (r1 == NULL || r1[0] == '\0')
+ p1 = 0;
+
+ if (f->f3a.i == 0 && (r2 == NULL || r2[0] == '\0'))
+ p2 = 0;
+
+ if (r3 == NULL || r3[0] == '\0')
+ p3 = 0;
+
+ if (p1 != 0) {
+ (void) strlcat(dhp->dh_buf, r1, dhp->dh_buflen);
+ if (p2 != 0 || p3 != 0)
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+ }
+
+ if (p2 != 0) {
+ if (f->f3.i == 0 || ((flags & FLG_NOIMM) != 0))
+ (void) strlcat(dhp->dh_buf, r2, dhp->dh_buflen);
+ else
+ prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
+ IMM_SIGNED);
+
+ if (p3 != 0)
+ (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
+ }
+
+ if (p3 != 0)
+ (void) strlcat(dhp->dh_buf, r3, dhp->dh_buflen);
+}
+
+/*
+ * just a handy function that takes care of managing the buffer length
+ * w/ printf
+ */
+
+/*
+ * PRINTF LIKE 1
+ */
+static void
+bprintf(dis_handle_t *dhp, const char *fmt, ...)
+{
+ size_t curlen;
+ va_list ap;
+
+ curlen = strlen(dhp->dh_buf);
+
+ va_start(ap, fmt);
+ (void) vsnprintf(dhp->dh_buf + curlen, dhp->dh_buflen - curlen, fmt,
+ ap);
+ va_end(ap);
+}