Cleaner error handling with ELFU_WARN and ELFU_WARNELF
[centaur.git] / src / model / fromFile.c
index f349335751900d03f56e48161137784bd5512541..fee6ec03fabd4cc08ddef6572757c42d821c7bed 100644 (file)
@@ -1,13 +1,13 @@
-#include <stdio.h>
+#include <assert.h>
 #include <stdlib.h>
-
-#include <libelf.h>
-#include <gelf.h>
-
+#include <string.h>
+#include <sys/types.h>
+#include <libelf/libelf.h>
+#include <libelf/gelf.h>
 #include <libelfu/libelfu.h>
 
 
-ElfuPhdr* elfu_modelFromPhdr(GElf_Phdr *phdr)
+static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
 {
   ElfuPhdr *mp;
 
@@ -22,43 +22,61 @@ ElfuPhdr* elfu_modelFromPhdr(GElf_Phdr *phdr)
 }
 
 
-ElfuScn* elfu_modelFromSection(Elf_Scn *scn)
+static ElfuScn* modelFromSection(Elf_Scn *scn)
 {
   ElfuScn *ms;
-  Elf_Data *data;
+
 
   ms = malloc(sizeof(ElfuScn));
   if (!ms) {
     return NULL;
   }
 
-  CIRCLEQ_INIT(&ms->dataList);
-
 
   if (gelf_getshdr(scn, &ms->shdr) != &ms->shdr) {
-    fprintf(stderr, "gelf_getshdr() failed: %s\n", elf_errmsg(-1));
+    ELFU_WARN("gelf_getshdr() failed: %s\n", elf_errmsg(-1));
     goto out;
   }
 
 
-
   /* Copy each data part in source segment */
-  data = elf_rawdata(scn, NULL);
-  while (data) {
-    ElfuData *md;
-
-    md = malloc(sizeof(ElfuData));
-    if (!md) {
+  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 > 1) {
+    Elf_Data *data;
+
+    ms->data.d_buf = malloc(ms->shdr.sh_size);
+    if (!ms->data.d_buf) {
+      ELFU_WARN("modelFromSection: Could not allocate data buffer (%jx bytes).\n", ms->shdr.sh_size);
       goto out;
     }
 
-    md->data = *data;
+    /* A non-empty section should contain at least on data block. */
+    data = elf_rawdata(scn, NULL);
+
+    assert(data);
 
-    CIRCLEQ_INSERT_TAIL(&ms->dataList, md, elem);
+    ms->data.d_align = data->d_align;
+    ms->data.d_type = data->d_type;
+    ms->data.d_version = data->d_version;
 
-    data = elf_rawdata(scn, data);
+    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);
+    }
   }
 
+
   return ms;
 
   out:
@@ -69,9 +87,16 @@ ElfuScn* elfu_modelFromSection(Elf_Scn *scn)
 
 
 
-ElfuElf* elfu_modelFromElf(Elf *e)
+ElfuElf* elfu_mFromElf(Elf *e)
 {
   ElfuElf *me;
+  Elf_Scn *scn;
+  size_t shstrndx;
+  size_t i, n;
+
+  if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+    shstrndx = 0;
+  }
 
   me = malloc(sizeof(ElfuElf));
   if (!me) {
@@ -80,17 +105,18 @@ ElfuElf* elfu_modelFromElf(Elf *e)
 
   CIRCLEQ_INIT(&me->scnList);
   CIRCLEQ_INIT(&me->phdrList);
+  me->shstrtab = NULL;
 
   /*
    * General stuff
    */
   me->elfclass = gelf_getclass(e);
   if (me->elfclass == ELFCLASSNONE) {
-    fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1));
+    ELFU_WARNELF("getclass");
   }
 
   if (!gelf_getehdr(e, &me->ehdr)) {
-    fprintf(stderr, "gelf_getehdr() failed: %s\n", elf_errmsg(-1));
+    ELFU_WARNELF("gelf_getehdr");
     goto out;
   }
 
@@ -98,19 +124,22 @@ ElfuElf* elfu_modelFromElf(Elf *e)
   /*
    * Sections
    */
-  Elf_Scn *scn;
-
   scn = elf_getscn(e, 1);
+  i = 1;
   while (scn) {
-    ElfuScn *ms = elfu_modelFromSection(scn);
+    ElfuScn *ms = modelFromSection(scn);
 
     if (ms) {
       CIRCLEQ_INSERT_TAIL(&me->scnList, ms, elem);
+      if (i == shstrndx) {
+        me->shstrtab = ms;
+      }
     } else {
       goto out;
     }
 
     scn = elf_nextscn(e, scn);
+    i++;
   }
 
 
@@ -118,10 +147,8 @@ ElfuElf* elfu_modelFromElf(Elf *e)
   /*
    * Segments
    */
-  size_t i, n;
-
   if (elf_getphdrnum(e, &n)) {
-    fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1));
+    ELFU_WARNELF("elf_getphdrnum");
   }
 
   for (i = 0; i < n; i++) {
@@ -129,11 +156,11 @@ ElfuElf* elfu_modelFromElf(Elf *e)
     ElfuPhdr *mp;
 
     if (gelf_getphdr(e, i, &phdr) != &phdr) {
-      fprintf(stderr, "gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1));
+      ELFU_WARN("gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1));
       break;
     }
 
-    mp = elfu_modelFromPhdr(&phdr);
+    mp = modelFromPhdr(&phdr);
 
     if (mp) {
       CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);