Rename elfedit to centaur, model to modelops
authornorly <ny-git@enpas.org>
Wed, 12 Jun 2013 17:41:42 +0000 (18:41 +0100)
committernorly <ny-git@enpas.org>
Wed, 12 Jun 2013 17:41:42 +0000 (18:41 +0100)
21 files changed:
Makefile
src/model/check.c [deleted file]
src/model/clone.c [deleted file]
src/model/dump.c [deleted file]
src/model/fromFile.c [deleted file]
src/model/layout.c [deleted file]
src/model/phdr.c [deleted file]
src/model/reladd.c [deleted file]
src/model/relocate.c [deleted file]
src/model/section.c [deleted file]
src/model/toFile.c [deleted file]
src/modelops/check.c [new file with mode: 0644]
src/modelops/clone.c [new file with mode: 0644]
src/modelops/dump.c [new file with mode: 0644]
src/modelops/fromFile.c [new file with mode: 0644]
src/modelops/layout.c [new file with mode: 0644]
src/modelops/phdr.c [new file with mode: 0644]
src/modelops/reladd.c [new file with mode: 0644]
src/modelops/relocate.c [new file with mode: 0644]
src/modelops/section.c [new file with mode: 0644]
src/modelops/toFile.c [new file with mode: 0644]

index 41e8fe5a34ee5be4a53b272f363d20e1e0179d2e..ef3548d8bc2dad0d332096f62e631163db8e8690 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-PROJ := elfedit
+PROJ := centaur
 
 LIBRARIES := libelf
 
