1//===-- PPCInstPrinter.cpp - Convert PPC 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 PPC MCInst to a .s file. 11// 12//===----------------------------------------------------------------------===// 13 14/* Capstone Disassembly Engine */ 15/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */ 16 17#ifdef CAPSTONE_HAS_POWERPC 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22 23#include "PPCInstPrinter.h" 24#include "PPCPredicates.h" 25#include "../../MCInst.h" 26#include "../../utils.h" 27#include "../../SStream.h" 28#include "../../MCRegisterInfo.h" 29#include "../../MathExtras.h" 30#include "PPCMapping.h" 31 32#ifndef CAPSTONE_DIET 33static char *getRegisterName(unsigned RegNo); 34#endif 35 36static void printOperand(MCInst *MI, unsigned OpNo, SStream *O); 37static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI); 38static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O); 39static char *printAliasInstr(MCInst *MI, SStream *OS, void *info); 40static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info); 41static void printCustomAliasOperand(MCInst *MI, unsigned OpIdx, 42 unsigned PrintMethodIdx, SStream *OS); 43 44static void set_mem_access(MCInst *MI, bool status) 45{ 46 if (MI->csh->detail != CS_OPT_ON) 47 return; 48 49 MI->csh->doing_mem = status; 50 51 if (status) { 52 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_MEM; 53 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = PPC_REG_INVALID; 54 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = 0; 55 } else { 56 // done, create the next operand slot 57 MI->flat_insn->detail->ppc.op_count++; 58 } 59} 60 61void PPC_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) 62{ 63 if (((cs_struct *)ud)->detail != CS_OPT_ON) 64 return; 65 66 // check if this insn has branch hint 67 if (strrchr(insn_asm, '+') != NULL && !strstr(insn_asm, ".+")) { 68 insn->detail->ppc.bh = PPC_BH_PLUS; 69 } else if (strrchr(insn_asm, '-') != NULL) { 70 insn->detail->ppc.bh = PPC_BH_MINUS; 71 } 72} 73 74#define GET_INSTRINFO_ENUM 75#include "PPCGenInstrInfo.inc" 76 77static int isBOCTRBranch(unsigned int op) 78{ 79 return ((op >= PPC_BDNZ) && (op <= PPC_BDZp)); 80} 81 82void PPC_printInst(MCInst *MI, SStream *O, void *Info) 83{ 84 char *mnem; 85 86 // Check for slwi/srwi mnemonics. 87 if (MCInst_getOpcode(MI) == PPC_RLWINM) { 88 unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2)); 89 unsigned char MB = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3)); 90 unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 4)); 91 bool useSubstituteMnemonic = false; 92 93 if (SH <= 31 && MB == 0 && ME == (31-SH)) { 94 SStream_concat0(O, "slwi\t"); 95 MCInst_setOpcodePub(MI, PPC_INS_SLWI); 96 useSubstituteMnemonic = true; 97 } 98 99 if (SH <= 31 && MB == (32-SH) && ME == 31) { 100 SStream_concat0(O, "srwi\t"); 101 MCInst_setOpcodePub(MI, PPC_INS_SRWI); 102 useSubstituteMnemonic = true; 103 SH = 32-SH; 104 } 105 106 if (useSubstituteMnemonic) { 107 printOperand(MI, 0, O); 108 SStream_concat0(O, ", "); 109 printOperand(MI, 1, O); 110 if (SH > HEX_THRESHOLD) 111 SStream_concat(O, ", 0x%x", (unsigned int)SH); 112 else 113 SStream_concat(O, ", %u", (unsigned int)SH); 114 115 if (MI->csh->detail) { 116 cs_ppc *ppc = &MI->flat_insn->detail->ppc; 117 118 ppc->operands[ppc->op_count].type = PPC_OP_IMM; 119 ppc->operands[ppc->op_count].imm = SH; 120 ++ppc->op_count; 121 } 122 123 return; 124 } 125 } 126 127 if ((MCInst_getOpcode(MI) == PPC_OR || MCInst_getOpcode(MI) == PPC_OR8) && 128 MCOperand_getReg(MCInst_getOperand(MI, 1)) == MCOperand_getReg(MCInst_getOperand(MI, 2))) { 129 SStream_concat0(O, "mr\t"); 130 MCInst_setOpcodePub(MI, PPC_INS_MR); 131 printOperand(MI, 0, O); 132 SStream_concat0(O, ", "); 133 printOperand(MI, 1, O); 134 return; 135 } 136 137 if (MCInst_getOpcode(MI) == PPC_RLDICR) { 138 unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2)); 139 unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3)); 140 // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH 141 if (63-SH == ME) { 142 SStream_concat0(O, "sldi\t"); 143 MCInst_setOpcodePub(MI, PPC_INS_SLDI); 144 printOperand(MI, 0, O); 145 SStream_concat0(O, ", "); 146 printOperand(MI, 1, O); 147 if (SH > HEX_THRESHOLD) 148 SStream_concat(O, ", 0x%x", (unsigned int)SH); 149 else 150 SStream_concat(O, ", %u", (unsigned int)SH); 151 152 return; 153 } 154 } 155 156 if ((MCInst_getOpcode(MI) == PPC_gBC)||(MCInst_getOpcode(MI) == PPC_gBCA)|| 157 (MCInst_getOpcode(MI) == PPC_gBCL)||(MCInst_getOpcode(MI) == PPC_gBCLA)) { 158 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 2)); 159 bd = SignExtend64(bd, 14); 160 MCOperand_setImm(MCInst_getOperand(MI, 2),bd); 161 } 162 163 if (isBOCTRBranch(MCInst_getOpcode(MI))) { 164 if (MCOperand_isImm(MCInst_getOperand(MI,0))) 165 { 166 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0)); 167 bd = SignExtend64(bd, 14); 168 MCOperand_setImm(MCInst_getOperand(MI, 0),bd); 169 } 170 } 171 172 if ((MCInst_getOpcode(MI) == PPC_B)||(MCInst_getOpcode(MI) == PPC_BA)|| 173 (MCInst_getOpcode(MI) == PPC_BL)||(MCInst_getOpcode(MI) == PPC_BLA)) { 174 int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0)); 175 bd = SignExtend64(bd, 24); 176 MCOperand_setImm(MCInst_getOperand(MI, 0),bd); 177 } 178 179 // consider our own alias instructions first 180 mnem = printAliasInstrEx(MI, O, Info); 181 if (!mnem) 182 mnem = printAliasInstr(MI, O, Info); 183 184 if (mnem != NULL) { 185 if (strlen(mnem) > 0) { 186 struct ppc_alias alias; 187 // check to remove the last letter of ('.', '-', '+') 188 if (mnem[strlen(mnem) - 1] == '-' || mnem[strlen(mnem) - 1] == '+' || mnem[strlen(mnem) - 1] == '.') 189 mnem[strlen(mnem) - 1] = '\0'; 190 191 if (PPC_alias_insn(mnem, &alias)) { 192 MCInst_setOpcodePub(MI, alias.id); 193 if (MI->csh->detail) { 194 MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc; 195 } 196 } 197 } 198 199 cs_mem_free(mnem); 200 } else 201 printInstruction(MI, O, NULL); 202} 203 204enum ppc_bc_hint { 205 PPC_BC_LT_MINUS = (0 << 5) | 14, 206 PPC_BC_LE_MINUS = (1 << 5) | 6, 207 PPC_BC_EQ_MINUS = (2 << 5) | 14, 208 PPC_BC_GE_MINUS = (0 << 5) | 6, 209 PPC_BC_GT_MINUS = (1 << 5) | 14, 210 PPC_BC_NE_MINUS = (2 << 5) | 6, 211 PPC_BC_UN_MINUS = (3 << 5) | 14, 212 PPC_BC_NU_MINUS = (3 << 5) | 6, 213 PPC_BC_LT_PLUS = (0 << 5) | 15, 214 PPC_BC_LE_PLUS = (1 << 5) | 7, 215 PPC_BC_EQ_PLUS = (2 << 5) | 15, 216 PPC_BC_GE_PLUS = (0 << 5) | 7, 217 PPC_BC_GT_PLUS = (1 << 5) | 15, 218 PPC_BC_NE_PLUS = (2 << 5) | 7, 219 PPC_BC_UN_PLUS = (3 << 5) | 15, 220 PPC_BC_NU_PLUS = (3 << 5) | 7, 221}; 222 223// normalize CC to remove _MINUS & _PLUS 224static int cc_normalize(int cc) 225{ 226 switch(cc) { 227 default: return cc; 228 case PPC_BC_LT_MINUS: return PPC_BC_LT; 229 case PPC_BC_LE_MINUS: return PPC_BC_LE; 230 case PPC_BC_EQ_MINUS: return PPC_BC_EQ; 231 case PPC_BC_GE_MINUS: return PPC_BC_GE; 232 case PPC_BC_GT_MINUS: return PPC_BC_GT; 233 case PPC_BC_NE_MINUS: return PPC_BC_NE; 234 case PPC_BC_UN_MINUS: return PPC_BC_UN; 235 case PPC_BC_NU_MINUS: return PPC_BC_NU; 236 case PPC_BC_LT_PLUS : return PPC_BC_LT; 237 case PPC_BC_LE_PLUS : return PPC_BC_LE; 238 case PPC_BC_EQ_PLUS : return PPC_BC_EQ; 239 case PPC_BC_GE_PLUS : return PPC_BC_GE; 240 case PPC_BC_GT_PLUS : return PPC_BC_GT; 241 case PPC_BC_NE_PLUS : return PPC_BC_NE; 242 case PPC_BC_UN_PLUS : return PPC_BC_UN; 243 case PPC_BC_NU_PLUS : return PPC_BC_NU; 244 } 245} 246 247static void printPredicateOperand(MCInst *MI, unsigned OpNo, 248 SStream *O, const char *Modifier) 249{ 250 unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 251 252 MI->flat_insn->detail->ppc.bc = (ppc_bc)cc_normalize(Code); 253 254 if (!strcmp(Modifier, "cc")) { 255 switch ((ppc_predicate)Code) { 256 default: // unreachable 257 case PPC_PRED_LT_MINUS: 258 case PPC_PRED_LT_PLUS: 259 case PPC_PRED_LT: 260 SStream_concat0(O, "lt"); 261 return; 262 case PPC_PRED_LE_MINUS: 263 case PPC_PRED_LE_PLUS: 264 case PPC_PRED_LE: 265 SStream_concat0(O, "le"); 266 return; 267 case PPC_PRED_EQ_MINUS: 268 case PPC_PRED_EQ_PLUS: 269 case PPC_PRED_EQ: 270 SStream_concat0(O, "eq"); 271 return; 272 case PPC_PRED_GE_MINUS: 273 case PPC_PRED_GE_PLUS: 274 case PPC_PRED_GE: 275 SStream_concat0(O, "ge"); 276 return; 277 case PPC_PRED_GT_MINUS: 278 case PPC_PRED_GT_PLUS: 279 case PPC_PRED_GT: 280 SStream_concat0(O, "gt"); 281 return; 282 case PPC_PRED_NE_MINUS: 283 case PPC_PRED_NE_PLUS: 284 case PPC_PRED_NE: 285 SStream_concat0(O, "ne"); 286 return; 287 case PPC_PRED_UN_MINUS: 288 case PPC_PRED_UN_PLUS: 289 case PPC_PRED_UN: 290 SStream_concat0(O, "un"); 291 return; 292 case PPC_PRED_NU_MINUS: 293 case PPC_PRED_NU_PLUS: 294 case PPC_PRED_NU: 295 SStream_concat0(O, "nu"); 296 return; 297 case PPC_PRED_BIT_SET: 298 case PPC_PRED_BIT_UNSET: 299 // llvm_unreachable("Invalid use of bit predicate code"); 300 SStream_concat0(O, "invalid-predicate"); 301 return; 302 } 303 } 304 305 if (!strcmp(Modifier, "pm")) { 306 switch ((ppc_predicate)Code) { 307 case PPC_PRED_LT: 308 case PPC_PRED_LE: 309 case PPC_PRED_EQ: 310 case PPC_PRED_GE: 311 case PPC_PRED_GT: 312 case PPC_PRED_NE: 313 case PPC_PRED_UN: 314 case PPC_PRED_NU: 315 return; 316 case PPC_PRED_LT_MINUS: 317 case PPC_PRED_LE_MINUS: 318 case PPC_PRED_EQ_MINUS: 319 case PPC_PRED_GE_MINUS: 320 case PPC_PRED_GT_MINUS: 321 case PPC_PRED_NE_MINUS: 322 case PPC_PRED_UN_MINUS: 323 case PPC_PRED_NU_MINUS: 324 SStream_concat0(O, "-"); 325 return; 326 case PPC_PRED_LT_PLUS: 327 case PPC_PRED_LE_PLUS: 328 case PPC_PRED_EQ_PLUS: 329 case PPC_PRED_GE_PLUS: 330 case PPC_PRED_GT_PLUS: 331 case PPC_PRED_NE_PLUS: 332 case PPC_PRED_UN_PLUS: 333 case PPC_PRED_NU_PLUS: 334 SStream_concat0(O, "+"); 335 return; 336 case PPC_PRED_BIT_SET: 337 case PPC_PRED_BIT_UNSET: 338 // llvm_unreachable("Invalid use of bit predicate code"); 339 SStream_concat0(O, "invalid-predicate"); 340 return; 341 default: // unreachable 342 return; 343 } 344 // llvm_unreachable("Invalid predicate code"); 345 } 346 347 //assert(StringRef(Modifier) == "reg" && 348 // "Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!"); 349 printOperand(MI, OpNo + 1, O); 350} 351 352static void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 353{ 354 unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 355 //assert(Value <= 3 && "Invalid u2imm argument!"); 356 357 if (Value > HEX_THRESHOLD) 358 SStream_concat(O, "0x%x", Value); 359 else 360 SStream_concat(O, "%u", Value); 361 362 if (MI->csh->detail) { 363 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 364 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; 365 MI->flat_insn->detail->ppc.op_count++; 366 } 367} 368 369static void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 370{ 371 unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 372 //assert(Value <= 15 && "Invalid u4imm argument!"); 373 374 if (Value > HEX_THRESHOLD) 375 SStream_concat(O, "0x%x", Value); 376 else 377 SStream_concat(O, "%u", Value); 378 379 if (MI->csh->detail) { 380 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 381 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; 382 MI->flat_insn->detail->ppc.op_count++; 383 } 384} 385 386static void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 387{ 388 int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 389 Value = SignExtend32(Value, 5); 390 391 if (Value >= 0) { 392 if (Value > HEX_THRESHOLD) 393 SStream_concat(O, "0x%x", Value); 394 else 395 SStream_concat(O, "%u", Value); 396 } else { 397 if (Value < -HEX_THRESHOLD) 398 SStream_concat(O, "-0x%x", -Value); 399 else 400 SStream_concat(O, "-%u", -Value); 401 } 402 403 if (MI->csh->detail) { 404 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 405 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; 406 MI->flat_insn->detail->ppc.op_count++; 407 } 408} 409 410static void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 411{ 412 unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 413 //assert(Value <= 31 && "Invalid u5imm argument!"); 414 if (Value > HEX_THRESHOLD) 415 SStream_concat(O, "0x%x", Value); 416 else 417 SStream_concat(O, "%u", Value); 418 419 if (MI->csh->detail) { 420 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 421 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; 422 MI->flat_insn->detail->ppc.op_count++; 423 } 424} 425 426static void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 427{ 428 unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 429 //assert(Value <= 63 && "Invalid u6imm argument!"); 430 if (Value > HEX_THRESHOLD) 431 SStream_concat(O, "0x%x", Value); 432 else 433 SStream_concat(O, "%u", Value); 434 435 if (MI->csh->detail) { 436 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 437 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; 438 MI->flat_insn->detail->ppc.op_count++; 439 } 440} 441 442static void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 443{ 444 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { 445 short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 446 if (Imm >= 0) { 447 if (Imm > HEX_THRESHOLD) 448 SStream_concat(O, "0x%x", Imm); 449 else 450 SStream_concat(O, "%u", Imm); 451 } else { 452 if (Imm < -HEX_THRESHOLD) 453 SStream_concat(O, "-0x%x", -Imm); 454 else 455 SStream_concat(O, "-%u", -Imm); 456 } 457 458 if (MI->csh->detail) { 459 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 460 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm; 461 MI->flat_insn->detail->ppc.op_count++; 462 } 463 } else 464 printOperand(MI, OpNo, O); 465} 466 467static void printS16ImmOperand_Mem(MCInst *MI, unsigned OpNo, SStream *O) 468{ 469 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { 470 short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 471 472 if (Imm >= 0) { 473 if (Imm > HEX_THRESHOLD) 474 SStream_concat(O, "0x%x", Imm); 475 else 476 SStream_concat(O, "%u", Imm); 477 } else { 478 if (Imm < -HEX_THRESHOLD) 479 SStream_concat(O, "-0x%x", -Imm); 480 else 481 SStream_concat(O, "-%u", -Imm); 482 } 483 484 if (MI->csh->detail) { 485 if (MI->csh->doing_mem) { 486 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = Imm; 487 } else { 488 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 489 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm; 490 MI->flat_insn->detail->ppc.op_count++; 491 } 492 } 493 } else 494 printOperand(MI, OpNo, O); 495} 496 497static void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) 498{ 499 if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { 500 unsigned short Imm = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 501 if (Imm > HEX_THRESHOLD) 502 SStream_concat(O, "0x%x", Imm); 503 else 504 SStream_concat(O, "%u", Imm); 505 506 if (MI->csh->detail) { 507 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 508 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm; 509 MI->flat_insn->detail->ppc.op_count++; 510 } 511 } else 512 printOperand(MI, OpNo, O); 513} 514 515static void printBranchOperand(MCInst *MI, unsigned OpNo, SStream *O) 516{ 517 if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { 518 printOperand(MI, OpNo, O); 519 return; 520 } 521 522 // Branches can take an immediate operand. This is used by the branch 523 // selection pass to print .+8, an eight byte displacement from the PC. 524 printAbsBranchOperand(MI, OpNo, O); 525} 526 527static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O) 528{ 529 int imm; 530 531 if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { 532 printOperand(MI, OpNo, O); 533 return; 534 } 535 536 imm = ((int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)) << 2); 537 538 if (!PPC_abs_branch(MI->csh, MCInst_getOpcode(MI))) { 539 imm = (int)MI->address + imm; 540 } 541 542 SStream_concat(O, "0x%x", imm); 543 544 if (MI->csh->detail) { 545 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 546 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm; 547 MI->flat_insn->detail->ppc.op_count++; 548 } 549} 550 551 552#define GET_REGINFO_ENUM 553#include "PPCGenRegisterInfo.inc" 554 555static void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O) 556{ 557 unsigned RegNo, tmp; 558 unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, OpNo)); 559 560 switch (CCReg) { 561 default: // llvm_unreachable("Unknown CR register"); 562 case PPC_CR0: RegNo = 0; break; 563 case PPC_CR1: RegNo = 1; break; 564 case PPC_CR2: RegNo = 2; break; 565 case PPC_CR3: RegNo = 3; break; 566 case PPC_CR4: RegNo = 4; break; 567 case PPC_CR5: RegNo = 5; break; 568 case PPC_CR6: RegNo = 6; break; 569 case PPC_CR7: RegNo = 7; break; 570 } 571 572 tmp = 0x80 >> RegNo; 573 if (tmp > HEX_THRESHOLD) 574 SStream_concat(O, "0x%x", tmp); 575 else 576 SStream_concat(O, "%u", tmp); 577} 578 579static void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O) 580{ 581 set_mem_access(MI, true); 582 583 printS16ImmOperand_Mem(MI, OpNo, O); 584 585 SStream_concat0(O, "("); 586 587 if (MCOperand_getReg(MCInst_getOperand(MI, OpNo + 1)) == PPC_R0) 588 SStream_concat0(O, "0"); 589 else 590 printOperand(MI, OpNo + 1, O); 591 592 SStream_concat0(O, ")"); 593 set_mem_access(MI, false); 594} 595 596static void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O) 597{ 598 // When used as the base register, r0 reads constant zero rather than 599 // the value contained in the register. For this reason, the darwin 600 // assembler requires that we print r0 as 0 (no r) when used as the base. 601 if (MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == PPC_R0) 602 SStream_concat0(O, "0"); 603 else 604 printOperand(MI, OpNo, O); 605 SStream_concat0(O, ", "); 606 607 printOperand(MI, OpNo + 1, O); 608} 609 610static void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O) 611{ 612 set_mem_access(MI, true); 613 //printBranchOperand(MI, OpNo, O); 614 615 // On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must 616 // come at the _end_ of the expression. 617 618 SStream_concat0(O, "("); 619 printOperand(MI, OpNo + 1, O); 620 SStream_concat0(O, ")"); 621 set_mem_access(MI, false); 622} 623 624#ifndef CAPSTONE_DIET 625/// stripRegisterPrefix - This method strips the character prefix from a 626/// register name so that only the number is left. Used by for linux asm. 627static char *stripRegisterPrefix(char *RegName) 628{ 629 switch (RegName[0]) { 630 case 'r': 631 case 'f': 632 case 'v': 633 if (RegName[1] == 's') 634 return RegName + 2; 635 return RegName + 1; 636 case 'c': 637 if (RegName[1] == 'r') 638 return RegName + 2; 639 } 640 641 return RegName; 642} 643#endif 644 645static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) 646{ 647 MCOperand *Op = MCInst_getOperand(MI, OpNo); 648 if (MCOperand_isReg(Op)) { 649 unsigned reg = MCOperand_getReg(Op); 650#ifndef CAPSTONE_DIET 651 char *RegName = getRegisterName(reg); 652#endif 653 // map to public register 654 reg = PPC_map_register(reg); 655#ifndef CAPSTONE_DIET 656 // The linux and AIX assembler does not take register prefixes. 657 if (MI->csh->syntax == CS_OPT_SYNTAX_NOREGNAME) 658 RegName = stripRegisterPrefix(RegName); 659 660 SStream_concat0(O, RegName); 661#endif 662 663 if (MI->csh->detail) { 664 if (MI->csh->doing_mem) { 665 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = reg; 666 } else { 667 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG; 668 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg; 669 MI->flat_insn->detail->ppc.op_count++; 670 } 671 } 672 673 return; 674 } 675 676 if (MCOperand_isImm(Op)) { 677 int32_t imm = (int32_t)MCOperand_getImm(Op); 678 if (imm >= 0) { 679 if (imm > HEX_THRESHOLD) 680 SStream_concat(O, "0x%x", imm); 681 else 682 SStream_concat(O, "%u", imm); 683 } else { 684 if (imm < -HEX_THRESHOLD) 685 SStream_concat(O, "-0x%x", -imm); 686 else 687 SStream_concat(O, "-%u", -imm); 688 } 689 690 if (MI->csh->detail) { 691 if (MI->csh->doing_mem) { 692 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = imm; 693 } else { 694 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 695 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm; 696 MI->flat_insn->detail->ppc.op_count++; 697 } 698 } 699 } 700} 701 702static void op_addImm(MCInst *MI, int v) 703{ 704 if (MI->csh->detail) { 705 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; 706 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = v; 707 MI->flat_insn->detail->ppc.op_count++; 708 } 709} 710 711static void op_addReg(MCInst *MI, unsigned int reg) 712{ 713 if (MI->csh->detail) { 714 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG; 715 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg; 716 MI->flat_insn->detail->ppc.op_count++; 717 } 718} 719 720static void op_addBC(MCInst *MI, unsigned int bc) 721{ 722 if (MI->csh->detail) { 723 MI->flat_insn->detail->ppc.bc = (ppc_bc)bc; 724 } 725} 726 727#define CREQ (0) 728#define CRGT (1) 729#define CRLT (2) 730#define CRUN (3) 731 732static int getBICRCond(int bi) 733{ 734 return (bi-PPC_CR0EQ) >> 3; 735} 736 737static int getBICR(int bi) 738{ 739 return ((bi - PPC_CR0EQ) & 7) + PPC_CR0; 740} 741 742static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info) 743{ 744#define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg))) 745 SStream ss; 746 const char *opCode; 747 char *tmp, *AsmMnem, *AsmOps, *c; 748 int OpIdx, PrintMethodIdx; 749 int decCtr = false, needComma = false; 750 MCRegisterInfo *MRI = (MCRegisterInfo *)info; 751 752 SStream_Init(&ss); 753 switch (MCInst_getOpcode(MI)) { 754 default: return NULL; 755 case PPC_gBC: 756 opCode = "b%s"; 757 break; 758 case PPC_gBCA: 759 opCode = "b%sa"; 760 break; 761 case PPC_gBCCTR: 762 opCode = "b%sctr"; 763 break; 764 case PPC_gBCCTRL: 765 opCode = "b%sctrl"; 766 break; 767 case PPC_gBCL: 768 opCode = "b%sl"; 769 break; 770 case PPC_gBCLA: 771 opCode = "b%sla"; 772 break; 773 case PPC_gBCLR: 774 opCode = "b%slr"; 775 break; 776 case PPC_gBCLRL: 777 opCode = "b%slrl"; 778 break; 779 } 780 781 if (MCInst_getNumOperands(MI) == 3 && 782 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 783 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) && 784 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) { 785 SStream_concat(&ss, opCode, "dnzf"); 786 decCtr = true; 787 } 788 789 if (MCInst_getNumOperands(MI) == 3 && 790 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 791 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) && 792 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) { 793 SStream_concat(&ss, opCode, "dzf"); 794 decCtr = true; 795 } 796 797 if (MCInst_getNumOperands(MI) == 3 && 798 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 799 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 4) && 800 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 7) && 801 MCOperand_isReg(MCInst_getOperand(MI, 1)) && 802 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) { 803 int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); 804 switch(cr) { 805 case CREQ: 806 SStream_concat(&ss, opCode, "ne"); 807 break; 808 case CRGT: 809 SStream_concat(&ss, opCode, "le"); 810 break; 811 case CRLT: 812 SStream_concat(&ss, opCode, "ge"); 813 break; 814 case CRUN: 815 SStream_concat(&ss, opCode, "ns"); 816 break; 817 } 818 819 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6) 820 SStream_concat0(&ss, "-"); 821 822 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7) 823 SStream_concat0(&ss, "+"); 824 825 decCtr = false; 826 } 827 828 if (MCInst_getNumOperands(MI) == 3 && 829 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 830 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) && 831 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) { 832 SStream_concat(&ss, opCode, "dnzt"); 833 decCtr = true; 834 } 835 836 if (MCInst_getNumOperands(MI) == 3 && 837 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 838 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) && 839 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) { 840 SStream_concat(&ss, opCode, "dzt"); 841 decCtr = true; 842 } 843 844 if (MCInst_getNumOperands(MI) == 3 && 845 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 846 (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) && 847 (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 15) && 848 MCOperand_isReg(MCInst_getOperand(MI, 1)) && 849 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) { 850 int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); 851 switch(cr) { 852 case CREQ: 853 SStream_concat(&ss, opCode, "eq"); 854 break; 855 case CRGT: 856 SStream_concat(&ss, opCode, "gt"); 857 break; 858 case CRLT: 859 SStream_concat(&ss, opCode, "lt"); 860 break; 861 case CRUN: 862 SStream_concat(&ss, opCode, "so"); 863 break; 864 } 865 866 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14) 867 SStream_concat0(&ss, "-"); 868 869 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15) 870 SStream_concat0(&ss, "+"); 871 872 decCtr = false; 873 } 874 875 if (MCInst_getNumOperands(MI) == 3 && 876 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 877 ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 16)) { 878 SStream_concat(&ss, opCode, "dnz"); 879 880 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 24) 881 SStream_concat0(&ss, "-"); 882 883 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25) 884 SStream_concat0(&ss, "+"); 885 886 needComma = false; 887 } 888 889 if (MCInst_getNumOperands(MI) == 3 && 890 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 891 ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 18)) { 892 SStream_concat(&ss, opCode, "dz"); 893 894 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 26) 895 SStream_concat0(&ss, "-"); 896 897 if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27) 898 SStream_concat0(&ss, "+"); 899 900 needComma = false; 901 } 902 903 if (MCOperand_isReg(MCInst_getOperand(MI, 1)) && 904 GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1) && 905 MCOperand_isImm(MCInst_getOperand(MI, 0)) && 906 (MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) { 907 int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1))); 908 909 if (decCtr) { 910 needComma = true; 911 SStream_concat0(&ss, " "); 912 913 if (cr > PPC_CR0) { 914 SStream_concat(&ss, "4*cr%d+", cr - PPC_CR0); 915 } 916 917 cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); 918 switch(cr) { 919 case CREQ: 920 SStream_concat0(&ss, "eq"); 921 op_addBC(MI, PPC_BC_EQ); 922 break; 923 case CRGT: 924 SStream_concat0(&ss, "gt"); 925 op_addBC(MI, PPC_BC_GT); 926 break; 927 case CRLT: 928 SStream_concat0(&ss, "lt"); 929 op_addBC(MI, PPC_BC_LT); 930 break; 931 case CRUN: 932 SStream_concat0(&ss, "so"); 933 op_addBC(MI, PPC_BC_SO); 934 break; 935 } 936 937 cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1))); 938 if (cr > PPC_CR0) { 939 if (MI->csh->detail) { 940 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_CRX; 941 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.scale = 4; 942 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.reg = PPC_REG_CR0 + cr - PPC_CR0; 943 MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.cond = MI->flat_insn->detail->ppc.bc; 944 MI->flat_insn->detail->ppc.op_count++; 945 } 946 } 947 } else { 948 if (cr > PPC_CR0) { 949 needComma = true; 950 SStream_concat(&ss, " cr%d", cr - PPC_CR0); 951 op_addReg(MI, PPC_REG_CR0 + cr - PPC_CR0); 952 } 953 } 954 } 955 956 if (MCOperand_isImm(MCInst_getOperand(MI, 2)) && 957 MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) { 958 if (needComma) 959 SStream_concat0(&ss, ","); 960 961 SStream_concat0(&ss, " $\xFF\x03\x01"); 962 } 963 964 tmp = cs_strdup(ss.buffer); 965 AsmMnem = tmp; 966 for(AsmOps = tmp; *AsmOps; AsmOps++) { 967 if (*AsmOps == ' ' || *AsmOps == '\t') { 968 *AsmOps = '\0'; 969 AsmOps++; 970 break; 971 } 972 } 973 974 SStream_concat0(OS, AsmMnem); 975 if (*AsmOps) { 976 SStream_concat0(OS, "\t"); 977 for (c = AsmOps; *c; c++) { 978 if (*c == '$') { 979 c += 1; 980 if (*c == (char)0xff) { 981 c += 1; 982 OpIdx = *c - 1; 983 c += 1; 984 PrintMethodIdx = *c - 1; 985 printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS); 986 } else 987 printOperand(MI, *c - 1, OS); 988 } else { 989 SStream_concat(OS, "%c", *c); 990 } 991 } 992 } 993 994 return tmp; 995} 996 997#define PRINT_ALIAS_INSTR 998#include "PPCGenAsmWriter.inc" 999 1000#endif 1001