Don't load macho segments over and over, use vec ##bin

This commit is contained in:
Luc Tielen 2023-08-01 11:32:36 +02:00 committed by pancake
parent 450a8fa19b
commit 6faca49abe
5 changed files with 134 additions and 87 deletions

View File

@ -63,6 +63,15 @@ typedef struct {
/* followed by dynamic content as located by offset fields above */
} CodeDirectory;
static inline void r_bin_section_fini(RBinSection *bs) {
if (bs) {
free (bs->name);
free (bs->format);
}
}
R_VEC_TYPE_WITH_FINI(RVecSegment, RBinSection, r_bin_section_fini);
// OMG; THIS SHOULD BE KILLED; this var exposes the local native endian, which is completely unnecessary
// USE THIS: int ws = bf->o->info->big_endian;
#define mach0_endian 1
@ -1753,7 +1762,7 @@ static int init_items(struct MACH0_(obj_t) *mo) {
mo->uuidn = 0;
mo->os = 0;
mo->has_crypto = 0;
mo->cached_segments = NULL;
mo->segments_vec = NULL;
r_pvector_init (&mo->libs_cache, (RPVectorFree) free);
if (mo->hdr.sizeofcmds > mo->size) {
@ -2226,8 +2235,8 @@ void *MACH0_(mach0_free)(struct MACH0_(obj_t) *mo) {
if (mo->sections_loaded) {
r_vector_fini (&mo->sections_cache);
}
r_list_free (mo->cached_segments);
mo->cached_segments = NULL;
RVecSegment_free (mo->segments_vec);
mo->segments_vec = NULL;
if (mo->relocs_loaded) {
r_skiplist_free (mo->relocs_cache);
}
@ -2444,84 +2453,120 @@ static const char *macho_section_type_tostring(int flags) {
return "";
}
RList *MACH0_(get_segments)(RBinFile *bf, struct MACH0_(obj_t) *macho) {
if (macho->cached_segments) {
return r_list_clone (macho->cached_segments, (RListClone)r_bin_section_clone);
static inline RVecSegment *MACH0_(get_segments_vec)(RBinFile *bf, struct MACH0_(obj_t) *mo) {
if (mo->segments_vec) {
return mo->segments_vec;
}
RList *list = r_list_newf ((RListFree)r_bin_section_free);
size_t i, j;
mo->segments_vec = RVecSegment_new ();
/* for core files */
if (macho->nsegs > 0) {
struct MACH0_(segment_command) *seg;
for (i = 0; i < macho->nsegs; i++) {
seg = &macho->segs[i];
if (!seg->initprot) {
continue;
}
RBinSection *s = r_bin_section_new (NULL);
if (!s) {
break;
}
s->vaddr = seg->vmaddr;
s->vsize = seg->vmsize;
s->size = seg->vmsize;
s->paddr = seg->fileoff;
s->paddr += bf->o->boffset;
//TODO s->flags = seg->flags;
s->name = r_str_ndup (seg->segname, 16);
s->is_segment = true;
r_str_filter (s->name, -1);
s->perm = prot2perm (seg->initprot);
s->add = true;
r_list_append (list, s);
}
}
const int ws = R_BIN_MACH0_WORD_SIZE;
if (macho->nsects > 0) {
int last_section = R_MIN (macho->nsects, MACHO_MAX_SECTIONS);
for (i = 0; i < last_section; i++) {
RBinSection *s = R_NEW0 (RBinSection);
if (!s) {
break;
}
s->vaddr = (ut64)macho->sects[i].addr;
s->vsize = (ut64)macho->sects[i].size;
s->is_segment = false;
s->size = (macho->sects[i].flags == S_ZEROFILL) ? 0 : (ut64)macho->sects[i].size;
s->type = macho_section_type_tostring (macho->sects[i].flags);
s->paddr = (ut64)macho->sects[i].offset;
int segment_index = 0;
for (j = 0; j < macho->nsegs; j++) {
if (s->vaddr >= macho->segs[j].vmaddr &&
s->vaddr < (macho->segs[j].vmaddr + macho->segs[j].vmsize)) {
s->perm = prot2perm (macho->segs[j].initprot);
segment_index = j;
if (mo->nsegs > 0) {
if (RVecSegment_reserve (mo->segments_vec, mo->nsegs)) {
size_t i;
for (i = 0; i < mo->nsegs; i++) {
struct MACH0_(segment_command) *seg = &mo->segs[i];
if (!seg->initprot) {
continue;
}
RBinSection *s = RVecSegment_emplace_back (mo->segments_vec);
if (!s) {
break;
}
memset (s, 0, sizeof (RBinSection)); // XXX redundant?
s->vaddr = seg->vmaddr;
s->vsize = seg->vmsize;
s->size = seg->vmsize;
s->paddr = seg->fileoff;
s->paddr += bf->o->boffset;
//TODO s->flags = seg->flags;
s->name = r_str_ndup (seg->segname, 16);
s->is_segment = true;
r_str_filter (s->name, -1);
s->perm = prot2perm (seg->initprot);
s->add = true;
}
char *section_name = r_str_ndup (macho->sects[i].sectname, 16);
char *segment_name = r_str_newf ("%u.%s", (ut32)i, macho->segs[segment_index].segname);
s->name = r_str_newf ("%s.%s", segment_name, section_name);
if (strstr (s->name, "__const")) {
s->format = r_str_newf ("Cd %d %"PFMT64d, ws, s->size / ws);
}
s->is_data = is_data_section (s);
if (strstr (section_name, "interpos") || strstr (section_name, "__mod_")) {
s->format = r_str_newf ("Cd %d[%"PFMT64d"]", ws, s->vsize / ws);
}
// https://github.com/radareorg/ideas/issues/104
// https://stackoverflow.com/questions/29665371/compiling-a-binary-immune-to-library-redirection-on-mac-os-x
if (strstr (section_name, "restrict") || strstr (section_name, "RESTRICT")) {
macho->has_libinjprot = true;
}
r_list_append (list, s);
free (segment_name);
free (section_name);
}
}
macho->cached_segments = r_list_clone (list, (RListClone)r_bin_section_clone);
const int ws = R_BIN_MACH0_WORD_SIZE;
if (mo->nsects > 0) {
const int last_section = R_MIN (mo->nsects, MACHO_MAX_SECTIONS);
const ut64 total_size = RVecSegment_length (mo->segments_vec) + last_section;
if (RVecSegment_reserve (mo->segments_vec, total_size)) {
size_t i;
for (i = 0; i < last_section; i++) {
RBinSection *s = RVecSegment_emplace_back (mo->segments_vec);
if (!s) {
break;
}
memset (s, 0, sizeof (RBinSection)); // XXX redundant?
s->vaddr = (ut64)mo->sects[i].addr;
s->vsize = (ut64)mo->sects[i].size;
s->is_segment = false;
s->size = (mo->sects[i].flags == S_ZEROFILL) ? 0 : (ut64)mo->sects[i].size;
s->type = macho_section_type_tostring (mo->sects[i].flags);
s->paddr = (ut64)mo->sects[i].offset;
int segment_index = 0;
size_t j;
for (j = 0; j < mo->nsegs; j++) {
if (s->vaddr >= mo->segs[j].vmaddr &&
s->vaddr < (mo->segs[j].vmaddr + mo->segs[j].vmsize)) {
s->perm = prot2perm (mo->segs[j].initprot);
segment_index = j;
break;
}
}
char *section_name = r_str_ndup (mo->sects[i].sectname, 16);
char *segment_name = r_str_newf ("%u.%s", (ut32)i, mo->segs[segment_index].segname);
s->name = r_str_newf ("%s.%s", segment_name, section_name);
if (strstr (s->name, "__const")) {
s->format = r_str_newf ("Cd %d %"PFMT64d, ws, s->size / ws);
}
s->is_data = is_data_section (s);
if (strstr (section_name, "interpos") || strstr (section_name, "__mod_")) {
free (s->format);
s->format = r_str_newf ("Cd %d[%"PFMT64d"]", ws, s->vsize / ws);
}
// https://github.com/radareorg/ideas/issues/104
// https://stackoverflow.com/questions/29665371/compiling-a-binary-immune-to-library-redirection-on-mac-os-x
if (strstr (section_name, "restrict") || strstr (section_name, "RESTRICT")) {
mo->has_libinjprot = true;
}
free (segment_name);
free (section_name);
}
}
}
return mo->segments_vec;
}
RList *MACH0_(get_segments)(RBinFile *bf, struct MACH0_(obj_t) *macho) {
RList *list = r_list_newf ((RListFree)r_bin_section_free);
if (!list) {
return NULL;
}
// R2_590 slow, should return vec directly
RVecSegment *segments = MACH0_(get_segments_vec)(bf, macho);
RBinSection *s;
R_VEC_FOREACH (segments, s) {
RBinSection *s_copy = r_bin_section_clone (s);
if (!s_copy) {
r_list_free (list);
return NULL;
}
r_list_append (list, s_copy);
}
return list;
}
@ -3182,16 +3227,17 @@ static void _parse_function_start_symbols(RBinFile *bf, struct MACH0_(obj_t) *mo
}
}
static bool _check_if_debug_build(RBinFile *bf, struct MACH0_(obj_t) *mo) {
#if 0
// R2_590
RBinSection *s;
R_VEC_FOREACH (bf->o->segments_vec, s) {
if (strstr (s->name, "DWARF.__debug_line")) {
return true;
}
}
// R2_590
static inline bool is_debug_segment(const RBinSection *s, const void *user) {
return strstr (s->name, "DWARF.__debug_line") != NULL;
}
static inline bool _check_if_debug_build(RBinFile *bf, struct MACH0_(obj_t) *mo) {
return RVecSegment_find (bf->o->segments_vec, NULL, is_debug_segment) != NULL;
}
#else
static bool _check_if_debug_build(RBinFile *bf, struct MACH0_(obj_t) *mo) {
RList *sections = MACH0_(get_segments) (bf, mo);
if (!sections) {
return false;
@ -3206,11 +3252,10 @@ static bool _check_if_debug_build(RBinFile *bf, struct MACH0_(obj_t) *mo) {
}
r_list_free (sections);
#endif
return false;
}
#endif
// R2_590 - should return bool
const bool MACH0_(load_symbols)(struct MACH0_(obj_t) *mo) {
r_return_val_if_fail (mo, false);
if (mo->symbols_loaded) {

View File

@ -100,6 +100,8 @@ struct MACH0_(opts_t) {
RBinFile *bf;
};
R_VEC_FORWARD_DECLARE(RVecSegment);
struct MACH0_(obj_t) {
struct MACH0_(mach_header) hdr;
struct MACH0_(segment_command) *segs;
@ -125,7 +127,6 @@ struct MACH0_(obj_t) {
RBinImport **imports_by_ord;
size_t imports_by_ord_size;
HtPP *imports_by_name;
RList *cached_segments;
struct MACH0_(opts_t) options;
struct dysymtab_command dysymtab;
@ -170,8 +171,8 @@ struct MACH0_(obj_t) {
ut64 header_at;
bool parse_start_symbols;
bool symbols_loaded;
//RVector symbols_cache;
RVecRBinSymbol *symbols_vec; // pointer to &bf->o->symbols_vec
RVecSegment *segments_vec; // R2_590 pointer of &bf->o->segments_vec
ut64 symbols_off;
void *user;
ut64 (*va2pa)(ut64 p, ut32 *offset, ut32 *left, RBinFile *bf);

View File

@ -144,7 +144,7 @@ static mach0_ut va2pa(mach0_ut p, ut32 *offset, ut32 *left, RBinFile *bf) {
return bin->va2pa (p, offset, left, bf);
}
mach0_ut addr = p;
RList *sections = MACH0_(get_segments) (bf, bin);
RList *sections = MACH0_(get_segments) (bf, bin); // XXX slow, don't allocate each time
RListIter *iter;
RBinSection *s;
r_list_foreach (sections, iter, s) {

View File

@ -77,9 +77,10 @@ static ut64 baddr(RBinFile *bf) {
return MACH0_(get_baddr)(mo);
}
// R2_590 return RVecSegment
static RList *sections(RBinFile *bf) {
struct MACH0_(obj_t) *mo = bf->o->bin_obj;
return MACH0_(get_segments) (bf, mo);
return MACH0_(get_segments) (bf, mo); // TODO split up sections and segments?
}
static RBinAddr *newEntry(ut64 hpaddr, ut64 paddr, int type, int bits) {

View File

@ -174,7 +174,7 @@ extern "C" {
r_return_if_fail (vec); \
memset (vec, 0, sizeof (vec_type)); \
} \
static inline R_MAYBE_UNUSED R_MUSTUSE vec_type *R_VEC_FUNC(vec_type, new)() { \
static inline R_MAYBE_UNUSED R_MUSTUSE vec_type *R_VEC_FUNC(vec_type, new)(void) { \
vec_type *vec = R_NEW (vec_type); \
if (R_LIKELY (vec)) { \
R_VEC_FUNC(vec_type, init) (vec); \