/src/capstonev5/arch/PowerPC/PPCInstPrinter.c
Line | Count | Source |
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); |
38 | | static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O); |
39 | | static char *printAliasInstr(MCInst *MI, SStream *OS, MCRegisterInfo *MRI); |
40 | | static char *printAliasBcc(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 | | |
60 | | static void set_mem_access(MCInst *MI, bool status) |
61 | 26.0k | { |
62 | 26.0k | if (MI->csh->detail != CS_OPT_ON) |
63 | 0 | return; |
64 | | |
65 | 26.0k | MI->csh->doing_mem = status; |
66 | | |
67 | 26.0k | if (status) { |
68 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_MEM; |
69 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = PPC_REG_INVALID; |
70 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = 0; |
71 | 13.0k | } else { |
72 | | // done, create the next operand slot |
73 | 13.0k | MI->flat_insn->detail->ppc.op_count++; |
74 | 13.0k | } |
75 | 26.0k | } |
76 | | |
77 | | void PPC_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) |
78 | 95.8k | { |
79 | 95.8k | if (((cs_struct *)ud)->detail != CS_OPT_ON) |
80 | 0 | return; |
81 | | |
82 | | // insn->mnemonic is not filled yet; the record-form '.' and the branch |
83 | | // hint '+'/'-' are always the last char of the mnemonic token of insn_asm |
84 | 95.8k | size_t n = strcspn(insn_asm, " \t"); |
85 | 95.8k | char c = n ? insn_asm[n - 1] : 0; |
86 | | |
87 | 95.8k | if (c == '+') { |
88 | 1.08k | insn->detail->ppc.bh = PPC_BH_PLUS; |
89 | 94.7k | } else if (c == '-') { |
90 | 1.24k | insn->detail->ppc.bh = PPC_BH_MINUS; |
91 | 93.5k | } else if (c == '.') { |
92 | 8.25k | insn->detail->ppc.update_cr0 = true; |
93 | 8.25k | } |
94 | 95.8k | } |
95 | | |
96 | | #define GET_INSTRINFO_ENUM |
97 | | #include "PPCGenInstrInfo.inc" |
98 | | |
99 | | #define GET_REGINFO_ENUM |
100 | | #include "PPCGenRegisterInfo.inc" |
101 | | |
102 | | static void op_addBC(MCInst *MI, unsigned int bc) |
103 | 1.35k | { |
104 | 1.35k | if (MI->csh->detail) { |
105 | 1.35k | MI->flat_insn->detail->ppc.bc = (ppc_bc)bc; |
106 | 1.35k | } |
107 | 1.35k | } |
108 | | |
109 | 578 | #define CREQ (0) |
110 | 423 | #define CRGT (1) |
111 | 587 | #define CRLT (2) |
112 | 556 | #define CRUN (3) |
113 | | |
114 | | static int getBICRCond(int bi) |
115 | 2.14k | { |
116 | 2.14k | return (bi - PPC_CR0EQ) >> 3; |
117 | 2.14k | } |
118 | | |
119 | | static int getBICR(int bi) |
120 | 2.14k | { |
121 | 2.14k | return ((bi - PPC_CR0EQ) & 7) + PPC_CR0; |
122 | 2.14k | } |
123 | | |
124 | | static void op_addReg(MCInst *MI, unsigned int reg) |
125 | 705 | { |
126 | 705 | if (MI->csh->detail) { |
127 | 705 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG; |
128 | 705 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg; |
129 | 705 | MI->flat_insn->detail->ppc.op_count++; |
130 | 705 | } |
131 | 705 | } |
132 | | |
133 | | static void add_CRxx(MCInst *MI, ppc_reg reg) |
134 | 435 | { |
135 | 435 | if (MI->csh->detail) { |
136 | 435 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG; |
137 | 435 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg; |
138 | 435 | MI->flat_insn->detail->ppc.op_count++; |
139 | 435 | } |
140 | 435 | } |
141 | | |
142 | | static char *printAliasBcc(MCInst *MI, SStream *OS, void *info) |
143 | 94.4k | { |
144 | 94.4k | #define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg))) |
145 | 94.4k | SStream ss; |
146 | 94.4k | const char *opCode; |
147 | 94.4k | char *tmp, *AsmMnem, *AsmOps, *c; |
148 | 94.4k | int OpIdx, PrintMethodIdx; |
149 | 94.4k | int decCtr = false, needComma = false; |
150 | 94.4k | MCRegisterInfo *MRI = (MCRegisterInfo *)info; |
151 | | |
152 | 94.4k | SStream_Init(&ss); |
153 | | |
154 | 94.4k | switch (MCInst_getOpcode(MI)) { |
155 | 90.2k | default: return NULL; |
156 | 1.79k | case PPC_gBC: |
157 | 1.79k | opCode = "b%s"; |
158 | 1.79k | break; |
159 | 937 | case PPC_gBCA: |
160 | 937 | opCode = "b%sa"; |
161 | 937 | break; |
162 | 115 | case PPC_gBCCTR: |
163 | 115 | opCode = "b%sctr"; |
164 | 115 | break; |
165 | 40 | case PPC_gBCCTRL: |
166 | 40 | opCode = "b%sctrl"; |
167 | 40 | break; |
168 | 648 | case PPC_gBCL: |
169 | 648 | opCode = "b%sl"; |
170 | 648 | break; |
171 | 560 | case PPC_gBCLA: |
172 | 560 | opCode = "b%sla"; |
173 | 560 | break; |
174 | 70 | case PPC_gBCLR: |
175 | 70 | opCode = "b%slr"; |
176 | 70 | break; |
177 | 15 | case PPC_gBCLRL: |
178 | 15 | opCode = "b%slrl"; |
179 | 15 | break; |
180 | 94.4k | } |
181 | | |
182 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
183 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
184 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) && |
185 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) { |
186 | 328 | SStream_concat(&ss, opCode, "dnzf"); |
187 | 328 | decCtr = true; |
188 | 328 | } |
189 | | |
190 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
191 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
192 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) && |
193 | 3.85k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) { |
194 | 373 | SStream_concat(&ss, opCode, "dzf"); |
195 | 373 | decCtr = true; |
196 | 373 | } |
197 | | |
198 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
199 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
200 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 4) && |
201 | 3.48k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 7) && |
202 | 428 | MCOperand_isReg(MCInst_getOperand(MI, 1)) && |
203 | 428 | GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) { |
204 | 428 | int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); |
205 | | |
206 | 428 | switch(cr) { |
207 | 130 | case CREQ: |
208 | 130 | SStream_concat(&ss, opCode, "ne"); |
209 | 130 | break; |
210 | 192 | case CRGT: |
211 | 192 | SStream_concat(&ss, opCode, "le"); |
212 | 192 | break; |
213 | 66 | case CRLT: |
214 | 66 | SStream_concat(&ss, opCode, "ge"); |
215 | 66 | break; |
216 | 40 | case CRUN: |
217 | 40 | SStream_concat(&ss, opCode, "ns"); |
218 | 40 | break; |
219 | 428 | } |
220 | | |
221 | 428 | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6) |
222 | 129 | SStream_concat0(&ss, "-"); |
223 | | |
224 | 428 | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7) |
225 | 221 | SStream_concat0(&ss, "+"); |
226 | | |
227 | 428 | decCtr = false; |
228 | 428 | } |
229 | | |
230 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
231 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
232 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) && |
233 | 3.05k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) { |
234 | 495 | SStream_concat(&ss, opCode, "dnzt"); |
235 | 495 | decCtr = true; |
236 | 495 | } |
237 | | |
238 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
239 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
240 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) && |
241 | 2.55k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) { |
242 | 159 | SStream_concat(&ss, opCode, "dzt"); |
243 | 159 | decCtr = true; |
244 | 159 | } |
245 | | |
246 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
247 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
248 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) && |
249 | 2.40k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 15) && |
250 | 361 | MCOperand_isReg(MCInst_getOperand(MI, 1)) && |
251 | 361 | GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) { |
252 | 361 | int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); |
253 | | |
254 | 361 | switch(cr) { |
255 | 69 | case CREQ: |
256 | 69 | SStream_concat(&ss, opCode, "eq"); |
257 | 69 | break; |
258 | 56 | case CRGT: |
259 | 56 | SStream_concat(&ss, opCode, "gt"); |
260 | 56 | break; |
261 | 198 | case CRLT: |
262 | 198 | SStream_concat(&ss, opCode, "lt"); |
263 | 198 | break; |
264 | 38 | case CRUN: |
265 | 38 | SStream_concat(&ss, opCode, "so"); |
266 | 38 | break; |
267 | 361 | } |
268 | | |
269 | 361 | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14) |
270 | 194 | SStream_concat0(&ss, "-"); |
271 | | |
272 | 361 | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15) |
273 | 61 | SStream_concat0(&ss, "+"); |
274 | | |
275 | 361 | decCtr = false; |
276 | 361 | } |
277 | | |
278 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
279 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
280 | 4.18k | ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 16)) { |
281 | 889 | SStream_concat(&ss, opCode, "dnz"); |
282 | | |
283 | 889 | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 24) |
284 | 292 | SStream_concat0(&ss, "-"); |
285 | | |
286 | 889 | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25) |
287 | 278 | SStream_concat0(&ss, "+"); |
288 | | |
289 | 889 | needComma = false; |
290 | 889 | } |
291 | | |
292 | 4.18k | if (MCInst_getNumOperands(MI) == 3 && |
293 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
294 | 4.18k | ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 18)) { |
295 | 1.15k | SStream_concat(&ss, opCode, "dz"); |
296 | | |
297 | 1.15k | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 26) |
298 | 453 | SStream_concat0(&ss, "-"); |
299 | | |
300 | 1.15k | if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27) |
301 | 270 | SStream_concat0(&ss, "+"); |
302 | | |
303 | 1.15k | needComma = false; |
304 | 1.15k | } |
305 | | |
306 | 4.18k | if (MCOperand_isReg(MCInst_getOperand(MI, 1)) && |
307 | 4.18k | GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1) && |
308 | 4.18k | MCOperand_isImm(MCInst_getOperand(MI, 0)) && |
309 | 4.18k | (MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) { |
310 | 2.14k | int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1))); |
311 | | |
312 | 2.14k | if (decCtr) { |
313 | 1.35k | int cd; |
314 | 1.35k | needComma = true; |
315 | 1.35k | SStream_concat0(&ss, " "); |
316 | | |
317 | 1.35k | if (cr > PPC_CR0) { |
318 | 920 | SStream_concat(&ss, "4*cr%d+", cr - PPC_CR0); |
319 | 920 | } |
320 | | |
321 | 1.35k | cd = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); |
322 | 1.35k | switch(cd) { |
323 | 379 | case CREQ: |
324 | 379 | SStream_concat0(&ss, "eq"); |
325 | 379 | if (cr <= PPC_CR0) |
326 | 71 | add_CRxx(MI, PPC_REG_CR0EQ); |
327 | 379 | op_addBC(MI, PPC_BC_EQ); |
328 | 379 | break; |
329 | 175 | case CRGT: |
330 | 175 | SStream_concat0(&ss, "gt"); |
331 | 175 | if (cr <= PPC_CR0) |
332 | 136 | add_CRxx(MI, PPC_REG_CR0GT); |
333 | 175 | op_addBC(MI, PPC_BC_GT); |
334 | 175 | break; |
335 | 323 | case CRLT: |
336 | 323 | SStream_concat0(&ss, "lt"); |
337 | 323 | if (cr <= PPC_CR0) |
338 | 134 | add_CRxx(MI, PPC_REG_CR0LT); |
339 | 323 | op_addBC(MI, PPC_BC_LT); |
340 | 323 | break; |
341 | 478 | case CRUN: |
342 | 478 | SStream_concat0(&ss, "so"); |
343 | 478 | if (cr <= PPC_CR0) |
344 | 94 | add_CRxx(MI, PPC_REG_CR0UN); |
345 | 478 | op_addBC(MI, PPC_BC_SO); |
346 | 478 | break; |
347 | 1.35k | } |
348 | | |
349 | 1.35k | if (cr > PPC_CR0) { |
350 | 920 | if (MI->csh->detail) { |
351 | 920 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG; |
352 | 920 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = MCOperand_getReg(MCInst_getOperand(MI, 1)); |
353 | 920 | MI->flat_insn->detail->ppc.op_count++; |
354 | 920 | } |
355 | 920 | } |
356 | 1.35k | } else { |
357 | 789 | if (cr > PPC_CR0) { |
358 | 705 | needComma = true; |
359 | 705 | SStream_concat(&ss, " cr%d", cr - PPC_CR0); |
360 | 705 | op_addReg(MI, PPC_REG_CR0 + cr - PPC_CR0); |
361 | 705 | } |
362 | 789 | } |
363 | 2.14k | } |
364 | | |
365 | 4.18k | if (MCOperand_isImm(MCInst_getOperand(MI, 2)) && |
366 | 4.18k | MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) { |
367 | 3.63k | if (needComma) |
368 | 1.61k | SStream_concat0(&ss, ","); |
369 | | |
370 | 3.63k | SStream_concat0(&ss, " $\xFF\x03\x01"); |
371 | 3.63k | } |
372 | | |
373 | 4.18k | tmp = cs_strdup(ss.buffer); |
374 | 4.18k | AsmMnem = tmp; |
375 | 25.0k | for(AsmOps = tmp; *AsmOps; AsmOps++) { |
376 | 24.9k | if (*AsmOps == ' ' || *AsmOps == '\t') { |
377 | 4.08k | *AsmOps = '\0'; |
378 | 4.08k | AsmOps++; |
379 | 4.08k | break; |
380 | 4.08k | } |
381 | 24.9k | } |
382 | | |
383 | 4.18k | SStream_concat0(OS, AsmMnem); |
384 | 4.18k | if (*AsmOps) { |
385 | 4.08k | SStream_concat0(OS, "\t"); |
386 | 21.2k | for (c = AsmOps; *c; c++) { |
387 | 17.2k | if (*c == '$') { |
388 | 3.63k | c += 1; |
389 | 3.63k | if (*c == (char)0xff) { |
390 | 3.63k | c += 1; |
391 | 3.63k | OpIdx = *c - 1; |
392 | 3.63k | c += 1; |
393 | 3.63k | PrintMethodIdx = *c - 1; |
394 | 3.63k | printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS); |
395 | 3.63k | } else |
396 | 0 | printOperand(MI, *c - 1, OS); |
397 | 13.5k | } else { |
398 | 13.5k | SStream_concat1(OS, *c); |
399 | 13.5k | } |
400 | 17.2k | } |
401 | 4.08k | } |
402 | | |
403 | 4.18k | return tmp; |
404 | 4.18k | } |
405 | | |
406 | | static bool isBOCTRBranch(unsigned int op) |
407 | 94.4k | { |
408 | 94.4k | return ((op >= PPC_BDNZ) && (op <= PPC_BDZp)); |
409 | 94.4k | } |
410 | | |
411 | | void PPC_printInst(MCInst *MI, SStream *O, void *Info) |
412 | 95.8k | { |
413 | 95.8k | char *mnem; |
414 | 95.8k | unsigned int opcode = MCInst_getOpcode(MI); |
415 | 95.8k | memset(O->buffer, 0, sizeof(O->buffer)); |
416 | | |
417 | | // printf("opcode = %u\n", opcode); |
418 | | |
419 | | // Check for slwi/srwi mnemonics. |
420 | 95.8k | if (opcode == PPC_RLWINM) { |
421 | 1.53k | unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2)); |
422 | 1.53k | unsigned char MB = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3)); |
423 | 1.53k | unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 4)); |
424 | 1.53k | bool useSubstituteMnemonic = false; |
425 | | |
426 | 1.53k | if (SH <= 31 && MB == 0 && ME == (31 - SH)) { |
427 | 307 | SStream_concat0(O, "slwi\t"); |
428 | 307 | MCInst_setOpcodePub(MI, PPC_INS_SLWI); |
429 | 307 | useSubstituteMnemonic = true; |
430 | 307 | } |
431 | | |
432 | 1.53k | if (SH <= 31 && MB == (32 - SH) && ME == 31) { |
433 | 139 | SStream_concat0(O, "srwi\t"); |
434 | 139 | MCInst_setOpcodePub(MI, PPC_INS_SRWI); |
435 | 139 | useSubstituteMnemonic = true; |
436 | 139 | SH = 32 - SH; |
437 | 139 | } |
438 | | |
439 | 1.53k | if (useSubstituteMnemonic) { |
440 | 446 | printOperand(MI, 0, O); |
441 | 446 | SStream_concat0(O, ", "); |
442 | 446 | printOperand(MI, 1, O); |
443 | | |
444 | 446 | if (SH > HEX_THRESHOLD) |
445 | 139 | SStream_concat(O, ", 0x%x", (unsigned int)SH); |
446 | 307 | else |
447 | 307 | SStream_concat(O, ", %u", (unsigned int)SH); |
448 | | |
449 | 446 | if (MI->csh->detail) { |
450 | 446 | cs_ppc *ppc = &MI->flat_insn->detail->ppc; |
451 | | |
452 | 446 | ppc->operands[ppc->op_count].type = PPC_OP_IMM; |
453 | 446 | ppc->operands[ppc->op_count].imm = SH; |
454 | 446 | ++ppc->op_count; |
455 | 446 | } |
456 | | |
457 | 446 | return; |
458 | 446 | } |
459 | 1.53k | } |
460 | | |
461 | 95.3k | if ((opcode == PPC_OR || opcode == PPC_OR8) && |
462 | 92 | MCOperand_getReg(MCInst_getOperand(MI, 1)) == MCOperand_getReg(MCInst_getOperand(MI, 2))) { |
463 | 58 | SStream_concat0(O, "mr\t"); |
464 | 58 | MCInst_setOpcodePub(MI, PPC_INS_MR); |
465 | | |
466 | 58 | printOperand(MI, 0, O); |
467 | 58 | SStream_concat0(O, ", "); |
468 | 58 | printOperand(MI, 1, O); |
469 | | |
470 | 58 | return; |
471 | 58 | } |
472 | | |
473 | 95.3k | if (opcode == PPC_RLDICR || |
474 | 94.9k | opcode == PPC_RLDICR_32) { |
475 | 382 | unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2)); |
476 | 382 | unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3)); |
477 | | |
478 | | // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH |
479 | 382 | if (63 - SH == ME) { |
480 | 32 | SStream_concat0(O, "sldi\t"); |
481 | 32 | MCInst_setOpcodePub(MI, PPC_INS_SLDI); |
482 | | |
483 | 32 | printOperand(MI, 0, O); |
484 | 32 | SStream_concat0(O, ", "); |
485 | 32 | printOperand(MI, 1, O); |
486 | | |
487 | 32 | if (SH > HEX_THRESHOLD) |
488 | 10 | SStream_concat(O, ", 0x%x", (unsigned int)SH); |
489 | 22 | else |
490 | 22 | SStream_concat(O, ", %u", (unsigned int)SH); |
491 | | |
492 | 32 | if (MI->csh->detail) { |
493 | 32 | cs_ppc *ppc = &MI->flat_insn->detail->ppc; |
494 | | |
495 | 32 | ppc->operands[ppc->op_count].type = PPC_OP_IMM; |
496 | 32 | ppc->operands[ppc->op_count].imm = SH; |
497 | 32 | ++ppc->op_count; |
498 | 32 | } |
499 | | |
500 | | |
501 | 32 | return; |
502 | 32 | } |
503 | 382 | } |
504 | | |
505 | | // dcbt[st] is printed manually here because: |
506 | | // 1. The assembly syntax is different between embedded and server targets |
507 | | // 2. We must print the short mnemonics for TH == 0 because the |
508 | | // embedded/server syntax default will not be stable across assemblers |
509 | | // The syntax for dcbt is: |
510 | | // dcbt ra, rb, th [server] |
511 | | // dcbt th, ra, rb [embedded] |
512 | | // where th can be omitted when it is 0. dcbtst is the same. |
513 | 95.2k | if (opcode == PPC_DCBT || opcode == PPC_DCBTST) { |
514 | 523 | unsigned char TH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 0)); |
515 | | |
516 | 523 | SStream_concat0(O, "dcbt"); |
517 | 523 | MCInst_setOpcodePub(MI, PPC_INS_DCBT); |
518 | | |
519 | 523 | if (opcode == PPC_DCBTST) { |
520 | 128 | SStream_concat0(O, "st"); |
521 | 128 | MCInst_setOpcodePub(MI, PPC_INS_DCBTST); |
522 | 128 | } |
523 | | |
524 | 523 | if (TH == 16) { |
525 | 218 | SStream_concat0(O, "t"); |
526 | 218 | MCInst_setOpcodePub(MI, PPC_INS_DCBTSTT); |
527 | 218 | } |
528 | | |
529 | 523 | SStream_concat0(O, "\t"); |
530 | | |
531 | 523 | if (MI->csh->mode & CS_MODE_BOOKE && TH != 0 && TH != 16) { |
532 | 0 | if (TH > HEX_THRESHOLD) |
533 | 0 | SStream_concat(O, "0x%x, ", (unsigned int)TH); |
534 | 0 | else |
535 | 0 | SStream_concat(O, "%u, ", (unsigned int)TH); |
536 | |
|
537 | 0 | if (MI->csh->detail) { |
538 | 0 | cs_ppc *ppc = &MI->flat_insn->detail->ppc; |
539 | |
|
540 | 0 | ppc->operands[ppc->op_count].type = PPC_OP_IMM; |
541 | 0 | ppc->operands[ppc->op_count].imm = TH; |
542 | 0 | ++ppc->op_count; |
543 | 0 | } |
544 | 0 | } |
545 | | |
546 | 523 | printOperand(MI, 1, O); |
547 | 523 | SStream_concat0(O, ", "); |
548 | 523 | printOperand(MI, 2, O); |
549 | | |
550 | 523 | if (!(MI->csh->mode & CS_MODE_BOOKE) && TH != 0 && TH != 16) { |
551 | 294 | if (TH > HEX_THRESHOLD) |
552 | 115 | SStream_concat(O, ", 0x%x", (unsigned int)TH); |
553 | 179 | else |
554 | 179 | SStream_concat(O, ", %u", (unsigned int)TH); |
555 | | |
556 | 294 | if (MI->csh->detail) { |
557 | 294 | cs_ppc *ppc = &MI->flat_insn->detail->ppc; |
558 | | |
559 | 294 | ppc->operands[ppc->op_count].type = PPC_OP_IMM; |
560 | 294 | ppc->operands[ppc->op_count].imm = TH; |
561 | 294 | ++ppc->op_count; |
562 | 294 | } |
563 | 294 | } |
564 | | |
565 | 523 | return; |
566 | 523 | } |
567 | | |
568 | 94.7k | if (opcode == PPC_DCBF) { |
569 | 492 | unsigned char L = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 0)); |
570 | | |
571 | 492 | if (!L || L == 1 || L == 3) { |
572 | 330 | SStream_concat0(O, "dcbf"); |
573 | 330 | MCInst_setOpcodePub(MI, PPC_INS_DCBF); |
574 | | |
575 | 330 | if (L == 1 || L == 3) { |
576 | 100 | SStream_concat0(O, "l"); |
577 | 100 | MCInst_setOpcodePub(MI, PPC_INS_DCBFL); |
578 | 100 | } |
579 | | |
580 | 330 | if (L == 3) { |
581 | 73 | SStream_concat0(O, "p"); |
582 | 73 | MCInst_setOpcodePub(MI, PPC_INS_DCBFLP); |
583 | 73 | } |
584 | | |
585 | 330 | SStream_concat0(O, "\t"); |
586 | | |
587 | 330 | printOperand(MI, 1, O); |
588 | 330 | SStream_concat0(O, ", "); |
589 | 330 | printOperand(MI, 2, O); |
590 | | |
591 | 330 | return; |
592 | 330 | } |
593 | 492 | } |
594 | | |
595 | 94.4k | if (opcode == PPC_B || opcode == PPC_BA || opcode == PPC_BL || |
596 | 92.7k | opcode == PPC_BLA) { |
597 | 1.97k | int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0)); |
598 | 1.97k | bd = SignExtend64(bd, 24); |
599 | 1.97k | MCOperand_setImm(MCInst_getOperand(MI, 0), bd); |
600 | 1.97k | } |
601 | | |
602 | 94.4k | if (opcode == PPC_gBC || opcode == PPC_gBCA || opcode == PPC_gBCL || |
603 | 91.0k | opcode == PPC_gBCLA) { |
604 | 3.94k | int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 2)); |
605 | 3.94k | bd = SignExtend64(bd, 14); |
606 | 3.94k | MCOperand_setImm(MCInst_getOperand(MI, 2), bd); |
607 | 3.94k | } |
608 | | |
609 | 94.4k | if (isBOCTRBranch(MCInst_getOpcode(MI))) { |
610 | 614 | if (MCOperand_isImm(MCInst_getOperand(MI,0))) { |
611 | 478 | int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0)); |
612 | 478 | bd = SignExtend64(bd, 14); |
613 | 478 | MCOperand_setImm(MCInst_getOperand(MI, 0), bd); |
614 | 478 | } |
615 | 614 | } |
616 | | |
617 | 94.4k | mnem = printAliasBcc(MI, O, Info); |
618 | 94.4k | if (!mnem) |
619 | 90.2k | mnem = printAliasInstr(MI, O, Info); |
620 | | |
621 | 94.4k | if (mnem != NULL) { |
622 | 27.5k | if (strlen(mnem) > 0) { |
623 | | // check to remove the last letter of ('.', '-', '+') |
624 | 27.5k | if (mnem[strlen(mnem) - 1] == '-' || mnem[strlen(mnem) - 1] == '+' || mnem[strlen(mnem) - 1] == '.') |
625 | 2.74k | mnem[strlen(mnem) - 1] = '\0'; |
626 | | |
627 | 27.5k | MCInst_setOpcodePub(MI, PPC_map_insn(mnem)); |
628 | | |
629 | 27.5k | if (MI->csh->detail) { |
630 | 27.5k | struct ppc_alias alias; |
631 | | |
632 | 27.5k | if (PPC_alias_insn(mnem, &alias)) { |
633 | 789 | MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc; |
634 | 789 | } |
635 | 27.5k | } |
636 | 27.5k | } |
637 | | |
638 | 27.5k | cs_mem_free(mnem); |
639 | 27.5k | } else |
640 | 66.8k | printInstruction(MI, O); |
641 | | |
642 | 94.4k | const char *mnem_end = strchr(O->buffer, ' '); |
643 | 94.4k | unsigned mnem_len = 0; |
644 | 94.4k | if (mnem_end) |
645 | 90.6k | mnem_len = mnem_end - O->buffer; |
646 | 94.4k | if (!mnem_end || mnem_len >= sizeof(MI->flat_insn->mnemonic)) |
647 | 3.75k | mnem_len = sizeof(MI->flat_insn->mnemonic) - 1; |
648 | | |
649 | 94.4k | memset(MI->flat_insn->mnemonic, 0, sizeof(MI->flat_insn->mnemonic)); |
650 | 94.4k | memcpy(MI->flat_insn->mnemonic, O->buffer, mnem_len); |
651 | 94.4k | } |
652 | | |
653 | | // FIXME |
654 | | enum ppc_bc_hint { |
655 | | PPC_BC_LT_MINUS = (0 << 5) | 14, |
656 | | PPC_BC_LE_MINUS = (1 << 5) | 6, |
657 | | PPC_BC_EQ_MINUS = (2 << 5) | 14, |
658 | | PPC_BC_GE_MINUS = (0 << 5) | 6, |
659 | | PPC_BC_GT_MINUS = (1 << 5) | 14, |
660 | | PPC_BC_NE_MINUS = (2 << 5) | 6, |
661 | | PPC_BC_UN_MINUS = (3 << 5) | 14, |
662 | | PPC_BC_NU_MINUS = (3 << 5) | 6, |
663 | | PPC_BC_LT_PLUS = (0 << 5) | 15, |
664 | | PPC_BC_LE_PLUS = (1 << 5) | 7, |
665 | | PPC_BC_EQ_PLUS = (2 << 5) | 15, |
666 | | PPC_BC_GE_PLUS = (0 << 5) | 7, |
667 | | PPC_BC_GT_PLUS = (1 << 5) | 15, |
668 | | PPC_BC_NE_PLUS = (2 << 5) | 7, |
669 | | PPC_BC_UN_PLUS = (3 << 5) | 15, |
670 | | PPC_BC_NU_PLUS = (3 << 5) | 7, |
671 | | }; |
672 | | |
673 | | // FIXME |
674 | | // normalize CC to remove _MINUS & _PLUS |
675 | | static int cc_normalize(int cc) |
676 | 0 | { |
677 | 0 | switch(cc) { |
678 | 0 | default: return cc; |
679 | 0 | case PPC_BC_LT_MINUS: return PPC_BC_LT; |
680 | 0 | case PPC_BC_LE_MINUS: return PPC_BC_LE; |
681 | 0 | case PPC_BC_EQ_MINUS: return PPC_BC_EQ; |
682 | 0 | case PPC_BC_GE_MINUS: return PPC_BC_GE; |
683 | 0 | case PPC_BC_GT_MINUS: return PPC_BC_GT; |
684 | 0 | case PPC_BC_NE_MINUS: return PPC_BC_NE; |
685 | 0 | case PPC_BC_UN_MINUS: return PPC_BC_UN; |
686 | 0 | case PPC_BC_NU_MINUS: return PPC_BC_NU; |
687 | 0 | case PPC_BC_LT_PLUS : return PPC_BC_LT; |
688 | 0 | case PPC_BC_LE_PLUS : return PPC_BC_LE; |
689 | 0 | case PPC_BC_EQ_PLUS : return PPC_BC_EQ; |
690 | 0 | case PPC_BC_GE_PLUS : return PPC_BC_GE; |
691 | 0 | case PPC_BC_GT_PLUS : return PPC_BC_GT; |
692 | 0 | case PPC_BC_NE_PLUS : return PPC_BC_NE; |
693 | 0 | case PPC_BC_UN_PLUS : return PPC_BC_UN; |
694 | 0 | case PPC_BC_NU_PLUS : return PPC_BC_NU; |
695 | 0 | } |
696 | 0 | } |
697 | | |
698 | | static void printPredicateOperand(MCInst *MI, unsigned OpNo, |
699 | | SStream *O, const char *Modifier) |
700 | 0 | { |
701 | 0 | unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
702 | |
|
703 | 0 | MI->flat_insn->detail->ppc.bc = (ppc_bc)cc_normalize(Code); |
704 | |
|
705 | 0 | if (!strcmp(Modifier, "cc")) { |
706 | 0 | switch ((ppc_predicate)Code) { |
707 | 0 | default: // unreachable |
708 | 0 | case PPC_PRED_LT_MINUS: |
709 | 0 | case PPC_PRED_LT_PLUS: |
710 | 0 | case PPC_PRED_LT: |
711 | 0 | SStream_concat0(O, "lt"); |
712 | 0 | return; |
713 | 0 | case PPC_PRED_LE_MINUS: |
714 | 0 | case PPC_PRED_LE_PLUS: |
715 | 0 | case PPC_PRED_LE: |
716 | 0 | SStream_concat0(O, "le"); |
717 | 0 | return; |
718 | 0 | case PPC_PRED_EQ_MINUS: |
719 | 0 | case PPC_PRED_EQ_PLUS: |
720 | 0 | case PPC_PRED_EQ: |
721 | 0 | SStream_concat0(O, "eq"); |
722 | 0 | return; |
723 | 0 | case PPC_PRED_GE_MINUS: |
724 | 0 | case PPC_PRED_GE_PLUS: |
725 | 0 | case PPC_PRED_GE: |
726 | 0 | SStream_concat0(O, "ge"); |
727 | 0 | return; |
728 | 0 | case PPC_PRED_GT_MINUS: |
729 | 0 | case PPC_PRED_GT_PLUS: |
730 | 0 | case PPC_PRED_GT: |
731 | 0 | SStream_concat0(O, "gt"); |
732 | 0 | return; |
733 | 0 | case PPC_PRED_NE_MINUS: |
734 | 0 | case PPC_PRED_NE_PLUS: |
735 | 0 | case PPC_PRED_NE: |
736 | 0 | SStream_concat0(O, "ne"); |
737 | 0 | return; |
738 | 0 | case PPC_PRED_UN_MINUS: |
739 | 0 | case PPC_PRED_UN_PLUS: |
740 | 0 | case PPC_PRED_UN: |
741 | 0 | SStream_concat0(O, "un"); |
742 | 0 | return; |
743 | 0 | case PPC_PRED_NU_MINUS: |
744 | 0 | case PPC_PRED_NU_PLUS: |
745 | 0 | case PPC_PRED_NU: |
746 | 0 | SStream_concat0(O, "nu"); |
747 | 0 | return; |
748 | 0 | case PPC_PRED_BIT_SET: |
749 | 0 | case PPC_PRED_BIT_UNSET: |
750 | | // llvm_unreachable("Invalid use of bit predicate code"); |
751 | 0 | SStream_concat0(O, "invalid-predicate"); |
752 | 0 | return; |
753 | 0 | } |
754 | 0 | } |
755 | | |
756 | 0 | if (!strcmp(Modifier, "pm")) { |
757 | 0 | switch ((ppc_predicate)Code) { |
758 | 0 | case PPC_PRED_LT: |
759 | 0 | case PPC_PRED_LE: |
760 | 0 | case PPC_PRED_EQ: |
761 | 0 | case PPC_PRED_GE: |
762 | 0 | case PPC_PRED_GT: |
763 | 0 | case PPC_PRED_NE: |
764 | 0 | case PPC_PRED_UN: |
765 | 0 | case PPC_PRED_NU: |
766 | 0 | return; |
767 | 0 | case PPC_PRED_LT_MINUS: |
768 | 0 | case PPC_PRED_LE_MINUS: |
769 | 0 | case PPC_PRED_EQ_MINUS: |
770 | 0 | case PPC_PRED_GE_MINUS: |
771 | 0 | case PPC_PRED_GT_MINUS: |
772 | 0 | case PPC_PRED_NE_MINUS: |
773 | 0 | case PPC_PRED_UN_MINUS: |
774 | 0 | case PPC_PRED_NU_MINUS: |
775 | 0 | SStream_concat0(O, "-"); |
776 | 0 | return; |
777 | 0 | case PPC_PRED_LT_PLUS: |
778 | 0 | case PPC_PRED_LE_PLUS: |
779 | 0 | case PPC_PRED_EQ_PLUS: |
780 | 0 | case PPC_PRED_GE_PLUS: |
781 | 0 | case PPC_PRED_GT_PLUS: |
782 | 0 | case PPC_PRED_NE_PLUS: |
783 | 0 | case PPC_PRED_UN_PLUS: |
784 | 0 | case PPC_PRED_NU_PLUS: |
785 | 0 | SStream_concat0(O, "+"); |
786 | 0 | return; |
787 | 0 | case PPC_PRED_BIT_SET: |
788 | 0 | case PPC_PRED_BIT_UNSET: |
789 | | // llvm_unreachable("Invalid use of bit predicate code"); |
790 | 0 | SStream_concat0(O, "invalid-predicate"); |
791 | 0 | return; |
792 | 0 | default: // unreachable |
793 | 0 | return; |
794 | 0 | } |
795 | | // llvm_unreachable("Invalid predicate code"); |
796 | 0 | } |
797 | | |
798 | | //assert(StringRef(Modifier) == "reg" && |
799 | | // "Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!"); |
800 | 0 | printOperand(MI, OpNo + 1, O); |
801 | 0 | } |
802 | | |
803 | | static void printATBitsAsHint(MCInst *MI, unsigned OpNo, SStream *O) |
804 | 0 | { |
805 | 0 | unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
806 | |
|
807 | 0 | if (Code == 2) { |
808 | 0 | SStream_concat0(O, "-"); |
809 | 0 | } else if (Code == 3) { |
810 | 0 | SStream_concat0(O, "+"); |
811 | 0 | } |
812 | 0 | } |
813 | | |
814 | | static void printU1ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
815 | 427 | { |
816 | 427 | unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
817 | | |
818 | | // assert(Value <= 1 && "Invalid u1imm argument!"); |
819 | | |
820 | 427 | printUInt32(O, Value); |
821 | | |
822 | 427 | if (MI->csh->detail) { |
823 | 427 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
824 | 427 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
825 | 427 | MI->flat_insn->detail->ppc.op_count++; |
826 | 427 | } |
827 | 427 | } |
828 | | |
829 | | static void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
830 | 2.36k | { |
831 | 2.36k | unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
832 | | //assert(Value <= 3 && "Invalid u2imm argument!"); |
833 | | |
834 | 2.36k | printUInt32(O, Value); |
835 | | |
836 | 2.36k | if (MI->csh->detail) { |
837 | 2.36k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
838 | 2.36k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
839 | 2.36k | MI->flat_insn->detail->ppc.op_count++; |
840 | 2.36k | } |
841 | 2.36k | } |
842 | | |
843 | | static void printU3ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
844 | 266 | { |
845 | 266 | unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
846 | | //assert(Value <= 8 && "Invalid u3imm argument!"); |
847 | | |
848 | 266 | printUInt32(O, Value); |
849 | | |
850 | 266 | if (MI->csh->detail) { |
851 | 266 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
852 | 266 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
853 | 266 | MI->flat_insn->detail->ppc.op_count++; |
854 | 266 | } |
855 | 266 | } |
856 | | |
857 | | static void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
858 | 1.11k | { |
859 | 1.11k | unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
860 | | //assert(Value <= 15 && "Invalid u4imm argument!"); |
861 | | |
862 | 1.11k | printUInt32(O, Value); |
863 | | |
864 | 1.11k | if (MI->csh->detail) { |
865 | 1.11k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
866 | 1.11k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
867 | 1.11k | MI->flat_insn->detail->ppc.op_count++; |
868 | 1.11k | } |
869 | 1.11k | } |
870 | | |
871 | | static void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
872 | 20 | { |
873 | 20 | int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
874 | 20 | Value = SignExtend32(Value, 5); |
875 | | |
876 | 20 | printInt32(O, Value); |
877 | | |
878 | 20 | if (MI->csh->detail) { |
879 | 20 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
880 | 20 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
881 | 20 | MI->flat_insn->detail->ppc.op_count++; |
882 | 20 | } |
883 | 20 | } |
884 | | |
885 | | static void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
886 | 18.1k | { |
887 | 18.1k | unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
888 | | |
889 | | //assert(Value <= 31 && "Invalid u5imm argument!"); |
890 | 18.1k | printUInt32(O, Value); |
891 | | |
892 | 18.1k | if (MI->csh->detail) { |
893 | 18.1k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
894 | 18.1k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
895 | 18.1k | MI->flat_insn->detail->ppc.op_count++; |
896 | 18.1k | } |
897 | 18.1k | } |
898 | | |
899 | | static void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
900 | 3.03k | { |
901 | 3.03k | unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
902 | | |
903 | | //assert(Value <= 63 && "Invalid u6imm argument!"); |
904 | 3.03k | printUInt32(O, Value); |
905 | | |
906 | 3.03k | if (MI->csh->detail) { |
907 | 3.03k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
908 | 3.03k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
909 | 3.03k | MI->flat_insn->detail->ppc.op_count++; |
910 | 3.03k | } |
911 | 3.03k | } |
912 | | |
913 | | static void printU7ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
914 | 112 | { |
915 | 112 | unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
916 | | |
917 | | //assert(Value <= 127 && "Invalid u7imm argument!"); |
918 | 112 | printUInt32(O, Value); |
919 | | |
920 | 112 | if (MI->csh->detail) { |
921 | 112 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
922 | 112 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
923 | 112 | MI->flat_insn->detail->ppc.op_count++; |
924 | 112 | } |
925 | 112 | } |
926 | | |
927 | | // Operands of BUILD_VECTOR are signed and we use this to print operands |
928 | | // of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and |
929 | | // print as unsigned. |
930 | | static void printU8ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
931 | 172 | { |
932 | 172 | unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
933 | | |
934 | 172 | printUInt32(O, Value); |
935 | | |
936 | 172 | if (MI->csh->detail) { |
937 | 172 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
938 | 172 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
939 | 172 | MI->flat_insn->detail->ppc.op_count++; |
940 | 172 | } |
941 | 172 | } |
942 | | |
943 | | static void printU10ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
944 | 400 | { |
945 | 400 | unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
946 | | |
947 | | //assert(Value <= 1023 && "Invalid u10imm argument!"); |
948 | 400 | printUInt32(O, Value); |
949 | | |
950 | 400 | if (MI->csh->detail) { |
951 | 400 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
952 | 400 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
953 | 400 | MI->flat_insn->detail->ppc.op_count++; |
954 | 400 | } |
955 | 400 | } |
956 | | |
957 | | static void printS12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
958 | 0 | { |
959 | 0 | if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { |
960 | 0 | int Imm = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
961 | 0 | Imm = SignExtend32(Imm, 12); |
962 | |
|
963 | 0 | printInt32(O, Imm); |
964 | |
|
965 | 0 | if (MI->csh->detail) { |
966 | 0 | if (MI->csh->doing_mem) { |
967 | 0 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = Imm; |
968 | 0 | } else { |
969 | 0 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
970 | 0 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm; |
971 | 0 | MI->flat_insn->detail->ppc.op_count++; |
972 | 0 | } |
973 | 0 | } |
974 | 0 | } else |
975 | 0 | printOperand(MI, OpNo, O); |
976 | 0 | } |
977 | | |
978 | | static void printU12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
979 | 543 | { |
980 | 543 | unsigned short Value = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
981 | | |
982 | | // assert(Value <= 4095 && "Invalid u12imm argument!"); |
983 | | |
984 | 543 | printUInt32(O, Value); |
985 | | |
986 | 543 | if (MI->csh->detail) { |
987 | 543 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
988 | 543 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value; |
989 | 543 | MI->flat_insn->detail->ppc.op_count++; |
990 | 543 | } |
991 | 543 | } |
992 | | |
993 | | static void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
994 | 26.1k | { |
995 | 26.1k | if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { |
996 | 26.1k | short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
997 | 26.1k | printInt32(O, Imm); |
998 | | |
999 | 26.1k | if (MI->csh->detail) { |
1000 | 26.1k | if (MI->csh->doing_mem) { |
1001 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = Imm; |
1002 | 13.0k | } else { |
1003 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
1004 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm; |
1005 | 13.0k | MI->flat_insn->detail->ppc.op_count++; |
1006 | 13.0k | } |
1007 | 26.1k | } |
1008 | 26.1k | } else |
1009 | 0 | printOperand(MI, OpNo, O); |
1010 | 26.1k | } |
1011 | | |
1012 | | static void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
1013 | 6.42k | { |
1014 | 6.42k | if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { |
1015 | 6.42k | unsigned short Imm = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
1016 | 6.42k | printUInt32(O, Imm); |
1017 | | |
1018 | 6.42k | if (MI->csh->detail) { |
1019 | 6.42k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
1020 | 6.42k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm; |
1021 | 6.42k | MI->flat_insn->detail->ppc.op_count++; |
1022 | 6.42k | } |
1023 | 6.42k | } else |
1024 | 0 | printOperand(MI, OpNo, O); |
1025 | 6.42k | } |
1026 | | |
1027 | | static void printBranchOperand(MCInst *MI, unsigned OpNo, SStream *O) |
1028 | 4.06k | { |
1029 | 4.06k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { |
1030 | 0 | printOperand(MI, OpNo, O); |
1031 | |
|
1032 | 0 | return; |
1033 | 0 | } |
1034 | | |
1035 | | // Branches can take an immediate operand. This is used by the branch |
1036 | | // selection pass to print .+8, an eight byte displacement from the PC. |
1037 | | // O << ".+"; |
1038 | 4.06k | printAbsBranchOperand(MI, OpNo, O); |
1039 | 4.06k | } |
1040 | | |
1041 | | static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O) |
1042 | 6.08k | { |
1043 | 6.08k | int64_t imm; |
1044 | | |
1045 | 6.08k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { |
1046 | 0 | printOperand(MI, OpNo, O); |
1047 | |
|
1048 | 0 | return; |
1049 | 0 | } |
1050 | | |
1051 | 6.08k | imm = SignExtend32(MCOperand_getImm(MCInst_getOperand(MI, OpNo)) * 4, 32); |
1052 | | //imm = MCOperand_getImm(MCInst_getOperand(MI, OpNo)) * 4; |
1053 | | |
1054 | 6.08k | if (!PPC_abs_branch(MI->csh, MCInst_getOpcode(MI))) { |
1055 | 2.57k | imm += MI->address; |
1056 | 2.57k | } |
1057 | | |
1058 | 6.08k | printUInt64(O, imm); |
1059 | | |
1060 | 6.08k | if (MI->csh->detail) { |
1061 | 6.08k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
1062 | 6.08k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm; |
1063 | 6.08k | MI->flat_insn->detail->ppc.op_count++; |
1064 | 6.08k | } |
1065 | 6.08k | } |
1066 | | |
1067 | | static void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O) |
1068 | 1.00k | { |
1069 | 1.00k | unsigned RegNo; |
1070 | 1.00k | unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, OpNo)); |
1071 | | |
1072 | 1.00k | switch (CCReg) { |
1073 | 0 | default: // llvm_unreachable("Unknown CR register"); |
1074 | 140 | case PPC_CR0: RegNo = 0; break; |
1075 | 61 | case PPC_CR1: RegNo = 1; break; |
1076 | 63 | case PPC_CR2: RegNo = 2; break; |
1077 | 78 | case PPC_CR3: RegNo = 3; break; |
1078 | 111 | case PPC_CR4: RegNo = 4; break; |
1079 | 45 | case PPC_CR5: RegNo = 5; break; |
1080 | 106 | case PPC_CR6: RegNo = 6; break; |
1081 | 400 | case PPC_CR7: RegNo = 7; break; |
1082 | 1.00k | } |
1083 | | |
1084 | 1.00k | printUInt32(O, 0x80 >> RegNo); |
1085 | 1.00k | } |
1086 | | |
1087 | | static void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O) |
1088 | 28.6k | { |
1089 | 28.6k | set_mem_access(MI, true); |
1090 | | |
1091 | 28.6k | printS16ImmOperand(MI, OpNo, O); |
1092 | | |
1093 | 28.6k | SStream_concat0(O, "("); |
1094 | | |
1095 | 28.6k | if (MCOperand_getReg(MCInst_getOperand(MI, OpNo + 1)) == PPC_R0) |
1096 | 0 | SStream_concat0(O, "0"); |
1097 | 28.6k | else |
1098 | 28.6k | printOperand(MI, OpNo + 1, O); |
1099 | | |
1100 | 28.6k | SStream_concat0(O, ")"); |
1101 | | |
1102 | 28.6k | set_mem_access(MI, false); |
1103 | 28.6k | } |
1104 | | |
1105 | | static void printPSMemRegImm(MCInst *MI, unsigned OpNo, SStream *O) |
1106 | 0 | { |
1107 | 0 | set_mem_access(MI, true); |
1108 | |
|
1109 | 0 | printS12ImmOperand(MI, OpNo, O); |
1110 | |
|
1111 | 0 | SStream_concat0(O, "("); |
1112 | 0 | printOperand(MI, OpNo + 1, O); |
1113 | 0 | SStream_concat0(O, ")"); |
1114 | |
|
1115 | 0 | set_mem_access(MI, false); |
1116 | 0 | } |
1117 | | |
1118 | | static void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O) |
1119 | 6.33k | { |
1120 | | // When used as the base register, r0 reads constant zero rather than |
1121 | | // the value contained in the register. For this reason, the darwin |
1122 | | // assembler requires that we print r0 as 0 (no r) when used as the base. |
1123 | 6.33k | if (MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == PPC_R0) |
1124 | 0 | SStream_concat0(O, "0"); |
1125 | 6.33k | else |
1126 | 6.33k | printOperand(MI, OpNo, O); |
1127 | 6.33k | SStream_concat0(O, ", "); |
1128 | | |
1129 | 6.33k | printOperand(MI, OpNo + 1, O); |
1130 | 6.33k | } |
1131 | | |
1132 | | static void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O) |
1133 | 0 | { |
1134 | 0 | set_mem_access(MI, true); |
1135 | | //printBranchOperand(MI, OpNo, O); |
1136 | | |
1137 | | // On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must |
1138 | | // come at the _end_ of the expression. |
1139 | |
|
1140 | 0 | SStream_concat0(O, "("); |
1141 | 0 | printOperand(MI, OpNo + 1, O); |
1142 | 0 | SStream_concat0(O, ")"); |
1143 | |
|
1144 | 0 | set_mem_access(MI, false); |
1145 | 0 | } |
1146 | | |
1147 | | /// stripRegisterPrefix - This method strips the character prefix from a |
1148 | | /// register name so that only the number is left. Used by for linux asm. |
1149 | | static char *stripRegisterPrefix(const char *RegName) |
1150 | 0 | { |
1151 | 0 | switch (RegName[0]) { |
1152 | 0 | case 'r': |
1153 | 0 | case 'f': |
1154 | 0 | case 'q': // for QPX |
1155 | 0 | case 'v': |
1156 | 0 | if (RegName[1] == 's') |
1157 | 0 | return cs_strdup(RegName + 2); |
1158 | | |
1159 | 0 | return cs_strdup(RegName + 1); |
1160 | 0 | case 'c': |
1161 | 0 | if (RegName[1] == 'r') { |
1162 | | // skip the first 2 letters "cr" |
1163 | 0 | char *name = cs_strdup(RegName + 2); |
1164 | | |
1165 | | // also strip the last 2 letters |
1166 | 0 | if(strlen(name) > 2) |
1167 | 0 | name[strlen(name) - 2] = '\0'; |
1168 | |
|
1169 | 0 | return name; |
1170 | 0 | } |
1171 | 0 | } |
1172 | | |
1173 | 0 | return cs_strdup(RegName); |
1174 | 0 | } |
1175 | | |
1176 | | static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) |
1177 | 179k | { |
1178 | 179k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
1179 | 179k | if (MCOperand_isReg(Op)) { |
1180 | 174k | unsigned reg = MCOperand_getReg(Op); |
1181 | 174k | #ifndef CAPSTONE_DIET |
1182 | 174k | const char *RegName = getRegisterName(reg); |
1183 | | |
1184 | | // printf("reg = %u (%s)\n", reg, RegName); |
1185 | | |
1186 | | // convert internal register ID to public register ID |
1187 | 174k | reg = PPC_name_reg(RegName); |
1188 | | |
1189 | | // The linux and AIX assembler does not take register prefixes. |
1190 | 174k | if (MI->csh->syntax == CS_OPT_SYNTAX_NOREGNAME) { |
1191 | 0 | char *name = stripRegisterPrefix(RegName); |
1192 | 0 | SStream_concat0(O, name); |
1193 | 0 | cs_mem_free(name); |
1194 | 0 | } else |
1195 | 174k | SStream_concat0(O, RegName); |
1196 | 174k | #endif |
1197 | | |
1198 | 174k | if (MI->csh->detail) { |
1199 | 174k | if (MI->csh->doing_mem) { |
1200 | 13.0k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = reg; |
1201 | 161k | } else { |
1202 | 161k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG; |
1203 | 161k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg; |
1204 | 161k | MI->flat_insn->detail->ppc.op_count++; |
1205 | 161k | } |
1206 | 174k | } |
1207 | | |
1208 | 174k | return; |
1209 | 174k | } |
1210 | | |
1211 | 4.71k | if (MCOperand_isImm(Op)) { |
1212 | 4.71k | int32_t imm = (int32_t)MCOperand_getImm(Op); |
1213 | 4.71k | printInt32(O, imm); |
1214 | | |
1215 | 4.71k | if (MI->csh->detail) { |
1216 | 4.71k | if (MI->csh->doing_mem) { |
1217 | 0 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = (int32_t)imm; |
1218 | 4.71k | } else { |
1219 | 4.71k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
1220 | 4.71k | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm; |
1221 | 4.71k | MI->flat_insn->detail->ppc.op_count++; |
1222 | 4.71k | } |
1223 | 4.71k | } |
1224 | 4.71k | } |
1225 | 4.71k | } |
1226 | | |
1227 | | static void op_addImm(MCInst *MI, int v) |
1228 | 70 | { |
1229 | 70 | if (MI->csh->detail) { |
1230 | 70 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM; |
1231 | 70 | MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = v; |
1232 | 70 | MI->flat_insn->detail->ppc.op_count++; |
1233 | 70 | } |
1234 | 70 | } |
1235 | | |
1236 | | #define PRINT_ALIAS_INSTR |
1237 | | #include "PPCGenRegisterName.inc" |
1238 | | #include "PPCGenAsmWriter.inc" |
1239 | | |
1240 | | #endif |