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