Rizin
unix-like reverse engineering framework and cli tools
rtti_msvc.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2018 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2009-2018 maijin <maijin21@gmail.com>
3 // SPDX-FileCopyrightText: 2009-2018 thestr4ng3r <info@florianmaerkl.de>
4 // SPDX-License-Identifier: LGPL-3.0-only
5 
6 #include "rz_analysis.h"
7 
8 #define NAME_BUF_SIZE 64
9 #define BASE_CLASSES_MAX 32
10 
13  ut32 vtable_offset; // offset of the vtable within class
14  ut32 cd_offset; // constructor displacement offset
15  ut32 type_descriptor_addr; // only a relative offset for 64bit
16  ut32 class_descriptor_addr; // only a relative offset for 64bit
17  ut32 object_base; // only for 64bit, see rtti_msvc_read_complete_object_locator()
19 
22  ut32 attributes; // bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
24  ut32 base_class_array_addr; // only a relative offset for 64bit
26 
28  ut32 type_descriptor_addr; // only a relative offset for 64bit
30  struct {
31  st32 mdisp; // member displacement
32  st32 pdisp; // vbtable displacement
33  st32 vdisp; // displacement inside vbtable
34  } where;
37 
38 typedef struct rtti_type_descriptor_t {
41  char *name;
43 
45  free(td->name);
46  td->name = NULL;
47 }
48 
49 static inline ut64 rtti_msvc_addr(RVTableContext *context, ut64 col_addr, ut64 col_base, ut32 addr) {
50  if (context->word_size != 8) {
51  return addr;
52  }
53  return addr + (col_addr - col_base);
54 }
55 
57  if (addr == UT64_MAX) {
58  return false;
59  }
60 
61  ut8 buf[6 * sizeof(ut32)];
62  int colSize = 5 * sizeof(ut32);
63  if (context->word_size == 8) {
64  colSize += sizeof(ut32);
65  }
66  if (colSize > sizeof(buf)) {
67  return false;
68  }
69 
70  if (!context->analysis->iob.read_at(context->analysis->iob.io, addr, buf, colSize)) {
71  return false;
72  }
73 
74  ut32 (*read_at_32)(const void *src, size_t offset) = context->analysis->big_endian ? rz_read_at_be32 : rz_read_at_le32;
75  col->signature = read_at_32(buf, 0);
76  col->vtable_offset = read_at_32(buf, 4);
77  col->cd_offset = read_at_32(buf, 8);
78 
79  int offsetSize = RZ_MIN(context->word_size, 4);
80  col->type_descriptor_addr = (ut32)rz_read_ble(buf + 12, (bool)context->analysis->big_endian, offsetSize * 8);
81  col->class_descriptor_addr = (ut32)rz_read_ble(buf + 12 + offsetSize, (bool)context->analysis->big_endian, offsetSize * 8);
82  if (context->word_size == 8) {
83  // 64bit is special:
84  // Type Descriptor and Class Hierarchy Descriptor addresses are computed
85  // by 32 bit values *(col+12) + *(col+0x14)
86  // and *(col+16) + *(col+0x14) respectively
87  col->object_base = read_at_32(buf, 20);
88  } else {
89  col->object_base = 0;
90  }
91 
92  return true;
93 }
94 
96  if (addr == UT64_MAX) {
97  return false;
98  }
99 
100  ut8 buf[4 * sizeof(ut32)];
101  int chdSize = 3 * sizeof(ut32) + RZ_MIN(4, context->word_size);
102  if (chdSize > sizeof(buf)) {
103  return false;
104  }
105 
106  if (!context->analysis->iob.read_at(context->analysis->iob.io, addr, buf, chdSize)) {
107  return false;
108  }
109 
110  ut32 (*read_at_32)(const void *src, size_t offset) = context->analysis->big_endian ? rz_read_at_be32 : rz_read_at_le32;
111  chd->signature = read_at_32(buf, 0);
112  chd->attributes = read_at_32(buf, 4);
113  chd->num_base_classes = read_at_32(buf, 8);
114  if (context->word_size <= 4) {
115  chd->base_class_array_addr = (ut32)rz_read_ble(buf + 12, (bool)context->analysis->big_endian, context->word_size * 8);
116  } else {
117  // 64bit is special, like in Complete Object Locator.
118  // Only the offset from the base from Complete Object Locator
119  // is contained in Class Hierarchy Descriptor
120  chd->base_class_array_addr = read_at_32(buf, 12);
121  }
122  return true;
123 }
124 
126  return context->word_size + 5 * sizeof(ut32);
127 }
128 
130  if (addr == UT64_MAX) {
131  return false;
132  }
133 
134  ut8 buf[sizeof(ut64) + 5 * sizeof(ut32)];
136  if (bcdSize > sizeof(buf)) {
137  return false;
138  }
139 
140  if (!context->analysis->iob.read_at(context->analysis->iob.io, addr, buf, bcdSize)) {
141  return false;
142  }
143 
144  ut32 (*read_at_32)(const void *src, size_t offset) = context->analysis->big_endian ? rz_read_at_be32 : rz_read_at_le32;
145  int typeDescriptorAddrSize = RZ_MIN(context->word_size, 4);
146  bcd->type_descriptor_addr = (ut32)rz_read_ble(buf, (bool)context->analysis->big_endian, typeDescriptorAddrSize * 8);
147  size_t offset = (size_t)typeDescriptorAddrSize;
148  bcd->num_contained_bases = read_at_32(buf, offset);
149  bcd->where.mdisp = read_at_32(buf, offset + sizeof(ut32));
150  bcd->where.pdisp = read_at_32(buf, offset + 2 * sizeof(ut32));
151  bcd->where.vdisp = read_at_32(buf, offset + 3 * sizeof(ut32));
152  bcd->attributes = read_at_32(buf, offset + 4 * sizeof(ut32));
153  return true;
154 }
155 
156 static RzList *rtti_msvc_read_base_class_array(RVTableContext *context, ut32 num_base_classes, ut64 base, ut32 offset) {
157  if (base == UT64_MAX || offset == UT32_MAX || num_base_classes == UT32_MAX) {
158  return NULL;
159  }
160 
161  RzList *ret = rz_list_newf(free);
162  if (!ret) {
163  return NULL;
164  }
165 
166  ut64 addr = base + offset;
167  ut64 stride = RZ_MIN(context->word_size, 4);
168 
169  if (num_base_classes > BASE_CLASSES_MAX) {
170  RZ_LOG_DEBUG("Length of base class array at 0x%08" PFMT64x " exceeds %d.\n", addr, BASE_CLASSES_MAX);
171  num_base_classes = BASE_CLASSES_MAX;
172  }
173 
175  while (num_base_classes > 0) {
176  if (rz_cons_is_breaked()) {
177  break;
178  }
179 
180  ut64 bcdAddr;
181  if (context->word_size <= 4) {
182  if (!context->read_addr(context->analysis, addr, &bcdAddr)) {
183  break;
184  }
185  if (bcdAddr == UT32_MAX) {
186  break;
187  }
188  } else {
189  // special offset calculation for 64bit
190  ut8 tmp[4] = { 0 };
191  if (!context->analysis->iob.read_at(context->analysis->iob.io, addr, tmp, 4)) {
192  rz_list_free(ret);
193  return NULL;
194  }
195  ut32 (*read_32)(const void *src) = context->analysis->big_endian ? rz_read_be32 : rz_read_le32;
196  ut32 bcdOffset = read_32(tmp);
197  if (bcdOffset == UT32_MAX) {
198  break;
199  }
200  bcdAddr = base + bcdOffset;
201  }
202 
204  if (!bcd) {
205  break;
206  }
207  if (!rtti_msvc_read_base_class_descriptor(context, bcdAddr, bcd)) {
208  free(bcd);
209  break;
210  }
211  rz_list_append(ret, bcd);
212  addr += stride;
213  num_base_classes--;
214  }
216 
217  if (num_base_classes > 0) {
218  // there was an error in the loop above
219  rz_list_free(ret);
220  return NULL;
221  }
222 
223  return ret;
224 }
225 
227  if (addr == UT64_MAX) {
228  return false;
229  }
230 
231  if (!context->read_addr(context->analysis, addr, &td->vtable_addr)) {
232  return false;
233  }
234  if (!context->read_addr(context->analysis, addr + context->word_size, &td->spare)) {
235  return false;
236  }
237 
238  ut64 nameAddr = addr + 2 * context->word_size;
240  ut64 bufOffset = 0;
241  size_t nameLen = 0;
242  bool endFound = false;
243  bool endInvalid = false;
244  while (1) {
245  context->analysis->iob.read_at(context->analysis->iob.io, nameAddr + bufOffset, buf, sizeof(buf));
246  int i;
247  for (i = 0; i < sizeof(buf); i++) {
248  if (buf[i] == '\0') {
249  endFound = true;
250  break;
251  }
252  if (buf[i] == 0xff) {
253  endInvalid = true;
254  break;
255  }
256  nameLen++;
257  }
258  if (endFound || endInvalid) {
259  break;
260  }
261  bufOffset += sizeof(buf);
262  }
263 
264  if (endInvalid) {
265  return false;
266  }
267 
268  td->name = malloc(nameLen + 1);
269  if (!td->name) {
270  return false;
271  }
272 
273  if (bufOffset == 0) {
274  memcpy(td->name, buf, nameLen + 1);
275  } else {
276  context->analysis->iob.read_at(context->analysis->iob.io, nameAddr,
277  (ut8 *)td->name, (int)(nameLen + 1));
278  }
279 
280  return true;
281 }
282 
284  rz_cons_printf("%sComplete Object Locator at 0x%08" PFMT64x ":\n"
285  "%s\tsignature: %#x\n"
286  "%s\tvftableOffset: %#x\n"
287  "%s\tcdOffset: %#x\n"
288  "%s\ttypeDescriptorAddr: 0x%08" PFMT32x "\n"
289  "%s\tclassDescriptorAddr: 0x%08" PFMT32x "\n",
290  prefix, addr,
291  prefix, col->signature,
292  prefix, col->vtable_offset,
293  prefix, col->cd_offset,
296  rz_cons_printf("%s\tobjectBase: 0x%08" PFMT32x "\n\n",
297  prefix, col->object_base);
298 }
299 
301  pj_o(pj);
302  pj_kn(pj, "signature", col->signature);
303  pj_kn(pj, "vftable_offset", col->vtable_offset);
304  pj_kn(pj, "cd_offset", col->cd_offset);
305  pj_kn(pj, "type_desc_addr", col->type_descriptor_addr);
306  pj_kn(pj, "class_desc_addr", col->class_descriptor_addr);
307  pj_kn(pj, "object_base", col->object_base);
308  pj_end(pj);
309 }
310 
312  rz_cons_printf("%sType Descriptor at 0x%08" PFMT64x ":\n"
313  "%s\tvtableAddr: 0x%08" PFMT64x "\n"
314  "%s\tspare: 0x%08" PFMT64x "\n"
315  "%s\tname: %s\n\n",
316  prefix, addr,
317  prefix, td->vtable_addr,
318  prefix, td->spare,
319  prefix, td->name);
320 }
321 
323  pj_o(pj);
324  pj_kn(pj, "vtable_addr", td->vtable_addr);
325  pj_kn(pj, "spare", td->spare);
326  pj_ks(pj, "name", td->name);
327  pj_end(pj);
328 }
329 
331  rz_cons_printf("%sClass Hierarchy Descriptor at 0x%08" PFMT64x ":\n"
332  "%s\tsignature: %#x\n"
333  "%s\tattributes: %#x\n"
334  "%s\tnumBaseClasses: %#x\n"
335  "%s\tbaseClassArrayAddr: 0x%08" PFMT32x "\n\n",
336  prefix, addr,
337  prefix, chd->signature,
338  prefix, chd->attributes,
339  prefix, chd->num_base_classes,
341 }
342 
344  pj_o(pj);
345  pj_kn(pj, "signature", chd->signature);
346  pj_kn(pj, "attributes", chd->attributes);
347  pj_kn(pj, "num_base_classes", chd->num_base_classes);
348  pj_kn(pj, "base_class_array_addr", chd->base_class_array_addr);
349  pj_end(pj);
350 }
351 
353  rz_cons_printf("%sBase Class Descriptor:\n"
354  "%s\ttypeDescriptorAddr: 0x%08" PFMT32x "\n"
355  "%s\tnumContainedBases: %#x\n"
356  "%s\twhere:\n"
357  "%s\t\tmdisp: %d\n"
358  "%s\t\tpdisp: %d\n"
359  "%s\t\tvdisp: %d\n"
360  "%s\tattributes: %#x\n\n",
361  prefix,
364  prefix,
365  prefix, bcd->where.mdisp,
366  prefix, bcd->where.pdisp,
367  prefix, bcd->where.vdisp,
368  prefix, bcd->attributes);
369 }
370 
372  pj_o(pj);
373  pj_kn(pj, "type_desc_addr", bcd->type_descriptor_addr);
374  pj_kn(pj, "num_contained_bases", bcd->num_contained_bases);
375  pj_ko(pj, "where");
376  pj_ki(pj, "mdisp", bcd->where.mdisp);
377  pj_ki(pj, "pdisp", bcd->where.pdisp);
378  pj_ki(pj, "vdisp", bcd->where.vdisp);
379  pj_end(pj);
380  pj_kn(pj, "attributes", bcd->attributes);
381  pj_end(pj);
382 }
383 
393 RZ_API char *rz_analysis_rtti_msvc_demangle_class_name(RVTableContext *context, const char *name) {
394  if (!name) {
395  return NULL;
396  }
397  size_t original_len = strlen(name);
398  if (original_len < 7 || (strncmp(name, ".?AV", 4) != 0 && strncmp(name, ".?AU", 4) != 0) || strncmp(name + original_len - 2, "@@", 2) != 0) {
399  return NULL;
400  }
401  char *ret = context->analysis->binb.demangle(NULL, "msvc", name, 0, false);
402  if (ret && *ret) {
403  char *n = strchr(ret, ' ');
404  if (n && *(++n)) {
405  char *tmp = strdup(n);
406  free(ret);
407  ret = tmp;
408  } else {
409  RZ_FREE(ret);
410  }
411  } else {
412  RZ_FREE(ret);
413  }
414  return ret;
415 }
416 
420  RZ_LOG_ERROR("Failed to parse complete object locator at 0x%08" PFMT64x "\n", addr);
421  return;
422  }
423 
424  if (mode == 'j') {
425  PJ *pj = pj_new();
426  if (!pj) {
427  return;
428  }
430  rz_cons_print(pj_string(pj));
431  pj_free(pj);
432  } else {
434  }
435 }
436 
438  rtti_type_descriptor td = { 0 };
440  RZ_LOG_ERROR("Failed to parse type descriptor at 0x%08" PFMT64x "\n", addr);
441  return;
442  }
443 
444  if (mode == 'j') {
445  PJ *pj = pj_new();
446  if (!pj) {
447  return;
448  }
450  rz_cons_print(pj_string(pj));
451  pj_free(pj);
452  } else {
454  }
455 
457 }
458 
462  RZ_LOG_ERROR("Failed to parse class hierarchy descriptor at 0x%08" PFMT64x "\n", addr);
463  return;
464  }
465 
466  if (mode == 'j') {
467  PJ *pj = pj_new();
468  if (!pj) {
469  return;
470  }
472  rz_cons_print(pj_string(pj));
473  pj_free(pj);
474  } else {
476  }
477 }
478 
482  RZ_LOG_ERROR("Failed to parse base class descriptor at 0x%08" PFMT64x "\n", addr);
483  return;
484  }
485 
486  if (mode == 'j') {
487  PJ *pj = pj_new();
488  if (!pj) {
489  return;
490  }
492  rz_cons_print(pj_string(pj));
493  pj_free(pj);
494  } else {
496  }
497 }
498 
499 static bool rtti_msvc_print_complete_object_locator_recurse(RVTableContext *context, ut64 atAddress, RzOutputMode mode, bool strict) {
500  ut64 colRefAddr = atAddress - context->word_size;
501  ut64 colAddr;
502  if (!context->read_addr(context->analysis, colRefAddr, &colAddr)) {
503  return false;
504  }
505 
506  // complete object locator
508  if (!rtti_msvc_read_complete_object_locator(context, colAddr, &col)) {
509  if (!strict) {
510  RZ_LOG_ERROR("Failed to parse complete object locator at 0x%08" PFMT64x " (referenced from 0x%08" PFMT64x ")\n", colAddr, colRefAddr);
511  }
512  return false;
513  }
514 
515  // type descriptor
516  ut64 typeDescriptorAddr = rtti_msvc_addr(context, colAddr, col.object_base, col.type_descriptor_addr);
517  rtti_type_descriptor td = { 0 };
518  if (!rtti_msvc_read_type_descriptor(context, typeDescriptorAddr, &td)) {
519  if (!strict) {
520  RZ_LOG_ERROR("Failed to parse type descriptor at 0x%08" PFMT64x "\n", typeDescriptorAddr);
521  }
522  return false;
523  }
524 
525  // class hierarchy descriptor
526  ut64 classHierarchyDescriptorAddr = rtti_msvc_addr(context, colAddr, col.object_base, col.class_descriptor_addr);
528  if (!rtti_msvc_read_class_hierarchy_descriptor(context, classHierarchyDescriptorAddr, &chd)) {
529  if (!strict) {
530  RZ_LOG_ERROR("Failed to parse class hierarchy descriptor at 0x%08" PFMT64x "\n", classHierarchyDescriptorAddr);
531  }
533  return false;
534  }
535 
536  ut64 base = chd.base_class_array_addr;
537  ut32 baseClassArrayOffset = 0;
538  if (context->word_size == 8) {
539  base = colAddr - col.object_base;
540  baseClassArrayOffset = chd.base_class_array_addr;
541  }
542 
543  RzList *baseClassArray = rtti_msvc_read_base_class_array(context, chd.num_base_classes, base, baseClassArrayOffset);
544  if (!baseClassArray) {
545  if (!strict) {
546  RZ_LOG_ERROR("Failed to parse base class array starting at 0x%08" PFMT64x "\n", base + baseClassArrayOffset);
547  }
549  return false;
550  }
551 
552  // print
553  bool use_json = mode == RZ_OUTPUT_MODE_JSON;
554  PJ *pj = NULL;
555  if (use_json) {
556  pj = pj_new();
557  if (!pj) {
558  return false;
559  }
560  pj_o(pj);
561  pj_k(pj, "complete_object_locator");
563  pj_k(pj, "type_desc");
565  pj_k(pj, "class_hierarchy_desc");
567  pj_ka(pj, "base_classes");
568  } else {
569  rtti_msvc_print_complete_object_locator(&col, colAddr, "");
570  rtti_msvc_print_type_descriptor(&td, typeDescriptorAddr, "\t");
571  rtti_msvc_print_class_hierarchy_descriptor(&chd, classHierarchyDescriptorAddr, "\t");
572  }
573 
574  // base classes
575  RzListIter *bcdIter;
577  rz_list_foreach (baseClassArray, bcdIter, bcd) {
578  if (use_json) {
579  pj_o(pj);
580  pj_k(pj, "desc");
582  } else {
584  }
585 
586  ut64 baseTypeDescriptorAddr = rtti_msvc_addr(context, colAddr, col.object_base, bcd->type_descriptor_addr);
587  rtti_type_descriptor btd = { 0 };
588  if (rtti_msvc_read_type_descriptor(context, baseTypeDescriptorAddr, &btd)) {
589  if (use_json) {
590  pj_k(pj, "type_desc");
592  } else {
593  rtti_msvc_print_type_descriptor(&btd, baseTypeDescriptorAddr, "\t\t\t");
594  }
596  } else {
597  if (!strict) {
598  RZ_LOG_ERROR("Failed to parse type descriptor at 0x%08" PFMT64x "\n", baseTypeDescriptorAddr);
599  }
600  }
601 
602  if (use_json) {
603  pj_end(pj);
604  }
605  }
606  if (use_json) {
607  pj_end(pj);
608  pj_end(pj);
609  rz_cons_print(pj_string(pj));
610  pj_free(pj);
611  }
612 
614  return true;
615 }
616 
619 }
620 
622 
627 
630  bool valid;
631  RVTableInfo *vtable;
635  RzList *bcd; // <rtti_base_class_descriptor>
636  RzVector base_td; // <RecoveryBaseDescriptor>
638 
641  if (!col) {
642  return NULL;
643  }
645  return col;
646 }
647 
649  if (!col) {
650  return;
651  }
652  rz_list_free(col->bcd);
653  rz_vector_clear(&col->base_td);
654  free(col);
655 }
656 
659  bool valid;
662 };
663 
666  if (!td) {
667  return NULL;
668  }
669 
670  td->addr = 0;
671  td->valid = false;
672  memset(&td->td, 0, sizeof(td->td));
673  td->col = NULL;
674  // td->vtable = NULL;
675  return td;
676 }
677 
679  if (!td) {
680  return;
681  }
683  free(td);
684 }
685 
687  RVTableContext *vt_context;
688  RzPVector vtables; // <RVTableInfo>
689  RzPVector complete_object_locators; // <RecoveryCompleteObjectLocator>
690  HtUP *addr_col; // <ut64, RecoveryCompleteObjectLocator *>
691  RzPVector type_descriptors; // <RecoveryTypeDescriptor>
692  HtUP *addr_td; // <ut64, RecoveryTypeDescriptor *>
693  HtUP *col_td_classes; // <ut64, char *> contains already recovered classes for col (or td) addresses
695 
697 
699  RecoveryCompleteObjectLocator *col = ht_up_find(context->addr_col, addr, NULL);
700  if (col) {
701  return col;
702  }
703 
705  if (!col) {
706  return NULL;
707  }
708  rz_pvector_push(&context->complete_object_locators, col);
709  ht_up_insert(context->addr_col, addr, col);
710  col->addr = addr;
711  col->valid = rtti_msvc_read_complete_object_locator(context->vt_context, addr, &col->col);
712  if (!col->valid) {
713  return col;
714  }
715  col->vtable = vtable;
716 
717  ut64 td_addr = rtti_msvc_addr(context->vt_context, col->addr, col->col.object_base, col->col.type_descriptor_addr);
718  col->td = recovery_analysis_type_descriptor(context, td_addr, col);
719  if (!col->td->valid) {
720  col->valid = false;
721  return col;
722  }
723  col->td->col = col;
724 
725  ut64 chd_addr = rtti_msvc_addr(context->vt_context, col->addr, col->col.object_base, col->col.class_descriptor_addr);
726  col->valid &= rtti_msvc_read_class_hierarchy_descriptor(context->vt_context, chd_addr, &col->chd);
727  if (!col->valid) {
728  return col;
729  }
730 
731  ut64 base = col->chd.base_class_array_addr;
732  ut32 baseClassArrayOffset = 0;
733  if (context->vt_context->word_size == 8) {
734  base = col->addr - col->col.object_base;
735  baseClassArrayOffset = col->chd.base_class_array_addr;
736  }
737 
738  col->bcd = rtti_msvc_read_base_class_array(context->vt_context, col->chd.num_base_classes, base, baseClassArrayOffset);
739  if (!col->bcd) {
740  col->valid = false;
741  return col;
742  }
743 
744  rz_vector_reserve(&col->base_td, (size_t)col->bcd->length);
745  RzListIter *bcdIter;
747  rz_list_foreach (col->bcd, bcdIter, bcd) {
748  ut64 base_td_addr = rtti_msvc_addr(context->vt_context, col->addr, col->col.object_base, bcd->type_descriptor_addr);
750  if (td == col->td) {
751  continue;
752  }
753  if (!td->valid) {
754  RZ_LOG_DEBUG("Type descriptor of base is invalid.\n");
755  continue;
756  }
757  RecoveryBaseDescriptor *base_desc = rz_vector_push(&col->base_td, NULL);
758  base_desc->bcd = bcd;
759  base_desc->td = td;
760  }
761 
762  return col;
763 }
764 
766  RecoveryTypeDescriptor *td = ht_up_find(context->addr_td, addr, NULL);
767  if (td) {
768  if (col != NULL) {
769  td->col = col;
770  }
771  return td;
772  }
773 
775  if (!td) {
776  return NULL;
777  }
778  rz_pvector_push(&context->type_descriptors, td);
779  ht_up_insert(context->addr_td, addr, td);
780  td->addr = addr;
781  td->valid = rtti_msvc_read_type_descriptor(context->vt_context, addr, &td->td);
782  if (!td->valid) {
783  return td;
784  }
785 
786  td->col = col;
787 
788  return td;
789 }
790 
791 static char *unique_class_name(RzAnalysis *analysis, const char *original_name) {
792  if (!rz_analysis_class_exists(analysis, original_name)) {
793  return strdup(original_name);
794  }
795 
796  char *name = NULL;
797  RZ_LOG_DEBUG("Class name '%s' was already taken!\n", original_name);
798  int i = 1;
799  do {
800  free(name);
801  name = rz_str_newf("%s.%d", original_name, i++);
802  if (!name) {
803  return NULL;
804  }
805  } while (rz_analysis_class_exists(analysis, name));
806 
807  return name;
808 }
809 
810 static void recovery_apply_vtable(RVTableContext *context, const char *class_name, RVTableInfo *vtable_info) {
811  if (!vtable_info) {
812  return;
813  }
814 
816 
817  RzAnalysisVTable vtable;
818  vtable.size = size;
819  vtable.id = NULL;
820  vtable.offset = 0;
821  vtable.addr = vtable_info->saddr;
822  rz_analysis_class_vtable_set(context->analysis, class_name, &vtable);
824 
825  RVTableMethodInfo *vmeth;
826  rz_vector_foreach(&vtable_info->methods, vmeth) {
827  RzAnalysisMethod meth;
828  if (!rz_analysis_class_method_exists_by_addr(context->analysis, class_name, vmeth->addr)) {
829  meth.addr = vmeth->addr;
830  meth.vtable_offset = vmeth->vtable_offset;
831  RzAnalysisFunction *fcn = rz_analysis_get_function_at(context->analysis, vmeth->addr);
832  meth.name = fcn ? rz_str_new(fcn->name) : rz_str_newf("virtual_%" PFMT64d, meth.vtable_offset);
833  // Temporarily set as attr name
834  meth.real_name = fcn ? rz_str_new(fcn->name) : rz_str_newf("virtual_%" PFMT64d, meth.vtable_offset);
835  meth.method_type = RZ_ANALYSIS_CLASS_METHOD_VIRTUAL;
836  } else {
837  RzAnalysisMethod exist_meth;
838  if (rz_analysis_class_method_get_by_addr(context->analysis, class_name, vmeth->addr, &exist_meth) == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
839  meth.addr = vmeth->addr;
840  meth.name = rz_str_new(exist_meth.name);
841  meth.real_name = rz_str_new(exist_meth.real_name);
842  meth.vtable_offset = vmeth->vtable_offset;
843  meth.method_type = RZ_ANALYSIS_CLASS_METHOD_VIRTUAL;
844  rz_analysis_class_method_fini(&exist_meth);
845  }
846  }
847  rz_analysis_class_method_set(context->analysis, class_name, &meth);
849  }
850 }
851 
854 
855 static void recovery_apply_bases(RRTTIMSVCAnalContext *context, const char *class_name, RzVector *base_descs) {
856  RecoveryBaseDescriptor *base_desc;
857  rz_vector_foreach(base_descs, base_desc) {
858  RecoveryTypeDescriptor *base_td = base_desc->td;
859  if (!base_td->valid) {
860  RZ_LOG_WARN("Base td is invalid!\n");
861  continue;
862  }
863 
864  const char *base_class_name;
865  if (!base_td->col) {
866  RZ_LOG_DEBUG("Base td %s has no col. Falling back to recovery from td only.\n", base_td->td.name);
867  base_class_name = recovery_apply_type_descriptor(context, base_td);
868  } else {
869  base_class_name = recovery_apply_complete_object_locator(context, base_td->col);
870  }
871 
872  if (!base_class_name) {
873  RZ_LOG_DEBUG("Failed to convert !base td->col or td to a class\n");
874  continue;
875  }
876 
877  RzAnalysisBaseClass base;
878  base.id = NULL;
879  base.offset = (ut64)base_desc->bcd->where.mdisp;
880  base.class_name = strdup(base_class_name);
881  rz_analysis_class_base_set(context->vt_context->analysis, class_name, &base);
883  }
884 }
885 
887  if (!col->valid) {
888  return NULL;
889  }
890 
891  if (!col->td) {
892  RZ_LOG_DEBUG("No recovery type descriptor for recovery object locator at 0x%" PFMT64x "\n", col->addr);
893  return NULL;
894  }
895 
896  RzAnalysis *analysis = context->vt_context->analysis;
897 
898  const char *existing = ht_up_find(context->col_td_classes, col->addr, NULL);
899  if (existing != NULL) {
900  return existing;
901  }
902 
903  char *name = rz_analysis_rtti_msvc_demangle_class_name(context->vt_context, col->td->td.name);
904  if (!name) {
905  RZ_LOG_DEBUG("Failed to demangle a class name: \"%s\"\n", col->td->td.name);
906  name = strdup(col->td->td.name);
907  if (!name) {
908  return NULL;
909  }
910  }
911 
912  char *tmp = name;
913  name = unique_class_name(analysis, name);
914  free(tmp);
915  if (!name) {
916  return NULL;
917  }
918 
919  rz_analysis_class_create(analysis, name);
920  ht_up_insert(context->col_td_classes, col->addr, name);
921 
922  recovery_apply_vtable(context->vt_context, name, col->vtable);
924 
925  return name;
926 }
927 
929  if (!td->valid) {
930  return NULL;
931  }
932 
933  RzAnalysis *analysis = context->vt_context->analysis;
934 
935  const char *existing = ht_up_find(context->col_td_classes, td->addr, NULL);
936  if (existing != NULL) {
937  return existing;
938  }
939 
941  if (!name) {
942  RZ_LOG_DEBUG("Failed to demangle a class name: \"%s\"\n", td->td.name);
943  name = strdup(td->td.name);
944  if (!name) {
945  return NULL;
946  }
947  }
948 
949  rz_analysis_class_create(analysis, name);
950  ht_up_insert(context->col_td_classes, td->addr, name);
951 
952  if (!td->col || !td->col->valid) {
953  return name;
954  }
955 
956  recovery_apply_vtable(context->vt_context, name, td->col->vtable);
958 
959  return name;
960 }
961 
962 void str_value_free(HtUPKv *kv) {
963  free(kv->value);
964 }
965 
966 RZ_API void rz_analysis_rtti_msvc_recover_all(RVTableContext *vt_context, RzList /*<RVTableInfo *>*/ *vtables) {
968  context.vt_context = vt_context;
970 
972  context.addr_col = ht_up_new0();
974  context.addr_td = ht_up_new0();
975 
976  context.col_td_classes = ht_up_new(NULL, (HtUPKvFreeFunc)str_value_free, (HtUPCalcSizeV)strlen);
977 
978  RzListIter *vtableIter;
979  RVTableInfo *table;
980  rz_list_foreach (vtables, vtableIter, table) {
981  ut64 colRefAddr = table->saddr - vt_context->word_size;
982  ut64 colAddr;
983  if (!vt_context->read_addr(vt_context->analysis, colRefAddr, &colAddr)) {
984  continue;
985  }
987  }
988 
989  void **it;
990 #if USE_TD_RECOVERY
991  rz_pvector_foreach (&context.type_descriptors, it) {
992  RecoveryTypeDescriptor *td = *it;
993  if (!td->valid) {
994  continue;
995  }
997  }
998 #else
999  rz_pvector_foreach (&context.complete_object_locators, it) {
1000  RecoveryCompleteObjectLocator *col = *it;
1001  if (!col->valid) {
1002  continue;
1003  }
1005  }
1006 #endif
1007 
1008  rz_pvector_clear(&context.vtables);
1009  rz_pvector_clear(&context.complete_object_locators);
1010  ht_up_free(context.addr_col);
1011  rz_pvector_clear(&context.type_descriptors);
1012  ht_up_free(context.addr_td);
1013  ht_up_free(context.col_td_classes);
1014 }
RZ_API RzAnalysisFunction * rz_analysis_get_function_at(RzAnalysis *analysis, ut64 addr)
Definition: function.c:184
#define PFMT32x
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
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 void rz_analysis_class_base_fini(RzAnalysisBaseClass *base)
Definition: class.c:880
RZ_API bool rz_analysis_class_exists(RzAnalysis *analysis, const char *name)
Definition: class.c:167
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 void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
#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
voidpf uLong offset
Definition: ioapi.h:144
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
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 * malloc(size_t size)
Definition: malloc.c:123
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
int n
Definition: mipsasm.c:19
const char * name
Definition: op.c:541
static void rtti_msvc_print_base_class_descriptor_json(PJ *pj, rtti_base_class_descriptor *bcd)
Definition: rtti_msvc.c:371
static ut64 rtti_msvc_base_class_descriptor_size(RVTableContext *context)
Definition: rtti_msvc.c:125
struct recovery_complete_object_locator_t RecoveryCompleteObjectLocator
RZ_API void rz_analysis_rtti_msvc_print_base_class_descriptor(RVTableContext *context, ut64 addr, int mode)
Definition: rtti_msvc.c:479
static void rtti_msvc_print_class_hierarchy_descriptor_json(PJ *pj, rtti_class_hierarchy_descriptor *chd)
Definition: rtti_msvc.c:343
RZ_API void rz_analysis_rtti_msvc_print_type_descriptor(RVTableContext *context, ut64 addr, int mode)
Definition: rtti_msvc.c:437
void recovery_complete_object_locator_free(RecoveryCompleteObjectLocator *col)
Definition: rtti_msvc.c:648
RZ_API void rz_analysis_rtti_msvc_recover_all(RVTableContext *vt_context, RzList *vtables)
Definition: rtti_msvc.c:966
#define NAME_BUF_SIZE
Definition: rtti_msvc.c:8
RZ_API void rz_analysis_rtti_msvc_print_complete_object_locator(RVTableContext *context, ut64 addr, int mode)
Definition: rtti_msvc.c:417
static void rtti_msvc_print_type_descriptor_json(PJ *pj, rtti_type_descriptor *td)
Definition: rtti_msvc.c:322
RZ_API char * rz_analysis_rtti_msvc_demangle_class_name(RVTableContext *context, const char *name)
Definition: rtti_msvc.c:393
RZ_API void rz_analysis_rtti_msvc_print_class_hierarchy_descriptor(RVTableContext *context, ut64 addr, int mode)
Definition: rtti_msvc.c:459
static const char * recovery_apply_complete_object_locator(RRTTIMSVCAnalContext *context, RecoveryCompleteObjectLocator *col)
Definition: rtti_msvc.c:886
static RzList * rtti_msvc_read_base_class_array(RVTableContext *context, ut32 num_base_classes, ut64 base, ut32 offset)
Definition: rtti_msvc.c:156
static bool rtti_msvc_print_complete_object_locator_recurse(RVTableContext *context, ut64 atAddress, RzOutputMode mode, bool strict)
Definition: rtti_msvc.c:499
static void rtti_msvc_print_complete_object_locator_json(PJ *pj, rtti_complete_object_locator *col)
Definition: rtti_msvc.c:300
struct rtti_class_hierarchy_descriptor_t rtti_class_hierarchy_descriptor
static bool rtti_msvc_read_class_hierarchy_descriptor(RVTableContext *context, ut64 addr, rtti_class_hierarchy_descriptor *chd)
Definition: rtti_msvc.c:95
RecoveryTypeDescriptor * recovery_analysis_type_descriptor(RRTTIMSVCAnalContext *context, ut64 addr, RecoveryCompleteObjectLocator *col)
Definition: rtti_msvc.c:765
static const char * recovery_apply_type_descriptor(RRTTIMSVCAnalContext *context, RecoveryTypeDescriptor *td)
Definition: rtti_msvc.c:928
void str_value_free(HtUPKv *kv)
Definition: rtti_msvc.c:962
RecoveryCompleteObjectLocator * recovery_complete_object_locator_new()
Definition: rtti_msvc.c:639
static ut64 rtti_msvc_addr(RVTableContext *context, ut64 col_addr, ut64 col_base, ut32 addr)
Definition: rtti_msvc.c:49
static void rtti_type_descriptor_fini(rtti_type_descriptor *td)
Definition: rtti_msvc.c:44
RecoveryCompleteObjectLocator * recovery_analysis_complete_object_locator(RRTTIMSVCAnalContext *context, ut64 addr, RVTableInfo *vtable)
Definition: rtti_msvc.c:698
static void rtti_msvc_print_base_class_descriptor(rtti_base_class_descriptor *bcd, const char *prefix)
Definition: rtti_msvc.c:352
static void rtti_msvc_print_class_hierarchy_descriptor(rtti_class_hierarchy_descriptor *chd, ut64 addr, const char *prefix)
Definition: rtti_msvc.c:330
static bool rtti_msvc_read_base_class_descriptor(RVTableContext *context, ut64 addr, rtti_base_class_descriptor *bcd)
Definition: rtti_msvc.c:129
RecoveryTypeDescriptor * recovery_type_descriptor_new()
Definition: rtti_msvc.c:664
static bool rtti_msvc_read_complete_object_locator(RVTableContext *context, ut64 addr, rtti_complete_object_locator *col)
Definition: rtti_msvc.c:56
struct rtti_base_class_descriptor_t rtti_base_class_descriptor
static void rtti_msvc_print_complete_object_locator(rtti_complete_object_locator *col, ut64 addr, const char *prefix)
Definition: rtti_msvc.c:283
static void rtti_msvc_print_type_descriptor(rtti_type_descriptor *td, ut64 addr, const char *prefix)
Definition: rtti_msvc.c:311
static void recovery_apply_bases(RRTTIMSVCAnalContext *context, const char *class_name, RzVector *base_descs)
Definition: rtti_msvc.c:855
RZ_API bool rz_analysis_rtti_msvc_print_at_vtable(RVTableContext *context, ut64 addr, RzOutputMode mode, bool strict)
Definition: rtti_msvc.c:617
struct rtti_msvc_analysis_context_t RRTTIMSVCAnalContext
struct recovery_base_descriptor_t RecoveryBaseDescriptor
static bool rtti_msvc_read_type_descriptor(RVTableContext *context, ut64 addr, rtti_type_descriptor *td)
Definition: rtti_msvc.c:226
struct rtti_complete_object_locator_t rtti_complete_object_locator
#define BASE_CLASSES_MAX
Definition: rtti_msvc.c:9
void recovery_type_descriptor_free(RecoveryTypeDescriptor *td)
Definition: rtti_msvc.c:678
struct rtti_type_descriptor_t rtti_type_descriptor
static void recovery_apply_vtable(RVTableContext *context, const char *class_name, RVTableInfo *vtable_info)
Definition: rtti_msvc.c:810
static char * unique_class_name(RzAnalysis *analysis, const char *original_name)
Definition: rtti_msvc.c:791
static ut32 rz_read_at_le32(const void *src, size_t offset)
Definition: rz_endian.h:248
static ut32 rz_read_le32(const void *src)
Definition: rz_endian.h:239
static ut64 rz_read_ble(const void *src, bool big_endian, int size)
Definition: rz_endian.h:517
static ut32 rz_read_at_be32(const void *src, size_t offset)
Definition: rz_endian.h:93
static ut32 rz_read_be32(const void *src)
Definition: rz_endian.h:87
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define RZ_LOG_DEBUG(fmtstr,...)
Definition: rz_log.h:49
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API PJ * pj_ko(PJ *j, const char *k)
Definition: pj.c:156
RZ_API PJ * pj_ka(PJ *j, const char *k)
Definition: pj.c:163
RZ_API PJ * pj_new(void)
Definition: pj.c:25
RZ_API PJ * pj_ki(PJ *j, const char *k, int d)
Definition: pj.c:149
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 char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEW(x)
Definition: rz_types.h:285
RzOutputMode
Enum to describe the way data are printed.
Definition: rz_types.h:38
@ RZ_OUTPUT_MODE_JSON
Definition: rz_types.h:40
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
#define UT32_MAX
Definition: rz_types_base.h:99
#define UT64_MAX
Definition: rz_types_base.h:86
#define st32
Definition: rz_types_base.h:12
RZ_API void rz_pvector_init(RzPVector *vec, RzPVectorFree free)
Definition: vector.c:298
RZ_API void * rz_vector_reserve(RzVector *vec, size_t capacity)
Definition: vector.c:214
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
void(* RzPVectorFree)(void *e)
Definition: rz_vector.h:43
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
RZ_API void rz_vector_clear(RzVector *vec)
Definition: vector.c:68
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:33
RZ_API void rz_pvector_clear(RzPVector *vec)
Definition: vector.c:326
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
static int
Definition: sfsocketcall.h:114
int size_t
Definition: sftypes.h:40
Definition: z80asm.h:102
Definition: rz_pj.h:12
rtti_base_class_descriptor * bcd
Definition: rtti_msvc.c:624
RecoveryTypeDescriptor * td
Definition: rtti_msvc.c:625
RecoveryTypeDescriptor * td
Definition: rtti_msvc.c:633
rtti_class_hierarchy_descriptor chd
Definition: rtti_msvc.c:634
rtti_complete_object_locator col
Definition: rtti_msvc.c:632
rtti_type_descriptor td
Definition: rtti_msvc.c:660
RecoveryCompleteObjectLocator * col
Definition: rtti_msvc.c:661
struct rtti_base_class_descriptor_t::@22 where
RVTableContext * vt_context
Definition: rtti_msvc.c:687
RzPVector complete_object_locators
Definition: rtti_msvc.c:689
ut32 length
Definition: rz_list.h:22
RZ_API ut64 rz_analysis_vtable_info_get_size(RVTableContext *context, RVTableInfo *vtable)
Definition: vtable.c:37
RZ_API void rz_analysis_vtable_info_free(RVTableInfo *vtable)
Definition: vtable.c:29
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58