/src/capstonenext/arch/PowerPC/PPCMapping.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */ |
3 | | |
4 | | #include "capstone/capstone.h" |
5 | | #ifdef CAPSTONE_HAS_POWERPC |
6 | | |
7 | | #include <stdio.h> // debug |
8 | | #include <string.h> |
9 | | |
10 | | #include "../../cs_simple_types.h" |
11 | | #include "../../Mapping.h" |
12 | | #include "../../MCDisassembler.h" |
13 | | #include "../../utils.h" |
14 | | |
15 | | #include "PPCLinkage.h" |
16 | | #include "PPCMapping.h" |
17 | | #include "PPCMCTargetDesc.h" |
18 | | |
19 | | static int P7InheritableFeatures[] = { |
20 | | PPC_DirectivePwr7, PPC_FeatureAltivec, |
21 | | PPC_FeatureVSX, PPC_FeatureMFOCRF, |
22 | | PPC_FeatureFCPSGN, PPC_FeatureFSqrt, |
23 | | PPC_FeatureFRE, PPC_FeatureFRES, |
24 | | PPC_FeatureFRSQRTE, PPC_FeatureFRSQRTES, |
25 | | PPC_FeatureRecipPrec, PPC_FeatureSTFIWX, |
26 | | PPC_FeatureLFIWAX, PPC_FeatureFPRND, |
27 | | PPC_FeatureFPCVT, PPC_FeatureISEL, |
28 | | PPC_FeaturePOPCNTD, PPC_FeatureCMPB, |
29 | | PPC_FeatureLDBRX, PPC_Feature64Bit, |
30 | | PPC_FeatureBPERMD, PPC_FeatureExtDiv, |
31 | | PPC_FeatureMFTB, PPC_DeprecatedDST, |
32 | | PPC_FeatureTwoConstNR, PPC_FeatureUnalignedFloats, |
33 | | PPC_FeatureISA2_06, INT_MAX |
34 | | }; |
35 | | |
36 | | static int *P7Features[] = { P7InheritableFeatures }; |
37 | | |
38 | | // Power8 |
39 | | static int P8AdditionalFeatures[] = { PPC_DirectivePwr8, |
40 | | PPC_FeatureP8Altivec, |
41 | | PPC_FeatureP8Vector, |
42 | | PPC_FeatureP8Crypto, |
43 | | PPC_FeatureHTM, |
44 | | PPC_FeatureDirectMove, |
45 | | PPC_FeatureICBT, |
46 | | PPC_FeaturePartwordAtomic, |
47 | | PPC_FeatureQuadwordAtomic, |
48 | | PPC_FeaturePredictableSelectIsExpensive, |
49 | | PPC_FeatureISA2_07, |
50 | | PPC_FeatureCRBits, |
51 | | INT_MAX }; |
52 | | |
53 | | static int P8SpecificFeatures[] = { PPC_FeatureAddiLoadFusion, |
54 | | PPC_FeatureAddisLoadFusion, INT_MAX }; |
55 | | |
56 | | static int *P8Features[] = { P7InheritableFeatures, P8AdditionalFeatures, |
57 | | P8SpecificFeatures }; |
58 | | |
59 | | static int P9AdditionalFeatures[] = { PPC_DirectivePwr9, |
60 | | PPC_FeatureP9Altivec, |
61 | | PPC_FeatureP9Vector, |
62 | | PPC_FeaturePPCPreRASched, |
63 | | PPC_FeaturePPCPostRASched, |
64 | | PPC_FeatureISA3_0, |
65 | | PPC_FeaturePredictableSelectIsExpensive, |
66 | | INT_MAX }; |
67 | | |
68 | | static int P9SpecificFeatures[] = { PPC_FeatureVectorsUseTwoUnits, INT_MAX }; |
69 | | |
70 | | static int *P9Features[] = { P7InheritableFeatures, P8AdditionalFeatures, |
71 | | P9AdditionalFeatures, P9SpecificFeatures }; |
72 | | |
73 | | static int P10AdditionalFeatures[] = { PPC_FeatureStoreFusion, |
74 | | PPC_FeatureAddLogicalFusion, |
75 | | PPC_FeatureLogicalAddFusion, |
76 | | PPC_FeatureLogicalFusion, |
77 | | PPC_FeatureArithAddFusion, |
78 | | PPC_FeatureSha3Fusion, |
79 | | PPC_DirectivePwr10, |
80 | | PPC_FeatureISA3_1, |
81 | | PPC_FeaturePrefixInstrs, |
82 | | PPC_FeaturePCRelativeMemops, |
83 | | PPC_FeatureP10Vector, |
84 | | PPC_FeatureMMA, |
85 | | PPC_FeaturePairedVectorMemops, |
86 | | PPC_FeatureFastMFLR, |
87 | | INT_MAX }; |
88 | | |
89 | | static int *P10Features[] = { P7InheritableFeatures, P8AdditionalFeatures, |
90 | | P9AdditionalFeatures, P10AdditionalFeatures }; |
91 | | |
92 | | static int FutureAdditionalFeatures[] = { PPC_FeatureISAFuture, INT_MAX }; |
93 | | |
94 | | static int *FutureFeatures[] = { P7InheritableFeatures, P8AdditionalFeatures, |
95 | | P9AdditionalFeatures, P10AdditionalFeatures, |
96 | | FutureAdditionalFeatures }; |
97 | | |
98 | | static inline bool is_feature_of(int feature, int **feature_set, int set_size) |
99 | 0 | { |
100 | 0 | for (size_t i = 0; i < set_size; ++i) { |
101 | 0 | size_t j = 0; |
102 | 0 | while (feature_set[i][j] != INT_MAX) { |
103 | 0 | if (feature == feature_set[i][j]) { |
104 | 0 | return true; |
105 | 0 | } |
106 | 0 | ++j; |
107 | 0 | } |
108 | 0 | } |
109 | 0 | return false; |
110 | 0 | } |
111 | | |
112 | | #define GET_REGINFO_MC_DESC |
113 | | #include "PPCGenRegisterInfo.inc" |
114 | | |
115 | | void PPC_init_mri(MCRegisterInfo *MRI) |
116 | 2.25k | { |
117 | 2.25k | MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, PPC_REG_ENDING, 0, 0, |
118 | 2.25k | PPCMCRegisterClasses, |
119 | 2.25k | ARR_SIZE(PPCMCRegisterClasses), 0, 0, |
120 | 2.25k | PPCRegDiffLists, 0, PPCSubRegIdxLists, |
121 | 2.25k | ARR_SIZE(PPCSubRegIdxLists), |
122 | 2.25k | PPCRegEncodingTable); |
123 | 2.25k | } |
124 | | |
125 | | const char *PPC_reg_name(csh handle, unsigned int reg) |
126 | 38.4k | { |
127 | 38.4k | if (reg > PPC_REG_INVALID && reg < PPC_REG_ENDING) |
128 | 38.4k | return PPC_LLVM_getRegisterName(reg); |
129 | 0 | return NULL; |
130 | 38.4k | } |
131 | | |
132 | | // given internal insn id, return public instruction info |
133 | | void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) |
134 | 47.6k | { |
135 | | // We do this after Instruction disassembly. |
136 | 47.6k | } |
137 | | |
138 | | #ifndef CAPSTONE_DIET |
139 | | |
140 | | static const char *const insn_name_maps[] = { |
141 | | #include "PPCGenCSMappingInsnName.inc" |
142 | | }; |
143 | | |
144 | | static const name_map insn_alias_mnem_map[] = { |
145 | | #include "PPCGenCSAliasMnemMap.inc" |
146 | | { PPC_INS_ALIAS_SLWI, "slwi" }, |
147 | | { PPC_INS_ALIAS_SRWI, "srwi" }, |
148 | | { PPC_INS_ALIAS_SLDI, "sldi" }, |
149 | | { PPC_INS_ALIAS_END, NULL }, |
150 | | }; |
151 | | |
152 | | #endif |
153 | | |
154 | | const char *PPC_insn_name(csh handle, unsigned int id) |
155 | 47.6k | { |
156 | 47.6k | #ifndef CAPSTONE_DIET |
157 | 47.6k | if (id < PPC_INS_ALIAS_END && id > PPC_INS_ALIAS_BEGIN) { |
158 | 0 | if (id - PPC_INS_ALIAS_BEGIN >= ARR_SIZE(insn_alias_mnem_map)) |
159 | 0 | return NULL; |
160 | | |
161 | 0 | return insn_alias_mnem_map[id - PPC_INS_ALIAS_BEGIN - 1].name; |
162 | 0 | } |
163 | 47.6k | if (id >= PPC_INS_ENDING) |
164 | 0 | return NULL; |
165 | | |
166 | 47.6k | return insn_name_maps[id]; |
167 | | #else |
168 | | return NULL; |
169 | | #endif |
170 | 47.6k | } |
171 | | |
172 | | #ifndef CAPSTONE_DIET |
173 | | static const name_map group_name_maps[] = { |
174 | | // generic groups |
175 | | { PPC_GRP_INVALID, NULL }, |
176 | | { PPC_GRP_JUMP, "jump" }, |
177 | | { PPC_GRP_CALL, "call" }, |
178 | | { PPC_GRP_RET, "ret" }, |
179 | | { PPC_GRP_INT, "int" }, |
180 | | { PPC_GRP_IRET, "iret" }, |
181 | | { PPC_GRP_PRIVILEGE, "privilege" }, |
182 | | { PPC_GRP_BRANCH_RELATIVE, "branch_relative" }, |
183 | | |
184 | | // architecture-specific groups |
185 | | #include "PPCGenCSFeatureName.inc" |
186 | | }; |
187 | | #endif |
188 | | |
189 | | const char *PPC_group_name(csh handle, unsigned int id) |
190 | 51.1k | { |
191 | 51.1k | #ifndef CAPSTONE_DIET |
192 | 51.1k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
193 | | #else |
194 | | return NULL; |
195 | | #endif |
196 | 51.1k | } |
197 | | |
198 | | const insn_map ppc_insns[] = { |
199 | | #include "PPCGenCSMappingInsn.inc" |
200 | | }; |
201 | | |
202 | | void PPC_check_updates_cr0(MCInst *MI) |
203 | 48.9k | { |
204 | 48.9k | #ifndef CAPSTONE_DIET |
205 | 48.9k | if (!detail_is_set(MI)) |
206 | 0 | return; |
207 | 48.9k | cs_detail *detail = get_detail(MI); |
208 | 64.0k | for (int i = 0; i < detail->regs_write_count; ++i) { |
209 | 17.5k | if (detail->regs_write[i] == 0) |
210 | 0 | return; |
211 | 17.5k | if (detail->regs_write[i] == PPC_REG_CR0) { |
212 | 2.42k | PPC_get_detail(MI)->update_cr0 = true; |
213 | 2.42k | return; |
214 | 2.42k | } |
215 | 17.5k | } |
216 | 48.9k | #endif // CAPSTONE_DIET |
217 | 48.9k | } |
218 | | |
219 | | /// Parses and adds the branch predicate information and the BH field. |
220 | | static void PPC_add_branch_predicates(MCInst *MI, const uint8_t *Bytes, |
221 | | size_t BytesLen) |
222 | 48.9k | { |
223 | 48.9k | if (!detail_is_set(MI)) |
224 | 0 | return; |
225 | 48.9k | #ifndef CAPSTONE_DIET |
226 | 48.9k | CS_ASSERT_RET(MI && Bytes); |
227 | 48.9k | if (BytesLen < 4) |
228 | 748 | return; |
229 | | |
230 | 48.1k | ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form; |
231 | 48.1k | bool b_form = ppc_is_b_form(form); |
232 | 48.1k | if (!(b_form || form == PPC_INSN_FORM_XLFORM_2)) |
233 | 40.5k | return; |
234 | | |
235 | 7.66k | uint32_t Inst = readBytes32(MI, Bytes); |
236 | | |
237 | 7.66k | uint8_t bi = 0; |
238 | 7.66k | if (b_form) |
239 | 6.76k | bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16; |
240 | 905 | else |
241 | 905 | bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16; |
242 | | |
243 | 7.66k | uint8_t bo = 0; |
244 | 7.66k | if (b_form) |
245 | 6.76k | bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21; |
246 | 905 | else |
247 | 905 | bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21; |
248 | | |
249 | 7.66k | PPC_get_detail(MI)->bc.bo = bo; |
250 | 7.66k | PPC_get_detail(MI)->bc.bi = bi; |
251 | 7.66k | PPC_get_detail(MI)->bc.crX_bit = bi % 4; |
252 | 7.66k | PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4); |
253 | 7.66k | PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo); |
254 | 7.66k | PPC_get_detail(MI)->bc.pred_cr = PPC_get_branch_pred(bi, bo, true); |
255 | 7.66k | PPC_get_detail(MI)->bc.pred_ctr = PPC_get_branch_pred(bi, bo, false); |
256 | | |
257 | 7.66k | if (ppc_is_b_form(form)) |
258 | 6.76k | return; |
259 | | |
260 | 905 | uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11; |
261 | 905 | uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1; |
262 | | // Pre-defined values for XO fields (PowerISA v3.1B) |
263 | 905 | uint16_t bcctr_xo_field = 528; |
264 | 905 | uint16_t bctar_xo_field = 560; |
265 | 905 | bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field); |
266 | 905 | switch (bh) { |
267 | 0 | default: |
268 | 0 | CS_ASSERT_RET(0 && "Invalid BH value."); |
269 | 286 | case 0: |
270 | 286 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_NO_SUBROUTINE_RET : |
271 | 286 | PPC_BH_SUBROUTINE_RET; |
272 | 286 | break; |
273 | 427 | case 1: |
274 | 427 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_RESERVED : |
275 | 427 | PPC_BH_NO_SUBROUTINE_RET; |
276 | 427 | break; |
277 | 129 | case 2: |
278 | 129 | PPC_get_detail(MI)->bc.bh = PPC_BH_RESERVED; |
279 | 129 | break; |
280 | 63 | case 3: |
281 | 63 | PPC_get_detail(MI)->bc.bh = PPC_BH_NOT_PREDICTABLE; |
282 | 63 | break; |
283 | 905 | } |
284 | 905 | #endif // CAPSTONE_DIET |
285 | 905 | } |
286 | | |
287 | | void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen) |
288 | 48.9k | { |
289 | 48.9k | map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns)); |
290 | 48.9k | map_implicit_reads(MI, ppc_insns); |
291 | 48.9k | map_implicit_writes(MI, ppc_insns); |
292 | 48.9k | map_groups(MI, ppc_insns); |
293 | 48.9k | PPC_add_branch_predicates(MI, Bytes, BytesLen); |
294 | 48.9k | PPC_check_updates_cr0(MI); |
295 | 48.9k | const ppc_suppl_info *suppl_info = map_get_suppl_info(MI, ppc_insns); |
296 | 48.9k | if (suppl_info) { |
297 | 48.9k | PPC_get_detail(MI)->format = suppl_info->form; |
298 | 48.9k | } |
299 | 48.9k | } |
300 | | |
301 | | /// Initialize PPCs detail. |
302 | | void PPC_init_cs_detail(MCInst *MI) |
303 | 48.9k | { |
304 | 48.9k | if (!detail_is_set(MI)) |
305 | 0 | return; |
306 | 48.9k | memset(get_detail(MI), 0, offsetof(cs_detail, ppc) + sizeof(cs_ppc)); |
307 | 48.9k | PPC_get_detail(MI)->bc.bi = UINT8_MAX; |
308 | 48.9k | PPC_get_detail(MI)->bc.bo = UINT8_MAX; |
309 | 48.9k | PPC_get_detail(MI)->bc.crX = PPC_REG_INVALID; |
310 | 48.9k | PPC_get_detail(MI)->bc.crX_bit = PPC_BI_INVALID; |
311 | 48.9k | PPC_get_detail(MI)->bc.pred_cr = PPC_PRED_INVALID; |
312 | 48.9k | PPC_get_detail(MI)->bc.pred_ctr = PPC_PRED_INVALID; |
313 | 48.9k | PPC_get_detail(MI)->bc.hint = PPC_BR_NOT_GIVEN; |
314 | 48.9k | PPC_get_detail(MI)->bc.bh = PPC_BH_INVALID; |
315 | 48.9k | } |
316 | | |
317 | | void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) |
318 | 47.6k | { |
319 | 47.6k | MI->MRI = (MCRegisterInfo *)info; |
320 | 47.6k | MI->fillDetailOps = detail_is_set(MI); |
321 | 47.6k | MI->flat_insn->usesAliasDetails = map_use_alias_details(MI); |
322 | 47.6k | PPC_LLVM_printInst(MI, MI->address, "", O); |
323 | 47.6k | #ifndef CAPSTONE_DIET |
324 | 47.6k | map_set_alias_id(MI, O, insn_alias_mnem_map, |
325 | 47.6k | ARR_SIZE(insn_alias_mnem_map)); |
326 | 47.6k | #endif |
327 | 47.6k | } |
328 | | |
329 | | bool PPC_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len, |
330 | | MCInst *instr, uint16_t *size, uint64_t address, |
331 | | void *info) |
332 | 48.9k | { |
333 | 48.9k | PPC_init_cs_detail(instr); |
334 | 48.9k | DecodeStatus result = PPC_LLVM_getInstruction( |
335 | 48.9k | handle, bytes, bytes_len, instr, size, address, info); |
336 | 48.9k | PPC_set_instr_map_data(instr, bytes, bytes_len); |
337 | 48.9k | return result != MCDisassembler_Fail; |
338 | 48.9k | } |
339 | | |
340 | | bool PPC_getFeatureBits(unsigned int mode, unsigned int feature) |
341 | 213k | { |
342 | 213k | if (feature == PPC_FeatureQPX) { |
343 | 52.7k | return (mode & CS_MODE_QPX) != 0; |
344 | 161k | } else if (feature == PPC_FeatureSPE) { |
345 | 26.6k | return (mode & CS_MODE_SPE) != 0; |
346 | 134k | } else if (feature == PPC_FeatureBookE) { |
347 | 741 | return (mode & CS_MODE_BOOKE) != 0; |
348 | 133k | } else if (feature == PPC_FeaturePS) { |
349 | 27.7k | return (mode & CS_MODE_PS) != 0; |
350 | 106k | } else if (feature == PPC_FeatureModernAIXAs) { |
351 | 48.5k | return (mode & CS_MODE_MODERN_AIX_AS) != 0; |
352 | 57.4k | } else if (feature == PPC_AIXOS) { |
353 | 191 | return (mode & CS_MODE_AIX_OS) != 0 || (mode & CS_MODE_MODERN_AIX_AS) != 0; |
354 | 57.2k | } else if (feature == PPC_FeatureMSYNC) { |
355 | 21 | return (mode & CS_MODE_MSYNC) != 0; |
356 | 21 | } |
357 | 57.2k | if ((mode & (CS_MODE_PWR7 | CS_MODE_PWR8 | CS_MODE_PWR9 | CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE)) == 0) { |
358 | | // By default support everything |
359 | 57.2k | return true; |
360 | 57.2k | } |
361 | | |
362 | 0 | if (is_feature_of(feature, P7Features, ARR_SIZE(P7Features))) { |
363 | 0 | return (mode & (CS_MODE_PWR7 | CS_MODE_PWR8 | CS_MODE_PWR9 | CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE)); |
364 | 0 | } |
365 | 0 | if (is_feature_of(feature, P8Features, ARR_SIZE(P8Features))) { |
366 | 0 | return (mode & (CS_MODE_PWR8 | CS_MODE_PWR9 | CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE)); |
367 | 0 | } |
368 | 0 | if (is_feature_of(feature, P9Features, ARR_SIZE(P9Features))) { |
369 | 0 | return (mode & (CS_MODE_PWR9 | CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE)); |
370 | 0 | } |
371 | 0 | if (is_feature_of(feature, P10Features, ARR_SIZE(P10Features))) { |
372 | 0 | return (mode & (CS_MODE_PWR10 | CS_MODE_PPC_ISA_FUTURE)); |
373 | 0 | } |
374 | 0 | if (is_feature_of(feature, FutureFeatures, ARR_SIZE(FutureFeatures))) { |
375 | 0 | return (mode & CS_MODE_PPC_ISA_FUTURE); |
376 | 0 | } |
377 | | |
378 | | // By default support everything |
379 | 0 | return true; |
380 | 0 | } |
381 | | |
382 | | #ifndef CAPSTONE_DIET |
383 | | static const map_insn_ops insn_operands[] = { |
384 | | #include "PPCGenCSMappingInsnOp.inc" |
385 | | }; |
386 | | #endif |
387 | | |
388 | | /// @brief Handles memory operands. |
389 | | /// @param MI The MCInst. |
390 | | /// @param OpNum The operand index. |
391 | | static void handle_memory_operand(MCInst *MI, unsigned OpNum) |
392 | 16.5k | { |
393 | 16.5k | cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
394 | | |
395 | | // If this is called from printOperand() we do not know if a |
396 | | // register is a base or an offset reg (imm is always disponent). |
397 | | // So we assume the base register is always added before the offset register |
398 | | // and set the flag appropriately. |
399 | 16.5k | bool is_off_reg = |
400 | 16.5k | ((op_type == CS_OP_REG) && |
401 | 16.5k | PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID); |
402 | 16.5k | PPC_set_detail_op_mem(MI, OpNum, MCInst_getOpVal(MI, OpNum), |
403 | 16.5k | is_off_reg); |
404 | 16.5k | } |
405 | | |
406 | | static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group, |
407 | | unsigned OpNum) |
408 | 149k | { |
409 | 149k | if (!detail_is_set(MI)) |
410 | 0 | return; |
411 | | |
412 | 149k | switch (op_group) { |
413 | 0 | default: |
414 | 0 | printf("General operand group %d not handled!\n", op_group); |
415 | 0 | return; |
416 | 95.7k | case PPC_OP_GROUP_Operand: { |
417 | 95.7k | cs_op_type op_type = map_get_op_type(MI, OpNum); |
418 | | |
419 | | // Check for memory operands emitted via printOperand() |
420 | 95.7k | if (doing_mem(MI) && !(op_type & CS_OP_MEM)) { |
421 | | // Close previous memory operand |
422 | 300 | set_mem_access(MI, false); |
423 | 95.4k | } else if (doing_mem(MI) || (op_type & CS_OP_MEM)) { |
424 | | // The memory operands use printOperand() to |
425 | | // emit their register and immediates. |
426 | 16.5k | if (!doing_mem(MI)) |
427 | 797 | set_mem_access(MI, true); |
428 | 16.5k | handle_memory_operand(MI, OpNum); |
429 | 16.5k | return; |
430 | 16.5k | } |
431 | | |
432 | 79.2k | CS_ASSERT_RET((op_type & CS_OP_MEM) == |
433 | 79.2k | 0); // doing_mem should have been true. |
434 | | |
435 | 79.2k | if (op_type == CS_OP_REG) |
436 | 78.1k | PPC_set_detail_op_reg(MI, OpNum, |
437 | 78.1k | MCInst_getOpVal(MI, OpNum)); |
438 | 1.09k | else if (op_type == CS_OP_IMM) |
439 | 1.09k | PPC_set_detail_op_imm(MI, OpNum, |
440 | 1.09k | MCInst_getOpVal(MI, OpNum)); |
441 | 0 | else |
442 | 0 | CS_ASSERT_RET(0 && "Operand type not handled."); |
443 | 79.2k | break; |
444 | 95.7k | } |
445 | 94 | case PPC_OP_GROUP_ImmZeroOperand: |
446 | 2.30k | case PPC_OP_GROUP_U1ImmOperand: |
447 | 2.88k | case PPC_OP_GROUP_U2ImmOperand: |
448 | 4.06k | case PPC_OP_GROUP_U3ImmOperand: |
449 | 4.75k | case PPC_OP_GROUP_U4ImmOperand: |
450 | 14.8k | case PPC_OP_GROUP_U5ImmOperand: |
451 | 16.7k | case PPC_OP_GROUP_U6ImmOperand: |
452 | 16.8k | case PPC_OP_GROUP_U7ImmOperand: |
453 | 16.9k | case PPC_OP_GROUP_U8ImmOperand: |
454 | 16.9k | case PPC_OP_GROUP_U10ImmOperand: |
455 | 17.3k | case PPC_OP_GROUP_U12ImmOperand: |
456 | 17.3k | PPC_set_detail_op_imm(MI, OpNum, |
457 | 17.3k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
458 | 17.3k | break; |
459 | 2.61k | case PPC_OP_GROUP_U16ImmOperand: |
460 | 2.61k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
461 | | // Handled in printOperand() |
462 | 0 | return; |
463 | 2.61k | PPC_set_detail_op_imm(MI, OpNum, |
464 | 2.61k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
465 | 2.61k | break; |
466 | 178 | case PPC_OP_GROUP_S5ImmOperand: { |
467 | 178 | int Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
468 | 178 | Imm = SignExtend32((Imm), 5); |
469 | 178 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
470 | 178 | break; |
471 | 2.61k | } |
472 | 675 | case PPC_OP_GROUP_S12ImmOperand: { |
473 | 675 | int64_t Imm = SignExtend64( |
474 | 675 | MCOperand_getImm(MCInst_getOperand(MI, (OpNum))), 12); |
475 | 675 | if (doing_mem(MI)) { |
476 | 675 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
477 | 675 | break; |
478 | 675 | } |
479 | 0 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
480 | 0 | break; |
481 | 675 | } |
482 | 13.6k | case PPC_OP_GROUP_S16ImmOperand: { |
483 | 13.6k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
484 | | // Handled in printOperand() |
485 | 0 | return; |
486 | 13.6k | int16_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
487 | 13.6k | if (doing_mem(MI)) { |
488 | 9.01k | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
489 | 9.01k | break; |
490 | 9.01k | } |
491 | 4.60k | PPC_set_detail_op_imm(MI, OpNum, Imm); |
492 | 4.60k | break; |
493 | 13.6k | } |
494 | 418 | case PPC_OP_GROUP_S34ImmOperand: { |
495 | 418 | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
496 | | // Handled in printOperand() |
497 | 0 | return; |
498 | 418 | int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
499 | 418 | if (doing_mem(MI)) { |
500 | 279 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
501 | 279 | break; |
502 | 279 | } |
503 | 139 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
504 | 139 | break; |
505 | 418 | } |
506 | 0 | case PPC_OP_GROUP_ATBitsAsHint: { |
507 | 0 | PPC_get_detail(MI)->bc.hint = |
508 | 0 | (ppc_br_hint)MCInst_getOpVal(MI, OpNum); |
509 | 0 | break; |
510 | 418 | } |
511 | 2.24k | case PPC_OP_GROUP_AbsBranchOperand: { |
512 | 2.24k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
513 | | // Handled in printOperand() |
514 | 0 | return; |
515 | 2.24k | unsigned Val = MCInst_getOpVal(MI, OpNum) << 2; |
516 | 2.24k | PPC_check_safe_inc(MI); |
517 | 2.24k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
518 | 2.24k | PPC_get_detail_op(MI, 0)->imm = Val; |
519 | 2.24k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
520 | 2.24k | PPC_inc_op_count(MI); |
521 | 2.24k | break; |
522 | 2.24k | } |
523 | 0 | case PPC_OP_GROUP_TLSCall: |
524 | | // Handled in PPCInstPrinter and printOperand. |
525 | 0 | return; |
526 | 141 | case PPC_OP_GROUP_crbitm: { |
527 | 141 | unsigned CCReg = MCInst_getOpVal(MI, OpNum); |
528 | 141 | PPC_set_detail_op_reg(MI, OpNum, CCReg); |
529 | 141 | break; |
530 | 2.24k | } |
531 | 5.33k | case PPC_OP_GROUP_BranchOperand: { |
532 | 5.33k | if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNum)))) |
533 | | // Handled in printOperand() |
534 | 0 | return; |
535 | 5.33k | int32_t Imm = SignExtend32( |
536 | 5.33k | ((unsigned)MCInst_getOpVal(MI, (OpNum)) << 2), 32); |
537 | 5.33k | uint64_t Address = MI->address + Imm; |
538 | 5.33k | if (IS_32BIT(MI->csh->mode)) |
539 | 1.71k | Address &= 0xffffffff; |
540 | 5.33k | PPC_check_safe_inc(MI); |
541 | 5.33k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
542 | 5.33k | PPC_get_detail_op(MI, 0)->imm = Address; |
543 | 5.33k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
544 | 5.33k | PPC_inc_op_count(MI); |
545 | 5.33k | break; |
546 | 5.33k | } |
547 | | // Memory operands have their `set_mem_access()` calls |
548 | | // in PPCInstPrinter. |
549 | 9.01k | case PPC_OP_GROUP_MemRegImm: |
550 | 10.9k | case PPC_OP_GROUP_MemRegReg: { |
551 | | // These cases print 0 if the base register is R0. |
552 | | // So no printOperand() function is called. |
553 | | // We must handle the zero case here. |
554 | 10.9k | unsigned OpNumReg = 0; |
555 | 10.9k | if (op_group == PPC_OP_GROUP_MemRegImm) |
556 | 9.01k | OpNumReg = OpNum + 1; |
557 | 1.97k | else |
558 | 1.97k | OpNumReg = OpNum; |
559 | | |
560 | 10.9k | MCOperand *Op = MCInst_getOperand(MI, OpNumReg); |
561 | 10.9k | if (MCOperand_isReg(Op) && MCOperand_getReg(Op) == PPC_R0) { |
562 | 0 | PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_ZERO; |
563 | 0 | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
564 | 0 | PPC_get_detail_op(MI, 0)->access = |
565 | 0 | map_get_op_access(MI, OpNum); |
566 | 0 | } |
567 | 10.9k | break; |
568 | 9.01k | } |
569 | 41 | case PPC_OP_GROUP_MemRegImmHash: |
570 | 236 | case PPC_OP_GROUP_MemRegImm34: |
571 | 320 | case PPC_OP_GROUP_MemRegImm34PCRel: |
572 | | // Handled in other printOperand functions. |
573 | 320 | break; |
574 | 149k | } |
575 | 149k | } |
576 | | |
577 | | void PPC_add_cs_detail_1(MCInst *MI, ppc_op_group op_group, unsigned OpNum, |
578 | | const char *Modifier) |
579 | 0 | { |
580 | 0 | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
581 | 0 | return; |
582 | | |
583 | 0 | switch (op_group) { |
584 | 0 | default: |
585 | 0 | printf("Operand group %d not handled!\n", op_group); |
586 | 0 | return; |
587 | 0 | case PPC_OP_GROUP_PredicateOperand: { |
588 | 0 | if ((strcmp(Modifier, "cc") == 0) || |
589 | 0 | (strcmp(Modifier, "pm") == 0)) { |
590 | 0 | unsigned Val = MCInst_getOpVal(MI, OpNum); |
591 | 0 | unsigned bo = Val & 0x1f; |
592 | 0 | unsigned bi = (Val & 0x1e0) >> 5; |
593 | 0 | PPC_get_detail(MI)->bc.bo = bo; |
594 | 0 | PPC_get_detail(MI)->bc.bi = bi; |
595 | 0 | PPC_get_detail(MI)->bc.crX_bit = bi % 4; |
596 | 0 | PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4); |
597 | 0 | PPC_get_detail(MI)->bc.pred_cr = |
598 | 0 | PPC_get_branch_pred(bi, bo, true); |
599 | 0 | PPC_get_detail(MI)->bc.pred_ctr = |
600 | 0 | PPC_get_branch_pred(bi, bo, false); |
601 | 0 | PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo); |
602 | 0 | } |
603 | 0 | return; |
604 | 0 | } |
605 | 0 | } |
606 | 0 | } |
607 | | |
608 | | /// Fills cs_detail with the data of the operand. |
609 | | /// Calls to this function should not be added by hand! Please checkout the |
610 | | /// patch `AddCSDetail` of the CppTranslator. |
611 | | void PPC_add_cs_detail_0(MCInst *MI, ppc_op_group op_group, unsigned OpNo) |
612 | 149k | { |
613 | 149k | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
614 | 0 | return; |
615 | | |
616 | 149k | switch (op_group) { |
617 | 0 | default: |
618 | 0 | printf("Operand group %d not handled!\n", op_group); |
619 | 0 | return; |
620 | 675 | case PPC_OP_GROUP_S12ImmOperand: |
621 | 96.4k | case PPC_OP_GROUP_Operand: |
622 | 98.4k | case PPC_OP_GROUP_MemRegReg: |
623 | 100k | case PPC_OP_GROUP_U6ImmOperand: |
624 | 110k | case PPC_OP_GROUP_U5ImmOperand: |
625 | 119k | case PPC_OP_GROUP_MemRegImm: |
626 | 133k | case PPC_OP_GROUP_S16ImmOperand: |
627 | 133k | case PPC_OP_GROUP_U2ImmOperand: |
628 | 136k | case PPC_OP_GROUP_U16ImmOperand: |
629 | 141k | case PPC_OP_GROUP_BranchOperand: |
630 | 143k | case PPC_OP_GROUP_AbsBranchOperand: |
631 | 146k | case PPC_OP_GROUP_U1ImmOperand: |
632 | 146k | case PPC_OP_GROUP_TLSCall: |
633 | 147k | case PPC_OP_GROUP_U3ImmOperand: |
634 | 147k | case PPC_OP_GROUP_S5ImmOperand: |
635 | 147k | case PPC_OP_GROUP_MemRegImmHash: |
636 | 148k | case PPC_OP_GROUP_U4ImmOperand: |
637 | 148k | case PPC_OP_GROUP_U10ImmOperand: |
638 | 148k | case PPC_OP_GROUP_crbitm: |
639 | 148k | case PPC_OP_GROUP_S34ImmOperand: |
640 | 148k | case PPC_OP_GROUP_ImmZeroOperand: |
641 | 149k | case PPC_OP_GROUP_MemRegImm34: |
642 | 149k | case PPC_OP_GROUP_MemRegImm34PCRel: |
643 | 149k | case PPC_OP_GROUP_U8ImmOperand: |
644 | 149k | case PPC_OP_GROUP_U12ImmOperand: |
645 | 149k | case PPC_OP_GROUP_U7ImmOperand: |
646 | 149k | case PPC_OP_GROUP_ATBitsAsHint: { |
647 | 149k | add_cs_detail_general(MI, op_group, OpNo); |
648 | 149k | return; |
649 | 149k | } |
650 | 149k | } |
651 | 149k | } |
652 | | |
653 | | void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val, |
654 | | bool is_off_reg) |
655 | 26.5k | { |
656 | 26.5k | if (!detail_is_set(MI)) |
657 | 0 | return; |
658 | | |
659 | 26.5k | CS_ASSERT_RET(map_get_op_type(MI, OpNum) & CS_OP_MEM); |
660 | 26.5k | cs_op_type secondary_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
661 | | |
662 | 26.5k | switch (secondary_type) { |
663 | 0 | default: |
664 | 0 | CS_ASSERT_RET(0 && "Secondary type not supported yet."); |
665 | 16.5k | case CS_OP_REG: |
666 | 16.5k | if (is_off_reg) { |
667 | 3.16k | PPC_get_detail_op(MI, 0)->mem.offset = Val; |
668 | 3.16k | if (PPC_get_detail_op(MI, 0)->mem.base != |
669 | 3.16k | PPC_REG_INVALID) |
670 | 3.16k | set_mem_access(MI, false); |
671 | 13.3k | } else { |
672 | 13.3k | PPC_get_detail_op(MI, 0)->mem.base = Val; |
673 | 13.3k | if (MCInst_opIsTying(MI, OpNum)) |
674 | 0 | map_add_implicit_write( |
675 | 0 | MI, MCInst_getOpVal(MI, OpNum)); |
676 | 13.3k | } |
677 | 16.5k | break; |
678 | 9.97k | case CS_OP_IMM: |
679 | 9.97k | PPC_get_detail_op(MI, 0)->mem.disp = Val; |
680 | 9.97k | if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID) |
681 | 0 | set_mem_access(MI, false); |
682 | 9.97k | break; |
683 | 26.5k | } |
684 | | |
685 | 26.5k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
686 | 26.5k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
687 | 26.5k | } |
688 | | |
689 | | /// Adds a register PPC operand at position OpNum and increases the op_count by |
690 | | /// one. |
691 | | void PPC_set_detail_op_reg(MCInst *MI, unsigned OpNum, ppc_reg Reg) |
692 | 78.2k | { |
693 | 78.2k | if (!detail_is_set(MI)) |
694 | 0 | return; |
695 | 78.2k | PPC_check_safe_inc(MI); |
696 | 78.2k | CS_ASSERT_RET(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
697 | 78.2k | CS_ASSERT_RET(map_get_op_type(MI, OpNum) == CS_OP_REG); |
698 | | |
699 | 78.2k | PPC_get_detail_op(MI, 0)->type = PPC_OP_REG; |
700 | 78.2k | PPC_get_detail_op(MI, 0)->reg = Reg; |
701 | 78.2k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
702 | 78.2k | PPC_inc_op_count(MI); |
703 | 78.2k | } |
704 | | |
705 | | /// Adds an immediate PPC operand at position OpNum and increases the op_count |
706 | | /// by one. |
707 | | void PPC_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm) |
708 | 26.4k | { |
709 | 26.4k | if (!detail_is_set(MI)) |
710 | 0 | return; |
711 | 26.4k | PPC_check_safe_inc(MI); |
712 | 26.4k | CS_ASSERT_RET(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
713 | 26.4k | CS_ASSERT_RET(map_get_op_type(MI, OpNum) == CS_OP_IMM); |
714 | | |
715 | 26.4k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
716 | 26.4k | PPC_get_detail_op(MI, 0)->imm = Imm; |
717 | 26.4k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
718 | 26.4k | PPC_inc_op_count(MI); |
719 | 26.4k | } |
720 | | |
721 | | void PPC_set_mem_access(MCInst *MI, bool status) |
722 | 29.6k | { |
723 | 29.6k | if (!detail_is_set(MI)) |
724 | 0 | return; |
725 | 29.6k | PPC_check_safe_inc(MI); |
726 | 29.6k | if ((!status && !doing_mem(MI)) || (status && doing_mem(MI))) |
727 | 2.67k | return; // Nothing to do |
728 | | |
729 | 26.9k | set_doing_mem(MI, status); |
730 | 26.9k | if (status) { |
731 | 13.4k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
732 | 13.4k | PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_INVALID; |
733 | 13.4k | PPC_get_detail_op(MI, 0)->mem.offset = PPC_REG_INVALID; |
734 | 13.4k | PPC_get_detail_op(MI, 0)->mem.disp = 0; |
735 | | |
736 | 13.4k | #ifndef CAPSTONE_DIET |
737 | 13.4k | uint8_t access = |
738 | 13.4k | map_get_op_access(MI, PPC_get_detail(MI)->op_count); |
739 | 13.4k | PPC_get_detail_op(MI, 0)->access = access; |
740 | 13.4k | #endif |
741 | 13.4k | } else { |
742 | | // done, select the next operand slot |
743 | 13.4k | PPC_inc_op_count(MI); |
744 | 13.4k | } |
745 | 26.9k | } |
746 | | |
747 | | void PPC_setup_op(cs_ppc_op *op) |
748 | 171 | { |
749 | 171 | memset(op, 0, sizeof(cs_ppc_op)); |
750 | 171 | op->type = PPC_OP_INVALID; |
751 | 171 | } |
752 | | |
753 | | /// Inserts a immediate to the detail operands at @index. |
754 | | /// Already present operands are moved. |
755 | | void PPC_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val, |
756 | | cs_ac_type access) |
757 | 171 | { |
758 | 171 | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
759 | 0 | return; |
760 | | |
761 | 171 | PPC_check_safe_inc(MI); |
762 | | |
763 | 171 | cs_ppc_op op; |
764 | 171 | PPC_setup_op(&op); |
765 | 171 | op.type = PPC_OP_IMM; |
766 | 171 | op.imm = Val; |
767 | 171 | op.access = access; |
768 | | |
769 | 171 | cs_ppc_op *ops = PPC_get_detail(MI)->operands; |
770 | 171 | int i = PPC_get_detail(MI)->op_count - 1; |
771 | 171 | for (; i >= index; --i) { |
772 | 0 | ops[i + 1] = ops[i]; |
773 | 0 | if (i == index) |
774 | 0 | break; |
775 | 0 | } |
776 | 171 | ops[index] = op; |
777 | 171 | PPC_inc_op_count(MI); |
778 | 171 | } |
779 | | |
780 | | #endif |