Clean up loader code
[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   assert(phdr);
15
16   mp = malloc(sizeof(ElfuPhdr));
17   if (!mp) {
18     ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
19     return NULL;
20   }
21
22   mp->phdr = *phdr;
23
24   return mp;
25 }
26
27
28 static ElfuScn* modelFromSection(Elf_Scn *scn)
29 {
30   ElfuScn *ms;
31
32   assert(scn);
33
34   ms = malloc(sizeof(ElfuScn));
35   if (!ms) {
36     ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
37     goto ERROR;
38   }
39
40
41   assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
42
43
44   /* Copy each data part in source segment */
45   ms->data.d_align = 1;
46   ms->data.d_buf  = NULL;
47   ms->data.d_off  = 0;
48   ms->data.d_type = ELF_T_BYTE;
49   ms->data.d_size = ms->shdr.sh_size;
50   ms->data.d_version = elf_version(EV_NONE);
51   if (ms->shdr.sh_type != SHT_NOBITS
52       && ms->shdr.sh_size > 0) {
53     Elf_Data *data;
54
55     ms->data.d_buf = malloc(ms->shdr.sh_size);
56     if (!ms->data.d_buf) {
57       ELFU_WARN("modelFromSection: malloc() failed for data buffer (%jx bytes).\n", ms->shdr.sh_size);
58       goto ERROR;
59     }
60
61     /* A non-empty section should contain at least one data block. */
62     data = elf_rawdata(scn, NULL);
63     assert(data);
64
65     ms->data.d_align = data->d_align;
66     ms->data.d_type = data->d_type;
67     ms->data.d_version = data->d_version;
68
69     while (data) {
70       if (data->d_off + data->d_size > ms->shdr.sh_size) {
71         ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
72       } else {
73         memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
74       }
75
76       data = elf_rawdata(scn, data);
77     }
78   }
79
80
81   return ms;
82
83   ERROR:
84   if (ms) {
85     free(ms);
86   }
87   return NULL;
88 }
89
90
91
92
93 ElfuElf* elfu_mFromElf(Elf *e)
94 {
95   ElfuElf *me;
96   size_t shstrndx;
97   size_t i, numPhdr, numShdr;
98
99   assert(e);
100   if (elfu_eCheck(e)) {
101     goto ERROR;
102   }
103
104   me = malloc(sizeof(ElfuElf));
105   if (!me) {
106     ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
107     goto ERROR;
108   }
109
110
111   /* General stuff */
112   CIRCLEQ_INIT(&me->scnList);
113   CIRCLEQ_INIT(&me->phdrList);
114   me->shstrtab = NULL;
115
116   me->elfclass = gelf_getclass(e);
117   assert(me->elfclass != ELFCLASSNONE);
118   assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
119
120
121   /* Get the section string table index */
122   if (elf_getshdrstrndx(e, &shstrndx) != 0) {
123     shstrndx = 0;
124   }
125
126
127   /* Load segments */
128   assert(!elf_getphdrnum(e, &numPhdr));
129   for (i = 0; i < numPhdr; i++) {
130     GElf_Phdr phdr;
131     ElfuPhdr *mp;
132
133     assert(gelf_getphdr(e, i, &phdr) == &phdr);
134
135     mp = modelFromPhdr(&phdr);
136     if (!mp) {
137       goto ERROR;
138     }
139
140     CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
141   }
142
143
144   /* Load sections */
145   assert(!elf_getshdrnum(e, &numShdr));
146   for (i = 1; i < numShdr; i++) {
147     Elf_Scn *scn;
148     ElfuScn *ms;
149
150     scn = elf_getscn(e, i);
151     assert(scn);
152
153     ms = modelFromSection(scn);
154     if (!ms) {
155       goto ERROR;
156     }
157
158     CIRCLEQ_INSERT_TAIL(&me->scnList, ms, elem);
159     if (i == shstrndx) {
160       me->shstrtab = ms;
161     }
162   }
163
164
165   /* Find sh_link dependencies */
166
167
168   /* Sort sections by offset */
169
170
171   /* Find PHDR -> Section dependencies */
172
173
174
175   return me;
176
177
178   ERROR:
179   if (me) {
180     // TODO: Free data structures
181   }
182
183   ELFU_WARN("elfu_mFromElf: Failed to load file.\n");
184   return NULL;
185 }