/src/capstonenext/arch/PowerPC/PPCInstPrinter.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine, http://www.capstone-engine.org */ |
2 | | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */ |
3 | | /* Rot127 <unisono@quyllur.org> 2022-2023 */ |
4 | | /* Automatically translated source file from LLVM. */ |
5 | | |
6 | | /* LLVM-commit: <commit> */ |
7 | | /* LLVM-tag: <tag> */ |
8 | | |
9 | | /* Only small edits allowed. */ |
10 | | /* For multiple similar edits, please create a Patch for the translator. */ |
11 | | |
12 | | /* Capstone's C++ file translator: */ |
13 | | /* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */ |
14 | | |
15 | | //===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===// |
16 | | // |
17 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
18 | | // See https://llvm.org/LICENSE.txt for license information. |
19 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
20 | | // |
21 | | //===----------------------------------------------------------------------===// |
22 | | // |
23 | | // This class prints an PPC MCInst to a .s file. |
24 | | // |
25 | | //===----------------------------------------------------------------------===// |
26 | | |
27 | | #include <capstone/platform.h> |
28 | | #include <stdio.h> |
29 | | #include <stdlib.h> |
30 | | #include <string.h> |
31 | | |
32 | | #include "../../utils.h" |
33 | | #include "../../LEB128.h" |
34 | | #include "../../Mapping.h" |
35 | | #include "../../MCInst.h" |
36 | | #include "../../MCInstPrinter.h" |
37 | | #include "../../MCInstrDesc.h" |
38 | | #include "../../MCRegisterInfo.h" |
39 | | #include "PPCInstrInfo.h" |
40 | | #include "PPCLinkage.h" |
41 | | #include "PPCMCTargetDesc.h" |
42 | | #include "PPCMapping.h" |
43 | | #include "PPCPredicates.h" |
44 | | #include "PPCRegisterInfo.h" |
45 | | |
46 | | #define CONCAT(a, b) CONCAT_(a, b) |
47 | | #define CONCAT_(a, b) a##_##b |
48 | | |
49 | | #define DEBUG_TYPE "asm-printer" |
50 | | |
51 | | extern const MCInstrDesc PPCInsts[]; |
52 | | |
53 | | // Static function declarations. These are functions which have the same identifiers |
54 | | // over all architectures. Therefor they need to be static. |
55 | | #ifndef CAPSTONE_DIET |
56 | | static void printCustomAliasOperand(MCInst *MI, uint64_t Address, |
57 | | unsigned OpIdx, unsigned PrintMethodIdx, |
58 | | SStream *O); |
59 | | #endif |
60 | | |
61 | | static const char *getRegisterName(unsigned RegNo); |
62 | | |
63 | | /// showRegistersWithPercentPrefix - Check if this register name should be |
64 | | /// printed with a percentage symbol as prefix. |
65 | | static inline bool showRegistersWithPercentPrefix(const MCInst *MI, |
66 | | const char *RegName) |
67 | 122k | { |
68 | 122k | if ((MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME) || |
69 | 122k | !(MI->csh->syntax & CS_OPT_SYNTAX_PERCENT) || |
70 | 122k | PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs)) |
71 | 122k | return false; |
72 | | |
73 | 0 | switch (RegName[0]) { |
74 | 0 | default: |
75 | 0 | return false; |
76 | 0 | case 'r': |
77 | 0 | case 'f': |
78 | 0 | case 'q': |
79 | 0 | case 'v': |
80 | 0 | case 'c': |
81 | 0 | return true; |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | /// getVerboseConditionalRegName - This method expands the condition register |
86 | | /// when requested explicitly or targeting Darwin. |
87 | | static inline const char *getVerboseConditionRegName(const MCInst *MI, |
88 | | unsigned RegNum, |
89 | | unsigned RegEncoding) |
90 | 122k | { |
91 | 122k | if (MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME) |
92 | 0 | return NULL; |
93 | 122k | if (RegNum < PPC_CR0EQ || RegNum > PPC_CR7UN) |
94 | 112k | return NULL; |
95 | 9.92k | const char *CRBits[] = { |
96 | 9.92k | "lt", "gt", "eq", "un", "4*cr1+lt", |
97 | 9.92k | "4*cr1+gt", "4*cr1+eq", "4*cr1+un", "4*cr2+lt", "4*cr2+gt", |
98 | 9.92k | "4*cr2+eq", "4*cr2+un", "4*cr3+lt", "4*cr3+gt", "4*cr3+eq", |
99 | 9.92k | "4*cr3+un", "4*cr4+lt", "4*cr4+gt", "4*cr4+eq", "4*cr4+un", |
100 | 9.92k | "4*cr5+lt", "4*cr5+gt", "4*cr5+eq", "4*cr5+un", "4*cr6+lt", |
101 | 9.92k | "4*cr6+gt", "4*cr6+eq", "4*cr6+un", "4*cr7+lt", "4*cr7+gt", |
102 | 9.92k | "4*cr7+eq", "4*cr7+un" |
103 | 9.92k | }; |
104 | 9.92k | return CRBits[RegEncoding]; |
105 | 122k | } |
106 | | |
107 | | // showRegistersWithPrefix - This method determines whether registers |
108 | | // should be number-only or include the prefix. |
109 | | static inline bool showRegistersWithPrefix(const MCInst *MI) |
110 | 122k | { |
111 | 122k | return !(MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME); |
112 | 122k | } |
113 | | |
114 | | static inline void printOperand(MCInst *MI, unsigned OpNo, SStream *O) |
115 | 123k | { |
116 | 123k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_Operand, OpNo); |
117 | 123k | MCOperand *Op = MCInst_getOperand(MI, (OpNo)); |
118 | 123k | if (MCOperand_isReg(Op)) { |
119 | 122k | unsigned Reg = MCOperand_getReg(Op); |
120 | 122k | if (!MI->csh->ShowVSRNumsAsVR) |
121 | 122k | Reg = PPCInstrInfo_getRegNumForOperand( |
122 | 122k | MCInstrDesc_get(MCInst_getOpcode(MI), |
123 | 122k | PPCDescs.Insts, |
124 | 122k | ARR_SIZE(PPCDescs.Insts)), |
125 | 122k | Reg, OpNo); |
126 | | |
127 | 122k | const char *RegName; |
128 | 122k | RegName = getVerboseConditionRegName( |
129 | 122k | MI, Reg, MI->MRI->RegEncodingTable[Reg]); |
130 | 122k | if (RegName == NULL) |
131 | 112k | RegName = getRegisterName(Reg); |
132 | 122k | if (showRegistersWithPercentPrefix(MI, RegName)) |
133 | 0 | SStream_concat0(O, "%"); |
134 | 122k | if (!showRegistersWithPrefix(MI)) |
135 | 0 | RegName = PPCRegisterInfo_stripRegisterPrefix(RegName); |
136 | | |
137 | 122k | SStream_concat0(O, RegName); |
138 | 122k | return; |
139 | 122k | } |
140 | | |
141 | 1.56k | if (MCOperand_isImm(Op)) { |
142 | 1.56k | printInt64(O, MCOperand_getImm(Op)); |
143 | 1.56k | return; |
144 | 1.56k | } |
145 | 1.56k | } |
146 | | |
147 | | static inline void printPredicateOperand(MCInst *MI, unsigned OpNo, SStream *O, |
148 | | const char *Modifier) |
149 | 0 | { |
150 | 0 | PPC_add_cs_detail_1(MI, PPC_OP_GROUP_PredicateOperand, OpNo, Modifier); |
151 | 0 | unsigned Code = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
152 | |
|
153 | 0 | if (strcmp(Modifier, "cc") == 0) { |
154 | 0 | switch ((PPC_Predicate)Code) { |
155 | 0 | default: |
156 | 0 | CS_ASSERT_RET(0 && "Invalid predicate code"); |
157 | 0 | case PPC_PRED_LT_MINUS: |
158 | 0 | case PPC_PRED_LT_PLUS: |
159 | 0 | case PPC_PRED_LT: |
160 | 0 | SStream_concat0(O, "lt"); |
161 | 0 | return; |
162 | 0 | case PPC_PRED_LE_MINUS: |
163 | 0 | case PPC_PRED_LE_PLUS: |
164 | 0 | case PPC_PRED_LE: |
165 | 0 | SStream_concat0(O, "le"); |
166 | 0 | return; |
167 | 0 | case PPC_PRED_EQ_MINUS: |
168 | 0 | case PPC_PRED_EQ_PLUS: |
169 | 0 | case PPC_PRED_EQ: |
170 | 0 | SStream_concat0(O, "eq"); |
171 | 0 | return; |
172 | 0 | case PPC_PRED_GE_MINUS: |
173 | 0 | case PPC_PRED_GE_PLUS: |
174 | 0 | case PPC_PRED_GE: |
175 | 0 | SStream_concat0(O, "ge"); |
176 | 0 | return; |
177 | 0 | case PPC_PRED_GT_MINUS: |
178 | 0 | case PPC_PRED_GT_PLUS: |
179 | 0 | case PPC_PRED_GT: |
180 | 0 | SStream_concat0(O, "gt"); |
181 | 0 | return; |
182 | 0 | case PPC_PRED_NE_MINUS: |
183 | 0 | case PPC_PRED_NE_PLUS: |
184 | 0 | case PPC_PRED_NE: |
185 | 0 | SStream_concat0(O, "ne"); |
186 | 0 | return; |
187 | 0 | case PPC_PRED_UN_MINUS: |
188 | 0 | case PPC_PRED_UN_PLUS: |
189 | 0 | case PPC_PRED_UN: |
190 | 0 | SStream_concat0(O, "un"); |
191 | 0 | return; |
192 | 0 | case PPC_PRED_NU_MINUS: |
193 | 0 | case PPC_PRED_NU_PLUS: |
194 | 0 | case PPC_PRED_NU: |
195 | 0 | SStream_concat0(O, "nu"); |
196 | 0 | return; |
197 | 0 | case PPC_PRED_BIT_SET: |
198 | 0 | case PPC_PRED_BIT_UNSET: |
199 | 0 | CS_ASSERT_RET(0 && "Invalid use of bit predicate code"); |
200 | 0 | } |
201 | 0 | CS_ASSERT_RET(0 && "Invalid predicate code"); |
202 | 0 | } |
203 | | |
204 | 0 | if (strcmp(Modifier, "pm") == 0) { |
205 | 0 | switch ((PPC_Predicate)Code) { |
206 | 0 | default: |
207 | 0 | CS_ASSERT_RET(0 && "Invalid predicate code"); |
208 | 0 | case PPC_PRED_LT: |
209 | 0 | case PPC_PRED_LE: |
210 | 0 | case PPC_PRED_EQ: |
211 | 0 | case PPC_PRED_GE: |
212 | 0 | case PPC_PRED_GT: |
213 | 0 | case PPC_PRED_NE: |
214 | 0 | case PPC_PRED_UN: |
215 | 0 | case PPC_PRED_NU: |
216 | 0 | return; |
217 | 0 | case PPC_PRED_LT_MINUS: |
218 | 0 | case PPC_PRED_LE_MINUS: |
219 | 0 | case PPC_PRED_EQ_MINUS: |
220 | 0 | case PPC_PRED_GE_MINUS: |
221 | 0 | case PPC_PRED_GT_MINUS: |
222 | 0 | case PPC_PRED_NE_MINUS: |
223 | 0 | case PPC_PRED_UN_MINUS: |
224 | 0 | case PPC_PRED_NU_MINUS: |
225 | 0 | SStream_concat0(O, "-"); |
226 | 0 | return; |
227 | 0 | case PPC_PRED_LT_PLUS: |
228 | 0 | case PPC_PRED_LE_PLUS: |
229 | 0 | case PPC_PRED_EQ_PLUS: |
230 | 0 | case PPC_PRED_GE_PLUS: |
231 | 0 | case PPC_PRED_GT_PLUS: |
232 | 0 | case PPC_PRED_NE_PLUS: |
233 | 0 | case PPC_PRED_UN_PLUS: |
234 | 0 | case PPC_PRED_NU_PLUS: |
235 | 0 | SStream_concat0(O, "+"); |
236 | 0 | return; |
237 | 0 | case PPC_PRED_BIT_SET: |
238 | 0 | case PPC_PRED_BIT_UNSET: |
239 | 0 | CS_ASSERT_RET(0 && "Invalid use of bit predicate code"); |
240 | 0 | } |
241 | 0 | CS_ASSERT_RET(0 && "Invalid predicate code"); |
242 | 0 | } |
243 | | |
244 | 0 | printOperand(MI, OpNo + 1, O); |
245 | 0 | } |
246 | | |
247 | | static inline void printATBitsAsHint(MCInst *MI, unsigned OpNo, SStream *O) |
248 | 0 | { |
249 | 0 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_ATBitsAsHint, OpNo); |
250 | 0 | unsigned Code = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
251 | 0 | if (Code == 2) |
252 | 0 | SStream_concat0(O, "-"); |
253 | 0 | else if (Code == 3) |
254 | 0 | SStream_concat0(O, "+"); |
255 | 0 | } |
256 | | |
257 | | static inline void printU1ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
258 | 2.31k | { |
259 | 2.31k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U1ImmOperand, OpNo); |
260 | 2.31k | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
261 | 2.31k | CS_ASSERT(Value <= 1 && "Invalid u1imm argument!"); |
262 | 2.31k | printUInt32(O, (unsigned int)Value); |
263 | 2.31k | } |
264 | | |
265 | | static inline void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
266 | 1.36k | { |
267 | 1.36k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U2ImmOperand, OpNo); |
268 | 1.36k | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
269 | 1.36k | CS_ASSERT(Value <= 3 && "Invalid u2imm argument!"); |
270 | 1.36k | printUInt32(O, (unsigned int)Value); |
271 | 1.36k | } |
272 | | |
273 | | static inline void printU3ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
274 | 983 | { |
275 | 983 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U3ImmOperand, OpNo); |
276 | 983 | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
277 | 983 | CS_ASSERT(Value <= 8 && "Invalid u3imm argument!"); |
278 | 983 | printUInt32(O, (unsigned int)Value); |
279 | 983 | } |
280 | | |
281 | | static inline void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
282 | 957 | { |
283 | 957 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U4ImmOperand, OpNo); |
284 | 957 | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
285 | 957 | CS_ASSERT(Value <= 15 && "Invalid u4imm argument!"); |
286 | 957 | printUInt32(O, (unsigned int)Value); |
287 | 957 | } |
288 | | |
289 | | static inline void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
290 | 168 | { |
291 | 168 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S5ImmOperand, OpNo); |
292 | 168 | int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
293 | 168 | Value = SignExtend32((Value), 5); |
294 | 168 | printInt32(O, (int)Value); |
295 | 168 | } |
296 | | |
297 | | static inline void printImmZeroOperand(MCInst *MI, unsigned OpNo, SStream *O) |
298 | 321 | { |
299 | 321 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_ImmZeroOperand, OpNo); |
300 | 321 | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
301 | 321 | CS_ASSERT(Value == 0 && "Operand must be zero"); |
302 | 321 | printUInt32(O, (unsigned int)Value); |
303 | 321 | } |
304 | | |
305 | | static inline void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
306 | 10.4k | { |
307 | 10.4k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U5ImmOperand, OpNo); |
308 | 10.4k | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
309 | 10.4k | CS_ASSERT(Value <= 31 && "Invalid u5imm argument!"); |
310 | 10.4k | printUInt32(O, (unsigned int)Value); |
311 | 10.4k | } |
312 | | |
313 | | static inline void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
314 | 1.94k | { |
315 | 1.94k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U6ImmOperand, OpNo); |
316 | 1.94k | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
317 | 1.94k | CS_ASSERT(Value <= 63 && "Invalid u6imm argument!"); |
318 | 1.94k | printUInt32(O, (unsigned int)Value); |
319 | 1.94k | } |
320 | | |
321 | | static inline void printU7ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
322 | 108 | { |
323 | 108 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U7ImmOperand, OpNo); |
324 | 108 | unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
325 | 108 | CS_ASSERT(Value <= 127 && "Invalid u7imm argument!"); |
326 | 108 | printUInt32(O, (unsigned int)Value); |
327 | 108 | } |
328 | | |
329 | | // Operands of BUILD_VECTOR are signed and we use this to print operands |
330 | | // of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and |
331 | | // print as unsigned. |
332 | | static inline void printU8ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
333 | 79 | { |
334 | 79 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U8ImmOperand, OpNo); |
335 | 79 | unsigned char Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
336 | 79 | CS_ASSERT(Value <= 255 && "Invalid u8imm argument!"); |
337 | 79 | printUInt32(O, (unsigned int)Value); |
338 | 79 | } |
339 | | |
340 | | static inline void printU10ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
341 | 489 | { |
342 | 489 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U10ImmOperand, OpNo); |
343 | 489 | unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
344 | 489 | CS_ASSERT(Value <= 1023 && "Invalid u10imm argument!"); |
345 | 489 | printUInt32(O, (unsigned short)Value); |
346 | 489 | } |
347 | | |
348 | | static inline void printU12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
349 | 134 | { |
350 | 134 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U12ImmOperand, OpNo); |
351 | 134 | unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
352 | 134 | CS_ASSERT(Value <= 4095 && "Invalid u12imm argument!"); |
353 | 134 | printUInt32(O, (unsigned short)Value); |
354 | 134 | } |
355 | | |
356 | | static inline void printS12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
357 | 327 | { |
358 | 327 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S12ImmOperand, OpNo); |
359 | 327 | if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { |
360 | 327 | int Imm = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); |
361 | 327 | Imm = SignExtend32(Imm, 12); |
362 | 327 | printInt32(O, Imm); |
363 | 327 | } else |
364 | 0 | printOperand(MI, OpNo, O); |
365 | 327 | } |
366 | | |
367 | | static inline void printMemRegImmPS(MCInst *MI, unsigned OpNo, SStream *O) |
368 | 327 | { |
369 | 327 | set_mem_access(MI, true); |
370 | | |
371 | 327 | printS12ImmOperand(MI, OpNo, O); |
372 | 327 | SStream_concat0(O, "("); |
373 | 327 | printOperand(MI, OpNo + 1, O); |
374 | 327 | SStream_concat0(O, ")"); |
375 | | |
376 | 327 | set_mem_access(MI, false); |
377 | 327 | } |
378 | | |
379 | | static inline void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
380 | 15.2k | { |
381 | 15.2k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S16ImmOperand, OpNo); |
382 | 15.2k | if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) |
383 | 15.2k | printInt32(O, (short)MCOperand_getImm( |
384 | 15.2k | MCInst_getOperand(MI, (OpNo)))); |
385 | 0 | else |
386 | 0 | printOperand(MI, OpNo, O); |
387 | 15.2k | } |
388 | | |
389 | | static inline void printS34ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
390 | 554 | { |
391 | 554 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S34ImmOperand, OpNo); |
392 | 554 | if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) { |
393 | 554 | long long Value = |
394 | 554 | MCOperand_getImm(MCInst_getOperand(MI, (OpNo))); |
395 | | |
396 | 554 | printInt64(O, (long long)Value); |
397 | 554 | } else |
398 | 0 | printOperand(MI, OpNo, O); |
399 | 554 | } |
400 | | |
401 | | static inline void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O) |
402 | 4.22k | { |
403 | 4.22k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U16ImmOperand, OpNo); |
404 | 4.22k | if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) |
405 | 4.22k | printUInt32(O, (unsigned short)MCOperand_getImm( |
406 | 4.22k | MCInst_getOperand(MI, (OpNo)))); |
407 | 0 | else |
408 | 0 | printOperand(MI, OpNo, O); |
409 | 4.22k | } |
410 | | |
411 | | static inline void printBranchOperand(MCInst *MI, uint64_t Address, |
412 | | unsigned OpNo, SStream *O) |
413 | 5.57k | { |
414 | 5.57k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_BranchOperand, OpNo); |
415 | 5.57k | if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) { |
416 | 0 | printOperand(MI, OpNo, O); |
417 | 0 | return; |
418 | 0 | } |
419 | 5.57k | int32_t Imm = SignExtend32( |
420 | 5.57k | ((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo))) |
421 | 5.57k | << 2), |
422 | 5.57k | 32); |
423 | 5.57k | if (MI->csh->PrintBranchImmAsAddress) { |
424 | 5.57k | uint64_t Target = Address + Imm; |
425 | 5.57k | if (!IS_64BIT(MI->csh->mode)) |
426 | 1.28k | Target &= 0xffffffff; |
427 | 5.57k | printUInt64(O, (Target)); |
428 | 5.57k | } else { |
429 | | // Branches can take an immediate operand. This is used by the branch |
430 | | // selection pass to print, for example `.+8` (for ELF) or `$+8` (for |
431 | | // AIX) to express an eight byte displacement from the program counter. |
432 | 0 | if (!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs)) |
433 | 0 | SStream_concat0(O, "."); |
434 | 0 | else |
435 | 0 | SStream_concat0(O, "$"); |
436 | |
|
437 | 0 | if (Imm >= 0) |
438 | 0 | SStream_concat0(O, "+"); |
439 | 0 | printInt32(O, Imm); |
440 | 0 | } |
441 | 5.57k | } |
442 | | |
443 | | static inline void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O) |
444 | 4.43k | { |
445 | 4.43k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_AbsBranchOperand, OpNo); |
446 | 4.43k | if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) { |
447 | 0 | printOperand(MI, OpNo, O); |
448 | 0 | return; |
449 | 0 | } |
450 | | |
451 | 4.43k | printUInt64(O, |
452 | 4.43k | ((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo))) |
453 | 4.43k | << 2)); |
454 | 4.43k | } |
455 | | |
456 | | static inline void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O) |
457 | 1.02k | { |
458 | 1.02k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_crbitm, OpNo); |
459 | 1.02k | unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, (OpNo))); |
460 | 1.02k | unsigned RegNo; |
461 | 1.02k | switch (CCReg) { |
462 | 0 | default: |
463 | 0 | CS_ASSERT_RET(0 && "Unknown CR register"); |
464 | 178 | case PPC_CR0: |
465 | 178 | RegNo = 0; |
466 | 178 | break; |
467 | 25 | case PPC_CR1: |
468 | 25 | RegNo = 1; |
469 | 25 | break; |
470 | 74 | case PPC_CR2: |
471 | 74 | RegNo = 2; |
472 | 74 | break; |
473 | 192 | case PPC_CR3: |
474 | 192 | RegNo = 3; |
475 | 192 | break; |
476 | 221 | case PPC_CR4: |
477 | 221 | RegNo = 4; |
478 | 221 | break; |
479 | 73 | case PPC_CR5: |
480 | 73 | RegNo = 5; |
481 | 73 | break; |
482 | 109 | case PPC_CR6: |
483 | 109 | RegNo = 6; |
484 | 109 | break; |
485 | 153 | case PPC_CR7: |
486 | 153 | RegNo = 7; |
487 | 153 | break; |
488 | 1.02k | } |
489 | 1.02k | printUInt32(O, (0x80 >> RegNo)); |
490 | 1.02k | } |
491 | | |
492 | | static inline void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O) |
493 | 25.3k | { |
494 | 25.3k | set_mem_access(MI, true); |
495 | 25.3k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm, OpNo); |
496 | 25.3k | printS16ImmOperand(MI, OpNo, O); |
497 | 25.3k | SStream_concat0(O, "("); |
498 | | |
499 | 25.3k | if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo + 1))) == PPC_R0) |
500 | 0 | SStream_concat0(O, "0"); |
501 | 25.3k | else |
502 | 25.3k | printOperand(MI, OpNo + 1, O); |
503 | 25.3k | SStream_concat0(O, ")"); |
504 | 25.3k | set_mem_access(MI, false); |
505 | 25.3k | } |
506 | | |
507 | | static inline void printMemRegImmHash(MCInst *MI, unsigned OpNo, SStream *O) |
508 | 102 | { |
509 | 102 | set_mem_access(MI, true); |
510 | 102 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImmHash, OpNo); |
511 | 102 | printInt32(O, MCOperand_getImm(MCInst_getOperand(MI, (OpNo)))); |
512 | 102 | SStream_concat0(O, "("); |
513 | | |
514 | 102 | printOperand(MI, OpNo + 1, O); |
515 | 102 | SStream_concat0(O, ")"); |
516 | 102 | set_mem_access(MI, false); |
517 | 102 | } |
518 | | |
519 | | static inline void printMemRegImm34PCRel(MCInst *MI, unsigned OpNo, SStream *O) |
520 | 297 | { |
521 | 297 | set_mem_access(MI, true); |
522 | 297 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm34PCRel, OpNo); |
523 | 297 | printS34ImmOperand(MI, OpNo, O); |
524 | 297 | SStream_concat0(O, "("); |
525 | | |
526 | 297 | printImmZeroOperand(MI, OpNo + 1, O); |
527 | 297 | SStream_concat0(O, ")"); |
528 | 297 | set_mem_access(MI, false); |
529 | 297 | } |
530 | | |
531 | | static inline void printMemRegImm34(MCInst *MI, unsigned OpNo, SStream *O) |
532 | 127 | { |
533 | 127 | set_mem_access(MI, true); |
534 | 127 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm34, OpNo); |
535 | 127 | printS34ImmOperand(MI, OpNo, O); |
536 | 127 | SStream_concat0(O, "("); |
537 | | |
538 | 127 | printOperand(MI, OpNo + 1, O); |
539 | 127 | SStream_concat0(O, ")"); |
540 | 127 | set_mem_access(MI, false); |
541 | 127 | } |
542 | | |
543 | | static inline void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O) |
544 | 7.47k | { |
545 | 7.47k | set_mem_access(MI, true); |
546 | 7.47k | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegReg, OpNo); |
547 | | // When used as the base register, r0 reads constant zero rather than |
548 | | // the value contained in the register. For this reason, the darwin |
549 | | // assembler requires that we print r0 as 0 (no r) when used as the base. |
550 | 7.47k | if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo))) == PPC_R0) |
551 | 0 | SStream_concat0(O, "0"); |
552 | 7.47k | else |
553 | 7.47k | printOperand(MI, OpNo, O); |
554 | 7.47k | SStream_concat0(O, ", "); |
555 | 7.47k | printOperand(MI, OpNo + 1, O); |
556 | 7.47k | set_mem_access(MI, false); |
557 | 7.47k | } |
558 | | |
559 | | static inline void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O) |
560 | 0 | { |
561 | 0 | PPC_add_cs_detail_0(MI, PPC_OP_GROUP_TLSCall, OpNo); |
562 | | |
563 | | // Expression logic removed. |
564 | |
|
565 | 0 | set_mem_access(MI, true); |
566 | 0 | SStream_concat0(O, "("); |
567 | |
|
568 | 0 | printOperand(MI, OpNo + 1, O); |
569 | 0 | SStream_concat0(O, ")"); |
570 | 0 | set_mem_access(MI, false); |
571 | 0 | } |
572 | | |
573 | | #define PRINT_ALIAS_INSTR |
574 | | #include "PPCGenAsmWriter.inc" |
575 | | |
576 | | static void printInst(MCInst *MI, uint64_t Address, const char *Annot, |
577 | | SStream *O) |
578 | 62.0k | { |
579 | 62.0k | bool isAlias = false; |
580 | 62.0k | bool useAliasDetails = false; |
581 | | // Customize printing of the addis instruction on AIX. When an operand is a |
582 | | // symbol reference, the instruction syntax is changed to look like a load |
583 | | // operation, i.e: |
584 | | // Transform: addis $rD, $rA, $src --> addis $rD, $src($rA). |
585 | 62.0k | if (PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs) && |
586 | 62.0k | (MCInst_getOpcode(MI) == PPC_ADDIS8 || |
587 | 0 | MCInst_getOpcode(MI) == PPC_ADDIS) && |
588 | 62.0k | MCOperand_isExpr(MCInst_getOperand(MI, (2)))) { |
589 | 0 | SStream_concat0(O, "\taddis "); |
590 | 0 | printOperand(MI, 0, O); |
591 | 0 | SStream_concat0(O, ", "); |
592 | 0 | printOperand(MI, 2, O); |
593 | 0 | SStream_concat0(O, "("); |
594 | 0 | printOperand(MI, 1, O); |
595 | 0 | SStream_concat0(O, ")"); |
596 | 0 | return; |
597 | 0 | } |
598 | | |
599 | | // Check if the last operand is an expression with the variant kind |
600 | | // VK_PPC_PCREL_OPT. If this is the case then this is a linker optimization |
601 | | // relocation and the .reloc directive needs to be added. |
602 | 62.0k | unsigned LastOp = MCInst_getNumOperands(MI) - 1; |
603 | 62.0k | if (MCInst_getNumOperands(MI) > 1) { |
604 | 60.2k | MCOperand *Operand = MCInst_getOperand(MI, (LastOp)); |
605 | 60.2k | if (MCOperand_isExpr(Operand)) { |
606 | 0 | CS_ASSERT_RET(0 && "Expressions not supported."); |
607 | 0 | } |
608 | 60.2k | } |
609 | | |
610 | | // Check for slwi/srwi mnemonics. |
611 | 62.0k | if (MCInst_getOpcode(MI) == PPC_RLWINM) { |
612 | 1.10k | unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2))); |
613 | 1.10k | unsigned char MB = MCOperand_getImm(MCInst_getOperand(MI, (3))); |
614 | 1.10k | unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (4))); |
615 | 1.10k | bool useSubstituteMnemonic = false; |
616 | 1.10k | if (SH <= 31 && MB == 0 && ME == (31 - SH)) { |
617 | 116 | SStream_concat0(O, "slwi "); |
618 | 116 | useSubstituteMnemonic = true; |
619 | 116 | } |
620 | 1.10k | if (SH <= 31 && MB == (32 - SH) && ME == 31) { |
621 | 52 | SStream_concat0(O, "srwi "); |
622 | 52 | useSubstituteMnemonic = true; |
623 | 52 | SH = 32 - SH; |
624 | 52 | } |
625 | 1.10k | useAliasDetails |= map_use_alias_details(MI); |
626 | 1.10k | map_set_fill_detail_ops(MI, useAliasDetails && |
627 | 1.10k | useSubstituteMnemonic); |
628 | 1.10k | if (useSubstituteMnemonic) { |
629 | 168 | isAlias |= true; |
630 | 168 | MCInst_setIsAlias(MI, isAlias); |
631 | | |
632 | 168 | printOperand(MI, 0, O); |
633 | 168 | SStream_concat0(O, ", "); |
634 | 168 | printOperand(MI, 1, O); |
635 | 168 | SStream_concat(O, "%s", ", "); |
636 | 168 | printUInt32(O, (unsigned int)SH); |
637 | 168 | PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ); |
638 | | |
639 | 168 | if (useAliasDetails) |
640 | 168 | return; |
641 | 168 | } |
642 | 1.10k | } |
643 | | |
644 | 61.8k | if (MCInst_getOpcode(MI) == PPC_RLDICR || |
645 | 61.8k | MCInst_getOpcode(MI) == PPC_RLDICR_32) { |
646 | 256 | unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2))); |
647 | 256 | unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (3))); |
648 | | |
649 | 256 | useAliasDetails |= map_use_alias_details(MI); |
650 | 256 | map_set_fill_detail_ops(MI, useAliasDetails && 63 - SH == ME); |
651 | | // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH |
652 | 256 | if (63 - SH == ME) { |
653 | 19 | isAlias |= true; |
654 | 19 | MCInst_setIsAlias(MI, isAlias); |
655 | 19 | SStream_concat0(O, "sldi "); |
656 | 19 | printOperand(MI, 0, O); |
657 | 19 | SStream_concat0(O, ", "); |
658 | 19 | printOperand(MI, 1, O); |
659 | 19 | SStream_concat(O, "%s", ", "); |
660 | 19 | printUInt32(O, (unsigned int)SH); |
661 | 19 | PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ); |
662 | | |
663 | 19 | if (useAliasDetails) |
664 | 19 | return; |
665 | 19 | } |
666 | 256 | } |
667 | | |
668 | | // dcbt[st] is printed manually here because: |
669 | | // 1. The assembly syntax is different between embedded and server targets |
670 | | // 2. We must print the short mnemonics for TH == 0 because the |
671 | | // embedded/server syntax default will not be stable across assemblers |
672 | | // The syntax for dcbt is: |
673 | | // dcbt ra, rb, th [server] |
674 | | // dcbt th, ra, rb [embedded] |
675 | | // where th can be omitted when it is 0. dcbtst is the same. |
676 | | // On AIX, only emit the extended mnemonics for dcbt and dcbtst if |
677 | | // the "modern assembler" is available. |
678 | 61.8k | if ((MCInst_getOpcode(MI) == PPC_DCBT || |
679 | 61.8k | MCInst_getOpcode(MI) == PPC_DCBTST) && |
680 | 61.8k | (!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))) { |
681 | 1.38k | unsigned char TH = MCOperand_getImm(MCInst_getOperand(MI, (0))); |
682 | 1.38k | SStream_concat0(O, "dcbt"); |
683 | 1.38k | if (MCInst_getOpcode(MI) == PPC_DCBTST) |
684 | 134 | SStream_concat0(O, "st"); |
685 | 1.38k | if (TH == 16) |
686 | 123 | SStream_concat0(O, "t"); |
687 | 1.38k | SStream_concat0(O, " "); |
688 | | |
689 | 1.38k | bool IsBookE = |
690 | 1.38k | PPC_getFeatureBits(MI->csh->mode, PPC_FeatureBookE); |
691 | 1.38k | if (IsBookE && TH != 0 && TH != 16) { |
692 | 0 | printUInt32(O, (unsigned int)TH); |
693 | 0 | SStream_concat0(O, ", "); |
694 | 0 | PPC_set_detail_op_imm(MI, 0, TH); |
695 | 0 | } |
696 | 1.38k | set_mem_access(MI, true); |
697 | 1.38k | printOperand(MI, 1, O); |
698 | 1.38k | SStream_concat0(O, ", "); |
699 | 1.38k | printOperand(MI, 2, O); |
700 | 1.38k | set_mem_access(MI, false); |
701 | | |
702 | 1.38k | if (!IsBookE && TH != 0 && TH != 16) { |
703 | 868 | SStream_concat(O, "%s", ", "); |
704 | 868 | printUInt32(O, (unsigned int)TH); |
705 | 868 | PPC_set_detail_op_imm(MI, 0, TH); |
706 | 868 | } |
707 | | |
708 | 1.38k | return; |
709 | 1.38k | } |
710 | | |
711 | 60.4k | if (MCInst_getOpcode(MI) == PPC_DCBF) { |
712 | 2.02k | unsigned char L = MCOperand_getImm(MCInst_getOperand(MI, (0))); |
713 | 2.02k | if (!L || L == 1 || L == 3 || L == 4 || L == 6) { |
714 | 1.98k | SStream_concat0(O, "dcb"); |
715 | 1.98k | if (L != 6) |
716 | 1.33k | SStream_concat0(O, "f"); |
717 | 1.98k | if (L == 1) |
718 | 25 | SStream_concat0(O, "l"); |
719 | 1.98k | if (L == 3) |
720 | 1.19k | SStream_concat0(O, "lp"); |
721 | 1.98k | if (L == 4) |
722 | 27 | SStream_concat0(O, "ps"); |
723 | 1.98k | if (L == 6) |
724 | 649 | SStream_concat0(O, "stps"); |
725 | 1.98k | SStream_concat0(O, " "); |
726 | | |
727 | 1.98k | printOperand(MI, 1, O); |
728 | 1.98k | SStream_concat0(O, ", "); |
729 | 1.98k | printOperand(MI, 2, O); |
730 | | |
731 | 1.98k | return; |
732 | 1.98k | } |
733 | 2.02k | } |
734 | | |
735 | | // isAlias/useAliasDetails could have been set before. |
736 | 58.4k | useAliasDetails |= map_use_alias_details(MI); |
737 | 58.4k | map_set_fill_detail_ops(MI, useAliasDetails); |
738 | 58.4k | isAlias |= printAliasInstr(MI, Address, O); |
739 | 58.4k | MCInst_setIsAlias(MI, isAlias); |
740 | | |
741 | 58.4k | if (!isAlias || !useAliasDetails) { |
742 | 49.1k | map_set_fill_detail_ops(MI, true); |
743 | 49.1k | if (isAlias) |
744 | 0 | SStream_Close(O); |
745 | 49.1k | printInstruction(MI, Address, O); |
746 | 49.1k | if (isAlias) |
747 | 0 | SStream_Open(O); |
748 | 49.1k | } |
749 | 58.4k | } |
750 | | |
751 | | const char *PPC_LLVM_getRegisterName(unsigned RegNo) |
752 | 48.4k | { |
753 | 48.4k | return getRegisterName(RegNo); |
754 | 48.4k | } |
755 | | |
756 | | void PPC_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot, |
757 | | SStream *O) |
758 | 62.0k | { |
759 | 62.0k | printInst(MI, Address, Annot, O); |
760 | 62.0k | } |