diff --git a/libr/bin/format/mach0/mach0.c b/libr/bin/format/mach0/mach0.c index 2be7b54061..93f46761f3 100644 --- a/libr/bin/format/mach0/mach0.c +++ b/libr/bin/format/mach0/mach0.c @@ -2194,6 +2194,9 @@ void *MACH0_(mach0_free)(struct MACH0_(obj_t) *mo) { } r_list_free (mo->cached_segments); mo->cached_segments = NULL; + if (mo->relocs_loaded) { + r_skiplist_free (mo->relocs_cache); + } if (mo->chained_starts) { for (i = 0; i < mo->nsegs && i < mo->segs_count; i++) { if (mo->chained_starts[i]) { @@ -3540,8 +3543,7 @@ static bool is_valid_ordinal_table_size(ut64 size) { return size > 0 && size <= UT16_MAX; } -RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { - RSkipList *relocs = NULL; +static inline bool _load_relocations(struct MACH0_(obj_t) *bin) { RPVector *threaded_binds = NULL; size_t wordsize = get_word_size (bin); if (bin->dyld_info) { @@ -3554,7 +3556,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { CASE(16); CASE(32); CASE(64); - default: return NULL; + default: return false; } #undef CASE bind_size = bin->dyld_info->bind_size; @@ -3562,40 +3564,35 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { weak_size = bin->dyld_info->weak_bind_size; if (!bind_size && !lazy_size) { - return NULL; + return false; } if ((bind_size + lazy_size) < 1) { - return NULL; + return false; } if (bin->dyld_info->bind_off > bin->size || bin->dyld_info->bind_off + bind_size > bin->size) { - return NULL; + return false; } if (bin->dyld_info->lazy_bind_off > bin->size || \ bin->dyld_info->lazy_bind_off + lazy_size > bin->size) { - return NULL; + return false; } if (bin->dyld_info->bind_off + bind_size + lazy_size > bin->size) { - return NULL; + return false; } if (bin->dyld_info->weak_bind_off + weak_size > bin->size) { - return NULL; + return false; } ut64 amount = bind_size + lazy_size + weak_size; if (amount == 0 || amount > UT32_MAX) { - return NULL; + return false; } if (!bin->segs) { - return NULL; - } - relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator); - if (!relocs) { - return NULL; + return false; } opcodes = calloc (1, amount + 1); if (!opcodes) { - r_skiplist_free (relocs); - return NULL; + return false; } int len = r_buf_read_at (bin->b, bin->dyld_info->bind_off, opcodes, bind_size); @@ -3604,8 +3601,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { if (len < amount) { R_LOG_ERROR ("read (dyld_info bind) at 0x%08"PFMT64x, (ut64)(size_t)bin->dyld_info->bind_off); R_FREE (opcodes); - r_skiplist_free (relocs); - return NULL; + return false; } size_t partition_sizes[] = {bind_size, lazy_size, weak_size}; @@ -3720,7 +3716,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { if (addend != -1) { reloc->addend = addend; } - r_skiplist_insert (relocs, reloc); + r_skiplist_insert (bin->relocs_cache, reloc); } addr += delta * wordsize; if (!delta) { @@ -3788,9 +3784,8 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { bprintf ("Error: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB" " has unexistent segment %d\n", seg_idx); free (opcodes); - r_skiplist_free (relocs); r_pvector_free (threaded_binds); - return NULL; // early exit to avoid future mayhem + return false; // early exit to avoid future mayhem } addr = bin->segs[seg_idx].vmaddr + read_uleb128 (&p, end); segment_end_addr = bin->segs[seg_idx].vmaddr \ @@ -3825,7 +3820,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { if (threaded_binds)\ r_pvector_set (threaded_binds, sym_ord, reloc);\ else\ - r_skiplist_insert (relocs, reloc);\ + r_skiplist_insert (bin->relocs_cache, reloc);\ } while (0) case BIND_OPCODE_DO_BIND: if (!threaded_binds && addr >= segment_end_addr) { @@ -3872,7 +3867,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { bprintf ("Error: unknown bind opcode 0x%02x in dyld_info\n", *p); R_FREE (opcodes); r_pvector_free (threaded_binds); - return relocs; + return false; } } @@ -3890,12 +3885,6 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { if (amount < 0) { amount = 0; } - if (!relocs) { - relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator); - if (!relocs) { - goto beach; - } - } for (j = 0; j < amount; j++) { struct reloc_t *reloc = R_NEW0 (struct reloc_t); if (!reloc) { @@ -3903,7 +3892,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { } if (parse_import_ptr (bin, reloc, bin->dysymtab.iundefsym + j)) { reloc->ord = j; - r_skiplist_insert_autofree (relocs, reloc); + r_skiplist_insert_autofree (bin->relocs_cache, reloc); } else { R_FREE (reloc); } @@ -3911,27 +3900,37 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) { } if (bin->symtab && bin->dysymtab.extreloff && bin->dysymtab.nextrel) { - if (!relocs) { - relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator); - if (!relocs) { - goto beach; - } - } - parse_relocation_info (bin, relocs, bin->dysymtab.extreloff, bin->dysymtab.nextrel); + parse_relocation_info (bin, bin->relocs_cache, bin->dysymtab.extreloff, bin->dysymtab.nextrel); } if (!bin->dyld_info && bin->chained_starts && bin->nsegs && bin->fixups_offset) { - if (!relocs) { - relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator); - if (!relocs) { - goto beach; - } - } - walk_bind_chains (bin, relocs); + walk_bind_chains (bin, bin->relocs_cache); } + beach: r_pvector_free (threaded_binds); - return relocs; + return true; +} + +const RSkipList *MACH0_(load_relocs)(struct MACH0_(obj_t) *bin) { + r_return_val_if_fail (bin, NULL); + + if (bin->relocs_loaded) { + return bin->relocs_cache; + } + + bin->relocs_loaded = true; + bin->relocs_cache = r_skiplist_new ((RListFree) free, (RListComparator) reloc_comparator); + if (!bin->relocs_cache) { + return NULL; + } + + bool is_success = _load_relocations (bin); + if (is_success) { + return bin->relocs_cache; + } + + return NULL; } struct addr_t *MACH0_(get_entrypoint)(struct MACH0_(obj_t) *bin) { diff --git a/libr/bin/format/mach0/mach0.h b/libr/bin/format/mach0/mach0.h index 023fee1b21..215dec3c08 100644 --- a/libr/bin/format/mach0/mach0.h +++ b/libr/bin/format/mach0/mach0.h @@ -62,7 +62,6 @@ struct reloc_t { st64 addend; ut8 type; int ord; - int last; char name[256]; bool external; bool pc_relative; @@ -180,6 +179,8 @@ struct MACH0_(obj_t) { RVector sections_cache; bool imports_loaded; RPVector imports_cache; + bool relocs_loaded; + RSkipList *relocs_cache; RList *reloc_fixups; ut8 *internal_buffer; int internal_buffer_size; @@ -247,7 +248,7 @@ RList *MACH0_(get_segments)(RBinFile *bf, struct MACH0_(obj_t) *bin); const RVector *MACH0_(load_symbols)(RBinFile *bf, struct MACH0_(obj_t) *bin); void MACH0_(pull_symbols)(struct MACH0_(obj_t) *mo, RBinSymbolCallback cb, void *user); const RPVector *MACH0_(load_imports)(RBinFile* bf, struct MACH0_(obj_t) *bin); -RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin); +const RSkipList *MACH0_(load_relocs)(struct MACH0_(obj_t) *bin); struct addr_t *MACH0_(get_entrypoint)(struct MACH0_(obj_t) *bin); const RPVector *MACH0_(load_libs)(struct MACH0_(obj_t) *bin); ut64 MACH0_(get_baddr)(struct MACH0_(obj_t) *bin); diff --git a/libr/bin/format/objc/mach0_classes.c b/libr/bin/format/objc/mach0_classes.c index ab1ed67a20..8839580682 100644 --- a/libr/bin/format/objc/mach0_classes.c +++ b/libr/bin/format/objc/mach0_classes.c @@ -112,7 +112,7 @@ static void get_objc_property_list(mach0_ut p, RBinFile *bf, RBinClass *klass); static void get_method_list_t(mach0_ut p, RBinFile *bf, char *class_name, RBinClass *klass, bool is_static, objc_cache_opt_info *oi); static void get_protocol_list_t(mach0_ut p, RBinFile *bf, RBinClass *klass, objc_cache_opt_info *oi); static void get_class_ro_t(mach0_ut p, RBinFile *bf, ut32 *is_meta_class, RBinClass *klass, objc_cache_opt_info *oi); -static RList *MACH0_(parse_categories)(RBinFile *bf, RSkipList *relocs, objc_cache_opt_info *oi); +static RList *MACH0_(parse_categories)(RBinFile *bf, const RSkipList *relocs, objc_cache_opt_info *oi); static bool read_ptr_pa(RBinFile *bf, ut64 paddr, mach0_ut *out); static bool read_ptr_va(RBinFile *bf, ut64 vaddr, mach0_ut *out); static char *read_str(RBinFile *bf, mach0_ut p, ut32 *offset, ut32 *left); @@ -1137,7 +1137,7 @@ static mach0_ut get_isa_value(void) { return 0; } -void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, RSkipList *relocs, objc_cache_opt_info *oi) { +void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, const RSkipList *relocs, objc_cache_opt_info *oi) { struct MACH0_(SClass) c = {0}; const int size = sizeof (struct MACH0_(SClass)); mach0_ut r = 0; @@ -1399,8 +1399,7 @@ RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi) { } bool bigendian = bf->o->info->big_endian; - RSkipList *relocs = MACH0_(get_relocs) (bf->o->bin_obj); - + const RSkipList *relocs = MACH0_(load_relocs) (bf->o->bin_obj); ret = MACH0_(parse_categories) (bf, relocs, oi); /* check if it's Swift */ @@ -1410,7 +1409,6 @@ RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi) { const RVector *sections = MACH0_(load_sections) (bf->o->bin_obj); if (!sections) { - r_skiplist_free (relocs); return ret; } @@ -1526,18 +1524,16 @@ RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi) { } r_list_append (ret, klass); } - r_skiplist_free (relocs); return ret; get_classes_error: r_list_free (sctns); r_list_free (ret); - r_skiplist_free (relocs); // XXX DOUBLE FREE r_bin_class_free (klass); return NULL; } -static RList *MACH0_(parse_categories)(RBinFile *bf, RSkipList *relocs, objc_cache_opt_info *oi) { +static RList *MACH0_(parse_categories)(RBinFile *bf, const RSkipList *relocs, objc_cache_opt_info *oi) { r_return_val_if_fail (bf && bf->o && bf->o->bin_obj && bf->o->info, NULL); RList /**/ *ret = NULL; @@ -1629,7 +1625,7 @@ error: return NULL; } -void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, RSkipList *relocs, objc_cache_opt_info *oi) { +void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, const RSkipList *relocs, objc_cache_opt_info *oi) { r_return_if_fail (bf && bf->o && bf->o->info); struct MACH0_(SCategory) c = {0}; diff --git a/libr/bin/format/objc/mach0_classes.h b/libr/bin/format/objc/mach0_classes.h index fcd7526101..6c0288d648 100644 --- a/libr/bin/format/objc/mach0_classes.h +++ b/libr/bin/format/objc/mach0_classes.h @@ -18,7 +18,7 @@ #define MACH0_CLASSES_H R_API RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi); -R_API void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, RSkipList *relocs, objc_cache_opt_info *oi); -R_API void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, RSkipList *relocs, objc_cache_opt_info *oi); +R_API void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, const RSkipList *relocs, objc_cache_opt_info *oi); +R_API void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, const RSkipList *relocs, objc_cache_opt_info *oi); #endif // MACH0_CLASSES_H diff --git a/libr/bin/p/bin_mach0.c b/libr/bin/p/bin_mach0.c index d58268ec2e..8108a2db69 100644 --- a/libr/bin/p/bin_mach0.c +++ b/libr/bin/p/bin_mach0.c @@ -282,7 +282,7 @@ static RList *relocs(RBinFile *bf) { return NULL; } ret->free = free; - RSkipList *relocs = MACH0_(get_relocs) (bf->o->bin_obj); + const RSkipList *relocs = MACH0_(load_relocs) (bf->o->bin_obj); if (!relocs) { return ret; } @@ -317,8 +317,6 @@ static RList *relocs(RBinFile *bf) { r_list_append (ret, ptr); } - r_skiplist_free (relocs); - return ret; } @@ -474,21 +472,19 @@ static RList* patch_relocs(RBin *b) { const bool apply_relocs = io->cached; // true; // !mo->b->readonly; const bool cache_relocs = io->cached; - RSkipList *all_relocs = MACH0_(get_relocs)(mo); + const RSkipList *all_relocs = MACH0_(load_relocs)(mo); if (!all_relocs) { return NULL; } - RList *ext_relocs = r_list_new (); - if (!ext_relocs) { - goto beach; - } + RPVector ext_relocs; + r_pvector_init (&ext_relocs, NULL); RSkipListNode *it; struct reloc_t *reloc; r_skiplist_foreach (all_relocs, it, reloc) { if (!reloc->external) { continue; } - r_list_append (ext_relocs, reloc); + r_pvector_push (&ext_relocs, reloc); } if (mo->reloc_fixups && r_list_length (mo->reloc_fixups) > 0) { if (!apply_relocs) { @@ -519,7 +515,7 @@ static RList* patch_relocs(RBin *b) { } } } - ut64 num_ext_relocs = r_list_length (ext_relocs); + ut64 num_ext_relocs = r_pvector_length (&ext_relocs); if (!num_ext_relocs) { goto beach; } @@ -569,8 +565,9 @@ static RList* patch_relocs(RBin *b) { goto beach; } ut64 vaddr = n_vaddr; - RListIter *liter; - r_list_foreach (ext_relocs, liter, reloc) { + void **ext_reloc_iter; + r_pvector_foreach (&ext_relocs, ext_reloc_iter) { + reloc = *ext_reloc_iter; bool found = false; ut64 sym_addr = ht_uu_find (relocs_by_sym, reloc->ord, &found); if (!found || !sym_addr) { @@ -599,13 +596,12 @@ static RList* patch_relocs(RBin *b) { goto beach; } ht_uu_free (relocs_by_sym); - r_list_free (ext_relocs); - r_skiplist_free (all_relocs); + r_pvector_fini (&ext_relocs); + // XXX r_io_desc_free (gotr2desc); return ret; beach: - r_list_free (ext_relocs); - r_skiplist_free (all_relocs); + r_pvector_fini (&ext_relocs); r_io_desc_free (gotr2desc); r_list_free (ret); ht_uu_free (relocs_by_sym); diff --git a/libr/include/r_skiplist.h b/libr/include/r_skiplist.h index 0dec5cfd83..e9aba96145 100644 --- a/libr/include/r_skiplist.h +++ b/libr/include/r_skiplist.h @@ -36,7 +36,7 @@ R_API RSkipListNode* r_skiplist_insert(RSkipList* list, void* data); R_API bool r_skiplist_insert_autofree(RSkipList* list, void* data); R_API bool r_skiplist_delete(RSkipList* list, void* data); R_API bool r_skiplist_delete_node(RSkipList *list, RSkipListNode *node); -R_API RSkipListNode* r_skiplist_find(RSkipList* list, void* data); +R_API RSkipListNode* r_skiplist_find(const RSkipList* list, void* data); R_API RSkipListNode* r_skiplist_find_geq(RSkipList* list, void* data); R_API RSkipListNode* r_skiplist_find_leq(RSkipList* list, void* data); R_API void r_skiplist_join(RSkipList *l1, RSkipList *l2); diff --git a/libr/util/skiplist.c b/libr/util/skiplist.c index bb81e43204..5e40e884d9 100644 --- a/libr/util/skiplist.c +++ b/libr/util/skiplist.c @@ -48,7 +48,7 @@ static inline void init_head(RSkipListNode *head) { // // NOTE: `updates` should be big enough to contain `list->list_level + 1` // elements, when provided. -static RSkipListNode *find_insertpoint(RSkipList *list, void *data, RSkipListNode **updates, bool by_data) { +static RSkipListNode *find_insertpoint(const RSkipList *list, void *data, RSkipListNode **updates, bool by_data) { RSkipListNode *x = list->head; int i; @@ -216,7 +216,7 @@ R_API bool r_skiplist_delete_node(RSkipList *list, RSkipListNode *node) { return delete_element (list, node, false); } -R_API RSkipListNode* r_skiplist_find(RSkipList* list, void* data) { +R_API RSkipListNode* r_skiplist_find(const RSkipList* list, void* data) { r_return_val_if_fail (list, NULL); RSkipListNode* x = find_insertpoint (list, data, NULL, true); if (x != list->head && list->compare (x->data, data) == 0) {