aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2023-12-12 23:43:00 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2023-12-12 23:43:00 +0000
commit0299afdff145e5d861797fe9c2de8b090c456fba (patch)
tree7f424aa8d74f77fea9c3c048fe945edef0aadb89
parentc40fa3dc98d3cd8c39605c19c9cc08026d8e72c9 (diff)
downloadsrc-0299afdff145e5d861797fe9c2de8b090c456fba.tar.gz
src-0299afdff145e5d861797fe9c2de8b090c456fba.zip
kldxref: Make use of libelf to be a portable cross tool
This allows kldxref to operate on kernel objects from any architecture, not just the native architecture. In particular, this will permit generating linker.hints files as part of a cross-arch release build. - elf.c is a new file that includes various wrappers around libelf including routines to read ELF data structures such as program and section headers and ELF relocations into the "generic" forms described in <gelf.h>. This file also provides routines for converting a linker set into an array of addresses (GElf_Addr) as well as reading architecture-specific mod_* structures and converting them into "generic" Gmod_* forms where pointers are replaced with addresses. - The various architecture-specific reloc handlers now use GElf_* types for most values (including GElf_Rel and GElf_Rela for relocation structures) and use routines from <sys/endian.h> to read and write target values. A new linker set matches reloc handlers to specific ELF (class, encoding, machine) tuples. - The bits of kldxref.c that write out linker.hints now use the encoding (ELFDATA2[LM]SB) of the first file encountered in a directory to set the endianness of the output file. Input files with a different architecture in the same directory are skipped with a warning. In addition, the initial version record for the file must be deferred until the first record is finished since the architecture of the output file is not known until then. - Various places that used 'sizeof(void *)' throughout now use 'elf_pointer_size()' to determine the size of a pointer in the target architecture. Tested by: amd64 binary on both amd64 and i386 /boot/kernel Reviewed by: imp Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D42966
-rw-r--r--usr.sbin/kldxref/Makefile9
-rw-r--r--usr.sbin/kldxref/ef.c730
-rw-r--r--usr.sbin/kldxref/ef.h291
-rw-r--r--usr.sbin/kldxref/ef_aarch64.c32
-rw-r--r--usr.sbin/kldxref/ef_amd64.c65
-rw-r--r--usr.sbin/kldxref/ef_i386.c56
-rw-r--r--usr.sbin/kldxref/ef_mips.c79
-rw-r--r--usr.sbin/kldxref/ef_nop.c40
-rw-r--r--usr.sbin/kldxref/ef_obj.c341
-rw-r--r--usr.sbin/kldxref/ef_powerpc.c62
-rw-r--r--usr.sbin/kldxref/ef_riscv.c35
-rw-r--r--usr.sbin/kldxref/elf.c674
-rw-r--r--usr.sbin/kldxref/kldxref.c196
13 files changed, 1685 insertions, 925 deletions
diff --git a/usr.sbin/kldxref/Makefile b/usr.sbin/kldxref/Makefile
index 3d4ce7163b48..6e0a7244328b 100644
--- a/usr.sbin/kldxref/Makefile
+++ b/usr.sbin/kldxref/Makefile
@@ -2,14 +2,11 @@
PACKAGE= runtime
PROG= kldxref
MAN= kldxref.8
-SRCS= kldxref.c ef.c ef_obj.c
+SRCS= kldxref.c ef.c ef_obj.c elf.c
+SRCS+= ef_aarch64.c ef_amd64.c ef_i386.c ef_mips.c ef_powerpc.c ef_riscv.c
WARNS?= 2
-.if exists(ef_${MACHINE_CPUARCH}.c)
-SRCS+= ef_${MACHINE_CPUARCH}.c
-.else
-SRCS+= ef_nop.c
-.endif
+LIBADD= elf
.include <bsd.prog.mk>
diff --git a/usr.sbin/kldxref/ef.c b/usr.sbin/kldxref/ef.c
index 72e023e30783..aa9123d7f540 100644
--- a/usr.sbin/kldxref/ef.c
+++ b/usr.sbin/kldxref/ef.c
@@ -33,16 +33,13 @@
*/
#include <sys/param.h>
-#include <sys/linker.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
+#include <gelf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <machine/elf.h>
#include "ef.h"
@@ -50,76 +47,52 @@
struct ef_file {
char *ef_name;
struct elf_file *ef_efile;
- Elf_Phdr *ef_ph;
- int ef_fd;
- int ef_type;
- Elf_Ehdr ef_hdr;
+ GElf_Phdr *ef_ph;
void *ef_fpage; /* First block of the file */
int ef_fplen; /* length of first block */
- Elf_Dyn *ef_dyn; /* Symbol table etc. */
- Elf_Hashelt ef_nbuckets;
- Elf_Hashelt ef_nchains;
- Elf_Hashelt *ef_buckets;
- Elf_Hashelt *ef_chains;
- Elf_Hashelt *ef_hashtab;
- Elf_Off ef_stroff;
+ GElf_Hashelt ef_nbuckets;
+ GElf_Hashelt ef_nchains;
+ GElf_Hashelt *ef_buckets;
+ GElf_Hashelt *ef_chains;
+ GElf_Hashelt *ef_hashtab;
caddr_t ef_strtab;
- int ef_strsz;
- Elf_Off ef_symoff;
- Elf_Sym *ef_symtab;
+ long ef_strsz;
+ GElf_Sym *ef_symtab;
int ef_nsegs;
- Elf_Phdr *ef_segs[MAXSEGS];
+ GElf_Phdr *ef_segs[MAXSEGS];
int ef_verbose;
- Elf_Rel *ef_rel; /* relocation table */
- int ef_relsz; /* number of entries */
- Elf_Rela *ef_rela; /* relocation table */
- int ef_relasz; /* number of entries */
+ GElf_Rel *ef_rel; /* relocation table */
+ long ef_relsz; /* number of entries */
+ GElf_Rela *ef_rela; /* relocation table */
+ long ef_relasz; /* number of entries */
};
-static void ef_print_phdr(Elf_Phdr *);
-static Elf_Off ef_get_offset(elf_file_t, Elf_Off);
-static int ef_parse_dynamic(elf_file_t);
+static void ef_print_phdr(GElf_Phdr *);
+static GElf_Off ef_get_offset(elf_file_t, GElf_Addr);
-static int ef_get_type(elf_file_t ef);
-static int ef_close(elf_file_t ef);
-static int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
-static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr);
+static void ef_close(elf_file_t ef);
-static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len,
+static int ef_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len,
void *dest);
-static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
- void *dest);
-static int ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len,
+static int ef_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len,
char *dest);
-static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr);
-static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr);
-
-static Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx);
-static int ef_lookup_set(elf_file_t ef, const char *name, long *startp,
- long *stopp, long *countp);
+
+static GElf_Addr ef_symaddr(elf_file_t ef, GElf_Size symidx);
+static int ef_lookup_set(elf_file_t ef, const char *name,
+ GElf_Addr *startp, GElf_Addr *stopp, long *countp);
static int ef_lookup_symbol(elf_file_t ef, const char *name,
- Elf_Sym **sym);
+ GElf_Sym **sym);
static struct elf_file_ops ef_file_ops = {
- .get_type = ef_get_type,
.close = ef_close,
- .read = ef_read,
- .read_entry = ef_read_entry,
- .seg_read = ef_seg_read,
.seg_read_rel = ef_seg_read_rel,
.seg_read_string = ef_seg_read_string,
- .seg_read_entry = ef_seg_read_entry,
- .seg_read_entry_rel = ef_seg_read_entry_rel,
.symaddr = ef_symaddr,
.lookup_set = ef_lookup_set,
- .lookup_symbol = ef_lookup_symbol
};
static void
-ef_print_phdr(Elf_Phdr *phdr)
+ef_print_phdr(GElf_Phdr *phdr)
{
if ((phdr->p_flags & PF_W) == 0) {
@@ -133,53 +106,29 @@ ef_print_phdr(Elf_Phdr *phdr)
}
}
-static Elf_Off
-ef_get_offset(elf_file_t ef, Elf_Off off)
+static GElf_Off
+ef_get_offset(elf_file_t ef, GElf_Addr addr)
{
- Elf_Phdr *ph;
+ GElf_Phdr *ph;
int i;
for (i = 0; i < ef->ef_nsegs; i++) {
ph = ef->ef_segs[i];
- if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
- return (ph->p_offset + (off - ph->p_vaddr));
+ if (addr >= ph->p_vaddr && addr < ph->p_vaddr + ph->p_memsz) {
+ return (ph->p_offset + (addr - ph->p_vaddr));
}
}
return (0);
}
-static int
-ef_get_type(elf_file_t ef)
-{
-
- return (ef->ef_type);
-}
-
/*
- * next three functions copied from link_elf.c
+ * next two functions copied from link_elf.c
*/
-static unsigned long
-elf_hash(const char *name)
-{
- unsigned long h, g;
- const unsigned char *p;
-
- h = 0;
- p = (const unsigned char *)name;
- while (*p != '\0') {
- h = (h << 4) + *p++;
- if ((g = h & 0xf0000000) != 0)
- h ^= g >> 24;
- h &= ~g;
- }
- return (h);
-}
-
static int
-ef_lookup_symbol(elf_file_t ef, const char *name, Elf_Sym **sym)
+ef_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
{
unsigned long hash, symnum;
- Elf_Sym *symp;
+ GElf_Sym *symp;
char *strp;
/* First, search hashed global symbols */
@@ -205,7 +154,7 @@ ef_lookup_symbol(elf_file_t ef, const char *name, Elf_Sym **sym)
if (strcmp(name, strp) == 0) {
if (symp->st_shndx != SHN_UNDEF ||
(symp->st_value != 0 &&
- ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
+ GELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
*sym = symp;
return (0);
} else
@@ -219,10 +168,10 @@ ef_lookup_symbol(elf_file_t ef, const char *name, Elf_Sym **sym)
}
static int
-ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
- long *countp)
+ef_lookup_set(elf_file_t ef, const char *name, GElf_Addr *startp,
+ GElf_Addr *stopp, long *countp)
{
- Elf_Sym *sym;
+ GElf_Sym *sym;
char *setsym;
int error, len;
@@ -246,258 +195,340 @@ ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
*stopp = sym->st_value;
/* and the number of entries */
- *countp = (*stopp - *startp) / sizeof(void *);
+ *countp = (*stopp - *startp) / elf_pointer_size(ef->ef_efile);
out:
free(setsym);
return (error);
}
-static Elf_Addr
-ef_symaddr(elf_file_t ef, Elf_Size symidx)
+static GElf_Addr
+ef_symaddr(elf_file_t ef, GElf_Size symidx)
{
- const Elf_Sym *sym;
+ const GElf_Sym *sym;
if (symidx >= ef->ef_nchains)
return (0);
sym = ef->ef_symtab + symidx;
- if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
+ if (GELF_ST_BIND(sym->st_info) == STB_LOCAL &&
sym->st_shndx != SHN_UNDEF && sym->st_value != 0)
return (sym->st_value);
return (0);
}
static int
-ef_parse_dynamic(elf_file_t ef)
+ef_parse_dynamic(elf_file_t ef, const GElf_Phdr *phdyn)
{
- Elf_Dyn *dp;
- Elf_Hashelt hashhdr[2];
+ GElf_Shdr *shdr;
+ GElf_Dyn *dyn, *dp;
+ size_t i, ndyn, nshdr, nsym;
int error;
- Elf_Off rel_off;
- Elf_Off rela_off;
+ GElf_Off hash_off, sym_off, str_off;
+ GElf_Off rel_off;
+ GElf_Off rela_off;
int rel_sz;
int rela_sz;
- int rel_entry;
- int rela_entry;
+ int dynamic_idx;
+
+ /*
+ * The kernel linker parses the PT_DYNAMIC segment to find
+ * various important tables. The gelf API of libelf is
+ * section-oriented and requires extracting data from sections
+ * instead of segments (program headers). As a result,
+ * iterate over section headers to read various tables after
+ * parsing values from PT_DYNAMIC.
+ */
+ error = elf_read_shdrs(ef->ef_efile, &nshdr, &shdr);
+ if (error != 0)
+ return (EFTYPE);
+ dyn = NULL;
+
+ /* Find section for .dynamic. */
+ dynamic_idx = -1;
+ for (i = 0; i < nshdr; i++) {
+ if (shdr[i].sh_type == SHT_DYNAMIC) {
+ if (shdr[i].sh_offset != phdyn->p_offset ||
+ shdr[i].sh_size != phdyn->p_filesz) {
+ warnx(".dynamic section doesn't match phdr");
+ error = EFTYPE;
+ goto out;
+ }
+ if (dynamic_idx != -1) {
+ warnx("multiple SHT_DYNAMIC sections");
+ error = EFTYPE;
+ goto out;
+ }
+ dynamic_idx = i;
+ }
+ }
+
+ error = elf_read_dynamic(ef->ef_efile, dynamic_idx, &ndyn, &dyn);
+ if (error != 0)
+ goto out;
- rel_off = rela_off = 0;
+ hash_off = rel_off = rela_off = sym_off = str_off = 0;
rel_sz = rela_sz = 0;
- rel_entry = rela_entry = 0;
- for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
+ for (i = 0; i < ndyn; i++) {
+ dp = &dyn[i];
+ if (dp->d_tag == DT_NULL)
+ break;
+
switch (dp->d_tag) {
case DT_HASH:
- error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
- sizeof(hashhdr), hashhdr);
- if (error != 0) {
- warnx("can't read hash header (%jx)",
- (uintmax_t)ef_get_offset(ef, dp->d_un.d_ptr));
- return (error);
- }
- ef->ef_nbuckets = hashhdr[0];
- ef->ef_nchains = hashhdr[1];
- error = ef_read_entry(ef, -1,
- (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
- (void **)&ef->ef_hashtab);
- if (error != 0) {
- warnx("can't read hash table");
- return (error);
- }
- ef->ef_buckets = ef->ef_hashtab;
- ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
+ if (hash_off != 0)
+ warnx("second DT_HASH entry ignored");
+ else
+ hash_off = ef_get_offset(ef, dp->d_un.d_ptr);
break;
case DT_STRTAB:
- ef->ef_stroff = dp->d_un.d_ptr;
- break;
- case DT_STRSZ:
- ef->ef_strsz = dp->d_un.d_val;
+ if (str_off != 0)
+ warnx("second DT_STRTAB entry ignored");
+ else
+ str_off = ef_get_offset(ef, dp->d_un.d_ptr);
break;
case DT_SYMTAB:
- ef->ef_symoff = dp->d_un.d_ptr;
+ if (sym_off != 0)
+ warnx("second DT_SYMTAB entry ignored");
+ else
+ sym_off = ef_get_offset(ef, dp->d_un.d_ptr);
break;
case DT_SYMENT:
- if (dp->d_un.d_val != sizeof(Elf_Sym))
- return (EFTYPE);
+ if (dp->d_un.d_val != elf_object_size(ef->ef_efile,
+ ELF_T_SYM)) {
+ error = EFTYPE;
+ goto out;
+ }
break;
case DT_REL:
if (rel_off != 0)
warnx("second DT_REL entry ignored");
- rel_off = dp->d_un.d_ptr;
+ else
+ rel_off = ef_get_offset(ef, dp->d_un.d_ptr);
break;
case DT_RELSZ:
if (rel_sz != 0)
warnx("second DT_RELSZ entry ignored");
- rel_sz = dp->d_un.d_val;
+ else
+ rel_sz = dp->d_un.d_val;
break;
case DT_RELENT:
- if (rel_entry != 0)
- warnx("second DT_RELENT entry ignored");
- rel_entry = dp->d_un.d_val;
+ if (dp->d_un.d_val != elf_object_size(ef->ef_efile,
+ ELF_T_REL)) {
+ error = EFTYPE;
+ goto out;
+ }
break;
case DT_RELA:
if (rela_off != 0)
warnx("second DT_RELA entry ignored");
- rela_off = dp->d_un.d_ptr;
+ else
+ rela_off = ef_get_offset(ef, dp->d_un.d_ptr);
break;
case DT_RELASZ:
if (rela_sz != 0)
- warnx("second DT_RELASZ entry ignored");
- rela_sz = dp->d_un.d_val;
+ warnx("second DT_RELSZ entry ignored");
+ else
+ rela_sz = dp->d_un.d_val;
break;
case DT_RELAENT:
- if (rela_entry != 0)
- warnx("second DT_RELAENT entry ignored");
- rela_entry = dp->d_un.d_val;
+ if (dp->d_un.d_val != elf_object_size(ef->ef_efile,
+ ELF_T_RELA)) {
+ error = EFTYPE;
+ goto out;
+ }
break;
}
}
- if (ef->ef_symoff == 0) {
+ if (hash_off == 0) {
+ warnx("%s: no .hash section found\n", ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ if (sym_off == 0) {
warnx("%s: no .dynsym section found\n", ef->ef_name);
- return (EFTYPE);
+ error = EFTYPE;
+ goto out;
}
- if (ef->ef_stroff == 0) {
+ if (str_off == 0) {
warnx("%s: no .dynstr section found\n", ef->ef_name);
- return (EFTYPE);
- }
- if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
- ef->ef_nchains * sizeof(Elf_Sym),
- (void **)&ef->ef_symtab) != 0) {
- if (ef->ef_verbose)
- warnx("%s: can't load .dynsym section (0x%jx)",
- ef->ef_name, (uintmax_t)ef->ef_symoff);
- return (EIO);
- }
- if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
- (void **)&ef->ef_strtab) != 0) {
- warnx("can't load .dynstr section");
- return (EIO);
- }
- if (rel_off != 0) {
- if (rel_entry == 0) {
- warnx("%s: no DT_RELENT for DT_REL", ef->ef_name);
- return (EFTYPE);
- }
- if (rel_entry != sizeof(Elf_Rel)) {
- warnx("%s: inconsistent DT_RELENT value",
- ef->ef_name);
- return (EFTYPE);
- }
- if (rel_sz % rel_entry != 0) {
- warnx("%s: inconsistent values for DT_RELSZ and "
- "DT_RELENT", ef->ef_name);
- return (EFTYPE);
- }
- if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz,
- (void **)&ef->ef_rel) != 0) {
- warnx("%s: cannot load DT_REL section", ef->ef_name);
- return (EIO);
- }
- ef->ef_relsz = rel_sz / rel_entry;
- if (ef->ef_verbose)
- warnx("%s: %d REL entries", ef->ef_name,
- ef->ef_relsz);
+ error = EFTYPE;
+ goto out;
}
- if (rela_off != 0) {
- if (rela_entry == 0) {
- warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name);
- return (EFTYPE);
- }
- if (rela_entry != sizeof(Elf_Rela)) {
- warnx("%s: inconsistent DT_RELAENT value",
- ef->ef_name);
- return (EFTYPE);
- }
- if (rela_sz % rela_entry != 0) {
- warnx("%s: inconsistent values for DT_RELASZ and "
- "DT_RELAENT", ef->ef_name);
- return (EFTYPE);
- }
- if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz,
- (void **)&ef->ef_rela) != 0) {
- warnx("%s: cannot load DT_RELA section", ef->ef_name);
- return (EIO);
- }
- ef->ef_relasz = rela_sz / rela_entry;
- if (ef->ef_verbose)
- warnx("%s: %d RELA entries", ef->ef_name,
- ef->ef_relasz);
+ if (rel_off == 0 && rela_off == 0) {
+ warnx("%s: no ELF relocation table found\n", ef->ef_name);
+ error = EFTYPE;
+ goto out;
}
- return (0);
-}
-static int
-ef_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
-{
- ssize_t r;
+ for (i = 0; i < nshdr; i++) {
+ switch (shdr[i].sh_type) {
+ case SHT_HASH:
+ if (shdr[i].sh_offset != hash_off) {
+ warnx("%s: ignoring SHT_HASH at different offset from DT_HASH",
+ ef->ef_name);
+ break;
+ }
- if (offset != (Elf_Off)-1) {
- if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
- return (EIO);
- }
+ /*
+ * libelf(3) mentions ELF_T_HASH, but it is
+ * not defined.
+ */
+ if (shdr[i].sh_size < sizeof(*ef->ef_hashtab) * 2) {
+ warnx("hash section too small");
+ error = EFTYPE;
+ goto out;
+ }
+ error = elf_read_data(ef->ef_efile, ELF_T_WORD,
+ shdr[i].sh_offset, shdr[i].sh_size,
+ (void **)&ef->ef_hashtab);
+ if (error != 0) {
+ warnc(error, "can't read hash table");
+ goto out;
+ }
+ ef->ef_nbuckets = ef->ef_hashtab[0];
+ ef->ef_nchains = ef->ef_hashtab[1];
+ if ((2 + ef->ef_nbuckets + ef->ef_nchains) *
+ sizeof(*ef->ef_hashtab) != shdr[i].sh_size) {
+ warnx("inconsistent hash section size");
+ error = EFTYPE;
+ goto out;
+ }
- r = read(ef->ef_fd, dest, len);
- if (r != -1 && (size_t)r == len)
- return (0);
- else
- return (EIO);
-}
+ ef->ef_buckets = ef->ef_hashtab + 2;
+ ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
+ break;
+ case SHT_DYNSYM:
+ if (shdr[i].sh_offset != sym_off) {
+ warnx("%s: ignoring SHT_DYNSYM at different offset from DT_SYMTAB",
+ ef->ef_name);
+ break;
+ }
+ error = elf_read_symbols(ef->ef_efile, i, &nsym,
+ &ef->ef_symtab);
+ if (error != 0) {
+ if (ef->ef_verbose)
+ warnx("%s: can't load .dynsym section (0x%jx)",
+ ef->ef_name, (uintmax_t)sym_off);
+ goto out;
+ }
+ break;
+ case SHT_STRTAB:
+ if (shdr[i].sh_offset != str_off)
+ break;
+ error = elf_read_string_table(ef->ef_efile,
+ &shdr[i], &ef->ef_strsz, &ef->ef_strtab);
+ if (error != 0) {
+ warnx("can't load .dynstr section");
+ error = EIO;
+ goto out;
+ }
+ break;
+ case SHT_REL:
+ if (shdr[i].sh_offset != rel_off)
+ break;
+ if (shdr[i].sh_size != rel_sz) {
+ warnx("%s: size mismatch for DT_REL section",
+ ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ error = elf_read_rel(ef->ef_efile, i, &ef->ef_relsz,
+ &ef->ef_rel);
+ if (error != 0) {
+ warnx("%s: cannot load DT_REL section",
+ ef->ef_name);
+ goto out;
+ }
+ break;
+ case SHT_RELA:
+ if (shdr[i].sh_offset != rela_off)
+ break;
+ if (shdr[i].sh_size != rela_sz) {
+ warnx("%s: size mismatch for DT_RELA section",
+ ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ error = elf_read_rela(ef->ef_efile, i, &ef->ef_relasz,
+ &ef->ef_rela);
+ if (error != 0) {
+ warnx("%s: cannot load DT_RELA section",
+ ef->ef_name);
+ goto out;
+ }
+ break;
+ }
+ }
-static int
-ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
-{
- int error;
+ if (ef->ef_hashtab == NULL) {
+ warnx("%s: did not find a symbol hash table", ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ if (ef->ef_symtab == NULL) {
+ warnx("%s: did not find a dynamic symbol table", ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ if (nsym != ef->ef_nchains) {
+ warnx("%s: symbol count mismatch", ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ if (ef->ef_strtab == NULL) {
+ warnx("%s: did not find a dynamic string table", ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ if (rel_off != 0 && ef->ef_rel == NULL) {
+ warnx("%s: did not find a DT_REL relocation table",
+ ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
+ if (rela_off != 0 && ef->ef_rela == NULL) {
+ warnx("%s: did not find a DT_RELA relocation table",
+ ef->ef_name);
+ error = EFTYPE;
+ goto out;
+ }
- *ptr = malloc(len);
- if (*ptr == NULL)
- return (errno);
- error = ef_read(ef, offset, len, *ptr);
- if (error != 0)
- free(*ptr);
+ error = 0;
+out:
+ free(dyn);
+ free(shdr);
return (error);
}
static int
-ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
+ef_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest)
{
- Elf_Off ofs;
-
- ofs = ef_get_offset(ef, offset);
- if (ofs == 0) {
- if (ef->ef_verbose)
- warnx("ef_seg_read(%s): zero offset (%jx:%ju)",
- ef->ef_name, (uintmax_t)offset, (uintmax_t)ofs);
- return (EFAULT);
- }
- return (ef_read(ef, ofs, len, dest));
-}
-
-static int
-ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
-{
- Elf_Off ofs;
- const Elf_Rela *a;
- const Elf_Rel *r;
+ GElf_Off ofs;
+ const GElf_Rela *a;
+ const GElf_Rel *r;
int error;
- ofs = ef_get_offset(ef, offset);
+ ofs = ef_get_offset(ef, address);
if (ofs == 0) {
if (ef->ef_verbose)
warnx("ef_seg_read_rel(%s): zero offset (%jx:%ju)",
- ef->ef_name, (uintmax_t)offset, (uintmax_t)ofs);
+ ef->ef_name, (uintmax_t)address, (uintmax_t)ofs);
return (EFAULT);
}
- if ((error = ef_read(ef, ofs, len, dest)) != 0)
+ error = elf_read_raw_data(ef->ef_efile, ofs, dest, len);
+ if (error != 0)
return (error);
for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
- error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len,
- dest);
+ error = elf_reloc(ef->ef_efile, r, ELF_T_REL, 0, address,
+ len, dest);
if (error != 0)
return (error);
}
for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
- error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len,
- dest);
+ error = elf_reloc(ef->ef_efile, a, ELF_T_RELA, 0, address,
+ len, dest);
if (error != 0)
return (error);
}
@@ -505,168 +536,115 @@ ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
}
static int
-ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest)
+ef_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char *dest)
{
- Elf_Off ofs;
- ssize_t r;
+ GElf_Off ofs;
+ int error;
- ofs = ef_get_offset(ef, offset);
- if (ofs == 0 || ofs == (Elf_Off)-1) {
+ ofs = ef_get_offset(ef, address);
+ if (ofs == 0 || ofs == (GElf_Off)-1) {
if (ef->ef_verbose)
warnx("ef_seg_read_string(%s): bad offset (%jx:%ju)",
- ef->ef_name, (uintmax_t)offset, (uintmax_t)ofs);
+ ef->ef_name, (uintmax_t)address, (uintmax_t)ofs);
return (EFAULT);
}
- r = pread(ef->ef_fd, dest, len, ofs);
- if (r < 0)
- return (errno);
+ error = elf_read_raw_data(ef->ef_efile, ofs, dest, len);
+ if (error != 0)
+ return (error);
if (strnlen(dest, len) == len)
return (EFAULT);
return (0);
}
-static int
-ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
-{
- int error;
-
- *ptr = malloc(len);
- if (*ptr == NULL)
- return (errno);
- error = ef_seg_read(ef, offset, len, *ptr);
- if (error != 0)
- free(*ptr);
- return (error);
-}
-
-static int
-ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
-{
- int error;
-
- *ptr = malloc(len);
- if (*ptr == NULL)
- return (errno);
- error = ef_seg_read_rel(ef, offset, len, *ptr);
- if (error != 0)
- free(*ptr);
- return (error);
-}
-
int
-ef_open(const char *filename, struct elf_file *efile, int verbose)
+ef_open(struct elf_file *efile, int verbose)
{
elf_file_t ef;
- Elf_Ehdr *hdr;
- int fd;
+ GElf_Ehdr *hdr;
+ size_t i, nphdr, nsegs;
int error;
- int phlen, res;
- int nsegs;
- Elf_Phdr *phdr, *phdyn, *phlimit;
+ GElf_Phdr *phdr, *phdyn;
- if (filename == NULL)
- return (EINVAL);
- if ((fd = open(filename, O_RDONLY)) == -1)
- return (errno);
+ hdr = &efile->ef_hdr;
+ if (hdr->e_phnum == 0 ||
+ hdr->e_phentsize != elf_object_size(efile, ELF_T_PHDR) ||
+ hdr->e_shnum == 0 || hdr->e_shoff == 0 ||
+ hdr->e_shentsize != elf_object_size(efile, ELF_T_SHDR))
+ return (EFTYPE);
ef = malloc(sizeof(*ef));
- if (ef == NULL) {
- close(fd);
+ if (ef == NULL)
return (errno);
- }
efile->ef_ef = ef;
efile->ef_ops = &ef_file_ops;
bzero(ef, sizeof(*ef));
ef->ef_verbose = verbose;
- ef->ef_fd = fd;
- ef->ef_name = strdup(filename);
+ ef->ef_name = strdup(efile->ef_filename);
ef->ef_efile = efile;
- hdr = (Elf_Ehdr *)&ef->ef_hdr;
- do {
- res = read(fd, hdr, sizeof(*hdr));
- error = EFTYPE;
- if (res != sizeof(*hdr))
- break;
- if (!IS_ELF(*hdr))
- break;
- if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
- hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
- hdr->e_ident[EI_VERSION] != EV_CURRENT ||
- hdr->e_version != EV_CURRENT ||
- hdr->e_machine != ELF_TARG_MACH ||
- hdr->e_phentsize != sizeof(Elf_Phdr))
- break;
- phlen = hdr->e_phnum * sizeof(Elf_Phdr);
- if (ef_read_entry(ef, hdr->e_phoff, phlen,
- (void **)&ef->ef_ph) != 0)
- break;
- phdr = ef->ef_ph;
- phlimit = phdr + hdr->e_phnum;
- nsegs = 0;
- phdyn = NULL;
- while (phdr < phlimit) {
- if (verbose > 1)
- ef_print_phdr(phdr);
- switch (phdr->p_type) {
- case PT_LOAD:
- if (nsegs < MAXSEGS)
- ef->ef_segs[nsegs] = phdr;
- nsegs++;
- break;
- case PT_PHDR:
- break;
- case PT_DYNAMIC:
- phdyn = phdr;
- break;
- }
- phdr++;
- }
+
+ error = elf_read_phdrs(efile, &nphdr, &ef->ef_ph);
+ if (error != 0) {
+ phdr = NULL;
+ goto out;
+ }
+
+ error = EFTYPE;
+ nsegs = 0;
+ phdyn = NULL;
+ phdr = ef->ef_ph;
+ for (i = 0; i < nphdr; i++, phdr++) {
if (verbose > 1)
- printf("\n");
- if (phdyn == NULL) {
- warnx("Skipping %s: not dynamically-linked",
- filename);
+ ef_print_phdr(phdr);
+ switch (phdr->p_type) {
+ case PT_LOAD:
+ if (nsegs < MAXSEGS)
+ ef->ef_segs[nsegs] = phdr;
+ nsegs++;
break;
- } else if (nsegs > MAXSEGS) {
- warnx("%s: too many segments", filename);
+ case PT_PHDR:
break;
- }
- ef->ef_nsegs = nsegs;
- if (ef_read_entry(ef, phdyn->p_offset,
- phdyn->p_filesz, (void **)&ef->ef_dyn) != 0) {
- printf("ef_read_entry failed\n");
+ case PT_DYNAMIC:
+ phdyn = phdr;
break;
}
- error = ef_parse_dynamic(ef);
- if (error != 0)
- break;
- if (hdr->e_type == ET_DYN) {
- ef->ef_type = EFT_KLD;
- error = 0;
- } else if (hdr->e_type == ET_EXEC) {
- ef->ef_type = EFT_KERNEL;
- error = 0;
- } else
- break;
- } while(0);
+ }
+ if (verbose > 1)
+ printf("\n");
+ if (phdyn == NULL) {
+ warnx("Skipping %s: not dynamically-linked",
+ ef->ef_name);
+ goto out;
+ }
+
+ if (nsegs > MAXSEGS) {
+ warnx("%s: too many segments", ef->ef_name);
+ goto out;
+ }
+ ef->ef_nsegs = nsegs;
+
+ error = ef_parse_dynamic(ef, phdyn);
+out:
if (error != 0)
ef_close(ef);
return (error);
}
-static int
+static void
ef_close(elf_file_t ef)
{
-
- close(ef->ef_fd);
+ free(ef->ef_rela);
+ free(ef->ef_rel);
+ free(ef->ef_strtab);
+ free(ef->ef_symtab);
+ free(ef->ef_hashtab);
+ free(ef->ef_ph);
if (ef->ef_name)
free(ef->ef_name);
ef->ef_efile->ef_ops = NULL;
ef->ef_efile->ef_ef = NULL;
free(ef);
- return (0);
}
diff --git a/usr.sbin/kldxref/ef.h b/usr.sbin/kldxref/ef.h
index 94aaca279a80..a96bd72d6931 100644
--- a/usr.sbin/kldxref/ef.h
+++ b/usr.sbin/kldxref/ef.h
@@ -35,71 +35,276 @@
#ifndef _EF_H_
#define _EF_H_
-#define EFT_KLD 1
-#define EFT_KERNEL 2
+#include <sys/linker_set.h>
+#include <stdbool.h>
-#define EF_RELOC_REL 1
-#define EF_RELOC_RELA 2
-
-#define EF_GET_TYPE(ef) \
- (ef)->ef_ops->get_type((ef)->ef_ef)
#define EF_CLOSE(ef) \
(ef)->ef_ops->close((ef)->ef_ef)
-#define EF_READ(ef, offset, len, dest) \
- (ef)->ef_ops->read((ef)->ef_ef, offset, len, dest)
-#define EF_READ_ENTRY(ef, offset, len, ptr) \
- (ef)->ef_ops->read_entry((ef)->ef_ef, offset, len, ptr)
-#define EF_SEG_READ(ef, offset, len, dest) \
- (ef)->ef_ops->seg_read((ef)->ef_ef, offset, len, dest)
-#define EF_SEG_READ_REL(ef, offset, len, dest) \
- (ef)->ef_ops->seg_read_rel((ef)->ef_ef, offset, len, dest)
-#define EF_SEG_READ_STRING(ef, offset, len, dest) \
- (ef)->ef_ops->seg_read_string((ef)->ef_ef, offset, len, dest)
-#define EF_SEG_READ_ENTRY(ef, offset, len, ptr) \
- (ef)->ef_ops->seg_read_entry((ef)->kf_ef, offset, len, ptr)
-#define EF_SEG_READ_ENTRY_REL(ef, offset, len, ptr) \
- (ef)->ef_ops->seg_read_entry_rel((ef)->ef_ef, offset, len, ptr)
+#define EF_SEG_READ_REL(ef, address, len, dest) \
+ (ef)->ef_ops->seg_read_rel((ef)->ef_ef, address, len, dest)
+#define EF_SEG_READ_STRING(ef, address, len, dest) \
+ (ef)->ef_ops->seg_read_string((ef)->ef_ef, address, len, dest)
#define EF_SYMADDR(ef, symidx) \
(ef)->ef_ops->symaddr((ef)->ef_ef, symidx)
#define EF_LOOKUP_SET(ef, name, startp, stopp, countp) \
(ef)->ef_ops->lookup_set((ef)->ef_ef, name, startp, stopp, countp)
-#define EF_LOOKUP_SYMBOL(ef, name, sym) \
- (ef)->ef_ops->lookup_symbol((ef)->ef_ef, name, sym)
/* XXX, should have a different name. */
typedef struct ef_file *elf_file_t;
+/* FreeBSD's headers define additional typedef's for ELF structures. */
+typedef Elf64_Size GElf_Size;
+typedef Elf64_Hashelt GElf_Hashelt;
+
+struct elf_file;
+
struct elf_file_ops {
- int (*get_type)(elf_file_t ef);
- int (*close)(elf_file_t ef);
- int (*read)(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
- int (*read_entry)(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr);
- int (*seg_read)(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
- int (*seg_read_rel)(elf_file_t ef, Elf_Off offset, size_t len,
+ void (*close)(elf_file_t ef);
+ int (*seg_read_rel)(elf_file_t ef, GElf_Addr address, size_t len,
void *dest);
- int (*seg_read_string)(elf_file_t, Elf_Off offset, size_t len,
+ int (*seg_read_string)(elf_file_t ef, GElf_Addr address, size_t len,
char *dest);
- int (*seg_read_entry)(elf_file_t ef, Elf_Off offset, size_t len,
- void**ptr);
- int (*seg_read_entry_rel)(elf_file_t ef, Elf_Off offset, size_t len,
- void**ptr);
- Elf_Addr (*symaddr)(elf_file_t ef, Elf_Size symidx);
- int (*lookup_set)(elf_file_t ef, const char *name, long *startp,
- long *stopp, long *countp);
- int (*lookup_symbol)(elf_file_t ef, const char* name, Elf_Sym** sym);
+ GElf_Addr (*symaddr)(elf_file_t ef, GElf_Size symidx);
+ int (*lookup_set)(elf_file_t ef, const char *name, GElf_Addr *startp,
+ GElf_Addr *stopp, long *countp);
+};
+
+typedef int (elf_reloc_t)(struct elf_file *ef, const void *reldata,
+ Elf_Type reltype, GElf_Addr relbase, GElf_Addr dataoff, size_t len,
+ void *dest);
+
+struct elf_reloc_data {
+ unsigned char class;
+ unsigned char data;
+ GElf_Half machine;
+ elf_reloc_t *reloc;
};
+#define ELF_RELOC(_class, _data, _machine, _reloc) \
+ static struct elf_reloc_data __CONCAT(elf_reloc_data_, __LINE__) = { \
+ .class = (_class), \
+ .data = (_data), \
+ .machine = (_machine), \
+ .reloc = (_reloc) \
+ }; \
+ DATA_SET(elf_reloc, __CONCAT(elf_reloc_data_, __LINE__))
+
struct elf_file {
elf_file_t ef_ef;
struct elf_file_ops *ef_ops;
+ const char *ef_filename;
+ Elf *ef_elf;
+ elf_reloc_t *ef_reloc;
+ GElf_Ehdr ef_hdr;
+ size_t ef_pointer_size;
+ int ef_fd;
+};
+
+#define elf_class(ef) ((ef)->ef_hdr.e_ident[EI_CLASS])
+#define elf_encoding(ef) ((ef)->ef_hdr.e_ident[EI_DATA])
+
+/*
+ * "Generic" versions of module metadata structures.
+ */
+struct Gmod_depend {
+ int md_ver_minimum;
+ int md_ver_preferred;
+ int md_ver_maximum;
+};
+
+struct Gmod_version {
+ int mv_version;
+};
+
+struct Gmod_metadata {
+ int md_version; /* structure version MDTV_* */
+ int md_type; /* type of entry MDT_* */
+ GElf_Addr md_data; /* specific data */
+ GElf_Addr md_cval; /* common string label */
+};
+
+struct Gmod_pnp_match_info
+{
+ GElf_Addr descr; /* Description of the table */
+ GElf_Addr bus; /* Name of the bus for this table */
+ GElf_Addr table; /* Pointer to pnp table */
+ int entry_len; /* Length of each entry in the table (may be */
+ /* longer than descr describes). */
+ int num_entry; /* Number of entries in the table */
};
__BEGIN_DECLS
-int ef_open(const char *filename, struct elf_file *ef, int verbose);
-int ef_obj_open(const char *filename, struct elf_file *ef, int verbose);
-int ef_reloc(struct elf_file *ef, const void *reldata, int reltype,
- Elf_Off relbase, Elf_Off dataoff, size_t len, void *dest);
+
+/*
+ * Attempt to parse an open ELF file as either an executable or DSO
+ * (ef_open) or an object file (ef_obj_open). On success, these
+ * routines initialize the 'ef_ef' and 'ef_ops' members of 'ef'.
+ */
+int ef_open(struct elf_file *ef, int verbose);
+int ef_obj_open(struct elf_file *ef, int verbose);
+
+/*
+ * Direct operations on an ELF file regardless of type. Many of these
+ * use libelf.
+ */
+
+/*
+ * Open an ELF file with libelf. Populates fields other than ef_ef
+ * and ef_ops in '*efile'.
+ */
+int elf_open_file(struct elf_file *efile, const char *filename,
+ int verbose);
+
+/* Close an ELF file. */
+void elf_close_file(struct elf_file *efile);
+
+/* Is an ELF file the same architecture as hdr? */
+bool elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr);
+
+/* The size of a single object of 'type'. */
+size_t elf_object_size(struct elf_file *efile, Elf_Type type);
+
+/* The size of a pointer in architecture of 'efile'. */
+size_t elf_pointer_size(struct elf_file *efile);
+
+/*
+ * Read and convert an array of a data type from an ELF file. This is
+ * a wrapper around gelf_xlatetom() which reads an array of raw ELF
+ * objects from the file and converts them into host structures using
+ * native endianness. The data is returned in a dynamically-allocated
+ * buffer.
+ */
+int elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset,
+ size_t len, void **out);
+
+/* Reads "raw" data from an ELF file without any translation. */
+int elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst,
+ size_t len);
+
+/*
+ * A wrapper around elf_read_raw_data which returns the data in a
+ * dynamically-allocated buffer.
+ */
+int elf_read_raw_data_alloc(struct elf_file *efile, off_t offset,
+ size_t len, void **out);
+
+/*
+ * Read relocated data from an ELF file and return it in a
+ * dynamically-allocated buffer. Note that no translation
+ * (byte-swapping for endianness, 32-vs-64) is performed on the
+ * returned data, but any ELF relocations which affect the contents
+ * are applied to the returned data. The address parameter gives the
+ * address of the data buffer if the ELF file were loaded into memory
+ * rather than a direct file offset.
+ */
+int elf_read_relocated_data(struct elf_file *efile, GElf_Addr address,
+ size_t len, void **buf);
+
+/*
+ * Read the program headers from an ELF file and return them in a
+ * dynamically-allocated array of GElf_Phdr objects.
+ */
+int elf_read_phdrs(struct elf_file *efile, size_t *nphdrp,
+ GElf_Phdr **phdrp);
+
+/*
+ * Read the section headers from an ELF file and return them in a
+ * dynamically-allocated array of GElf_Shdr objects.
+ */
+int elf_read_shdrs(struct elf_file *efile, size_t *nshdrp,
+ GElf_Shdr **shdrp);
+
+/*
+ * Read the dynamic table from a section of an ELF file into a
+ * dynamically-allocated array of GElf_Dyn objects.
+ */
+int elf_read_dynamic(struct elf_file *efile, int section_index, long *ndynp,
+ GElf_Dyn **dynp);
+
+/*
+ * Read a symbol table from a section of an ELF file into a
+ * dynamically-allocated array of GElf_Sym objects.
+ */
+int elf_read_symbols(struct elf_file *efile, int section_index,
+ long *nsymp, GElf_Sym **symp);
+
+/*
+ * Read a string table described by a section header of an ELF file
+ * into a dynamically-allocated buffer.
+ */
+int elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
+ long *strcnt, char **strtab);
+
+/*
+ * Read a table of relocation objects from a section of an ELF file
+ * into a dynamically-allocated array of GElf_Rel objects.
+ */
+int elf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
+ GElf_Rel **relp);
+
+/*
+ * Read a table of relocation-with-addend objects from a section of an
+ * ELF file into a dynamically-allocated array of GElf_Rela objects.
+ */
+int elf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
+ GElf_Rela **relap);
+
+/*
+ * Read a string from an ELF file and return it in the provided
+ * buffer. If the string is longer than the buffer, this fails with
+ * EFAULT. The address parameter gives the address of the data buffer
+ * if the ELF file were loaded into memory rather than a direct file
+ * offset.
+ */
+int elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
+ size_t len);
+
+/* Return the address extracted from a target pointer stored at 'p'. */
+GElf_Addr elf_address_from_pointer(struct elf_file *efile, const void *p);
+
+/*
+ * Read a linker set and return an array of addresses extracted from the
+ * relocated pointers in the linker set.
+ */
+int elf_read_linker_set(struct elf_file *efile, const char *name,
+ GElf_Addr **buf, long *countp);
+
+/*
+ * Read and convert a target 'struct mod_depend' into a host
+ * 'struct Gmod_depend'.
+ */
+int elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_depend *mdp);
+
+/*
+ * Read and convert a target 'struct mod_version' into a host
+ * 'struct Gmod_version'.
+ */
+int elf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_version *mdv);
+
+/*
+ * Read and convert a target 'struct mod_metadata' into a host
+ * 'struct Gmod_metadata'.
+ */
+int elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_metadata *md);
+
+/*
+ * Read and convert a target 'struct mod_pnp_match_info' into a host
+ * 'struct Gmod_pnp_match_info'.
+ */
+int elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_pnp_match_info *pnp);
+
+/*
+ * Apply relocations to the values obtained from the file. `relbase' is the
+ * target relocation address of the section, and `dataoff/len' is the region
+ * that is to be relocated, and has been copied to *dest
+ */
+int elf_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest);
+
__END_DECLS
#endif /* _EF_H_*/
diff --git a/usr.sbin/kldxref/ef_aarch64.c b/usr.sbin/kldxref/ef_aarch64.c
index 9c57457ae930..5bd521b28e38 100644
--- a/usr.sbin/kldxref/ef_aarch64.c
+++ b/usr.sbin/kldxref/ef_aarch64.c
@@ -25,12 +25,11 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <machine/elf.h>
+#include <sys/endian.h>
#include <err.h>
#include <errno.h>
-#include <string.h>
+#include <gelf.h>
#include "ef.h"
@@ -39,28 +38,29 @@
* target relocation address of the section, and `dataoff/len' is the region
* that is to be relocated, and has been copied to *dest
*/
-int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *dest)
+static int
+ef_aarch64_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
- Elf_Addr *where, addend;
- Elf_Size rtype;
- const Elf_Rela *rela;
+ char *where;
+ Elf64_Addr addend;
+ GElf_Size rtype;
+ const GElf_Rela *rela;
- if (reltype != EF_RELOC_RELA)
+ if (reltype != ELF_T_RELA)
return (EINVAL);
- rela = (const Elf_Rela *)reldata;
- where = (Elf_Addr *) ((Elf_Off)dest - dataoff + rela->r_offset);
+ rela = (const GElf_Rela *)reldata;
+ where = (char *)dest - dataoff + rela->r_offset;
addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
+ rtype = GELF_R_TYPE(rela->r_info);
- if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len)
+ if (where < (char *)dest || where >= (char *)dest + len)
return (0);
switch(rtype) {
case R_AARCH64_RELATIVE:
- *where = relbase + addend;
+ le64enc(where, relbase + addend);
break;
case R_AARCH64_ABS64:
break;
@@ -70,3 +70,5 @@ ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
}
return (0);
}
+
+ELF_RELOC(ELFCLASS64, ELFDATA2LSB, EM_AARCH64, ef_aarch64_reloc);
diff --git a/usr.sbin/kldxref/ef_amd64.c b/usr.sbin/kldxref/ef_amd64.c
index 789894518329..729039daa509 100644
--- a/usr.sbin/kldxref/ef_amd64.c
+++ b/usr.sbin/kldxref/ef_amd64.c
@@ -27,11 +27,11 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <machine/elf.h>
+#include <sys/endian.h>
#include <err.h>
#include <errno.h>
+#include <gelf.h>
#include "ef.h"
@@ -40,48 +40,48 @@
* target relocation address of the section, and `dataoff' is the target
* relocation address of the data in `dest'.
*/
-int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *dest)
+static int
+ef_amd64_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
- Elf64_Addr *where, val;
- Elf32_Addr *where32, val32;
- Elf_Addr addend, addr;
- Elf_Size rtype, symidx;
- const Elf_Rel *rel;
- const Elf_Rela *rela;
+ char *where;
+ GElf_Addr val;
+ GElf_Addr addend, addr;
+ GElf_Size rtype, symidx;
+ const GElf_Rel *rel;
+ const GElf_Rela *rela;
switch (reltype) {
- case EF_RELOC_REL:
- rel = (const Elf_Rel *)reldata;
- where = (Elf_Addr *)(dest + relbase + rel->r_offset - dataoff);
+ case ELF_T_REL:
+ rel = (const GElf_Rel *)reldata;
+ where = (char *)dest + relbase + rel->r_offset - dataoff;
addend = 0;
- rtype = ELF_R_TYPE(rel->r_info);
- symidx = ELF_R_SYM(rel->r_info);
+ rtype = GELF_R_TYPE(rel->r_info);
+ symidx = GELF_R_SYM(rel->r_info);
break;
- case EF_RELOC_RELA:
- rela = (const Elf_Rela *)reldata;
- where = (Elf_Addr *)(dest + relbase + rela->r_offset - dataoff);
+ case ELF_T_RELA:
+ rela = (const GElf_Rela *)reldata;
+ where = (char *)dest + relbase + rela->r_offset - dataoff;
addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
- symidx = ELF_R_SYM(rela->r_info);
+ rtype = GELF_R_TYPE(rela->r_info);
+ symidx = GELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
- if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len)
+ if (where < (char *)dest || where >= (char *)dest + len)
return (0);
- if (reltype == EF_RELOC_REL) {
+ if (reltype == ELF_T_REL) {
/* Addend is 32 bit on 32 bit relocs */
switch (rtype) {
case R_X86_64_PC32:
case R_X86_64_32S:
- addend = *(Elf32_Addr *)where;
+ addend = le32dec(where);
break;
default:
- addend = *where;
+ addend = le64dec(where);
break;
}
}
@@ -92,25 +92,26 @@ ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
case R_X86_64_64: /* S + A */
addr = EF_SYMADDR(ef, symidx);
val = addr + addend;
- *where = val;
+ le64enc(where, val);
break;
case R_X86_64_32S: /* S + A sign extend */
addr = EF_SYMADDR(ef, symidx);
- val32 = (Elf32_Addr)(addr + addend);
- where32 = (Elf32_Addr *)where;
- *where32 = val32;
+ val = (Elf32_Addr)(addr + addend);
+ le32enc(where, val);
break;
case R_X86_64_GLOB_DAT: /* S */
addr = EF_SYMADDR(ef, symidx);
- *where = addr;
+ le64enc(where, addr);
break;
case R_X86_64_RELATIVE: /* B + A */
- addr = (Elf_Addr)addend + relbase;
+ addr = addend + relbase;
val = addr;
- *where = val;
+ le64enc(where, val);
break;
default:
warnx("unhandled relocation type %d", (int)rtype);
}
return (0);
}
+
+ELF_RELOC(ELFCLASS64, ELFDATA2LSB, EM_X86_64, ef_amd64_reloc);
diff --git a/usr.sbin/kldxref/ef_i386.c b/usr.sbin/kldxref/ef_i386.c
index 3e637cd62525..e4f73877c430 100644
--- a/usr.sbin/kldxref/ef_i386.c
+++ b/usr.sbin/kldxref/ef_i386.c
@@ -27,11 +27,11 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <machine/elf.h>
+#include <sys/endian.h>
#include <err.h>
#include <errno.h>
+#include <gelf.h>
#include "ef.h"
@@ -40,57 +40,59 @@
* target relocation address of the section, and `dataoff' is the target
* relocation address of the data in `dest'.
*/
-int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *_dest)
+static int
+ef_i386_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
- Elf_Addr *where, addr, addend;
- Elf_Size rtype, symidx;
- const Elf_Rel *rel;
- const Elf_Rela *rela;
- char *dest = _dest;
+ char *where;
+ GElf_Addr addr, addend;
+ GElf_Size rtype, symidx;
+ const GElf_Rel *rel;
+ const GElf_Rela *rela;
switch (reltype) {
- case EF_RELOC_REL:
- rel = (const Elf_Rel *)reldata;
- where = (Elf_Addr *)(dest + relbase + rel->r_offset - dataoff);
+ case ELF_T_REL:
+ rel = (const GElf_Rel *)reldata;
+ where = (char *)dest + relbase + rel->r_offset - dataoff;
addend = 0;
- rtype = ELF_R_TYPE(rel->r_info);
- symidx = ELF_R_SYM(rel->r_info);
+ rtype = GELF_R_TYPE(rel->r_info);
+ symidx = GELF_R_SYM(rel->r_info);
break;
- case EF_RELOC_RELA:
- rela = (const Elf_Rela *)reldata;
- where = (Elf_Addr *)(dest + relbase + rela->r_offset - dataoff);
+ case ELF_T_RELA:
+ rela = (const GElf_Rela *)reldata;
+ where = (char *)dest + relbase + rela->r_offset - dataoff;
addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
- symidx = ELF_R_SYM(rela->r_info);
+ rtype = GELF_R_TYPE(rela->r_info);
+ symidx = GELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
- if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len)
+ if (where < (char *)dest || where >= (char *)dest + len)
return (0);
- if (reltype == EF_RELOC_REL)
- addend = *where;
+ if (reltype == ELF_T_REL)
+ addend = le32dec(where);
switch (rtype) {
case R_386_RELATIVE: /* A + B */
- addr = (Elf_Addr)addend + relbase;
- *where = addr;
+ addr = addend + relbase;
+ le32enc(where, addr);
break;
case R_386_32: /* S + A - P */
addr = EF_SYMADDR(ef, symidx);
addr += addend;
- *where = addr;
+ le32enc(where, addr);
break;
case R_386_GLOB_DAT: /* S */
addr = EF_SYMADDR(ef, symidx);
- *where = addr;
+ le32enc(where, addr);
break;
default:
warnx("unhandled relocation type %d", (int)rtype);
}
return (0);
}
+
+ELF_RELOC(ELFCLASS32, ELFDATA2LSB, EM_386, ef_i386_reloc);
diff --git a/usr.sbin/kldxref/ef_mips.c b/usr.sbin/kldxref/ef_mips.c
index 2897b4e7a235..edc99a7d2505 100644
--- a/usr.sbin/kldxref/ef_mips.c
+++ b/usr.sbin/kldxref/ef_mips.c
@@ -30,11 +30,11 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <machine/elf.h>
+#include <sys/endian.h>
#include <err.h>
#include <errno.h>
+#include <gelf.h>
#include "ef.h"
@@ -43,55 +43,78 @@
* target relocation address of the section, and `dataoff' is the target
* relocation address of the data in `dest'.
*/
-int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *dest)
+static int
+ef_mips_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
- Elf_Addr *where, val;
- const Elf_Rel *rel;
- const Elf_Rela *rela;
- Elf_Addr addend, addr;
- Elf_Size rtype, symidx;
+ char *where;
+ GElf_Addr val;
+ const GElf_Rel *rel;
+ const GElf_Rela *rela;
+ GElf_Addr addend, addr;
+ GElf_Size rtype, symidx;
switch (reltype) {
- case EF_RELOC_REL:
- rel = (const Elf_Rel *)reldata;
- where = (Elf_Addr *)((char *)dest + relbase + rel->r_offset -
- dataoff);
+ case ELF_T_REL:
+ rel = (const GElf_Rel *)reldata;
+ where = (char *)dest + relbase + rel->r_offset - dataoff;
addend = 0;
- rtype = ELF_R_TYPE(rel->r_info);
- symidx = ELF_R_SYM(rel->r_info);
+ rtype = GELF_R_TYPE(rel->r_info);
+ symidx = GELF_R_SYM(rel->r_info);
break;
- case EF_RELOC_RELA:
- rela = (const Elf_Rela *)reldata;
- where = (Elf_Addr *)((char *)dest + relbase + rela->r_offset -
- dataoff);
+ case ELF_T_RELA:
+ rela = (const GElf_Rela *)reldata;
+ where = (char *)dest + relbase + rela->r_offset - dataoff;
addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
- symidx = ELF_R_SYM(rela->r_info);
+ rtype = GELF_R_TYPE(rela->r_info);
+ symidx = GELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
- if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len)
+ if (where < (char *)dest || where >= (char *)dest + len)
return (0);
- if (reltype == EF_RELOC_REL)
+ if (reltype == ELF_T_REL) {
+ if (elf_class(ef) == ELFCLASS64) {
+ if (elf_encoding(ef) == ELFDATA2LSB)
+ addend = le64dec(where);
+ else
+ addend = be64dec(where);
+ } else {
+ if (elf_encoding(ef) == ELFDATA2LSB)
+ addend = le32dec(where);
+ else
+ addend = be32dec(where);
+ }
addend = *where;
+ }
switch (rtype) {
-#ifdef __LP64__
case R_MIPS_64: /* S + A */
-#else
+ addr = EF_SYMADDR(ef, symidx);
+ val = addr + addend;
+ if (elf_encoding(ef) == ELFDATA2LSB)
+ le64enc(where, val);
+ else
+ be64enc(where, val);
+ break;
case R_MIPS_32: /* S + A */
-#endif
addr = EF_SYMADDR(ef, symidx);
val = addr + addend;
- *where = val;
+ if (elf_encoding(ef) == ELFDATA2LSB)
+ le32enc(where, val);
+ else
+ be32enc(where, val);
break;
default:
warnx("unhandled relocation type %d", (int)rtype);
}
return (0);
}
+
+ELF_RELOC(ELFCLASS32, ELFDATA2LSB, EM_MIPS, ef_mips_reloc);
+ELF_RELOC(ELFCLASS32, ELFDATA2MSB, EM_MIPS, ef_mips_reloc);
+ELF_RELOC(ELFCLASS64, ELFDATA2LSB, EM_MIPS, ef_mips_reloc);
+ELF_RELOC(ELFCLASS64, ELFDATA2MSB, EM_MIPS, ef_mips_reloc);
diff --git a/usr.sbin/kldxref/ef_nop.c b/usr.sbin/kldxref/ef_nop.c
deleted file mode 100644
index 23e779d3f6c5..000000000000
--- a/usr.sbin/kldxref/ef_nop.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2003 Jake Burkholder.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <machine/elf.h>
-
-#include "ef.h"
-
-int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *dest)
-{
-
- return (0);
-}
diff --git a/usr.sbin/kldxref/ef_obj.c b/usr.sbin/kldxref/ef_obj.c
index 027408876a5e..a1d46241b803 100644
--- a/usr.sbin/kldxref/ef_obj.c
+++ b/usr.sbin/kldxref/ef_obj.c
@@ -35,48 +35,42 @@
*/
#include <sys/param.h>
-#include <sys/linker.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
+#include <gelf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <machine/elf.h>
#include "ef.h"
typedef struct {
- void *addr;
- Elf_Off size;
+ char *addr;
+ GElf_Off size;
int flags;
int sec; /* Original section */
char *name;
} Elf_progent;
typedef struct {
- Elf_Rel *rel;
- int nrel;
+ GElf_Rel *rel;
+ long nrel;
int sec;
} Elf_relent;
typedef struct {
- Elf_Rela *rela;
- int nrela;
+ GElf_Rela *rela;
+ long nrela;
int sec;
} Elf_relaent;
struct ef_file {
char *ef_name;
- int ef_fd;
- Elf_Ehdr ef_hdr;
struct elf_file *ef_efile;
- caddr_t address;
- Elf_Off size;
- Elf_Shdr *e_shdr;
+ char *address;
+ GElf_Off size;
Elf_progent *progtab;
int nprogtab;
@@ -87,7 +81,7 @@ struct ef_file {
Elf_relent *reltab;
int nrel;
- Elf_Sym *ddbsymtab; /* The symbol table we are using */
+ GElf_Sym *ddbsymtab; /* The symbol table we are using */
long ddbsymcnt; /* Number of symbols */
caddr_t ddbstrtab; /* String table */
long ddbstrcnt; /* number of bytes in string table */
@@ -98,54 +92,31 @@ struct ef_file {
int ef_verbose;
};
-static int ef_obj_get_type(elf_file_t ef);
-static int ef_obj_close(elf_file_t ef);
-static int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len,
- void* dest);
-static int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr);
-static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len,
- void *dest);
-static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
- void *dest);
-static int ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset,
+static void ef_obj_close(elf_file_t ef);
+
+static int ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address,
+ size_t len, void *dest);
+static int ef_obj_seg_read_string(elf_file_t ef, GElf_Addr address,
size_t len, char *dest);
-static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr);
-static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset,
- size_t len, void **ptr);
-static Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx);
-static int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp,
- long *stopp, long *countp);
-static int ef_obj_lookup_symbol(elf_file_t ef, const char* name,
- Elf_Sym** sym);
+
+static GElf_Addr ef_obj_symaddr(elf_file_t ef, GElf_Size symidx);
+static int ef_obj_lookup_set(elf_file_t ef, const char *name,
+ GElf_Addr *startp, GElf_Addr *stopp, long *countp);
+static int ef_obj_lookup_symbol(elf_file_t ef, const char *name,
+ GElf_Sym **sym);
static struct elf_file_ops ef_obj_file_ops = {
- .get_type = ef_obj_get_type,
.close = ef_obj_close,
- .read = ef_obj_read,
- .read_entry = ef_obj_read_entry,
- .seg_read = ef_obj_seg_read,
.seg_read_rel = ef_obj_seg_read_rel,
.seg_read_string = ef_obj_seg_read_string,
- .seg_read_entry = ef_obj_seg_read_entry,
- .seg_read_entry_rel = ef_obj_seg_read_entry_rel,
.symaddr = ef_obj_symaddr,
.lookup_set = ef_obj_lookup_set,
- .lookup_symbol = ef_obj_lookup_symbol
};
static int
-ef_obj_get_type(elf_file_t __unused ef)
-{
-
- return (EFT_KLD);
-}
-
-static int
-ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
+ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
{
- Elf_Sym *symp;
+ GElf_Sym *symp;
const char *strp;
int i;
@@ -160,102 +131,58 @@ ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
}
static int
-ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
- long *countp)
+ef_obj_lookup_set(elf_file_t ef, const char *name, GElf_Addr *startp,
+ GElf_Addr *stopp, long *countp)
{
int i;
for (i = 0; i < ef->nprogtab; i++) {
if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) &&
strcmp(ef->progtab[i].name + 4, name) == 0) {
- *startp = (char *)ef->progtab[i].addr - ef->address;
- *stopp = (char *)ef->progtab[i].addr +
- ef->progtab[i].size - ef->address;
- *countp = (*stopp - *startp) / sizeof(void *);
+ *startp = ef->progtab[i].addr - ef->address;
+ *stopp = ef->progtab[i].addr + ef->progtab[i].size -
+ ef->address;
+ *countp = (*stopp - *startp) /
+ elf_pointer_size(ef->ef_efile);
return (0);
}
}
return (ESRCH);
}
-static Elf_Addr
-ef_obj_symaddr(elf_file_t ef, Elf_Size symidx)
+static GElf_Addr
+ef_obj_symaddr(elf_file_t ef, GElf_Size symidx)
{
- const Elf_Sym *sym;
+ const GElf_Sym *sym;
- if (symidx >= (size_t) ef->ddbsymcnt)
+ if (symidx >= (size_t)ef->ddbsymcnt)
return (0);
sym = ef->ddbsymtab + symidx;
if (sym->st_shndx != SHN_UNDEF)
- return (sym->st_value - (Elf_Addr)ef->address);
+ return (sym->st_value - (GElf_Addr)ef->address);
return (0);
}
static int
-ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
-{
- ssize_t r;
-
- if (offset != (Elf_Off)-1) {
- if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
- return (EIO);
- }
-
- r = read(ef->ef_fd, dest, len);
- if (r != -1 && (size_t)r == len)
- return (0);
- else
- return (EIO);
-}
-
-static int
-ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
-{
- int error;
-
- *ptr = malloc(len);
- if (*ptr == NULL)
- return (errno);
- error = ef_obj_read(ef, offset, len, *ptr);
- if (error != 0)
- free(*ptr);
- return (error);
-}
-
-static int
-ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
-{
-
- if (offset + len > ef->size) {
- if (ef->ef_verbose)
- warnx("ef_obj_seg_read(%s): bad offset/len (%lx:%ld)",
- ef->ef_name, (long)offset, (long)len);
- return (EFAULT);
- }
- bcopy(ef->address + offset, dest, len);
- return (0);
-}
-
-static int
-ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
+ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest)
{
char *memaddr;
- Elf_Rel *r;
- Elf_Rela *a;
- Elf_Off secbase, dataoff;
+ GElf_Rel *r;
+ GElf_Rela *a;
+ GElf_Addr secbase, dataoff;
int error, i, sec;
- if (offset + len > ef->size) {
+ if (address + len > ef->size) {
if (ef->ef_verbose)
warnx("ef_obj_seg_read_rel(%s): bad offset/len (%lx:%ld)",
- ef->ef_name, (long)offset, (long)len);
+ ef->ef_name, (long)address, (long)len);
return (EFAULT);
}
- bcopy(ef->address + offset, dest, len);
+ bcopy(ef->address + address, dest, len);
/* Find out which section contains the data. */
- memaddr = ef->address + offset;
+ memaddr = ef->address + address;
sec = -1;
secbase = dataoff = 0;
for (i = 0; i < ef->nprogtab; i++) {
@@ -280,7 +207,7 @@ ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
continue;
for (r = ef->reltab[i].rel;
r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) {
- error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase,
+ error = elf_reloc(ef->ef_efile, r, ELF_T_REL, secbase,
dataoff, len, dest);
if (error != 0)
return (error);
@@ -291,8 +218,8 @@ ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
continue;
for (a = ef->relatab[i].rela;
a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) {
- error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA,
- secbase, dataoff, len, dest);
+ error = elf_reloc(ef->ef_efile, a, ELF_T_RELA, secbase,
+ dataoff, len, dest);
if (error != 0)
return (error);
}
@@ -301,117 +228,65 @@ ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
}
static int
-ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest)
+ef_obj_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char *dest)
{
- if (offset >= ef->size) {
+ if (address >= ef->size) {
if (ef->ef_verbose)
- warnx("ef_obj_seg_read_string(%s): bad offset (%lx)",
- ef->ef_name, (long)offset);
+ warnx("ef_obj_seg_read_string(%s): bad address (%lx)",
+ ef->ef_name, (long)address);
return (EFAULT);
}
- if (ef->size - offset < len)
- len = ef->size - offset;
+ if (ef->size - address < len)
+ len = ef->size - address;
- if (strnlen(ef->address + offset, len) == len)
+ if (strnlen(ef->address + address, len) == len)
return (EFAULT);
- memcpy(dest, ef->address + offset, len);
+ memcpy(dest, ef->address + address, len);
return (0);
}
-static int
-ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
-{
- int error;
-
- *ptr = malloc(len);
- if (*ptr == NULL)
- return (errno);
- error = ef_obj_seg_read(ef, offset, len, *ptr);
- if (error != 0)
- free(*ptr);
- return (error);
-}
-
-static int
-ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
- void **ptr)
-{
- int error;
-
- *ptr = malloc(len);
- if (*ptr == NULL)
- return (errno);
- error = ef_obj_seg_read_rel(ef, offset, len, *ptr);
- if (error != 0)
- free(*ptr);
- return (error);
-}
-
int
-ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
+ef_obj_open(struct elf_file *efile, int verbose)
{
elf_file_t ef;
- Elf_Ehdr *hdr;
- Elf_Shdr *shdr;
- Elf_Sym *es;
+ GElf_Ehdr *hdr;
+ GElf_Shdr *shdr;
+ GElf_Sym *es;
char *mapbase;
- void *vtmp;
- size_t mapsize, alignmask, max_addralign;
- int error, fd, pb, ra, res, rl;
- int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex;
-
- if (filename == NULL)
- return (EINVAL);
- if ((fd = open(filename, O_RDONLY)) == -1)
- return (errno);
+ size_t i, mapsize, alignmask, max_addralign, nshdr;
+ int error, pb, ra, rl;
+ int j, nsym, symstrindex, symtabindex;
+
+ hdr = &efile->ef_hdr;
+ if (hdr->e_type != ET_REL || hdr->e_shnum == 0 || hdr->e_shoff == 0 ||
+ hdr->e_shentsize != elf_object_size(efile, ELF_T_SHDR))
+ return (EFTYPE);
ef = calloc(1, sizeof(*ef));
- if (ef == NULL) {
- close(fd);
+ if (ef == NULL)
return (errno);
- }
efile->ef_ef = ef;
efile->ef_ops = &ef_obj_file_ops;
ef->ef_verbose = verbose;
- ef->ef_fd = fd;
- ef->ef_name = strdup(filename);
+ ef->ef_name = strdup(efile->ef_filename);
ef->ef_efile = efile;
- hdr = (Elf_Ehdr *)&ef->ef_hdr;
- res = read(fd, hdr, sizeof(*hdr));
- error = EFTYPE;
- if (res != sizeof(*hdr))
- goto out;
- if (!IS_ELF(*hdr))
- goto out;
- if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
- hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
- hdr->e_ident[EI_VERSION] != EV_CURRENT ||
- hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH ||
- hdr->e_type != ET_REL)
- goto out;
-
- nbytes = hdr->e_shnum * hdr->e_shentsize;
- if (nbytes == 0 || hdr->e_shoff == 0 ||
- hdr->e_shentsize != sizeof(Elf_Shdr))
- goto out;
-
- if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) {
- printf("ef_read_entry failed\n");
+ error = elf_read_shdrs(efile, &nshdr, &shdr);
+ if (error != 0) {
+ shdr = NULL;
goto out;
}
- ef->e_shdr = shdr = vtmp;
- /* Scan the section header for information and table sizing. */
+ /* Scan the section headers for information and table sizing. */
nsym = 0;
symtabindex = -1;
symstrindex = -1;
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < nshdr; i++) {
switch (shdr[i].sh_type) {
case SHT_PROGBITS:
case SHT_NOBITS:
@@ -434,16 +309,16 @@ ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
}
if (ef->nprogtab == 0) {
- warnx("%s: file has no contents", filename);
+ warnx("%s: file has no contents", ef->ef_name);
goto out;
}
if (nsym != 1) {
- warnx("%s: file has no valid symbol table", filename);
+ warnx("%s: file has no valid symbol table", ef->ef_name);
goto out;
}
- if (symstrindex < 0 || symstrindex > hdr->e_shnum ||
+ if (symstrindex < 0 || symstrindex > nshdr ||
shdr[symstrindex].sh_type != SHT_STRTAB) {
- warnx("%s: file has invalid symbol strings", filename);
+ warnx("%s: file has invalid symbol strings", ef->ef_name);
goto out;
}
@@ -462,29 +337,24 @@ ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
goto out;
}
- ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym);
- if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset,
- shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) {
- printf("ef_read_entry failed\n");
+ if (elf_read_symbols(efile, symtabindex, &ef->ddbsymcnt,
+ &ef->ddbsymtab) != 0) {
+ printf("elf_read_symbols failed\n");
goto out;
}
- ef->ddbstrcnt = shdr[symstrindex].sh_size;
- if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset,
- shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) {
- printf("ef_read_entry failed\n");
+ if (elf_read_string_table(efile, &shdr[symstrindex], &ef->ddbstrcnt,
+ &ef->ddbstrtab) != 0) {
+ printf("elf_read_string_table failed\n");
goto out;
}
/* Do we have a string table for the section names? */
- shstrindex = -1;
if (hdr->e_shstrndx != 0 &&
shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) {
- shstrindex = hdr->e_shstrndx;
- ef->shstrcnt = shdr[shstrindex].sh_size;
- if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset,
- shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) {
- printf("ef_read_entry failed\n");
+ if (elf_read_string_table(efile, &shdr[hdr->e_shstrndx],
+ &ef->shstrcnt, &ef->shstrtab) != 0) {
+ printf("elf_read_string_table failed\n");
goto out;
}
}
@@ -493,7 +363,7 @@ ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
alignmask = 0;
max_addralign = 0;
mapsize = 0;
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < nshdr; i++) {
switch (shdr[i].sh_type) {
case SHT_PROGBITS:
case SHT_NOBITS:
@@ -523,19 +393,19 @@ ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
rl = 0;
ra = 0;
alignmask = 0;
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < nshdr; i++) {
switch (shdr[i].sh_type) {
case SHT_PROGBITS:
case SHT_NOBITS:
alignmask = shdr[i].sh_addralign - 1;
mapbase += alignmask;
- mapbase = (char *)((uintptr_t)mapbase & ~alignmask);
+ mapbase = (char *)((uintptr_t)mapbase & ~alignmask);
ef->progtab[pb].addr = (void *)(uintptr_t)mapbase;
if (shdr[i].sh_type == SHT_PROGBITS) {
ef->progtab[pb].name = "<<PROGBITS>>";
- if (ef_obj_read(ef, shdr[i].sh_offset,
- shdr[i].sh_size,
- ef->progtab[pb].addr) != 0) {
+ if (elf_read_raw_data(efile,
+ shdr[i].sh_offset, ef->progtab[pb].addr,
+ shdr[i].sh_size) != 0) {
printf("failed to read progbits\n");
goto out;
}
@@ -554,30 +424,25 @@ ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
es = &ef->ddbsymtab[j];
if (es->st_shndx != i)
continue;
- es->st_value += (Elf_Addr)ef->progtab[pb].addr;
+ es->st_value += (GElf_Addr)ef->progtab[pb].addr;
}
mapbase += shdr[i].sh_size;
pb++;
break;
case SHT_REL:
- ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel);
ef->reltab[rl].sec = shdr[i].sh_info;
- if (ef_obj_read_entry(ef, shdr[i].sh_offset,
- shdr[i].sh_size, (void**)&ef->reltab[rl].rel) !=
- 0) {
- printf("ef_read_entry failed\n");
+ if (elf_read_rel(efile, i, &ef->reltab[rl].nrel,
+ &ef->reltab[rl].rel) != 0) {
+ printf("elf_read_rel failed\n");
goto out;
}
rl++;
break;
case SHT_RELA:
- ef->relatab[ra].nrela =
- shdr[i].sh_size / sizeof(Elf_Rela);
ef->relatab[ra].sec = shdr[i].sh_info;
- if (ef_obj_read_entry(ef, shdr[i].sh_offset,
- shdr[i].sh_size, (void**)&ef->relatab[ra].rela) !=
- 0) {
- printf("ef_read_entry failed\n");
+ if (elf_read_rela(efile, i, &ef->relatab[ra].nrela,
+ &ef->relatab[ra].rela) != 0) {
+ printf("elf_read_rela failed\n");
goto out;
}
ra++;
@@ -586,21 +451,19 @@ ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
}
error = 0;
out:
+ free(shdr);
if (error != 0)
ef_obj_close(ef);
return (error);
}
-static int
+static void
ef_obj_close(elf_file_t ef)
{
int i;
- close(ef->ef_fd);
if (ef->ef_name)
free(ef->ef_name);
- if (ef->e_shdr != NULL)
- free(ef->e_shdr);
if (ef->size != 0)
free(ef->address);
if (ef->nprogtab != 0)
@@ -626,6 +489,4 @@ ef_obj_close(elf_file_t ef)
ef->ef_efile->ef_ops = NULL;
ef->ef_efile->ef_ef = NULL;
free(ef);
-
- return (0);
}
diff --git a/usr.sbin/kldxref/ef_powerpc.c b/usr.sbin/kldxref/ef_powerpc.c
index 2d84104248a5..068c8117e4a6 100644
--- a/usr.sbin/kldxref/ef_powerpc.c
+++ b/usr.sbin/kldxref/ef_powerpc.c
@@ -27,63 +27,67 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <machine/elf.h>
+#include <sys/endian.h>
#include <err.h>
#include <errno.h>
-#include <inttypes.h>
-#include <string.h>
+#include <gelf.h>
#include "ef.h"
-#ifdef __powerpc64__
-#define PRI_ELF_SIZE PRIu64
-#else
-#define PRI_ELF_SIZE PRIu32
-#endif
-
/*
* Apply relocations to the values obtained from the file. `relbase' is the
* target relocation address of the section, and `dataoff/len' is the region
* that is to be relocated, and has been copied to *dest
*/
int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *dest)
+ef_ppc_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
- Elf_Addr *where, addend;
- Elf32_Addr *where32;
- Elf_Size rtype, symidx;
- const Elf_Rela *rela;
+ char *where;
+ GElf_Addr addend, val;
+ GElf_Size rtype, symidx;
+ const GElf_Rela *rela;
- if (reltype != EF_RELOC_RELA)
+ if (reltype != ELF_T_RELA)
return (EINVAL);
- rela = (const Elf_Rela *)reldata;
- where = (Elf_Addr *) ((Elf_Off)dest - dataoff + rela->r_offset);
- where32 = (Elf32_Addr *) ((Elf_Off)dest - dataoff + rela->r_offset);
+ rela = (const GElf_Rela *)reldata;
+ where = (char *)dest - dataoff + rela->r_offset;
addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
- symidx = ELF_R_SYM(rela->r_info);
+ rtype = GELF_R_TYPE(rela->r_info);
+ symidx = GELF_R_SYM(rela->r_info);
- if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len)
+ if (where < (char *)dest || where >= (char *)dest + len)
return (0);
switch (rtype) {
case R_PPC_RELATIVE: /* word32|doubleword64 B + A */
- *where = relbase + addend;
+ val = relbase + addend;
+ if (elf_class(ef) == ELFCLASS64) {
+ if (elf_encoding(ef) == ELFDATA2LSB)
+ le64enc(where, val);
+ else
+ be64enc(where, val);
+ }
break;
case R_PPC_ADDR32: /* word32 S + A */
- *where32 = EF_SYMADDR(ef, symidx) + addend;
+ val = EF_SYMADDR(ef, symidx) + addend;
+ be32enc(where, val);
break;
-#ifdef __powerpc64__
case R_PPC64_ADDR64: /* doubleword64 S + A */
- *where = EF_SYMADDR(ef, symidx) + addend;
+ val = EF_SYMADDR(ef, symidx) + addend;
+ if (elf_encoding(ef) == ELFDATA2LSB)
+ le64enc(where, val);
+ else
+ be64enc(where, val);
break;
-#endif
default:
- warnx("unhandled relocation type %" PRI_ELF_SIZE, rtype);
+ warnx("unhandled relocation type %d", (int)rtype);
}
return (0);
}
+
+ELF_RELOC(ELFCLASS32, ELFDATA2MSB, EM_PPC, ef_ppc_reloc);
+ELF_RELOC(ELFCLASS64, ELFDATA2LSB, EM_PPC64, ef_ppc_reloc);
+ELF_RELOC(ELFCLASS64, ELFDATA2MSB, EM_PPC64, ef_ppc_reloc);
diff --git a/usr.sbin/kldxref/ef_riscv.c b/usr.sbin/kldxref/ef_riscv.c
index c5ba17ed1ae1..38299a1e9b46 100644
--- a/usr.sbin/kldxref/ef_riscv.c
+++ b/usr.sbin/kldxref/ef_riscv.c
@@ -30,50 +30,51 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <machine/elf.h>
+#include <sys/endian.h>
#include <err.h>
#include <errno.h>
+#include <gelf.h>
#include "ef.h"
int
-ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase,
- Elf_Off dataoff, size_t len, void *dest)
+ef_riscv_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
{
- Elf_Addr *where;
- const Elf_Rela *rela;
- Elf_Addr addend, addr;
- Elf_Size rtype, symidx;
+ char *where;
+ const GElf_Rela *rela;
+ GElf_Addr addend, addr;
+ GElf_Size rtype, symidx;
switch (reltype) {
- case EF_RELOC_RELA:
- rela = (const Elf_Rela *)reldata;
- where = (Elf_Addr *)((char *)dest + relbase + rela->r_offset -
- dataoff);
+ case ELF_T_RELA:
+ rela = (const GElf_Rela *)reldata;
+ where = (char *)dest + relbase + rela->r_offset - dataoff;
addend = rela->r_addend;
- rtype = ELF_R_TYPE(rela->r_info);
- symidx = ELF_R_SYM(rela->r_info);
+ rtype = GELF_R_TYPE(rela->r_info);
+ symidx = GELF_R_SYM(rela->r_info);
break;
default:
return (EINVAL);
}
- if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len)
+ if (where < (char *)dest || where >= (char *)dest + len)
return (0);
switch (rtype) {
case R_RISCV_64: /* S + A */
addr = EF_SYMADDR(ef, symidx) + addend;
- *where = addr;
+ le64enc(where, addr);
break;
case R_RISCV_RELATIVE: /* B + A */
addr = addend + relbase;
- *where = addr;
+ le64enc(where, addr);
break;
default:
warnx("unhandled relocation type %d", (int)rtype);
}
return (0);
}
+
+ELF_RELOC(ELFCLASS64, ELFDATA2LSB, EM_RISCV, ef_riscv_reloc);
diff --git a/usr.sbin/kldxref/elf.c b/usr.sbin/kldxref/elf.c
new file mode 100644
index 000000000000..a30eb4456a76
--- /dev/null
+++ b/usr.sbin/kldxref/elf.c
@@ -0,0 +1,674 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2023 John Baldwin <jhb@FreeBSD.org>
+ *
+ * This software was developed by SRI International and the University
+ * of Cambridge Computer Laboratory (Department of Computer Science
+ * and Technology) under Defense Advanced Research Projects Agency
+ * (DARPA) contract HR0011-18-C-0016 ("ECATS"), as part of the DARPA
+ * SSITH research programme and under DARPA Contract No. HR001122S0003
+ * ("MTSS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <libelf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ef.h"
+
+SET_DECLARE(elf_reloc, struct elf_reloc_data);
+
+static elf_reloc_t *
+elf_find_reloc(const GElf_Ehdr *hdr)
+{
+ struct elf_reloc_data **erd;
+
+ SET_FOREACH(erd, elf_reloc) {
+ if (hdr->e_ident[EI_CLASS] == (*erd)->class &&
+ hdr->e_ident[EI_DATA] == (*erd)->data &&
+ hdr->e_machine == (*erd)->machine)
+ return ((*erd)->reloc);
+ }
+ return (NULL);
+}
+
+int
+elf_open_file(struct elf_file *efile, const char *filename, int verbose)
+{
+ int error;
+
+ memset(efile, 0, sizeof(*efile));
+ efile->ef_filename = filename;
+ efile->ef_fd = open(filename, O_RDONLY);
+ if (efile->ef_fd == -1) {
+ if (verbose)
+ warn("open(%s)", filename);
+ return (errno);
+ }
+
+ efile->ef_elf = elf_begin(efile->ef_fd, ELF_C_READ, NULL);
+ if (efile->ef_elf == NULL) {
+ if (verbose)
+ warnx("elf_begin(%s): %s", filename, elf_errmsg(0));
+ elf_close_file(efile);
+ return (EINVAL);
+ }
+
+ if (elf_kind(efile->ef_elf) != ELF_K_ELF) {
+ if (verbose)
+ warnx("%s: not an ELF file", filename);
+ elf_close_file(efile);
+ return (EINVAL);
+ }
+
+ if (gelf_getehdr(efile->ef_elf, &efile->ef_hdr) == NULL) {
+ if (verbose)
+ warnx("gelf_getehdr(%s): %s", filename, elf_errmsg(0));
+ elf_close_file(efile);
+ return (EINVAL);
+ }
+
+ efile->ef_reloc = elf_find_reloc(&efile->ef_hdr);
+ if (efile->ef_reloc == NULL) {
+ if (verbose)
+ warnx("%s: unsupported architecture", filename);
+ elf_close_file(efile);
+ return (EFTYPE);
+ }
+
+ error = ef_open(efile, verbose);
+ if (error != 0) {
+ error = ef_obj_open(efile, verbose);
+ if (error != 0) {
+ if (verbose)
+ warnc(error, "%s: not a valid DSO or object file",
+ filename);
+ elf_close_file(efile);
+ return (error);
+ }
+ }
+
+ efile->ef_pointer_size = elf_object_size(efile, ELF_T_ADDR);
+
+ return (0);
+}
+
+void
+elf_close_file(struct elf_file *efile)
+{
+ if (efile->ef_ops != NULL) {
+ EF_CLOSE(efile);
+ }
+ if (efile->ef_elf != NULL) {
+ elf_end(efile->ef_elf);
+ efile->ef_elf = NULL;
+ }
+ if (efile->ef_fd > 0) {
+ close(efile->ef_fd);
+ efile->ef_fd = -1;
+ }
+}
+
+bool
+elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr)
+{
+ if (efile->ef_hdr.e_ident[EI_CLASS] != hdr->e_ident[EI_CLASS] ||
+ efile->ef_hdr.e_ident[EI_DATA] != hdr->e_ident[EI_DATA] ||
+ efile->ef_hdr.e_machine != hdr->e_machine)
+ return (false);
+ return (true);
+}
+
+size_t
+elf_object_size(struct elf_file *efile, Elf_Type type)
+{
+ return (gelf_fsize(efile->ef_elf, type, 1, efile->ef_hdr.e_version));
+}
+
+/*
+ * The number of objects of 'type' in region of the file of size
+ * 'file_size'.
+ */
+static size_t
+elf_object_count(struct elf_file *efile, Elf_Type type, size_t file_size)
+{
+ return (file_size / elf_object_size(efile, type));
+}
+
+int
+elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, size_t len)
+{
+ ssize_t nread;
+
+ if (offset != (off_t)-1) {
+ if (lseek(efile->ef_fd, offset, SEEK_SET) == -1)
+ return (EIO);
+ }
+ nread = read(efile->ef_fd, dst, len);
+ if (nread == -1)
+ return (errno);
+ if (nread != len)
+ return (EIO);
+ return (0);
+}
+
+int
+elf_read_raw_data_alloc(struct elf_file *efile, off_t offset, size_t len,
+ void **out)
+{
+ void *buf;
+ int error;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return (ENOMEM);
+ error = elf_read_raw_data(efile, offset, buf, len);
+ if (error != 0) {
+ free(buf);
+ return (error);
+ }
+ *out = buf;
+ return (0);
+}
+
+int
+elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len,
+ void **out)
+{
+ Elf_Data dst, src;
+ void *buf;
+ int error;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ error = elf_read_raw_data(efile, offset, buf, len);
+ if (error != 0) {
+ free(buf);
+ return (error);
+ }
+
+ memset(&dst, 0, sizeof(dst));
+ memset(&src, 0, sizeof(src));
+
+ src.d_buf = buf;
+ src.d_size = len;
+ src.d_type = type;
+ src.d_version = efile->ef_hdr.e_version;
+
+ dst.d_buf = buf;
+ dst.d_size = len;
+ dst.d_version = EV_CURRENT;
+
+ if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
+ NULL) {
+ free(buf);
+ return (ENXIO);
+ }
+
+ if (dst.d_size != len)
+ warnx("elf_read_data: translation of type %u size mismatch",
+ type);
+
+ *out = buf;
+ return (0);
+}
+
+int
+elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len,
+ void **buf)
+{
+ int error;
+ void *p;
+
+ p = malloc(len);
+ if (p == NULL)
+ return (ENOMEM);
+ error = EF_SEG_READ_REL(efile, address, len, p);
+ if (error != 0) {
+ free(p);
+ return (error);
+ }
+ *buf = p;
+ return (0);
+}
+
+int
+elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp)
+{
+ GElf_Phdr *phdr;
+ size_t nphdr, i;
+ int error;
+
+ if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1)
+ return (EFTYPE);
+
+ phdr = calloc(nphdr, sizeof(*phdr));
+ if (phdr == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nphdr; i++) {
+ if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) {
+ error = EFTYPE;
+ goto out;
+ }
+ }
+
+ *nphdrp = nphdr;
+ *phdrp = phdr;
+ return (0);
+out:
+ free(phdr);
+ return (error);
+}
+
+int
+elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp)
+{
+ GElf_Shdr *shdr;
+ Elf_Scn *scn;
+ size_t nshdr, i;
+ int error;
+
+ if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1)
+ return (EFTYPE);
+
+ shdr = calloc(nshdr, sizeof(*shdr));
+ if (shdr == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nshdr; i++) {
+ scn = elf_getscn(efile->ef_elf, i);
+ if (scn == NULL) {
+ error = EFTYPE;
+ goto out;
+ }
+ if (gelf_getshdr(scn, &shdr[i]) == NULL) {
+ error = EFTYPE;
+ goto out;
+ }
+ }
+
+ *nshdrp = nshdr;
+ *shdrp = shdr;
+ return (0);
+out:
+ free(shdr);
+ return (error);
+}
+
+int
+elf_read_dynamic(struct elf_file *efile, int section_index, long *ndynp,
+ GElf_Dyn **dynp)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Dyn *dyn;
+ long i, ndyn;
+
+ scn = elf_getscn(efile->ef_elf, section_index);
+ if (scn == NULL)
+ return (EINVAL);
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return (EINVAL);
+ data = elf_getdata(scn, NULL);
+ if (data == NULL)
+ return (EINVAL);
+
+ ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size);
+ dyn = calloc(ndyn, sizeof(*dyn));
+ if (dyn == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < ndyn; i++) {
+ if (gelf_getdyn(data, i, &dyn[i]) == NULL) {
+ free(dyn);
+ return (EINVAL);
+ }
+ }
+
+ *ndynp = ndyn;
+ *dynp = dyn;
+ return (0);
+}
+
+int
+elf_read_symbols(struct elf_file *efile, int section_index, long *nsymp,
+ GElf_Sym **symp)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Sym *sym;
+ long i, nsym;
+
+ scn = elf_getscn(efile->ef_elf, section_index);
+ if (scn == NULL)
+ return (EINVAL);
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return (EINVAL);
+ data = elf_getdata(scn, NULL);
+ if (data == NULL)
+ return (EINVAL);
+
+ nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size);
+ sym = calloc(nsym, sizeof(*sym));
+ if (sym == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nsym; i++) {
+ if (gelf_getsym(data, i, &sym[i]) == NULL) {
+ free(sym);
+ return (EINVAL);
+ }
+ }
+
+ *nsymp = nsym;
+ *symp = sym;
+ return (0);
+}
+
+int
+elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
+ long *strcnt, char **strtab)
+{
+ int error;
+
+ if (shdr->sh_type != SHT_STRTAB)
+ return (EINVAL);
+ error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size,
+ (void **)strtab);
+ if (error != 0)
+ return (error);
+ *strcnt = shdr->sh_size;
+ return (0);
+}
+
+int
+elf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
+ GElf_Rel **relp)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Rel *rel;
+ long i, nrel;
+
+ scn = elf_getscn(efile->ef_elf, section_index);
+ if (scn == NULL)
+ return (EINVAL);
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return (EINVAL);
+ data = elf_getdata(scn, NULL);
+ if (data == NULL)
+ return (EINVAL);
+
+ nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size);
+ rel = calloc(nrel, sizeof(*rel));
+ if (rel == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nrel; i++) {
+ if (gelf_getrel(data, i, &rel[i]) == NULL) {
+ free(rel);
+ return (EINVAL);
+ }
+ }
+
+ *nrelp = nrel;
+ *relp = rel;
+ return (0);
+}
+
+int
+elf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
+ GElf_Rela **relap)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Rela *rela;
+ long i, nrela;
+
+ scn = elf_getscn(efile->ef_elf, section_index);
+ if (scn == NULL)
+ return (EINVAL);
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return (EINVAL);
+ data = elf_getdata(scn, NULL);
+ if (data == NULL)
+ return (EINVAL);
+
+ nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size);
+ rela = calloc(nrela, sizeof(*rela));
+ if (rela == NULL)
+ return (ENOMEM);
+
+ for (i = 0; i < nrela; i++) {
+ if (gelf_getrela(data, i, &rela[i]) == NULL) {
+ free(rela);
+ return (EINVAL);
+ }
+ }
+
+ *nrelap = nrela;
+ *relap = rela;
+ return (0);
+}
+
+size_t
+elf_pointer_size(struct elf_file *efile)
+{
+ return (efile->ef_pointer_size);
+}
+
+int
+elf_int(struct elf_file *efile, const void *p)
+{
+ if (elf_encoding(efile) == ELFDATA2LSB)
+ return (le32dec(p));
+ else
+ return (be32dec(p));
+}
+
+GElf_Addr
+elf_address_from_pointer(struct elf_file *efile, const void *p)
+{
+ switch (elf_class(efile)) {
+ case ELFCLASS32:
+ if (elf_encoding(efile) == ELFDATA2LSB)
+ return (le32dec(p));
+ else
+ return (be32dec(p));
+ case ELFCLASS64:
+ if (elf_encoding(efile) == ELFDATA2LSB)
+ return (le64dec(p));
+ else
+ return (be64dec(p));
+ default:
+ __builtin_unreachable();
+ }
+}
+
+int
+elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
+ size_t len)
+{
+ return (EF_SEG_READ_STRING(efile, address, len, dst));
+}
+
+int
+elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp,
+ long *countp)
+{
+ GElf_Addr *buf, start, stop;
+ char *p;
+ void *raw;
+ long i, count;
+ int error;
+
+ error = EF_LOOKUP_SET(efile, name, &start, &stop, &count);
+ if (error != 0)
+ return (error);
+
+ error = elf_read_relocated_data(efile, start,
+ count * elf_pointer_size(efile), &raw);
+ if (error != 0)
+ return (error);
+
+ buf = calloc(count, sizeof(*buf));
+ if (buf == NULL) {
+ free(raw);
+ return (ENOMEM);
+ }
+
+ p = raw;
+ for (i = 0; i < count; i++) {
+ buf[i] = elf_address_from_pointer(efile, p);
+ p += elf_pointer_size(efile);
+ }
+ free(raw);
+
+ *bufp = buf;
+ *countp = count;
+ return (0);
+}
+
+int
+elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_depend *mdp)
+{
+ int *p;
+ int error;
+
+ error = elf_read_relocated_data(efile, addr, sizeof(int) * 3,
+ (void **)&p);
+ if (error != 0)
+ return (error);
+
+ memset(mdp, 0, sizeof(*mdp));
+ mdp->md_ver_minimum = elf_int(efile, p);
+ mdp->md_ver_preferred = elf_int(efile, p + 1);
+ mdp->md_ver_maximum = elf_int(efile, p + 2);
+ free(p);
+ return (0);
+}
+
+int
+elf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_version *mdv)
+{
+ int error, value;
+
+ error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value);
+ if (error != 0)
+ return (error);
+
+ memset(mdv, 0, sizeof(*mdv));
+ mdv->mv_version = elf_int(efile, &value);
+ return (0);
+}
+
+int
+elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_metadata *md)
+{
+ char *p;
+ size_t len, offset, pointer_size;
+ int error;
+
+ pointer_size = elf_pointer_size(efile);
+ len = 2 * sizeof(int);
+ len = roundup(len, pointer_size);
+ len += 2 * pointer_size;
+
+ error = elf_read_relocated_data(efile, addr, len, (void **)&p);
+ if (error != 0)
+ return (error);
+
+ memset(md, 0, sizeof(*md));
+ offset = 0;
+ md->md_version = elf_int(efile, p + offset);
+ offset += sizeof(int);
+ md->md_type = elf_int(efile, p + offset);
+ offset += sizeof(int);
+ offset = roundup(offset, pointer_size);
+ md->md_data = elf_address_from_pointer(efile, p + offset);
+ offset += pointer_size;
+ md->md_cval = elf_address_from_pointer(efile, p + offset);
+ free(p);
+ return (0);
+}
+
+int
+elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
+ struct Gmod_pnp_match_info *pnp)
+{
+ char *p;
+ size_t len, offset, pointer_size;
+ int error;
+
+ pointer_size = elf_pointer_size(efile);
+ len = 3 * pointer_size;
+ len = roundup(len, pointer_size);
+ len += 2 * sizeof(int);
+
+ error = elf_read_relocated_data(efile, addr, len, (void **)&p);
+ if (error != 0)
+ return (error);
+
+ memset(pnp, 0, sizeof(*pnp));
+ offset = 0;
+ pnp->descr = elf_address_from_pointer(efile, p + offset);
+ offset += pointer_size;
+ pnp->bus = elf_address_from_pointer(efile, p + offset);
+ offset += pointer_size;
+ pnp->table = elf_address_from_pointer(efile, p + offset);
+ offset += pointer_size;
+ offset = roundup(offset, pointer_size);
+ pnp->entry_len = elf_int(efile, p + offset);
+ offset += sizeof(int);
+ pnp->num_entry = elf_int(efile, p + offset);
+ free(p);
+ return (0);
+}
+
+int
+elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
+ GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
+{
+ return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len,
+ dest));
+}
diff --git a/usr.sbin/kldxref/kldxref.c b/usr.sbin/kldxref/kldxref.c
index 913b64ee2a16..68f010a6db98 100644
--- a/usr.sbin/kldxref/kldxref.c
+++ b/usr.sbin/kldxref/kldxref.c
@@ -32,27 +32,24 @@
* SUCH DAMAGE.
*/
-#include <sys/types.h>
#include <sys/param.h>
#include <sys/endian.h>
-#include <sys/exec.h>
#include <sys/queue.h>
-#include <sys/kernel.h>
-#include <sys/reboot.h>
-#include <sys/linker.h>
#include <sys/stat.h>
#include <sys/module.h>
+#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
+#include <gelf.h>
+#include <libelf.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <machine/elf.h>
#include "ef.h"
@@ -63,6 +60,9 @@ static bool dflag; /* do not create a hint file, only write on stdout */
static int verbose;
static FILE *fxref; /* current hints file */
+static int byte_order;
+static GElf_Ehdr ehdr;
+static char *ehdr_filename;
static const char *xref_file = "linker.hints";
@@ -81,6 +81,19 @@ intalign(void)
}
static void
+write_int(int val)
+{
+ char buf[4];
+
+ assert(byte_order != ELFDATANONE);
+ if (byte_order == ELFDATA2LSB)
+ le32enc(buf, val);
+ else
+ be32enc(buf, val);
+ fwrite(buf, sizeof(buf), 1, fxref);
+}
+
+static void
record_start(void)
{
@@ -92,11 +105,24 @@ static int
record_end(void)
{
- if (recpos == 0)
+ if (recpos == 0) {
+ /*
+ * Pretend to have written a record in debug mode so
+ * the architecture check works.
+ */
+ if (dflag)
+ reccnt++;
return (0);
+ }
+
+ if (reccnt == 0) {
+ /* File version record. */
+ write_int(1);
+ }
+
reccnt++;
intalign();
- fwrite(&recpos, sizeof(recpos), 1, fxref);
+ write_int(recpos);
return (fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0);
}
@@ -112,14 +138,21 @@ record_buf(const void *buf, size_t size)
}
/*
- * An int is stored in host order and aligned
+ * An int is stored in target byte order and aligned
*/
static int
record_int(int val)
{
+ char buf[4];
+
+ assert(byte_order != ELFDATANONE);
+ if (byte_order == ELFDATA2LSB)
+ le32enc(buf, val);
+ else
+ be32enc(buf, val);
intalign();
- return (record_buf(&val, sizeof(val)));
+ return (record_buf(buf, sizeof(buf)));
}
/*
@@ -227,7 +260,8 @@ typedef TAILQ_HEAD(pnp_head, pnp_elt) pnp_list;
* sign extension to uint32_t to simplify parsing downstream.
*/
static int
-parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
+parse_pnp_list(struct elf_file *ef, const char *desc, char **new_desc,
+ pnp_list *list)
{
const char *walker, *ep;
const char *colon, *semi;
@@ -274,7 +308,7 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
printf("Found type %s for name %s\n", type, key);
/* Skip pointer place holders */
if (strcmp(type, "P") == 0) {
- off += sizeof(void *);
+ off += elf_pointer_size(ef);
continue;
}
@@ -333,8 +367,8 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
/* doesn't actually consume space in the table */
off = elt->pe_offset;
} else {
- elt->pe_offset = roundup2(elt->pe_offset, sizeof(void *));
- off = elt->pe_offset + sizeof(void *);
+ elt->pe_offset = roundup2(elt->pe_offset, elf_pointer_size(ef));
+ off = elt->pe_offset + elf_pointer_size(ef);
}
if (elt->pe_kind & TYPE_PAIRED) {
char *word, *ctx, newtype;
@@ -392,6 +426,24 @@ free_pnp_list(char *new_desc, pnp_list *list)
free(new_desc);
}
+static uint16_t
+parse_16(const void *p)
+{
+ if (byte_order == ELFDATA2LSB)
+ return (le16dec(p));
+ else
+ return (be16dec(p));
+}
+
+static uint32_t
+parse_32(const void *p)
+{
+ if (byte_order == ELFDATA2LSB)
+ return (le32dec(p));
+ else
+ return (be32dec(p));
+}
+
static void
parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker)
{
@@ -402,7 +454,7 @@ parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker)
char buffer[1024];
if (elt->pe_kind == TYPE_W32) {
- memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+ v4 = parse_32(walker + elt->pe_offset);
value = v4 & 0xffff;
record_int(value);
if (verbose > 1)
@@ -421,14 +473,14 @@ parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker)
value = v1;
break;
case 2:
- memcpy(&v2, walker + elt->pe_offset, sizeof(v2));
+ v2 = parse_16(walker + elt->pe_offset);
if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff)
value = -1;
else
value = v2;
break;
case 4:
- memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+ v4 = parse_32(walker + elt->pe_offset);
if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff)
value = -1;
else
@@ -444,16 +496,17 @@ parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker)
/* Do nothing */
} else { /* E, Z or D -- P already filtered */
if (elt->pe_kind == TYPE_E) {
- memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+ v4 = parse_32(walker + elt->pe_offset);
strcpy(buffer, pnp_eisaformat(v4));
} else {
- char *ptr;
+ GElf_Addr address;
- ptr = *(char **)(walker + elt->pe_offset);
+ address = elf_address_from_pointer(ef, walker +
+ elt->pe_offset);
buffer[0] = '\0';
- if (ptr != NULL) {
- EF_SEG_READ_STRING(ef, (Elf_Off)ptr,
- sizeof(buffer), buffer);
+ if (address != 0) {
+ elf_read_string(ef, address, buffer,
+ sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
}
}
@@ -466,7 +519,7 @@ parse_pnp_entry(struct elf_file *ef, struct pnp_elt *elt, const char *walker)
static void
record_pnp_info(struct elf_file *ef, const char *cval,
- struct mod_pnp_match_info *pnp, const char *descr)
+ struct Gmod_pnp_match_info *pnp, const char *descr)
{
pnp_list list;
struct pnp_elt *elt;
@@ -483,17 +536,15 @@ record_pnp_info(struct elf_file *ef, const char *cval,
* Parse descr to weed out the chaff and to create a list
* of offsets to output.
*/
- parse_pnp_list(descr, &new_descr, &list);
+ parse_pnp_list(ef, descr, &new_descr, &list);
record_int(MDT_PNP_INFO);
record_string(cval);
record_string(new_descr);
record_int(pnp->num_entry);
len = pnp->num_entry * pnp->entry_len;
- table = malloc(len);
- error = EF_SEG_READ_REL(ef, (Elf_Off)pnp->table, len, table);
+ error = elf_read_relocated_data(ef, pnp->table, len, &table);
if (error != 0) {
free_pnp_list(new_descr, &list);
- free(table);
return;
}
@@ -517,29 +568,29 @@ record_pnp_info(struct elf_file *ef, const char *cval,
}
static int
-parse_entry(struct mod_metadata *md, const char *cval,
+parse_entry(struct Gmod_metadata *md, const char *cval,
struct elf_file *ef, const char *kldname)
{
- struct mod_depend mdp;
- struct mod_version mdv;
- struct mod_pnp_match_info pnp;
+ struct Gmod_depend mdp;
+ struct Gmod_version mdv;
+ struct Gmod_pnp_match_info pnp;
char descr[1024];
- Elf_Off data;
+ GElf_Addr data;
int error;
- data = (Elf_Off)md->md_data;
+ data = md->md_data;
error = 0;
record_start();
switch (md->md_type) {
case MDT_DEPEND:
if (!dflag)
break;
- check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp));
+ check(elf_read_mod_depend(ef, data, &mdp));
printf(" depends on %s.%d (%d,%d)\n", cval,
mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum);
break;
case MDT_VERSION:
- check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv));
+ check(elf_read_mod_version(ef, data, &mdv));
if (dflag) {
printf(" interface %s.%d\n", cval, mdv.mv_version);
} else {
@@ -559,9 +610,8 @@ parse_entry(struct mod_metadata *md, const char *cval,
}
break;
case MDT_PNP_INFO:
- check(EF_SEG_READ_REL(ef, data, sizeof(pnp), &pnp));
- check(EF_SEG_READ_STRING(ef, (Elf_Off)pnp.descr, sizeof(descr), descr));
- descr[sizeof(descr) - 1] = '\0';
+ check(elf_read_mod_pnp_match_info(ef, data, &pnp));
+ check(elf_read_string(ef, pnp.descr, descr, sizeof(descr)));
if (dflag) {
printf(" pnp info for bus %s format %s %d entries of %d bytes\n",
cval, descr, pnp.num_entry, pnp.entry_len);
@@ -580,34 +630,35 @@ parse_entry(struct mod_metadata *md, const char *cval,
static int
read_kld(char *filename, char *kldname)
{
- struct mod_metadata md;
+ struct Gmod_metadata md;
struct elf_file ef;
- void **p;
- int error, eftype;
- long start, finish, entries, i;
+ GElf_Addr *p;
+ int error;
+ long entries, i;
char cval[MAXMODNAME + 1];
if (verbose || dflag)
printf("%s\n", filename);
- error = ef_open(filename, &ef, verbose);
- if (error != 0) {
- error = ef_obj_open(filename, &ef, verbose);
- if (error != 0) {
- if (verbose)
- warnc(error, "elf_open(%s)", filename);
- return (error);
- }
- }
- eftype = EF_GET_TYPE(&ef);
- if (eftype != EFT_KLD && eftype != EFT_KERNEL) {
- EF_CLOSE(&ef);
- return (0);
+
+ error = elf_open_file(&ef, filename, verbose);
+ if (error != 0)
+ return (error);
+
+ if (reccnt == 0) {
+ ehdr = ef.ef_hdr;
+ byte_order = elf_encoding(&ef);
+ free(ehdr_filename);
+ ehdr_filename = strdup(filename);
+ } else if (!elf_compatible(&ef, &ehdr)) {
+ warnx("%s does not match architecture of %s",
+ filename, ehdr_filename);
+ elf_close_file(&ef);
+ return (EINVAL);
}
+
do {
- check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish,
- &entries));
- check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries,
- (void *)&p));
+ check(elf_read_linker_set(&ef, MDT_SETNAME, &p, &entries));
+
/*
* Do a first pass to find MDT_MODULE. It is required to be
* ordered first in the output linker.hints stream because it
@@ -627,16 +678,16 @@ read_kld(char *filename, char *kldname)
* in the same kld.
*/
for (i = 0; i < entries; i++) {
- check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md),
- &md));
- check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
- sizeof(cval), cval));
+ check(elf_read_mod_metadata(&ef, p[i], &md));
+ check(elf_read_string(&ef, md.md_cval, cval,
+ sizeof(cval)));
if (md.md_type == MDT_MODULE) {
parse_entry(&md, cval, &ef, kldname);
break;
}
}
if (error != 0) {
+ free(p);
warnc(error, "error while reading %s", filename);
break;
}
@@ -645,10 +696,9 @@ read_kld(char *filename, char *kldname)
* Second pass for all !MDT_MODULE entries.
*/
for (i = 0; i < entries; i++) {
- check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md),
- &md));
- check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
- sizeof(cval), cval));
+ check(elf_read_mod_metadata(&ef, p[i], &md));
+ check(elf_read_string(&ef, md.md_cval, cval,
+ sizeof(cval)));
if (md.md_type != MDT_MODULE)
parse_entry(&md, cval, &ef, kldname);
}
@@ -656,7 +706,7 @@ read_kld(char *filename, char *kldname)
warnc(error, "error while reading %s", filename);
free(p);
} while(0);
- EF_CLOSE(&ef);
+ elf_close_file(&ef);
return (error);
}
@@ -714,7 +764,7 @@ main(int argc, char *argv[])
FTS *ftsp;
FTSENT *p;
char *dot = NULL;
- int opt, fts_options, ival;
+ int opt, fts_options;
struct stat sb;
fts_options = FTS_PHYSICAL;
@@ -750,6 +800,9 @@ main(int argc, char *argv[])
err(1, "%s", argv[0]);
}
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ errx(1, "unsupported libelf");
+
ftsp = fts_open(argv, fts_options, compare);
if (ftsp == NULL)
exit(1);
@@ -777,8 +830,7 @@ main(int argc, char *argv[])
fxref = maketempfile(tempname, ftsp->fts_path);
if (fxref == NULL)
err(1, "can't create %s", tempname);
- ival = 1;
- fwrite(&ival, sizeof(ival), 1, fxref);
+ byte_order = ELFDATANONE;
reccnt = 0;
}
/* skip non-files.. */