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