5 #include <libelfu/libelfu.h>
8 static char* symstr(ElfuScn *symtab, size_t off)
11 assert(symtab->linkptr);
12 assert(symtab->linkptr->data.d_buf);
13 assert(off < symtab->linkptr->data.d_size);
15 return &(((char*)symtab->linkptr->data.d_buf)[off]);
19 static ElfuSymtab* symtabFromScn32(ElfuScn *ms, ElfuScn**origScnArr)
25 assert(ms->data.d_buf);
29 st = malloc(sizeof(*st));
31 ELFU_WARN("elfu_mSymtabFromScn32: malloc() failed for st.\n");
35 CIRCLEQ_INIT(&st->syms);
38 for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
39 Elf32_Sym *cursym = &(((Elf32_Sym*)ms->data.d_buf)[i]);
40 ElfuSym *sym = malloc(sizeof(*sym));
43 sym->name = symstr(ms, cursym->st_name);
44 sym->value = cursym->st_value;
45 sym->size = cursym->st_size;
46 sym->bind = ELF32_ST_BIND(cursym->st_info);
47 sym->type = ELF32_ST_TYPE(cursym->st_info);
48 sym->other = cursym->st_other;
50 switch (cursym->st_shndx) {
55 sym->shndx = cursym->st_shndx;
58 sym->scnptr = origScnArr[cursym->st_shndx - 1];
63 CIRCLEQ_INSERT_TAIL(&st->syms, sym, elem);
77 static ElfuReltab* reltabFromScn32(ElfuScn *ms)
83 assert(ms->data.d_buf);
86 rt = malloc(sizeof(*rt));
88 ELFU_WARN("elfu_mReltabFromScn32: malloc() failed for rt.\n");
92 CIRCLEQ_INIT(&rt->rels);
95 for (i = 0; (i + 1) * sizeof(Elf32_Rel) <= ms->shdr.sh_size; i++) {
96 Elf32_Rel *currel = &(((Elf32_Rel*)ms->data.d_buf)[i]);
99 rel = malloc(sizeof(*rel));
102 rel->offset = currel->r_offset;
104 rel->sym = ELF32_R_SYM(currel->r_info);
105 rel->type = ELF32_R_TYPE(currel->r_info);
110 CIRCLEQ_INSERT_TAIL(&rt->rels, rel, elem);
124 static int cmpScnOffs(const void *ms1, const void *ms2)
129 ElfuScn *s1 = *(ElfuScn**)ms1;
130 ElfuScn *s2 = *(ElfuScn**)ms2;
136 if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
138 } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
140 } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
147 static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
154 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
155 if (mp->phdr.p_type != PT_LOAD) {
159 if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
163 /* Give sections a second chance if they do not have any sh_addr
165 /* Actually we don't, because it's ambiguous.
166 * Re-enable for experiments with strangely-formatted files.
167 if (ms->shdr.sh_addr == 0
168 && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
169 && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
170 <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
180 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
186 mp = malloc(sizeof(ElfuPhdr));
188 ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
194 CIRCLEQ_INIT(&mp->childScnList);
195 CIRCLEQ_INIT(&mp->childPhdrList);
201 static ElfuScn* modelFromSection(Elf_Scn *scn)
207 ms = malloc(sizeof(ElfuScn));
209 ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
214 assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
217 /* Copy each data part in source segment */
218 ms->data.d_align = 1;
219 ms->data.d_buf = NULL;
221 ms->data.d_type = ELF_T_BYTE;
222 ms->data.d_size = ms->shdr.sh_size;
223 ms->data.d_version = elf_version(EV_NONE);
224 if (ms->shdr.sh_type != SHT_NOBITS
225 && ms->shdr.sh_size > 0) {
228 ms->data.d_buf = malloc(ms->shdr.sh_size);
229 if (!ms->data.d_buf) {
230 ELFU_WARN("modelFromSection: malloc() failed for data buffer (%jx bytes).\n", ms->shdr.sh_size);
234 /* A non-empty section should contain at least one data block. */
235 data = elf_rawdata(scn, NULL);
238 ms->data.d_align = data->d_align;
239 ms->data.d_type = data->d_type;
240 ms->data.d_version = data->d_version;
243 if (data->d_off + data->d_size > ms->shdr.sh_size) {
244 ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
246 memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
249 data = elf_rawdata(scn, data);
274 ElfuElf* elfu_mFromElf(Elf *e)
278 size_t i, numPhdr, numShdr;
279 ElfuScn **secArray = NULL;
282 if (elfu_eCheck(e)) {
286 me = malloc(sizeof(ElfuElf));
288 ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
294 CIRCLEQ_INIT(&me->phdrList);
295 CIRCLEQ_INIT(&me->orphanScnList);
298 me->elfclass = gelf_getclass(e);
299 assert(me->elfclass != ELFCLASSNONE);
300 assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
303 /* Get the section string table index */
304 if (elf_getshdrstrndx(e, &shstrndx) != 0) {
310 assert(!elf_getphdrnum(e, &numPhdr));
311 for (i = 0; i < numPhdr; i++) {
315 assert(gelf_getphdr(e, i, &phdr) == &phdr);
317 mp = modelFromPhdr(&phdr);
322 CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
328 /* Find PHDR -> PHDR dependencies (needs sorted sections) */
329 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
332 if (mp->phdr.p_type != PT_LOAD) {
336 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
341 if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
342 && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
343 CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
351 assert(!elf_getshdrnum(e, &numShdr));
353 secArray = malloc((numShdr - 1) * sizeof(*secArray));
355 ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
359 for (i = 1; i < numShdr; i++) {
363 scn = elf_getscn(e, i);
366 ms = modelFromSection(scn);
379 /* Find sh_link and sh_info dependencies (needs sections in original order) */
380 for (i = 0; i < numShdr - 1; i++) {
381 ElfuScn *ms = secArray[i];
383 switch (ms->shdr.sh_type) {
386 if (ms->shdr.sh_info > 0) {
387 ms->infoptr = secArray[ms->shdr.sh_info - 1];
395 case SHT_GNU_verneed:
396 if (ms->shdr.sh_link > 0) {
397 ms->linkptr = secArray[ms->shdr.sh_link - 1];
403 /* Parse symtabs (needs sections in original order) */
404 for (i = 0; i < numShdr - 1; i++) {
405 ElfuScn *ms = secArray[i];
407 switch (ms->shdr.sh_type) {
410 if (me->elfclass == ELFCLASS32) {
411 ms->symtab = symtabFromScn32(ms, secArray);
412 } else if (me->elfclass == ELFCLASS64) {
421 /* Parse relocations */
422 for (i = 0; i < numShdr - 1; i++) {
423 ElfuScn *ms = secArray[i];
425 switch (ms->shdr.sh_type) {
427 if (me->elfclass == ELFCLASS32) {
428 ms->reltab = reltabFromScn32(ms);
429 } else if (me->elfclass == ELFCLASS64) {
435 if (me->elfclass == ELFCLASS32) {
437 } else if (me->elfclass == ELFCLASS64) {
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 assert(ms->shdr.sh_addr == shaddr);
466 CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
468 CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
482 // TODO: Free data structures
485 ELFU_WARN("elfu_mFromElf: Failed to load file.\n");