Home | History | Annotate | Download | only in Sparc
      1 //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax --------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This class prints an Sparc MCInst to a .s file.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 /* Capstone Disassembly Engine */
     15 /* By Nguyen Anh Quynh <aquynh (at) gmail.com>, 2013-2014 */
     16 
     17 #ifdef CAPSTONE_HAS_SPARC
     18 
     19 #ifdef _MSC_VER
     20 #define _CRT_SECURE_NO_WARNINGS
     21 #endif
     22 
     23 #if defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)
     24 #pragma warning(disable:28719)		// disable MSVC's warning on strncpy()
     25 #endif
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 
     31 #include "SparcInstPrinter.h"
     32 #include "../../MCInst.h"
     33 #include "../../utils.h"
     34 #include "../../SStream.h"
     35 #include "../../MCRegisterInfo.h"
     36 #include "../../MathExtras.h"
     37 #include "SparcMapping.h"
     38 
     39 #include "Sparc.h"
     40 
     41 static char *getRegisterName(unsigned RegNo);
     42 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
     43 static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier);
     44 static void printOperand(MCInst *MI, int opNum, SStream *O);
     45 
     46 static void Sparc_add_hint(MCInst *MI, unsigned int hint)
     47 {
     48 	if (MI->csh->detail) {
     49 		MI->flat_insn->detail->sparc.hint = hint;
     50 	}
     51 }
     52 
     53 static void Sparc_add_reg(MCInst *MI, unsigned int reg)
     54 {
     55 	if (MI->csh->detail) {
     56 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
     57 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
     58 		MI->flat_insn->detail->sparc.op_count++;
     59 	}
     60 }
     61 
     62 static void set_mem_access(MCInst *MI, bool status)
     63 {
     64 	if (MI->csh->detail != CS_OPT_ON)
     65 		return;
     66 
     67 	MI->csh->doing_mem = status;
     68 
     69 	if (status) {
     70 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM;
     71 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID;
     72 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0;
     73 	} else {
     74 		// done, create the next operand slot
     75 		MI->flat_insn->detail->sparc.op_count++;
     76 	}
     77 }
     78 
     79 void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
     80 {
     81 	if (((cs_struct *)ud)->detail != CS_OPT_ON)
     82 		return;
     83 
     84 	// fix up some instructions
     85 	if (insn->id == SPARC_INS_CASX) {
     86 		// first op is actually a memop, not regop
     87 		insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
     88 		insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg;
     89 		insn->detail->sparc.operands[0].mem.disp = 0;
     90 	}
     91 }
     92 
     93 static void printRegName(SStream *OS, unsigned RegNo)
     94 {
     95 	SStream_concat0(OS, "%");
     96 	SStream_concat0(OS, getRegisterName(RegNo));
     97 }
     98 
     99 #define GET_INSTRINFO_ENUM
    100 #include "SparcGenInstrInfo.inc"
    101 
    102 #define GET_REGINFO_ENUM
    103 #include "SparcGenRegisterInfo.inc"
    104 
    105 static bool printSparcAliasInstr(MCInst *MI, SStream *O)
    106 {
    107 	switch (MCInst_getOpcode(MI)) {
    108 		default: return false;
    109 		case SP_JMPLrr:
    110 		case SP_JMPLri:
    111 				 if (MCInst_getNumOperands(MI) != 3)
    112 					 return false;
    113 				 if (!MCOperand_isReg(MCInst_getOperand(MI, 0)))
    114 					 return false;
    115 
    116 				 switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) {
    117 					 default: return false;
    118 					 case SP_G0: // jmp $addr | ret | retl
    119 							  if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
    120 									MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) {
    121 								  switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) {
    122 									  default: break;
    123 									  case SP_I7: SStream_concat0(O, "ret"); MCInst_setOpcodePub(MI, SPARC_INS_RET); return true;
    124 									  case SP_O7: SStream_concat0(O, "retl"); MCInst_setOpcodePub(MI, SPARC_INS_RETL); return true;
    125 								  }
    126 							  }
    127 
    128 							  SStream_concat0(O, "jmp\t");
    129 							  MCInst_setOpcodePub(MI, SPARC_INS_JMP);
    130 							  printMemOperand(MI, 1, O, NULL);
    131 							  return true;
    132 					 case SP_O7: // call $addr
    133 							  SStream_concat0(O, "call ");
    134 							  MCInst_setOpcodePub(MI, SPARC_INS_CALL);
    135 							  printMemOperand(MI, 1, O, NULL);
    136 							  return true;
    137 				 }
    138 		case SP_V9FCMPS:
    139 		case SP_V9FCMPD:
    140 		case SP_V9FCMPQ:
    141 		case SP_V9FCMPES:
    142 		case SP_V9FCMPED:
    143 		case SP_V9FCMPEQ:
    144 				 if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) ||
    145 						 (!MCOperand_isReg(MCInst_getOperand(MI, 0))) ||
    146 						 (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0))
    147 						 return false;
    148 				 // if V8, skip printing %fcc0.
    149 				 switch(MCInst_getOpcode(MI)) {
    150 					 default:
    151 					 case SP_V9FCMPS:  SStream_concat0(O, "fcmps\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPS); break;
    152 					 case SP_V9FCMPD:  SStream_concat0(O, "fcmpd\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPD); break;
    153 					 case SP_V9FCMPQ:  SStream_concat0(O, "fcmpq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPQ); break;
    154 					 case SP_V9FCMPES: SStream_concat0(O, "fcmpes\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPES); break;
    155 					 case SP_V9FCMPED: SStream_concat0(O, "fcmped\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPED); break;
    156 					 case SP_V9FCMPEQ: SStream_concat0(O, "fcmpeq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPEQ); break;
    157 				 }
    158 				 printOperand(MI, 1, O);
    159 				 SStream_concat0(O, ", ");
    160 				 printOperand(MI, 2, O);
    161 				 return true;
    162 	}
    163 }
    164 
    165 static void printOperand(MCInst *MI, int opNum, SStream *O)
    166 {
    167 	int Imm;
    168 	unsigned reg;
    169 	MCOperand *MO = MCInst_getOperand(MI, opNum);
    170 
    171 	if (MCOperand_isReg(MO)) {
    172 		reg = MCOperand_getReg(MO);
    173 		printRegName(O, reg);
    174 		reg = Sparc_map_register(reg);
    175 
    176 		if (MI->csh->detail) {
    177 			if (MI->csh->doing_mem) {
    178 				if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base)
    179 					MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = (uint8_t)reg;
    180 				else
    181 					MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = (uint8_t)reg;
    182 			} else {
    183 				MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
    184 				MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
    185 				MI->flat_insn->detail->sparc.op_count++;
    186 			}
    187 		}
    188 
    189 		return;
    190 	}
    191 
    192 	if (MCOperand_isImm(MO)) {
    193 		Imm = (int)MCOperand_getImm(MO);
    194 
    195 		// Conditional branches displacements needs to be signextended to be
    196 		// able to jump backwards.
    197 		//
    198 		// Displacements are measured as the number of instructions forward or
    199 		// backward, so they need to be multiplied by 4
    200 		switch (MI->Opcode) {
    201 			case SP_CALL:
    202 				Imm = SignExtend32(Imm, 30);
    203 				Imm += (uint32_t)MI->address;
    204 				break;
    205 
    206 			// Branch on integer condition with prediction (BPcc)
    207 			// Branch on floating point condition with prediction (FBPfcc)
    208 			case SP_BPICC:
    209 			case SP_BPICCA:
    210 			case SP_BPICCANT:
    211 			case SP_BPICCNT:
    212 			case SP_BPXCC:
    213 			case SP_BPXCCA:
    214 			case SP_BPXCCANT:
    215 			case SP_BPXCCNT:
    216 			case SP_BPFCC:
    217 			case SP_BPFCCA:
    218 			case SP_BPFCCANT:
    219 			case SP_BPFCCNT:
    220 				Imm = SignExtend32(Imm, 19);
    221 				Imm = (uint32_t)MI->address + Imm * 4;
    222 				break;
    223 
    224 			// Branch on integer condition (Bicc)
    225 			// Branch on floating point condition (FBfcc)
    226 			case SP_BA:
    227 			case SP_BCOND:
    228 			case SP_BCONDA:
    229 			case SP_FBCOND:
    230 			case SP_FBCONDA:
    231 				Imm = SignExtend32(Imm, 22);
    232 				Imm = (uint32_t)MI->address + Imm * 4;
    233 				break;
    234 
    235 			// Branch on integer register with prediction (BPr)
    236 			case SP_BPGEZapn:
    237 			case SP_BPGEZapt:
    238 			case SP_BPGEZnapn:
    239 			case SP_BPGEZnapt:
    240 			case SP_BPGZapn:
    241 			case SP_BPGZapt:
    242 			case SP_BPGZnapn:
    243 			case SP_BPGZnapt:
    244 			case SP_BPLEZapn:
    245 			case SP_BPLEZapt:
    246 			case SP_BPLEZnapn:
    247 			case SP_BPLEZnapt:
    248 			case SP_BPLZapn:
    249 			case SP_BPLZapt:
    250 			case SP_BPLZnapn:
    251 			case SP_BPLZnapt:
    252 			case SP_BPNZapn:
    253 			case SP_BPNZapt:
    254 			case SP_BPNZnapn:
    255 			case SP_BPNZnapt:
    256 			case SP_BPZapn:
    257 			case SP_BPZapt:
    258 			case SP_BPZnapn:
    259 			case SP_BPZnapt:
    260 				Imm = SignExtend32(Imm, 16);
    261 				Imm = (uint32_t)MI->address + Imm * 4;
    262 				break;
    263 		}
    264 
    265 		if (Imm >= 0) {
    266 			if (Imm > HEX_THRESHOLD)
    267 				SStream_concat(O, "0x%x", Imm);
    268 			else
    269 				SStream_concat(O, "%u", Imm);
    270 		} else {
    271 			if (Imm < -HEX_THRESHOLD)
    272 				SStream_concat(O, "-0x%x", -Imm);
    273 			else
    274 				SStream_concat(O, "-%u", -Imm);
    275 		}
    276 
    277 		if (MI->csh->detail) {
    278 			if (MI->csh->doing_mem) {
    279 				MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm;
    280 			} else {
    281 				MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM;
    282 				MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm;
    283 				MI->flat_insn->detail->sparc.op_count++;
    284 			}
    285 		}
    286 	}
    287 
    288 	return;
    289 }
    290 
    291 static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier)
    292 {
    293 	MCOperand *MO;
    294 
    295 	set_mem_access(MI, true);
    296 	printOperand(MI, opNum, O);
    297 
    298 	// If this is an ADD operand, emit it like normal operands.
    299 	if (Modifier && !strcmp(Modifier, "arith")) {
    300 		SStream_concat0(O, ", ");
    301 		printOperand(MI, opNum + 1, O);
    302 		set_mem_access(MI, false);
    303 		return;
    304 	}
    305 
    306 	MO = MCInst_getOperand(MI, opNum + 1);
    307 
    308 	if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) {
    309 		set_mem_access(MI, false);
    310 		return;   // don't print "+%g0"
    311 	}
    312 
    313 	if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) {
    314 		set_mem_access(MI, false);
    315 		return;   // don't print "+0"
    316 	}
    317 
    318 	SStream_concat0(O, "+");	// qq
    319 
    320 	printOperand(MI, opNum + 1, O);
    321 	set_mem_access(MI, false);
    322 }
    323 
    324 static void printCCOperand(MCInst *MI, int opNum, SStream *O)
    325 {
    326 	int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256;
    327 
    328 	switch (MCInst_getOpcode(MI)) {
    329 		default: break;
    330 		case SP_FBCOND:
    331 		case SP_FBCONDA:
    332 		case SP_BPFCC:
    333 		case SP_BPFCCA:
    334 		case SP_BPFCCNT:
    335 		case SP_BPFCCANT:
    336 		case SP_MOVFCCrr:  case SP_V9MOVFCCrr:
    337 		case SP_MOVFCCri:  case SP_V9MOVFCCri:
    338 		case SP_FMOVS_FCC: case SP_V9FMOVS_FCC:
    339 		case SP_FMOVD_FCC: case SP_V9FMOVD_FCC:
    340 		case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC:
    341 				 // Make sure CC is a fp conditional flag.
    342 				 CC = (CC < 16+256) ? (CC + 16) : CC;
    343 				 break;
    344 	}
    345 
    346 	SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
    347 
    348 	if (MI->csh->detail)
    349 		MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
    350 }
    351 
    352 
    353 static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
    354 {
    355 	return true;
    356 }
    357 
    358 
    359 #define PRINT_ALIAS_INSTR
    360 #include "SparcGenAsmWriter.inc"
    361 
    362 void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
    363 {
    364 	char *mnem, *p;
    365 	char instr[64];	// Sparc has no instruction this long
    366 
    367 	mnem = printAliasInstr(MI, O, Info);
    368 	if (mnem) {
    369 		// fixup instruction id due to the change in alias instruction
    370 		strncpy(instr, mnem, strlen(mnem));
    371 		instr[strlen(mnem)] = '\0';
    372 		// does this contains hint with a coma?
    373 		p = strchr(instr, ',');
    374 		if (p)
    375 			*p = '\0';	// now instr only has instruction mnemonic
    376 		MCInst_setOpcodePub(MI, Sparc_map_insn(instr));
    377 		switch(MCInst_getOpcode(MI)) {
    378 			case SP_BCOND:
    379 			case SP_BCONDA:
    380 			case SP_BPICCANT:
    381 			case SP_BPICCNT:
    382 			case SP_BPXCCANT:
    383 			case SP_BPXCCNT:
    384 			case SP_TXCCri:
    385 			case SP_TXCCrr:
    386 				if (MI->csh->detail) {
    387 					// skip 'b', 't'
    388 					MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 1);
    389 					MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
    390 				}
    391 				break;
    392 			case SP_BPFCCANT:
    393 			case SP_BPFCCNT:
    394 				if (MI->csh->detail) {
    395 					// skip 'fb'
    396 					MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 2);
    397 					MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
    398 				}
    399 				break;
    400 			case SP_FMOVD_ICC:
    401 			case SP_FMOVD_XCC:
    402 			case SP_FMOVQ_ICC:
    403 			case SP_FMOVQ_XCC:
    404 			case SP_FMOVS_ICC:
    405 			case SP_FMOVS_XCC:
    406 				if (MI->csh->detail) {
    407 					// skip 'fmovd', 'fmovq', 'fmovs'
    408 					MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 5);
    409 					MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
    410 				}
    411 				break;
    412 			case SP_MOVICCri:
    413 			case SP_MOVICCrr:
    414 			case SP_MOVXCCri:
    415 			case SP_MOVXCCrr:
    416 				if (MI->csh->detail) {
    417 					// skip 'mov'
    418 					MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 3);
    419 					MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
    420 				}
    421 				break;
    422 			case SP_V9FMOVD_FCC:
    423 			case SP_V9FMOVQ_FCC:
    424 			case SP_V9FMOVS_FCC:
    425 				if (MI->csh->detail) {
    426 					// skip 'fmovd', 'fmovq', 'fmovs'
    427 					MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 5);
    428 					MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
    429 				}
    430 				break;
    431 			case SP_V9MOVFCCri:
    432 			case SP_V9MOVFCCrr:
    433 				if (MI->csh->detail) {
    434 					// skip 'mov'
    435 					MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 3);
    436 					MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
    437 				}
    438 				break;
    439 			default:
    440 				break;
    441 		}
    442 		cs_mem_free(mnem);
    443 	} else {
    444 		if (!printSparcAliasInstr(MI, O))
    445 			printInstruction(MI, O, NULL);
    446 	}
    447 }
    448 
    449 void Sparc_addReg(MCInst *MI, int reg)
    450 {
    451 	if (MI->csh->detail) {
    452 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
    453 		MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
    454 		MI->flat_insn->detail->sparc.op_count++;
    455 	}
    456 }
    457 
    458 #endif
    459