2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2009 Jason King. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A
2N/A#include <sys/byteorder.h>
2N/A#include <stdarg.h>
2N/A
2N/A#if !defined(DIS_STANDALONE)
2N/A#include <stdio.h>
2N/A#endif /* DIS_STANDALONE */
2N/A
2N/A#include "libdisasm.h"
2N/A#include "libdisasm_impl.h"
2N/A#include "dis_sparc.h"
2N/A#include "dis_sparc_fmt.h"
2N/A
2N/Aextern char *strncpy(char *, const char *, size_t);
2N/Aextern size_t strlen(const char *);
2N/Aextern int strcmp(const char *, const char *);
2N/Aextern int strncmp(const char *, const char *, size_t);
2N/Aextern size_t strlcat(char *, const char *, size_t);
2N/Aextern size_t strlcpy(char *, const char *, size_t);
2N/Aextern int snprintf(char *, size_t, const char *, ...);
2N/Aextern int vsnprintf(char *, size_t, const char *, va_list);
2N/A
2N/A/*
2N/A * This file has the functions that do all the dirty work of outputting the
2N/A * disassembled instruction
2N/A *
2N/A * All the non-static functions follow the format_fcn (in dis_sparc.h):
2N/A * Input:
2N/A * disassembler handle/context
2N/A * instruction to disassemble
2N/A * instruction definition pointer (inst_t *)
2N/A * index in the table of the instruction
2N/A * Return:
2N/A * 0 Success
2N/A * !0 Invalid instruction
2N/A *
2N/A * Generally, instructions found in the same table use the same output format
2N/A * or have a few minor differences (which are described in the 'flags' field
2N/A * of the instruction definition. In some cases, certain instructions differ
2N/A * radically enough from those in the same table, that their own format
2N/A * function is used.
2N/A *
2N/A * Typically each table has a unique format function defined in this file. In
2N/A * some cases (such as branches) a common one for all the tables is used.
2N/A *
2N/A * When adding support for new instructions, it is largely a judgement call
2N/A * as to when a new format function is defined.
2N/A */
2N/A
2N/A/* The various instruction formats of a sparc instruction */
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format1 {
2N/A uint32_t op:2;
2N/A uint32_t disp30:30;
2N/A} format1_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format1 {
2N/A uint32_t disp30:30;
2N/A uint32_t op:2;
2N/A} format1_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format2 {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op2:3;
2N/A uint32_t imm22:22;
2N/A} format2_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format2 {
2N/A uint32_t imm22:22;
2N/A uint32_t op2:3;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} format2_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format2a {
2N/A uint32_t op:2;
2N/A uint32_t a:1;
2N/A uint32_t cond:4;
2N/A uint32_t op2:3;
2N/A uint32_t disp22:22;
2N/A} format2a_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format2a {
2N/A uint32_t disp22:22;
2N/A uint32_t op2:3;
2N/A uint32_t cond:4;
2N/A uint32_t a:1;
2N/A uint32_t op:2;
2N/A} format2a_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format2b {
2N/A uint32_t op:2;
2N/A uint32_t a:1;
2N/A uint32_t cond:4;
2N/A uint32_t op2:3;
2N/A uint32_t cc:2;
2N/A uint32_t p:1;
2N/A uint32_t disp19:19;
2N/A} format2b_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format2b {
2N/A uint32_t disp19:19;
2N/A uint32_t p:1;
2N/A uint32_t cc:2;
2N/A uint32_t op2:3;
2N/A uint32_t cond:4;
2N/A uint32_t a:1;
2N/A uint32_t op:2;
2N/A} format2b_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format2c {
2N/A uint32_t op:2;
2N/A uint32_t a:1;
2N/A uint32_t cond:4;
2N/A uint32_t op2:3;
2N/A uint32_t d16hi:2;
2N/A uint32_t p:1;
2N/A uint32_t rs1:5;
2N/A uint32_t d16lo:14;
2N/A} format2c_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format2c {
2N/A uint32_t d16lo:14;
2N/A uint32_t rs1:5;
2N/A uint32_t p:1;
2N/A uint32_t d16hi:2;
2N/A uint32_t op2:3;
2N/A uint32_t cond:4;
2N/A uint32_t a:1;
2N/A uint32_t op:2;
2N/A} format2c_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format2d {
2N/A uint32_t op:2;
2N/A uint32_t c_hi:1;
2N/A uint32_t op2:1;
2N/A uint32_t c_lo:3;
2N/A uint32_t op3:3;
2N/A uint32_t cc2:1;
2N/A uint32_t d10_hi:2;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t d10_lo:8;
2N/A uint32_t rs2:5;
2N/A} format2d_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format2d {
2N/A uint32_t rs2:5;
2N/A uint32_t d10_lo:8;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t d10_hi:2;
2N/A uint32_t cc2:1;
2N/A uint32_t op3:3;
2N/A uint32_t c_lo:3;
2N/A uint32_t op2:1;
2N/A uint32_t c_hi:1;
2N/A uint32_t op:2;
2N/A} format2d_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format3 {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t asi:8;
2N/A uint32_t rs2:5;
2N/A} format3_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format3 {
2N/A uint32_t rs2:5;
2N/A uint32_t asi:8;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} format3_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format3a {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t simm13:13;
2N/A} format3a_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format3a {
2N/A uint32_t simm13:13;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} format3a_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format3b {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t x:1;
2N/A uint32_t undef:6;
2N/A uint32_t shcnt:6;
2N/A} format3b_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format3b {
2N/A uint32_t shcnt:6;
2N/A uint32_t undef:6;
2N/A uint32_t x:1;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} format3b_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format3c {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t cc2:1;
2N/A uint32_t cond:4;
2N/A uint32_t i:1;
2N/A uint32_t cc:2;
2N/A uint32_t simm11:11;
2N/A} format3c_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format3c {
2N/A uint32_t simm11:11;
2N/A uint32_t cc:2;
2N/A uint32_t i:1;
2N/A uint32_t cond:4;
2N/A uint32_t cc2:1;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} format3c_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct format3d {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t rcond:3;
2N/A uint32_t simm10:10;
2N/A} format3d_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct format3d {
2N/A uint32_t simm10:10;
2N/A uint32_t rcond:3;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} format3d_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formatcp {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t opc:9;
2N/A uint32_t rs2:5;
2N/A} formatcp_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formatcp {
2N/A uint32_t rs2:5;
2N/A uint32_t opc:9;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} formatcp_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formattcc {
2N/A uint32_t op:2;
2N/A uint32_t undef:1;
2N/A uint32_t cond:4;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t cc:2;
2N/A uint32_t undef2:3;
2N/A uint32_t immtrap:8;
2N/A} formattcc_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formattcc {
2N/A uint32_t immtrap:8;
2N/A uint32_t undef2:3;
2N/A uint32_t cc:2;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t cond:4;
2N/A uint32_t undef:1;
2N/A uint32_t op:2;
2N/A} formattcc_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formattcc2 {
2N/A uint32_t op:2;
2N/A uint32_t undef:1;
2N/A uint32_t cond:4;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t cc:2;
2N/A uint32_t undef2:6;
2N/A uint32_t rs2:5;
2N/A} formattcc2_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formattcc2 {
2N/A uint32_t rs2:5;
2N/A uint32_t undef2:6;
2N/A uint32_t cc:2;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t cond:4;
2N/A uint32_t undef:1;
2N/A uint32_t op:2;
2N/A} formattcc2_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formatmbr {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t i:1;
2N/A uint32_t undef:6;
2N/A uint32_t cmask:3;
2N/A uint32_t mmask:4;
2N/A} formatmbr_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formatmbr {
2N/A uint32_t mmask:4;
2N/A uint32_t cmask:3;
2N/A uint32_t undef:6;
2N/A uint32_t i:1;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} formatmbr_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formatfcmp {
2N/A uint32_t op:2;
2N/A uint32_t undef:3;
2N/A uint32_t cc:2;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t opf:9;
2N/A uint32_t rs2:5;
2N/A} formatfcmp_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formatfcmp {
2N/A uint32_t rs2:5;
2N/A uint32_t opf:9;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t cc:2;
2N/A uint32_t undef:3;
2N/A uint32_t op:2;
2N/A} formatfcmp_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formatfmov {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t undef:1;
2N/A uint32_t cond:4;
2N/A uint32_t cc:3;
2N/A uint32_t opf:6;
2N/A uint32_t rs2:5;
2N/A} formatfmov_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formatfmov {
2N/A uint32_t rs2:5;
2N/A uint32_t opf:6;
2N/A uint32_t cc:3;
2N/A uint32_t cond:4;
2N/A uint32_t undef:1;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} formatfmov_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formatfused {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t rs3:5;
2N/A uint32_t op5:4;
2N/A uint32_t rs2:5;
2N/A} formatfused_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formatfused {
2N/A uint32_t rs2:5;
2N/A uint32_t op5:4;
2N/A uint32_t rs3:5;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} formatfused_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/A#if defined(_BIT_FIELDS_HTOL)
2N/Atypedef struct formatcrypto {
2N/A uint32_t op:2;
2N/A uint32_t rd:5;
2N/A uint32_t op3:6;
2N/A uint32_t rs1:5;
2N/A uint32_t opf:9;
2N/A uint32_t imm5:5;
2N/A} formatcrypto_t;
2N/A#elif defined(_BIT_FIELDS_LTOH)
2N/Atypedef struct formatcrypto {
2N/A uint32_t imm5:5;
2N/A uint32_t opf:9;
2N/A uint32_t rs1:5;
2N/A uint32_t op3:6;
2N/A uint32_t rd:5;
2N/A uint32_t op:2;
2N/A} formatcrypto_t;
2N/A#else
2N/A#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
2N/A#endif
2N/A
2N/Atypedef union ifmt {
2N/A uint32_t i;
2N/A format1_t f1;
2N/A format2_t f2;
2N/A format2a_t f2a;
2N/A format2b_t f2b;
2N/A format2c_t f2c;
2N/A format2d_t f2d;
2N/A format3_t f3;
2N/A format3a_t f3a;
2N/A format3b_t f3b;
2N/A format3c_t f3c;
2N/A format3d_t f3d;
2N/A formatcp_t fcp;
2N/A formattcc_t ftcc;
2N/A formattcc2_t ftcc2;
2N/A formatfcmp_t fcmp;
2N/A formatmbr_t fmb;
2N/A formatfmov_t fmv;
2N/A formatfused_t fused;
2N/A formatcrypto_t fcrypto;
2N/A} ifmt_t;
2N/A
2N/A/* integer register names */
2N/Astatic const char *reg_names[32] = {
2N/A "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
2N/A "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
2N/A "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
2N/A "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7"
2N/A};
2N/A
2N/A/* floating point register names */
2N/Astatic const char *freg_names[32] = {
2N/A "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
2N/A "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
2N/A "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
2N/A "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31"
2N/A};
2N/A
2N/A/* double precision register names */
2N/Astatic const char *fdreg_names[32] = {
2N/A "%d0", "%d32", "%d2", "%d34", "%d4", "%d36", "%d6", "%d38",
2N/A "%d8", "%d40", "%d10", "%d42", "%d12", "%d44", "%d14", "%d46",
2N/A "%d16", "%d48", "%d18", "%d50", "%d20", "%d52", "%d22", "%d54",
2N/A "%d24", "%d56", "%d26", "%d58", "%d28", "%d60", "%d30", "%d62"
2N/A};
2N/A
2N/Astatic const char *compat_fdreg_names[32] = {
2N/A "%f0", "%f32", "%f2", "%f34", "%f4", "%f36", "%f6", "%f38",
2N/A "%f8", "%f40", "%f10", "%f42", "%f12", "%f44", "%f14", "%f46",
2N/A "%f16", "%f48", "%f18", "%f50", "%f20", "%f52", "%f22", "%f54",
2N/A "%f24", "%f56", "%f26", "%f58", "%f28", "%f60", "%f30", "%f62"
2N/A};
2N/A
2N/A
2N/Astatic const char *fqreg_names[32] = {
2N/A "%q0", "%q32", "%f2", "%f3", "%f4", "%q4", "%q36", "%f6",
2N/A "%f7", "%q8", "%q40", "%f10", "%f11", "%q12", "%q44", "%f14",
2N/A "%f15", "%q16", "%q48", "%f18", "%f19", "%q20", "%q52", "%f22",
2N/A "%f23", "%q24", "%q56", "%f26", "%f27", "%q28", "%q60", "%f30",
2N/A};
2N/A
2N/A
2N/A/* coprocessor register names -- sparcv8 only */
2N/Astatic const char *cpreg_names[32] = {
2N/A "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
2N/A "%c8", "%c9", "%c10", "%c11", "%c12", "%c13", "%c14", "%c15",
2N/A "%c16", "%c17", "%c18", "%c19", "%c20", "%c21", "%c22", "%c23",
2N/A "%c24", "%c25", "%c26", "%c27", "%c28", "%c29", "%c30", "%c31",
2N/A};
2N/A
2N/A/* floating point condition code names */
2N/Astatic const char *fcc_names[4] = {
2N/A "%fcc0", "%fcc1", "%fcc2", "%fcc3"
2N/A};
2N/A
2N/A/* condition code names */
2N/Astatic const char *icc_names[4] = {
2N/A "%icc", NULL, "%xcc", NULL
2N/A};
2N/A
2N/A/* bitmask values for membar */
2N/Astatic const char *membar_mmask[4] = {
2N/A "#LoadLoad", "#StoreLoad", "#LoadStore", "#StoreStore"
2N/A};
2N/A
2N/Astatic const char *membar_cmask[3] = {
2N/A "#Lookaside", "#MemIssue", "#Sync"
2N/A};
2N/A
2N/A/* v8 ancillary state register names */
2N/Astatic const char *asr_names[32] = {
2N/A "%y", "%asr1", "%asr2", "%asr3",
2N/A "%asr4", "%asr5", "%asr6", "%asr7",
2N/A "%asr8", "%asr9", "%asr10", "%asr11",
2N/A "%asr12", "%asr13", "%asr14", "%asr15",
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL
2N/A};
2N/Astatic const uint32_t asr_rdmask = 0x0000ffffL;
2N/Astatic const uint32_t asr_wrmask = 0x0000ffffL;
2N/A
2N/Astatic const char *v9_asr_names[32] = {
2N/A "%y", NULL, "%ccr", "%asi",
2N/A "%tick", "%pc", "%fprs", NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A "%pcr", "%pic", "%dcr", "%gsr",
2N/A "%softint_set", "%softint_clr", "%softint", "%tick_cmpr",
2N/A "%stick", "%stick_cmpr", "%cfr", "%pause",
2N/A NULL, NULL, NULL, NULL
2N/A};
2N/A/*
2N/A * on v9, only certain registers are valid for read or writing
2N/A * these are bitmasks corresponding to which registers are valid in which
2N/A * case. Any access to %dcr is illegal.
2N/A */
2N/Astatic const uint32_t v9_asr_rdmask = 0x0fcb007d;
2N/Astatic const uint32_t v9_asr_wrmask = 0x0ffb004d;
2N/A
2N/A/* privledged register names on v9 */
2N/A/* TODO: compat - NULL to %priv_nn */
2N/Astatic const char *v9_privreg_names[32] = {
2N/A "%tpc", "%tnpc", "%tstate", "%tt",
2N/A "%tick", "%tba", "%pstate", "%tl",
2N/A "%pil", "%cwp", "%cansave", "%canrestore",
2N/A "%cleanwin", "%otherwin", "%wstate", "%fq",
2N/A "%gl", NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, "%ver"
2N/A};
2N/A
2N/A/* hyper privileged register names on v9 */
2N/Astatic const char *v9_hprivreg_names[32] = {
2N/A "%hpstate", "%htstate", NULL, "%hintp",
2N/A NULL, "%htba", "%hver", NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, "%hstick_cmpr"
2N/A};
2N/A
2N/Astatic const uint32_t v9_pr_rdmask = 0x80017fff;
2N/Astatic const uint32_t v9_pr_wrmask = 0x00017fff;
2N/Astatic const uint32_t v9_hpr_rdmask = 0x8000006b;
2N/Astatic const uint32_t v9_hpr_wrmask = 0x8000006b;
2N/A
2N/Astatic const char *prefetch_str[32] = {
2N/A "#n_reads", "#one_read",
2N/A "#n_writes", "#one_write",
2N/A "#page", NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, "#unified", NULL, NULL,
2N/A "#n_reads_strong", "#one_read_strong",
2N/A "#n_writes_strong", "#one_write_strong",
2N/A NULL, NULL, NULL, NULL,
2N/A NULL, NULL, NULL, NULL
2N/A};
2N/A
2N/Astatic void prt_field(const char *, uint32_t, int);
2N/A
2N/Astatic const char *get_regname(dis_handle_t *, int, uint32_t);
2N/Astatic int32_t sign_extend(int32_t, int32_t);
2N/A
2N/Astatic void prt_name(dis_handle_t *, const char *, int);
2N/A
2N/A#define IMM_SIGNED 0x01 /* Is immediate value signed */
2N/A#define IMM_ADDR 0x02 /* Is immediate value part of an address */
2N/Astatic void prt_imm(dis_handle_t *, uint32_t, int);
2N/A
2N/Astatic void prt_asi(dis_handle_t *, uint32_t);
2N/Astatic const char *get_asi_name(uint8_t);
2N/Astatic void prt_address(dis_handle_t *, uint32_t, int);
2N/Astatic void prt_aluargs(dis_handle_t *, uint32_t, uint32_t);
2N/Astatic void bprintf(dis_handle_t *, const char *, ...);
2N/A
2N/A/*
2N/A * print out val (which is 'bitlen' bits long) in binary
2N/A */
2N/A#if defined(DIS_STANDALONE)
2N/A/* ARGSUSED */
2N/Avoid
2N/Aprt_binary(uint32_t val, int bitlen)
2N/A{
2N/A
2N/A}
2N/A
2N/A#else
2N/A
2N/Avoid
2N/Aprt_binary(uint32_t val, int bitlen)
2N/A{
2N/A int i;
2N/A
2N/A for (i = bitlen - 1; i >= 0; --i) {
2N/A (void) fprintf(stderr, ((val & (1L << i)) != 0) ? "1" : "0");
2N/A
2N/A if (i % 4 == 0 && i != 0)
2N/A (void) fprintf(stderr, " ");
2N/A }
2N/A}
2N/A#endif /* DIS_STANDALONE */
2N/A
2N/A
2N/A/*
2N/A * print out a call instruction
2N/A * format: call address <name>
2N/A */
2N/A/* ARGSUSED1 */
2N/Aint
2N/Afmt_call(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A int32_t disp;
2N/A size_t curlen;
2N/A
2N/A int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f1.op, 2);
2N/A prt_field("disp30", f->f1.disp30, 30);
2N/A }
2N/A
2N/A disp = sign_extend(f->f1.disp30, 30) * 4;
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A
2N/A bprintf(dhp, (octal != 0) ? "%s0%-11lo" : "%s0x%-10lx",
2N/A (disp < 0) ? "-" : "+",
2N/A (disp < 0) ? (-disp) : disp);
2N/A
2N/A (void) strlcat(dhp->dh_buf, " <", dhp->dh_buflen);
2N/A
2N/A curlen = strlen(dhp->dh_buf);
2N/A dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
2N/A dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL,
2N/A NULL);
2N/A (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
2N/A
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmt_sethi(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f2.op, 2);
2N/A prt_field("op2", f->f2.op2, 3);
2N/A prt_field("rd", f->f2.rd, 5);
2N/A prt_field("imm22", f->f2.imm22, 22);
2N/A }
2N/A
2N/A if (idx == 0) {
2N/A /* unimp / illtrap */
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A prt_imm(dhp, f->f2.imm22, 0);
2N/A return (0);
2N/A }
2N/A
2N/A if (f->f2.imm22 == 0 && f->f2.rd == 0) {
2N/A prt_name(dhp, "nop", 0);
2N/A return (0);
2N/A }
2N/A
2N/A /* ?? Should we return -1 if rd == 0 && disp != 0 */
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A
2N/A bprintf(dhp,
2N/A ((dhp->dh_flags & DIS_OCTAL) != 0) ?
2N/A "%%hi(0%lo), %s" : "%%hi(0x%lx), %s",
2N/A f->f2.imm22 << 10,
2N/A reg_names[f->f2.rd]);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_branch(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A const char *name = inp->in_data.in_def.in_name;
2N/A const char *r = NULL;
2N/A const char *annul = "";
2N/A const char *pred = "";
2N/A
2N/A char buf[15];
2N/A
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A size_t curlen;
2N/A int32_t disp;
2N/A uint32_t flags = inp->in_data.in_def.in_flags;
2N/A int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f2.op, 2);
2N/A prt_field("op2", f->f2.op2, 3);
2N/A
2N/A switch (FLG_DISP_VAL(flags)) {
2N/A case DISP22:
2N/A prt_field("cond", f->f2a.cond, 4);
2N/A prt_field("a", f->f2a.a, 1);
2N/A prt_field("disp22", f->f2a.disp22, 22);
2N/A break;
2N/A
2N/A case DISP19:
2N/A prt_field("cond", f->f2a.cond, 4);
2N/A prt_field("a", f->f2a.a, 1);
2N/A prt_field("p", f->f2b.p, 1);
2N/A prt_field("cc", f->f2b.cc, 2);
2N/A prt_field("disp19", f->f2b.disp19, 19);
2N/A break;
2N/A
2N/A case DISP16:
2N/A prt_field("bit 28", ((instr & (1L << 28)) >> 28), 1);
2N/A prt_field("rcond", f->f2c.cond, 3);
2N/A prt_field("p", f->f2c.p, 1);
2N/A prt_field("rs1", f->f2c.rs1, 5);
2N/A prt_field("d16hi", f->f2c.d16hi, 2);
2N/A prt_field("d16lo", f->f2c.d16lo, 14);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (f->f2b.op2 == 0x01 && idx == 0x00 && f->f2b.p == 1 &&
2N/A f->f2b.cc == 0x02 && ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0)) {
2N/A name = "iprefetch";
2N/A flags = FLG_RS1(REG_NONE)|FLG_DISP(DISP19);
2N/A }
2N/A
2N/A
2N/A switch (FLG_DISP_VAL(flags)) {
2N/A case DISP22:
2N/A disp = sign_extend(f->f2a.disp22, 22);
2N/A break;
2N/A
2N/A case DISP19:
2N/A disp = sign_extend(f->f2b.disp19, 19);
2N/A break;
2N/A
2N/A case DISP16:
2N/A disp = sign_extend((f->f2c.d16hi << 14)|f->f2c.d16lo, 16);
2N/A break;
2N/A
2N/A }
2N/A
2N/A disp *= 4;
2N/A
2N/A if ((FLG_RS1_VAL(flags) == REG_ICC) || (FLG_RS1_VAL(flags) == REG_FCC))
2N/A r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2b.cc);
2N/A else
2N/A r = get_regname(dhp, FLG_RS1_VAL(flags), f->f2c.rs1);
2N/A
2N/A if (r == NULL)
2N/A return (-1);
2N/A
2N/A if (f->f2a.a == 1)
2N/A annul = ",a";
2N/A
2N/A if ((flags & FLG_PRED) != 0) {
2N/A if (f->f2b.p == 0) {
2N/A pred = ",pn";
2N/A } else {
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)
2N/A pred = ",pt";
2N/A }
2N/A }
2N/A
2N/A (void) snprintf(buf, sizeof (buf), "%s%s%s", name, annul, pred);
2N/A prt_name(dhp, buf, 1);
2N/A
2N/A
2N/A switch (FLG_DISP_VAL(flags)) {
2N/A case DISP22:
2N/A bprintf(dhp,
2N/A (octal != 0) ? "%s0%-11lo <" : "%s0x%-10lx <",
2N/A (disp < 0) ? "-" : "+",
2N/A (disp < 0) ? (-disp) : disp);
2N/A break;
2N/A
2N/A case DISP19:
2N/A bprintf(dhp,
2N/A (octal != 0) ? "%s, %s0%-5lo <" :
2N/A "%s, %s0x%-04lx <", r,
2N/A (disp < 0) ? "-" : "+",
2N/A (disp < 0) ? (-disp) : disp);
2N/A break;
2N/A
2N/A case DISP16:
2N/A bprintf(dhp,
2N/A (octal != 0) ? "%s, %s0%-6lo <" : "%s, %s0x%-5lx <",
2N/A r,
2N/A (disp < 0) ? "-" : "+",
2N/A (disp < 0) ? (-disp) : disp);
2N/A break;
2N/A }
2N/A
2N/A curlen = strlen(dhp->dh_buf);
2N/A dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
2N/A dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL, NULL);
2N/A
2N/A (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A
2N/A/*
2N/A * print out the compare and swap instructions (casa/casxa)
2N/A * format: casa/casxa [%rs1] imm_asi, %rs2, %rd
2N/A * casa/casxa [%rs1] %asi, %rs2, %rd
2N/A *
2N/A * If DIS_DEBUG_SYN_ALL is set, synthetic instructions are emitted
2N/A * when an immediate ASI value is given as follows:
2N/A *
2N/A * casa [%rs1]#ASI_P, %rs2, %rd -> cas [%rs1], %rs2, %rd
2N/A * casa [%rs1]#ASI_P_L, %rs2, %rd -> casl [%rs1], %rs2, %rd
2N/A * casxa [%rs1]#ASI_P, %rs2, %rd -> casx [%rs1], %rs2, %rd
2N/A * casxa [%rs1]#ASI_P_L, %rs2, %rd -> casxl [%rs1], %rs2, %rd
2N/A */
2N/Astatic int
2N/Afmt_cas(dis_handle_t *dhp, uint32_t instr, const char *name)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A const char *asistr = NULL;
2N/A int noasi = 0;
2N/A
2N/A asistr = get_asi_name(f->f3.asi);
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT)) != 0) {
2N/A if (f->f3.op3 == 0x3c && f->f3.i == 0) {
2N/A if (f->f3.asi == 0x80) {
2N/A noasi = 1;
2N/A name = "cas";
2N/A }
2N/A
2N/A if (f->f3.asi == 0x88) {
2N/A noasi = 1;
2N/A name = "casl";
2N/A }
2N/A }
2N/A
2N/A if (f->f3.op3 == 0x3e && f->f3.i == 0) {
2N/A if (f->f3.asi == 0x80) {
2N/A noasi = 1;
2N/A name = "casx";
2N/A }
2N/A
2N/A if (f->f3.asi == 0x88) {
2N/A noasi = 1;
2N/A name = "casxl";
2N/A }
2N/A }
2N/A }
2N/A
2N/A prt_name(dhp, name, 1);
2N/A
2N/A bprintf(dhp, "[%s]", reg_names[f->f3.rs1]);
2N/A
2N/A if (noasi == 0) {
2N/A (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
2N/A prt_asi(dhp, instr);
2N/A }
2N/A
2N/A bprintf(dhp, ", %s, %s", reg_names[f->f3.rs2], reg_names[f->f3.rd]);
2N/A
2N/A if (noasi == 0 && asistr != NULL)
2N/A bprintf(dhp, "\t<%s>", asistr);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * format a load/store instruction
2N/A * format: ldXX [%rs1 + %rs2], %rd load, i==0
2N/A * ldXX [%rs1 +/- nn], %rd load, i==1
2N/A * ldXX [%rs1 + %rs2] #XX, %rd load w/ imm_asi, i==0
2N/A * ldXX [%rs1 +/- nn] %asi, %rd load from asi[%asi], i==1
2N/A *
2N/A * stXX %rd, [%rs1 + %rs2] store, i==0
2N/A * stXX %rd, [%rs1 +/- nn] store, i==1
2N/A * stXX %rd, [%rs1 + %rs1] #XX store to imm_asi, i==0
2N/A * stXX %rd, [%rs1 +/-nn] %asi store to asi[%asi], i==1
2N/A *
2N/A * The register sets used for %rd are set in the instructions flags field
2N/A * The asi variants are used if FLG_ASI is set in the instructions flags field
2N/A *
2N/A * If DIS_DEBUG_SYNTH_ALL or DIS_DEBUG_COMPAT are set,
2N/A * When %rs1, %rs2 or nn are 0, they are not printed, i.e.
2N/A * [ %rs1 + 0x0 ], %rd -> [%rs1], %rd for example
2N/A *
2N/A * The following synthetic instructions are also implemented:
2N/A *
2N/A * stb %g0, [addr] -> clrb [addr] DIS_DEBUG_SYNTH_ALL
2N/A * sth %g0, [addr] -> crlh [addr] DIS_DEBUG_SYNTH_ALL
2N/A * stw %g0, [addr] -> clr [addr] DIS_DEBUG_SYNTH_ALL|DIS_DEBUG_COMPAT
2N/A * stx %g0, [addr] -> clrx [addr] DIS_DEBUG_SYNTH_ALL
2N/A *
2N/A * If DIS_DEBUG_COMPAT is set, the following substitutions also take place
2N/A * lduw -> ld
2N/A * ldtw -> ld
2N/A * stuw -> st
2N/A * sttw -> st
2N/A */
2N/Aint
2N/Afmt_ls(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A const char *regstr = NULL;
2N/A const char *asistr = NULL;
2N/A
2N/A const char *iname = inp->in_data.in_def.in_name;
2N/A uint32_t flags = inp->in_data.in_def.in_flags;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f3.op, 2);
2N/A prt_field("op3", f->f3.op3, 6);
2N/A prt_field("rs1", f->f3.rs1, 5);
2N/A prt_field("i", f->f3.i, 1);
2N/A if (f->f3.i != 0) {
2N/A prt_field("simm13", f->f3a.simm13, 13);
2N/A } else {
2N/A if ((flags & FLG_ASI) != 0)
2N/A prt_field("imm_asi", f->f3.asi, 8);
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A }
2N/A prt_field("rd", f->f3.rd, 5);
2N/A }
2N/A
2N/A if (idx == 0x2d || idx == 0x3d) {
2N/A /* prefetch / prefetcha */
2N/A
2N/A prt_name(dhp, iname, 1);
2N/A
2N/A prt_address(dhp, instr, 0);
2N/A
2N/A if (idx == 0x3d) {
2N/A (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
2N/A prt_asi(dhp, instr);
2N/A }
2N/A
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A
2N/A /* fcn field is the same as rd */
2N/A if (prefetch_str[f->f3.rd] != NULL)
2N/A (void) strlcat(dhp->dh_buf, prefetch_str[f->f3.rd],
2N/A dhp->dh_buflen);
2N/A else
2N/A prt_imm(dhp, f->f3.rd, 0);
2N/A
2N/A if (idx == 0x3d && f->f3.i == 0) {
2N/A asistr = get_asi_name(f->f3.asi);
2N/A if (asistr != NULL)
2N/A bprintf(dhp, "\t<%s>", asistr);
2N/A }
2N/A
2N/A return (0);
2N/A }
2N/A
2N/A /* casa / casxa */
2N/A if (idx == 0x3c || idx == 0x3e)
2N/A return (fmt_cas(dhp, instr, iname));
2N/A
2N/A /* synthetic instructions & special cases */
2N/A switch (idx) {
2N/A case 0x00:
2N/A /* ld */
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
2N/A iname = "lduw";
2N/A break;
2N/A
2N/A case 0x03:
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
2N/A iname = "ldtw";
2N/A break;
2N/A
2N/A case 0x04:
2N/A /* stw */
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
2N/A iname = "stuw";
2N/A
2N/A if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rd == 0) {
2N/A iname = "clr";
2N/A flags = FLG_RD(REG_NONE);
2N/A }
2N/A break;
2N/A
2N/A case 0x05:
2N/A /* stb */
2N/A if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rd == 0) {
2N/A iname = "clrb";
2N/A flags = FLG_RD(REG_NONE);
2N/A }
2N/A break;
2N/A
2N/A case 0x06:
2N/A /* sth */
2N/A if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rd == 0) {
2N/A iname = "clrh";
2N/A flags = FLG_RD(REG_NONE);
2N/A }
2N/A break;
2N/A
2N/A case 0x07:
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
2N/A iname = "sttw";
2N/A break;
2N/A
2N/A case 0x0e:
2N/A /* stx */
2N/A
2N/A if ((dhp->dh_flags & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rd == 0) {
2N/A iname = "clrx";
2N/A flags = FLG_RD(REG_NONE);
2N/A }
2N/A break;
2N/A
2N/A case 0x13:
2N/A /* ldtwa */
2N/A if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) &&
2N/A ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
2N/A iname = "ldtwa";
2N/A break;
2N/A
2N/A case 0x17:
2N/A /* sttwa */
2N/A if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) &&
2N/A ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
2N/A iname = "sttwa";
2N/A break;
2N/A
2N/A case 0x21:
2N/A case 0x25:
2N/A /*
2N/A * on sparcv8 it merely says that rd != 1 should generate an
2N/A * exception, on v9, it is illegal
2N/A */
2N/A if ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0)
2N/A break;
2N/A
2N/A iname = (idx == 0x21) ? "ldx" : "stx";
2N/A
2N/A if (f->f3.rd > 1)
2N/A return (-1);
2N/A
2N/A break;
2N/A
2N/A case 0x31:
2N/A /* stda */
2N/A switch (f->f3.asi) {
2N/A case 0xc0:
2N/A case 0xc1:
2N/A case 0xc8:
2N/A case 0xc9:
2N/A case 0xc2:
2N/A case 0xc3:
2N/A case 0xca:
2N/A case 0xcb:
2N/A case 0xc4:
2N/A case 0xc5:
2N/A case 0xcc:
2N/A case 0xcd:
2N/A /*
2N/A * store partial floating point, only valid w/
2N/A * vis
2N/A *
2N/A * Somewhat confusingly, it uses the same op
2N/A * code as 'stda' -- store double to alternate
2N/A * space. It is distinguised by specific
2N/A * imm_asi values (as seen above), and
2N/A * has a slightly different output syntax
2N/A */
2N/A
2N/A if ((dhp->dh_flags & DIS_SPARC_V9_SGI) == 0)
2N/A break;
2N/A if (f->f3.i != 0)
2N/A break;
2N/A prt_name(dhp, iname, 1);
2N/A bprintf(dhp, "%s, %s, [%s] ",
2N/A get_regname(dhp, REG_FPD, f->f3.rd),
2N/A get_regname(dhp, REG_FPD, f->f3.rs2),
2N/A get_regname(dhp, REG_FPD, f->f3.rs1));
2N/A prt_asi(dhp, instr);
2N/A asistr = get_asi_name(f->f3.asi);
2N/A if (asistr != NULL)
2N/A bprintf(dhp, "\t<%s>", asistr);
2N/A
2N/A return (0);
2N/A
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A }
2N/A
2N/A regstr = get_regname(dhp, FLG_RD_VAL(flags), f->f3.rd);
2N/A
2N/A if (f->f3.i == 0)
2N/A asistr = get_asi_name(f->f3.asi);
2N/A
2N/A prt_name(dhp, iname, 1);
2N/A
2N/A if ((flags & FLG_STORE) != 0) {
2N/A if (regstr[0] != '\0') {
2N/A (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A }
2N/A
2N/A prt_address(dhp, instr, 0);
2N/A if ((flags & FLG_ASI) != 0) {
2N/A (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
2N/A prt_asi(dhp, instr);
2N/A }
2N/A } else {
2N/A prt_address(dhp, instr, 0);
2N/A if ((flags & FLG_ASI) != 0) {
2N/A (void) strlcat(dhp->dh_buf, " ", dhp->dh_buflen);
2N/A prt_asi(dhp, instr);
2N/A }
2N/A
2N/A if (regstr[0] != '\0') {
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
2N/A }
2N/A }
2N/A
2N/A if ((flags & FLG_ASI) != 0 && asistr != NULL)
2N/A bprintf(dhp, "\t<%s>", asistr);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Afmt_cpop(dis_handle_t *dhp, uint32_t instr, const inst_t *inp)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int flags = FLG_P1(REG_CP)|FLG_P2(REG_CP)|FLG_NOIMM|FLG_P3(REG_CP);
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->fcp.op, 2);
2N/A prt_field("op3", f->fcp.op3, 6);
2N/A prt_field("opc", f->fcp.opc, 9);
2N/A prt_field("rs1", f->fcp.rs1, 5);
2N/A prt_field("rs2", f->fcp.rs2, 5);
2N/A prt_field("rd", f->fcp.rd, 5);
2N/A }
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A prt_imm(dhp, f->fcp.opc, 0);
2N/A
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A (void) prt_aluargs(dhp, instr, flags);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Adis_fmt_rdwr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A const char *psr_str = "%psr";
2N/A const char *wim_str = "%wim";
2N/A const char *tbr_str = "%tbr";
2N/A
2N/A const char *name = inp->in_data.in_def.in_name;
2N/A const char *regstr = NULL;
2N/A
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A int rd = (idx < 0x30);
2N/A int v9 = (dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI));
2N/A int ridx = f->f3.rs1;
2N/A int i, first;
2N/A int pr_rs1 = 1;
2N/A int pr_rs2 = 1;
2N/A
2N/A int use_mask = 1;
2N/A uint32_t mask;
2N/A
2N/A if (rd == 0)
2N/A ridx = f->f3.rd;
2N/A
2N/A switch (idx) {
2N/A case 0x28:
2N/A /* rd */
2N/A
2N/A /* stbar */
2N/A if ((f->f3.rd == 0) && (f->f3.rs1 == 15) && (f->f3.i == 0)) {
2N/A prt_name(dhp, "stbar", 0);
2N/A return (0);
2N/A }
2N/A
2N/A /* membar */
2N/A if ((v9 != 0) && (f->f3.rd == 0) && (f->f3.rs1 == 15) &&
2N/A (f->f3.i == 1) && ((f->i & (1L << 12)) == 0)) {
2N/A
2N/A prt_name(dhp, "membar",
2N/A ((f->fmb.cmask != 0) || (f->fmb.mmask != 0)));
2N/A
2N/A first = 0;
2N/A
2N/A for (i = 0; i < 4; ++i) {
2N/A if ((f->fmb.cmask & (1L << i)) != 0) {
2N/A bprintf(dhp, "%s%s",
2N/A (first != 0) ? "|" : "",
2N/A membar_cmask[i]);
2N/A first = 1;
2N/A }
2N/A }
2N/A
2N/A for (i = 0; i < 5; ++i) {
2N/A if ((f->fmb.mmask & (1L << i)) != 0) {
2N/A bprintf(dhp, "%s%s",
2N/A (first != 0) ? "|" : "",
2N/A membar_mmask[i]);
2N/A first = 1;
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A }
2N/A
2N/A if (v9 != 0) {
2N/A regstr = v9_asr_names[ridx];
2N/A mask = v9_asr_rdmask;
2N/A } else {
2N/A regstr = asr_names[ridx];
2N/A mask = asr_rdmask;
2N/A }
2N/A break;
2N/A
2N/A case 0x29:
2N/A if (v9 != 0) {
2N/A regstr = v9_hprivreg_names[ridx];
2N/A mask = v9_hpr_rdmask;
2N/A } else {
2N/A regstr = psr_str;
2N/A use_mask = 0;
2N/A }
2N/A break;
2N/A
2N/A case 0x2a:
2N/A if (v9 != 0) {
2N/A regstr = v9_privreg_names[ridx];
2N/A mask = v9_pr_rdmask;
2N/A } else {
2N/A regstr = wim_str;
2N/A use_mask = 0;
2N/A }
2N/A break;
2N/A
2N/A case 0x2b:
2N/A if (v9 != 0) {
2N/A /* flushw */
2N/A prt_name(dhp, name, 0);
2N/A return (0);
2N/A }
2N/A
2N/A regstr = tbr_str;
2N/A use_mask = 0;
2N/A break;
2N/A
2N/A case 0x30:
2N/A if (v9 != 0) {
2N/A regstr = v9_asr_names[ridx];
2N/A mask = v9_asr_wrmask;
2N/A } else {
2N/A regstr = asr_names[ridx];
2N/A mask = asr_wrmask;
2N/A }
2N/A
2N/A /*
2N/A * sir is shoehorned in here, per Ultrasparc 2007
2N/A * hyperprivileged edition, section 7.88, all of
2N/A * these must be true to distinguish from WRasr
2N/A */
2N/A if (v9 != 0 && f->f3.rd == 15 && f->f3.rs1 == 0 &&
2N/A f->f3.i == 1) {
2N/A prt_name(dhp, "sir", 1);
2N/A prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
2N/A IMM_SIGNED);
2N/A return (0);
2N/A }
2N/A
2N/A /* synth: mov */
2N/A if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
2N/A == 0)
2N/A break;
2N/A
2N/A if (v9 == 0) {
2N/A if (f->f3.rs1 == 0) {
2N/A name = "mov";
2N/A pr_rs1 = 0;
2N/A }
2N/A
2N/A if ((f->f3.i == 0 && f->f3.rs2 == 0) ||
2N/A (f->f3.i == 1 && f->f3a.simm13 == 0)) {
2N/A name = "mov";
2N/A pr_rs2 = 0;
2N/A }
2N/A }
2N/A
2N/A if (pr_rs1 == 0)
2N/A pr_rs2 = 1;
2N/A
2N/A break;
2N/A
2N/A case 0x31:
2N/A /*
2N/A * NOTE: due to the presence of an overlay entry for another
2N/A * table, this case only happens when doing v8 instructions
2N/A * only
2N/A */
2N/A regstr = psr_str;
2N/A use_mask = 0;
2N/A break;
2N/A
2N/A case 0x32:
2N/A if (v9 != 0) {
2N/A regstr = v9_privreg_names[ridx];
2N/A mask = v9_pr_wrmask;
2N/A } else {
2N/A regstr = wim_str;
2N/A use_mask = 0;
2N/A }
2N/A break;
2N/A
2N/A case 0x33:
2N/A if (v9 != 0) {
2N/A if (ridx == 30) {
2N/A /* special case for halt */
2N/A prt_name(dhp, "halt", 0);
2N/A return (0);
2N/A }
2N/A regstr = v9_hprivreg_names[ridx];
2N/A mask = v9_hpr_wrmask;
2N/A } else {
2N/A regstr = tbr_str;
2N/A use_mask = 0;
2N/A }
2N/A break;
2N/A }
2N/A
2N/A if (regstr == NULL)
2N/A return (-1);
2N/A
2N/A if (use_mask != 0 && ((1L << ridx) & mask) == 0)
2N/A return (-1);
2N/A
2N/A prt_name(dhp, name, 1);
2N/A
2N/A if (rd != 0) {
2N/A bprintf(dhp, "%s, %s", regstr, reg_names[f->f3.rd]);
2N/A } else {
2N/A if (pr_rs1 == 1)
2N/A bprintf(dhp, "%s, ", reg_names[f->f3.rs1]);
2N/A
2N/A if (pr_rs2 != 0) {
2N/A if (f->f3.i == 1)
2N/A prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
2N/A IMM_SIGNED);
2N/A else
2N/A (void) strlcat(dhp->dh_buf,
2N/A reg_names[f->f3.rs2], dhp->dh_buflen);
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A }
2N/A
2N/A (void) strlcat(dhp->dh_buf, regstr, dhp->dh_buflen);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_trap(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A int v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
2N/A int p_rs1, p_t;
2N/A
2N/A if (f->ftcc.undef != 0)
2N/A return (-1);
2N/A
2N/A if (icc_names[f->ftcc.cc] == NULL)
2N/A return (-1);
2N/A
2N/A if (f->ftcc.i == 1 && f->ftcc.undef2 != 0)
2N/A return (-1);
2N/A
2N/A if (f->ftcc2.i == 0 && f->ftcc2.undef2 != 0)
2N/A return (-1);
2N/A
2N/A p_rs1 = ((f->ftcc.rs1 != 0) ||
2N/A ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0));
2N/A
2N/A if (f->ftcc.i == 0) {
2N/A p_t = (f->f3.rs2 != 0 || p_rs1 == 0);
2N/A
2N/A bprintf(dhp, "%-9s %s%s%s%s%s", inp->in_data.in_def.in_name,
2N/A (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
2N/A (v9 != 0) ? ", " : "",
2N/A (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
2N/A (p_rs1 != 0) ? " + " : "",
2N/A (p_t != 0) ? reg_names[f->f3.rs2] : "");
2N/A } else {
2N/A bprintf(dhp, "%-9s %s%s%s%s0x%x", inp->in_data.in_def.in_name,
2N/A (v9 != 0) ? icc_names[f->ftcc2.cc] : "",
2N/A (v9 != 0) ? ", " : "",
2N/A (p_rs1 != 0) ? reg_names[f->ftcc2.rs1] : "",
2N/A (p_rs1 != 0) ? " + " : "",
2N/A f->ftcc.immtrap);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aprt_shift(dis_handle_t *dhp, uint32_t instr, const inst_t *inp)
2N/A{
2N/A char name[5];
2N/A uint32_t cnt;
2N/A
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2N/A
2N/A name[0] = '\0';
2N/A (void) strlcat(name, inp->in_data.in_def.in_name, sizeof (name));
2N/A
2N/A if (f->f3b.i == 1)
2N/A cnt = f->f3.rs2;
2N/A
2N/A if (f->f3b.x == 1 && ((dhp->dh_flags & DIS_SPARC_V8) == 0)) {
2N/A cnt = f->f3b.shcnt;
2N/A (void) strlcat(name, "x", sizeof (name));
2N/A }
2N/A
2N/A prt_name(dhp, name, 1);
2N/A
2N/A if (f->f3b.i == 1)
2N/A bprintf(dhp, (octal != 0) ? "%s, 0%lo, %s" : "%s, 0x%lx, %s",
2N/A reg_names[f->f3.rs1], cnt, reg_names[f->f3.rd]);
2N/A else
2N/A bprintf(dhp, "%s, %s, %s", reg_names[f->f3.rs1],
2N/A reg_names[f->f3.rs2], reg_names[f->f3.rd]);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Astatic int
2N/Aprt_jmpl(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A const char *name = inp->in_data.in_def.in_name;
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0))
2N/A name = "call";
2N/A
2N/A if (f->f3.rd == 0) {
2N/A if (f->f3.i == 1 && f->f3a.simm13 == 8) {
2N/A if (f->f3.rs1 == 15) {
2N/A prt_name(dhp, "retl", 0);
2N/A return (0);
2N/A }
2N/A
2N/A if (f->f3.rs1 == 31) {
2N/A prt_name(dhp, "ret", 0);
2N/A return (0);
2N/A }
2N/A }
2N/A
2N/A name = "jmp";
2N/A }
2N/A
2N/A prt_name(dhp, name, 1);
2N/A prt_address(dhp, instr, 1);
2N/A
2N/A if (f->f3.rd == 0)
2N/A return (0);
2N/A
2N/A if (f->f3.rd == 15 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0))
2N/A return (0);
2N/A
2N/A bprintf(dhp, ", %s", reg_names[f->f3.rd]);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmt_alu(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A const char *name = inp->in_data.in_def.in_name;
2N/A int flags = inp->in_data.in_def.in_flags;
2N/A int arg = 0;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f3.op, 2);
2N/A prt_field("op3", f->f3.op3, 6);
2N/A prt_field("rs1", f->f3.rs1, 5);
2N/A
2N/A switch (idx) {
2N/A /* TODO: more formats */
2N/A
2N/A default:
2N/A if (f->f3.i == 0)
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A else
2N/A prt_field("simm13", f->f3a.simm13, 13);
2N/A
2N/A prt_field("rd", f->f3.rd, 5);
2N/A }
2N/A
2N/A }
2N/A
2N/A switch (idx) {
2N/A case 0x00:
2N/A /* add */
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 == 1) {
2N/A name = "inc";
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 != 1) {
2N/A name = "inc";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A break;
2N/A
2N/A case 0x02:
2N/A /* or */
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
2N/A == 0)
2N/A break;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) != 0) {
2N/A if (f->f3.rs1 == f->f3.rd) {
2N/A name = "bset";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (((f->f3.i == 0 && f->f3.rs2 == 0) ||
2N/A (f->f3.i == 1 && f->f3a.simm13 == 0)) &&
2N/A (f->f3.rs1 == 0)) {
2N/A name = "clr";
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs1 == 0) {
2N/A name = "mov";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A break;
2N/A
2N/A case 0x04:
2N/A /* sub */
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 == f->f3.rd) {
2N/A name = "neg";
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE);
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs1 == 0 && f->f3.i == 0 && f->f3.rs2 != f->f3.rd) {
2N/A name = "neg";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 == 1) {
2N/A name = "dec";
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 != 1) {
2N/A name = "dec";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A break;
2N/A
2N/A case 0x07:
2N/A /* xnor */
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
2N/A == 0)
2N/A break;
2N/A
2N/A /*
2N/A * xnor -> not when you have:
2N/A * xnor %rs1, 0x0 or %g0, %rd
2N/A */
2N/A if ((f->f3.i == 0 && f->f3.rs2 != 0) ||
2N/A (f->f3.i == 1 && f->f3a.simm13 != 0))
2N/A break;
2N/A
2N/A name = "not";
2N/A
2N/A if (f->f3.rs1 == f->f3.rd)
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM|
2N/A FLG_P3(REG_INT);
2N/A else
2N/A flags = FLG_P1(REG_INT)|FLG_P2(REG_NONE)|FLG_NOIMM|
2N/A FLG_P3(REG_INT);
2N/A
2N/A break;
2N/A
2N/A case 0x10:
2N/A /* addcc */
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_SYN_ALL) == 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 == 1) {
2N/A name = "inccc";
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 != 1) {
2N/A name = "inccc";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A break;
2N/A
2N/A case 0x11:
2N/A /* andcc */
2N/A
2N/A if (f->f3.rd != 0)
2N/A break;
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL))
2N/A == 0)
2N/A break;
2N/A
2N/A if (((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0) &&
2N/A ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) == 0))
2N/A break;
2N/A
2N/A name = "btst";
2N/A flags = FLG_P1(REG_NONE);
2N/A f->f3.rd = f->f3.rs1;
2N/A break;
2N/A
2N/A case 0x12:
2N/A /* orcc */
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
2N/A name = "tst";
2N/A flags = FLG_P1(REG_NONE)|FLG_P3(REG_NONE);
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs2 == 0 && f->f3.rd == 0 && f->f3.i == 0) {
2N/A name = "tst";
2N/A flags = FLG_P2(REG_NONE)|FLG_P3(REG_NONE);
2N/A break;
2N/A }
2N/A
2N/A break;
2N/A
2N/A case 0x14:
2N/A /* subcc */
2N/A
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rd == 0) {
2N/A name = "cmp";
2N/A flags = FLG_P3(REG_NONE);
2N/A break;
2N/A }
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 == 1) {
2N/A name = "deccc";
2N/A flags = FLG_P1(REG_NONE)|FLG_P2(REG_NONE)|FLG_NOIMM;
2N/A break;
2N/A }
2N/A
2N/A if (f->f3.rs1 == f->f3.rd && f->f3.i == 1 &&
2N/A f->f3a.simm13 != 1) {
2N/A name = "deccc";
2N/A flags = FLG_P1(REG_NONE);
2N/A break;
2N/A }
2N/A
2N/A break;
2N/A
2N/A case 0x25:
2N/A case 0x26:
2N/A case 0x27:
2N/A return (prt_shift(dhp, instr, inp));
2N/A
2N/A case 0x28:
2N/A case 0x29:
2N/A case 0x2a:
2N/A case 0x2b:
2N/A case 0x30:
2N/A case 0x31:
2N/A case 0x32:
2N/A case 0x33:
2N/A return (dis_fmt_rdwr(dhp, instr, inp, idx));
2N/A
2N/A case 0x36:
2N/A case 0x37:
2N/A /* NOTE: overlayed on v9 */
2N/A if ((dhp->dh_flags & DIS_SPARC_V8) != 0)
2N/A return (fmt_cpop(dhp, instr, inp));
2N/A break;
2N/A
2N/A case 0x38:
2N/A /* jmpl */
2N/A return (prt_jmpl(dhp, instr, inp, idx));
2N/A
2N/A case 0x39:
2N/A /* rett / return */
2N/A prt_name(dhp, name, 1);
2N/A prt_address(dhp, instr, 1);
2N/A return (0);
2N/A
2N/A case 0x3b:
2N/A /* flush */
2N/A prt_name(dhp, name, 1);
2N/A prt_address(dhp, instr, 0);
2N/A return (0);
2N/A
2N/A case 0x3c:
2N/A case 0x3d:
2N/A /* save / restore */
2N/A if ((dhp->dh_debug & (DIS_DEBUG_SYN_ALL|DIS_DEBUG_COMPAT))
2N/A == 0)
2N/A break;
2N/A
2N/A if (f->f3.rs1 != 0 || f->f3.rs2 != 0 || f->f3.rd != 0)
2N/A break;
2N/A
2N/A if (f->f3.i != 0 && ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0))
2N/A break;
2N/A
2N/A prt_name(dhp, name, 0);
2N/A return (0);
2N/A }
2N/A
2N/A if (FLG_P1_VAL(flags) != REG_NONE || FLG_P2_VAL(flags) != REG_NONE ||
2N/A FLG_P3_VAL(flags) != REG_NONE)
2N/A arg = 1;
2N/A
2N/A prt_name(dhp, name, (arg != 0));
2N/A prt_aluargs(dhp, instr, flags);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED1 */
2N/Aint
2N/Afmt_regwin(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 0);
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED1 */
2N/Aint
2N/Afmt_trap_ret(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A
2N/A if (f->f3.rd == 0xf) {
2N/A /* jpriv */
2N/A prt_address(dhp, instr, 1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_movcc(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A const char **regs = NULL;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f3c.op, 2);
2N/A prt_field("op3", f->f3c.op3, 6);
2N/A prt_field("cond", f->f3c.cond, 4);
2N/A prt_field("cc2", f->f3c.cc2, 1);
2N/A prt_field("cc", f->f3c.cc, 2);
2N/A prt_field("i", f->f3c.i, 1);
2N/A
2N/A if (f->f3c.i == 0)
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A else
2N/A prt_field("simm11", f->f3c.simm11, 11);
2N/A
2N/A prt_field("rd", f->f3.rd, 5);
2N/A }
2N/A
2N/A if (f->f3c.cc2 == 0) {
2N/A regs = fcc_names;
2N/A } else {
2N/A regs = icc_names;
2N/A if (regs[f->f3c.cc] == NULL)
2N/A return (-1);
2N/A }
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A
2N/A bprintf(dhp, "%s, ", regs[f->f3c.cc]);
2N/A
2N/A if (f->f3c.i == 1)
2N/A prt_imm(dhp, sign_extend(f->f3c.simm11, 11), IMM_SIGNED);
2N/A else
2N/A (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2],
2N/A dhp->dh_buflen);
2N/A
2N/A bprintf(dhp, ", %s", reg_names[f->f3.rd]);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_movr(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A
2N/A bprintf(dhp, "%s, ", reg_names[f->f3d.rs1]);
2N/A
2N/A if (f->f3d.i == 1)
2N/A prt_imm(dhp, sign_extend(f->f3d.simm10, 10), IMM_SIGNED);
2N/A else
2N/A (void) strlcat(dhp->dh_buf, reg_names[f->f3.rs2],
2N/A dhp->dh_buflen);
2N/A
2N/A bprintf(dhp, ", %s", reg_names[f->f3.rd]);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_fpop1(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int flags = inp->in_data.in_def.in_flags;
2N/A
2N/A flags |= FLG_NOIMM;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f3.op, 2);
2N/A prt_field("op3", f->f3.op3, 6);
2N/A prt_field("opf", f->fcmp.opf, 9);
2N/A prt_field("rs1", f->f3.rs1, 5);
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A prt_field("rd", f->f3.rd, 5);
2N/A }
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A prt_aluargs(dhp, instr, flags);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmt_fpop2(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A static const char *condstr_icc[16] = {
2N/A "n", "e", "le", "l", "leu", "lu", "neg", "vs",
2N/A "a", "nz", "g", "ge", "gu", "geu", "pos", "vc"
2N/A };
2N/A
2N/A static const char *condstr_fcc[16] = {
2N/A "n", "nz", "lg", "ul", "l", "ug", "g", "u",
2N/A "a", "e", "ue", "ge", "uge", "le", "ule", "o"
2N/A };
2N/A
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A const char *ccstr = "";
2N/A char name[15];
2N/A
2N/A int flags = inp->in_data.in_def.in_flags;
2N/A int is_cmp = (idx == 0x51 || idx == 0x52 || idx == 0x53 ||
2N/A idx == 0x55 || idx == 0x56 || idx == 0x57);
2N/A int is_fmov = (idx & 0x3f);
2N/A int is_v9 = ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0);
2N/A int is_compat = ((dhp->dh_debug & DIS_DEBUG_COMPAT) != 0);
2N/A
2N/A int p_cc = 0;
2N/A
2N/A is_fmov = (is_fmov == 0x1 || is_fmov == 0x2 || is_fmov == 0x3);
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f3.op, 2);
2N/A prt_field("op3", f->f3.op3, 6);
2N/A prt_field("opf", f->fcmp.opf, 9);
2N/A
2N/A switch (idx & 0x3f) {
2N/A case 0x51:
2N/A case 0x52:
2N/A case 0x53:
2N/A case 0x55:
2N/A case 0x56:
2N/A case 0x57:
2N/A prt_field("cc", f->fcmp.cc, 2);
2N/A prt_field("rs1", f->f3.rs1, 5);
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A break;
2N/A
2N/A case 0x01:
2N/A case 0x02:
2N/A case 0x03:
2N/A prt_field("opf_low", f->fmv.opf, 6);
2N/A prt_field("cond", f->fmv.cond, 4);
2N/A prt_field("opf_cc", f->fmv.cc, 3);
2N/A prt_field("rs2", f->fmv.rs2, 5);
2N/A break;
2N/A
2N/A default:
2N/A prt_field("rs1", f->f3.rs1, 5);
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A prt_field("rd", f->f3.rd, 5);
2N/A }
2N/A }
2N/A
2N/A name[0] = '\0';
2N/A (void) strlcat(name, inp->in_data.in_def.in_name, sizeof (name));
2N/A
2N/A if (is_fmov != 0) {
2N/A (void) strlcat(name,
2N/A (f->fmv.cc < 4) ? condstr_fcc[f->fmv.cond]
2N/A : condstr_icc[f->fmv.cond],
2N/A sizeof (name));
2N/A }
2N/A
2N/A prt_name(dhp, name, 1);
2N/A
2N/A if (is_cmp != 0)
2N/A ccstr = fcc_names[f->fcmp.cc];
2N/A
2N/A if (is_fmov != 0)
2N/A ccstr = (f->fmv.cc < 4) ? fcc_names[f->fmv.cc & 0x3]
2N/A : icc_names[f->fmv.cc & 0x3];
2N/A
2N/A if (ccstr == NULL)
2N/A return (-1);
2N/A
2N/A p_cc = (is_compat == 0 || is_v9 != 0 ||
2N/A (is_cmp != 0 && f->fcmp.cc != 0) ||
2N/A (is_fmov != 0 && f->fmv.cc != 0));
2N/A
2N/A if (p_cc != 0)
2N/A bprintf(dhp, "%s, ", ccstr);
2N/A
2N/A prt_aluargs(dhp, instr, flags);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Afmt_vis(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int flags = inp->in_data.in_def.in_flags;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f3.op, 2);
2N/A prt_field("op3", f->f3.op3, 6);
2N/A prt_field("opf", f->fcmp.opf, 9);
2N/A
2N/A if (idx == 0x081) {
2N/A prt_field("mode", instr & 02L, 2);
2N/A } else {
2N/A prt_field("rs1", f->f3.rs1, 5);
2N/A prt_field("rs2", f->f3.rs2, 5);
2N/A prt_field("rd", f->f3.rd, 5);
2N/A }
2N/A }
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A
2N/A if (idx == 0x081) {
2N/A /* siam */
2N/A bprintf(dhp, "%d", instr & 0x7L);
2N/A return (0);
2N/A }
2N/A
2N/A prt_aluargs(dhp, instr, flags);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_fused(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int flags = inp->in_data.in_def.in_flags;
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A bprintf(dhp, "%s, %s, %s, %s",
2N/A get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs1),
2N/A get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs2),
2N/A get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs3),
2N/A get_regname(dhp, FLG_P1_VAL(flags), f->fused.rd));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_cbcond(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A const char *name = inp->in_data.in_def.in_name;
2N/A const char *regname = NULL;
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A uint32_t flags = inp->in_data.in_def.in_flags;
2N/A int32_t disp;
2N/A size_t curlen;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->f2d.op, 2);
2N/A prt_field("c_hi", f->f2d.c_hi, 2);
2N/A prt_field("c_lo", f->f2d.c_lo, 3);
2N/A prt_field("cc2", f->f2d.cc2, 1);
2N/A prt_field("d10_hi", f->f2d.d10_hi, 2);
2N/A prt_field("i", f->f2d.i, 1);
2N/A prt_field("rs1", f->f2d.rs1, 5);
2N/A prt_field("d10_lo", f->f2d.d10_lo, 8);
2N/A prt_field("rs2", f->f2d.rs2, 5);
2N/A }
2N/A
2N/A disp = sign_extend((f->f2d.d10_hi << 8)|(f->f2d.d10_lo), 10);
2N/A disp *= 4;
2N/A
2N/A prt_name(dhp, name, 1);
2N/A
2N/A regname = get_regname(dhp, FLG_RS1_VAL(flags), f->f2d.rs1);
2N/A bprintf(dhp, "%s, ", regname);
2N/A
2N/A if (f->f2d.i == 1) {
2N/A prt_imm(dhp, sign_extend(f->f2d.rs2, 5), IMM_SIGNED);
2N/A } else {
2N/A regname = get_regname(dhp, FLG_RS1_VAL(flags), f->f2d.rs2);
2N/A bprintf(dhp, "%s", regname);
2N/A }
2N/A
2N/A bprintf(dhp, ", %s0x%-5lx <", (disp < 0) ? "-" : "+",
2N/A (disp < 0) ? (-disp) : disp);
2N/A
2N/A curlen = strlen(dhp->dh_buf);
2N/A dhp->dh_lookup(dhp->dh_data, dhp->dh_addr + (int64_t)disp,
2N/A dhp->dh_buf + curlen, dhp->dh_buflen - curlen - 1, NULL, NULL);
2N/A
2N/A (void) strlcat(dhp->dh_buf, ">", dhp->dh_buflen);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_crypto(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A
2N/A if ((dhp->dh_debug & DIS_DEBUG_PRTFMT) != 0) {
2N/A prt_field("op", f->fcrypto.op, 2);
2N/A prt_field("rd", f->fcrypto.rd, 5);
2N/A prt_field("op3", f->fcrypto.op3, 6);
2N/A prt_field("rs1", f->fcrypto.rs1, 5);
2N/A prt_field("opf", f->fcrypto.opf, 9);
2N/A prt_field("imm5", f->fcrypto.imm5, 5);
2N/A }
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A prt_imm(dhp, f->fcrypto.imm5, 0);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Aint
2N/Afmt_crypto4op(dis_handle_t *dhp, uint32_t instr, const inst_t *inp, int idx)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int flags = inp->in_data.in_def.in_flags;
2N/A
2N/A prt_name(dhp, inp->in_data.in_def.in_name, 1);
2N/A bprintf(dhp, "%s, %s, ", get_regname(dhp, FLG_P1_VAL(flags),
2N/A f->fused.rs1), get_regname(dhp, FLG_P1_VAL(flags), f->fused.rs2));
2N/A
2N/A if (idx == 0x8) {
2N/A /* aes_kexpand1 */
2N/A prt_imm(dhp, f->fused.rs3, 0);
2N/A } else {
2N/A bprintf(dhp, "%s", get_regname(dhp, FLG_P1_VAL(flags),
2N/A f->fused.rs3));
2N/A }
2N/A
2N/A bprintf(dhp, ", %s", get_regname(dhp, FLG_P1_VAL(flags), f->fused.rd));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * put name into the output buffer
2N/A * if add_space !=0, append a space after it
2N/A */
2N/Astatic void
2N/Aprt_name(dis_handle_t *dhp, const char *name, int add_space)
2N/A{
2N/A bprintf(dhp, (add_space == 0) ? "%s" : "%-9s ", name);
2N/A}
2N/A
2N/A/*
2N/A * For debugging, print out a field of the instruction
2N/A * field is the name of the field
2N/A * val is the value of the field
2N/A * len is the length of the field (in bits)
2N/A */
2N/A#if defined(DIS_STANDALONE)
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aprt_field(const char *field, uint32_t val, int len)
2N/A{
2N/A
2N/A}
2N/A
2N/A#else
2N/Astatic void
2N/Aprt_field(const char *field, uint32_t val, int len)
2N/A{
2N/A (void) fprintf(stderr, "DISASM: %8s = 0x%-8x (", field, val);
2N/A prt_binary(val, len);
2N/A (void) fprintf(stderr, ")\n");
2N/A}
2N/A#endif /* DIS_STANDALONE */
2N/A
2N/A/*
2N/A * sign extend a val (that is 'bits' bits in length) to a 32-bit signed
2N/A * integer
2N/A */
2N/Astatic int32_t
2N/Asign_extend(int32_t val, int32_t bits)
2N/A{
2N/A if ((val & (1L << (bits - 1))) == 0)
2N/A return (val);
2N/A
2N/A return ((-1L << bits) | val);
2N/A}
2N/A
2N/A/*
2N/A * print out an immediate (i.e. constant) value
2N/A * val is the value
2N/A * format indicates if it is:
2N/A * 0 Unsigned
2N/A * IMM_SIGNED A signed value (prepend +/- to the value)
2N/A * IMM_ADDR Part of an address expression (prepend +/- but with a space
2N/A * between the sign and the value for things like [%i1 + 0x55]
2N/A */
2N/Astatic void
2N/Aprt_imm(dis_handle_t *dhp, uint32_t val, int format)
2N/A{
2N/A const char *fmtstr = NULL;
2N/A int32_t sv = (int32_t)val;
2N/A int octal = dhp->dh_flags & DIS_OCTAL;
2N/A
2N/A switch (format) {
2N/A case IMM_ADDR:
2N/A if (sv < 0) {
2N/A sv = -sv;
2N/A fmtstr = (octal != 0) ? "- 0%lo" : "- 0x%lx";
2N/A } else {
2N/A fmtstr = (octal != 0) ? "+ 0%lo" : "+ 0x%lx";
2N/A }
2N/A break;
2N/A
2N/A case IMM_SIGNED:
2N/A if (sv < 0) {
2N/A sv = -sv;
2N/A fmtstr = (octal != 0) ? "-0%lo" : "-0x%lx";
2N/A break;
2N/A }
2N/A /* fall through */
2N/A
2N/A default:
2N/A fmtstr = (octal != 0) ? "0%lo" : "0x%lx";
2N/A }
2N/A
2N/A bprintf(dhp, fmtstr, sv);
2N/A}
2N/A
2N/A/*
2N/A * return the symbolic name of a register
2N/A * regset is one of the REG_* values indicating which type of register it is
2N/A * such as integer, floating point, etc.
2N/A * idx is the numeric value of the register
2N/A *
2N/A * If regset is REG_NONE, an empty, but non-NULL string is returned
2N/A * NULL may be returned if the index indicates an invalid register value
2N/A * such as with the %icc/%xcc sets
2N/A */
2N/Astatic const char *
2N/Aget_regname(dis_handle_t *dhp, int regset, uint32_t idx)
2N/A{
2N/A const char *regname = NULL;
2N/A
2N/A switch (regset) {
2N/A case REG_INT:
2N/A regname = reg_names[idx];
2N/A break;
2N/A
2N/A case REG_FP:
2N/A regname = freg_names[idx];
2N/A break;
2N/A
2N/A case REG_FPD:
2N/A if (((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0) ||
2N/A ((dhp->dh_flags & (DIS_SPARC_V9|DIS_SPARC_V9_SGI)) != 0))
2N/A regname = fdreg_names[idx];
2N/A else
2N/A regname = compat_fdreg_names[idx];
2N/A
2N/A break;
2N/A
2N/A case REG_FPQ:
2N/A if ((dhp->dh_debug & DIS_DEBUG_COMPAT) == 0)
2N/A regname = fqreg_names[idx];
2N/A else
2N/A regname = freg_names[idx];
2N/A
2N/A break;
2N/A
2N/A case REG_CP:
2N/A regname = cpreg_names[idx];
2N/A break;
2N/A
2N/A case REG_ICC:
2N/A regname = icc_names[idx];
2N/A break;
2N/A
2N/A case REG_FCC:
2N/A regname = fcc_names[idx];
2N/A break;
2N/A
2N/A case REG_FSR:
2N/A regname = "%fsr";
2N/A break;
2N/A
2N/A case REG_CSR:
2N/A regname = "%csr";
2N/A break;
2N/A
2N/A case REG_CQ:
2N/A regname = "%cq";
2N/A break;
2N/A
2N/A case REG_NONE:
2N/A regname = "";
2N/A break;
2N/A }
2N/A
2N/A return (regname);
2N/A}
2N/A
2N/A/*
2N/A * output the asi value from the instruction
2N/A *
2N/A * TODO: investigate if this should perhaps have a mask -- are undefined ASI
2N/A * values for an instruction still disassembled??
2N/A */
2N/Astatic void
2N/Aprt_asi(dis_handle_t *dhp, uint32_t instr)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2N/A
2N/A if (f->f3.i != 0)
2N/A bprintf(dhp, "%%asi");
2N/A else
2N/A bprintf(dhp, (octal != 0) ? "0%03o" : "0x%02x", f->f3.asi);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * put an address expression into the output buffer
2N/A *
2N/A * instr is the instruction to use
2N/A * if nobrackets != 0, [] are not added around the instruction
2N/A *
2N/A * Currently this option is set when printing out the address portion
2N/A * of a jmpl instruction, but otherwise 0 for load/stores
2N/A *
2N/A * If no debug flags are set, the full expression is output, even when
2N/A * %g0 or 0x0 appears in the address
2N/A *
2N/A * If DIS_DEBUG_SYN_ALL or DIS_DEBUG_COMPAT are set, when %g0 or 0x0
2N/A * appear in the address, they are not output. If the wierd (and probably
2N/A * shouldn't happen) address of [%g0 + %g0] or [%g0 + 0x0] is encountered,
2N/A * [%g0] is output
2N/A */
2N/Astatic void
2N/Aprt_address(dis_handle_t *dhp, uint32_t instr, int nobrackets)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A int32_t simm13;
2N/A int octal = ((dhp->dh_flags & DIS_OCTAL) != 0);
2N/A int p1 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
2N/A int p2 = ((dhp->dh_debug & (DIS_DEBUG_COMPAT|DIS_DEBUG_SYN_ALL)) == 0);
2N/A
2N/A if (f->f3a.i == 0) {
2N/A p1 |= ((f->f3a.rs1 != 0) || f->f3.rs2 == 0);
2N/A p2 |= (f->f3.rs2 != 0);
2N/A
2N/A bprintf(dhp, "%s%s%s%s%s",
2N/A (nobrackets == 0) ? "[" : "",
2N/A (p1 != 0) ? reg_names[f->f3a.rs1] : "",
2N/A (p1 != 0 && p2 != 0) ? " + " : "",
2N/A (p2 != 0) ? reg_names[f->f3.rs2] : "",
2N/A (nobrackets == 0) ? "]" : "");
2N/A } else {
2N/A const char *sign;
2N/A
2N/A simm13 = sign_extend(f->f3a.simm13, 13);
2N/A sign = (simm13 < 0) ? "-" : "+";
2N/A
2N/A p1 |= (f->f3a.rs1 != 0);
2N/A p2 |= (p1 == 0 || simm13 != 0);
2N/A
2N/A if (p1 == 0 && simm13 == 0)
2N/A p2 = 1;
2N/A
2N/A if (p1 == 0 && simm13 >= 0)
2N/A sign = "";
2N/A
2N/A if (p2 != 0)
2N/A bprintf(dhp,
2N/A (octal != 0) ? "%s%s%s%s%s0%lo%s" :
2N/A "%s%s%s%s%s0x%lx%s",
2N/A (nobrackets == 0) ? "[" : "",
2N/A (p1 != 0) ? reg_names[f->f3a.rs1] : "",
2N/A (p1 != 0) ? " " : "",
2N/A sign,
2N/A (p1 != 0) ? " " : "",
2N/A (simm13 < 0) ? -(simm13) : simm13,
2N/A (nobrackets == 0) ? "]" : "");
2N/A else
2N/A bprintf(dhp, "%s%s%s",
2N/A (nobrackets == 0) ? "[" : "",
2N/A reg_names[f->f3a.rs1],
2N/A (nobrackets == 0) ? "]" : "");
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * print out the arguments to an alu operation (add, sub, etc.)
2N/A * contained in 'instr'.
2N/A *
2N/A * alu instructions have the following format:
2N/A * %rs1, %rs2, %rd (i == 0)
2N/A * %rs1, 0xnnn, %rd (i == 1)
2N/A * ^ ^ ^
2N/A * | | |
2N/A * p1 p2 p3
2N/A *
2N/A * flags indicates the register set to use for each position (p1, p2, p3)
2N/A * as well as if immediate values (i == 1) are allowed
2N/A *
2N/A * if flags indicates a specific position has REG_NONE set as it's register
2N/A * set, it is omitted from the output. This is primarly used for certain
2N/A * floating point operations
2N/A */
2N/Astatic void
2N/Aprt_aluargs(dis_handle_t *dhp, uint32_t instr, uint32_t flags)
2N/A{
2N/A ifmt_t *f = (ifmt_t *)&instr;
2N/A const char *r1, *r2, *r3;
2N/A int p1, p2, p3;
2N/A unsigned int opf = 0;
2N/A
2N/A r1 = get_regname(dhp, FLG_P1_VAL(flags), f->f3.rs1);
2N/A r2 = get_regname(dhp, FLG_P2_VAL(flags), f->f3.rs2);
2N/A r3 = get_regname(dhp, FLG_P3_VAL(flags), f->f3.rd);
2N/A
2N/A p1 = (FLG_P1_VAL(flags) != REG_NONE);
2N/A p2 = (((flags & FLG_NOIMM) == 0) || (FLG_P2_VAL(flags) != REG_NONE));
2N/A p3 = (FLG_RD_VAL(flags) != REG_NONE);
2N/A
2N/A if (r1 == NULL || r1[0] == '\0')
2N/A p1 = 0;
2N/A
2N/A if (f->f3a.i == 0 && (r2 == NULL || r2[0] == '\0'))
2N/A p2 = 0;
2N/A
2N/A if (r3 == NULL || r3[0] == '\0')
2N/A p3 = 0;
2N/A
2N/A if ((f->fcmp.op == 2) && (f->fcmp.op3 == 0x36) && (f->fcmp.cc != 0))
2N/A opf = f->fcmp.opf;
2N/A
2N/A if ((opf == 0x151) || (opf == 0x152)) {
2N/A (void) strlcat(dhp->dh_buf, r3, dhp->dh_buflen);
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A p3 = 0;
2N/A }
2N/A
2N/A if (p1 != 0) {
2N/A (void) strlcat(dhp->dh_buf, r1, dhp->dh_buflen);
2N/A if (p2 != 0 || p3 != 0)
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A }
2N/A
2N/A if (p2 != 0) {
2N/A if (f->f3.i == 0 || ((flags & FLG_NOIMM) != 0))
2N/A (void) strlcat(dhp->dh_buf, r2, dhp->dh_buflen);
2N/A else if (opf == 0x136) {
2N/A /* special case for des_kexpand */
2N/A prt_imm(dhp, f->fcrypto.imm5, 0);
2N/A } else {
2N/A prt_imm(dhp, sign_extend(f->f3a.simm13, 13),
2N/A IMM_SIGNED);
2N/A }
2N/A
2N/A if (p3 != 0)
2N/A (void) strlcat(dhp->dh_buf, ", ", dhp->dh_buflen);
2N/A }
2N/A
2N/A if (p3 != 0)
2N/A (void) strlcat(dhp->dh_buf, r3, dhp->dh_buflen);
2N/A}
2N/A
2N/Astatic const char *
2N/Aget_asi_name(uint8_t asi)
2N/A{
2N/A switch (asi) {
2N/A case 0x04:
2N/A return ("ASI_N");
2N/A
2N/A case 0x0c:
2N/A return ("ASI_NL");
2N/A
2N/A case 0x10:
2N/A return ("ASI_AIUP");
2N/A
2N/A case 0x11:
2N/A return ("ASI_AIUS");
2N/A
2N/A case 0x14:
2N/A return ("ASI_REAL");
2N/A
2N/A case 0x15:
2N/A return ("ASI_REAL_IO");
2N/A
2N/A case 0x16:
2N/A return ("ASI_BLK_AIUP");
2N/A
2N/A case 0x17:
2N/A return ("ASI_BLK_AIUS");
2N/A
2N/A case 0x18:
2N/A return ("ASI_AIUPL");
2N/A
2N/A case 0x19:
2N/A return ("ASI_AIUSL");
2N/A
2N/A case 0x1c:
2N/A return ("ASI_REAL_L");
2N/A
2N/A case 0x1d:
2N/A return ("ASI_REAL_IO_L");
2N/A
2N/A case 0x1e:
2N/A return ("ASI_BLK_AIUPL");
2N/A
2N/A case 0x1f:
2N/A return ("ASI_BLK_AIUS_L");
2N/A
2N/A case 0x20:
2N/A return ("ASI_SCRATCHPAD");
2N/A
2N/A case 0x21:
2N/A return ("ASI_MMU_CONTEXTID");
2N/A
2N/A case 0x22:
2N/A return ("ASI_TWINX_AIUP");
2N/A
2N/A case 0x23:
2N/A return ("ASI_TWINX_AIUS");
2N/A
2N/A case 0x25:
2N/A return ("ASI_QUEUE");
2N/A
2N/A case 0x26:
2N/A return ("ASI_TWINX_R");
2N/A
2N/A case 0x27:
2N/A return ("ASI_TWINX_N");
2N/A
2N/A case 0x2a:
2N/A return ("ASI_LDTX_AIUPL");
2N/A
2N/A case 0x2b:
2N/A return ("ASI_TWINX_AIUS_L");
2N/A
2N/A case 0x2e:
2N/A return ("ASI_TWINX_REAL_L");
2N/A
2N/A case 0x2f:
2N/A return ("ASI_TWINX_NL");
2N/A
2N/A case 0x30:
2N/A return ("ASI_AIPP");
2N/A
2N/A case 0x31:
2N/A return ("ASI_AIPS");
2N/A
2N/A case 0x36:
2N/A return ("ASI_AIPN");
2N/A
2N/A case 0x38:
2N/A return ("ASI_AIPP_L");
2N/A
2N/A case 0x39:
2N/A return ("ASI_AIPS_L");
2N/A
2N/A case 0x3e:
2N/A return ("ASI_AIPN_L");
2N/A
2N/A case 0x41:
2N/A return ("ASI_CMT_SHARED");
2N/A
2N/A case 0x4f:
2N/A return ("ASI_HYP_SCRATCHPAD");
2N/A
2N/A case 0x50:
2N/A return ("ASI_IMMU");
2N/A
2N/A case 0x52:
2N/A return ("ASI_MMU_REAL");
2N/A
2N/A case 0x54:
2N/A return ("ASI_MMU");
2N/A
2N/A case 0x55:
2N/A return ("ASI_ITLB_DATA_ACCESS_REG");
2N/A
2N/A case 0x56:
2N/A return ("ASI_ITLB_TAG_READ_REG");
2N/A
2N/A case 0x57:
2N/A return ("ASI_IMMU_DEMAP");
2N/A
2N/A case 0x58:
2N/A return ("ASI_DMMU / ASI_UMMU");
2N/A
2N/A case 0x5c:
2N/A return ("ASI_DTLB_DATA_IN_REG");
2N/A
2N/A case 0x5d:
2N/A return ("ASI_DTLB_DATA_ACCESS_REG");
2N/A
2N/A case 0x5e:
2N/A return ("ASI_DTLB_TAG_READ_REG");
2N/A
2N/A case 0x5f:
2N/A return ("ASI_DMMU_DEMAP");
2N/A
2N/A case 0x63:
2N/A return ("ASI_CMT_PER_STRAND / ASI_CMT_PER_CORE");
2N/A
2N/A case 0x80:
2N/A return ("ASI_P");
2N/A
2N/A case 0x81:
2N/A return ("ASI_S");
2N/A
2N/A case 0x82:
2N/A return ("ASI_PNF");
2N/A
2N/A case 0x83:
2N/A return ("ASI_SNF");
2N/A
2N/A case 0x88:
2N/A return ("ASI_PL");
2N/A
2N/A case 0x89:
2N/A return ("ASI_SL");
2N/A
2N/A case 0x8a:
2N/A return ("ASI_PNFL");
2N/A
2N/A case 0x8b:
2N/A return ("ASI_SNFL");
2N/A
2N/A case 0xc0:
2N/A return ("ASI_PST8_P");
2N/A
2N/A case 0xc1:
2N/A return ("ASI_PST8_S");
2N/A
2N/A case 0xc2:
2N/A return ("ASI_PST16_P");
2N/A
2N/A case 0xc3:
2N/A return ("ASI_PST16_S");
2N/A
2N/A case 0xc4:
2N/A return ("ASI_PST32_P");
2N/A
2N/A case 0xc5:
2N/A return ("ASI_PST32_S");
2N/A
2N/A case 0xc8:
2N/A return ("ASI_PST8_PL");
2N/A
2N/A case 0xc9:
2N/A return ("ASI_PST8_SL");
2N/A
2N/A case 0xca:
2N/A return ("ASI_PST16_PL");
2N/A
2N/A case 0xcb:
2N/A return ("ASI_PST16_SL");
2N/A
2N/A case 0xcc:
2N/A return ("ASI_PST32_PL");
2N/A
2N/A case 0xcd:
2N/A return ("ASI_PST32_SL");
2N/A
2N/A case 0xd0:
2N/A return ("ASI_FL8_P");
2N/A
2N/A case 0xd1:
2N/A return ("ASI_FL8_S");
2N/A
2N/A case 0xd2:
2N/A return ("ASI_FL16_P");
2N/A
2N/A case 0xd3:
2N/A return ("ASI_FL16_S");
2N/A
2N/A case 0xd8:
2N/A return ("ASI_FL8_PL");
2N/A
2N/A case 0xd9:
2N/A return ("ASI_FL8_SL");
2N/A
2N/A case 0xda:
2N/A return ("ASI_FL16_PL");
2N/A
2N/A case 0xdb:
2N/A return ("ASI_FL16_SL");
2N/A
2N/A case 0xe0:
2N/A return ("ASI_BLK_COMMIT_P");
2N/A
2N/A case 0xe1:
2N/A return ("ASI_BLK_SOMMIT_S");
2N/A
2N/A case 0xe2:
2N/A return ("ASI_TWINX_P");
2N/A
2N/A case 0xe3:
2N/A return ("ASI_TWINX_S");
2N/A
2N/A case 0xea:
2N/A return ("ASI_TWINX_PL");
2N/A
2N/A case 0xeb:
2N/A return ("ASI_TWINX_SL");
2N/A
2N/A case 0xf0:
2N/A return ("ASI_BLK_P");
2N/A
2N/A case 0xf1:
2N/A return ("ASI_BLK_S");
2N/A
2N/A case 0xf8:
2N/A return ("ASI_BLK_PL");
2N/A
2N/A case 0xf9:
2N/A return ("ASI_BLK_SL");
2N/A
2N/A default:
2N/A return (NULL);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * just a handy function that takes care of managing the buffer length
2N/A * w/ printf
2N/A */
2N/A
2N/A/*
2N/A * PRINTF LIKE 1
2N/A */
2N/Astatic void
2N/Abprintf(dis_handle_t *dhp, const char *fmt, ...)
2N/A{
2N/A size_t curlen;
2N/A va_list ap;
2N/A
2N/A curlen = strlen(dhp->dh_buf);
2N/A
2N/A va_start(ap, fmt);
2N/A (void) vsnprintf(dhp->dh_buf + curlen, dhp->dh_buflen - curlen, fmt,
2N/A ap);
2N/A va_end(ap);
2N/A}