Rizin
unix-like reverse engineering framework and cli tools
rtti_itanium.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2018 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2018 r00tus3r <iamakshayajayan@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_analysis.h>
6 #include <rz_core.h>
7 #include <rz_flag.h>
8 #include <rz_cons.h>
9 #include <rz_cmd.h>
10 
11 #define VMI_CLASS_TYPE_INFO_NAME "__vmi_class_type_info"
12 #define SI_CLASS_TYPE_INFO_NAME "__si_class_type_info"
13 #define CLASS_TYPE_INFO_NAME "__class_type_info"
14 #define NAME_BUF_SIZE 256
15 
16 #define VT_WORD_SIZE(ctx) \
17  (ctx->word_size)
18 
19 typedef enum {
25 
26 typedef struct class_type_info_t {
32  char *name;
35 
36 typedef struct base_class_type_info_t {
41  base_is_public = 0x2
44 
45 typedef struct si_class_type_info_t {
51  char *name;
55 
56 typedef struct vmi_class_type_info_t {
62  char *name;
64  int vmi_flags;
71  public_base_mask = 0x8
74 
75 static bool rtti_itanium_read_type_name(RVTableContext *context, ut64 addr, class_type_info *cti) {
76  ut64 at;
77  if (!context->read_addr(context->analysis, addr, &at)) {
78  return false;
79  }
80  ut64 unique_mask = 1ULL << (VT_WORD_SIZE(context) * 8 - 1);
81  cti->name_unique = (at & unique_mask) == 0;
82  at &= ~unique_mask;
83  cti->name_addr = at;
85  if (!context->analysis->iob.read_at(context->analysis->iob.io, at, buf, sizeof(buf))) {
86  return false;
87  }
88  buf[NAME_BUF_SIZE - 1] = 0;
90  if (!cti->name) {
91  return false;
92  }
93  return true;
94 }
95 
96 // Custom for the prototype now
97 static char *rtti_itanium_read_type_name_custom(RVTableContext *context, ut64 addr, ut64 *str_addr, bool *unique_name) {
98  ut64 at;
99  if (!context->read_addr(context->analysis, addr, &at)) {
100  return NULL;
101  }
102  ut64 unique_mask = 1ULL << (VT_WORD_SIZE(context) * 8 - 1);
103  *unique_name = (at & unique_mask) == 0;
104  at &= ~unique_mask;
105  *str_addr = at;
107  if (!context->analysis->iob.read_at(context->analysis->iob.io, at, buf, sizeof(buf))) {
108  return NULL;
109  }
110  buf[NAME_BUF_SIZE - 1] = 0;
112 
113  return name;
114 }
115 
117  if (cti) {
118  free(cti->name);
119  }
120 }
121 
123  if (cti == NULL) {
124  return;
125  }
126 
128  free(cti);
129 }
130 
133  ut64 at;
134  if (addr == UT64_MAX) {
135  return false;
136  }
137  if (!context->read_addr(context->analysis, addr, &at)) {
138  return false;
139  }
140  cti->vtable_addr = at;
142 }
143 
144 static class_type_info *rtti_itanium_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable) {
146  if (!result) {
147  return NULL;
148  }
149 
152  return NULL;
153  }
154 
155  result->class_vtable_addr = source_vtable;
156  result->typeinfo_addr = addr;
157 
158  return result;
159 }
160 
162  if (vmi_cti) {
163  free(vmi_cti->vmi_bases);
164  free(vmi_cti->name);
165  }
166 }
167 
169  if (cti == NULL) {
170  return;
171  }
172 
174  free(cti);
175 }
176 
178  vmi_cti->type = RZ_TYPEINFO_TYPE_VMI_CLASS;
179  ut64 at;
180  if (addr == UT64_MAX) {
181  return false;
182  }
183  if (!context->read_addr(context->analysis, addr, &at)) {
184  return false;
185  }
186  vmi_cti->vtable_addr = at;
189  return false;
190  }
192  if (!context->read_addr(context->analysis, addr, &at)) {
193  return false;
194  }
195  vmi_cti->vmi_flags = at & 0xffffffff;
196  addr += 0x4;
197  if (!context->read_addr(context->analysis, addr, &at)) {
198  return false;
199  }
200  at = at & 0xffffffff;
201  if (at < 1 || at > 0xfffff) {
202  RZ_LOG_ERROR("Cannot read vmi_base_count\n");
203  return false;
204  }
205  vmi_cti->vmi_base_count = at;
206  vmi_cti->vmi_bases = calloc(sizeof(base_class_type_info), vmi_cti->vmi_base_count);
207  if (!vmi_cti->vmi_bases) {
208  return false;
209  }
210  ut64 tmp_addr = addr + 0x4;
211 
212  int i;
213  for (i = 0; i < vmi_cti->vmi_base_count; i++) {
214  if (!context->read_addr(context->analysis, tmp_addr, &at)) {
215  return false;
216  }
217  vmi_cti->vmi_bases[i].base_class_addr = at;
218  tmp_addr += VT_WORD_SIZE(context);
219  if (!context->read_addr(context->analysis, tmp_addr, &at)) {
220  return false;
221  }
222  vmi_cti->vmi_bases[i].flags = at;
223  tmp_addr += VT_WORD_SIZE(context);
224  }
225  return true;
226 }
227 
230  if (!result) {
231  return NULL;
232  }
233 
236  return NULL;
237  }
238 
239  result->class_vtable_addr = source_vtable;
240  result->typeinfo_addr = addr;
241 
242  return result;
243 }
244 
246  if (si_cti) {
247  free(si_cti->name);
248  }
249 }
250 
252  if (cti == NULL) {
253  return;
254  }
255 
257  free(cti);
258 }
259 
262  ut64 at;
263  if (addr == UT64_MAX) {
264  return false;
265  }
266  if (!context->read_addr(context->analysis, addr, &at)) {
267  return false;
268  }
269  si_cti->vtable_addr = at;
271  return false;
272  }
273  if (!context->read_addr(context->analysis, addr + 2 * VT_WORD_SIZE(context), &at)) {
274  return false;
275  }
276  si_cti->base_class_addr = at;
277  return true;
278 }
279 
282  if (!result) {
283  return NULL;
284  }
285 
288  return NULL;
289  }
290 
291  result->class_vtable_addr = source_vtable;
292  result->typeinfo_addr = addr;
293 
294  return result;
295 }
296 
297 static const char *type_to_string(RTypeInfoType type) {
298  switch (type) {
300  return CLASS_TYPE_INFO_NAME;
305  default:
307  }
308 }
310  rz_cons_printf("%sType Info at 0x%08" PFMT64x ":\n"
311  "%s Type Info type: %s\n"
312  "%s Belongs to class vtable: 0x%08" PFMT64x "\n"
313  "%s Reference to RTTI's type class: 0x%08" PFMT64x "\n"
314  "%s Reference to type's name: 0x%08" PFMT64x "\n"
315  "%s Type Name: %s\n"
316  "%s Name unique: %s\n",
317  prefix, cti->typeinfo_addr,
318  prefix, type_to_string(cti->type),
320  prefix, cti->vtable_addr,
321  prefix, cti->name_addr,
322  prefix, cti->name,
323  prefix, cti->name_unique ? "true" : "false");
324 }
325 
327  PJ *pj = pj_new();
328  if (!pj) {
329  return;
330  }
331 
332  pj_o(pj);
333  pj_ks(pj, "type", type_to_string(cti->type));
334  pj_kn(pj, "found_at", cti->typeinfo_addr);
335  pj_kn(pj, "class_vtable", cti->class_vtable_addr);
336  pj_kn(pj, "ref_to_type_class", cti->vtable_addr);
337  pj_kn(pj, "ref_to_type_name", cti->name_addr);
338  pj_ks(pj, "name", cti->name);
339  pj_kb(pj, "name_unique", cti->name_unique);
340  pj_end(pj);
341 
342  rz_cons_print(pj_string(pj));
343  pj_free(pj);
344 }
345 
347  rz_cons_printf("%sType Info at 0x%08" PFMT64x ":\n"
348  "%s Type Info type: %s\n"
349  "%s Belongs to class vtable: 0x%08" PFMT64x "\n"
350  "%s Reference to RTTI's type class: 0x%08" PFMT64x "\n"
351  "%s Reference to type's name: 0x%08" PFMT64x "\n"
352  "%s Type Name: %s\n"
353  "%s Name unique: %s\n"
354  "%s Flags: 0x%x\n"
355  "%s Count of base classes: 0x%x"
356  "\n",
357  prefix, vmi_cti->typeinfo_addr,
358  prefix, type_to_string(vmi_cti->type),
359  prefix, vmi_cti->class_vtable_addr,
360  prefix, vmi_cti->vtable_addr,
361  prefix, vmi_cti->name_addr,
362  prefix, vmi_cti->name,
363  prefix, vmi_cti->name_unique ? "true" : "false",
364  prefix, vmi_cti->vmi_flags,
365  prefix, vmi_cti->vmi_base_count);
366 
367  int i;
368  for (i = 0; i < vmi_cti->vmi_base_count; i++) {
369  rz_cons_printf("%s Base class type descriptor address: 0x%08" PFMT64x "\n"
370  "%s Base class flags: 0x%" PFMT64x
371  "\n",
372  prefix, vmi_cti->vmi_bases[i].base_class_addr,
373  prefix, vmi_cti->vmi_bases[i].flags);
374  }
375 }
376 
378  PJ *pj = pj_new();
379  if (!pj) {
380  return;
381  }
382 
383  pj_o(pj);
384  pj_ks(pj, "type", type_to_string(vmi_cti->type));
385  pj_kn(pj, "found_at", vmi_cti->typeinfo_addr);
386  pj_kn(pj, "class_vtable", vmi_cti->class_vtable_addr);
387  pj_kn(pj, "ref_to_type_class", vmi_cti->vtable_addr);
388  pj_kn(pj, "ref_to_type_name", vmi_cti->name_addr);
389  pj_ks(pj, "name", vmi_cti->name);
390  pj_kb(pj, "name_unique", vmi_cti->name_unique);
391  pj_kn(pj, "flags", vmi_cti->vmi_flags);
392  pj_k(pj, "base_classes");
393  pj_a(pj);
394  int i;
395  for (i = 0; i < vmi_cti->vmi_base_count; i++) {
396  pj_o(pj);
397  pj_kn(pj, "type_desc_addr", vmi_cti->vmi_bases[i].base_class_addr);
398  pj_kN(pj, "flags", vmi_cti->vmi_bases[i].flags);
399  pj_end(pj);
400  }
401  pj_end(pj);
402  pj_end(pj);
403 
404  rz_cons_print(pj_string(pj));
405  pj_free(pj);
406 }
407 
409  rz_cons_printf("%sType Info at 0x%08" PFMT64x ":\n"
410  "%s Type Info type: %s\n"
411  "%s Belongs to class vtable: 0x%08" PFMT64x "\n"
412  "%s Reference to RTTI's type class: 0x%08" PFMT64x "\n"
413  "%s Reference to type's name: 0x%08" PFMT64x "\n"
414  "%s Type Name: %s\n"
415  "%s Name unique: %s\n"
416  "%s Reference to parent's type info: 0x%08" PFMT64x "\n",
417  prefix, si_cti->typeinfo_addr,
418  prefix, type_to_string(si_cti->type),
419  prefix, si_cti->class_vtable_addr,
420  prefix, si_cti->vtable_addr,
421  prefix, si_cti->name_addr,
422  prefix, si_cti->name,
423  prefix, si_cti->name_unique ? "true" : "false",
424  prefix, si_cti->base_class_addr);
425 }
426 
428  PJ *pj = pj_new();
429  if (!pj) {
430  return;
431  }
432 
433  pj_o(pj);
434  pj_ks(pj, "type", type_to_string(si_cti->type));
435  pj_kn(pj, "found_at", si_cti->typeinfo_addr);
436  pj_kn(pj, "class_vtable", si_cti->class_vtable_addr);
437  pj_kn(pj, "ref_to_type_class", si_cti->vtable_addr);
438  pj_kn(pj, "ref_to_type_name", si_cti->name_addr);
439  pj_ks(pj, "name", si_cti->name);
440  pj_kb(pj, "name_unique", si_cti->name_unique);
441  pj_kn(pj, "ref_to_parent_type", si_cti->base_class_addr);
442  pj_end(pj);
443 
444  rz_cons_print(pj_string(pj));
445  pj_free(pj);
446 }
447 
449  RzCore *core = context->analysis->coreb.core;
451 
452  // get the reloc flags
453  const RzList *flags = context->analysis->flb.get_list(core->flags, atAddress);
454  if (!flags) {
456  }
457 
458  RzListIter *iter;
459  RzFlagItem *flag;
460  rz_list_foreach (flags, iter, flag) {
461  if (strstr(flag->name, VMI_CLASS_TYPE_INFO_NAME)) {
463  } else if (strstr(flag->name, SI_CLASS_TYPE_INFO_NAME)) {
465  } else if (strstr(flag->name, CLASS_TYPE_INFO_NAME)) {
466  return RZ_TYPEINFO_TYPE_CLASS;
467  }
468  }
469 
471 }
472 
473 // used to check if vpointer or RTTI can be in the section
475  if (!section) {
476  return false;
477  }
478  if (section->is_data) {
479  return true;
480  }
481  return !strcmp(section->name, ".data.rel.ro") ||
482  !strcmp(section->name, ".data.rel.ro.local") ||
483  rz_str_endswith(section->name, "__const");
484 }
485 
486 static class_type_info *create_class_type(ut64 vtable_addr, char *name, ut64 name_addr, bool unique_name, ut64 typeinfo_addr, ut64 source_vtable) {
488  if (!result) {
489  return NULL;
490  }
491  result->type = RZ_TYPEINFO_TYPE_CLASS;
492 
493  result->vtable_addr = vtable_addr;
494  result->name_addr = name_addr;
495  result->name = name;
496  result->name_unique = unique_name;
497  result->typeinfo_addr = typeinfo_addr;
498  result->class_vtable_addr = source_vtable;
499  return result;
500 }
501 
502 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) {
504  if (!result) {
505  return NULL;
506  }
508  result->base_class_addr = basetype_addr;
509  result->vtable_addr = vtable_addr;
510  result->name_addr = name_addr;
511  result->name = name;
512  result->name_unique = unique_name;
513  result->typeinfo_addr = typeinfo_addr;
514  result->class_vtable_addr = source_vtable;
515  return result;
516 }
517 
518 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) {
520  if (!result) {
521  return NULL;
522  }
524  result->vmi_bases = bases;
525  result->vmi_base_count = base_count;
526  result->vmi_flags = flags;
527  result->vtable_addr = vtable_addr;
528  result->name_addr = name_addr;
529  result->name = name;
530  result->name_unique = unique_name;
531  result->typeinfo_addr = typeinfo_addr;
532  result->class_vtable_addr = source_vtable;
533  return result;
534 }
535 
544 static class_type_info *raw_rtti_parse(RVTableContext *context, ut64 vtable_addr, ut64 rtti_addr) {
545  /*
546  rtti_ptr -----> | vptr |
547  |--------------------------------------|
548  | type_name |
549  |--------------------------------------| --- enough for __class_type_info
550  | __class_type_info *base_type |
551  |--------------------------------------| --- enough for __si_class_type_info
552  | uint flags | --- must be atleast 16bits, it's 32 bit for 64-bit Itanium ABI
553  |--------------------------------------|
554  | uint base_count |
555  |--------------------------------------|
556  | __base_class_type_info base_info[] |
557  |--------------------------------------|
558  |--------- ARRAY --------|
559  |-----__class_type_info *base_type-----|
560  |--------- long __offset_flags --------| ----- enough for __vmi_class_type_info
561  */
562  ut64 rtti_vptr = 0;
563  ut64 addr = rtti_addr;
564  if (!context->read_addr(context->analysis, addr, &rtti_vptr)) {
565  return NULL;
566  }
567  RzBinSection *rtti_section = context->analysis->binb.get_vsect_at(context->analysis->binb.bin, rtti_vptr);
568  if (rtti_vptr && !can_section_contain_rtti_vpointer(rtti_section)) {
569  ;
570  ;
571  ; // Right now ignore, seems that some binaries have some weird values inside there....
572  }
573  addr += VT_WORD_SIZE(context); // Move to the next member
574 
575  ut64 name_addr = 0;
576  bool name_unique = false;
577  char *type_name = rtti_itanium_read_type_name_custom(context, addr, &name_addr, &name_unique);
578  if (!type_name) {
579  return NULL;
580  }
581 
582  addr += VT_WORD_SIZE(context); // Move to the next member
583 
584  // Right now we already have atleast __class_type_info;
585 
586  ut64 base_type_rtti = 0;
587  if (!context->read_addr(context->analysis, addr, &base_type_rtti)) {
588  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
589  }
590 
591  RzBinSection *base_type_rtti_section = context->analysis->binb.get_vsect_at(context->analysis->binb.bin, base_type_rtti);
592  if (can_section_contain_rtti_vpointer(base_type_rtti_section)) {
593  return (class_type_info *)create_si_class_type(rtti_vptr, type_name, name_addr, name_unique, base_type_rtti, rtti_addr, vtable_addr);
594  }
595 
596  // if it's not a valid base_type_rtti ptr, it might be flags for VMI
597  // assume uint are 32bit
598  ut64 integers = 0;
599  if (!context->read_addr(context->analysis, addr, &integers)) {
600  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
601  }
602  ut32 vmi_flags = integers & 0xffffffff;
603  addr += 0x4;
604  if (!context->read_addr(context->analysis, addr, &integers)) {
605  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
606  }
607  integers = integers & 0xffffffff;
608  if (integers < 1 || integers > 0xfffff) {
609  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
610  }
611  ut32 vmi_base_count = integers;
612 
613  base_class_type_info *vmi_bases = calloc(sizeof(base_class_type_info), vmi_base_count);
614  if (!vmi_bases) {
615  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
616  }
617  ut64 tmp_addr = addr + 0x4;
618 
619  int i;
620  for (i = 0; i < vmi_base_count; i++) {
621  if (!context->read_addr(context->analysis, tmp_addr, &integers)) {
622  free(vmi_bases);
623  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
624  }
625  vmi_bases[i].base_class_addr = integers;
626  tmp_addr += VT_WORD_SIZE(context);
627  if (!context->read_addr(context->analysis, tmp_addr, &integers)) {
628  free(vmi_bases);
629  return create_class_type(rtti_vptr, type_name, name_addr, name_unique, rtti_addr, vtable_addr);
630  }
631  vmi_bases[i].flags = integers;
632  tmp_addr += VT_WORD_SIZE(context);
633  }
634  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);
635 }
636 
637 static class_type_info *rtti_itanium_type_info_new(RVTableContext *context, ut64 vtable_addr) {
638  /*
639  vpointer - 2 words | offset to top |
640  |---------------|
641  vpointer - word | RTTI pointer |
642  |---------------|
643  vpointer -----> | virt_func_0 |
644  */
645  ut64 rtti_ptr = vtable_addr - VT_WORD_SIZE(context); // RTTI pointer
646  ut64 rtti_addr; // RTTI address
647 
648  if (!context->read_addr(context->analysis, rtti_ptr, &rtti_addr)) {
649  return NULL;
650  }
651 
653  // If there isn't flag telling us the type of TypeInfo
654  // try to find the flag in it's vtable
656  ut64 follow;
657  if (!context->read_addr(context->analysis, rtti_addr, &follow)) {
658  return NULL;
659  }
660  follow -= 2 * context->word_size;
662  }
663 
665  return raw_rtti_parse(context, vtable_addr, rtti_addr);
666  }
667  switch (type) {
669  return (class_type_info *)rtti_itanium_vmi_class_type_info_new(context, rtti_addr, vtable_addr);
671  return (class_type_info *)rtti_itanium_si_class_type_info_new(context, rtti_addr, vtable_addr);
673  return rtti_itanium_class_type_info_new(context, rtti_addr, vtable_addr);
674  default:
676  }
677 }
678 
679 static void rtti_itanium_type_info_free(void *info) {
680  class_type_info *cti = info;
681  if (!cti) {
682  return;
683  }
684 
685  switch (cti->type) {
688  return;
691  return;
694  return;
695  default:
697  }
698 }
699 
701  bool use_json = mode == RZ_OUTPUT_MODE_JSON;
703  if (!cti) {
704  return false;
705  }
706 
707  switch (cti->type) {
709  vmi_class_type_info *vmi_cti = (vmi_class_type_info *)cti;
710  if (use_json) {
712  } else {
714  }
716  }
717  return true;
719  si_class_type_info *si_cti = (si_class_type_info *)cti;
720  if (use_json) {
722  } else {
724  }
726  }
727  return true;
728  case RZ_TYPEINFO_TYPE_CLASS: {
729  if (use_json) {
731  } else {
733  }
735  }
736  return true;
737  default:
740  }
741 }
742 
744  if (!name || !*name) {
745  return NULL;
746  }
747 
748  char *result = NULL;
749 
750  if (name[0] != '_') {
751  char *to_demangle = rz_str_newf("_Z%s", name);
752  result = context->analysis->binb.demangle(NULL, "cxx", to_demangle, 0, false);
753  free(to_demangle);
754  } else {
755  result = context->analysis->binb.demangle(NULL, "cxx", name, 0, false);
756  }
757 
758  return result;
759 }
760 
761 static void recovery_apply_vtable(RVTableContext *context, const char *class_name, RVTableInfo *vtable_info) {
762  if (!vtable_info) {
763  return;
764  }
765 
767 
768  RzAnalysisVTable vtable = { .id = NULL, .offset = 0, .size = size, .addr = vtable_info->saddr };
769  rz_analysis_class_vtable_set(context->analysis, class_name, &vtable);
771 
772  RVTableMethodInfo *vmeth;
773  rz_vector_foreach(&vtable_info->methods, vmeth) {
774  RzAnalysisMethod meth;
775  if (!rz_analysis_class_method_exists_by_addr(context->analysis, class_name, vmeth->addr)) {
776  meth.addr = vmeth->addr;
777  meth.vtable_offset = vmeth->vtable_offset;
778  RzAnalysisFunction *fcn = rz_analysis_get_function_at(context->analysis, vmeth->addr);
779  meth.name = fcn ? rz_str_new(fcn->name) : rz_str_newf("virtual_%" PFMT64d, meth.vtable_offset);
780  // Temporarily set as attr name
781  meth.real_name = fcn ? rz_str_new(fcn->name) : rz_str_newf("virtual_%" PFMT64d, meth.vtable_offset);
782  meth.method_type = RZ_ANALYSIS_CLASS_METHOD_VIRTUAL;
783  } else {
784  RzAnalysisMethod exist_meth;
785  if (rz_analysis_class_method_get_by_addr(context->analysis, class_name, vmeth->addr, &exist_meth) == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
786  meth.addr = vmeth->addr;
787  meth.name = rz_str_new(exist_meth.name);
788  meth.real_name = rz_str_new(exist_meth.real_name);
789  meth.vtable_offset = vmeth->vtable_offset;
790  meth.method_type = RZ_ANALYSIS_CLASS_METHOD_VIRTUAL;
791  rz_analysis_class_method_fini(&exist_meth);
792  }
793  }
794  rz_analysis_class_method_set(context->analysis, class_name, &meth);
796  }
797 }
798 
805 static void add_class_bases(RVTableContext *context, const class_type_info *cti) {
806  class_type_info base_info;
807  int i;
808 
809  switch (cti->type) {
811  si_class_type_info *si_class = (void *)cti;
812  ut64 base_addr = si_class->base_class_addr;
813  base_addr += VT_WORD_SIZE(context); // offset to name
814  if (rtti_itanium_read_type_name(context, base_addr, &base_info)) {
815  // TODO in future, store the RTTI offset from vtable and use it
816  RzAnalysisBaseClass base = { .class_name = base_info.name, .offset = 0 };
817  rz_analysis_class_base_set(context->analysis, cti->name, &base);
819  }
820  } break;
822  vmi_class_type_info *vmi_class = (void *)cti;
823  for (i = 0; i < vmi_class->vmi_base_count; i++) {
824  base_class_type_info *base_class_info = vmi_class->vmi_bases + i;
825  ut64 base_addr = base_class_info->base_class_addr + VT_WORD_SIZE(context); // offset to name
826  if (rtti_itanium_read_type_name(context, base_addr, &base_info)) {
827  // TODO in future, store the RTTI offset from vtable and use it
828  RzAnalysisBaseClass base = { .class_name = base_info.name, .offset = 0 };
829  rz_analysis_class_base_set(context->analysis, cti->name, &base);
831  }
832  }
833  } break;
834  default: // other types have no parent classes
835  break;
836  }
837 }
838 
840  RzVector *vec = rz_analysis_class_method_get_all(analysis, cti->name);
841  RzAnalysisMethod *meth;
842  rz_vector_foreach(vec, meth) {
843  if (!rz_str_cmp(meth->real_name, cti->name, -1)) {
844  meth->method_type = RZ_ANALYSIS_CLASS_METHOD_CONSTRUCTOR;
845  rz_analysis_class_method_set(analysis, cti->name, meth);
846  continue;
847  } else if (rz_str_startswith(meth->real_name, "~") && !rz_str_cmp(meth->real_name + 1, cti->name, -1)) {
848  if (meth->method_type == RZ_ANALYSIS_CLASS_METHOD_VIRTUAL) {
849  meth->method_type = RZ_ANALYSIS_CLASS_METHOD_VIRTUAL_DESTRUCTOR;
850  } else {
851  meth->method_type = RZ_ANALYSIS_CLASS_METHOD_DESTRUCTOR;
852  }
853  rz_analysis_class_method_set(analysis, cti->name, meth);
854  continue;
855  }
856  }
857  rz_vector_free(vec);
858 }
859 
860 RZ_API void rz_analysis_rtti_itanium_recover_all(RVTableContext *context, RzList /*<RVTableInfo *>*/ *vtables) {
861  RzList /*<class_type_info>*/ *rtti_list = rz_list_new();
862  rtti_list->free = rtti_itanium_type_info_free;
863  // to escape multiple same infos from multiple inheritance
864  SetU *unique_rttis = set_u_new();
865 
866  RzListIter *iter;
867  RVTableInfo *vtable;
868  rz_list_foreach (vtables, iter, vtable) {
869  class_type_info *cti = rtti_itanium_type_info_new(context, vtable->saddr);
870  if (!cti) {
871  continue;
872  }
873 
874  rz_analysis_class_create(context->analysis, cti->name);
875  // can't we name virtual functions virtual even without RTTI?
876  recovery_apply_vtable(context, cti->name, vtable);
877  // Temporarily detect by method name
878  detect_constructor_destructor(context->analysis, cti);
879 
880  // we only need one of a kind
881  if (set_u_contains(unique_rttis, cti->typeinfo_addr)) {
883  } else {
884  set_u_add(unique_rttis, cti->typeinfo_addr);
885  rz_list_append(rtti_list, cti);
886  }
887  }
888 
889  class_type_info *cti;
890  rz_list_foreach (rtti_list, iter, cti) {
891  add_class_bases(context, cti);
892  }
893 
894  set_u_free(unique_rttis);
895  rz_list_free(rtti_list);
896 }
RZ_API RzAnalysisFunction * rz_analysis_get_function_at(RzAnalysis *analysis, ut64 addr)
Definition: function.c:184
lzma_index ** i
Definition: index.h:629
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
RZ_API bool rz_analysis_class_method_exists_by_addr(RzAnalysis *analysis, const char *class_name, ut64 addr)
Definition: class.c:643
RZ_API RzAnalysisClassErr rz_analysis_class_base_set(RzAnalysis *analysis, const char *class_name, RzAnalysisBaseClass *base)
Definition: class.c:983
RZ_API RzVector * rz_analysis_class_method_get_all(RzAnalysis *analysis, const char *class_name)
Definition: class.c:735
RZ_API void rz_analysis_class_base_fini(RzAnalysisBaseClass *base)
Definition: class.c:880
RZ_API void rz_analysis_class_vtable_fini(RzAnalysisVTable *vtable)
Definition: class.c:1069
RZ_API RzAnalysisClassErr rz_analysis_class_vtable_set(RzAnalysis *analysis, const char *class_name, RzAnalysisVTable *vtable)
Definition: class.c:1153
RZ_API RzAnalysisClassErr rz_analysis_class_method_set(RzAnalysis *analysis, const char *class_name, RzAnalysisMethod *meth)
Definition: class.c:770
RZ_API void rz_analysis_class_method_fini(RzAnalysisMethod *meth)
Definition: class.c:606
RZ_API RzAnalysisClassErr rz_analysis_class_create(RzAnalysis *analysis, const char *name)
Definition: class.c:79
RZ_API RzAnalysisClassErr rz_analysis_class_method_get_by_addr(RzAnalysis *analysis, const char *class_name, ut64 addr, RzAnalysisMethod *method)
Definition: class.c:659
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
unsigned short prefix[65536]
Definition: gun.c:163
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
int type
Definition: mipsasm.c:17
const char * name
Definition: op.c:541
static void rtti_itanium_print_si_class_type_info(si_class_type_info *si_cti, const char *prefix)
Definition: rtti_itanium.c:408
static vmi_class_type_info * rtti_itanium_vmi_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable)
Definition: rtti_itanium.c:228
RZ_API void rz_analysis_rtti_itanium_recover_all(RVTableContext *context, RzList *vtables)
Definition: rtti_itanium.c:860
RZ_API char * rz_analysis_rtti_itanium_demangle_class_name(RVTableContext *context, const char *name)
Definition: rtti_itanium.c:743
static class_type_info * raw_rtti_parse(RVTableContext *context, ut64 vtable_addr, ut64 rtti_addr)
Try to parse as much valid looking RTTI as you can.
Definition: rtti_itanium.c:544
static void rtti_itanium_vmi_class_type_info_free(vmi_class_type_info *cti)
Definition: rtti_itanium.c:168
static RTypeInfoType rtti_itanium_type_info_type_from_flag(RVTableContext *context, ut64 atAddress)
Definition: rtti_itanium.c:448
struct vmi_class_type_info_t vmi_class_type_info
#define NAME_BUF_SIZE
Definition: rtti_itanium.c:14
static void rtti_itanium_vmi_class_type_info_fini(vmi_class_type_info *vmi_cti)
Definition: rtti_itanium.c:161
static const char * type_to_string(RTypeInfoType type)
Definition: rtti_itanium.c:297
static bool rtti_itanium_vmi_class_type_info_init(RVTableContext *context, ut64 addr, vmi_class_type_info *vmi_cti)
Definition: rtti_itanium.c:177
RTypeInfoType
Definition: rtti_itanium.c:19
@ RZ_TYPEINFO_TYPE_SI_CLASS
Definition: rtti_itanium.c:22
@ RZ_TYPEINFO_TYPE_CLASS
Definition: rtti_itanium.c:21
@ RZ_TYPEINFO_TYPE_VMI_CLASS
Definition: rtti_itanium.c:23
@ RZ_TYPEINFO_TYPE_UNKNOWN
Definition: rtti_itanium.c:20
static void rtti_itanium_print_si_class_type_info_json(si_class_type_info *si_cti)
Definition: rtti_itanium.c:427
#define VMI_CLASS_TYPE_INFO_NAME
Definition: rtti_itanium.c:11
static void rtti_itanium_print_class_type_info(class_type_info *cti, const char *prefix)
Definition: rtti_itanium.c:309
static void rtti_itanium_print_class_type_info_json(class_type_info *cti)
Definition: rtti_itanium.c:326
RZ_API bool rz_analysis_rtti_itanium_print_at_vtable(RVTableContext *context, ut64 addr, RzOutputMode mode)
Definition: rtti_itanium.c:700
struct base_class_type_info_t base_class_type_info
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)
Definition: rtti_itanium.c:502
static void rtti_itanium_class_type_info_fini(class_type_info *cti)
Definition: rtti_itanium.c:116
static void rtti_itanium_print_vmi_class_type_info_json(vmi_class_type_info *vmi_cti)
Definition: rtti_itanium.c:377
static si_class_type_info * rtti_itanium_si_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable)
Definition: rtti_itanium.c:280
static bool rtti_itanium_read_type_name(RVTableContext *context, ut64 addr, class_type_info *cti)
Definition: rtti_itanium.c:75
static void rtti_itanium_si_class_type_info_free(si_class_type_info *cti)
Definition: rtti_itanium.c:251
static class_type_info * rtti_itanium_class_type_info_new(RVTableContext *context, ut64 addr, ut64 source_vtable)
Definition: rtti_itanium.c:144
static bool rtti_itanium_si_class_type_info_init(RVTableContext *context, ut64 addr, si_class_type_info *si_cti)
Definition: rtti_itanium.c:260
static void rtti_itanium_print_vmi_class_type_info(vmi_class_type_info *vmi_cti, const char *prefix)
Definition: rtti_itanium.c:346
#define SI_CLASS_TYPE_INFO_NAME
Definition: rtti_itanium.c:12
static class_type_info * create_class_type(ut64 vtable_addr, char *name, ut64 name_addr, bool unique_name, ut64 typeinfo_addr, ut64 source_vtable)
Definition: rtti_itanium.c:486
#define VT_WORD_SIZE(ctx)
Definition: rtti_itanium.c:16
static char * rtti_itanium_read_type_name_custom(RVTableContext *context, ut64 addr, ut64 *str_addr, bool *unique_name)
Definition: rtti_itanium.c:97
static void add_class_bases(RVTableContext *context, const class_type_info *cti)
Add any base class information about the type into analysis/classes.
Definition: rtti_itanium.c:805
#define CLASS_TYPE_INFO_NAME
Definition: rtti_itanium.c:13
static bool rtti_itanium_class_type_info_init(RVTableContext *context, ut64 addr, class_type_info *cti)
Definition: rtti_itanium.c:131
static void detect_constructor_destructor(RzAnalysis *analysis, class_type_info *cti)
Definition: rtti_itanium.c:839
static void rtti_itanium_si_class_type_info_fini(si_class_type_info *si_cti)
Definition: rtti_itanium.c:245
struct class_type_info_t class_type_info
static class_type_info * rtti_itanium_type_info_new(RVTableContext *context, ut64 vtable_addr)
Definition: rtti_itanium.c:637
static void rtti_itanium_class_type_info_free(class_type_info *cti)
Definition: rtti_itanium.c:122
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)
Definition: rtti_itanium.c:518
struct si_class_type_info_t si_class_type_info
static bool can_section_contain_rtti_vpointer(RzBinSection *section)
Definition: rtti_itanium.c:474
static void recovery_apply_vtable(RVTableContext *context, const char *class_name, RVTableInfo *vtable_info)
Definition: rtti_itanium.c:761
static void rtti_itanium_type_info_free(void *info)
Definition: rtti_itanium.c:679
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define rz_return_val_if_reached(val)
Definition: rz_assert.h:122
#define rz_return_if_reached()
Definition: rz_assert.h:116
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_kb(PJ *j, const char *k, bool v)
Definition: pj.c:177
RZ_API PJ * pj_k(PJ *j, const char *k)
Definition: pj.c:104
RZ_API PJ * pj_end(PJ *j)
Definition: pj.c:87
RZ_API const char * pj_string(PJ *pj)
Definition: pj.c:57
RZ_API void pj_free(PJ *j)
Definition: pj.c:34
RZ_API PJ * pj_o(PJ *j)
Definition: pj.c:75
RZ_API PJ * pj_ks(PJ *j, const char *k, const char *v)
Definition: pj.c:170
RZ_API PJ * pj_kn(PJ *j, const char *k, ut64 n)
Definition: pj.c:121
RZ_API PJ * pj_a(PJ *j)
Definition: pj.c:81
RZ_API PJ * pj_kN(PJ *j, const char *k, st64 n)
Definition: pj.c:128
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API int rz_str_cmp(const char *dst, const char *orig, int len)
Definition: str.c:974
RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string ends with a specifc sequence of characters (case sensitive)
Definition: str.c:3329
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
RzOutputMode
Enum to describe the way data are printed.
Definition: rz_types.h:38
@ RZ_OUTPUT_MODE_JSON
Definition: rz_types.h:40
#define PFMT64x
Definition: rz_types.h:393
#define UT64_MAX
Definition: rz_types_base.h:86
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
RZ_API void rz_vector_free(RzVector *vec)
Definition: vector.c:75
RZ_API SetU * set_u_new(void)
Definition: set.c:30
RZ_API void set_u_free(SetU *s)
Definition: set.c:46
RZ_API void set_u_add(SetU *s, ut64 u)
Definition: set.c:34
RZ_API bool set_u_contains(SetU *s, ut64 u)
Definition: set.c:38
HtUP SetU
Definition: set.h:22
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
enum base_class_type_info_t::flags_masks_e flags_masks
RTypeInfoType type
Definition: rtti_itanium.c:27
Definition: z80asm.h:102
Definition: rz_pj.h:12
RzFlag * flags
Definition: rz_core.h:330
char * name
Definition: rz_flag.h:35
RzListFree free
Definition: rz_list.h:21
RTypeInfoType type
Definition: rtti_itanium.c:46
enum vmi_class_type_info_t::vmi_flags_masks_e vmi_flags_masks
RTypeInfoType type
Definition: rtti_itanium.c:57
base_class_type_info * vmi_bases
Definition: rtti_itanium.c:66
RZ_API ut64 rz_analysis_vtable_info_get_size(RVTableContext *context, RVTableInfo *vtable)
Definition: vtable.c:37
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58