Cleaner error handling with ELFU_WARN and ELFU_WARNELF
[centaur.git] / src / model / fromFile.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <libelf/libelf.h>
6 #include <libelf/gelf.h>
7 #include <libelfu/libelfu.h>
8
9
10 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
11 {
12   ElfuPhdr *mp;
13
14   mp = malloc(sizeof(ElfuPhdr));
15   if (!mp) {
16     return NULL;
17   }
18
19   mp->phdr = *phdr;
20
21   return mp;
22 }
23
24
25 static ElfuScn* modelFromSection(Elf_Scn *scn)
26 {
27   ElfuScn *ms;
28
29
30   ms = malloc(sizeof(ElfuScn));
31   if (!ms) {
32     return NULL;
33   }
34
35
36   if (gelf_getshdr(scn, &ms->shdr) != &ms->shdr) {
37     ELFU_WARN("gelf_getshdr() failed: %s\n", elf_errmsg(-1));
38     goto out;
39   }
40
41
42   /* Copy each data part in source segment */
43   ms->data.d_align = 1;
44   ms->data.d_buf  = NULL;
45   ms->data.d_off  = 0;
46   ms->data.d_type = ELF_T_BYTE;
47   ms->data.d_size = ms->shdr.sh_size;
48   ms->data.d_version = elf_version(EV_NONE);
49   if (ms->shdr.sh_type != SHT_NOBITS
50       && ms->shdr.sh_size > 1) {
51     Elf_Data *data;
52
53     ms->data.d_buf = malloc(ms->shdr.sh_size);
54     if (!ms->data.d_buf) {
55       ELFU_WARN("modelFromSection: Could not allocate data buffer (%jx bytes).\n", ms->shdr.sh_size);
56       goto out;
57     }
58
59     /* A non-empty section should contain at least on data block. */
60     data = elf_rawdata(scn, NULL);
61
62     assert(data);
63
64     ms->data.d_align = data->d_align;
65     ms->data.d_type = data->d_type;
66     ms->data.d_version = data->d_version;
67
68     while (data) {
69       if (data->d_off + data->d_size > ms->shdr.sh_size) {
70         ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
71       } else {
72         memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
73       }
74
75       data = elf_rawdata(scn, data);
76     }
77   }
78
79
80   return ms;
81
82   out:
83   // FIXME
84   return NULL;
85 }
86
87
88
89
90 ElfuElf* elfu_mFromElf(Elf *e)
91 {
92   ElfuElf *me;
93   Elf_Scn *scn;
94   size_t shstrndx;
95   size_t i, n;
96
97   if (elf_getshdrstrndx(e, &shstrndx) != 0) {
98     shstrndx = 0;
99   }
100
101   me = malloc(sizeof(ElfuElf));
102   if (!me) {
103     return NULL;
104   }
105
106   CIRCLEQ_INIT(&me->scnList);
107   CIRCLEQ_INIT(&me->phdrList);
108   me->shstrtab = NULL;
109
110   /*
111    * General stuff
112    */
113   me->elfclass = gelf_getclass(e);
114   if (me->elfclass == ELFCLASSNONE) {
115     ELFU_WARNELF("getclass");
116   }
117
118   if (!gelf_getehdr(e, &me->ehdr)) {
119     ELFU_WARNELF("gelf_getehdr");
120     goto out;
121   }
122
123
124   /*
125    * Sections
126    */
127   scn = elf_getscn(e, 1);
128   i = 1;
129   while (scn) {
130     ElfuScn *ms = modelFromSection(scn);
131
132     if (ms) {
133       CIRCLEQ_INSERT_TAIL(&me->scnList, ms, elem);
134       if (i == shstrndx) {
135         me->shstrtab = ms;
136       }
137     } else {
138       goto out;
139     }
140
141     scn = elf_nextscn(e, scn);
142     i++;
143   }
144
145
146
147   /*
148    * Segments
149    */
150   if (elf_getphdrnum(e, &n)) {
151     ELFU_WARNELF("elf_getphdrnum");
152   }
153
154   for (i = 0; i < n; i++) {
155     GElf_Phdr phdr;
156     ElfuPhdr *mp;
157
158     if (gelf_getphdr(e, i, &phdr) != &phdr) {
159       ELFU_WARN("gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1));
160       break;
161     }
162
163     mp = modelFromPhdr(&phdr);
164
165     if (mp) {
166       CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
167     } else {
168       goto out;
169     }
170   }
171
172
173
174   return me;
175
176   out:
177   // FIXME
178   return NULL;
179 }