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