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