/src/capstonenext/arch/LoongArch/LoongArchMapping.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Jiajie Chen <c@jia.je>, 2024 */ |
3 | | /* Yanglin Xun <1109673069@qq.com>, 2024 */ |
4 | | |
5 | | #ifdef CAPSTONE_HAS_LOONGARCH |
6 | | |
7 | | #include <stdio.h> |
8 | | #include <string.h> |
9 | | |
10 | | #include <capstone/capstone.h> |
11 | | #include <capstone/loongarch.h> |
12 | | |
13 | | #include "../../Mapping.h" |
14 | | #include "../../MCDisassembler.h" |
15 | | #include "../../cs_priv.h" |
16 | | #include "../../cs_simple_types.h" |
17 | | |
18 | | #include "LoongArchMapping.h" |
19 | | #include "LoongArchLinkage.h" |
20 | | |
21 | | #define GET_REGINFO_ENUM |
22 | | #define GET_REGINFO_MC_DESC |
23 | | #include "LoongArchGenRegisterInfo.inc" |
24 | | |
25 | | #define GET_INSTRINFO_ENUM |
26 | | #include "LoongArchGenInstrInfo.inc" |
27 | | |
28 | | void LoongArch_init_mri(MCRegisterInfo *MRI) |
29 | 0 | { |
30 | 0 | MCRegisterInfo_InitMCRegisterInfo(MRI, LoongArchRegDesc, |
31 | 0 | sizeof(LoongArchRegDesc), 0, 0, |
32 | 0 | LoongArchMCRegisterClasses, |
33 | 0 | ARR_SIZE(LoongArchMCRegisterClasses), |
34 | 0 | 0, 0, LoongArchRegDiffLists, 0, |
35 | 0 | LoongArchSubRegIdxLists, |
36 | 0 | ARR_SIZE(LoongArchSubRegIdxLists), 0); |
37 | 0 | } |
38 | | |
39 | | const char *LoongArch_reg_name(csh handle, unsigned int reg) |
40 | 0 | { |
41 | 0 | int syntax_opt = ((cs_struct *)(uintptr_t)handle)->syntax; |
42 | |
|
43 | 0 | if (syntax_opt & CS_OPT_SYNTAX_NOREGNAME) { |
44 | 0 | return LoongArch_LLVM_getRegisterName(reg, |
45 | 0 | LoongArch_NoRegAltName); |
46 | 0 | } |
47 | 0 | return LoongArch_LLVM_getRegisterName(reg, LoongArch_RegAliasName); |
48 | 0 | } |
49 | | |
50 | | void LoongArch_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) |
51 | 0 | { |
52 | | // Not used by LoongArch. Information is set after disassembly. |
53 | 0 | } |
54 | | |
55 | | static const char *const insn_name_maps[] = { |
56 | | #include "LoongArchGenCSMappingInsnName.inc" |
57 | | }; |
58 | | |
59 | | const char *LoongArch_insn_name(csh handle, unsigned int id) |
60 | 0 | { |
61 | 0 | #ifndef CAPSTONE_DIET |
62 | 0 | if (id < ARR_SIZE(insn_name_maps)) |
63 | 0 | return insn_name_maps[id]; |
64 | | // not found |
65 | 0 | return NULL; |
66 | | #else |
67 | | return NULL; |
68 | | #endif |
69 | 0 | } |
70 | | |
71 | | #ifndef CAPSTONE_DIET |
72 | | static const name_map group_name_maps[] = { |
73 | | { LOONGARCH_GRP_INVALID, NULL }, |
74 | | |
75 | | { LOONGARCH_GRP_JUMP, "jump" }, |
76 | | { LOONGARCH_GRP_CALL, "call" }, |
77 | | { LOONGARCH_GRP_RET, "return" }, |
78 | | { LOONGARCH_GRP_INT, "int" }, |
79 | | { LOONGARCH_GRP_IRET, "iret" }, |
80 | | { LOONGARCH_GRP_PRIVILEGE, "privilege" }, |
81 | | { LOONGARCH_GRP_BRANCH_RELATIVE, "branch_relative" }, |
82 | | |
83 | | // architecture-specific groups |
84 | | #include "LoongArchGenCSFeatureName.inc" |
85 | | }; |
86 | | #endif |
87 | | |
88 | | const char *LoongArch_group_name(csh handle, unsigned int id) |
89 | 0 | { |
90 | 0 | #ifndef CAPSTONE_DIET |
91 | 0 | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
92 | | #else |
93 | | return NULL; |
94 | | #endif |
95 | 0 | } |
96 | | |
97 | | void LoongArch_reg_access(const cs_insn *insn, cs_regs regs_read, |
98 | | uint8_t *regs_read_count, cs_regs regs_write, |
99 | | uint8_t *regs_write_count) |
100 | 0 | { |
101 | 0 | uint8_t i; |
102 | 0 | uint8_t read_count, write_count; |
103 | 0 | cs_loongarch *loongarch = &(insn->detail->loongarch); |
104 | |
|
105 | 0 | read_count = insn->detail->regs_read_count; |
106 | 0 | write_count = insn->detail->regs_write_count; |
107 | | |
108 | | // implicit registers |
109 | 0 | memcpy(regs_read, insn->detail->regs_read, |
110 | 0 | read_count * sizeof(insn->detail->regs_read[0])); |
111 | 0 | memcpy(regs_write, insn->detail->regs_write, |
112 | 0 | write_count * sizeof(insn->detail->regs_write[0])); |
113 | | |
114 | | // explicit registers |
115 | 0 | for (i = 0; i < loongarch->op_count; i++) { |
116 | 0 | cs_loongarch_op *op = &(loongarch->operands[i]); |
117 | 0 | switch ((int)op->type) { |
118 | 0 | case LOONGARCH_OP_REG: |
119 | 0 | if ((op->access & CS_AC_READ) && |
120 | 0 | !arr_exist(regs_read, read_count, op->reg)) { |
121 | 0 | regs_read[read_count] = (uint16_t)op->reg; |
122 | 0 | read_count++; |
123 | 0 | } |
124 | 0 | if ((op->access & CS_AC_WRITE) && |
125 | 0 | !arr_exist(regs_write, write_count, op->reg)) { |
126 | 0 | regs_write[write_count] = (uint16_t)op->reg; |
127 | 0 | write_count++; |
128 | 0 | } |
129 | 0 | break; |
130 | 0 | case LOONGARCH_OP_MEM: |
131 | | // registers appeared in memory references always being read |
132 | 0 | if ((op->mem.base != LOONGARCH_REG_INVALID) && |
133 | 0 | !arr_exist(regs_read, read_count, op->mem.base)) { |
134 | 0 | regs_read[read_count] = (uint16_t)op->mem.base; |
135 | 0 | read_count++; |
136 | 0 | } |
137 | 0 | if ((insn->detail->writeback) && |
138 | 0 | (op->mem.base != LOONGARCH_REG_INVALID) && |
139 | 0 | !arr_exist(regs_write, write_count, op->mem.base)) { |
140 | 0 | regs_write[write_count] = |
141 | 0 | (uint16_t)op->mem.base; |
142 | 0 | write_count++; |
143 | 0 | } |
144 | 0 | default: |
145 | 0 | break; |
146 | 0 | } |
147 | 0 | } |
148 | | |
149 | 0 | *regs_read_count = read_count; |
150 | 0 | *regs_write_count = write_count; |
151 | 0 | } |
152 | | |
153 | | const insn_map loongarch_insns[] = { |
154 | | #include "LoongArchGenCSMappingInsn.inc" |
155 | | }; |
156 | | |
157 | | void LoongArch_rewrite_memory_operand(MCInst *MI) |
158 | 0 | { |
159 | | // rewrite base + disp operands to memory operands in memory instructions |
160 | | // convert e.g. |
161 | | // ld.d $t3, $t2, 0x410 |
162 | | // op_count: 3 |
163 | | // operands[0].type: REG = t3 |
164 | | // operands[0].access: WRITE |
165 | | // operands[1].type: REG = t2 |
166 | | // operands[1].access: READ |
167 | | // operands[2].type: IMM = 0x410 |
168 | | // operands[2].access: READ |
169 | | // to: |
170 | | // op_count: 3 |
171 | | // operands[0].type: REG = t3 |
172 | | // operands[0].access: WRITE |
173 | | // operands[1].type: MEM |
174 | | // operands[1].mem.base: REG = t2 |
175 | | // operands[1].mem.disp: 0x410 |
176 | | // operands[1].access: READ |
177 | |
|
178 | 0 | if (!detail_is_set(MI)) |
179 | 0 | return; |
180 | | |
181 | 0 | const loongarch_suppl_info *suppl_info = |
182 | 0 | map_get_suppl_info(MI, loongarch_insns); |
183 | 0 | if (suppl_info->memory_access == CS_AC_INVALID) { |
184 | | // not memory instruction |
185 | 0 | return; |
186 | 0 | } |
187 | | |
188 | | // handle special cases |
189 | 0 | unsigned int base; |
190 | 0 | switch (MI->flat_insn->id) { |
191 | 0 | case LOONGARCH_INS_SC_Q: |
192 | 0 | case LOONGARCH_INS_LLACQ_W: |
193 | 0 | case LOONGARCH_INS_LLACQ_D: |
194 | 0 | case LOONGARCH_INS_SCREL_W: |
195 | 0 | case LOONGARCH_INS_SCREL_D: |
196 | | // last register rj is memory operand |
197 | 0 | LoongArch_get_detail_op(MI, -1)->type = LOONGARCH_OP_MEM; |
198 | 0 | base = LoongArch_get_detail_op(MI, -1)->reg; |
199 | 0 | LoongArch_get_detail_op(MI, -1)->mem.base = base; |
200 | 0 | LoongArch_get_detail_op(MI, -1)->access = |
201 | 0 | suppl_info->memory_access; |
202 | 0 | return; |
203 | | |
204 | 0 | case LOONGARCH_INS_LDGT_B: |
205 | 0 | case LOONGARCH_INS_LDGT_H: |
206 | 0 | case LOONGARCH_INS_LDGT_W: |
207 | 0 | case LOONGARCH_INS_LDGT_D: |
208 | 0 | case LOONGARCH_INS_LDLE_B: |
209 | 0 | case LOONGARCH_INS_LDLE_H: |
210 | 0 | case LOONGARCH_INS_LDLE_W: |
211 | 0 | case LOONGARCH_INS_LDLE_D: |
212 | 0 | case LOONGARCH_INS_STGT_B: |
213 | 0 | case LOONGARCH_INS_STGT_H: |
214 | 0 | case LOONGARCH_INS_STGT_W: |
215 | 0 | case LOONGARCH_INS_STGT_D: |
216 | 0 | case LOONGARCH_INS_STLE_B: |
217 | 0 | case LOONGARCH_INS_STLE_H: |
218 | 0 | case LOONGARCH_INS_STLE_W: |
219 | 0 | case LOONGARCH_INS_STLE_D: |
220 | 0 | case LOONGARCH_INS_FLDLE_S: |
221 | 0 | case LOONGARCH_INS_FLDLE_D: |
222 | 0 | case LOONGARCH_INS_FLDGT_S: |
223 | 0 | case LOONGARCH_INS_FLDGT_D: |
224 | 0 | case LOONGARCH_INS_FSTLE_S: |
225 | 0 | case LOONGARCH_INS_FSTLE_D: |
226 | 0 | case LOONGARCH_INS_FSTGT_S: |
227 | 0 | case LOONGARCH_INS_FSTGT_D: |
228 | | // second register rj is memory operand |
229 | 0 | LoongArch_get_detail_op(MI, -2)->type = LOONGARCH_OP_MEM; |
230 | 0 | base = LoongArch_get_detail_op(MI, -2)->reg; |
231 | 0 | LoongArch_get_detail_op(MI, -2)->mem.base = base; |
232 | 0 | LoongArch_get_detail_op(MI, -2)->access = |
233 | 0 | suppl_info->memory_access; |
234 | 0 | return; |
235 | 0 | default: |
236 | 0 | break; |
237 | 0 | } |
238 | | |
239 | 0 | switch (suppl_info->form) { |
240 | 0 | case LOONGARCH_INSN_FORM_FMT2RI12: // ld, ldl, ldr, st, stl, str |
241 | 0 | case LOONGARCH_INSN_FORM_FMT2RI14: // ll, sc, ldptr, stptr |
242 | 0 | case LOONGARCH_INSN_FORM_FMT2RI9_VRI: // vldrepl.d |
243 | 0 | case LOONGARCH_INSN_FORM_FMT2RI10_VRI: // vldrepl.w |
244 | 0 | case LOONGARCH_INSN_FORM_FMT2RI11_VRI: // vldrepl.h |
245 | 0 | case LOONGARCH_INSN_FORM_FMT2RI12_VRI: // vld, vldrepl, vst |
246 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I1_VRII: // vstelm.d |
247 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I2_VRII: // vstelm.w |
248 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I3_VRII: // vstelm.h |
249 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I4_VRII: // vstelm.b |
250 | 0 | case LOONGARCH_INSN_FORM_FMT2RI9_XRI: // xvldrepl.d |
251 | 0 | case LOONGARCH_INSN_FORM_FMT2RI10_XRI: // xvldrepl.w |
252 | 0 | case LOONGARCH_INSN_FORM_FMT2RI11_XRI: // xvldrepl.h |
253 | 0 | case LOONGARCH_INSN_FORM_FMT2RI12_XRI: // xvld, xvldrepl, xvst |
254 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I2_XRII: // xvstelm.d |
255 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I3_XRII: // xvstelm.w |
256 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I4_XRII: // xvstelm.h |
257 | 0 | case LOONGARCH_INSN_FORM_FMT2RI8I5_XRII: // xvstelm.b |
258 | 0 | case LOONGARCH_INSN_FORM_FMTPRELD: // preld |
259 | 0 | case LOONGARCH_INSN_FORM_FPFMT2RI12: // fld, fst |
260 | | // immediate offset |
261 | 0 | LoongArch_get_detail_op(MI, -2)->type = LOONGARCH_OP_MEM; |
262 | 0 | base = LoongArch_get_detail_op(MI, -2)->reg; |
263 | 0 | LoongArch_get_detail_op(MI, -2)->mem.base = base; |
264 | 0 | LoongArch_get_detail_op(MI, -2)->mem.disp = |
265 | 0 | LoongArch_get_detail_op(MI, -1)->imm; |
266 | 0 | LoongArch_get_detail_op(MI, -2)->access = |
267 | 0 | suppl_info->memory_access; |
268 | 0 | LoongArch_dec_op_count(MI); |
269 | 0 | break; |
270 | | |
271 | 0 | case LOONGARCH_INSN_FORM_FMT3R: // ldx, stx, amo |
272 | 0 | if (suppl_info->memory_access == CS_AC_READ_WRITE) { |
273 | | // amo: read + write |
274 | | // last register rj is memory operand |
275 | 0 | LoongArch_get_detail_op(MI, -1)->type = |
276 | 0 | LOONGARCH_OP_MEM; |
277 | 0 | base = LoongArch_get_detail_op(MI, -1)->reg; |
278 | 0 | LoongArch_get_detail_op(MI, -1)->mem.base = base; |
279 | 0 | LoongArch_get_detail_op(MI, -1)->access = |
280 | 0 | suppl_info->memory_access; |
281 | 0 | break; |
282 | 0 | } |
283 | | // fallthrough |
284 | | |
285 | 0 | case LOONGARCH_INSN_FORM_FPFMTMEM: // fldx, fstx |
286 | 0 | case LOONGARCH_INSN_FORM_FMT3R_VRR: // vldx, vstx |
287 | 0 | case LOONGARCH_INSN_FORM_FMT3R_XRR: // xvldx, xvstx |
288 | 0 | case LOONGARCH_INSN_FORM_FMTPRELDX: // preldx |
289 | | // register offset |
290 | 0 | LoongArch_get_detail_op(MI, -2)->type = LOONGARCH_OP_MEM; |
291 | 0 | base = LoongArch_get_detail_op(MI, -2)->reg; |
292 | 0 | LoongArch_get_detail_op(MI, -2)->mem.base = base; |
293 | 0 | LoongArch_get_detail_op(MI, -2)->mem.index = |
294 | 0 | LoongArch_get_detail_op(MI, -1)->reg; |
295 | 0 | LoongArch_get_detail_op(MI, -2)->access = |
296 | 0 | suppl_info->memory_access; |
297 | 0 | LoongArch_dec_op_count(MI); |
298 | 0 | break; |
299 | | |
300 | 0 | default: |
301 | 0 | assert(0 && "Unknown LoongArch memory instruction"); |
302 | 0 | break; |
303 | 0 | } |
304 | 0 | } |
305 | | |
306 | | void LoongArch_set_instr_map_data(MCInst *MI) |
307 | 0 | { |
308 | 0 | map_cs_id(MI, loongarch_insns, ARR_SIZE(loongarch_insns)); |
309 | 0 | map_implicit_reads(MI, loongarch_insns); |
310 | 0 | map_implicit_writes(MI, loongarch_insns); |
311 | 0 | map_groups(MI, loongarch_insns); |
312 | 0 | const loongarch_suppl_info *suppl_info = |
313 | 0 | map_get_suppl_info(MI, loongarch_insns); |
314 | 0 | if (suppl_info) { |
315 | 0 | LoongArch_get_detail(MI)->format = suppl_info->form; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | | bool LoongArch_getInstruction(csh handle, const uint8_t *code, size_t code_len, |
320 | | MCInst *instr, uint16_t *size, uint64_t address, |
321 | | void *info) |
322 | 0 | { |
323 | 0 | uint64_t temp_size; |
324 | 0 | LoongArch_init_cs_detail(instr); |
325 | 0 | bool Result = LoongArch_LLVM_getInstruction(instr, &temp_size, code, |
326 | 0 | code_len, address, info) != |
327 | 0 | MCDisassembler_Fail; |
328 | 0 | LoongArch_set_instr_map_data(instr); |
329 | 0 | *size = temp_size; |
330 | 0 | return Result; |
331 | 0 | } |
332 | | |
333 | | /// Adds group to the instruction which are not defined in LLVM. |
334 | | static void LoongArch_add_cs_groups(MCInst *MI) |
335 | 0 | { |
336 | 0 | if (!MI->flat_insn->detail) |
337 | 0 | return; |
338 | 0 | unsigned Opcode = MI->flat_insn->id; |
339 | 0 | cs_loongarch *loongarch = &(MI->flat_insn->detail->loongarch); |
340 | 0 | switch (Opcode) { |
341 | 0 | default: |
342 | 0 | return; |
343 | 0 | case LOONGARCH_INS_BL: |
344 | 0 | add_group(MI, LOONGARCH_GRP_CALL); |
345 | 0 | break; |
346 | 0 | case LOONGARCH_INS_JIRL: |
347 | 0 | if (loongarch->op_count == 3 && |
348 | 0 | loongarch->operands[0].reg == LOONGARCH_REG_RA) { |
349 | | // call: jirl ra, rj, offs16 |
350 | 0 | add_group(MI, LOONGARCH_GRP_CALL); |
351 | 0 | } else if (loongarch->op_count == 0) { |
352 | | // ret |
353 | 0 | add_group(MI, LOONGARCH_GRP_RET); |
354 | 0 | } else if (loongarch->op_count == 1) { |
355 | | // jr rj |
356 | 0 | add_group(MI, LOONGARCH_GRP_JUMP); |
357 | 0 | } |
358 | 0 | break; |
359 | 0 | case LOONGARCH_INS_B: |
360 | 0 | case LOONGARCH_INS_BCEQZ: |
361 | 0 | case LOONGARCH_INS_BEQ: |
362 | 0 | case LOONGARCH_INS_BEQZ: |
363 | 0 | case LOONGARCH_INS_BGE: |
364 | 0 | case LOONGARCH_INS_BGEU: |
365 | 0 | case LOONGARCH_INS_BLT: |
366 | 0 | case LOONGARCH_INS_BLTU: |
367 | 0 | case LOONGARCH_INS_BNE: |
368 | 0 | case LOONGARCH_INS_BNEZ: |
369 | 0 | add_group(MI, LOONGARCH_GRP_JUMP); |
370 | 0 | add_group(MI, LOONGARCH_GRP_BRANCH_RELATIVE); |
371 | 0 | break; |
372 | 0 | case LOONGARCH_INS_SYSCALL: |
373 | 0 | add_group(MI, LOONGARCH_GRP_INT); |
374 | 0 | break; |
375 | 0 | case LOONGARCH_INS_ERTN: |
376 | 0 | add_group(MI, LOONGARCH_GRP_IRET); |
377 | 0 | add_group(MI, LOONGARCH_GRP_PRIVILEGE); |
378 | 0 | break; |
379 | 0 | case LOONGARCH_INS_CSRXCHG: |
380 | 0 | case LOONGARCH_INS_CACOP: |
381 | 0 | case LOONGARCH_INS_LDDIR: |
382 | 0 | case LOONGARCH_INS_LDPTE: |
383 | 0 | case LOONGARCH_INS_IOCSRRD_B: |
384 | 0 | case LOONGARCH_INS_IOCSRRD_H: |
385 | 0 | case LOONGARCH_INS_IOCSRRD_W: |
386 | 0 | case LOONGARCH_INS_IOCSRRD_D: |
387 | 0 | case LOONGARCH_INS_IOCSRWR_B: |
388 | 0 | case LOONGARCH_INS_IOCSRWR_H: |
389 | 0 | case LOONGARCH_INS_IOCSRWR_W: |
390 | 0 | case LOONGARCH_INS_IOCSRWR_D: |
391 | 0 | case LOONGARCH_INS_TLBCLR: |
392 | 0 | case LOONGARCH_INS_TLBFLUSH: |
393 | 0 | case LOONGARCH_INS_TLBSRCH: |
394 | 0 | case LOONGARCH_INS_TLBRD: |
395 | 0 | case LOONGARCH_INS_TLBWR: |
396 | 0 | case LOONGARCH_INS_INVTLB: |
397 | 0 | add_group(MI, LOONGARCH_GRP_PRIVILEGE); |
398 | 0 | break; |
399 | 0 | } |
400 | 0 | } |
401 | | |
402 | | void LoongArch_printer(MCInst *MI, SStream *O, |
403 | | void * /* MCRegisterInfo* */ info) |
404 | 0 | { |
405 | 0 | MCRegisterInfo *MRI = (MCRegisterInfo *)info; |
406 | 0 | MI->MRI = MRI; |
407 | |
|
408 | 0 | LoongArch_LLVM_printInst(MI, MI->address, "", O); |
409 | |
|
410 | 0 | LoongArch_rewrite_memory_operand(MI); |
411 | 0 | LoongArch_add_cs_groups(MI); |
412 | 0 | } |
413 | | |
414 | | void LoongArch_setup_op(cs_loongarch_op *op) |
415 | 0 | { |
416 | 0 | memset(op, 0, sizeof(cs_loongarch_op)); |
417 | 0 | op->type = LOONGARCH_OP_INVALID; |
418 | 0 | } |
419 | | |
420 | | void LoongArch_init_cs_detail(MCInst *MI) |
421 | 0 | { |
422 | 0 | if (detail_is_set(MI)) { |
423 | 0 | unsigned int i; |
424 | |
|
425 | 0 | memset(get_detail(MI), 0, |
426 | 0 | offsetof(cs_detail, loongarch) + sizeof(cs_loongarch)); |
427 | |
|
428 | 0 | for (i = 0; i < ARR_SIZE(LoongArch_get_detail(MI)->operands); |
429 | 0 | i++) |
430 | 0 | LoongArch_setup_op( |
431 | 0 | &LoongArch_get_detail(MI)->operands[i]); |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | static const map_insn_ops insn_operands[] = { |
436 | | #include "LoongArchGenCSMappingInsnOp.inc" |
437 | | }; |
438 | | |
439 | | void LoongArch_set_detail_op_imm(MCInst *MI, unsigned OpNum, |
440 | | loongarch_op_type ImmType, int64_t Imm) |
441 | 0 | { |
442 | 0 | if (!detail_is_set(MI)) |
443 | 0 | return; |
444 | 0 | assert((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_IMM); |
445 | 0 | assert(ImmType == LOONGARCH_OP_IMM); |
446 | | |
447 | 0 | LoongArch_get_detail_op(MI, 0)->type = ImmType; |
448 | 0 | LoongArch_get_detail_op(MI, 0)->imm = Imm; |
449 | 0 | LoongArch_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
450 | 0 | LoongArch_inc_op_count(MI); |
451 | 0 | } |
452 | | |
453 | | void LoongArch_set_detail_op_reg(MCInst *MI, unsigned OpNum, loongarch_reg Reg) |
454 | 0 | { |
455 | 0 | if (!detail_is_set(MI)) |
456 | 0 | return; |
457 | 0 | assert((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_REG); |
458 | | |
459 | 0 | LoongArch_get_detail_op(MI, 0)->type = LOONGARCH_OP_REG; |
460 | 0 | LoongArch_get_detail_op(MI, 0)->reg = Reg; |
461 | 0 | LoongArch_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
462 | 0 | LoongArch_inc_op_count(MI); |
463 | 0 | } |
464 | | |
465 | | void LoongArch_add_cs_detail(MCInst *MI, int /* loongarch_op_group */ op_group, |
466 | | va_list args) |
467 | 0 | { |
468 | 0 | if (!detail_is_set(MI)) |
469 | 0 | return; |
470 | | |
471 | 0 | unsigned OpNum = va_arg(args, unsigned); |
472 | | // Handle memory operands later |
473 | 0 | cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; |
474 | | |
475 | | // Fill cs_detail |
476 | 0 | switch (op_group) { |
477 | 0 | default: |
478 | 0 | printf("ERROR: Operand group %d not handled!\n", op_group); |
479 | 0 | assert(0); |
480 | 0 | case LOONGARCH_OP_GROUP_OPERAND: |
481 | 0 | if (op_type == CS_OP_IMM) { |
482 | 0 | LoongArch_set_detail_op_imm(MI, OpNum, LOONGARCH_OP_IMM, |
483 | 0 | MCInst_getOpVal(MI, OpNum)); |
484 | 0 | } else if (op_type == CS_OP_REG) { |
485 | 0 | LoongArch_set_detail_op_reg(MI, OpNum, |
486 | 0 | MCInst_getOpVal(MI, OpNum)); |
487 | 0 | } else |
488 | 0 | assert(0 && "Op type not handled."); |
489 | 0 | break; |
490 | 0 | case LOONGARCH_OP_GROUP_ATOMICMEMOP: |
491 | 0 | assert(op_type == CS_OP_REG); |
492 | | // converted to MEM operand later in LoongArch_rewrite_memory_operand |
493 | 0 | LoongArch_set_detail_op_reg(MI, OpNum, |
494 | 0 | MCInst_getOpVal(MI, OpNum)); |
495 | 0 | break; |
496 | 0 | } |
497 | 0 | } |
498 | | |
499 | | #endif |