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 }