Rizin
unix-like reverse engineering framework and cli tools
class.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2018 thestr4ng3r <info@florianmaerkl.de>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_analysis.h>
5 #include <rz_vector.h>
7 #include <rz_util/rz_table.h>
8 #include "../include/rz_analysis.h"
9 #include "../include/rz_util/rz_graph.h"
10 
11 static void rz_analysis_class_base_delete_class(RzAnalysis *analysis, const char *class_name);
12 static void rz_analysis_class_method_delete_class(RzAnalysis *analysis, const char *class_name);
13 static void rz_analysis_class_vtable_delete_class(RzAnalysis *analysis, const char *class_name);
14 static void rz_analysis_class_base_rename_class(RzAnalysis *analysis, const char *class_name_old, const char *class_name_new);
15 static void rz_analysis_class_method_rename_class(RzAnalysis *analysis, const char *old_class_name, const char *new_class_name);
16 static void rz_analysis_class_vtable_rename_class(RzAnalysis *analysis, const char *old_class_name, const char *new_class_name);
17 
18 static const char *key_class(const char *name) {
19  return name;
20 }
21 
22 static char *key_attr_types(const char *name) {
23  return rz_str_newf("attrtypes.%s", name);
24 }
25 
26 static char *key_attr_type_attrs(const char *class_name, const char *attr_type) {
27  return rz_str_newf("attr.%s.%s", class_name, attr_type);
28 }
29 
30 static char *key_attr_content(const char *class_name, const char *attr_type, const char *attr_id) {
31  return rz_str_newf("attr.%s.%s.%s", class_name, attr_type, attr_id);
32 }
33 
34 static char *key_attr_content_specific(const char *class_name, const char *attr_type, const char *attr_id) {
35  return rz_str_newf("attr.%s.%s.%s.specific", class_name, attr_type, attr_id);
36 }
37 
38 typedef enum {
43 
44 static const char *attr_type_id(RzAnalysisClassAttrType attr_type) {
45  switch (attr_type) {
47  return "method";
49  return "vtable";
51  return "base";
52  default:
53  return NULL;
54  }
55 }
56 
60  if (classes) {
61  RzListIter *iter_class;
62  RzBinClass *class;
63  rz_list_foreach (classes, iter_class, class) {
64  if (rz_cons_is_breaked()) {
65  break;
66  }
67  if (!rz_analysis_class_exists(analysis, class->name)) {
68  rz_analysis_class_create(analysis, class->name);
69  RzList *methods = class->methods;
70  if (methods) {
71  rz_analysis_class_method_recover(analysis, class, methods);
72  }
73  }
74  }
75  }
77 }
78 
79 RZ_API RzAnalysisClassErr rz_analysis_class_create(RzAnalysis *analysis, const char *name) {
80  char *name_sanitized = rz_str_sanitize_sdb_key(name);
81  if (!name_sanitized) {
82  return RZ_ANALYSIS_CLASS_ERR_OTHER;
83  }
84  RzAnalysisClassErr err = RZ_ANALYSIS_CLASS_ERR_SUCCESS;
85  const char *key = key_class(name_sanitized);
86  if (!sdb_exists(analysis->sdb_classes, key)) {
87  sdb_set(analysis->sdb_classes, key, "c", 0);
88  RzEventClass event = { .name = name_sanitized };
89  rz_event_send(analysis->ev, RZ_EVENT_CLASS_NEW, &event);
90  } else {
91  err = RZ_ANALYSIS_CLASS_ERR_CLASH;
92  }
93 
94  free(name_sanitized);
95  return err;
96 }
97 
98 RZ_API void rz_analysis_class_delete(RzAnalysis *analysis, const char *name) {
99  char *class_name_sanitized = rz_str_sanitize_sdb_key(name);
100  if (!class_name_sanitized) {
101  return;
102  }
103 
104  rz_analysis_class_base_delete_class(analysis, class_name_sanitized);
105  rz_analysis_class_method_delete_class(analysis, class_name_sanitized);
106  rz_analysis_class_vtable_delete_class(analysis, class_name_sanitized);
107 
108  if (!sdb_remove(analysis->sdb_classes, key_class(class_name_sanitized), 0)) {
109  free(class_name_sanitized);
110  return;
111  }
112 
113  char *key = key_attr_types(class_name_sanitized);
114  if (!key) {
115  free(class_name_sanitized);
116  return;
117  }
118  char *attr_type_array = sdb_get(analysis->sdb_classes_attrs, key, 0);
119  free(key);
120 
121  char *attr_type;
122  sdb_aforeach(attr_type, attr_type_array) {
123  key = key_attr_type_attrs(class_name_sanitized, attr_type);
124  if (!key) {
125  continue;
126  }
127  char *attr_id_array = sdb_get(analysis->sdb_classes_attrs, key, 0);
128  sdb_remove(analysis->sdb_classes_attrs, key, 0);
129  free(key);
130  if (attr_id_array) {
131  char *attr_id;
132  sdb_aforeach(attr_id, attr_id_array) {
133  key = key_attr_content(class_name_sanitized, attr_type, attr_id);
134  if (key) {
135  sdb_remove(analysis->sdb_classes_attrs, key, 0);
136  free(key);
137  }
138  key = key_attr_content_specific(class_name_sanitized, attr_type, attr_id);
139  if (key) {
140  sdb_remove(analysis->sdb_classes_attrs, key, 0);
141  free(key);
142  }
143  sdb_aforeach_next(attr_id);
144  }
145  free(attr_id_array);
146  }
147  sdb_aforeach_next(attr_type);
148  }
149  free(attr_type_array);
150 
151  key = key_attr_types(class_name_sanitized);
152  if (key) {
153  sdb_remove(analysis->sdb_classes_attrs, key, 0);
154  free(key);
155  }
156 
157  RzEventClass event = { .name = class_name_sanitized };
158  rz_event_send(analysis->ev, RZ_EVENT_CLASS_DEL, &event);
159 
160  free(class_name_sanitized);
161 }
162 
163 static bool rz_analysis_class_exists_raw(RzAnalysis *analysis, const char *name) {
164  return sdb_exists(analysis->sdb_classes, key_class(name));
165 }
166 
167 RZ_API bool rz_analysis_class_exists(RzAnalysis *analysis, const char *name) {
168  char *class_name_sanitized = rz_str_sanitize_sdb_key(name);
169  if (!class_name_sanitized) {
170  return false;
171  }
172  bool r = rz_analysis_class_exists_raw(analysis, class_name_sanitized);
173  free(class_name_sanitized);
174  return r;
175 }
176 
178  return sdb_foreach_list(analysis->sdb_classes, sorted);
179 }
180 
182  sdb_foreach(analysis->sdb_classes, cb, user);
183 }
184 
185 static bool rename_key(Sdb *sdb, const char *key_old, const char *key_new) {
186  char *content = sdb_get(sdb, key_old, 0);
187  if (!content) {
188  return false;
189  }
190  sdb_remove(sdb, key_old, 0);
191  sdb_set(sdb, key_new, content, 0);
192  free(content);
193  return true;
194 }
195 
196 RZ_API RzAnalysisClassErr rz_analysis_class_rename(RzAnalysis *analysis, const char *old_name, const char *new_name) {
197  if (rz_analysis_class_exists(analysis, new_name)) {
198  return RZ_ANALYSIS_CLASS_ERR_CLASH;
199  }
200 
201  char *old_name_sanitized = rz_str_sanitize_sdb_key(old_name);
202  if (!old_name_sanitized) {
203  return RZ_ANALYSIS_CLASS_ERR_OTHER;
204  }
205  char *new_name_sanitized = rz_str_sanitize_sdb_key(new_name);
206  if (!new_name_sanitized) {
207  free(old_name_sanitized);
208  return RZ_ANALYSIS_CLASS_ERR_OTHER;
209  }
210 
211  RzAnalysisClassErr err = RZ_ANALYSIS_CLASS_ERR_SUCCESS;
212 
213  rz_analysis_class_base_rename_class(analysis, old_name, new_name);
214  rz_analysis_class_method_rename_class(analysis, old_name, new_name);
215  rz_analysis_class_vtable_rename_class(analysis, old_name, new_name);
216 
217  if (!rename_key(analysis->sdb_classes, key_class(old_name_sanitized), key_class(new_name_sanitized))) {
218  err = RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_CLASS;
219  goto beach;
220  }
221 
222  char *key = key_attr_types(old_name_sanitized);
223  if (key) {
224  char *attr_types = sdb_get(analysis->sdb_classes_attrs, key, 0);
225  free(key);
226  char *attr_type_cur;
227  sdb_aforeach(attr_type_cur, attr_types) {
228  char *key = key_attr_type_attrs(old_name, attr_type_cur);
229  if (!key) {
230  continue;
231  }
232  char *attr_ids = sdb_get(analysis->sdb_classes_attrs, key, 0);
233  free(key);
234  char *attr_id_cur;
235  sdb_aforeach(attr_id_cur, attr_ids) {
236  key = key_attr_content(old_name, attr_type_cur, attr_id_cur);
237  char *new_key = key_attr_content(new_name, attr_type_cur, attr_id_cur);
238  if (key && new_key) {
239  rename_key(analysis->sdb_classes_attrs, key, new_key);
240  }
241  free(key);
242  free(new_key);
243  sdb_aforeach_next(attr_id_cur);
244  }
245  free(attr_ids);
246  key = key_attr_type_attrs(old_name, attr_type_cur);
247  char *new_key = key_attr_type_attrs(new_name, attr_type_cur);
248  if (key && new_key) {
249  rename_key(analysis->sdb_classes_attrs, key, new_key);
250  }
251  sdb_aforeach_next(attr_type_cur);
252  }
253  free(attr_types);
254  }
255 
256  key = key_attr_types(old_name_sanitized);
257  char *new_key = key_attr_types(new_name_sanitized);
258  if (key && new_key) {
259  rename_key(analysis->sdb_classes_attrs, key, new_key);
260  }
261  free(key);
262  free(new_key);
263 
264  RzEventClassRename event = {
265  .name_old = old_name_sanitized,
266  .name_new = new_name_sanitized
267  };
268  rz_event_send(analysis->ev, RZ_EVENT_CLASS_RENAME, &event);
269 
270 beach:
271  free(old_name_sanitized);
272  free(new_name_sanitized);
273  return err;
274 }
275 
276 // all ids must be sanitized
277 static char *rz_analysis_class_get_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, bool specific) {
278  const char *attr_type_str = attr_type_id(attr_type);
279  char *key = specific
280  ? key_attr_content_specific(class_name, attr_type_str, attr_id)
281  : key_attr_content(class_name, attr_type_str, attr_id);
282  if (!key) {
283  return NULL;
284  }
285  char *ret = sdb_get(analysis->sdb_classes_attrs, key, 0);
286  free(key);
287  return ret;
288 }
289 
290 // ids will be sanitized automatically
291 static char *rz_analysis_class_get_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, bool specific) {
292  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
293  if (!class_name_sanitized) {
294  return false;
295  }
296  char *attr_id_sanitized = rz_str_sanitize_sdb_key(attr_id);
297  if (!attr_id_sanitized) {
298  free(class_name_sanitized);
299  return false;
300  }
301 
302  char *ret = rz_analysis_class_get_attr_raw(analysis, class_name_sanitized, attr_type, attr_id_sanitized, specific);
303 
304  free(class_name_sanitized);
305  free(attr_id_sanitized);
306 
307  return ret;
308 }
309 
310 // all ids must be sanitized
311 static RzAnalysisClassErr rz_analysis_class_set_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, const char *content) {
312  const char *attr_type_str = attr_type_id(attr_type);
313 
314  if (!rz_analysis_class_exists_raw(analysis, class_name)) {
315  return RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_CLASS;
316  }
317 
318  char *key = key_attr_types(class_name);
319  if (key) {
320  sdb_array_add(analysis->sdb_classes_attrs, key, attr_type_str, 0);
321  free(key);
322  }
323  key = key_attr_type_attrs(class_name, attr_type_str);
324  if (key) {
325  sdb_array_add(analysis->sdb_classes_attrs, key, attr_id, 0);
326  free(key);
327  }
328  key = key_attr_content(class_name, attr_type_str, attr_id);
329  if (key) {
330  sdb_set(analysis->sdb_classes_attrs, key, content, 0);
331  free(key);
332  }
333 
334  RzEventClassAttrSet event = {
335  .attr = {
336  .class_name = class_name,
337  .attr_type = attr_type,
338  .attr_id = attr_id },
339  .content = content
340  };
341  rz_event_send(analysis->ev, RZ_EVENT_CLASS_ATTR_SET, &event);
342 
343  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
344 }
345 
346 // ids will be sanitized automatically
347 static RzAnalysisClassErr rz_analysis_class_set_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, const char *content) {
348  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
349  if (!class_name_sanitized) {
350  return RZ_ANALYSIS_CLASS_ERR_OTHER;
351  }
352 
353  char *attr_id_sanitized = rz_str_sanitize_sdb_key(attr_id);
354  if (!attr_id_sanitized) {
355  free(class_name_sanitized);
356  return RZ_ANALYSIS_CLASS_ERR_OTHER;
357  }
358 
359  RzAnalysisClassErr err = rz_analysis_class_set_attr_raw(analysis, class_name_sanitized, attr_type, attr_id_sanitized, content);
360 
361  free(class_name_sanitized);
362  free(attr_id_sanitized);
363 
364  return err;
365 }
366 
367 static RzAnalysisClassErr rz_analysis_class_delete_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id) {
368  const char *attr_type_str = attr_type_id(attr_type);
369 
370  char *key = key_attr_content(class_name, attr_type_str, attr_id);
371  if (key) {
372  sdb_remove(analysis->sdb_classes_attrs, key, 0);
373  free(key);
374  }
375  key = key_attr_content_specific(class_name, attr_type_str, attr_id);
376  if (key) {
377  sdb_remove(analysis->sdb_classes_attrs, key, 0);
378  free(key);
379  }
380 
381  key = key_attr_type_attrs(class_name, attr_type_str);
382  if (key) {
383  sdb_array_remove(analysis->sdb_classes_attrs, key, attr_id, 0);
384  if (!sdb_exists(analysis->sdb_classes_attrs, key)) {
385  sdb_array_remove(analysis->sdb_classes_attrs, key_attr_types(class_name), attr_type_str, 0);
386  }
387  free(key);
388  }
389 
390  RzEventClassAttr event = {
391  .class_name = class_name,
392  .attr_type = attr_type,
393  .attr_id = attr_id
394  };
395  rz_event_send(analysis->ev, RZ_EVENT_CLASS_ATTR_DEL, &event);
396 
397  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
398 }
399 
400 static RzAnalysisClassErr rz_analysis_class_delete_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id) {
401  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
402  if (!class_name_sanitized) {
403  return RZ_ANALYSIS_CLASS_ERR_OTHER;
404  }
405 
406  char *attr_id_sanitized = rz_str_sanitize_sdb_key(attr_id);
407  if (!attr_id_sanitized) {
408  free(class_name_sanitized);
409  return RZ_ANALYSIS_CLASS_ERR_OTHER;
410  }
411 
412  RzAnalysisClassErr err = rz_analysis_class_delete_attr_raw(analysis, class_name_sanitized, attr_type, attr_id_sanitized);
413 
414  free(class_name_sanitized);
415  free(attr_id_sanitized);
416  return err;
417 }
418 
419 static RzAnalysisClassErr rz_analysis_class_rename_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id_old, const char *attr_id_new) {
420  const char *attr_type_str = attr_type_id(attr_type);
421  char *key = key_attr_type_attrs(class_name, attr_type_str);
422  if (!key) {
423  return RZ_ANALYSIS_CLASS_ERR_OTHER;
424  }
425 
426  if (sdb_array_contains(analysis->sdb_classes_attrs, key, attr_id_new, 0)) {
427  free(key);
428  return RZ_ANALYSIS_CLASS_ERR_CLASH;
429  }
430 
431  if (!sdb_array_remove(analysis->sdb_classes_attrs, key, attr_id_old, 0)) {
432  free(key);
433  return RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_ATTR;
434  }
435 
436  sdb_array_add(analysis->sdb_classes_attrs, key, attr_id_new, 0);
437  free(key);
438 
439  key = key_attr_content(class_name, attr_type_str, attr_id_old);
440  if (key) {
441  char *content = sdb_get(analysis->sdb_classes_attrs, key, 0);
442  if (content) {
443  sdb_remove(analysis->sdb_classes_attrs, key, 0);
444  key = key_attr_content(class_name, attr_type_str, attr_id_new);
445  sdb_set(analysis->sdb_classes_attrs, key, content, 0);
446  free(content);
447  }
448  free(key);
449  }
450 
451  key = key_attr_content_specific(class_name, attr_type_str, attr_id_old);
452  if (key) {
453  char *content = sdb_get(analysis->sdb_classes_attrs, key, 0);
454  if (content) {
455  sdb_remove(analysis->sdb_classes_attrs, key, 0);
456  key = key_attr_content_specific(class_name, attr_type_str, attr_id_new);
457  sdb_set(analysis->sdb_classes_attrs, key, content, 0);
458  free(content);
459  }
460  free(key);
461  }
462 
463  RzEventClassAttrRename event = {
464  .attr = {
465  .class_name = class_name,
466  .attr_type = attr_type,
467  .attr_id = attr_id_old },
468  .attr_id_new = attr_id_new
469  };
470  rz_event_send(analysis->ev, RZ_EVENT_CLASS_ATTR_RENAME, &event);
471 
472  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
473 }
474 
475 static RzAnalysisClassErr rz_analysis_class_rename_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id_old, const char *attr_id_new) {
476  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
477  if (!class_name_sanitized) {
478  return RZ_ANALYSIS_CLASS_ERR_OTHER;
479  }
480  char *attr_id_old_sanitized = rz_str_sanitize_sdb_key(attr_id_old);
481  if (!attr_id_old_sanitized) {
482  free(class_name_sanitized);
483  return RZ_ANALYSIS_CLASS_ERR_OTHER;
484  }
485  char *attr_id_new_sanitized = rz_str_sanitize_sdb_key(attr_id_new);
486  if (!attr_id_new_sanitized) {
487  free(class_name_sanitized);
488  free(attr_id_old_sanitized);
489  return RZ_ANALYSIS_CLASS_ERR_OTHER;
490  }
491  RzAnalysisClassErr ret = rz_analysis_class_rename_attr_raw(analysis, class_name_sanitized, attr_type, attr_id_old_sanitized, attr_id_new_sanitized);
492  free(class_name_sanitized);
493  free(attr_id_old_sanitized);
494  free(attr_id_new_sanitized);
495  return ret;
496 }
497 
498 static void rz_analysis_class_unique_attr_id_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, char *out, size_t out_size) {
499  ut64 id = 0;
500  char *key = key_attr_type_attrs(class_name, attr_type_id(attr_type));
501  if (!key) {
502  return;
503  }
504  do {
505  snprintf(out, out_size, "%" PFMT64u, id);
506  id++;
507  } while (sdb_array_contains(analysis->sdb_classes_attrs, key, out, 0));
508  free(key);
509 }
510 
511 static char *flagname_attr(const char *attr_type, const char *class_name, const char *attr_id) {
512  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
513  if (!class_name_sanitized) {
514  return NULL;
515  }
516  char *attr_id_sanitized = rz_str_sanitize_sdb_key(attr_id);
517  if (!attr_id_sanitized) {
518  free(class_name_sanitized);
519  return NULL;
520  }
521  char *r = rz_str_newf("%s.%s.%s", attr_type, class_name, attr_id);
522  free(class_name_sanitized);
523  free(attr_id_sanitized);
524  return r;
525 }
526 
527 static void rz_analysis_class_set_flag(RzAnalysis *analysis, const char *name, ut64 addr, ut32 size) {
528  if (!name || !analysis->flg_class_set) {
529  return;
530  }
531  analysis->flg_class_set(analysis->flb.f, name, addr, size);
532 }
533 
534 static void rz_analysis_class_unset_flag(RzAnalysis *analysis, const char *name) {
535  if (!name || !analysis->flb.unset_name || !analysis->flg_class_get) {
536  return;
537  }
538  if (analysis->flg_class_get(analysis->flb.f, name)) {
539  analysis->flb.unset_name(analysis->flb.f, name);
540  }
541 }
542 
543 static void rz_analysis_class_rename_flag(RzAnalysis *analysis, const char *old_name, const char *new_name) {
544  if (!old_name || !new_name || !analysis->flb.unset || !analysis->flg_class_get || !analysis->flg_class_set) {
545  return;
546  }
547  RzFlagItem *flag = analysis->flg_class_get(analysis->flb.f, old_name);
548  if (!flag) {
549  return;
550  }
551  ut64 addr = flag->offset;
552  analysis->flb.unset(analysis->flb.f, flag);
553  analysis->flg_class_set(analysis->flb.f, new_name, addr, 0);
554 }
555 
556 static RzAnalysisClassErr rz_analysis_class_add_attr_unique_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *content, char *attr_id_out, size_t attr_id_out_size) {
557  char attr_id[16];
558  rz_analysis_class_unique_attr_id_raw(analysis, class_name, attr_type, attr_id, sizeof(attr_id));
559 
560  RzAnalysisClassErr err = rz_analysis_class_set_attr(analysis, class_name, attr_type, attr_id, content);
561  if (err != RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
562  return err;
563  }
564 
565  if (attr_id_out) {
566  rz_str_ncpy(attr_id_out, attr_id, attr_id_out_size);
567  }
568 
569  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
570 }
571 
572 static RzAnalysisClassErr rz_analysis_class_add_attr_unique(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *content, char *attr_id_out, size_t attr_id_out_size) {
573  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
574  if (!class_name_sanitized) {
575  return RZ_ANALYSIS_CLASS_ERR_OTHER;
576  }
577 
578  RzAnalysisClassErr err = rz_analysis_class_add_attr_unique_raw(analysis, class_name_sanitized, attr_type, content, attr_id_out, attr_id_out_size);
579 
580  free(class_name_sanitized);
581  return err;
582 }
583 
584 // ---- METHODS ----
585 // Format: addr,vtable_offset
586 
587 static int symbol_method_sort_by_addr(const void *x, const void *y) {
588  RzBinSymbol *a = (RzBinSymbol *)x;
589  RzBinSymbol *b = (RzBinSymbol *)y;
590  if (a->vaddr > b->vaddr) {
591  return 1;
592  }
593  if (a->vaddr < b->vaddr) {
594  return -1;
595  }
596  return 0;
597 }
598 
599 static char *flagname_method(const char *class_name, const char *meth_name) {
600  if (rz_str_startswith(meth_name, "method.")) {
601  return rz_str_new(meth_name);
602  }
603  return flagname_attr("method", class_name, meth_name);
604 }
605 
606 RZ_API void rz_analysis_class_method_fini(RzAnalysisMethod *meth) {
607  free(meth->name);
608  free(meth->real_name);
609 }
610 
611 RZ_API void rz_analysis_class_method_recover(RzAnalysis *analysis, RzBinClass *cls, RzList /*<RzBinSymbol *>*/ *methods) {
612  RzListIter *iter_method;
613  RzBinSymbol *sym;
615  rz_list_foreach (methods, iter_method, sym) {
616  if (!rz_analysis_class_method_exists(analysis, cls->name, sym->name)) {
617  // detect constructor or destructor but not implemented
618  // Temporarily set to default
619  RzAnalysisMethod method;
620  method.addr = sym->vaddr;
621  method.vtable_offset = -1;
623  char *method_name = rz_str_new(sym->name);
624  rz_str_split(method_name, '(');
625  method.name = fcn ? rz_str_new(fcn->name) : rz_str_new(method_name);
626  method.real_name = method_name;
627  method.method_type = RZ_ANALYSIS_CLASS_METHOD_DEFAULT;
628  rz_analysis_class_method_set(analysis, cls->name, &method);
630  }
631  }
632 }
633 
634 RZ_API bool rz_analysis_class_method_exists(RzAnalysis *analysis, const char *class_name, const char *meth_name) {
635  char *content = rz_analysis_class_get_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_METHOD, meth_name, false);
636  if (!content) {
637  return false;
638  }
639 
640  return true;
641 }
642 
643 RZ_API bool rz_analysis_class_method_exists_by_addr(RzAnalysis *analysis, const char *class_name, ut64 addr) {
644  RzVector *vec = rz_analysis_class_method_get_all(analysis, class_name);
645  if (!vec) {
646  return false;
647  }
648  RzAnalysisMethod *meth;
649  rz_vector_foreach(vec, meth) {
650  if (meth->addr == addr) {
651  rz_vector_free(vec);
652  return true;
653  }
654  }
655  rz_vector_free(vec);
656  return false;
657 }
658 
659 RZ_API RzAnalysisClassErr rz_analysis_class_method_get_by_addr(RzAnalysis *analysis, const char *class_name, ut64 addr, RzAnalysisMethod *method) {
660  RzVector *vec = rz_analysis_class_method_get_all(analysis, class_name);
661  if (!vec) {
662  return RZ_ANALYSIS_CLASS_ERR_OTHER;
663  }
664  RzAnalysisMethod *meth;
665  rz_vector_foreach(vec, meth) {
666  if (meth->addr == addr) {
667  method->name = rz_str_new(meth->name);
668  method->addr = meth->addr;
669  method->method_type = meth->method_type;
670  method->vtable_offset = meth->vtable_offset;
671  method->real_name = rz_str_new(meth->real_name);
672  rz_vector_free(vec);
673  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
674  }
675  }
676  rz_vector_free(vec);
677  return RZ_ANALYSIS_CLASS_ERR_OTHER;
678 }
679 
680 // if the method exists: store it in *meth and return RZ_ANALYSIS_CLASS_ERR_SUCCESS
681 // else return the error, contents of *meth are undefined
682 RZ_API RzAnalysisClassErr rz_analysis_class_method_get(RzAnalysis *analysis, const char *class_name, const char *meth_name, RzAnalysisMethod *meth) {
683  char *content = rz_analysis_class_get_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_METHOD, meth_name, false);
684  if (!content) {
685  return RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_ATTR;
686  }
687 
688  char *cur = content;
689  char *next;
690  sdb_anext(cur, &next);
691 
692  meth->addr = rz_num_math(NULL, cur);
693  cur = next;
694 
695  if (!cur) {
696  free(content);
697  return RZ_ANALYSIS_CLASS_ERR_OTHER;
698  }
699  sdb_anext(cur, &next);
700  meth->vtable_offset = atoll(cur);
701  cur = next;
702 
703  if (!cur) {
704  free(content);
705  return RZ_ANALYSIS_CLASS_ERR_OTHER;
706  }
707  sdb_anext(cur, &next);
708  meth->method_type = rz_num_math(NULL, cur);
709  cur = next;
710 
711  if (!cur) {
712  free(content);
713  return RZ_ANALYSIS_CLASS_ERR_OTHER;
714  }
715  sdb_anext(cur, NULL);
716 
717  meth->real_name = rz_str_new(cur);
718 
719  free(content);
720 
721  meth->name = rz_str_sanitize_sdb_key(meth_name);
722  if (!meth->name) {
723  return RZ_ANALYSIS_CLASS_ERR_OTHER;
724  }
725 
726  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
727 }
728 
729 static void rz_analysis_class_method_fini_proxy(void *e, void *user) {
730  (void)user;
731  RzAnalysisMethod *meth = e;
733 }
734 
735 RZ_API RzVector /*<RzAnalysisMethod>*/ *rz_analysis_class_method_get_all(RzAnalysis *analysis, const char *class_name) {
736  RzVector *vec = rz_vector_new(sizeof(RzAnalysisMethod), rz_analysis_class_method_fini_proxy, NULL);
737  if (!vec) {
738  return NULL;
739  }
740 
741  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
742  if (!class_name_sanitized) {
743  rz_vector_free(vec);
744  return NULL;
745  }
747  if (!key) {
748  rz_vector_free(vec);
749  free(class_name_sanitized);
750  return NULL;
751  }
752  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
753  free(key);
754  free(class_name_sanitized);
755 
756  rz_vector_reserve(vec, (size_t)sdb_alen(array));
757  char *cur;
758  sdb_aforeach(cur, array) {
759  RzAnalysisMethod meth;
760  if (rz_analysis_class_method_get(analysis, class_name, cur, &meth) == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
761  rz_vector_push(vec, &meth);
762  }
763  sdb_aforeach_next(cur);
764  }
765  free(array);
766 
767  return vec;
768 }
769 
770 RZ_API RzAnalysisClassErr rz_analysis_class_method_set(RzAnalysis *analysis, const char *class_name, RzAnalysisMethod *meth) {
771  char *content = rz_str_newf("%" PFMT64u "%c%" PFMT64d "%c%" PFMT32u "%c%s", meth->addr, SDB_RS, meth->vtable_offset, SDB_RS, meth->method_type, SDB_RS, meth->real_name);
772  if (!content) {
773  return RZ_ANALYSIS_CLASS_ERR_OTHER;
774  }
775  RzAnalysisClassErr err = rz_analysis_class_set_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_METHOD, meth->name, content);
776  free(content);
777  if (err != RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
778  return err;
779  }
780  char *fn = flagname_method(class_name, meth->name);
781  if (fn) {
782  rz_analysis_class_set_flag(analysis, fn, meth->addr, 0);
783  free(fn);
784  }
785  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
786 }
787 
788 RZ_API RzAnalysisClassErr rz_analysis_class_method_rename(RzAnalysis *analysis, const char *class_name, const char *old_meth_name, const char *new_meth_name) {
789  RzAnalysisMethod meth;
790  if (rz_analysis_class_method_get(analysis, class_name, old_meth_name, &meth) == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
791  meth.real_name = rz_str_new(new_meth_name);
792  rz_analysis_class_method_set(analysis, class_name, &meth);
794  }
795 
796  RzAnalysisClassErr err = rz_analysis_class_rename_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_METHOD, old_meth_name, new_meth_name);
797  if (err != RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
798  return err;
799  }
800  char *old_fn = flagname_method(class_name, old_meth_name);
801  char *new_fn = flagname_method(class_name, new_meth_name);
802  if (old_fn && new_fn) {
803  rz_analysis_class_rename_flag(analysis, old_fn, new_fn);
804  }
805  free(old_fn);
806  free(new_fn);
807  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
808 }
809 
810 static void rz_analysis_class_method_rename_class(RzAnalysis *analysis, const char *old_class_name, const char *new_class_name) {
812  if (!key) {
813  return;
814  }
815  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
816  free(key);
817  if (!array) {
818  return;
819  }
820  char *cur;
821  sdb_aforeach(cur, array) {
822  char *old_fn = flagname_method(old_class_name, cur);
823  char *new_fn = flagname_method(new_class_name, cur);
824  if (old_fn && new_fn) {
825  rz_analysis_class_rename_flag(analysis, old_fn, new_fn);
826  }
827  free(old_fn);
828  free(new_fn);
829  sdb_aforeach_next(cur);
830  }
831  free(array);
832 }
833 
834 static void rz_analysis_class_method_delete_class(RzAnalysis *analysis, const char *class_name) {
836  if (!key) {
837  return;
838  }
839  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
840  if (!array) {
841  return;
842  }
843  char *cur;
844  sdb_aforeach(cur, array) {
845  char *fn = flagname_method(class_name, cur);
846  if (fn) {
847  rz_analysis_class_unset_flag(analysis, fn);
848  }
849  free(fn);
850  sdb_aforeach_next(cur);
851  }
852  free(array);
853 }
854 
855 RZ_API RzAnalysisClassErr rz_analysis_class_method_delete(RzAnalysis *analysis, const char *class_name, const char *meth_name) {
856  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
857  if (!class_name_sanitized) {
858  return RZ_ANALYSIS_CLASS_ERR_OTHER;
859  }
860  char *meth_name_sanitized = rz_str_sanitize_sdb_key(meth_name);
861  if (!meth_name_sanitized) {
862  free(class_name_sanitized);
863  return RZ_ANALYSIS_CLASS_ERR_OTHER;
864  }
865  RzAnalysisClassErr err = rz_analysis_class_delete_attr_raw(analysis, class_name_sanitized, RZ_ANALYSIS_CLASS_ATTR_TYPE_METHOD, meth_name_sanitized);
866  if (err == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
867  char *fn = flagname_method(class_name_sanitized, meth_name_sanitized);
868  if (fn) {
869  rz_analysis_class_unset_flag(analysis, fn);
870  }
871  free(fn);
872  }
873  free(class_name_sanitized);
874  free(meth_name_sanitized);
875  return err;
876 }
877 
878 // ---- BASE ----
879 
880 RZ_API void rz_analysis_class_base_fini(RzAnalysisBaseClass *base) {
881  free(base->id);
882  free(base->class_name);
883 }
884 
885 RZ_API RzAnalysisClassErr rz_analysis_class_base_get(RzAnalysis *analysis, const char *class_name, const char *base_id, RzAnalysisBaseClass *base) {
886  char *content = rz_analysis_class_get_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_BASE, base_id, false);
887  if (!content) {
888  return RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_ATTR;
889  }
890 
891  char *cur = content;
892  char *next;
893  sdb_anext(cur, &next);
894 
895  base->class_name = strdup(cur);
896  if (!base->class_name) {
897  free(content);
898  return RZ_ANALYSIS_CLASS_ERR_OTHER;
899  }
900 
901  cur = next;
902  if (!cur) {
903  free(content);
904  free(base->class_name);
905  return RZ_ANALYSIS_CLASS_ERR_OTHER;
906  }
907  sdb_anext(cur, NULL);
908 
909  base->offset = rz_num_math(NULL, cur);
910 
911  free(content);
912 
913  base->id = rz_str_sanitize_sdb_key(base_id);
914  if (!base->id) {
915  free(base->class_name);
916  return RZ_ANALYSIS_CLASS_ERR_OTHER;
917  }
918 
919  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
920 }
921 
922 static void rz_analysis_class_base_fini_proxy(void *e, void *user) {
923  (void)user;
924  RzAnalysisBaseClass *base = e;
926 }
927 
928 RZ_API RzVector /*<RzAnalysisBaseClass>*/ *rz_analysis_class_base_get_all(RzAnalysis *analysis, const char *class_name) {
929  RzVector *vec = rz_vector_new(sizeof(RzAnalysisBaseClass), rz_analysis_class_base_fini_proxy, NULL);
930  if (!vec) {
931  return NULL;
932  }
933 
934  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
935  if (!class_name_sanitized) {
936  rz_vector_free(vec);
937  return NULL;
938  }
940  if (!key) {
941  rz_vector_free(vec);
942  free(class_name_sanitized);
943  return NULL;
944  }
945  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
946  free(key);
947  free(class_name_sanitized);
948 
949  rz_vector_reserve(vec, (size_t)sdb_alen(array));
950  char *cur;
951  sdb_aforeach(cur, array) {
952  RzAnalysisBaseClass base;
953  if (rz_analysis_class_base_get(analysis, class_name, cur, &base) == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
954  rz_vector_push(vec, &base);
955  }
956  sdb_aforeach_next(cur);
957  }
958  free(array);
959 
960  return vec;
961 }
962 
963 static RzAnalysisClassErr rz_analysis_class_base_set_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisBaseClass *base, const char *base_class_name_sanitized) {
964  char *content = rz_str_newf("%s" SDB_SS "%" PFMT64u, base_class_name_sanitized, base->offset);
965  if (!content) {
966  return RZ_ANALYSIS_CLASS_ERR_OTHER;
967  }
968  RzAnalysisClassErr err;
969  if (base->id) {
970  err = rz_analysis_class_set_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_BASE, base->id, content);
971  } else {
972  base->id = malloc(16);
973  if (base->id) {
974  err = rz_analysis_class_add_attr_unique(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_BASE, content, base->id, 16);
975  } else {
976  err = RZ_ANALYSIS_CLASS_ERR_OTHER;
977  }
978  }
979  free(content);
980  return err;
981 }
982 
983 RZ_API RzAnalysisClassErr rz_analysis_class_base_set(RzAnalysis *analysis, const char *class_name, RzAnalysisBaseClass *base) {
984  char *base_class_name_sanitized = rz_str_sanitize_sdb_key(base->class_name);
985  if (!base_class_name_sanitized) {
986  return RZ_ANALYSIS_CLASS_ERR_OTHER;
987  }
988 
989  if (!rz_analysis_class_exists_raw(analysis, base_class_name_sanitized)) {
990  free(base_class_name_sanitized);
991  return RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_CLASS;
992  }
993  RzVector /*<RzAnalysisBaseClass>*/ *bases = rz_analysis_class_base_get_all(analysis, class_name);
994  if (bases) {
995  RzAnalysisBaseClass *existing_base;
996  rz_vector_foreach(bases, existing_base) {
997  if (!strcmp(existing_base->class_name, base->class_name)) {
998  free(base_class_name_sanitized);
999  rz_vector_free(bases);
1000  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1001  }
1002  }
1003  }
1004  RzAnalysisClassErr err = rz_analysis_class_base_set_raw(analysis, class_name, base, base_class_name_sanitized);
1005  free(base_class_name_sanitized);
1006  rz_vector_free(bases);
1007  return err;
1008 }
1009 
1010 RZ_API RzAnalysisClassErr rz_analysis_class_base_delete(RzAnalysis *analysis, const char *class_name, const char *base_id) {
1011  return rz_analysis_class_delete_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_BASE, base_id);
1012 }
1013 
1014 typedef struct {
1016  const char *class_name;
1017 } DeleteClassCtx;
1018 
1019 static bool rz_analysis_class_base_delete_class_cb(void *user, const char *k, const char *v) {
1020  (void)v;
1021  DeleteClassCtx *ctx = user;
1022  RzVector *bases = rz_analysis_class_base_get_all(ctx->analysis, k);
1023  RzAnalysisBaseClass *base;
1024  rz_vector_foreach(bases, base) {
1025  if (base->class_name && strcmp(base->class_name, ctx->class_name) == 0) {
1026  rz_analysis_class_base_delete(ctx->analysis, k, base->id);
1027  }
1028  }
1029  rz_vector_free(bases);
1030  return true;
1031 }
1032 
1033 static void rz_analysis_class_base_delete_class(RzAnalysis *analysis, const char *class_name) {
1034  DeleteClassCtx ctx = { analysis, class_name };
1036 }
1037 
1038 typedef struct {
1040  const char *class_name_old;
1041  const char *class_name_new;
1042 } RenameClassCtx;
1043 
1044 static bool rz_analysis_class_base_rename_class_cb(void *user, const char *k, const char *v) {
1045  (void)v;
1046  RenameClassCtx *ctx = user;
1047  RzVector *bases = rz_analysis_class_base_get_all(ctx->analysis, k);
1048  RzAnalysisBaseClass *base;
1049  rz_vector_foreach(bases, base) {
1050  if (base->class_name && strcmp(base->class_name, ctx->class_name_old) == 0) {
1051  rz_analysis_class_base_set_raw(ctx->analysis, k, base, ctx->class_name_new);
1052  }
1053  }
1054  rz_vector_free(bases);
1055  return 1;
1056 }
1057 
1058 static void rz_analysis_class_base_rename_class(RzAnalysis *analysis, const char *class_name_old, const char *class_name_new) {
1059  RenameClassCtx ctx = { analysis, class_name_old, class_name_new };
1061 }
1062 
1063 // ---- VTABLE ----
1064 
1065 static char *flagname_vtable(const char *class_name, const char *vtable_id) {
1066  return flagname_attr("vtable", class_name, vtable_id);
1067 }
1068 
1069 RZ_API void rz_analysis_class_vtable_fini(RzAnalysisVTable *vtable) {
1070  free(vtable->id);
1071 }
1072 
1073 RZ_API RzAnalysisClassErr rz_analysis_class_vtable_get(RzAnalysis *analysis, const char *class_name, const char *vtable_id, RzAnalysisVTable *vtable) {
1074  char *content = rz_analysis_class_get_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_VTABLE, vtable_id, false);
1075  if (!content) {
1076  return RZ_ANALYSIS_CLASS_ERR_NONEXISTENT_ATTR;
1077  }
1078 
1079  char *cur = content;
1080  char *next;
1081  sdb_anext(cur, &next);
1082 
1083  vtable->addr = rz_num_math(NULL, cur);
1084 
1085  cur = next;
1086  if (!cur) {
1087  free(content);
1088  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1089  }
1090  sdb_anext(cur, &next);
1091 
1092  vtable->offset = rz_num_math(NULL, cur);
1093 
1094  if (next) {
1095  cur = next;
1096  sdb_anext(cur, NULL);
1097  vtable->size = rz_num_get(NULL, cur);
1098  } else {
1099  vtable->size = 0;
1100  }
1101 
1102  free(content);
1103 
1104  vtable->id = rz_str_sanitize_sdb_key(vtable_id);
1105  if (!vtable->id) {
1106  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1107  }
1108 
1109  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
1110 }
1111 
1112 static void rz_analysis_class_vtable_fini_proxy(void *e, void *user) {
1113  (void)user;
1114  RzAnalysisVTable *vtable = e;
1116 }
1117 
1118 RZ_API RzVector /*<RzAnalysisVTable>*/ *rz_analysis_class_vtable_get_all(RzAnalysis *analysis, const char *class_name) {
1119  RzVector *vec = rz_vector_new(sizeof(RzAnalysisVTable), rz_analysis_class_vtable_fini_proxy, NULL);
1120  if (!vec) {
1121  return NULL;
1122  }
1123 
1124  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
1125  if (!class_name_sanitized) {
1126  rz_vector_free(vec);
1127  return NULL;
1128  }
1130  if (!key) {
1131  rz_vector_free(vec);
1132  free(class_name_sanitized);
1133  return NULL;
1134  }
1135  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
1136  free(key);
1137  free(class_name_sanitized);
1138 
1139  rz_vector_reserve(vec, (size_t)sdb_alen(array));
1140  char *cur;
1141  sdb_aforeach(cur, array) {
1142  RzAnalysisVTable vtable;
1143  if (rz_analysis_class_vtable_get(analysis, class_name, cur, &vtable) == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
1144  rz_vector_push(vec, &vtable);
1145  }
1146  sdb_aforeach_next(cur);
1147  }
1148  free(array);
1149 
1150  return vec;
1151 }
1152 
1153 RZ_API RzAnalysisClassErr rz_analysis_class_vtable_set(RzAnalysis *analysis, const char *class_name, RzAnalysisVTable *vtable) {
1154  /* Check if vtable exists before setting it */
1155  RzVector /*<RzAnalysisVTable>*/ *vtables = rz_analysis_class_vtable_get_all(analysis, class_name);
1156  if (vtables) {
1157  RzAnalysisVTable *existing_vtable;
1158  rz_vector_foreach(vtables, existing_vtable) {
1159  if (vtable->addr == existing_vtable->addr) {
1160  rz_vector_free(vtables);
1161  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1162  }
1163  }
1164  }
1165  rz_vector_free(vtables);
1166 
1167  char *content = rz_str_newf("0x%" PFMT64x SDB_SS "%" PFMT64u SDB_SS "%" PFMT64u, vtable->addr, vtable->offset, vtable->size);
1168  if (!content) {
1169  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1170  }
1171  if (vtable->id) {
1172  RzAnalysisClassErr r = rz_analysis_class_set_attr(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_VTABLE, vtable->id, content);
1173  free(content);
1174  return r;
1175  }
1176 
1177  vtable->id = malloc(16);
1178  if (!vtable->id) {
1179  free(content);
1180  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1181  }
1182  RzAnalysisClassErr err = rz_analysis_class_add_attr_unique(analysis, class_name, RZ_ANALYSIS_CLASS_ATTR_TYPE_VTABLE, content, vtable->id, 16);
1183  free(content);
1184  if (err != RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
1185  return err;
1186  }
1187 
1188  rz_analysis_class_set_flag(analysis, flagname_vtable(class_name, vtable->id), vtable->addr, vtable->size);
1189 
1190  return RZ_ANALYSIS_CLASS_ERR_SUCCESS;
1191 }
1192 
1193 static void rz_analysis_class_vtable_rename_class(RzAnalysis *analysis, const char *old_class_name, const char *new_class_name) {
1195  if (!key) {
1196  return;
1197  }
1198  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
1199  free(key);
1200  if (!array) {
1201  return;
1202  }
1203  char *cur;
1204  sdb_aforeach(cur, array) {
1205  char *old_fn = flagname_vtable(old_class_name, cur);
1206  char *new_fn = flagname_vtable(new_class_name, cur);
1207  if (old_fn && new_fn) {
1208  rz_analysis_class_rename_flag(analysis, old_fn, new_fn);
1209  }
1210  free(old_fn);
1211  free(new_fn);
1212  sdb_aforeach_next(cur);
1213  }
1214  free(array);
1215 }
1216 
1217 static void rz_analysis_class_vtable_delete_class(RzAnalysis *analysis, const char *class_name) {
1219  if (!key) {
1220  return;
1221  }
1222  char *array = sdb_get(analysis->sdb_classes_attrs, key, 0);
1223  free(key);
1224  if (!array) {
1225  return;
1226  }
1227  char *cur;
1228  sdb_aforeach(cur, array) {
1229  rz_analysis_class_unset_flag(analysis, flagname_vtable(class_name, cur));
1230  sdb_aforeach_next(cur);
1231  }
1232  free(array);
1233 }
1234 
1235 RZ_API RzAnalysisClassErr rz_analysis_class_vtable_delete(RzAnalysis *analysis, const char *class_name, const char *vtable_id) {
1236  char *class_name_sanitized = rz_str_sanitize_sdb_key(class_name);
1237  if (!class_name_sanitized) {
1238  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1239  }
1240  char *vtable_id_sanitized = rz_str_sanitize_sdb_key(vtable_id);
1241  if (!vtable_id_sanitized) {
1242  free(class_name_sanitized);
1243  return RZ_ANALYSIS_CLASS_ERR_OTHER;
1244  }
1245  RzAnalysisClassErr err = rz_analysis_class_delete_attr_raw(analysis, class_name_sanitized, RZ_ANALYSIS_CLASS_ATTR_TYPE_VTABLE, vtable_id_sanitized);
1246  if (err == RZ_ANALYSIS_CLASS_ERR_SUCCESS) {
1247  rz_analysis_class_unset_flag(analysis, flagname_vtable(class_name_sanitized, vtable_id_sanitized));
1248  }
1249  free(class_name_sanitized);
1250  free(vtable_id_sanitized);
1251  return err;
1252 }
1253 
1262  rz_return_val_if_fail(analysis, NULL);
1263  RzGraph *class_graph = rz_graph_new();
1264  if (!class_graph) {
1265  return NULL;
1266  }
1267  SdbList *classes = rz_analysis_class_get_all(analysis, true);
1268  if (!classes) {
1269  rz_graph_free(class_graph);
1270  return NULL;
1271  }
1272  HtPP /*<char *name, RzGraphNode *node>*/ *hashmap = ht_pp_new0();
1273  if (!hashmap) {
1274  rz_graph_free(class_graph);
1275  ls_free(classes);
1276  return NULL;
1277  }
1278  SdbListIter *iter;
1279  SdbKv *kv;
1280  // Traverse each class and create a node and edges
1281  ls_foreach (classes, iter, kv) {
1282  const char *name = sdbkv_key(kv);
1283  // create nodes
1284  RzGraphNode *curr_node = ht_pp_find(hashmap, name, NULL);
1285  if (!curr_node) {
1286  curr_node = rz_graph_add_node_info(class_graph, name, NULL, 0);
1287  if (!curr_node) {
1288  goto failure;
1289  }
1290  ht_pp_insert(hashmap, name, curr_node);
1291  }
1292  // create edges between node and it's parents
1293  RzVector *bases = rz_analysis_class_base_get_all(analysis, name);
1294  RzAnalysisBaseClass *base;
1295  rz_vector_foreach(bases, base) {
1296  bool base_found = false;
1297  RzGraphNode *base_node = ht_pp_find(hashmap, base->class_name, &base_found);
1298  // If base isn't processed, do it now
1299  if (!base_found) {
1300  base_node = rz_graph_add_node_info(class_graph, base->class_name, NULL, 0);
1301  if (!base_node) {
1302  goto failure;
1303  }
1304  ht_pp_insert(hashmap, base->class_name, base_node);
1305  }
1306  rz_graph_add_edge(class_graph, base_node, curr_node);
1307  }
1308  rz_vector_free(bases);
1309  }
1310  ls_free(classes);
1311  ht_pp_free(hashmap);
1312  return class_graph;
1313 
1314 failure:
1315  ls_free(classes);
1316  ht_pp_free(hashmap);
1317  rz_graph_free(class_graph);
1318  return NULL;
1319 }
1320 
1323  rz_analysis_rtti_recover_all(analysis);
1324 }
RZ_API RzAnalysisFunction * rz_analysis_get_function_at(RzAnalysis *analysis, ut64 addr)
Definition: function.c:184
#define e(frag)
static RzILOpEffect * cls(cs_insn *insn)
Definition: arm_il64.c:915
static bool err
Definition: armass.c:435
RZ_API int sdb_array_add(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: array.c:224
RZ_API int sdb_array_remove(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: array.c:436
RZ_API bool sdb_array_contains(Sdb *s, const char *key, const char *val, ut32 *cas)
Definition: array.c:497
RZ_DEPRECATE RZ_API RZ_BORROW RzList * rz_bin_get_classes(RZ_NONNULL RzBin *bin)
Definition: bin.c:883
static RzList * classes(RzBinFile *bf)
Definition: bin_dex.c:71
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
static bool rz_analysis_class_exists_raw(RzAnalysis *analysis, const char *name)
Definition: class.c:163
static const char * key_class(const char *name)
Definition: class.c:18
static RzAnalysisClassErr rz_analysis_class_rename_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id_old, const char *attr_id_new)
Definition: class.c:475
static char * flagname_vtable(const char *class_name, const char *vtable_id)
Definition: class.c:1065
static char * rz_analysis_class_get_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, bool specific)
Definition: class.c:291
RZ_API RzVector * rz_analysis_class_base_get_all(RzAnalysis *analysis, const char *class_name)
Definition: class.c:928
RZ_API void rz_analysis_class_method_recover(RzAnalysis *analysis, RzBinClass *cls, RzList *methods)
Definition: class.c:611
RZ_API bool rz_analysis_class_method_exists_by_addr(RzAnalysis *analysis, const char *class_name, ut64 addr)
Definition: class.c:643
static void rz_analysis_class_base_delete_class(RzAnalysis *analysis, const char *class_name)
Definition: class.c:1033
RZ_API RzAnalysisClassErr rz_analysis_class_vtable_delete(RzAnalysis *analysis, const char *class_name, const char *vtable_id)
Definition: class.c:1235
static void rz_analysis_class_base_fini_proxy(void *e, void *user)
Definition: class.c:922
RZ_API RzAnalysisClassErr rz_analysis_class_method_rename(RzAnalysis *analysis, const char *class_name, const char *old_meth_name, const char *new_meth_name)
Definition: class.c:788
RZ_API RzAnalysisClassErr rz_analysis_class_base_set(RzAnalysis *analysis, const char *class_name, RzAnalysisBaseClass *base)
Definition: class.c:983
static bool rename_key(Sdb *sdb, const char *key_old, const char *key_new)
Definition: class.c:185
RZ_API RzVector * rz_analysis_class_method_get_all(RzAnalysis *analysis, const char *class_name)
Definition: class.c:735
static RzAnalysisClassErr rz_analysis_class_set_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, const char *content)
Definition: class.c:311
static RzAnalysisClassErr rz_analysis_class_delete_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id)
Definition: class.c:400
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
static void rz_analysis_class_unique_attr_id_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, char *out, size_t out_size)
Definition: class.c:498
static RzAnalysisClassErr rz_analysis_class_add_attr_unique(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *content, char *attr_id_out, size_t attr_id_out_size)
Definition: class.c:572
static bool rz_analysis_class_base_delete_class_cb(void *user, const char *k, const char *v)
Definition: class.c:1019
RZ_API void rz_analysis_class_recover_all(RzAnalysis *analysis)
Definition: class.c:1321
static void rz_analysis_class_rename_flag(RzAnalysis *analysis, const char *old_name, const char *new_name)
Definition: class.c:543
static void rz_analysis_class_set_flag(RzAnalysis *analysis, const char *name, ut64 addr, ut32 size)
Definition: class.c:527
RZ_API void rz_analysis_class_vtable_fini(RzAnalysisVTable *vtable)
Definition: class.c:1069
static RzAnalysisClassErr rz_analysis_class_delete_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id)
Definition: class.c:367
RZ_API RzAnalysisClassErr rz_analysis_class_rename(RzAnalysis *analysis, const char *old_name, const char *new_name)
Definition: class.c:196
static char * flagname_attr(const char *attr_type, const char *class_name, const char *attr_id)
Definition: class.c:511
RZ_API RzAnalysisClassErr rz_analysis_class_method_delete(RzAnalysis *analysis, const char *class_name, const char *meth_name)
Definition: class.c:855
static void rz_analysis_class_method_delete_class(RzAnalysis *analysis, const char *class_name)
Definition: class.c:834
RZ_API RzAnalysisClassErr rz_analysis_class_base_delete(RzAnalysis *analysis, const char *class_name, const char *base_id)
Definition: class.c:1010
RZ_API RzAnalysisClassErr rz_analysis_class_method_get(RzAnalysis *analysis, const char *class_name, const char *meth_name, RzAnalysisMethod *meth)
Definition: class.c:682
static RzAnalysisClassErr rz_analysis_class_add_attr_unique_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *content, char *attr_id_out, size_t attr_id_out_size)
Definition: class.c:556
static void rz_analysis_class_base_rename_class(RzAnalysis *analysis, const char *class_name_old, const char *class_name_new)
Definition: class.c:1058
static char * key_attr_type_attrs(const char *class_name, const char *attr_type)
Definition: class.c:26
static void rz_analysis_class_vtable_delete_class(RzAnalysis *analysis, const char *class_name)
Definition: class.c:1217
static char * flagname_method(const char *class_name, const char *meth_name)
Definition: class.c:599
static void rz_analysis_class_method_fini_proxy(void *e, void *user)
Definition: class.c:729
static void rz_analysis_class_unset_flag(RzAnalysis *analysis, const char *name)
Definition: class.c:534
RZ_API void rz_analysis_class_recover_from_rzbin(RzAnalysis *analysis)
Definition: class.c:57
static const char * attr_type_id(RzAnalysisClassAttrType attr_type)
Definition: class.c:44
static RzAnalysisClassErr rz_analysis_class_rename_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id_old, const char *attr_id_new)
Definition: class.c:419
RZ_API RzGraph * rz_analysis_class_get_inheritance_graph(RzAnalysis *analysis)
Creates RzGraph from class inheritance information where each node has RzGraphNodeInfo as generic dat...
Definition: class.c:1261
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 SdbList * rz_analysis_class_get_all(RzAnalysis *analysis, bool sorted)
Definition: class.c:177
RZ_API void rz_analysis_class_method_fini(RzAnalysisMethod *meth)
Definition: class.c:606
RZ_API RzVector * rz_analysis_class_vtable_get_all(RzAnalysis *analysis, const char *class_name)
Definition: class.c:1118
RZ_API void rz_analysis_class_foreach(RzAnalysis *analysis, SdbForeachCallback cb, void *user)
Definition: class.c:181
RZ_API RzAnalysisClassErr rz_analysis_class_create(RzAnalysis *analysis, const char *name)
Definition: class.c:79
static void rz_analysis_class_vtable_rename_class(RzAnalysis *analysis, const char *old_class_name, const char *new_class_name)
Definition: class.c:1193
RZ_API bool rz_analysis_class_method_exists(RzAnalysis *analysis, const char *class_name, const char *meth_name)
Definition: class.c:634
static void rz_analysis_class_vtable_fini_proxy(void *e, void *user)
Definition: class.c:1112
RZ_API RzAnalysisClassErr rz_analysis_class_base_get(RzAnalysis *analysis, const char *class_name, const char *base_id, RzAnalysisBaseClass *base)
Definition: class.c:885
RZ_API RzAnalysisClassErr rz_analysis_class_method_get_by_addr(RzAnalysis *analysis, const char *class_name, ut64 addr, RzAnalysisMethod *method)
Definition: class.c:659
static char * key_attr_content_specific(const char *class_name, const char *attr_type, const char *attr_id)
Definition: class.c:34
static bool rz_analysis_class_base_rename_class_cb(void *user, const char *k, const char *v)
Definition: class.c:1044
static char * rz_analysis_class_get_attr_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, bool specific)
Definition: class.c:277
static char * key_attr_content(const char *class_name, const char *attr_type, const char *attr_id)
Definition: class.c:30
static RzAnalysisClassErr rz_analysis_class_base_set_raw(RzAnalysis *analysis, const char *class_name, RzAnalysisBaseClass *base, const char *base_class_name_sanitized)
Definition: class.c:963
static char * key_attr_types(const char *name)
Definition: class.c:22
RZ_API void rz_analysis_class_delete(RzAnalysis *analysis, const char *name)
Definition: class.c:98
RZ_API RzAnalysisClassErr rz_analysis_class_vtable_get(RzAnalysis *analysis, const char *class_name, const char *vtable_id, RzAnalysisVTable *vtable)
Definition: class.c:1073
static void rz_analysis_class_method_rename_class(RzAnalysis *analysis, const char *old_class_name, const char *new_class_name)
Definition: class.c:810
static int symbol_method_sort_by_addr(const void *x, const void *y)
Definition: class.c:587
static RzAnalysisClassErr rz_analysis_class_set_attr(RzAnalysis *analysis, const char *class_name, RzAnalysisClassAttrType attr_type, const char *attr_id, const char *content)
Definition: class.c:347
RzAnalysisClassAttrType
Definition: class.c:38
@ RZ_ANALYSIS_CLASS_ATTR_TYPE_METHOD
Definition: class.c:39
@ RZ_ANALYSIS_CLASS_ATTR_TYPE_BASE
Definition: class.c:41
@ RZ_ANALYSIS_CLASS_ATTR_TYPE_VTABLE
Definition: class.c:40
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 bool rz_cons_is_breaked(void)
Definition: cons.c:373
#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 static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
uint32_t ut32
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
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
void * malloc(size_t size)
Definition: malloc.c:123
static const char struct stat static buf struct stat static buf static idle const char static path static fd const char static len const void static prot const char struct module static image struct kernel_sym static table unsigned char static buf static fsuid unsigned struct dirent unsigned static count const struct iovec static count static pid const void static len static flags const struct sched_param static p static pid static policy struct timespec static tp static suid unsigned fn
Definition: sflib.h:186
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")
RZ_API void ls_free(SdbList *list)
Definition: ls.c:191
#define ls_foreach(list, it, pos)
Definition: ls.h:31
int x
Definition: mipsasm.c:20
const char * name
Definition: op.c:541
RZ_API void rz_analysis_rtti_recover_all(RzAnalysis *analysis)
Definition: rtti.c:87
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API void rz_event_send(RzEvent *ev, int type, void *data)
Definition: event.c:115
@ RZ_EVENT_CLASS_ATTR_SET
Definition: rz_event.h:38
@ RZ_EVENT_CLASS_DEL
Definition: rz_event.h:36
@ RZ_EVENT_CLASS_NEW
Definition: rz_event.h:35
@ RZ_EVENT_CLASS_ATTR_DEL
Definition: rz_event.h:39
@ RZ_EVENT_CLASS_ATTR_RENAME
Definition: rz_event.h:40
@ RZ_EVENT_CLASS_RENAME
Definition: rz_event.h:37
RZ_API RzGraph * rz_graph_new(void)
Definition: graph.c:108
RZ_API void rz_graph_add_edge(RzGraph *g, RzGraphNode *from, RzGraphNode *to)
Definition: graph.c:199
RZ_API void rz_graph_free(RzGraph *g)
Definition: graph.c:124
RZ_API RzGraphNode * rz_graph_add_node_info(RzGraph *graph, const char *title, const char *body, ut64 offset)
RZ_API ut64 rz_num_get(RzNum *num, const char *str)
Definition: unum.c:172
RZ_API ut64 rz_num_math(RzNum *num, const char *str)
Definition: unum.c:456
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_sanitize_sdb_key(const char *s)
Definition: str.c:1405
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n)
Secure string copy with null terminator.
Definition: str.c:923
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API size_t rz_str_split(char *str, char ch)
Split string str in place by using ch as a delimiter.
Definition: str.c:406
#define PFMT64d
Definition: rz_types.h:394
#define PFMT32u
Definition: rz_types.h:409
#define PFMT64u
Definition: rz_types.h:395
#define PFMT64x
Definition: rz_types.h:393
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
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
RZ_API void rz_vector_free(RzVector *vec)
Definition: vector.c:75
RZ_API RzVector * rz_vector_new(size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:42
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
Definition: sdb.c:611
RZ_API char * sdb_get(Sdb *s, const char *key, ut32 *cas)
Definition: sdb.c:290
RZ_API bool sdb_remove(Sdb *s, const char *key, ut32 cas)
Definition: sdb.c:299
RZ_API bool sdb_foreach(Sdb *s, SdbForeachCallback cb, void *user)
Definition: sdb.c:758
RZ_API SdbList * sdb_foreach_list(Sdb *s, bool sorted)
Definition: sdb.c:630
RZ_API bool sdb_exists(Sdb *s, const char *key)
Definition: sdb.c:358
RZ_API char * sdb_anext(char *str, char **next)
Definition: util.c:192
bool(* SdbForeachCallback)(void *user, const char *k, const char *v)
Definition: sdb.h:115
RZ_API int sdb_alen(const char *str)
Definition: util.c:151
#define SDB_SS
Definition: sdb.h:48
#define sdb_aforeach_next(x)
Definition: sdb.h:348
#define sdb_aforeach(x, y)
Definition: sdb.h:342
#define SDB_RS
Definition: sdb.h:47
static char * sdbkv_key(const SdbKv *kv)
Definition: sdbht.h:21
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
RzAnalysis * analysis
Definition: class.c:1015
const char * class_name
Definition: class.c:1016
const char * class_name_new
Definition: class.c:1041
RzAnalysis * analysis
Definition: class.c:1039
const char * class_name_old
Definition: class.c:1040
Definition: ls.h:17
Definition: ls.h:22
Definition: z80asm.h:102
RzFlagSet flg_class_set
Definition: rz_analysis.h:576
RzEvent * ev
Definition: rz_analysis.h:617
RzBinBind binb
Definition: rz_analysis.h:579
RzFlagGet flg_class_get
Definition: rz_analysis.h:577
Sdb * sdb_classes_attrs
Definition: rz_analysis.h:606
RzFlagBind flb
Definition: rz_analysis.h:575
Sdb * sdb_classes
Definition: rz_analysis.h:605
RzBin * bin
Definition: rz_bin.h:807
char * name
Definition: rz_bin.h:675
RzEventClassAttr attr
Definition: rz_event.h:76
RzEventClassAttr attr
Definition: rz_event.h:71
const char * class_name
Definition: rz_event.h:65
const char * name_old
Definition: rz_event.h:60
const char * name
Definition: rz_event.h:56
RzFlagUnsetName unset_name
Definition: rz_flag.h:86
RzFlag * f
Definition: rz_flag.h:78
RzFlagUnset unset
Definition: rz_flag.h:85
ut64 offset
Definition: rz_flag.h:38
Definition: sdbht.h:14
Definition: sdb.h:63
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const char * cb[]
Definition: z80_tab.h:176
static int addr
Definition: z80asm.c:58