1 /* radare - LGPL - Copyright 2015 - danielps */
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 #include <r_util.h>
9 
10 #include <v810_disas.h>
11 
12 enum {
13 	V810_FLAG_CY = 1,
14 	V810_FLAG_OV = 2,
15 	V810_FLAG_S = 4,
16 	V810_FLAG_Z = 8,
17 };
18 
update_flags(RAnalOp * op,int flags)19 static void update_flags(RAnalOp *op, int flags) {
20 	if (flags & V810_FLAG_CY) {
21 		r_strbuf_append (&op->esil, ",31,$c,cy,:=");
22 	}
23 	if (flags & V810_FLAG_OV) {
24 		r_strbuf_append (&op->esil, ",31,$o,ov,:=");
25 	}
26 	if (flags & V810_FLAG_S) {
27 		r_strbuf_append (&op->esil, ",31,$s,s,:=");
28 	}
29 	if (flags & V810_FLAG_Z) {
30 		r_strbuf_append (&op->esil, ",$z,z,:=");
31 	}
32 }
33 
clear_flags(RAnalOp * op,int flags)34 static void clear_flags(RAnalOp *op, int flags) {
35 	if (flags & V810_FLAG_CY) {
36 		r_strbuf_append (&op->esil, ",0,cy,:=");
37 	}
38 	if (flags & V810_FLAG_OV) {
39 		r_strbuf_append (&op->esil, ",0,ov,:=");
40 	}
41 	if (flags & V810_FLAG_S) {
42 		r_strbuf_append (&op->esil, ",0,s,:=");
43 	}
44 	if (flags & V810_FLAG_Z) {
45 		r_strbuf_append (&op->esil, ",0,z,:=");
46 	}
47 }
48 
v810_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf,int len,RAnalOpMask mask)49 static int v810_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
50 	int ret;
51 	ut8 opcode, reg1, reg2, imm5, cond;
52 	ut16 word1, word2 = 0;
53 	st32 jumpdisp;
54 	struct v810_cmd cmd;
55 
56 	memset (&cmd, 0, sizeof(cmd));
57 
58 	ret = op->size = v810_decode_command (buf, len, &cmd);
59 	if (ret <= 0) {
60 		return ret;
61 	}
62 
63 	word1 = r_read_ble16 (buf, anal->big_endian);
64 
65 	if (ret == 4) {
66 		word2 = r_read_ble16 (buf+2, anal->big_endian);
67 	}
68 
69 	op->addr = addr;
70 
71 	opcode = OPCODE(word1);
72 	if (opcode >> 3 == 0x4) {
73 		opcode &= 0x20;
74 	}
75 
76 	switch (opcode) {
77 	case V810_MOV:
78 		op->type = R_ANAL_OP_TYPE_MOV;
79 		r_strbuf_appendf (&op->esil, "r%u,r%u,=",
80 						 REG1(word1), REG2(word1));
81 		break;
82 	case V810_MOV_IMM5:
83 		op->type = R_ANAL_OP_TYPE_MOV;
84 		r_strbuf_appendf (&op->esil, "%d,r%u,=",
85 						  (st8)SEXT5(IMM5(word1)), REG2(word1));
86 		break;
87 	case V810_MOVHI:
88 		op->type = R_ANAL_OP_TYPE_MOV;
89 		r_strbuf_appendf (&op->esil, "16,%hu,<<,r%u,+,r%u,=",
90 						 word2, REG1(word1), REG2(word1));
91 		break;
92 	case V810_MOVEA:
93 		op->type = R_ANAL_OP_TYPE_MOV;
94 		r_strbuf_appendf (&op->esil, "%hd,r%u,+,r%u,=",
95 						 word2, REG1(word1), REG2(word1));
96 		break;
97 	case V810_LDSR:
98 		op->type = R_ANAL_OP_TYPE_MOV;
99 		break;
100 	case V810_STSR:
101 		op->type = R_ANAL_OP_TYPE_MOV;
102 		break;
103 	case V810_NOT:
104 		op->type = R_ANAL_OP_TYPE_NOT;
105 		r_strbuf_appendf (&op->esil, "r%u,0xffffffff,^,r%u,=",
106 						 REG1(word1), REG2(word1));
107 		update_flags (op, V810_FLAG_S | V810_FLAG_Z);
108 		clear_flags (op, V810_FLAG_OV);
109 		break;
110 	case V810_DIV:
111 	case V810_DIVU:
112 		op->type = R_ANAL_OP_TYPE_DIV;
113 		r_strbuf_appendf (&op->esil, "r%u,r%u,/=,r%u,r%u,%%,r30,=",
114 						 REG1(word1), REG2(word1),
115 						 REG1(word1), REG2(word1));
116 		update_flags (op, V810_FLAG_OV | V810_FLAG_S | V810_FLAG_Z);
117 		break;
118 	case V810_JMP:
119 		if (REG1 (word1) == 31) {
120 			op->type = R_ANAL_OP_TYPE_RET;
121 		} else {
122 			op->type = R_ANAL_OP_TYPE_UJMP;
123 		}
124 		r_strbuf_appendf (&op->esil, "r%u,pc,=",
125 						 REG1(word1));
126 		break;
127 	case V810_OR:
128 		op->type = R_ANAL_OP_TYPE_OR;
129 		r_strbuf_appendf (&op->esil, "r%u,r%u,|=",
130 						 REG1(word1), REG2(word1));
131 		update_flags (op, V810_FLAG_S | V810_FLAG_Z);
132 		clear_flags (op, V810_FLAG_OV);
133 		break;
134 	case V810_ORI:
135 		op->type = R_ANAL_OP_TYPE_OR;
136 		r_strbuf_appendf (&op->esil, "%hu,r%u,|,r%u,=",
137 						 word2, REG1(word1), REG2(word1));
138 		update_flags (op, V810_FLAG_S | V810_FLAG_Z);
139 		clear_flags (op, V810_FLAG_OV);
140 		break;
141 	case V810_MUL:
142 	case V810_MULU:
143 		op->type = R_ANAL_OP_TYPE_MUL;
144 		r_strbuf_appendf (&op->esil, "r%u,r%u,*=,32,r%u,r%u,*,>>,r30,=",
145 						 REG1(word1), REG2(word1),
146 						 REG1(word1), REG2(word1));
147 		update_flags (op, V810_FLAG_OV | V810_FLAG_S | V810_FLAG_Z);
148 		break;
149 	case V810_XOR:
150 		op->type = R_ANAL_OP_TYPE_XOR;
151 		r_strbuf_appendf (&op->esil, "r%u,r%u,^=",
152 						 REG1(word1), REG2(word1));
153 		update_flags (op, V810_FLAG_S | V810_FLAG_Z);
154 		clear_flags (op, V810_FLAG_OV);
155 		break;
156 	case V810_XORI:
157 		op->type = R_ANAL_OP_TYPE_XOR;
158 		r_strbuf_appendf (&op->esil, "%hu,r%u,^,r%u,=",
159 						 word2, REG1(word1), REG2(word1));
160 		update_flags (op, V810_FLAG_S | V810_FLAG_Z);
161 		clear_flags (op, V810_FLAG_OV);
162 		break;
163 	case V810_AND:
164 		op->type = R_ANAL_OP_TYPE_AND;
165 		r_strbuf_appendf (&op->esil, "r%u,r%u,&=",
166 						 REG1(word1), REG2(word1));
167 		update_flags (op, V810_FLAG_S | V810_FLAG_Z);
168 		clear_flags (op, V810_FLAG_OV);
169 		break;
170 	case V810_ANDI:
171 		op->type = R_ANAL_OP_TYPE_AND;
172 		r_strbuf_appendf (&op->esil, "%hu,r%u,&,r%u,=",
173 						 word2, REG1(word1), REG2(word1));
174 		update_flags (op, V810_FLAG_Z);
175 		clear_flags (op, V810_FLAG_OV | V810_FLAG_S);
176 		break;
177 	case V810_CMP:
178 		op->type = R_ANAL_OP_TYPE_CMP;
179 		r_strbuf_appendf (&op->esil, "r%u,r%u,==",
180 						 REG1(word1), REG2(word1));
181 		update_flags (op, -1);
182 		break;
183 	case V810_CMP_IMM5:
184 		op->type = R_ANAL_OP_TYPE_CMP;
185 		r_strbuf_appendf (&op->esil, "%d,r%u,==",
186 						  (st8)SEXT5(IMM5(word1)), REG2(word1));
187 		update_flags (op, -1);
188 		break;
189 	case V810_SUB:
190 		op->type = R_ANAL_OP_TYPE_SUB;
191 		r_strbuf_appendf (&op->esil, "r%u,r%u,-=",
192 						 REG1(word1), REG2(word1));
193 		update_flags (op, -1);
194 		break;
195 	case V810_ADD:
196 		op->type = R_ANAL_OP_TYPE_ADD;
197 		r_strbuf_appendf (&op->esil, "r%u,r%u,+=",
198 						 REG1(word1), REG2(word1));
199 		update_flags (op, -1);
200 		break;
201 	case V810_ADDI:
202 		op->type = R_ANAL_OP_TYPE_ADD;
203 		r_strbuf_appendf (&op->esil, "%hd,r%u,+,r%u,=",
204 						 word2, REG1(word1), REG2(word1));
205 		update_flags (op, -1);
206 		break;
207 	case V810_ADD_IMM5:
208 		op->type = R_ANAL_OP_TYPE_ADD;
209 		r_strbuf_appendf (&op->esil, "%d,r%u,+=",
210 						  (st8)SEXT5(IMM5(word1)), REG2(word1));
211 		update_flags(op, -1);
212 		break;
213 	case V810_SHR:
214 		op->type = R_ANAL_OP_TYPE_SHR;
215 		r_strbuf_appendf (&op->esil, "r%u,r%u,>>=",
216 						 REG1(word1), REG2(word1));
217 		update_flags (op, V810_FLAG_CY | V810_FLAG_S | V810_FLAG_Z);
218 		clear_flags (op, V810_FLAG_OV);
219 		break;
220 	case V810_SHR_IMM5:
221 		op->type = R_ANAL_OP_TYPE_SHR;
222 		r_strbuf_appendf (&op->esil, "%u,r%u,>>=",
223 						  (ut8)IMM5(word1), REG2(word1));
224 		update_flags (op, V810_FLAG_CY | V810_FLAG_S | V810_FLAG_Z);
225 		clear_flags (op, V810_FLAG_OV);
226 		break;
227 	case V810_SAR:
228 		op->type = R_ANAL_OP_TYPE_SAR;
229 		reg1 = REG1(word1);
230 		reg2 = REG2(word1);
231 		r_strbuf_appendf (&op->esil, "31,r%u,>>,?{,r%u,32,-,r%u,1,<<,--,<<,}{,0,},r%u,r%u,>>,|,r%u,=",
232 						 reg2, reg1, reg1, reg1, reg2, reg2);
233 		update_flags (op, V810_FLAG_CY | V810_FLAG_S | V810_FLAG_Z);
234 		clear_flags (op, V810_FLAG_OV);
235 		break;
236 	case V810_SAR_IMM5:
237 		op->type = R_ANAL_OP_TYPE_SAR;
238 		imm5 = IMM5(word1);
239 		reg2 = REG2(word1);
240 		r_strbuf_appendf (&op->esil, "31,r%u,>>,?{,%u,32,-,%u,1,<<,--,<<,}{,0,},%u,r%u,>>,|,r%u,=",
241 						  reg2, (ut8)imm5, (ut8)imm5, (ut8)imm5, reg2, reg2);
242 		update_flags (op, V810_FLAG_CY | V810_FLAG_S | V810_FLAG_Z);
243 		clear_flags (op, V810_FLAG_OV);
244 		break;
245 	case V810_SHL:
246 		op->type = R_ANAL_OP_TYPE_SHL;
247 		r_strbuf_appendf (&op->esil, "r%u,r%u,<<=",
248 						 REG1(word1), REG2(word1));
249 		update_flags (op, V810_FLAG_CY | V810_FLAG_S | V810_FLAG_Z);
250 		clear_flags (op, V810_FLAG_OV);
251 		break;
252 	case V810_SHL_IMM5:
253 		op->type = R_ANAL_OP_TYPE_SHL;
254 		r_strbuf_appendf (&op->esil, "%u,r%u,<<=",
255 						  (ut8)IMM5(word1), REG2(word1));
256 		update_flags (op, V810_FLAG_CY | V810_FLAG_S | V810_FLAG_Z);
257 		clear_flags (op, V810_FLAG_OV);
258 		break;
259 	case V810_LDB:
260 		op->type = R_ANAL_OP_TYPE_LOAD;
261 		r_strbuf_appendf (&op->esil, "r%u,%hd,+,[1],r%u,=",
262 						 REG1(word1), word2, REG2(word1));
263 		r_strbuf_appendf (&op->esil, ",DUP,0x80,&,?{,0xffffff00,|,}");
264 		break;
265 	case V810_LDH:
266 		op->type = R_ANAL_OP_TYPE_LOAD;
267 		r_strbuf_appendf (&op->esil, "r%u,%hd,+,0xfffffffe,&,[2],r%u,=",
268 						 REG1(word1), word2, REG2(word1));
269 		r_strbuf_appendf (&op->esil, ",DUP,0x8000,&,?{,0xffffff00,|,}");
270 		break;
271 	case V810_LDW:
272 		op->type = R_ANAL_OP_TYPE_LOAD;
273 		r_strbuf_appendf (&op->esil, "r%u,%hd,+,0xfffffffc,&,[4],r%u,=",
274 						 REG1(word1), word2, REG2(word1));
275 		r_strbuf_appendf (&op->esil, ",DUP,0x80000000,&,?{,0xffffff00,|,}");
276 		break;
277 	case V810_STB:
278 		op->type = R_ANAL_OP_TYPE_STORE;
279 		r_strbuf_appendf (&op->esil, "r%u,r%u,%hd,+,=[1]",
280 						 REG2(word1), REG1(word1), word2);
281 		break;
282 	case V810_STH:
283 		op->type = R_ANAL_OP_TYPE_STORE;
284 		r_strbuf_appendf (&op->esil, "r%u,r%u,%hd,+,0xfffffffe,&,=[2]",
285 						 REG2(word1), REG1(word1), word2);
286 		break;
287 	case V810_STW:
288 		op->type = R_ANAL_OP_TYPE_STORE;
289 		r_strbuf_appendf (&op->esil, "r%u,r%u,%hd,+,=[4]",
290 						 REG2(word1), REG1(word1), word2);
291 		break;
292 	case V810_INB:
293 	case V810_INH:
294 	case V810_INW:
295 	case V810_OUTB:
296 	case V810_OUTH:
297 	case V810_OUTW:
298 		op->type = R_ANAL_OP_TYPE_IO;
299 		break;
300 	case V810_TRAP:
301 		op->type = R_ANAL_OP_TYPE_TRAP;
302 		r_strbuf_appendf (&op->esil, "%u,TRAP", IMM5(word1));
303 		break;
304 	case V810_RETI:
305 		op->type = R_ANAL_OP_TYPE_RET;
306 		//r_strbuf_appendf (&op->esil, "np,?{,fepc,fepsw,}{,eipc,eipsw,},psw,=,pc,=");
307 		break;
308 	case V810_JAL:
309 	case V810_JR:
310 		jumpdisp = DISP26(word1, word2);
311 		op->jump = addr + jumpdisp;
312 		op->fail = addr + 4;
313 
314 		if (opcode == V810_JAL) {
315 			op->type = R_ANAL_OP_TYPE_CALL;
316 			r_strbuf_appendf (&op->esil, "$$,4,+,r31,=,");
317 		} else {
318 			op->type = R_ANAL_OP_TYPE_JMP;
319 		}
320 
321 		r_strbuf_appendf (&op->esil, "$$,%d,+,pc,=", jumpdisp);
322 		break;
323 	case V810_BCOND:
324 		cond = COND(word1);
325 		if (cond == V810_COND_NOP) {
326 			op->type = R_ANAL_OP_TYPE_NOP;
327 			break;
328 		}
329 
330 		jumpdisp = DISP9(word1);
331 		op->jump = addr + jumpdisp;
332 		op->fail = addr + 2;
333 		op->type = R_ANAL_OP_TYPE_CJMP;
334 
335 		switch (cond) {
336 		case V810_COND_V:
337 			r_strbuf_appendf (&op->esil, "ov");
338 			break;
339 		case V810_COND_L:
340 			r_strbuf_appendf (&op->esil, "cy");
341 			break;
342 		case V810_COND_E:
343 			r_strbuf_appendf (&op->esil, "z");
344 			break;
345 		case V810_COND_NH:
346 			r_strbuf_appendf (&op->esil, "cy,z,|");
347 			break;
348 		case V810_COND_N:
349 			r_strbuf_appendf (&op->esil, "s");
350 			break;
351 		case V810_COND_NONE:
352 			r_strbuf_appendf (&op->esil, "1");
353 			break;
354 		case V810_COND_LT:
355 			r_strbuf_appendf (&op->esil, "s,ov,^");
356 			break;
357 		case V810_COND_LE:
358 			r_strbuf_appendf (&op->esil, "s,ov,^,z,|");
359 			break;
360 		case V810_COND_NV:
361 			r_strbuf_appendf (&op->esil, "ov,!");
362 			break;
363 		case V810_COND_NL:
364 			r_strbuf_appendf (&op->esil, "cy,!");
365 			break;
366 		case V810_COND_NE:
367 			r_strbuf_appendf (&op->esil, "z,!");
368 			break;
369 		case V810_COND_H:
370 			r_strbuf_appendf (&op->esil, "cy,z,|,!");
371 			break;
372 		case V810_COND_P:
373 			r_strbuf_appendf (&op->esil, "s,!");
374 			break;
375 		case V810_COND_GE:
376 			r_strbuf_appendf (&op->esil, "s,ov,^,!");
377 			break;
378 		case V810_COND_GT:
379 			r_strbuf_appendf (&op->esil, "s,ov,^,z,|,!");
380 			break;
381 		}
382 		r_strbuf_appendf (&op->esil, ",?{,$$,%d,+,pc,=,}", jumpdisp);
383 		break;
384 	}
385 
386 	return ret;
387 }
388 
set_reg_profile(RAnal * anal)389 static bool set_reg_profile(RAnal *anal) {
390 	const char *p =
391 		"=PC	pc\n"
392 		"=SP	r3\n"
393 		"=A0	r0\n"
394 		"=ZF	z\n"
395 		"=SF	s\n"
396 		"=OF	ov\n"
397 		"=CF	cy\n"
398 
399 		"gpr	r0	.32	0   0\n"
400 		"gpr	r1	.32	4   0\n"
401 		"gpr	r2	.32	8   0\n"
402 		"gpr	r3	.32	12  0\n"
403 		"gpr	r4	.32	16  0\n"
404 		"gpr	r5	.32	20  0\n"
405 		"gpr	r6	.32	24  0\n"
406 		"gpr	r7	.32	28  0\n"
407 		"gpr	r8	.32	32  0\n"
408 		"gpr	r9	.32	36  0\n"
409 		"gpr	r10	.32	40  0\n"
410 		"gpr	r11	.32	44  0\n"
411 		"gpr	r12	.32	48  0\n"
412 		"gpr	r13	.32	52  0\n"
413 		"gpr	r14	.32	56  0\n"
414 		"gpr	r15	.32	60  0\n"
415 		"gpr	r16	.32	64  0\n"
416 		"gpr	r17	.32	68  0\n"
417 		"gpr	r18	.32	72  0\n"
418 		"gpr	r19	.32	76  0\n"
419 		"gpr	r20	.32	80  0\n"
420 		"gpr	r21	.32	84  0\n"
421 		"gpr	r22	.32	88  0\n"
422 		"gpr	r23	.32	92  0\n"
423 		"gpr	r24	.32	96  0\n"
424 		"gpr	r25	.32	100 0\n"
425 		"gpr	r26	.32	104 0\n"
426 		"gpr	r27	.32	108 0\n"
427 		"gpr	r28	.32	112 0\n"
428 		"gpr	r29	.32	116 0\n"
429 		"gpr	r30	.32	120 0\n"
430 		"gpr	r31	.32	124 0\n"
431 		"gpr	pc	.32	128 0\n"
432 
433 		"gpr	psw .32 132 0\n"
434 		"gpr	np  .1 132.16 0\n"
435 		"gpr	ep  .1 132.17 0\n"
436 		"gpr	ae  .1 132.18 0\n"
437 		"gpr	id  .1 132.19 0\n"
438 		"flg	cy  .1 132.28 0\n"
439 		"flg	ov  .1 132.29 0\n"
440 		"flg	s   .1 132.30 0\n"
441 		"flg	z   .1 132.31 0\n";
442 
443 	return r_reg_set_profile_string (anal->reg, p);
444 }
445 
446 RAnalPlugin r_anal_plugin_v810 = {
447 	.name = "v810",
448 	.desc = "V810 code analysis plugin",
449 	.license = "LGPL3",
450 	.arch = "v810",
451 	.bits = 32,
452 	.op = v810_op,
453 	.esil = true,
454 	.set_reg_profile = set_reg_profile,
455 };
456 
457 #ifndef R2_PLUGIN_INCORE
458 R_API RLibStruct radare_plugin = {
459 	.type = R_LIB_TYPE_ANAL,
460 	.data = &r_anal_plugin_v810,
461 	.version = R2_VERSION
462 };
463 #endif
464