1 /* This file is part of centaur.
3 * centaur is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License 2 as
5 * published by the Free Software Foundation.
7 * centaur is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with centaur. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
20 #include <libelfu/libelfu.h>
23 static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
32 /* Parse symbols from their elfclass-specific format */
33 if (me->elfclass == ELFCLASS32) {
34 for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
35 Elf32_Sym *cursym = ((Elf32_Sym*)ms->databuf) + i;
36 ElfuSym *newsym = malloc(sizeof(*sym));
39 newsym->name = cursym->st_name;
40 newsym->value = cursym->st_value;
41 newsym->size = cursym->st_size;
42 newsym->bind = ELF32_ST_BIND(cursym->st_info);
43 newsym->type = ELF32_ST_TYPE(cursym->st_info);
44 newsym->other = cursym->st_other;
45 newsym->shndx = cursym->st_shndx;
47 CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
49 } else if (me->elfclass == ELFCLASS64) {
50 for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) {
51 Elf64_Sym *cursym = ((Elf64_Sym*)ms->databuf) + i;
52 ElfuSym *newsym = malloc(sizeof(*sym));
55 newsym->name = cursym->st_name;
56 newsym->value = cursym->st_value;
57 newsym->size = cursym->st_size;
58 newsym->bind = ELF64_ST_BIND(cursym->st_info);
59 newsym->type = ELF64_ST_TYPE(cursym->st_info);
60 newsym->other = cursym->st_other;
61 newsym->shndx = cursym->st_shndx;
63 CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
66 /* Unknown elfclass */
70 /* For each section, find the section it points to if any. */
71 CIRCLEQ_FOREACH(sym, &ms->symtab.syms, elem) {
79 sym->scnptr = origScnArr[sym->shndx - 1];
86 static void parseReltab(ElfuElf *me, ElfuScn *ms)
93 if (me->elfclass == ELFCLASS32) {
94 for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
95 Elf32_Rel *currel = &(((Elf32_Rel*)ms->databuf)[i]);
98 rel = malloc(sizeof(*rel));
101 rel->offset = currel->r_offset;
102 rel->sym = ELF32_R_SYM(currel->r_info);
103 rel->type = ELF32_R_TYPE(currel->r_info);
107 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
109 } else if (me->elfclass == ELFCLASS64) {
110 for (i = 0; (i + 1) * sizeof(Elf64_Rel) <= ms->shdr.sh_size; i++) {
111 Elf64_Rel *currel = &(((Elf64_Rel*)ms->databuf)[i]);
114 rel = malloc(sizeof(*rel));
117 rel->offset = currel->r_offset;
118 rel->sym = ELF64_R_SYM(currel->r_info);
119 rel->type = ELF64_R_TYPE(currel->r_info);
123 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
126 /* Unknown elfclass */
132 static void parseRelatab(ElfuElf *me, ElfuScn *ms)
139 if (me->elfclass == ELFCLASS32) {
140 for (i = 0; (i + 1) * sizeof(Elf32_Rela) <= ms->shdr.sh_size; i++) {
141 Elf32_Rela *currel = &(((Elf32_Rela*)ms->databuf)[i]);
144 rel = malloc(sizeof(*rel));
147 rel->offset = currel->r_offset;
148 rel->sym = ELF32_R_SYM(currel->r_info);
149 rel->type = ELF32_R_TYPE(currel->r_info);
151 rel->addend = currel->r_addend;
153 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
155 } else if (me->elfclass == ELFCLASS64) {
156 for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
157 Elf64_Rela *currel = &(((Elf64_Rela*)ms->databuf)[i]);
160 rel = malloc(sizeof(*rel));
163 rel->offset = currel->r_offset;
164 rel->sym = ELF64_R_SYM(currel->r_info);
165 rel->type = ELF64_R_TYPE(currel->r_info);
167 rel->addend = currel->r_addend;
169 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
172 /* Unknown elfclass */
178 static int cmpScnOffs(const void *ms1, const void *ms2)
180 ElfuScn *s1 = *(ElfuScn**)ms1;
181 ElfuScn *s2 = *(ElfuScn**)ms2;
186 s1 = *(ElfuScn**)ms1;
187 s2 = *(ElfuScn**)ms2;
193 if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
195 } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
197 } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
204 static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
211 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
212 if (mp->phdr.p_type != PT_LOAD) {
216 if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
225 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
231 mp = elfu_mPhdrAlloc();
242 static ElfuScn* modelFromSection(Elf_Scn *scn)
248 ms = elfu_mScnAlloc();
254 assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
256 /* Copy each data part in source segment */
257 if (SCNFILESIZE(&ms->shdr) > 0) {
260 ms->databuf = malloc(ms->shdr.sh_size);
262 ELFU_WARN("modelFromSection: malloc() failed for data buffer (%x bytes).\n", (unsigned)ms->shdr.sh_size);
266 /* A non-empty section should contain at least one data block. */
267 data = elf_rawdata(scn, NULL);
271 if (data->d_off + data->d_size > ms->shdr.sh_size) {
272 ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
274 memcpy((char*)ms->databuf + data->d_off, data->d_buf, data->d_size);
277 data = elf_rawdata(scn, data);
293 ElfuElf* elfu_mFromElf(Elf *e)
297 size_t i, numPhdr, numShdr;
298 ElfuScn **secArray = NULL;
301 if (elfu_eCheck(e)) {
305 me = elfu_mElfAlloc();
310 me->elfclass = gelf_getclass(e);
311 assert(me->elfclass != ELFCLASSNONE);
312 assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
315 /* Get the section string table index */
316 if (elf_getshdrstrndx(e, &shstrndx) != 0) {
322 assert(!elf_getphdrnum(e, &numPhdr));
323 for (i = 0; i < numPhdr; i++) {
327 assert(gelf_getphdr(e, i, &phdr) == &phdr);
329 mp = modelFromPhdr(&phdr);
334 CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
340 /* Find PHDR -> PHDR dependencies (needs sorted sections) */
341 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
344 if (mp->phdr.p_type != PT_LOAD) {
348 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
353 if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
354 && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
355 /* Remove from the main list so only LOADs remain there */
356 CIRCLEQ_REMOVE(&me->phdrList, mp2, elem);
357 CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
365 assert(!elf_getshdrnum(e, &numShdr));
367 secArray = malloc((numShdr - 1) * sizeof(*secArray));
369 ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
373 for (i = 1; i < numShdr; i++) {
377 scn = elf_getscn(e, i);
380 ms = modelFromSection(scn);
393 /* Find sh_link and sh_info dependencies (needs sections in original order) */
394 for (i = 0; i < numShdr - 1; i++) {
395 ElfuScn *ms = secArray[i];
397 switch (ms->shdr.sh_type) {
400 if (ms->shdr.sh_info > 0) {
401 ms->infoptr = secArray[ms->shdr.sh_info - 1];
409 case SHT_GNU_verneed:
410 if (ms->shdr.sh_link > 0) {
411 ms->linkptr = secArray[ms->shdr.sh_link - 1];
417 /* Parse symtabs (needs sections in original order) */
418 for (i = 0; i < numShdr - 1; i++) {
419 ElfuScn *ms = secArray[i];
421 switch (ms->shdr.sh_type) {
425 parseSymtab(me, ms, secArray);
431 /* Parse relocations (needs sections in original order) */
432 for (i = 0; i < numShdr - 1; i++) {
433 ElfuScn *ms = secArray[i];
435 switch (ms->shdr.sh_type) {
440 parseRelatab(me, ms);
446 /* Sort sections by file offset */
447 qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
450 /* Find PHDR -> Section dependencies (needs sorted sections) */
451 for (i = 0; i < numShdr - 1; i++) {
452 ElfuScn *ms = secArray[i];
454 ElfuPhdr *parent = parentPhdr(me, ms);
457 GElf_Off shaddr = parent->phdr.p_vaddr +
458 (ms->shdr.sh_offset - parent->phdr.p_offset);
460 if (ms->shdr.sh_addr == 0) {
461 ms->shdr.sh_addr = shaddr;
463 if (ms->shdr.sh_type != SHT_NOBITS) {
464 assert(ms->shdr.sh_addr == shaddr);
465 } else if (ms->shdr.sh_addr > shaddr) {
466 parent->phdr.p_filesz = MAX(parent->phdr.p_filesz,
467 ms->shdr.sh_addr - parent->phdr.p_vaddr);
471 CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
473 CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
489 elfu_mElfDestroy(me);
492 ELFU_WARN("elfu_mFromElf: Failed to load file.\n");