uint8_t *dump_section_data(Elf *elf_object, int *size) { uint8_t *buffer = NULL; Elf_Data *data = NULL; size_t shdr_num; size_t max_saddr = 0; GElf_Shdr shdr; size_t shstrndx; char *name = NULL; *size = 0; int ret = elf_getshdrnum(elf_object, &shdr_num); if (ret) { printf("Problem during ELF parsing\n"); return NULL; } if (shdr_num == 0) return NULL; Elf_Scn *cur_section = NULL; ret = elf_getshdrstrndx(elf_object, &shstrndx); if (ret) printf("No string table found\n"); while ((cur_section = elf_nextscn(elf_object, cur_section)) != NULL ) { if (gelf_getshdr(cur_section, &shdr) != &shdr) { printf("Problem during ELF parsing\n"); return NULL; } if ((shdr.sh_type == SHT_PROGBITS) && (shdr.sh_flags & SHF_ALLOC) && shdr.sh_size != 0) { name = elf_strptr(elf_object, shstrndx , shdr.sh_name); printf("Loading section %s, size 0x%08X lma 0x%08X\n", name ? name : "??", (unsigned int)shdr.sh_size, (unsigned int)shdr.sh_addr); if (shdr.sh_addr + shdr.sh_size >= max_saddr) { max_saddr = shdr.sh_addr + shdr.sh_size; buffer = realloc(buffer, max_saddr); } data = elf_getdata(cur_section, data); if (data != NULL) memcpy(buffer + shdr.sh_addr, data->d_buf, data->d_size); else { printf("Couldn't load section data chunk\n"); return NULL; } } } *size = max_saddr; return buffer; }
static void elf_foreach_resource_section (Elf *elf, SectionCallback callback, gpointer data) { size_t shstrndx, shnum; size_t scnidx; Elf_Scn *scn; GElf_Shdr *shdr, shdr_mem; const gchar *section_name; elf_getshdrstrndx (elf, &shstrndx); g_assert (shstrndx >= 0); elf_getshdrnum (elf, &shnum); g_assert (shnum >= 0); for (scnidx = 1; scnidx < shnum; scnidx++) { scn = elf_getscn (elf, scnidx); if (scn == NULL) continue; shdr = gelf_getshdr (scn, &shdr_mem); if (shdr == NULL) continue; if (shdr->sh_type != SHT_PROGBITS) continue; section_name = elf_strptr (elf, shstrndx, shdr->sh_name); if (section_name == NULL || !g_str_has_prefix (section_name, ".gresource.")) continue; if (!callback (shdr, section_name + strlen (".gresource."), data)) break; } }
int elfu_eCheck(Elf *e) { int elfclass; GElf_Ehdr ehdr; GElf_Phdr *phdrs = NULL; GElf_Shdr *shdrs = NULL; size_t i, j, numPhdr, numShdr; int retval = 0; assert(e); elfclass = gelf_getclass(e); if (elfclass == ELFCLASSNONE) { ELFU_WARNELF("getclass"); goto ERROR; } if (!gelf_getehdr(e, &ehdr)) { ELFU_WARNELF("gelf_getehdr"); goto ERROR; } if (ehdr.e_machine != EM_386 && ehdr.e_machine != EM_X86_64) { ELFU_WARN("Sorry, only x86-32 and x86-64 ELF files are supported at the moment.\n"); goto ERROR; } if (elf_getphdrnum(e, &numPhdr)) { ELFU_WARNELF("elf_getphdrnum"); goto ERROR; } if (elf_getshdrnum(e, &numShdr)) { ELFU_WARNELF("elf_getshdrnum"); goto ERROR; } if (numPhdr > 0) { phdrs = malloc(numPhdr * sizeof(GElf_Phdr)); if (!phdrs) { ELFU_WARN("elfu_eCheck: malloc() failed for phdrs.\n"); goto ERROR; } /* Attempt to load all PHDRs at once to catch any errors early */ for (i = 0; i < numPhdr; i++) { GElf_Phdr phdr; if (gelf_getphdr(e, i, &phdr) != &phdr) { ELFU_WARN("gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1)); goto ERROR; } phdrs[i] = phdr; } /* Check that LOAD PHDR memory ranges do not overlap, and that others * are either fully contained in a LOAD range, or not at all. */ for (i = 0; i < numPhdr; i++) { if (phdrs[i].p_type != PT_LOAD) { continue; } for (j = 0; j < numPhdr; j++) { if (j == i || phdrs[j].p_type != PT_LOAD) { continue; } if (OVERLAPPING(phdrs[i].p_vaddr, phdrs[i].p_memsz, phdrs[j].p_vaddr, phdrs[j].p_memsz)) { if (phdrs[j].p_type == PT_LOAD) { ELFU_WARN("elfu_eCheck: Found LOAD PHDRs that overlap in memory.\n"); goto ERROR; } else if (!FULLY_OVERLAPPING(phdrs[i].p_vaddr, phdrs[i].p_memsz, phdrs[j].p_vaddr, phdrs[j].p_memsz)) { ELFU_WARN("elfu_eCheck: PHDRs %d and %d partially overlap in memory.\n", i, j); goto ERROR; } } } } } if (numShdr > 1) { /* SHDRs should not overlap with PHDRs. */ if (OVERLAPPING(ehdr.e_shoff, numShdr * ehdr.e_shentsize, ehdr.e_phoff, numPhdr * ehdr.e_phentsize)) { ELFU_WARN("elfu_eCheck: SHDRs overlap with PHDRs.\n"); goto ERROR; } shdrs = malloc(numShdr * sizeof(GElf_Shdr)); if (!shdrs) { ELFU_WARN("elfu_eCheck: malloc() failed for shdrs.\n"); goto ERROR; } /* Attempt to load all SHDRs at once to catch any errors early */ for (i = 1; i < numShdr; i++) { Elf_Scn *scn; GElf_Shdr shdr; scn = elf_getscn(e, i); if (!scn) { ELFU_WARN("elf_getscn() failed for #%d: %s\n", i, elf_errmsg(-1)); } if (gelf_getshdr(scn, &shdr) != &shdr) { ELFU_WARNELF("gelf_getshdr"); goto ERROR; } shdrs[i] = shdr; } /* Check that Section memory ranges do not overlap. * NB: Section 0 is reserved and thus ignored. */ for (i = 1; i < numShdr; i++) { /* Section should not overlap with EHDR. */ if (shdrs[i].sh_offset == 0) { ELFU_WARN("elfu_eCheck: Section %d overlaps with EHDR.\n", i); goto ERROR; } /* Section should not overlap with PHDRs. */ if (OVERLAPPING(shdrs[i].sh_offset, SCNFILESIZE(&shdrs[i]), ehdr.e_phoff, numPhdr * ehdr.e_phentsize)) { ELFU_WARN("elfu_eCheck: Section %d overlaps with PHDR.\n", i); goto ERROR; } /* Section should not overlap with SHDRs. */ if (OVERLAPPING(shdrs[i].sh_offset, SCNFILESIZE(&shdrs[i]), ehdr.e_shoff, numShdr * ehdr.e_shentsize)) { ELFU_WARN("elfu_eCheck: Section %d overlaps with SHDRs.\n", i); goto ERROR; } for (j = 1; j < numShdr; j++) { if (j == i) { continue; } /* Sections must not overlap in memory. */ if (shdrs[i].sh_addr != 0 && shdrs[j].sh_addr != 0 && OVERLAPPING(shdrs[i].sh_addr, shdrs[i].sh_size, shdrs[j].sh_addr, shdrs[j].sh_size)) { ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in memory.\n", i, j); goto ERROR; } /* Sections must not overlap in file. */ if (OVERLAPPING(shdrs[i].sh_offset, SCNFILESIZE(&shdrs[i]), shdrs[j].sh_offset, SCNFILESIZE(&shdrs[j]))) { ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in file.\n", i, j); goto ERROR; } /* We may not have more than one symbol table */ if (shdrs[i].sh_type == SHT_SYMTAB && shdrs[j].sh_type == SHT_SYMTAB) { ELFU_WARN("elfu_eCheck: Found more than one SYMTAB section.\n"); goto ERROR; } /* We may not have more than one dynamic symbol table */ if (shdrs[i].sh_type == SHT_DYNSYM && shdrs[j].sh_type == SHT_DYNSYM) { ELFU_WARN("elfu_eCheck: Found more than one DYNSYM section.\n"); goto ERROR; } } /* Section addr/offset should match parent PHDR. * Find parent PHDR: */ for (j = 0; j < numPhdr; j++) { if (PHDR_CONTAINS_SCN_IN_MEMORY(&phdrs[j], &shdrs[i])) { GElf_Off shoff = phdrs[j].p_offset + (shdrs[i].sh_addr - phdrs[j].p_vaddr); if ((shdrs[i].sh_offset != shoff && shdrs[i].sh_type != SHT_NOBITS) || !PHDR_CONTAINS_SCN_IN_FILE(&phdrs[j], &shdrs[i])) { ELFU_WARN("elfu_eCheck: SHDR %d and PHDR %d report conflicting file/memory regions.\n", i, j); goto ERROR; } } } /* sh_link members should not point to sections out of range. */ if (shdrs[i].sh_link >= numShdr) { ELFU_WARN("elfu_eCheck: Bogus sh_link in SHDR %d.\n", i); } } } DONE: if (phdrs) { free(phdrs); } if (shdrs) { free(shdrs); } return retval; ERROR: ELFU_WARN("elfu_eCheck: Errors found.\n"); retval = -1; goto DONE; }
int init(char* fname) { char *id, bytes[5]; if (elf_version (EV_CURRENT) == EV_NONE) { errx (EXIT_FAILURE, " ELF library initialization " " failed : %s", elf_errmsg (-1)); return -1; } int fd; if ((fd = open (fname, O_RDONLY, 0)) < 0) { err (EXIT_FAILURE, " open \"%s\" failed ", fname); return -1; } g.fd = fd; Elf *e; if ((e = elf_begin (fd, ELF_C_READ, NULL)) == NULL) { errx (EXIT_FAILURE, " elf_begin () failed : %s.", elf_errmsg (-1)); return -1; } if (elf_kind (e) != ELF_K_ELF) { errx (EXIT_FAILURE, " \"%s\" is not an ELF object .", fname); return -1; } g.e = e; GElf_Ehdr ehdr; if (gelf_getehdr (e, &ehdr) == NULL) { errx (EXIT_FAILURE, " getehdr () failed : %s.", elf_errmsg (-1)); return -1; } g.ehdr = ehdr; int i; if ((i = gelf_getclass (e)) == ELFCLASSNONE) { errx (EXIT_FAILURE, " getclass () failed : %s.", elf_errmsg (-1)); return -1; } if ((id = elf_getident (e, NULL)) == NULL) { errx (EXIT_FAILURE, " getident () failed : %s.", elf_errmsg (-1)); return -1; } size_t n; if (elf_getshdrnum (e, &n) != 0) { errx (EXIT_FAILURE, " getshdrnum () failed : %s.", elf_errmsg (-1)); return -1; } g.shdrnum = n; if (elf_getshdrstrndx (e, &n) != 0) { errx (EXIT_FAILURE, " getshdrstrndx () failed : %s.", elf_errmsg (-1)); return -1; } g.shstrndx = n; if (elf_getphdrnum (e, &n) != 0) { errx (EXIT_FAILURE, " getphdrnum () failed : %s.", elf_errmsg (-1)); return -1; } g.phdrnum = n; init_scns(); init_phdrs(); return 0; }
static int ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags) { GElf_Ehdr sehdr, dehdr; Elf_Scn *sscn, *dscn; Elf_Data *sdata, *ddata; GElf_Shdr shdr; int symtab_idx = -1; off_t new_offset = 0; off_t ctfnameoff = 0; int compress = (flags & CTF_ELFWRITE_F_COMPRESS); int *secxlate = NULL; int srcidx, dstidx, pad, i; int curnmoff = 0; int changing = 0; int ret; size_t nshdr, nphdr, strndx; void *strdatabuf = NULL, *symdatabuf = NULL; size_t strdatasz = 0, symdatasz = 0; void *cdata = NULL; size_t elfsize, asize; if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) { ret = ctf_set_errno(fp, EINVAL); goto out; } if (gelf_newehdr(dst, gelf_getclass(src)) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_getehdr(src, &sehdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } (void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); if (gelf_update_ehdr(dst, &dehdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * Use libelf to get the number of sections and the string section to * deal with ELF files that may have a large number of sections. We just * always use this to make our live easier. */ if (elf_getphdrnum(src, &nphdr) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_getshdrnum(src, &nshdr) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_getshdrstrndx(src, &strndx) != 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * Neither the existing debug sections nor the SUNW_ctf sections (new or * existing) are SHF_ALLOC'd, so they won't be in areas referenced by * program headers. As such, we can just blindly copy the program * headers from the existing file to the new file. */ if (nphdr != 0) { (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); if (gelf_newphdr(dst, nphdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } for (i = 0; i < nphdr; i++) { GElf_Phdr phdr; if (gelf_getphdr(src, i, &phdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_update_phdr(dst, i, &phdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } } } secxlate = ctf_alloc(sizeof (int) * nshdr); for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) { Elf_Scn *scn = elf_getscn(src, srcidx); GElf_Shdr shdr; char *sname; if (gelf_getshdr(scn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } sname = elf_strptr(src, strndx, shdr.sh_name); if (sname == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { secxlate[srcidx] = -1; } else { secxlate[srcidx] = dstidx++; curnmoff += strlen(sname) + 1; } new_offset = (off_t)dehdr.e_phoff; } for (srcidx = 1; srcidx < nshdr; srcidx++) { char *sname; sscn = elf_getscn(src, srcidx); if (gelf_getshdr(sscn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (secxlate[srcidx] == -1) { changing = 1; continue; } dscn = elf_newscn(dst); if (dscn == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* * If this file has program headers, we need to explicitly lay * out sections. If none of the sections prior to this one have * been removed, then we can just use the existing location. If * one or more sections have been changed, then we need to * adjust this one to avoid holes. */ if (changing && nphdr != 0) { pad = new_offset % shdr.sh_addralign; if (pad != 0) new_offset += shdr.sh_addralign - pad; shdr.sh_offset = new_offset; } shdr.sh_link = secxlate[shdr.sh_link]; if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) shdr.sh_info = secxlate[shdr.sh_info]; sname = elf_strptr(src, strndx, shdr.sh_name); if (sname == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if ((sdata = elf_getdata(sscn, NULL)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if ((ddata = elf_newdata(dscn)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } bcopy(sdata, ddata, sizeof (Elf_Data)); if (srcidx == strndx) { char seclen = strlen(CTF_ELF_SCN_NAME); strdatasz = ddata->d_size + shdr.sh_size + seclen + 1; ddata->d_buf = strdatabuf = ctf_alloc(strdatasz); if (ddata->d_buf == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); (void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size, CTF_ELF_SCN_NAME); ctfnameoff = (off_t)shdr.sh_size; shdr.sh_size += seclen + 1; ddata->d_size += seclen + 1; if (nphdr != 0) changing = 1; } if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) { int nsym = shdr.sh_size / shdr.sh_entsize; symtab_idx = secxlate[srcidx]; symdatasz = shdr.sh_size; ddata->d_buf = symdatabuf = ctf_alloc(symdatasz); if (ddata->d_buf == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } (void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); for (i = 0; i < nsym; i++) { GElf_Sym sym; short newscn; (void) gelf_getsym(ddata, i, &sym); if (sym.st_shndx >= SHN_LORESERVE) continue; if ((newscn = secxlate[sym.st_shndx]) != sym.st_shndx) { sym.st_shndx = (newscn == -1 ? 1 : newscn); if (gelf_update_sym(ddata, i, &sym) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } } } } if (gelf_update_shdr(dscn, &shdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } new_offset = (off_t)shdr.sh_offset; if (shdr.sh_type != SHT_NOBITS) new_offset += shdr.sh_size; } if (symtab_idx == -1) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* Add the ctf section */ if ((dscn = elf_newscn(dst)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (gelf_getshdr(dscn, &shdr) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } shdr.sh_name = ctfnameoff; shdr.sh_type = SHT_PROGBITS; shdr.sh_size = fp->ctf_size; shdr.sh_link = symtab_idx; shdr.sh_addralign = 4; if (changing && nphdr != 0) { pad = new_offset % shdr.sh_addralign; if (pad) new_offset += shdr.sh_addralign - pad; shdr.sh_offset = new_offset; new_offset += shdr.sh_size; } if ((ddata = elf_newdata(dscn)) == NULL) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (compress != 0) { int err; if (ctf_zopen(&err) == NULL) { ret = ctf_set_errno(fp, err); goto out; } if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) { ret = ctf_set_errno(fp, err); goto out; } ddata->d_buf = cdata; ddata->d_size = elfsize; } else { ddata->d_buf = (void *)fp->ctf_base; ddata->d_size = fp->ctf_size; } ddata->d_align = shdr.sh_addralign; if (gelf_update_shdr(dscn, &shdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } /* update the section header location */ if (nphdr != 0) { size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); size_t r = new_offset % align; if (r) new_offset += align - r; dehdr.e_shoff = new_offset; } /* commit to disk */ if (sehdr.e_shstrndx == SHN_XINDEX) dehdr.e_shstrndx = SHN_XINDEX; else dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; if (gelf_update_ehdr(dst, &dehdr) == 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } if (elf_update(dst, ELF_C_WRITE) < 0) { ret = ctf_set_errno(fp, ECTF_ELF); goto out; } ret = 0; out: if (strdatabuf != NULL) ctf_free(strdatabuf, strdatasz); if (symdatabuf != NULL) ctf_free(symdatabuf, symdatasz); if (cdata != NULL) ctf_data_free(cdata, fp->ctf_size); if (secxlate != NULL) ctf_free(secxlate, sizeof (int) * nshdr); return (ret); }
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); }