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