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