summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSunil Nimmagadda <sunil@cvs.openbsd.org>2019-05-14 03:16:56 +0000
committerSunil Nimmagadda <sunil@cvs.openbsd.org>2019-05-14 03:16:56 +0000
commit51bcd0c26ec6365524f28426f2310d77f324cce1 (patch)
tree68bd59bc0304b77686fb945c3c45f11d8226fae2
parent502ea20b4e716f9f6fe460b8889b7ff795e66b52 (diff)
Use elf(3) api instead of an ad-hoc elf parser.
Ok mpi@
-rw-r--r--usr.bin/ctfdump/Makefile6
-rw-r--r--usr.bin/ctfdump/ctfdump.c172
-rw-r--r--usr.bin/ctfdump/elf.c348
3 files changed, 106 insertions, 420 deletions
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 <bsd.prog.mk>
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 <mpi@openbsd.org>
@@ -21,9 +21,10 @@
#include <sys/mman.h>
#include <sys/ctf.h>
-#include <elf.h>
#include <err.h>
#include <fcntl.h>
+#include <gelf.h>
+#include <libelf.h>
#include <locale.h>
#include <stdio.h>
#include <stdint.h>
@@ -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];
-
- if (ELF_ST_TYPE(st->st_info) != type)
- continue;
-
- if (st->st_name >= strtabsz)
- break;
+ 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;
- *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;
+
+ if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+ warnx("elf_getshdrstrndx: %s", elf_errmsg(-1));
+ return error;
+ }
- /* Find section header string table location and size. */
- if (elf_getshstab(p, filesize, &shstab, &shstabsz))
- 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;
+ }
- /* Find symbol table and associated string table. */
- if (elf_getsymtab(p, filesize, shstab, shstabsz, &symtab, &nsymb,
- &strtab, &strtabsz) == -1)
- warnx("symbol table not found");
+ if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
+ warnx("elf_strptr: %s", elf_errmsg(-1));
+ return error;
+ }
- /* 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 (strcmp(name, ELF_CTF) == 0)
+ scnctf = scn;
- if ((sh->sh_link >= eh->e_shnum) ||
- (sh->sh_name >= shstabsz))
- continue;
+ 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 (strncmp(shstab + sh->sh_name, ELF_CTF, strlen(ELF_CTF)))
- continue;
+ if (strcmp(name, ELF_STRTAB) == 0 &&
+ shdr.sh_type == SHT_STRTAB) {
+ strtabndx = elf_ndxscn(scn);
+ strtabsz = shdr.sh_size;
+ }
+ }
- if ((sh->sh_offset + sh->sh_size) > filesize)
- continue;
+ if (scnctf == NULL) {
+ warnx("%s section not found", ELF_CTF);
+ return error;
+ }
- if (!isctf(p + sh->sh_offset, sh->sh_size))
- break;
+ 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;
+ }
- return ctf_dump(p + sh->sh_offset, sh->sh_size, flags);
+ if (isctf(data->d_buf, data->d_size))
+ error |= ctf_dump(data->d_buf, data->d_size, flags);
}
- warnx("%s section not found", ELF_CTF);
- return 1;
+ 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 <mpi@openbsd.org>
- *
- * 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 <sys/types.h>
-
-#include <machine/reloc.h>
-
-#include <assert.h>
-#include <elf.h>
-#include <err.h>
-#include <string.h>
-
-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;
- }
- }
-}