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 * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 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 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. 2N/A * Copyright 2009 Jason King. All rights reserved. 2N/A * Use is subject to license terms. 2N/A#
endif /* DIS_STANDALONE */ 2N/Aextern int strcmp(
const char *,
const char *);
2N/A * This file has the functions that do all the dirty work of outputting the 2N/A * disassembled instruction 2N/A * All the non-static functions follow the format_fcn (in dis_sparc.h): 2N/A * instruction to disassemble 2N/A * instruction definition pointer (inst_t *) 2N/A * index in the table of the instruction 2N/A * !0 Invalid instruction 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 * 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 * 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/* The various instruction formats of a sparc instruction */ 2N/A/* integer register names */ 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/* floating point register names */ 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/* double precision register names */ 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 "%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 "%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/* coprocessor register names -- sparcv8 only */ 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/* floating point condition code names */ 2N/A "%fcc0",
"%fcc1",
"%fcc2",
"%fcc3" 2N/A/* condition code names */ 2N/A/* bitmask values for membar */ 2N/A "#LoadLoad",
"#StoreLoad",
"#LoadStore",
"#StoreStore" 2N/A "#Lookaside",
"#MemIssue",
"#Sync" 2N/A/* v8 ancillary state register names */ 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 "%pcr",
"%pic",
"%dcr",
"%gsr",
2N/A "%softint_set",
"%softint_clr",
"%softint",
"%tick_cmpr",
2N/A "%stick",
"%stick_cmpr",
"%cfr",
"%pause",
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/* privledged register names on v9 */ 2N/A/* TODO: compat - NULL to %priv_nn */ 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/* hyper privileged register names on v9 */ 2N/A "%hpstate",
"%htstate",
NULL,
"%hintp",
2N/A "#n_reads",
"#one_read",
2N/A "#n_writes",
"#one_write",
2N/A "#n_reads_strong",
"#one_read_strong",
2N/A "#n_writes_strong",
"#one_write_strong",
2N/A#
define IMM_ADDR 0x02 /* Is immediate value part of an address */ 2N/A * print out val (which is 'bitlen' bits long) in binary 2N/A if (i %
4 == 0 && i != 0)
2N/A#
endif /* DIS_STANDALONE */ 2N/A * print out a call instruction 2N/A * format: call address <name> 2N/A /* unimp / illtrap */ 2N/A /* ?? Should we return -1 if rd == 0 && disp != 0 */ 2N/A "%%hi(0%lo), %s" :
"%%hi(0x%lx), %s",
2N/A (
octal != 0) ?
"%s0%-11lo <" :
"%s0x%-10lx <",
2N/A "%s, %s0x%-04lx <", r,
2N/A (
octal != 0) ?
"%s, %s0%-6lo <" :
"%s, %s0x%-5lx <",
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 * 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 * 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 * 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 * 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 * 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 * The following synthetic instructions are also implemented: 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 * If DIS_DEBUG_COMPAT is set, the following substitutions also take place 2N/A /* prefetch / prefetcha */ 2N/A /* fcn field is the same as rd */ 2N/A /* synthetic instructions & special cases */ 2N/A * on sparcv8 it merely says that rd != 1 should generate an 2N/A * exception, on v9, it is illegal 2N/A * store partial floating point, only valid w/ 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 (f->
f3.i ==
1) && ((f->i & (
1L <<
12)) == 0)) {
2N/A for (i = 0; i <
4; ++i) {
2N/A for (i = 0; i <
5; ++i) {
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 * NOTE: due to the presence of an overlay entry for another 2N/A * table, this case only happens when doing v8 instructions 2N/A /* special case for halt */ 2N/A /* TODO: more formats */ 2N/A * xnor -> not when you have: 2N/A * xnor %rs1, 0x0 or %g0, %rd 2N/A /* NOTE: overlayed on v9 */ 2N/A /* save / restore */ 2N/A "n",
"e",
"le",
"l",
"leu",
"lu",
"neg",
"vs",
2N/A "a",
"nz",
"g",
"ge",
"gu",
"geu",
"pos",
"vc" 2N/A "n",
"nz",
"lg",
"ul",
"l",
"ug",
"g",
"u",
2N/A "a",
"e",
"ue",
"ge",
"uge",
"le",
"ule",
"o" 2N/A * put name into the output buffer 2N/A * if add_space !=0, append a space after it 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#
endif /* DIS_STANDALONE */ 2N/A * sign extend a val (that is 'bits' bits in length) to a 32-bit signed 2N/A * print out an immediate (i.e. constant) value 2N/A * format indicates if it is: 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 * 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 * 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 * output the asi value from the instruction 2N/A * TODO: investigate if this should perhaps have a mask -- are undefined ASI 2N/A * values for an instruction still disassembled?? 2N/A * put an address expression into the output buffer 2N/A * instr is the instruction to use 2N/A * if nobrackets != 0, [] are not added around the instruction 2N/A * Currently this option is set when printing out the address portion 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 * 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 "%s%s%s%s%s0x%lx%s",
2N/A * print out the arguments to an alu operation (add, sub, etc.) 2N/A * contained in 'instr'. 2N/A * alu instructions have the following format: 2N/A * %rs1, %rs2, %rd (i == 0) 2N/A * %rs1, 0xnnn, %rd (i == 1) 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 * 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 /* special case for des_kexpand */ 2N/A return (
"ASI_AIUP");
2N/A return (
"ASI_AIUS");
2N/A return (
"ASI_REAL");
2N/A return (
"ASI_REAL_IO");
2N/A return (
"ASI_BLK_AIUP");
2N/A return (
"ASI_BLK_AIUS");
2N/A return (
"ASI_AIUPL");
2N/A return (
"ASI_AIUSL");
2N/A return (
"ASI_REAL_L");
2N/A return (
"ASI_REAL_IO_L");
2N/A return (
"ASI_BLK_AIUPL");
2N/A return (
"ASI_BLK_AIUS_L");
2N/A return (
"ASI_SCRATCHPAD");
2N/A return (
"ASI_MMU_CONTEXTID");
2N/A return (
"ASI_TWINX_AIUP");
2N/A return (
"ASI_TWINX_AIUS");
2N/A return (
"ASI_QUEUE");
2N/A return (
"ASI_TWINX_R");
2N/A return (
"ASI_TWINX_N");
2N/A return (
"ASI_LDTX_AIUPL");
2N/A return (
"ASI_TWINX_AIUS_L");
2N/A return (
"ASI_TWINX_REAL_L");
2N/A return (
"ASI_TWINX_NL");
2N/A return (
"ASI_AIPP");
2N/A return (
"ASI_AIPS");
2N/A return (
"ASI_AIPN");
2N/A return (
"ASI_AIPP_L");
2N/A return (
"ASI_AIPS_L");
2N/A return (
"ASI_AIPN_L");
2N/A return (
"ASI_CMT_SHARED");
2N/A return (
"ASI_HYP_SCRATCHPAD");
2N/A return (
"ASI_IMMU");
2N/A return (
"ASI_MMU_REAL");
2N/A return (
"ASI_ITLB_DATA_ACCESS_REG");
2N/A return (
"ASI_ITLB_TAG_READ_REG");
2N/A return (
"ASI_IMMU_DEMAP");
2N/A return (
"ASI_DMMU / ASI_UMMU");
2N/A return (
"ASI_DTLB_DATA_IN_REG");
2N/A return (
"ASI_DTLB_DATA_ACCESS_REG");
2N/A return (
"ASI_DTLB_TAG_READ_REG");
2N/A return (
"ASI_DMMU_DEMAP");
2N/A return (
"ASI_CMT_PER_STRAND / ASI_CMT_PER_CORE");
2N/A return (
"ASI_PNFL");
2N/A return (
"ASI_SNFL");
2N/A return (
"ASI_PST8_P");
2N/A return (
"ASI_PST8_S");
2N/A return (
"ASI_PST16_P");
2N/A return (
"ASI_PST16_S");
2N/A return (
"ASI_PST32_P");
2N/A return (
"ASI_PST32_S");
2N/A return (
"ASI_PST8_PL");
2N/A return (
"ASI_PST8_SL");
2N/A return (
"ASI_PST16_PL");
2N/A return (
"ASI_PST16_SL");
2N/A return (
"ASI_PST32_PL");
2N/A return (
"ASI_PST32_SL");
2N/A return (
"ASI_FL8_P");
2N/A return (
"ASI_FL8_S");
2N/A return (
"ASI_FL16_P");
2N/A return (
"ASI_FL16_S");
2N/A return (
"ASI_FL8_PL");
2N/A return (
"ASI_FL8_SL");
2N/A return (
"ASI_FL16_PL");
2N/A return (
"ASI_FL16_SL");
2N/A return (
"ASI_BLK_COMMIT_P");
2N/A return (
"ASI_BLK_SOMMIT_S");
2N/A return (
"ASI_TWINX_P");
2N/A return (
"ASI_TWINX_S");
2N/A return (
"ASI_TWINX_PL");
2N/A return (
"ASI_TWINX_SL");
2N/A return (
"ASI_BLK_P");
2N/A return (
"ASI_BLK_S");
2N/A return (
"ASI_BLK_PL");
2N/A return (
"ASI_BLK_SL");
2N/A * just a handy function that takes care of managing the buffer length