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