5 #include <libelf/libelf.h>
6 #include <libelf/gelf.h>
7 #include <libelfu/libelfu.h>
10 static int cmpScnOffs(const void *ms1, const void *ms2)
15 ElfuScn *s1 = *(ElfuScn**)ms1;
16 ElfuScn *s2 = *(ElfuScn**)ms2;
22 if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
24 } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
26 } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
33 static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
40 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
41 if (mp->phdr.p_type != PT_LOAD) {
45 if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
49 /* Give sections a second chance if they do not have any sh_addr
51 /* Actually we don't, because it's ambiguous.
52 * Re-enable for experiments with strangely-formatted files.
53 if (ms->shdr.sh_addr == 0
54 && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
55 && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
56 <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
66 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
72 mp = malloc(sizeof(ElfuPhdr));
74 ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
80 CIRCLEQ_INIT(&mp->childScnList);
81 CIRCLEQ_INIT(&mp->childPhdrList);
87 static ElfuScn* modelFromSection(Elf_Scn *scn)
93 ms = malloc(sizeof(ElfuScn));
95 ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
100 assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
103 /* Copy each data part in source segment */
104 ms->data.d_align = 1;
105 ms->data.d_buf = NULL;
107 ms->data.d_type = ELF_T_BYTE;
108 ms->data.d_size = ms->shdr.sh_size;
109 ms->data.d_version = elf_version(EV_NONE);
110 if (ms->shdr.sh_type != SHT_NOBITS
111 && ms->shdr.sh_size > 0) {
114 ms->data.d_buf = malloc(ms->shdr.sh_size);
115 if (!ms->data.d_buf) {
116 ELFU_WARN("modelFromSection: malloc() failed for data buffer (%jx bytes).\n", ms->shdr.sh_size);
120 /* A non-empty section should contain at least one data block. */
121 data = elf_rawdata(scn, NULL);
124 ms->data.d_align = data->d_align;
125 ms->data.d_type = data->d_type;
126 ms->data.d_version = data->d_version;
129 if (data->d_off + data->d_size > ms->shdr.sh_size) {
130 ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
132 memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
135 data = elf_rawdata(scn, data);
157 ElfuElf* elfu_mFromElf(Elf *e)
161 size_t i, numPhdr, numShdr;
162 ElfuScn **secArray = NULL;
165 if (elfu_eCheck(e)) {
169 me = malloc(sizeof(ElfuElf));
171 ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
177 CIRCLEQ_INIT(&me->phdrList);
178 CIRCLEQ_INIT(&me->orphanScnList);
181 me->elfclass = gelf_getclass(e);
182 assert(me->elfclass != ELFCLASSNONE);
183 assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
186 /* Get the section string table index */
187 if (elf_getshdrstrndx(e, &shstrndx) != 0) {
193 assert(!elf_getphdrnum(e, &numPhdr));
194 for (i = 0; i < numPhdr; i++) {
198 assert(gelf_getphdr(e, i, &phdr) == &phdr);
200 mp = modelFromPhdr(&phdr);
205 CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
211 /* Find PHDR -> PHDR dependencies (needs sorted sections) */
212 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
215 if (mp->phdr.p_type != PT_LOAD) {
219 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
224 if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
225 && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
226 CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
234 assert(!elf_getshdrnum(e, &numShdr));
236 secArray = malloc((numShdr - 1) * sizeof(*secArray));
238 ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
242 for (i = 1; i < numShdr; i++) {
246 scn = elf_getscn(e, i);
249 ms = modelFromSection(scn);
262 /* Find sh_link dependencies */
263 for (i = 0; i < numShdr - 1; i++) {
264 ElfuScn *ms = secArray[i];
266 switch (ms->shdr.sh_type) {
269 if (ms->shdr.sh_info > 0) {
270 ms->infoptr = secArray[ms->shdr.sh_info - 1];
278 case SHT_GNU_verneed:
279 if (ms->shdr.sh_link > 0) {
280 ms->linkptr = secArray[ms->shdr.sh_link - 1];
286 /* Sort sections by file offset */
287 qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
290 /* Find PHDR -> Section dependencies (needs sorted sections) */
291 for (i = 0; i < numShdr - 1; i++) {
292 ElfuScn *ms = secArray[i];
294 ElfuPhdr *parent = parentPhdr(me, ms);
297 GElf_Off shaddr = parent->phdr.p_vaddr +
298 (ms->shdr.sh_offset - parent->phdr.p_offset);
300 if (ms->shdr.sh_addr == 0) {
301 ms->shdr.sh_addr = shaddr;
303 assert(ms->shdr.sh_addr == shaddr);
306 CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
308 CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
322 // TODO: Free data structures
325 ELFU_WARN("elfu_mFromElf: Failed to load file.\n");