static const value_t * elf_get_phdrs(const value_t *this_fn, parser_state_t *state, const char *filename, int binfd, Elf *e, GElf_Ehdr *ehdr, void *arg) { const value_t *resval = NULL; size_t n; if (elf_getphdrnum(e, &n) != 0) parser_report(state, "ELF file has unknown number of segments - %s\n", elf_errmsg(-1)); else { size_t i; dir_t *partdir = dir_vec_new(); for (i = 0; i < n; i++) { GElf_Phdr phdr; dir_t *pdir = dir_id_new(); if (gelf_getphdr(e, i, &phdr) != &phdr) parser_report(state, "ELF segment %d unretrievable - %s\n", i, elf_errmsg(-1)); else { dir_string_set(pdir,"type" , value_int_new(phdr.p_type)); dir_string_set(pdir,"offset" , value_int_new(phdr.p_offset)); dir_string_set(pdir,"vaddr" , value_int_new(phdr.p_vaddr)); dir_string_set(pdir,"paddr" , value_int_new(phdr.p_paddr)); dir_string_set(pdir,"filesz" , value_int_new(phdr.p_filesz)); dir_string_set(pdir,"memsz" , value_int_new(phdr.p_memsz)); dir_string_set(pdir,"flags" , value_int_new(phdr.p_flags)); dir_string_set(pdir,"align" , value_int_new(phdr.p_align)); dir_int_set(partdir, i, dir_value(pdir)); } } resval = dir_value(partdir); } return resval; }
extern bool FTL_EXTENSION_MAIN(parser_state_t *state, dir_t *cmds) { mod_add_val(cmds, "version", value_int_new(42)); }
/* Invoke the argument FTL function with <addr> <buf> arguments for each of the ELF file's program segments */ static const value_t * elf_load_with_fn(const value_t *this_fn, parser_state_t *state, const char *filename, int binfd, Elf *e, GElf_Ehdr *ehdr, void *arg) { elf_loadfn_args_t *fnarg = (elf_loadfn_args_t *)arg; const value_t *hdrcheckfn = fnarg->hdrcheckfn; const value_t *memwrfn = fnarg->memwrfn; const value_t *resval = value_false; size_t n; if (elf_getphdrnum(e, &n) != 0) parser_report(state, "ELF file has unknown number of segments - %s\n", elf_errmsg(-1)); else { size_t i; bool ok = FALSE; if (hdrcheckfn != NULL) { const value_t *ehdrval = elf_get_ehdr(this_fn, state, filename, binfd, e, ehdr, /*arg*/NULL); if (ehdrval != NULL) { const value_t *code = value_closure_bind(hdrcheckfn, ehdrval); if (code == NULL) { parser_error(state, "couldn't apply " "header argument to check function\n"); } else { const value_t *fnres = invoke(code, state); /* we expect this to return a TRUE/FALSE value */ ok = (fnres == value_true); /*if (!ok) printf("%s: check fn returns non-TRUE\n", codeid());*/ } } } else ok = TRUE; resval = ok? value_true: value_false; if (ok && memwrfn != NULL) { for (i = 0; ok && i < n; i++) { GElf_Phdr phdr; if (gelf_getphdr(e, i, &phdr) != &phdr) parser_report(state, "ELF segment %d unretrievable - %s\n", i, elf_errmsg(-1)); else { long offset = (long)phdr.p_offset; if (phdr.p_offset != (Elf64_Off)offset) parser_report(state, "ELF segment %d - " "offset does not fit in 32-bits\n", i); else if (-1 == fe_lseek(binfd, offset)) parser_report(state, "ELF segment %d - " "offset 0X%lX is outside file\n", i, offset); else if (phdr.p_memsz < phdr.p_filesz) parser_report(state, "ELF segment %d - smaller size in memory (%d)" "than on file (%d) - corrupt header?\n", i, phdr.p_memsz, phdr.p_filesz); else { number_t addr = phdr.p_vaddr; /* where to load segment */ char *buf = NULL; size_t buflen = (size_t)phdr.p_memsz; value_t *addrval = value_int_new(addr); value_t *dataval = value_string_alloc_new(buflen, &buf); if (phdr.p_memsz != (Elf64_Xword)buflen) parser_report(state, "ELF segment %d - " "size does not fit in 32-bits\n", i); else if (dataval == NULL) parser_report(state, "ELF segment %d - no memory for " "next %d bytes\n", i, buflen); else { ssize_t readbytes = fe_read(binfd, buf, buflen); if (readbytes < buflen) parser_report(state, "ELF segment %d - " "only %d bytes of %d read\n", i, readbytes); else { const value_t *code; ok = TRUE; /* zero any uninitialized area */ if (phdr.p_memsz > phdr.p_filesz) { size_t extra_bytes = (size_t) (phdr.p_memsz - phdr.p_filesz); if ((Elf64_Xword)extra_bytes != phdr.p_memsz-phdr.p_filesz) { ok = FALSE; parser_report(state, "ELF segment %d - " "BSS area larger than 32-bits\n", i); } else memset(&buf[phdr.p_filesz], '\0', extra_bytes); } code = value_closure_bind_2(state, memwrfn, "address", addrval, "data", dataval); if (NULL != code) { const value_t *fnres = invoke(code, state); /* we expect this to return a TRUE/FALSE value */ if (fnres != value_true) { /*printf("%s: seg fn returns non-TRUE\n", codeid());*/ ok = FALSE; } /* we rely on garbage collection to collect the data * buffer */ } else value_delete(&dataval); } } } } } if (!ok) resval = value_false; } } return resval; }
static const value_t * elf_get_ehdr(const value_t *this_fn, parser_state_t *state, const char *filename, int binfd, Elf *e, GElf_Ehdr *ehdr, void *arg) { int eclass = gelf_getclass(e); char *id = elf_getident(e, NULL); dir_t *einfo = dir_id_new(); dir_t *edir = dir_id_new(); size_t n; if (eclass == ELFCLASS32) dir_string_set(einfo, "class", value_int_new(32)); else if (eclass == ELFCLASS64) dir_string_set(einfo, "class", value_int_new(64)); else { dir_string_set(einfo, "class", &value_null); if (eclass != ELFCLASSNONE) parser_report(state, "ELF file has unknown class %d - %s\n", eclass, elf_errmsg(-1)); } if (id == NULL) parser_report(state, "ELF file has unknown identity - %s\n", elf_errmsg(-1)); else dir_string_set(einfo, "id", value_string_new(id, EI_NIDENT)); dir_string_set(einfo, "ehdr", dir_value(edir)); dir_string_set(edir,"type" , value_int_new(ehdr->e_type)); dir_string_set(edir,"machine", value_int_new(ehdr->e_machine)); dir_string_set(edir,"version", value_int_new(ehdr->e_version)); dir_string_set(edir,"entry" , value_int_new(ehdr->e_entry)); dir_string_set(edir,"phoff" , value_int_new(ehdr->e_phoff)); dir_string_set(edir,"shoff" , value_int_new(ehdr->e_shoff)); dir_string_set(edir,"flags" , value_int_new(ehdr->e_flags)); dir_string_set(edir,"ehsize" , value_int_new(ehdr->e_ehsize)); dir_string_set(edir,"phentsize", value_int_new(ehdr->e_phentsize)); dir_string_set(edir,"shentsize", value_int_new(ehdr->e_shentsize)); if (elf_getphdrnum(e, &n) != 0) parser_report(state,"ELF file has unknown number of segments - %s\n", elf_errmsg(-1)); else dir_string_set(einfo, "progsects", value_int_new(n)); if (elf_getshdrnum(e, &n) != 0) parser_report(state, "%s: ELF file has unknown number of sections - %s\n", elf_errmsg(-1)); else dir_string_set(einfo, "sections", value_int_new(n)); if (elf_getshdrstrndx(e, &n) != 0) parser_report(state, "%s: ELF file has no section names - %s\n", elf_errmsg(-1)); else dir_string_set(einfo, "shdrstrndx", value_int_new(n)); return dir_value(einfo); }