Basic x86-64 support, not very usable in practice
[centaur.git] / src / modelops / fromFile.c
index 23105e60a76f541a4dc251bca53c0dfa4f0a69b1..bc089bfe99a9b427983091daad31474f03a62ed0 100644 (file)
@@ -5,93 +5,81 @@
 #include <libelfu/libelfu.h>
 
 
-static char* symstr(ElfuScn *symtab, size_t off)
+static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
 {
-  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;
+  ElfuSym *sym;
   size_t i;
 
   assert(ms);
   assert(ms->data.d_buf);
   assert(origScnArr);
 
+  /* Parse symbols from their elfclass-specific format */
+  if (me->elfclass == ELFCLASS32) {
+    for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
+      Elf32_Sym *cursym = ((Elf32_Sym*)ms->data.d_buf) + i;
+      ElfuSym *newsym = malloc(sizeof(*sym));
+      assert(newsym);
 
-  st = malloc(sizeof(*st));
-  if (!st) {
-    ELFU_WARN("elfu_mSymtabFromScn32: malloc() failed for st.\n");
-    goto ERROR;
-  }
+      newsym->name = cursym->st_name;
+      newsym->value = cursym->st_value;
+      newsym->size = cursym->st_size;
+      newsym->bind = ELF32_ST_BIND(cursym->st_info);
+      newsym->type = ELF32_ST_TYPE(cursym->st_info);
+      newsym->other = cursym->st_other;
+      newsym->shndx = cursym->st_shndx;
 
-  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);
+      CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
+    }
+  } else if (me->elfclass == ELFCLASS64) {
+    for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) {
+      Elf64_Sym *cursym = ((Elf64_Sym*)ms->data.d_buf) + i;
+      ElfuSym *newsym = malloc(sizeof(*sym));
+      assert(newsym);
+
+      newsym->name = cursym->st_name;
+      newsym->value = cursym->st_value;
+      newsym->size = cursym->st_size;
+      newsym->bind = ELF64_ST_BIND(cursym->st_info);
+      newsym->type = ELF64_ST_TYPE(cursym->st_info);
+      newsym->other = cursym->st_other;
+      newsym->shndx = cursym->st_shndx;
+
 
-    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) {
+      CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
+    }
+  } else {
+    // Unknown elfclass
+    assert(0);
+  }
+
+  /* For each section, find the section it points to if any. */
+  CIRCLEQ_FOREACH(sym, &ms->symtab.syms, elem) {
+    switch (sym->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];
+        sym->scnptr = origScnArr[sym->shndx - 1];
         break;
     }
-
-
-    CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem);
-  }
-
-
-  return st;
-
-  ERROR:
-  if (st) {
-    free(st);
   }
-  return NULL;
 }
 
 
-static ElfuReltab* reltabFromScn32(ElfuScn *ms)
+static void parseReltab32(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;
@@ -100,24 +88,39 @@ static ElfuReltab* reltabFromScn32(ElfuScn *ms)
     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);
+    CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
   }
+}
 
 
-  return rt;
+static void parseRelatab64(ElfuScn *ms)
+{
+  size_t i;
 
-  ERROR:
-  if (rt) {
-    free(rt);
+  assert(ms);
+  assert(ms->data.d_buf);
+
+
+  for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
+    Elf64_Rela *currel = &(((Elf64_Rela*)ms->data.d_buf)[i]);
+    ElfuRel *rel;
+
+    rel = malloc(sizeof(*rel));
+    assert(rel);
+
+    rel->offset = currel->r_offset;
+    rel->sym = ELF64_R_SYM(currel->r_info);
+    rel->type = ELF64_R_TYPE(currel->r_info);
+    rel->addendUsed = 1;
+    rel->addend = currel->r_addend;
+
+    CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
   }
-  return NULL;
 }
 
 
@@ -255,8 +258,8 @@ static ElfuScn* modelFromSection(Elf_Scn *scn)
 
   ms->oldptr = NULL;
 
-  ms->symtab = NULL;
-  ms->reltab = NULL;
+  CIRCLEQ_INIT(&ms->symtab.syms);
+  CIRCLEQ_INIT(&ms->reltab.rels);
 
 
   return ms;
@@ -294,6 +297,7 @@ ElfuElf* elfu_mFromElf(Elf *e)
   CIRCLEQ_INIT(&me->phdrList);
   CIRCLEQ_INIT(&me->orphanScnList);
   me->shstrtab = NULL;
+  me->symtab = NULL;
 
   me->elfclass = gelf_getclass(e);
   assert(me->elfclass != ELFCLASSNONE);
@@ -406,13 +410,9 @@ ElfuElf* elfu_mFromElf(Elf *e)
 
       switch (ms->shdr.sh_type) {
         case SHT_SYMTAB:
+          me->symtab = ms;
         case SHT_DYNSYM:
-          if (me->elfclass == ELFCLASS32) {
-            ms->symtab = symtabFromScn32(ms, secArray);
-          } else if (me->elfclass == ELFCLASS64) {
-            // TODO
-          }
-          assert(ms->symtab);
+          parseSymtab(me, ms, secArray);
           break;
       }
     }
@@ -425,19 +425,17 @@ ElfuElf* elfu_mFromElf(Elf *e)
       switch (ms->shdr.sh_type) {
         case SHT_REL:
           if (me->elfclass == ELFCLASS32) {
-            ms->reltab = reltabFromScn32(ms);
+            parseReltab32(ms);
           } else if (me->elfclass == ELFCLASS64) {
-            // TODO
+            // Not used on x86-64
           }
-          assert(ms->reltab);
           break;
         case SHT_RELA:
           if (me->elfclass == ELFCLASS32) {
             // TODO
           } else if (me->elfclass == ELFCLASS64) {
-            // TODO
+            parseRelatab64(ms);
           }
-          assert(ms->reltab);
           break;
       }
     }