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, &reg_d);
705 	xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &reg_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, &reg_d);
848 	xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &reg_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, &reg);
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, &reg_dst);
1666 	xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &reg_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, &reg_dst);
1704 	xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &reg_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, &reg_dst);
1739 	xtensa_operand_get_field (isa, opcode, 1, format, i, slot_buffer, &reg_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