/src/capstonenext/arch/ARC/ARCMapping.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Dmitry Sibirtsev <sibirtsevdl@gmail.com>, 2024 */ |
3 | | |
4 | | #ifdef CAPSTONE_HAS_ARC |
5 | | |
6 | | #include <stdio.h> |
7 | | #include <string.h> |
8 | | |
9 | | #include <capstone/capstone.h> |
10 | | #include <capstone/arc.h> |
11 | | |
12 | | #include "../../Mapping.h" |
13 | | #include "../../MCDisassembler.h" |
14 | | #include "../../cs_priv.h" |
15 | | #include "../../cs_simple_types.h" |
16 | | |
17 | | #include "ARCMapping.h" |
18 | | #include "ARCLinkage.h" |
19 | | |
20 | | #define GET_REGINFO_ENUM |
21 | | #define GET_REGINFO_MC_DESC |
22 | | #include "ARCGenRegisterInfo.inc" |
23 | | |
24 | | #define GET_INSTRINFO_ENUM |
25 | | #include "ARCGenInstrInfo.inc" |
26 | | |
27 | | void ARC_init_mri(MCRegisterInfo *MRI) |
28 | 0 | { |
29 | 0 | MCRegisterInfo_InitMCRegisterInfo(MRI, ARCRegDesc, |
30 | 0 | sizeof(ARCRegDesc), 0, 0, |
31 | 0 | ARCMCRegisterClasses, |
32 | 0 | ARR_SIZE(ARCMCRegisterClasses), |
33 | 0 | 0, 0, ARCRegDiffLists, 0, |
34 | 0 | ARCSubRegIdxLists, |
35 | 0 | ARR_SIZE(ARCSubRegIdxLists), 0); |
36 | 0 | } |
37 | | |
38 | | const char *ARC_reg_name(csh handle, unsigned int reg) |
39 | 0 | { |
40 | 0 | return ARC_LLVM_getRegisterName(reg); |
41 | 0 | } |
42 | | |
43 | | void ARC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) |
44 | 0 | { |
45 | | // Not used by ARC. Information is set after disassembly. |
46 | 0 | } |
47 | | |
48 | | static const char *const insn_name_maps[] = { |
49 | | #include "ARCGenCSMappingInsnName.inc" |
50 | | }; |
51 | | |
52 | | const char *ARC_insn_name(csh handle, unsigned int id) |
53 | 0 | { |
54 | 0 | #ifndef CAPSTONE_DIET |
55 | 0 | if (id < ARR_SIZE(insn_name_maps)) |
56 | 0 | return insn_name_maps[id]; |
57 | | // not found |
58 | 0 | return NULL; |
59 | | #else |
60 | | return NULL; |
61 | | #endif |
62 | 0 | } |
63 | | |
64 | | #ifndef CAPSTONE_DIET |
65 | | static const name_map group_name_maps[] = { |
66 | | { ARC_GRP_INVALID, NULL }, |
67 | | |
68 | | { ARC_GRP_JUMP, "jump" }, |
69 | | { ARC_GRP_CALL, "call" }, |
70 | | { ARC_GRP_RET, "return" }, |
71 | | { ARC_GRP_BRANCH_RELATIVE, "branch_relative" }, |
72 | | |
73 | | }; |
74 | | #endif |
75 | | |
76 | | const char *ARC_group_name(csh handle, unsigned int id) |
77 | 0 | { |
78 | 0 | #ifndef CAPSTONE_DIET |
79 | 0 | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
80 | | #else |
81 | | return NULL; |
82 | | #endif |
83 | 0 | } |
84 | | |
85 | | void ARC_reg_access(const cs_insn *insn, cs_regs regs_read, |
86 | | uint8_t *regs_read_count, cs_regs regs_write, |
87 | | uint8_t *regs_write_count) |
88 | 0 | { |
89 | 0 | uint8_t i; |
90 | 0 | uint8_t read_count, write_count; |
91 | 0 | cs_arc *arc = &(insn->detail->arc); |
92 | |
|
93 | 0 | read_count = insn->detail->regs_read_count; |
94 | 0 | write_count = insn->detail->regs_write_count; |
95 | | |
96 | | // implicit registers |
97 | 0 | memcpy(regs_read, insn->detail->regs_read, |
98 | 0 | read_count * sizeof(insn->detail->regs_read[0])); |
99 | 0 | memcpy(regs_write, insn->detail->regs_write, |
100 | 0 | write_count * sizeof(insn->detail->regs_write[0])); |
101 | | |
102 | | // explicit registers |
103 | 0 | for (i = 0; i < arc->op_count; i++) { |
104 | 0 | cs_arc_op *op = &(arc->operands[i]); |
105 | 0 | switch ((int)op->type) { |
106 | 0 | case ARC_OP_REG: |
107 | 0 | if ((op->access & CS_AC_READ) && |
108 | 0 | !arr_exist(regs_read, read_count, op->reg)) { |
109 | 0 | regs_read[read_count] = (uint16_t)op->reg; |
110 | 0 | read_count++; |
111 | 0 | } |
112 | 0 | if ((op->access & CS_AC_WRITE) && |
113 | 0 | !arr_exist(regs_write, write_count, op->reg)) { |
114 | 0 | regs_write[write_count] = (uint16_t)op->reg; |
115 | 0 | write_count++; |
116 | 0 | } |
117 | 0 | break; |
118 | 0 | default: |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | } |
122 | | |
123 | 0 | *regs_read_count = read_count; |
124 | 0 | *regs_write_count = write_count; |
125 | 0 | } |
126 | | |
127 | | const insn_map arc_insns[] = { |
128 | | #include "ARCGenCSMappingInsn.inc" |
129 | | }; |
130 | | |
131 | | void ARC_set_instr_map_data(MCInst *MI) |
132 | 0 | { |
133 | 0 | map_cs_id(MI, arc_insns, ARR_SIZE(arc_insns)); |
134 | 0 | map_implicit_reads(MI, arc_insns); |
135 | 0 | map_implicit_writes(MI, arc_insns); |
136 | 0 | map_groups(MI, arc_insns); |
137 | 0 | } |
138 | | |
139 | | bool ARC_getInstruction(csh handle, const uint8_t *code, size_t code_len, |
140 | | MCInst *instr, uint16_t *size, uint64_t address, |
141 | | void *info) |
142 | 0 | { |
143 | 0 | uint64_t temp_size; |
144 | 0 | ARC_init_cs_detail(instr); |
145 | 0 | DecodeStatus Result = ARC_LLVM_getInstruction(instr, &temp_size, code, |
146 | 0 | code_len, address, info); |
147 | 0 | ARC_set_instr_map_data(instr); |
148 | 0 | *size = temp_size; |
149 | 0 | if (Result == MCDisassembler_SoftFail) { |
150 | 0 | MCInst_setSoftFail(instr); |
151 | 0 | } |
152 | 0 | return Result != MCDisassembler_Fail; |
153 | 0 | } |
154 | | |
155 | | void ARC_printer(MCInst *MI, SStream *O, |
156 | | void * /* MCRegisterInfo* */ info) |
157 | 0 | { |
158 | 0 | MCRegisterInfo *MRI = (MCRegisterInfo *)info; |
159 | 0 | MI->MRI = MRI; |
160 | |
|
161 | 0 | ARC_LLVM_printInst(MI, MI->address, "", O); |
162 | 0 | } |
163 | | |
164 | | void ARC_setup_op(cs_arc_op *op) |
165 | 0 | { |
166 | 0 | memset(op, 0, sizeof(cs_arc_op)); |
167 | 0 | op->type = ARC_OP_INVALID; |
168 | 0 | } |
169 | | |
170 | | void ARC_init_cs_detail(MCInst *MI) |
171 | 0 | { |
172 | 0 | if (!detail_is_set(MI)) { |
173 | 0 | return; |
174 | 0 | } |
175 | 0 | unsigned int i; |
176 | |
|
177 | 0 | memset(get_detail(MI), 0, |
178 | 0 | offsetof(cs_detail, arc) + sizeof(cs_arc)); |
179 | |
|
180 | 0 | for (i = 0; i < ARR_SIZE(ARC_get_detail(MI)->operands); |
181 | 0 | i++) |
182 | 0 | ARC_setup_op( |
183 | 0 | &ARC_get_detail(MI)->operands[i]); |
184 | 0 | } |
185 | | |
186 | | static const map_insn_ops insn_operands[] = { |
187 | | #include "ARCGenCSMappingInsnOp.inc" |
188 | | }; |
189 | | |
190 | | void ARC_set_detail_op_imm(MCInst *MI, unsigned OpNum, |
191 | | arc_op_type ImmType, int64_t Imm) |
192 | 0 | { |
193 | 0 | if (!detail_is_set(MI)) |
194 | 0 | return; |
195 | 0 | ARC_check_safe_inc(MI); |
196 | 0 | CS_ASSERT((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_IMM); |
197 | 0 | CS_ASSERT(ImmType == ARC_OP_IMM); |
198 | |
|
199 | 0 | ARC_get_detail_op(MI, 0)->type = ImmType; |
200 | 0 | ARC_get_detail_op(MI, 0)->imm = Imm; |
201 | 0 | ARC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
202 | 0 | ARC_inc_op_count(MI); |
203 | 0 | } |
204 | | |
205 | | void ARC_set_detail_op_reg(MCInst *MI, unsigned OpNum, arc_reg Reg) |
206 | 0 | { |
207 | 0 | if (!detail_is_set(MI)) |
208 | 0 | return; |
209 | 0 | ARC_check_safe_inc(MI); |
210 | 0 | CS_ASSERT((map_get_op_type(MI, OpNum) & ~CS_OP_MEM) == CS_OP_REG); |
211 | |
|
212 | 0 | ARC_get_detail_op(MI, 0)->type = ARC_OP_REG; |
213 | 0 | ARC_get_detail_op(MI, 0)->reg = Reg; |
214 | 0 | ARC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); |
215 | 0 | ARC_inc_op_count(MI); |
216 | 0 | } |
217 | | |
218 | | void ARC_add_cs_detail(MCInst *MI, int op_group, |
219 | | va_list args) |
220 | 0 | { |
221 | 0 | if (!detail_is_set(MI)) |
222 | 0 | return; |
223 | | |
224 | 0 | unsigned OpNum = va_arg(args, unsigned); |
225 | 0 | cs_op_type op_type = map_get_op_type(MI, OpNum); |
226 | 0 | cs_op_type base_op_type = op_type; |
227 | 0 | cs_op_type offset_op_type; |
228 | | // Fill cs_detail |
229 | 0 | switch (op_group) { |
230 | 0 | default: |
231 | 0 | printf("ERROR: Operand group %d not handled!\n", op_group); |
232 | 0 | CS_ASSERT_RET(0); |
233 | 0 | case ARC_OP_GROUP_Operand: |
234 | 0 | if (op_type == CS_OP_IMM) { |
235 | 0 | ARC_set_detail_op_imm(MI, OpNum, ARC_OP_IMM, |
236 | 0 | MCInst_getOpVal(MI, OpNum)); |
237 | 0 | } else if (op_type == CS_OP_REG) { |
238 | 0 | ARC_set_detail_op_reg(MI, OpNum, |
239 | 0 | MCInst_getOpVal(MI, OpNum)); |
240 | 0 | } else { |
241 | | // Expression |
242 | 0 | ARC_set_detail_op_imm(MI, OpNum, ARC_OP_IMM, |
243 | 0 | MCOperand_getImm(MCInst_getOperand(MI, OpNum))); |
244 | 0 | } |
245 | 0 | break; |
246 | 0 | case ARC_OP_GROUP_PredicateOperand: |
247 | 0 | if (op_type == CS_OP_IMM) { |
248 | 0 | ARC_set_detail_op_imm(MI, OpNum, ARC_OP_IMM, |
249 | 0 | MCInst_getOpVal(MI, OpNum)); |
250 | 0 | } else |
251 | 0 | CS_ASSERT(0 && "Op type not handled."); |
252 | 0 | break; |
253 | 0 | case ARC_OP_GROUP_MemOperandRI: |
254 | 0 | if (base_op_type == CS_OP_REG) { |
255 | 0 | ARC_set_detail_op_reg(MI, OpNum, |
256 | 0 | MCInst_getOpVal(MI, OpNum)); |
257 | 0 | } else |
258 | 0 | CS_ASSERT(0 && "Op type not handled."); |
259 | 0 | offset_op_type = map_get_op_type(MI, OpNum+1); |
260 | 0 | if (offset_op_type == CS_OP_IMM) { |
261 | 0 | ARC_set_detail_op_imm(MI, OpNum+1, ARC_OP_IMM, |
262 | 0 | MCInst_getOpVal(MI, OpNum+1)); |
263 | 0 | } else |
264 | 0 | CS_ASSERT(0 && "Op type not handled."); |
265 | 0 | break; |
266 | 0 | case ARC_OP_GROUP_BRCCPredicateOperand: |
267 | 0 | if (op_type == CS_OP_IMM) { |
268 | 0 | ARC_set_detail_op_imm(MI, OpNum, ARC_OP_IMM, |
269 | 0 | MCInst_getOpVal(MI, OpNum)); |
270 | 0 | } else |
271 | 0 | CS_ASSERT(0 && "Op type not handled."); |
272 | 0 | break; |
273 | 0 | case ARC_OP_GROUP_CCOperand: |
274 | 0 | if (op_type == CS_OP_IMM) { |
275 | 0 | ARC_set_detail_op_imm(MI, OpNum, ARC_OP_IMM, |
276 | 0 | MCInst_getOpVal(MI, OpNum)); |
277 | 0 | } else |
278 | 0 | CS_ASSERT(0 && "Op type not handled."); |
279 | 0 | break; |
280 | 0 | case ARC_OP_GROUP_U6: |
281 | 0 | if (op_type == CS_OP_IMM) { |
282 | 0 | ARC_set_detail_op_imm(MI, OpNum, ARC_OP_IMM, |
283 | 0 | MCInst_getOpVal(MI, OpNum)); |
284 | 0 | } else |
285 | 0 | CS_ASSERT(0 && "Op type not handled."); |
286 | 0 | break; |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | | #endif |