/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/ppc.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 | | #define GET_REGINFO_MC_DESC |
20 | | #include "PPCGenRegisterInfo.inc" |
21 | | |
22 | | void PPC_init_mri(MCRegisterInfo *MRI) |
23 | 1.92k | { |
24 | 1.92k | MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, PPC_REG_ENDING, 0, 0, |
25 | 1.92k | PPCMCRegisterClasses, |
26 | 1.92k | ARR_SIZE(PPCMCRegisterClasses), 0, 0, |
27 | 1.92k | PPCRegDiffLists, 0, PPCSubRegIdxLists, |
28 | 1.92k | ARR_SIZE(PPCSubRegIdxLists), |
29 | 1.92k | PPCRegEncodingTable); |
30 | 1.92k | } |
31 | | |
32 | | const char *PPC_reg_name(csh handle, unsigned int reg) |
33 | 36.6k | { |
34 | 36.6k | if (reg > PPC_REG_INVALID && reg < PPC_REG_ENDING) |
35 | 36.6k | return PPC_LLVM_getRegisterName(reg); |
36 | 0 | return NULL; |
37 | 36.6k | } |
38 | | |
39 | | // given internal insn id, return public instruction info |
40 | | void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) |
41 | 50.9k | { |
42 | | // We do this after Instruction disassembly. |
43 | 50.9k | } |
44 | | |
45 | | #ifndef CAPSTONE_DIET |
46 | | |
47 | | static const char *const insn_name_maps[] = { |
48 | | #include "PPCGenCSMappingInsnName.inc" |
49 | | }; |
50 | | |
51 | | static const name_map insn_alias_mnem_map[] = { |
52 | | #include "PPCGenCSAliasMnemMap.inc" |
53 | | { PPC_INS_ALIAS_SLWI, "slwi" }, |
54 | | { PPC_INS_ALIAS_SRWI, "srwi" }, |
55 | | { PPC_INS_ALIAS_SLDI, "sldi" }, |
56 | | { PPC_INS_ALIAS_END, NULL }, |
57 | | }; |
58 | | |
59 | | #endif |
60 | | |
61 | | const char *PPC_insn_name(csh handle, unsigned int id) |
62 | 50.9k | { |
63 | 50.9k | #ifndef CAPSTONE_DIET |
64 | 50.9k | if (id < PPC_INS_ALIAS_END && id > PPC_INS_ALIAS_BEGIN) { |
65 | 0 | if (id - PPC_INS_ALIAS_BEGIN >= ARR_SIZE(insn_alias_mnem_map)) |
66 | 0 | return NULL; |
67 | | |
68 | 0 | return insn_alias_mnem_map[id - PPC_INS_ALIAS_BEGIN - 1].name; |
69 | 0 | } |
70 | 50.9k | if (id >= PPC_INS_ENDING) |
71 | 0 | return NULL; |
72 | | |
73 | 50.9k | return insn_name_maps[id]; |
74 | | #else |
75 | | return NULL; |
76 | | #endif |
77 | 50.9k | } |
78 | | |
79 | | #ifndef CAPSTONE_DIET |
80 | | static const name_map group_name_maps[] = { |
81 | | // generic groups |
82 | | { PPC_GRP_INVALID, NULL }, |
83 | | { PPC_GRP_JUMP, "jump" }, |
84 | | { PPC_GRP_CALL, "call" }, |
85 | | { PPC_GRP_INT, "int" }, |
86 | | { PPC_GRP_PRIVILEGE, "privilege" }, |
87 | | { PPC_GRP_BRANCH_RELATIVE, "branch_relative" }, |
88 | | |
89 | | // architecture-specific groups |
90 | | #include "PPCGenCSFeatureName.inc" |
91 | | }; |
92 | | #endif |
93 | | |
94 | | const char *PPC_group_name(csh handle, unsigned int id) |
95 | 43.7k | { |
96 | 43.7k | #ifndef CAPSTONE_DIET |
97 | 43.7k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
98 | | #else |
99 | | return NULL; |
100 | | #endif |
101 | 43.7k | } |
102 | | |
103 | | const insn_map ppc_insns[] = { |
104 | | #include "PPCGenCSMappingInsn.inc" |
105 | | }; |
106 | | |
107 | | void PPC_check_updates_cr0(MCInst *MI) |
108 | 52.2k | { |
109 | 52.2k | #ifndef CAPSTONE_DIET |
110 | 52.2k | if (!detail_is_set(MI)) |
111 | 0 | return; |
112 | 52.2k | cs_detail *detail = get_detail(MI); |
113 | 65.2k | for (int i = 0; i < detail->regs_write_count; ++i) { |
114 | 15.7k | if (detail->regs_write[i] == 0) |
115 | 0 | return; |
116 | 15.7k | if (detail->regs_write[i] == PPC_REG_CR0) { |
117 | 2.77k | PPC_get_detail(MI)->update_cr0 = true; |
118 | 2.77k | return; |
119 | 2.77k | } |
120 | 15.7k | } |
121 | 52.2k | #endif // CAPSTONE_DIET |
122 | 52.2k | } |
123 | | |
124 | | /// Parses and adds the branch predicate information and the BH field. |
125 | | static void PPC_add_branch_predicates(MCInst *MI, const uint8_t *Bytes, |
126 | | size_t BytesLen) |
127 | 52.2k | { |
128 | 52.2k | if (!detail_is_set(MI)) |
129 | 0 | return; |
130 | 52.2k | #ifndef CAPSTONE_DIET |
131 | 52.2k | assert(MI && Bytes); |
132 | 52.2k | if (BytesLen < 4) |
133 | 711 | return; |
134 | | |
135 | 51.5k | ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form; |
136 | 51.5k | bool b_form = ppc_is_b_form(form); |
137 | 51.5k | if (!(b_form || form == PPC_INSN_FORM_XLFORM_2)) |
138 | 43.8k | return; |
139 | | |
140 | 7.65k | uint32_t Inst = readBytes32(MI, Bytes); |
141 | | |
142 | 7.65k | uint8_t bi = 0; |
143 | 7.65k | if (b_form) |
144 | 7.52k | bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16; |
145 | 133 | else |
146 | 133 | bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16; |
147 | | |
148 | 7.65k | uint8_t bo = 0; |
149 | 7.65k | if (b_form) |
150 | 7.52k | bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21; |
151 | 133 | else |
152 | 133 | bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21; |
153 | | |
154 | 7.65k | PPC_get_detail(MI)->bc.bo = bo; |
155 | 7.65k | PPC_get_detail(MI)->bc.bi = bi; |
156 | 7.65k | PPC_get_detail(MI)->bc.crX_bit = bi % 4; |
157 | 7.65k | PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4); |
158 | 7.65k | PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo); |
159 | 7.65k | PPC_get_detail(MI)->bc.pred_cr = PPC_get_branch_pred(bi, bo, true); |
160 | 7.65k | PPC_get_detail(MI)->bc.pred_ctr = PPC_get_branch_pred(bi, bo, false); |
161 | | |
162 | 7.65k | if (ppc_is_b_form(form)) |
163 | 7.52k | return; |
164 | | |
165 | 133 | uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11; |
166 | 133 | uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1; |
167 | | // Pre-defined values for XO fields (PowerISA v3.1B) |
168 | 133 | uint16_t bcctr_xo_field = 528; |
169 | 133 | uint16_t bctar_xo_field = 560; |
170 | 133 | bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field); |
171 | 133 | switch (bh) { |
172 | 0 | default: |
173 | 0 | assert(0 && "Invalid BH value."); |
174 | 56 | case 0b00: |
175 | 56 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_NO_SUBROUTINE_RET : |
176 | 56 | PPC_BH_SUBROUTINE_RET; |
177 | 56 | break; |
178 | 56 | case 0b01: |
179 | 56 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_RESERVED : |
180 | 56 | PPC_BH_NO_SUBROUTINE_RET; |
181 | 56 | break; |
182 | 11 | case 0b10: |
183 | 11 | PPC_get_detail(MI)->bc.bh = PPC_BH_RESERVED; |
184 | 11 | break; |
185 | 10 | case 0b11: |
186 | 10 | PPC_get_detail(MI)->bc.bh = PPC_BH_NOT_PREDICTABLE; |
187 | 10 | break; |
188 | 133 | } |
189 | 133 | #endif // CAPSTONE_DIET |
190 | 133 | } |
191 | | |
192 | | void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen) |
193 | 52.2k | { |
194 | 52.2k | map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns)); |
195 | 52.2k | map_implicit_reads(MI, ppc_insns); |
196 | 52.2k | map_implicit_writes(MI, ppc_insns); |
197 | 52.2k | map_groups(MI, ppc_insns); |
198 | 52.2k | PPC_add_branch_predicates(MI, Bytes, BytesLen); |
199 | 52.2k | PPC_check_updates_cr0(MI); |
200 | 52.2k | } |
201 | | |
202 | | /// Inialize PPCs detail. |
203 | | void PPC_init_cs_detail(MCInst *MI) |
204 | 52.2k | { |
205 | 52.2k | if (!detail_is_set(MI)) |
206 | 0 | return; |
207 | 52.2k | memset(get_detail(MI), 0, offsetof(cs_detail, ppc) + sizeof(cs_ppc)); |
208 | 52.2k | PPC_get_detail(MI)->bc.bi = UINT8_MAX; |
209 | 52.2k | PPC_get_detail(MI)->bc.bo = UINT8_MAX; |
210 | 52.2k | PPC_get_detail(MI)->bc.crX = PPC_REG_INVALID; |
211 | 52.2k | PPC_get_detail(MI)->bc.crX_bit = PPC_BI_INVALID; |
212 | 52.2k | PPC_get_detail(MI)->bc.pred_cr = PPC_PRED_INVALID; |
213 | 52.2k | PPC_get_detail(MI)->bc.pred_ctr = PPC_PRED_INVALID; |
214 | 52.2k | PPC_get_detail(MI)->bc.hint = PPC_BR_NOT_GIVEN; |
215 | 52.2k | PPC_get_detail(MI)->bc.bh = PPC_BH_INVALID; |
216 | 52.2k | } |
217 | | |
218 | | void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) |
219 | 50.9k | { |
220 | 50.9k | MI->MRI = (MCRegisterInfo *)info; |
221 | 50.9k | MI->fillDetailOps = detail_is_set(MI); |
222 | 50.9k | MI->flat_insn->usesAliasDetails = map_use_alias_details(MI); |
223 | 50.9k | PPC_LLVM_printInst(MI, MI->address, "", O); |
224 | 50.9k | map_set_alias_id(MI, O, insn_alias_mnem_map, |
225 | 50.9k | ARR_SIZE(insn_alias_mnem_map)); |
226 | 50.9k | } |
227 | | |
228 | | bool PPC_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len, |
229 | | MCInst *instr, uint16_t *size, uint64_t address, |
230 | | void *info) |
231 | 52.2k | { |
232 | 52.2k | PPC_init_cs_detail(instr); |
233 | 52.2k | DecodeStatus result = PPC_LLVM_getInstruction( |
234 | 52.2k | handle, bytes, bytes_len, instr, size, address, info); |
235 | 52.2k | PPC_set_instr_map_data(instr, bytes, bytes_len); |
236 | 52.2k | return result != MCDisassembler_Fail; |
237 | 52.2k | } |
238 | | |
239 | | bool PPC_getFeatureBits(unsigned int mode, unsigned int feature) |
240 | 222k | { |
241 | 222k | if ((feature == PPC_FeatureQPX) && (mode & CS_MODE_QPX) == 0) { |
242 | 26.2k | return false; |
243 | 196k | } else if ((feature == PPC_FeatureSPE) && (mode & CS_MODE_SPE) == 0) { |
244 | 26.2k | return false; |
245 | 170k | } else if ((feature == PPC_FeatureBookE) && |
246 | 170k | (mode & CS_MODE_BOOKE) == 0) { |
247 | 120 | return false; |
248 | 170k | } else if ((feature == PPC_FeaturePS) && (mode & CS_MODE_PS) == 0) { |
249 | 15.8k | return false; |
250 | 15.8k | } |
251 | | |
252 | | // No AIX support for now. |
253 | 154k | if (feature == PPC_FeatureModernAIXAs || feature == PPC_AIXOS) |
254 | 51.2k | return false; |
255 | | // TODO Make it optional |
256 | 102k | if (feature == PPC_FeatureMSYNC) |
257 | 72 | return false; |
258 | | |
259 | | // By default support everything |
260 | 102k | return true; |
261 | 102k | } |
262 | | |
263 | | static const map_insn_ops insn_operands[] = { |
264 | | #include "PPCGenCSMappingInsnOp.inc" |
265 | | }; |
266 | | |
267 | | /// @brief Handles memory operands. |
268 | | /// @param MI The MCInst. |
269 | | /// @param OpNum The operand index. |
270 | | static void handle_memory_operand(MCInst *MI, unsigned OpNum) |
271 | 18.1k | { |
272 | 18.1k | cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
273 | | |
274 | | // If this is called from printOperand() we do not know if a |
275 | | // register is a base or an offset reg (imm is always disponent). |
276 | | // So we assume the base register is always added before the offset register |
277 | | // and set the flag appropriately. |
278 | 18.1k | bool is_off_reg = |
279 | 18.1k | ((op_type == CS_OP_REG) && |
280 | 18.1k | PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID); |
281 | 18.1k | PPC_set_detail_op_mem(MI, OpNum, MCInst_getOpVal(MI, OpNum), |
282 | 18.1k | is_off_reg); |
283 | 18.1k | } |
284 | | |
285 | | static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group, |
286 | | unsigned OpNum) |
287 | 162k | { |
288 | 162k | if (!detail_is_set(MI)) |
289 | 0 | return; |
290 | | |
291 | 162k | switch (op_group) { |
292 | 0 | default: |
293 | 0 | printf("General operand group %d not handled!\n", op_group); |
294 | 0 | return; |
295 | 100k | case PPC_OP_GROUP_Operand: { |
296 | 100k | cs_op_type op_type = map_get_op_type(MI, OpNum); |
297 | | |
298 | | // Check for memory operands emitted via printOperand() |
299 | 100k | if (doing_mem(MI) && !(op_type & CS_OP_MEM)) { |
300 | | // Close previous memory operand |
301 | 63 | set_mem_access(MI, false); |
302 | 100k | } else if (doing_mem(MI) || (op_type & CS_OP_MEM)) { |
303 | | // The memory operands use printOperand() to |
304 | | // emit their register and immediates. |
305 | 18.1k | if (!doing_mem(MI)) |
306 | 766 | set_mem_access(MI, true); |
307 | 18.1k | handle_memory_operand(MI, OpNum); |
308 | 18.1k | return; |
309 | 18.1k | } |
310 | | |
311 | 82.2k | assert((op_type & CS_OP_MEM) == |
312 | 82.2k | 0); // doing_mem should have been true. |
313 | | |
314 | 82.2k | if (op_type == CS_OP_REG) |
315 | 81.6k | PPC_set_detail_op_reg(MI, OpNum, |
316 | 81.6k | MCInst_getOpVal(MI, OpNum)); |
317 | 656 | else if (op_type == CS_OP_IMM) |
318 | 656 | PPC_set_detail_op_imm(MI, OpNum, |
319 | 656 | MCInst_getOpVal(MI, OpNum)); |
320 | 0 | else |
321 | 0 | assert(0 && "Operand type not handled."); |
322 | 82.2k | break; |
323 | 82.2k | } |
324 | 82.2k | case PPC_OP_GROUP_ImmZeroOperand: |
325 | 1.26k | case PPC_OP_GROUP_U1ImmOperand: |
326 | 1.78k | case PPC_OP_GROUP_U2ImmOperand: |
327 | 2.86k | case PPC_OP_GROUP_U3ImmOperand: |
328 | 3.45k | case PPC_OP_GROUP_U4ImmOperand: |
329 | 14.4k | case PPC_OP_GROUP_U5ImmOperand: |
330 | 15.5k | case PPC_OP_GROUP_U6ImmOperand: |
331 | 15.6k | case PPC_OP_GROUP_U7ImmOperand: |
332 | 15.7k | case PPC_OP_GROUP_U8ImmOperand: |
333 | 15.7k | case PPC_OP_GROUP_U10ImmOperand: |
334 | 16.2k | case PPC_OP_GROUP_U12ImmOperand: |
335 | 16.2k | PPC_set_detail_op_imm(MI, OpNum, |
336 | 16.2k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
337 | 16.2k | break; |
338 | 4.99k | case PPC_OP_GROUP_U16ImmOperand: |
339 | 4.99k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
340 | | // Handled in printOperand() |
341 | 0 | return; |
342 | 4.99k | PPC_set_detail_op_imm(MI, OpNum, |
343 | 4.99k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
344 | 4.99k | break; |
345 | 18 | case PPC_OP_GROUP_S5ImmOperand: { |
346 | 18 | int Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
347 | 18 | Imm = SignExtend32((Imm), 5); |
348 | 18 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
349 | 18 | break; |
350 | 4.99k | } |
351 | 885 | case PPC_OP_GROUP_S12ImmOperand: { |
352 | 885 | int64_t Imm = SignExtend64( |
353 | 885 | MCOperand_getImm(MCInst_getOperand(MI, (OpNum))), 12); |
354 | 885 | if (doing_mem(MI)) { |
355 | 885 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
356 | 885 | break; |
357 | 885 | } |
358 | 0 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
359 | 0 | break; |
360 | 885 | } |
361 | 17.2k | case PPC_OP_GROUP_S16ImmOperand: { |
362 | 17.2k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
363 | | // Handled in printOperand() |
364 | 0 | return; |
365 | 17.2k | int16_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
366 | 17.2k | if (doing_mem(MI)) { |
367 | 12.0k | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
368 | 12.0k | break; |
369 | 12.0k | } |
370 | 5.21k | PPC_set_detail_op_imm(MI, OpNum, Imm); |
371 | 5.21k | break; |
372 | 17.2k | } |
373 | 246 | case PPC_OP_GROUP_S34ImmOperand: { |
374 | 246 | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
375 | | // Handled in printOperand() |
376 | 0 | return; |
377 | 246 | int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
378 | 246 | if (doing_mem(MI)) { |
379 | 215 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
380 | 215 | break; |
381 | 215 | } |
382 | 31 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
383 | 31 | break; |
384 | 246 | } |
385 | 0 | case PPC_OP_GROUP_ATBitsAsHint: { |
386 | 0 | PPC_get_detail(MI)->bc.hint = |
387 | 0 | (ppc_br_hint)MCInst_getOpVal(MI, OpNum); |
388 | 0 | break; |
389 | 246 | } |
390 | 2.51k | case PPC_OP_GROUP_AbsBranchOperand: { |
391 | 2.51k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
392 | | // Handled in printOperand() |
393 | 0 | return; |
394 | 2.51k | unsigned Val = MCInst_getOpVal(MI, OpNum) << 2; |
395 | 2.51k | int32_t Imm = SignExtend32(Val, 32); |
396 | 2.51k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
397 | 2.51k | PPC_get_detail_op(MI, 0)->imm = Imm; |
398 | 2.51k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
399 | 2.51k | PPC_inc_op_count(MI); |
400 | 2.51k | break; |
401 | 2.51k | } |
402 | 0 | case PPC_OP_GROUP_TLSCall: |
403 | | // Handled in PPCInstPrinter and printOperand. |
404 | 0 | return; |
405 | 46 | case PPC_OP_GROUP_crbitm: { |
406 | 46 | unsigned CCReg = MCInst_getOpVal(MI, OpNum); |
407 | 46 | PPC_set_detail_op_reg(MI, OpNum, CCReg); |
408 | 46 | break; |
409 | 2.51k | } |
410 | 5.67k | case PPC_OP_GROUP_BranchOperand: { |
411 | 5.67k | if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNum)))) |
412 | | // Handled in printOperand() |
413 | 0 | return; |
414 | 5.67k | int32_t Imm = SignExtend32( |
415 | 5.67k | ((unsigned)MCInst_getOpVal(MI, (OpNum)) << 2), 32); |
416 | 5.67k | uint64_t Address = MI->address + Imm; |
417 | 5.67k | if (IS_32BIT(MI->csh->mode)) |
418 | 1.27k | Address &= 0xffffffff; |
419 | 5.67k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
420 | 5.67k | PPC_get_detail_op(MI, 0)->imm = Address; |
421 | 5.67k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
422 | 5.67k | PPC_inc_op_count(MI); |
423 | 5.67k | break; |
424 | 5.67k | } |
425 | | // Memory operands have their `set_mem_access()` calls |
426 | | // in PPCInstPrinter. |
427 | 12.0k | case PPC_OP_GROUP_MemRegImm: |
428 | 13.7k | case PPC_OP_GROUP_MemRegReg: { |
429 | | // These cases print 0 if the base register is R0. |
430 | | // So no printOperand() function is called. |
431 | | // We must handle the zero case here. |
432 | 13.7k | unsigned OpNumReg = 0; |
433 | 13.7k | if (op_group == PPC_OP_GROUP_MemRegImm) |
434 | 12.0k | OpNumReg = OpNum + 1; |
435 | 1.73k | else |
436 | 1.73k | OpNumReg = OpNum; |
437 | | |
438 | 13.7k | MCOperand *Op = MCInst_getOperand(MI, OpNumReg); |
439 | 13.7k | if (MCOperand_isReg(Op) && MCOperand_getReg(Op) == PPC_R0) { |
440 | 0 | PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_ZERO; |
441 | 0 | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
442 | 0 | PPC_get_detail_op(MI, 0)->access = |
443 | 0 | map_get_op_access(MI, OpNum); |
444 | 0 | } |
445 | 13.7k | break; |
446 | 12.0k | } |
447 | 78 | case PPC_OP_GROUP_MemRegImmHash: |
448 | 167 | case PPC_OP_GROUP_MemRegImm34: |
449 | 293 | case PPC_OP_GROUP_MemRegImm34PCRel: |
450 | | // Handled in other printOperand functions. |
451 | 293 | break; |
452 | 162k | } |
453 | 162k | } |
454 | | |
455 | | /// Fills cs_detail with the data of the operand. |
456 | | /// Calls to this function should not be added by hand! Please checkout the |
457 | | /// patch `AddCSDetail` of the CppTranslator. |
458 | | void PPC_add_cs_detail(MCInst *MI, ppc_op_group op_group, va_list args) |
459 | 162k | { |
460 | 162k | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
461 | 0 | return; |
462 | | |
463 | 162k | switch (op_group) { |
464 | 0 | default: |
465 | 0 | printf("Operand group %d not handled!\n", op_group); |
466 | 0 | return; |
467 | 0 | case PPC_OP_GROUP_PredicateOperand: { |
468 | 0 | unsigned OpNum = va_arg(args, unsigned); |
469 | 0 | const char *Modifier = va_arg(args, const char *); |
470 | 0 | if ((strcmp(Modifier, "cc") == 0) || |
471 | 0 | (strcmp(Modifier, "pm") == 0)) { |
472 | 0 | unsigned Val = MCInst_getOpVal(MI, OpNum); |
473 | 0 | unsigned bo = Val & 0x1f; |
474 | 0 | unsigned bi = (Val & 0x1e0) >> 5; |
475 | 0 | PPC_get_detail(MI)->bc.bo = bo; |
476 | 0 | PPC_get_detail(MI)->bc.bi = bi; |
477 | 0 | PPC_get_detail(MI)->bc.crX_bit = bi % 4; |
478 | 0 | PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4); |
479 | 0 | PPC_get_detail(MI)->bc.pred_cr = |
480 | 0 | PPC_get_branch_pred(bi, bo, true); |
481 | 0 | PPC_get_detail(MI)->bc.pred_ctr = |
482 | 0 | PPC_get_branch_pred(bi, bo, false); |
483 | 0 | PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo); |
484 | 0 | } |
485 | 0 | return; |
486 | 0 | } |
487 | 885 | case PPC_OP_GROUP_S12ImmOperand: |
488 | 101k | case PPC_OP_GROUP_Operand: |
489 | 103k | case PPC_OP_GROUP_MemRegReg: |
490 | 104k | case PPC_OP_GROUP_U6ImmOperand: |
491 | 115k | case PPC_OP_GROUP_U5ImmOperand: |
492 | 127k | case PPC_OP_GROUP_MemRegImm: |
493 | 144k | case PPC_OP_GROUP_S16ImmOperand: |
494 | 144k | case PPC_OP_GROUP_U2ImmOperand: |
495 | 149k | case PPC_OP_GROUP_U16ImmOperand: |
496 | 155k | case PPC_OP_GROUP_BranchOperand: |
497 | 158k | case PPC_OP_GROUP_AbsBranchOperand: |
498 | 159k | case PPC_OP_GROUP_U1ImmOperand: |
499 | 159k | case PPC_OP_GROUP_TLSCall: |
500 | 160k | case PPC_OP_GROUP_U3ImmOperand: |
501 | 160k | case PPC_OP_GROUP_S5ImmOperand: |
502 | 160k | case PPC_OP_GROUP_MemRegImmHash: |
503 | 161k | case PPC_OP_GROUP_U4ImmOperand: |
504 | 161k | case PPC_OP_GROUP_U10ImmOperand: |
505 | 161k | case PPC_OP_GROUP_crbitm: |
506 | 161k | case PPC_OP_GROUP_S34ImmOperand: |
507 | 161k | case PPC_OP_GROUP_ImmZeroOperand: |
508 | 161k | case PPC_OP_GROUP_MemRegImm34: |
509 | 161k | case PPC_OP_GROUP_MemRegImm34PCRel: |
510 | 161k | case PPC_OP_GROUP_U8ImmOperand: |
511 | 162k | case PPC_OP_GROUP_U12ImmOperand: |
512 | 162k | case PPC_OP_GROUP_U7ImmOperand: |
513 | 162k | case PPC_OP_GROUP_ATBitsAsHint: { |
514 | 162k | unsigned OpNum = va_arg(args, unsigned); |
515 | 162k | add_cs_detail_general(MI, op_group, OpNum); |
516 | 162k | return; |
517 | 162k | } |
518 | 162k | } |
519 | 162k | } |
520 | | |
521 | | void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val, |
522 | | bool is_off_reg) |
523 | 31.2k | { |
524 | 31.2k | if (!detail_is_set(MI)) |
525 | 0 | return; |
526 | | |
527 | 31.2k | assert(map_get_op_type(MI, OpNum) & CS_OP_MEM); |
528 | 31.2k | cs_op_type secondary_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
529 | | |
530 | 31.2k | switch (secondary_type) { |
531 | 0 | default: |
532 | 0 | assert(0 && "Secondary type not supported yet."); |
533 | 18.1k | case CS_OP_REG: |
534 | 18.1k | if (is_off_reg) { |
535 | 2.50k | PPC_get_detail_op(MI, 0)->mem.offset = Val; |
536 | 2.50k | if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID) |
537 | 2.50k | set_mem_access(MI, false); |
538 | 15.6k | } else { |
539 | 15.6k | PPC_get_detail_op(MI, 0)->mem.base = Val; |
540 | 15.6k | if (MCInst_opIsTying(MI, OpNum)) |
541 | 0 | map_add_implicit_write(MI, MCInst_getOpVal(MI, OpNum)); |
542 | 15.6k | } |
543 | 18.1k | break; |
544 | 13.1k | case CS_OP_IMM: |
545 | 13.1k | PPC_get_detail_op(MI, 0)->mem.disp = Val; |
546 | 13.1k | if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID) |
547 | 0 | set_mem_access(MI, false); |
548 | 13.1k | break; |
549 | 31.2k | } |
550 | | |
551 | 31.2k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
552 | 31.2k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
553 | 31.2k | } |
554 | | |
555 | | /// Adds a register PPC operand at position OpNum and increases the op_count by |
556 | | /// one. |
557 | | void PPC_set_detail_op_reg(MCInst *MI, unsigned OpNum, ppc_reg Reg) |
558 | 81.6k | { |
559 | 81.6k | if (!detail_is_set(MI)) |
560 | 0 | return; |
561 | 81.6k | assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
562 | 81.6k | assert(map_get_op_type(MI, OpNum) == CS_OP_REG); |
563 | | |
564 | 81.6k | PPC_get_detail_op(MI, 0)->type = PPC_OP_REG; |
565 | 81.6k | PPC_get_detail_op(MI, 0)->reg = Reg; |
566 | 81.6k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
567 | 81.6k | PPC_inc_op_count(MI); |
568 | 81.6k | } |
569 | | |
570 | | /// Adds an immediate PPC operand at position OpNum and increases the op_count |
571 | | /// by one. |
572 | | void PPC_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm) |
573 | 27.2k | { |
574 | 27.2k | if (!detail_is_set(MI)) |
575 | 0 | return; |
576 | 27.2k | assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
577 | 27.2k | assert(map_get_op_type(MI, OpNum) == CS_OP_IMM); |
578 | | |
579 | 27.2k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
580 | 27.2k | PPC_get_detail_op(MI, 0)->imm = Imm; |
581 | 27.2k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
582 | 27.2k | PPC_inc_op_count(MI); |
583 | 27.2k | } |
584 | | |
585 | | void PPC_set_mem_access(MCInst *MI, bool status) |
586 | 33.3k | { |
587 | 33.3k | if (!detail_is_set(MI)) |
588 | 0 | return; |
589 | 33.3k | if ((!status && !doing_mem(MI)) || (status && doing_mem(MI))) |
590 | 1.88k | return; // Nothing to do |
591 | | |
592 | 31.5k | set_doing_mem(MI, status); |
593 | 31.5k | if (status) { |
594 | 15.7k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
595 | 15.7k | PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_INVALID; |
596 | 15.7k | PPC_get_detail_op(MI, 0)->mem.offset = PPC_REG_INVALID; |
597 | 15.7k | PPC_get_detail_op(MI, 0)->mem.disp = 0; |
598 | | |
599 | 15.7k | #ifndef CAPSTONE_DIET |
600 | 15.7k | uint8_t access = |
601 | 15.7k | map_get_op_access(MI, PPC_get_detail(MI)->op_count); |
602 | 15.7k | PPC_get_detail_op(MI, 0)->access = access; |
603 | 15.7k | #endif |
604 | 15.7k | } else { |
605 | | // done, select the next operand slot |
606 | 15.7k | PPC_inc_op_count(MI); |
607 | 15.7k | } |
608 | 31.5k | } |
609 | | |
610 | | void PPC_setup_op(cs_ppc_op *op) |
611 | 384 | { |
612 | 384 | memset(op, 0, sizeof(cs_ppc_op)); |
613 | 384 | op->type = PPC_OP_INVALID; |
614 | 384 | } |
615 | | |
616 | | /// Inserts a immediate to the detail operands at @index. |
617 | | /// Already present operands are moved. |
618 | | void PPC_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val, |
619 | | cs_ac_type access) |
620 | 384 | { |
621 | 384 | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
622 | 0 | return; |
623 | | |
624 | 384 | assert(PPC_get_detail(MI)->op_count < PPC_NUM_OPS); |
625 | | |
626 | 384 | cs_ppc_op op; |
627 | 384 | PPC_setup_op(&op); |
628 | 384 | op.type = PPC_OP_IMM; |
629 | 384 | op.imm = Val; |
630 | 384 | op.access = access; |
631 | | |
632 | 384 | cs_ppc_op *ops = PPC_get_detail(MI)->operands; |
633 | 384 | int i = PPC_get_detail(MI)->op_count - 1; |
634 | 1.14k | for (; i >= 0; --i) { |
635 | 762 | ops[i + 1] = ops[i]; |
636 | 762 | if (i == index) |
637 | 6 | break; |
638 | 762 | } |
639 | 384 | ops[index] = op; |
640 | 384 | PPC_inc_op_count(MI); |
641 | 384 | } |
642 | | |
643 | | #endif |