/src/capstonenext/arch/Xtensa/XtensaMapping.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By billow <billow.fun@gmail.com>, 2024 */ |
3 | | |
4 | | #include <capstone/xtensa.h> |
5 | | |
6 | | #include "../../MCRegisterInfo.h" |
7 | | #include "../../MCInst.h" |
8 | | #include "../../SStream.h" |
9 | | #include "../../Mapping.h" |
10 | | #include "../../utils.h" |
11 | | #include "../../cs_simple_types.h" |
12 | | #include "XtensaDisassembler.h" |
13 | | #include "XtensaInstPrinter.h" |
14 | | #include "priv.h" |
15 | | #include "XtensaMapping.h" |
16 | | |
17 | | #ifndef CAPSTONE_DIET |
18 | | |
19 | | static const char *const insn_name_maps[] = { |
20 | | #include "XtensaGenCSMappingInsnName.inc" |
21 | | }; |
22 | | |
23 | | static const name_map group_name_maps[] = { |
24 | | #include "XtensaGenCSFeatureName.inc" |
25 | | }; |
26 | | |
27 | | static const insn_map mapping_insns[] = { |
28 | | #include "XtensaGenCSMappingInsn.inc" |
29 | | }; |
30 | | |
31 | | static const map_insn_ops insn_operands[] = { |
32 | | #include "XtensaGenCSMappingInsnOp.inc" |
33 | | }; |
34 | | |
35 | | #endif |
36 | | |
37 | | #define GET_REGINFO_MC_DESC |
38 | | #include "XtensaGenRegisterInfo.inc" |
39 | | #include "../../MathExtras.h" |
40 | | |
41 | | void Xtensa_init_mri(MCRegisterInfo *mri) |
42 | 1.20k | { |
43 | 1.20k | MCRegisterInfo_InitMCRegisterInfo( |
44 | 1.20k | mri, XtensaRegDesc, ARR_SIZE(XtensaRegDesc), 0, 0, |
45 | 1.20k | XtensaMCRegisterClasses, ARR_SIZE(XtensaMCRegisterClasses), 0, |
46 | 1.20k | 0, XtensaRegDiffLists, NULL, XtensaSubRegIdxLists, |
47 | 1.20k | ARR_SIZE(XtensaSubRegIdxLists), XtensaRegEncodingTable); |
48 | 1.20k | } |
49 | | |
50 | | void Xtensa_printer(MCInst *MI, SStream *OS, void *info) |
51 | 55.3k | { |
52 | 55.3k | Xtensa_LLVM_printInstruction(MI, MI->address, OS); |
53 | 55.3k | } |
54 | | |
55 | | static void set_instr_map_data(MCInst *MI) |
56 | 55.3k | { |
57 | 55.3k | #ifndef CAPSTONE_DIET |
58 | 55.3k | map_cs_id(MI, mapping_insns, ARR_SIZE(mapping_insns)); |
59 | 55.3k | map_implicit_reads(MI, mapping_insns); |
60 | 55.3k | map_implicit_writes(MI, mapping_insns); |
61 | 55.3k | map_groups(MI, mapping_insns); |
62 | | |
63 | 55.3k | const xtensa_suppl_info *suppl_info = |
64 | 55.3k | map_get_suppl_info(MI, mapping_insns); |
65 | 55.3k | if (suppl_info) { |
66 | 55.3k | Xtensa_get_detail(MI)->format = suppl_info->form; |
67 | 55.3k | } |
68 | 55.3k | #endif |
69 | 55.3k | } |
70 | | |
71 | | bool Xtensa_disasm(csh handle, const uint8_t *code, size_t code_len, |
72 | | MCInst *instr, uint16_t *size, uint64_t address, void *info) |
73 | 55.9k | { |
74 | 55.9k | DecodeStatus res = Xtensa_LLVM_getInstruction(instr, size, code, |
75 | 55.9k | code_len, address); |
76 | 55.9k | if (res != MCDisassembler_Fail) { |
77 | 55.3k | set_instr_map_data(instr); |
78 | 55.3k | } |
79 | 55.9k | if (res == MCDisassembler_SoftFail) { |
80 | 0 | MCInst_setSoftFail(instr); |
81 | 0 | } |
82 | 55.9k | return res != MCDisassembler_Fail; |
83 | 55.9k | } |
84 | | |
85 | | const char *Xtensa_reg_name(csh handle, unsigned int id) |
86 | 5.80k | { |
87 | 5.80k | return Xtensa_LLVM_getRegisterName(id); |
88 | 5.80k | } |
89 | | |
90 | | void Xtensa_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) |
91 | 55.3k | { |
92 | | // Done in Xtensa_disasm |
93 | 55.3k | } |
94 | | |
95 | | const char *Xtensa_insn_name(csh handle, unsigned int id) |
96 | 55.3k | { |
97 | 55.3k | #ifndef CAPSTONE_DIET |
98 | 55.3k | if (id >= ARR_SIZE(insn_name_maps)) { |
99 | 0 | return NULL; |
100 | 0 | } |
101 | 55.3k | return insn_name_maps[id]; |
102 | | #else |
103 | | return NULL; |
104 | | #endif |
105 | 55.3k | } |
106 | | |
107 | | const char *Xtensa_group_name(csh handle, unsigned int id) |
108 | 43.5k | { |
109 | 43.5k | #ifndef CAPSTONE_DIET |
110 | 43.5k | return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); |
111 | | #else |
112 | | return NULL; |
113 | | #endif |
114 | 43.5k | } |
115 | | |
116 | | #ifndef CAPSTONE_DIET |
117 | | void Xtensa_reg_access(const cs_insn *insn, cs_regs regs_read, |
118 | | uint8_t *regs_read_count, cs_regs regs_write, |
119 | | uint8_t *regs_write_count) |
120 | 0 | { |
121 | 0 | uint8_t i; |
122 | 0 | uint8_t read_count, write_count; |
123 | 0 | cs_xtensa *detail = &(insn->detail->xtensa); |
124 | |
|
125 | 0 | read_count = insn->detail->regs_read_count; |
126 | 0 | write_count = insn->detail->regs_write_count; |
127 | | |
128 | | // implicit registers |
129 | 0 | memcpy(regs_read, insn->detail->regs_read, |
130 | 0 | read_count * sizeof(insn->detail->regs_read[0])); |
131 | 0 | memcpy(regs_write, insn->detail->regs_write, |
132 | 0 | write_count * sizeof(insn->detail->regs_write[0])); |
133 | | |
134 | | // explicit registers |
135 | 0 | for (i = 0; i < detail->op_count; i++) { |
136 | 0 | cs_xtensa_op *op = &(detail->operands[i]); |
137 | 0 | switch (op->type) { |
138 | 0 | case XTENSA_OP_REG: |
139 | 0 | if ((op->access & CS_AC_READ) && |
140 | 0 | !arr_exist(regs_read, read_count, op->reg)) { |
141 | 0 | regs_read[read_count] = (uint16_t)op->reg; |
142 | 0 | read_count++; |
143 | 0 | } |
144 | 0 | if ((op->access & CS_AC_WRITE) && |
145 | 0 | !arr_exist(regs_write, write_count, op->reg)) { |
146 | 0 | regs_write[write_count] = (uint16_t)op->reg; |
147 | 0 | write_count++; |
148 | 0 | } |
149 | 0 | break; |
150 | 0 | case XTENSA_OP_MEM: |
151 | | // registers appeared in memory references always being read |
152 | 0 | if ((op->mem.base != XTENSA_REG_INVALID) && |
153 | 0 | !arr_exist(regs_read, read_count, op->mem.base)) { |
154 | 0 | regs_read[read_count] = (uint16_t)op->mem.base; |
155 | 0 | read_count++; |
156 | 0 | } |
157 | 0 | if ((insn->detail->writeback) && |
158 | 0 | (op->mem.base != XTENSA_REG_INVALID) && |
159 | 0 | !arr_exist(regs_write, write_count, op->mem.base)) { |
160 | 0 | regs_write[write_count] = |
161 | 0 | (uint16_t)op->mem.base; |
162 | 0 | write_count++; |
163 | 0 | } |
164 | 0 | default: |
165 | 0 | break; |
166 | 0 | } |
167 | 0 | } |
168 | | |
169 | 0 | *regs_read_count = read_count; |
170 | 0 | *regs_write_count = write_count; |
171 | 0 | } |
172 | | #endif |
173 | | |
174 | | int64_t Xtensa_L32R_Value(MCInst *MI, int op_num) |
175 | 6.17k | { |
176 | 6.17k | int64_t InstrOff = MCOperand_getImm(MCInst_getOperand(MI, (op_num))); |
177 | 6.17k | CS_ASSERT((InstrOff >= -262144 && InstrOff <= -4) && |
178 | 6.17k | "Invalid argument, value must be in ranges [-262144,-4]"); |
179 | 6.17k | int64_t Value = 0; |
180 | 6.17k | if (MI->csh->LITBASE & 0x1) { |
181 | 0 | Value = (MI->csh->LITBASE & 0xfffff000) + InstrOff; |
182 | 6.17k | } else { |
183 | 6.17k | Value = (((int64_t)MI->address + 3) & ~0x3) + InstrOff; |
184 | 6.17k | } |
185 | 6.17k | return Value; |
186 | 6.17k | } |
187 | | |
188 | | void Xtensa_add_cs_detail_0(MCInst *MI, xtensa_op_group op_group, int op_num) |
189 | 154k | { |
190 | 154k | if (!detail_is_set(MI)) { |
191 | 0 | return; |
192 | 0 | } |
193 | | |
194 | 154k | cs_xtensa_op *xop = Xtensa_get_detail_op(MI, 0); |
195 | 154k | switch (op_group) { |
196 | 114k | case Xtensa_OP_GROUP_Operand: { |
197 | 114k | const MCOperand *MC = MCInst_getOperand(MI, op_num); |
198 | 114k | if (MCOperand_isReg(MC)) { |
199 | 114k | xop->type = XTENSA_OP_REG; |
200 | 114k | xop->reg = MC->RegVal; |
201 | 114k | } else if (MCOperand_isImm(MC)) { |
202 | 0 | xop->type = XTENSA_OP_IMM; |
203 | 0 | xop->imm = MC->ImmVal; |
204 | 0 | } |
205 | 114k | } break; |
206 | 476 | case Xtensa_OP_GROUP_Imm1_16_AsmOperand: |
207 | 3.82k | case Xtensa_OP_GROUP_Imm1n_15_AsmOperand: |
208 | 3.87k | case Xtensa_OP_GROUP_Imm7_22_AsmOperand: |
209 | 4.00k | case Xtensa_OP_GROUP_Imm8_AsmOperand: |
210 | 4.25k | case Xtensa_OP_GROUP_Imm8_sh8_AsmOperand: |
211 | 4.28k | case Xtensa_OP_GROUP_Imm8n_7_AsmOperand: |
212 | 4.28k | case Xtensa_OP_GROUP_Imm12_AsmOperand: |
213 | 4.59k | case Xtensa_OP_GROUP_Imm12m_AsmOperand: |
214 | 6.07k | case Xtensa_OP_GROUP_Imm32n_95_AsmOperand: |
215 | 6.21k | case Xtensa_OP_GROUP_Imm64n_4n_AsmOperand: |
216 | 6.21k | case Xtensa_OP_GROUP_ImmOperand_minus32_28_4: |
217 | 7.41k | case Xtensa_OP_GROUP_Uimm5_AsmOperand: |
218 | 8.57k | case Xtensa_OP_GROUP_Uimm4_AsmOperand: |
219 | 8.76k | case Xtensa_OP_GROUP_Shimm0_31_AsmOperand: |
220 | 8.76k | case Xtensa_OP_GROUP_Shimm1_31_AsmOperand: |
221 | 9.54k | case Xtensa_OP_GROUP_B4const_AsmOperand: |
222 | 9.94k | case Xtensa_OP_GROUP_B4constu_AsmOperand: |
223 | 9.94k | case Xtensa_OP_GROUP_ImmOperand_minus16_14_2: |
224 | 9.94k | case Xtensa_OP_GROUP_ImmOperand_minus64_56_8: |
225 | 9.94k | case Xtensa_OP_GROUP_ImmOperand_0_56_8: |
226 | 9.94k | case Xtensa_OP_GROUP_ImmOperand_minus16_47_1: |
227 | 9.94k | case Xtensa_OP_GROUP_ImmOperand_0_3_1: |
228 | 9.94k | case Xtensa_OP_GROUP_ImmOperand_0_63_1: |
229 | 10.2k | case Xtensa_OP_GROUP_Entry_Imm12_AsmOperand: |
230 | 11.2k | case Xtensa_OP_GROUP_Offset8m32_AsmOperand: |
231 | 13.0k | case Xtensa_OP_GROUP_Select_4_AsmOperand: |
232 | 13.7k | case Xtensa_OP_GROUP_Select_2_AsmOperand: |
233 | 15.1k | case Xtensa_OP_GROUP_Select_8_AsmOperand: |
234 | 15.5k | case Xtensa_OP_GROUP_Offset_16_16_AsmOperand: |
235 | 17.0k | case Xtensa_OP_GROUP_Offset_256_8_AsmOperand: |
236 | 17.7k | case Xtensa_OP_GROUP_Offset_256_16_AsmOperand: |
237 | 18.1k | case Xtensa_OP_GROUP_Offset_256_4_AsmOperand: |
238 | 18.9k | case Xtensa_OP_GROUP_Select_16_AsmOperand: |
239 | 19.2k | case Xtensa_OP_GROUP_Offset_128_2_AsmOperand: |
240 | 19.2k | case Xtensa_OP_GROUP_Offset_128_1_AsmOperand: |
241 | 21.2k | case Xtensa_OP_GROUP_Offset_64_16_AsmOperand: |
242 | 21.5k | case Xtensa_OP_GROUP_Select_256_AsmOperand: { |
243 | 21.5k | int64_t val = MCOperand_getImm(MCInst_getOperand(MI, op_num)); |
244 | 21.5k | xop->type = XTENSA_OP_IMM; |
245 | 21.5k | xop->imm = (int32_t)val; |
246 | 21.5k | } break; |
247 | 4.17k | case Xtensa_OP_GROUP_BranchTarget: |
248 | 5.22k | case Xtensa_OP_GROUP_JumpTarget: |
249 | 7.79k | case Xtensa_OP_GROUP_CallOperand: |
250 | 7.80k | case Xtensa_OP_GROUP_LoopTarget: { |
251 | 7.80k | int64_t val = |
252 | 7.80k | MCOperand_getImm(MCInst_getOperand(MI, op_num)) + 4; |
253 | 7.80k | xop->type = XTENSA_OP_IMM; |
254 | 7.80k | xop->imm = (int32_t)val; |
255 | 7.80k | } break; |
256 | 3.08k | case Xtensa_OP_GROUP_L32RTarget: { |
257 | 3.08k | xop->type = XTENSA_OP_L32R; |
258 | 3.08k | xop->imm = (int32_t)Xtensa_L32R_Value(MI, op_num); |
259 | 3.08k | } break; |
260 | 6.79k | case Xtensa_OP_GROUP_MemOperand: { |
261 | 6.79k | unsigned reg = |
262 | 6.79k | MCOperand_getReg(MCInst_getOperand(MI, (op_num))); |
263 | 6.79k | int64_t imm8 = |
264 | 6.79k | MCOperand_getImm(MCInst_getOperand(MI, op_num + 1)); |
265 | 6.79k | xop->type = XTENSA_OP_MEM; |
266 | 6.79k | xop->mem.base = reg; |
267 | 6.79k | xop->mem.disp = (int32_t)imm8; |
268 | 6.79k | } break; |
269 | 154k | } |
270 | | |
271 | 154k | xop->access = map_get_op_access(MI, op_num); |
272 | 154k | Xtensa_inc_op_count(MI); |
273 | 154k | } |