Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157593723
D42966.id131142.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
93 KB
Referenced Files
None
Subscribers
None
D42966.id131142.diff
View Options
diff --git a/usr.sbin/kldxref/Makefile b/usr.sbin/kldxref/Makefile
--- 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.h b/usr.sbin/kldxref/ef.h
--- a/usr.sbin/kldxref/ef.h
+++ b/usr.sbin/kldxref/ef.h
@@ -35,71 +35,282 @@
#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.
+ */
+int elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset,
+ size_t len, void *out);
+
+/*
+ * A variant of elf_read_data which returns a dynamically-allocated
+ * output buffer.
+ */
+int elf_read_data_alloc(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_alloc(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.c b/usr.sbin/kldxref/ef.c
--- 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 @@
}
}
-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 @@
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 @@
}
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 @@
*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;
- rel_off = rela_off = 0;
+ /*
+ * 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;
+
+ 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);
+ error = EFTYPE;
+ goto out;
}
- 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 (rel_off == 0 && rela_off == 0) {
+ warnx("%s: no ELF relocation table found\n", ef->ef_name);
+ error = EFTYPE;
+ goto out;
}
- 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);
- }
- 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);
- }
- 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_alloc(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 @@
}
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_aarch64.c b/usr.sbin/kldxref/ef_aarch64.c
--- 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 @@
}
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
--- 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 @@
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
--- 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
--- 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
--- 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
--- 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 @@
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 @@
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)
+ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
{
-
- return (EFT_KLD);
-}
-
-static int
-ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
-{
- Elf_Sym *symp;
+ GElf_Sym *symp;
const char *strp;
int i;
@@ -160,102 +131,58 @@
}
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 @@
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 @@
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 @@
}
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;
+ size_t i, mapsize, alignmask, max_addralign, nshdr;
+ int error, pb, ra, rl;
+ int j, nsym, symstrindex, symtabindex;
- if (filename == NULL)
- return (EINVAL);
- if ((fd = open(filename, O_RDONLY)) == -1)
- return (errno);
+ 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
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->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
--- 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
--- 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
--- /dev/null
+++ b/usr.sbin/kldxref/elf.c
@@ -0,0 +1,685 @@
+/*-
+ * 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;
+ int error;
+
+ error = elf_read_raw_data(efile, offset, out, len);
+ if (error != 0)
+ return (error);
+
+ memset(&dst, 0, sizeof(dst));
+ memset(&src, 0, sizeof(src));
+
+ src.d_buf = out;
+ src.d_size = len;
+ src.d_type = type;
+ src.d_version = efile->ef_hdr.e_version;
+
+ dst.d_buf = out;
+ dst.d_size = len;
+ dst.d_version = EV_CURRENT;
+
+ if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
+ NULL)
+ return (ENXIO);
+
+ if (dst.d_size != len)
+ warnx("elf_read_data: translation of type %u size mismatch",
+ type);
+
+ return (0);
+}
+
+int
+elf_read_data_alloc(struct elf_file *efile, Elf_Type type, off_t offset,
+ size_t len, void **out)
+{
+ void *buf;
+ int error;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ error = elf_read_data(efile, type, offset, len, buf);
+ if (error != 0) {
+ free(buf);
+ return (error);
+ }
+
+ *out = buf;
+ return (0);
+}
+
+int
+elf_read_relocated_data_alloc(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_alloc(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_alloc(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_alloc(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_alloc(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
--- 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 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";
@@ -80,6 +80,19 @@
recpos = roundup2(recpos, sizeof(int));
}
+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 @@
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 @@
}
/*
- * 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 @@
* 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 @@
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 @@
/* 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(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 @@
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 @@
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 @@
/* 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 @@
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,14 +536,13 @@
* 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;
- walker = table = malloc(len);
- error = EF_SEG_READ_REL(ef, (Elf_Off)pnp->table, len, table);
+ error = elf_read_relocated_data_alloc(ef, pnp->table, len, &table);
if (error != 0)
return;
@@ -498,6 +550,7 @@
* Walk the list and output things. We've collapsed all the
* variant forms of the table down to just ints and strings.
*/
+ walker = table;
for (i = 0; i < pnp->num_entry; i++) {
TAILQ_FOREACH(elt, &list, next) {
parse_pnp_entry(ef, elt, walker);
@@ -513,29 +566,29 @@
}
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 {
@@ -555,9 +608,8 @@
}
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);
@@ -576,34 +628,35 @@
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
@@ -623,16 +676,16 @@
* 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;
}
@@ -641,10 +694,9 @@
* 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);
}
@@ -652,7 +704,7 @@
warnc(error, "error while reading %s", filename);
free(p);
} while(0);
- EF_CLOSE(&ef);
+ elf_close_file(&ef);
return (error);
}
@@ -710,7 +762,7 @@
FTS *ftsp;
FTSENT *p;
char *dot = NULL;
- int opt, fts_options, ival;
+ int opt, fts_options;
struct stat sb;
fts_options = FTS_PHYSICAL;
@@ -746,6 +798,9 @@
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);
@@ -773,8 +828,7 @@
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.. */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, May 24, 4:56 AM (12 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33464214
Default Alt Text
D42966.id131142.diff (93 KB)
Attached To
Mode
D42966: kldxref: Make use of libelf to be a portable cross tool
Attached
Detach File
Event Timeline
Log In to Comment