1 /* radare - LGPL - Copyright 2010-2020 - pancake, oddcoder */
2 
3 #include <r_anal.h>
4 #include <r_util.h>
5 #include <r_cons.h>
6 #include <r_core.h>
7 #include <r_list.h>
8 
9 #define ACCESS_CMP(x, y) ((st64)((ut64)(x) - ((RAnalVarAccess *)y)->offset))
10 
r_anal_var_display(RAnal * anal,RAnalVar * var)11 R_API bool r_anal_var_display(RAnal *anal, RAnalVar *var) {
12 	char *fmt = r_type_format (anal->sdb_types, var->type);
13 	RRegItem *i;
14 	if (!fmt) {
15 		eprintf ("type:%s doesn't exist\n", var->type);
16 		return false;
17 	}
18 	bool usePxr = !strcmp (var->type, "int"); // hacky but useful
19 	switch (var->kind) {
20 	case R_ANAL_VAR_KIND_REG:
21 		i = r_reg_index_get (anal->reg, var->delta);
22 		if (i) {
23 			if (usePxr) {
24 				anal->cb_printf ("pxr $w @r:%s\n", i->name);
25 			} else {
26 				anal->cb_printf ("pf r (%s)\n", i->name);
27 			}
28 		} else {
29 			eprintf ("register not found\n");
30 		}
31 		break;
32 	case R_ANAL_VAR_KIND_BPV: {
33 		const st32 real_delta = var->delta + var->fcn->bp_off;
34 		const ut32 udelta = R_ABS (real_delta);
35 		const char sign = real_delta >= 0 ? '+' : '-';
36 		if (usePxr) {
37 			anal->cb_printf ("pxr $w @%s%c0x%x\n", anal->reg->name[R_REG_NAME_BP], sign, udelta);
38 		} else {
39 			anal->cb_printf ("pf %s @%s%c0x%x\n", fmt, anal->reg->name[R_REG_NAME_BP], sign, udelta);
40 		}
41 	}
42 		break;
43 	case R_ANAL_VAR_KIND_SPV: {
44 		ut32 udelta = R_ABS (var->delta + var->fcn->maxstack);
45 		if (usePxr) {
46 			anal->cb_printf ("pxr $w @%s+0x%x\n", anal->reg->name[R_REG_NAME_SP], udelta);
47 		} else {
48 			anal->cb_printf ("pf %s @ %s+0x%x\n", fmt, anal->reg->name[R_REG_NAME_SP], udelta);
49 		}
50 		break;
51 	}
52 	}
53 	free (fmt);
54 	return true;
55 }
56 
__int_type_from_size(int size)57 static const char *__int_type_from_size(int size) {
58 	switch (size) {
59 	case 1: return "int8_t";
60 	case 2: return "int16_t";
61 	case 4: return "int32_t";
62 	case 8: return "int64_t";
63 	default: return NULL;
64 	}
65 }
66 
r_anal_function_rebase_vars(RAnal * a,RAnalFunction * fcn)67 R_API bool r_anal_function_rebase_vars(RAnal *a, RAnalFunction *fcn) {
68 	r_return_val_if_fail (a && fcn, false);
69 	RListIter *it;
70 	RAnalVar *var;
71 	RList *var_list = r_anal_var_all_list (a, fcn);
72 	r_return_val_if_fail (var_list, false);
73 
74 	r_list_foreach (var_list, it, var) {
75 		// Resync delta in case the registers list changed
76 		if (var->isarg && var->kind == 'r') {
77 			RRegItem *reg = r_reg_get (a->reg, var->regname, -1);
78 			if (reg) {
79 				if (var->delta != reg->index) {
80 					var->delta = reg->index;
81 				}
82 			}
83 		}
84 	}
85 
86 	r_list_free (var_list);
87 	return true;
88 }
89 
90 // If the type of var is a struct,
91 // remove all other vars that are overlapped by var and are at the offset of one of its struct members
shadow_var_struct_members(RAnalVar * var)92 static void shadow_var_struct_members(RAnalVar *var) {
93 	Sdb *TDB = var->fcn->anal->sdb_types;
94 	const char *type_kind = sdb_const_get (TDB, var->type, 0);
95 	if (type_kind && r_str_startswith (type_kind, "struct")) {
96 		char *field;
97 		int field_n;
98 		char *type_key = r_str_newf ("%s.%s", type_kind, var->type);
99 		for (field_n = 0; (field = sdb_array_get (TDB, type_key, field_n, NULL)); field_n++) {
100 			char field_key[0x300];
101 			if (snprintf (field_key, sizeof (field_key), "%s.%s", type_key, field) < 0) {
102 				continue;
103 			}
104 			char *field_type = sdb_array_get (TDB, field_key, 0, NULL);
105 			ut64 field_offset = sdb_array_get_num (TDB, field_key, 1, NULL);
106 			if (field_offset != 0) { // delete variables which are overlaid by structure
107 				RAnalVar *other = r_anal_function_get_var (var->fcn, var->kind, var->delta + field_offset);
108 				if (other && other != var) {
109 					r_anal_var_delete (other);
110 				}
111 			}
112 			free (field_type);
113 			free (field);
114 		}
115 		free (type_key);
116 	}
117 }
118 
r_anal_function_set_var(RAnalFunction * fcn,int delta,char kind,R_NULLABLE const char * type,int size,bool isarg,R_NONNULL const char * name)119 R_API RAnalVar *r_anal_function_set_var(RAnalFunction *fcn, int delta, char kind, R_NULLABLE const char *type, int size, bool isarg, R_NONNULL const char *name) {
120 	r_return_val_if_fail (fcn && name, NULL);
121 	RAnalVar *existing = r_anal_function_get_var_byname (fcn, name);
122 	if (existing && (existing->kind != kind || existing->delta != delta)) {
123 		// var name already exists at a different kind+delta
124 		return NULL;
125 	}
126 	RRegItem *reg = NULL;
127 	if (!kind) {
128 		kind = R_ANAL_VAR_KIND_BPV;
129 	}
130 	if (!type) {
131 		type = __int_type_from_size (size);
132 		if (!type) {
133 			type = __int_type_from_size (fcn->anal->bits);
134 		}
135 		if (!type) {
136 			type = "int32_t";
137 		}
138 	}
139 	switch (kind) {
140 	case R_ANAL_VAR_KIND_BPV: // base pointer var/args
141 	case R_ANAL_VAR_KIND_SPV: // stack pointer var/args
142 	case R_ANAL_VAR_KIND_REG: // registers args
143 		break;
144 	default:
145 		eprintf ("Invalid var kind '%c'\n", kind);
146 		return NULL;
147 	}
148 	if (kind == R_ANAL_VAR_KIND_REG) {
149 		reg = r_reg_index_get (fcn->anal->reg, R_ABS (delta));
150 		if (!reg) {
151 			eprintf ("Register wasn't found at the given delta\n");
152 			return NULL;
153 		}
154 	}
155 	RAnalVar *var = r_anal_function_get_var (fcn, kind, delta);
156 	if (!var) {
157 		var = R_NEW0 (RAnalVar);
158 		if (!var) {
159 			return NULL;
160 		}
161 		r_pvector_push (&fcn->vars, var);
162 		var->fcn = fcn;
163 		r_vector_init (&var->accesses, sizeof (RAnalVarAccess), NULL, NULL);
164 		r_vector_init (&var->constraints, sizeof (RAnalVarConstraint), NULL, NULL);
165 	} else {
166 		free (var->name);
167 		free (var->regname);
168 		free (var->type);
169 	}
170 	var->name = strdup (name);
171 	var->regname = reg ? strdup (reg->name) : NULL; // TODO: no strdup here? pool? or not keep regname at all?
172 	var->type = strdup (type);
173 	var->kind = kind;
174 	var->isarg = isarg;
175 	var->delta = delta;
176 	shadow_var_struct_members (var);
177 	return var;
178 }
179 
r_anal_var_set_type(RAnalVar * var,const char * type)180 R_API void r_anal_var_set_type(RAnalVar *var, const char *type) {
181 	char *nt = strdup (type);
182 	if (!nt) {
183 		return;
184 	}
185 	free (var->type);
186 	var->type = nt;
187 	shadow_var_struct_members (var);
188 }
189 
var_free(RAnalVar * var)190 static void var_free(RAnalVar *var) {
191 	if (!var) {
192 		return;
193 	}
194 	r_anal_var_clear_accesses (var);
195 	r_vector_fini (&var->constraints);
196 	free (var->name);
197 	free (var->regname);
198 	free (var->type);
199 	free (var->comment);
200 	free (var);
201 }
202 
r_anal_var_delete(RAnalVar * var)203 R_API void r_anal_var_delete(RAnalVar *var) {
204 	r_return_if_fail (var);
205 	RAnalFunction *fcn = var->fcn;
206 	size_t i;
207 	for (i = 0; i < r_pvector_len (&fcn->vars); i++) {
208 		RAnalVar *v = r_pvector_at (&fcn->vars, i);
209 		if (v == var) {
210 			r_pvector_remove_at (&fcn->vars, i);
211 			var_free (v);
212 			return;
213 		}
214 	}
215 }
216 
r_anal_function_delete_vars_by_kind(RAnalFunction * fcn,RAnalVarKind kind)217 R_API void r_anal_function_delete_vars_by_kind(RAnalFunction *fcn, RAnalVarKind kind) {
218 	r_return_if_fail (fcn);
219 	size_t i;
220 	for (i = 0; i < r_pvector_len (&fcn->vars);) {
221 		RAnalVar *var = r_pvector_at (&fcn->vars, i);
222 		if (var->kind == kind) {
223 			r_pvector_remove_at (&fcn->vars, i);
224 			var_free (var);
225 			continue;
226 		}
227 		i++;
228 	}
229 }
230 
r_anal_function_delete_all_vars(RAnalFunction * fcn)231 R_API void r_anal_function_delete_all_vars(RAnalFunction *fcn) {
232 	void **it;
233 	r_pvector_foreach (&fcn->vars, it) {
234 		var_free (*it);
235 	}
236 	r_pvector_clear (&fcn->vars);
237 }
238 
r_anal_function_delete_unused_vars(RAnalFunction * fcn)239 R_API void r_anal_function_delete_unused_vars(RAnalFunction *fcn) {
240 	void **v;
241 	RPVector *vars_clone = (RPVector *)r_vector_clone ((RVector *)&fcn->vars);
242 	r_pvector_foreach (vars_clone, v) {
243 		RAnalVar *var = *v;
244 		if (r_vector_empty (&var->accesses)) {
245 			r_anal_function_delete_var (fcn, var);
246 		}
247 	}
248 	r_pvector_free (vars_clone);
249 }
250 
r_anal_function_delete_var(RAnalFunction * fcn,RAnalVar * var)251 R_API void r_anal_function_delete_var(RAnalFunction *fcn, RAnalVar *var) {
252 	r_return_if_fail (fcn && var);
253 	r_pvector_remove_data (&fcn->vars, var);
254 	var_free (var);
255 }
256 
r_anal_function_get_var_byname(RAnalFunction * fcn,const char * name)257 R_API R_BORROW RAnalVar *r_anal_function_get_var_byname(RAnalFunction *fcn, const char *name) {
258 	r_return_val_if_fail (fcn && name, NULL);
259 	void **it;
260 	r_pvector_foreach (&fcn->vars, it) {
261 		RAnalVar *var = *it;
262 		if (!strcmp (var->name, name)) {
263 			return var;
264 		}
265 	}
266 	return NULL;
267 }
268 
r_anal_function_get_var(RAnalFunction * fcn,char kind,int delta)269 R_API RAnalVar *r_anal_function_get_var(RAnalFunction *fcn, char kind, int delta) {
270 	void **it;
271 	r_pvector_foreach (&fcn->vars, it) {
272 		RAnalVar *var = *it;
273 		if (var->kind == kind && var->delta == delta) {
274 			return var;
275 		}
276 	}
277 	return NULL;
278 }
279 
r_anal_var_addr(RAnalVar * var)280 R_API ut64 r_anal_var_addr(RAnalVar *var) {
281 	r_return_val_if_fail (var, UT64_MAX);
282 	RAnal *anal = var->fcn->anal;
283 	const char *regname = NULL;
284 	if (var->kind == R_ANAL_VAR_KIND_BPV) {
285 		regname = r_reg_get_name (anal->reg, R_REG_NAME_BP);
286 		return r_reg_getv (anal->reg, regname) + var->delta + var->fcn->bp_off;
287 	} else if (var->kind == R_ANAL_VAR_KIND_SPV) {
288 		regname = r_reg_get_name (anal->reg, R_REG_NAME_SP);
289 		return r_reg_getv (anal->reg, regname) + var->delta;
290 	}
291 	return 0;
292 }
293 
r_anal_function_get_var_stackptr_at(RAnalFunction * fcn,st64 delta,ut64 addr)294 R_API st64 r_anal_function_get_var_stackptr_at(RAnalFunction *fcn, st64 delta, ut64 addr) {
295 	st64 offset = addr - fcn->addr;
296 	RPVector *inst_accesses = ht_up_find (fcn->inst_vars, offset, NULL);
297 	if (!inst_accesses) {
298 		return ST64_MAX;
299 	}
300 	RAnalVar *var = NULL;
301 	void **it;
302 	r_pvector_foreach (inst_accesses, it) {
303 		RAnalVar *v = *it;
304 		if (v->delta == delta) {
305 			var = v;
306 			break;
307 		}
308 	}
309 	if (!var) {
310 		return ST64_MAX;
311 	}
312 	size_t index;
313 	r_vector_lower_bound (&var->accesses, offset, index, ACCESS_CMP);
314 	RAnalVarAccess *acc = NULL;
315 	if (index < var->accesses.len) {
316 		acc = r_vector_index_ptr (&var->accesses, index);
317 	}
318 	if (!acc || acc->offset != offset) {
319 		return ST64_MAX;
320 	}
321 	return acc->stackptr;
322 }
323 
r_anal_function_get_var_reg_at(RAnalFunction * fcn,st64 delta,ut64 addr)324 R_API const char *r_anal_function_get_var_reg_at(RAnalFunction *fcn, st64 delta, ut64 addr) {
325 	st64 offset = addr - fcn->addr;
326 	RPVector *inst_accesses = ht_up_find (fcn->inst_vars, offset, NULL);
327 	if (!inst_accesses) {
328 		return NULL;
329 	}
330 	RAnalVar *var = NULL;
331 	void **it;
332 	r_pvector_foreach (inst_accesses, it) {
333 		RAnalVar *v = *it;
334 		if (v->delta == delta) {
335 			var = v;
336 			break;
337 		}
338 	}
339 	if (!var) {
340 		return NULL;
341 	}
342 	size_t index;
343 	r_vector_lower_bound (&var->accesses, offset, index, ACCESS_CMP);
344 	RAnalVarAccess *acc = NULL;
345 	if (index < var->accesses.len) {
346 		acc = r_vector_index_ptr (&var->accesses, index);
347 	}
348 	if (!acc || acc->offset != offset) {
349 		return NULL;
350 	}
351 	return acc->reg;
352 }
353 
r_anal_var_check_name(const char * name)354 R_API bool r_anal_var_check_name(const char *name) {
355 	return !isdigit ((unsigned char)*name) && strcspn (name, "., =/");
356 }
357 
r_anal_var_rename(RAnalVar * var,const char * new_name,bool verbose)358 R_API bool r_anal_var_rename(RAnalVar *var, const char *new_name, bool verbose) {
359 	r_return_val_if_fail (var, false);
360 	if (!r_anal_var_check_name (new_name)) {
361 		return false;
362 	}
363 	RAnalVar *v1 = r_anal_function_get_var_byname (var->fcn, new_name);
364 	if (v1) {
365 		if (verbose) {
366 			eprintf ("variable or arg with name `%s` already exist\n", new_name);
367 		}
368 		return false;
369 	}
370 	char *nn = strdup (new_name);
371 	if (!nn) {
372 		return false;
373 	}
374 	free (var->name);
375 	var->name = nn;
376 	return true;
377 }
378 
r_anal_var_get_argnum(RAnalVar * var)379 R_API int r_anal_var_get_argnum(RAnalVar *var) {
380 	r_return_val_if_fail (var, -1);
381 	RAnal *anal = var->fcn->anal;
382 	if (!var->isarg || var->kind != R_ANAL_VAR_KIND_REG) { // TODO: support bp and sp too
383 		return -1;
384 	}
385 	if (!var->regname) {
386 		return -1;
387 	}
388 	RRegItem *reg = r_reg_get (anal->reg, var->regname, -1);
389 	if (!reg) {
390 		return -1;
391 	}
392 	int i;
393 	int arg_max = var->fcn->cc ? r_anal_cc_max_arg (anal, var->fcn->cc) : 0;
394 	for (i = 0; i < arg_max; i++) {
395 		const char *reg_arg = r_anal_cc_arg (anal, var->fcn->cc, i);
396 		if (reg_arg && !strcmp (reg->name, reg_arg)) {
397 			return i;
398 		}
399 	}
400 	return -1;
401 }
402 
r_anal_function_get_vars_used_at(RAnalFunction * fcn,ut64 op_addr)403 R_API R_BORROW RPVector *r_anal_function_get_vars_used_at(RAnalFunction *fcn, ut64 op_addr) {
404 	r_return_val_if_fail (fcn, NULL);
405 	return ht_up_find (fcn->inst_vars, op_addr - fcn->addr, NULL);
406 }
407 
r_anal_get_used_function_var(RAnal * anal,ut64 addr)408 R_API R_DEPRECATE RAnalVar *r_anal_get_used_function_var(RAnal *anal, ut64 addr) {
409 	RList *fcns = r_anal_get_functions_in (anal, addr);
410 	if (!fcns) {
411 		return NULL;
412 	}
413 	RAnalVar *var = NULL;
414 	RListIter *it;
415 	RAnalFunction *fcn;
416 	r_list_foreach (fcns, it, fcn) {
417 		RPVector *used_vars = r_anal_function_get_vars_used_at (fcn, addr);
418 		if (used_vars && !r_pvector_empty (used_vars)) {
419 			var = r_pvector_at (used_vars, 0);
420 			break;
421 		}
422 	}
423 	r_list_free (fcns);
424 	return var;
425 }
426 
r_anal_var_get_dst_var(RAnalVar * var)427 R_API RAnalVar *r_anal_var_get_dst_var(RAnalVar *var) {
428 	r_return_val_if_fail (var, NULL);
429 	RAnalVarAccess *acc;
430 	r_vector_foreach (&var->accesses, acc) {
431 		if (!(acc->type & R_ANAL_VAR_ACCESS_TYPE_READ)) {
432 			continue;
433 		}
434 		ut64 addr = var->fcn->addr + acc->offset;
435 		RPVector *used_vars = r_anal_function_get_vars_used_at (var->fcn, addr);
436 		void **it;
437 		r_pvector_foreach (used_vars, it) {
438 			RAnalVar *used_var = *it;
439 			if (used_var == var) {
440 				continue;
441 			}
442 			RAnalVarAccess *other_acc = r_anal_var_get_access_at (used_var, addr);
443 			if (other_acc && other_acc->type & R_ANAL_VAR_ACCESS_TYPE_WRITE) {
444 				return used_var;
445 			}
446 		}
447 	}
448 	return NULL;
449 }
450 
r_anal_var_set_access(RAnalVar * var,const char * reg,ut64 access_addr,int access_type,st64 stackptr)451 R_API void r_anal_var_set_access(RAnalVar *var, const char *reg, ut64 access_addr, int access_type, st64 stackptr) {
452 	r_return_if_fail (var);
453 	st64 offset = access_addr - var->fcn->addr;
454 
455 	// accesses are stored ordered by offset, use binary search to get the matching existing or the index to insert a new one
456 	size_t index;
457 	r_vector_lower_bound (&var->accesses, offset, index, ACCESS_CMP);
458 	RAnalVarAccess *acc = NULL;
459 	if (index < var->accesses.len) {
460 		acc = r_vector_index_ptr (&var->accesses, index);
461 	}
462 	if (!acc || acc->offset != offset) {
463 		acc = r_vector_insert (&var->accesses, index, NULL);
464 		acc->offset = offset;
465 		acc->type = 0;
466 	}
467 
468 	acc->type |= (ut8)access_type;
469 	acc->stackptr = stackptr;
470 	acc->reg = r_str_constpool_get (&var->fcn->anal->constpool, reg);
471 
472 	// add the inverse reference from the instruction to the var
473 	RPVector *inst_accesses = ht_up_find (var->fcn->inst_vars, (ut64)offset, NULL);
474 	if (!inst_accesses) {
475 		inst_accesses = r_pvector_new (NULL);
476 		if (!inst_accesses) {
477 			return;
478 		}
479 		ht_up_insert (var->fcn->inst_vars, (ut64)offset, inst_accesses);
480 	}
481 	if (!r_pvector_contains (inst_accesses, var)) {
482 		r_pvector_push (inst_accesses, var);
483 	}
484 }
485 
r_anal_var_remove_access_at(RAnalVar * var,ut64 address)486 R_API void r_anal_var_remove_access_at(RAnalVar *var, ut64 address) {
487 	r_return_if_fail (var);
488 	st64 offset = address - var->fcn->addr;
489 	size_t index;
490 	r_vector_lower_bound (&var->accesses, offset, index, ACCESS_CMP);
491 	if (index >= var->accesses.len) {
492 		return;
493 	}
494 	RAnalVarAccess *acc = r_vector_index_ptr (&var->accesses, index);
495 	if (acc->offset == offset) {
496 		r_vector_remove_at (&var->accesses, index, NULL);
497 		RPVector *inst_accesses = ht_up_find (var->fcn->inst_vars, (ut64)offset, NULL);
498 		r_pvector_remove_data (inst_accesses, var);
499 	}
500 }
501 
r_anal_var_clear_accesses(RAnalVar * var)502 R_API void r_anal_var_clear_accesses(RAnalVar *var) {
503 	r_return_if_fail (var);
504 	RAnalFunction *fcn = var->fcn;
505 	if (fcn->inst_vars) {
506 		// remove all inverse references to the var's accesses
507 		RAnalVarAccess *acc;
508 		r_vector_foreach (&var->accesses, acc) {
509 			RPVector *inst_accesses = ht_up_find (fcn->inst_vars, (ut64)acc->offset, NULL);
510 			if (!inst_accesses) {
511 				continue;
512 			}
513 			r_pvector_remove_data (inst_accesses, var);
514 		}
515 	}
516 	r_vector_clear (&var->accesses);
517 }
518 
r_anal_var_get_access_at(RAnalVar * var,ut64 addr)519 R_API RAnalVarAccess *r_anal_var_get_access_at(RAnalVar *var, ut64 addr) {
520 	r_return_val_if_fail (var, NULL);
521 	st64 offset = addr - var->fcn->addr;
522 	size_t index;
523 	r_vector_lower_bound (&var->accesses, offset, index, ACCESS_CMP);
524 	if (index >= var->accesses.len) {
525 		return NULL;
526 	}
527 	RAnalVarAccess *acc = r_vector_index_ptr (&var->accesses, index);
528 	if (acc->offset == offset) {
529 		return acc;
530 	}
531 	return NULL;
532 }
533 
r_anal_var_add_constraint(RAnalVar * var,R_BORROW RAnalVarConstraint * constraint)534 R_API void r_anal_var_add_constraint(RAnalVar *var, R_BORROW RAnalVarConstraint *constraint) {
535 	r_vector_push (&var->constraints, constraint);
536 }
537 
r_anal_var_get_constraints_readable(RAnalVar * var)538 R_API char *r_anal_var_get_constraints_readable(RAnalVar *var) {
539 	size_t n = var->constraints.len;
540 	if (!n) {
541 		return NULL;
542 	}
543 	bool low = false, high = false;
544 	RStrBuf sb;
545 	r_strbuf_init (&sb);
546 	size_t i;
547 	for (i = 0; i < n; i += 1) {
548 		RAnalVarConstraint *constr = r_vector_index_ptr (&var->constraints, i);
549 		switch (constr->cond) {
550 		case R_ANAL_COND_LE:
551 			if (high) {
552 				r_strbuf_append (&sb, " && ");
553 			}
554 			r_strbuf_appendf (&sb, "<= 0x%"PFMT64x "", constr->val);
555 			low = true;
556 			break;
557 		case R_ANAL_COND_LT:
558 			if (high) {
559 				r_strbuf_append (&sb, " && ");
560 			}
561 			r_strbuf_appendf (&sb, "< 0x%"PFMT64x "", constr->val);
562 			low = true;
563 			break;
564 		case R_ANAL_COND_GE:
565 			r_strbuf_appendf (&sb, ">= 0x%"PFMT64x "", constr->val);
566 			high = true;
567 			break;
568 		case R_ANAL_COND_GT:
569 			r_strbuf_appendf (&sb, "> 0x%"PFMT64x "", constr->val);
570 			high = true;
571 			break;
572 		default:
573 			break;
574 		}
575 		if (low && high && i != n - 1) {
576 			r_strbuf_append (&sb, " || ");
577 			low = false;
578 			high = false;
579 		}
580 	}
581 	return r_strbuf_drain_nofree (&sb);
582 }
583 
r_anal_var_count(RAnal * a,RAnalFunction * fcn,int kind,int type)584 R_API int r_anal_var_count(RAnal *a, RAnalFunction *fcn, int kind, int type) {
585 	// type { local: 0, arg: 1 };
586 	RList *list = r_anal_var_list (a, fcn, kind);
587 	RAnalVar *var;
588 	RListIter *iter;
589 	int count[2] = {
590 		0
591 	};
592 	r_list_foreach (list, iter, var) {
593 		if (kind == R_ANAL_VAR_KIND_REG) {
594 			count[1]++;
595 			continue;
596 		}
597 		count[var->isarg]++;
598 	}
599 	r_list_free (list);
600 	return count[type];
601 }
602 
var_add_structure_fields_to_list(RAnal * a,RAnalVar * av,RList * list)603 static bool var_add_structure_fields_to_list(RAnal *a, RAnalVar *av, RList *list) {
604 	Sdb *TDB = a->sdb_types;
605 	const char *type_kind = sdb_const_get (TDB, av->type, 0);
606 	if (type_kind && !strcmp (type_kind, "struct")) {
607 		char *field_name, *new_name;
608 		int field_n;
609 		char *type_key = r_str_newf ("%s.%s", type_kind, av->type);
610 		for (field_n = 0; (field_name = sdb_array_get (TDB, type_key, field_n, NULL)); field_n++) {
611 			char *field_key = r_str_newf ("%s.%s", type_key, field_name);
612 			char *field_type = sdb_array_get (TDB, field_key, 0, NULL);
613 			ut64 field_offset = sdb_array_get_num (TDB, field_key, 1, NULL);
614 			new_name = r_str_newf ("%s.%s", av->name, field_name);
615 			RAnalVarField *field = R_NEW0 (RAnalVarField);
616 			field->name = new_name;
617 			field->delta = av->delta + field_offset;
618 			field->field = true;
619 			r_list_append (list, field);
620 			free (field_type);
621 			free (field_key);
622 			free (field_name);
623 		}
624 		free (type_key);
625 		return true;
626 	}
627 	return false;
628 }
629 
get_regname(RAnal * anal,RAnalValue * value)630 static const char *get_regname(RAnal *anal, RAnalValue *value) {
631 	const char *name = NULL;
632 	if (value && value->reg && value->reg->name) {
633 		name = value->reg->name;
634 		RRegItem *ri = r_reg_get (anal->reg, value->reg->name, -1);
635 		if (ri && (ri->size == 32) && (anal->bits == 64)) {
636 			name = r_reg_32_to_64 (anal->reg, value->reg->name);
637 		}
638 	}
639 	return name;
640 }
641 
r_anal_function_autoname_var(RAnalFunction * fcn,char kind,const char * pfx,int ptr)642 R_API R_OWN char *r_anal_function_autoname_var(RAnalFunction *fcn, char kind, const char *pfx, int ptr) {
643 	void **it;
644 	const ut32 uptr = R_ABS (ptr);
645 	char *varname = r_str_newf ("%s_%xh", pfx, uptr);
646 	r_pvector_foreach (&fcn->vars, it) {
647 		RAnalVar *var = *it;
648 		if (!strcmp (varname, var->name)) {
649 			if (var->kind != kind) {
650 				const char *k = kind == R_ANAL_VAR_KIND_SPV ? "sp" : "bp";
651 				free (varname);
652 				varname = r_str_newf ("%s_%s_%xh", pfx, k, uptr);
653 				return varname;
654 			}
655 			int i = 2;
656 			do {
657 				free (varname);
658 				varname = r_str_newf ("%s_%xh_%u", pfx, uptr, i++);
659 			} while (r_anal_function_get_var_byname (fcn, varname));
660 			return varname;
661 		}
662 	}
663 	return varname;
664 }
665 
get_stack_var(RAnalFunction * fcn,int delta)666 static RAnalVar *get_stack_var(RAnalFunction *fcn, int delta) {
667 	void **it;
668 	r_pvector_foreach (&fcn->vars, it) {
669 		RAnalVar *var = *it;
670 		bool is_stack = var->kind == R_ANAL_VAR_KIND_SPV || var->kind == R_ANAL_VAR_KIND_BPV;
671 		if (is_stack && var->delta == delta) {
672 			return var;
673 		}
674 	}
675 	return NULL;
676 }
677 
extract_arg(RAnal * anal,RAnalFunction * fcn,RAnalOp * op,const char * reg,const char * sign,char type)678 static void extract_arg(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, const char *reg, const char *sign, char type) {
679 	st64 ptr = 0;
680 	char *addr, *esil_buf = NULL;
681 
682 	r_return_if_fail (anal && fcn && op && reg);
683 
684 	size_t i;
685 	for (i = 0; i < R_ARRAY_SIZE (op->src); i++) {
686 		if (op->src[i] && op->src[i]->reg && op->src[i]->reg->name) {
687 			if (!strcmp (reg, op->src[i]->reg->name)) {
688 				st64 delta = op->src[i]->delta;
689 				if ((delta > 0 && *sign == '+') || (delta < 0 && *sign == '-')) {
690 					ptr = R_ABS (op->src[i]->delta);
691 					break;
692 				}
693 			}
694 		}
695 	}
696 
697 	if (!ptr) {
698 		const char *op_esil = r_strbuf_get (&op->esil);
699 		if (!op_esil) {
700 			return;
701 		}
702 		esil_buf = strdup (op_esil);
703 		if (!esil_buf) {
704 			return;
705 		}
706 		char *ptr_end = strstr (esil_buf, sdb_fmt (",%s,%s,", reg, sign));
707 		if (!ptr_end) {
708 			free (esil_buf);
709 			return;
710 		}
711 		*ptr_end = 0;
712 		addr = ptr_end;
713 		while ((addr[0] != '0' || addr[1] != 'x') && addr >= esil_buf + 1 && *addr != ',') {
714 			addr--;
715 		}
716 		if (strncmp (addr, "0x", 2)) {
717 			//XXX: This is a workaround for inconsistent esil
718 			if (!op->stackop && op->dst) {
719 				const char *sp = r_reg_get_name (anal->reg, R_REG_NAME_SP);
720 				const char *bp = r_reg_get_name (anal->reg, R_REG_NAME_BP);
721 				const char *rn = op->dst->reg ? op->dst->reg->name : NULL;
722 				if (rn && ((bp && !strcmp (bp, rn)) || (sp && !strcmp (sp, rn)))) {
723 					if (anal->verbose) {
724 						eprintf ("Warning: Analysis didn't fill op->stackop for instruction that alters stack at 0x%" PFMT64x ".\n", op->addr);
725 					}
726 					goto beach;
727 				}
728 			}
729 			if (*addr == ',') {
730 				addr++;
731 			}
732 			if (!op->stackop && op->type != R_ANAL_OP_TYPE_PUSH && op->type != R_ANAL_OP_TYPE_POP
733 				&& op->type != R_ANAL_OP_TYPE_RET && r_str_isnumber (addr)) {
734 				ptr = (st64)r_num_get (NULL, addr);
735 				if (ptr && op->src[0] && ptr == op->src[0]->imm) {
736 					goto beach;
737 				}
738 			} else if ((op->stackop == R_ANAL_STACK_SET) || (op->stackop == R_ANAL_STACK_GET)) {
739 				if (op->ptr % 4) {
740 					goto beach;
741 				}
742 				ptr = R_ABS (op->ptr);
743 			} else {
744 				goto beach;
745 			}
746 		} else {
747 			ptr = (st64)r_num_get (NULL, addr);
748 		}
749 	}
750 
751 	if (anal->verbose && (!op->src[0] || !op->dst)) {
752 		eprintf ("Warning: Analysis didn't fill op->src/dst at 0x%" PFMT64x ".\n", op->addr);
753 	}
754 
755 	int rw = (op->direction == R_ANAL_OP_DIR_WRITE) ? R_ANAL_VAR_ACCESS_TYPE_WRITE : R_ANAL_VAR_ACCESS_TYPE_READ;
756 	if (*sign == '+') {
757 		const bool isarg = type == R_ANAL_VAR_KIND_SPV ? ptr >= fcn->stack : ptr >= fcn->bp_off;
758 		const char *pfx = isarg ? ARGPREFIX : VARPREFIX;
759 		st64 frame_off;
760 		if (type == R_ANAL_VAR_KIND_SPV) {
761 			frame_off = ptr - fcn->stack;
762 		} else {
763 			frame_off = ptr - fcn->bp_off;
764 		}
765 		RAnalVar *var = get_stack_var (fcn, frame_off);
766 		if (var) {
767 			r_anal_var_set_access (var, reg, op->addr, rw, ptr);
768 			goto beach;
769 		}
770 		char *varname = NULL, *vartype = NULL;
771 		if (isarg) {
772 			const char *place = fcn->cc ? r_anal_cc_arg (anal, fcn->cc, ST32_MAX) : NULL;
773 			bool stack_rev = place ? !strcmp (place, "stack_rev") : false;
774 			char *fname = r_type_func_guess (anal->sdb_types, fcn->name);
775 			if (fname) {
776 				ut64 sum_sz = 0;
777 				size_t from, to, i;
778 				if (stack_rev) {
779 					const size_t cnt = r_type_func_args_count (anal->sdb_types, fname);
780 					from = cnt ? cnt - 1 : cnt;
781 					to = fcn->cc ? r_anal_cc_max_arg (anal, fcn->cc) : 0;
782 				} else {
783 					from = fcn->cc ? r_anal_cc_max_arg (anal, fcn->cc) : 0;
784 					to = r_type_func_args_count (anal->sdb_types, fname);
785 				}
786 				const int bytes = (fcn->bits ? fcn->bits : anal->bits) / 8;
787 				for (i = from; stack_rev ? i >= to : i < to; stack_rev ? i-- : i++) {
788 					char *tp = r_type_func_args_type (anal->sdb_types, fname, i);
789 					if (!tp) {
790 						break;
791 					}
792 					if (sum_sz == frame_off) {
793 						vartype = tp;
794 						varname = strdup (r_type_func_args_name (anal->sdb_types, fname, i));
795 						break;
796 					}
797 					ut64 bit_sz = r_type_get_bitsize (anal->sdb_types, tp);
798 					sum_sz += bit_sz ? bit_sz / 8 : bytes;
799 					sum_sz = R_ROUND (sum_sz, bytes);
800 					free (tp);
801 				}
802 				free (fname);
803 			}
804 		}
805 		if (!varname) {
806 			if (anal->opt.varname_stack) {
807 				varname = r_str_newf ("%s_%" PFMT64x "h", pfx, R_ABS (frame_off));
808 			} else {
809 				varname = r_anal_function_autoname_var (fcn, type, pfx, ptr);
810 			}
811 		}
812 		if (varname) {
813 			RAnalVar *var = r_anal_function_set_var (fcn, frame_off, type, vartype, anal->bits / 8, isarg, varname);
814 			if (var) {
815 				r_anal_var_set_access (var, reg, op->addr, rw, ptr);
816 			}
817 			free (varname);
818 		}
819 		free (vartype);
820 	} else {
821 		st64 frame_off = -(ptr + fcn->bp_off);
822 		RAnalVar *var = get_stack_var (fcn, frame_off);
823 		if (var) {
824 			r_anal_var_set_access (var, reg, op->addr, rw, -ptr);
825 			goto beach;
826 		}
827 		char *varname = anal->opt.varname_stack
828 			? r_str_newf ("%s_%" PFMT64x "h", VARPREFIX, R_ABS (frame_off))
829 			: r_anal_function_autoname_var (fcn, type, VARPREFIX, -ptr);
830 		if (varname) {
831 			RAnalVar *var = r_anal_function_set_var (fcn, frame_off, type, NULL, anal->bits / 8, false, varname);
832 			if (var) {
833 				r_anal_var_set_access (var, reg, op->addr, rw, -ptr);
834 			}
835 			free (varname);
836 		}
837 	}
838 beach:
839 	free (esil_buf);
840 }
841 
842 static bool is_reg_in_src(const char *regname, RAnal *anal, RAnalOp *op);
843 
op_affect_dst(RAnalOp * op)844 static inline bool op_affect_dst(RAnalOp* op) {
845 	switch (op->type) {
846 	case R_ANAL_OP_TYPE_ADD:
847 	case R_ANAL_OP_TYPE_SUB:
848 	case R_ANAL_OP_TYPE_MUL:
849 	case R_ANAL_OP_TYPE_DIV:
850 	case R_ANAL_OP_TYPE_SHR:
851 	case R_ANAL_OP_TYPE_SHL:
852 	case R_ANAL_OP_TYPE_SAL:
853 	case R_ANAL_OP_TYPE_SAR:
854 	case R_ANAL_OP_TYPE_OR:
855 	case R_ANAL_OP_TYPE_AND:
856 	case R_ANAL_OP_TYPE_XOR:
857 	case R_ANAL_OP_TYPE_NOR:
858 	case R_ANAL_OP_TYPE_NOT:
859 	case R_ANAL_OP_TYPE_ROR:
860 	case R_ANAL_OP_TYPE_ROL:
861 	case R_ANAL_OP_TYPE_CAST:
862 		return true;
863 	default:
864 		return false;
865 	}
866 }
867 
868 #define STR_EQUAL(s1, s2) (s1 && s2 && !strcmp (s1, s2))
869 
arch_destroys_dst(const char * arch)870 static inline bool arch_destroys_dst(const char *arch) {
871 	return (STR_EQUAL (arch, "arm") || STR_EQUAL (arch, "riscv") || STR_EQUAL (arch, "ppc"));
872 }
873 
is_used_like_arg(const char * regname,const char * opsreg,const char * opdreg,RAnalOp * op,RAnal * anal)874 static bool is_used_like_arg(const char *regname, const char *opsreg, const char *opdreg, RAnalOp *op, RAnal *anal) {
875 	RAnalValue *dst = op->dst;
876 	RAnalValue *src = op->src[0];
877 	switch (op->type) {
878 	case R_ANAL_OP_TYPE_POP:
879 		return false;
880 	case R_ANAL_OP_TYPE_MOV:
881 		return (is_reg_in_src (regname, anal, op)) || (STR_EQUAL (opdreg, regname) && dst->memref);
882 	case R_ANAL_OP_TYPE_CMOV:
883 		if (STR_EQUAL (opdreg, regname)) {
884 			return false;
885 		}
886 		if (is_reg_in_src (regname, anal, op)) {
887 			return true;
888 		}
889 		return false;
890 	case R_ANAL_OP_TYPE_LEA:
891 	case R_ANAL_OP_TYPE_LOAD:
892 		if (is_reg_in_src (regname, anal, op)) {
893 			return true;
894 		}
895 		if (STR_EQUAL (opdreg, regname)) {
896 			return false;
897 		}
898     		return false;
899 	case R_ANAL_OP_TYPE_XOR:
900 		if (STR_EQUAL (opsreg, opdreg) && !src->memref && !dst->memref) {
901 			return false;
902 		}
903 		//fallthrough
904 	default:
905 		if (op_affect_dst (op) && arch_destroys_dst (anal->cur->arch)) {
906 			if (is_reg_in_src (regname, anal, op)) {
907 				return true;
908 			}
909 			return false;
910 		}
911 		return ((STR_EQUAL (opdreg, regname)) || (is_reg_in_src (regname, anal, op)));
912 	}
913 }
914 
is_reg_in_src(const char * regname,RAnal * anal,RAnalOp * op)915 static bool is_reg_in_src (const char *regname, RAnal *anal, RAnalOp *op) {
916 	const char* opsreg0 = op->src[0] ? get_regname (anal, op->src[0]) : NULL;
917 	const char* opsreg1 = op->src[1] ? get_regname (anal, op->src[1]) : NULL;
918 	const char* opsreg2 = op->src[2] ? get_regname (anal, op->src[2]) : NULL;
919 	return (STR_EQUAL (regname, opsreg0)) || (STR_EQUAL (regname, opsreg1)) || (STR_EQUAL (regname, opsreg2));
920 }
921 
r_anal_extract_rarg(RAnal * anal,RAnalOp * op,RAnalFunction * fcn,int * reg_set,int * count)922 R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int *reg_set, int *count) {
923 	int i, argc = 0;
924 	r_return_if_fail (anal && op && fcn);
925 	const char *opsreg = op->src[0] ? get_regname (anal, op->src[0]) : NULL;
926 	const char *opdreg = op->dst ? get_regname (anal, op->dst) : NULL;
927 	const int size = (fcn->bits ? fcn->bits : anal->bits) / 8;
928 	if (!fcn->cc) {
929 		R_LOG_DEBUG ("No calling convention for function '%s' to extract register arguments\n", fcn->name);
930 		return;
931 	}
932 	char *fname = r_type_func_guess (anal->sdb_types, fcn->name);
933 	Sdb *TDB = anal->sdb_types;
934 	int max_count = r_anal_cc_max_arg (anal, fcn->cc);
935 	if (!max_count || (*count >= max_count)) {
936 		free (fname);
937 		return;
938 	}
939 	if (fname) {
940 		argc = r_type_func_args_count (TDB, fname);
941 	}
942 
943 	bool is_call = (op->type & 0xf) == R_ANAL_OP_TYPE_CALL || (op->type & 0xf) == R_ANAL_OP_TYPE_UCALL;
944 	if (is_call && *count < max_count) {
945 		RList *callee_rargs_l = NULL;
946 		int callee_rargs = 0;
947 		char *callee = NULL;
948 		ut64 offset = op->jump == UT64_MAX ? op->ptr : op->jump;
949 		RAnalFunction *f = r_anal_get_function_at (anal, offset);
950 		if (!f) {
951 			RCore *core = (RCore *)anal->coreb.core;
952 			RFlagItem *flag = r_flag_get_by_spaces (core->flags, offset, R_FLAGS_FS_IMPORTS, NULL);
953 			if (flag) {
954 				callee = r_type_func_guess (TDB, flag->name);
955 				if (callee) {
956 					const char *cc = r_anal_cc_func (anal, callee);
957 					if (cc && !strcmp (fcn->cc, cc)) {
958 						callee_rargs = R_MIN (max_count, r_type_func_args_count (TDB, callee));
959 					}
960 				}
961 			}
962 		} else if (!f->is_variadic && !strcmp (fcn->cc, f->cc)) {
963 			callee = r_type_func_guess (TDB, f->name);
964 			if (callee) {
965 				callee_rargs = R_MIN (max_count, r_type_func_args_count (TDB, callee));
966 			}
967 			callee_rargs = callee_rargs
968 				? callee_rargs
969 				: r_anal_var_count (anal, f, R_ANAL_VAR_KIND_REG, 1);
970 			callee_rargs_l = r_anal_var_list (anal, f, R_ANAL_VAR_KIND_REG);
971 		}
972 		size_t i;
973 		for (i = 0; i < callee_rargs; i++) {
974 			if (reg_set[i]) {
975 				continue;
976 			}
977 			const char *vname = NULL;
978 			char *type = NULL;
979 			char *name = NULL;
980 			int delta = 0;
981 			const char *regname = r_anal_cc_arg (anal, fcn->cc, i);
982 			RRegItem *ri = r_reg_get (anal->reg, regname, -1);
983 			if (ri) {
984 				delta = ri->index;
985 			}
986 			if (fname) {
987 				type = r_type_func_args_type (TDB, fname, i);
988 				vname = r_type_func_args_name (TDB, fname, i);
989 			}
990 			if (!vname && callee) {
991 				type = r_type_func_args_type (TDB, callee, i);
992 				vname = r_type_func_args_name (TDB, callee, i);
993 			}
994 			if (vname) {
995 				reg_set[i] = 1;
996 			} else {
997 				RListIter *it;
998 				RAnalVar *arg, *found_arg = NULL;
999 				r_list_foreach (callee_rargs_l, it, arg) {
1000 					if (r_anal_var_get_argnum (arg) == i) {
1001 						found_arg = arg;
1002 						break;
1003 					}
1004 				}
1005 				if (found_arg) {
1006 					type = strdup (found_arg->type);
1007 					vname = name = strdup (found_arg->name);
1008 				}
1009 			}
1010 			if (!vname) {
1011 				name = r_str_newf ("arg%u", (int)i + 1);
1012 				vname = name;
1013 			}
1014 			r_anal_function_set_var (fcn, delta, R_ANAL_VAR_KIND_REG, type, size, true, vname);
1015 			(*count)++;
1016 			free (name);
1017 			free (type);
1018 		}
1019 		free (callee);
1020 		r_list_free (callee_rargs_l);
1021 		free (fname);
1022 		return;
1023 	}
1024 
1025 	for (i = 0; i < max_count; i++) {
1026 		const char *regname = r_anal_cc_arg (anal, fcn->cc, i);
1027 		if (regname) {
1028 			int delta = 0;
1029 			RRegItem *ri = NULL;
1030 			RAnalVar *var = NULL;
1031 			bool is_used_like_an_arg = is_used_like_arg (regname, opsreg, opdreg, op, anal);
1032 			if (reg_set[i] != 2 && is_used_like_an_arg) {
1033 				ri = r_reg_get (anal->reg, regname, -1);
1034 				if (ri) {
1035 					delta = ri->index;
1036 				}
1037 			}
1038 			if (reg_set[i] == 1 && is_used_like_an_arg) {
1039 				var = r_anal_function_get_var (fcn, R_ANAL_VAR_KIND_REG, delta);
1040 			} else if (reg_set[i] != 2 && is_used_like_an_arg) {
1041 				const char *vname = NULL;
1042 				char *type = NULL;
1043 				char *name = NULL;
1044 				if ((i < argc) && fname) {
1045 					type = r_type_func_args_type (TDB, fname, i);
1046 					vname = r_type_func_args_name (TDB, fname, i);
1047 				}
1048 				if (!vname) {
1049 					name = r_str_newf ("arg%d", i + 1);
1050 					vname = name;
1051 				}
1052 				var = r_anal_function_set_var (fcn, delta, R_ANAL_VAR_KIND_REG, type, size, true, vname);
1053 				free (name);
1054 				free (type);
1055 				(*count)++;
1056 			} else {
1057 				if (is_reg_in_src (regname, anal, op) || STR_EQUAL (opdreg, regname)) {
1058 					reg_set[i] = 2;
1059 				}
1060 				continue;
1061 			}
1062 			if (is_reg_in_src (regname, anal, op) || STR_EQUAL (regname, opdreg)) {
1063 				reg_set[i] = 1;
1064 			}
1065 			if (var) {
1066 				r_anal_var_set_access (var, var->regname, op->addr, R_ANAL_VAR_ACCESS_TYPE_READ, 0);
1067 				r_meta_set_string (anal, R_META_TYPE_VARTYPE, op->addr, var->name);
1068 			}
1069 		}
1070 	}
1071 
1072 	const char *selfreg = r_anal_cc_self (anal, fcn->cc);
1073 	if (selfreg) {
1074 		bool is_used_like_an_arg = is_used_like_arg (selfreg, opsreg, opdreg, op, anal);
1075 		if (reg_set[i] != 2 && is_used_like_an_arg) {
1076 			int delta = 0;
1077 			char *vname = strdup ("self");
1078 			RRegItem *ri = r_reg_get (anal->reg, selfreg, -1);
1079 			if (ri) {
1080 				delta = ri->index;
1081 			}
1082 			RAnalVar *newvar = r_anal_function_set_var (fcn, delta, R_ANAL_VAR_KIND_REG, 0, size, true, vname);
1083 			if (newvar) {
1084 				r_anal_var_set_access (newvar, newvar->regname, op->addr, R_ANAL_VAR_ACCESS_TYPE_READ, 0);
1085 			}
1086 			r_meta_set_string (anal, R_META_TYPE_VARTYPE, op->addr, vname);
1087 			free (vname);
1088 			(*count)++;
1089 		} else {
1090 			if (is_reg_in_src (selfreg, anal, op) || STR_EQUAL (opdreg, selfreg)) {
1091 				reg_set[i] = 2;
1092 			}
1093 		}
1094 		i++;
1095 	}
1096 
1097 	const char *errorreg = r_anal_cc_error (anal, fcn->cc);
1098 	if (errorreg) {
1099 		if (reg_set[i] == 0 && STR_EQUAL (opdreg, errorreg)) {
1100 			int delta = 0;
1101 			char *vname = strdup ("error");
1102 			RRegItem *ri = r_reg_get (anal->reg, errorreg, -1);
1103 			if (ri) {
1104 				delta = ri->index;
1105 			}
1106 			RAnalVar *newvar = r_anal_function_set_var (fcn, delta, R_ANAL_VAR_KIND_REG, 0, size, true, vname);
1107 			if (newvar) {
1108 				r_anal_var_set_access (newvar, newvar->regname, op->addr, R_ANAL_VAR_ACCESS_TYPE_READ, 0);
1109 			}
1110 			r_meta_set_string (anal, R_META_TYPE_VARTYPE, op->addr, vname);
1111 			free (vname);
1112 			(*count)++;
1113 			reg_set[i] = 2;
1114 		}
1115 	}
1116 	free (fname);
1117 }
1118 
r_anal_extract_vars(RAnal * anal,RAnalFunction * fcn,RAnalOp * op)1119 R_API void r_anal_extract_vars(RAnal *anal, RAnalFunction *fcn, RAnalOp *op) {
1120 	r_return_if_fail (anal && fcn && op);
1121 
1122 	const char *BP = anal->reg->name[R_REG_NAME_BP];
1123 	const char *SP = anal->reg->name[R_REG_NAME_SP];
1124 	if (BP) {
1125 		extract_arg (anal, fcn, op, BP, "+", R_ANAL_VAR_KIND_BPV);
1126 		extract_arg (anal, fcn, op, BP, "-", R_ANAL_VAR_KIND_BPV);
1127 	}
1128 	extract_arg (anal, fcn, op, SP, "+", R_ANAL_VAR_KIND_SPV);
1129 }
1130 
var_generate_list(RAnal * a,RAnalFunction * fcn,int kind)1131 static RList *var_generate_list(RAnal *a, RAnalFunction *fcn, int kind) {
1132 	if (!a || !fcn) {
1133 		return NULL;
1134 	}
1135 	RList *list = r_list_new ();
1136 	if (kind < 1) {
1137 		kind = R_ANAL_VAR_KIND_BPV; // by default show vars
1138 	}
1139 	void **it;
1140 	r_pvector_foreach (&fcn->vars, it) {
1141 		RAnalVar *var = *it;
1142 		if (var->kind == kind) {
1143 			r_list_push (list, var);
1144 		}
1145 	}
1146 	return list;
1147 }
1148 
r_anal_var_all_list(RAnal * anal,RAnalFunction * fcn)1149 R_API RList *r_anal_var_all_list(RAnal *anal, RAnalFunction *fcn) {
1150 	// r_anal_var_list if there are not vars with that kind returns a list with
1151 	// zero element.. which is an unnecessary loss of cpu time
1152 	RList *list = r_list_new ();
1153 	if (!list) {
1154 		return NULL;
1155 	}
1156 	RList *reg_vars = r_anal_var_list (anal, fcn, R_ANAL_VAR_KIND_REG);
1157 	RList *bpv_vars = r_anal_var_list (anal, fcn, R_ANAL_VAR_KIND_BPV);
1158 	RList *spv_vars = r_anal_var_list (anal, fcn, R_ANAL_VAR_KIND_SPV);
1159 	r_list_join (list, reg_vars);
1160 	r_list_join (list, bpv_vars);
1161 	r_list_join (list, spv_vars);
1162 	r_list_free (reg_vars);
1163 	r_list_free (bpv_vars);
1164 	r_list_free (spv_vars);
1165 	return list;
1166 }
1167 
r_anal_var_list(RAnal * a,RAnalFunction * fcn,int kind)1168 R_API RList *r_anal_var_list(RAnal *a, RAnalFunction *fcn, int kind) {
1169 	return var_generate_list (a, fcn, kind);
1170 }
1171 
var_field_free(RAnalVarField * field)1172 static void var_field_free(RAnalVarField *field) {
1173 	if (!field) {
1174 		return;
1175 	}
1176 	free (field->name);
1177 	free (field);
1178 }
1179 
r_anal_function_get_var_fields(RAnalFunction * fcn,int kind)1180 R_API RList *r_anal_function_get_var_fields(RAnalFunction *fcn, int kind) {
1181 	if (!fcn) {
1182 		return NULL;
1183 	}
1184 	RList *list = r_list_newf ((RListFree)var_field_free);
1185 	if (kind < 1) {
1186 		kind = R_ANAL_VAR_KIND_BPV; // by default show vars
1187 	}
1188 	void **it;
1189 	r_pvector_foreach (&fcn->vars, it) {
1190 		RAnalVar *var = *it;
1191 		if (var->kind != kind) {
1192 			continue;
1193 		}
1194 		if (var_add_structure_fields_to_list (fcn->anal, var, list)) {
1195 			// this var is a struct and var_add_structure_fields_to_list added all the fields
1196 			continue;
1197 		}
1198 		RAnalVarField *field = R_NEW0 (RAnalVarField);
1199 		if (!field) {
1200 			break;
1201 		}
1202 		field->name = strdup (var->name);
1203 		if (!field->name) {
1204 			var_field_free (field);
1205 			break;
1206 		}
1207 		field->delta = var->delta;
1208 		r_list_push (list, field);
1209 	}
1210 	return list;
1211 }
1212 
var_comparator(const RAnalVar * a,const RAnalVar * b)1213 static int var_comparator(const RAnalVar *a, const RAnalVar *b){
1214 	// avoid NULL dereference
1215 	return (a && b)? (a->delta > b->delta) - (a->delta < b->delta) : 0;
1216 }
1217 
regvar_comparator(const RAnalVar * a,const RAnalVar * b)1218 static int regvar_comparator(const RAnalVar *a, const RAnalVar *b){
1219 	// avoid NULL dereference
1220 	return (a && b)? (a->argnum > b->argnum) - (a->argnum < b->argnum): 0;
1221 }
1222 
r_anal_var_list_show(RAnal * anal,RAnalFunction * fcn,int kind,int mode,PJ * pj)1223 R_API void r_anal_var_list_show(RAnal *anal, RAnalFunction *fcn, int kind, int mode, PJ *pj) {
1224 	RList *list = r_anal_var_list (anal, fcn, kind);
1225 	RAnalVar *var;
1226 	RListIter *iter;
1227 	if (!pj && mode == 'j') {
1228 		return;
1229 	}
1230 	if (mode == 'j') {
1231 		pj_a (pj);
1232 	}
1233 	if (!list) {
1234 		if (mode == 'j') {
1235 			pj_end (pj);
1236 		}
1237 		return;
1238 	}
1239 	r_list_sort (list, (RListComparator) var_comparator);
1240 	r_list_foreach (list, iter, var) {
1241 		if (var->kind != kind) {
1242 			continue;
1243 		}
1244 		switch (mode) {
1245 		case '*':
1246 			// we can't express all type info here :(
1247 			if (kind == R_ANAL_VAR_KIND_REG) { // registers
1248 				RRegItem *i = r_reg_index_get (anal->reg, var->delta);
1249 				if (!i) {
1250 					eprintf ("Register not found");
1251 					break;
1252 				}
1253 				anal->cb_printf ("afv%c %s %s %s @ 0x%"PFMT64x "\n",
1254 					kind, i->name, var->name, var->type, fcn->addr);
1255 			} else {
1256 				int delta = kind == R_ANAL_VAR_KIND_BPV
1257 					? var->delta + fcn->bp_off
1258 					: var->delta;
1259 				anal->cb_printf ("afv%c %d %s %s @ 0x%"PFMT64x "\n",
1260 					kind, delta, var->name, var->type,
1261 					fcn->addr);
1262 			}
1263 			break;
1264 		case 'j':
1265 			switch (var->kind) {
1266 			case R_ANAL_VAR_KIND_BPV: {
1267 				st64 delta = (st64)var->delta + fcn->bp_off;
1268 				pj_o (pj);
1269 				pj_ks (pj, "name", var->name);
1270 				if (var->isarg) {
1271 					pj_ks (pj, "kind", "arg");
1272 				} else {
1273 					pj_ks (pj, "kind", "var");
1274 				}
1275 				pj_ks (pj, "type", var->type);
1276 				pj_k (pj, "ref");
1277 				pj_o (pj);
1278 				pj_ks (pj, "base", anal->reg->name[R_REG_NAME_BP]);
1279 				pj_kN (pj, "offset", delta);
1280 				pj_end (pj);
1281 				pj_end (pj);
1282 			}
1283 				break;
1284 			case R_ANAL_VAR_KIND_REG: {
1285 				RRegItem *i = r_reg_index_get (anal->reg, var->delta);
1286 				if (!i) {
1287 					eprintf ("Register not found");
1288 					break;
1289 				}
1290 				pj_o (pj);
1291 				pj_ks (pj, "name", var->name);
1292 				pj_ks (pj, "kind", "reg");
1293 				pj_ks (pj, "type", var->type);
1294 				pj_ks (pj, "ref", i->name);
1295 				pj_end (pj);
1296 			}
1297 				break;
1298 			case R_ANAL_VAR_KIND_SPV: {
1299 				st64 delta = (st64)var->delta + fcn->maxstack;
1300 				pj_o (pj);
1301 				pj_ks (pj, "name", var->name);
1302 				if (var->isarg) {
1303 					pj_ks (pj, "kind", "arg");
1304 				} else {
1305 					pj_ks (pj, "kind", "var");
1306 				}
1307 				pj_ks (pj, "type", var->type);
1308 				pj_k (pj, "ref");
1309 				pj_o (pj);
1310 				pj_ks (pj, "base", anal->reg->name[R_REG_NAME_SP]);
1311 				pj_kN (pj, "offset", delta);
1312 				pj_end (pj);
1313 				pj_end (pj);
1314 			}
1315 				break;
1316 			}
1317 			break;
1318 		default:
1319 			switch (kind) {
1320 			case R_ANAL_VAR_KIND_BPV:
1321 			{
1322 				int delta = var->delta + fcn->bp_off;
1323 				if (var->isarg) {
1324 					anal->cb_printf ("arg %s %s @ %s+0x%x\n",
1325 						var->type, var->name,
1326 						anal->reg->name[R_REG_NAME_BP],
1327 						delta);
1328 				} else {
1329 					char sign = (-var->delta <= fcn->bp_off) ? '+' : '-';
1330 					anal->cb_printf ("var %s %s @ %s%c0x%x\n",
1331 						var->type, var->name,
1332 						anal->reg->name[R_REG_NAME_BP],
1333 						sign, R_ABS (delta));
1334 				}
1335 			}
1336 				break;
1337 			case R_ANAL_VAR_KIND_REG: {
1338 				RRegItem *i = r_reg_index_get (anal->reg, var->delta);
1339 				if (!i) {
1340 					eprintf ("Register not found");
1341 					break;
1342 				}
1343 				anal->cb_printf ("arg %s %s @ %s\n",
1344 					var->type, var->name, i->name);
1345 				}
1346 				break;
1347 			case R_ANAL_VAR_KIND_SPV:
1348 			{
1349 				int delta = fcn->maxstack + var->delta;
1350 				if (!var->isarg) {
1351 					char sign = (-var->delta <= fcn->maxstack) ? '+' : '-';
1352 					anal->cb_printf ("var %s %s @ %s%c0x%x\n",
1353 						var->type, var->name,
1354 						anal->reg->name[R_REG_NAME_SP],
1355 						sign, R_ABS (delta));
1356 				} else {
1357 					anal->cb_printf ("arg %s %s @ %s+0x%x\n",
1358 						var->type, var->name,
1359 						anal->reg->name[R_REG_NAME_SP],
1360 						delta);
1361 
1362 				}
1363 			}
1364 				break;
1365 			}
1366 		}
1367 	}
1368 	if (mode == 'j') {
1369 		pj_end (pj);
1370 	}
1371 	r_list_free (list);
1372 }
1373 
r_anal_fcn_vars_cache_init(RAnal * anal,RAnalFcnVarsCache * cache,RAnalFunction * fcn)1374 R_API void r_anal_fcn_vars_cache_init(RAnal *anal, RAnalFcnVarsCache *cache, RAnalFunction *fcn) {
1375 	cache->bvars = r_anal_var_list (anal, fcn, R_ANAL_VAR_KIND_BPV);
1376 	cache->rvars = r_anal_var_list (anal, fcn, R_ANAL_VAR_KIND_REG);
1377 	cache->svars = r_anal_var_list (anal, fcn, R_ANAL_VAR_KIND_SPV);
1378 	r_list_sort (cache->bvars, (RListComparator)var_comparator);
1379 	RListIter *it;
1380 	RAnalVar *var;
1381 	r_list_foreach (cache->rvars, it, var) {
1382 		var->argnum = r_anal_var_get_argnum (var);
1383 	}
1384 	r_list_sort (cache->rvars, (RListComparator)regvar_comparator);
1385 	r_list_sort (cache->svars, (RListComparator)var_comparator);
1386 }
1387 
r_anal_fcn_vars_cache_fini(RAnalFcnVarsCache * cache)1388 R_API void r_anal_fcn_vars_cache_fini(RAnalFcnVarsCache *cache) {
1389 	if (!cache) {
1390 		return;
1391 	}
1392 	r_list_free (cache->bvars);
1393 	r_list_free (cache->rvars);
1394 	r_list_free (cache->svars);
1395 }
1396 
r_anal_fcn_format_sig(R_NONNULL RAnal * anal,R_NONNULL RAnalFunction * fcn,R_NULLABLE char * fcn_name,R_NULLABLE RAnalFcnVarsCache * reuse_cache,R_NULLABLE const char * fcn_name_pre,R_NULLABLE const char * fcn_name_post)1397 R_API char *r_anal_fcn_format_sig(R_NONNULL RAnal *anal, R_NONNULL RAnalFunction *fcn, R_NULLABLE char *fcn_name,
1398 		R_NULLABLE RAnalFcnVarsCache *reuse_cache, R_NULLABLE const char *fcn_name_pre, R_NULLABLE const char *fcn_name_post) {
1399 	RAnalFcnVarsCache *cache = NULL;
1400 
1401 	if (!fcn_name) {
1402 		fcn_name = fcn->name;
1403 		if (!fcn_name) {
1404 			return NULL;
1405 		}
1406 	}
1407 
1408 	RStrBuf *buf = r_strbuf_new (NULL);
1409 	if (!buf) {
1410 		return NULL;
1411 	}
1412 
1413 	Sdb *TDB = anal->sdb_types;
1414 	char *type_fcn_name = r_type_func_guess (TDB, fcn_name);
1415 	if (type_fcn_name && r_type_func_exist (TDB, type_fcn_name)) {
1416 		const char *fcn_type = r_type_func_ret (anal->sdb_types, type_fcn_name);
1417 		if (fcn_type) {
1418 			const char *sp = " ";
1419 			if (*fcn_type && (fcn_type[strlen (fcn_type) - 1] == '*')) {
1420 				sp = "";
1421 			}
1422 			r_strbuf_appendf (buf, "%s%s", fcn_type, sp);
1423 		}
1424 	}
1425 
1426 	if (fcn_name_pre) {
1427 		r_strbuf_append (buf, fcn_name_pre);
1428 	}
1429 	r_strbuf_append (buf, fcn_name);
1430 	if (fcn_name_post) {
1431 		r_strbuf_append (buf, fcn_name_post);
1432 	}
1433 	r_strbuf_append (buf, " (");
1434 
1435 	if (type_fcn_name && r_type_func_exist (TDB, type_fcn_name)) {
1436 		int i, argc = r_type_func_args_count (TDB, type_fcn_name);
1437 		bool comma = true;
1438 		// This avoids false positives present in argument recovery
1439 		// and straight away print arguments fetched from types db
1440 		for (i = 0; i < argc; i++) {
1441 			char *type = r_type_func_args_type (TDB, type_fcn_name, i);
1442 			const char *name = r_type_func_args_name (TDB, type_fcn_name, i);
1443 			if (!type || !name) {
1444 				eprintf ("Missing type for %s\n", type_fcn_name);
1445 				goto beach;
1446 			}
1447 			if (i == argc - 1) {
1448 				comma = false;
1449 			}
1450 			size_t len = strlen (type);
1451 			const char *tc = len > 0 && type[len - 1] == '*'? "": " ";
1452 			r_strbuf_appendf (buf, "%s%s%s%s", type, tc, name, comma? ", ": "");
1453 			free (type);
1454 		}
1455 		goto beach;
1456 	}
1457 	R_FREE (type_fcn_name);
1458 
1459 
1460 	cache = reuse_cache;
1461 	if (!cache) {
1462 		cache = R_NEW0 (RAnalFcnVarsCache);
1463 		if (!cache) {
1464 			type_fcn_name = NULL;
1465 			goto beach;
1466 		}
1467 		r_anal_fcn_vars_cache_init (anal, cache, fcn);
1468 	}
1469 
1470 	bool comma = true;
1471 	bool arg_bp = false;
1472 	size_t tmp_len;
1473 	RAnalVar *var;
1474 	RListIter *iter;
1475 
1476 	r_list_foreach (cache->rvars, iter, var) {
1477 		// assume self, error are always the last
1478 		if (!strcmp (var->name, "self") || !strcmp (var->name, "error")) {
1479 			r_strbuf_slice (buf, 0, r_strbuf_length (buf) - 2);
1480 			break;
1481 		}
1482 		tmp_len = strlen (var->type);
1483 		r_strbuf_appendf (buf, "%s%s%s%s", var->type,
1484 			tmp_len && var->type[tmp_len - 1] == '*' ? "" : " ",
1485 			var->name, iter->n ? ", " : "");
1486 	}
1487 
1488 	r_list_foreach (cache->bvars, iter, var) {
1489 		if (var->isarg) {
1490 			if (!r_list_empty (cache->rvars) && comma) {
1491 				r_strbuf_append (buf, ", ");
1492 				comma = false;
1493 			}
1494 			arg_bp = true;
1495 			tmp_len = strlen (var->type);
1496 			r_strbuf_appendf (buf, "%s%s%s%s", var->type,
1497 				tmp_len && var->type[tmp_len - 1] =='*' ? "" : " ",
1498 				var->name, iter->n ? ", " : "");
1499 		}
1500 	}
1501 
1502 	comma = true;
1503 	const char *maybe_comma = ", ";
1504 	r_list_foreach (cache->svars, iter, var) {
1505 		if (var->isarg) {
1506 			if (!*maybe_comma || ((arg_bp || !r_list_empty (cache->rvars)) && comma)) {
1507 				comma = false;
1508 				r_strbuf_append (buf, ", ");
1509 			}
1510 			tmp_len = strlen (var->type);
1511 			if (iter->n && ((RAnalVar *)iter->n->data)->isarg) {
1512 				maybe_comma = ", ";
1513 			} else {
1514 				maybe_comma = "";
1515 			}
1516 			r_strbuf_appendf (buf, "%s%s%s%s", var->type,
1517 				tmp_len && var->type[tmp_len - 1] =='*' ? "" : " ",
1518 				var->name, maybe_comma);
1519 		}
1520 	}
1521 
1522 beach:
1523 	r_strbuf_append (buf, ");");
1524 	R_FREE (type_fcn_name);
1525 	if (!reuse_cache) {
1526 		// !reuse_cache => we created our own cache
1527 		r_anal_fcn_vars_cache_fini (cache);
1528 		free (cache);
1529 	}
1530 	return r_strbuf_drain (buf);
1531 }
1532