5 #include <libelfu/libelfu.h>
8 static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
14 assert(ms->data.d_buf);
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->data.d_buf) + 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;
34 CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
36 } else if (me->elfclass == ELFCLASS64) {
37 for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) {
38 Elf64_Sym *cursym = ((Elf64_Sym*)ms->data.d_buf) + i;
39 ElfuSym *newsym = malloc(sizeof(*sym));
42 newsym->name = cursym->st_name;
43 newsym->value = cursym->st_value;
44 newsym->size = cursym->st_size;
45 newsym->bind = ELF64_ST_BIND(cursym->st_info);
46 newsym->type = ELF64_ST_TYPE(cursym->st_info);
47 newsym->other = cursym->st_other;
48 newsym->shndx = cursym->st_shndx;
52 CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
55 /* Unknown elfclass */
59 /* For each section, find the section it points to if any. */
60 CIRCLEQ_FOREACH(sym, &ms->symtab.syms, elem) {
68 sym->scnptr = origScnArr[sym->shndx - 1];
75 static void parseReltab32(ElfuScn *ms)
80 assert(ms->data.d_buf);
83 for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
84 Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]);
87 rel = malloc(sizeof(*rel));
90 rel->offset = currel->r_offset;
91 rel->sym = ELF32_R_SYM(currel->r_info);
92 rel->type = ELF32_R_TYPE(currel->r_info);
96 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
101 static void parseRelatab64(ElfuScn *ms)
106 assert(ms->data.d_buf);
109 for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
110 Elf64_Rela *currel = &(((Elf64_Rela*)ms->data.d_buf)[i]);
113 rel = malloc(sizeof(*rel));
116 rel->offset = currel->r_offset;
117 rel->sym = ELF64_R_SYM(currel->r_info);
118 rel->type = ELF64_R_TYPE(currel->r_info);
120 rel->addend = currel->r_addend;
122 CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
127 static int cmpScnOffs(const void *ms1, const void *ms2)
129 ElfuScn *s1 = *(ElfuScn**)ms1;
130 ElfuScn *s2 = *(ElfuScn**)ms2;
135 s1 = *(ElfuScn**)ms1;
136 s2 = *(ElfuScn**)ms2;
142 if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
144 } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
146 } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
153 static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
160 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
161 if (mp->phdr.p_type != PT_LOAD) {
165 if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
169 /* Give sections a second chance if they do not have any sh_addr
171 /* Actually we don't, because it's ambiguous.
172 * Re-enable for experiments with strangely-formatted files.
173 if (ms->shdr.sh_addr == 0
174 && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
175 && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
176 <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
186 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
192 mp = malloc(sizeof(ElfuPhdr));
194 ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
200 CIRCLEQ_INIT(&mp->childScnList);
201 CIRCLEQ_INIT(&mp->childPhdrList);
207 static ElfuScn* modelFromSection(Elf_Scn *scn)
213 ms = malloc(sizeof(ElfuScn));
215 ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
220 assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
223 /* Copy each data part in source segment */
224 ms->data.d_align = 1;
225 ms->data.d_buf = NULL;
227 ms->data.d_type = ELF_T_BYTE;
228 ms->data.d_size = ms->shdr.sh_size;
229 ms->data.d_version = elf_version(EV_NONE);
230 if (ms->shdr.sh_type != SHT_NOBITS
231 && ms->shdr.sh_size > 0) {
234 ms->data.d_buf = malloc(ms->shdr.sh_size);
235 if (!ms->data.d_buf) {
236 ELFU_WARN("modelFromSection: malloc() failed for data buffer (%x bytes).\n", (unsigned)ms->shdr.sh_size);
240 /* A non-empty section should contain at least one data block. */
241 data = elf_rawdata(scn, NULL);
244 ms->data.d_align = data->d_align;
245 ms->data.d_type = data->d_type;
246 ms->data.d_version = data->d_version;
249 if (data->d_off + data->d_size > ms->shdr.sh_size) {
250 ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
252 memcpy((char*)ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
255 data = elf_rawdata(scn, data);
264 CIRCLEQ_INIT(&ms->symtab.syms);
265 CIRCLEQ_INIT(&ms->reltab.rels);
280 ElfuElf* elfu_mFromElf(Elf *e)
284 size_t i, numPhdr, numShdr;
285 ElfuScn **secArray = NULL;
288 if (elfu_eCheck(e)) {
292 me = malloc(sizeof(ElfuElf));
294 ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
300 CIRCLEQ_INIT(&me->phdrList);
301 CIRCLEQ_INIT(&me->orphanScnList);
305 me->elfclass = gelf_getclass(e);
306 assert(me->elfclass != ELFCLASSNONE);
307 assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
310 /* Get the section string table index */
311 if (elf_getshdrstrndx(e, &shstrndx) != 0) {
317 assert(!elf_getphdrnum(e, &numPhdr));
318 for (i = 0; i < numPhdr; i++) {
322 assert(gelf_getphdr(e, i, &phdr) == &phdr);
324 mp = modelFromPhdr(&phdr);
329 CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
335 /* Find PHDR -> PHDR dependencies (needs sorted sections) */
336 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
339 if (mp->phdr.p_type != PT_LOAD) {
343 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
348 if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
349 && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
350 CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
358 assert(!elf_getshdrnum(e, &numShdr));
360 secArray = malloc((numShdr - 1) * sizeof(*secArray));
362 ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
366 for (i = 1; i < numShdr; i++) {
370 scn = elf_getscn(e, i);
373 ms = modelFromSection(scn);
386 /* Find sh_link and sh_info dependencies (needs sections in original order) */
387 for (i = 0; i < numShdr - 1; i++) {
388 ElfuScn *ms = secArray[i];
390 switch (ms->shdr.sh_type) {
393 if (ms->shdr.sh_info > 0) {
394 ms->infoptr = secArray[ms->shdr.sh_info - 1];
402 case SHT_GNU_verneed:
403 if (ms->shdr.sh_link > 0) {
404 ms->linkptr = secArray[ms->shdr.sh_link - 1];
410 /* Parse symtabs (needs sections in original order) */
411 for (i = 0; i < numShdr - 1; i++) {
412 ElfuScn *ms = secArray[i];
414 switch (ms->shdr.sh_type) {
418 parseSymtab(me, ms, secArray);
424 /* Parse relocations */
425 for (i = 0; i < numShdr - 1; i++) {
426 ElfuScn *ms = secArray[i];
428 switch (ms->shdr.sh_type) {
430 if (me->elfclass == ELFCLASS32) {
432 } else if (me->elfclass == ELFCLASS64) {
433 /* Not used on x86-64 */
438 if (me->elfclass == ELFCLASS32) {
439 /* Not used on x86-32 */
441 } else if (me->elfclass == ELFCLASS64) {
449 /* Sort sections by file offset */
450 qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
453 /* Find PHDR -> Section dependencies (needs sorted sections) */
454 for (i = 0; i < numShdr - 1; i++) {
455 ElfuScn *ms = secArray[i];
457 ElfuPhdr *parent = parentPhdr(me, ms);
460 GElf_Off shaddr = parent->phdr.p_vaddr +
461 (ms->shdr.sh_offset - parent->phdr.p_offset);
463 if (ms->shdr.sh_addr == 0) {
464 ms->shdr.sh_addr = shaddr;
466 assert(ms->shdr.sh_addr == shaddr);
469 CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
471 CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
485 // TODO: Free data structures
488 ELFU_WARN("elfu_mFromElf: Failed to load file.\n");