Extend relocation parser to full 32/64 bits
[centaur.git] / src / libelfu / modelops / fromFile.c
index dd8b46222b5654b0220b631f491249188d30db5e..9671b5fc0f402858ef3f53bb58ffa5ef6637dae0 100644 (file)
@@ -11,13 +11,13 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
   size_t i;
 
   assert(ms);
-  assert(ms->data.d_buf);
+  assert(ms->databuf);
   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;
+      Elf32_Sym *cursym = ((Elf32_Sym*)ms->databuf) + i;
       ElfuSym *newsym = malloc(sizeof(*sym));
       assert(newsym);
 
@@ -29,13 +29,11 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
       newsym->other = cursym->st_other;
       newsym->shndx = cursym->st_shndx;
 
-
-
       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;
+      Elf64_Sym *cursym = ((Elf64_Sym*)ms->databuf) + i;
       ElfuSym *newsym = malloc(sizeof(*sym));
       assert(newsym);
 
@@ -47,8 +45,6 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
       newsym->other = cursym->st_other;
       newsym->shndx = cursym->st_shndx;
 
-
-
       CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
     }
   } else {
@@ -72,54 +68,94 @@ static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
 }
 
 
-static void parseReltab32(ElfuScn *ms)
+static void parseReltab(ElfuElf *me, ElfuScn *ms)
 {
   size_t i;
 
   assert(ms);
-  assert(ms->data.d_buf);
+  assert(ms->databuf);
 
+  if (me->elfclass == ELFCLASS32) {
+    for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
+      Elf32_Rel *currel = &(((Elf32_Rel*)ms->databuf)[i]);
+      ElfuRel *rel;
 
-  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(&ms->reltab.rels, rel, elem);
+    }
+  } else if (me->elfclass == ELFCLASS64) {
+    for (i = 0; (i + 1) * sizeof(Elf64_Rel) <= ms->shdr.sh_size; i++) {
+      Elf64_Rel *currel = &(((Elf64_Rel*)ms->databuf)[i]);
+      ElfuRel *rel;
 
-    rel = malloc(sizeof(*rel));
-    assert(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;
+      rel->offset = currel->r_offset;
+      rel->sym = ELF64_R_SYM(currel->r_info);
+      rel->type = ELF64_R_TYPE(currel->r_info);
+      rel->addendUsed = 0;
+      rel->addend = 0;
 
-    CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
+      CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
+    }
+  } else {
+    /* Unknown elfclass */
+    assert(0);
   }
 }
 
 
-static void parseRelatab64(ElfuScn *ms)
+static void parseRelatab(ElfuElf *me, ElfuScn *ms)
 {
   size_t i;
 
   assert(ms);
-  assert(ms->data.d_buf);
+  assert(ms->databuf);
 
+  if (me->elfclass == ELFCLASS32) {
+    for (i = 0; (i + 1) * sizeof(Elf32_Rela) <= ms->shdr.sh_size; i++) {
+      Elf32_Rela *currel = &(((Elf32_Rela*)ms->databuf)[i]);
+      ElfuRel *rel;
+
+      rel = malloc(sizeof(*rel));
+      assert(rel);
 
-  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->offset = currel->r_offset;
+      rel->sym = ELF32_R_SYM(currel->r_info);
+      rel->type = ELF32_R_TYPE(currel->r_info);
+      rel->addendUsed = 1;
+      rel->addend = currel->r_addend;
+
+      CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
+    }
+  } else if (me->elfclass == ELFCLASS64) {
+    for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
+      Elf64_Rela *currel = &(((Elf64_Rela*)ms->databuf)[i]);
+      ElfuRel *rel;
 
-    rel = malloc(sizeof(*rel));
-    assert(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;
+      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);
+      CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
+    }
+  } else {
+    /* Unknown elfclass */
+    assert(0);
   }
 }
 
@@ -165,18 +201,6 @@ static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
     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;
@@ -189,17 +213,13 @@ static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
 
   assert(phdr);
 
-  mp = malloc(sizeof(ElfuPhdr));
+  mp = elfu_mPhdrAlloc();
   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;
 }
 
@@ -210,29 +230,20 @@ static ElfuScn* modelFromSection(Elf_Scn *scn)
 
   assert(scn);
 
-  ms = malloc(sizeof(ElfuScn));
+  ms = elfu_mScnAlloc();
   if (!ms) {
-    ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
     goto ERROR;
   }
 
-
+  /* Copy SHDR */
   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) {
+  if (SCNFILESIZE(&ms->shdr) > 0) {
     Elf_Data *data;
 
-    ms->data.d_buf = malloc(ms->shdr.sh_size);
-    if (!ms->data.d_buf) {
+    ms->databuf = malloc(ms->shdr.sh_size);
+    if (!ms->databuf) {
       ELFU_WARN("modelFromSection: malloc() failed for data buffer (%x bytes).\n", (unsigned)ms->shdr.sh_size);
       goto ERROR;
     }
@@ -241,30 +252,20 @@ static ElfuScn* modelFromSection(Elf_Scn *scn)
     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;
+    /* elf_rawdata() always returns ELF_T_BYTE */
+    assert(data->d_type == ELF_T_BYTE);
 
     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((char*)ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
+        memcpy((char*)ms->databuf + data->d_off, data->d_buf, data->d_size);
       }
 
       data = elf_rawdata(scn, data);
     }
   }
 
-  ms->linkptr = NULL;
-  ms->infoptr = NULL;
-
-  ms->oldptr = NULL;
-
-  CIRCLEQ_INIT(&ms->symtab.syms);
-  CIRCLEQ_INIT(&ms->reltab.rels);
-
-
   return ms;
 
   ERROR:
@@ -421,26 +422,16 @@ ElfuElf* elfu_mFromElf(Elf *e)
     }
 
 
-    /* Parse relocations */
+    /* Parse relocations (needs sections in original order) */
     for (i = 0; i < numShdr - 1; i++) {
       ElfuScn *ms = secArray[i];
 
       switch (ms->shdr.sh_type) {
         case SHT_REL:
-          if (me->elfclass == ELFCLASS32) {
-            parseReltab32(ms);
-          } else if (me->elfclass == ELFCLASS64) {
-            /* Not used on x86-64 */
-            assert(0);
-          }
+          parseReltab(me, ms);
           break;
         case SHT_RELA:
-          if (me->elfclass == ELFCLASS32) {
-            /* Not used on x86-32 */
-            assert(0);
-          } else if (me->elfclass == ELFCLASS64) {
-            parseRelatab64(ms);
-          }
+          parseRelatab(me, ms);
           break;
       }
     }