diff --git a/src/model/check.c b/src/model/check.c
deleted file mode 100644 (file)
index 5234bef..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <libelfu/libelfu.h>
-
-
-int elfu_mCheck(ElfuElf *me)
-{
-  size_t numSecs;
-  ElfuScn **sortedSecs;
-  size_t i;
-
-  sortedSecs = elfu_mScnSortedByOffset(me, &numSecs);
-  if (!sortedSecs) {
-    return -1;
-  }
-
-
-  /* Check for overlapping sections */
-  for (i = 0; i < numSecs - 1; i++) {
-    if (sortedSecs[i]->shdr.sh_offset + SCNFILESIZE(&sortedSecs[i]->shdr)
-        > sortedSecs[i+1]->shdr.sh_offset) {
-      ELFU_WARN("elfu_check: Found overlapping sections: %s and %s.\n",
-                elfu_mScnName(me, sortedSecs[i]),
-                elfu_mScnName(me, sortedSecs[i+1]));
-    }
-  }
-
-
-  /* Check for sections overlapping with EHDR */
-  for (i = 0; i < numSecs; i++) {
-    if (sortedSecs[i]->shdr.sh_offset < me->ehdr.e_ehsize) {
-      ELFU_WARN("elfu_check: Found section overlapping with EHDR: %s.\n",
-                elfu_mScnName(me, sortedSecs[i]));
-    }
-  }
-
-
-  /* Check for sections overlapping with PHDRs */
-  for (i = 0; i < numSecs; i++) {
-    if (OVERLAPPING(sortedSecs[i]->shdr.sh_offset,
-                    SCNFILESIZE(&sortedSecs[i]->shdr),
-                    me->ehdr.e_phoff,
-                    me->ehdr.e_phentsize * me->ehdr.e_phnum)) {
-      ELFU_WARN("elfu_check: Found section overlapping with PHDRs: %s.\n",
-                elfu_mScnName(me, sortedSecs[i]));
-    }
-  }
-
-
-  free(sortedSecs);
-
-  return 0;
-}
diff --git a/src/model/clone.c b/src/model/clone.c
deleted file mode 100644 (file)
index ca4b38f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libelfu/libelfu.h>
-
-ElfuScn* elfu_mCloneScn(ElfuScn *ms)
-{
-  ElfuScn *newscn;
-
-  assert(ms);
-
-  newscn = malloc(sizeof(ElfuScn));
-  if (!newscn) {
-    ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new ElfuScn.\n");
-    return NULL;
-  }
-
-  newscn->shdr = ms->shdr;
-  newscn->data = ms->data;
-  if (ms->data.d_buf) {
-    void *newbuf = malloc(ms->data.d_size);
-    if (!newbuf) {
-      ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new data buffer.\n");
-      free(newscn);
-      return NULL;
-    }
-
-    memcpy(newbuf, ms->data.d_buf, ms->data.d_size);
-    newscn->data.d_buf = newbuf;
-  }
-
-  newscn->linkptr = NULL;
-  newscn->infoptr = NULL;
-
-  newscn->oldptr = ms;
-
-  ms->symtab = NULL;
-  ms->reltab = NULL;
-
-  return newscn;
-}
diff --git a/src/model/dump.c b/src/model/dump.c
deleted file mode 100644 (file)
index 27556f9..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-#include <assert.h>
-#include <libelfu/libelfu.h>
-
-
-static char* segmentTypeStr(Elf32_Word p_type)
-{
-  switch(p_type) {
-    case PT_NULL: /* 0 */
-      return "NULL";
-    case PT_LOAD: /* 1 */
-      return "LOAD";
-    case PT_DYNAMIC: /* 2 */
-      return "DYNAMIC";
-    case PT_INTERP: /* 3 */
-      return "INTERP";
-    case PT_NOTE: /* 4 */
-      return "NOTE";
-    case PT_SHLIB: /* 5 */
-      return "SHLIB";
-    case PT_PHDR: /* 6 */
-      return "PHDR";
-    case PT_TLS: /* 7 */
-      return "TLS";
-    case PT_NUM: /* 8 */
-      return "NUM";
-    case PT_GNU_EH_FRAME: /* 0x6474e550 */
-      return "GNU_EH_FRAME";
-    case PT_GNU_STACK: /* 0x6474e551 */
-      return "GNU_STACK";
-    case PT_GNU_RELRO: /* 0x6474e552 */
-      return "GNU_RELRO";
-  }
-
-  return "-?-";
-}
-
-static char* sectionTypeStr(Elf32_Word sh_type)
-{
-  switch(sh_type) {
-    case SHT_NULL: /* 0 */
-      return "NULL";
-    case SHT_PROGBITS: /* 1 */
-      return "PROGBITS";
-    case SHT_SYMTAB: /* 2 */
-      return "SYMTAB";
-    case SHT_STRTAB: /* 3 */
-      return "STRTAB";
-    case SHT_RELA: /* 4 */
-      return "RELA";
-    case SHT_HASH: /* 5 */
-      return "HASH";
-    case SHT_DYNAMIC: /* 6 */
-      return "DYNAMIC";
-    case SHT_NOTE: /* 7 */
-      return "NOTE";
-    case SHT_NOBITS: /* 8 */
-      return "NOBITS";
-    case SHT_REL: /* 9 */
-      return "REL";
-    case SHT_SHLIB: /* 10 */
-      return "SHLIB";
-    case SHT_DYNSYM: /* 11 */
-      return "DYNSYM";
-    case SHT_INIT_ARRAY: /* 14 */
-      return "INIT_ARRAY";
-    case SHT_FINI_ARRAY: /* 15 */
-      return "FINI_ARRAY";
-    case SHT_PREINIT_ARRAY: /* 16 */
-      return "PREINIT_ARRAY";
-    case SHT_GROUP: /* 17 */
-      return "SHT_GROUP";
-    case SHT_SYMTAB_SHNDX: /* 18 */
-      return "SYMTAB_SHNDX";
-    case SHT_NUM: /* 19 */
-      return "NUM";
-
-    case SHT_GNU_ATTRIBUTES: /* 0x6ffffff5 */
-      return "GNU_ATTRIBUTES";
-    case SHT_GNU_HASH: /* 0x6ffffff6 */
-      return "GNU_HASH";
-    case SHT_GNU_LIBLIST: /* 0x6ffffff7 */
-      return "GNU_LIBLIST";
-    case SHT_GNU_verdef: /* 0x6ffffffd */
-      return "GNU_verdef";
-    case SHT_GNU_verneed: /* 0x6ffffffe */
-      return "GNU_verneed";
-    case SHT_GNU_versym: /* 0x6fffffff */
-      return "GNU_versym";
-  }
-
-  return "-?-";
-}
-
-
-
-
-void elfu_mDumpPhdr(ElfuElf *me, ElfuPhdr *mp)
-{
-  assert(me);
-  assert(mp);
-
-  ELFU_INFO("%12s %8jx %8jx %8jx %8jx %8jx %8jx %8jx %8jx\n",
-            segmentTypeStr(mp->phdr.p_type),
-            (uintmax_t) mp->phdr.p_type,
-            (uintmax_t) mp->phdr.p_offset,
-            (uintmax_t) mp->phdr.p_vaddr,
-            (uintmax_t) mp->phdr.p_paddr,
-            (uintmax_t) mp->phdr.p_filesz,
-            (uintmax_t) mp->phdr.p_memsz,
-            (uintmax_t) mp->phdr.p_flags,
-            (uintmax_t) mp->phdr.p_align);
-
-  if (!CIRCLEQ_EMPTY(&mp->childPhdrList)) {
-    ElfuPhdr *mpc;
-
-    ELFU_INFO("      -> Child PHDRs:\n");
-    CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
-      ELFU_INFO("        * %-8s @ %8jx\n",
-                segmentTypeStr(mpc->phdr.p_type),
-                mpc->phdr.p_vaddr);
-    }
-  }
-
-  if (!CIRCLEQ_EMPTY(&mp->childScnList)) {
-    ElfuScn *msc;
-
-    ELFU_INFO("      -> Child sections:\n");
-    CIRCLEQ_FOREACH(msc, &mp->childScnList, elemChildScn) {
-      ELFU_INFO("        * %-17s @ %8jx\n",
-                elfu_mScnName(me, msc),
-                msc->shdr.sh_addr);
-    }
-  }
-}
-
-
-void elfu_mDumpScn(ElfuElf *me, ElfuScn *ms)
-{
-  char *namestr, *typestr, *linkstr, *infostr;
-
-  assert(me);
-  assert(ms);
-
-  namestr = elfu_mScnName(me, ms);
-  typestr = sectionTypeStr(ms->shdr.sh_type);
-  linkstr = ms->linkptr ? elfu_mScnName(me, ms->linkptr) : "";
-  infostr = ms->infoptr ? elfu_mScnName(me, ms->infoptr) : "";
-
-  ELFU_INFO("%-17s %-15s %8jx %9jx %8jx %2jx %2jx %2jd %-17s %-17s\n",
-            namestr,
-            typestr,
-            ms->shdr.sh_addr,
-            ms->shdr.sh_offset,
-            ms->shdr.sh_size,
-            ms->shdr.sh_entsize,
-            ms->shdr.sh_flags,
-            ms->shdr.sh_addralign,
-            linkstr,
-            infostr);
-}
-
-
-void elfu_mDumpEhdr(ElfuElf *me)
-{
-  assert(me);
-
-  ELFU_INFO("ELF header:\n");
-  ELFU_INFO("   %d-bit ELF object\n", me->elfclass == ELFCLASS32 ? 32 : 64);
-
-  ELFU_INFO("   EHDR:\n");
-
-  ELFU_INFO("     e_type       %8x\n", me->ehdr.e_type);
-  ELFU_INFO("     e_machine    %8x\n", me->ehdr.e_machine);
-  ELFU_INFO("     e_version    %8x\n", me->ehdr.e_version);
-  ELFU_INFO("     e_entry      %8jx\n", me->ehdr.e_entry);
-  ELFU_INFO("     e_phoff      %8jx\n", me->ehdr.e_phoff);
-  ELFU_INFO("     e_shoff      %8jx\n", me->ehdr.e_shoff);
-  ELFU_INFO("     e_flags      %8x\n", me->ehdr.e_flags);
-  ELFU_INFO("     e_ehsize     %8x\n", me->ehdr.e_ehsize);
-  ELFU_INFO("     e_phentsize  %8x\n", me->ehdr.e_phentsize);
-  ELFU_INFO("     e_shentsize  %8x\n", me->ehdr.e_shentsize);
-
-  ELFU_INFO("   shstrtab: %s\n", me->shstrtab ? elfu_mScnName(me, me->shstrtab) : "(none)");
-}
-
-
-
-static void* subScnDump(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
-{
-  (void) aux1;
-  (void) aux2;
-
-  printf(" [%4d] ", elfu_mScnIndex(me, ms));
-  elfu_mDumpScn(me, ms);
-
-  return NULL;
-}
-
-
-void elfu_mDumpElf(ElfuElf *me)
-{
-  ElfuPhdr *mp;
-  ElfuScn *ms;
-  size_t i;
-
-  assert(me);
-
-
-  elfu_mDumpEhdr(me);
-  ELFU_INFO("\n");
-
-
-  ELFU_INFO("Segments:\n");
-  ELFU_INFO("     #        (type)   p_type p_offset  p_vaddr  p_paddr p_filesz  p_memsz  p_flags  p_align\n");
-  ELFU_INFO("       |            |        |        |        |        |        |        |        |        \n");
-  i = 0;
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    printf(" [%4d] ", i);
-    elfu_mDumpPhdr(me, mp);
-    i++;
-  }
-  ELFU_INFO("\n");
-
-
-  ELFU_INFO("Orphaned sections:\n");
-  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
-    ELFU_INFO("        * %-17s @ %8jx\n",
-              elfu_mScnName(me, ms),
-              ms->shdr.sh_addr);
-  }
-  ELFU_INFO("\n");
-
-
-  ELFU_INFO("Sections:\n");
-  ELFU_INFO("     #  Name              sh_type          sh_addr sh_offset  sh_size ES Fl Al sh_link           sh_info          \n");
-  ELFU_INFO("       |                 |               |        |         |        |  |  |  |                 |                 \n");
-  elfu_mScnForall(me, subScnDump, &i, NULL);
-  ELFU_INFO("\n");
-}
diff --git a/src/model/fromFile.c b/src/model/fromFile.c
deleted file mode 100644 (file)
index 23105e6..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <libelfu/libelfu.h>
-
-
-static char* symstr(ElfuScn *symtab, size_t off)
-{
-  assert(symtab);
-  assert(symtab->linkptr);
-  assert(symtab->linkptr->data.d_buf);
-  assert(off < symtab->linkptr->data.d_size);
-
-  return &(((char*)symtab->linkptr->data.d_buf)[off]);
-}
-
-
-static ElfuSymtab* symtabFromScn32(ElfuScn *ms, ElfuScn**origScnArr)
-{
-  ElfuSymtab *st;
-  size_t i;
-
-  assert(ms);
-  assert(ms->data.d_buf);
-  assert(origScnArr);
-
-
-  st = malloc(sizeof(*st));
-  if (!st) {
-    ELFU_WARN("elfu_mSymtabFromScn32: malloc() failed for st.\n");
-    goto ERROR;
-  }
-
-  CIRCLEQ_INIT(&st->syms);
-
-
-  for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
-    Elf32_Sym *cursym = &(((Elf32_Sym*)ms->data.d_buf)[i]);
-    ElfuSym *sym = malloc(sizeof(*sym));
-    assert(sym);
-
-    sym->name = symstr(ms, cursym->st_name);
-    sym->value = cursym->st_value;
-    sym->size = cursym->st_size;
-    sym->bind = ELF32_ST_BIND(cursym->st_info);
-    sym->type = ELF32_ST_TYPE(cursym->st_info);
-    sym->other = cursym->st_other;
-
-    switch (cursym->st_shndx) {
-      case SHN_UNDEF:
-      case SHN_ABS:
-      case SHN_COMMON:
-        sym->scnptr = NULL;
-        sym->shndx = cursym->st_shndx;
-        break;
-      default:
-        sym->scnptr = origScnArr[cursym->st_shndx - 1];
-        break;
-    }
-
-
-    CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem);
-  }
-
-
-  return st;
-
-  ERROR:
-  if (st) {
-    free(st);
-  }
-  return NULL;
-}
-
-
-static ElfuReltab* reltabFromScn32(ElfuScn *ms)
-{
-  ElfuReltab *rt;
-  size_t i;
-
-  assert(ms);
-  assert(ms->data.d_buf);
-
-
-  rt = malloc(sizeof(*rt));
-  if (!rt) {
-    ELFU_WARN("elfu_mReltabFromScn32: malloc() failed for rt.\n");
-    goto ERROR;
-  }
-
-  CIRCLEQ_INIT(&rt->rels);
-
-
-  for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
-    Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]);
-    ElfuRel *rel;
-
-    rel = malloc(sizeof(*rel));
-    assert(rel);
-
-    rel->offset = currel->r_offset;
-
-    rel->sym = ELF32_R_SYM(currel->r_info);
-    rel->type = ELF32_R_TYPE(currel->r_info);
-
-    rel->addendUsed = 0;
-    rel->addend = 0;
-
-    CIRCLEQ_INSERT_TAIL(&rt->rels, rel, elem);
-  }
-
-
-  return rt;
-
-  ERROR:
-  if (rt) {
-    free(rt);
-  }
-  return NULL;
-}
-
-
-static int cmpScnOffs(const void *ms1, const void *ms2)
-{
-  assert(ms1);
-  assert(ms2);
-
-  ElfuScn *s1 = *(ElfuScn**)ms1;
-  ElfuScn *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;
-  }
-}
-
-
-
-static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
-{
-  ElfuPhdr *mp;
-
-  assert(me);
-  assert(ms);
-
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    if (mp->phdr.p_type != PT_LOAD) {
-      continue;
-    }
-
-    if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
-      return mp;
-    }
-
-    /* Give sections a second chance if they do not have any sh_addr
-     * at all. */
-    /* Actually we don't, because it's ambiguous.
-     * Re-enable for experiments with strangely-formatted files.
-    if (ms->shdr.sh_addr == 0
-        && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
-        && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
-            <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
-      return mp;
-    }
-    */
-  }
-
-  return NULL;
-}
-
-
-static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
-{
-  ElfuPhdr *mp;
-
-  assert(phdr);
-
-  mp = malloc(sizeof(ElfuPhdr));
-  if (!mp) {
-    ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
-    return NULL;
-  }
-
-  mp->phdr = *phdr;
-
-  CIRCLEQ_INIT(&mp->childScnList);
-  CIRCLEQ_INIT(&mp->childPhdrList);
-
-  return mp;
-}
-
-
-static ElfuScn* modelFromSection(Elf_Scn *scn)
-{
-  ElfuScn *ms;
-
-  assert(scn);
-
-  ms = malloc(sizeof(ElfuScn));
-  if (!ms) {
-    ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
-    goto ERROR;
-  }
-
-
-  assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
-
-
-  /* Copy each data part in source segment */
-  ms->data.d_align = 1;
-  ms->data.d_buf  = NULL;
-  ms->data.d_off  = 0;
-  ms->data.d_type = ELF_T_BYTE;
-  ms->data.d_size = ms->shdr.sh_size;
-  ms->data.d_version = elf_version(EV_NONE);
-  if (ms->shdr.sh_type != SHT_NOBITS
-      && ms->shdr.sh_size > 0) {
-    Elf_Data *data;
-
-    ms->data.d_buf = malloc(ms->shdr.sh_size);
-    if (!ms->data.d_buf) {
-      ELFU_WARN("modelFromSection: malloc() failed for data buffer (%jx bytes).\n", ms->shdr.sh_size);
-      goto ERROR;
-    }
-
-    /* A non-empty section should contain at least one data block. */
-    data = elf_rawdata(scn, NULL);
-    assert(data);
-
-    ms->data.d_align = data->d_align;
-    ms->data.d_type = data->d_type;
-    ms->data.d_version = data->d_version;
-
-    while (data) {
-      if (data->d_off + data->d_size > ms->shdr.sh_size) {
-        ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
-      } else {
-        memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
-      }
-
-      data = elf_rawdata(scn, data);
-    }
-  }
-
-  ms->linkptr = NULL;
-  ms->infoptr = NULL;
-
-  ms->oldptr = NULL;
-
-  ms->symtab = NULL;
-  ms->reltab = NULL;
-
-
-  return ms;
-
-  ERROR:
-  if (ms) {
-    free(ms);
-  }
-  return NULL;
-}
-
-
-
-
-ElfuElf* elfu_mFromElf(Elf *e)
-{
-  ElfuElf *me;
-  size_t shstrndx;
-  size_t i, numPhdr, numShdr;
-  ElfuScn **secArray = NULL;
-
-  assert(e);
-  if (elfu_eCheck(e)) {
-    goto ERROR;
-  }
-
-  me = malloc(sizeof(ElfuElf));
-  if (!me) {
-    ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
-    goto ERROR;
-  }
-
-
-  /* General stuff */
-  CIRCLEQ_INIT(&me->phdrList);
-  CIRCLEQ_INIT(&me->orphanScnList);
-  me->shstrtab = NULL;
-
-  me->elfclass = gelf_getclass(e);
-  assert(me->elfclass != ELFCLASSNONE);
-  assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
-
-
-  /* Get the section string table index */
-  if (elf_getshdrstrndx(e, &shstrndx) != 0) {
-    shstrndx = 0;
-  }
-
-
-  /* Load segments */
-  assert(!elf_getphdrnum(e, &numPhdr));
-  for (i = 0; i < numPhdr; i++) {
-    GElf_Phdr phdr;
-    ElfuPhdr *mp;
-
-    assert(gelf_getphdr(e, i, &phdr) == &phdr);
-
-    mp = modelFromPhdr(&phdr);
-    if (!mp) {
-      goto ERROR;
-    }
-
-    CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
-  }
-
-  if (numPhdr > 0) {
-    ElfuPhdr *mp;
-
-    /* Find PHDR -> PHDR dependencies (needs sorted sections) */
-    CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-      ElfuPhdr *mp2;
-
-      if (mp->phdr.p_type != PT_LOAD) {
-        continue;
-      }
-
-      CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
-        if (mp2 == mp) {
-          continue;
-        }
-
-        if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
-            && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
-          CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
-        }
-      }
-    }
-  }
-
-
-  /* Load sections */
-  assert(!elf_getshdrnum(e, &numShdr));
-  if (numShdr > 1) {
-    secArray = malloc((numShdr - 1) * sizeof(*secArray));
-    if (!secArray) {
-      ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
-      goto ERROR;
-    }
-
-    for (i = 1; i < numShdr; i++) {
-      Elf_Scn *scn;
-      ElfuScn *ms;
-
-      scn = elf_getscn(e, i);
-      assert(scn);
-
-      ms = modelFromSection(scn);
-      if (!ms) {
-        goto ERROR;
-      }
-
-      secArray[i-1] =  ms;
-
-      if (i == shstrndx) {
-        me->shstrtab = ms;
-      }
-    }
-
-
-    /* Find sh_link and sh_info dependencies (needs sections in original order) */
-    for (i = 0; i < numShdr - 1; i++) {
-      ElfuScn *ms = secArray[i];
-
-      switch (ms->shdr.sh_type) {
-        case SHT_REL:
-        case SHT_RELA:
-          if (ms->shdr.sh_info > 0) {
-            ms->infoptr = secArray[ms->shdr.sh_info - 1];
-          }
-        case SHT_DYNAMIC:
-        case SHT_HASH:
-        case SHT_SYMTAB:
-        case SHT_DYNSYM:
-        case SHT_GNU_versym:
-        case SHT_GNU_verdef:
-        case SHT_GNU_verneed:
-          if (ms->shdr.sh_link > 0) {
-            ms->linkptr = secArray[ms->shdr.sh_link - 1];
-          }
-      }
-    }
-
-
-    /* Parse symtabs (needs sections in original order) */
-    for (i = 0; i < numShdr - 1; i++) {
-      ElfuScn *ms = secArray[i];
-
-      switch (ms->shdr.sh_type) {
-        case SHT_SYMTAB:
-        case SHT_DYNSYM:
-          if (me->elfclass == ELFCLASS32) {
-            ms->symtab = symtabFromScn32(ms, secArray);
-          } else if (me->elfclass == ELFCLASS64) {
-            // TODO
-          }
-          assert(ms->symtab);
-          break;
-      }
-    }
-
-
-    /* Parse relocations */
-    for (i = 0; i < numShdr - 1; i++) {
-      ElfuScn *ms = secArray[i];
-
-      switch (ms->shdr.sh_type) {
-        case SHT_REL:
-          if (me->elfclass == ELFCLASS32) {
-            ms->reltab = reltabFromScn32(ms);
-          } else if (me->elfclass == ELFCLASS64) {
-            // TODO
-          }
-          assert(ms->reltab);
-          break;
-        case SHT_RELA:
-          if (me->elfclass == ELFCLASS32) {
-            // TODO
-          } else if (me->elfclass == ELFCLASS64) {
-            // TODO
-          }
-          assert(ms->reltab);
-          break;
-      }
-    }
-
-
-    /* Sort sections by file offset */
-    qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
-
-
-    /* Find PHDR -> Section dependencies (needs sorted sections) */
-    for (i = 0; i < numShdr - 1; i++) {
-      ElfuScn *ms = secArray[i];
-
-      ElfuPhdr *parent = parentPhdr(me, ms);
-
-      if (parent) {
-        GElf_Off shaddr = parent->phdr.p_vaddr +
-                         (ms->shdr.sh_offset - parent->phdr.p_offset);
-
-        if (ms->shdr.sh_addr == 0) {
-          ms->shdr.sh_addr = shaddr;
-        } else {
-          assert(ms->shdr.sh_addr == shaddr);
-        }
-
-        CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
-      } else {
-        CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
-      }
-    }
-  }
-
-
-  return me;
-
-
-  ERROR:
-  if (secArray) {
-    free(secArray);
-  }
-  if (me) {
-    // TODO: Free data structures
-  }
-
-  ELFU_WARN("elfu_mFromElf: Failed to load file.\n");
-  return NULL;
-}
diff --git a/src/model/layout.c b/src/model/layout.c
deleted file mode 100644 (file)
index e4b3fb1..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libelfu/libelfu.h>
-
-
-
-static GElf_Word shiftStuffAtAfterOffset(ElfuElf *me,
-                                         GElf_Off offset,
-                                         GElf_Word size)
-{
-  ElfuPhdr *mp;
-  ElfuScn *ms;
-  /* Force a minimum alignment, just to be sure. */
-  GElf_Word align = 64;
-
-  /* Find maximum alignment size by which we have to shift.
-   * Assumes alignment sizes are always 2^x. */
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    if (mp->phdr.p_offset >= offset) {
-      if (mp->phdr.p_align > align) {
-        align = mp->phdr.p_align;
-      }
-    }
-  }
-
-  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
-    if (ms->shdr.sh_offset >= offset) {
-      if (ms->shdr.sh_addralign > align) {
-        align = ms->shdr.sh_addralign;
-      }
-    }
-  }
-
-  size = ROUNDUP(size, align);
-
-  /* Shift stuff */
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    if (mp->phdr.p_type != PT_LOAD) {
-      continue;
-    }
-
-    if (mp->phdr.p_offset >= offset) {
-      mp->phdr.p_offset += size;
-
-      elfu_mPhdrUpdateChildOffsets(mp);
-    }
-  }
-
-  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
-    if (ms->shdr.sh_offset >= offset) {
-      ms->shdr.sh_offset += size;
-    }
-  }
-
-  if (me->ehdr.e_phoff >= offset) {
-    me->ehdr.e_phoff += size;
-  }
-
-  if (me->ehdr.e_shoff >= offset) {
-    me->ehdr.e_shoff += size;
-  }
-
-  return size;
-}
-
-
-
-
-
-/* Finds a suitable PHDR to insert a hole into and expands it
- * if necessary.
- * Returns memory address the hole will be mapped to, or 0 if
- * the operation failed. */
-GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size,
-                                     GElf_Word align, int w, int x,
-                                     ElfuPhdr **injPhdr)
-{
-  ElfuPhdr *first = NULL;
-  ElfuPhdr *last = NULL;
-  ElfuPhdr *mp;
-
-  assert(!(w && x));
-
-  /* Treat read-only data as executable.
-   * That's what the GNU toolchain does on x86. */
-  if (!w && !x) {
-    x = 1;
-  }
-
-  /* Find first and last LOAD PHDRs.
-   * Don't compare p_memsz - segments don't overlap in memory. */
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    if (mp->phdr.p_type != PT_LOAD) {
-      continue;
-    }
-    if (!first || mp->phdr.p_vaddr < first->phdr.p_vaddr) {
-      first = mp;
-    }
-    if (!last || mp->phdr.p_vaddr > last->phdr.p_vaddr) {
-      last = mp;
-    }
-  }
-
-  if ((w && (last->phdr.p_flags & PF_W))
-      || (x && (last->phdr.p_flags & PF_X))) {
-    /* Need to append. */
-    GElf_Off injOffset = OFFS_END(last->phdr.p_offset, last->phdr.p_filesz);
-    GElf_Word injSpace = 0;
-    GElf_Word nobitsize = last->phdr.p_memsz - last->phdr.p_filesz;
-
-    /* Expand NOBITS if any */
-    if (nobitsize > 0) {
-      GElf_Off endOff = OFFS_END(last->phdr.p_offset, last->phdr.p_filesz);
-      GElf_Off endAddr = OFFS_END(last->phdr.p_vaddr, last->phdr.p_filesz);
-      ElfuScn *ms;
-
-      ELFU_INFO("Expanding NOBITS at address 0x%jx...\n", endAddr);
-
-      CIRCLEQ_FOREACH(ms, &last->childScnList, elemChildScn) {
-        if (ms->shdr.sh_offset == endOff) {
-          assert(ms->shdr.sh_type == SHT_NOBITS);
-          assert(ms->shdr.sh_size == nobitsize);
-          ms->data.d_buf = malloc(ms->shdr.sh_size);
-          memset(ms->data.d_buf, '\0', ms->shdr.sh_size);
-          if (!ms->data.d_buf) {
-            ELFU_WARN("mExpandNobits: Could not allocate %jd bytes for NOBITS expansion. Data may be inconsistent.\n", ms->shdr.sh_size);
-            assert(0);
-            goto ERROR;
-          }
-
-          ms->data.d_align = 1;
-          ms->data.d_off  = 0;
-          ms->data.d_type = ELF_T_BYTE;
-          ms->data.d_size = ms->shdr.sh_size;
-          ms->data.d_version = elf_version(EV_NONE);
-
-          ms->shdr.sh_type = SHT_PROGBITS;
-          ms->shdr.sh_addr = endAddr;
-        }
-      }
-
-      injSpace += shiftStuffAtAfterOffset(me, endOff, nobitsize);
-      injSpace -= nobitsize;
-      injOffset += nobitsize;
-      last->phdr.p_filesz += nobitsize;
-      assert(last->phdr.p_filesz == last->phdr.p_memsz);
-    }
-
-    /* Calculate how much space we need, taking alignment into account */
-    size += ROUNDUP(injOffset, align) - injOffset;
-
-    /* If there is not enough space left, create even more. */
-    if (injSpace < size) {
-      injSpace += shiftStuffAtAfterOffset(me, injOffset, size - injSpace);
-    }
-    assert(injSpace >= size);
-
-    /* Remap ourselves */
-    last->phdr.p_filesz += size;
-    last->phdr.p_memsz += size;
-
-    injOffset = ROUNDUP(injOffset, align);
-
-    if (injPhdr) {
-      *injPhdr = last;
-    }
-    return last->phdr.p_vaddr + (injOffset - last->phdr.p_offset);
-  } else if ((w && (first->phdr.p_flags & PF_W))
-             || (x && (first->phdr.p_flags & PF_X))) {
-    /* Need to prepend or split up the PHDR. */
-    GElf_Off injOffset = OFFS_END(first->phdr.p_offset, first->phdr.p_filesz);
-    ElfuScn *ms;
-
-    /* Round up size to take PHDR alignment into account.
-     * We assume that this is a multiple of the alignment asked for. */
-    assert(first->phdr.p_align >= align);
-    size = ROUNDUP(size, first->phdr.p_align);
-
-    /* Find first section. We assume there is at least one. */
-    assert(!CIRCLEQ_EMPTY(&first->childScnList));
-    injOffset = CIRCLEQ_FIRST(&first->childScnList)->shdr.sh_offset;
-
-    /* Move our sections */
-    CIRCLEQ_FOREACH(ms, &first->childScnList, elemChildScn) {
-      if (ms->shdr.sh_offset >= injOffset) {
-        ms->shdr.sh_offset += size;
-      }
-    }
-
-    /* Move our PHDRs */
-    CIRCLEQ_FOREACH(mp, &first->childPhdrList, elemChildPhdr) {
-      if (mp->phdr.p_offset >= injOffset) {
-        mp->phdr.p_offset += size;
-      } else {
-        mp->phdr.p_vaddr -= size;
-        mp->phdr.p_paddr -= size;
-      }
-    }
-
-    /* Move other PHDRs and sections */
-    assert(size <= shiftStuffAtAfterOffset(me, injOffset, size));
-
-    /* Remap ourselves */
-    first->phdr.p_vaddr -= size;
-    first->phdr.p_paddr -= size;
-    first->phdr.p_filesz += size;
-    first->phdr.p_memsz += size;
-
-    injOffset = ROUNDUP(injOffset, align);
-
-    if (injPhdr) {
-      *injPhdr = first;
-    }
-    return first->phdr.p_vaddr + (injOffset - first->phdr.p_offset);
-  }
-
-  ERROR:
-  if (injPhdr) {
-    *injPhdr = NULL;
-  }
-  return 0;
-}
-
-
-
-
-static int cmpPhdrOffs(const void *mp1, const void *mp2)
-{
-  assert(mp1);
-  assert(mp2);
-
-  ElfuPhdr *p1 = *(ElfuPhdr**)mp1;
-  ElfuPhdr *p2 = *(ElfuPhdr**)mp2;
-
-  assert(p1);
-  assert(p2);
-
-
-  if (p1->phdr.p_offset < p2->phdr.p_offset) {
-    return -1;
-  } else if (p1->phdr.p_offset == p2->phdr.p_offset) {
-    return 0;
-  } else /* if (p1->phdr.p_offset > p2->phdr.p_offset) */ {
-    return 1;
-  }
-}
-
-int elfu_mLayoutAuto(ElfuElf *me)
-{
-  ElfuPhdr *mp;
-  ElfuScn *ms;
-  ElfuPhdr **phdrArr;
-  GElf_Off lastend = 0;
-  size_t i, j;
-
-  assert(me);
-
-  phdrArr = malloc(elfu_mPhdrCount(me) * sizeof(*phdrArr));
-  if (!phdrArr) {
-    ELFU_WARN("elfu_mLayoutAuto: malloc failed for phdrArr.\n");
-    return 1;
-  }
-
-  i = 0;
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    if (mp->phdr.p_type != PT_LOAD) {
-      continue;
-    }
-
-    phdrArr[i] = mp;
-    i++;
-  }
-
-  /* Assume we have at least one LOAD PHDR,
-   * and that it ends after EHDR and PHDRs */
-  assert(i > 1);
-
-  /* Sort array by file offset */
-  qsort(phdrArr, i, sizeof(*phdrArr), cmpPhdrOffs);
-
-  lastend = OFFS_END(phdrArr[0]->phdr.p_offset, phdrArr[0]->phdr.p_filesz);
-
-  /* Wiggle offsets of 2nd, 3rd etc so take minimum space */
-  for (j = 1; j < i; j++) {
-    GElf_Off subalign = phdrArr[j]->phdr.p_offset % phdrArr[j]->phdr.p_align;
-
-    if ((lastend % phdrArr[j]->phdr.p_align) <= subalign) {
-      lastend += subalign - (lastend % phdrArr[j]->phdr.p_align);
-    } else {
-      lastend += phdrArr[j]->phdr.p_align - ((lastend % phdrArr[j]->phdr.p_align) - subalign);
-    }
-
-    phdrArr[j]->phdr.p_offset = lastend;
-
-    elfu_mPhdrUpdateChildOffsets(phdrArr[j]);
-
-    lastend = OFFS_END(phdrArr[j]->phdr.p_offset, phdrArr[j]->phdr.p_filesz);
-  }
-
-  free(phdrArr);
-
-
-  /* Place orphaned sections afterwards, maintaining alignment */
-  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
-    lastend = ROUNDUP(lastend, ms->shdr.sh_addralign);
-
-    ms->shdr.sh_offset = lastend;
-
-    lastend = OFFS_END(ms->shdr.sh_offset, SCNFILESIZE(&ms->shdr));
-  }
-
-
-  /* Move SHDRs to end */
-  lastend = ROUNDUP(lastend, 8);
-  me->ehdr.e_shoff = lastend;
-
-
-  return 0;
-}
diff --git a/src/model/phdr.c b/src/model/phdr.c
deleted file mode 100644 (file)
index d26eb77..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <assert.h>
-#include <libelfu/libelfu.h>
-
-
-size_t elfu_mPhdrCount(ElfuElf *me)
-{
-  ElfuPhdr *mp;
-  size_t i = 0;
-
-  assert(me);
-
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    i++;
-  }
-
-  return i;
-}
-
-
-
-void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
-{
-  ElfuScn *ms;
-  ElfuPhdr *mpc;
-
-  assert(mp);
-  assert(mp->phdr.p_type == PT_LOAD);
-
-  CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
-    mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr);
-  }
-
-  CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
-    ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr);
-  }
-}
diff --git a/src/model/reladd.c b/src/model/reladd.c
deleted file mode 100644 (file)
index 2fdfb48..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <libelfu/libelfu.h>
-
-
-static int appendData(ElfuScn *ms, void *buf, size_t len)
-{
-  void *newbuf;
-
-  assert(ms);
-  assert(ms->shdr.sh_type != SHT_NOBITS);
-  assert(ms->data.d_buf);
-
-  newbuf = realloc(ms->data.d_buf, ms->shdr.sh_size + len);
-  if (!newbuf) {
-    ELFU_WARN("appendData: malloc() failed for newbuf.\n");
-    return 1;
-  }
-
-  ms->data.d_buf = newbuf;
-  memcpy(newbuf + ms->shdr.sh_size, buf, len);
-  ms->shdr.sh_size += len;
-  ms->data.d_size += len;
-  assert(ms->shdr.sh_size == ms->data.d_size);
-
-  return 0;
-}
-
-
-static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
-{
-  ElfuScn *newscn = NULL;
-  GElf_Addr injAddr;
-  GElf_Off injOffset;
-  ElfuPhdr *injPhdr;
-
-  if (oldscn->shdr.sh_flags & SHF_ALLOC) {
-    newscn = elfu_mCloneScn(oldscn);
-    if (!newscn) {
-      return NULL;
-    }
-
-    if (newscn->shdr.sh_type == SHT_NOBITS) {
-      /* Expand this to SHT_PROGBITS, then insert as such. */
-
-      assert(!newscn->data.d_buf);
-
-      newscn->data.d_buf = malloc(newscn->shdr.sh_size);
-      if (!newscn->data.d_buf) {
-        goto ERROR;
-      }
-      newscn->data.d_size = newscn->shdr.sh_size;
-      newscn->shdr.sh_type = SHT_PROGBITS;
-    }
-
-    injAddr = elfu_mLayoutGetSpaceInPhdr(me,
-                                         newscn->shdr.sh_size,
-                                         newscn->shdr.sh_addralign,
-                                         newscn->shdr.sh_flags & SHF_WRITE,
-                                         newscn->shdr.sh_flags & SHF_EXECINSTR,
-                                         &injPhdr);
-
-    if (!injPhdr) {
-      ELFU_WARN("insertSection: Could not find a place to insert section.\n");
-      goto ERROR;
-    }
-
-    ELFU_INFO("Inserting %s at address 0x%jx...\n",
-              elfu_mScnName(mrel, oldscn),
-              injAddr);
-
-    injOffset = injAddr - injPhdr->phdr.p_vaddr + injPhdr->phdr.p_offset;
-
-    newscn->shdr.sh_addr = injAddr;
-    newscn->shdr.sh_offset = injOffset;
-
-    if (CIRCLEQ_EMPTY(&injPhdr->childScnList)
-        || CIRCLEQ_LAST(&injPhdr->childScnList)->shdr.sh_offset < injOffset) {
-      CIRCLEQ_INSERT_TAIL(&injPhdr->childScnList, newscn, elemChildScn);
-    } else {
-      ElfuScn *ms;
-      CIRCLEQ_FOREACH(ms, &injPhdr->childScnList, elemChildScn) {
-        if (injOffset < ms->shdr.sh_offset) {
-          CIRCLEQ_INSERT_BEFORE(&injPhdr->childScnList, ms, newscn, elemChildScn);
-          break;
-        }
-      }
-    }
-
-
-    /* Inject name */
-    if (me->shstrtab) {
-      char *newname;
-      size_t newnamelen;
-
-      newnamelen = strlen("reladd") + 1;
-      if (elfu_mScnName(mrel, oldscn)) {
-        newnamelen += strlen(elfu_mScnName(mrel, oldscn));
-      }
-
-      newname = malloc(newnamelen);
-      strcpy(newname, "reladd");
-      strcat(newname, elfu_mScnName(mrel, oldscn));
-
-      if (!newname) {
-        ELFU_WARN("insertSection: malloc() failed for newname. Leaving section name empty.\n");
-        newscn->shdr.sh_name = 0;
-      } else {
-        size_t offset = me->shstrtab->shdr.sh_size;
-
-        if (!appendData(me->shstrtab, newname, newnamelen)) {
-          newscn->shdr.sh_name = offset;
-        }
-
-        free(newname);
-      }
-    }
-
-    return newscn;
-  } else {
-      ELFU_WARN("insertSection: Skipping non-memory section %s (type %d flags %jd).\n",
-                elfu_mScnName(mrel, oldscn),
-                oldscn->shdr.sh_type,
-                oldscn->shdr.sh_flags);
-      goto ERROR;
-  }
-
-  ERROR:
-  if (newscn) {
-    // TODO: Destroy newscn
-  }
-  return NULL;
-}
-
-
-static void* subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
-{
-  (void)aux2;
-  ElfuElf *me = (ElfuElf*)aux1;
-
-  ElfuScn *newscn;
-
-  switch(ms->shdr.sh_type) {
-    case SHT_PROGBITS: /* 1 */
-    case SHT_NOBITS: /* 8 */
-      /* Ignore empty sections */
-      if (ms->shdr.sh_size == 0) {
-        break;
-      }
-
-      /* Find a place where it belongs and shove it in. */
-      newscn = insertSection(me, mrel, ms);
-      if (!newscn) {
-        ELFU_WARN("mReladd: Could not insert section %s (type %d), skipping.\n",
-                  elfu_mScnName(mrel, ms),
-                  ms->shdr.sh_type);
-      }
-      break;
-  }
-
-  return NULL;
-}
-
-
-static void* subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
-{
-  (void)aux2;
-  ElfuElf *me = (ElfuElf*)aux1;
-  (void)me;
-
-  switch(ms->shdr.sh_type) {
-    case SHT_NULL: /* 0 */
-    case SHT_PROGBITS: /* 1 */
-    case SHT_STRTAB: /* 3 */
-    case SHT_NOBITS: /* 8 */
-      break;
-
-
-    case SHT_REL: /* 9 */
-      /* Relocate. */
-      elfu_mRelocate32(me, elfu_mScnByOldscn(me, ms->infoptr), ms);
-      break;
-
-    case SHT_RELA: /* 4 */
-      // TODO: Needs a parser
-      //elfu_mRelocate(elfu_mScnByOldscn(me, ms->infoptr), ms);
-
-    case SHT_SYMTAB: /* 2 */
-      /* Merge with the existing table. Take care of string tables also. */
-
-    /* The next section types either do not occur in .o files, or are
-     * not strictly necessary to process here. */
-    case SHT_NOTE: /* 7 */
-    case SHT_HASH: /* 5 */
-    case SHT_DYNAMIC: /* 6 */
-    case SHT_SHLIB: /* 10 */
-    case SHT_DYNSYM: /* 11 */
-    case SHT_INIT_ARRAY: /* 14 */
-    case SHT_FINI_ARRAY: /* 15 */
-    case SHT_PREINIT_ARRAY: /* 16 */
-    case SHT_GROUP: /* 17 */
-    case SHT_SYMTAB_SHNDX: /* 18 */
-    case SHT_NUM: /* 19 */
-    default:
-      ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
-                elfu_mScnName(mrel, ms),
-                ms->shdr.sh_type);
-  }
-
-  return NULL;
-}
-
-
-void elfu_mReladd(ElfuElf *me, ElfuElf *mrel)
-{
-  assert(me);
-  assert(mrel);
-
-  /* For each section in object file, guess how to insert it */
-  elfu_mScnForall(mrel, subScnAdd1, me, NULL);
-
-  /* Do relocations and other stuff */
-  elfu_mScnForall(mrel, subScnAdd2, me, NULL);
-
-  /* Re-layout to accommodate new contents */
-  elfu_mLayoutAuto(me);
-}
diff --git a/src/model/relocate.c b/src/model/relocate.c
deleted file mode 100644 (file)
index 972bda3..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libelfu/libelfu.h>
-
-
-static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
-{
-  char *name = (char*)aux1;
-  (void)aux2;
-
-  if (elfu_mScnName(me, ms)) {
-    if (!strcmp(elfu_mScnName(me, ms), name)) {
-      return ms;
-    }
-  }
-
-  /* Continue */
-  return NULL;
-}
-
-/* Hazard a guess where a function may be found in the PLT */
-static GElf_Word pltLookupVal(ElfuElf *metarget, char *name)
-{
-  ElfuScn *relplt;
-  ElfuScn *plt;
-  ElfuRel *rel;
-  GElf_Word j;
-
-  relplt = elfu_mScnForall(metarget, subFindByName, ".rel.plt", NULL);
-  if (!relplt) {
-    ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
-    return 0;
-  }
-
-  plt = elfu_mScnForall(metarget, subFindByName, ".plt", NULL);
-  if (!plt) {
-    ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
-    return 0;
-  }
-
-
-  /* Look up name */
-  assert(relplt->reltab);
-  assert(relplt->linkptr);
-  assert(relplt->linkptr->symtab);
-  j = 0;
-  CIRCLEQ_FOREACH(rel, &relplt->reltab->rels, elem) {
-    GElf_Word i;
-    ElfuSym *sym;
-
-    j++;
-
-    if (rel->type != R_386_JMP_SLOT) {
-      continue;
-    }
-
-    sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab->syms);
-    for (i = 1; i < rel->sym; i++) {
-      sym = CIRCLEQ_NEXT(sym, elem);
-    }
-
-    if (!sym->name) {
-      continue;
-    }
-
-    if (!strcmp(sym->name, name)) {
-      /* If this is the symbol we are looking for, then in an x86 binary
-       * the jump to the dynamic symbol is probably at offset (j * 16)
-       * from the start of the PLT, where j is the PLT entry and 16 is
-       * the number of bytes the machine code in a PLT entry take. */
-      GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
-      ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j);
-      return addr;
-    }
-  }
-
-  ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
-
-  return 0;
-}
-
-
-static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
-{
-  GElf_Word i;
-  ElfuSym *sym;
-
-  assert(metarget);
-  assert(msst);
-  assert(msst->symtab);
-  assert(entry > 0);
-  assert(!CIRCLEQ_EMPTY(&msst->symtab->syms));
-
-  sym = CIRCLEQ_FIRST(&msst->symtab->syms);
-  for (i = 1; i < entry; i++) {
-    sym = CIRCLEQ_NEXT(sym, elem);
-  }
-
-  switch (sym->type) {
-    case STT_NOTYPE:
-    case STT_OBJECT:
-    case STT_FUNC:
-      if (sym->scnptr) {
-        assert(elfu_mScnByOldscn(metarget, sym->scnptr));
-        return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value;
-      } else if (sym->shndx == SHN_UNDEF) {
-        /* Look the symbol up in .dyn.plt. If it cannot be found there then
-         * .rel.dyn may need to be expanded with a COPY relocation so the
-         * dynamic linker fixes up the (TODO). */
-        return pltLookupVal(metarget, sym->name);
-      } else if (sym->shndx == SHN_ABS) {
-        return sym->value;
-      } else {
-        ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
-        return 0;
-      }
-      break;
-    case STT_SECTION:
-      assert(sym->scnptr);
-      assert(elfu_mScnByOldscn(metarget, sym->scnptr));
-      return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr;
-    case STT_FILE:
-      ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n");
-      return 0;
-    default:
-      ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, sym->name);
-      return 0;
-  }
-}
-
-void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
-{
-  ElfuRel *rel;
-
-  assert(mstarget);
-  assert(msrt);
-
-  ELFU_DEBUG("Relocating in section of type %d size %jx\n",
-             mstarget->shdr.sh_type,
-             mstarget->shdr.sh_size);
-
-  CIRCLEQ_FOREACH(rel, &msrt->reltab->rels, elem) {
-    Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
-    Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
-    Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
-    Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
-    Elf32_Word newval = *dest;
-
-    switch(rel->type) {
-      case R_386_NONE:
-        ELFU_DEBUG("Skipping relocation: R_386_NONE");
-        break;
-      case R_386_32:
-        ELFU_DEBUG("Relocation: R_386_32");
-        newval = s + a;
-        break;
-      case R_386_PC32:
-        ELFU_DEBUG("Relocation: R_386_PC32");
-        newval = s + a - p;
-        break;
-
-      default:
-        ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
-    }
-    ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval);
-    *dest = newval;
-  }
-}
diff --git a/src/model/section.c b/src/model/section.c
deleted file mode 100644 (file)
index a96377c..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <libelfu/libelfu.h>
-
-
-/* Meta-functions */
-
-void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
-{
-  ElfuPhdr *mp;
-  ElfuScn *ms;
-
-  // TODO: Sort PHDRs by offset before interating
-
-  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->data.d_buf) {
-    return NULL;
-  }
-
-  return &((char*)me->shstrtab->data.d_buf)[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)
-{
-  assert(ms1);
-  assert(ms2);
-
-  ElfuScn *s1 = *(ElfuScn**)ms1;
-  ElfuScn *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)
-{
-  assert(me);
-
-  size_t numSecs;
-  ElfuScn **sortedSecs;
-  size_t i;
-
-  /* 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;
-}
diff --git a/src/model/toFile.c b/src/model/toFile.c
deleted file mode 100644 (file)
index da06f4a..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#include <stdlib.h>
-#include <libelfu/libelfu.h>
-
-
-
-static void modelToPhdrs(ElfuElf *me, Elf *e)
-{
-  ElfuPhdr *mp;
-  size_t i;
-
-  /* Count PHDRs */
-  i = 0;
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    i++;
-  }
-
-  if (!gelf_newphdr(e, i)) {
-    ELFU_WARNELF("gelf_newphdr");
-  }
-
-  /* Copy PHDRs */
-  i = 0;
-  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
-    if (!gelf_update_phdr (e, i, &mp->phdr)) {
-      ELFU_WARNELF("gelf_update_phdr");
-    }
-
-    i++;
-  }
-}
-
-
-
-static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
-{
-  (void) me;
-  (void) aux2;
-  Elf *e = (Elf*)aux1;
-  Elf_Scn *scnOut;
-
-  scnOut = elf_newscn(e);
-  if (!scnOut) {
-    ELFU_WARNELF("elf_newscn");
-    return (void*)-1;
-  }
-
-
-  /* SHDR */
-  if (ms->linkptr) {
-    ms->shdr.sh_link = elfu_mScnIndex(me, ms->linkptr);
-  }
-  if (ms->infoptr) {
-    ms->shdr.sh_info = elfu_mScnIndex(me, ms->infoptr);
-  }
-  if (!gelf_update_shdr(scnOut, &ms->shdr)) {
-    ELFU_WARNELF("gelf_update_shdr");
-  }
-
-
-  /* Data */
-  if (ms->data.d_buf) {
-    Elf_Data *dataOut = elf_newdata(scnOut);
-    if (!dataOut) {
-      ELFU_WARNELF("elf_newdata");
-    }
-
-    dataOut->d_align = ms->data.d_align;
-    dataOut->d_buf  = ms->data.d_buf;
-    dataOut->d_off  = ms->data.d_off;
-    dataOut->d_type = ms->data.d_type;
-    dataOut->d_size = ms->data.d_size;
-    dataOut->d_version = ms->data.d_version;
-  }
-
-  return NULL;
-}
-
-
-
-
-
-void elfu_mToElf(ElfuElf *me, Elf *e)
-{
-  /* We control the ELF file's layout now. */
-  /* tired's libelf also offers ELF_F_LAYOUT_OVERLAP for overlapping sections,
-   * but we don't want that since we filtered it out in the reading stage
-   * already. It would be too mind-blowing to handle the dependencies between
-   * the PHDRs and sections then... */
-  elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
-
-
-  /* EHDR */
-  if (!gelf_newehdr(e, me->elfclass)) {
-    ELFU_WARNELF("gelf_newehdr");
-  }
-
-  if (me->shstrtab) {
-    me->ehdr.e_shstrndx = elfu_mScnIndex(me, me->shstrtab);
-  }
-
-  if (!gelf_update_ehdr(e, &me->ehdr)) {
-    ELFU_WARNELF("gelf_update_ehdr");
-  }
-
-
-  /* Sections */
-  elfu_mScnForall(me, modelToSection, e, NULL);
-
-
-  /* PHDRs */
-  modelToPhdrs(me, e);
-
-
-  elf_flagelf(e, ELF_C_SET, ELF_F_DIRTY);
-}
diff --git a/src/modelops/check.c b/src/modelops/check.c
new file mode 100644 (file)
index 0000000..5234bef
--- /dev/null
@@ -0,0 +1,54 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <libelfu/libelfu.h>
+
+
+int elfu_mCheck(ElfuElf *me)
+{
+  size_t numSecs;
+  ElfuScn **sortedSecs;
+  size_t i;
+
+  sortedSecs = elfu_mScnSortedByOffset(me, &numSecs);
+  if (!sortedSecs) {
+    return -1;
+  }
+
+
+  /* Check for overlapping sections */
+  for (i = 0; i < numSecs - 1; i++) {
+    if (sortedSecs[i]->shdr.sh_offset + SCNFILESIZE(&sortedSecs[i]->shdr)
+        > sortedSecs[i+1]->shdr.sh_offset) {
+      ELFU_WARN("elfu_check: Found overlapping sections: %s and %s.\n",
+                elfu_mScnName(me, sortedSecs[i]),
+                elfu_mScnName(me, sortedSecs[i+1]));
+    }
+  }
+
+
+  /* Check for sections overlapping with EHDR */
+  for (i = 0; i < numSecs; i++) {
+    if (sortedSecs[i]->shdr.sh_offset < me->ehdr.e_ehsize) {
+      ELFU_WARN("elfu_check: Found section overlapping with EHDR: %s.\n",
+                elfu_mScnName(me, sortedSecs[i]));
+    }
+  }
+
+
+  /* Check for sections overlapping with PHDRs */
+  for (i = 0; i < numSecs; i++) {
+    if (OVERLAPPING(sortedSecs[i]->shdr.sh_offset,
+                    SCNFILESIZE(&sortedSecs[i]->shdr),
+                    me->ehdr.e_phoff,
+                    me->ehdr.e_phentsize * me->ehdr.e_phnum)) {
+      ELFU_WARN("elfu_check: Found section overlapping with PHDRs: %s.\n",
+                elfu_mScnName(me, sortedSecs[i]));
+    }
+  }
+
+
+  free(sortedSecs);
+
+  return 0;
+}
diff --git a/src/modelops/clone.c b/src/modelops/clone.c
new file mode 100644 (file)
index 0000000..ca4b38f
--- /dev/null
@@ -0,0 +1,41 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libelfu/libelfu.h>
+
+ElfuScn* elfu_mCloneScn(ElfuScn *ms)
+{
+  ElfuScn *newscn;
+
+  assert(ms);
+
+  newscn = malloc(sizeof(ElfuScn));
+  if (!newscn) {
+    ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new ElfuScn.\n");
+    return NULL;
+  }
+
+  newscn->shdr = ms->shdr;
+  newscn->data = ms->data;
+  if (ms->data.d_buf) {
+    void *newbuf = malloc(ms->data.d_size);
+    if (!newbuf) {
+      ELFU_WARN("elfu_nCloneScn: Could not allocate memory for new data buffer.\n");
+      free(newscn);
+      return NULL;
+    }
+
+    memcpy(newbuf, ms->data.d_buf, ms->data.d_size);
+    newscn->data.d_buf = newbuf;
+  }
+
+  newscn->linkptr = NULL;
+  newscn->infoptr = NULL;
+
+  newscn->oldptr = ms;
+
+  ms->symtab = NULL;
+  ms->reltab = NULL;
+
+  return newscn;
+}
diff --git a/src/modelops/dump.c b/src/modelops/dump.c
new file mode 100644 (file)
index 0000000..27556f9
--- /dev/null
@@ -0,0 +1,239 @@
+#include <assert.h>
+#include <libelfu/libelfu.h>
+
+
+static char* segmentTypeStr(Elf32_Word p_type)
+{
+  switch(p_type) {
+    case PT_NULL: /* 0 */
+      return "NULL";
+    case PT_LOAD: /* 1 */
+      return "LOAD";
+    case PT_DYNAMIC: /* 2 */
+      return "DYNAMIC";
+    case PT_INTERP: /* 3 */
+      return "INTERP";
+    case PT_NOTE: /* 4 */
+      return "NOTE";
+    case PT_SHLIB: /* 5 */
+      return "SHLIB";
+    case PT_PHDR: /* 6 */
+      return "PHDR";
+    case PT_TLS: /* 7 */
+      return "TLS";
+    case PT_NUM: /* 8 */
+      return "NUM";
+    case PT_GNU_EH_FRAME: /* 0x6474e550 */
+      return "GNU_EH_FRAME";
+    case PT_GNU_STACK: /* 0x6474e551 */
+      return "GNU_STACK";
+    case PT_GNU_RELRO: /* 0x6474e552 */
+      return "GNU_RELRO";
+  }
+
+  return "-?-";
+}
+
+static char* sectionTypeStr(Elf32_Word sh_type)
+{
+  switch(sh_type) {
+    case SHT_NULL: /* 0 */
+      return "NULL";
+    case SHT_PROGBITS: /* 1 */
+      return "PROGBITS";
+    case SHT_SYMTAB: /* 2 */
+      return "SYMTAB";
+    case SHT_STRTAB: /* 3 */
+      return "STRTAB";
+    case SHT_RELA: /* 4 */
+      return "RELA";
+    case SHT_HASH: /* 5 */
+      return "HASH";
+    case SHT_DYNAMIC: /* 6 */
+      return "DYNAMIC";
+    case SHT_NOTE: /* 7 */
+      return "NOTE";
+    case SHT_NOBITS: /* 8 */
+      return "NOBITS";
+    case SHT_REL: /* 9 */
+      return "REL";
+    case SHT_SHLIB: /* 10 */
+      return "SHLIB";
+    case SHT_DYNSYM: /* 11 */
+      return "DYNSYM";
+    case SHT_INIT_ARRAY: /* 14 */
+      return "INIT_ARRAY";
+    case SHT_FINI_ARRAY: /* 15 */
+      return "FINI_ARRAY";
+    case SHT_PREINIT_ARRAY: /* 16 */
+      return "PREINIT_ARRAY";
+    case SHT_GROUP: /* 17 */
+      return "SHT_GROUP";
+    case SHT_SYMTAB_SHNDX: /* 18 */
+      return "SYMTAB_SHNDX";
+    case SHT_NUM: /* 19 */
+      return "NUM";
+
+    case SHT_GNU_ATTRIBUTES: /* 0x6ffffff5 */
+      return "GNU_ATTRIBUTES";
+    case SHT_GNU_HASH: /* 0x6ffffff6 */
+      return "GNU_HASH";
+    case SHT_GNU_LIBLIST: /* 0x6ffffff7 */
+      return "GNU_LIBLIST";
+    case SHT_GNU_verdef: /* 0x6ffffffd */
+      return "GNU_verdef";
+    case SHT_GNU_verneed: /* 0x6ffffffe */
+      return "GNU_verneed";
+    case SHT_GNU_versym: /* 0x6fffffff */
+      return "GNU_versym";
+  }
+
+  return "-?-";
+}
+
+
+
+
+void elfu_mDumpPhdr(ElfuElf *me, ElfuPhdr *mp)
+{
+  assert(me);
+  assert(mp);
+
+  ELFU_INFO("%12s %8jx %8jx %8jx %8jx %8jx %8jx %8jx %8jx\n",
+            segmentTypeStr(mp->phdr.p_type),
+            (uintmax_t) mp->phdr.p_type,
+            (uintmax_t) mp->phdr.p_offset,
+            (uintmax_t) mp->phdr.p_vaddr,
+            (uintmax_t) mp->phdr.p_paddr,
+            (uintmax_t) mp->phdr.p_filesz,
+            (uintmax_t) mp->phdr.p_memsz,
+            (uintmax_t) mp->phdr.p_flags,
+            (uintmax_t) mp->phdr.p_align);
+
+  if (!CIRCLEQ_EMPTY(&mp->childPhdrList)) {
+    ElfuPhdr *mpc;
+
+    ELFU_INFO("      -> Child PHDRs:\n");
+    CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
+      ELFU_INFO("        * %-8s @ %8jx\n",
+                segmentTypeStr(mpc->phdr.p_type),
+                mpc->phdr.p_vaddr);
+    }
+  }
+
+  if (!CIRCLEQ_EMPTY(&mp->childScnList)) {
+    ElfuScn *msc;
+
+    ELFU_INFO("      -> Child sections:\n");
+    CIRCLEQ_FOREACH(msc, &mp->childScnList, elemChildScn) {
+      ELFU_INFO("        * %-17s @ %8jx\n",
+                elfu_mScnName(me, msc),
+                msc->shdr.sh_addr);
+    }
+  }
+}
+
+
+void elfu_mDumpScn(ElfuElf *me, ElfuScn *ms)
+{
+  char *namestr, *typestr, *linkstr, *infostr;
+
+  assert(me);
+  assert(ms);
+
+  namestr = elfu_mScnName(me, ms);
+  typestr = sectionTypeStr(ms->shdr.sh_type);
+  linkstr = ms->linkptr ? elfu_mScnName(me, ms->linkptr) : "";
+  infostr = ms->infoptr ? elfu_mScnName(me, ms->infoptr) : "";
+
+  ELFU_INFO("%-17s %-15s %8jx %9jx %8jx %2jx %2jx %2jd %-17s %-17s\n",
+            namestr,
+            typestr,
+            ms->shdr.sh_addr,
+            ms->shdr.sh_offset,
+            ms->shdr.sh_size,
+            ms->shdr.sh_entsize,
+            ms->shdr.sh_flags,
+            ms->shdr.sh_addralign,
+            linkstr,
+            infostr);
+}
+
+
+void elfu_mDumpEhdr(ElfuElf *me)
+{
+  assert(me);
+
+  ELFU_INFO("ELF header:\n");
+  ELFU_INFO("   %d-bit ELF object\n", me->elfclass == ELFCLASS32 ? 32 : 64);
+
+  ELFU_INFO("   EHDR:\n");
+
+  ELFU_INFO("     e_type       %8x\n", me->ehdr.e_type);
+  ELFU_INFO("     e_machine    %8x\n", me->ehdr.e_machine);
+  ELFU_INFO("     e_version    %8x\n", me->ehdr.e_version);
+  ELFU_INFO("     e_entry      %8jx\n", me->ehdr.e_entry);
+  ELFU_INFO("     e_phoff      %8jx\n", me->ehdr.e_phoff);
+  ELFU_INFO("     e_shoff      %8jx\n", me->ehdr.e_shoff);
+  ELFU_INFO("     e_flags      %8x\n", me->ehdr.e_flags);
+  ELFU_INFO("     e_ehsize     %8x\n", me->ehdr.e_ehsize);
+  ELFU_INFO("     e_phentsize  %8x\n", me->ehdr.e_phentsize);
+  ELFU_INFO("     e_shentsize  %8x\n", me->ehdr.e_shentsize);
+
+  ELFU_INFO("   shstrtab: %s\n", me->shstrtab ? elfu_mScnName(me, me->shstrtab) : "(none)");
+}
+
+
+
+static void* subScnDump(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+  (void) aux1;
+  (void) aux2;
+
+  printf(" [%4d] ", elfu_mScnIndex(me, ms));
+  elfu_mDumpScn(me, ms);
+
+  return NULL;
+}
+
+
+void elfu_mDumpElf(ElfuElf *me)
+{
+  ElfuPhdr *mp;
+  ElfuScn *ms;
+  size_t i;
+
+  assert(me);
+
+
+  elfu_mDumpEhdr(me);
+  ELFU_INFO("\n");
+
+
+  ELFU_INFO("Segments:\n");
+  ELFU_INFO("     #        (type)   p_type p_offset  p_vaddr  p_paddr p_filesz  p_memsz  p_flags  p_align\n");
+  ELFU_INFO("       |            |        |        |        |        |        |        |        |        \n");
+  i = 0;
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    printf(" [%4d] ", i);
+    elfu_mDumpPhdr(me, mp);
+    i++;
+  }
+  ELFU_INFO("\n");
+
+
+  ELFU_INFO("Orphaned sections:\n");
+  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+    ELFU_INFO("        * %-17s @ %8jx\n",
+              elfu_mScnName(me, ms),
+              ms->shdr.sh_addr);
+  }
+  ELFU_INFO("\n");
+
+
+  ELFU_INFO("Sections:\n");
+  ELFU_INFO("     #  Name              sh_type          sh_addr sh_offset  sh_size ES Fl Al sh_link           sh_info          \n");
+  ELFU_INFO("       |                 |               |        |         |        |  |  |  |                 |                 \n");
+  elfu_mScnForall(me, subScnDump, &i, NULL);
+  ELFU_INFO("\n");
+}
diff --git a/src/modelops/fromFile.c b/src/modelops/fromFile.c
new file mode 100644 (file)
index 0000000..23105e6
--- /dev/null
@@ -0,0 +1,487 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <libelfu/libelfu.h>
+
+
+static char* symstr(ElfuScn *symtab, size_t off)
+{
+  assert(symtab);
+  assert(symtab->linkptr);
+  assert(symtab->linkptr->data.d_buf);
+  assert(off < symtab->linkptr->data.d_size);
+
+  return &(((char*)symtab->linkptr->data.d_buf)[off]);
+}
+
+
+static ElfuSymtab* symtabFromScn32(ElfuScn *ms, ElfuScn**origScnArr)
+{
+  ElfuSymtab *st;
+  size_t i;
+
+  assert(ms);
+  assert(ms->data.d_buf);
+  assert(origScnArr);
+
+
+  st = malloc(sizeof(*st));
+  if (!st) {
+    ELFU_WARN("elfu_mSymtabFromScn32: malloc() failed for st.\n");
+    goto ERROR;
+  }
+
+  CIRCLEQ_INIT(&st->syms);
+
+
+  for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
+    Elf32_Sym *cursym = &(((Elf32_Sym*)ms->data.d_buf)[i]);
+    ElfuSym *sym = malloc(sizeof(*sym));
+    assert(sym);
+
+    sym->name = symstr(ms, cursym->st_name);
+    sym->value = cursym->st_value;
+    sym->size = cursym->st_size;
+    sym->bind = ELF32_ST_BIND(cursym->st_info);
+    sym->type = ELF32_ST_TYPE(cursym->st_info);
+    sym->other = cursym->st_other;
+
+    switch (cursym->st_shndx) {
+      case SHN_UNDEF:
+      case SHN_ABS:
+      case SHN_COMMON:
+        sym->scnptr = NULL;
+        sym->shndx = cursym->st_shndx;
+        break;
+      default:
+        sym->scnptr = origScnArr[cursym->st_shndx - 1];
+        break;
+    }
+
+
+    CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem);
+  }
+
+
+  return st;
+
+  ERROR:
+  if (st) {
+    free(st);
+  }
+  return NULL;
+}
+
+
+static ElfuReltab* reltabFromScn32(ElfuScn *ms)
+{
+  ElfuReltab *rt;
+  size_t i;
+
+  assert(ms);
+  assert(ms->data.d_buf);
+
+
+  rt = malloc(sizeof(*rt));
+  if (!rt) {
+    ELFU_WARN("elfu_mReltabFromScn32: malloc() failed for rt.\n");
+    goto ERROR;
+  }
+
+  CIRCLEQ_INIT(&rt->rels);
+
+
+  for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
+    Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]);
+    ElfuRel *rel;
+
+    rel = malloc(sizeof(*rel));
+    assert(rel);
+
+    rel->offset = currel->r_offset;
+
+    rel->sym = ELF32_R_SYM(currel->r_info);
+    rel->type = ELF32_R_TYPE(currel->r_info);
+
+    rel->addendUsed = 0;
+    rel->addend = 0;
+
+    CIRCLEQ_INSERT_TAIL(&rt->rels, rel, elem);
+  }
+
+
+  return rt;
+
+  ERROR:
+  if (rt) {
+    free(rt);
+  }
+  return NULL;
+}
+
+
+static int cmpScnOffs(const void *ms1, const void *ms2)
+{
+  assert(ms1);
+  assert(ms2);
+
+  ElfuScn *s1 = *(ElfuScn**)ms1;
+  ElfuScn *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;
+  }
+}
+
+
+
+static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
+{
+  ElfuPhdr *mp;
+
+  assert(me);
+  assert(ms);
+
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_type != PT_LOAD) {
+      continue;
+    }
+
+    if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
+      return mp;
+    }
+
+    /* Give sections a second chance if they do not have any sh_addr
+     * at all. */
+    /* Actually we don't, because it's ambiguous.
+     * Re-enable for experiments with strangely-formatted files.
+    if (ms->shdr.sh_addr == 0
+        && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
+        && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
+            <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
+      return mp;
+    }
+    */
+  }
+
+  return NULL;
+}
+
+
+static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
+{
+  ElfuPhdr *mp;
+
+  assert(phdr);
+
+  mp = malloc(sizeof(ElfuPhdr));
+  if (!mp) {
+    ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
+    return NULL;
+  }
+
+  mp->phdr = *phdr;
+
+  CIRCLEQ_INIT(&mp->childScnList);
+  CIRCLEQ_INIT(&mp->childPhdrList);
+
+  return mp;
+}
+
+
+static ElfuScn* modelFromSection(Elf_Scn *scn)
+{
+  ElfuScn *ms;
+
+  assert(scn);
+
+  ms = malloc(sizeof(ElfuScn));
+  if (!ms) {
+    ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
+    goto ERROR;
+  }
+
+
+  assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
+
+
+  /* Copy each data part in source segment */
+  ms->data.d_align = 1;
+  ms->data.d_buf  = NULL;
+  ms->data.d_off  = 0;
+  ms->data.d_type = ELF_T_BYTE;
+  ms->data.d_size = ms->shdr.sh_size;
+  ms->data.d_version = elf_version(EV_NONE);
+  if (ms->shdr.sh_type != SHT_NOBITS
+      && ms->shdr.sh_size > 0) {
+    Elf_Data *data;
+
+    ms->data.d_buf = malloc(ms->shdr.sh_size);
+    if (!ms->data.d_buf) {
+      ELFU_WARN("modelFromSection: malloc() failed for data buffer (%jx bytes).\n", ms->shdr.sh_size);
+      goto ERROR;
+    }
+
+    /* A non-empty section should contain at least one data block. */
+    data = elf_rawdata(scn, NULL);
+    assert(data);
+
+    ms->data.d_align = data->d_align;
+    ms->data.d_type = data->d_type;
+    ms->data.d_version = data->d_version;
+
+    while (data) {
+      if (data->d_off + data->d_size > ms->shdr.sh_size) {
+        ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
+      } else {
+        memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
+      }
+
+      data = elf_rawdata(scn, data);
+    }
+  }
+
+  ms->linkptr = NULL;
+  ms->infoptr = NULL;
+
+  ms->oldptr = NULL;
+
+  ms->symtab = NULL;
+  ms->reltab = NULL;
+
+
+  return ms;
+
+  ERROR:
+  if (ms) {
+    free(ms);
+  }
+  return NULL;
+}
+
+
+
+
+ElfuElf* elfu_mFromElf(Elf *e)
+{
+  ElfuElf *me;
+  size_t shstrndx;
+  size_t i, numPhdr, numShdr;
+  ElfuScn **secArray = NULL;
+
+  assert(e);
+  if (elfu_eCheck(e)) {
+    goto ERROR;
+  }
+
+  me = malloc(sizeof(ElfuElf));
+  if (!me) {
+    ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
+    goto ERROR;
+  }
+
+
+  /* General stuff */
+  CIRCLEQ_INIT(&me->phdrList);
+  CIRCLEQ_INIT(&me->orphanScnList);
+  me->shstrtab = NULL;
+
+  me->elfclass = gelf_getclass(e);
+  assert(me->elfclass != ELFCLASSNONE);
+  assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
+
+
+  /* Get the section string table index */
+  if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+    shstrndx = 0;
+  }
+
+
+  /* Load segments */
+  assert(!elf_getphdrnum(e, &numPhdr));
+  for (i = 0; i < numPhdr; i++) {
+    GElf_Phdr phdr;
+    ElfuPhdr *mp;
+
+    assert(gelf_getphdr(e, i, &phdr) == &phdr);
+
+    mp = modelFromPhdr(&phdr);
+    if (!mp) {
+      goto ERROR;
+    }
+
+    CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
+  }
+
+  if (numPhdr > 0) {
+    ElfuPhdr *mp;
+
+    /* Find PHDR -> PHDR dependencies (needs sorted sections) */
+    CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+      ElfuPhdr *mp2;
+
+      if (mp->phdr.p_type != PT_LOAD) {
+        continue;
+      }
+
+      CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
+        if (mp2 == mp) {
+          continue;
+        }
+
+        if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
+            && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
+          CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
+        }
+      }
+    }
+  }
+
+
+  /* Load sections */
+  assert(!elf_getshdrnum(e, &numShdr));
+  if (numShdr > 1) {
+    secArray = malloc((numShdr - 1) * sizeof(*secArray));
+    if (!secArray) {
+      ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
+      goto ERROR;
+    }
+
+    for (i = 1; i < numShdr; i++) {
+      Elf_Scn *scn;
+      ElfuScn *ms;
+
+      scn = elf_getscn(e, i);
+      assert(scn);
+
+      ms = modelFromSection(scn);
+      if (!ms) {
+        goto ERROR;
+      }
+
+      secArray[i-1] =  ms;
+
+      if (i == shstrndx) {
+        me->shstrtab = ms;
+      }
+    }
+
+
+    /* Find sh_link and sh_info dependencies (needs sections in original order) */
+    for (i = 0; i < numShdr - 1; i++) {
+      ElfuScn *ms = secArray[i];
+
+      switch (ms->shdr.sh_type) {
+        case SHT_REL:
+        case SHT_RELA:
+          if (ms->shdr.sh_info > 0) {
+            ms->infoptr = secArray[ms->shdr.sh_info - 1];
+          }
+        case SHT_DYNAMIC:
+        case SHT_HASH:
+        case SHT_SYMTAB:
+        case SHT_DYNSYM:
+        case SHT_GNU_versym:
+        case SHT_GNU_verdef:
+        case SHT_GNU_verneed:
+          if (ms->shdr.sh_link > 0) {
+            ms->linkptr = secArray[ms->shdr.sh_link - 1];
+          }
+      }
+    }
+
+
+    /* Parse symtabs (needs sections in original order) */
+    for (i = 0; i < numShdr - 1; i++) {
+      ElfuScn *ms = secArray[i];
+
+      switch (ms->shdr.sh_type) {
+        case SHT_SYMTAB:
+        case SHT_DYNSYM:
+          if (me->elfclass == ELFCLASS32) {
+            ms->symtab = symtabFromScn32(ms, secArray);
+          } else if (me->elfclass == ELFCLASS64) {
+            // TODO
+          }
+          assert(ms->symtab);
+          break;
+      }
+    }
+
+
+    /* Parse relocations */
+    for (i = 0; i < numShdr - 1; i++) {
+      ElfuScn *ms = secArray[i];
+
+      switch (ms->shdr.sh_type) {
+        case SHT_REL:
+          if (me->elfclass == ELFCLASS32) {
+            ms->reltab = reltabFromScn32(ms);
+          } else if (me->elfclass == ELFCLASS64) {
+            // TODO
+          }
+          assert(ms->reltab);
+          break;
+        case SHT_RELA:
+          if (me->elfclass == ELFCLASS32) {
+            // TODO
+          } else if (me->elfclass == ELFCLASS64) {
+            // TODO
+          }
+          assert(ms->reltab);
+          break;
+      }
+    }
+
+
+    /* Sort sections by file offset */
+    qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
+
+
+    /* Find PHDR -> Section dependencies (needs sorted sections) */
+    for (i = 0; i < numShdr - 1; i++) {
+      ElfuScn *ms = secArray[i];
+
+      ElfuPhdr *parent = parentPhdr(me, ms);
+
+      if (parent) {
+        GElf_Off shaddr = parent->phdr.p_vaddr +
+                         (ms->shdr.sh_offset - parent->phdr.p_offset);
+
+        if (ms->shdr.sh_addr == 0) {
+          ms->shdr.sh_addr = shaddr;
+        } else {
+          assert(ms->shdr.sh_addr == shaddr);
+        }
+
+        CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
+      } else {
+        CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
+      }
+    }
+  }
+
+
+  return me;
+
+
+  ERROR:
+  if (secArray) {
+    free(secArray);
+  }
+  if (me) {
+    // TODO: Free data structures
+  }
+
+  ELFU_WARN("elfu_mFromElf: Failed to load file.\n");
+  return NULL;
+}
diff --git a/src/modelops/layout.c b/src/modelops/layout.c
new file mode 100644 (file)
index 0000000..e4b3fb1
--- /dev/null
@@ -0,0 +1,320 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libelfu/libelfu.h>
+
+
+
+static GElf_Word shiftStuffAtAfterOffset(ElfuElf *me,
+                                         GElf_Off offset,
+                                         GElf_Word size)
+{
+  ElfuPhdr *mp;
+  ElfuScn *ms;
+  /* Force a minimum alignment, just to be sure. */
+  GElf_Word align = 64;
+
+  /* Find maximum alignment size by which we have to shift.
+   * Assumes alignment sizes are always 2^x. */
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_offset >= offset) {
+      if (mp->phdr.p_align > align) {
+        align = mp->phdr.p_align;
+      }
+    }
+  }
+
+  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+    if (ms->shdr.sh_offset >= offset) {
+      if (ms->shdr.sh_addralign > align) {
+        align = ms->shdr.sh_addralign;
+      }
+    }
+  }
+
+  size = ROUNDUP(size, align);
+
+  /* Shift stuff */
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_type != PT_LOAD) {
+      continue;
+    }
+
+    if (mp->phdr.p_offset >= offset) {
+      mp->phdr.p_offset += size;
+
+      elfu_mPhdrUpdateChildOffsets(mp);
+    }
+  }
+
+  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+    if (ms->shdr.sh_offset >= offset) {
+      ms->shdr.sh_offset += size;
+    }
+  }
+
+  if (me->ehdr.e_phoff >= offset) {
+    me->ehdr.e_phoff += size;
+  }
+
+  if (me->ehdr.e_shoff >= offset) {
+    me->ehdr.e_shoff += size;
+  }
+
+  return size;
+}
+
+
+
+
+
+/* Finds a suitable PHDR to insert a hole into and expands it
+ * if necessary.
+ * Returns memory address the hole will be mapped to, or 0 if
+ * the operation failed. */
+GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size,
+                                     GElf_Word align, int w, int x,
+                                     ElfuPhdr **injPhdr)
+{
+  ElfuPhdr *first = NULL;
+  ElfuPhdr *last = NULL;
+  ElfuPhdr *mp;
+
+  assert(!(w && x));
+
+  /* Treat read-only data as executable.
+   * That's what the GNU toolchain does on x86. */
+  if (!w && !x) {
+    x = 1;
+  }
+
+  /* Find first and last LOAD PHDRs.
+   * Don't compare p_memsz - segments don't overlap in memory. */
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_type != PT_LOAD) {
+      continue;
+    }
+    if (!first || mp->phdr.p_vaddr < first->phdr.p_vaddr) {
+      first = mp;
+    }
+    if (!last || mp->phdr.p_vaddr > last->phdr.p_vaddr) {
+      last = mp;
+    }
+  }
+
+  if ((w && (last->phdr.p_flags & PF_W))
+      || (x && (last->phdr.p_flags & PF_X))) {
+    /* Need to append. */
+    GElf_Off injOffset = OFFS_END(last->phdr.p_offset, last->phdr.p_filesz);
+    GElf_Word injSpace = 0;
+    GElf_Word nobitsize = last->phdr.p_memsz - last->phdr.p_filesz;
+
+    /* Expand NOBITS if any */
+    if (nobitsize > 0) {
+      GElf_Off endOff = OFFS_END(last->phdr.p_offset, last->phdr.p_filesz);
+      GElf_Off endAddr = OFFS_END(last->phdr.p_vaddr, last->phdr.p_filesz);
+      ElfuScn *ms;
+
+      ELFU_INFO("Expanding NOBITS at address 0x%jx...\n", endAddr);
+
+      CIRCLEQ_FOREACH(ms, &last->childScnList, elemChildScn) {
+        if (ms->shdr.sh_offset == endOff) {
+          assert(ms->shdr.sh_type == SHT_NOBITS);
+          assert(ms->shdr.sh_size == nobitsize);
+          ms->data.d_buf = malloc(ms->shdr.sh_size);
+          memset(ms->data.d_buf, '\0', ms->shdr.sh_size);
+          if (!ms->data.d_buf) {
+            ELFU_WARN("mExpandNobits: Could not allocate %jd bytes for NOBITS expansion. Data may be inconsistent.\n", ms->shdr.sh_size);
+            assert(0);
+            goto ERROR;
+          }
+
+          ms->data.d_align = 1;
+          ms->data.d_off  = 0;
+          ms->data.d_type = ELF_T_BYTE;
+          ms->data.d_size = ms->shdr.sh_size;
+          ms->data.d_version = elf_version(EV_NONE);
+
+          ms->shdr.sh_type = SHT_PROGBITS;
+          ms->shdr.sh_addr = endAddr;
+        }
+      }
+
+      injSpace += shiftStuffAtAfterOffset(me, endOff, nobitsize);
+      injSpace -= nobitsize;
+      injOffset += nobitsize;
+      last->phdr.p_filesz += nobitsize;
+      assert(last->phdr.p_filesz == last->phdr.p_memsz);
+    }
+
+    /* Calculate how much space we need, taking alignment into account */
+    size += ROUNDUP(injOffset, align) - injOffset;
+
+    /* If there is not enough space left, create even more. */
+    if (injSpace < size) {
+      injSpace += shiftStuffAtAfterOffset(me, injOffset, size - injSpace);
+    }
+    assert(injSpace >= size);
+
+    /* Remap ourselves */
+    last->phdr.p_filesz += size;
+    last->phdr.p_memsz += size;
+
+    injOffset = ROUNDUP(injOffset, align);
+
+    if (injPhdr) {
+      *injPhdr = last;
+    }
+    return last->phdr.p_vaddr + (injOffset - last->phdr.p_offset);
+  } else if ((w && (first->phdr.p_flags & PF_W))
+             || (x && (first->phdr.p_flags & PF_X))) {
+    /* Need to prepend or split up the PHDR. */
+    GElf_Off injOffset = OFFS_END(first->phdr.p_offset, first->phdr.p_filesz);
+    ElfuScn *ms;
+
+    /* Round up size to take PHDR alignment into account.
+     * We assume that this is a multiple of the alignment asked for. */
+    assert(first->phdr.p_align >= align);
+    size = ROUNDUP(size, first->phdr.p_align);
+
+    /* Find first section. We assume there is at least one. */
+    assert(!CIRCLEQ_EMPTY(&first->childScnList));
+    injOffset = CIRCLEQ_FIRST(&first->childScnList)->shdr.sh_offset;
+
+    /* Move our sections */
+    CIRCLEQ_FOREACH(ms, &first->childScnList, elemChildScn) {
+      if (ms->shdr.sh_offset >= injOffset) {
+        ms->shdr.sh_offset += size;
+      }
+    }
+
+    /* Move our PHDRs */
+    CIRCLEQ_FOREACH(mp, &first->childPhdrList, elemChildPhdr) {
+      if (mp->phdr.p_offset >= injOffset) {
+        mp->phdr.p_offset += size;
+      } else {
+        mp->phdr.p_vaddr -= size;
+        mp->phdr.p_paddr -= size;
+      }
+    }
+
+    /* Move other PHDRs and sections */
+    assert(size <= shiftStuffAtAfterOffset(me, injOffset, size));
+
+    /* Remap ourselves */
+    first->phdr.p_vaddr -= size;
+    first->phdr.p_paddr -= size;
+    first->phdr.p_filesz += size;
+    first->phdr.p_memsz += size;
+
+    injOffset = ROUNDUP(injOffset, align);
+
+    if (injPhdr) {
+      *injPhdr = first;
+    }
+    return first->phdr.p_vaddr + (injOffset - first->phdr.p_offset);
+  }
+
+  ERROR:
+  if (injPhdr) {
+    *injPhdr = NULL;
+  }
+  return 0;
+}
+
+
+
+
+static int cmpPhdrOffs(const void *mp1, const void *mp2)
+{
+  assert(mp1);
+  assert(mp2);
+
+  ElfuPhdr *p1 = *(ElfuPhdr**)mp1;
+  ElfuPhdr *p2 = *(ElfuPhdr**)mp2;
+
+  assert(p1);
+  assert(p2);
+
+
+  if (p1->phdr.p_offset < p2->phdr.p_offset) {
+    return -1;
+  } else if (p1->phdr.p_offset == p2->phdr.p_offset) {
+    return 0;
+  } else /* if (p1->phdr.p_offset > p2->phdr.p_offset) */ {
+    return 1;
+  }
+}
+
+int elfu_mLayoutAuto(ElfuElf *me)
+{
+  ElfuPhdr *mp;
+  ElfuScn *ms;
+  ElfuPhdr **phdrArr;
+  GElf_Off lastend = 0;
+  size_t i, j;
+
+  assert(me);
+
+  phdrArr = malloc(elfu_mPhdrCount(me) * sizeof(*phdrArr));
+  if (!phdrArr) {
+    ELFU_WARN("elfu_mLayoutAuto: malloc failed for phdrArr.\n");
+    return 1;
+  }
+
+  i = 0;
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_type != PT_LOAD) {
+      continue;
+    }
+
+    phdrArr[i] = mp;
+    i++;
+  }
+
+  /* Assume we have at least one LOAD PHDR,
+   * and that it ends after EHDR and PHDRs */
+  assert(i > 1);
+
+  /* Sort array by file offset */
+  qsort(phdrArr, i, sizeof(*phdrArr), cmpPhdrOffs);
+
+  lastend = OFFS_END(phdrArr[0]->phdr.p_offset, phdrArr[0]->phdr.p_filesz);
+
+  /* Wiggle offsets of 2nd, 3rd etc so take minimum space */
+  for (j = 1; j < i; j++) {
+    GElf_Off subalign = phdrArr[j]->phdr.p_offset % phdrArr[j]->phdr.p_align;
+
+    if ((lastend % phdrArr[j]->phdr.p_align) <= subalign) {
+      lastend += subalign - (lastend % phdrArr[j]->phdr.p_align);
+    } else {
+      lastend += phdrArr[j]->phdr.p_align - ((lastend % phdrArr[j]->phdr.p_align) - subalign);
+    }
+
+    phdrArr[j]->phdr.p_offset = lastend;
+
+    elfu_mPhdrUpdateChildOffsets(phdrArr[j]);
+
+    lastend = OFFS_END(phdrArr[j]->phdr.p_offset, phdrArr[j]->phdr.p_filesz);
+  }
+
+  free(phdrArr);
+
+
+  /* Place orphaned sections afterwards, maintaining alignment */
+  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+    lastend = ROUNDUP(lastend, ms->shdr.sh_addralign);
+
+    ms->shdr.sh_offset = lastend;
+
+    lastend = OFFS_END(ms->shdr.sh_offset, SCNFILESIZE(&ms->shdr));
+  }
+
+
+  /* Move SHDRs to end */
+  lastend = ROUNDUP(lastend, 8);
+  me->ehdr.e_shoff = lastend;
+
+
+  return 0;
+}
diff --git a/src/modelops/phdr.c b/src/modelops/phdr.c
new file mode 100644 (file)
index 0000000..d26eb77
--- /dev/null
@@ -0,0 +1,36 @@
+#include <assert.h>
+#include <libelfu/libelfu.h>
+
+
+size_t elfu_mPhdrCount(ElfuElf *me)
+{
+  ElfuPhdr *mp;
+  size_t i = 0;
+
+  assert(me);
+
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    i++;
+  }
+
+  return i;
+}
+
+
+
+void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
+{
+  ElfuScn *ms;
+  ElfuPhdr *mpc;
+
+  assert(mp);
+  assert(mp->phdr.p_type == PT_LOAD);
+
+  CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
+    mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr);
+  }
+
+  CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
+    ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr);
+  }
+}
diff --git a/src/modelops/reladd.c b/src/modelops/reladd.c
new file mode 100644 (file)
index 0000000..2fdfb48
--- /dev/null
@@ -0,0 +1,229 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <libelfu/libelfu.h>
+
+
+static int appendData(ElfuScn *ms, void *buf, size_t len)
+{
+  void *newbuf;
+
+  assert(ms);
+  assert(ms->shdr.sh_type != SHT_NOBITS);
+  assert(ms->data.d_buf);
+
+  newbuf = realloc(ms->data.d_buf, ms->shdr.sh_size + len);
+  if (!newbuf) {
+    ELFU_WARN("appendData: malloc() failed for newbuf.\n");
+    return 1;
+  }
+
+  ms->data.d_buf = newbuf;
+  memcpy(newbuf + ms->shdr.sh_size, buf, len);
+  ms->shdr.sh_size += len;
+  ms->data.d_size += len;
+  assert(ms->shdr.sh_size == ms->data.d_size);
+
+  return 0;
+}
+
+
+static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
+{
+  ElfuScn *newscn = NULL;
+  GElf_Addr injAddr;
+  GElf_Off injOffset;
+  ElfuPhdr *injPhdr;
+
+  if (oldscn->shdr.sh_flags & SHF_ALLOC) {
+    newscn = elfu_mCloneScn(oldscn);
+    if (!newscn) {
+      return NULL;
+    }
+
+    if (newscn->shdr.sh_type == SHT_NOBITS) {
+      /* Expand this to SHT_PROGBITS, then insert as such. */
+
+      assert(!newscn->data.d_buf);
+
+      newscn->data.d_buf = malloc(newscn->shdr.sh_size);
+      if (!newscn->data.d_buf) {
+        goto ERROR;
+      }
+      newscn->data.d_size = newscn->shdr.sh_size;
+      newscn->shdr.sh_type = SHT_PROGBITS;
+    }
+
+    injAddr = elfu_mLayoutGetSpaceInPhdr(me,
+                                         newscn->shdr.sh_size,
+                                         newscn->shdr.sh_addralign,
+                                         newscn->shdr.sh_flags & SHF_WRITE,
+                                         newscn->shdr.sh_flags & SHF_EXECINSTR,
+                                         &injPhdr);
+
+    if (!injPhdr) {
+      ELFU_WARN("insertSection: Could not find a place to insert section.\n");
+      goto ERROR;
+    }
+
+    ELFU_INFO("Inserting %s at address 0x%jx...\n",
+              elfu_mScnName(mrel, oldscn),
+              injAddr);
+
+    injOffset = injAddr - injPhdr->phdr.p_vaddr + injPhdr->phdr.p_offset;
+
+    newscn->shdr.sh_addr = injAddr;
+    newscn->shdr.sh_offset = injOffset;
+
+    if (CIRCLEQ_EMPTY(&injPhdr->childScnList)
+        || CIRCLEQ_LAST(&injPhdr->childScnList)->shdr.sh_offset < injOffset) {
+      CIRCLEQ_INSERT_TAIL(&injPhdr->childScnList, newscn, elemChildScn);
+    } else {
+      ElfuScn *ms;
+      CIRCLEQ_FOREACH(ms, &injPhdr->childScnList, elemChildScn) {
+        if (injOffset < ms->shdr.sh_offset) {
+          CIRCLEQ_INSERT_BEFORE(&injPhdr->childScnList, ms, newscn, elemChildScn);
+          break;
+        }
+      }
+    }
+
+
+    /* Inject name */
+    if (me->shstrtab) {
+      char *newname;
+      size_t newnamelen;
+
+      newnamelen = strlen("reladd") + 1;
+      if (elfu_mScnName(mrel, oldscn)) {
+        newnamelen += strlen(elfu_mScnName(mrel, oldscn));
+      }
+
+      newname = malloc(newnamelen);
+      strcpy(newname, "reladd");
+      strcat(newname, elfu_mScnName(mrel, oldscn));
+
+      if (!newname) {
+        ELFU_WARN("insertSection: malloc() failed for newname. Leaving section name empty.\n");
+        newscn->shdr.sh_name = 0;
+      } else {
+        size_t offset = me->shstrtab->shdr.sh_size;
+
+        if (!appendData(me->shstrtab, newname, newnamelen)) {
+          newscn->shdr.sh_name = offset;
+        }
+
+        free(newname);
+      }
+    }
+
+    return newscn;
+  } else {
+      ELFU_WARN("insertSection: Skipping non-memory section %s (type %d flags %jd).\n",
+                elfu_mScnName(mrel, oldscn),
+                oldscn->shdr.sh_type,
+                oldscn->shdr.sh_flags);
+      goto ERROR;
+  }
+
+  ERROR:
+  if (newscn) {
+    // TODO: Destroy newscn
+  }
+  return NULL;
+}
+
+
+static void* subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
+{
+  (void)aux2;
+  ElfuElf *me = (ElfuElf*)aux1;
+
+  ElfuScn *newscn;
+
+  switch(ms->shdr.sh_type) {
+    case SHT_PROGBITS: /* 1 */
+    case SHT_NOBITS: /* 8 */
+      /* Ignore empty sections */
+      if (ms->shdr.sh_size == 0) {
+        break;
+      }
+
+      /* Find a place where it belongs and shove it in. */
+      newscn = insertSection(me, mrel, ms);
+      if (!newscn) {
+        ELFU_WARN("mReladd: Could not insert section %s (type %d), skipping.\n",
+                  elfu_mScnName(mrel, ms),
+                  ms->shdr.sh_type);
+      }
+      break;
+  }
+
+  return NULL;
+}
+
+
+static void* subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
+{
+  (void)aux2;
+  ElfuElf *me = (ElfuElf*)aux1;
+  (void)me;
+
+  switch(ms->shdr.sh_type) {
+    case SHT_NULL: /* 0 */
+    case SHT_PROGBITS: /* 1 */
+    case SHT_STRTAB: /* 3 */
+    case SHT_NOBITS: /* 8 */
+      break;
+
+
+    case SHT_REL: /* 9 */
+      /* Relocate. */
+      elfu_mRelocate32(me, elfu_mScnByOldscn(me, ms->infoptr), ms);
+      break;
+
+    case SHT_RELA: /* 4 */
+      // TODO: Needs a parser
+      //elfu_mRelocate(elfu_mScnByOldscn(me, ms->infoptr), ms);
+
+    case SHT_SYMTAB: /* 2 */
+      /* Merge with the existing table. Take care of string tables also. */
+
+    /* The next section types either do not occur in .o files, or are
+     * not strictly necessary to process here. */
+    case SHT_NOTE: /* 7 */
+    case SHT_HASH: /* 5 */
+    case SHT_DYNAMIC: /* 6 */
+    case SHT_SHLIB: /* 10 */
+    case SHT_DYNSYM: /* 11 */
+    case SHT_INIT_ARRAY: /* 14 */
+    case SHT_FINI_ARRAY: /* 15 */
+    case SHT_PREINIT_ARRAY: /* 16 */
+    case SHT_GROUP: /* 17 */
+    case SHT_SYMTAB_SHNDX: /* 18 */
+    case SHT_NUM: /* 19 */
+    default:
+      ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
+                elfu_mScnName(mrel, ms),
+                ms->shdr.sh_type);
+  }
+
+  return NULL;
+}
+
+
+void elfu_mReladd(ElfuElf *me, ElfuElf *mrel)
+{
+  assert(me);
+  assert(mrel);
+
+  /* For each section in object file, guess how to insert it */
+  elfu_mScnForall(mrel, subScnAdd1, me, NULL);
+
+  /* Do relocations and other stuff */
+  elfu_mScnForall(mrel, subScnAdd2, me, NULL);
+
+  /* Re-layout to accommodate new contents */
+  elfu_mLayoutAuto(me);
+}
diff --git a/src/modelops/relocate.c b/src/modelops/relocate.c
new file mode 100644 (file)
index 0000000..972bda3
--- /dev/null
@@ -0,0 +1,169 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libelfu/libelfu.h>
+
+
+static void* subFindByName(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+  char *name = (char*)aux1;
+  (void)aux2;
+
+  if (elfu_mScnName(me, ms)) {
+    if (!strcmp(elfu_mScnName(me, ms), name)) {
+      return ms;
+    }
+  }
+
+  /* Continue */
+  return NULL;
+}
+
+/* Hazard a guess where a function may be found in the PLT */
+static GElf_Word pltLookupVal(ElfuElf *metarget, char *name)
+{
+  ElfuScn *relplt;
+  ElfuScn *plt;
+  ElfuRel *rel;
+  GElf_Word j;
+
+  relplt = elfu_mScnForall(metarget, subFindByName, ".rel.plt", NULL);
+  if (!relplt) {
+    ELFU_WARN("dynsymLookupVal: Could not find .rel.plt section in destination ELF.\n");
+    return 0;
+  }
+
+  plt = elfu_mScnForall(metarget, subFindByName, ".plt", NULL);
+  if (!plt) {
+    ELFU_WARN("dynsymLookupVal: Could not find .plt section in destination ELF.\n");
+    return 0;
+  }
+
+
+  /* Look up name */
+  assert(relplt->reltab);
+  assert(relplt->linkptr);
+  assert(relplt->linkptr->symtab);
+  j = 0;
+  CIRCLEQ_FOREACH(rel, &relplt->reltab->rels, elem) {
+    GElf_Word i;
+    ElfuSym *sym;
+
+    j++;
+
+    if (rel->type != R_386_JMP_SLOT) {
+      continue;
+    }
+
+    sym = CIRCLEQ_FIRST(&relplt->linkptr->symtab->syms);
+    for (i = 1; i < rel->sym; i++) {
+      sym = CIRCLEQ_NEXT(sym, elem);
+    }
+
+    if (!sym->name) {
+      continue;
+    }
+
+    if (!strcmp(sym->name, name)) {
+      /* If this is the symbol we are looking for, then in an x86 binary
+       * the jump to the dynamic symbol is probably at offset (j * 16)
+       * from the start of the PLT, where j is the PLT entry and 16 is
+       * the number of bytes the machine code in a PLT entry take. */
+      GElf_Addr addr = plt->shdr.sh_addr + (16 * j);
+      ELFU_DEBUG("dynsymLookupVal: Guessing symbol '%s' is in destination memory at %jx (PLT entry #%d).\n", name, addr, j);
+      return addr;
+    }
+  }
+
+  ELFU_WARN("dynsymLookupVal: Could not find symbol '%s' in destination ELF.\n", name);
+
+  return 0;
+}
+
+
+static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
+{
+  GElf_Word i;
+  ElfuSym *sym;
+
+  assert(metarget);
+  assert(msst);
+  assert(msst->symtab);
+  assert(entry > 0);
+  assert(!CIRCLEQ_EMPTY(&msst->symtab->syms));
+
+  sym = CIRCLEQ_FIRST(&msst->symtab->syms);
+  for (i = 1; i < entry; i++) {
+    sym = CIRCLEQ_NEXT(sym, elem);
+  }
+
+  switch (sym->type) {
+    case STT_NOTYPE:
+    case STT_OBJECT:
+    case STT_FUNC:
+      if (sym->scnptr) {
+        assert(elfu_mScnByOldscn(metarget, sym->scnptr));
+        return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value;
+      } else if (sym->shndx == SHN_UNDEF) {
+        /* Look the symbol up in .dyn.plt. If it cannot be found there then
+         * .rel.dyn may need to be expanded with a COPY relocation so the
+         * dynamic linker fixes up the (TODO). */
+        return pltLookupVal(metarget, sym->name);
+      } else if (sym->shndx == SHN_ABS) {
+        return sym->value;
+      } else {
+        ELFU_WARN("symtabLookupVal: Symbol binding COMMON is not supported, using 0.\n");
+        return 0;
+      }
+      break;
+    case STT_SECTION:
+      assert(sym->scnptr);
+      assert(elfu_mScnByOldscn(metarget, sym->scnptr));
+      return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr;
+    case STT_FILE:
+      ELFU_WARN("symtabLookupVal: Symbol type FILE is not supported, using 0.\n");
+      return 0;
+    default:
+      ELFU_WARN("symtabLookupVal: Unknown symbol type %d for %s.\n", sym->type, sym->name);
+      return 0;
+  }
+}
+
+void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
+{
+  ElfuRel *rel;
+
+  assert(mstarget);
+  assert(msrt);
+
+  ELFU_DEBUG("Relocating in section of type %d size %jx\n",
+             mstarget->shdr.sh_type,
+             mstarget->shdr.sh_size);
+
+  CIRCLEQ_FOREACH(rel, &msrt->reltab->rels, elem) {
+    Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+    Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
+    Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
+    Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
+    Elf32_Word newval = *dest;
+
+    switch(rel->type) {
+      case R_386_NONE:
+        ELFU_DEBUG("Skipping relocation: R_386_NONE");
+        break;
+      case R_386_32:
+        ELFU_DEBUG("Relocation: R_386_32");
+        newval = s + a;
+        break;
+      case R_386_PC32:
+        ELFU_DEBUG("Relocation: R_386_PC32");
+        newval = s + a - p;
+        break;
+
+      default:
+        ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
+    }
+    ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval);
+    *dest = newval;
+  }
+}
diff --git a/src/modelops/section.c b/src/modelops/section.c
new file mode 100644 (file)
index 0000000..a96377c
--- /dev/null
@@ -0,0 +1,193 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <libelfu/libelfu.h>
+
+
+/* Meta-functions */
+
+void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
+{
+  ElfuPhdr *mp;
+  ElfuScn *ms;
+
+  // TODO: Sort PHDRs by offset before interating
+
+  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->data.d_buf) {
+    return NULL;
+  }
+
+  return &((char*)me->shstrtab->data.d_buf)[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)
+{
+  assert(ms1);
+  assert(ms2);
+
+  ElfuScn *s1 = *(ElfuScn**)ms1;
+  ElfuScn *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)
+{
+  assert(me);
+
+  size_t numSecs;
+  ElfuScn **sortedSecs;
+  size_t i;
+
+  /* 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;
+}
diff --git a/src/modelops/toFile.c b/src/modelops/toFile.c
new file mode 100644 (file)
index 0000000..da06f4a
--- /dev/null
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <libelfu/libelfu.h>
+
+
+
+static void modelToPhdrs(ElfuElf *me, Elf *e)
+{
+  ElfuPhdr *mp;
+  size_t i;
+
+  /* Count PHDRs */
+  i = 0;
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    i++;
+  }
+
+  if (!gelf_newphdr(e, i)) {
+    ELFU_WARNELF("gelf_newphdr");
+  }
+
+  /* Copy PHDRs */
+  i = 0;
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (!gelf_update_phdr (e, i, &mp->phdr)) {
+      ELFU_WARNELF("gelf_update_phdr");
+    }
+
+    i++;
+  }
+}
+
+
+
+static void* modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+  (void) me;
+  (void) aux2;
+  Elf *e = (Elf*)aux1;
+  Elf_Scn *scnOut;
+
+  scnOut = elf_newscn(e);
+  if (!scnOut) {
+    ELFU_WARNELF("elf_newscn");
+    return (void*)-1;
+  }
+
+
+  /* SHDR */
+  if (ms->linkptr) {
+    ms->shdr.sh_link = elfu_mScnIndex(me, ms->linkptr);
+  }
+  if (ms->infoptr) {
+    ms->shdr.sh_info = elfu_mScnIndex(me, ms->infoptr);
+  }
+  if (!gelf_update_shdr(scnOut, &ms->shdr)) {
+    ELFU_WARNELF("gelf_update_shdr");
+  }
+
+
+  /* Data */
+  if (ms->data.d_buf) {
+    Elf_Data *dataOut = elf_newdata(scnOut);
+    if (!dataOut) {
+      ELFU_WARNELF("elf_newdata");
+    }
+
+    dataOut->d_align = ms->data.d_align;
+    dataOut->d_buf  = ms->data.d_buf;
+    dataOut->d_off  = ms->data.d_off;
+    dataOut->d_type = ms->data.d_type;
+    dataOut->d_size = ms->data.d_size;
+    dataOut->d_version = ms->data.d_version;
+  }
+
+  return NULL;
+}
+
+
+
+
+
+void elfu_mToElf(ElfuElf *me, Elf *e)
+{
+  /* We control the ELF file's layout now. */
+  /* tired's libelf also offers ELF_F_LAYOUT_OVERLAP for overlapping sections,
+   * but we don't want that since we filtered it out in the reading stage
+   * already. It would be too mind-blowing to handle the dependencies between
+   * the PHDRs and sections then... */
+  elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
+
+
+  /* EHDR */
+  if (!gelf_newehdr(e, me->elfclass)) {
+    ELFU_WARNELF("gelf_newehdr");
+  }
+
+  if (me->shstrtab) {
+    me->ehdr.e_shstrndx = elfu_mScnIndex(me, me->shstrtab);
+  }
+
+  if (!gelf_update_ehdr(e, &me->ehdr)) {
+    ELFU_WARNELF("gelf_update_ehdr");
+  }
+
+
+  /* Sections */
+  elfu_mScnForall(me, modelToSection, e, NULL);
+
+
+  /* PHDRs */
+  modelToPhdrs(me, e);
+
+
+  elf_flagelf(e, ELF_C_SET, ELF_F_DIRTY);
+}