/src/capstonenext/arch/SystemZ/SystemZMapping.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Rot127 <unisono@quyllur.org> 2022-2023 */ |
3 | | |
4 | | #ifdef CAPSTONE_HAS_SYSTEMZ |
5 | | |
6 | | #include <stdio.h> // debug |
7 | | #include <string.h> |
8 | | |
9 | | #include "../../Mapping.h" |
10 | | #include "../../utils.h" |
11 | | #include "../../cs_simple_types.h" |
12 | | #include <capstone/cs_operand.h> |
13 | | |
14 | | #include "SystemZMCTargetDesc.h" |
15 | | #include "SystemZMapping.h" |
16 | | #include "SystemZLinkage.h" |
17 | | |
18 | | #ifndef CAPSTONE_DIET |
19 | | |
20 | | static const char *const insn_name_maps[] = { |
21 | | #include "SystemZGenCSMappingInsnName.inc" |
22 | | }; |
23 | | |
24 | | static const name_map insn_alias_mnem_map[] = { |
25 | | #include "SystemZGenCSAliasMnemMap.inc" |
26 | | { SYSTEMZ_INS_ALIAS_END, NULL }, |
27 | | }; |
28 | | |
29 | | static const map_insn_ops insn_operands[] = { |
30 | | #include "SystemZGenCSMappingInsnOp.inc" |
31 | | }; |
32 | | |
33 | | #endif |
34 | | |
35 | | #define GET_REGINFO_MC_DESC |
36 | | #include "SystemZGenRegisterInfo.inc" |
37 | | |
38 | | const insn_map systemz_insns[] = { |
39 | | #include "SystemZGenCSMappingInsn.inc" |
40 | | }; |
41 | | |
42 | | void SystemZ_set_instr_map_data(MCInst *MI, const uint8_t *Bytes, |
43 | | size_t BytesLen) |
44 | 133k | { |
45 | 133k | map_cs_id(MI, systemz_insns, ARR_SIZE(systemz_insns)); |
46 | 133k | map_implicit_reads(MI, systemz_insns); |
47 | 133k | map_implicit_writes(MI, systemz_insns); |
48 | 133k | map_groups(MI, systemz_insns); |
49 | 133k | const systemz_suppl_info *suppl_info = |
50 | 133k | map_get_suppl_info(MI, systemz_insns); |
51 | 133k | if (suppl_info) { |
52 | 133k | SystemZ_get_detail(MI)->format = suppl_info->form; |
53 | 133k | } |
54 | 133k | } |
55 | | |
56 | | void SystemZ_init_mri(MCRegisterInfo *MRI) |
57 | 3.89k | { |
58 | 3.89k | MCRegisterInfo_InitMCRegisterInfo( |
59 | 3.89k | MRI, SystemZRegDesc, AARCH64_REG_ENDING, 0, 0, |
60 | 3.89k | SystemZMCRegisterClasses, ARR_SIZE(SystemZMCRegisterClasses), 0, |
61 | 3.89k | 0, SystemZRegDiffLists, 0, SystemZSubRegIdxLists, |
62 | 3.89k | ARR_SIZE(SystemZSubRegIdxLists), 0); |
63 | 3.89k | } |
64 | | |
65 | | const char *SystemZ_reg_name(csh handle, unsigned int reg) |
66 | 80.8k | { |
67 | 80.8k | return SystemZ_LLVM_getRegisterName(reg); |
68 | 80.8k | } |
69 | | |
70 | | void SystemZ_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) |
71 | 131k | { |
72 | 131k | MI->MRI = (MCRegisterInfo *)info; |
73 | 131k | MI->fillDetailOps = detail_is_set(MI); |
74 | 131k | SystemZ_LLVM_printInstruction(MI, "", O); |
75 | 131k | #ifndef CAPSTONE_DIET |
76 | 131k | map_set_alias_id(MI, O, insn_alias_mnem_map, |
77 | 131k | ARR_SIZE(insn_alias_mnem_map)); |
78 | 131k | #endif |
79 | 131k | } |
80 | | |
81 | | void SystemZ_init_cs_detail(MCInst *MI) |
82 | 133k | { |
83 | 133k | if (!detail_is_set(MI)) { |
84 | 0 | return; |
85 | 0 | } |
86 | 133k | memset(get_detail(MI), 0, sizeof(cs_detail)); |
87 | 133k | if (detail_is_set(MI)) { |
88 | 133k | SystemZ_get_detail(MI)->cc = SYSTEMZ_CC_INVALID; |
89 | 133k | } |
90 | 133k | } |
91 | | |
92 | | bool SystemZ_getInstruction(csh handle, const uint8_t *bytes, size_t bytes_len, |
93 | | MCInst *MI, uint16_t *size, uint64_t address, |
94 | | void *info) |
95 | 133k | { |
96 | 133k | SystemZ_init_cs_detail(MI); |
97 | 133k | MI->MRI = (MCRegisterInfo *)info; |
98 | 133k | DecodeStatus Result = SystemZ_LLVM_getInstruction( |
99 | 133k | handle, bytes, bytes_len, MI, size, address, info); |
100 | 133k | SystemZ_set_instr_map_data(MI, bytes, bytes_len); |
101 | 133k | if (Result == MCDisassembler_SoftFail) { |
102 | 0 | MCInst_setSoftFail(MI); |
103 | 0 | } |
104 | 133k | return Result != MCDisassembler_Fail; |
105 | 133k | } |
106 | | |
107 | | // given internal insn id, return public instruction info |
108 | | void SystemZ_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) |
109 | 131k | { |
110 | | // We do this after Instruction disassembly. |
111 | 131k | } |
112 | | |
113 | | const char *SystemZ_insn_name(csh handle, unsigned int id) |
114 | 131k | { |
115 | 131k | #ifndef CAPSTONE_DIET |
116 | 131k | if (id < SYSTEMZ_INS_ALIAS_END && id > SYSTEMZ_INS_ALIAS_BEGIN) { |
117 | 0 | if (id - SYSTEMZ_INS_ALIAS_BEGIN >= |
118 | 0 | ARR_SIZE(insn_alias_mnem_map)) |
119 | 0 | return NULL; |
120 | | |
121 | 0 | return insn_alias_mnem_map[id - SYSTEMZ_INS_ALIAS_BEGIN - 1] |
122 | 0 | .name; |
123 | 0 | } |
124 | 131k | if (id >= SYSTEMZ_INS_ENDING) |
125 | 0 | return NULL; |
126 | | |
127 | 131k | if (id < ARR_SIZE(insn_name_maps)) |
128 | 131k | return insn_name_maps[id]; |
129 | | |
130 | | // not found |
131 | 0 | return NULL; |
132 | | #else |
133 | | return NULL; |
134 | | #endif |
135 | 131k | } |
136 | | |
137 | | #ifndef CAPSTONE_DIET |
138 | | static const name_map group_name_maps[] = { |
139 | | // generic groups |
140 | | { SYSTEMZ_GRP_INVALID, NULL }, |
141 | | { SYSTEMZ_GRP_JUMP, "jump" }, |
142 | | { SYSTEMZ_GRP_CALL, "call" }, |
143 | | { SYSTEMZ_GRP_RET, "return" }, |
144 | | { SYSTEMZ_GRP_INT, "int" }, |
145 | | { SYSTEMZ_GRP_IRET, "iret" }, |
146 | | { SYSTEMZ_GRP_PRIVILEGE, "privilege" }, |
147 | | { SYSTEMZ_GRP_BRANCH_RELATIVE, "branch_relative" }, |
148 | | |
149 | | #include "SystemZGenCSFeatureName.inc" |
150 | | }; |
151 | | #endif |
152 | | |
153 | | const char *SystemZ_group_name(csh handle, unsigned int id) |
154 | 79.5k | { |
155 | 79.5k | #ifndef CAPSTONE_DIET |
156 | 79.5k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
157 | | #else |
158 | | return NULL; |
159 | | #endif |
160 | 79.5k | } |
161 | | |
162 | | void SystemZ_add_cs_detail(MCInst *MI, int /* aarch64_op_group */ op_group, |
163 | | va_list args) |
164 | 311k | { |
165 | 311k | #ifndef CAPSTONE_DIET |
166 | 311k | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
167 | 0 | return; |
168 | | |
169 | 311k | unsigned op_num = va_arg(args, unsigned); |
170 | | |
171 | 311k | switch (op_group) { |
172 | 0 | default: |
173 | 0 | printf("Operand group %d not handled\n", op_group); |
174 | 0 | break; |
175 | 175k | case SystemZ_OP_GROUP_Operand: { |
176 | 175k | cs_op_type secondary_op_type = map_get_op_type(MI, op_num) & |
177 | 175k | ~(CS_OP_MEM | CS_OP_BOUND); |
178 | 175k | if (secondary_op_type == CS_OP_IMM) { |
179 | 0 | SystemZ_set_detail_op_imm( |
180 | 0 | MI, op_num, MCInst_getOpVal(MI, op_num), 0); |
181 | 175k | } else if (secondary_op_type == CS_OP_REG) { |
182 | 175k | SystemZ_set_detail_op_reg(MI, op_num, |
183 | 175k | MCInst_getOpVal(MI, op_num)); |
184 | 175k | } else { |
185 | 0 | CS_ASSERT_RET(0 && "Op type not handled."); |
186 | 0 | } |
187 | 175k | break; |
188 | 0 | } |
189 | 0 | case SystemZ_OP_GROUP_Cond4Operand: { |
190 | 0 | systemz_cc cc = MCInst_getOpVal(MI, op_num); |
191 | 0 | SystemZ_get_detail(MI)->cc = cc; |
192 | 0 | break; |
193 | 0 | } |
194 | 39.8k | case SystemZ_OP_GROUP_BDAddrOperand: |
195 | 39.8k | CS_ASSERT_RET(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
196 | 39.8k | CS_ASSERT_RET(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
197 | 39.8k | CS_ASSERT_RET(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
198 | 39.8k | CS_ASSERT_RET( |
199 | 39.8k | MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
200 | 39.8k | SystemZ_set_detail_op_mem(MI, op_num, |
201 | 39.8k | MCInst_getOpVal(MI, (op_num)), |
202 | 39.8k | MCInst_getOpVal(MI, (op_num + 1)), 0, |
203 | 39.8k | 0, SYSTEMZ_AM_BD); |
204 | 39.8k | break; |
205 | 683 | case SystemZ_OP_GROUP_BDVAddrOperand: |
206 | 35.1k | case SystemZ_OP_GROUP_BDXAddrOperand: { |
207 | 35.1k | CS_ASSERT(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
208 | 35.1k | CS_ASSERT(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
209 | 35.1k | CS_ASSERT(map_get_op_type(MI, (op_num + 2)) & CS_OP_MEM); |
210 | 35.1k | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
211 | 35.1k | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
212 | 35.1k | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num + 2)))); |
213 | 35.1k | SystemZ_set_detail_op_mem( |
214 | 35.1k | MI, op_num, MCInst_getOpVal(MI, (op_num)), |
215 | 35.1k | MCInst_getOpVal(MI, (op_num + 1)), 0, |
216 | 35.1k | MCInst_getOpVal(MI, (op_num + 2)), |
217 | 35.1k | (op_group == SystemZ_OP_GROUP_BDXAddrOperand ? |
218 | 34.4k | SYSTEMZ_AM_BDX : |
219 | 35.1k | SYSTEMZ_AM_BDV)); |
220 | 35.1k | break; |
221 | 683 | } |
222 | 11.9k | case SystemZ_OP_GROUP_BDLAddrOperand: |
223 | 11.9k | CS_ASSERT(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
224 | 11.9k | CS_ASSERT(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
225 | 11.9k | CS_ASSERT(map_get_op_type(MI, (op_num + 2)) & CS_OP_MEM); |
226 | 11.9k | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
227 | 11.9k | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
228 | 11.9k | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 2)))); |
229 | 11.9k | SystemZ_set_detail_op_mem(MI, op_num, |
230 | 11.9k | MCInst_getOpVal(MI, (op_num)), |
231 | 11.9k | MCInst_getOpVal(MI, (op_num + 1)), |
232 | 11.9k | MCInst_getOpVal(MI, (op_num + 2)), 0, |
233 | 11.9k | SYSTEMZ_AM_BDL); |
234 | 11.9k | break; |
235 | 595 | case SystemZ_OP_GROUP_BDRAddrOperand: |
236 | 595 | CS_ASSERT(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
237 | 595 | CS_ASSERT(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
238 | 595 | CS_ASSERT(map_get_op_type(MI, (op_num + 2)) & CS_OP_MEM); |
239 | 595 | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
240 | 595 | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
241 | 595 | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num + 2)))); |
242 | 595 | SystemZ_set_detail_op_mem(MI, op_num, |
243 | 595 | MCInst_getOpVal(MI, (op_num)), |
244 | 595 | MCInst_getOpVal(MI, (op_num + 1)), |
245 | 595 | MCInst_getOpVal(MI, (op_num + 2)), 0, |
246 | 595 | SYSTEMZ_AM_BDL); |
247 | 595 | break; |
248 | 5.02k | case SystemZ_OP_GROUP_PCRelOperand: |
249 | 5.02k | SystemZ_set_detail_op_imm(MI, op_num, |
250 | 5.02k | MCInst_getOpVal(MI, op_num), 0); |
251 | 5.02k | break; |
252 | 1.46k | case SystemZ_OP_GROUP_U1ImmOperand: |
253 | 1.46k | SystemZ_set_detail_op_imm(MI, op_num, |
254 | 1.46k | MCInst_getOpVal(MI, op_num), 1); |
255 | 1.46k | break; |
256 | 1.92k | case SystemZ_OP_GROUP_U2ImmOperand: |
257 | 1.92k | SystemZ_set_detail_op_imm(MI, op_num, |
258 | 1.92k | MCInst_getOpVal(MI, op_num), 2); |
259 | 1.92k | break; |
260 | 1.01k | case SystemZ_OP_GROUP_U3ImmOperand: |
261 | 1.01k | SystemZ_set_detail_op_imm(MI, op_num, |
262 | 1.01k | MCInst_getOpVal(MI, op_num), 3); |
263 | 1.01k | break; |
264 | 21.9k | case SystemZ_OP_GROUP_U4ImmOperand: |
265 | 21.9k | SystemZ_set_detail_op_imm(MI, op_num, |
266 | 21.9k | MCInst_getOpVal(MI, op_num), 4); |
267 | 21.9k | break; |
268 | 8.48k | case SystemZ_OP_GROUP_U8ImmOperand: |
269 | 10.0k | case SystemZ_OP_GROUP_S8ImmOperand: |
270 | 10.0k | SystemZ_set_detail_op_imm(MI, op_num, |
271 | 10.0k | MCInst_getOpVal(MI, op_num), 8); |
272 | 10.0k | break; |
273 | 139 | case SystemZ_OP_GROUP_U12ImmOperand: |
274 | 139 | SystemZ_set_detail_op_imm(MI, op_num, |
275 | 139 | MCInst_getOpVal(MI, op_num), 12); |
276 | 139 | break; |
277 | 2.28k | case SystemZ_OP_GROUP_U16ImmOperand: |
278 | 4.54k | case SystemZ_OP_GROUP_S16ImmOperand: |
279 | 4.54k | SystemZ_set_detail_op_imm(MI, op_num, |
280 | 4.54k | MCInst_getOpVal(MI, op_num), 16); |
281 | 4.54k | break; |
282 | 1.34k | case SystemZ_OP_GROUP_U32ImmOperand: |
283 | 2.57k | case SystemZ_OP_GROUP_S32ImmOperand: |
284 | 2.57k | SystemZ_set_detail_op_imm(MI, op_num, |
285 | 2.57k | MCInst_getOpVal(MI, op_num), 32); |
286 | 2.57k | break; |
287 | 0 | case SystemZ_OP_GROUP_U48ImmOperand: |
288 | 0 | SystemZ_set_detail_op_imm(MI, op_num, |
289 | 0 | MCInst_getOpVal(MI, op_num), 48); |
290 | 0 | break; |
291 | 311k | } |
292 | 311k | #endif |
293 | 311k | } |
294 | | |
295 | | #ifndef CAPSTONE_DIET |
296 | | |
297 | | void SystemZ_set_detail_op_imm(MCInst *MI, unsigned op_num, int64_t Imm, |
298 | | size_t width) |
299 | 48.7k | { |
300 | 48.7k | if (!detail_is_set(MI)) |
301 | 0 | return; |
302 | 48.7k | CS_ASSERT((map_get_op_type(MI, op_num) & ~CS_OP_MEM) == CS_OP_IMM); |
303 | | |
304 | 48.7k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_IMM; |
305 | 48.7k | SystemZ_get_detail_op(MI, 0)->imm = Imm; |
306 | 48.7k | SystemZ_get_detail_op(MI, 0)->access = map_get_op_access(MI, op_num); |
307 | 48.7k | SystemZ_get_detail_op(MI, 0)->imm_width = width; |
308 | 48.7k | SystemZ_inc_op_count(MI); |
309 | 48.7k | } |
310 | | |
311 | | void SystemZ_set_detail_op_reg(MCInst *MI, unsigned op_num, systemz_reg Reg) |
312 | 175k | { |
313 | 175k | if (!detail_is_set(MI)) |
314 | 0 | return; |
315 | 175k | CS_ASSERT((map_get_op_type(MI, op_num) & ~CS_OP_MEM) == CS_OP_REG); |
316 | 175k | if (Reg == SYSTEMZ_REG_INVALID) { |
317 | | // This case is legal. The ISA says: |
318 | | // " |
319 | | // When the R1 field is not zero, bits 8-15 of the instruction designated |
320 | | // by the second-operand address are ORed with bits 56-63 of |
321 | | // general register R1. [...] When the R1 field is zero, no ORing takes place |
322 | | // " |
323 | | // This means we just save the neutral element for ORing, so 0. |
324 | 1.73k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_IMM; |
325 | 1.73k | SystemZ_get_detail_op(MI, 0)->imm = 0; |
326 | 1.73k | SystemZ_get_detail_op(MI, 0)->access = |
327 | 1.73k | map_get_op_access(MI, op_num); |
328 | 1.73k | SystemZ_get_detail_op(MI, 0)->imm_width = 0; |
329 | 1.73k | SystemZ_inc_op_count(MI); |
330 | 1.73k | return; |
331 | 1.73k | } |
332 | | |
333 | 173k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_REG; |
334 | 173k | SystemZ_get_detail_op(MI, 0)->reg = Reg; |
335 | 173k | SystemZ_get_detail_op(MI, 0)->access = map_get_op_access(MI, op_num); |
336 | 173k | SystemZ_inc_op_count(MI); |
337 | 173k | } |
338 | | |
339 | | void SystemZ_set_detail_op_mem(MCInst *MI, unsigned op_num, systemz_reg base, |
340 | | int64_t disp, uint64_t length, systemz_reg index, |
341 | | systemz_addr_mode am) |
342 | 87.5k | { |
343 | 87.5k | if (!detail_is_set(MI)) |
344 | 0 | return; |
345 | 87.5k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_MEM; |
346 | 87.5k | SystemZ_get_detail_op(MI, 0)->access = map_get_op_access(MI, op_num); |
347 | 87.5k | SystemZ_get_detail_op(MI, 0)->mem.am = am; |
348 | 87.5k | switch (am) { |
349 | 0 | default: |
350 | 0 | CS_ASSERT(0 && "Address mode not handled\n"); |
351 | 0 | break; |
352 | 39.8k | case SYSTEMZ_AM_BD: |
353 | 39.8k | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
354 | 39.8k | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
355 | 39.8k | break; |
356 | 34.4k | case SYSTEMZ_AM_BDX: |
357 | 35.1k | case SYSTEMZ_AM_BDV: |
358 | 35.1k | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
359 | 35.1k | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
360 | 35.1k | SystemZ_get_detail_op(MI, 0)->mem.index = index; |
361 | 35.1k | break; |
362 | 12.5k | case SYSTEMZ_AM_BDL: |
363 | 12.5k | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
364 | 12.5k | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
365 | 12.5k | SystemZ_get_detail_op(MI, 0)->mem.length = length; |
366 | 12.5k | break; |
367 | 0 | case SYSTEMZ_AM_BDR: |
368 | 0 | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
369 | 0 | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
370 | 0 | SystemZ_get_detail_op(MI, 0)->mem.length = length; |
371 | 0 | break; |
372 | 87.5k | } |
373 | 87.5k | SystemZ_inc_op_count(MI); |
374 | 87.5k | } |
375 | | |
376 | | #endif |
377 | | |
378 | | #endif |