57cb51971bb84016e08ad07202b23a0657330db9
[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   assert(e);
98   if (elfu_eCheck(e)) {
99     goto ERROR;
100   }
101
102   /* Get the section string table index */
103   if (elf_getshdrstrndx(e, &shstrndx) != 0) {
104     shstrndx = 0;
105   }
106
107   me = malloc(sizeof(ElfuElf));
108   if (!me) {
109     return NULL;
110   }
111
112   CIRCLEQ_INIT(&me->scnList);
113   CIRCLEQ_INIT(&me->phdrList);
114   me->shstrtab = NULL;
115
116   /*
117    * General stuff
118    */
119   me->elfclass = gelf_getclass(e);
120   if (me->elfclass == ELFCLASSNONE) {
121     ELFU_WARNELF("getclass");
122   }
123
124   if (!gelf_getehdr(e, &me->ehdr)) {
125     ELFU_WARNELF("gelf_getehdr");
126     goto ERROR;
127   }
128
129
130   /*
131    * Sections
132    */
133   scn = elf_getscn(e, 1);
134   i = 1;
135   while (scn) {
136     ElfuScn *ms = modelFromSection(scn);
137
138     if (ms) {
139       CIRCLEQ_INSERT_TAIL(&me->scnList, ms, elem);
140       if (i == shstrndx) {
141         me->shstrtab = ms;
142       }
143     } else {
144       goto ERROR;
145     }
146
147     scn = elf_nextscn(e, scn);
148     i++;
149   }
150
151
152
153   /*
154    * Segments
155    */
156   if (elf_getphdrnum(e, &n)) {
157     ELFU_WARNELF("elf_getphdrnum");
158   }
159
160   for (i = 0; i < n; i++) {
161     GElf_Phdr phdr;
162     ElfuPhdr *mp;
163
164     if (gelf_getphdr(e, i, &phdr) != &phdr) {
165       ELFU_WARN("gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1));
166       break;
167     }
168
169     mp = modelFromPhdr(&phdr);
170
171     if (mp) {
172       CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
173     } else {
174       goto ERROR;
175     }
176   }
177
178   return me;
179
180
181   ERROR:
182   // TODO: Free data structures
183
184   ELFU_WARN("elfu_mFromElf: Failed to load file.\n");
185   return NULL;
186 }