/* This file is part of centaur. * * centaur is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License 2 as * published by the Free Software Foundation. * centaur is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with centaur. If not, see . */ #include #include #include #include /* Meta-functions */ void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2) { ElfuPhdr *mp; ElfuScn *ms; CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { if (mp->phdr.p_type != PT_LOAD) { continue; } CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) { void *rv = f(me, ms, aux1, aux2); if (rv) { return rv; } } } CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) { void *rv = f(me, ms, aux1, aux2); if (rv) { return rv; } } return NULL; } /* Counting */ static void* subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) { size_t *i = (size_t*)aux1; ElfuScn *otherScn = (ElfuScn*)aux2; if (ms == otherScn) { return ms; } *i += 1; /* Continue */ return NULL; } size_t elfu_mScnCount(ElfuElf *me) { /* NULL section *is not* counted */ size_t i = 0; assert(me); elfu_mScnForall(me, subCounter, &i, NULL); return i; } /* Returns the index a section would have in the flattened ELF */ size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms) { /* NULL section *is* counted */ size_t i = 1; assert(me); assert(ms); elfu_mScnForall(me, subCounter, &i, ms); /* If this assertion is broken then ms is not a section in me. */ assert(i <= elfu_mScnCount(me)); return i; } static void* subOldscn(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) { ElfuScn *otherScn = (ElfuScn*)aux1; (void)aux2; if (ms->oldptr == otherScn) { return ms; } /* Continue */ return NULL; } /* Returns the section with oldscn == oldscn */ ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn) { assert(me); assert(oldscn); return elfu_mScnForall(me, subOldscn, oldscn, NULL); } /* Convenience */ char* elfu_mScnName(ElfuElf *me, ElfuScn *ms) { assert(me); assert(ms); if (!me->shstrtab) { return NULL; } if (!me->shstrtab->databuf) { return NULL; } return &me->shstrtab->databuf[ms->shdr.sh_name]; } static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2) { ElfuScn **arr = (ElfuScn**)aux1; size_t *i = (size_t*)aux2; arr[(*i)] = ms; *i += 1; /* Continue */ return NULL; } static int cmpScnOffs(const void *ms1, const void *ms2) { ElfuScn *s1; ElfuScn *s2; assert(ms1); assert(ms2); s1 = *(ElfuScn**)ms1; s2 = *(ElfuScn**)ms2; assert(s1); assert(s2); if (s1->shdr.sh_offset < s2->shdr.sh_offset) { return -1; } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) { return 0; } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ { return 1; } } ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count) { size_t numSecs; ElfuScn **sortedSecs; size_t i; assert(me); /* Sort sections by offset in file */ numSecs = elfu_mScnCount(me); sortedSecs = malloc(numSecs * sizeof(*sortedSecs)); if (!sortedSecs) { ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n"); return NULL; } i = 0; elfu_mScnForall(me, subScnsToArray, sortedSecs, &i); assert(i == numSecs); qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs); *count = numSecs; return sortedSecs; } int elfu_mScnAppendData(ElfuScn *ms, void *buf, size_t len) { char *newbuf; assert(ms); assert(ms->shdr.sh_type != SHT_NOBITS); assert(ms->databuf); newbuf = realloc(ms->databuf, ms->shdr.sh_size + len); if (!newbuf) { ELFU_WARN("elfu_mScnAppendData: malloc() failed for newbuf.\n"); return -1; } ms->databuf = newbuf; memcpy(newbuf + ms->shdr.sh_size, buf, len); ms->shdr.sh_size += len; assert(ms->shdr.sh_size == ms->shdr.sh_size); return 0; } /* * Allocation, destruction */ ElfuScn* elfu_mScnAlloc() { ElfuScn *ms; ms = malloc(sizeof(ElfuScn)); if (!ms) { ELFU_WARN("mScnCreate: malloc() failed for ElfuScn.\n"); return NULL; } memset(ms, 0, sizeof(*ms)); CIRCLEQ_INIT(&ms->symtab.syms); CIRCLEQ_INIT(&ms->reltab.rels); return ms; } void elfu_mScnDestroy(ElfuScn* ms) { assert(ms); if (!CIRCLEQ_EMPTY(&ms->symtab.syms)) { ElfuSym *nextsym; nextsym = CIRCLEQ_FIRST(&ms->symtab.syms); while ((void*)nextsym != (void*)&ms->symtab.syms) { ElfuSym *cursym = nextsym; nextsym = CIRCLEQ_NEXT(cursym, elem); CIRCLEQ_REMOVE(&ms->symtab.syms, cursym, elem); free(cursym); } } if (!CIRCLEQ_EMPTY(&ms->reltab.rels)) { ElfuRel *nextrel; nextrel = CIRCLEQ_FIRST(&ms->reltab.rels); while ((void*)nextrel != (void*)&ms->reltab.rels) { ElfuRel *currel = nextrel; nextrel = CIRCLEQ_NEXT(currel, elem); CIRCLEQ_REMOVE(&ms->reltab.rels, currel, elem); free(currel); } } if (ms->databuf) { free(ms->databuf); } free(ms); }