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