• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This class prints an PPC MCInst to a .s file.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 /* Capstone Disassembly Engine */
15 /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */
16 
17 #ifdef CAPSTONE_HAS_POWERPC
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "PPCInstPrinter.h"
24 #include "PPCPredicates.h"
25 #include "../../MCInst.h"
26 #include "../../utils.h"
27 #include "../../SStream.h"
28 #include "../../MCRegisterInfo.h"
29 #include "../../MathExtras.h"
30 #include "PPCMapping.h"
31 
32 #ifndef CAPSTONE_DIET
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 
set_mem_access(MCInst * MI,bool status)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 
PPC_post_printer(csh ud,cs_insn * insn,char * insn_asm,MCInst * mci)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 
isBOCTRBranch(unsigned int op)77 static int isBOCTRBranch(unsigned int op)
78 {
79 	return ((op >= PPC_BDNZ) && (op <= PPC_BDZp));
80 }
81 
PPC_printInst(MCInst * MI,SStream * O,void * Info)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
cc_normalize(int cc)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 
printPredicateOperand(MCInst * MI,unsigned OpNo,SStream * O,const char * Modifier)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 
printU2ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printU4ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printS5ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printU5ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printU6ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printS16ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printS16ImmOperand_Mem(MCInst * MI,unsigned OpNo,SStream * O)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 
printU16ImmOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printBranchOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printAbsBranchOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printcrbitm(MCInst * MI,unsigned OpNo,SStream * O)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 
printMemRegImm(MCInst * MI,unsigned OpNo,SStream * O)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 
printMemRegReg(MCInst * MI,unsigned OpNo,SStream * O)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 
printTLSCall(MCInst * MI,unsigned OpNo,SStream * O)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.
stripRegisterPrefix(char * RegName)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 
printOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
op_addImm(MCInst * MI,int v)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 
op_addReg(MCInst * MI,unsigned int reg)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 
op_addBC(MCInst * MI,unsigned int bc)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 
getBICRCond(int bi)732 static int getBICRCond(int bi)
733 {
734 	return (bi-PPC_CR0EQ) >> 3;
735 }
736 
getBICR(int bi)737 static int getBICR(int bi)
738 {
739 	return ((bi - PPC_CR0EQ) & 7) + PPC_CR0;
740 }
741 
printAliasInstrEx(MCInst * MI,SStream * OS,void * info)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