Home | History | Annotate | Download | only in Mips
      1 //===-- MipsInstPrinter.cpp - Convert Mips 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 Mips 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_MIPS
     18 
     19 #include <platform.h>
     20 #include <stdlib.h>
     21 #include <stdio.h>	// debug
     22 #include <string.h>
     23 
     24 #include "MipsInstPrinter.h"
     25 #include "../../MCInst.h"
     26 #include "../../utils.h"
     27 #include "../../SStream.h"
     28 #include "../../MCRegisterInfo.h"
     29 #include "MipsMapping.h"
     30 
     31 #include "MipsInstPrinter.h"
     32 
     33 static void printUnsignedImm(MCInst *MI, int opNum, SStream *O);
     34 static char *printAliasInstr(MCInst *MI, SStream *O, void *info);
     35 static char *printAlias(MCInst *MI, SStream *OS);
     36 
     37 // These enumeration declarations were originally in MipsInstrInfo.h but
     38 // had to be moved here to avoid circular dependencies between
     39 // LLVMMipsCodeGen and LLVMMipsAsmPrinter.
     40 
     41 // Mips Condition Codes
     42 typedef enum Mips_CondCode {
     43 	// To be used with float branch True
     44 	Mips_FCOND_F,
     45 	Mips_FCOND_UN,
     46 	Mips_FCOND_OEQ,
     47 	Mips_FCOND_UEQ,
     48 	Mips_FCOND_OLT,
     49 	Mips_FCOND_ULT,
     50 	Mips_FCOND_OLE,
     51 	Mips_FCOND_ULE,
     52 	Mips_FCOND_SF,
     53 	Mips_FCOND_NGLE,
     54 	Mips_FCOND_SEQ,
     55 	Mips_FCOND_NGL,
     56 	Mips_FCOND_LT,
     57 	Mips_FCOND_NGE,
     58 	Mips_FCOND_LE,
     59 	Mips_FCOND_NGT,
     60 
     61 	// To be used with float branch False
     62 	// This conditions have the same mnemonic as the
     63 	// above ones, but are used with a branch False;
     64 	Mips_FCOND_T,
     65 	Mips_FCOND_OR,
     66 	Mips_FCOND_UNE,
     67 	Mips_FCOND_ONE,
     68 	Mips_FCOND_UGE,
     69 	Mips_FCOND_OGE,
     70 	Mips_FCOND_UGT,
     71 	Mips_FCOND_OGT,
     72 	Mips_FCOND_ST,
     73 	Mips_FCOND_GLE,
     74 	Mips_FCOND_SNE,
     75 	Mips_FCOND_GL,
     76 	Mips_FCOND_NLT,
     77 	Mips_FCOND_GE,
     78 	Mips_FCOND_NLE,
     79 	Mips_FCOND_GT
     80 } Mips_CondCode;
     81 
     82 #define GET_INSTRINFO_ENUM
     83 #include "MipsGenInstrInfo.inc"
     84 
     85 static char *getRegisterName(unsigned RegNo);
     86 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
     87 
     88 static void set_mem_access(MCInst *MI, bool status)
     89 {
     90 	MI->csh->doing_mem = status;
     91 
     92 	if (MI->csh->detail != CS_OPT_ON)
     93 		return;
     94 
     95 	if (status) {
     96 		MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_MEM;
     97 		MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.base = MIPS_REG_INVALID;
     98 		MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.disp = 0;
     99 	} else {
    100 		// done, create the next operand slot
    101 		MI->flat_insn->detail->mips.op_count++;
    102 	}
    103 }
    104 
    105 static bool isReg(MCInst *MI, unsigned OpNo, unsigned R)
    106 {
    107 	return (MCOperand_isReg(MCInst_getOperand(MI, OpNo)) &&
    108 			MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == R);
    109 }
    110 
    111 static char* MipsFCCToString(Mips_CondCode CC)
    112 {
    113 	switch (CC) {
    114 		default: return 0;	// never reach
    115 		case Mips_FCOND_F:
    116 		case Mips_FCOND_T:   return "f";
    117 		case Mips_FCOND_UN:
    118 		case Mips_FCOND_OR:  return "un";
    119 		case Mips_FCOND_OEQ:
    120 		case Mips_FCOND_UNE: return "eq";
    121 		case Mips_FCOND_UEQ:
    122 		case Mips_FCOND_ONE: return "ueq";
    123 		case Mips_FCOND_OLT:
    124 		case Mips_FCOND_UGE: return "olt";
    125 		case Mips_FCOND_ULT:
    126 		case Mips_FCOND_OGE: return "ult";
    127 		case Mips_FCOND_OLE:
    128 		case Mips_FCOND_UGT: return "ole";
    129 		case Mips_FCOND_ULE:
    130 		case Mips_FCOND_OGT: return "ule";
    131 		case Mips_FCOND_SF:
    132 		case Mips_FCOND_ST:  return "sf";
    133 		case Mips_FCOND_NGLE:
    134 		case Mips_FCOND_GLE: return "ngle";
    135 		case Mips_FCOND_SEQ:
    136 		case Mips_FCOND_SNE: return "seq";
    137 		case Mips_FCOND_NGL:
    138 		case Mips_FCOND_GL:  return "ngl";
    139 		case Mips_FCOND_LT:
    140 		case Mips_FCOND_NLT: return "lt";
    141 		case Mips_FCOND_NGE:
    142 		case Mips_FCOND_GE:  return "nge";
    143 		case Mips_FCOND_LE:
    144 		case Mips_FCOND_NLE: return "le";
    145 		case Mips_FCOND_NGT:
    146 		case Mips_FCOND_GT:  return "ngt";
    147 	}
    148 }
    149 
    150 static void printRegName(SStream *OS, unsigned RegNo)
    151 {
    152 	SStream_concat(OS, "$%s", getRegisterName(RegNo));
    153 }
    154 
    155 void Mips_printInst(MCInst *MI, SStream *O, void *info)
    156 {
    157 	char *mnem;
    158 
    159 	switch (MCInst_getOpcode(MI)) {
    160 		default: break;
    161 		case Mips_Save16:
    162 		case Mips_SaveX16:
    163 		case Mips_Restore16:
    164 		case Mips_RestoreX16:
    165 			return;
    166 	}
    167 
    168 	// Try to print any aliases first.
    169 	mnem = printAliasInstr(MI, O, info);
    170 	if (!mnem) {
    171 		mnem = printAlias(MI, O);
    172 		if (!mnem) {
    173 			printInstruction(MI, O, NULL);
    174 		}
    175 	}
    176 
    177 	if (mnem) {
    178 		// fixup instruction id due to the change in alias instruction
    179 		MCInst_setOpcodePub(MI, Mips_map_insn(mnem));
    180 		cs_mem_free(mnem);
    181 	}
    182 }
    183 
    184 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
    185 {
    186 	MCOperand *Op;
    187 
    188 	if (OpNo >= MI->size)
    189 		return;
    190 
    191 	Op = MCInst_getOperand(MI, OpNo);
    192 	if (MCOperand_isReg(Op)) {
    193 		unsigned int reg = MCOperand_getReg(Op);
    194 		printRegName(O, reg);
    195 		reg = Mips_map_register(reg);
    196 		if (MI->csh->detail) {
    197 			if (MI->csh->doing_mem) {
    198 				MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.base = reg;
    199 			} else {
    200 				MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_REG;
    201 				MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].reg = reg;
    202 				MI->flat_insn->detail->mips.op_count++;
    203 			}
    204 		}
    205 	} else if (MCOperand_isImm(Op)) {
    206 		int64_t imm = MCOperand_getImm(Op);
    207 		if (MI->csh->doing_mem) {
    208 			if (imm) {	// only print Imm offset if it is not 0
    209 				if (imm >= 0) {
    210 					if (imm > HEX_THRESHOLD)
    211 						SStream_concat(O, "0x%"PRIx64, imm);
    212 					else
    213 						SStream_concat(O, "%"PRIu64, imm);
    214 				} else {
    215 					if (imm < -HEX_THRESHOLD)
    216 						SStream_concat(O, "-0x%"PRIx64, -imm);
    217 					else
    218 						SStream_concat(O, "-%"PRIu64, -imm);
    219 				}
    220 			}
    221 			if (MI->csh->detail)
    222 				MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.disp = imm;
    223 		} else {
    224 			if (imm >= 0) {
    225 				if (imm > HEX_THRESHOLD)
    226 					SStream_concat(O, "0x%"PRIx64, imm);
    227 				else
    228 					SStream_concat(O, "%"PRIu64, imm);
    229 			} else {
    230 				if (imm < -HEX_THRESHOLD)
    231 					SStream_concat(O, "-0x%"PRIx64, -imm);
    232 				else
    233 					SStream_concat(O, "-%"PRIu64, -imm);
    234 			}
    235 
    236 			if (MI->csh->detail) {
    237 				MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;
    238 				MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = imm;
    239 				MI->flat_insn->detail->mips.op_count++;
    240 			}
    241 		}
    242 	}
    243 }
    244 
    245 static void printUnsignedImm(MCInst *MI, int opNum, SStream *O)
    246 {
    247 	MCOperand *MO = MCInst_getOperand(MI, opNum);
    248 	if (MCOperand_isImm(MO)) {
    249 		int64_t imm = MCOperand_getImm(MO);
    250 		if (imm >= 0) {
    251 			if (imm > HEX_THRESHOLD)
    252 				SStream_concat(O, "0x%x", (unsigned short int)imm);
    253 			else
    254 				SStream_concat(O, "%u", (unsigned short int)imm);
    255 		} else {
    256 			if (imm < -HEX_THRESHOLD)
    257 				SStream_concat(O, "-0x%x", (short int)-imm);
    258 			else
    259 				SStream_concat(O, "-%u", (short int)-imm);
    260 		}
    261 		if (MI->csh->detail) {
    262 			MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;
    263 			MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = (unsigned short int)imm;
    264 			MI->flat_insn->detail->mips.op_count++;
    265 		}
    266 	} else
    267 		printOperand(MI, opNum, O);
    268 }
    269 
    270 static void printUnsignedImm8(MCInst *MI, int opNum, SStream *O)
    271 {
    272 	MCOperand *MO = MCInst_getOperand(MI, opNum);
    273 	if (MCOperand_isImm(MO)) {
    274 		uint8_t imm = (uint8_t)MCOperand_getImm(MO);
    275 		if (imm > HEX_THRESHOLD)
    276 			SStream_concat(O, "0x%x", imm);
    277 		else
    278 			SStream_concat(O, "%u", imm);
    279 		if (MI->csh->detail) {
    280 			MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;
    281 			MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = imm;
    282 			MI->flat_insn->detail->mips.op_count++;
    283 		}
    284 	} else
    285 		printOperand(MI, opNum, O);
    286 }
    287 
    288 static void printMemOperand(MCInst *MI, int opNum, SStream *O)
    289 {
    290 	// Load/Store memory operands -- imm($reg)
    291 	// If PIC target the target is loaded as the
    292 	// pattern lw $25,%call16($28)
    293 	set_mem_access(MI, true);
    294 	printOperand(MI, opNum + 1, O);
    295 	SStream_concat0(O, "(");
    296 	printOperand(MI, opNum, O);
    297 	SStream_concat0(O, ")");
    298 	set_mem_access(MI, false);
    299 }
    300 
    301 // TODO???
    302 static void printMemOperandEA(MCInst *MI, int opNum, SStream *O)
    303 {
    304 	// when using stack locations for not load/store instructions
    305 	// print the same way as all normal 3 operand instructions.
    306 	printOperand(MI, opNum, O);
    307 	SStream_concat0(O, ", ");
    308 	printOperand(MI, opNum + 1, O);
    309 	return;
    310 }
    311 
    312 static void printFCCOperand(MCInst *MI, int opNum, SStream *O)
    313 {
    314 	MCOperand *MO = MCInst_getOperand(MI, opNum);
    315 	SStream_concat0(O, MipsFCCToString((Mips_CondCode)MCOperand_getImm(MO)));
    316 }
    317 
    318 static char *printAlias1(char *Str, MCInst *MI, unsigned OpNo, SStream *OS)
    319 {
    320 	SStream_concat(OS, "%s\t", Str);
    321 	printOperand(MI, OpNo, OS);
    322 	return cs_strdup(Str);
    323 }
    324 
    325 static char *printAlias2(char *Str, MCInst *MI,
    326 		unsigned OpNo0, unsigned OpNo1, SStream *OS)
    327 {
    328 	char *tmp;
    329 
    330 	tmp = printAlias1(Str, MI, OpNo0, OS);
    331 	SStream_concat0(OS, ", ");
    332 	printOperand(MI, OpNo1, OS);
    333 
    334 	return tmp;
    335 }
    336 
    337 #define GET_REGINFO_ENUM
    338 #include "MipsGenRegisterInfo.inc"
    339 
    340 static char *printAlias(MCInst *MI, SStream *OS)
    341 {
    342 	switch (MCInst_getOpcode(MI)) {
    343 		case Mips_BEQ:
    344 			// beq $zero, $zero, $L2 => b $L2
    345 			// beq $r0, $zero, $L2 => beqz $r0, $L2
    346 			if (isReg(MI, 0, Mips_ZERO) && isReg(MI, 1, Mips_ZERO))
    347 				return printAlias1("b", MI, 2, OS);
    348 			if (isReg(MI, 1, Mips_ZERO))
    349 				return printAlias2("beqz", MI, 0, 2, OS);
    350 			return NULL;
    351 		case Mips_BEQL:
    352 			// beql $r0, $zero, $L2 => beqzl $r0, $L2
    353 			if (isReg(MI, 0, Mips_ZERO) && isReg(MI, 1, Mips_ZERO))
    354 				return printAlias2("beqzl", MI, 0, 2, OS);
    355 			return NULL;
    356 		case Mips_BEQ64:
    357 			// beq $r0, $zero, $L2 => beqz $r0, $L2
    358 			if (isReg(MI, 1, Mips_ZERO_64))
    359 				return printAlias2("beqz", MI, 0, 2, OS);
    360 			return NULL;
    361 		case Mips_BNE:
    362 			// bne $r0, $zero, $L2 => bnez $r0, $L2
    363 			if (isReg(MI, 1, Mips_ZERO))
    364 				return printAlias2("bnez", MI, 0, 2, OS);
    365 			return NULL;
    366 		case Mips_BNEL:
    367 			// bnel $r0, $zero, $L2 => bnezl $r0, $L2
    368 			if (isReg(MI, 1, Mips_ZERO))
    369 				return printAlias2("bnezl", MI, 0, 2, OS);
    370 			return NULL;
    371 		case Mips_BNE64:
    372 			// bne $r0, $zero, $L2 => bnez $r0, $L2
    373 			if (isReg(MI, 1, Mips_ZERO_64))
    374 				return printAlias2("bnez", MI, 0, 2, OS);
    375 			return NULL;
    376 		case Mips_BGEZAL:
    377 			// bgezal $zero, $L1 => bal $L1
    378 			if (isReg(MI, 0, Mips_ZERO))
    379 				return printAlias1("bal", MI, 1, OS);
    380 			return NULL;
    381 		case Mips_BC1T:
    382 			// bc1t $fcc0, $L1 => bc1t $L1
    383 			if (isReg(MI, 0, Mips_FCC0))
    384 				return printAlias1("bc1t", MI, 1, OS);
    385 			return NULL;
    386 		case Mips_BC1F:
    387 			// bc1f $fcc0, $L1 => bc1f $L1
    388 			if (isReg(MI, 0, Mips_FCC0))
    389 				return printAlias1("bc1f", MI, 1, OS);
    390 			return NULL;
    391 		case Mips_JALR:
    392 			// jalr $ra, $r1 => jalr $r1
    393 			if (isReg(MI, 0, Mips_RA))
    394 				return printAlias1("jalr", MI, 1, OS);
    395 			return NULL;
    396 		case Mips_JALR64:
    397 			// jalr $ra, $r1 => jalr $r1
    398 			if (isReg(MI, 0, Mips_RA_64))
    399 				return printAlias1("jalr", MI, 1, OS);
    400 			return NULL;
    401 		case Mips_NOR:
    402 		case Mips_NOR_MM:
    403 			// nor $r0, $r1, $zero => not $r0, $r1
    404 			if (isReg(MI, 2, Mips_ZERO))
    405 				return printAlias2("not", MI, 0, 1, OS);
    406 			return NULL;
    407 		case Mips_NOR64:
    408 			// nor $r0, $r1, $zero => not $r0, $r1
    409 			if (isReg(MI, 2, Mips_ZERO_64))
    410 				return printAlias2("not", MI, 0, 1, OS);
    411 			return NULL;
    412 		case Mips_OR:
    413 			// or $r0, $r1, $zero => move $r0, $r1
    414 			if (isReg(MI, 2, Mips_ZERO))
    415 				return printAlias2("move", MI, 0, 1, OS);
    416 			return NULL;
    417 		default: return NULL;
    418 	}
    419 }
    420 
    421 #define PRINT_ALIAS_INSTR
    422 #include "MipsGenAsmWriter.inc"
    423 
    424 #endif
    425