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