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