Rizin
unix-like reverse engineering framework and cli tools
mach0_classes.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015-2020 inisider <inisider@gmail.com>
2 // SPDX-FileCopyrightText: 2015-2020 pancake <pancake@nopcode.org>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include "../../i/private.h"
6 #include "mach0_classes.h"
7 
8 #define RO_META (1 << 0)
9 #define MAX_CLASS_NAME_LEN 256
10 
11 #ifdef RZ_BIN_MACH064
12 #define FAST_DATA_MASK 0x00007ffffffffff8UL
13 #else
14 #define FAST_DATA_MASK 0xfffffffcUL
15 #endif
16 
17 #define METHOD_LIST_FLAG_IS_SMALL 0x80000000
18 #define METHOD_LIST_FLAG_IS_PREOPT 0x3
19 #define METHOD_LIST_ENTSIZE_FLAG_MASK 0xffff0003
20 
21 #define RO_DATA_PTR(x) ((x)&FAST_DATA_MASK)
22 
23 struct MACH0_(SMethodList) {
24  ut32 entsize;
25  ut32 count;
26  /* SMethod first; These structures follow inline */
27 };
28 
29 struct MACH0_(SMethod) {
30  mach0_ut name; /* SEL (32/64-bit pointer) */
31  mach0_ut types; /* const char * (32/64-bit pointer) */
32  mach0_ut imp; /* IMP (32/64-bit pointer) */
33 };
34 
35 struct MACH0_(SClass) {
36  mach0_ut isa; /* SClass* (32/64-bit pointer) */
37  mach0_ut superclass; /* SClass* (32/64-bit pointer) */
38  mach0_ut cache; /* Cache (32/64-bit pointer) */
39  mach0_ut vtable; /* IMP * (32/64-bit pointer) */
40  mach0_ut data; /* SClassRoT * (32/64-bit pointer) */
41 };
42 
43 struct MACH0_(SClassRoT) {
44  ut32 flags;
45  ut32 instanceStart;
46  ut32 instanceSize;
47 #ifdef RZ_BIN_MACH064
48  ut32 reserved;
49 #endif
50  mach0_ut ivarLayout; /* const uint8_t* (32/64-bit pointer) */
51  mach0_ut name; /* const char* (32/64-bit pointer) */
52  mach0_ut baseMethods; /* const SMEthodList* (32/64-bit pointer) */
53  mach0_ut baseProtocols; /* const SProtocolList* (32/64-bit pointer) */
54  mach0_ut ivars; /* const SIVarList* (32/64-bit pointer) */
55  mach0_ut weakIvarLayout; /* const uint8_t * (32/64-bit pointer) */
56  mach0_ut baseProperties; /* const SObjcPropertyList* (32/64-bit pointer) */
57 };
58 
59 struct MACH0_(SProtocolList) {
60  mach0_ut count; /* uintptr_t (a 32/64-bit value) */
61  /* SProtocol* list[0]; These pointers follow inline */
62 };
63 
64 struct MACH0_(SProtocol) {
65  mach0_ut isa; /* id* (32/64-bit pointer) */
66  mach0_ut name; /* const char * (32/64-bit pointer) */
67  mach0_ut protocols; /* SProtocolList* (32/64-bit pointer) */
68  mach0_ut instanceMethods; /* SMethodList* (32/64-bit pointer) */
69  mach0_ut classMethods; /* SMethodList* (32/64-bit pointer) */
70  mach0_ut optionalInstanceMethods; /* SMethodList* (32/64-bit pointer) */
71  mach0_ut optionalClassMethods; /* SMethodList* (32/64-bit pointer) */
72  mach0_ut instanceProperties; /* struct SObjcPropertyList* (32/64-bit pointer) */
73 };
74 
75 struct MACH0_(SIVarList) {
76  ut32 entsize;
77  ut32 count;
78  /* SIVar first; These structures follow inline */
79 };
80 
81 struct MACH0_(SIVar) {
82  mach0_ut offset; /* uintptr_t * (32/64-bit pointer) */
83  mach0_ut name; /* const char * (32/64-bit pointer) */
84  mach0_ut type; /* const char * (32/64-bit pointer) */
85  ut32 alignment;
86  ut32 size;
87 };
88 
89 struct MACH0_(SObjcProperty) {
90  mach0_ut name; /* const char * (32/64-bit pointer) */
91  mach0_ut attributes; /* const char * (32/64-bit pointer) */
92 };
93 
94 struct MACH0_(SObjcPropertyList) {
95  ut32 entsize;
96  ut32 count;
97  /* struct SObjcProperty first; These structures follow inline */
98 };
99 
100 struct MACH0_(SCategory) {
101  mach0_ut name;
102  mach0_ut targetClass;
103  mach0_ut instanceMethods;
104  mach0_ut classMethods;
105  mach0_ut protocols;
106  mach0_ut properties;
107 };
108 
109 static mach0_ut va2pa(mach0_ut p, ut32 *offset, ut32 *left, RzBinFile *bf);
110 static void copy_sym_name_with_namespace(char *class_name, char *read_name, RzBinSymbol *sym);
111 static void get_ivar_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass);
112 static void get_objc_property_list(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass);
113 static void get_method_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, char *class_name, RzBinClass *klass, bool is_static, objc_cache_opt_info *oi);
115 static void get_class_ro_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, ut32 *is_meta_class, RzBinClass *klass, objc_cache_opt_info *oi);
117 static bool read_ptr_pa(RzBinFile *bf, RzBuffer *buf, ut64 paddr, mach0_ut *out);
118 static bool read_ptr_va(RzBinFile *bf, RzBuffer *buf, ut64 vaddr, mach0_ut *out);
119 static char *read_str(RzBinFile *bf, RzBuffer *buf, mach0_ut p, ut32 *offset, ut32 *left);
120 static char *get_class_name(mach0_ut p, RzBinFile *bf, RzBuffer *buf);
121 static bool is_thumb(RzBinFile *bf) {
122  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
123  if (bin->hdr.cputype == 12) {
124  if (bin->hdr.cpusubtype == 9) {
125  return true;
126  }
127  }
128  return false;
129 }
130 
131 static mach0_ut va2pa(mach0_ut p, ut32 *offset, ut32 *left, RzBinFile *bf) {
132  rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, 0);
133 
134  mach0_ut r;
135  mach0_ut addr;
136 
137  RzListIter *iter = NULL;
138  RzBinSection *s = NULL;
139  RzBinObject *obj = bf->o;
140 
141  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)obj->bin_obj;
142  if (bin->va2pa) {
143  return bin->va2pa(p, offset, left, bf);
144  }
145 
146  const RzList *sctns = bin->sections_cache;
147  if (!sctns) {
148  sctns = rz_bin_plugin_mach.sections(bf);
149  if (!sctns) {
150  return 0;
151  }
152  }
153 
154  addr = p;
155  rz_list_foreach (sctns, iter, s) {
156  if (addr >= s->vaddr && addr < s->vaddr + s->vsize) {
157  if (offset) {
158  *offset = addr - s->vaddr;
159  }
160  if (left) {
161  *left = s->vsize - (addr - s->vaddr);
162  }
163  r = (s->paddr - obj->boffset + (addr - s->vaddr));
164  return r;
165  }
166  }
167 
168  if (offset) {
169  *offset = 0;
170  }
171  if (left) {
172  *left = 0;
173  }
174 
175  return 0;
176 }
177 
178 static void copy_sym_name_with_namespace(char *class_name, char *read_name, RzBinSymbol *sym) {
179  if (!class_name) {
180  class_name = "";
181  }
182  sym->classname = strdup(class_name);
183  sym->name = strdup(read_name);
184 }
185 
186 static int sort_by_offset(const void *_a, const void *_b) {
187  RzBinField *a = (RzBinField *)_a;
188  RzBinField *b = (RzBinField *)_b;
189  return a->offset - b->offset;
190 }
191 
193  struct MACH0_(SIVarList) il = { 0 };
194  struct MACH0_(SIVar) i;
195  mach0_ut r;
196  ut32 offset, left, j;
197 
198  int len;
199  bool bigendian;
200  mach0_ut ivar_offset;
201  RzBinField *field = NULL;
202  ut8 sivarlist[sizeof(struct MACH0_(SIVarList))] = { 0 };
203  ut8 sivar[sizeof(struct MACH0_(SIVar))] = { 0 };
204  ut8 offs[sizeof(mach0_ut)] = { 0 };
205 
206  if (!bf || !bf->o || !bf->o->bin_obj || !bf->o->info) {
207  RZ_LOG_ERROR("Invalid RzBinFile pointer\n");
208  return;
209  }
210  bigendian = bf->o->info->big_endian;
211  if (!(r = va2pa(p, &offset, &left, bf))) {
212  return;
213  }
214  if (r + left < r || r + sizeof(struct MACH0_(SIVarList)) < r) {
215  return;
216  }
217  if (r > bf->size || r + left > bf->size) {
218  return;
219  }
220  if (r + sizeof(struct MACH0_(SIVarList)) > bf->size) {
221  return;
222  }
223  if (left < sizeof(struct MACH0_(SIVarList))) {
224  if (rz_buf_read_at(buf, r, sivarlist, left) != left) {
225  return;
226  }
227  } else {
228  len = rz_buf_read_at(buf, r, sivarlist, sizeof(struct MACH0_(SIVarList)));
229  if (len != sizeof(struct MACH0_(SIVarList))) {
230  return;
231  }
232  }
233  il.entsize = rz_read_ble(&sivarlist[0], bigendian, 32);
234  il.count = rz_read_ble(&sivarlist[4], bigendian, 32);
235  p += sizeof(struct MACH0_(SIVarList));
236  offset += sizeof(struct MACH0_(SIVarList));
237 
238  for (j = 0; j < il.count; j++) {
239  r = va2pa(p, &offset, &left, bf);
240  if (!r) {
241  return;
242  }
243  field = RZ_NEW0(RzBinField);
244  memset(&i, '\0', sizeof(struct MACH0_(SIVar)));
245  if (r + left < r || r + sizeof(struct MACH0_(SIVar)) < r) {
246  goto error;
247  }
248  if (r > bf->size || r + left > bf->size) {
249  goto error;
250  }
251  if (r + sizeof(struct MACH0_(SIVar)) > bf->size) {
252  goto error;
253  }
254  if (left < sizeof(struct MACH0_(SIVar))) {
255  if (rz_buf_read_at(buf, r, sivar, left) != left) {
256  goto error;
257  }
258  } else {
259  len = rz_buf_read_at(buf, r, sivar, sizeof(struct MACH0_(SIVar)));
260  if (len != sizeof(struct MACH0_(SIVar))) {
261  goto error;
262  }
263  }
264 #if RZ_BIN_MACH064
265  i.offset = rz_read_ble(&sivar[0], bigendian, 64);
266  i.name = rz_read_ble(&sivar[8], bigendian, 64);
267  i.type = rz_read_ble(&sivar[16], bigendian, 64);
268  i.alignment = rz_read_ble(&sivar[24], bigendian, 32);
269  i.size = rz_read_ble(&sivar[28], bigendian, 32);
270 #else
271  i.offset = rz_read_ble(&sivar[0], bigendian, 32);
272  i.name = rz_read_ble(&sivar[4], bigendian, 32);
273  i.type = rz_read_ble(&sivar[8], bigendian, 32);
274  i.alignment = rz_read_ble(&sivar[12], bigendian, 32);
275  i.size = rz_read_ble(&sivar[16], bigendian, 32);
276 #endif
277  field->vaddr = i.offset;
278  mach0_ut offset_at = va2pa(i.offset, NULL, &left, bf);
279 
280  if (offset_at > bf->size) {
281  goto error;
282  }
283  if (offset_at + sizeof(ivar_offset) > bf->size) {
284  goto error;
285  }
286  if (offset_at != 0 && left >= sizeof(mach0_ut)) {
287  len = rz_buf_read_at(buf, offset_at, offs, sizeof(mach0_ut));
288  if (len != sizeof(mach0_ut)) {
289  RZ_LOG_ERROR("Cannot read mach0_ut\n");
290  goto error;
291  }
292  ivar_offset = rz_read_ble(offs, bigendian, 8 * sizeof(mach0_ut));
293  field->offset = ivar_offset;
294  }
295  r = va2pa(i.name, NULL, &left, bf);
296  if (r) {
297  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
298  if (r + left < r) {
299  goto error;
300  }
301  if (r > bf->size || r + left > bf->size) {
302  goto error;
303  }
304  char *name;
305  if (bin->has_crypto) {
306  name = strdup("some_encrypted_data");
307  left = strlen(name) + 1;
308  } else {
309  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
310  name = malloc(name_len + 1);
311  len = rz_buf_read_at(buf, r, (ut8 *)name, name_len);
312  if (len < 1) {
313  RZ_LOG_ERROR("Cannot read class name from buffer\n");
314  RZ_FREE(name);
315  goto error;
316  }
317  name[name_len] = 0;
318  }
319  // XXX the field name shouldnt contain the class name
320  field->name = rz_str_newf("%s::%s%s", klass->name, "(ivar)", name);
321  RZ_FREE(name);
322  }
323 
324  r = va2pa(i.type, NULL, &left, bf);
325  if (r) {
326  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
327  int is_crypted = bin->has_crypto;
328  if (r + left < r) {
329  goto error;
330  }
331  if (r > bf->size || r + left > bf->size) {
332  goto error;
333  }
334  char *type = NULL;
335  if (is_crypted == 1) {
336  type = strdup("some_encrypted_data");
337  // left = strlen (name) + 1;
338  } else {
339  int type_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
340  type = calloc(1, type_len + 1);
341  if (type) {
342  rz_buf_read_at(buf, r, (ut8 *)type, type_len);
343  type[type_len] = 0;
344  }
345  }
346  if (type) {
347  field->type = type;
348  type = NULL;
349  } else {
350  field->type = NULL;
351  }
352  rz_list_append(klass->fields, field);
353  } else {
354  goto error;
355  }
356  p += sizeof(struct MACH0_(SIVar));
357  offset += sizeof(struct MACH0_(SIVar));
358  }
359  if (!rz_list_empty(klass->fields)) {
361  }
362  RzBinField *isa_field = RZ_NEW0(RzBinField);
363  isa_field->name = strdup("isa");
364  isa_field->size = sizeof(mach0_ut);
365  isa_field->type = strdup("struct objc_class *");
366  isa_field->vaddr = 0;
367  isa_field->offset = 0;
368  rz_list_prepend(klass->fields, isa_field);
369  return;
370 error:
371  rz_bin_field_free(field);
372 }
373 
376  struct MACH0_(SObjcPropertyList) opl;
377  struct MACH0_(SObjcProperty) op;
378  mach0_ut r;
379  ut32 offset, left, j;
380  char *name = NULL;
381  int len;
382  bool bigendian;
383  RzBinField *property = NULL;
384  ut8 sopl[sizeof(struct MACH0_(SObjcPropertyList))] = { 0 };
385  ut8 sop[sizeof(struct MACH0_(SObjcProperty))] = { 0 };
386 
387  if (!bf || !bf->o || !bf->o->bin_obj || !bf->o->info) {
388  RZ_LOG_ERROR("Invalid RzBinFile pointer\n");
389  return;
390  }
391  bigendian = bf->o->info->big_endian;
392  r = va2pa(p, &offset, &left, bf);
393  if (!r) {
394  return;
395  }
396  memset(&opl, '\0', sizeof(struct MACH0_(SObjcPropertyList)));
397  if (r + left < r || r + sizeof(struct MACH0_(SObjcPropertyList)) < r) {
398  return;
399  }
400  if (r > bf->size || r + left > bf->size) {
401  return;
402  }
403  if (r + sizeof(struct MACH0_(SObjcPropertyList)) > bf->size) {
404  return;
405  }
406  if (left < sizeof(struct MACH0_(SObjcPropertyList))) {
407  if (rz_buf_read_at(buf, r, sopl, left) != left) {
408  return;
409  }
410  } else {
411  len = rz_buf_read_at(buf, r, sopl, sizeof(struct MACH0_(SObjcPropertyList)));
412  if (len != sizeof(struct MACH0_(SObjcPropertyList))) {
413  return;
414  }
415  }
416 
417  opl.entsize = rz_read_ble(&sopl[0], bigendian, 32);
418  opl.count = rz_read_ble(&sopl[4], bigendian, 32);
419 
420  p += sizeof(struct MACH0_(SObjcPropertyList));
421  offset += sizeof(struct MACH0_(SObjcPropertyList));
422  for (j = 0; j < opl.count; j++) {
423  r = va2pa(p, &offset, &left, bf);
424  if (!r) {
425  return;
426  }
427 
428  if (!(property = RZ_NEW0(RzBinField))) {
429  return;
430  }
431 
432  memset(&op, '\0', sizeof(struct MACH0_(SObjcProperty)));
433 
434  if (r + left < r || r + sizeof(struct MACH0_(SObjcProperty)) < r) {
435  goto error;
436  }
437  if (r > bf->size || r + left > bf->size) {
438  goto error;
439  }
440  if (r + sizeof(struct MACH0_(SObjcProperty)) > bf->size) {
441  goto error;
442  }
443 
444  if (left < sizeof(struct MACH0_(SObjcProperty))) {
445  if (rz_buf_read_at(buf, r, sop, left) != left) {
446  goto error;
447  }
448  } else {
449  len = rz_buf_read_at(buf, r, sop, sizeof(struct MACH0_(SObjcProperty)));
450  if (len != sizeof(struct MACH0_(SObjcProperty))) {
451  goto error;
452  }
453  }
454  op.name = rz_read_ble(&sop[0], bigendian, 8 * sizeof(mach0_ut));
455  op.attributes = rz_read_ble(&sop[sizeof(mach0_ut)], bigendian, 8 * sizeof(mach0_ut));
456  r = va2pa(op.name, NULL, &left, bf);
457  if (r) {
458  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
459  if (r > bf->size || r + left > bf->size) {
460  goto error;
461  }
462  if (r + left < r) {
463  goto error;
464  }
465  if (bin->has_crypto) {
466  name = strdup("some_encrypted_data");
467  left = strlen(name) + 1;
468  } else {
469  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
470  name = calloc(1, name_len + 1);
471  if (!name) {
472  goto error;
473  }
474  if (rz_buf_read_at(buf, r, (ut8 *)name, name_len) != name_len) {
475  goto error;
476  }
477  }
478  property->name = rz_str_newf("%s::%s%s", klass->name,
479  "(property)", name);
480  RZ_FREE(name);
481  }
482 #if 0
483  r = va2pa (op.attributes, NULL, &left, bf);
484  if (r != 0) {
485  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *) bf->o->bin_obj;
486  int is_crypted = bin->has_crypto;
487 
488  if (r > bf->size || r + left > bf->size) goto error;
489  if (r + left < r) goto error;
490 
491  if (is_crypted == 1) {
492  name = strdup ("some_encrypted_data");
493  left = strlen (name) + 1;
494  } else {
495  name = malloc (left);
496  len = rz_buf_read_at (buf, r, (ut8 *)name, left);
497  if (len == 0 || len == -1) goto error;
498  }
499 
500  RZ_FREE (name);
501  }
502 #endif
503  rz_list_append(klass->fields, property);
504 
505  p += sizeof(struct MACH0_(SObjcProperty));
506  offset += sizeof(struct MACH0_(SObjcProperty));
507  }
508  return;
509 error:
510  RZ_FREE(property);
511  RZ_FREE(name);
512  return;
513 }
514 
516 static void get_method_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, char *class_name, RzBinClass *klass, bool is_static, objc_cache_opt_info *oi) {
517  struct MACH0_(SMethodList) ml;
518  mach0_ut r;
519  ut32 offset, left, i;
520  char *name = NULL;
521  char *rtype = NULL;
522  int len;
523  bool bigendian;
524  ut8 sml[sizeof(struct MACH0_(SMethodList))] = { 0 };
525  ut8 sm[sizeof(struct MACH0_(SMethod))] = { 0 };
526 
527  RzBinSymbol *method = NULL;
528  if (!bf || !bf->o || !bf->o->bin_obj || !bf->o->info) {
529  RZ_LOG_ERROR("Invalid RzBinFile pointer\n");
530  return;
531  }
532  bigendian = bf->o->info->big_endian;
533  r = va2pa(p, &offset, &left, bf);
534  if (!r) {
535  return;
536  }
537  memset(&ml, '\0', sizeof(struct MACH0_(SMethodList)));
538 
539  if (r + left < r || r + sizeof(struct MACH0_(SMethodList)) < r) {
540  return;
541  }
542  if (r > bf->size) {
543  return;
544  }
545  if (r + sizeof(struct MACH0_(SMethodList)) > bf->size) {
546  return;
547  }
548  if (left < sizeof(struct MACH0_(SMethodList))) {
549  if (rz_buf_read_at(buf, r, sml, left) != left) {
550  return;
551  }
552  } else {
553  len = rz_buf_read_at(buf, r, sml, sizeof(struct MACH0_(SMethodList)));
554  if (len != sizeof(struct MACH0_(SMethodList))) {
555  return;
556  }
557  }
558  ml.entsize = rz_read_ble(&sml[0], bigendian, 32);
559  ml.count = rz_read_ble(&sml[4], bigendian, 32);
560  if (ml.count < 1 || ml.count > ST32_MAX) {
561  return;
562  }
563  if (r + (ml.count * (ml.entsize & ~METHOD_LIST_ENTSIZE_FLAG_MASK)) > bf->size) {
564  return;
565  }
566 
567  bool is_small = (ml.entsize & METHOD_LIST_FLAG_IS_SMALL) != 0;
568  ut8 mlflags = ml.entsize & 0x3;
569 
570  p += sizeof(struct MACH0_(SMethodList));
571  offset += sizeof(struct MACH0_(SMethodList));
572 
573  size_t read_size = is_small ? 3 * sizeof(ut32) : sizeof(struct MACH0_(SMethod));
574 
575  for (i = 0; i < ml.count; i++) {
576  r = va2pa(p, &offset, &left, bf);
577  if (!r || r == -1) {
578  return;
579  }
580 
581  if (!(method = RZ_NEW0(RzBinSymbol))) {
582  return;
583  }
584  struct MACH0_(SMethod) m;
585  memset(&m, '\0', sizeof(struct MACH0_(SMethod)));
586  if (r + left < r || r + read_size < r) {
587  goto error;
588  }
589  if (r > bf->size) {
590  goto error;
591  }
592  if (r + read_size > bf->size) {
593  goto error;
594  }
595  if (left < read_size) {
596  if (rz_buf_read_at(buf, r, sm, left) != left) {
597  goto error;
598  }
599  } else {
600  len = rz_buf_read_at(buf, r, sm, read_size);
601  if (len != read_size) {
602  goto error;
603  }
604  }
605  if (!is_small) {
606  m.name = rz_read_ble(&sm[0], bigendian, 8 * sizeof(mach0_ut));
607  m.types = rz_read_ble(&sm[sizeof(mach0_ut)], bigendian, 8 * sizeof(mach0_ut));
608  m.imp = rz_read_ble(&sm[2 * sizeof(mach0_ut)], bigendian, 8 * sizeof(mach0_ut));
609  } else {
610  st64 name_offset = (st32)rz_read_ble(&sm[0], bigendian, 8 * sizeof(ut32));
611  mach0_ut name;
612  if (oi && oi->sel_string_base) {
613  name = oi->sel_string_base + name_offset;
614  } else {
615  name = p + name_offset;
616  }
617  if (mlflags != METHOD_LIST_FLAG_IS_PREOPT) {
618  r = va2pa(name, &offset, &left, bf);
619  if (!r) {
620  goto error;
621  }
622  ut8 tmp[8];
623  if (rz_buf_read_at(buf, r, tmp, sizeof(mach0_ut)) != sizeof(mach0_ut)) {
624  goto error;
625  }
626  m.name = rz_read_ble(tmp, bigendian, 8 * sizeof(mach0_ut));
627  } else {
628  m.name = name;
629  }
630  st64 types_offset = (st32)rz_read_ble(&sm[sizeof(ut32)], bigendian, 8 * sizeof(ut32));
631  m.types = p + types_offset + 4;
632  st64 imp_offset = (st32)rz_read_ble(&sm[2 * sizeof(ut32)], bigendian, 8 * sizeof(ut32));
633  m.imp = p + imp_offset + 8;
634  }
635 
636  r = va2pa(m.name, NULL, &left, bf);
637  if (r) {
638  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
639  if (r + left < r) {
640  goto error;
641  }
642  if (r > bf->size || r + MAX_CLASS_NAME_LEN > bf->size) {
643  goto error;
644  }
645  if (bin->has_crypto) {
646  name = strdup("some_encrypted_data");
647  left = strlen(name) + 1;
648  } else {
649  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
650  name = malloc(name_len + 1);
651  len = rz_buf_read_at(buf, r, (ut8 *)name, name_len);
652  name[name_len] = 0;
653  if (len < 1) {
654  goto error;
655  }
656  }
657  copy_sym_name_with_namespace(class_name, name, method);
658  RZ_FREE(name);
659  }
660 
661  r = va2pa(m.types, NULL, &left, bf);
662  if (r != 0) {
663  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
664  if (r + left > bf->size) {
665  left = bf->size - r;
666  }
667  if (r + left < r || r > bf->size || r + left > bf->size) {
668  goto error;
669  }
670  if (bin->has_crypto) {
671  rtype = strdup("some_encrypted_data");
672  left = strlen(rtype) + 1;
673  } else {
674  left = 1;
675  rtype = malloc(left + 1);
676  if (!rtype) {
677  goto error;
678  }
679  if (rz_buf_read_at(buf, r, (ut8 *)rtype, left) != left) {
680  free(rtype);
681  goto error;
682  }
683  rtype[left] = 0;
684  }
685  method->rtype = strdup(rtype);
686  RZ_FREE(rtype);
687  }
688 
689  method->vaddr = m.imp;
690  if (!method->vaddr) {
691  RZ_FREE(method);
692  goto next;
693  }
694  method->type = is_static ? RZ_BIN_TYPE_FUNC_STR : RZ_BIN_TYPE_METH_STR;
695  if (is_static) {
696  method->method_flags |= RZ_BIN_METH_CLASS;
697  }
698  if (is_thumb(bf)) {
699  if (method->vaddr & 1) {
700  method->vaddr >>= 1;
701  method->vaddr <<= 1;
702  }
703  }
704  rz_list_append(klass->methods, method);
705  next:
706  p += read_size;
707  offset += read_size;
708  }
709  return;
710 error:
711  RZ_FREE(method);
712  RZ_FREE(name);
713  return;
714 }
715 
718  struct MACH0_(SProtocolList) pl = { 0 };
719  struct MACH0_(SProtocol) pc;
720  char *class_name = NULL;
721  ut32 offset, left, i, j;
722  mach0_ut q, r;
723  int len;
724  bool bigendian;
725  ut8 spl[sizeof(struct MACH0_(SProtocolList))] = { 0 };
726  ut8 spc[sizeof(struct MACH0_(SProtocol))] = { 0 };
727  ut8 sptr[sizeof(mach0_ut)] = { 0 };
728 
729  if (!bf || !bf->o || !bf->o->bin_obj || !bf->o->info) {
730  RZ_LOG_ERROR("Invalid RzBinFile pointer\n");
731  return;
732  }
733  bigendian = bf->o->info->big_endian;
734  if (!(r = va2pa(p, &offset, &left, bf))) {
735  return;
736  }
737  if (r + left < r || r + sizeof(struct MACH0_(SProtocolList)) < r) {
738  return;
739  }
740  if (r > bf->size || r + left > bf->size) {
741  return;
742  }
743  if (r + sizeof(struct MACH0_(SProtocolList)) > bf->size) {
744  return;
745  }
746  if (left < sizeof(struct MACH0_(SProtocolList))) {
747  if (rz_buf_read_at(buf, r, spl, left) != left) {
748  return;
749  }
750  } else {
751  len = rz_buf_read_at(buf, r, spl, sizeof(struct MACH0_(SProtocolList)));
752  if (len != sizeof(struct MACH0_(SProtocolList))) {
753  return;
754  }
755  }
756  pl.count = rz_read_ble(&spl[0], bigendian, 8 * sizeof(mach0_ut));
757 
758  p += sizeof(struct MACH0_(SProtocolList));
759  offset += sizeof(struct MACH0_(SProtocolList));
760  for (i = 0; i < pl.count; i++) {
761  if (!(r = va2pa(p, &offset, &left, bf))) {
762  return;
763  }
764  if (r + left < r || r + sizeof(mach0_ut) < r) {
765  return;
766  }
767  if (r > bf->size || r + left > bf->size) {
768  return;
769  }
770  if (r + sizeof(mach0_ut) > bf->size) {
771  return;
772  }
773  if (left < sizeof(ut32)) {
774  if (rz_buf_read_at(buf, r, sptr, left) != left) {
775  return;
776  }
777  } else {
778  len = rz_buf_read_at(buf, r, sptr, sizeof(mach0_ut));
779  if (len != sizeof(mach0_ut)) {
780  return;
781  }
782  }
783  q = rz_read_ble(&sptr[0], bigendian, 8 * sizeof(mach0_ut));
784  if (!(r = va2pa(q, &offset, &left, bf))) {
785  return;
786  }
787  memset(&pc, '\0', sizeof(struct MACH0_(SProtocol)));
788  if (r + left < r || r + sizeof(struct MACH0_(SProtocol)) < r) {
789  return;
790  }
791  if (r > bf->size || r + left > bf->size) {
792  return;
793  }
794  if (r + sizeof(struct MACH0_(SProtocol)) > bf->size) {
795  return;
796  }
797  if (left < sizeof(struct MACH0_(SProtocol))) {
798  if (rz_buf_read_at(buf, r, spc, left) != left) {
799  return;
800  }
801  } else {
802  len = rz_buf_read_at(buf, r, spc, sizeof(struct MACH0_(SProtocol)));
803  if (len != sizeof(struct MACH0_(SProtocol))) {
804  return;
805  }
806  }
807  j = 0;
808  pc.isa = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
809 
810  j += sizeof(mach0_ut);
811  pc.name = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
812  j += sizeof(mach0_ut);
813  pc.protocols = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
814  j += sizeof(mach0_ut);
815  pc.instanceMethods = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
816  j += sizeof(mach0_ut);
817  pc.classMethods = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
818  j += sizeof(mach0_ut);
819  pc.optionalInstanceMethods = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
820  j += sizeof(mach0_ut);
821  pc.optionalClassMethods = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
822  j += sizeof(mach0_ut);
823  pc.instanceProperties = rz_read_ble(&spc[j], bigendian, 8 * sizeof(mach0_ut));
824  r = va2pa(pc.name, NULL, &left, bf);
825  if (r != 0) {
826  char *name = NULL;
827  struct MACH0_(obj_t) *bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
828  if (r + left < r) {
829  return;
830  }
831  if (r > bf->size || r + left > bf->size) {
832  return;
833  }
834  if (bin->has_crypto) {
835  name = strdup("some_encrypted_data");
836  left = strlen(name) + 1;
837  } else {
838  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
839  name = malloc(name_len + 1);
840  if (!name) {
841  return;
842  }
843  if (rz_buf_read_at(buf, r, (ut8 *)name, name_len) != name_len) {
844  RZ_FREE(name);
845  return;
846  }
847  name[name_len] = 0;
848  }
849  class_name = rz_str_newf("%s::%s%s", klass->name, "(protocol)", name);
850  RZ_FREE(name);
851  }
852 
853  if (pc.instanceMethods > 0) {
854  get_method_list_t(pc.instanceMethods, bf, buf, class_name, klass, false, oi);
855  }
856  if (pc.classMethods > 0) {
857  get_method_list_t(pc.classMethods, bf, buf, class_name, klass, true, oi);
858  }
859  RZ_FREE(class_name);
860  p += sizeof(ut32);
861  offset += sizeof(ut32);
862  }
863 }
864 
865 static const char *skipnum(const char *s) {
866  while (IS_DIGIT(*s)) {
867  s++;
868  }
869  return s;
870 }
871 
872 // TODO: split up between module + classname
873 static char *demangle_classname(const char *s) {
874  int modlen, len;
875  const char *kstr;
876  char *ret, *klass, *module;
877  if (!strncmp(s, "_TtC", 4)) {
878  int off = 4;
879  while (s[off] && (s[off] < '0' || s[off] > '9')) {
880  off++;
881  }
882  len = atoi(s + off);
883  modlen = strlen(s + off);
884  if (!len || len >= modlen) {
885  return strdup(s);
886  }
888  int skip = (skipnum(s + off) - s) + len;
889  if (s[skip] == 'P') {
890  skip++;
891  len = atoi(s + skip);
892  skip = (skipnum(s + skip) - s) + len;
893  }
894  kstr = s + skip;
895  len = atoi(kstr);
896  modlen = strlen(kstr);
897  if (!len || len >= modlen) {
898  free(module);
899  return strdup(s);
900  }
901  klass = rz_str_ndup(skipnum(kstr), len);
902  ret = rz_str_newf("%s.%s", module, klass);
903  free(module);
904  free(klass);
905  } else {
906  ret = strdup(s);
907  }
908  return ret;
909 }
910 
912  struct MACH0_(obj_t) * bin;
913  ut32 offset, left;
914  ut64 r;
915  int len;
916  bool bigendian;
917  ut8 sc[sizeof(mach0_ut)] = { 0 };
918  const ut32 ptr_size = sizeof(mach0_ut);
919 
920  if (!bf || !bf->o || !bf->o->bin_obj || !bf->o->info) {
921  RZ_LOG_ERROR("Invalid RzBinFile pointer\n");
922  return NULL;
923  }
924  if (!p) {
925  return NULL;
926  }
927  bigendian = bf->o->info->big_endian;
928  bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
929 
930  if (!(r = va2pa(p, &offset, &left, bf))) {
931  return NULL;
932  }
933  if ((r + left) < r || (r + sizeof(sc)) < r) {
934  return NULL;
935  }
936  if (r > bf->size) {
937  return NULL;
938  }
939  if (r + sizeof(sc) > bf->size) {
940  return NULL;
941  }
942  if (left < sizeof(sc)) {
943  return NULL;
944  }
945  len = rz_buf_read_at(buf, r + 4 * ptr_size, sc, sizeof(sc));
946  if (len != sizeof(sc)) {
947  return NULL;
948  }
949 
950  ut64 rodata = rz_read_ble(sc, bigendian, 8 * ptr_size);
951  if (!(r = va2pa(rodata, &offset, &left, bf))) {
952  return NULL;
953  }
954  if (r + left < r || r + sizeof(sc) < r) {
955  return NULL;
956  }
957  if (r > bf->size) {
958  return NULL;
959  }
960  if (r + sizeof(sc) > bf->size) {
961  return NULL;
962  }
963  if (left < sizeof(sc)) {
964  return NULL;
965  }
966 
967 #ifdef RZ_BIN_MACH064
968  len = rz_buf_read_at(buf, r + 4 * sizeof(ut32) + ptr_size, sc, sizeof(sc));
969 #else
970  len = rz_buf_read_at(buf, r + 3 * sizeof(ut32) + ptr_size, sc, sizeof(sc));
971 #endif
972  if (len != sizeof(sc)) {
973  return NULL;
974  }
975  ut64 name = rz_read_ble(sc, bigendian, 8 * ptr_size);
976 
977  if ((r = va2pa(name, NULL, &left, bf))) {
978  if (left < 1 || r + left < r) {
979  return NULL;
980  }
981  if (r > bf->size || r + MAX_CLASS_NAME_LEN > bf->size) {
982  return NULL;
983  }
984  if (bin->has_crypto) {
985  return strdup("some_encrypted_data");
986  } else {
987  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
988  char *name = malloc(name_len + 1);
989  if (name) {
990  int rc = rz_buf_read_at(buf, r, (ut8 *)name, name_len);
991  if (rc != name_len) {
992  rc = 0;
993  }
994  name[rc] = 0;
995  char *result = demangle_classname(name);
996  free(name);
997  return result;
998  }
999  }
1000  }
1001 
1002  return NULL;
1003 }
1004 
1006 static void get_class_ro_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, ut32 *is_meta_class, RzBinClass *klass, objc_cache_opt_info *oi) {
1007  struct MACH0_(obj_t) * bin;
1008  struct MACH0_(SClassRoT) cro = { 0 };
1009  ut32 offset, left, i;
1010  ut64 r, s;
1011  int len;
1012  bool bigendian;
1013  ut8 scro[sizeof(struct MACH0_(SClassRoT))] = { 0 };
1014 
1015  if (!bf || !bf->o || !bf->o->bin_obj || !bf->o->info) {
1016  RZ_LOG_ERROR("Invalid RzBinFile pointer\n");
1017  return;
1018  }
1019  bigendian = bf->o->info->big_endian;
1020  bin = (struct MACH0_(obj_t) *)bf->o->bin_obj;
1021  if (!(r = va2pa(p, &offset, &left, bf))) {
1022  return;
1023  }
1024 
1025  if (r + left < r || r + sizeof(cro) < r) {
1026  return;
1027  }
1028  if (r > bf->size || r + sizeof(cro) >= bf->size) {
1029  return;
1030  }
1031  if (r + sizeof(cro) > bf->size) {
1032  return;
1033  }
1034 
1035  // TODO: use rz_buf_fread to avoid endianness issues
1036  if (left < sizeof(cro)) {
1037  RZ_LOG_ERROR("Not enough data for SClassRoT\n");
1038  return;
1039  }
1040  len = rz_buf_read_at(buf, r, scro, sizeof(cro));
1041  if (len < 1) {
1042  return;
1043  }
1044  i = 0;
1045  cro.flags = rz_read_ble(&scro[i], bigendian, 8 * sizeof(ut32));
1046  i += sizeof(ut32);
1047  cro.instanceStart = rz_read_ble(&scro[i], bigendian, 8 * sizeof(ut32));
1048  i += sizeof(ut32);
1049  cro.instanceSize = rz_read_ble(&scro[i], bigendian, 8 * sizeof(ut32));
1050  i += sizeof(ut32);
1051 #ifdef RZ_BIN_MACH064
1052  cro.reserved = rz_read_ble(&scro[i], bigendian, 8 * sizeof(ut32));
1053  i += sizeof(ut32);
1054 #endif
1055  cro.ivarLayout = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1056  i += sizeof(mach0_ut);
1057  cro.name = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1058  i += sizeof(mach0_ut);
1059  cro.baseMethods = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1060  i += sizeof(mach0_ut);
1061  cro.baseProtocols = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1062  i += sizeof(mach0_ut);
1063  cro.ivars = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1064  i += sizeof(mach0_ut);
1065  cro.weakIvarLayout = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1066  i += sizeof(mach0_ut);
1067  cro.baseProperties = rz_read_ble(&scro[i], bigendian, 8 * sizeof(mach0_ut));
1068 
1069  s = r;
1070  if ((r = va2pa(cro.name, NULL, &left, bf))) {
1071  if (left < 1 || r + left < r) {
1072  return;
1073  }
1074  if (r > bf->size || r + left > bf->size) {
1075  return;
1076  }
1077  if (bin->has_crypto) {
1078  klass->name = strdup("some_encrypted_data");
1079  left = strlen(klass->name) + 1;
1080  } else {
1081  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, left);
1082  char *name = malloc(name_len + 1);
1083  if (name) {
1084  int rc = rz_buf_read_at(buf, r, (ut8 *)name, name_len);
1085  if (rc != name_len) {
1086  rc = 0;
1087  }
1088  name[rc] = 0;
1089  klass->name = demangle_classname(name);
1090  free(name);
1091  }
1092  }
1093  sdb_num_set(bin->kv, sdb_fmt("objc_class_%s.offset", klass->name), s, 0);
1094  }
1095 #ifdef RZ_BIN_MACH064
1096  sdb_set(bin->kv, sdb_fmt("objc_class.format"), "lllll isa super cache vtable data", 0);
1097 #else
1098  sdb_set(bin->kv, sdb_fmt("objc_class.format"), "xxxxx isa super cache vtable data", 0);
1099 #endif
1100 
1101  if (cro.baseMethods > 0) {
1102  get_method_list_t(cro.baseMethods, bf, buf, klass->name, klass, (cro.flags & RO_META) ? true : false, oi);
1103  }
1104 
1105  if (cro.baseProtocols > 0) {
1106  get_protocol_list_t(cro.baseProtocols, bf, buf, klass, oi);
1107  }
1108 
1109  if (cro.ivars > 0) {
1110  get_ivar_list_t(cro.ivars, bf, buf, klass);
1111  }
1112 
1113  if (cro.baseProperties > 0) {
1114  get_objc_property_list(cro.baseProperties, bf, buf, klass);
1115  }
1116 
1117  if (is_meta_class) {
1118  *is_meta_class = (cro.flags & RO_META) ? 1 : 0;
1119  }
1120 }
1121 
1122 static mach0_ut get_isa_value(void) {
1123  // TODO: according to otool sources this is taken from relocs
1124  return 0;
1125 }
1126 
1128  struct MACH0_(SClass) c = { 0 };
1129  const int size = sizeof(struct MACH0_(SClass));
1130  mach0_ut r = 0;
1131  ut32 offset = 0, left = 0;
1132  ut32 is_meta_class = 0;
1133  int len;
1134  bool bigendian;
1135  ut8 sc[sizeof(struct MACH0_(SClass))] = { 0 };
1136  ut32 i;
1137 
1138  if (!bf || !bf->o || !bf->o->info) {
1139  return;
1140  }
1141  bigendian = bf->o->info->big_endian;
1142  if (!(r = va2pa(p, &offset, &left, bf))) {
1143  return;
1144  }
1145  if ((r + left) < r || (r + size) < r) {
1146  return;
1147  }
1148  if (r > bf->size) {
1149  return;
1150  }
1151  if (r + size > bf->size) {
1152  return;
1153  }
1154  if (left < size) {
1155  RZ_LOG_ERROR("Cannot parse obj class info (out of bounds)\n");
1156  return;
1157  }
1158  len = rz_buf_read_at(buf, r, sc, size);
1159  if (len != size) {
1160  return;
1161  }
1162 
1163  i = 0;
1164  c.isa = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1165  i += sizeof(mach0_ut);
1166  c.superclass = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1167  i += sizeof(mach0_ut);
1168  c.cache = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1169  i += sizeof(mach0_ut);
1170  c.vtable = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1171  i += sizeof(mach0_ut);
1172  c.data = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1173 
1174  klass->addr = c.isa;
1175  if (c.superclass) {
1176  klass->super = get_class_name(c.superclass, bf, buf);
1177  } else if (relocs) {
1178  struct reloc_t reloc_at_class_addr;
1179  reloc_at_class_addr.addr = p + sizeof(mach0_ut);
1180  RzSkipListNode *found = rz_skiplist_find(relocs, &reloc_at_class_addr);
1181  if (found) {
1182  const char *_objc_class = "_OBJC_CLASS_$_";
1183  const int _objc_class_len = strlen(_objc_class);
1184  char *target_class_name = (char *)((struct reloc_t *)found->data)->name;
1185  if (rz_str_startswith(target_class_name, _objc_class)) {
1186  target_class_name += _objc_class_len;
1187  klass->super = strdup(target_class_name);
1188  }
1189  }
1190  }
1191  get_class_ro_t(RO_DATA_PTR(c.data), bf, buf, &is_meta_class, klass, oi);
1192 
1193 #if SWIFT_SUPPORT
1194  if (q(c.data + n_value) & 7) {
1195  RZ_LOG_INFO("This is a Swift class");
1196  }
1197 #endif
1198  if (!is_meta_class && !dupe) {
1199  mach0_ut isa_n_value = get_isa_value();
1200  ut64 tmp = klass->addr;
1202  (c.isa + isa_n_value, bf, buf, klass, true, relocs, oi);
1203  klass->addr = tmp;
1204  }
1205 }
1206 
1207 #if 0
1208 static RzList *parse_swift_classes(RzBinFile *bf) {
1209  bool is_swift = false;
1210  RzBinString *str;
1211  RzListIter *iter;
1212  RzBinClass *cls;
1213  RzList *ret;
1214  char *lib;
1215 
1216  rz_list_foreach (bf->o->libs, iter, lib) {
1217  if (strstr (lib, "libswift")) {
1218  is_swift = true;
1219  break;
1220  }
1221  }
1222  if (!is_swift) {
1223  return NULL;
1224  }
1225 
1226  int idx = 0;
1228  rz_list_foreach (bf->o->strings, iter, str) {
1229  if (!strncmp (str->string, "_TtC", 4)) {
1230  char *msg = strdup (str->string + 4);
1231  cls = RZ_NEW0 (RzBinClass);
1232  cls->name = strdup (msg);
1233  cls->super = strdup (msg);
1234  cls->index = idx++;
1235  rz_list_append (ret, cls);
1236  free (msg);
1237  }
1238  }
1239  return ret;
1240 }
1241 #endif
1242 
1244  RzList /*<RzBinClass>*/ *ret = NULL;
1245  ut64 num_of_unnamed_class = 0;
1246  RzBinClass *klass = NULL;
1247  ut32 i = 0, size = 0;
1248  RzList *sctns = NULL;
1249  bool is_found = false;
1250  mach0_ut p = 0;
1251  ut32 left = 0;
1252  int len;
1253  ut64 paddr;
1254  ut64 s_size;
1255  bool bigendian;
1256  ut8 pp[sizeof(mach0_ut)] = { 0 };
1257 
1258  rz_return_val_if_fail(bf && bf->o, NULL);
1259 
1260  if (!bf->o->bin_obj || !bf->o->info) {
1261  return NULL;
1262  }
1263  bigendian = bf->o->info->big_endian;
1264 
1265  RzBuffer *buf = bf->buf;
1266  RzBuffer *owned_buf = NULL;
1267  if (MACH0_(needs_rebasing_and_stripping)(bf->o->bin_obj)) {
1268  owned_buf = MACH0_(new_rebasing_and_stripping_buf)(bf->o->bin_obj);
1269  if (!owned_buf) {
1270  return NULL;
1271  }
1272  buf = owned_buf;
1273  }
1274 
1275  RzSkipList *relocs = MACH0_(get_relocs)(bf->o->bin_obj);
1276 
1277  ret = MACH0_(parse_categories)(bf, buf, relocs, oi);
1278 
1279  /* check if it's Swift */
1280  // ret = parse_swift_classes (bf);
1281 
1282  // sebfing of section with name __objc_classlist
1283 
1284  struct section_t *sections = NULL;
1285  if (!(sections = MACH0_(get_sections)(bf->o->bin_obj))) {
1286  rz_buf_free(owned_buf);
1287  return ret;
1288  }
1289 
1290  for (i = 0; !sections[i].last; i++) {
1291  if (strstr(sections[i].name, "__objc_classlist")) {
1292  is_found = true;
1293  paddr = sections[i].offset;
1294  s_size = sections[i].size;
1295  break;
1296  }
1297  }
1298 
1299  RZ_FREE(sections);
1300 
1301  if (!is_found) {
1302  // retain just for debug
1303  // RZ_LOG_ERROR("there is no section __objc_classlist\n");
1304  goto get_classes_error;
1305  }
1306  // end of seaching of section with name __objc_classlist
1307 
1308  if (!ret && !(ret = rz_list_newf((RzListFree)rz_bin_class_free))) {
1309  // retain just for debug
1310  // RZ_LOG_ERROR("RzList<RzBinClass> allocation error\n");
1311  goto get_classes_error;
1312  }
1313  // start of getting information about each class in file
1314  for (i = 0; i < s_size; i += sizeof(mach0_ut)) {
1315  left = s_size - i;
1316  if (left < sizeof(mach0_ut)) {
1317  RZ_LOG_ERROR("Truncated classlist data\n");
1318  break;
1319  }
1320  if (!(klass = RZ_NEW0(RzBinClass))) {
1321  // retain just for debug
1322  // RZ_LOG_ERROR("RzBinClass allocation error\n");
1323  goto get_classes_error;
1324  }
1325  if (!(klass->methods = rz_list_new())) {
1326  // retain just for debug
1327  // RZ_LOG_ERROR("RzList<RzBinField> allocation error\n");
1328  goto get_classes_error;
1329  }
1330  if (!(klass->fields = rz_list_new())) {
1331  // retain just for debug
1332  // RZ_LOG_ERROR("RzList<RzBinSymbol> allocation error\n");
1333  goto get_classes_error;
1334  }
1335  size = sizeof(mach0_ut);
1336  if (paddr > bf->size || paddr + size > bf->size) {
1337  goto get_classes_error;
1338  }
1339  if (paddr + size < paddr) {
1340  goto get_classes_error;
1341  }
1342  len = rz_buf_read_at(buf, paddr + i, pp, sizeof(mach0_ut));
1343  if (len != sizeof(mach0_ut)) {
1344  goto get_classes_error;
1345  }
1346  p = rz_read_ble(&pp[0], bigendian, 8 * sizeof(mach0_ut));
1348  (p, bf, buf, klass, false, relocs, oi);
1349  if (!klass->name) {
1350  klass->name = rz_str_newf("UnnamedClass%" PFMT64d, num_of_unnamed_class);
1351  if (!klass->name) {
1352  goto get_classes_error;
1353  }
1354  num_of_unnamed_class++;
1355  }
1356  rz_list_append(ret, klass);
1357  }
1358  return ret;
1359 
1360 get_classes_error:
1361  rz_list_free(sctns);
1362  rz_list_free(ret);
1363  rz_buf_free(owned_buf);
1364  // XXX DOUBLE FREE rz_bin_class_free (klass);
1365  return NULL;
1366 }
1367 
1369  rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj && bf->o->info, NULL);
1370 
1371  RzList /*<RzBinClass>*/ *ret = NULL;
1372  RzBinObject *obj = bf->o;
1373  const ut32 ptr_size = sizeof(mach0_ut);
1374  bool is_found = false;
1375  ut64 paddr;
1376  ut64 s_size;
1377 
1378  struct section_t *sections = NULL;
1379  if (!(sections = MACH0_(get_sections)(obj->bin_obj))) {
1380  return ret;
1381  }
1382 
1383  ut32 i = 0;
1384  for (; !sections[i].last; i++) {
1385  if (strstr(sections[i].name, "__objc_catlist")) {
1386  is_found = true;
1387  paddr = sections[i].offset;
1388  s_size = sections[i].size;
1389  break;
1390  }
1391  }
1392 
1393  RZ_FREE(sections);
1394 
1395  if (!is_found) {
1396  goto error;
1397  }
1398 
1399  if (!ret && !(ret = rz_list_newf((RzListFree)rz_bin_class_free))) {
1400  goto error;
1401  }
1402 
1403  if (!relocs) {
1404  goto error;
1405  }
1406 
1407  for (i = 0; i < s_size; i += ptr_size) {
1408  RzBinClass *klass;
1409  mach0_ut p;
1410 
1411  if ((s_size - i) < ptr_size) {
1412  RZ_LOG_ERROR("Truncated catlist data\n");
1413  break;
1414  }
1415  if (!(klass = RZ_NEW0(RzBinClass))) {
1416  goto error;
1417  }
1418  if (!(klass->methods = rz_list_new())) {
1419  RZ_FREE(klass);
1420  goto error;
1421  }
1422  if (!(klass->fields = rz_list_new())) {
1423  RZ_FREE(klass);
1424  goto error;
1425  }
1426  if (!read_ptr_pa(bf, buf, paddr + i, &p)) {
1427  RZ_FREE(klass);
1428  goto error;
1429  }
1431  (p, bf, buf, klass, relocs, oi);
1432  if (!klass->name) {
1433  RZ_FREE(klass);
1434  continue;
1435  }
1436  rz_list_append(ret, klass);
1437  }
1438  return ret;
1439 
1440 error:
1441  rz_list_free(ret);
1442  return NULL;
1443 }
1444 
1446  rz_return_if_fail(bf && bf->o && bf->o->info);
1447 
1448  struct MACH0_(SCategory) c = { 0 };
1449  const int size = sizeof(struct MACH0_(SCategory));
1450  mach0_ut r = 0;
1451  ut32 offset = 0, left = 0;
1452  int len;
1453  bool bigendian = bf->o->info->big_endian;
1454  ut8 sc[sizeof(struct MACH0_(SCategory))] = { 0 };
1455  ut32 i;
1456 
1457  if (!(r = va2pa(p, &offset, &left, bf))) {
1458  return;
1459  }
1460  if ((r + left) < r || (r + size) < r) {
1461  return;
1462  }
1463  if (r > bf->size || r + left > bf->size) {
1464  return;
1465  }
1466  if (r + size > bf->size) {
1467  return;
1468  }
1469  if (left < size) {
1470  RZ_LOG_ERROR("Cannot parse obj category info out of bounds\n");
1471  return;
1472  }
1473  len = rz_buf_read_at(buf, r, sc, size);
1474  if (len != size) {
1475  return;
1476  }
1477 
1478  ut32 ptr_size = sizeof(mach0_ut);
1479  ut32 bits = 8 * ptr_size;
1480 
1481  i = 0;
1482  c.name = rz_read_ble(&sc[i], bigendian, bits);
1483  i += ptr_size;
1484  c.targetClass = rz_read_ble(&sc[i], bigendian, bits);
1485  i += ptr_size;
1486  c.instanceMethods = rz_read_ble(&sc[i], bigendian, bits);
1487  i += ptr_size;
1488  c.classMethods = rz_read_ble(&sc[i], bigendian, bits);
1489  i += ptr_size;
1490  c.protocols = rz_read_ble(&sc[i], bigendian, bits);
1491  i += ptr_size;
1492  c.properties = rz_read_ble(&sc[i], bigendian, bits);
1493 
1494  char *category_name = read_str(bf, buf, c.name, &offset, &left);
1495  if (!category_name) {
1496  return;
1497  }
1498 
1499  char *target_class_name = NULL;
1500  if (c.targetClass == 0) {
1501  if (!relocs) {
1502  RZ_FREE(category_name);
1503  return;
1504  }
1505  struct reloc_t reloc_at_class_addr;
1506  reloc_at_class_addr.addr = p + ptr_size;
1507  RzSkipListNode *found = rz_skiplist_find(relocs, &reloc_at_class_addr);
1508  if (!found) {
1509  RZ_FREE(category_name);
1510  return;
1511  }
1512 
1513  const char *_objc_class = "_OBJC_CLASS_$_";
1514  const int _objc_class_len = strlen(_objc_class);
1515  target_class_name = (char *)((struct reloc_t *)found->data)->name;
1516  if (!rz_str_startswith(target_class_name, _objc_class)) {
1517  RZ_FREE(category_name);
1518  return;
1519  }
1520  target_class_name += _objc_class_len;
1521  klass->name = rz_str_newf("%s(%s)", target_class_name, category_name);
1522  } else {
1523  mach0_ut ro_data_field = c.targetClass + 4 * ptr_size;
1524  mach0_ut ro_data;
1525  if (!read_ptr_va(bf, buf, ro_data_field, &ro_data)) {
1526  RZ_FREE(category_name);
1527  return;
1528  }
1529  mach0_ut name_field = RO_DATA_PTR(ro_data) + 3 * 4 + ptr_size;
1530 #ifdef RZ_BIN_MACH064
1531  name_field += 4;
1532 #endif
1533  mach0_ut name_at;
1534  if (!read_ptr_va(bf, buf, name_field & ~1, &name_at)) {
1535  RZ_FREE(category_name);
1536  return;
1537  }
1538 
1539  target_class_name = read_str(bf, buf, name_at, &offset, &left);
1540  char *demangled = NULL;
1541  if (target_class_name) {
1542  demangled = demangle_classname(target_class_name);
1543  }
1544  klass->name = rz_str_newf("%s(%s)", rz_str_get_null(demangled), category_name);
1545  RZ_FREE(target_class_name);
1546  RZ_FREE(demangled);
1547  }
1548 
1549  klass->addr = p;
1550 
1551  RZ_FREE(category_name);
1552 
1553  if (c.instanceMethods > 0) {
1554  get_method_list_t(c.instanceMethods, bf, buf, klass->name, klass, false, oi);
1555  }
1556 
1557  if (c.classMethods > 0) {
1558  get_method_list_t(c.classMethods, bf, buf, klass->name, klass, true, oi);
1559  }
1560 
1561  if (c.protocols > 0) {
1562  get_protocol_list_t(c.protocols, bf, buf, klass, oi);
1563  }
1564 
1565  if (c.properties > 0) {
1566  get_objc_property_list(c.properties, bf, buf, klass);
1567  }
1568 }
1569 
1570 static bool read_ptr_pa(RzBinFile *bf, RzBuffer *buf, ut64 paddr, mach0_ut *out) {
1571  rz_return_val_if_fail(out, false);
1572  rz_return_val_if_fail(bf && bf->o && bf->o->info, false);
1573 
1574  size_t ptr_size = sizeof(mach0_ut);
1575  ut8 pp[sizeof(mach0_ut)] = { 0 };
1576 
1577  int len = rz_buf_read_at(buf, paddr, pp, ptr_size);
1578  if (len != ptr_size) {
1579  return false;
1580  }
1581 
1582  mach0_ut p = rz_read_ble(&pp[0], bf->o->info->big_endian, 8 * ptr_size);
1583  *out = p;
1584 
1585  return true;
1586 }
1587 
1588 static bool read_ptr_va(RzBinFile *bf, RzBuffer *buf, ut64 vaddr, mach0_ut *out) {
1589  rz_return_val_if_fail(bf, false);
1590  ut32 offset = 0, left = 0;
1591  mach0_ut paddr = va2pa(vaddr, &offset, &left, bf);
1592  if (paddr == 0 || left < sizeof(mach0_ut)) {
1593  return false;
1594  }
1595  return read_ptr_pa(bf, buf, paddr, out);
1596 }
1597 
1598 static char *read_str(RzBinFile *bf, RzBuffer *buf, mach0_ut p, ut32 *offset, ut32 *left) {
1599  rz_return_val_if_fail(bf && offset && left, NULL);
1600 
1601  mach0_ut paddr = va2pa(p, offset, left, bf);
1602  if (paddr == 0 || *left <= 1) {
1603  return NULL;
1604  }
1605 
1606  int name_len = RZ_MIN(MAX_CLASS_NAME_LEN, *left);
1607  char *name = calloc(1, name_len + 1);
1608  int len = rz_buf_read_at(buf, paddr, (ut8 *)name, name_len);
1609  if (len < name_len) {
1610  RZ_LOG_ERROR("Cannot read string\n");
1611  RZ_FREE(name);
1612  return NULL;
1613  }
1614 
1615  return name;
1616 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static RzILOpEffect * cls(cs_insn *insn)
Definition: arm_il64.c:915
RZ_IPI void rz_bin_class_free(RzBinClass *k)
Definition: bfile.c:512
RZ_API void rz_bin_string_free(void *_str)
Definition: bin.c:192
RZ_API void rz_bin_field_free(RzBinField *field)
Definition: bin.c:950
RzList * sections(RzBinFile *bf)
Definition: bin_ne.c:110
RzList * relocs(RzBinFile *bf)
Definition: bin_ne.c:114
int bits(struct state *s, int need)
Definition: blast.c:72
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
char * read_name()
Definition: cabinfo.c:332
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
uint32_t ut32
static char sc[]
Definition: egg_cb.c:6
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
void skip(file *in, unsigned n)
Definition: gzappend.c:202
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
RZ_API RZ_BORROW RzListIter * rz_list_prepend(RZ_NONNULL RzList *list, void *data)
Appends at the beginning of the list a new element.
Definition: list.c:316
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_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
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
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
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")
@ reserved
Definition: lm32_isa.h:94
struct section_t *MACH0_() get_sections(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2411
RZ_BORROW RzSkipList *MACH0_() get_relocs(struct MACH0_(obj_t) *bin)
Definition: mach0_relocs.c:120
RZ_API RzBuffer *MACH0_() new_rebasing_and_stripping_buf(struct MACH0_(obj_t) *obj)
Definition: mach0_rebase.c:224
RZ_API bool MACH0_() needs_rebasing_and_stripping(struct MACH0_(obj_t) *obj)
Definition: mach0_rebase.c:228
#define MAX_CLASS_NAME_LEN
Definition: mach0_classes.c:9
static void get_protocol_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, objc_cache_opt_info *oi)
RZ_API void MACH0_() get_class_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, bool dupe, RzSkipList *relocs, objc_cache_opt_info *oi)
struct MACH0_(SMethodList)
Definition: mach0_classes.c:23
#define RO_META
Definition: mach0_classes.c:8
static char * demangle_classname(const char *s)
static mach0_ut get_isa_value(void)
static char * read_str(RzBinFile *bf, RzBuffer *buf, mach0_ut p, ut32 *offset, ut32 *left)
#define METHOD_LIST_FLAG_IS_PREOPT
Definition: mach0_classes.c:18
RZ_API void MACH0_() get_category_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, RzSkipList *relocs, objc_cache_opt_info *oi)
static bool read_ptr_pa(RzBinFile *bf, RzBuffer *buf, ut64 paddr, mach0_ut *out)
#define METHOD_LIST_FLAG_IS_SMALL
Definition: mach0_classes.c:17
static int sort_by_offset(const void *_a, const void *_b)
static void get_ivar_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass)
static RzList *MACH0_() parse_categories(RzBinFile *bf, RzBuffer *buf, RzSkipList *relocs, objc_cache_opt_info *oi)
static void get_method_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, char *class_name, RzBinClass *klass, bool is_static, objc_cache_opt_info *oi)
#define METHOD_LIST_ENTSIZE_FLAG_MASK
Definition: mach0_classes.c:19
#define RO_DATA_PTR(x)
Definition: mach0_classes.c:21
static const char * skipnum(const char *s)
static void get_class_ro_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, ut32 *is_meta_class, RzBinClass *klass, objc_cache_opt_info *oi)
static void get_objc_property_list(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass)
static bool is_thumb(RzBinFile *bf)
static char * get_class_name(mach0_ut p, RzBinFile *bf, RzBuffer *buf)
RZ_API RzList *MACH0_() parse_classes(RzBinFile *bf, objc_cache_opt_info *oi)
static bool read_ptr_va(RzBinFile *bf, RzBuffer *buf, ut64 vaddr, mach0_ut *out)
static mach0_ut va2pa(mach0_ut p, ut32 *offset, ut32 *left, RzBinFile *bf)
static void copy_sym_name_with_namespace(char *class_name, char *read_name, RzBinSymbol *sym)
#define mach0_ut
Definition: mach0_classes.h:17
#define rz_bin_plugin_mach
Definition: mach0_classes.h:18
int type
Definition: mipsasm.c:17
int idx
Definition: setup.py:197
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
Definition: num.c:25
const char * name
Definition: op.c:541
insn_type_descr_t types[]
Definition: or1k_disas.c:7
int off
Definition: pal.c:13
unsigned long sop
Definition: regex2.h:62
static RzSocket * s
Definition: rtr.c:28
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define RZ_BIN_METH_CLASS
Definition: rz_bin.h:83
#define RZ_BIN_TYPE_METH_STR
Definition: rz_bin.h:122
#define RZ_BIN_TYPE_FUNC_STR
Definition: rz_bin.h:119
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
static ut64 rz_read_ble(const void *src, bool big_endian, int size)
Definition: rz_endian.h:517
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_INFO(fmtstr,...)
Definition: rz_log.h:54
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API RzSkipListNode * rz_skiplist_find(RzSkipList *list, void *data)
Definition: skiplist.c:210
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
static const char * rz_str_get_null(const char *str)
Definition: rz_str.h:190
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
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define ST32_MAX
Definition: rz_types_base.h:97
#define st32
Definition: rz_types_base.h:12
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
Definition: malloc.c:26
Definition: sftypes.h:77
Definition: z80asm.h:102
uint64_t sel_string_base
Definition: mach0_specs.h:346
Definition: mach0.h:71
ut64 addr
Definition: mach0.h:73
RzList * fields
Definition: rz_bin.h:654
char * name
Definition: rz_bin.h:647
RzList * methods
Definition: rz_bin.h:653
ut64 vaddr
Definition: rz_bin.h:762
char * name
Definition: rz_bin.h:767
char * type
Definition: rz_bin.h:768
XX curplugin == o->plugin.
Definition: rz_bin.h:298
RzBinObject * o
Definition: rz_bin.h:305
int big_endian
Definition: rz_bin.h:235
ut64 boffset
Definition: rz_bin.h:262
RzBinStrDb * strings
Definition: rz_bin.h:280
RzBinInfo * info
Definition: rz_bin.h:287
void * bin_obj
Definition: rz_bin.h:293
RzList * libs
Definition: rz_bin.h:278
const char * rtype
Definition: rz_bin.h:683
const char * type
Definition: rz_bin.h:682
char * name
Definition: rz_bin.h:675
char * classname
Definition: rz_bin.h:678
ut64 method_flags
Definition: rz_bin.h:696
Definition: dis.c:32
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58