1 /* radare - LGPL - Copyright 2009-2019 - pancake, nibble, defragger, ret2libc */
2
3 #include <r_anal.h>
4 #include <r_cons.h>
5
6 #if 0
7 DICT
8 ====
9
10 refs
11 10 -> 20 C
12 16 -> 10 J
13 20 -> 10 C
14
15 xrefs
16 20 -> [ 10 C ]
17 10 -> [ 16 J, 20 C ]
18
19 10: call 20
20 16: jmp 10
21 20: call 10
22 #endif
23
24 // XXX: is it possible to have multiple type for the same (from, to) pair?
25 // if it is, things need to be adjusted
26
r_anal_ref_new(ut64 addr,ut64 at,ut64 type)27 static RAnalRef *r_anal_ref_new(ut64 addr, ut64 at, ut64 type) {
28 RAnalRef *ref = R_NEW (RAnalRef);
29 if (ref) {
30 ref->addr = addr;
31 ref->at = at;
32 ref->type = (type == -1)? R_ANAL_REF_TYPE_CODE: type;
33 }
34 return ref;
35 }
36
r_anal_ref_free(void * ref)37 static void r_anal_ref_free(void *ref) {
38 free (ref);
39 }
40
r_anal_ref_list_new(void)41 R_API RList *r_anal_ref_list_new(void) {
42 return r_list_newf (r_anal_ref_free);
43 }
44
xrefs_ht_free(HtUPKv * kv)45 static void xrefs_ht_free(HtUPKv *kv) {
46 ht_up_free (kv->value);
47 }
48
xrefs_ref_free(HtUPKv * kv)49 static void xrefs_ref_free(HtUPKv *kv) {
50 r_anal_ref_free (kv->value);
51 }
52
appendRef(void * u,const ut64 k,const void * v)53 static bool appendRef(void *u, const ut64 k, const void *v) {
54 RList *list = (RList *)u;
55 RAnalRef *ref = (RAnalRef *)v;
56 RAnalRef *cloned = r_anal_ref_new (ref->addr, ref->at, ref->type);
57 if (cloned) {
58 r_list_append (list, cloned);
59 return true;
60 }
61 return false;
62 }
63
mylistrefs_cb(void * list,const ut64 k,const void * v)64 static bool mylistrefs_cb(void *list, const ut64 k, const void *v) {
65 HtUP *ht = (HtUP *)v;
66 ht_up_foreach (ht, appendRef, list);
67 return true;
68 }
69
ref_cmp(const RAnalRef * a,const RAnalRef * b)70 static int ref_cmp(const RAnalRef *a, const RAnalRef *b) {
71 if (a->at < b->at) {
72 return -1;
73 }
74 if (a->at > b->at) {
75 return 1;
76 }
77 if (a->addr < b->addr) {
78 return -1;
79 }
80 if (a->addr > b->addr) {
81 return 1;
82 }
83 return 0;
84 }
85
sortxrefs(RList * list)86 static void sortxrefs(RList *list) {
87 r_list_sort (list, (RListComparator)ref_cmp);
88 }
89
listxrefs(HtUP * m,ut64 addr,RList * list)90 static void listxrefs(HtUP *m, ut64 addr, RList *list) {
91 if (addr == UT64_MAX) {
92 ht_up_foreach (m, mylistrefs_cb, list);
93 } else {
94 bool found;
95 HtUP *d = ht_up_find (m, addr, &found);
96 if (!found) {
97 return;
98 }
99
100 ht_up_foreach (d, appendRef, list);
101 }
102 }
103
setxref(HtUP * m,ut64 from,ut64 to,int type)104 static void setxref(HtUP *m, ut64 from, ut64 to, int type) {
105 bool found;
106 HtUP *ht = ht_up_find (m, from, &found);
107 if (!found) {
108 ht = ht_up_new (NULL, xrefs_ref_free, NULL);
109 if (!ht) {
110 return;
111 }
112 ht_up_insert (m, from, ht);
113 }
114 RAnalRef *ref = r_anal_ref_new (to, from, type);
115 if (ref) {
116 ht_up_update (ht, to, ref);
117 }
118 }
119
120 // set a reference from FROM to TO and a cross-reference(xref) from TO to FROM.
r_anal_xrefs_set(RAnal * anal,ut64 from,ut64 to,const RAnalRefType type)121 R_API int r_anal_xrefs_set(RAnal *anal, ut64 from, ut64 to, const RAnalRefType type) {
122 if (!anal || from == to) {
123 return false;
124 }
125 if (anal->iob.is_valid_offset) {
126 if (!anal->iob.is_valid_offset (anal->iob.io, from, 0)) {
127 return false;
128 }
129 if (!anal->iob.is_valid_offset (anal->iob.io, to, 0)) {
130 return false;
131 }
132 }
133 setxref (anal->dict_xrefs, to, from, type);
134 setxref (anal->dict_refs, from, to, type);
135 return true;
136 }
137
r_anal_xrefs_deln(RAnal * anal,ut64 from,ut64 to,const RAnalRefType type)138 R_API int r_anal_xrefs_deln(RAnal *anal, ut64 from, ut64 to, const RAnalRefType type) {
139 if (!anal) {
140 return false;
141 }
142 ht_up_delete (anal->dict_refs, from);
143 ht_up_delete (anal->dict_xrefs, to);
144 return true;
145 }
146
r_anal_xref_del(RAnal * anal,ut64 from,ut64 to)147 R_API int r_anal_xref_del(RAnal *anal, ut64 from, ut64 to) {
148 bool res = false;
149 res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_NULL);
150 res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_CODE);
151 res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_CALL);
152 res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_DATA);
153 res |= r_anal_xrefs_deln (anal, from, to, R_ANAL_REF_TYPE_STRING);
154 return res;
155 }
156
r_anal_xrefs_from(RAnal * anal,RList * list,const char * kind,const RAnalRefType type,ut64 addr)157 R_API int r_anal_xrefs_from(RAnal *anal, RList *list, const char *kind, const RAnalRefType type, ut64 addr) {
158 listxrefs (anal->dict_refs, addr, list);
159 sortxrefs (list);
160 return true;
161 }
162
r_anal_xrefs_get(RAnal * anal,ut64 to)163 R_API RList *r_anal_xrefs_get(RAnal *anal, ut64 to) {
164 RList *list = r_anal_ref_list_new ();
165 if (!list) {
166 return NULL;
167 }
168 listxrefs (anal->dict_xrefs, to, list);
169 sortxrefs (list);
170 if (r_list_empty (list)) {
171 r_list_free (list);
172 list = NULL;
173 }
174 return list;
175 }
176
r_anal_refs_get(RAnal * anal,ut64 from)177 R_API RList *r_anal_refs_get(RAnal *anal, ut64 from) {
178 RList *list = r_anal_ref_list_new ();
179 if (!list) {
180 return NULL;
181 }
182 listxrefs (anal->dict_refs, from, list);
183 sortxrefs (list);
184 if (r_list_empty (list)) {
185 r_list_free (list);
186 list = NULL;
187 }
188 return list;
189 }
190
r_anal_xrefs_get_from(RAnal * anal,ut64 to)191 R_API RList *r_anal_xrefs_get_from(RAnal *anal, ut64 to) {
192 RList *list = r_anal_ref_list_new ();
193 if (!list) {
194 return NULL;
195 }
196 listxrefs (anal->dict_refs, to, list);
197 sortxrefs (list);
198 if (r_list_empty (list)) {
199 r_list_free (list);
200 list = NULL;
201 }
202 return list;
203 }
204
r_anal_xrefs_list(RAnal * anal,int rad)205 R_API void r_anal_xrefs_list(RAnal *anal, int rad) {
206 RListIter *iter;
207 RAnalRef *ref;
208 PJ *pj = NULL;
209 RList *list = r_anal_ref_list_new();
210 listxrefs (anal->dict_refs, UT64_MAX, list);
211 sortxrefs (list);
212 if (rad == 'j') {
213 pj = anal->coreb.pjWithEncoding (anal->coreb.core);
214 if (!pj) {
215 return;
216 }
217 pj_a (pj);
218 }
219 r_list_foreach (list, iter, ref) {
220 int t = ref->type ? ref->type: ' ';
221 switch (rad) {
222 case '*':
223 anal->cb_printf ("ax%c 0x%"PFMT64x" 0x%"PFMT64x"\n", t, ref->addr, ref->at);
224 break;
225 case '\0':
226 {
227 char *name = anal->coreb.getNameDelta (anal->coreb.core, ref->at);
228 if (name) {
229 r_str_replace_ch (name, ' ', 0, true);
230 anal->cb_printf ("%40s", name);
231 free (name);
232 } else {
233 anal->cb_printf ("%40s", "?");
234 }
235 anal->cb_printf (" 0x%"PFMT64x" -> %9s -> 0x%"PFMT64x, ref->at, r_anal_xrefs_type_tostring (t), ref->addr);
236 name = anal->coreb.getNameDelta (anal->coreb.core, ref->addr);
237 if (name) {
238 r_str_replace_ch (name, ' ', 0, true);
239 anal->cb_printf (" %s\n", name);
240 free (name);
241 } else {
242 anal->cb_printf ("\n");
243 }
244 }
245 break;
246 case 'q':
247 anal->cb_printf ("0x%08"PFMT64x" -> 0x%08"PFMT64x" %s\n", ref->at, ref->addr, r_anal_xrefs_type_tostring (t));
248 break;
249 case 'j':
250 {
251 pj_o (pj);
252 char *name = anal->coreb.getNameDelta (anal->coreb.core, ref->at);
253 if (name) {
254 r_str_replace_ch (name, ' ', 0, true);
255 pj_ks (pj, "name", name);
256 free (name);
257 }
258 pj_kn (pj, "from", ref->at);
259 pj_ks (pj, "type", r_anal_xrefs_type_tostring (t));
260 pj_kn (pj, "addr", ref->addr);
261 name = anal->coreb.getNameDelta (anal->coreb.core, ref->addr);
262 if (name) {
263 r_str_replace_ch (name, ' ', 0, true);
264 pj_ks (pj, "refname", name);
265 free (name);
266 }
267 pj_end (pj);
268 }
269 break;
270 default:
271 break;
272 }
273 }
274 if (rad == 'j') {
275 pj_end (pj);
276 anal->cb_printf ("%s\n", pj_string (pj));
277 pj_free (pj);
278 }
279 r_list_free (list);
280 }
281
r_anal_xrefs_type_tostring(RAnalRefType type)282 R_API const char *r_anal_xrefs_type_tostring(RAnalRefType type) {
283 switch (type) {
284 case R_ANAL_REF_TYPE_CODE:
285 return "CODE";
286 case R_ANAL_REF_TYPE_CALL:
287 return "CALL";
288 case R_ANAL_REF_TYPE_DATA:
289 return "DATA";
290 case R_ANAL_REF_TYPE_STRING:
291 return "STRING";
292 case R_ANAL_REF_TYPE_NULL:
293 default:
294 return "UNKNOWN";
295 }
296 }
297
r_anal_xrefs_type(char ch)298 R_API RAnalRefType r_anal_xrefs_type(char ch) {
299 switch (ch) {
300 case R_ANAL_REF_TYPE_CODE:
301 case R_ANAL_REF_TYPE_CALL:
302 case R_ANAL_REF_TYPE_DATA:
303 case R_ANAL_REF_TYPE_STRING:
304 case R_ANAL_REF_TYPE_NULL:
305 return (RAnalRefType)ch;
306 default:
307 return R_ANAL_REF_TYPE_NULL;
308 }
309 }
310
r_anal_xrefs_init(RAnal * anal)311 R_API bool r_anal_xrefs_init(RAnal *anal) {
312 ht_up_free (anal->dict_refs);
313 anal->dict_refs = NULL;
314 ht_up_free (anal->dict_xrefs);
315 anal->dict_xrefs = NULL;
316
317 HtUP *tmp = ht_up_new (NULL, xrefs_ht_free, NULL);
318 if (!tmp) {
319 return false;
320 }
321 anal->dict_refs = tmp;
322
323 tmp = ht_up_new (NULL, xrefs_ht_free, NULL);
324 if (!tmp) {
325 ht_up_free (anal->dict_refs);
326 anal->dict_refs = NULL;
327 return false;
328 }
329 anal->dict_xrefs = tmp;
330 return true;
331 }
332
count_cb(void * user,const ut64 k,const void * v)333 static bool count_cb(void *user, const ut64 k, const void *v) {
334 (*(ut64 *)user) += ((HtUP *)v)->count;
335 return true;
336 }
337
r_anal_xrefs_count(RAnal * anal)338 R_API ut64 r_anal_xrefs_count(RAnal *anal) {
339 ut64 ret = 0;
340 ht_up_foreach (anal->dict_xrefs, count_cb, &ret);
341 return ret;
342 }
343
fcn_get_refs(RAnalFunction * fcn,HtUP * ht)344 static RList *fcn_get_refs(RAnalFunction *fcn, HtUP *ht) {
345 RListIter *iter;
346 RAnalBlock *bb;
347 RList *list = r_anal_ref_list_new ();
348 if (!list) {
349 return NULL;
350 }
351 r_list_foreach (fcn->bbs, iter, bb) {
352 int i;
353
354 for (i = 0; i < bb->ninstr; i++) {
355 ut64 at = bb->addr + r_anal_bb_offset_inst (bb, i);
356 listxrefs (ht, at, list);
357 }
358 }
359 sortxrefs (list);
360 return list;
361 }
362
r_anal_function_get_refs(RAnalFunction * fcn)363 R_API RList *r_anal_function_get_refs(RAnalFunction *fcn) {
364 r_return_val_if_fail (fcn, NULL);
365 return fcn_get_refs (fcn, fcn->anal->dict_refs);
366 }
367
r_anal_function_get_xrefs(RAnalFunction * fcn)368 R_API RList *r_anal_function_get_xrefs(RAnalFunction *fcn) {
369 r_return_val_if_fail (fcn, NULL);
370 return fcn_get_refs (fcn, fcn->anal->dict_xrefs);
371 }
372
r_anal_ref_type_tostring(RAnalRefType t)373 R_API const char *r_anal_ref_type_tostring(RAnalRefType t) {
374 switch (t) {
375 case R_ANAL_REF_TYPE_NULL:
376 return "null";
377 case R_ANAL_REF_TYPE_CODE:
378 return "code";
379 case R_ANAL_REF_TYPE_CALL:
380 return "call";
381 case R_ANAL_REF_TYPE_DATA:
382 return "data";
383 case R_ANAL_REF_TYPE_STRING:
384 return "string";
385 }
386 return "unknown";
387 }
388