1 /* radare - LGPL - Copyright 2010-2020 - pancake, nibble */
2 
3 #include <r_anal.h>
4 #include <r_util.h>
5 #include <r_list.h>
6 
r_anal_op_new(void)7 R_API RAnalOp *r_anal_op_new(void) {
8 	RAnalOp *op = R_NEW (RAnalOp);
9 	r_anal_op_init (op);
10 	return op;
11 }
12 
r_anal_op_list_new(void)13 R_API RList *r_anal_op_list_new(void) {
14 	RList *list = r_list_new ();
15 	if (list) {
16 		list->free = &r_anal_op_free;
17 	}
18 	return list;
19 }
20 
r_anal_op_init(RAnalOp * op)21 R_API void r_anal_op_init(RAnalOp *op) {
22 	if (op) {
23 		memset (op, 0, sizeof (*op));
24 		op->addr = UT64_MAX;
25 		op->jump = UT64_MAX;
26 		op->fail = UT64_MAX;
27 		op->ptr = UT64_MAX;
28 		op->refptr = 0;
29 		op->val = UT64_MAX;
30 		op->disp = UT64_MAX;
31 	}
32 }
33 
r_anal_op_fini(RAnalOp * op)34 R_API bool r_anal_op_fini(RAnalOp *op) {
35 	if (!op) {
36 		return false;
37 	}
38 	r_anal_value_free (op->src[0]);
39 	r_anal_value_free (op->src[1]);
40 	r_anal_value_free (op->src[2]);
41 	op->src[0] = NULL;
42 	op->src[1] = NULL;
43 	op->src[2] = NULL;
44 	r_anal_value_free (op->dst);
45 	op->dst = NULL;
46 	r_list_free (op->access);
47 	op->access = NULL;
48 	r_strbuf_fini (&op->opex);
49 	r_strbuf_fini (&op->esil);
50 	r_anal_switch_op_free (op->switch_op);
51 	op->switch_op = NULL;
52 	R_FREE (op->mnemonic);
53 	return true;
54 }
55 
r_anal_op_free(void * _op)56 R_API void r_anal_op_free(void *_op) {
57 	if (!_op) {
58 		return;
59 	}
60 	r_anal_op_fini (_op);
61 	memset (_op, 0, sizeof (RAnalOp));
62 	free (_op);
63 }
64 
defaultCycles(RAnalOp * op)65 static int defaultCycles(RAnalOp *op) {
66 	switch (op->type) {
67 	case R_ANAL_OP_TYPE_PUSH:
68 	case R_ANAL_OP_TYPE_POP:
69 	case R_ANAL_OP_TYPE_STORE:
70 	case R_ANAL_OP_TYPE_LOAD:
71 		return 2;
72 	case R_ANAL_OP_TYPE_LEA:
73 	case R_ANAL_OP_TYPE_MOV:
74 	case R_ANAL_OP_TYPE_NOP:
75 		return 1;
76 	case R_ANAL_OP_TYPE_TRAP:
77 	case R_ANAL_OP_TYPE_SWI:
78 		return 4;
79 	case R_ANAL_OP_TYPE_SYNC:
80 		return 4;
81 	case R_ANAL_OP_TYPE_RET:
82 	case R_ANAL_OP_TYPE_JMP:
83 	case R_ANAL_OP_TYPE_RJMP:
84 	case R_ANAL_OP_TYPE_CALL:
85 		return 4;
86 	default:
87 		return 1;
88 	}
89 }
90 
r_anal_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * data,int len,RAnalOpMask mask)91 R_API int r_anal_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) {
92 	r_anal_op_init (op);
93 	r_return_val_if_fail (anal && op && len > 0, -1);
94 
95 	int ret = R_MIN (2, len);
96 	if (len > 0 && anal->cur && anal->cur->op) {
97 		//use core binding to set asm.bits correctly based on the addr
98 		//this is because of the hassle of arm/thumb
99 		if (anal && anal->coreb.archbits) {
100 			anal->coreb.archbits (anal->coreb.core, addr);
101 		}
102 		if (anal->pcalign && addr % anal->pcalign) {
103 			op->type = R_ANAL_OP_TYPE_ILL;
104 			op->addr = addr;
105 			// eprintf ("Unaligned instruction for %d bits at 0x%"PFMT64x"\n", anal->bits, addr);
106 			op->size = 1;
107 			return -1;
108 		}
109 		ret = anal->cur->op (anal, op, addr, data, len, mask);
110 		if (ret < 1) {
111 			op->type = R_ANAL_OP_TYPE_ILL;
112 		}
113 		op->addr = addr;
114 		/* consider at least 1 byte to be part of the opcode */
115 		if (op->nopcode < 1) {
116 			op->nopcode = 1;
117 		}
118 	} else if (!memcmp (data, "\xff\xff\xff\xff", R_MIN (4, len))) {
119 		op->type = R_ANAL_OP_TYPE_ILL;
120 	} else {
121 		op->type = R_ANAL_OP_TYPE_MOV;
122 		if (op->cycles == 0) {
123 			op->cycles = defaultCycles (op);
124 		}
125 	}
126 	if (!op->mnemonic && (mask & R_ANAL_OP_MASK_DISASM)) {
127 		if (anal->verbose) {
128 			eprintf ("Warning: unhandled R_ANAL_OP_MASK_DISASM in r_anal_op\n");
129 		}
130         }
131 	if (mask & R_ANAL_OP_MASK_HINT) {
132 		RAnalHint *hint = r_anal_hint_get (anal, addr);
133 		if (hint) {
134 			r_anal_op_hint (op, hint);
135 			r_anal_hint_free (hint);
136 		}
137 	}
138 	return ret;
139 }
140 
r_anal_op_copy(RAnalOp * op)141 R_API RAnalOp *r_anal_op_copy(RAnalOp *op) {
142 	RAnalOp *nop = R_NEW0 (RAnalOp);
143 	if (!nop) {
144 		return NULL;
145 	}
146 	*nop = *op;
147 	if (op->mnemonic) {
148 		nop->mnemonic = strdup (op->mnemonic);
149 		if (!nop->mnemonic) {
150 			free (nop);
151 			return NULL;
152 		}
153 	} else {
154 		nop->mnemonic = NULL;
155 	}
156 	nop->src[0] = r_anal_value_copy (op->src[0]);
157 	nop->src[1] = r_anal_value_copy (op->src[1]);
158 	nop->src[2] = r_anal_value_copy (op->src[2]);
159 	nop->dst = r_anal_value_copy (op->dst);
160 	if (op->access) {
161 		RListIter *it;
162 		RAnalValue *val;
163 		RList *naccess = r_list_newf ((RListFree)r_anal_value_free);
164 		r_list_foreach (op->access, it, val) {
165 			r_list_append (naccess, r_anal_value_copy (val));
166 		}
167 		nop->access = naccess;
168 	}
169 	r_strbuf_init (&nop->esil);
170 	r_strbuf_copy (&nop->esil, &op->esil);
171 	return nop;
172 }
173 
r_anal_op_nonlinear(int t)174 R_API bool r_anal_op_nonlinear(int t) {
175 	t &= R_ANAL_OP_TYPE_MASK;
176 	switch (t) {
177 	//call
178 	case R_ANAL_OP_TYPE_CALL:
179 	case R_ANAL_OP_TYPE_RCALL:
180 	case R_ANAL_OP_TYPE_ICALL:
181 	case R_ANAL_OP_TYPE_UCALL:
182 	case R_ANAL_OP_TYPE_IRCALL:
183 	case R_ANAL_OP_TYPE_UCCALL:
184 	// jmp
185 	case R_ANAL_OP_TYPE_JMP:
186 	case R_ANAL_OP_TYPE_MJMP:
187 	case R_ANAL_OP_TYPE_UJMP:
188 	case R_ANAL_OP_TYPE_CJMP:
189 	case R_ANAL_OP_TYPE_UCJMP:
190 	case R_ANAL_OP_TYPE_RJMP:
191 	case R_ANAL_OP_TYPE_IJMP:
192 	case R_ANAL_OP_TYPE_IRJMP:
193 	// trap| ill| unk
194 	case R_ANAL_OP_TYPE_TRAP:
195 	case R_ANAL_OP_TYPE_ILL:
196 	case R_ANAL_OP_TYPE_UNK:
197 	case R_ANAL_OP_TYPE_SWI:
198 	case R_ANAL_OP_TYPE_RET:
199 		return true;
200 	default:
201 		return false;
202 	}
203 }
204 
r_anal_op_ismemref(int t)205 R_API bool r_anal_op_ismemref(int t) {
206 	t &= R_ANAL_OP_TYPE_MASK;
207 	switch (t) {
208 	case R_ANAL_OP_TYPE_LOAD:
209 	case R_ANAL_OP_TYPE_MOV:
210 	case R_ANAL_OP_TYPE_STORE:
211 	case R_ANAL_OP_TYPE_LEA:
212 	case R_ANAL_OP_TYPE_CMP:
213 		return true;
214 	default:
215 		return false;
216 	}
217 }
218 
219 static struct optype {
220 	int type;
221 	const char *name;
222 } optypes[] = {
223 	{ R_ANAL_OP_TYPE_IO, "io" },
224 	{ R_ANAL_OP_TYPE_ACMP, "acmp" },
225 	{ R_ANAL_OP_TYPE_ADD, "add" },
226 	{ R_ANAL_OP_TYPE_SYNC, "sync" },
227 	{ R_ANAL_OP_TYPE_AND, "and" },
228 	{ R_ANAL_OP_TYPE_CALL, "call" },
229 	{ R_ANAL_OP_TYPE_CCALL, "ccall" },
230 	{ R_ANAL_OP_TYPE_CJMP, "cjmp" },
231 	{ R_ANAL_OP_TYPE_MJMP, "mjmp" },
232 	{ R_ANAL_OP_TYPE_CMP, "cmp" },
233 	{ R_ANAL_OP_TYPE_IO, "cret" },
234 	{ R_ANAL_OP_TYPE_ILL, "ill" },
235 	{ R_ANAL_OP_TYPE_JMP, "jmp" },
236 	{ R_ANAL_OP_TYPE_LEA, "lea" },
237 	{ R_ANAL_OP_TYPE_LEAVE, "leave" },
238 	{ R_ANAL_OP_TYPE_LOAD, "load" },
239 	{ R_ANAL_OP_TYPE_NEW, "new" },
240 	{ R_ANAL_OP_TYPE_MOD, "mod" },
241 	{ R_ANAL_OP_TYPE_CMOV, "cmov" },
242 	{ R_ANAL_OP_TYPE_MOV, "mov" },
243 	{ R_ANAL_OP_TYPE_CAST, "cast" },
244 	{ R_ANAL_OP_TYPE_MUL, "mul" },
245 	{ R_ANAL_OP_TYPE_DIV, "div" },
246 	{ R_ANAL_OP_TYPE_NOP, "nop" },
247 	{ R_ANAL_OP_TYPE_NOT, "not" },
248 	{ R_ANAL_OP_TYPE_NULL  , "null" },
249 	{ R_ANAL_OP_TYPE_OR    , "or" },
250 	{ R_ANAL_OP_TYPE_POP   , "pop" },
251 	{ R_ANAL_OP_TYPE_PUSH  , "push" },
252 	{ R_ANAL_OP_TYPE_REP   , "rep" },
253 	{ R_ANAL_OP_TYPE_RET   , "ret" },
254 	{ R_ANAL_OP_TYPE_ROL   , "rol" },
255 	{ R_ANAL_OP_TYPE_ROR   , "ror" },
256 	{ R_ANAL_OP_TYPE_SAL   , "sal" },
257 	{ R_ANAL_OP_TYPE_SAR   , "sar" },
258 	{ R_ANAL_OP_TYPE_SHL   , "shl" },
259 	{ R_ANAL_OP_TYPE_SHR   , "shr" },
260 	{ R_ANAL_OP_TYPE_STORE , "store" },
261 	{ R_ANAL_OP_TYPE_SUB   , "sub" },
262 	{ R_ANAL_OP_TYPE_SWI   , "swi" },
263 	{ R_ANAL_OP_TYPE_CSWI  , "cswi" },
264 	{ R_ANAL_OP_TYPE_SWITCH, "switch" },
265 	{ R_ANAL_OP_TYPE_TRAP  , "trap" },
266 	{ R_ANAL_OP_TYPE_UCALL , "ucall" },
267 	{ R_ANAL_OP_TYPE_RCALL , "rcall" }, // needs to be changed
268 	{ R_ANAL_OP_TYPE_ICALL , "ucall" }, // needs to be changed
269 	{ R_ANAL_OP_TYPE_IRCALL, "ucall" }, // needs to be changed
270 	{ R_ANAL_OP_TYPE_UCCALL, "uccall" },
271 	{ R_ANAL_OP_TYPE_UCJMP , "ucjmp" },
272 	{ R_ANAL_OP_TYPE_UJMP  , "ujmp" },
273 	{ R_ANAL_OP_TYPE_RJMP  , "rjmp" }, // needs to be changed
274 	{ R_ANAL_OP_TYPE_IJMP  , "ujmp" }, // needs to be changed
275 	{ R_ANAL_OP_TYPE_IRJMP , "ujmp" }, // needs to be changed
276 	{ R_ANAL_OP_TYPE_UNK   , "unk" },
277 	{ R_ANAL_OP_TYPE_UPUSH , "upush" },
278 	{ R_ANAL_OP_TYPE_RPUSH , "rpush" },
279 	{ R_ANAL_OP_TYPE_XCHG  , "xchg" },
280 	{ R_ANAL_OP_TYPE_XOR   , "xor" },
281 	{ R_ANAL_OP_TYPE_CASE  , "case" },
282 	{ R_ANAL_OP_TYPE_CPL   , "cpl" },
283 	{ R_ANAL_OP_TYPE_CRYPTO, "crypto" },
284 	{0,NULL}
285 };
286 
r_anal_optype_from_string(const char * type)287 R_API int r_anal_optype_from_string(const char *type) {
288 	int i;
289 	for  (i = 0; optypes[i].name;i++) {
290 		if (!strcmp (optypes[i].name, type)) {
291 			return optypes[i].type;
292 		}
293 	}
294 	return -1;
295 }
296 
r_anal_optype_to_string(int t)297 R_API const char *r_anal_optype_to_string(int t) {
298 	bool once = true;
299 repeat:
300 	// TODO: delete
301 	switch (t) {
302 	case R_ANAL_OP_TYPE_IO    : return "io";
303 	case R_ANAL_OP_TYPE_ACMP  : return "acmp";
304 	case R_ANAL_OP_TYPE_ADD   : return "add";
305 	case R_ANAL_OP_TYPE_SYNC  : return "sync";
306 	case R_ANAL_OP_TYPE_AND   : return "and";
307 	case R_ANAL_OP_TYPE_CALL  : return "call";
308 	case R_ANAL_OP_TYPE_CCALL : return "ccall";
309 	case R_ANAL_OP_TYPE_CJMP  : return "cjmp";
310 	case R_ANAL_OP_TYPE_MJMP  : return "mjmp";
311 	case R_ANAL_OP_TYPE_CMP   : return "cmp";
312 	case R_ANAL_OP_TYPE_CRET  : return "cret";
313 	case R_ANAL_OP_TYPE_DIV   : return "div";
314 	case R_ANAL_OP_TYPE_ILL   : return "ill";
315 	case R_ANAL_OP_TYPE_JMP   : return "jmp";
316 	case R_ANAL_OP_TYPE_LEA   : return "lea";
317 	case R_ANAL_OP_TYPE_LEAVE : return "leave";
318 	case R_ANAL_OP_TYPE_LOAD  : return "load";
319 	case R_ANAL_OP_TYPE_NEW   : return "new";
320 	case R_ANAL_OP_TYPE_MOD   : return "mod";
321 	case R_ANAL_OP_TYPE_CMOV  : return "cmov";
322 	case R_ANAL_OP_TYPE_MOV   : return "mov";
323 	case R_ANAL_OP_TYPE_CAST  : return "cast";
324 	case R_ANAL_OP_TYPE_MUL   : return "mul";
325 	case R_ANAL_OP_TYPE_NOP   : return "nop";
326 	case R_ANAL_OP_TYPE_NOT   : return "not";
327 	case R_ANAL_OP_TYPE_NULL  : return "null";
328 	case R_ANAL_OP_TYPE_OR    : return "or";
329 	case R_ANAL_OP_TYPE_POP   : return "pop";
330 	case R_ANAL_OP_TYPE_PUSH  : return "push";
331 	case R_ANAL_OP_TYPE_RPUSH : return "rpush";
332 	case R_ANAL_OP_TYPE_REP   : return "rep";
333 	case R_ANAL_OP_TYPE_RET   : return "ret";
334 	case R_ANAL_OP_TYPE_ROL   : return "rol";
335 	case R_ANAL_OP_TYPE_ROR   : return "ror";
336 	case R_ANAL_OP_TYPE_SAL   : return "sal";
337 	case R_ANAL_OP_TYPE_SAR   : return "sar";
338 	case R_ANAL_OP_TYPE_SHL   : return "shl";
339 	case R_ANAL_OP_TYPE_SHR   : return "shr";
340 	case R_ANAL_OP_TYPE_STORE : return "store";
341 	case R_ANAL_OP_TYPE_SUB   : return "sub";
342 	case R_ANAL_OP_TYPE_SWI   : return "swi";
343 	case R_ANAL_OP_TYPE_CSWI  : return "cswi";
344 	case R_ANAL_OP_TYPE_SWITCH: return "switch";
345 	case R_ANAL_OP_TYPE_TRAP  : return "trap";
346 	case R_ANAL_OP_TYPE_UCALL : return "ucall";
347 	case R_ANAL_OP_TYPE_RCALL : return "rcall"; // needs to be changed
348 	case R_ANAL_OP_TYPE_ICALL : return "ucall"; // needs to be changed
349 	case R_ANAL_OP_TYPE_IRCALL: return "ucall"; // needs to be changed
350 	case R_ANAL_OP_TYPE_UCCALL: return "uccall";
351 	case R_ANAL_OP_TYPE_UCJMP : return "ucjmp";
352 	case R_ANAL_OP_TYPE_UJMP  : return "ujmp";
353 	case R_ANAL_OP_TYPE_RJMP  : return "rjmp"; // needs to be changed
354 	case R_ANAL_OP_TYPE_IJMP  : return "ujmp"; // needs to be changed
355 	case R_ANAL_OP_TYPE_IRJMP : return "ujmp"; // needs to be changed
356 	case R_ANAL_OP_TYPE_UNK   : return "unk";
357 	case R_ANAL_OP_TYPE_UPUSH : return "upush";
358 	case R_ANAL_OP_TYPE_XCHG  : return "xchg";
359 	case R_ANAL_OP_TYPE_XOR   : return "xor";
360 	case R_ANAL_OP_TYPE_CASE  : return "case";
361 	case R_ANAL_OP_TYPE_CPL   : return "cpl";
362 	case R_ANAL_OP_TYPE_CRYPTO: return "crypto";
363 	}
364 	if (once) {
365 		once = false;
366 		t &= R_ANAL_OP_TYPE_MASK; // ignore the modifier bits... we don't want this!
367 		goto repeat;
368 	}
369 	return "undefined";
370 }
371 
r_anal_op_to_esil_string(RAnal * anal,RAnalOp * op)372 R_API const char *r_anal_op_to_esil_string(RAnal *anal, RAnalOp *op) {
373 	return r_strbuf_get (&op->esil);
374 }
375 
376 // TODO: use esil here?
r_anal_op_to_string(RAnal * anal,RAnalOp * op)377 R_API char *r_anal_op_to_string(RAnal *anal, RAnalOp *op) {
378 	RAnalBlock *bb;
379 	RAnalFunction *f;
380 	char *cstr, ret[128];
381 	char *r0 = r_anal_value_to_string (op->dst);
382 	char *a0 = r_anal_value_to_string (op->src[0]);
383 	char *a1 = r_anal_value_to_string (op->src[1]);
384 	if (!r0) {
385 		r0 = strdup ("?");
386 	}
387 	if (!a0) {
388 		a0 = strdup ("?");
389 	}
390 	if (!a1) {
391 		a1 = strdup ("?");
392 	}
393 
394 	switch (op->type) {
395 	case R_ANAL_OP_TYPE_MOV:
396 		snprintf (ret, sizeof (ret), "%s = %s", r0, a0);
397 		break;
398 	case R_ANAL_OP_TYPE_CJMP:
399 		if ((bb = r_anal_bb_from_offset (anal, op->addr))) {
400 			cstr = r_anal_cond_to_string (bb->cond);
401 			snprintf (ret, sizeof (ret), "if (%s) goto 0x%"PFMT64x, cstr, op->jump);
402 			free (cstr);
403 		} else {
404 			snprintf (ret, sizeof (ret), "if (%s) goto 0x%"PFMT64x, "?", op->jump);
405 		}
406 		break;
407 	case R_ANAL_OP_TYPE_JMP:
408 		snprintf (ret, sizeof (ret), "goto 0x%"PFMT64x, op->jump);
409 		break;
410 	case R_ANAL_OP_TYPE_UJMP:
411 	case R_ANAL_OP_TYPE_RJMP:
412 	case R_ANAL_OP_TYPE_IJMP:
413 	case R_ANAL_OP_TYPE_IRJMP:
414 		snprintf (ret, sizeof (ret), "goto %s", r0);
415 		break;
416 	case R_ANAL_OP_TYPE_PUSH:
417 	case R_ANAL_OP_TYPE_UPUSH:
418 	case R_ANAL_OP_TYPE_RPUSH:
419 		snprintf (ret, sizeof (ret), "push %s", a0);
420 		break;
421 	case R_ANAL_OP_TYPE_POP:
422 		snprintf (ret, sizeof (ret), "pop %s", r0);
423 		break;
424 	case R_ANAL_OP_TYPE_UCALL:
425 	case R_ANAL_OP_TYPE_RCALL:
426 	case R_ANAL_OP_TYPE_ICALL:
427 	case R_ANAL_OP_TYPE_IRCALL:
428 		snprintf (ret, sizeof (ret), "%s()", r0);
429 		break;
430 	case R_ANAL_OP_TYPE_CALL:
431 		f = r_anal_get_fcn_in (anal, op->jump, R_ANAL_FCN_TYPE_NULL);
432 		if (f) {
433 			snprintf (ret, sizeof (ret), "%s()", f->name);
434 		} else {
435 			snprintf (ret, sizeof (ret), "0x%"PFMT64x"()", op->jump);
436 		}
437 		break;
438 	case R_ANAL_OP_TYPE_CCALL:
439 		f = r_anal_get_fcn_in (anal, op->jump, R_ANAL_FCN_TYPE_NULL);
440 		if ((bb = r_anal_bb_from_offset (anal, op->addr))) {
441 			cstr = r_anal_cond_to_string (bb->cond);
442 			if (f) {
443 				snprintf (ret, sizeof (ret), "if (%s) %s()", cstr, f->name);
444 			} else {
445 				snprintf (ret, sizeof (ret), "if (%s) 0x%" PFMT64x "()", cstr, op->jump);
446 			}
447 			free (cstr);
448 		} else {
449 			if (f) {
450 				snprintf (ret, sizeof (ret), "if (unk) %s()", f->name);
451 			} else {
452 				snprintf (ret, sizeof (ret), "if (unk) 0x%" PFMT64x "()", op->jump);
453 			}
454 		}
455 		break;
456 	case R_ANAL_OP_TYPE_ADD:
457 		if (!a1 || !strcmp (a0, a1)) {
458 			snprintf (ret, sizeof (ret), "%s += %s", r0, a0);
459 		} else {
460 			snprintf (ret, sizeof (ret), "%s = %s + %s", r0, a0, a1);
461 		}
462 		break;
463 	case R_ANAL_OP_TYPE_SUB:
464 		if (!a1 || !strcmp (a0, a1)) {
465 			snprintf (ret, sizeof (ret), "%s -= %s", r0, a0);
466 		} else {
467 			snprintf (ret, sizeof (ret), "%s = %s - %s", r0, a0, a1);
468 		}
469 		break;
470 	case R_ANAL_OP_TYPE_MUL:
471 		if (!a1 || !strcmp (a0, a1)) {
472 			snprintf (ret, sizeof (ret), "%s *= %s", r0, a0);
473 		} else {
474 			snprintf (ret, sizeof (ret), "%s = %s * %s", r0, a0, a1);
475 		}
476 		break;
477 	case R_ANAL_OP_TYPE_DIV:
478 		if (!a1 || !strcmp (a0, a1)) {
479 			snprintf (ret, sizeof (ret), "%s /= %s", r0, a0);
480 		} else {
481 			snprintf (ret, sizeof (ret), "%s = %s / %s", r0, a0, a1);
482 		}
483 		break;
484 	case R_ANAL_OP_TYPE_AND:
485 		if (!a1 || !strcmp (a0, a1)) {
486 			snprintf (ret, sizeof (ret), "%s &= %s", r0, a0);
487 		} else {
488 			snprintf (ret, sizeof (ret), "%s = %s & %s", r0, a0, a1);
489 		}
490 		break;
491 	case R_ANAL_OP_TYPE_OR:
492 		if (!a1 || !strcmp (a0, a1)) {
493 			snprintf (ret, sizeof (ret), "%s |= %s", r0, a0);
494 		} else {
495 			snprintf (ret, sizeof (ret), "%s = %s | %s", r0, a0, a1);
496 		}
497 		break;
498 	case R_ANAL_OP_TYPE_XOR:
499 		if (!a1 || !strcmp (a0, a1)) {
500 			snprintf (ret, sizeof (ret), "%s ^= %s", r0, a0);
501 		} else {
502 			snprintf (ret, sizeof (ret), "%s = %s ^ %s", r0, a0, a1);
503 		}
504 		break;
505 	case R_ANAL_OP_TYPE_LEA:
506 		snprintf (ret, sizeof (ret), "%s -> %s", r0, a0);
507 		break;
508 	case R_ANAL_OP_TYPE_CMP:
509 		memcpy (ret, ";", 2);
510 		break;
511 	case R_ANAL_OP_TYPE_NOP:
512 		memcpy (ret, "nop", 4);
513 		break;
514 	case R_ANAL_OP_TYPE_RET:
515 		memcpy (ret, "ret", 4);
516 		break;
517 	case R_ANAL_OP_TYPE_CRET:
518 		if ((bb = r_anal_bb_from_offset (anal, op->addr))) {
519 			cstr = r_anal_cond_to_string (bb->cond);
520 			snprintf (ret, sizeof (ret), "if (%s) ret", cstr);
521 			free (cstr);
522 		} else {
523 			strcpy (ret, "if (unk) ret");
524 		}
525 		break;
526 	case R_ANAL_OP_TYPE_LEAVE:
527 		memcpy (ret, "leave", 6);
528 		break;
529 	case R_ANAL_OP_TYPE_MOD:
530 		if (!a1 || !strcmp (a0, a1)) {
531 			snprintf (ret, sizeof (ret), "%s %%= %s", r0, a0);
532 		} else {
533 			snprintf (ret, sizeof (ret), "%s = %s %% %s", r0, a0, a1);
534 		}
535 		break;
536 	case R_ANAL_OP_TYPE_XCHG:
537 		if (!a1 || !strcmp (a0, a1)) {
538 			snprintf (ret, sizeof (ret), "tmp = %s; %s = %s; %s = tmp", r0, r0, a0, a0);
539 		} else {
540 			snprintf (ret, sizeof (ret), "%s = %s ^ %s", r0, a0, a1);
541 		}
542 		break;
543 	case R_ANAL_OP_TYPE_ROL:
544 	case R_ANAL_OP_TYPE_ROR:
545 	case R_ANAL_OP_TYPE_SWITCH:
546 	case R_ANAL_OP_TYPE_CASE:
547 		eprintf ("Command not implemented.\n");
548 		free (r0);
549 		free (a0);
550 		free (a1);
551 		return NULL;
552 	default:
553 		free (r0);
554 		free (a0);
555 		free (a1);
556 		return NULL;
557 	}
558 	free (r0);
559 	free (a0);
560 	free (a1);
561 	return strdup (ret);
562 }
563 
r_anal_stackop_tostring(int s)564 R_API const char *r_anal_stackop_tostring(int s) {
565 	switch (s) {
566 	case R_ANAL_STACK_NULL:
567 		return "null";
568 	case R_ANAL_STACK_NOP:
569 		return "nop";
570 	case R_ANAL_STACK_INC:
571 		return "inc";
572 	case R_ANAL_STACK_GET:
573 		return "get";
574 	case R_ANAL_STACK_SET:
575 		return "set";
576 	case R_ANAL_STACK_RESET:
577 		return "reset";
578 	}
579 	return "unk";
580 }
581 
r_anal_op_family_to_string(int n)582 R_API const char *r_anal_op_family_to_string(int n) {
583 	switch (n) {
584 	case R_ANAL_OP_FAMILY_UNKNOWN: return "unk";
585 	case R_ANAL_OP_FAMILY_CPU: return "cpu";
586 	case R_ANAL_OP_FAMILY_SECURITY: return "sec";
587 	case R_ANAL_OP_FAMILY_FPU: return "fpu";
588 	case R_ANAL_OP_FAMILY_MMX: return "mmx";
589 	case R_ANAL_OP_FAMILY_SSE: return "sse";
590 	case R_ANAL_OP_FAMILY_PRIV: return "priv";
591 	case R_ANAL_OP_FAMILY_THREAD: return "thrd";
592 	case R_ANAL_OP_FAMILY_CRYPTO: return "crpt";
593 	case R_ANAL_OP_FAMILY_IO: return "io";
594 	case R_ANAL_OP_FAMILY_VIRT: return "virt";
595 	}
596 	return NULL;
597 }
598 
r_anal_op_family_from_string(const char * f)599 R_API int r_anal_op_family_from_string(const char *f) {
600 	struct op_family {
601 		const char *name;
602 		int id;
603 	};
604 	static const struct op_family of[] = {
605 		{"cpu", R_ANAL_OP_FAMILY_CPU},
606 		{"fpu", R_ANAL_OP_FAMILY_FPU},
607 		{"mmx", R_ANAL_OP_FAMILY_MMX},
608 		{"sse", R_ANAL_OP_FAMILY_SSE},
609 		{"priv", R_ANAL_OP_FAMILY_PRIV},
610 		{"virt", R_ANAL_OP_FAMILY_VIRT},
611 		{"crpt", R_ANAL_OP_FAMILY_CRYPTO},
612 		{"io", R_ANAL_OP_FAMILY_IO},
613 		{"sec", R_ANAL_OP_FAMILY_SECURITY},
614 		{"thread", R_ANAL_OP_FAMILY_THREAD},
615 	};
616 
617 	int i;
618 	for (i = 0; i < sizeof (of) / sizeof (of[0]); i ++) {
619 		if (!strcmp (f, of[i].name)) {
620 			return of[i].id;
621 		}
622 	}
623 	return R_ANAL_OP_FAMILY_UNKNOWN;
624 }
625 
626 /* apply hint to op, return the number of hints applied */
r_anal_op_hint(RAnalOp * op,RAnalHint * hint)627 R_API int r_anal_op_hint(RAnalOp *op, RAnalHint *hint) {
628 	int changes = 0;
629 	if (hint) {
630 		if (hint->val != UT64_MAX) {
631 			op->val = hint->val;
632 			changes++;
633 		}
634 		if (hint->type > 0) {
635 			op->type = hint->type;
636 			changes++;
637 		}
638 		if (hint->jump != UT64_MAX) {
639 			op->jump = hint->jump;
640 			changes++;
641 		}
642 		if (hint->fail != UT64_MAX) {
643 			op->fail = hint->fail;
644 			changes++;
645 		}
646 		if (hint->opcode) {
647 			/* XXX: this is not correct */
648 			free (op->mnemonic);
649 			op->mnemonic = strdup (hint->opcode);
650 			changes++;
651 		}
652 		if (hint->esil) {
653 			r_strbuf_set (&op->esil, hint->esil);
654 			changes++;
655 		}
656 		if (hint->size) {
657 			op->size = hint->size;
658 			changes++;
659 		}
660 	}
661 	return changes;
662 }
663 
664 // returns the '33' in 'rax + 33'
665 // returns value for the given register name in specific address / range
666 // imho this should not iterate, should be just a helper to get that value
r_anal_op_reg_delta(RAnal * anal,ut64 addr,const char * name)667 R_API int r_anal_op_reg_delta(RAnal *anal, ut64 addr, const char *name) {
668 	ut8 buf[32];
669 	anal->iob.read_at (anal->iob.io, addr, buf, sizeof (buf));
670 	RAnalOp op = { 0 };
671 	if (r_anal_op (anal, &op, addr, buf, sizeof (buf), R_ANAL_OP_MASK_ALL) > 0) {
672 		if (op.dst && op.dst->reg && op.dst->reg->name && (!name || !strcmp (op.dst->reg->name, name))) {
673 			if (op.src[0]) {
674 				return op.src[0]->delta;
675 			}
676 		}
677 	}
678 	return 0;
679 }
680