/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 | 1.84k | { |
117 | 1.84k | MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, PPC_REG_ENDING, 0, 0, |
118 | 1.84k | PPCMCRegisterClasses, |
119 | 1.84k | ARR_SIZE(PPCMCRegisterClasses), 0, 0, |
120 | 1.84k | PPCRegDiffLists, 0, PPCSubRegIdxLists, |
121 | 1.84k | ARR_SIZE(PPCSubRegIdxLists), |
122 | 1.84k | PPCRegEncodingTable); |
123 | 1.84k | } |
124 | | |
125 | | const char *PPC_reg_name(csh handle, unsigned int reg) |
126 | 35.1k | { |
127 | 35.1k | if (reg > PPC_REG_INVALID && reg < PPC_REG_ENDING) |
128 | 35.1k | return PPC_LLVM_getRegisterName(reg); |
129 | 0 | return NULL; |
130 | 35.1k | } |
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 | 39.1k | { |
135 | | // We do this after Instruction disassembly. |
136 | 39.1k | } |
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 | 39.1k | { |
156 | 39.1k | #ifndef CAPSTONE_DIET |
157 | 39.1k | 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 | 39.1k | if (id >= PPC_INS_ENDING) |
164 | 0 | return NULL; |
165 | | |
166 | 39.1k | return insn_name_maps[id]; |
167 | | #else |
168 | | return NULL; |
169 | | #endif |
170 | 39.1k | } |
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 | 22.0k | { |
191 | 22.0k | #ifndef CAPSTONE_DIET |
192 | 22.0k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
193 | | #else |
194 | | return NULL; |
195 | | #endif |
196 | 22.0k | } |
197 | | |
198 | | const insn_map ppc_insns[] = { |
199 | | #include "PPCGenCSMappingInsn.inc" |
200 | | }; |
201 | | |
202 | | void PPC_check_updates_cr0(MCInst *MI) |
203 | 40.0k | { |
204 | 40.0k | #ifndef CAPSTONE_DIET |
205 | 40.0k | if (!detail_is_set(MI)) |
206 | 0 | return; |
207 | 40.0k | cs_detail *detail = get_detail(MI); |
208 | 54.3k | for (int i = 0; i < detail->regs_write_count; ++i) { |
209 | 16.3k | if (detail->regs_write[i] == 0) |
210 | 0 | return; |
211 | 16.3k | if (detail->regs_write[i] == PPC_REG_CR0) { |
212 | 2.01k | PPC_get_detail(MI)->update_cr0 = true; |
213 | 2.01k | return; |
214 | 2.01k | } |
215 | 16.3k | } |
216 | 40.0k | #endif // CAPSTONE_DIET |
217 | 40.0k | } |
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 | 40.0k | { |
223 | 40.0k | if (!detail_is_set(MI)) |
224 | 0 | return; |
225 | 40.0k | #ifndef CAPSTONE_DIET |
226 | 40.0k | CS_ASSERT_RET(MI && Bytes); |
227 | 40.0k | if (BytesLen < 4) |
228 | 620 | return; |
229 | | |
230 | 39.4k | ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form; |
231 | 39.4k | bool b_form = ppc_is_b_form(form); |
232 | 39.4k | if (!(b_form || form == PPC_INSN_FORM_XLFORM_2)) |
233 | 32.1k | return; |
234 | | |
235 | 7.22k | uint32_t Inst = readBytes32(MI, Bytes); |
236 | | |
237 | 7.22k | uint8_t bi = 0; |
238 | 7.22k | if (b_form) |
239 | 6.60k | bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16; |
240 | 623 | else |
241 | 623 | bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16; |
242 | | |
243 | 7.22k | uint8_t bo = 0; |
244 | 7.22k | if (b_form) |
245 | 6.60k | bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21; |
246 | 623 | else |
247 | 623 | bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21; |
248 | | |
249 | 7.22k | PPC_get_detail(MI)->bc.bo = bo; |
250 | 7.22k | PPC_get_detail(MI)->bc.bi = bi; |
251 | 7.22k | PPC_get_detail(MI)->bc.crX_bit = bi % 4; |
252 | 7.22k | PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4); |
253 | 7.22k | PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo); |
254 | 7.22k | PPC_get_detail(MI)->bc.pred_cr = PPC_get_branch_pred(bi, bo, true); |
255 | 7.22k | PPC_get_detail(MI)->bc.pred_ctr = PPC_get_branch_pred(bi, bo, false); |
256 | | |
257 | 7.22k | if (ppc_is_b_form(form)) |
258 | 6.60k | return; |
259 | | |
260 | 623 | uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11; |
261 | 623 | uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1; |
262 | | // Pre-defined values for XO fields (PowerISA v3.1B) |
263 | 623 | uint16_t bcctr_xo_field = 528; |
264 | 623 | uint16_t bctar_xo_field = 560; |
265 | 623 | bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field); |
266 | 623 | switch (bh) { |
267 | 0 | default: |
268 | 0 | CS_ASSERT_RET(0 && "Invalid BH value."); |
269 | 276 | case 0: |
270 | 276 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_NO_SUBROUTINE_RET : |
271 | 276 | PPC_BH_SUBROUTINE_RET; |
272 | 276 | break; |
273 | 168 | case 1: |
274 | 168 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_RESERVED : |
275 | 168 | PPC_BH_NO_SUBROUTINE_RET; |
276 | 168 | break; |
277 | 128 | case 2: |
278 | 128 | PPC_get_detail(MI)->bc.bh = PPC_BH_RESERVED; |
279 | 128 | break; |
280 | 51 | case 3: |
281 | 51 | PPC_get_detail(MI)->bc.bh = PPC_BH_NOT_PREDICTABLE; |
282 | 51 | break; |
283 | 623 | } |
284 | 623 | #endif // CAPSTONE_DIET |
285 | 623 | } |
286 | | |
287 | | void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen) |
288 | 40.0k | { |
289 | 40.0k | map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns)); |
290 | 40.0k | map_implicit_reads(MI, ppc_insns); |
291 | 40.0k | map_implicit_writes(MI, ppc_insns); |
292 | 40.0k | map_groups(MI, ppc_insns); |
293 | 40.0k | PPC_add_branch_predicates(MI, Bytes, BytesLen); |
294 | 40.0k | PPC_check_updates_cr0(MI); |
295 | 40.0k | const ppc_suppl_info *suppl_info = map_get_suppl_info(MI, ppc_insns); |
296 | 40.0k | if (suppl_info) { |
297 | 40.0k | PPC_get_detail(MI)->format = suppl_info->form; |
298 | 40.0k | } |
299 | 40.0k | } |
300 | | |
301 | | /// Initialize PPCs detail. |
302 | | void PPC_init_cs_detail(MCInst *MI) |
303 | 40.0k | { |
304 | 40.0k | if (!detail_is_set(MI)) |
305 | 0 | return; |
306 | 40.0k | memset(get_detail(MI), 0, offsetof(cs_detail, ppc) + sizeof(cs_ppc)); |
307 | 40.0k | PPC_get_detail(MI)->bc.bi = UINT8_MAX; |
308 | 40.0k | PPC_get_detail(MI)->bc.bo = UINT8_MAX; |
309 | 40.0k | PPC_get_detail(MI)->bc.crX = PPC_REG_INVALID; |
310 | 40.0k | PPC_get_detail(MI)->bc.crX_bit = PPC_BI_INVALID; |
311 | 40.0k | PPC_get_detail(MI)->bc.pred_cr = PPC_PRED_INVALID; |
312 | 40.0k | PPC_get_detail(MI)->bc.pred_ctr = PPC_PRED_INVALID; |
313 | 40.0k | PPC_get_detail(MI)->bc.hint = PPC_BR_NOT_GIVEN; |
314 | 40.0k | PPC_get_detail(MI)->bc.bh = PPC_BH_INVALID; |
315 | 40.0k | } |
316 | | |
317 | | void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) |
318 | 39.1k | { |
319 | 39.1k | MI->MRI = (MCRegisterInfo *)info; |
320 | 39.1k | MI->fillDetailOps = detail_is_set(MI); |
321 | 39.1k | MI->flat_insn->usesAliasDetails = map_use_alias_details(MI); |
322 | 39.1k | PPC_LLVM_printInst(MI, MI->address, "", O); |
323 | 39.1k | #ifndef CAPSTONE_DIET |
324 | 39.1k | map_set_alias_id(MI, O, insn_alias_mnem_map, |
325 | 39.1k | ARR_SIZE(insn_alias_mnem_map)); |
326 | 39.1k | #endif |
327 | 39.1k | } |
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 | 40.0k | { |
333 | 40.0k | PPC_init_cs_detail(instr); |
334 | 40.0k | DecodeStatus result = PPC_LLVM_getInstruction( |
335 | 40.0k | handle, bytes, bytes_len, instr, size, address, info); |
336 | 40.0k | PPC_set_instr_map_data(instr, bytes, bytes_len); |
337 | 40.0k | return result != MCDisassembler_Fail; |
338 | 40.0k | } |
339 | | |
340 | | bool PPC_getFeatureBits(unsigned int mode, unsigned int feature) |
341 | 174k | { |
342 | 174k | if (feature == PPC_FeatureQPX) { |
343 | 43.4k | return (mode & CS_MODE_QPX) != 0; |
344 | 131k | } else if (feature == PPC_FeatureSPE) { |
345 | 22.0k | return (mode & CS_MODE_SPE) != 0; |
346 | 109k | } else if (feature == PPC_FeatureBookE) { |
347 | 377 | return (mode & CS_MODE_BOOKE) != 0; |
348 | 109k | } else if (feature == PPC_FeaturePS) { |
349 | 22.8k | return (mode & CS_MODE_PS) != 0; |
350 | 86.2k | } else if (feature == PPC_FeatureModernAIXAs) { |
351 | 39.6k | return (mode & CS_MODE_MODERN_AIX_AS) != 0; |
352 | 46.5k | } else if (feature == PPC_AIXOS) { |
353 | 190 | return (mode & CS_MODE_AIX_OS) != 0 || (mode & CS_MODE_MODERN_AIX_AS) != 0; |
354 | 46.3k | } else if (feature == PPC_FeatureMSYNC) { |
355 | 4 | return (mode & CS_MODE_MSYNC) != 0; |
356 | 4 | } |
357 | 46.3k | 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 | 46.3k | return true; |
360 | 46.3k | } |
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 | 13.2k | { |
393 | 13.2k | 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 | 13.2k | bool is_off_reg = |
400 | 13.2k | ((op_type == CS_OP_REG) && |
401 | 13.2k | PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID); |
402 | 13.2k | PPC_set_detail_op_mem(MI, OpNum, MCInst_getOpVal(MI, OpNum), |
403 | 13.2k | is_off_reg); |
404 | 13.2k | } |
405 | | |
406 | | static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group, |
407 | | unsigned OpNum) |
408 | 121k | { |
409 | 121k | if (!detail_is_set(MI)) |
410 | 0 | return; |
411 | | |
412 | 121k | switch (op_group) { |
413 | 0 | default: |
414 | 0 | printf("General operand group %d not handled!\n", op_group); |
415 | 0 | return; |
416 | 76.0k | case PPC_OP_GROUP_Operand: { |
417 | 76.0k | cs_op_type op_type = map_get_op_type(MI, OpNum); |
418 | | |
419 | | // Check for memory operands emitted via printOperand() |
420 | 76.0k | if (doing_mem(MI) && !(op_type & CS_OP_MEM)) { |
421 | | // Close previous memory operand |
422 | 200 | set_mem_access(MI, false); |
423 | 75.8k | } else if (doing_mem(MI) || (op_type & CS_OP_MEM)) { |
424 | | // The memory operands use printOperand() to |
425 | | // emit their register and immediates. |
426 | 13.2k | if (!doing_mem(MI)) |
427 | 572 | set_mem_access(MI, true); |
428 | 13.2k | handle_memory_operand(MI, OpNum); |
429 | 13.2k | return; |
430 | 13.2k | } |
431 | | |
432 | 62.8k | CS_ASSERT_RET((op_type & CS_OP_MEM) == |
433 | 62.8k | 0); // doing_mem should have been true. |
434 | | |
435 | 62.8k | if (op_type == CS_OP_REG) |
436 | 62.0k | PPC_set_detail_op_reg(MI, OpNum, |
437 | 62.0k | MCInst_getOpVal(MI, OpNum)); |
438 | 727 | else if (op_type == CS_OP_IMM) |
439 | 727 | PPC_set_detail_op_imm(MI, OpNum, |
440 | 727 | MCInst_getOpVal(MI, OpNum)); |
441 | 0 | else |
442 | 0 | CS_ASSERT_RET(0 && "Operand type not handled."); |
443 | 62.8k | break; |
444 | 76.0k | } |
445 | 70 | case PPC_OP_GROUP_ImmZeroOperand: |
446 | 1.32k | case PPC_OP_GROUP_U1ImmOperand: |
447 | 1.76k | case PPC_OP_GROUP_U2ImmOperand: |
448 | 2.72k | case PPC_OP_GROUP_U3ImmOperand: |
449 | 3.19k | case PPC_OP_GROUP_U4ImmOperand: |
450 | 11.6k | case PPC_OP_GROUP_U5ImmOperand: |
451 | 12.9k | case PPC_OP_GROUP_U6ImmOperand: |
452 | 13.0k | case PPC_OP_GROUP_U7ImmOperand: |
453 | 13.1k | case PPC_OP_GROUP_U8ImmOperand: |
454 | 13.1k | case PPC_OP_GROUP_U10ImmOperand: |
455 | 13.4k | case PPC_OP_GROUP_U12ImmOperand: |
456 | 13.4k | PPC_set_detail_op_imm(MI, OpNum, |
457 | 13.4k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
458 | 13.4k | break; |
459 | 2.18k | case PPC_OP_GROUP_U16ImmOperand: |
460 | 2.18k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
461 | | // Handled in printOperand() |
462 | 0 | return; |
463 | 2.18k | PPC_set_detail_op_imm(MI, OpNum, |
464 | 2.18k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
465 | 2.18k | break; |
466 | 109 | case PPC_OP_GROUP_S5ImmOperand: { |
467 | 109 | int Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
468 | 109 | Imm = SignExtend32((Imm), 5); |
469 | 109 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
470 | 109 | break; |
471 | 2.18k | } |
472 | 502 | case PPC_OP_GROUP_S12ImmOperand: { |
473 | 502 | int64_t Imm = SignExtend64( |
474 | 502 | MCOperand_getImm(MCInst_getOperand(MI, (OpNum))), 12); |
475 | 502 | if (doing_mem(MI)) { |
476 | 502 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
477 | 502 | break; |
478 | 502 | } |
479 | 0 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
480 | 0 | break; |
481 | 502 | } |
482 | 11.8k | case PPC_OP_GROUP_S16ImmOperand: { |
483 | 11.8k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
484 | | // Handled in printOperand() |
485 | 0 | return; |
486 | 11.8k | int16_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
487 | 11.8k | if (doing_mem(MI)) { |
488 | 8.08k | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
489 | 8.08k | break; |
490 | 8.08k | } |
491 | 3.73k | PPC_set_detail_op_imm(MI, OpNum, Imm); |
492 | 3.73k | break; |
493 | 11.8k | } |
494 | 339 | case PPC_OP_GROUP_S34ImmOperand: { |
495 | 339 | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
496 | | // Handled in printOperand() |
497 | 0 | return; |
498 | 339 | int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
499 | 339 | if (doing_mem(MI)) { |
500 | 215 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
501 | 215 | break; |
502 | 215 | } |
503 | 124 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
504 | 124 | break; |
505 | 339 | } |
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 | 339 | } |
511 | 1.58k | case PPC_OP_GROUP_AbsBranchOperand: { |
512 | 1.58k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
513 | | // Handled in printOperand() |
514 | 0 | return; |
515 | 1.58k | unsigned Val = MCInst_getOpVal(MI, OpNum) << 2; |
516 | 1.58k | PPC_check_safe_inc(MI); |
517 | 1.58k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
518 | 1.58k | PPC_get_detail_op(MI, 0)->imm = Val; |
519 | 1.58k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
520 | 1.58k | PPC_inc_op_count(MI); |
521 | 1.58k | break; |
522 | 1.58k | } |
523 | 0 | case PPC_OP_GROUP_TLSCall: |
524 | | // Handled in PPCInstPrinter and printOperand. |
525 | 0 | return; |
526 | 100 | case PPC_OP_GROUP_crbitm: { |
527 | 100 | unsigned CCReg = MCInst_getOpVal(MI, OpNum); |
528 | 100 | PPC_set_detail_op_reg(MI, OpNum, CCReg); |
529 | 100 | break; |
530 | 1.58k | } |
531 | 5.74k | case PPC_OP_GROUP_BranchOperand: { |
532 | 5.74k | if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNum)))) |
533 | | // Handled in printOperand() |
534 | 0 | return; |
535 | 5.74k | int32_t Imm = SignExtend32( |
536 | 5.74k | ((unsigned)MCInst_getOpVal(MI, (OpNum)) << 2), 32); |
537 | 5.74k | uint64_t Address = MI->address + Imm; |
538 | 5.74k | if (IS_32BIT(MI->csh->mode)) |
539 | 1.42k | Address &= 0xffffffff; |
540 | 5.74k | PPC_check_safe_inc(MI); |
541 | 5.74k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
542 | 5.74k | PPC_get_detail_op(MI, 0)->imm = Address; |
543 | 5.74k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
544 | 5.74k | PPC_inc_op_count(MI); |
545 | 5.74k | break; |
546 | 5.74k | } |
547 | | // Memory operands have their `set_mem_access()` calls |
548 | | // in PPCInstPrinter. |
549 | 8.08k | case PPC_OP_GROUP_MemRegImm: |
550 | 9.48k | 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 | 9.48k | unsigned OpNumReg = 0; |
555 | 9.48k | if (op_group == PPC_OP_GROUP_MemRegImm) |
556 | 8.08k | OpNumReg = OpNum + 1; |
557 | 1.40k | else |
558 | 1.40k | OpNumReg = OpNum; |
559 | | |
560 | 9.48k | MCOperand *Op = MCInst_getOperand(MI, OpNumReg); |
561 | 9.48k | 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 | 9.48k | break; |
568 | 8.08k | } |
569 | 23 | case PPC_OP_GROUP_MemRegImmHash: |
570 | 173 | case PPC_OP_GROUP_MemRegImm34: |
571 | 238 | case PPC_OP_GROUP_MemRegImm34PCRel: |
572 | | // Handled in other printOperand functions. |
573 | 238 | break; |
574 | 121k | } |
575 | 121k | } |
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 | 121k | { |
613 | 121k | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
614 | 0 | return; |
615 | | |
616 | 121k | switch (op_group) { |
617 | 0 | default: |
618 | 0 | printf("Operand group %d not handled!\n", op_group); |
619 | 0 | return; |
620 | 502 | case PPC_OP_GROUP_S12ImmOperand: |
621 | 76.5k | case PPC_OP_GROUP_Operand: |
622 | 77.9k | case PPC_OP_GROUP_MemRegReg: |
623 | 79.2k | case PPC_OP_GROUP_U6ImmOperand: |
624 | 87.7k | case PPC_OP_GROUP_U5ImmOperand: |
625 | 95.8k | case PPC_OP_GROUP_MemRegImm: |
626 | 107k | case PPC_OP_GROUP_S16ImmOperand: |
627 | 108k | case PPC_OP_GROUP_U2ImmOperand: |
628 | 110k | case PPC_OP_GROUP_U16ImmOperand: |
629 | 116k | case PPC_OP_GROUP_BranchOperand: |
630 | 117k | case PPC_OP_GROUP_AbsBranchOperand: |
631 | 118k | case PPC_OP_GROUP_U1ImmOperand: |
632 | 118k | case PPC_OP_GROUP_TLSCall: |
633 | 119k | case PPC_OP_GROUP_U3ImmOperand: |
634 | 119k | case PPC_OP_GROUP_S5ImmOperand: |
635 | 119k | case PPC_OP_GROUP_MemRegImmHash: |
636 | 120k | case PPC_OP_GROUP_U4ImmOperand: |
637 | 120k | case PPC_OP_GROUP_U10ImmOperand: |
638 | 120k | case PPC_OP_GROUP_crbitm: |
639 | 120k | case PPC_OP_GROUP_S34ImmOperand: |
640 | 120k | case PPC_OP_GROUP_ImmZeroOperand: |
641 | 121k | case PPC_OP_GROUP_MemRegImm34: |
642 | 121k | case PPC_OP_GROUP_MemRegImm34PCRel: |
643 | 121k | case PPC_OP_GROUP_U8ImmOperand: |
644 | 121k | case PPC_OP_GROUP_U12ImmOperand: |
645 | 121k | case PPC_OP_GROUP_U7ImmOperand: |
646 | 121k | case PPC_OP_GROUP_ATBitsAsHint: { |
647 | 121k | add_cs_detail_general(MI, op_group, OpNo); |
648 | 121k | return; |
649 | 121k | } |
650 | 121k | } |
651 | 121k | } |
652 | | |
653 | | void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val, |
654 | | bool is_off_reg) |
655 | 22.0k | { |
656 | 22.0k | if (!detail_is_set(MI)) |
657 | 0 | return; |
658 | | |
659 | 22.0k | CS_ASSERT_RET(map_get_op_type(MI, OpNum) & CS_OP_MEM); |
660 | 22.0k | cs_op_type secondary_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
661 | | |
662 | 22.0k | switch (secondary_type) { |
663 | 0 | default: |
664 | 0 | CS_ASSERT_RET(0 && "Secondary type not supported yet."); |
665 | 13.2k | case CS_OP_REG: |
666 | 13.2k | if (is_off_reg) { |
667 | 2.13k | PPC_get_detail_op(MI, 0)->mem.offset = Val; |
668 | 2.13k | if (PPC_get_detail_op(MI, 0)->mem.base != |
669 | 2.13k | PPC_REG_INVALID) |
670 | 2.13k | set_mem_access(MI, false); |
671 | 11.0k | } else { |
672 | 11.0k | PPC_get_detail_op(MI, 0)->mem.base = Val; |
673 | 11.0k | if (MCInst_opIsTying(MI, OpNum)) |
674 | 0 | map_add_implicit_write( |
675 | 0 | MI, MCInst_getOpVal(MI, OpNum)); |
676 | 11.0k | } |
677 | 13.2k | break; |
678 | 8.79k | case CS_OP_IMM: |
679 | 8.79k | PPC_get_detail_op(MI, 0)->mem.disp = Val; |
680 | 8.79k | if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID) |
681 | 0 | set_mem_access(MI, false); |
682 | 8.79k | break; |
683 | 22.0k | } |
684 | | |
685 | 22.0k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
686 | 22.0k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
687 | 22.0k | } |
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 | 62.1k | { |
693 | 62.1k | if (!detail_is_set(MI)) |
694 | 0 | return; |
695 | 62.1k | PPC_check_safe_inc(MI); |
696 | 62.1k | CS_ASSERT_RET(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
697 | 62.1k | CS_ASSERT_RET(map_get_op_type(MI, OpNum) == CS_OP_REG); |
698 | | |
699 | 62.1k | PPC_get_detail_op(MI, 0)->type = PPC_OP_REG; |
700 | 62.1k | PPC_get_detail_op(MI, 0)->reg = Reg; |
701 | 62.1k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
702 | 62.1k | PPC_inc_op_count(MI); |
703 | 62.1k | } |
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 | 20.5k | { |
709 | 20.5k | if (!detail_is_set(MI)) |
710 | 0 | return; |
711 | 20.5k | PPC_check_safe_inc(MI); |
712 | 20.5k | CS_ASSERT_RET(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
713 | 20.5k | CS_ASSERT_RET(map_get_op_type(MI, OpNum) == CS_OP_IMM); |
714 | | |
715 | 20.5k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
716 | 20.5k | PPC_get_detail_op(MI, 0)->imm = Imm; |
717 | 20.5k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
718 | 20.5k | PPC_inc_op_count(MI); |
719 | 20.5k | } |
720 | | |
721 | | void PPC_set_mem_access(MCInst *MI, bool status) |
722 | 24.0k | { |
723 | 24.0k | if (!detail_is_set(MI)) |
724 | 0 | return; |
725 | 24.0k | PPC_check_safe_inc(MI); |
726 | 24.0k | if ((!status && !doing_mem(MI)) || (status && doing_mem(MI))) |
727 | 1.76k | return; // Nothing to do |
728 | | |
729 | 22.3k | set_doing_mem(MI, status); |
730 | 22.3k | if (status) { |
731 | 11.1k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
732 | 11.1k | PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_INVALID; |
733 | 11.1k | PPC_get_detail_op(MI, 0)->mem.offset = PPC_REG_INVALID; |
734 | 11.1k | PPC_get_detail_op(MI, 0)->mem.disp = 0; |
735 | | |
736 | 11.1k | #ifndef CAPSTONE_DIET |
737 | 11.1k | uint8_t access = |
738 | 11.1k | map_get_op_access(MI, PPC_get_detail(MI)->op_count); |
739 | 11.1k | PPC_get_detail_op(MI, 0)->access = access; |
740 | 11.1k | #endif |
741 | 11.1k | } else { |
742 | | // done, select the next operand slot |
743 | 11.1k | PPC_inc_op_count(MI); |
744 | 11.1k | } |
745 | 22.3k | } |
746 | | |
747 | | void PPC_setup_op(cs_ppc_op *op) |
748 | 117 | { |
749 | 117 | memset(op, 0, sizeof(cs_ppc_op)); |
750 | 117 | op->type = PPC_OP_INVALID; |
751 | 117 | } |
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 | 117 | { |
758 | 117 | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
759 | 0 | return; |
760 | | |
761 | 117 | PPC_check_safe_inc(MI); |
762 | | |
763 | 117 | cs_ppc_op op; |
764 | 117 | PPC_setup_op(&op); |
765 | 117 | op.type = PPC_OP_IMM; |
766 | 117 | op.imm = Val; |
767 | 117 | op.access = access; |
768 | | |
769 | 117 | cs_ppc_op *ops = PPC_get_detail(MI)->operands; |
770 | 117 | int i = PPC_get_detail(MI)->op_count - 1; |
771 | 117 | for (; i >= index; --i) { |
772 | 0 | ops[i + 1] = ops[i]; |
773 | 0 | if (i == index) |
774 | 0 | break; |
775 | 0 | } |
776 | 117 | ops[index] = op; |
777 | 117 | PPC_inc_op_count(MI); |
778 | 117 | } |
779 | | |
780 | | #endif |