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