5 #include <libelfu/libelfu.h>
8 static int cmpScnOffs(const void *ms1, const void *ms2)
13 ElfuScn *s1 = *(ElfuScn**)ms1;
14 ElfuScn *s2 = *(ElfuScn**)ms2;
20 if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
22 } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
24 } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
31 static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
38 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
39 if (mp->phdr.p_type != PT_LOAD) {
43 if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
47 /* Give sections a second chance if they do not have any sh_addr
49 /* Actually we don't, because it's ambiguous.
50 * Re-enable for experiments with strangely-formatted files.
51 if (ms->shdr.sh_addr == 0
52 && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
53 && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
54 <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
64 static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
70 mp = malloc(sizeof(ElfuPhdr));
72 ELFU_WARN("modelFromPhdr: malloc() failed for ElfuPhdr.\n");
78 CIRCLEQ_INIT(&mp->childScnList);
79 CIRCLEQ_INIT(&mp->childPhdrList);
85 static ElfuScn* modelFromSection(Elf_Scn *scn)
91 ms = malloc(sizeof(ElfuScn));
93 ELFU_WARN("modelFromSection: malloc() failed for ElfuScn.\n");
98 assert(gelf_getshdr(scn, &ms->shdr) == &ms->shdr);
101 /* Copy each data part in source segment */
102 ms->data.d_align = 1;
103 ms->data.d_buf = NULL;
105 ms->data.d_type = ELF_T_BYTE;
106 ms->data.d_size = ms->shdr.sh_size;
107 ms->data.d_version = elf_version(EV_NONE);
108 if (ms->shdr.sh_type != SHT_NOBITS
109 && ms->shdr.sh_size > 0) {
112 ms->data.d_buf = malloc(ms->shdr.sh_size);
113 if (!ms->data.d_buf) {
114 ELFU_WARN("modelFromSection: malloc() failed for data buffer (%jx bytes).\n", ms->shdr.sh_size);
118 /* A non-empty section should contain at least one data block. */
119 data = elf_rawdata(scn, NULL);
122 ms->data.d_align = data->d_align;
123 ms->data.d_type = data->d_type;
124 ms->data.d_version = data->d_version;
127 if (data->d_off + data->d_size > ms->shdr.sh_size) {
128 ELFU_WARN("modelFromSection: libelf delivered a bogus data blob. Skipping\n");
130 memcpy(ms->data.d_buf + data->d_off, data->d_buf, data->d_size);
133 data = elf_rawdata(scn, data);
155 ElfuElf* elfu_mFromElf(Elf *e)
159 size_t i, numPhdr, numShdr;
160 ElfuScn **secArray = NULL;
163 if (elfu_eCheck(e)) {
167 me = malloc(sizeof(ElfuElf));
169 ELFU_WARN("elfu_mFromElf: malloc() failed for ElfuElf.\n");
175 CIRCLEQ_INIT(&me->phdrList);
176 CIRCLEQ_INIT(&me->orphanScnList);
179 me->elfclass = gelf_getclass(e);
180 assert(me->elfclass != ELFCLASSNONE);
181 assert(gelf_getehdr(e, &me->ehdr) == &me->ehdr);
184 /* Get the section string table index */
185 if (elf_getshdrstrndx(e, &shstrndx) != 0) {
191 assert(!elf_getphdrnum(e, &numPhdr));
192 for (i = 0; i < numPhdr; i++) {
196 assert(gelf_getphdr(e, i, &phdr) == &phdr);
198 mp = modelFromPhdr(&phdr);
203 CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
209 /* Find PHDR -> PHDR dependencies (needs sorted sections) */
210 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
213 if (mp->phdr.p_type != PT_LOAD) {
217 CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
222 if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
223 && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
224 CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
232 assert(!elf_getshdrnum(e, &numShdr));
234 secArray = malloc((numShdr - 1) * sizeof(*secArray));
236 ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
240 for (i = 1; i < numShdr; i++) {
244 scn = elf_getscn(e, i);
247 ms = modelFromSection(scn);
260 /* Find sh_link dependencies */
261 for (i = 0; i < numShdr - 1; i++) {
262 ElfuScn *ms = secArray[i];
264 switch (ms->shdr.sh_type) {
267 if (ms->shdr.sh_info > 0) {
268 ms->infoptr = secArray[ms->shdr.sh_info - 1];
276 case SHT_GNU_verneed:
277 if (ms->shdr.sh_link > 0) {
278 ms->linkptr = secArray[ms->shdr.sh_link - 1];
284 /* Sort sections by file offset */
285 qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
288 /* Find PHDR -> Section dependencies (needs sorted sections) */
289 for (i = 0; i < numShdr - 1; i++) {
290 ElfuScn *ms = secArray[i];
292 ElfuPhdr *parent = parentPhdr(me, ms);
295 GElf_Off shaddr = parent->phdr.p_vaddr +
296 (ms->shdr.sh_offset - parent->phdr.p_offset);
298 if (ms->shdr.sh_addr == 0) {
299 ms->shdr.sh_addr = shaddr;
301 assert(ms->shdr.sh_addr == shaddr);
304 CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
306 CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
320 // TODO: Free data structures
323 ELFU_WARN("elfu_mFromElf: Failed to load file.\n");