/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 | 2.19k | { |
24 | 2.19k | MCRegisterInfo_InitMCRegisterInfo(MRI, PPCRegDesc, PPC_REG_ENDING, 0, 0, |
25 | 2.19k | PPCMCRegisterClasses, |
26 | 2.19k | ARR_SIZE(PPCMCRegisterClasses), 0, 0, |
27 | 2.19k | PPCRegDiffLists, 0, PPCSubRegIdxLists, |
28 | 2.19k | ARR_SIZE(PPCSubRegIdxLists), |
29 | 2.19k | PPCRegEncodingTable); |
30 | 2.19k | } |
31 | | |
32 | | const char *PPC_reg_name(csh handle, unsigned int reg) |
33 | 29.4k | { |
34 | 29.4k | if (reg > PPC_REG_INVALID && reg < PPC_REG_ENDING) |
35 | 29.4k | return PPC_LLVM_getRegisterName(reg); |
36 | 0 | return NULL; |
37 | 29.4k | } |
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 | 63.8k | { |
42 | | // We do this after Instruction disassembly. |
43 | 63.8k | } |
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 | 63.8k | { |
63 | 63.8k | #ifndef CAPSTONE_DIET |
64 | 63.8k | 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 | 63.8k | if (id >= PPC_INS_ENDING) |
71 | 0 | return NULL; |
72 | | |
73 | 63.8k | return insn_name_maps[id]; |
74 | | #else |
75 | | return NULL; |
76 | | #endif |
77 | 63.8k | } |
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 | 25.7k | { |
96 | 25.7k | #ifndef CAPSTONE_DIET |
97 | 25.7k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
98 | | #else |
99 | | return NULL; |
100 | | #endif |
101 | 25.7k | } |
102 | | |
103 | | const insn_map ppc_insns[] = { |
104 | | #include "PPCGenCSMappingInsn.inc" |
105 | | }; |
106 | | |
107 | | void PPC_check_updates_cr0(MCInst *MI) |
108 | 64.9k | { |
109 | 64.9k | #ifndef CAPSTONE_DIET |
110 | 64.9k | if (!detail_is_set(MI)) |
111 | 0 | return; |
112 | 64.9k | cs_detail *detail = get_detail(MI); |
113 | 74.6k | for (int i = 0; i < detail->regs_write_count; ++i) { |
114 | 13.9k | if (detail->regs_write[i] == 0) |
115 | 0 | return; |
116 | 13.9k | if (detail->regs_write[i] == PPC_REG_CR0) { |
117 | 4.23k | PPC_get_detail(MI)->update_cr0 = true; |
118 | 4.23k | return; |
119 | 4.23k | } |
120 | 13.9k | } |
121 | 64.9k | #endif // CAPSTONE_DIET |
122 | 64.9k | } |
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 | 64.9k | { |
128 | 64.9k | if (!detail_is_set(MI)) |
129 | 0 | return; |
130 | 64.9k | #ifndef CAPSTONE_DIET |
131 | 64.9k | assert(MI && Bytes); |
132 | 64.9k | if (BytesLen < 4) |
133 | 772 | return; |
134 | | |
135 | 64.1k | ppc_insn_form form = ppc_insns[MI->Opcode].suppl_info.ppc.form; |
136 | 64.1k | bool b_form = ppc_is_b_form(form); |
137 | 64.1k | if (!(b_form || form == PPC_INSN_FORM_XLFORM_2)) |
138 | 60.0k | return; |
139 | | |
140 | 4.14k | uint32_t Inst = readBytes32(MI, Bytes); |
141 | | |
142 | 4.14k | uint8_t bi = 0; |
143 | 4.14k | if (b_form) |
144 | 3.78k | bi = (Inst & PPC_INSN_FORM_B_BI_MASK) >> 16; |
145 | 368 | else |
146 | 368 | bi = (Inst & PPC_INSN_FORM_XL_BI_MASK) >> 16; |
147 | | |
148 | 4.14k | uint8_t bo = 0; |
149 | 4.14k | if (b_form) |
150 | 3.78k | bo = (Inst & PPC_INSN_FORM_B_BO_MASK) >> 21; |
151 | 368 | else |
152 | 368 | bo = (Inst & PPC_INSN_FORM_XL_BO_MASK) >> 21; |
153 | | |
154 | 4.14k | PPC_get_detail(MI)->bc.bo = bo; |
155 | 4.14k | PPC_get_detail(MI)->bc.bi = bi; |
156 | 4.14k | PPC_get_detail(MI)->bc.crX_bit = bi % 4; |
157 | 4.14k | PPC_get_detail(MI)->bc.crX = PPC_REG_CR0 + (bi / 4); |
158 | 4.14k | PPC_get_detail(MI)->bc.hint = PPC_get_hint(bo); |
159 | 4.14k | PPC_get_detail(MI)->bc.pred_cr = PPC_get_branch_pred(bi, bo, true); |
160 | 4.14k | PPC_get_detail(MI)->bc.pred_ctr = PPC_get_branch_pred(bi, bo, false); |
161 | | |
162 | 4.14k | if (ppc_is_b_form(form)) |
163 | 3.78k | return; |
164 | | |
165 | 368 | uint8_t bh = (Inst & PPC_INSN_FORM_XL_BH_MASK) >> 11; |
166 | 368 | uint16_t xo = (Inst & PPC_INSN_FORM_XL_XO_MASK) >> 1; |
167 | | // Pre-defined values for XO fields (PowerISA v3.1B) |
168 | 368 | uint16_t bcctr_xo_field = 528; |
169 | 368 | uint16_t bctar_xo_field = 560; |
170 | 368 | bool cond = (xo == bcctr_xo_field || xo == bctar_xo_field); |
171 | 368 | switch (bh) { |
172 | 0 | default: |
173 | 0 | assert(0 && "Invalid BH value."); |
174 | 46 | case 0b00: |
175 | 46 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_NO_SUBROUTINE_RET : |
176 | 46 | PPC_BH_SUBROUTINE_RET; |
177 | 46 | break; |
178 | 67 | case 0b01: |
179 | 67 | PPC_get_detail(MI)->bc.bh = cond ? PPC_BH_RESERVED : |
180 | 67 | PPC_BH_NO_SUBROUTINE_RET; |
181 | 67 | break; |
182 | 222 | case 0b10: |
183 | 222 | PPC_get_detail(MI)->bc.bh = PPC_BH_RESERVED; |
184 | 222 | break; |
185 | 33 | case 0b11: |
186 | 33 | PPC_get_detail(MI)->bc.bh = PPC_BH_NOT_PREDICTABLE; |
187 | 33 | break; |
188 | 368 | } |
189 | 368 | #endif // CAPSTONE_DIET |
190 | 368 | } |
191 | | |
192 | | void PPC_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, size_t BytesLen) |
193 | 64.9k | { |
194 | 64.9k | map_cs_id(MI, ppc_insns, ARR_SIZE(ppc_insns)); |
195 | 64.9k | map_implicit_reads(MI, ppc_insns); |
196 | 64.9k | map_implicit_writes(MI, ppc_insns); |
197 | 64.9k | map_groups(MI, ppc_insns); |
198 | 64.9k | PPC_add_branch_predicates(MI, Bytes, BytesLen); |
199 | 64.9k | PPC_check_updates_cr0(MI); |
200 | 64.9k | } |
201 | | |
202 | | /// Inialize PPCs detail. |
203 | | void PPC_init_cs_detail(MCInst *MI) |
204 | 64.9k | { |
205 | 64.9k | if (!detail_is_set(MI)) |
206 | 0 | return; |
207 | 64.9k | memset(get_detail(MI), 0, offsetof(cs_detail, ppc) + sizeof(cs_ppc)); |
208 | 64.9k | PPC_get_detail(MI)->bc.bi = UINT8_MAX; |
209 | 64.9k | PPC_get_detail(MI)->bc.bo = UINT8_MAX; |
210 | 64.9k | PPC_get_detail(MI)->bc.crX = PPC_REG_INVALID; |
211 | 64.9k | PPC_get_detail(MI)->bc.crX_bit = PPC_BI_INVALID; |
212 | 64.9k | PPC_get_detail(MI)->bc.pred_cr = PPC_PRED_INVALID; |
213 | 64.9k | PPC_get_detail(MI)->bc.pred_ctr = PPC_PRED_INVALID; |
214 | 64.9k | PPC_get_detail(MI)->bc.hint = PPC_BR_NOT_GIVEN; |
215 | 64.9k | PPC_get_detail(MI)->bc.bh = PPC_BH_INVALID; |
216 | 64.9k | } |
217 | | |
218 | | void PPC_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) |
219 | 63.8k | { |
220 | 63.8k | MI->MRI = (MCRegisterInfo *)info; |
221 | 63.8k | MI->fillDetailOps = detail_is_set(MI); |
222 | 63.8k | MI->flat_insn->usesAliasDetails = map_use_alias_details(MI); |
223 | 63.8k | PPC_LLVM_printInst(MI, MI->address, "", O); |
224 | 63.8k | map_set_alias_id(MI, O, insn_alias_mnem_map, |
225 | 63.8k | ARR_SIZE(insn_alias_mnem_map)); |
226 | 63.8k | } |
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 | 64.9k | { |
232 | 64.9k | PPC_init_cs_detail(instr); |
233 | 64.9k | DecodeStatus result = PPC_LLVM_getInstruction( |
234 | 64.9k | handle, bytes, bytes_len, instr, size, address, info); |
235 | 64.9k | PPC_set_instr_map_data(instr, bytes, bytes_len); |
236 | 64.9k | return result != MCDisassembler_Fail; |
237 | 64.9k | } |
238 | | |
239 | | bool PPC_getFeatureBits(unsigned int mode, unsigned int feature) |
240 | 273k | { |
241 | 273k | if ((feature == PPC_FeatureQPX) && (mode & CS_MODE_QPX) == 0) { |
242 | 30.7k | return false; |
243 | 243k | } else if ((feature == PPC_FeatureSPE) && (mode & CS_MODE_SPE) == 0) { |
244 | 30.7k | return false; |
245 | 212k | } else if ((feature == PPC_FeatureBookE) && |
246 | 212k | (mode & CS_MODE_BOOKE) == 0) { |
247 | 456 | return false; |
248 | 212k | } else if ((feature == PPC_FeaturePS) && (mode & CS_MODE_PS) == 0) { |
249 | 22.7k | return false; |
250 | 22.7k | } |
251 | | |
252 | | // No AIX support for now. |
253 | 189k | if (feature == PPC_FeatureModernAIXAs || feature == PPC_AIXOS) |
254 | 65.5k | return false; |
255 | | // TODO Make it optional |
256 | 123k | if (feature == PPC_FeatureMSYNC) |
257 | 18 | return false; |
258 | | |
259 | | // By default support everything |
260 | 123k | return true; |
261 | 123k | } |
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 | 21.4k | { |
272 | 21.4k | 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 | 21.4k | bool is_off_reg = |
279 | 21.4k | ((op_type == CS_OP_REG) && |
280 | 21.4k | PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID); |
281 | 21.4k | PPC_set_detail_op_mem(MI, OpNum, MCInst_getOpVal(MI, OpNum), |
282 | 21.4k | is_off_reg); |
283 | 21.4k | } |
284 | | |
285 | | static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group, |
286 | | unsigned OpNum) |
287 | 193k | { |
288 | 193k | if (!detail_is_set(MI)) |
289 | 0 | return; |
290 | | |
291 | 193k | switch (op_group) { |
292 | 0 | default: |
293 | 0 | printf("General operand group %d not handled!\n", op_group); |
294 | 0 | return; |
295 | 128k | case PPC_OP_GROUP_Operand: { |
296 | 128k | cs_op_type op_type = map_get_op_type(MI, OpNum); |
297 | | |
298 | | // Check for memory operands emitted via printOperand() |
299 | 128k | if (doing_mem(MI) && !(op_type & CS_OP_MEM)) { |
300 | | // Close previous memory operand |
301 | 73 | set_mem_access(MI, false); |
302 | 128k | } else if (doing_mem(MI) || (op_type & CS_OP_MEM)) { |
303 | | // The memory operands use printOperand() to |
304 | | // emit their register and immediates. |
305 | 21.4k | if (!doing_mem(MI)) |
306 | 1.28k | set_mem_access(MI, true); |
307 | 21.4k | handle_memory_operand(MI, OpNum); |
308 | 21.4k | return; |
309 | 21.4k | } |
310 | | |
311 | 107k | assert((op_type & CS_OP_MEM) == |
312 | 107k | 0); // doing_mem should have been true. |
313 | | |
314 | 107k | if (op_type == CS_OP_REG) |
315 | 105k | PPC_set_detail_op_reg(MI, OpNum, |
316 | 105k | MCInst_getOpVal(MI, OpNum)); |
317 | 1.08k | else if (op_type == CS_OP_IMM) |
318 | 1.08k | PPC_set_detail_op_imm(MI, OpNum, |
319 | 1.08k | MCInst_getOpVal(MI, OpNum)); |
320 | 0 | else |
321 | 0 | assert(0 && "Operand type not handled."); |
322 | 107k | break; |
323 | 107k | } |
324 | 107k | case PPC_OP_GROUP_ImmZeroOperand: |
325 | 2.23k | case PPC_OP_GROUP_U1ImmOperand: |
326 | 3.18k | case PPC_OP_GROUP_U2ImmOperand: |
327 | 4.07k | case PPC_OP_GROUP_U3ImmOperand: |
328 | 5.04k | case PPC_OP_GROUP_U4ImmOperand: |
329 | 15.0k | case PPC_OP_GROUP_U5ImmOperand: |
330 | 17.2k | case PPC_OP_GROUP_U6ImmOperand: |
331 | 17.5k | case PPC_OP_GROUP_U7ImmOperand: |
332 | 17.6k | case PPC_OP_GROUP_U8ImmOperand: |
333 | 17.6k | case PPC_OP_GROUP_U10ImmOperand: |
334 | 18.7k | case PPC_OP_GROUP_U12ImmOperand: |
335 | 18.7k | PPC_set_detail_op_imm(MI, OpNum, |
336 | 18.7k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
337 | 18.7k | break; |
338 | 5.64k | case PPC_OP_GROUP_U16ImmOperand: |
339 | 5.64k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
340 | | // Handled in printOperand() |
341 | 0 | return; |
342 | 5.64k | PPC_set_detail_op_imm(MI, OpNum, |
343 | 5.64k | (uint32_t)MCInst_getOpVal(MI, OpNum)); |
344 | 5.64k | break; |
345 | 45 | case PPC_OP_GROUP_S5ImmOperand: { |
346 | 45 | int Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
347 | 45 | Imm = SignExtend32((Imm), 5); |
348 | 45 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
349 | 45 | break; |
350 | 5.64k | } |
351 | 442 | case PPC_OP_GROUP_S12ImmOperand: { |
352 | 442 | int64_t Imm = SignExtend64( |
353 | 442 | MCOperand_getImm(MCInst_getOperand(MI, (OpNum))), 12); |
354 | 442 | if (doing_mem(MI)) { |
355 | 442 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
356 | 442 | break; |
357 | 442 | } |
358 | 0 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
359 | 0 | break; |
360 | 442 | } |
361 | 18.4k | case PPC_OP_GROUP_S16ImmOperand: { |
362 | 18.4k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
363 | | // Handled in printOperand() |
364 | 0 | return; |
365 | 18.4k | int16_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
366 | 18.4k | if (doing_mem(MI)) { |
367 | 10.9k | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
368 | 10.9k | break; |
369 | 10.9k | } |
370 | 7.48k | PPC_set_detail_op_imm(MI, OpNum, Imm); |
371 | 7.48k | break; |
372 | 18.4k | } |
373 | 959 | case PPC_OP_GROUP_S34ImmOperand: { |
374 | 959 | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
375 | | // Handled in printOperand() |
376 | 0 | return; |
377 | 959 | int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); |
378 | 959 | if (doing_mem(MI)) { |
379 | 472 | PPC_set_detail_op_mem(MI, OpNum, Imm, true); |
380 | 472 | break; |
381 | 472 | } |
382 | 487 | PPC_set_detail_op_imm(MI, OpNum, Imm); |
383 | 487 | break; |
384 | 959 | } |
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 | 959 | } |
390 | 2.44k | case PPC_OP_GROUP_AbsBranchOperand: { |
391 | 2.44k | if (!MCOperand_isImm(MCInst_getOperand(MI, OpNum))) |
392 | | // Handled in printOperand() |
393 | 0 | return; |
394 | 2.44k | unsigned Val = MCInst_getOpVal(MI, OpNum) << 2; |
395 | 2.44k | int32_t Imm = SignExtend32(Val, 32); |
396 | 2.44k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
397 | 2.44k | PPC_get_detail_op(MI, 0)->imm = Imm; |
398 | 2.44k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
399 | 2.44k | PPC_inc_op_count(MI); |
400 | 2.44k | break; |
401 | 2.44k | } |
402 | 0 | case PPC_OP_GROUP_TLSCall: |
403 | | // Handled in PPCInstPrinter and printOperand. |
404 | 0 | return; |
405 | 1.25k | case PPC_OP_GROUP_crbitm: { |
406 | 1.25k | unsigned CCReg = MCInst_getOpVal(MI, OpNum); |
407 | 1.25k | PPC_set_detail_op_reg(MI, OpNum, CCReg); |
408 | 1.25k | break; |
409 | 2.44k | } |
410 | 2.14k | case PPC_OP_GROUP_BranchOperand: { |
411 | 2.14k | if (!MCOperand_isImm(MCInst_getOperand(MI, (OpNum)))) |
412 | | // Handled in printOperand() |
413 | 0 | return; |
414 | 2.14k | int32_t Imm = SignExtend32( |
415 | 2.14k | ((unsigned)MCInst_getOpVal(MI, (OpNum)) << 2), 32); |
416 | 2.14k | uint64_t Address = MI->address + Imm; |
417 | 2.14k | if (IS_32BIT(MI->csh->mode)) |
418 | 385 | Address &= 0xffffffff; |
419 | 2.14k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
420 | 2.14k | PPC_get_detail_op(MI, 0)->imm = Address; |
421 | 2.14k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
422 | 2.14k | PPC_inc_op_count(MI); |
423 | 2.14k | break; |
424 | 2.14k | } |
425 | | // Memory operands have their `set_mem_access()` calls |
426 | | // in PPCInstPrinter. |
427 | 10.9k | case PPC_OP_GROUP_MemRegImm: |
428 | 14.1k | 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 | 14.1k | unsigned OpNumReg = 0; |
433 | 14.1k | if (op_group == PPC_OP_GROUP_MemRegImm) |
434 | 10.9k | OpNumReg = OpNum + 1; |
435 | 3.23k | else |
436 | 3.23k | OpNumReg = OpNum; |
437 | | |
438 | 14.1k | MCOperand *Op = MCInst_getOperand(MI, OpNumReg); |
439 | 14.1k | 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 | 14.1k | break; |
446 | 10.9k | } |
447 | 162 | case PPC_OP_GROUP_MemRegImmHash: |
448 | 473 | case PPC_OP_GROUP_MemRegImm34: |
449 | 634 | case PPC_OP_GROUP_MemRegImm34PCRel: |
450 | | // Handled in other printOperand functions. |
451 | 634 | break; |
452 | 193k | } |
453 | 193k | } |
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 | 193k | { |
460 | 193k | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
461 | 0 | return; |
462 | | |
463 | 193k | 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 | 442 | case PPC_OP_GROUP_S12ImmOperand: |
488 | 128k | case PPC_OP_GROUP_Operand: |
489 | 132k | case PPC_OP_GROUP_MemRegReg: |
490 | 134k | case PPC_OP_GROUP_U6ImmOperand: |
491 | 144k | case PPC_OP_GROUP_U5ImmOperand: |
492 | 155k | case PPC_OP_GROUP_MemRegImm: |
493 | 173k | case PPC_OP_GROUP_S16ImmOperand: |
494 | 174k | case PPC_OP_GROUP_U2ImmOperand: |
495 | 180k | case PPC_OP_GROUP_U16ImmOperand: |
496 | 182k | case PPC_OP_GROUP_BranchOperand: |
497 | 184k | case PPC_OP_GROUP_AbsBranchOperand: |
498 | 186k | case PPC_OP_GROUP_U1ImmOperand: |
499 | 186k | case PPC_OP_GROUP_TLSCall: |
500 | 187k | case PPC_OP_GROUP_U3ImmOperand: |
501 | 187k | case PPC_OP_GROUP_S5ImmOperand: |
502 | 187k | case PPC_OP_GROUP_MemRegImmHash: |
503 | 188k | case PPC_OP_GROUP_U4ImmOperand: |
504 | 188k | case PPC_OP_GROUP_U10ImmOperand: |
505 | 190k | case PPC_OP_GROUP_crbitm: |
506 | 190k | case PPC_OP_GROUP_S34ImmOperand: |
507 | 191k | case PPC_OP_GROUP_ImmZeroOperand: |
508 | 191k | case PPC_OP_GROUP_MemRegImm34: |
509 | 191k | case PPC_OP_GROUP_MemRegImm34PCRel: |
510 | 192k | case PPC_OP_GROUP_U8ImmOperand: |
511 | 193k | case PPC_OP_GROUP_U12ImmOperand: |
512 | 193k | case PPC_OP_GROUP_U7ImmOperand: |
513 | 193k | case PPC_OP_GROUP_ATBitsAsHint: { |
514 | 193k | unsigned OpNum = va_arg(args, unsigned); |
515 | 193k | add_cs_detail_general(MI, op_group, OpNum); |
516 | 193k | return; |
517 | 193k | } |
518 | 193k | } |
519 | 193k | } |
520 | | |
521 | | void PPC_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val, |
522 | | bool is_off_reg) |
523 | 33.2k | { |
524 | 33.2k | if (!detail_is_set(MI)) |
525 | 0 | return; |
526 | | |
527 | 33.2k | assert(map_get_op_type(MI, OpNum) & CS_OP_MEM); |
528 | 33.2k | cs_op_type secondary_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
529 | | |
530 | 33.2k | switch (secondary_type) { |
531 | 0 | default: |
532 | 0 | assert(0 && "Secondary type not supported yet."); |
533 | 21.4k | case CS_OP_REG: |
534 | 21.4k | if (is_off_reg) { |
535 | 4.75k | PPC_get_detail_op(MI, 0)->mem.offset = Val; |
536 | 4.75k | if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID) |
537 | 4.75k | set_mem_access(MI, false); |
538 | 16.6k | } else { |
539 | 16.6k | PPC_get_detail_op(MI, 0)->mem.base = Val; |
540 | 16.6k | if (MCInst_opIsTying(MI, OpNum)) |
541 | 0 | map_add_implicit_write(MI, MCInst_getOpVal(MI, OpNum)); |
542 | 16.6k | } |
543 | 21.4k | break; |
544 | 11.8k | case CS_OP_IMM: |
545 | 11.8k | PPC_get_detail_op(MI, 0)->mem.disp = Val; |
546 | 11.8k | if (PPC_get_detail_op(MI, 0)->mem.base != PPC_REG_INVALID) |
547 | 0 | set_mem_access(MI, false); |
548 | 11.8k | break; |
549 | 33.2k | } |
550 | | |
551 | 33.2k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
552 | 33.2k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
553 | 33.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 | 107k | { |
559 | 107k | if (!detail_is_set(MI)) |
560 | 0 | return; |
561 | 107k | assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
562 | 107k | assert(map_get_op_type(MI, OpNum) == CS_OP_REG); |
563 | | |
564 | 107k | PPC_get_detail_op(MI, 0)->type = PPC_OP_REG; |
565 | 107k | PPC_get_detail_op(MI, 0)->reg = Reg; |
566 | 107k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
567 | 107k | PPC_inc_op_count(MI); |
568 | 107k | } |
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 | 33.5k | { |
574 | 33.5k | if (!detail_is_set(MI)) |
575 | 0 | return; |
576 | 33.5k | assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); |
577 | 33.5k | assert(map_get_op_type(MI, OpNum) == CS_OP_IMM); |
578 | | |
579 | 33.5k | PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; |
580 | 33.5k | PPC_get_detail_op(MI, 0)->imm = Imm; |
581 | 33.5k | PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
582 | 33.5k | PPC_inc_op_count(MI); |
583 | 33.5k | } |
584 | | |
585 | | void PPC_set_mem_access(MCInst *MI, bool status) |
586 | 37.1k | { |
587 | 37.1k | if (!detail_is_set(MI)) |
588 | 0 | return; |
589 | 37.1k | if ((!status && !doing_mem(MI)) || (status && doing_mem(MI))) |
590 | 3.54k | return; // Nothing to do |
591 | | |
592 | 33.6k | set_doing_mem(MI, status); |
593 | 33.6k | if (status) { |
594 | 16.8k | PPC_get_detail_op(MI, 0)->type = PPC_OP_MEM; |
595 | 16.8k | PPC_get_detail_op(MI, 0)->mem.base = PPC_REG_INVALID; |
596 | 16.8k | PPC_get_detail_op(MI, 0)->mem.offset = PPC_REG_INVALID; |
597 | 16.8k | PPC_get_detail_op(MI, 0)->mem.disp = 0; |
598 | | |
599 | 16.8k | #ifndef CAPSTONE_DIET |
600 | 16.8k | uint8_t access = |
601 | 16.8k | map_get_op_access(MI, PPC_get_detail(MI)->op_count); |
602 | 16.8k | PPC_get_detail_op(MI, 0)->access = access; |
603 | 16.8k | #endif |
604 | 16.8k | } else { |
605 | | // done, select the next operand slot |
606 | 16.8k | PPC_inc_op_count(MI); |
607 | 16.8k | } |
608 | 33.6k | } |
609 | | |
610 | | void PPC_setup_op(cs_ppc_op *op) |
611 | 110 | { |
612 | 110 | memset(op, 0, sizeof(cs_ppc_op)); |
613 | 110 | op->type = PPC_OP_INVALID; |
614 | 110 | } |
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 | 110 | { |
621 | 110 | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
622 | 0 | return; |
623 | | |
624 | 110 | assert(PPC_get_detail(MI)->op_count < PPC_NUM_OPS); |
625 | | |
626 | 110 | cs_ppc_op op; |
627 | 110 | PPC_setup_op(&op); |
628 | 110 | op.type = PPC_OP_IMM; |
629 | 110 | op.imm = Val; |
630 | 110 | op.access = access; |
631 | | |
632 | 110 | cs_ppc_op *ops = PPC_get_detail(MI)->operands; |
633 | 110 | int i = PPC_get_detail(MI)->op_count - 1; |
634 | 330 | for (; i >= 0; --i) { |
635 | 220 | ops[i + 1] = ops[i]; |
636 | 220 | if (i == index) |
637 | 0 | break; |
638 | 220 | } |
639 | 110 | ops[index] = op; |
640 | 110 | PPC_inc_op_count(MI); |
641 | 110 | } |
642 | | |
643 | | #endif |