Home | History | Annotate | Download | only in PowerPC
      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 (at) 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
     33 static char *getRegisterName(unsigned RegNo);
     34 #endif
     35 
     36 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
     37 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
     38 static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O);
     39 static char *printAliasInstr(MCInst *MI, SStream *OS, void *info);
     40 static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info);
     41 static void printCustomAliasOperand(MCInst *MI, unsigned OpIdx,
     42 		unsigned PrintMethodIdx, SStream *OS);
     43 
     44 static 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 
     61 void 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 
     77 static int isBOCTRBranch(unsigned int op)
     78 {
     79 	return ((op >= PPC_BDNZ) && (op <= PPC_BDZp));
     80 }
     81 
     82 void 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 
    204 enum 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
    224 static 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 
    247 static 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 
    352 static 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 
    369 static 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 
    386 static 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 
    410 static 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 
    426 static 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 
    442 static 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 
    467 static 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 
    497 static 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 
    515 static 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 
    527 static 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 
    555 static 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 
    579 static 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 
    596 static 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 
    610 static 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.
    627 static 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 
    645 static 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 
    702 static 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 
    711 static 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 
    720 static 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 
    732 static int getBICRCond(int bi)
    733 {
    734 	return (bi-PPC_CR0EQ) >> 3;
    735 }
    736 
    737 static int getBICR(int bi)
    738 {
    739 	return ((bi - PPC_CR0EQ) & 7) + PPC_CR0;
    740 }
    741 
    742 static 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