1 /* radare - LGPL - Copyright 2019 - pancake, thestr4ng3r */
2 
3 #include <r_anal.h>
4 
5 #define D if (anal->verbose)
6 
get_functions_block_cb(RAnalBlock * block,void * user)7 static bool get_functions_block_cb(RAnalBlock *block, void *user) {
8 	RList *list = user;
9 	RListIter *iter;
10 	RAnalFunction *fcn;
11 	r_list_foreach (block->fcns, iter, fcn) {
12 		if (r_list_contains (list, fcn)) {
13 			continue;
14 		}
15 		r_list_push (list, fcn);
16 	}
17 	return true;
18 }
19 
r_anal_get_functions_in(RAnal * anal,ut64 addr)20 R_API RList *r_anal_get_functions_in(RAnal *anal, ut64 addr) {
21 	RList *list = r_list_new ();
22 	if (!list) {
23 		return NULL;
24 	}
25 	r_anal_blocks_foreach_in (anal, addr, get_functions_block_cb, list);
26 	return list;
27 }
28 
__fcn_exists(RAnal * anal,const char * name,ut64 addr)29 static bool __fcn_exists(RAnal *anal, const char *name, ut64 addr) {
30 	// check if name is already registered
31 	bool found = false;
32 	if (addr == UT64_MAX) {
33 		eprintf ("Invalid function address (-1) '%s'\n", name);
34 		return true;
35 	}
36 	if (!name) {
37 		eprintf ("TODO: Empty function name, we must auto generate one\n");
38 		return true;
39 	}
40 	RAnalFunction *f = ht_pp_find (anal->ht_name_fun, name, &found);
41 	if (f && found) {
42 		eprintf ("Invalid function name '%s' at 0x%08"PFMT64x"\n", name, addr);
43 		return true;
44 	}
45 	// check if there's a function already in the given address
46 	found = false;
47 	f = ht_up_find (anal->ht_addr_fun, addr, &found);
48 	if (f && found) {
49 		eprintf ("Function already defined in 0x%08"PFMT64x"\n", addr);
50 		return true;
51 	}
52 	return false;
53 }
54 
55 R_IPI void r_anal_var_free(RAnalVar *av);
56 
inst_vars_kv_free(HtUPKv * kv)57 static void inst_vars_kv_free(HtUPKv *kv) {
58 	r_pvector_free (kv->value);
59 }
60 
labels_kv_free(HtUPKv * kv)61 static void labels_kv_free(HtUPKv *kv) {
62 	free (kv->value);
63 }
64 
label_addrs_kv_free(HtPPKv * kv)65 static void label_addrs_kv_free(HtPPKv *kv) {
66 	free (kv->key);
67 	free (kv->value);
68 }
69 
r_anal_function_new(RAnal * anal)70 R_API RAnalFunction *r_anal_function_new(RAnal *anal) {
71 	RAnalFunction *fcn = R_NEW0 (RAnalFunction);
72 	if (!fcn) {
73 		return NULL;
74 	}
75 	fcn->anal = anal;
76 	fcn->addr = UT64_MAX;
77 	fcn->cc = r_str_constpool_get (&anal->constpool, r_anal_cc_default (anal));
78 	fcn->bits = anal->bits;
79 	fcn->bbs = r_list_new ();
80 	fcn->diff = r_anal_diff_new ();
81 	fcn->has_changed = true;
82 	fcn->bp_frame = true;
83 	fcn->is_noreturn = false;
84 	fcn->meta._min = UT64_MAX;
85 	r_pvector_init (&fcn->vars, NULL);
86 	fcn->inst_vars = ht_up_new (NULL, inst_vars_kv_free, NULL);
87 	fcn->labels = ht_up_new (NULL, labels_kv_free, NULL);
88 	fcn->label_addrs = ht_pp_new (NULL, label_addrs_kv_free, NULL);
89 	return fcn;
90 }
91 
r_anal_function_free(void * _fcn)92 R_API void r_anal_function_free(void *_fcn) {
93 	RAnalFunction *fcn = _fcn;
94 	if (!_fcn) {
95 		return;
96 	}
97 
98 	RAnalBlock *block;
99 	RListIter *iter;
100 	r_list_foreach (fcn->bbs, iter, block) {
101 		r_list_delete_data (block->fcns, fcn);
102 		r_anal_block_unref (block);
103 	}
104 	r_list_free (fcn->bbs);
105 
106 	RAnal *anal = fcn->anal;
107 	if (ht_up_find (anal->ht_addr_fun, fcn->addr, NULL) == _fcn) {
108 		ht_up_delete (anal->ht_addr_fun, fcn->addr);
109 	}
110 	if (ht_pp_find (anal->ht_name_fun, fcn->name, NULL) == _fcn) {
111 		ht_pp_delete (anal->ht_name_fun, fcn->name);
112 	}
113 
114 	ht_up_free (fcn->inst_vars);
115 	fcn->inst_vars = NULL;
116 	r_anal_function_delete_all_vars (fcn);
117 
118 	ht_up_free (fcn->labels);
119 	ht_pp_free (fcn->label_addrs);
120 
121 	free (fcn->name);
122 	fcn->bbs = NULL;
123 	free (fcn->fingerprint);
124 	r_anal_diff_free (fcn->diff);
125 	r_list_free (fcn->imports);
126 	free (fcn);
127 }
128 
r_anal_add_function(RAnal * anal,RAnalFunction * fcn)129 R_API bool r_anal_add_function(RAnal *anal, RAnalFunction *fcn) {
130 	if (__fcn_exists (anal, fcn->name, fcn->addr)) {
131 		return false;
132 	}
133 	if (anal->cb.on_fcn_new) {
134 		anal->cb.on_fcn_new (anal, anal->user, fcn);
135 	}
136 	if (anal->flg_fcn_set) {
137 		anal->flg_fcn_set (anal->flb.f, fcn->name, fcn->addr, r_anal_function_size_from_entry (fcn));
138 	}
139 	fcn->is_noreturn = r_anal_noreturn_at_addr (anal, fcn->addr);
140 	r_list_append (anal->fcns, fcn);
141 	ht_pp_insert (anal->ht_name_fun, fcn->name, fcn);
142 	ht_up_insert (anal->ht_addr_fun, fcn->addr, fcn);
143 	return true;
144 }
145 
r_anal_create_function(RAnal * anal,const char * name,ut64 addr,int type,RAnalDiff * diff)146 R_API RAnalFunction *r_anal_create_function(RAnal *anal, const char *name, ut64 addr, int type, RAnalDiff *diff) {
147 	RAnalFunction *fcn = r_anal_function_new (anal);
148 	if (!fcn) {
149 		return NULL;
150 	}
151 	fcn->addr = addr;
152 	fcn->type = type;
153 	fcn->cc = r_str_constpool_get (&anal->constpool, r_anal_cc_default (anal));
154 	fcn->bits = anal->bits;
155 	if (name) {
156 		free (fcn->name);
157 		fcn->name = strdup (name);
158 	} else {
159 		const char *fcnprefix = anal->coreb.cfgGet ? anal->coreb.cfgGet (anal->coreb.core, "anal.fcnprefix") : NULL;
160 		if (!fcnprefix) {
161 			fcnprefix = "fcn";
162 		}
163 		fcn->name = r_str_newf ("%s.%08"PFMT64x, fcnprefix, fcn->addr);
164 	}
165 	if (diff) {
166 		fcn->diff->type = diff->type;
167 		fcn->diff->addr = diff->addr;
168 		R_FREE (fcn->diff->name);
169 		if (diff->name) {
170 			fcn->diff->name = strdup (diff->name);
171 		}
172 	}
173 	if (!r_anal_add_function (anal, fcn)) {
174 		r_anal_function_free (fcn);
175 		return NULL;
176 	}
177 	return fcn;
178 }
179 
r_anal_function_delete(RAnalFunction * fcn)180 R_API bool r_anal_function_delete(RAnalFunction *fcn) {
181 	return r_list_delete_data (fcn->anal->fcns, fcn);
182 }
183 
r_anal_get_function_at(RAnal * anal,ut64 addr)184 R_API RAnalFunction *r_anal_get_function_at(RAnal *anal, ut64 addr) {
185 	bool found = false;
186 	RAnalFunction *f = ht_up_find (anal->ht_addr_fun, addr, &found);
187 	if (f && found) {
188 		return f;
189 	}
190 	return NULL;
191 }
192 
193 typedef struct {
194 	HtUP *inst_vars_new;
195 	st64 delta;
196 } InstVarsRelocateCtx;
197 
inst_vars_relocate_cb(void * user,const ut64 k,const void * v)198 static bool inst_vars_relocate_cb(void *user, const ut64 k, const void *v) {
199 	InstVarsRelocateCtx *ctx = user;
200 	ht_up_insert (ctx->inst_vars_new, k - ctx->delta, (void *)v);
201 	return true;
202 }
203 
r_anal_function_relocate(RAnalFunction * fcn,ut64 addr)204 R_API bool r_anal_function_relocate(RAnalFunction *fcn, ut64 addr) {
205 	if (fcn->addr == addr) {
206 		return true;
207 	}
208 	if (r_anal_get_function_at (fcn->anal, addr)) {
209 		return false;
210 	}
211 	ht_up_delete (fcn->anal->ht_addr_fun, fcn->addr);
212 
213 	// relocate the var accesses (their addrs are relative to the function addr)
214 	st64 delta = addr - fcn->addr;
215 	void **it;
216 	r_pvector_foreach (&fcn->vars, it) {
217 		RAnalVar *var = *it;
218 		RAnalVarAccess *acc;
219 		r_vector_foreach (&var->accesses, acc) {
220 			acc->offset -= (ut64)delta;
221 		}
222 	}
223 	InstVarsRelocateCtx ctx = {
224 		.inst_vars_new = ht_up_new (NULL, inst_vars_kv_free, NULL),
225 		.delta = delta
226 	};
227 	if (ctx.inst_vars_new) {
228 		ht_up_foreach (fcn->inst_vars, inst_vars_relocate_cb, &ctx);
229 		// Do not free the elements of the Ht, because they were moved to ctx.inst_vars_new
230 		fcn->inst_vars->opt.freefn = NULL;
231 		ht_up_free (fcn->inst_vars);
232 		fcn->inst_vars = ctx.inst_vars_new;
233 	}
234 
235 	fcn->addr = addr;
236 	ht_up_insert (fcn->anal->ht_addr_fun, addr, fcn);
237 	return true;
238 }
239 
r_anal_function_rename(RAnalFunction * fcn,const char * name)240 R_API bool r_anal_function_rename(RAnalFunction *fcn, const char *name) {
241 	RAnal *anal = fcn->anal;
242 	RAnalFunction *existing = ht_pp_find (anal->ht_name_fun, name, NULL);
243 	if (existing) {
244 		if (existing == fcn) {
245 			// fcn->name == name, nothing to do
246 			return true;
247 		}
248 		return false;
249 	}
250 	char *newname = strdup (name);
251 	if (!newname) {
252 		return false;
253 	}
254 	bool in_tree = ht_pp_delete (anal->ht_name_fun, fcn->name);
255 	free (fcn->name);
256 	fcn->name = newname;
257 	if (in_tree) {
258 		// only re-insert if it really was in the tree before
259 		ht_pp_insert (anal->ht_name_fun, fcn->name, fcn);
260 	}
261 	return true;
262 }
263 
r_anal_function_add_block(RAnalFunction * fcn,RAnalBlock * bb)264 R_API void r_anal_function_add_block(RAnalFunction *fcn, RAnalBlock *bb) {
265 	if (r_list_contains (bb->fcns, fcn)) {
266 		return;
267 	}
268 	r_list_append (bb->fcns, fcn); // associate the given fcn with this bb
269 	r_anal_block_ref (bb);
270 	r_list_append (fcn->bbs, bb);
271 
272 	if (fcn->meta._min != UT64_MAX) {
273 		if (bb->addr + bb->size > fcn->meta._max) {
274 			fcn->meta._max = bb->addr + bb->size;
275 		}
276 		if (bb->addr < fcn->meta._min) {
277 			fcn->meta._min = bb->addr;
278 		}
279 	}
280 
281 	if (fcn->anal->cb.on_fcn_bb_new) {
282 		fcn->anal->cb.on_fcn_bb_new (fcn->anal, fcn->anal->user, fcn, bb);
283 	}
284 }
285 
r_anal_function_remove_block(RAnalFunction * fcn,RAnalBlock * bb)286 R_API void r_anal_function_remove_block(RAnalFunction *fcn, RAnalBlock *bb) {
287 	r_list_delete_data (bb->fcns, fcn);
288 
289 	if (fcn->meta._min != UT64_MAX
290 		&& (fcn->meta._min == bb->addr || fcn->meta._max == bb->addr + bb->size)) {
291 		// If a block is removed at the beginning or end, updating min/max is not trivial anymore, just invalidate
292 		fcn->meta._min = UT64_MAX;
293 	}
294 
295 	r_list_delete_data (fcn->bbs, bb);
296 	r_anal_block_unref (bb);
297 }
298 
ensure_fcn_range(RAnalFunction * fcn)299 static void ensure_fcn_range(RAnalFunction *fcn) {
300 	if (fcn->meta._min != UT64_MAX) { // recalculate only if invalid
301 		return;
302 	}
303 	ut64 minval = UT64_MAX;
304 	ut64 maxval = UT64_MIN;
305 	RAnalBlock *block;
306 	RListIter *iter;
307 	r_list_foreach (fcn->bbs, iter, block) {
308 			if (block->addr < minval) {
309 				minval = block->addr;
310 			}
311 			if (block->addr + block->size > maxval) {
312 				maxval = block->addr + block->size;
313 			}
314 		}
315 	fcn->meta._min = minval;
316 	fcn->meta._max = minval == UT64_MAX ? UT64_MAX : maxval;
317 }
318 
r_anal_function_linear_size(RAnalFunction * fcn)319 R_API ut64 r_anal_function_linear_size(RAnalFunction *fcn) {
320 	ensure_fcn_range (fcn);
321 	return fcn->meta._max - fcn->meta._min;
322 }
323 
r_anal_function_min_addr(RAnalFunction * fcn)324 R_API ut64 r_anal_function_min_addr(RAnalFunction *fcn) {
325 	ensure_fcn_range (fcn);
326 	return fcn->meta._min;
327 }
328 
r_anal_function_max_addr(RAnalFunction * fcn)329 R_API ut64 r_anal_function_max_addr(RAnalFunction *fcn) {
330 	ensure_fcn_range (fcn);
331 	return fcn->meta._max;
332 }
333 
r_anal_function_size_from_entry(RAnalFunction * fcn)334 R_API ut64 r_anal_function_size_from_entry(RAnalFunction *fcn) {
335 	ensure_fcn_range (fcn);
336 	return fcn->meta._min == UT64_MAX ? 0 : fcn->meta._max - fcn->addr;
337 }
338 
r_anal_function_realsize(const RAnalFunction * fcn)339 R_API ut64 r_anal_function_realsize(const RAnalFunction *fcn) {
340 	RListIter *iter;
341 	RAnalBlock *bb;
342 	ut64 sz = 0;
343 	if (!sz) {
344 		r_list_foreach (fcn->bbs, iter, bb) {
345 			sz += bb->size;
346 		}
347 	}
348 	return sz;
349 }
350 
fcn_in_cb(RAnalBlock * block,void * user)351 static bool fcn_in_cb(RAnalBlock *block, void *user) {
352 	RListIter *iter;
353 	RAnalFunction *fcn;
354 	r_list_foreach (block->fcns, iter, fcn) {
355 		if (fcn == user) {
356 			return false;
357 		}
358 	}
359 	return true;
360 }
361 
r_anal_function_contains(RAnalFunction * fcn,ut64 addr)362 R_API bool r_anal_function_contains(RAnalFunction *fcn, ut64 addr) {
363 	// fcn_in_cb breaks with false if it finds the fcn
364 	return !r_anal_blocks_foreach_in (fcn->anal, addr, fcn_in_cb, fcn);
365 }
366 
r_anal_function_was_modified(RAnalFunction * fcn)367 R_API bool r_anal_function_was_modified(RAnalFunction *fcn) {
368 	r_return_val_if_fail (fcn, false);
369 	RListIter *it;
370 	RAnalBlock *bb;
371 	r_list_foreach (fcn->bbs, it, bb) {
372 		if (r_anal_block_was_modified (bb)) {
373 			return true;
374 		}
375 	}
376 	return false;
377 }
378