5 #include <libelfu/libelfu.h>
8 static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
17 /* Parse symbols from their elfclass-specific format */
18 if (me->elfclass == ELFCLASS32) {
19 for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
20 Elf32_Sym *cursym = ((Elf32_Sym*)ms->databuf) + i;
21 ElfuSym *newsym = malloc(sizeof(*sym));
24 newsym->name = cursym->st_name;
25 newsym->value = cursym->st_value;
26 newsym->size = cursym->st_size;
27 newsym->bind = ELF32_ST_BIND(cursym->st_info);
28 newsym->type = ELF32_ST_TYPE(cursym->st_info);
29 newsym->other = cursym->st_other;
30 newsym->shndx = cursym->st_shndx;
32 CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
34 } else if (me->elfclass == ELFCLASS64) {
35 for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) {
36 Elf64_Sym *cursym = ((Elf64_Sym*)ms->databuf) + i;
37 ElfuSym *newsym = malloc(sizeof(*sym));
40 newsym->name = cursym->st_name;
41 newsym->value = cursym->st_value;
42 newsym->size = cursym->st_size;
43 newsym->bind = ELF64_ST_BIND(cursym->st_info);
44 newsym->type = ELF64_ST_TYPE(cursym->st_info);
45 newsym->other = cursym->st_other;
46 newsym->shndx = cursym->st_shndx;
48 CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
51 /* Unknown elfclass */
55 /* For each section, find the section it points to if any. */
56 CIRCLEQ_FOREACH(sym, &ms->symtab.syms, elem) {
64 sym->scnptr = origScnArr[sym->shndx - 1];
71 static void parseReltab(ElfuElf *me, ElfuScn *ms)
78 if (me->elfclass == ELFCLASS32) {
79 for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
80 Elf32_Rel *currel = &(((Elf32_Rel*)ms->databuf)[i]);
83 rel = malloc(sizeof(*rel));
86 rel->offset = currel->r_offset;
87 rel->sym = ELF32_R_SYM(currel->r_info);
88 rel->type = ELF32_R_TYPE(currel->r_info);
92 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
94 } else if (me->elfclass == ELFCLASS64) {
95 for (i = 0; (i + 1) * sizeof(Elf64_Rel) <= ms->shdr.sh_size; i++) {
96 Elf64_Rel *currel = &(((Elf64_Rel*)ms->databuf)[i]);
99 rel = malloc(sizeof(*rel));
102 rel->offset = currel->r_offset;
103 rel->sym = ELF64_R_SYM(currel->r_info);
104 rel->type = ELF64_R_TYPE(currel->r_info);
108 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
111 /* Unknown elfclass */
117 static void parseRelatab(ElfuElf *me, ElfuScn *ms)
124 if (me->elfclass == ELFCLASS32) {
125 for (i = 0; (i + 1) * sizeof(Elf32_Rela) <= ms->shdr.sh_size; i++) {
126 Elf32_Rela *currel = &(((Elf32_Rela*)ms->databuf)[i]);
129 rel = malloc(sizeof(*rel));
132 rel->offset = currel->r_offset;
133 rel->sym = ELF32_R_SYM(currel->r_info);
134 rel->type = ELF32_R_TYPE(currel->r_info);
136 rel->addend = currel->r_addend;
138 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
140 } else if (me->elfclass == ELFCLASS64) {
141 for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
142 Elf64_Rela *currel = &(((Elf64_Rela*)ms->databuf)[i]);
145 rel = malloc(sizeof(*rel));
148 rel->offset = currel->r_offset;
149 rel->sym = ELF64_R_SYM(currel->r_info);
150 rel->type = ELF64_R_TYPE(currel->r_info);
152 rel->addend = currel->r_addend;
154 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
157 /* Unknown elfclass */
163 static int cmpScnOffs(const void *ms1, const void *ms2)
165 ElfuScn *s1 = *(ElfuScn**)ms1;
166 ElfuScn *s2 = *(ElfuScn**)ms2;
171 s1 = *(ElfuScn**)ms1;
172 s2 = *(ElfuScn**)ms2;
178 if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
180 } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
182 } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
189 static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
196 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
197 if (mp->phdr.p_type != PT_LOAD) {
201 if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
210 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
216 mp = elfu_mPhdrAlloc();
227 static ElfuScn* modelFromSection(Elf_Scn *scn)
233 ms = elfu_mScnAlloc();
239 assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
241 /* Copy each data part in source segment */
242 if (SCNFILESIZE(&ms->shdr) > 0) {
245 ms->databuf = malloc(ms->shdr.sh_size);
247 ELFU_WARN("modelFromSection: malloc() failed for data buffer (%x bytes).\n", (unsigned)ms->shdr.sh_size);
251 /* A non-empty section should contain at least one data block. */
252 data = elf_rawdata(scn, NULL);
255 /* elf_rawdata() always returns ELF_T_BYTE */
256 assert(data->d_type == ELF_T_BYTE);
259 if (data->d_off + data->d_size > ms->shdr.sh_size) {
260 ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
262 memcpy((char*)ms->databuf + data->d_off, data->d_buf, data->d_size);
265 data = elf_rawdata(scn, data);
281 ElfuElf* elfu_mFromElf(Elf *e)
285 size_t i, numPhdr, numShdr;
286 ElfuScn **secArray = NULL;
289 if (elfu_eCheck(e)) {
293 me = malloc(sizeof(ElfuElf));
295 ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
301 CIRCLEQ_INIT(&me->phdrList);
302 CIRCLEQ_INIT(&me->orphanScnList);
306 me->elfclass = gelf_getclass(e);
307 assert(me->elfclass != ELFCLASSNONE);
308 assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
311 /* Get the section string table index */
312 if (elf_getshdrstrndx(e, &shstrndx) != 0) {
318 assert(!elf_getphdrnum(e, &numPhdr));
319 for (i = 0; i < numPhdr; i++) {
323 assert(gelf_getphdr(e, i, &phdr) == &phdr);
325 mp = modelFromPhdr(&phdr);
330 CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
336 /* Find PHDR -> PHDR dependencies (needs sorted sections) */
337 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
340 if (mp->phdr.p_type != PT_LOAD) {
344 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
349 if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
350 && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
351 CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
359 assert(!elf_getshdrnum(e, &numShdr));
361 secArray = malloc((numShdr - 1) * sizeof(*secArray));
363 ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
367 for (i = 1; i < numShdr; i++) {
371 scn = elf_getscn(e, i);
374 ms = modelFromSection(scn);
387 /* Find sh_link and sh_info dependencies (needs sections in original order) */
388 for (i = 0; i < numShdr - 1; i++) {
389 ElfuScn *ms = secArray[i];
391 switch (ms->shdr.sh_type) {
394 if (ms->shdr.sh_info > 0) {
395 ms->infoptr = secArray[ms->shdr.sh_info - 1];
403 case SHT_GNU_verneed:
404 if (ms->shdr.sh_link > 0) {
405 ms->linkptr = secArray[ms->shdr.sh_link - 1];
411 /* Parse symtabs (needs sections in original order) */
412 for (i = 0; i < numShdr - 1; i++) {
413 ElfuScn *ms = secArray[i];
415 switch (ms->shdr.sh_type) {
419 parseSymtab(me, ms, secArray);
425 /* Parse relocations (needs sections in original order) */
426 for (i = 0; i < numShdr - 1; i++) {
427 ElfuScn *ms = secArray[i];
429 switch (ms->shdr.sh_type) {
434 parseRelatab(me, ms);
440 /* Sort sections by file offset */
441 qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
444 /* Find PHDR -> Section dependencies (needs sorted sections) */
445 for (i = 0; i < numShdr - 1; i++) {
446 ElfuScn *ms = secArray[i];
448 ElfuPhdr *parent = parentPhdr(me, ms);
451 GElf_Off shaddr = parent->phdr.p_vaddr +
452 (ms->shdr.sh_offset - parent->phdr.p_offset);
454 if (ms->shdr.sh_addr == 0) {
455 ms->shdr.sh_addr = shaddr;
457 assert(ms->shdr.sh_addr == shaddr);
460 CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
462 CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
476 // TODO: Free data structures
479 ELFU_WARN("elfu_mFromElf: Failed to load file.\n");