1 /* radare - LGPL - Copyright 2018 - pancake, r00tus3r */
2
3 #include <r_anal.h>
4 #include <r_core.h>
5 #include <r_flag.h>
6 #include <r_cons.h>
7
8 #define VMI_CLASS_TYPE_INFO_NAME "__vmi_class_type_info"
9 #define SI_CLASS_TYPE_INFO_NAME "__si_class_type_info"
10 #define CLASS_TYPE_INFO_NAME "__class_type_info"
11 #define NAME_BUF_SIZE 256
12
13 #define VT_WORD_SIZE(ctx)\
14 (ctx->word_size)
15
16 typedef enum {
17 R_TYPEINFO_TYPE_UNKNOWN,
18 R_TYPEINFO_TYPE_CLASS,
19 R_TYPEINFO_TYPE_SI_CLASS,
20 R_TYPEINFO_TYPE_VMI_CLASS
21 } RTypeInfoType;
22
23 typedef struct class_type_info_t {
24 RTypeInfoType type;
25 ut64 class_vtable_addr;
26 ut64 typeinfo_addr;
27 ut64 vtable_addr;
28 ut64 name_addr;
29 char *name;
30 bool name_unique;
31 } class_type_info;
32
33 typedef struct base_class_type_info_t {
34 ut64 base_class_addr;
35 ut64 flags;
36 enum flags_masks_e {
37 base_is_virtual = 0x1,
38 base_is_public = 0x2
39 } flags_masks;
40 } base_class_type_info;
41
42 typedef struct si_class_type_info_t {
43 RTypeInfoType type;
44 ut64 class_vtable_addr;
45 ut64 typeinfo_addr;
46 ut64 vtable_addr;
47 ut64 name_addr;
48 char *name;
49 bool name_unique;
50 ut64 base_class_addr;
51 } si_class_type_info;
52
53 typedef struct vmi_class_type_info_t {
54 RTypeInfoType type;
55 ut64 class_vtable_addr;
56 ut64 typeinfo_addr;
57 ut64 vtable_addr;
58 ut64 name_addr;
59 char *name;
60 bool name_unique;
61 int vmi_flags;
62 int vmi_base_count;
63 base_class_type_info *vmi_bases;
64 enum vmi_flags_masks_e {
65 non_diamond_repeat_mask = 0x1,
66 diamond_shaped_mask = 0x2,
67 non_public_base_mask = 0x4,
68 public_base_mask = 0x8
69 } vmi_flags_masks;
70 } vmi_class_type_info;
71
rtti_itanium_read_type_name(RVTableContext * context,ut64 addr,class_type_info * cti)72 static bool rtti_itanium_read_type_name(RVTableContext *context, ut64 addr, class_type_info *cti) {
73 ut64 at;
74 if (!context->read_addr (context->anal, addr, &at)) {
75 return false;
76 }
77 ut64 unique_mask = 1ULL << (VT_WORD_SIZE (context) * 8 - 1);
78 cti->name_unique = (at & unique_mask) == 0;
79 at &= ~unique_mask;
80 cti->name_addr = at;
81 ut8 buf[NAME_BUF_SIZE];
82 if (!context->anal->iob.read_at (context->anal->iob.io, at, buf, sizeof (buf))) {
83 return false;
84 }
85 buf[NAME_BUF_SIZE - 1] = 0;
86 cti->name = r_anal_rtti_itanium_demangle_class_name (context, (char *)buf);
87 if (!cti->name) {
88 return false;
89 }
90 return true;
91 }
92
93 // Custom for the prototype now
rtti_itanium_read_type_name_custom(RVTableContext * context,ut64 addr,ut64 * str_addr,bool * unique_name)94 static char *rtti_itanium_read_type_name_custom(RVTableContext *context, ut64 addr, ut64 *str_addr, bool *unique_name) {
95 ut64 at;
96 if (!context->read_addr (context->anal, addr, &at)) {
97 return NULL;
98 }
99 ut64 unique_mask = 1ULL << (VT_WORD_SIZE (context) * 8 - 1);
100 *unique_name = (at & unique_mask) == 0;
101 at &= ~unique_mask;
102 *str_addr = at;
103 ut8 buf[NAME_BUF_SIZE];
104 if (!context->anal->iob.read_at (context->anal->iob.io, at, buf, sizeof (buf))) {
105 return NULL;
106 }
107 buf[NAME_BUF_SIZE - 1] = 0;
108 char *name = r_anal_rtti_itanium_demangle_class_name (context, (char *)buf);
109
110 return name;
111 }
112
rtti_itanium_class_type_info_fini(class_type_info * cti)113 static void rtti_itanium_class_type_info_fini(class_type_info *cti) {
114 if (cti) {
115 free (cti->name);
116 }
117 }
118
rtti_itanium_class_type_info_free(class_type_info * cti)119 static void rtti_itanium_class_type_info_free(class_type_info *cti) {
120 if (cti == NULL) {
121 return;
122 }
123
124 rtti_itanium_class_type_info_fini (cti);
125 free (cti);
126 }
127
rtti_itanium_class_type_info_init(RVTableContext * context,ut64 addr,class_type_info * cti)128 static bool rtti_itanium_class_type_info_init(RVTableContext *context, ut64 addr, class_type_info *cti) {
129 cti->type = R_TYPEINFO_TYPE_CLASS;
130 ut64 at;
131 if (addr == UT64_MAX) {
132 return false;
133 }
134 if (!context->read_addr (context->anal, addr, &at)) {
135 return false;
136 }
137 cti->vtable_addr = at;
138 return rtti_itanium_read_type_name (context, addr + VT_WORD_SIZE (context), cti);
139 }
140
rtti_itanium_class_type_info_new(RVTableContext * context,ut64 addr,ut64 source_vtable)141 static class_type_info *rtti_itanium_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable) {
142 class_type_info *result = R_NEW0 (class_type_info);
143 if (!result) {
144 return NULL;
145 }
146
147 if (!rtti_itanium_class_type_info_init (context, addr, result)) {
148 rtti_itanium_class_type_info_free (result);
149 return NULL;
150 }
151
152 result->class_vtable_addr = source_vtable;
153 result->typeinfo_addr = addr;
154
155 return result;
156 }
157
rtti_itanium_vmi_class_type_info_fini(vmi_class_type_info * vmi_cti)158 static void rtti_itanium_vmi_class_type_info_fini(vmi_class_type_info *vmi_cti) {
159 if (vmi_cti) {
160 free (vmi_cti->vmi_bases);
161 free (vmi_cti->name);
162 }
163 }
164
rtti_itanium_vmi_class_type_info_free(vmi_class_type_info * cti)165 static void rtti_itanium_vmi_class_type_info_free(vmi_class_type_info *cti) {
166 if (cti == NULL) {
167 return;
168 }
169
170 rtti_itanium_vmi_class_type_info_fini (cti);
171 free (cti);
172 }
173
rtti_itanium_vmi_class_type_info_init(RVTableContext * context,ut64 addr,vmi_class_type_info * vmi_cti)174 static bool rtti_itanium_vmi_class_type_info_init(RVTableContext *context, ut64 addr, vmi_class_type_info *vmi_cti) {
175 vmi_cti->type = R_TYPEINFO_TYPE_VMI_CLASS;
176 ut64 at;
177 if (addr == UT64_MAX) {
178 return false;
179 }
180 if (!context->read_addr (context->anal, addr, &at)) {
181 return false;
182 }
183 vmi_cti->vtable_addr = at;
184 addr += VT_WORD_SIZE (context);
185 if (!rtti_itanium_read_type_name (context, addr, (class_type_info *)vmi_cti)) {
186 return false;
187 }
188 addr += VT_WORD_SIZE (context);
189 if (!context->read_addr (context->anal, addr, &at)) {
190 return false;
191 }
192 vmi_cti->vmi_flags = at & 0xffffffff;
193 addr += 0x4;
194 if (!context->read_addr (context->anal, addr, &at)) {
195 return false;
196 }
197 at = at & 0xffffffff;
198 if (at < 1 || at > 0xfffff) {
199 eprintf ("Error reading vmi_base_count\n");
200 return false;
201 }
202 vmi_cti->vmi_base_count = at;
203 vmi_cti->vmi_bases = calloc (sizeof (base_class_type_info), vmi_cti->vmi_base_count);
204 if (!vmi_cti->vmi_bases) {
205 return false;
206 }
207 ut64 tmp_addr = addr + 0x4;
208
209 int i;
210 for (i = 0; i < vmi_cti->vmi_base_count; i++) {
211 if (!context->read_addr (context->anal, tmp_addr, &at)) {
212 return false;
213 }
214 vmi_cti->vmi_bases[i].base_class_addr = at;
215 tmp_addr += VT_WORD_SIZE (context);
216 if (!context->read_addr (context->anal, tmp_addr, &at)) {
217 return false;
218 }
219 vmi_cti->vmi_bases[i].flags = at;
220 tmp_addr += VT_WORD_SIZE (context);
221 }
222 return true;
223 }
224
rtti_itanium_vmi_class_type_info_new(RVTableContext * context,ut64 addr,ut64 source_vtable)225 static vmi_class_type_info *rtti_itanium_vmi_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable) {
226 vmi_class_type_info *result = R_NEW0 (vmi_class_type_info);
227 if (!result) {
228 return NULL;
229 }
230
231 if (!rtti_itanium_vmi_class_type_info_init (context, addr, result)) {
232 rtti_itanium_vmi_class_type_info_free (result);
233 return NULL;
234 }
235
236 result->class_vtable_addr = source_vtable;
237 result->typeinfo_addr = addr;
238
239 return result;
240 }
241
rtti_itanium_si_class_type_info_fini(si_class_type_info * si_cti)242 static void rtti_itanium_si_class_type_info_fini(si_class_type_info *si_cti) {
243 if (si_cti) {
244 free (si_cti->name);
245 }
246 }
247
rtti_itanium_si_class_type_info_free(si_class_type_info * cti)248 static void rtti_itanium_si_class_type_info_free(si_class_type_info *cti) {
249 if (cti == NULL) {
250 return;
251 }
252
253 rtti_itanium_si_class_type_info_fini (cti);
254 free (cti);
255 }
256
rtti_itanium_si_class_type_info_init(RVTableContext * context,ut64 addr,si_class_type_info * si_cti)257 static bool rtti_itanium_si_class_type_info_init(RVTableContext *context, ut64 addr, si_class_type_info *si_cti) {
258 si_cti->type = R_TYPEINFO_TYPE_SI_CLASS;
259 ut64 at;
260 if (addr == UT64_MAX) {
261 return false;
262 }
263 if (!context->read_addr (context->anal, addr, &at)) {
264 return false;
265 }
266 si_cti->vtable_addr = at;
267 if (!rtti_itanium_read_type_name (context, addr + VT_WORD_SIZE (context), (class_type_info *)si_cti)) {
268 return false;
269 }
270 if (!context->read_addr (context->anal, addr + 2 * VT_WORD_SIZE (context), &at)) {
271 return false;
272 }
273 si_cti->base_class_addr = at;
274 return true;
275 }
276
rtti_itanium_si_class_type_info_new(RVTableContext * context,ut64 addr,ut64 source_vtable)277 static si_class_type_info *rtti_itanium_si_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable) {
278 si_class_type_info *result = R_NEW0 (si_class_type_info);
279 if (!result) {
280 return NULL;
281 }
282
283 if (!rtti_itanium_si_class_type_info_init (context, addr, result)) {
284 rtti_itanium_si_class_type_info_free (result);
285 return NULL;
286 }
287
288 result->class_vtable_addr = source_vtable;
289 result->typeinfo_addr = addr;
290
291 return result;
292 }
293
type_to_string(RTypeInfoType type)294 static const char *type_to_string(RTypeInfoType type) {
295 switch (type) {
296 case R_TYPEINFO_TYPE_CLASS:
297 return CLASS_TYPE_INFO_NAME;
298 case R_TYPEINFO_TYPE_SI_CLASS:
299 return SI_CLASS_TYPE_INFO_NAME;
300 case R_TYPEINFO_TYPE_VMI_CLASS:
301 return VMI_CLASS_TYPE_INFO_NAME;
302 default:
303 r_return_val_if_reached (CLASS_TYPE_INFO_NAME);
304 }
305 }
rtti_itanium_print_class_type_info(class_type_info * cti,const char * prefix)306 static void rtti_itanium_print_class_type_info(class_type_info *cti, const char *prefix) {
307 r_cons_printf ("%sType Info at 0x%08" PFMT64x ":\n"
308 "%s Type Info type: %s\n"
309 "%s Belongs to class vtable: 0x%08" PFMT64x "\n"
310 "%s Reference to RTTI's type class: 0x%08" PFMT64x "\n"
311 "%s Reference to type's name: 0x%08" PFMT64x "\n"
312 "%s Type Name: %s\n"
313 "%s Name unique: %s\n",
314 prefix, cti->typeinfo_addr,
315 prefix, type_to_string (cti->type),
316 prefix, cti->class_vtable_addr,
317 prefix, cti->vtable_addr,
318 prefix, cti->name_addr,
319 prefix, cti->name,
320 prefix, cti->name_unique ? "true" : "false");
321 }
322
rtti_itanium_print_class_type_info_json(class_type_info * cti)323 static void rtti_itanium_print_class_type_info_json(class_type_info *cti) {
324 PJ *pj = pj_new ();
325 if (!pj) {
326 return;
327 }
328
329 pj_o (pj);
330 pj_ks (pj, "type", type_to_string (cti->type));
331 pj_kn (pj, "found_at", cti->typeinfo_addr);
332 pj_kn (pj, "class_vtable", cti->class_vtable_addr);
333 pj_kn (pj, "ref_to_type_class", cti->vtable_addr);
334 pj_kn (pj, "ref_to_type_name", cti->name_addr);
335 pj_ks (pj, "name", cti->name);
336 pj_kb (pj, "name_unique", cti->name_unique);
337 pj_end (pj);
338
339 r_cons_print (pj_string (pj));
340 pj_free (pj);
341 }
342
rtti_itanium_print_vmi_class_type_info(vmi_class_type_info * vmi_cti,const char * prefix)343 static void rtti_itanium_print_vmi_class_type_info(vmi_class_type_info *vmi_cti, const char *prefix) {
344 r_cons_printf ("%sType Info at 0x%08" PFMT64x ":\n"
345 "%s Type Info type: %s\n"
346 "%s Belongs to class vtable: 0x%08" PFMT64x "\n"
347 "%s Reference to RTTI's type class: 0x%08" PFMT64x "\n"
348 "%s Reference to type's name: 0x%08" PFMT64x "\n"
349 "%s Type Name: %s\n"
350 "%s Name unique: %s\n"
351 "%s Flags: 0x%x\n"
352 "%s Count of base classes: 0x%x"
353 "\n",
354 prefix, vmi_cti->typeinfo_addr,
355 prefix, type_to_string (vmi_cti->type),
356 prefix, vmi_cti->class_vtable_addr,
357 prefix, vmi_cti->vtable_addr,
358 prefix, vmi_cti->name_addr,
359 prefix, vmi_cti->name,
360 prefix, vmi_cti->name_unique ? "true" : "false",
361 prefix, vmi_cti->vmi_flags,
362 prefix, vmi_cti->vmi_base_count);
363
364 int i;
365 for (i = 0; i < vmi_cti->vmi_base_count; i++) {
366 r_cons_printf ("%s Base class type descriptor address: 0x%08" PFMT64x "\n"
367 "%s Base class flags: 0x%" PFMT64x
368 "\n",
369 prefix, vmi_cti->vmi_bases[i].base_class_addr,
370 prefix, vmi_cti->vmi_bases[i].flags);
371 }
372 }
373
rtti_itanium_print_vmi_class_type_info_json(vmi_class_type_info * vmi_cti)374 static void rtti_itanium_print_vmi_class_type_info_json(vmi_class_type_info *vmi_cti) {
375 PJ *pj = pj_new ();
376 if (!pj) {
377 return;
378 }
379
380 pj_o (pj);
381 pj_ks (pj, "type", type_to_string (vmi_cti->type));
382 pj_kn (pj, "found_at", vmi_cti->typeinfo_addr);
383 pj_kn (pj, "class_vtable", vmi_cti->class_vtable_addr);
384 pj_kn (pj, "ref_to_type_class", vmi_cti->vtable_addr);
385 pj_kn (pj, "ref_to_type_name", vmi_cti->name_addr);
386 pj_ks (pj, "name", vmi_cti->name);
387 pj_kb (pj, "name_unique", vmi_cti->name_unique);
388 pj_kn (pj, "flags", vmi_cti->vmi_flags);
389 pj_k (pj, "base_classes");
390 pj_a (pj);
391 int i;
392 for (i = 0; i < vmi_cti->vmi_base_count; i++) {
393 pj_o (pj);
394 pj_kn (pj, "type_desc_addr", vmi_cti->vmi_bases[i].base_class_addr);
395 pj_kN (pj, "flags", vmi_cti->vmi_bases[i].flags);
396 pj_end (pj);
397 }
398 pj_end (pj);
399 pj_end (pj);
400
401 r_cons_print (pj_string (pj));
402 pj_free (pj);
403 }
404
rtti_itanium_print_si_class_type_info(si_class_type_info * si_cti,const char * prefix)405 static void rtti_itanium_print_si_class_type_info(si_class_type_info *si_cti, const char *prefix) {
406 r_cons_printf ("%sType Info at 0x%08" PFMT64x ":\n"
407 "%s Type Info type: %s\n"
408 "%s Belongs to class vtable: 0x%08" PFMT64x "\n"
409 "%s Reference to RTTI's type class: 0x%08" PFMT64x "\n"
410 "%s Reference to type's name: 0x%08" PFMT64x "\n"
411 "%s Type Name: %s\n"
412 "%s Name unique: %s\n"
413 "%s Reference to parent's type info: 0x%08" PFMT64x "\n",
414 prefix, si_cti->typeinfo_addr,
415 prefix, type_to_string (si_cti->type),
416 prefix, si_cti->class_vtable_addr,
417 prefix, si_cti->vtable_addr,
418 prefix, si_cti->name_addr,
419 prefix, si_cti->name,
420 prefix, si_cti->name_unique ? "true" : "false",
421 prefix, si_cti->base_class_addr);
422 }
423
rtti_itanium_print_si_class_type_info_json(si_class_type_info * si_cti)424 static void rtti_itanium_print_si_class_type_info_json(si_class_type_info *si_cti) {
425 PJ *pj = pj_new ();
426 if (!pj) {
427 return;
428 }
429
430 pj_o (pj);
431 pj_ks (pj, "type", type_to_string (si_cti->type));
432 pj_kn (pj, "found_at", si_cti->typeinfo_addr);
433 pj_kn (pj, "class_vtable", si_cti->class_vtable_addr);
434 pj_kn (pj, "ref_to_type_class", si_cti->vtable_addr);
435 pj_kn (pj, "ref_to_type_name", si_cti->name_addr);
436 pj_ks (pj, "name", si_cti->name);
437 pj_kb (pj, "name_unique", si_cti->name_unique);
438 pj_kn (pj, "ref_to_parent_type", si_cti->base_class_addr);
439 pj_end (pj);
440
441 r_cons_print (pj_string (pj));
442 pj_free (pj);
443 }
444
rtti_itanium_type_info_type_from_flag(RVTableContext * context,ut64 atAddress)445 static RTypeInfoType rtti_itanium_type_info_type_from_flag(RVTableContext *context, ut64 atAddress) {
446 RCore *core = context->anal->coreb.core;
447 r_return_val_if_fail (core, R_TYPEINFO_TYPE_CLASS);
448
449 // get the reloc flags
450 const RList *flags = context->anal->flb.get_list (core->flags, atAddress);
451 if (!flags) {
452 return R_TYPEINFO_TYPE_UNKNOWN;
453 }
454
455 RListIter *iter;
456 RFlagItem *flag;
457 r_list_foreach (flags, iter, flag) {
458 if (strstr (flag->name, VMI_CLASS_TYPE_INFO_NAME)) {
459 return R_TYPEINFO_TYPE_VMI_CLASS;
460 } else if (strstr (flag->name, SI_CLASS_TYPE_INFO_NAME)) {
461 return R_TYPEINFO_TYPE_SI_CLASS;
462 } else if (strstr (flag->name, CLASS_TYPE_INFO_NAME)) {
463 return R_TYPEINFO_TYPE_CLASS;
464 }
465 }
466
467 return R_TYPEINFO_TYPE_UNKNOWN;
468 }
469
470 // used to check if vpointer or RTTI can be in the section
can_section_contain_rtti_vpointer(RBinSection * section)471 static bool can_section_contain_rtti_vpointer(RBinSection *section) {
472 if (!section) {
473 return false;
474 }
475 if (section->is_data) {
476 return true;
477 }
478 return !strcmp (section->name, ".data.rel.ro") ||
479 !strcmp (section->name, ".data.rel.ro.local") ||
480 r_str_endswith (section->name, "__const");
481 }
482
create_class_type(ut64 vtable_addr,char * name,ut64 name_addr,bool unique_name,ut64 typeinfo_addr,ut64 source_vtable)483 static class_type_info *create_class_type(ut64 vtable_addr, char *name, ut64 name_addr, bool unique_name, ut64 typeinfo_addr, ut64 source_vtable) {
484 class_type_info *result = R_NEW0 (class_type_info);
485 if (!result) {
486 return NULL;
487 }
488 result->type = R_TYPEINFO_TYPE_CLASS;
489
490 result->vtable_addr = vtable_addr;
491 result->name_addr = name_addr;
492 result->name = name;
493 result->name_unique = unique_name;
494 result->typeinfo_addr = typeinfo_addr;
495 result->class_vtable_addr = source_vtable;
496 return result;
497 }
498
create_si_class_type(ut64 vtable_addr,char * name,ut64 name_addr,bool unique_name,ut64 basetype_addr,ut64 typeinfo_addr,ut64 source_vtable)499 static si_class_type_info *create_si_class_type(ut64 vtable_addr, char *name, ut64 name_addr, bool unique_name, ut64 basetype_addr, ut64 typeinfo_addr, ut64 source_vtable) {
500 si_class_type_info *result = R_NEW0 (si_class_type_info);
501 if (!result) {
502 return NULL;
503 }
504 result->type = R_TYPEINFO_TYPE_SI_CLASS;
505 result->base_class_addr = basetype_addr;
506 result->vtable_addr = vtable_addr;
507 result->name_addr = name_addr;
508 result->name = name;
509 result->name_unique = unique_name;
510 result->typeinfo_addr = typeinfo_addr;
511 result->class_vtable_addr = source_vtable;
512 return result;
513 }
514
create_vmi_class_type(ut64 vtable_addr,char * name,ut64 name_addr,bool unique_name,ut32 flags,ut32 base_count,base_class_type_info * bases,ut64 typeinfo_addr,ut64 source_vtable)515 static vmi_class_type_info *create_vmi_class_type(ut64 vtable_addr, char *name, ut64 name_addr, bool unique_name, ut32 flags, ut32 base_count, base_class_type_info *bases, ut64 typeinfo_addr, ut64 source_vtable) {
516 vmi_class_type_info *result = R_NEW0 (vmi_class_type_info);
517 if (!result) {
518 return NULL;
519 }
520 result->type = R_TYPEINFO_TYPE_VMI_CLASS;
521 result->vmi_bases = bases;
522 result->vmi_base_count = base_count;
523 result->vmi_flags = flags;
524 result->vtable_addr = vtable_addr;
525 result->name_addr = name_addr;
526 result->name = name;
527 result->name_unique = unique_name;
528 result->typeinfo_addr = typeinfo_addr;
529 result->class_vtable_addr = source_vtable;
530 return result;
531 }
532
533 /**
534 * @brief Try to parse as much valid looking RTTI as you can
535 *
536 * @param context
537 * @param vtable_addr
538 * @param rtti_addr
539 * @return class_type_info* NULL if not even default class RTTI could be parsed or error
540 */
raw_rtti_parse(RVTableContext * context,ut64 vtable_addr,ut64 rtti_addr)541 static class_type_info *raw_rtti_parse(RVTableContext *context, ut64 vtable_addr, ut64 rtti_addr) {
542 /*
543 rtti_ptr -----> | vptr |
544 |--------------------------------------|
545 | type_name |
546 |--------------------------------------| --- enough for __class_type_info
547 | __class_type_info *base_type |
548 |--------------------------------------| --- enough for __si_class_type_info
549 | uint flags | --- must be atleast 16bits, it's 32 bit for 64-bit Itanium ABI
550 |--------------------------------------|
551 | uint base_count |
552 |--------------------------------------|
553 | __base_class_type_info base_info[] |
554 |--------------------------------------|
555 |--------- ARRAY --------|
556 |-----__class_type_info *base_type-----|
557 |--------- long __offset_flags --------| ----- enough for __vmi_class_type_info
558 */
559 ut64 rtti_vptr = 0;
560 ut64 addr = rtti_addr;
561 if (!context->read_addr (context->anal, addr, &rtti_vptr)) {
562 return NULL;
563 }
564 RBinSection *rtti_section = context->anal->binb.get_vsect_at (context->anal->binb.bin, rtti_vptr);
565 if (rtti_vptr && !can_section_contain_rtti_vpointer (rtti_section)) {
566 ;;; // Right now ignore, seems that some binaries have some weird values inside there....
567 }
568 addr += VT_WORD_SIZE (context); // Move to the next member
569
570 ut64 name_addr = 0;
571 bool name_unique = false;
572 char *type_name = rtti_itanium_read_type_name_custom (context, addr, &name_addr, &name_unique);
573 if (!type_name) {
574 return NULL;
575 }
576
577 addr += VT_WORD_SIZE (context); // Move to the next member
578
579 // Right now we already have atleast __class_type_info;
580
581 ut64 base_type_rtti = 0;
582 if (!context->read_addr (context->anal, addr, &base_type_rtti)) {
583 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
584 }
585
586 RBinSection *base_type_rtti_section = context->anal->binb.get_vsect_at (context->anal->binb.bin, base_type_rtti);
587 if (can_section_contain_rtti_vpointer (base_type_rtti_section)) {
588 return (class_type_info *)create_si_class_type (rtti_vptr, type_name, name_addr, name_unique, base_type_rtti, rtti_addr, vtable_addr);
589 }
590
591 // if it's not a valid base_type_rtti ptr, it might be flags for VMI
592 // assume uint are 32bit
593 ut64 integers = 0;
594 if (!context->read_addr (context->anal, addr, &integers)) {
595 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
596 }
597 ut32 vmi_flags = integers & 0xffffffff;
598 addr += 0x4;
599 if (!context->read_addr (context->anal, addr, &integers)) {
600 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
601 }
602 integers = integers & 0xffffffff;
603 if (integers < 1 || integers > 0xfffff) {
604 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
605 }
606 ut32 vmi_base_count = integers;
607
608 base_class_type_info *vmi_bases = calloc (sizeof (base_class_type_info), vmi_base_count);
609 if (!vmi_bases) {
610 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
611 }
612 ut64 tmp_addr = addr + 0x4;
613
614 int i;
615 for (i = 0; i < vmi_base_count; i++) {
616 if (!context->read_addr (context->anal, tmp_addr, &integers)) {
617 free (vmi_bases);
618 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
619 }
620 vmi_bases[i].base_class_addr = integers;
621 tmp_addr += VT_WORD_SIZE (context);
622 if (!context->read_addr (context->anal, tmp_addr, &integers)) {
623 free (vmi_bases);
624 return create_class_type (rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
625 }
626 vmi_bases[i].flags = integers;
627 tmp_addr += VT_WORD_SIZE (context);
628 }
629 return (class_type_info *)create_vmi_class_type (rtti_vptr, type_name, name_addr, name_unique, vmi_flags, vmi_base_count, vmi_bases, rtti_addr, vtable_addr);
630 }
631
rtti_itanium_type_info_new(RVTableContext * context,ut64 vtable_addr)632 static class_type_info *rtti_itanium_type_info_new(RVTableContext *context, ut64 vtable_addr) {
633 /*
634 vpointer - 2 words | offset to top |
635 |---------------|
636 vpointer - word | RTTI pointer |
637 |---------------|
638 vpointer -----> | virt_func_0 |
639 */
640 ut64 rtti_ptr = vtable_addr - VT_WORD_SIZE (context); // RTTI pointer
641 ut64 rtti_addr; // RTTI address
642
643 if (!context->read_addr (context->anal, rtti_ptr, &rtti_addr)) {
644 return NULL;
645 }
646
647 RTypeInfoType type = rtti_itanium_type_info_type_from_flag (context, rtti_addr);
648 // If there isn't flag telling us the type of TypeInfo
649 // try to find the flag in it's vtable
650 if (type == R_TYPEINFO_TYPE_UNKNOWN) {
651 ut64 follow;
652 if (!context->read_addr (context->anal, rtti_addr, &follow)) {
653 return NULL;
654 }
655 follow -= 2 * context->word_size;
656 type = rtti_itanium_type_info_type_from_flag (context, follow);
657 }
658
659 if (type == R_TYPEINFO_TYPE_UNKNOWN) {
660 return raw_rtti_parse (context, vtable_addr, rtti_addr);
661 }
662 switch (type) {
663 case R_TYPEINFO_TYPE_VMI_CLASS:
664 return (class_type_info *)rtti_itanium_vmi_class_type_info_new (context, rtti_addr, vtable_addr);
665 case R_TYPEINFO_TYPE_SI_CLASS:
666 return (class_type_info *)rtti_itanium_si_class_type_info_new (context, rtti_addr, vtable_addr);
667 case R_TYPEINFO_TYPE_CLASS:
668 return rtti_itanium_class_type_info_new (context, rtti_addr, vtable_addr);
669 default:
670 r_return_val_if_reached (NULL);
671 }
672 }
673
rtti_itanium_type_info_free(void * info)674 static void rtti_itanium_type_info_free(void *info) {
675 class_type_info *cti = info;
676 if (!cti) {
677 return;
678 }
679
680 switch (cti->type) {
681 case R_TYPEINFO_TYPE_VMI_CLASS:
682 rtti_itanium_vmi_class_type_info_free ((vmi_class_type_info *)cti);
683 return;
684 case R_TYPEINFO_TYPE_SI_CLASS:
685 rtti_itanium_si_class_type_info_free ((si_class_type_info *)cti);
686 return;
687 case R_TYPEINFO_TYPE_CLASS:
688 rtti_itanium_class_type_info_free (cti);
689 return;
690 default:
691 r_return_if_reached ();
692 }
693 }
694
r_anal_rtti_itanium_print_at_vtable(RVTableContext * context,ut64 addr,int mode)695 R_API bool r_anal_rtti_itanium_print_at_vtable(RVTableContext *context, ut64 addr, int mode) {
696 bool use_json = mode == 'j';
697 class_type_info *cti = rtti_itanium_type_info_new (context, addr);
698 if (!cti) {
699 return false;
700 }
701
702 switch (cti->type) {
703 case R_TYPEINFO_TYPE_VMI_CLASS: {
704 vmi_class_type_info *vmi_cti = (vmi_class_type_info *)cti;
705 if (use_json) {
706 rtti_itanium_print_vmi_class_type_info_json (vmi_cti);
707 } else {
708 rtti_itanium_print_vmi_class_type_info (vmi_cti, "");
709 }
710 rtti_itanium_vmi_class_type_info_free (vmi_cti);
711 }
712 return true;
713 case R_TYPEINFO_TYPE_SI_CLASS: {
714 si_class_type_info *si_cti = (si_class_type_info *)cti;
715 if (use_json) {
716 rtti_itanium_print_si_class_type_info_json (si_cti);
717 } else {
718 rtti_itanium_print_si_class_type_info (si_cti, "");
719 }
720 rtti_itanium_si_class_type_info_free (si_cti);
721 }
722 return true;
723 case R_TYPEINFO_TYPE_CLASS: {
724 if (use_json) {
725 rtti_itanium_print_class_type_info_json (cti);
726 } else {
727 rtti_itanium_print_class_type_info (cti, "");
728 }
729 rtti_itanium_class_type_info_free (cti);
730 }
731 return true;
732 default:
733 rtti_itanium_class_type_info_free (cti);
734 r_return_val_if_reached (false);
735 }
736 }
737
r_anal_rtti_itanium_demangle_class_name(RVTableContext * context,const char * name)738 R_API char *r_anal_rtti_itanium_demangle_class_name(RVTableContext *context, const char *name) {
739 if (!name || !*name) {
740 return NULL;
741 }
742
743 char *result = NULL;
744
745 if (name[0] != '_') {
746 char *to_demangle = r_str_newf ("_Z%s", name);
747 result = context->anal->binb.demangle (NULL, "cxx", to_demangle, 0, false);
748 free (to_demangle);
749 } else {
750 result = context->anal->binb.demangle (NULL, "cxx", name, 0, false);
751 }
752
753 return result;
754 }
755
recovery_apply_vtable(RVTableContext * context,const char * class_name,RVTableInfo * vtable_info)756 static void recovery_apply_vtable(RVTableContext *context, const char *class_name, RVTableInfo *vtable_info) {
757 if (!vtable_info) {
758 return;
759 }
760
761 RAnalVTable vtable = { .id = NULL, .offset = 0, .size = 0, .addr = vtable_info->saddr};
762 r_anal_class_vtable_set (context->anal, class_name, &vtable);
763 r_anal_class_vtable_fini (&vtable);
764
765 RVTableMethodInfo *vmeth;
766 r_vector_foreach (&vtable_info->methods, vmeth) {
767 RAnalMethod meth;
768 meth.addr = vmeth->addr;
769 meth.vtable_offset = vmeth->vtable_offset;
770 meth.name = r_str_newf ("virtual_%" PFMT64d, meth.vtable_offset);
771 r_anal_class_method_set (context->anal, class_name, &meth);
772 r_anal_class_method_fini (&meth);
773 }
774 }
775
776 /**
777 * @brief Add any base class information about the type into anal/classes
778 *
779 * @param context
780 * @param cti
781 */
add_class_bases(RVTableContext * context,const class_type_info * cti)782 static void add_class_bases(RVTableContext *context, const class_type_info *cti) {
783 class_type_info base_info;
784 int i;
785
786 switch (cti->type) {
787 case R_TYPEINFO_TYPE_SI_CLASS: {
788 si_class_type_info *si_class = (void *)cti;
789 ut64 base_addr = si_class->base_class_addr;
790 base_addr += VT_WORD_SIZE (context); // offset to name
791 if (rtti_itanium_read_type_name (context, base_addr, &base_info)) {
792 // TODO in future, store the RTTI offset from vtable and use it
793 RAnalBaseClass base = { .class_name = base_info.name, .offset = 0 };
794 r_anal_class_base_set (context->anal, cti->name, &base);
795 r_anal_class_base_fini (&base);
796 }
797 break;
798 }
799 case R_TYPEINFO_TYPE_VMI_CLASS: {
800 vmi_class_type_info *vmi_class = (void *)cti;
801 for (i = 0; i < vmi_class->vmi_base_count; i++) {
802 base_class_type_info *base_class_info = vmi_class->vmi_bases + i;
803 ut64 base_addr = base_class_info->base_class_addr + VT_WORD_SIZE (context); // offset to name
804 if (rtti_itanium_read_type_name (context, base_addr, &base_info)) {
805 // TODO in future, store the RTTI offset from vtable and use it
806 RAnalBaseClass base = { .class_name = base_info.name, .offset = 0 };
807 r_anal_class_base_set (context->anal, cti->name, &base);
808 r_anal_class_base_fini (&base);
809 }
810 }
811 break;
812 }
813 default: // other types have no parent classes
814 break;
815 }
816 }
817
r_anal_rtti_itanium_recover_all(RVTableContext * context,RList * vtables)818 R_API void r_anal_rtti_itanium_recover_all(RVTableContext *context, RList *vtables) {
819 RList /*<class_type_info>*/ *rtti_list = r_list_new ();
820 rtti_list->free = rtti_itanium_type_info_free;
821 // to escape multiple same infos from multiple inheritance
822 SetU *unique_rttis = set_u_new ();
823
824 RListIter *iter;
825 RVTableInfo *vtable;
826 r_list_foreach (vtables, iter, vtable) {
827 class_type_info *cti = rtti_itanium_type_info_new (context, vtable->saddr);
828 if (!cti) {
829 continue;
830 }
831
832 r_anal_class_create (context->anal, cti->name);
833 // can't we name virtual functions virtual even without RTTI?
834 recovery_apply_vtable (context, cti->name, vtable);
835
836 // we only need one of a kind
837 if (set_u_contains (unique_rttis, cti->typeinfo_addr)) {
838 rtti_itanium_type_info_free (cti);
839 } else {
840 set_u_add (unique_rttis, cti->typeinfo_addr);
841 r_list_append (rtti_list, cti);
842 }
843 }
844
845 class_type_info *cti;
846 r_list_foreach (rtti_list, iter, cti) {
847 add_class_bases (context, cti);
848 }
849
850 set_u_free (unique_rttis);
851 r_list_free (rtti_list);
852 }
853