1 /* radare - LGPL - Copyright 2018 - thestr4ng3r */
2 
3 #include <r_anal.h>
4 #include <r_vector.h>
5 #include <r_util/r_graph_drawable.h>
6 #include "../include/r_anal.h"
7 #include "../include/r_util/r_graph.h"
8 
9 static void r_anal_class_base_delete_class(RAnal *anal, const char *class_name);
10 static void r_anal_class_method_delete_class(RAnal *anal, const char *class_name);
11 static void r_anal_class_vtable_delete_class(RAnal *anal, const char *class_name);
12 static void r_anal_class_base_rename_class(RAnal *anal, const char *class_name_old, const char *class_name_new);
13 static void r_anal_class_method_rename_class(RAnal *anal, const char *old_class_name, const char *new_class_name);
14 static void r_anal_class_vtable_rename_class(RAnal *anal, const char *old_class_name, const char *new_class_name);
15 
key_class(const char * name)16 static const char *key_class(const char *name) {
17 	return name;
18 }
19 
key_attr_types(const char * name)20 static char *key_attr_types(const char *name) {
21 	return sdb_fmt ("attrtypes.%s", name);
22 }
23 
key_attr_type_attrs(const char * class_name,const char * attr_type)24 static char *key_attr_type_attrs(const char *class_name, const char *attr_type) {
25 	return sdb_fmt ("attr.%s.%s", class_name, attr_type);
26 }
27 
key_attr_content(const char * class_name,const char * attr_type,const char * attr_id)28 static char *key_attr_content(const char *class_name, const char *attr_type, const char *attr_id) {
29 	return sdb_fmt ("attr.%s.%s.%s", class_name, attr_type, attr_id);
30 }
31 
key_attr_content_specific(const char * class_name,const char * attr_type,const char * attr_id)32 static char *key_attr_content_specific(const char *class_name, const char *attr_type, const char *attr_id) {
33 	return sdb_fmt ("attr.%s.%s.%s.specific", class_name, attr_type, attr_id);
34 }
35 
36 typedef enum {
37 	R_ANAL_CLASS_ATTR_TYPE_METHOD,
38 	R_ANAL_CLASS_ATTR_TYPE_VTABLE,
39 	R_ANAL_CLASS_ATTR_TYPE_BASE
40 } RAnalClassAttrType;
41 
attr_type_id(RAnalClassAttrType attr_type)42 static const char *attr_type_id(RAnalClassAttrType attr_type) {
43 	switch (attr_type) {
44 	case R_ANAL_CLASS_ATTR_TYPE_METHOD:
45 		return "method";
46 	case R_ANAL_CLASS_ATTR_TYPE_VTABLE:
47 		return "vtable";
48 	case R_ANAL_CLASS_ATTR_TYPE_BASE:
49 		return "base";
50 	default:
51 		return NULL;
52 	}
53 }
54 
r_anal_class_create(RAnal * anal,const char * name)55 R_API void r_anal_class_create(RAnal *anal, const char *name) {
56 	char *name_sanitized = r_str_sanitize_sdb_key (name);
57 	if (!name_sanitized) {
58 		return;
59 	}
60 	const char *key = key_class (name_sanitized);
61 	if (!sdb_exists (anal->sdb_classes, key)) {
62 		sdb_set (anal->sdb_classes, key, "c", 0);
63 	}
64 
65 	REventClass event = { .name = name_sanitized };
66 	r_event_send (anal->ev, R_EVENT_CLASS_NEW, &event);
67 
68 	free (name_sanitized);
69 }
70 
71 
r_anal_class_delete(RAnal * anal,const char * name)72 R_API void r_anal_class_delete(RAnal *anal, const char *name) {
73 	char *class_name_sanitized = r_str_sanitize_sdb_key (name);
74 	if (!class_name_sanitized) {
75 		return;
76 	}
77 
78 	r_anal_class_base_delete_class (anal, class_name_sanitized);
79 	r_anal_class_method_delete_class (anal, class_name_sanitized);
80 	r_anal_class_vtable_delete_class (anal, class_name_sanitized);
81 
82 	if (!sdb_remove (anal->sdb_classes, key_class (class_name_sanitized), 0)) {
83 		free (class_name_sanitized);
84 		return;
85 	}
86 
87 	char *key = key_attr_types (class_name_sanitized);
88 	char *attr_type_array = sdb_get (anal->sdb_classes_attrs, key, 0);
89 
90 	char *attr_type;
91 	sdb_aforeach (attr_type, attr_type_array) {
92 		key = key_attr_type_attrs (class_name_sanitized, attr_type);
93 		char *attr_id_array = sdb_get (anal->sdb_classes_attrs, key, 0);
94 		sdb_remove (anal->sdb_classes_attrs, key, 0);
95 		if (attr_id_array) {
96 			char *attr_id;
97 			sdb_aforeach (attr_id, attr_id_array) {
98 				key = key_attr_content (class_name_sanitized, attr_type, attr_id);
99 				sdb_remove (anal->sdb_classes_attrs, key, 0);
100 				key = key_attr_content_specific (class_name_sanitized, attr_type, attr_id);
101 				sdb_remove (anal->sdb_classes_attrs, key, 0);
102 				sdb_aforeach_next (attr_id);
103 			}
104 			free (attr_id_array);
105 		}
106 		sdb_aforeach_next (attr_type);
107 	}
108 	free (attr_type_array);
109 
110 	sdb_remove (anal->sdb_classes_attrs, key_attr_types (class_name_sanitized), 0);
111 
112 	REventClass event = { .name = class_name_sanitized };
113 	r_event_send (anal->ev, R_EVENT_CLASS_DEL, &event);
114 
115 	free (class_name_sanitized);
116 }
117 
r_anal_class_exists_raw(RAnal * anal,const char * name)118 static bool r_anal_class_exists_raw(RAnal *anal, const char *name) {
119 	return sdb_exists (anal->sdb_classes, key_class (name));
120 }
121 
r_anal_class_exists(RAnal * anal,const char * name)122 R_API bool r_anal_class_exists(RAnal *anal, const char *name) {
123 	char *class_name_sanitized = r_str_sanitize_sdb_key (name);
124 	if (!class_name_sanitized) {
125 		return false;
126 	}
127 	bool r = r_anal_class_exists_raw (anal, class_name_sanitized);
128 	free (class_name_sanitized);
129 	return r;
130 }
131 
r_anal_class_get_all(RAnal * anal,bool sorted)132 R_API SdbList *r_anal_class_get_all(RAnal *anal, bool sorted) {
133 	return sdb_foreach_list (anal->sdb_classes, sorted);
134 }
135 
r_anal_class_foreach(RAnal * anal,SdbForeachCallback cb,void * user)136 R_API void r_anal_class_foreach(RAnal *anal, SdbForeachCallback cb, void *user) {
137 	sdb_foreach (anal->sdb_classes, cb, user);
138 }
139 
rename_key(Sdb * sdb,const char * key_old,const char * key_new)140 static bool rename_key(Sdb *sdb, const char *key_old, const char *key_new) {
141 	char *content = sdb_get (sdb, key_old, 0);
142 	if (!content) {
143 		return false;
144 	}
145 	sdb_remove (sdb, key_old, 0);
146 	sdb_set (sdb, key_new, content, 0);
147 	free (content);
148 	return true;
149 }
150 
r_anal_class_rename(RAnal * anal,const char * old_name,const char * new_name)151 R_API RAnalClassErr r_anal_class_rename(RAnal *anal, const char *old_name, const char *new_name) {
152 	if (r_anal_class_exists (anal, new_name)) {
153 		return R_ANAL_CLASS_ERR_CLASH;
154 	}
155 
156 	char *old_name_sanitized = r_str_sanitize_sdb_key (old_name);
157 	if (!old_name_sanitized) {
158 		return R_ANAL_CLASS_ERR_OTHER;
159 	}
160 	char *new_name_sanitized = r_str_sanitize_sdb_key (new_name);
161 	if (!new_name_sanitized) {
162 		free (old_name_sanitized);
163 		return R_ANAL_CLASS_ERR_OTHER;
164 	}
165 
166 	RAnalClassErr err = R_ANAL_CLASS_ERR_SUCCESS;
167 
168 	r_anal_class_base_rename_class (anal, old_name, new_name);
169 	r_anal_class_method_rename_class (anal, old_name, new_name);
170 	r_anal_class_vtable_rename_class (anal, old_name, new_name);
171 
172 	if (!rename_key (anal->sdb_classes, key_class (old_name_sanitized), key_class (new_name_sanitized))) {
173 		err = R_ANAL_CLASS_ERR_NONEXISTENT_CLASS;
174 		goto beach;
175 	}
176 
177 	char *attr_types = sdb_get (anal->sdb_classes_attrs, key_attr_types (old_name_sanitized), 0);
178 	char *attr_type_cur;
179 	sdb_aforeach (attr_type_cur, attr_types) {
180 		char *attr_ids = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (old_name, attr_type_cur), 0);
181 		char *attr_id_cur;
182 		sdb_aforeach (attr_id_cur, attr_ids) {
183 			rename_key (anal->sdb_classes_attrs,
184 					key_attr_content (old_name, attr_type_cur, attr_id_cur),
185 					key_attr_content (new_name, attr_type_cur, attr_id_cur));
186 			sdb_aforeach_next (attr_id_cur);
187 		}
188 		free (attr_ids);
189 		rename_key (anal->sdb_classes_attrs,
190 				key_attr_type_attrs (old_name, attr_type_cur),
191 				key_attr_type_attrs (new_name, attr_type_cur));
192 		sdb_aforeach_next (attr_type_cur);
193 	}
194 	free (attr_types);
195 
196 	rename_key (anal->sdb_classes_attrs, key_attr_types (old_name_sanitized), key_attr_types (new_name_sanitized));
197 
198 	REventClassRename event = {
199 		.name_old = old_name_sanitized,
200 		.name_new = new_name_sanitized
201 	};
202 	r_event_send (anal->ev, R_EVENT_CLASS_RENAME, &event);
203 
204 beach:
205 	free (old_name_sanitized);
206 	free (new_name_sanitized);
207 	return err;
208 }
209 
210 // all ids must be sanitized
r_anal_class_get_attr_raw(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id,bool specific)211 static char *r_anal_class_get_attr_raw(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id, bool specific) {
212 	const char *attr_type_str = attr_type_id (attr_type);
213 	char *key = specific
214 			? key_attr_content_specific (class_name, attr_type_str, attr_id)
215 			: key_attr_content (class_name, attr_type_str, attr_id);
216 	char *ret = sdb_get (anal->sdb_classes_attrs, key, 0);
217 	return ret;
218 }
219 
220 // ids will be sanitized automatically
r_anal_class_get_attr(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id,bool specific)221 static char *r_anal_class_get_attr(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id, bool specific) {
222 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
223 	if (!class_name_sanitized) {
224 		return false;
225 	}
226 	char *attr_id_sanitized = r_str_sanitize_sdb_key (attr_id);
227 	if (!attr_id_sanitized) {
228 		free (class_name_sanitized);
229 		return false;
230 	}
231 
232 	char *ret = r_anal_class_get_attr_raw (anal, class_name_sanitized, attr_type, attr_id_sanitized, specific);
233 
234 	free (class_name_sanitized);
235 	free (attr_id_sanitized);
236 
237 	return ret;
238 }
239 
240 // all ids must be sanitized
r_anal_class_set_attr_raw(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id,const char * content)241 static RAnalClassErr r_anal_class_set_attr_raw(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id, const char *content) {
242 	const char *attr_type_str = attr_type_id (attr_type);
243 
244 	if (!r_anal_class_exists_raw (anal, class_name)) {
245 		return R_ANAL_CLASS_ERR_NONEXISTENT_CLASS;
246 	}
247 
248 	sdb_array_add (anal->sdb_classes_attrs, key_attr_types (class_name), attr_type_str, 0);
249 	sdb_array_add (anal->sdb_classes_attrs, key_attr_type_attrs (class_name, attr_type_str), attr_id, 0);
250 	sdb_set (anal->sdb_classes_attrs, key_attr_content (class_name, attr_type_str, attr_id), content, 0);
251 
252 	REventClassAttrSet event = {
253 		.attr = {
254 			.class_name = class_name,
255 			.attr_type = attr_type,
256 			.attr_id = attr_id
257 		},
258 		.content = content
259 	};
260 	r_event_send (anal->ev, R_EVENT_CLASS_ATTR_SET, &event);
261 
262 	return R_ANAL_CLASS_ERR_SUCCESS;
263 }
264 
265 // ids will be sanitized automatically
r_anal_class_set_attr(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id,const char * content)266 static RAnalClassErr r_anal_class_set_attr(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id, const char *content) {
267 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
268 	if (!class_name_sanitized) {
269 		return R_ANAL_CLASS_ERR_OTHER;
270 	}
271 
272 	char *attr_id_sanitized = r_str_sanitize_sdb_key (attr_id);
273 	if (!attr_id_sanitized) {
274 		free (class_name_sanitized);
275 		return R_ANAL_CLASS_ERR_OTHER;
276 	}
277 
278 	RAnalClassErr err = r_anal_class_set_attr_raw (anal, class_name_sanitized, attr_type, attr_id_sanitized, content);
279 
280 	free (class_name_sanitized);
281 	free (attr_id_sanitized);
282 
283 	return err;
284 }
285 
r_anal_class_delete_attr_raw(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id)286 static RAnalClassErr r_anal_class_delete_attr_raw(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id) {
287 	const char *attr_type_str = attr_type_id (attr_type);
288 
289 	char *key = key_attr_content (class_name, attr_type_str, attr_id);
290 	sdb_remove (anal->sdb_classes_attrs, key, 0);
291 	key = key_attr_content_specific (class_name, attr_type_str, attr_id);
292 	sdb_remove (anal->sdb_classes_attrs, key, 0);
293 
294 	key = key_attr_type_attrs (class_name, attr_type_str);
295 	sdb_array_remove (anal->sdb_classes_attrs, key, attr_id, 0);
296 	if (!sdb_exists (anal->sdb_classes_attrs, key)) {
297 		sdb_array_remove (anal->sdb_classes_attrs, key_attr_types (class_name), attr_type_str, 0);
298 	}
299 
300 	REventClassAttr event = {
301 		.class_name = class_name,
302 		.attr_type = attr_type,
303 		.attr_id = attr_id
304 	};
305 	r_event_send (anal->ev, R_EVENT_CLASS_ATTR_DEL, &event);
306 
307 	return R_ANAL_CLASS_ERR_SUCCESS;
308 }
309 
r_anal_class_delete_attr(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id)310 static RAnalClassErr r_anal_class_delete_attr(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id) {
311 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
312 	if (!class_name_sanitized) {
313 		return R_ANAL_CLASS_ERR_OTHER;
314 	}
315 
316 	char *attr_id_sanitized = r_str_sanitize_sdb_key (attr_id);
317 	if (!attr_id_sanitized) {
318 		free (class_name_sanitized);
319 		return R_ANAL_CLASS_ERR_OTHER;
320 	}
321 
322 	RAnalClassErr err = r_anal_class_delete_attr_raw (anal, class_name_sanitized, attr_type, attr_id_sanitized);
323 
324 	free (class_name_sanitized);
325 	free (attr_id_sanitized);
326 	return err;
327 }
328 
r_anal_class_rename_attr_raw(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id_old,const char * attr_id_new)329 static RAnalClassErr r_anal_class_rename_attr_raw(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id_old, const char *attr_id_new) {
330 	const char *attr_type_str = attr_type_id (attr_type);
331 	char *key = key_attr_type_attrs (class_name, attr_type_str);
332 
333 	if (sdb_array_contains (anal->sdb_classes_attrs, key, attr_id_new, 0)) {
334 		return R_ANAL_CLASS_ERR_CLASH;
335 	}
336 
337 	if (!sdb_array_remove (anal->sdb_classes_attrs, key, attr_id_old, 0)) {
338 		return R_ANAL_CLASS_ERR_NONEXISTENT_ATTR;
339 	}
340 
341 	sdb_array_add (anal->sdb_classes_attrs, key, attr_id_new, 0);
342 
343 	key = key_attr_content (class_name, attr_type_str, attr_id_old);
344 	char *content = sdb_get (anal->sdb_classes_attrs, key, 0);
345 	if (content) {
346 		sdb_remove (anal->sdb_classes_attrs, key, 0);
347 		key = key_attr_content (class_name, attr_type_str, attr_id_new);
348 		sdb_set (anal->sdb_classes_attrs, key, content, 0);
349 		free (content);
350 	}
351 
352 	key = key_attr_content_specific (class_name, attr_type_str, attr_id_old);
353 	content = sdb_get (anal->sdb_classes_attrs, key, 0);
354 	if (content) {
355 		sdb_remove (anal->sdb_classes_attrs, key, 0);
356 		key = key_attr_content_specific (class_name, attr_type_str, attr_id_new);
357 		sdb_set (anal->sdb_classes_attrs, key, content, 0);
358 		free (content);
359 	}
360 
361 	REventClassAttrRename event = {
362 		.attr = {
363 			.class_name = class_name,
364 			.attr_type = attr_type,
365 			.attr_id = attr_id_old
366 		},
367 		.attr_id_new = attr_id_new
368 	};
369 	r_event_send (anal->ev, R_EVENT_CLASS_ATTR_RENAME, &event);
370 
371 	return R_ANAL_CLASS_ERR_SUCCESS;
372 }
373 
r_anal_class_rename_attr(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * attr_id_old,const char * attr_id_new)374 static RAnalClassErr r_anal_class_rename_attr(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *attr_id_old, const char *attr_id_new) {
375 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
376 	if (!class_name_sanitized) {
377 		return R_ANAL_CLASS_ERR_OTHER;
378 	}
379 	char *attr_id_old_sanitized = r_str_sanitize_sdb_key (attr_id_old);
380 	if (!attr_id_old_sanitized) {
381 		free (class_name_sanitized);
382 		return R_ANAL_CLASS_ERR_OTHER;
383 	}
384 	char *attr_id_new_sanitized = r_str_sanitize_sdb_key (attr_id_new);
385 	if (!attr_id_new_sanitized) {
386 		free (class_name_sanitized);
387 		free (attr_id_old_sanitized);
388 		return R_ANAL_CLASS_ERR_OTHER;
389 	}
390 	RAnalClassErr ret = r_anal_class_rename_attr_raw (anal, class_name_sanitized, attr_type, attr_id_old_sanitized, attr_id_new_sanitized);
391 	free (class_name_sanitized);
392 	free (attr_id_old_sanitized);
393 	free (attr_id_new_sanitized);
394 	return ret;
395 }
396 
r_anal_class_unique_attr_id_raw(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,char * out,size_t out_size)397 static void r_anal_class_unique_attr_id_raw(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, char *out, size_t out_size) {
398 	ut64 id = 0;
399 	char *key = key_attr_type_attrs (class_name, attr_type_id (attr_type));
400 	do {
401 		snprintf (out, out_size, "%"PFMT64u, id);
402 		id++;
403 	} while (sdb_array_contains (anal->sdb_classes_attrs, key, out, 0));
404 }
405 
flagname_attr(const char * attr_type,const char * class_name,const char * attr_id)406 static char *flagname_attr(const char *attr_type, const char *class_name, const char *attr_id) {
407 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
408 	if (!class_name_sanitized) {
409 		return NULL;
410 	}
411 	char *attr_id_sanitized = r_str_sanitize_sdb_key (attr_id);
412 	if (!attr_id_sanitized) {
413 		free (class_name_sanitized);
414 		return NULL;
415 	}
416 	char *r = sdb_fmt ("%s.%s.%s", attr_type, class_name, attr_id);
417 	free (class_name_sanitized);
418 	free (attr_id_sanitized);
419 	return r;
420 }
421 
r_anal_class_set_flag(RAnal * anal,const char * name,ut64 addr,ut32 size)422 static void r_anal_class_set_flag(RAnal *anal, const char *name, ut64 addr, ut32 size) {
423 	if (!name || !anal->flg_class_set) {
424 		return;
425 	}
426 	anal->flg_class_set (anal->flb.f, name, addr, size);
427 }
428 
r_anal_class_unset_flag(RAnal * anal,const char * name)429 static void r_anal_class_unset_flag(RAnal *anal, const char *name) {
430 	if (!name || !anal->flb.unset_name || !anal->flg_class_get) {
431 		return;
432 	}
433 	if (anal->flg_class_get (anal->flb.f, name)) {
434 		anal->flb.unset_name (anal->flb.f, name);
435 	}
436 }
437 
r_anal_class_rename_flag(RAnal * anal,const char * old_name,const char * new_name)438 static void r_anal_class_rename_flag(RAnal *anal, const char *old_name, const char *new_name) {
439 	if (!old_name || !new_name || !anal->flb.unset || !anal->flg_class_get || !anal->flg_class_set) {
440 		return;
441 	}
442 	RFlagItem *flag = anal->flg_class_get (anal->flb.f, old_name);
443 	if (!flag) {
444 		return;
445 	}
446 	ut64 addr = flag->offset;
447 	anal->flb.unset (anal->flb.f, flag);
448 	anal->flg_class_set (anal->flb.f, new_name, addr, 0);
449 }
450 
r_anal_class_add_attr_unique_raw(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * content,char * attr_id_out,size_t attr_id_out_size)451 static RAnalClassErr r_anal_class_add_attr_unique_raw(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *content, char *attr_id_out, size_t attr_id_out_size) {
452 	char attr_id[16];
453 	r_anal_class_unique_attr_id_raw (anal, class_name, attr_type, attr_id, sizeof(attr_id));
454 
455 	RAnalClassErr err = r_anal_class_set_attr (anal, class_name, attr_type, attr_id, content);
456 	if (err != R_ANAL_CLASS_ERR_SUCCESS) {
457 		return err;
458 	}
459 
460 	if (attr_id_out) {
461 		r_str_ncpy (attr_id_out, attr_id, attr_id_out_size);
462 	}
463 
464 	return R_ANAL_CLASS_ERR_SUCCESS;
465 }
466 
r_anal_class_add_attr_unique(RAnal * anal,const char * class_name,RAnalClassAttrType attr_type,const char * content,char * attr_id_out,size_t attr_id_out_size)467 static RAnalClassErr r_anal_class_add_attr_unique(RAnal *anal, const char *class_name, RAnalClassAttrType attr_type, const char *content, char *attr_id_out, size_t attr_id_out_size) {
468 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
469 	if (!class_name_sanitized) {
470 		return R_ANAL_CLASS_ERR_OTHER;
471 	}
472 
473 	RAnalClassErr err = r_anal_class_add_attr_unique_raw (anal, class_name_sanitized, attr_type, content, attr_id_out, attr_id_out_size);
474 
475 	free (class_name_sanitized);
476 	return err;
477 }
478 
479 
480 // ---- METHODS ----
481 // Format: addr,vtable_offset
482 
flagname_method(const char * class_name,const char * meth_name)483 static char *flagname_method(const char *class_name, const char *meth_name) {
484 	return flagname_attr ("method", class_name, meth_name);
485 }
486 
r_anal_class_method_fini(RAnalMethod * meth)487 R_API void r_anal_class_method_fini(RAnalMethod *meth) {
488 	free (meth->name);
489 }
490 
491 // if the method exists: store it in *meth and return R_ANAL_CLASS_ERR_SUCCESS
492 // else return the error, contents of *meth are undefined
r_anal_class_method_get(RAnal * anal,const char * class_name,const char * meth_name,RAnalMethod * meth)493 R_API RAnalClassErr r_anal_class_method_get(RAnal *anal, const char *class_name, const char *meth_name, RAnalMethod *meth) {
494 	char *content = r_anal_class_get_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_METHOD, meth_name, false);
495 	if (!content) {
496 		return R_ANAL_CLASS_ERR_NONEXISTENT_ATTR;
497 	}
498 
499 	char *cur = content;
500 	char *next;
501 	sdb_anext (cur, &next);
502 
503 	meth->addr = r_num_math (NULL, cur);
504 
505 	cur = next;
506 	if (!cur) {
507 		free (content);
508 		return R_ANAL_CLASS_ERR_OTHER;
509 	}
510 	sdb_anext (cur, NULL);
511 
512 	meth->vtable_offset = atoll (cur);
513 
514 	free (content);
515 
516 	meth->name = r_str_sanitize_sdb_key (meth_name);
517 	if (!meth->name) {
518 		return R_ANAL_CLASS_ERR_OTHER;
519 	}
520 
521 	return R_ANAL_CLASS_ERR_SUCCESS;
522 }
523 
r_anal_class_method_fini_proxy(void * e,void * user)524 static void r_anal_class_method_fini_proxy(void *e, void *user) {
525 	(void)user;
526 	RAnalMethod *meth = e;
527 	r_anal_class_method_fini (meth);
528 }
529 
r_anal_class_method_get_all(RAnal * anal,const char * class_name)530 R_API RVector/*<RAnalMethod>*/ *r_anal_class_method_get_all(RAnal *anal, const char *class_name) {
531 	RVector *vec = r_vector_new (sizeof(RAnalMethod), r_anal_class_method_fini_proxy, NULL);
532 	if (!vec) {
533 		return NULL;
534 	}
535 
536 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
537 	if (!class_name_sanitized) {
538 		r_vector_free (vec);
539 		return NULL;
540 	}
541 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (class_name_sanitized, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_METHOD)), 0);
542 	free (class_name_sanitized);
543 
544 	r_vector_reserve (vec, (size_t) sdb_alen (array));
545 	char *cur;
546 	sdb_aforeach (cur, array) {
547 		RAnalMethod meth;
548 		if (r_anal_class_method_get (anal, class_name, cur, &meth) == R_ANAL_CLASS_ERR_SUCCESS) {
549 			r_vector_push (vec, &meth);
550 		}
551 		sdb_aforeach_next (cur);
552 	}
553 	free (array);
554 
555 	return vec;
556 }
557 
r_anal_class_method_set(RAnal * anal,const char * class_name,RAnalMethod * meth)558 R_API RAnalClassErr r_anal_class_method_set(RAnal *anal, const char *class_name, RAnalMethod *meth) {
559 	char *content = sdb_fmt ("%"PFMT64u"%c%"PFMT64d, meth->addr, SDB_RS, meth->vtable_offset);
560 	RAnalClassErr err = r_anal_class_set_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_METHOD, meth->name, content);
561 	if (err != R_ANAL_CLASS_ERR_SUCCESS) {
562 		return err;
563 	}
564 	r_anal_class_set_flag (anal, flagname_method (class_name, meth->name), meth->addr, 0);
565 	return R_ANAL_CLASS_ERR_SUCCESS;
566 }
567 
r_anal_class_method_rename(RAnal * anal,const char * class_name,const char * old_meth_name,const char * new_meth_name)568 R_API RAnalClassErr r_anal_class_method_rename(RAnal *anal, const char *class_name, const char *old_meth_name, const char *new_meth_name) {
569 	RAnalClassErr err = r_anal_class_rename_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_METHOD, old_meth_name, new_meth_name);
570 	if (err != R_ANAL_CLASS_ERR_SUCCESS) {
571 		return err;
572 	}
573 	r_anal_class_rename_flag (anal,
574 			flagname_method (class_name, old_meth_name),
575 			flagname_method (class_name, new_meth_name));
576 	return R_ANAL_CLASS_ERR_SUCCESS;
577 }
578 
r_anal_class_method_rename_class(RAnal * anal,const char * old_class_name,const char * new_class_name)579 static void r_anal_class_method_rename_class(RAnal *anal, const char *old_class_name, const char *new_class_name) {
580 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (old_class_name, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_METHOD)), 0);
581 	if (!array) {
582 		return;
583 	}
584 	char *cur;
585 	sdb_aforeach (cur, array) {
586 		r_anal_class_rename_flag (anal,
587 				flagname_method (old_class_name, cur),
588 				flagname_method (new_class_name, cur));
589 		sdb_aforeach_next (cur);
590 	}
591 	free (array);
592 }
593 
r_anal_class_method_delete_class(RAnal * anal,const char * class_name)594 static void r_anal_class_method_delete_class(RAnal *anal, const char *class_name) {
595 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (class_name, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_METHOD)), 0);
596 	if (!array) {
597 		return;
598 	}
599 	char *cur;
600 	sdb_aforeach (cur, array) {
601 		r_anal_class_unset_flag (anal, flagname_method (class_name, cur));
602 		sdb_aforeach_next (cur);
603 	}
604 	free (array);
605 }
606 
r_anal_class_method_delete(RAnal * anal,const char * class_name,const char * meth_name)607 R_API RAnalClassErr r_anal_class_method_delete(RAnal *anal, const char *class_name, const char *meth_name) {
608 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
609 	if (!class_name_sanitized) {
610 		return R_ANAL_CLASS_ERR_OTHER;
611 	}
612 	char *meth_name_sanitized = r_str_sanitize_sdb_key (meth_name);
613 	if (!meth_name_sanitized) {
614 		free (class_name_sanitized);
615 		return R_ANAL_CLASS_ERR_OTHER;
616 	}
617 	RAnalClassErr err = r_anal_class_delete_attr_raw (anal, class_name_sanitized, R_ANAL_CLASS_ATTR_TYPE_METHOD, meth_name_sanitized);
618 	if (err == R_ANAL_CLASS_ERR_SUCCESS) {
619 		r_anal_class_unset_flag (anal, flagname_method (class_name_sanitized, meth_name_sanitized));
620 	}
621 	free (class_name_sanitized);
622 	free (meth_name_sanitized);
623 	return err;
624 }
625 
626 
627 // ---- BASE ----
628 
r_anal_class_base_fini(RAnalBaseClass * base)629 R_API void r_anal_class_base_fini(RAnalBaseClass *base) {
630 	free (base->id);
631 	free (base->class_name);
632 }
633 
r_anal_class_base_get(RAnal * anal,const char * class_name,const char * base_id,RAnalBaseClass * base)634 R_API RAnalClassErr r_anal_class_base_get(RAnal *anal, const char *class_name, const char *base_id, RAnalBaseClass *base) {
635 	char *content = r_anal_class_get_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_BASE, base_id, false);
636 	if (!content) {
637 		return R_ANAL_CLASS_ERR_NONEXISTENT_ATTR;
638 	}
639 
640 	char *cur = content;
641 	char *next;
642 	sdb_anext (cur, &next);
643 
644 	base->class_name = strdup (cur);
645 	if (!base->class_name) {
646 		free (content);
647 		return R_ANAL_CLASS_ERR_OTHER;
648 	}
649 
650 	cur = next;
651 	if (!cur) {
652 		free (content);
653 		free (base->class_name);
654 		return R_ANAL_CLASS_ERR_OTHER;
655 	}
656 	sdb_anext (cur, NULL);
657 
658 	base->offset = r_num_math (NULL, cur);
659 
660 	free (content);
661 
662 	base->id = r_str_sanitize_sdb_key (base_id);
663 	if (!base->id) {
664 		free (base->class_name);
665 		return R_ANAL_CLASS_ERR_OTHER;
666 	}
667 
668 	return R_ANAL_CLASS_ERR_SUCCESS;
669 }
670 
r_anal_class_base_fini_proxy(void * e,void * user)671 static void r_anal_class_base_fini_proxy(void *e, void *user) {
672 	(void)user;
673 	RAnalBaseClass *base = e;
674 	r_anal_class_base_fini (base);
675 }
676 
r_anal_class_base_get_all(RAnal * anal,const char * class_name)677 R_API RVector/*<RAnalBaseClass>*/ *r_anal_class_base_get_all(RAnal *anal, const char *class_name) {
678 	RVector *vec = r_vector_new (sizeof(RAnalBaseClass), r_anal_class_base_fini_proxy, NULL);
679 	if (!vec) {
680 		return NULL;
681 	}
682 
683 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
684 	if (!class_name_sanitized) {
685 		r_vector_free (vec);
686 		return NULL;
687 	}
688 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (class_name_sanitized, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_BASE)), 0);
689 	free (class_name_sanitized);
690 
691 	r_vector_reserve (vec, (size_t) sdb_alen (array));
692 	char *cur;
693 	sdb_aforeach (cur, array) {
694 		RAnalBaseClass base;
695 		if (r_anal_class_base_get (anal, class_name, cur, &base) == R_ANAL_CLASS_ERR_SUCCESS) {
696 			r_vector_push (vec, &base);
697 		}
698 		sdb_aforeach_next (cur);
699 	}
700 	free (array);
701 
702 	return vec;
703 }
704 
r_anal_class_base_set_raw(RAnal * anal,const char * class_name,RAnalBaseClass * base,const char * base_class_name_sanitized)705 static RAnalClassErr r_anal_class_base_set_raw(RAnal *anal, const char *class_name, RAnalBaseClass *base, const char *base_class_name_sanitized) {
706 	char *content = sdb_fmt ("%s" SDB_SS "%"PFMT64u, base_class_name_sanitized, base->offset);
707 	RAnalClassErr err;
708 	if (base->id) {
709 		err = r_anal_class_set_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_BASE, base->id, content);
710 	} else {
711 		base->id = malloc(16);
712 		if (base->id) {
713 			err = r_anal_class_add_attr_unique (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_BASE, content, base->id, 16);
714 		} else {
715 			err = R_ANAL_CLASS_ERR_OTHER;
716 		}
717 	}
718 	return err;
719 }
720 
r_anal_class_base_set(RAnal * anal,const char * class_name,RAnalBaseClass * base)721 R_API RAnalClassErr r_anal_class_base_set(RAnal *anal, const char *class_name, RAnalBaseClass *base) {
722 	char *base_class_name_sanitized = r_str_sanitize_sdb_key (base->class_name);
723 	if (!base_class_name_sanitized) {
724 		return R_ANAL_CLASS_ERR_OTHER;
725 	}
726 
727 	if (!r_anal_class_exists_raw (anal, base_class_name_sanitized)) {
728 		free (base_class_name_sanitized);
729 		return R_ANAL_CLASS_ERR_NONEXISTENT_CLASS;
730 	}
731 	RVector /*<RAnalBaseClass>*/ *bases = r_anal_class_base_get_all (anal, class_name);
732 	if (bases) {
733 		RAnalBaseClass *existing_base;
734 		r_vector_foreach (bases, existing_base) {
735 			if (!strcmp (existing_base->class_name, base->class_name)) {
736 				free (base_class_name_sanitized);
737 				r_vector_free (bases);
738 				return R_ANAL_CLASS_ERR_OTHER;
739 			}
740 		}
741 	}
742 	RAnalClassErr err = r_anal_class_base_set_raw (anal, class_name, base, base_class_name_sanitized);
743 	free (base_class_name_sanitized);
744 	r_vector_free (bases);
745 	return err;
746 }
747 
r_anal_class_base_delete(RAnal * anal,const char * class_name,const char * base_id)748 R_API RAnalClassErr r_anal_class_base_delete(RAnal *anal, const char *class_name, const char *base_id) {
749 	return r_anal_class_delete_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_BASE, base_id);
750 }
751 
752 typedef struct {
753 	RAnal *anal;
754 	const char *class_name;
755 } DeleteClassCtx;
756 
r_anal_class_base_delete_class_cb(void * user,const char * k,const char * v)757 static bool r_anal_class_base_delete_class_cb(void *user, const char *k, const char *v) {
758 	(void)v;
759 	DeleteClassCtx *ctx = user;
760 	RVector *bases = r_anal_class_base_get_all (ctx->anal, k);
761 	RAnalBaseClass *base;
762 	r_vector_foreach (bases, base) {
763 		if (base->class_name && strcmp (base->class_name, ctx->class_name) == 0) {
764 			r_anal_class_base_delete (ctx->anal, k, base->id);
765 		}
766 	}
767 	r_vector_free (bases);
768 	return true;
769 }
770 
r_anal_class_base_delete_class(RAnal * anal,const char * class_name)771 static void r_anal_class_base_delete_class(RAnal *anal, const char *class_name) {
772 	DeleteClassCtx ctx = { anal, class_name };
773 	r_anal_class_foreach (anal, r_anal_class_base_delete_class_cb, &ctx);
774 }
775 
776 typedef struct {
777 	RAnal *anal;
778 	const char *class_name_old;
779 	const char *class_name_new;
780 } RenameClassCtx;
781 
r_anal_class_base_rename_class_cb(void * user,const char * k,const char * v)782 static bool r_anal_class_base_rename_class_cb(void *user, const char *k, const char *v) {
783 	(void)v;
784 	RenameClassCtx *ctx = user;
785 	RVector *bases = r_anal_class_base_get_all (ctx->anal, k);
786 	RAnalBaseClass *base;
787 	r_vector_foreach (bases, base) {
788 		if (base->class_name && strcmp (base->class_name, ctx->class_name_old) == 0) {
789 			r_anal_class_base_set_raw (ctx->anal, k, base, ctx->class_name_new);
790 		}
791 	}
792 	r_vector_free (bases);
793 	return 1;
794 }
795 
r_anal_class_base_rename_class(RAnal * anal,const char * class_name_old,const char * class_name_new)796 static void r_anal_class_base_rename_class(RAnal *anal, const char *class_name_old, const char *class_name_new) {
797 	RenameClassCtx ctx = { anal, class_name_old, class_name_new };
798 	r_anal_class_foreach (anal, r_anal_class_base_rename_class_cb, &ctx);
799 }
800 
801 // ---- VTABLE ----
802 
flagname_vtable(const char * class_name,const char * vtable_id)803 static char *flagname_vtable(const char *class_name, const char *vtable_id) {
804 	return flagname_attr ("vtable", class_name, vtable_id);
805 }
806 
r_anal_class_vtable_fini(RAnalVTable * vtable)807 R_API void r_anal_class_vtable_fini(RAnalVTable *vtable) {
808 	free (vtable->id);
809 }
810 
r_anal_class_vtable_get(RAnal * anal,const char * class_name,const char * vtable_id,RAnalVTable * vtable)811 R_API RAnalClassErr r_anal_class_vtable_get(RAnal *anal, const char *class_name, const char *vtable_id, RAnalVTable *vtable) {
812 	char *content = r_anal_class_get_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_VTABLE, vtable_id, false);
813 	if (!content) {
814 		return R_ANAL_CLASS_ERR_NONEXISTENT_ATTR;
815 	}
816 
817 	char *cur = content;
818 	char *next;
819 	sdb_anext (cur, &next);
820 
821 	vtable->addr = r_num_math (NULL, cur);
822 
823 	cur = next;
824 	if (!cur) {
825 		free (content);
826 		return R_ANAL_CLASS_ERR_OTHER;
827 	}
828 	sdb_anext (cur, &next);
829 
830 	vtable->offset = r_num_math (NULL, cur);
831 
832 	if (next) {
833 		cur = next;
834 		sdb_anext (cur, NULL);
835 		vtable->size = r_num_get (NULL, cur);
836 	} else {
837 		vtable->size = 0;
838 	}
839 
840 	free (content);
841 
842 	vtable->id = r_str_sanitize_sdb_key (vtable_id);
843 	if (!vtable->id) {
844 		return R_ANAL_CLASS_ERR_OTHER;
845 	}
846 
847 	return R_ANAL_CLASS_ERR_SUCCESS;
848 }
849 
r_anal_class_vtable_fini_proxy(void * e,void * user)850 static void r_anal_class_vtable_fini_proxy(void *e, void *user) {
851 	(void)user;
852 	RAnalVTable *vtable = e;
853 	r_anal_class_vtable_fini (vtable);
854 }
855 
r_anal_class_vtable_get_all(RAnal * anal,const char * class_name)856 R_API RVector/*<RAnalVTable>*/ *r_anal_class_vtable_get_all(RAnal *anal, const char *class_name) {
857 	RVector *vec = r_vector_new (sizeof(RAnalVTable), r_anal_class_vtable_fini_proxy, NULL);
858 	if (!vec) {
859 		return NULL;
860 	}
861 
862 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
863 	if (!class_name_sanitized) {
864 		r_vector_free (vec);
865 		return NULL;
866 	}
867 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (class_name_sanitized, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_VTABLE)), 0);
868 	free (class_name_sanitized);
869 
870 	r_vector_reserve (vec, (size_t) sdb_alen (array));
871 	char *cur;
872 	sdb_aforeach (cur, array) {
873 		RAnalVTable vtable;
874 		if (r_anal_class_vtable_get (anal, class_name, cur, &vtable) == R_ANAL_CLASS_ERR_SUCCESS) {
875 			r_vector_push (vec, &vtable);
876 		}
877 		sdb_aforeach_next (cur);
878 	}
879 	free (array);
880 
881 	return vec;
882 }
883 
r_anal_class_vtable_set(RAnal * anal,const char * class_name,RAnalVTable * vtable)884 R_API RAnalClassErr r_anal_class_vtable_set(RAnal *anal, const char *class_name, RAnalVTable *vtable) {
885 	char *content = sdb_fmt ("0x%"PFMT64x SDB_SS "%"PFMT64u SDB_SS "%"PFMT64u, vtable->addr, vtable->offset, vtable->size);
886 	if (vtable->id) {
887 		return r_anal_class_set_attr (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_VTABLE, vtable->id, content);
888 	}
889 	vtable->id = malloc(16);
890 	if (!vtable->id) {
891 		return R_ANAL_CLASS_ERR_OTHER;
892 	}
893 	RAnalClassErr err = r_anal_class_add_attr_unique (anal, class_name, R_ANAL_CLASS_ATTR_TYPE_VTABLE, content, vtable->id, 16);
894 	if (err != R_ANAL_CLASS_ERR_SUCCESS) {
895 		return err;
896 	}
897 
898 	r_anal_class_set_flag (anal, flagname_vtable (class_name, vtable->id), vtable->addr, vtable->size);
899 
900 	return R_ANAL_CLASS_ERR_SUCCESS;
901 }
902 
r_anal_class_vtable_rename_class(RAnal * anal,const char * old_class_name,const char * new_class_name)903 static void r_anal_class_vtable_rename_class(RAnal *anal, const char *old_class_name, const char *new_class_name) {
904 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (old_class_name, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_VTABLE)), 0);
905 	if (!array) {
906 		return;
907 	}
908 	char *cur;
909 	sdb_aforeach (cur, array) {
910 		r_anal_class_rename_flag (anal,
911 				flagname_vtable (old_class_name, cur),
912 				flagname_vtable (new_class_name, cur));
913 		sdb_aforeach_next (cur);
914 	}
915 	free (array);
916 }
917 
r_anal_class_vtable_delete_class(RAnal * anal,const char * class_name)918 static void r_anal_class_vtable_delete_class(RAnal *anal, const char *class_name) {
919 	char *array = sdb_get (anal->sdb_classes_attrs, key_attr_type_attrs (class_name, attr_type_id (R_ANAL_CLASS_ATTR_TYPE_VTABLE)), 0);
920 	if (!array) {
921 		return;
922 	}
923 	char *cur;
924 	sdb_aforeach (cur, array) {
925 		r_anal_class_unset_flag (anal, flagname_vtable (class_name, cur));
926 		sdb_aforeach_next (cur);
927 	}
928 	free (array);
929 }
930 
r_anal_class_vtable_delete(RAnal * anal,const char * class_name,const char * vtable_id)931 R_API RAnalClassErr r_anal_class_vtable_delete(RAnal *anal, const char *class_name, const char *vtable_id) {
932 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
933 	if (!class_name_sanitized) {
934 		return R_ANAL_CLASS_ERR_OTHER;
935 	}
936 	char *vtable_id_sanitized = r_str_sanitize_sdb_key (vtable_id);
937 	if (!vtable_id_sanitized) {
938 		free (class_name_sanitized);
939 		return R_ANAL_CLASS_ERR_OTHER;
940 	}
941 	RAnalClassErr err = r_anal_class_delete_attr_raw (anal, class_name_sanitized, R_ANAL_CLASS_ATTR_TYPE_VTABLE, vtable_id_sanitized);
942 	if (err == R_ANAL_CLASS_ERR_SUCCESS) {
943 		r_anal_class_unset_flag (anal, flagname_vtable (class_name_sanitized, vtable_id_sanitized));
944 	}
945 	free (class_name_sanitized);
946 	free (vtable_id_sanitized);
947 	return err;
948 }
949 
950 
951 // ---- PRINT ----
952 
953 
r_anal_class_print(RAnal * anal,const char * class_name,bool detailed)954 R_API void r_anal_class_print(RAnal *anal, const char *class_name, bool detailed) {
955 	r_cons_print (class_name);
956 
957 	RVector *bases = r_anal_class_base_get_all (anal, class_name);
958 	if (bases) {
959 		RAnalBaseClass *base;
960 		bool first = true;
961 		r_vector_foreach (bases, base) {
962 			if (first) {
963 				r_cons_print (": ");
964 				first = false;
965 			} else {
966 				r_cons_print (", ");
967 			}
968 			r_cons_print (base->class_name);
969 		}
970 		r_vector_free (bases);
971 	}
972 
973 	r_cons_print ("\n");
974 
975 
976 	if (detailed) {
977 		RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
978 		if (vtables) {
979 			RAnalVTable *vtable;
980 			r_vector_foreach (vtables, vtable) {
981 				r_cons_printf ("  (vtable at 0x%"PFMT64x, vtable->addr);
982 				if (vtable->offset > 0) {
983 					r_cons_printf (" in class at +0x%"PFMT64x")\n", vtable->offset);
984 				} else {
985 					r_cons_print (")\n");
986 				}
987 			}
988 			r_vector_free (vtables);
989 		}
990 
991 		RVector *methods = r_anal_class_method_get_all (anal, class_name);
992 		if (methods) {
993 			RAnalMethod *meth;
994 			r_vector_foreach (methods, meth) {
995 				r_cons_printf ("  %s @ 0x%"PFMT64x, meth->name, meth->addr);
996 				if (meth->vtable_offset >= 0) {
997 					r_cons_printf (" (vtable + 0x%"PFMT64x")\n", (ut64)meth->vtable_offset);
998 				} else {
999 					r_cons_print ("\n");
1000 				}
1001 			}
1002 			r_vector_free (methods);
1003 		}
1004 	}
1005 }
1006 
r_anal_class_print_cmd(RAnal * anal,const char * class_name)1007 static void r_anal_class_print_cmd(RAnal *anal, const char *class_name) {
1008 	RVector *bases = r_anal_class_base_get_all (anal, class_name);
1009 	if (bases) {
1010 		RAnalBaseClass *base;
1011 		r_vector_foreach (bases, base) {
1012 			r_cons_printf ("acb %s %s %"PFMT64u"\n", class_name, base->class_name, base->offset);
1013 		}
1014 		r_vector_free (bases);
1015 	}
1016 
1017 	RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
1018 	if (vtables) {
1019 		RAnalVTable *vtable;
1020 		r_vector_foreach (vtables, vtable) {
1021 			r_cons_printf ("acv %s 0x%"PFMT64x" %"PFMT64u"\n", class_name, vtable->addr, vtable->offset);
1022 		}
1023 		r_vector_free (vtables);
1024 	}
1025 
1026 	RVector *methods = r_anal_class_method_get_all (anal, class_name);
1027 	if (methods) {
1028 		RAnalMethod *meth;
1029 		r_vector_foreach (methods, meth) {
1030 			r_cons_printf ("acm %s %s 0x%"PFMT64x" %"PFMT64d"\n", class_name, meth->name, meth->addr, meth->vtable_offset);
1031 		}
1032 		r_vector_free (methods);
1033 	}
1034 }
1035 
r_anal_class_json(RAnal * anal,PJ * j,const char * class_name)1036 R_API void r_anal_class_json(RAnal *anal, PJ *j, const char *class_name) {
1037 	pj_o (j);
1038 	pj_ks (j, "name", class_name);
1039 
1040 	pj_k (j, "bases");
1041 	pj_a (j);
1042 	RVector *bases = r_anal_class_base_get_all (anal, class_name);
1043 	if (bases) {
1044 		RAnalBaseClass *base;
1045 		r_vector_foreach (bases, base) {
1046 			pj_o (j);
1047 			pj_ks (j, "id", base->id);
1048 			pj_ks (j, "name", base->class_name);
1049 			pj_kn (j, "offset", base->offset);
1050 			pj_end (j);
1051 		}
1052 		r_vector_free (bases);
1053 	}
1054 	pj_end (j);
1055 
1056 	pj_k (j, "vtables");
1057 	pj_a (j);
1058 	RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
1059 	if (vtables) {
1060 		RAnalVTable *vtable;
1061 		r_vector_foreach (vtables, vtable) {
1062 			pj_o (j);
1063 			pj_ks (j, "id", vtable->id);
1064 			pj_kn (j, "addr", vtable->addr);
1065 			pj_kn (j, "offset", vtable->offset);
1066 			pj_end (j);
1067 		}
1068 	}
1069 	pj_end (j);
1070 
1071 	pj_k (j, "methods");
1072 	pj_a (j);
1073 	RVector *methods = r_anal_class_method_get_all (anal, class_name);
1074 	if (methods) {
1075 		RAnalMethod *meth;
1076 		r_vector_foreach (methods, meth) {
1077 			pj_o (j);
1078 			pj_ks (j, "name", meth->name);
1079 			pj_kn (j, "addr", meth->addr);
1080 			if (meth->vtable_offset >= 0) {
1081 				pj_kn (j, "vtable_offset", (ut64)meth->vtable_offset);
1082 			}
1083 			pj_end (j);
1084 		}
1085 		r_vector_free (methods);
1086 	}
1087 	pj_end (j);
1088 
1089 	pj_end (j);
1090 }
1091 
1092 typedef struct {
1093 	RAnal *anal;
1094 	PJ *j;
1095 } ListJsonCtx;
1096 
r_anal_class_list_json_cb(void * user,const char * k,const char * v)1097 static bool r_anal_class_list_json_cb(void *user, const char *k, const char *v) {
1098 	ListJsonCtx *ctx = user;
1099 	r_anal_class_json (ctx->anal, ctx->j, k);
1100 	return true;
1101 }
1102 
r_anal_class_list_json(RAnal * anal)1103 static void r_anal_class_list_json(RAnal *anal) {
1104 	PJ *j = anal->coreb.pjWithEncoding (anal->coreb.core);
1105 	if (!j) {
1106 		return;
1107 	}
1108 	pj_a (j);
1109 
1110 	ListJsonCtx ctx;
1111 	ctx.anal = anal;
1112 	ctx.j = j;
1113 	r_anal_class_foreach (anal, r_anal_class_list_json_cb, &ctx);
1114 
1115 	pj_end (j);
1116 	r_cons_printf ("%s\n", pj_string (j));
1117 	pj_free (j);
1118 }
1119 
r_anal_class_list(RAnal * anal,int mode)1120 R_API void r_anal_class_list(RAnal *anal, int mode) {
1121 	if (mode == 'j') {
1122 		r_anal_class_list_json (anal);
1123 		return;
1124 	}
1125 
1126 	SdbList *classes = r_anal_class_get_all (anal, mode != '*');
1127 	SdbListIter *iter;
1128 	SdbKv *kv;
1129 	if (mode == '*') {
1130 		ls_foreach (classes, iter, kv) {
1131 			// need to create all classes first, so they can be referenced
1132 			r_cons_printf ("ac %s\n", sdbkv_key (kv));
1133 		}
1134 		ls_foreach (classes, iter, kv) {
1135 			r_anal_class_print_cmd(anal, sdbkv_key (kv));
1136 		}
1137 	} else {
1138 		ls_foreach (classes, iter, kv) {
1139 			r_anal_class_print (anal, sdbkv_key (kv), mode == 'l');
1140 		}
1141 	}
1142 	ls_free (classes);
1143 }
1144 
r_anal_class_list_bases(RAnal * anal,const char * class_name)1145 R_API void r_anal_class_list_bases(RAnal *anal, const char *class_name) {
1146 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
1147 	if (!class_name_sanitized) {
1148 		return;
1149 	}
1150 	if (!r_anal_class_exists_raw (anal, class_name_sanitized)) {
1151 		free (class_name_sanitized);
1152 		return;
1153 	}
1154 	r_cons_printf ("%s:\n", class_name_sanitized);
1155 	free (class_name_sanitized);
1156 
1157 	RVector *bases = r_anal_class_base_get_all (anal, class_name);
1158 	RAnalBaseClass *base;
1159 	r_vector_foreach (bases, base) {
1160 		r_cons_printf ("  %4s %s @ +0x%"PFMT64x"\n", base->id, base->class_name, base->offset);
1161 	}
1162 	r_vector_free (bases);
1163 }
1164 
r_anal_class_list_vtables(RAnal * anal,const char * class_name)1165 R_API void r_anal_class_list_vtables(RAnal *anal, const char *class_name) {
1166 	char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
1167 	if (!class_name_sanitized) {
1168 		return;
1169 	}
1170 	if (!r_anal_class_exists_raw (anal, class_name_sanitized)) {
1171 		free (class_name_sanitized);
1172 		return;
1173 	}
1174 	r_cons_printf ("%s:\n", class_name_sanitized);
1175 	free (class_name_sanitized);
1176 
1177 	RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
1178 	if (vtables) {
1179 		RAnalVTable *vtable;
1180 		r_vector_foreach (vtables, vtable) {
1181 			r_cons_printf ("  %4s vtable 0x%"PFMT64x" @ +0x%"PFMT64x" size:+0x%"PFMT64x"\n", vtable->id, vtable->addr, vtable->offset, vtable->size);
1182 		}
1183 		r_vector_free (vtables);
1184 	}
1185 }
1186 
list_all_functions_at_vtable_offset(RAnal * anal,const char * class_name,ut64 offset)1187 static void list_all_functions_at_vtable_offset(RAnal *anal, const char *class_name, ut64 offset) {
1188 	RVTableContext vtableContext;
1189 	r_anal_vtable_begin (anal, &vtableContext);
1190 	ut8 function_ptr_size = vtableContext.word_size;
1191 
1192 	ut64 func_address;
1193 	RVector *vtables = r_anal_class_vtable_get_all (anal, class_name);
1194 	RAnalVTable *vtable;
1195 
1196 	if (!vtables) {
1197 		return;
1198 	}
1199 
1200 	r_vector_foreach (vtables, vtable) {
1201 		if (vtable->size < offset + function_ptr_size) {
1202 			continue;
1203 		}
1204 
1205 		if (vtableContext.read_addr(anal, vtable->addr+offset, &func_address))
1206 			r_cons_printf ("Function address: 0x%08"PFMT64x", in %s vtable %s\n", func_address, class_name, vtable->id);
1207 	}
1208 	r_vector_free (vtables);
1209 }
1210 
r_anal_class_list_vtable_offset_functions(RAnal * anal,const char * class_name,ut64 offset)1211 R_API void r_anal_class_list_vtable_offset_functions(RAnal *anal, const char *class_name, ut64 offset) {
1212 	if (class_name) {
1213 		char *class_name_sanitized = r_str_sanitize_sdb_key (class_name);
1214 		if (!class_name_sanitized) {
1215 			return;
1216 		}
1217 		if (!r_anal_class_exists_raw (anal, class_name_sanitized)) {
1218 			free (class_name_sanitized);
1219 			return;
1220 		}
1221 		free (class_name_sanitized);
1222 
1223 		list_all_functions_at_vtable_offset (anal, class_name, offset);
1224 	} else {
1225 		SdbList *classes = r_anal_class_get_all (anal, true);
1226 		SdbListIter *iter;
1227 		SdbKv *kv;
1228 		ls_foreach (classes, iter, kv) {
1229 			const char *name = sdbkv_key (kv);
1230 			list_all_functions_at_vtable_offset (anal, name, offset);
1231 		}
1232 		ls_free (classes);
1233 	}
1234 }
1235 
1236 /**
1237  * @brief Creates RGraph from class inheritance information where
1238  *        each node has RGraphNodeInfo as generic data
1239  *
1240  * @param anal
1241  * @return RGraph* NULL if failure
1242  */
r_anal_class_get_inheritance_graph(RAnal * anal)1243 R_API RGraph *r_anal_class_get_inheritance_graph(RAnal *anal) {
1244 	r_return_val_if_fail (anal, NULL);
1245 	RGraph *class_graph = r_graph_new ();
1246 	if (!class_graph) {
1247 		return NULL;
1248 	}
1249 	SdbList *classes = r_anal_class_get_all (anal, true);
1250 	if (!classes) {
1251 		r_graph_free (class_graph);
1252 		return NULL;
1253 	}
1254 	HtPP /*<char *name, RGraphNode *node>*/ *hashmap = ht_pp_new0 ();
1255 	if (!hashmap) {
1256 		r_graph_free (class_graph);
1257 		ls_free (classes);
1258 		return NULL;
1259 	}
1260 	SdbListIter *iter;
1261 	SdbKv *kv;
1262 	// Traverse each class and create a node and edges
1263 	ls_foreach (classes, iter, kv) {
1264 		const char *name = sdbkv_key (kv);
1265 		// create nodes
1266 		RGraphNode *curr_node = ht_pp_find (hashmap, name, NULL);
1267 		if (!curr_node) {
1268 			curr_node = r_graph_add_node_info (class_graph, name, NULL, 0);
1269 			if (!curr_node) {
1270 				goto failure;
1271 			}
1272 			ht_pp_insert (hashmap, name, curr_node);
1273 		}
1274 		// create edges between node and it's parents
1275 		RVector *bases = r_anal_class_base_get_all (anal, name);
1276 		RAnalBaseClass *base;
1277 		r_vector_foreach (bases, base) {
1278 			bool base_found = false;
1279 			RGraphNode *base_node = ht_pp_find (hashmap, base->class_name, &base_found);
1280 			// If base isn't processed, do it now
1281 			if (!base_found) {
1282 				base_node = r_graph_add_node_info (class_graph, base->class_name, NULL, 0);
1283 				if (!base_node) {
1284 					goto failure;
1285 				}
1286 				ht_pp_insert (hashmap, base->class_name, base_node);
1287 			}
1288 			r_graph_add_edge (class_graph, base_node, curr_node);
1289 		}
1290 		r_vector_free (bases);
1291 	}
1292 	ls_free (classes);
1293 	ht_pp_free (hashmap);
1294 	return class_graph;
1295 
1296 failure:
1297 	ls_free (classes);
1298 	ht_pp_free (hashmap);
1299 	r_graph_free (class_graph);
1300 	return NULL;
1301 }