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