/src/capstonenext/arch/SystemZ/SystemZMapping.c
Line | Count | Source |
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 | 58.8k | { |
45 | 58.8k | map_cs_id(MI, systemz_insns, ARR_SIZE(systemz_insns)); |
46 | 58.8k | map_implicit_reads(MI, systemz_insns); |
47 | 58.8k | map_implicit_writes(MI, systemz_insns); |
48 | 58.8k | map_groups(MI, systemz_insns); |
49 | 58.8k | const systemz_suppl_info *suppl_info = |
50 | 58.8k | map_get_suppl_info(MI, systemz_insns); |
51 | 58.8k | if (suppl_info) { |
52 | 58.8k | SystemZ_get_detail(MI)->format = suppl_info->form; |
53 | 58.8k | } |
54 | 58.8k | } |
55 | | |
56 | | void SystemZ_init_mri(MCRegisterInfo *MRI) |
57 | 1.64k | { |
58 | 1.64k | MCRegisterInfo_InitMCRegisterInfo( |
59 | 1.64k | MRI, SystemZRegDesc, AARCH64_REG_ENDING, 0, 0, |
60 | 1.64k | SystemZMCRegisterClasses, ARR_SIZE(SystemZMCRegisterClasses), 0, |
61 | 1.64k | 0, SystemZRegDiffLists, 0, SystemZSubRegIdxLists, |
62 | 1.64k | ARR_SIZE(SystemZSubRegIdxLists), 0); |
63 | 1.64k | } |
64 | | |
65 | | const char *SystemZ_reg_name(csh handle, unsigned int reg) |
66 | 35.9k | { |
67 | 35.9k | return SystemZ_LLVM_getRegisterName(reg); |
68 | 35.9k | } |
69 | | |
70 | | void SystemZ_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info) |
71 | 57.9k | { |
72 | 57.9k | MI->MRI = (MCRegisterInfo *)info; |
73 | 57.9k | MI->fillDetailOps = detail_is_set(MI); |
74 | 57.9k | SystemZ_LLVM_printInstruction(MI, "", O); |
75 | 57.9k | #ifndef CAPSTONE_DIET |
76 | 57.9k | map_set_alias_id(MI, O, insn_alias_mnem_map, |
77 | 57.9k | ARR_SIZE(insn_alias_mnem_map)); |
78 | 57.9k | #endif |
79 | 57.9k | } |
80 | | |
81 | | void SystemZ_init_cs_detail(MCInst *MI) |
82 | 58.8k | { |
83 | 58.8k | if (!detail_is_set(MI)) { |
84 | 0 | return; |
85 | 0 | } |
86 | 58.8k | memset(get_detail(MI), 0, sizeof(cs_detail)); |
87 | 58.8k | if (detail_is_set(MI)) { |
88 | 58.8k | SystemZ_get_detail(MI)->cc = SYSTEMZ_CC_INVALID; |
89 | 58.8k | } |
90 | 58.8k | } |
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 | 58.8k | { |
96 | 58.8k | SystemZ_init_cs_detail(MI); |
97 | 58.8k | MI->MRI = (MCRegisterInfo *)info; |
98 | 58.8k | DecodeStatus Result = SystemZ_LLVM_getInstruction( |
99 | 58.8k | handle, bytes, bytes_len, MI, size, address, info); |
100 | 58.8k | SystemZ_set_instr_map_data(MI, bytes, bytes_len); |
101 | 58.8k | if (Result == MCDisassembler_SoftFail) { |
102 | 0 | MCInst_setSoftFail(MI); |
103 | 0 | } |
104 | 58.8k | return Result != MCDisassembler_Fail; |
105 | 58.8k | } |
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 | 57.9k | { |
110 | | // We do this after Instruction disassembly. |
111 | 57.9k | } |
112 | | |
113 | | const char *SystemZ_insn_name(csh handle, unsigned int id) |
114 | 57.9k | { |
115 | 57.9k | #ifndef CAPSTONE_DIET |
116 | 57.9k | 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 | 57.9k | if (id >= SYSTEMZ_INS_ENDING) |
125 | 0 | return NULL; |
126 | | |
127 | 57.9k | if (id < ARR_SIZE(insn_name_maps)) |
128 | 57.9k | return insn_name_maps[id]; |
129 | | |
130 | | // not found |
131 | 0 | return NULL; |
132 | | #else |
133 | | return NULL; |
134 | | #endif |
135 | 57.9k | } |
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 | 23.2k | { |
155 | 23.2k | #ifndef CAPSTONE_DIET |
156 | 23.2k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
157 | | #else |
158 | | return NULL; |
159 | | #endif |
160 | 23.2k | } |
161 | | |
162 | | void SystemZ_add_cs_detail(MCInst *MI, int /* aarch64_op_group */ op_group, |
163 | | va_list args) |
164 | 139k | { |
165 | 139k | #ifndef CAPSTONE_DIET |
166 | 139k | if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) |
167 | 0 | return; |
168 | | |
169 | 139k | unsigned op_num = va_arg(args, unsigned); |
170 | | |
171 | 139k | switch (op_group) { |
172 | 0 | default: |
173 | 0 | printf("Operand group %d not handled\n", op_group); |
174 | 0 | break; |
175 | 79.4k | case SystemZ_OP_GROUP_Operand: { |
176 | 79.4k | cs_op_type secondary_op_type = map_get_op_type(MI, op_num) & |
177 | 79.4k | ~(CS_OP_MEM | CS_OP_BOUND); |
178 | 79.4k | 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 | 79.4k | } else if (secondary_op_type == CS_OP_REG) { |
182 | 79.4k | SystemZ_set_detail_op_reg(MI, op_num, |
183 | 79.4k | MCInst_getOpVal(MI, op_num)); |
184 | 79.4k | } else { |
185 | 0 | CS_ASSERT_RET(0 && "Op type not handled."); |
186 | 0 | } |
187 | 79.4k | 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 | 16.9k | case SystemZ_OP_GROUP_BDAddrOperand: |
195 | 16.9k | CS_ASSERT_RET(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
196 | 16.9k | CS_ASSERT_RET(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
197 | 16.9k | CS_ASSERT_RET(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
198 | 16.9k | CS_ASSERT_RET( |
199 | 16.9k | MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
200 | 16.9k | SystemZ_set_detail_op_mem(MI, op_num, |
201 | 16.9k | MCInst_getOpVal(MI, (op_num)), |
202 | 16.9k | MCInst_getOpVal(MI, (op_num + 1)), 0, |
203 | 16.9k | 0, SYSTEMZ_AM_BD); |
204 | 16.9k | break; |
205 | 900 | case SystemZ_OP_GROUP_BDVAddrOperand: |
206 | 14.5k | case SystemZ_OP_GROUP_BDXAddrOperand: { |
207 | 14.5k | CS_ASSERT(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
208 | 14.5k | CS_ASSERT(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
209 | 14.5k | CS_ASSERT(map_get_op_type(MI, (op_num + 2)) & CS_OP_MEM); |
210 | 14.5k | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
211 | 14.5k | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
212 | 14.5k | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num + 2)))); |
213 | 14.5k | SystemZ_set_detail_op_mem( |
214 | 14.5k | MI, op_num, MCInst_getOpVal(MI, (op_num)), |
215 | 14.5k | MCInst_getOpVal(MI, (op_num + 1)), 0, |
216 | 14.5k | MCInst_getOpVal(MI, (op_num + 2)), |
217 | 14.5k | (op_group == SystemZ_OP_GROUP_BDXAddrOperand ? |
218 | 13.6k | SYSTEMZ_AM_BDX : |
219 | 14.5k | SYSTEMZ_AM_BDV)); |
220 | 14.5k | break; |
221 | 900 | } |
222 | 4.06k | case SystemZ_OP_GROUP_BDLAddrOperand: |
223 | 4.06k | CS_ASSERT(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
224 | 4.06k | CS_ASSERT(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
225 | 4.06k | CS_ASSERT(map_get_op_type(MI, (op_num + 2)) & CS_OP_MEM); |
226 | 4.06k | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
227 | 4.06k | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
228 | 4.06k | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 2)))); |
229 | 4.06k | SystemZ_set_detail_op_mem(MI, op_num, |
230 | 4.06k | MCInst_getOpVal(MI, (op_num)), |
231 | 4.06k | MCInst_getOpVal(MI, (op_num + 1)), |
232 | 4.06k | MCInst_getOpVal(MI, (op_num + 2)), 0, |
233 | 4.06k | SYSTEMZ_AM_BDL); |
234 | 4.06k | break; |
235 | 221 | case SystemZ_OP_GROUP_BDRAddrOperand: |
236 | 221 | CS_ASSERT(map_get_op_type(MI, (op_num)) & CS_OP_MEM); |
237 | 221 | CS_ASSERT(map_get_op_type(MI, (op_num + 1)) & CS_OP_MEM); |
238 | 221 | CS_ASSERT(map_get_op_type(MI, (op_num + 2)) & CS_OP_MEM); |
239 | 221 | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num)))); |
240 | 221 | CS_ASSERT(MCOperand_isImm(MCInst_getOperand(MI, (op_num + 1)))); |
241 | 221 | CS_ASSERT(MCOperand_isReg(MCInst_getOperand(MI, (op_num + 2)))); |
242 | 221 | SystemZ_set_detail_op_mem(MI, op_num, |
243 | 221 | MCInst_getOpVal(MI, (op_num)), |
244 | 221 | MCInst_getOpVal(MI, (op_num + 1)), |
245 | 221 | MCInst_getOpVal(MI, (op_num + 2)), 0, |
246 | 221 | SYSTEMZ_AM_BDL); |
247 | 221 | break; |
248 | 2.43k | case SystemZ_OP_GROUP_PCRelOperand: |
249 | 2.43k | SystemZ_set_detail_op_imm(MI, op_num, |
250 | 2.43k | MCInst_getOpVal(MI, op_num), 0); |
251 | 2.43k | break; |
252 | 1.22k | case SystemZ_OP_GROUP_U1ImmOperand: |
253 | 1.22k | SystemZ_set_detail_op_imm(MI, op_num, |
254 | 1.22k | MCInst_getOpVal(MI, op_num), 1); |
255 | 1.22k | break; |
256 | 638 | case SystemZ_OP_GROUP_U2ImmOperand: |
257 | 638 | SystemZ_set_detail_op_imm(MI, op_num, |
258 | 638 | MCInst_getOpVal(MI, op_num), 2); |
259 | 638 | break; |
260 | 467 | case SystemZ_OP_GROUP_U3ImmOperand: |
261 | 467 | SystemZ_set_detail_op_imm(MI, op_num, |
262 | 467 | MCInst_getOpVal(MI, op_num), 3); |
263 | 467 | break; |
264 | 10.0k | case SystemZ_OP_GROUP_U4ImmOperand: |
265 | 10.0k | SystemZ_set_detail_op_imm(MI, op_num, |
266 | 10.0k | MCInst_getOpVal(MI, op_num), 4); |
267 | 10.0k | break; |
268 | 4.97k | case SystemZ_OP_GROUP_U8ImmOperand: |
269 | 5.84k | case SystemZ_OP_GROUP_S8ImmOperand: |
270 | 5.84k | SystemZ_set_detail_op_imm(MI, op_num, |
271 | 5.84k | MCInst_getOpVal(MI, op_num), 8); |
272 | 5.84k | break; |
273 | 229 | case SystemZ_OP_GROUP_U12ImmOperand: |
274 | 229 | SystemZ_set_detail_op_imm(MI, op_num, |
275 | 229 | MCInst_getOpVal(MI, op_num), 12); |
276 | 229 | break; |
277 | 616 | case SystemZ_OP_GROUP_U16ImmOperand: |
278 | 1.76k | case SystemZ_OP_GROUP_S16ImmOperand: |
279 | 1.76k | SystemZ_set_detail_op_imm(MI, op_num, |
280 | 1.76k | MCInst_getOpVal(MI, op_num), 16); |
281 | 1.76k | break; |
282 | 467 | case SystemZ_OP_GROUP_U32ImmOperand: |
283 | 1.52k | case SystemZ_OP_GROUP_S32ImmOperand: |
284 | 1.52k | SystemZ_set_detail_op_imm(MI, op_num, |
285 | 1.52k | MCInst_getOpVal(MI, op_num), 32); |
286 | 1.52k | 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 | 139k | } |
292 | 139k | #endif |
293 | 139k | } |
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 | 24.1k | { |
300 | 24.1k | if (!detail_is_set(MI)) |
301 | 0 | return; |
302 | 24.1k | CS_ASSERT((map_get_op_type(MI, op_num) & ~CS_OP_MEM) == CS_OP_IMM); |
303 | | |
304 | 24.1k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_IMM; |
305 | 24.1k | SystemZ_get_detail_op(MI, 0)->imm = Imm; |
306 | 24.1k | SystemZ_get_detail_op(MI, 0)->access = map_get_op_access(MI, op_num); |
307 | 24.1k | SystemZ_get_detail_op(MI, 0)->imm_width = width; |
308 | 24.1k | SystemZ_inc_op_count(MI); |
309 | 24.1k | } |
310 | | |
311 | | void SystemZ_set_detail_op_reg(MCInst *MI, unsigned op_num, systemz_reg Reg) |
312 | 79.4k | { |
313 | 79.4k | if (!detail_is_set(MI)) |
314 | 0 | return; |
315 | 79.4k | CS_ASSERT((map_get_op_type(MI, op_num) & ~CS_OP_MEM) == CS_OP_REG); |
316 | 79.4k | 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 | 688 | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_IMM; |
325 | 688 | SystemZ_get_detail_op(MI, 0)->imm = 0; |
326 | 688 | SystemZ_get_detail_op(MI, 0)->access = |
327 | 688 | map_get_op_access(MI, op_num); |
328 | 688 | SystemZ_get_detail_op(MI, 0)->imm_width = 0; |
329 | 688 | SystemZ_inc_op_count(MI); |
330 | 688 | return; |
331 | 688 | } |
332 | | |
333 | 78.8k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_REG; |
334 | 78.8k | SystemZ_get_detail_op(MI, 0)->reg = Reg; |
335 | 78.8k | SystemZ_get_detail_op(MI, 0)->access = map_get_op_access(MI, op_num); |
336 | 78.8k | SystemZ_inc_op_count(MI); |
337 | 78.8k | } |
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 | 35.7k | { |
343 | 35.7k | if (!detail_is_set(MI)) |
344 | 0 | return; |
345 | 35.7k | SystemZ_get_detail_op(MI, 0)->type = SYSTEMZ_OP_MEM; |
346 | 35.7k | SystemZ_get_detail_op(MI, 0)->access = map_get_op_access(MI, op_num); |
347 | 35.7k | SystemZ_get_detail_op(MI, 0)->mem.am = am; |
348 | 35.7k | switch (am) { |
349 | 0 | default: |
350 | 0 | CS_ASSERT(0 && "Address mode not handled\n"); |
351 | 0 | break; |
352 | 16.9k | case SYSTEMZ_AM_BD: |
353 | 16.9k | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
354 | 16.9k | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
355 | 16.9k | break; |
356 | 13.6k | case SYSTEMZ_AM_BDX: |
357 | 14.5k | case SYSTEMZ_AM_BDV: |
358 | 14.5k | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
359 | 14.5k | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
360 | 14.5k | SystemZ_get_detail_op(MI, 0)->mem.index = index; |
361 | 14.5k | break; |
362 | 4.28k | case SYSTEMZ_AM_BDL: |
363 | 4.28k | SystemZ_get_detail_op(MI, 0)->mem.base = base; |
364 | 4.28k | SystemZ_get_detail_op(MI, 0)->mem.disp = disp; |
365 | 4.28k | SystemZ_get_detail_op(MI, 0)->mem.length = length; |
366 | 4.28k | 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 | 35.7k | } |
373 | 35.7k | SystemZ_inc_op_count(MI); |
374 | 35.7k | } |
375 | | |
376 | | #endif |
377 | | |
378 | | #endif |