1 /* radare - LGPL - Copyright 2012 - pancake<nopcode.org>
2 				2013 - condret		*/
3 
4 #include <string.h>
5 #include <r_types.h>
6 #include <r_lib.h>
7 #include <r_asm.h>
8 #include <r_anal.h>
9 #include "../../asm/arch/z80/z80_tab.h"
10 
z80_op_size(const ut8 * data,int len,int * size,int * size_prefix)11 static void z80_op_size(const ut8 *data, int len, int *size, int *size_prefix) {
12 	int type = 0;
13 	if (len <1) {
14 		return;
15 	}
16 	switch (data[0]) {
17 	case 0xed:
18 		if (len > 1) {
19 			int idx = z80_ed_branch_index_res (data[1]);
20 			type = ed[idx].type;
21 		}
22 		break;
23 	case 0xcb:
24 		type = Z80_OP16;
25 		break;
26 	case 0xdd:
27 		if (len >1) {
28 			type = dd[z80_fddd_branch_index_res(data[1])].type;
29 		}
30 		break;
31 	case 0xfd:
32 		if (len > 1) {
33 			type = fd[z80_fddd_branch_index_res(data[1])].type;
34 		}
35 		break;
36 	default:
37 		type = z80_op[data[0]].type;
38 		break;
39 	}
40 
41 	if (type & Z80_OP8) {
42 		*size_prefix = 1;
43 	} else if (type & Z80_OP16) {
44 		*size_prefix = 2;
45 	} else if (type & Z80_OP24) {
46 		*size_prefix = 3;
47 	}
48 
49 	if (type & Z80_ARG16) {
50 		*size = *size_prefix + 2;
51 	} else if (type & Z80_ARG8) {
52 		*size = *size_prefix + 1;
53 	} else {
54 		*size = *size_prefix;
55 	}
56 }
57 
z80_anal_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * data,int len,RAnalOpMask mask)58 static int z80_anal_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) {
59 	int ilen = 0;
60 	z80_op_size (data, len, &ilen, &op->nopcode);
61 
62 	op->addr = addr;
63 	op->size = ilen;
64 	op->type = R_ANAL_OP_TYPE_UNK;
65 
66 	switch (data[0]) {
67 	case 0x00:
68 		op->type = R_ANAL_OP_TYPE_NOP;
69 		break;
70 	case 0x03:
71 	case 0x04:
72 	case 0x0c:
73 	case 0x13:
74 	case 0x14:
75 	case 0x1c:
76 	case 0x23:
77 	case 0x24:
78 	case 0x2c:
79 	case 0x33:
80 	case 0x34:
81 	case 0x3c:
82 		op->type = R_ANAL_OP_TYPE_ADD; // INC
83 		break;
84 	case 0x09:
85 	case 0x19:
86 	case 0x29:
87 	case 0x39:
88 	case 0x80:
89 	case 0x81:
90 	case 0x82:
91 	case 0x83:
92 	case 0x84:
93 	case 0x85:
94 	case 0x86:
95 	case 0x87:
96 	case 0xc6:
97 		op->type = R_ANAL_OP_TYPE_ADD;
98 		break;
99 	case 0x90:
100 	case 0x91:
101 	case 0x92:
102 	case 0x93:
103 	case 0x94:
104 	case 0x95:
105 	case 0x96:
106 	case 0x97:
107 	case 0xd6:
108 		op->type = R_ANAL_OP_TYPE_SUB;
109                 break;
110 	case 0x22: // ld (**), hl
111 		op->type = R_ANAL_OP_TYPE_STORE;
112 		op->refptr = 2;
113 		op->ptr = data[1] | data[2] << 8;
114 		break;
115 	case 0x32: // ld (**), a
116 		op->type = R_ANAL_OP_TYPE_STORE;
117 		op->refptr = 1;
118 		op->ptr = data[1] | data[2] << 8;
119 		break;
120 	case 0x2a: // ld hl, (**)
121 		op->type = R_ANAL_OP_TYPE_LOAD;
122 		op->refptr = 2;
123 		op->ptr = data[1] | data[2] << 8;
124 		break;
125 	case 0x3a: // ld a, (**)
126 		op->type = R_ANAL_OP_TYPE_LOAD;
127 		op->refptr = 1;
128 		op->ptr = data[1] | data[2] << 8;
129 		break;
130 	case 0xc0:
131 	case 0xc8:
132 	case 0xd0:
133 	case 0xd8:
134 	case 0xe0:
135 	case 0xe8:
136 	case 0xf0:
137 	case 0xf8:
138 		op->type = R_ANAL_OP_TYPE_CRET;
139 		break;
140 	case 0xc9:
141 		op->type = R_ANAL_OP_TYPE_RET;
142 		op->eob = true;
143 		op->stackop = R_ANAL_STACK_INC;
144 		op->stackptr = -2;
145 		break;
146 	case 0xed:
147 		switch(data[1]) {
148 		case 0x43:
149 		case 0x53:
150 		case 0x63:
151 		case 0x73:
152 			op->type = R_ANAL_OP_TYPE_STORE;
153 			op->refptr = 2;
154 			op->ptr = data[2] | data[3] << 8;
155 			break;
156 		case 0x4b:
157 		case 0x5b:
158 		case 0x6b:
159 		case 0x7b:
160 			op->type = R_ANAL_OP_TYPE_LOAD;
161 			op->refptr = 2;
162 			op->ptr = data[2] | data[3] << 8;
163 			break;
164 		case 0x45:	//retn
165 		case 0x4d:	//reti
166 			op->type = R_ANAL_OP_TYPE_RET;
167 			op->eob = true;
168 			break;
169 		}
170 		break;
171 	case 0xdd: // IX ops prefix
172 	case 0xfd: // IY ops prefix
173 		switch (data[1]) {
174 		case 0x22: // ld (**), ix; ld (**), iy
175 			op->type = R_ANAL_OP_TYPE_STORE;
176 			op->refptr = 2;
177 			op->ptr = data[2] | data[3] << 8;
178 			break;
179 		case 0x2a: // ld ix, (**); ld ix, (**)
180 			op->type = R_ANAL_OP_TYPE_LOAD;
181 			op->refptr = 2;
182 			op->ptr = data[2] | data[3] << 8;
183 			break;
184 		}
185 		break;
186 	case 0x05:
187 	case 0x0b:
188 	case 0x0d:
189 	case 0x15:
190 	case 0x1b:
191 	case 0x1d:
192 	case 0x25:
193 	case 0x2b:
194 	case 0x2d:
195 	case 0x35:
196 	case 0x3b:
197 	case 0x3d:
198 		// XXXX: DEC
199 		op->type = R_ANAL_OP_TYPE_SUB;
200 		break;
201 	case 0xc5:
202 	case 0xd5:
203 	case 0xe5:
204 	case 0xf5:
205 		op->type = R_ANAL_OP_TYPE_PUSH;
206 		break;
207 	case 0xc1:
208 	case 0xd1:
209 	case 0xe1:
210 	case 0xf1:
211 		op->type = R_ANAL_OP_TYPE_POP;
212 		break;
213 	// ld from register to register
214 	case 0x40:
215 	case 0x49:
216 	case 0x52:
217 	case 0x5b:
218 	case 0x64:
219 	case 0x6d:
220 	case 0x7f:
221 		break;
222 	case 0x76:
223 		op->type = R_ANAL_OP_TYPE_TRAP; // HALT
224 		break;
225 
226 	case 0x10: // djnz
227 		op->type = R_ANAL_OP_TYPE_CJMP;
228 		op->jump = addr + (st8)data[1] + ilen ;
229 		op->fail = addr + ilen;
230 		break;
231 	case 0x18: // jr xx
232 		op->type = R_ANAL_OP_TYPE_JMP;
233 		op->jump = addr + (st8)data[1] + ilen;
234 		break;
235 	// jr cond, xx
236 	case 0x20:
237 	case 0x28:
238 	case 0x30:
239 	case 0x38:
240 		op->type = R_ANAL_OP_TYPE_CJMP;
241 		op->jump = addr + ((len>1)? (st8)data[1]:0) + ilen;
242 		op->fail = addr + ilen;
243 		break;
244 
245 	// conditional jumps
246 	case 0xc2:
247 	case 0xca:
248 	case 0xd2:
249 	case 0xda:
250 	case 0xe2:
251 	case 0xea:
252 	case 0xf2:
253 	case 0xfa:
254 		op->type = R_ANAL_OP_TYPE_CJMP;
255 		op->jump = (len > 2)? data[1] | data[2] << 8: 0;
256 		op->fail = addr + ilen;
257 		break;
258 	case 0xc3: // jp xx
259 		op->type = R_ANAL_OP_TYPE_JMP;
260 		op->jump = (len > 2)? data[1] | data[2] << 8: 0;
261 		break;
262 	case 0xe9: // jp (HL)
263 		op->type = R_ANAL_OP_TYPE_UJMP;
264 		break;
265 
266 	case 0xc7:				//rst 0
267 		op->jump = 0x00;
268 		op->type = R_ANAL_OP_TYPE_SWI;
269 		break;
270 	case 0xcf:				//rst 8
271 		op->jump = 0x08;
272 		op->type = R_ANAL_OP_TYPE_SWI;
273 		break;
274 	case 0xd7:				//rst 16
275 		op->jump = 0x10;
276 		op->type = R_ANAL_OP_TYPE_SWI;
277 		break;
278 	case 0xdf:				//rst 24
279 		op->jump = 0x18;
280 		op->type = R_ANAL_OP_TYPE_SWI;
281 		break;
282 	case 0xe7:				//rst 32
283 		op->jump = 0x20;
284 		op->type = R_ANAL_OP_TYPE_SWI;
285 		break;
286 	case 0xef:				//rst 40
287 		op->jump = 0x28;
288 		op->type = R_ANAL_OP_TYPE_SWI;
289 		break;
290 	case 0xf7:				//rst 48
291 		op->jump = 0x30;
292 		op->type = R_ANAL_OP_TYPE_SWI;
293 		break;
294 	case 0xff:				//rst 56
295 		op->jump = 0x38;
296 		op->type = R_ANAL_OP_TYPE_SWI;
297 		break;				// condret: i think that foo resets some regs, but i'm not sure
298 
299 	// conditional call
300 	case 0xc4: // nz
301 	case 0xd4: // nc
302 	case 0xe4: // po
303 	case 0xf4: // p
304 
305 	case 0xcc: // z
306 	case 0xdc: // c
307 	case 0xec: // pe
308 	case 0xfc: // m
309 		op->type = R_ANAL_OP_TYPE_CCALL;
310 		op->jump = (len>2)? data[1] | data[2] << 8: 0;
311 		op->fail = addr + ilen;
312 		break;
313 
314 	// call
315 	case 0xcd:
316 		op->type = R_ANAL_OP_TYPE_CALL;
317 		op->stackop = R_ANAL_STACK_INC;
318 		op->stackptr = 2;
319 		op->jump = data[1] | data[2] << 8;
320 		break;
321 	case 0xcb:			//the same as for gameboy
322 		switch(data[1]/8) {
323 		case 0:
324 		case 2:
325 		case 4:
326 		case 6:				//swap
327 			op->type = R_ANAL_OP_TYPE_ROL;
328 			break;
329 		case 1:
330 		case 3:
331 		case 5:
332 		case 7:
333 			op->type = R_ANAL_OP_TYPE_ROR;
334 			break;
335 		case 8:
336 		case 9:
337 		case 10:
338 		case 11:
339 		case 12:
340 		case 13:
341 		case 14:
342 		case 15:
343 			op->type = R_ANAL_OP_TYPE_AND;
344 			break;			//bit
345 		case 16:
346 		case 17:
347 		case 18:
348 		case 19:
349 		case 20:
350 		case 21:
351 		case 22:
352 		case 23:
353 			op->type = R_ANAL_OP_TYPE_XOR;
354 			break;			//set
355 		case 24:
356 		case 25:
357 		case 26:
358 		case 27:
359 		case 28:
360 		case 29:
361 		case 30:
362 		case 31:
363 			op->type = R_ANAL_OP_TYPE_MOV;
364 			break;			//res
365 		}
366 		break;
367 	}
368 	return ilen;
369 }
370 
set_reg_profile(RAnal * anal)371 static bool set_reg_profile(RAnal *anal) {
372 	const char *p =
373 		"=PC	mpc\n"
374 		"=SP	sp\n"
375 		"=A0	af\n"
376 		"=A1	bc\n"
377 		"=A2	de\n"
378 		"=A3	hl\n"
379 
380 		"gpr	mpc	.32	0	0\n"
381 		"gpr	pc	.16	0	0\n"
382 		"gpr	m	.16	2	0\n"
383 
384 		"gpr	sp	.16	4	0\n"
385 
386 		"gpr	af	.16	6	0\n"
387 		"gpr	f	.8	6	0\n"
388 		"gpr	a	.8	7	0\n"
389 		"gpr	Z	.1	.55	0\n"
390 		"gpr	N	.1	.54	0\n"
391 		"gpr	H	.1	.53	0\n"
392 		"gpr	C	.1	.52	0\n"
393 
394 		"gpr	bc	.16	8	0\n"
395 		"gpr	c	.8	8	0\n"
396 		"gpr	b	.8	9	0\n"
397 
398 		"gpr	de	.16	10	0\n"
399 		"gpr	e	.8	10	0\n"
400 		"gpr	d	.8	11	0\n"
401 
402 		"gpr	hl	.16	12	0\n"
403 		"gpr	l	.8	12	0\n"
404 		"gpr	h	.8	13	0\n"
405 
406 		"gpr	mbcrom	.16	14	0\n"
407 		"gpr	mbcram	.16	16	0\n"
408 
409 		"gpr	ime	.1	18	0\n";
410 	return r_reg_set_profile_string (anal->reg, p);
411 }
412 
archinfo(RAnal * anal,int q)413 static int archinfo(RAnal *anal, int q) {
414 	return 1;
415 }
416 
417 RAnalPlugin r_anal_plugin_z80 = {
418 	.name = "z80",
419 	.arch = "z80",
420 	.license = "LGPL3",
421 	.bits = 16,
422 	.set_reg_profile = &set_reg_profile,
423 	.desc = "Z80 CPU code analysis plugin",
424 	.archinfo = archinfo,
425 	.op = &z80_anal_op,
426 };
427 
428 #ifndef R2_PLUGIN_INCORE
429 R_API RLibStruct radare_plugin = {
430 	.type = R_LIB_TYPE_ANAL,
431 	.data = &r_anal_plugin_z80,
432 	.version = R2_VERSION
433 };
434 #endif
435