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