/src/capstonenext/arch/PowerPC/PPCInstPrinter.c
Line  | Count  | Source  | 
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  | 138k  | { | 
68  | 138k  |   if ((MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME) ||  | 
69  | 138k  |       !(MI->csh->syntax & CS_OPT_SYNTAX_PERCENT) ||  | 
70  | 0  |       PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))  | 
71  | 138k  |     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  | 138k  | { | 
91  | 138k  |   if (MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME)  | 
92  | 0  |     return NULL;  | 
93  | 138k  |   if (RegNum < PPC_CR0EQ || RegNum > PPC_CR7UN)  | 
94  | 129k  |     return NULL;  | 
95  | 8.80k  |   const char *CRBits[] = { | 
96  | 8.80k  |     "lt",     "gt", "eq",     "un", "4*cr1+lt",  | 
97  | 8.80k  |     "4*cr1+gt", "4*cr1+eq", "4*cr1+un", "4*cr2+lt", "4*cr2+gt",  | 
98  | 8.80k  |     "4*cr2+eq", "4*cr2+un", "4*cr3+lt", "4*cr3+gt", "4*cr3+eq",  | 
99  | 8.80k  |     "4*cr3+un", "4*cr4+lt", "4*cr4+gt", "4*cr4+eq", "4*cr4+un",  | 
100  | 8.80k  |     "4*cr5+lt", "4*cr5+gt", "4*cr5+eq", "4*cr5+un", "4*cr6+lt",  | 
101  | 8.80k  |     "4*cr6+gt", "4*cr6+eq", "4*cr6+un", "4*cr7+lt", "4*cr7+gt",  | 
102  | 8.80k  |     "4*cr7+eq", "4*cr7+un"  | 
103  | 8.80k  |   };  | 
104  | 8.80k  |   return CRBits[RegEncoding];  | 
105  | 138k  | }  | 
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  | 138k  | { | 
111  | 138k  |   return !(MI->csh->syntax & CS_OPT_SYNTAX_NOREGNAME);  | 
112  | 138k  | }  | 
113  |  |  | 
114  |  | static inline void printOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
115  | 140k  | { | 
116  | 140k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_Operand, OpNo);  | 
117  | 140k  |   MCOperand *Op = MCInst_getOperand(MI, (OpNo));  | 
118  | 140k  |   if (MCOperand_isReg(Op)) { | 
119  | 138k  |     unsigned Reg = MCOperand_getReg(Op);  | 
120  | 138k  |     if (!MI->csh->ShowVSRNumsAsVR)  | 
121  | 138k  |       Reg = PPCInstrInfo_getRegNumForOperand(  | 
122  | 138k  |         MCInstrDesc_get(MCInst_getOpcode(MI),  | 
123  | 138k  |             PPCDescs.Insts,  | 
124  | 138k  |             ARR_SIZE(PPCDescs.Insts)),  | 
125  | 138k  |         Reg, OpNo);  | 
126  |  |  | 
127  | 138k  |     const char *RegName;  | 
128  | 138k  |     RegName = getVerboseConditionRegName(  | 
129  | 138k  |       MI, Reg, MI->MRI->RegEncodingTable[Reg]);  | 
130  | 138k  |     if (RegName == NULL)  | 
131  | 129k  |       RegName = getRegisterName(Reg);  | 
132  | 138k  |     if (showRegistersWithPercentPrefix(MI, RegName))  | 
133  | 0  |       SStream_concat0(O, "%");  | 
134  | 138k  |     if (!showRegistersWithPrefix(MI))  | 
135  | 0  |       RegName = PPCRegisterInfo_stripRegisterPrefix(RegName);  | 
136  |  |  | 
137  | 138k  |     SStream_concat0(O, RegName);  | 
138  | 138k  |     return;  | 
139  | 138k  |   }  | 
140  |  |  | 
141  | 1.55k  |   if (MCOperand_isImm(Op)) { | 
142  | 1.55k  |     printInt64(O, MCOperand_getImm(Op));  | 
143  | 1.55k  |     return;  | 
144  | 1.55k  |   }  | 
145  | 1.55k  | }  | 
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  | 3.05k  | { | 
259  | 3.05k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U1ImmOperand, OpNo);  | 
260  | 3.05k  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
261  | 3.05k  |   CS_ASSERT(Value <= 1 && "Invalid u1imm argument!");  | 
262  | 3.05k  |   printUInt32(O, (unsigned int)Value);  | 
263  | 3.05k  | }  | 
264  |  |  | 
265  |  | static inline void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
266  | 1.76k  | { | 
267  | 1.76k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U2ImmOperand, OpNo);  | 
268  | 1.76k  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
269  | 1.76k  |   CS_ASSERT(Value <= 3 && "Invalid u2imm argument!");  | 
270  | 1.76k  |   printUInt32(O, (unsigned int)Value);  | 
271  | 1.76k  | }  | 
272  |  |  | 
273  |  | static inline void printU3ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
274  | 1.70k  | { | 
275  | 1.70k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U3ImmOperand, OpNo);  | 
276  | 1.70k  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
277  | 1.70k  |   CS_ASSERT(Value <= 8 && "Invalid u3imm argument!");  | 
278  | 1.70k  |   printUInt32(O, (unsigned int)Value);  | 
279  | 1.70k  | }  | 
280  |  |  | 
281  |  | static inline void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
282  | 1.92k  | { | 
283  | 1.92k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U4ImmOperand, OpNo);  | 
284  | 1.92k  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
285  | 1.92k  |   CS_ASSERT(Value <= 15 && "Invalid u4imm argument!");  | 
286  | 1.92k  |   printUInt32(O, (unsigned int)Value);  | 
287  | 1.92k  | }  | 
288  |  |  | 
289  |  | static inline void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
290  | 382  | { | 
291  | 382  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S5ImmOperand, OpNo);  | 
292  | 382  |   int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
293  | 382  |   Value = SignExtend32((Value), 5);  | 
294  | 382  |   printInt32(O, (int)Value);  | 
295  | 382  | }  | 
296  |  |  | 
297  |  | static inline void printImmZeroOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
298  | 312  | { | 
299  | 312  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_ImmZeroOperand, OpNo);  | 
300  | 312  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
301  | 312  |   CS_ASSERT(Value == 0 && "Operand must be zero");  | 
302  | 312  |   printUInt32(O, (unsigned int)Value);  | 
303  | 312  | }  | 
304  |  |  | 
305  |  | static inline void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
306  | 10.2k  | { | 
307  | 10.2k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U5ImmOperand, OpNo);  | 
308  | 10.2k  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
309  | 10.2k  |   CS_ASSERT(Value <= 31 && "Invalid u5imm argument!");  | 
310  | 10.2k  |   printUInt32(O, (unsigned int)Value);  | 
311  | 10.2k  | }  | 
312  |  |  | 
313  |  | static inline void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
314  | 2.56k  | { | 
315  | 2.56k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U6ImmOperand, OpNo);  | 
316  | 2.56k  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
317  | 2.56k  |   CS_ASSERT(Value <= 63 && "Invalid u6imm argument!");  | 
318  | 2.56k  |   printUInt32(O, (unsigned int)Value);  | 
319  | 2.56k  | }  | 
320  |  |  | 
321  |  | static inline void printU7ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
322  | 258  | { | 
323  | 258  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U7ImmOperand, OpNo);  | 
324  | 258  |   unsigned int Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
325  | 258  |   CS_ASSERT(Value <= 127 && "Invalid u7imm argument!");  | 
326  | 258  |   printUInt32(O, (unsigned int)Value);  | 
327  | 258  | }  | 
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  | 188  | { | 
334  | 188  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U8ImmOperand, OpNo);  | 
335  | 188  |   unsigned char Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
336  | 188  |   CS_ASSERT(Value <= 255 && "Invalid u8imm argument!");  | 
337  | 188  |   printUInt32(O, (unsigned int)Value);  | 
338  | 188  | }  | 
339  |  |  | 
340  |  | static inline void printU10ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
341  | 34  | { | 
342  | 34  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U10ImmOperand, OpNo);  | 
343  | 34  |   unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
344  | 34  |   CS_ASSERT(Value <= 1023 && "Invalid u10imm argument!");  | 
345  | 34  |   printUInt32(O, (unsigned short)Value);  | 
346  | 34  | }  | 
347  |  |  | 
348  |  | static inline void printU12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
349  | 387  | { | 
350  | 387  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U12ImmOperand, OpNo);  | 
351  | 387  |   unsigned short Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
352  | 387  |   CS_ASSERT(Value <= 4095 && "Invalid u12imm argument!");  | 
353  | 387  |   printUInt32(O, (unsigned short)Value);  | 
354  | 387  | }  | 
355  |  |  | 
356  |  | static inline void printS12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
357  | 501  | { | 
358  | 501  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S12ImmOperand, OpNo);  | 
359  | 501  |   if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) { | 
360  | 501  |     int Imm = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));  | 
361  | 501  |     Imm = SignExtend32(Imm, 12);  | 
362  | 501  |     printInt32(O, Imm);  | 
363  | 501  |   } else  | 
364  | 0  |     printOperand(MI, OpNo, O);  | 
365  | 501  | }  | 
366  |  |  | 
367  |  | static inline void printMemRegImmPS(MCInst *MI, unsigned OpNo, SStream *O)  | 
368  | 501  | { | 
369  | 501  |   set_mem_access(MI, true);  | 
370  |  |  | 
371  | 501  |   printS12ImmOperand(MI, OpNo, O);  | 
372  | 501  |   SStream_concat0(O, "("); | 
373  | 501  |   printOperand(MI, OpNo + 1, O);  | 
374  | 501  |   SStream_concat0(O, ")");  | 
375  |  |  | 
376  | 501  |   set_mem_access(MI, false);  | 
377  | 501  | }  | 
378  |  |  | 
379  |  | static inline void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
380  | 15.6k  | { | 
381  | 15.6k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S16ImmOperand, OpNo);  | 
382  | 15.6k  |   if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo))))  | 
383  | 15.6k  |     printInt32(O, (short)MCOperand_getImm(  | 
384  | 15.6k  |               MCInst_getOperand(MI, (OpNo))));  | 
385  | 0  |   else  | 
386  | 0  |     printOperand(MI, OpNo, O);  | 
387  | 15.6k  | }  | 
388  |  |  | 
389  |  | static inline void printS34ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
390  | 750  | { | 
391  | 750  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_S34ImmOperand, OpNo);  | 
392  | 750  |   if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) { | 
393  | 750  |     long long Value =  | 
394  | 750  |       MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));  | 
395  |  |  | 
396  | 750  |     printInt64(O, (long long)Value);  | 
397  | 750  |   } else  | 
398  | 0  |     printOperand(MI, OpNo, O);  | 
399  | 750  | }  | 
400  |  |  | 
401  |  | static inline void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
402  | 3.05k  | { | 
403  | 3.05k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_U16ImmOperand, OpNo);  | 
404  | 3.05k  |   if (MCOperand_isImm(MCInst_getOperand(MI, (OpNo))))  | 
405  | 3.05k  |     printUInt32(O, (unsigned short)MCOperand_getImm(  | 
406  | 3.05k  |                MCInst_getOperand(MI, (OpNo))));  | 
407  | 0  |   else  | 
408  | 0  |     printOperand(MI, OpNo, O);  | 
409  | 3.05k  | }  | 
410  |  |  | 
411  |  | static inline void printBranchOperand(MCInst *MI, uint64_t Address,  | 
412  |  |               unsigned OpNo, SStream *O)  | 
413  | 5.45k  | { | 
414  | 5.45k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_BranchOperand, OpNo);  | 
415  | 5.45k  |   if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) { | 
416  | 0  |     printOperand(MI, OpNo, O);  | 
417  | 0  |     return;  | 
418  | 0  |   }  | 
419  | 5.45k  |   int32_t Imm = SignExtend32(  | 
420  | 5.45k  |     ((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo)))  | 
421  | 5.45k  |      << 2),  | 
422  | 5.45k  |     32);  | 
423  | 5.45k  |   if (MI->csh->PrintBranchImmAsAddress) { | 
424  | 5.45k  |     uint64_t Target = Address + Imm;  | 
425  | 5.45k  |     if (!IS_64BIT(MI->csh->mode))  | 
426  | 1.12k  |       Target &= 0xffffffff;  | 
427  | 5.45k  |     printUInt64(O, (Target));  | 
428  | 5.45k  |   } 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.45k  | }  | 
442  |  |  | 
443  |  | static inline void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)  | 
444  | 2.74k  | { | 
445  | 2.74k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_AbsBranchOperand, OpNo);  | 
446  | 2.74k  |   if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNo)))) { | 
447  | 0  |     printOperand(MI, OpNo, O);  | 
448  | 0  |     return;  | 
449  | 0  |   }  | 
450  |  |  | 
451  | 2.74k  |   printUInt64(O,  | 
452  | 2.74k  |         ((unsigned)MCOperand_getImm(MCInst_getOperand(MI, (OpNo)))  | 
453  | 2.74k  |          << 2));  | 
454  | 2.74k  | }  | 
455  |  |  | 
456  |  | static inline void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O)  | 
457  | 870  | { | 
458  | 870  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_crbitm, OpNo);  | 
459  | 870  |   unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, (OpNo)));  | 
460  | 870  |   unsigned RegNo;  | 
461  | 870  |   switch (CCReg) { | 
462  | 0  |   default:  | 
463  | 0  |     CS_ASSERT_RET(0 && "Unknown CR register");  | 
464  | 51  |   case PPC_CR0:  | 
465  | 51  |     RegNo = 0;  | 
466  | 51  |     break;  | 
467  | 68  |   case PPC_CR1:  | 
468  | 68  |     RegNo = 1;  | 
469  | 68  |     break;  | 
470  | 221  |   case PPC_CR2:  | 
471  | 221  |     RegNo = 2;  | 
472  | 221  |     break;  | 
473  | 135  |   case PPC_CR3:  | 
474  | 135  |     RegNo = 3;  | 
475  | 135  |     break;  | 
476  | 249  |   case PPC_CR4:  | 
477  | 249  |     RegNo = 4;  | 
478  | 249  |     break;  | 
479  | 57  |   case PPC_CR5:  | 
480  | 57  |     RegNo = 5;  | 
481  | 57  |     break;  | 
482  | 9  |   case PPC_CR6:  | 
483  | 9  |     RegNo = 6;  | 
484  | 9  |     break;  | 
485  | 80  |   case PPC_CR7:  | 
486  | 80  |     RegNo = 7;  | 
487  | 80  |     break;  | 
488  | 870  |   }  | 
489  | 870  |   printUInt32(O, (0x80 >> RegNo));  | 
490  | 870  | }  | 
491  |  |  | 
492  |  | static inline void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O)  | 
493  | 26.2k  | { | 
494  | 26.2k  |   set_mem_access(MI, true);  | 
495  | 26.2k  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm, OpNo);  | 
496  | 26.2k  |   printS16ImmOperand(MI, OpNo, O);  | 
497  | 26.2k  |   SStream_concat0(O, "("); | 
498  |  |  | 
499  | 26.2k  |   if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo + 1))) == PPC_R0)  | 
500  | 0  |     SStream_concat0(O, "0");  | 
501  | 26.2k  |   else  | 
502  | 26.2k  |     printOperand(MI, OpNo + 1, O);  | 
503  | 26.2k  |   SStream_concat0(O, ")");  | 
504  | 26.2k  |   set_mem_access(MI, false);  | 
505  | 26.2k  | }  | 
506  |  |  | 
507  |  | static inline void printMemRegImmHash(MCInst *MI, unsigned OpNo, SStream *O)  | 
508  | 295  | { | 
509  | 295  |   set_mem_access(MI, true);  | 
510  | 295  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImmHash, OpNo);  | 
511  | 295  |   printInt32(O, MCOperand_getImm(MCInst_getOperand(MI, (OpNo))));  | 
512  | 295  |   SStream_concat0(O, "("); | 
513  |  |  | 
514  | 295  |   printOperand(MI, OpNo + 1, O);  | 
515  | 295  |   SStream_concat0(O, ")");  | 
516  | 295  |   set_mem_access(MI, false);  | 
517  | 295  | }  | 
518  |  |  | 
519  |  | static inline void printMemRegImm34PCRel(MCInst *MI, unsigned OpNo, SStream *O)  | 
520  | 293  | { | 
521  | 293  |   set_mem_access(MI, true);  | 
522  | 293  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm34PCRel, OpNo);  | 
523  | 293  |   printS34ImmOperand(MI, OpNo, O);  | 
524  | 293  |   SStream_concat0(O, "("); | 
525  |  |  | 
526  | 293  |   printImmZeroOperand(MI, OpNo + 1, O);  | 
527  | 293  |   SStream_concat0(O, ")");  | 
528  | 293  |   set_mem_access(MI, false);  | 
529  | 293  | }  | 
530  |  |  | 
531  |  | static inline void printMemRegImm34(MCInst *MI, unsigned OpNo, SStream *O)  | 
532  | 264  | { | 
533  | 264  |   set_mem_access(MI, true);  | 
534  | 264  |   PPC_add_cs_detail_0(MI, PPC_OP_GROUP_MemRegImm34, OpNo);  | 
535  | 264  |   printS34ImmOperand(MI, OpNo, O);  | 
536  | 264  |   SStream_concat0(O, "("); | 
537  |  |  | 
538  | 264  |   printOperand(MI, OpNo + 1, O);  | 
539  | 264  |   SStream_concat0(O, ")");  | 
540  | 264  |   set_mem_access(MI, false);  | 
541  | 264  | }  | 
542  |  |  | 
543  |  | static inline void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O)  | 
544  | 7.94k  | { | 
545  | 7.94k  |   set_mem_access(MI, true);  | 
546  | 7.94k  |   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.94k  |   if (MCOperand_getReg(MCInst_getOperand(MI, (OpNo))) == PPC_R0)  | 
551  | 0  |     SStream_concat0(O, "0");  | 
552  | 7.94k  |   else  | 
553  | 7.94k  |     printOperand(MI, OpNo, O);  | 
554  | 7.94k  |   SStream_concat0(O, ", ");  | 
555  | 7.94k  |   printOperand(MI, OpNo + 1, O);  | 
556  | 7.94k  |   set_mem_access(MI, false);  | 
557  | 7.94k  | }  | 
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  | 68.0k  | { | 
579  | 68.0k  |   bool isAlias = false;  | 
580  | 68.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  | 68.0k  |   if (PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs) &&  | 
586  | 0  |       (MCInst_getOpcode(MI) == PPC_ADDIS8 ||  | 
587  | 0  |        MCInst_getOpcode(MI) == PPC_ADDIS) &&  | 
588  | 0  |       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  | 68.0k  |   unsigned LastOp = MCInst_getNumOperands(MI) - 1;  | 
603  | 68.0k  |   if (MCInst_getNumOperands(MI) > 1) { | 
604  | 65.7k  |     MCOperand *Operand = MCInst_getOperand(MI, (LastOp));  | 
605  | 65.7k  |     if (MCOperand_isExpr(Operand)) { | 
606  | 0  |       CS_ASSERT_RET(0 && "Expressions not supported.");  | 
607  | 0  |     }  | 
608  | 65.7k  |   }  | 
609  |  |  | 
610  |  |   // Check for slwi/srwi mnemonics.  | 
611  | 68.0k  |   if (MCInst_getOpcode(MI) == PPC_RLWINM) { | 
612  | 1.46k  |     unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2)));  | 
613  | 1.46k  |     unsigned char MB = MCOperand_getImm(MCInst_getOperand(MI, (3)));  | 
614  | 1.46k  |     unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (4)));  | 
615  | 1.46k  |     bool useSubstituteMnemonic = false;  | 
616  | 1.46k  |     if (SH <= 31 && MB == 0 && ME == (31 - SH)) { | 
617  | 157  |       SStream_concat0(O, "slwi ");  | 
618  | 157  |       useSubstituteMnemonic = true;  | 
619  | 157  |     }  | 
620  | 1.46k  |     if (SH <= 31 && MB == (32 - SH) && ME == 31) { | 
621  | 87  |       SStream_concat0(O, "srwi ");  | 
622  | 87  |       useSubstituteMnemonic = true;  | 
623  | 87  |       SH = 32 - SH;  | 
624  | 87  |     }  | 
625  | 1.46k  |     useAliasDetails |= map_use_alias_details(MI);  | 
626  | 1.46k  |     map_set_fill_detail_ops(MI, useAliasDetails &&  | 
627  | 1.46k  |                 useSubstituteMnemonic);  | 
628  | 1.46k  |     if (useSubstituteMnemonic) { | 
629  | 244  |       isAlias |= true;  | 
630  | 244  |       MCInst_setIsAlias(MI, isAlias);  | 
631  |  |  | 
632  | 244  |       printOperand(MI, 0, O);  | 
633  | 244  |       SStream_concat0(O, ", ");  | 
634  | 244  |       printOperand(MI, 1, O);  | 
635  | 244  |       SStream_concat(O, "%s", ", ");  | 
636  | 244  |       printUInt32(O, (unsigned int)SH);  | 
637  | 244  |       PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ);  | 
638  |  |  | 
639  | 244  |       if (useAliasDetails)  | 
640  | 244  |         return;  | 
641  | 244  |     }  | 
642  | 1.46k  |   }  | 
643  |  |  | 
644  | 67.8k  |   if (MCInst_getOpcode(MI) == PPC_RLDICR ||  | 
645  | 67.6k  |       MCInst_getOpcode(MI) == PPC_RLDICR_32) { | 
646  | 203  |     unsigned char SH = MCOperand_getImm(MCInst_getOperand(MI, (2)));  | 
647  | 203  |     unsigned char ME = MCOperand_getImm(MCInst_getOperand(MI, (3)));  | 
648  |  |  | 
649  | 203  |     useAliasDetails |= map_use_alias_details(MI);  | 
650  | 203  |     map_set_fill_detail_ops(MI, useAliasDetails && 63 - SH == ME);  | 
651  |  |     // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH  | 
652  | 203  |     if (63 - SH == ME) { | 
653  | 67  |       isAlias |= true;  | 
654  | 67  |       MCInst_setIsAlias(MI, isAlias);  | 
655  | 67  |       SStream_concat0(O, "sldi ");  | 
656  | 67  |       printOperand(MI, 0, O);  | 
657  | 67  |       SStream_concat0(O, ", ");  | 
658  | 67  |       printOperand(MI, 1, O);  | 
659  | 67  |       SStream_concat(O, "%s", ", ");  | 
660  | 67  |       printUInt32(O, (unsigned int)SH);  | 
661  | 67  |       PPC_insert_detail_op_imm_at(MI, 2, SH, CS_AC_READ);  | 
662  |  |  | 
663  | 67  |       if (useAliasDetails)  | 
664  | 67  |         return;  | 
665  | 67  |     }  | 
666  | 203  |   }  | 
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  | 67.7k  |   if ((MCInst_getOpcode(MI) == PPC_DCBT ||  | 
679  | 67.6k  |        MCInst_getOpcode(MI) == PPC_DCBTST) &&  | 
680  | 178  |       (!PPC_getFeatureBits(MI->csh->mode, PPC_FeatureModernAIXAs))) { | 
681  | 178  |     unsigned char TH = MCOperand_getImm(MCInst_getOperand(MI, (0)));  | 
682  | 178  |     SStream_concat0(O, "dcbt");  | 
683  | 178  |     if (MCInst_getOpcode(MI) == PPC_DCBTST)  | 
684  | 92  |       SStream_concat0(O, "st");  | 
685  | 178  |     if (TH == 16)  | 
686  | 34  |       SStream_concat0(O, "t");  | 
687  | 178  |     SStream_concat0(O, " ");  | 
688  |  |  | 
689  | 178  |     bool IsBookE =  | 
690  | 178  |       PPC_getFeatureBits(MI->csh->mode, PPC_FeatureBookE);  | 
691  | 178  |     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  | 178  |     set_mem_access(MI, true);  | 
697  | 178  |     printOperand(MI, 1, O);  | 
698  | 178  |     SStream_concat0(O, ", ");  | 
699  | 178  |     printOperand(MI, 2, O);  | 
700  | 178  |     set_mem_access(MI, false);  | 
701  |  |  | 
702  | 178  |     if (!IsBookE && TH != 0 && TH != 16) { | 
703  | 71  |       SStream_concat(O, "%s", ", ");  | 
704  | 71  |       printUInt32(O, (unsigned int)TH);  | 
705  | 71  |       PPC_set_detail_op_imm(MI, 0, TH);  | 
706  | 71  |     }  | 
707  |  |  | 
708  | 178  |     return;  | 
709  | 178  |   }  | 
710  |  |  | 
711  | 67.5k  |   if (MCInst_getOpcode(MI) == PPC_DCBF) { | 
712  | 1.02k  |     unsigned char L = MCOperand_getImm(MCInst_getOperand(MI, (0)));  | 
713  | 1.02k  |     if (!L || L == 1 || L == 3 || L == 4 || L == 6) { | 
714  | 686  |       SStream_concat0(O, "dcb");  | 
715  | 686  |       if (L != 6)  | 
716  | 297  |         SStream_concat0(O, "f");  | 
717  | 686  |       if (L == 1)  | 
718  | 70  |         SStream_concat0(O, "l");  | 
719  | 686  |       if (L == 3)  | 
720  | 67  |         SStream_concat0(O, "lp");  | 
721  | 686  |       if (L == 4)  | 
722  | 87  |         SStream_concat0(O, "ps");  | 
723  | 686  |       if (L == 6)  | 
724  | 389  |         SStream_concat0(O, "stps");  | 
725  | 686  |       SStream_concat0(O, " ");  | 
726  |  |  | 
727  | 686  |       printOperand(MI, 1, O);  | 
728  | 686  |       SStream_concat0(O, ", ");  | 
729  | 686  |       printOperand(MI, 2, O);  | 
730  |  |  | 
731  | 686  |       return;  | 
732  | 686  |     }  | 
733  | 1.02k  |   }  | 
734  |  |  | 
735  |  |   // isAlias/useAliasDetails could have been set before.  | 
736  | 66.8k  |   useAliasDetails |= map_use_alias_details(MI);  | 
737  | 66.8k  |   map_set_fill_detail_ops(MI, useAliasDetails);  | 
738  | 66.8k  |   isAlias |= printAliasInstr(MI, Address, O);  | 
739  | 66.8k  |   MCInst_setIsAlias(MI, isAlias);  | 
740  |  |  | 
741  | 66.8k  |   if (!isAlias || !useAliasDetails) { | 
742  | 56.9k  |     map_set_fill_detail_ops(MI, true);  | 
743  | 56.9k  |     if (isAlias)  | 
744  | 0  |       SStream_Close(O);  | 
745  | 56.9k  |     printInstruction(MI, Address, O);  | 
746  | 56.9k  |     if (isAlias)  | 
747  | 0  |       SStream_Open(O);  | 
748  | 56.9k  |   }  | 
749  | 66.8k  | }  | 
750  |  |  | 
751  |  | const char *PPC_LLVM_getRegisterName(unsigned RegNo)  | 
752  | 44.1k  | { | 
753  | 44.1k  |   return getRegisterName(RegNo);  | 
754  | 44.1k  | }  | 
755  |  |  | 
756  |  | void PPC_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot,  | 
757  |  |       SStream *O)  | 
758  | 68.0k  | { | 
759  | 68.0k  |   printInst(MI, Address, Annot, O);  | 
760  | 68.0k  | }  |