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