1 /* radare - LGPL - Copyright 2016-2020 - pancake */
2
3 #include <string.h>
4 #include <r_types.h>
5 #include <r_util.h>
6 #include <r_lib.h>
7 #include <r_asm.h>
8 #include <r_anal.h>
9
10 #define AVR_SOFTCAST(x,y) ((x)+((y)*0x100))
11
set_reg_profile(RAnal * anal)12 static bool set_reg_profile(RAnal *anal) {
13 const char *p =
14 "=PC PC\n"
15 /* syntax not yet supported */
16 // "=SP &PC1\n"
17 "=A0 r0\n"
18 "=A1 r1\n"
19 "=A2 r2\n"
20 "=A3 r3\n"
21 "=R0 r0\n"
22 "gpr r0 .4 0 0\n"
23 "gpr r1 .4 1 0\n"
24 "gpr r2 .4 2 0\n"
25 "gpr r3 .4 3 0\n"
26 "gpr r4 .4 4 0\n"
27 "gpr r5 .4 5 0\n"
28 "gpr r6 .4 6 0\n"
29 "gpr r7 .4 7 0\n"
30 "gpr r8 .4 8 0\n"
31 "gpr r9 .4 9 0\n"
32 "gpr r10 .4 10 0\n"
33 "gpr r11 .4 11 0\n"
34 "gpr r12 .4 12 0\n"
35 "gpr r13 .4 13 0\n"
36 "gpr r14 .4 14 0\n"
37 "gpr r15 .4 15 0\n"
38 "gpr PC .64 32 0\n"
39 /* stack */
40 "gpr PC1 .64 34 0\n"
41 "gpr PC2 .64 34 0\n"
42 "gpr PC3 .64 34 0\n"
43 ;
44
45 return r_reg_set_profile_string (anal->reg, p);
46 }
47
48 /* That 3 is a hack */
49 static const int i4004_ins_len[16] = {
50 1, 2, 3, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1
51 };
52
53 static const char *i4004_e[16] = {
54 "wrm",
55 "wmp",
56 "wrr",
57 "wpm",
58 "wr0",
59 "wr1",
60 "wr2",
61 "wr3",
62 "sbm",
63 "rdm",
64 "rdr",
65 "adm",
66 "rd0",
67 "rd1",
68 "rd2",
69 "rd3"
70 };
71
72 static const char *i4004_f[16] = {
73 "clb",
74 "clc",
75 "iac",
76 "cmc",
77 "cma",
78 "ral",
79 "rar",
80 "tcc",
81 "dac", // decrement
82 "tcs",
83 "stc",
84 "daa",
85 "kbp",
86 "dcl",
87 "invalid",
88 "invalid"
89 };
90
i4004_get_ins_len(ut8 hex)91 static int i4004_get_ins_len (ut8 hex) {
92 ut8 high = (hex & 0xf0)>>4;
93 int ret = i4004_ins_len[high];
94 if (ret == 3) {
95 ret = (hex & 1) ? 1 : 2;
96 }
97 return ret;
98 }
99
i4004_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * buf,int len,RAnalOpMask mask)100 static int i4004_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
101 char basm[128];
102 const size_t basz = sizeof (basm)-1;
103 int rlen = i4004_get_ins_len (*buf);
104 if (!op) {
105 return 2;
106 }
107 ut8 high = (*buf & 0xf0)>>4;
108 ut8 low = (*buf & 0xf);
109 basm[0] = 0;
110
111 if (rlen > len) {
112 return op->size = 0;
113 }
114 switch (high) {
115 case 0:
116 if (low) {
117 op->type = R_ANAL_OP_TYPE_ILL;
118 } else {
119 op->type = R_ANAL_OP_TYPE_NOP;
120 }
121 break;
122 case 1: //snprintf (basm, basz, "jcn %d 0x%02x", low, buf[1]); break;
123 op->type = R_ANAL_OP_TYPE_CJMP;
124 op->jump = (addr & (~0xFF)) + buf[1];
125 op->fail = addr + rlen;
126 break;
127 case 2:
128 if (rlen == 1) {
129 snprintf (basm, basz, "scr r%d", (low & 0xe));
130 } else {
131 op->type = R_ANAL_OP_TYPE_MOV;
132 op->val = buf[1];
133 snprintf (basm, basz, "fim r%d, 0x%02x", (low & 0xe), buf[1]);
134 }
135 break;
136 case 3:
137 if (low & 1) {
138 op->type = R_ANAL_OP_TYPE_RJMP;
139 } else {
140 op->type = R_ANAL_OP_TYPE_MOV;
141 snprintf (basm, basz, "fin r%d", (low & 0xe));
142 }
143 break;
144 case 4:
145 op->type = R_ANAL_OP_TYPE_JMP;
146 op->jump = (ut16) (low<<8) | buf[1];
147 break;
148 case 5: //snprintf (basm, basz, "jms 0x%03x", ((ut16)(low<<8) | buf[1])); break;
149 op->type = R_ANAL_OP_TYPE_CALL;
150 op->jump = (ut16) (low<<8) | buf[1];
151 op->fail = addr + rlen;
152 break;
153 case 6: //snprintf (basm, basz, "inc r%d", low); break;
154 op->type = R_ANAL_OP_TYPE_ADD;
155 break;
156 case 7: //snprintf (basm, basz, "isz r%d, 0x%02x", low, buf[1]);
157 op->type = R_ANAL_OP_TYPE_CJMP;
158 op->fail = (addr & (~0xFF)) + buf[1];
159 op->jump = addr + rlen;
160 break;
161 case 8:
162 op->type = R_ANAL_OP_TYPE_ADD;
163 //snprintf (basm, basz, "add r%d", low); break;
164 break;
165 case 9:
166 op->type = R_ANAL_OP_TYPE_SUB;
167 //snprintf (basm, basz, "sub r%d", low); break;
168 break;
169 case 10: //snprintf (basm, basz, "ld r%d", low); break;
170 op->type = R_ANAL_OP_TYPE_MOV;
171 break;
172 case 11: //snprintf (basm, basz, "xch r%d", low); break;
173 op->type = R_ANAL_OP_TYPE_XCHG;
174 break;
175 case 12: //snprintf (basm, basz, "bbl %d", low); break;
176 op->type = R_ANAL_OP_TYPE_RET;
177 break;
178 case 13:
179 op->type = R_ANAL_OP_TYPE_LOAD;
180 //snprintf (basm, basz, "ldm %d", low); break;
181 break;
182 case 14:
183 strncpy (basm, i4004_e[low], basz);
184 basm[basz] = '\0';
185 break;
186 case 15:
187 strncpy (basm, i4004_f[low], basz);
188 basm[basz] = '\0';
189 if (!strcmp (basm, "dac")) {
190 op->type = R_ANAL_OP_TYPE_SUB;
191 }
192 break;
193 }
194 if (!strcmp (basm, "invalid")) {
195 op->type = R_ANAL_OP_TYPE_ILL;
196 } else if (!strcmp (basm, "ral")) {
197 op->type = R_ANAL_OP_TYPE_SHL;
198 } else if (!strcmp (basm, "rar")) {
199 op->type = R_ANAL_OP_TYPE_SHR;
200 }
201 return op->size = rlen;
202 }
203
204 RAnalPlugin r_anal_plugin_i4004 = {
205 .name = "i4004",
206 .desc = "i4004 code analysis plugin",
207 .license = "LGPL3",
208 .arch = "i4004",
209 .esil = true,
210 .bits = 8,
211 .op = &i4004_op,
212 .set_reg_profile = &set_reg_profile
213 };
214
215 #ifndef R2_PLUGIN_INCORE
216 R_API RLibStruct radare_plugin = {
217 .type = R_LIB_TYPE_ANAL,
218 .data = &r_anal_plugin_i4004,
219 .version = R2_VERSION
220 };
221 #endif
222