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