diff --git a/usr.bin/ctfdump/Makefile b/usr.bin/ctfdump/Makefile index f051dd7cdd3..00fbbbcaa44 100644 --- a/usr.bin/ctfdump/Makefile +++ b/usr.bin/ctfdump/Makefile @@ -1,11 +1,11 @@ PROG= ctfdump -SRCS= ctfdump.c elf.c +SRCS= ctfdump.c CFLAGS+= -W -Wall -Wstrict-prototypes -Wno-unused -Wunused-variable CFLAGS+= -DZLIB -LDADD+= -lz -DPADD+= ${LIBZ} +LDADD+= -lelf -lz +DPADD+= ${LIBELF} ${LIBZ} .include diff --git a/usr.bin/ctfdump/ctfdump.c b/usr.bin/ctfdump/ctfdump.c index cda3f17e3dd..0c3f6d263fc 100644 --- a/usr.bin/ctfdump/ctfdump.c +++ b/usr.bin/ctfdump/ctfdump.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ctfdump.c,v 1.22 2019/03/16 16:35:03 sunil Exp $ */ +/* $OpenBSD: ctfdump.c,v 1.23 2019/05/14 03:16:55 sunil Exp $ */ /* * Copyright (c) 2016 Martin Pieuchot @@ -21,9 +21,10 @@ #include #include -#include #include #include +#include +#include #include #include #include @@ -60,19 +61,9 @@ const char *ctf_fpenc2name(uint16_t); const char *ctf_off2name(struct ctf_header *, const char *, off_t, uint32_t); -int elf_dump(char *, size_t, uint8_t); -const char *elf_idx2sym(size_t *, uint8_t); - -/* elf.c */ -int iself(const char *, size_t); -int elf_getshstab(const char *, size_t, const char **, size_t *); -ssize_t elf_getsymtab(const char *, size_t filesize, const char *, - size_t, const Elf_Sym **, size_t *, const char **, - size_t *); -ssize_t elf_getsection(char *, size_t, const char *, const char *, - size_t, const char **, size_t *); - char *decompress(const char *, size_t, off_t); +int elf_dump(uint8_t); +const char *elf_idx2sym(size_t *, uint8_t); int main(int argc, char *argv[]) @@ -121,119 +112,162 @@ main(int argc, char *argv[]) if (flags == 0) flags = 0xff; + if (elf_version(EV_CURRENT) == EV_NONE) + errx(1, "elf_version: %s", elf_errmsg(-1)); + while ((filename = *argv++) != NULL) error |= dump(filename, flags); return error; } +Elf *e; +Elf_Scn *scnsymtab; +size_t strtabndx, strtabsz, nsymb; + int dump(const char *path, uint8_t flags) { - struct stat st; - int fd, error = 1; - char *p; + struct stat st; + char *p; + int fd, error = 1; fd = open(path, O_RDONLY); if (fd == -1) { warn("open"); return 1; } + + if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + warnx("elf_begin: %s", elf_errmsg(-1)); + goto done; + } + + if (elf_kind(e) == ELF_K_ELF) { + error = elf_dump(flags); + elf_end(e); + goto done; + } + elf_end(e); + if (fstat(fd, &st) == -1) { warn("fstat"); - close(fd); - return 1; + goto done; } if ((uintmax_t)st.st_size > SIZE_MAX) { warnx("file too big to fit memory"); - close(fd); - return 1; + goto done; } p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) err(1, "mmap"); - if (iself(p, st.st_size)) { - error = elf_dump(p, st.st_size, flags); - } else if (isctf(p, st.st_size)) { + if (isctf(p, st.st_size)) error = ctf_dump(p, st.st_size, flags); - } munmap(p, st.st_size); - close(fd); + done: + close(fd); return error; } -const char *strtab; -const Elf_Sym *symtab; -size_t strtabsz, nsymb; - const char * elf_idx2sym(size_t *idx, uint8_t type) { - const Elf_Sym *st; + GElf_Sym sym; + Elf_Data *data; + char *name; size_t i; - if (strtab == NULL) + if (scnsymtab == NULL || strtabndx == 0) return NULL; - for (i = *idx + 1; i < nsymb; i++) { - st = &symtab[i]; + data = NULL; + while ((data = elf_rawdata(scnsymtab, data)) != NULL) { + for (i = *idx + 1; i < nsymb; i++) { + if (gelf_getsym(data, i, &sym) != &sym) + continue; + if (GELF_ST_TYPE(sym.st_info) != type) + continue; + if (sym.st_name >= strtabsz) + break; + if ((name = elf_strptr(e, strtabndx, + sym.st_name)) == NULL) + continue; - if (ELF_ST_TYPE(st->st_info) != type) - continue; - - if (st->st_name >= strtabsz) - break; - - *idx = i; - return strtab + st->st_name; + *idx = i; + return name; + } } return NULL; } int -elf_dump(char *p, size_t filesize, uint8_t flags) +elf_dump(uint8_t flags) { - Elf_Ehdr *eh = (Elf_Ehdr *)p; - Elf_Shdr *sh; - const char *shstab; - size_t i, shstabsz; + GElf_Shdr shdr; + Elf_Scn *scn, *scnctf; + Elf_Data *data; + char *name; + size_t shstrndx; + int error = 1; - /* Find section header string table location and size. */ - if (elf_getshstab(p, filesize, &shstab, &shstabsz)) - return 1; - - /* Find symbol table and associated string table. */ - if (elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, &nsymb, - &strtab, &strtabsz) == -1) - warnx("symbol table not found"); - - /* Find CTF section and dump it. */ - for (i = 0; i < eh->e_shnum; i++) { - sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize); - - if ((sh->sh_link >= eh->e_shnum) || - (sh->sh_name >= shstabsz)) - continue; - - if (strncmp(shstab + sh->sh_name, ELF_CTF, strlen(ELF_CTF))) - continue; - - if ((sh->sh_offset + sh->sh_size) > filesize) - continue; - - if (!isctf(p + sh->sh_offset, sh->sh_size)) - break; - - return ctf_dump(p + sh->sh_offset, sh->sh_size, flags); + if (elf_getshdrstrndx(e, &shstrndx) != 0) { + warnx("elf_getshdrstrndx: %s", elf_errmsg(-1)); + return error; } - warnx("%s section not found", ELF_CTF); - return 1; + scn = scnctf = NULL; + while ((scn = elf_nextscn(e, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != &shdr) { + warnx("elf_getshdr: %s", elf_errmsg(-1)); + return error; + } + + if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { + warnx("elf_strptr: %s", elf_errmsg(-1)); + return error; + } + + if (strcmp(name, ELF_CTF) == 0) + scnctf = scn; + + if (strcmp(name, ELF_SYMTAB) == 0 && + shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) { + scnsymtab = scn; + nsymb = shdr.sh_size / shdr.sh_entsize; + } + + if (strcmp(name, ELF_STRTAB) == 0 && + shdr.sh_type == SHT_STRTAB) { + strtabndx = elf_ndxscn(scn); + strtabsz = shdr.sh_size; + } + } + + if (scnctf == NULL) { + warnx("%s section not found", ELF_CTF); + return error; + } + + if (scnsymtab == NULL) + warnx("symbol table not found"); + + data = NULL; + while ((data = elf_rawdata(scnctf, data)) != NULL) { + if (data->d_buf == NULL) { + warnx("%s section size is zero", ELF_CTF); + return error; + } + + if (isctf(data->d_buf, data->d_size)) + error |= ctf_dump(data->d_buf, data->d_size, flags); + } + + return error; } int diff --git a/usr.bin/ctfdump/elf.c b/usr.bin/ctfdump/elf.c index 32d846b621b..e69de29bb2d 100644 --- a/usr.bin/ctfdump/elf.c +++ b/usr.bin/ctfdump/elf.c @@ -1,348 +0,0 @@ -/* $OpenBSD: elf.c,v 1.8 2017/11/14 09:14:50 mpi Exp $ */ - -/* - * Copyright (c) 2016 Martin Pieuchot - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include - -#include -#include -#include -#include - -static int elf_reloc_size(unsigned long); -static void elf_reloc_apply(const char *, size_t, const char *, size_t, - ssize_t, char *, size_t); - -int -iself(const char *p, size_t filesize) -{ - Elf_Ehdr *eh = (Elf_Ehdr *)p; - - if (filesize < (off_t)sizeof(Elf_Ehdr)) { - warnx("file too small to be ELF"); - return 0; - } - - if (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh)) - return 0; - - if (eh->e_ident[EI_CLASS] != ELFCLASS) { - warnx("unexpected word size %u", eh->e_ident[EI_CLASS]); - return 0; - } - if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) { - warnx("unexpected version %u", eh->e_ident[EI_VERSION]); - return 0; - } - if (eh->e_ident[EI_DATA] >= ELFDATANUM) { - warnx("unexpected data format %u", eh->e_ident[EI_DATA]); - return 0; - } - if (eh->e_shoff > filesize) { - warnx("bogus section table offset 0x%llx", (off_t)eh->e_shoff); - return 0; - } - if (eh->e_shentsize < sizeof(Elf_Shdr)) { - warnx("bogus section header size %u", eh->e_shentsize); - return 0; - } - if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) { - warnx("bogus section header count %u", eh->e_shnum); - return 0; - } - if (eh->e_shstrndx >= eh->e_shnum) { - warnx("bogus string table index %u", eh->e_shstrndx); - return 0; - } - - return 1; -} - -int -elf_getshstab(const char *p, size_t filesize, const char **shstab, - size_t *shstabsize) -{ - Elf_Ehdr *eh = (Elf_Ehdr *)p; - Elf_Shdr *sh; - size_t shoff; - - shoff = eh->e_shoff + eh->e_shstrndx * eh->e_shentsize; - if (shoff > (filesize - sizeof(*sh))) { - warnx("unexpected string table size"); - return -1; - } - - sh = (Elf_Shdr *)(p + shoff); - if (sh->sh_type != SHT_STRTAB) { - warnx("unexpected string table type"); - return -1; - } - if (sh->sh_offset > filesize) { - warnx("bogus string table offset"); - return -1; - } - if (sh->sh_size > filesize - sh->sh_offset) { - warnx("bogus string table size"); - return -1; - } - if (shstab != NULL) - *shstab = p + sh->sh_offset; - if (shstabsize != NULL) - *shstabsize = sh->sh_size; - - return 0; -} - -ssize_t -elf_getsymtab(const char *p, size_t filesize, const char *shstab, - size_t shstabsz, const Elf_Sym **symtab, size_t *nsymb, const char **strtab, - size_t *strtabsz) -{ - Elf_Ehdr *eh = (Elf_Ehdr *)p; - Elf_Shdr *sh, *symsh; - size_t snlen, shoff; - ssize_t i; - - snlen = strlen(ELF_SYMTAB); - symsh = NULL; - - for (i = 0; i < eh->e_shnum; i++) { - shoff = eh->e_shoff + i * eh->e_shentsize; - if (shoff > (filesize - sizeof(*sh))) - continue; - - sh = (Elf_Shdr *)(p + shoff); - if (sh->sh_type != SHT_SYMTAB) - continue; - - if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz)) - continue; - - if (sh->sh_offset > filesize) - continue; - - if (sh->sh_size > (filesize - sh->sh_offset)) - continue; - - if (sh->sh_entsize == 0) - continue; - - if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) { - if (symtab != NULL) - *symtab = (Elf_Sym *)(p + sh->sh_offset); - if (nsymb != NULL) - *nsymb = (sh->sh_size / sh->sh_entsize); - symsh = sh; - - break; - } - } - - if (symsh == NULL || (symsh->sh_link >= eh->e_shnum)) - return -1; - - shoff = eh->e_shoff + symsh->sh_link * eh->e_shentsize; - if (shoff > (filesize - sizeof(*sh))) - return -1; - - sh = (Elf_Shdr *)(p + shoff); - if ((sh->sh_offset + sh->sh_size) > filesize) - return -1; - - if (strtab != NULL) - *strtab = p + sh->sh_offset; - if (strtabsz != NULL) - *strtabsz = sh->sh_size; - - return i; -} - -ssize_t -elf_getsection(char *p, size_t filesize, const char *sname, const char *shstab, - size_t shstabsz, const char **psdata, size_t *pssz) -{ - Elf_Ehdr *eh = (Elf_Ehdr *)p; - Elf_Shdr *sh; - char *sdata = NULL; - size_t snlen, shoff, ssz = 0; - ssize_t sidx, i; - - snlen = strlen(sname); - if (snlen == 0) - return -1; - - /* Find the given section. */ - for (i = 0; i < eh->e_shnum; i++) { - shoff = eh->e_shoff + i * eh->e_shentsize; - if (shoff > (filesize - sizeof(*sh))) - continue; - - sh = (Elf_Shdr *)(p + shoff); - if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz)) - continue; - - if (sh->sh_offset > filesize) - continue; - - if (sh->sh_size > (filesize - sh->sh_offset)) - continue; - - if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) { - sidx = i; - sdata = p + sh->sh_offset; - ssz = sh->sh_size; - elf_reloc_apply(p, filesize, shstab, shstabsz, sidx, - sdata, ssz); - break; - } - } - - if (sdata == NULL) - return -1; - - if (psdata != NULL) - *psdata = sdata; - if (pssz != NULL) - *pssz = ssz; - - return sidx; -} - -static int -elf_reloc_size(unsigned long type) -{ - switch (type) { -#ifdef R_X86_64_64 - case R_X86_64_64: - return sizeof(uint64_t); -#endif -#ifdef R_X86_64_32 - case R_X86_64_32: - return sizeof(uint32_t); -#endif -#ifdef RELOC_32 - case RELOC_32: - return sizeof(uint32_t); -#endif - default: - break; - } - - return -1; -} - -#define ELF_WRITE_RELOC(buf, val, rsize) \ -do { \ - if (rsize == 4) { \ - uint32_t v32 = val; \ - memcpy(buf, &v32, sizeof(v32)); \ - } else { \ - uint64_t v64 = val; \ - memcpy(buf, &v64, sizeof(v64)); \ - } \ -} while (0) - -static void -elf_reloc_apply(const char *p, size_t filesize, const char *shstab, - size_t shstabsz, ssize_t sidx, char *sdata, size_t ssz) -{ - Elf_Ehdr *eh = (Elf_Ehdr *)p; - Elf_Shdr *sh; - Elf_Rel *rel = NULL; - Elf_RelA *rela = NULL; - const Elf_Sym *symtab, *sym; - ssize_t symtabidx; - size_t nsymb, rsym, rtyp, roff; - size_t shoff, i, j; - uint64_t value; - int rsize; - - /* Find symbol table location and number of symbols. */ - symtabidx = elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, - &nsymb, NULL, NULL); - if (symtabidx == -1) { - warnx("symbol table not found"); - return; - } - - /* Apply possible relocation. */ - for (i = 0; i < eh->e_shnum; i++) { - shoff = eh->e_shoff + i * eh->e_shentsize; - if (shoff > (filesize - sizeof(*sh))) - continue; - - sh = (Elf_Shdr *)(p + shoff); - if (sh->sh_size == 0) - continue; - - if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx)) - continue; - - if (sh->sh_offset > filesize) - continue; - - if (sh->sh_size > (filesize - sh->sh_offset)) - continue; - - switch (sh->sh_type) { - case SHT_RELA: - rela = (Elf_RelA *)(p + sh->sh_offset); - for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) { - rsym = ELF_R_SYM(rela[j].r_info); - rtyp = ELF_R_TYPE(rela[j].r_info); - roff = rela[j].r_offset; - if (rsym >= nsymb) - continue; - if (roff >= filesize) - continue; - sym = &symtab[rsym]; - value = sym->st_value + rela[j].r_addend; - - rsize = elf_reloc_size(rtyp); - if (rsize == -1 || roff + rsize >= ssz) - continue; - - ELF_WRITE_RELOC(sdata + roff, value, rsize); - } - break; - case SHT_REL: - rel = (Elf_Rel *)(p + sh->sh_offset); - for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) { - rsym = ELF_R_SYM(rel[j].r_info); - rtyp = ELF_R_TYPE(rel[j].r_info); - roff = rel[j].r_offset; - if (rsym >= nsymb) - continue; - if (roff >= filesize) - continue; - sym = &symtab[rsym]; - value = sym->st_value; - - rsize = elf_reloc_size(rtyp); - if (rsize == -1 || roff + rsize >= ssz) - continue; - - ELF_WRITE_RELOC(sdata + roff, value, rsize); - } - break; - default: - continue; - } - } -}