1 /* radare2 - LGPL - Copyright 2016-2018 - pancake */
2
3 #include <string.h>
4 #include <r_types.h>
5 #include <r_lib.h>
6 #include <r_asm.h>
7 #include <r_anal.h>
8
9 #include <xtensa-isa.h>
10
11 #define CM ","
12 #define XTENSA_MAX_LENGTH 8
13
xtensa_length(const ut8 * insn)14 static int xtensa_length(const ut8 *insn) {
15 static int length_table[16] = { 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 8, 8 };
16 return length_table[*insn & 0xf];
17 }
18
xtensa_offset(ut64 addr,const ut8 * buf)19 static inline ut64 xtensa_offset (ut64 addr, const ut8 *buf) {
20 ut32 offset = ((buf[0] >> 4) & 0xc) | (((ut32)buf[1]) << 4) | (((ut32)buf[2]) << 12);
21 if (offset & 0x80000) {
22 return (addr + 4 + offset - 0x100000) & ~3;
23 }
24 return (addr + 4 + offset) & ~3;
25 }
26
xtensa_imm18s(ut64 addr,const ut8 * buf)27 static inline ut64 xtensa_imm18s (ut64 addr, const ut8 *buf) {
28 ut32 offset = (buf[0] >> 6) | (((ut32)buf[1]) << 2) | (((ut32)buf[2]) << 10);
29 if (offset & 0x20000) {
30 return addr + 4 + offset - 0x40000;
31 }
32 return addr + 4 + offset;
33 }
34
xtensa_imm6s(ut64 addr,const ut8 * buf)35 static inline ut64 xtensa_imm6s (ut64 addr, const ut8 *buf) {
36 ut8 imm6 = (buf[1] >> 4) | (buf[0] & 0x30);
37 return (addr + 4 + imm6);
38 }
39
xtensa_imm8s(ut64 addr,ut8 imm8)40 static inline ut64 xtensa_imm8s (ut64 addr, ut8 imm8) {
41 if (imm8 & 0x80) {
42 return (addr + 4 + imm8 - 0x100);
43 }
44 return (addr + 4 + imm8);
45 }
46
xtensa_imm12s(ut64 addr,const ut8 * buf)47 static inline ut64 xtensa_imm12s (ut64 addr, const ut8 *buf) {
48 ut16 imm12 = (buf[1] >> 4) | (((ut16)buf[2]) << 4);
49 if (imm12 & 0x800) {
50 return (addr + 4 + imm12 - 0x1000);
51 }
52 return (addr + 4 + imm12);
53 }
54
55 typedef void (*XtensaOpFn) (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf);
56
xtensa_null_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)57 static void xtensa_null_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
58 op->type = R_ANAL_OP_TYPE_NULL;
59 }
60
xtensa_unk_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)61 static void xtensa_unk_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
62 op->type = R_ANAL_OP_TYPE_UNK;
63 }
64
xtensa_mov_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)65 static void xtensa_mov_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
66 op->type = R_ANAL_OP_TYPE_MOV;
67 }
68
xtensa_load_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)69 static void xtensa_load_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
70 op->type = R_ANAL_OP_TYPE_LOAD;
71 }
72
xtensa_store_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)73 static void xtensa_store_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
74 op->type = R_ANAL_OP_TYPE_STORE;
75 }
76
xtensa_add_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)77 static void xtensa_add_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
78 op->type = R_ANAL_OP_TYPE_ADD;
79 }
80
xtensa_sub_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)81 static void xtensa_sub_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
82 op->type = R_ANAL_OP_TYPE_SUB;
83 }
84
xtensa_mul_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)85 static void xtensa_mul_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
86 op->type = R_ANAL_OP_TYPE_MUL;
87 }
88
xtensa_div_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)89 static void xtensa_div_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
90 op->type = R_ANAL_OP_TYPE_DIV;
91 }
92
xtensa_mod_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)93 static void xtensa_mod_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
94 op->type = R_ANAL_OP_TYPE_MOD;
95 }
96
xtensa_and_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)97 static void xtensa_and_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
98 op->type = R_ANAL_OP_TYPE_AND;
99 }
100
xtensa_or_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)101 static void xtensa_or_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
102 op->type = R_ANAL_OP_TYPE_OR;
103 }
104
xtensa_xor_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)105 static void xtensa_xor_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
106 op->type = R_ANAL_OP_TYPE_XOR;
107 }
108
xtensa_shl_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)109 static void xtensa_shl_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
110 op->type = R_ANAL_OP_TYPE_SHL;
111 }
112
xtensa_shr_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)113 static void xtensa_shr_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
114 op->type = R_ANAL_OP_TYPE_SHR;
115 }
116
xtensa_l32r_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)117 static void xtensa_l32r_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
118 op->type = R_ANAL_OP_TYPE_LOAD;
119 op->ptr = ((addr + 3) & ~3) + ((buf[2] << 8 | buf[1]) << 2) - 0x40000;
120 }
121
xtensa_snm0_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)122 static void xtensa_snm0_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
123 switch ((buf[0] >> 4) & 0xf) {
124 case 0x0: case 0x1: case 0x2: case 0x3:
125 op->type = R_ANAL_OP_TYPE_ILL;
126 break;
127 case 0x8: case 0x9:
128 op->type = R_ANAL_OP_TYPE_RET;
129 break;
130 case 0xa:
131 op->type = R_ANAL_OP_TYPE_UJMP;
132 break;
133 case 0xc: case 0xd: case 0xe: case 0xf:
134 op->type = R_ANAL_OP_TYPE_UCALL;
135 break;
136 default:
137 xtensa_unk_op (anal, op, addr, buf);
138 break;
139 }
140 }
141
xtensa_sync_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)142 static void xtensa_sync_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
143 switch ((buf[0] >> 4) & 0xf) {
144 case 0x0: case 0x1: case 0x2: case 0x3:
145 case 0x8:
146 case 0xc: case 0xd:
147 /* Wait/sync instructions? */
148 op->type = R_ANAL_OP_TYPE_NULL;
149 break;
150 default:
151 xtensa_unk_op (anal, op, addr, buf);
152 break;
153 }
154 }
155
xtensa_rfei_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)156 static void xtensa_rfei_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
157 switch ((buf[0] >> 4) & 0xf) {
158 case 0x0:
159 switch (buf[1] & 0xf) {
160 case 0x0: case 0x1: case 0x2:
161 case 0x4: case 0x5:
162 op->type = R_ANAL_OP_TYPE_RET;
163 break;
164 default:
165 xtensa_unk_op (anal, op, addr, buf);
166 break;
167 }
168 break;
169 case 0x1: case 0x2:
170 op->type = R_ANAL_OP_TYPE_RET;
171 break;
172 default:
173 xtensa_unk_op (anal, op, addr, buf);
174 break;
175 }
176 }
177
xtensa_st0_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)178 static void xtensa_st0_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
179 switch ((buf[1] >> 4) & 0xf) {
180 case 0x0:
181 xtensa_snm0_op (anal, op, addr, buf);
182 break;
183 case 0x1:
184 op->type = R_ANAL_OP_TYPE_CMOV;
185 break;
186 case 0x2:
187 xtensa_sync_op (anal, op, addr, buf);
188 break;
189 case 0x3:
190 xtensa_rfei_op (anal, op, addr, buf);
191 break;
192 case 0x4:
193 op->type = R_ANAL_OP_TYPE_TRAP;
194 break;
195 case 0x5: case 0x6: case 0x7:
196 op->type = R_ANAL_OP_TYPE_SWI;
197 break;
198 case 0x8: case 0x9: case 0xa: case 0xb:
199 op->type = R_ANAL_OP_TYPE_MOV;
200 break;
201 default:
202 xtensa_unk_op (anal, op, addr, buf);
203 break;
204 }
205 }
206
xtensa_st1_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)207 static void xtensa_st1_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
208 switch ((buf[1] >> 4) & 0xf) {
209 case 0x0: case 0x1: case 0x2: case 0x3:
210 case 0x4:
211 /* Set shift-amount-register */
212 op->type = R_ANAL_OP_TYPE_NULL;
213 /*op->type = R_ANAL_OP_TYPE_MOV;*/
214 break;
215 case 0x6: case 0x7:
216 op->type = R_ANAL_OP_TYPE_IO;
217 /*op->type = R_ANAL_OP_TYPE_MOV;*/
218 break;
219 case 0x8:
220 op->type = R_ANAL_OP_TYPE_SWI;
221 break;
222 case 0xe: case 0xf:
223 op->type = R_ANAL_OP_TYPE_NULL;
224 break;
225 default:
226 xtensa_unk_op (anal, op, addr, buf);
227 break;
228 }
229 }
230
xtensa_rt0_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)231 static void xtensa_rt0_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
232 switch (buf[1] & 0xf) {
233 case 0:
234 op->type = R_ANAL_OP_TYPE_NOT;
235 break;
236 case 1:
237 /*op->type = R_ANAL_OP_TYPE_ABS;*/
238 op->type = R_ANAL_OP_TYPE_MOV;
239 break;
240 default:
241 xtensa_unk_op (anal, op, addr, buf);
242 break;
243 }
244 }
245
xtensa_tlb_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)246 static void xtensa_tlb_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
247 switch ((buf[2] >> 4) & 0xf) {
248 case 0x3:
249 case 0x4: case 0x5: case 0x6: case 0x7:
250 case 0xb:
251 case 0xc: case 0xd: case 0xe: case 0xf:
252 op->type = R_ANAL_OP_TYPE_MOV;
253 break;
254 default:
255 xtensa_unk_op (anal, op, addr, buf);
256 break;
257 }
258 }
259
xtensa_accer_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)260 static void xtensa_accer_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
261 switch ((buf[2] >> 4) & 0xf) {
262 case 0x0:
263 case 0x8:
264 op->type = R_ANAL_OP_TYPE_IO;
265 /*op->type = R_ANAL_OP_TYPE_MOV;*/
266 break;
267 default:
268 xtensa_unk_op (anal, op, addr, buf);
269 break;
270 }
271 }
272
xtensa_imp_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)273 static void xtensa_imp_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
274 switch ((buf[1] >> 4) & 0xf) {
275 case 0x0: case 0x1: case 0x2: case 0x3:
276 case 0x8: case 0x9:
277 op->type = R_ANAL_OP_TYPE_NULL;
278 break;
279 case 0xe:
280 if (((buf[0] >> 4) & 0xf) <= 1) {
281 op->type = R_ANAL_OP_TYPE_RET;
282 } else {
283 xtensa_unk_op (anal, op, addr, buf);
284 }
285 break;
286 default:
287 xtensa_unk_op (anal, op, addr, buf);
288 break;
289 }
290 }
291
292 static XtensaOpFn xtensa_rst0_fns[] = {
293 xtensa_st0_op,
294 xtensa_and_op,
295 xtensa_or_op,
296 xtensa_xor_op,
297 xtensa_st1_op,
298 xtensa_tlb_op,
299 xtensa_rt0_op,
300 xtensa_unk_op,
301 xtensa_add_op,
302 xtensa_add_op,
303 xtensa_add_op,
304 xtensa_add_op,
305 xtensa_sub_op,
306 xtensa_sub_op,
307 xtensa_sub_op,
308 xtensa_sub_op
309 };
310
311 static XtensaOpFn xtensa_rst1_fns[] = {
312 xtensa_shl_op,
313 xtensa_shl_op,
314 xtensa_shr_op,
315 xtensa_shr_op,
316 xtensa_shr_op,
317 xtensa_unk_op,
318 xtensa_null_op,
319 xtensa_accer_op,
320 xtensa_shr_op,
321 xtensa_shr_op,
322 xtensa_shl_op,
323 xtensa_shr_op,
324 xtensa_mul_op,
325 xtensa_mul_op,
326 xtensa_unk_op,
327 xtensa_imp_op
328 };
329
330 static XtensaOpFn xtensa_rst2_fns[] = {
331 xtensa_and_op,
332 xtensa_and_op,
333 xtensa_or_op,
334 xtensa_or_op,
335 xtensa_xor_op,
336 xtensa_unk_op,
337 xtensa_unk_op,
338 xtensa_unk_op,
339 xtensa_mul_op,
340 xtensa_unk_op,
341 xtensa_mul_op,
342 xtensa_mul_op,
343 xtensa_div_op,
344 xtensa_div_op,
345 xtensa_mod_op,
346 xtensa_mod_op
347 };
348
xtensa_rst0_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)349 static void xtensa_rst0_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
350 xtensa_rst0_fns[(buf[2] >> 4) & 0xf] (anal, op, addr, buf);
351 }
xtensa_rst1_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)352 static void xtensa_rst1_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
353 xtensa_rst1_fns[(buf[2] >> 4) & 0xf] (anal, op, addr, buf);
354 }
355
xtensa_rst2_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)356 static void xtensa_rst2_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
357 xtensa_rst2_fns[(buf[2] >> 4) & 0xf] (anal, op, addr, buf);
358 }
359
xtensa_lsc4_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)360 static void xtensa_lsc4_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
361 switch ((buf[2] >> 4) & 0xf) {
362 case 0x0:
363 xtensa_load_op (anal, op, addr, buf);
364 break;
365 case 0x4:
366 xtensa_store_op (anal, op, addr, buf);
367 break;
368 default:
369 xtensa_unk_op (anal, op, addr, buf);
370 break;
371 }
372 }
373
xtensa_lscx_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)374 static void xtensa_lscx_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
375 op->family = R_ANAL_OP_FAMILY_FPU;
376 switch ((buf[2] >> 4) & 0xf) {
377 case 0x0: case 0x1:
378 xtensa_load_op (anal, op, addr, buf);
379 break;
380 case 0x4: case 0x5:
381 xtensa_store_op (anal, op, addr, buf);
382 break;
383 default:
384 xtensa_unk_op (anal, op, addr, buf);
385 break;
386 }
387 }
388
xtensa_fp0_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)389 static void xtensa_fp0_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
390 op->family = R_ANAL_OP_FAMILY_FPU;
391 switch ((buf[2] >> 4) & 0xf) {
392 case 0x0: case 0x4:
393 op->type = R_ANAL_OP_TYPE_ADD;
394 break;
395 case 0x1: case 0x5:
396 op->type = R_ANAL_OP_TYPE_SUB;
397 break;
398 case 0x2:
399 op->type = R_ANAL_OP_TYPE_MUL;
400 break;
401 case 0x8: case 0x9: case 0xa: case 0xb:
402 case 0xc: case 0xd: case 0xe:
403 op->type = R_ANAL_OP_TYPE_MOV;
404 break;
405 case 0xf:
406 switch ((buf[0] >> 4) & 0xf) {
407 case 0x0: case 0x4: case 0x5:
408 op->type = R_ANAL_OP_TYPE_MOV;
409 break;
410 case 0x1:
411 op->type = R_ANAL_OP_TYPE_ABS;
412 break;
413 case 0x6:
414 op->type = R_ANAL_OP_TYPE_NOT;
415 break;
416 default:
417 xtensa_unk_op (anal, op, addr, buf);
418 break;
419 }
420 break;
421 default:
422 xtensa_unk_op (anal, op, addr, buf);
423 break;
424 }
425 }
426
xtensa_fp1_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)427 static void xtensa_fp1_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
428 op->family = R_ANAL_OP_FAMILY_FPU;
429 switch ((buf[2] >> 4) & 0xf) {
430 case 0x1: case 0x2: case 0x3:
431 case 0x4: case 0x5: case 0x6: case 0x7:
432 op->type = R_ANAL_OP_TYPE_CMP;
433 break;
434 case 0x8: case 0x9: case 0xa: case 0xb:
435 case 0xc: case 0xd:
436 op->type = R_ANAL_OP_TYPE_MOV;
437 break;
438 default:
439 xtensa_unk_op (anal, op, addr, buf);
440 break;
441 }
442 }
443
444 static XtensaOpFn xtensa_qrst_fns[] = {
445 xtensa_rst0_op,
446 xtensa_rst1_op,
447 xtensa_rst2_op,
448 xtensa_mov_op, /*xtensa_rst3_op,*/
449 xtensa_null_op, /*xtensa_extui_op,*/
450 xtensa_null_op, /*xtensa_extui_op,*/
451 xtensa_unk_op, /*xtensa_cust0_op,*/
452 xtensa_unk_op, /*xtensa_cust1_op,*/
453 xtensa_lscx_op,
454 xtensa_lsc4_op,
455 xtensa_fp0_op,
456 xtensa_fp1_op,
457 xtensa_unk_op,
458 xtensa_unk_op,
459 xtensa_unk_op,
460 xtensa_unk_op
461 };
462
xtensa_qrst_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)463 static void xtensa_qrst_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
464 xtensa_qrst_fns[buf[2] & 0xf] (anal, op, addr, buf);
465 }
466
467 static XtensaOpFn xtensa_lsai_fns[] = {
468 xtensa_load_op,
469 xtensa_load_op,
470 xtensa_load_op,
471 xtensa_unk_op,
472 xtensa_store_op,
473 xtensa_store_op,
474 xtensa_store_op,
475 xtensa_null_op, /*xtensa_cache_op,probably not interesting for anal?*/
476 xtensa_unk_op,
477 xtensa_load_op,
478 xtensa_mov_op,
479 xtensa_load_op,
480 xtensa_add_op,
481 xtensa_add_op,
482 xtensa_store_op,
483 xtensa_store_op
484 };
485
xtensa_lsai_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)486 static void xtensa_lsai_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
487 xtensa_lsai_fns[(buf[1] >> 4) & 0xf] (anal, op, addr, buf);
488 }
489
xtensa_lsci_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)490 static void xtensa_lsci_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
491 ut8 r = buf[1] >> 4;
492 op->family = R_ANAL_OP_FAMILY_FPU;
493 if ((r & 3) == 0) {
494 if (r & 4) {
495 xtensa_store_op (anal, op, addr, buf);
496 } else {
497 xtensa_load_op (anal, op, addr, buf);
498 }
499 } else {
500 xtensa_unk_op (anal, op, addr, buf);
501 }
502 }
503
xtensa_calln_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)504 static void xtensa_calln_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
505 op->type = R_ANAL_OP_TYPE_CALL;
506 op->fail = addr + op->size;
507 op->jump = xtensa_offset (addr, buf);
508 }
509
xtensa_b_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)510 static void xtensa_b_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
511 op->type = R_ANAL_OP_TYPE_CJMP;
512 op->fail = addr + op->size;
513 op->jump = xtensa_imm8s (addr, buf[2]);
514 }
515
xtensa_si_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)516 static void xtensa_si_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
517 ut8 n = (buf[0] >> 4) & 3;
518 ut8 m = (buf[0] >> 6);
519 switch (n) {
520 case 0:
521 op->type = R_ANAL_OP_TYPE_JMP;
522 op->jump = xtensa_imm18s (addr, buf);
523 break;
524 case 1:
525 op->type = R_ANAL_OP_TYPE_CJMP;
526 op->fail = addr + op->size;
527 op->jump = xtensa_imm12s (addr, buf);
528 break;
529 case 2:
530 xtensa_b_op (anal, op, addr, buf);
531 break;
532 case 3:
533 switch (m) {
534 case 0:
535 op->type = R_ANAL_OP_TYPE_UPUSH;
536 break;
537 case 1:
538 switch (buf[1] >> 4) {
539 case 0: case 1:
540 xtensa_b_op (anal, op, addr, buf);
541 break;
542 case 0x8: case 0x9: case 0xa:
543 op->type = R_ANAL_OP_TYPE_CJMP;
544 op->fail = addr + op->size;
545 op->jump = addr + 4 + buf[2];
546 break;
547 default:
548 xtensa_unk_op (anal, op, addr, buf);
549 break;
550 }
551 break;
552 case 2: case 3:
553 xtensa_b_op (anal, op, addr, buf);
554 break;
555 default:
556 xtensa_unk_op (anal, op, addr, buf);
557 break;
558 }
559 break;
560 default:
561 xtensa_unk_op (anal, op, addr, buf);
562 break;
563 }
564 }
565
xtensa_st2n_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)566 static void xtensa_st2n_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
567 if (buf[0] & 0x80) {
568 op->type = R_ANAL_OP_TYPE_CJMP;
569 op->fail = addr + op->size;
570 op->jump = xtensa_imm6s (addr, buf);
571 } else {
572 op->type = R_ANAL_OP_TYPE_MOV;
573 }
574 }
575
xtensa_st3n_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf)576 static void xtensa_st3n_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf) {
577 switch ((buf[1] >> 4) & 0xf) {
578 case 0x0:
579 op->type = R_ANAL_OP_TYPE_MOV;
580 break;
581 case 0xf:
582 switch ((buf[0] >> 4) & 0xf) {
583 case 0: case 1:
584 op->type = R_ANAL_OP_TYPE_RET;
585 break;
586 case 2:
587 op->type = R_ANAL_OP_TYPE_TRAP;
588 break;
589 case 3:
590 op->type = R_ANAL_OP_TYPE_NOP;
591 break;
592 case 6:
593 op->type = R_ANAL_OP_TYPE_ILL;
594 break;
595 default:
596 xtensa_unk_op (anal, op, addr, buf);
597 break;
598 }
599 break;
600 default:
601 xtensa_unk_op (anal, op, addr, buf);
602 break;
603 }
604 }
605
606 static XtensaOpFn xtensa_op0_fns[] = {
607 xtensa_qrst_op,
608 xtensa_l32r_op,
609 xtensa_lsai_op,
610 xtensa_lsci_op,
611 xtensa_null_op, /*xtensa_mac16_op,*/
612 xtensa_calln_op,
613 xtensa_si_op,
614 xtensa_b_op,
615
616 xtensa_load_op,
617 xtensa_store_op,
618 xtensa_add_op,
619 xtensa_add_op,
620 xtensa_st2n_op,
621 xtensa_st3n_op,
622 xtensa_null_op, /*xtensa_xt_format1_op,*/ /*TODO*/
623 xtensa_null_op /*xtensa_xt_format2_op*/ /*TODO*/
624 };
625
sign_extend(st32 * value,ut8 bit)626 static inline void sign_extend(st32 *value, ut8 bit) {
627 if (*value & (1 << bit)) {
628 *value |= 0xFFFFFFFF << bit;
629 }
630 }
631
sign_extend2(st32 * value,ut8 bit1,ut8 bit2,ut8 shift)632 static inline void sign_extend2(st32 *value, ut8 bit1, ut8 bit2, ut8 shift) {
633 if (((*value >> bit1) & 1) && ((*value >> bit2) & 1)) {
634 *value |= UT32_MAX << (32 - shift);
635 }
636 }
637
xtensa_check_stack_op(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)638 static void xtensa_check_stack_op(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
639 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
640 st32 imm;
641 ut32 dst;
642 ut32 src;
643
644 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst);
645 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &src);
646 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &imm);
647
648 // wide form of addi requires sign extension
649 if (opcode == 39) {
650 sign_extend (&imm, 7);
651 }
652
653 // a1 = stack
654 if (dst == 1 && src == 1) {
655 op->val = imm;
656 op->stackptr = -imm;
657 op->stackop = R_ANAL_STACK_INC;
658 }
659 }
660
esil_push_signed_imm(RStrBuf * esil,st32 imm)661 static void esil_push_signed_imm(RStrBuf * esil, st32 imm) {
662 if (imm >= 0) {
663 r_strbuf_appendf (esil, "0x%x" CM, imm);
664 } else {
665 r_strbuf_appendf (
666 esil,
667 "0x%x" CM
668 "0x0" CM
669 "-" CM,
670 - imm
671 );
672 }
673 }
674
esil_sign_extend(RStrBuf * esil,ut8 bit)675 static void esil_sign_extend(RStrBuf *esil, ut8 bit) {
676 // check sign bit, and, if needed, apply or mask
677
678 ut32 bit_mask = 1 << bit;
679 ut32 extend_mask = 0xFFFFFFFF << bit;
680
681 r_strbuf_appendf (
682 esil,
683 "DUP" CM
684 "0x%x" CM
685 "&" CM
686 "0" CM
687 "==,$z,!" CM
688 "?{" CM
689 "0x%x" CM
690 "|" CM
691 "}" CM,
692 bit_mask,
693 extend_mask
694 );
695 }
696
esil_load_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)697 static void esil_load_imm(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
698 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
699 ut32 offset;
700 ut32 reg_d;
701 ut32 reg_a;
702 ut8 sign_extend_bit;
703
704 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, ®_d);
705 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, ®_a);
706 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &offset);
707
708 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
709 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
710
711 // example: l32i a2, a1, 0x10
712 // 0x10,a1,+, // address on stack
713 // [x], // read data
714 // a2, // push data reg
715 // = // assign to data reg
716
717 ut8 data_size = opcode == 82 ? 2 // l16ui
718 : opcode == 83 ? 2 // l16si
719 : opcode == 84 ? 4 // l32i
720 : opcode == 31 ? 4 // l32i.n
721 : 1; // opcode == 86 ? 1 : 1; // l8ui
722
723 sign_extend_bit = 0;
724
725 switch (opcode) {
726 case 84: // l32i
727 case 31: // l32i.n
728 offset <<= 2;
729 break;
730 case 83: // l16si
731 sign_extend_bit = 15;
732 /* no break */
733 case 82: // l16ui
734 offset <<= 1;
735 break;
736 }
737
738 r_strbuf_appendf (
739 &op->esil,
740 "0x%x" CM
741 "%s%d" CM
742 "+" CM
743 "[%d]" CM,
744 // offset
745 offset,
746 // address
747 xtensa_regfile_shortname (isa, src_rf),
748 reg_a,
749 // size
750 data_size
751 );
752
753 if (sign_extend_bit != 0) {
754 esil_sign_extend (&op->esil, sign_extend_bit);
755 }
756
757 r_strbuf_appendf (
758 &op->esil,
759 "%s%d" CM
760 "=",
761 // data
762 xtensa_regfile_shortname (isa, dst_rf),
763 reg_d
764 );
765 }
766
esil_load_relative(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)767 static void esil_load_relative(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
768 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
769 ut32 offset;
770 st32 dst;
771
772 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, (ut32 *) &dst);
773 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &offset);
774
775 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
776
777 // example: l32r a2, 0x10
778 // 0x10,$$,3,+ // l32r address + 3 on stack
779 // 0xFFFFFFFC,&, // clear 2 lsb
780 // -, // subtract offset
781 // [4], // read data
782 // a2, // push data reg
783 // = // assign to data reg
784
785 offset = - ((offset | 0xFFFF0000) << 2);
786
787 r_strbuf_appendf (
788 &op->esil,
789 "0x%x" CM
790 "$$" CM
791 "3" CM
792 "+" CM
793 "0xFFFFFFFC" CM
794 "&" CM
795 "-" CM
796 "[4]" CM
797 "%s%d" CM
798 "=",
799 // offset
800 offset,
801 // data
802 xtensa_regfile_shortname (isa, dst_rf),
803 dst
804 );
805 }
806
esil_add_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)807 static void esil_add_imm(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
808 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
809 st32 imm;
810 ut32 dst;
811 ut32 src;
812
813 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst);
814 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &src);
815 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &imm);
816
817 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
818 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
819
820 // example: addi a3, a4, 0x01
821 // a4,0x01,+,a3,=
822
823 // wide form of addi requires sign extension
824 if (opcode == 39) {
825 sign_extend (&imm, 7);
826 }
827
828 r_strbuf_appendf (&op->esil, "%s%d" CM, xtensa_regfile_shortname (isa, src_rf), src);
829 esil_push_signed_imm (&op->esil, imm);
830 r_strbuf_appendf (
831 &op->esil,
832 "+" CM
833 "%s%d" CM
834 "=",
835 xtensa_regfile_shortname (isa, dst_rf),
836 dst
837 );
838 }
839
esil_store_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)840 static void esil_store_imm(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
841 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
842
843 ut32 offset;
844 ut32 reg_d;
845 ut32 reg_a;
846
847 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, ®_d);
848 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, ®_a);
849 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &offset);
850
851 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
852 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
853
854 // example: s32i a2, a1, 0x10
855 // a2, // push data
856 // 0x10,a1,+, // address on stack
857 // =[x] // write data
858
859 ut8 data_size =
860 opcode == 453 ? 4 // s32cli
861 : opcode == 36 ? 4 // s32i.n
862 : opcode == 100 ? 4 // s32i
863 : opcode == 99 ? 2 // s16i
864 : 1; // opcode == 101 ? 1 : 1; // s8i
865
866 switch (opcode) {
867 case 100: // s32i
868 case 453: // s32cli
869 case 36: // s32i.n
870 offset <<= 2;
871 break;
872 case 99: // s16i
873 offset <<= 1;
874 break;
875 }
876
877 r_strbuf_appendf (
878 &op->esil,
879 "%s%d" CM
880 "0x%x" CM
881 "%s%d" CM
882 "+" CM
883 "=[%d]",
884 // data
885 xtensa_regfile_shortname (isa, dst_rf),
886 reg_d,
887 // offset
888 offset,
889 // address
890 xtensa_regfile_shortname (isa, src_rf),
891 reg_a,
892 // size
893 data_size
894 );
895 }
896
esil_move_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)897 static void esil_move_imm(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
898 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
899 st32 imm;
900 ut32 reg;
901
902 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, ®);
903 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, (ut32 *) &imm);
904
905 xtensa_regfile rf = xtensa_operand_regfile (isa, opcode, 0);
906
907 // sign extension
908 // 90: movi
909 if (opcode == 90) {
910 sign_extend (&imm, 11);
911 }
912
913 // 33: movi.n
914 if (opcode == 33) {
915 sign_extend2 (&imm, 6, 5, 25);
916 }
917
918 esil_push_signed_imm (&op->esil, imm);
919
920 r_strbuf_appendf (
921 &op->esil,
922 "%s%d" CM
923 "=",
924 xtensa_regfile_shortname (isa, rf),
925 reg
926 );
927 }
928
esil_move(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)929 static void esil_move(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
930 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
931 ut32 dst;
932 ut32 src;
933
934 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst);
935 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &src);
936
937 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
938 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
939
940 r_strbuf_appendf (
941 &op->esil,
942 "%s%d" CM
943 "%s%d" CM
944 "=",
945 xtensa_regfile_shortname (isa, src_rf),
946 src,
947 xtensa_regfile_shortname (isa, dst_rf),
948 dst
949 );
950 }
951
esil_move_conditional(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)952 static void esil_move_conditional(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
953 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
954 ut32 dst;
955 ut32 src;
956 ut32 cond;
957
958 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst);
959 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &src);
960 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &cond);
961
962 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
963 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
964 xtensa_regfile cond_rf = xtensa_operand_regfile (isa, opcode, 2);
965
966 const char *compare_op = "";
967
968 switch (opcode) {
969 case 91: /* moveqz */
970 compare_op = "==,$z";
971 break;
972 case 92: /* movnez */
973 compare_op = "==,$z,!";
974 break;
975 case 93: /* movltz */
976 compare_op = "<";
977 break;
978 case 94: /* movgez */
979 compare_op = ">=";
980 break;
981 }
982
983 // example: moveqz a3, a4, a5
984 // 0,
985 // a5,
986 // ==,
987 // ?{,
988 // a4,
989 // a3,
990 // =,
991 // }
992
993 r_strbuf_appendf (
994 &op->esil,
995 "0" CM
996 "%s%d" CM
997 "%s" CM
998 "?{" CM
999 "%s%d" CM
1000 "%s%d" CM
1001 "=" CM
1002 "}",
1003 xtensa_regfile_shortname (isa, cond_rf),
1004 cond,
1005 compare_op,
1006 xtensa_regfile_shortname (isa, src_rf),
1007 src,
1008 xtensa_regfile_shortname (isa, dst_rf),
1009 dst
1010 );
1011 }
1012
esil_add_sub(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1013 static void esil_add_sub(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
1014 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1015 ut32 dst;
1016 ut32 op1;
1017 ut32 op2;
1018 bool is_add;
1019 ut8 shift;
1020
1021 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst);
1022 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &op1);
1023 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &op2);
1024
1025 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
1026 xtensa_regfile op1_rf = xtensa_operand_regfile (isa, opcode, 1);
1027 xtensa_regfile op2_rf = xtensa_operand_regfile (isa, opcode, 2);
1028
1029 is_add =
1030 (opcode == 26) ||
1031 (opcode == 41) ||
1032 (opcode == 43) ||
1033 (opcode == 44) ||
1034 (opcode == 45);
1035
1036 switch (opcode) {
1037 case 43:
1038 case 46:
1039 shift = 1;
1040 break;
1041 case 44:
1042 case 47:
1043 shift = 2;
1044 break;
1045 case 45:
1046 case 48:
1047 shift = 3;
1048 break;
1049 default:
1050 shift = 0;
1051 break;
1052 }
1053
1054 r_strbuf_appendf (
1055 &op->esil,
1056 "%s%d" CM
1057 "%d" CM
1058 "%s%d" CM
1059 "<<" CM
1060 "%s" CM
1061 "%s%d" CM
1062 "=",
1063 xtensa_regfile_shortname (isa, op2_rf),
1064 op2,
1065 shift,
1066 xtensa_regfile_shortname (isa, op1_rf),
1067 op1,
1068 (is_add ? "+" : "-"),
1069 xtensa_regfile_shortname (isa, dst_rf),
1070 dst
1071 );
1072 }
1073
esil_branch_compare_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1074 static void esil_branch_compare_imm(xtensa_isa isa, xtensa_opcode opcode,
1075 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1076 ut32 cmp_reg;
1077 // Unsigned immediate operands still fit in st32
1078 st32 cmp_imm;
1079 st32 branch_imm;
1080
1081 const char *compare_op = "";
1082
1083 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &cmp_reg);
1084 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, (ut32 *) &cmp_imm);
1085 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &branch_imm);
1086
1087 xtensa_regfile cmp_rf = xtensa_operand_regfile (isa, opcode, 0);
1088
1089 // TODO: unsigned comparisons
1090 switch (opcode) {
1091 case 52: /* beqi */
1092 compare_op = "==,$z";
1093 break;
1094 case 53: /* bnei */
1095 compare_op = "==,$z,!";
1096 break;
1097 case 58: /* bgeui */
1098 case 54: /* bgei */
1099 compare_op = ">=";
1100 break;
1101 case 59: /* bltui */
1102 case 55: /* blti */
1103 compare_op = "<";
1104 break;
1105 }
1106
1107 // example: beqi a4, 4, offset
1108 // a4, // push data reg
1109 // 0x4, // push imm operand
1110 // ==,
1111 // ?{,
1112 // offset,
1113 // pc,
1114 // +=,
1115 // }
1116
1117 r_strbuf_appendf (
1118 &op->esil,
1119 "%s%d" CM,
1120 // data reg
1121 xtensa_regfile_shortname (isa, cmp_rf),
1122 cmp_reg
1123 );
1124
1125 esil_push_signed_imm (&op->esil, cmp_imm);
1126
1127 r_strbuf_appendf (&op->esil, "%s" CM, compare_op);
1128 r_strbuf_appendf (&op->esil, "?{" CM);
1129
1130 // ISA defines branch target as offset + 4,
1131 // but at the time of ESIL evaluation
1132 // PC will be already incremented by 3
1133 esil_push_signed_imm (&op->esil, branch_imm + 4 - 3);
1134
1135 r_strbuf_appendf (&op->esil, "pc" CM "+=" CM "}");
1136 }
1137
esil_branch_compare(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1138 static void esil_branch_compare(xtensa_isa isa, xtensa_opcode opcode,
1139 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1140 ut32 op1_reg;
1141 ut32 op2_reg;
1142 st32 branch_imm;
1143
1144 const char *compare_op = "";
1145
1146 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &op1_reg);
1147 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &op2_reg);
1148 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &branch_imm);
1149
1150 xtensa_regfile op1_rf = xtensa_operand_regfile (isa, opcode, 0);
1151 xtensa_regfile op2_rf = xtensa_operand_regfile (isa, opcode, 1);
1152
1153 switch (opcode) {
1154 case 60: /* beq */
1155 compare_op = "==,$z";
1156 break;
1157 case 61: /* bne */
1158 compare_op = "==,$z,!";
1159 break;
1160 case 62: /* bge */
1161 case 64: /* bgeu */
1162 compare_op = ">=";
1163 break;
1164 case 63: /* blt */
1165 case 65: /* bltu */
1166 compare_op = "<";
1167 break;
1168 }
1169
1170 sign_extend (&branch_imm, 7);
1171 branch_imm += 4 - 3;
1172
1173 // example: beq a4, a3, offset
1174 // a3, // push op1
1175 // a4, // push op2
1176 // ==,
1177 // ?{,
1178 // offset,
1179 // pc,
1180 // +=,
1181 // }
1182
1183 r_strbuf_appendf (
1184 &op->esil,
1185 "%s%d" CM
1186 "%s%d" CM
1187 "%s" CM
1188 "?{" CM,
1189 xtensa_regfile_shortname (isa, op2_rf),
1190 op2_reg,
1191 xtensa_regfile_shortname (isa, op1_rf),
1192 op1_reg,
1193 compare_op
1194 );
1195
1196 esil_push_signed_imm (&op->esil, branch_imm);
1197
1198 r_strbuf_append (&op->esil, "pc" CM "+=" CM "}");
1199 }
1200
esil_branch_compare_single(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1201 static void esil_branch_compare_single(xtensa_isa isa, xtensa_opcode opcode,
1202 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1203 ut32 op_reg;
1204 st32 branch_imm;
1205
1206 const char *compare_op = "";
1207
1208 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &op_reg);
1209 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, (ut32 *) &branch_imm);
1210
1211 xtensa_regfile op_rf = xtensa_operand_regfile (isa, opcode, 0);
1212
1213 switch (opcode) {
1214 case 72: /* beqz */
1215 case 28: /* beqz.n */
1216 compare_op = "==,$z";
1217 break;
1218 case 73: /* bnez */
1219 case 29: /* bnez.n */
1220 compare_op = "==,$z,!";
1221 break;
1222 case 74: /* bgez */
1223 compare_op = ">=";
1224 break;
1225 case 75: /* bltz */
1226 compare_op = "<";
1227 break;
1228 }
1229
1230 sign_extend (&branch_imm, 12);
1231 branch_imm += 4 - 3;
1232
1233 // example: beqz a4, 0, offset
1234 // 0, // push 0
1235 // a4, // push op
1236 // ==,
1237 // ?{,
1238 // offset,
1239 // pc,
1240 // +=,
1241 // }
1242
1243 r_strbuf_appendf (
1244 &op->esil,
1245 "0" CM
1246 "%s%d" CM
1247 "%s" CM
1248 "?{" CM,
1249 xtensa_regfile_shortname (isa, op_rf),
1250 op_reg,
1251 compare_op
1252 );
1253
1254 esil_push_signed_imm (&op->esil, branch_imm);
1255
1256 r_strbuf_append (&op->esil, "pc" CM "+=" CM "}");
1257 }
1258
esil_branch_check_mask(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1259 static void esil_branch_check_mask(xtensa_isa isa, xtensa_opcode opcode,
1260 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1261 ut32 op1_reg;
1262 ut32 op2_reg;
1263 st32 branch_imm;
1264
1265 const char *compare_op = "";
1266 char compare_val[4] = "0";
1267
1268 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &op1_reg);
1269 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &op2_reg);
1270 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &branch_imm);
1271
1272 xtensa_regfile op1_rf = xtensa_operand_regfile (isa, opcode, 0);
1273 xtensa_regfile op2_rf = xtensa_operand_regfile (isa, opcode, 1);
1274
1275 switch (opcode) {
1276 case 69: /* bnall */
1277 case 66: /* bany */
1278 compare_op = "==,$z,!";
1279 break;
1280 case 68: /* ball */
1281 case 67: /* bnone */
1282 compare_op = "==,$z";
1283 break;
1284 }
1285
1286 switch (opcode) {
1287 case 69: /* bnall */
1288 case 68: /* ball */
1289 snprintf(
1290 compare_val,
1291 sizeof(compare_val),
1292 "%s%d",
1293 xtensa_regfile_shortname (isa, op2_rf),
1294 op2_reg
1295 );
1296 break;
1297 }
1298
1299 sign_extend (&branch_imm, 7);
1300 branch_imm += 4 - 3;
1301
1302 // example: bnall a4, a3, offset
1303 // a4, // push op1
1304 // a3, // push op2
1305 // &,
1306 // a3,
1307 // ==,!,
1308 // ?{,
1309 // offset,
1310 // pc,
1311 // +=,
1312 // }
1313
1314 r_strbuf_appendf (
1315 &op->esil,
1316 "%s%d" CM
1317 "%s%d" CM
1318 "&" CM
1319 "%s%d" CM
1320 "%s" CM
1321 "?{" CM,
1322 xtensa_regfile_shortname (isa, op1_rf),
1323 op1_reg,
1324 xtensa_regfile_shortname (isa, op2_rf),
1325 op2_reg,
1326 xtensa_regfile_shortname (isa, op2_rf),
1327 op2_reg,
1328 compare_op
1329 );
1330
1331 esil_push_signed_imm (&op->esil, branch_imm);
1332
1333 r_strbuf_append (&op->esil, "pc" CM "+=" CM "}");
1334 }
1335
esil_bitwise_op(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1336 static void esil_bitwise_op(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
1337 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1338 ut32 dst;
1339 ut32 op1;
1340 ut32 op2;
1341 char bop;
1342
1343 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst);
1344 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &op1);
1345 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &op2);
1346
1347 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
1348 xtensa_regfile op1_rf = xtensa_operand_regfile (isa, opcode, 1);
1349 xtensa_regfile op2_rf = xtensa_operand_regfile (isa, opcode, 2);
1350
1351 switch (opcode) {
1352 case 49: /* and */
1353 bop = '&';
1354 break;
1355 case 50: /* or */
1356 bop = '|';
1357 break;
1358 case 51: /* xor */
1359 bop = '^';
1360 break;
1361 default:
1362 bop = '=';
1363 break;
1364 }
1365
1366 r_strbuf_appendf (
1367 &op->esil,
1368 "%s%d" CM
1369 "%s%d" CM
1370 "%c" CM
1371 "%s%d" CM
1372 "=",
1373 xtensa_regfile_shortname (isa, op1_rf),
1374 op1,
1375 xtensa_regfile_shortname (isa, op2_rf),
1376 op2,
1377 bop,
1378 xtensa_regfile_shortname (isa, dst_rf),
1379 dst
1380 );
1381 }
1382
esil_branch_check_bit_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1383 static void esil_branch_check_bit_imm(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
1384 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1385 ut32 src_reg;
1386 ut32 imm_bit;
1387 st32 imm_offset;
1388 ut8 bit_clear;
1389 ut32 mask;
1390 const char *cmp_op;
1391
1392 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &src_reg);
1393 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &imm_bit);
1394 xtensa_operand_decode (isa, opcode, 1, &imm_bit);
1395 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &imm_offset);
1396
1397 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 0);
1398
1399 bit_clear = opcode == 56;
1400 cmp_op = bit_clear ? "==,$z" : "==,$z,!";
1401 mask = 1 << imm_bit;
1402
1403 sign_extend (&imm_offset, 7);
1404 imm_offset += 4 - 3;
1405
1406 // example: bbsi a4, 2, offset
1407 // a4,
1408 // mask,
1409 // &,
1410 // 0,
1411 // ==,
1412 // ?{,
1413 // offset,
1414 // pc,
1415 // +=,
1416 // }
1417
1418 r_strbuf_appendf (
1419 &op->esil,
1420 "%s%d" CM
1421 "0x%x" CM
1422 "&" CM
1423 "0" CM
1424 "%s" CM
1425 "?{" CM,
1426 xtensa_regfile_shortname (isa, src_rf),
1427 src_reg,
1428 mask,
1429 cmp_op
1430 );
1431
1432 esil_push_signed_imm (&op->esil, imm_offset);
1433
1434 r_strbuf_appendf (
1435 &op->esil,
1436 "pc" CM
1437 "+=" CM
1438 "}"
1439 );
1440 }
1441
esil_branch_check_bit(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1442 static void esil_branch_check_bit(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
1443 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1444 ut32 src_reg;
1445 ut32 bit_reg;
1446 st32 imm_offset;
1447
1448 ut8 bit_clear;
1449 const char *cmp_op;
1450
1451 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &src_reg);
1452 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &bit_reg);
1453 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, (ut32 *) &imm_offset);
1454
1455 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 0);
1456 xtensa_regfile bit_rf = xtensa_operand_regfile (isa, opcode, 1);
1457
1458 // bbc
1459 bit_clear = opcode == 70;
1460 cmp_op = bit_clear ? "==,$z" : "==,$z,!";
1461
1462 sign_extend (&imm_offset, 7);
1463 imm_offset += 4 - 3;
1464
1465 // example: bbc a4, a2, offset
1466 // a2,
1467 // 1,
1468 // <<,
1469 // a4,
1470 // &
1471 // 0
1472 // ==,
1473 // ?{,
1474 // offset,
1475 // pc,
1476 // +=,
1477 // }
1478
1479 r_strbuf_appendf (
1480 &op->esil,
1481 "%s%d" CM
1482 "1" CM
1483 "<<" CM
1484 "%s%d" CM
1485 "&" CM
1486 "0" CM
1487 "%s" CM
1488 "?{" CM,
1489 xtensa_regfile_shortname (isa, bit_rf),
1490 bit_reg,
1491 xtensa_regfile_shortname (isa, src_rf),
1492 src_reg,
1493 cmp_op
1494 );
1495
1496 esil_push_signed_imm (&op->esil, imm_offset);
1497
1498 r_strbuf_appendf (
1499 &op->esil,
1500 "pc" CM
1501 "+=" CM
1502 "}"
1503 );
1504 }
1505
esil_abs_neg(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1506 static void esil_abs_neg(xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
1507 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1508 ut32 src_reg;
1509 ut32 dst_reg;
1510
1511 ut8 neg;
1512
1513 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &dst_reg);
1514 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &src_reg);
1515
1516 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 1);
1517 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 0);
1518
1519 neg = opcode == 95;
1520
1521 if (!neg) {
1522 r_strbuf_appendf (
1523 &op->esil,
1524 "0" CM
1525 "%s%d" CM
1526 "<" CM
1527 "?{" CM
1528 "0" CM
1529 "%s%d" CM
1530 "-" CM
1531 "}" CM
1532 "0" CM
1533 "%s%d" CM
1534 ">=" CM
1535 "?{" CM
1536 "%s%d" CM
1537 "}" CM,
1538 xtensa_regfile_shortname (isa, src_rf),
1539 src_reg,
1540 xtensa_regfile_shortname (isa, src_rf),
1541 src_reg,
1542 xtensa_regfile_shortname (isa, src_rf),
1543 src_reg,
1544 xtensa_regfile_shortname (isa, src_rf),
1545 src_reg
1546 );
1547 } else {
1548 r_strbuf_appendf (
1549 &op->esil,
1550 "0" CM
1551 "%s%d" CM
1552 "-" CM,
1553 xtensa_regfile_shortname (isa, src_rf),
1554 src_reg
1555 );
1556 }
1557
1558 r_strbuf_appendf (
1559 &op->esil,
1560 "%s%d" CM
1561 "=" CM,
1562 xtensa_regfile_shortname (isa, dst_rf),
1563 dst_reg
1564 );
1565 }
1566
esil_call(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1567 static void esil_call(xtensa_isa isa, xtensa_opcode opcode,
1568 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1569 bool call = opcode == 76;
1570 st32 imm_offset;
1571
1572 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer,
1573 (ut32 *) &imm_offset);
1574
1575 if (call) {
1576 r_strbuf_append(
1577 &op->esil,
1578 "pc" CM
1579 "a0" CM
1580 "=" CM
1581 );
1582 }
1583
1584 sign_extend (&imm_offset, 17);
1585
1586 if (call) {
1587 imm_offset <<= 2;
1588 }
1589
1590 imm_offset += 4 - 3;
1591
1592 esil_push_signed_imm (&op->esil, imm_offset);
1593
1594 r_strbuf_append (&op->esil, "pc" CM "+=");
1595 }
1596
esil_callx(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1597 static void esil_callx(xtensa_isa isa, xtensa_opcode opcode,
1598 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1599 bool callx = opcode == 77;
1600 ut32 dst_reg;
1601
1602 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &dst_reg);
1603 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
1604
1605 r_strbuf_appendf (
1606 &op->esil,
1607 "%s%d" CM "0" CM "+" CM,
1608 xtensa_regfile_shortname (isa, dst_rf),
1609 dst_reg
1610 );
1611
1612 if (callx) {
1613 r_strbuf_append (
1614 &op->esil,
1615 "pc" CM
1616 "a0" CM
1617 "=" CM
1618 );
1619 }
1620
1621 r_strbuf_append (&op->esil, "pc" CM "=");
1622 }
1623
esil_set_shift_amount(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1624 static void esil_set_shift_amount(xtensa_isa isa, xtensa_opcode opcode,
1625 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1626 ut32 src_reg;
1627
1628 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &src_reg);
1629 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 0);
1630
1631 r_strbuf_appendf (
1632 &op->esil,
1633 "%s%d" CM
1634 "sar" CM
1635 "=",
1636 xtensa_regfile_shortname (isa, src_rf),
1637 src_reg
1638 );
1639 }
1640
esil_set_shift_amount_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1641 static void esil_set_shift_amount_imm(xtensa_isa isa, xtensa_opcode opcode,
1642 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1643 ut32 sa_imm;
1644
1645 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, &sa_imm);
1646 xtensa_operand_decode (isa, opcode, 0, &sa_imm);
1647
1648 r_strbuf_appendf (
1649 &op->esil,
1650 "0x%x" CM
1651 "sar" CM
1652 "=",
1653 sa_imm
1654 );
1655 }
1656
esil_shift_logic_imm(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1657 static void esil_shift_logic_imm(xtensa_isa isa, xtensa_opcode opcode,
1658 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1659 ut32 reg_dst;
1660 ut32 reg_src;
1661 ut32 imm_amount;
1662
1663 const char *shift_op = "";
1664
1665 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, ®_dst);
1666 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, ®_src);
1667 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &imm_amount);
1668 xtensa_operand_decode (isa, opcode, 2, &imm_amount);
1669
1670 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
1671 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
1672
1673 // srli
1674 if (opcode == 113) {
1675 shift_op = ">>";
1676 } else {
1677 shift_op = "<<";
1678 }
1679
1680 r_strbuf_appendf (
1681 &op->esil,
1682 "0x%x" CM
1683 "%s%d" CM
1684 "%s" CM
1685 "%s%d" CM
1686 "=",
1687 imm_amount,
1688 xtensa_regfile_shortname (isa, src_rf),
1689 reg_src,
1690 shift_op,
1691 xtensa_regfile_shortname (isa, dst_rf),
1692 reg_dst
1693 );
1694 }
1695
esil_shift_logic_sar(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1696 static void esil_shift_logic_sar(xtensa_isa isa, xtensa_opcode opcode,
1697 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1698 ut32 reg_dst;
1699 ut32 reg_src;
1700
1701 const char *shift_op = "";
1702
1703 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, ®_dst);
1704 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, ®_src);
1705
1706 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
1707 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
1708
1709 // srl
1710 if (opcode == 109) {
1711 shift_op = ">>";
1712 } else {
1713 shift_op = "<<";
1714 }
1715
1716 r_strbuf_appendf (
1717 &op->esil,
1718 "sar" CM
1719 "%s%d" CM
1720 "%s" CM
1721 "%s%d" CM
1722 "=",
1723 xtensa_regfile_shortname (isa, src_rf),
1724 reg_src,
1725 shift_op,
1726 xtensa_regfile_shortname (isa, dst_rf),
1727 reg_dst
1728 );
1729 }
1730
esil_extract_unsigned(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1731 static void esil_extract_unsigned(xtensa_isa isa, xtensa_opcode opcode,
1732 xtensa_format format, size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1733 ut32 reg_dst;
1734 ut32 reg_src;
1735 ut32 imm_shift;
1736 ut32 imm_mask;
1737
1738 xtensa_operand_get_field (isa, opcode, 0, format, i, slot_buffer, ®_dst);
1739 xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, ®_src);
1740 xtensa_operand_get_field (isa, opcode, 2, format, i, slot_buffer, &imm_shift);
1741 xtensa_operand_get_field (isa, opcode, 3, format, i, slot_buffer, &imm_mask);
1742
1743 xtensa_regfile dst_rf = xtensa_operand_regfile (isa, opcode, 0);
1744 xtensa_regfile src_rf = xtensa_operand_regfile (isa, opcode, 1);
1745
1746 ut32 and_mask = (1 << (imm_mask + 1)) - 1;
1747
1748 r_strbuf_appendf (
1749 &op->esil,
1750 "0x%x" CM
1751 "%s%d" CM
1752 ">>" CM
1753 "0x%x" CM
1754 "&" CM
1755 "%s%d" CM
1756 "=",
1757 imm_shift,
1758 xtensa_regfile_shortname (isa, src_rf),
1759 reg_src,
1760 and_mask,
1761 xtensa_regfile_shortname (isa, dst_rf),
1762 reg_dst
1763 );
1764 }
1765
analop_esil(xtensa_isa isa,xtensa_opcode opcode,xtensa_format format,size_t i,xtensa_insnbuf slot_buffer,RAnalOp * op)1766 static void analop_esil (xtensa_isa isa, xtensa_opcode opcode, xtensa_format format,
1767 size_t i, xtensa_insnbuf slot_buffer, RAnalOp *op) {
1768 switch (opcode) {
1769 case 26: /* add.n */
1770 case 41: /* add */
1771 case 43: /* addx2 */
1772 case 44: /* addx4 */
1773 case 45: /* addx8 */
1774 case 42: /* sub */
1775 case 46: /* subx2 */
1776 case 47: /* subx4 */
1777 case 48: /* subx8 */
1778 esil_add_sub (isa, opcode, format, i, slot_buffer, op);
1779 break;
1780 case 32: /* mov.n */
1781 esil_move (isa, opcode, format, i, slot_buffer, op);
1782 break;
1783 case 90: /* movi */
1784 case 33: /* movi.n */
1785 esil_move_imm (isa, opcode, format, i, slot_buffer, op);
1786 break;
1787 case 0: /* excw */
1788 case 34: /* nop.n */
1789 r_strbuf_setf (&op->esil, "%s", "");
1790 break;
1791 // TODO: s32cli (s32c1i) is conditional (CAS)
1792 // should it be handled here?
1793 case 453: /* s32c1i */
1794 case 36: /* s32i.n */
1795 case 100: /* s32i */
1796 case 99: /* s16i */
1797 case 101: /* s8i */
1798 esil_store_imm (isa, opcode, format, i, slot_buffer, op);
1799 break;
1800 case 27: /* addi.n */
1801 case 39: /* addi */
1802 xtensa_check_stack_op (isa, opcode, format, i, slot_buffer, op);
1803 esil_add_imm (isa, opcode, format, i, slot_buffer, op);
1804 break;
1805 case 98: /* ret */
1806 case 35: /* ret.n */
1807 r_strbuf_setf (&op->esil, "a0,pc,=");
1808 break;
1809 case 82: /* l16ui */
1810 case 83: /* l16si */
1811 case 84: /* l32i */
1812 case 31: /* l32i.n */
1813 case 86: /* l8ui */
1814 esil_load_imm (isa, opcode, format, i, slot_buffer, op);
1815 break;
1816 // TODO: s32r
1817 // l32r is different because it is relative to LITBASE
1818 // which also may or may not be present
1819 case 85: /* l32r */
1820 esil_load_relative (isa, opcode, format, i, slot_buffer, op);
1821 break;
1822 case 40: /* addmi */
1823 break;
1824 case 49: /* and */
1825 case 50: /* or */
1826 case 51: /* xor */
1827 esil_bitwise_op (isa, opcode, format, i, slot_buffer, op);
1828 break;
1829 case 52: /* beqi */
1830 case 53: /* bnei */
1831 case 54: /* bgei */
1832 case 55: /* blti */
1833 case 58: /* bgeui */
1834 case 59: /* bltui */
1835 esil_branch_compare_imm (isa, opcode, format, i, slot_buffer, op);
1836 break;
1837 case 56: /* bbci */
1838 case 57: /* bbsi */
1839 esil_branch_check_bit_imm (isa, opcode, format, i, slot_buffer, op);
1840 break;
1841 case 60: /* beq */
1842 case 61: /* bne */
1843 case 62: /* bge */
1844 case 63: /* blt */
1845 case 64: /* bgeu */
1846 case 65: /* bltu */
1847 esil_branch_compare (isa, opcode, format, i, slot_buffer, op);
1848 break;
1849 case 66: /* bany */
1850 case 67: /* bnone */
1851 case 68: /* ball */
1852 case 69: /* bnall */
1853 esil_branch_check_mask (isa, opcode, format, i, slot_buffer, op);
1854 break;
1855 case 70: /* bbc */
1856 case 71: /* bbs */
1857 esil_branch_check_bit (isa, opcode, format, i, slot_buffer, op);
1858 break;
1859 case 72: /* beqz */
1860 case 73: /* bnez */
1861 case 28: /* beqz.n */
1862 case 29: /* bnez.n */
1863 case 74: /* bgez */
1864 case 75: /* bltz */
1865 esil_branch_compare_single (isa, opcode, format, i, slot_buffer, op);
1866 break;
1867 case 78: /* extui */
1868 esil_extract_unsigned (isa, opcode, format, i, slot_buffer, op);
1869 break;
1870 case 79: /* ill */
1871 r_strbuf_setf (&op->esil, "%s", "");
1872 break;
1873 // TODO: windowed calls?
1874 case 7: /* call4 */
1875 break;
1876 case 76: /* call0 */
1877 case 80: /* j */
1878 esil_call (isa, opcode, format, i, slot_buffer, op);
1879 break;
1880 case 81: /* jx */
1881 case 77: /* callx0 */
1882 esil_callx (isa, opcode, format, i, slot_buffer, op);
1883 break;
1884 case 91: /* moveqz */
1885 case 92: /* movnez */
1886 case 93: /* movltz */
1887 case 94: /* movgez */
1888 esil_move_conditional (isa, opcode, format, i, slot_buffer, op);
1889 break;
1890 case 96: /* abs */
1891 case 95: /* neg */
1892 esil_abs_neg (isa, opcode, format, i, slot_buffer, op);
1893 break;
1894 case 102: /* ssr */
1895 case 103: /* ssl */
1896 esil_set_shift_amount (isa, opcode, format, i, slot_buffer, op);
1897 break;
1898 case 111: /* slli */
1899 case 113: /* srli */
1900 esil_shift_logic_imm (isa, opcode, format, i, slot_buffer, op);
1901 break;
1902 case 106: /* ssai */
1903 esil_set_shift_amount_imm (isa, opcode, format, i, slot_buffer, op);
1904 break;
1905 case 107: /* sll */
1906 case 109: /* srl */
1907 esil_shift_logic_sar (isa, opcode, format, i, slot_buffer, op);
1908 break;
1909 }
1910 }
1911
xtensa_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf_original,int len_original,RAnalOpMask mask)1912 static int xtensa_op (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf_original, int len_original, RAnalOpMask mask) {
1913 if (!op) {
1914 return 1;
1915 }
1916
1917 op->size = xtensa_length (buf_original);
1918 if (op->size > len_original) {
1919 return 1;
1920 }
1921
1922 xtensa_op0_fns[(buf_original[0] & 0xf)] (anal, op, addr, buf_original);
1923
1924 ut8 buffer[XTENSA_MAX_LENGTH] = { 0 };
1925 int len = R_MIN(op->size, XTENSA_MAX_LENGTH);
1926 memcpy (buffer, buf_original, len);
1927
1928 unsigned int i;
1929 if (!xtensa_default_isa) {
1930 xtensa_default_isa = xtensa_isa_init (0, 0);
1931 }
1932
1933 xtensa_opcode opcode;
1934 xtensa_isa isa = xtensa_default_isa;
1935 xtensa_format format;
1936 int nslots;
1937
1938 static xtensa_insnbuf insn_buffer = NULL;
1939 static xtensa_insnbuf slot_buffer = NULL;
1940
1941 if (!insn_buffer) {
1942 insn_buffer = xtensa_insnbuf_alloc (isa);
1943 slot_buffer = xtensa_insnbuf_alloc (isa);
1944 }
1945
1946 memset (insn_buffer, 0, xtensa_insnbuf_size (isa) * sizeof(xtensa_insnbuf_word));
1947
1948 xtensa_insnbuf_from_chars (isa, insn_buffer, buffer, len);
1949 format = xtensa_format_decode (isa, insn_buffer);
1950
1951 if (format == XTENSA_UNDEFINED) {
1952 return op->size;
1953 }
1954
1955 nslots = xtensa_format_num_slots (isa, format);
1956 if (nslots < 1) {
1957 return op->size;
1958 }
1959
1960 for (i = 0; i < nslots; i++) {
1961 xtensa_format_get_slot (isa, format, i, insn_buffer, slot_buffer);
1962 opcode = xtensa_opcode_decode (isa, format, i, slot_buffer);
1963
1964 if (opcode == 39) { /* addi */
1965 xtensa_check_stack_op (isa, opcode, format, i, slot_buffer, op);
1966 }
1967
1968 if (mask & R_ANAL_OP_MASK_ESIL) {
1969 analop_esil (isa, opcode, format, i, slot_buffer, op);
1970 }
1971 }
1972
1973 return op->size;
1974 }
1975
get_reg_profile(RAnal * anal)1976 static char *get_reg_profile(RAnal *anal) {
1977 return strdup (
1978 // Assuming call0 ABI
1979 "# a0 return address\n"
1980 "# a1 stack pointer\n"
1981 "# a2-a7 arguments\n"
1982 "# a2-a5 return value (call0 ABI)\n"
1983 "# a12-a15 callee-saved (call0 ABI)\n"
1984 "=PC pc\n"
1985 "=BP a14\n"
1986 "=SP a1\n"
1987 "=A0 a2\n"
1988 "=A1 a3\n"
1989 "=A2 a4\n"
1990 "=A3 a5\n"
1991 "=A4 a6\n"
1992 "=A5 a7\n"
1993 "gpr a0 .32 0 0\n"
1994 "gpr a1 .32 4 0\n"
1995 "gpr a2 .32 8 0\n"
1996 "gpr a3 .32 16 0\n"
1997 "gpr a4 .32 20 0\n"
1998 "gpr a5 .32 24 0\n"
1999 "gpr a6 .32 28 0\n"
2000 "gpr a7 .32 32 0\n"
2001 "gpr a8 .32 36 0\n"
2002 "gpr a9 .32 40 0\n"
2003 "gpr a10 .32 44 0\n"
2004 "gpr a11 .32 48 0\n"
2005 "gpr a12 .32 52 0\n"
2006 "gpr a13 .32 56 0\n"
2007 "gpr a14 .32 60 0\n"
2008 "gpr a15 .32 64 0\n"
2009
2010 // pc
2011 "gpr pc .32 68 0\n"
2012
2013 // sr
2014 "gpr sar .32 72 0\n"
2015 );
2016 }
2017
2018 RAnalPlugin r_anal_plugin_xtensa = {
2019 .name = "xtensa",
2020 .desc = "Xtensa disassembler",
2021 .license = "LGPL3",
2022 .arch = "xtensa",
2023 .bits = 8,
2024 .esil = true,
2025 .op = &xtensa_op,
2026 .get_reg_profile = get_reg_profile,
2027 };
2028
2029 #ifndef R2_PLUGIN_INCORE
2030 R_API RLibStruct radare_plugin = {
2031 .type = R_LIB_TYPE_ANAL,
2032 .data = &r_anal_plugin_xtensa,
2033 .version = R2_VERSION
2034 };
2035 #endif
2036