summaryrefslogtreecommitdiffstats
path: root/usr.sbin/kldxref
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2004-08-27 00:51:21 +0000
committeriedowse <iedowse@FreeBSD.org>2004-08-27 00:51:21 +0000
commitca4083743c48cec21ba5c9a25cbce859b03dd5ee (patch)
treecafc6d44f1ca4971ce6a150dd1e2a3b9b970cf2c /usr.sbin/kldxref
parent878483bef2ba8584138f0acac5145affaba34958 (diff)
downloadFreeBSD-src-ca4083743c48cec21ba5c9a25cbce859b03dd5ee.zip
FreeBSD-src-ca4083743c48cec21ba5c9a25cbce859b03dd5ee.tar.gz
Call the file format specific code through a table of function
pointers and remove knowledge of the file format from kldxref.c. This will make it possible to support more than one file format.
Diffstat (limited to 'usr.sbin/kldxref')
-rw-r--r--usr.sbin/kldxref/ef.c181
-rw-r--r--usr.sbin/kldxref/ef.h93
-rw-r--r--usr.sbin/kldxref/ef_nop.c3
-rw-r--r--usr.sbin/kldxref/ef_sparc64.c8
-rw-r--r--usr.sbin/kldxref/kldxref.c34
5 files changed, 244 insertions, 75 deletions
diff --git a/usr.sbin/kldxref/ef.c b/usr.sbin/kldxref/ef.c
index 142c9cb..55efb53 100644
--- a/usr.sbin/kldxref/ef.c
+++ b/usr.sbin/kldxref/ef.c
@@ -48,11 +48,70 @@
#include "ef.h"
+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;
+ 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;
+ caddr_t ef_strtab;
+ int ef_strsz;
+ Elf_Off ef_symoff;
+ Elf_Sym* ef_symtab;
+ int ef_nsegs;
+ Elf_Phdr * ef_segs[2];
+ 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 */
+};
+
static void ef_print_phdr(Elf_Phdr *);
static u_long ef_get_offset(elf_file_t, Elf_Off);
static int ef_parse_dynamic(elf_file_t);
-void
+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 int ef_seg_read(elf_file_t ef, Elf_Off offset, 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_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_Word symidx);
+static int ef_lookup_set(elf_file_t ef, const char *name, long *startp,
+ long *stopp, long *countp);
+static int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
+
+static struct elf_file_ops ef_file_ops = {
+ ef_get_type,
+ ef_close,
+ ef_read,
+ ef_read_entry,
+ ef_seg_read,
+ ef_seg_read_rel,
+ ef_seg_read_entry,
+ ef_seg_read_entry_rel,
+ ef_symaddr,
+ ef_lookup_set,
+ ef_lookup_symbol
+};
+
+static void
ef_print_phdr(Elf_Phdr *phdr)
{
@@ -66,7 +125,7 @@ ef_print_phdr(Elf_Phdr *phdr)
}
}
-u_long
+static u_long
ef_get_offset(elf_file_t ef, Elf_Off off)
{
Elf_Phdr *ph;
@@ -81,6 +140,13 @@ ef_get_offset(elf_file_t ef, Elf_Off off)
return 0;
}
+static int
+ef_get_type(elf_file_t ef)
+{
+
+ return (ef->ef_type);
+}
+
/*
* next three functions copied from link_elf.c
*/
@@ -100,7 +166,7 @@ elf_hash(const char *name)
return h;
}
-int
+static int
ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
{
unsigned long symnum;
@@ -144,7 +210,57 @@ ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
return ENOENT;
}
-int
+static int
+ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
+ long *countp)
+{
+ Elf_Sym *sym;
+ char *setsym;
+ int error, len;
+
+ len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
+ setsym = malloc(len);
+ if (setsym == NULL)
+ return (ENOMEM);
+
+ /* get address of first entry */
+ snprintf(setsym, len, "%s%s", "__start_set_", name);
+ error = ef_lookup_symbol(ef, setsym, &sym);
+ if (error)
+ goto out;
+ *startp = sym->st_value;
+
+ /* get address of last entry */
+ snprintf(setsym, len, "%s%s", "__stop_set_", name);
+ error = ef_lookup_symbol(ef, setsym, &sym);
+ if (error)
+ goto out;
+ *stopp = sym->st_value;
+
+ /* and the number of entries */
+ *countp = (*stopp - *startp) / sizeof(void *);
+
+out:
+ free(setsym);
+ return (error);
+}
+
+static Elf_Addr
+ef_symaddr(elf_file_t ef, Elf_Word symidx)
+{
+ const Elf_Sym *sym;
+
+ if (symidx >= ef->ef_nchains)
+ return (0);
+ sym = ef->ef_symtab + symidx;
+
+ if (ELF_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)
{
Elf_Dyn *dp;
@@ -302,7 +418,7 @@ ef_parse_dynamic(elf_file_t ef)
return 0;
}
-int
+static int
ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
{
ssize_t r;
@@ -319,7 +435,7 @@ ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
return EIO;
}
-int
+static int
ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
{
int error;
@@ -333,7 +449,7 @@ ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
return error;
}
-int
+static int
ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
{
u_long ofs = ef_get_offset(ef, offset);
@@ -347,10 +463,12 @@ ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
return ef_read(ef, ofs, len, dest);
}
-int
+static int
ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
{
u_long ofs = ef_get_offset(ef, offset);
+ const Elf_Rela *a;
+ const Elf_Rel *r;
int error;
if (ofs == 0) {
@@ -361,10 +479,23 @@ ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
}
if ((error = ef_read(ef, ofs, len, dest)) != 0)
return (error);
- return (ef_reloc(ef, offset, len, dest));
+
+ for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
+ error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, offset, 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, offset, len,
+ dest);
+ if (error != 0)
+ return (error);
+ }
+ return (0);
}
-int
+static int
ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
{
int error;
@@ -378,7 +509,7 @@ ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
return error;
}
-int
+static int
ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
{
int error;
@@ -393,8 +524,9 @@ ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
}
int
-ef_open(const char *filename, elf_file_t ef, int verbose)
+ef_open(const char *filename, struct elf_file *efile, int verbose)
{
+ elf_file_t ef;
Elf_Ehdr *hdr;
int fd;
int error;
@@ -402,14 +534,25 @@ ef_open(const char *filename, elf_file_t ef, int verbose)
int nsegs;
Elf_Phdr *phdr, *phdyn, *phphdr, *phlimit;
- bzero(ef, sizeof(*ef));
if (filename == NULL)
return EFTYPE;
- ef->ef_verbose = verbose;
if ((fd = open(filename, O_RDONLY)) == -1)
return errno;
+
+ ef = malloc(sizeof(*ef));
+ if (ef == NULL) {
+ close(fd);
+ return (ENOMEM);
+ }
+
+ 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_efile = efile;
hdr = (Elf_Ehdr *)&ef->ef_hdr;
do {
res = read(fd, hdr, sizeof(*hdr));
@@ -485,15 +628,12 @@ ef_open(const char *filename, elf_file_t ef, int verbose)
} else
break;
} while(0);
- if (error) {
+ if (error)
ef_close(ef);
- if (ef->ef_verbose)
- warnc(error, "elf_open(%s)", filename);
- }
return error;
}
-int
+static int
ef_close(elf_file_t ef)
{
close(ef->ef_fd);
@@ -501,5 +641,8 @@ ef_close(elf_file_t ef)
free(ef->ef_fpage);*/
if (ef->ef_name)
free(ef->ef_name);
+ ef->ef_efile->ef_ops = NULL;
+ ef->ef_efile->ef_ef = NULL;
+ free(ef);
return 0;
}
diff --git a/usr.sbin/kldxref/ef.h b/usr.sbin/kldxref/ef.h
index f9a7884..6a5a627 100644
--- a/usr.sbin/kldxref/ef.h
+++ b/usr.sbin/kldxref/ef.h
@@ -6,45 +6,64 @@
#define EFT_KLD 1
#define EFT_KERNEL 2
-typedef struct elf_file {
- char* ef_name;
- Elf_Phdr * ef_ph;
- int ef_fd;
- int ef_type;
- Elf_Ehdr ef_hdr;
- 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;
- caddr_t ef_strtab;
- int ef_strsz;
- Elf_Off ef_symoff;
- Elf_Sym* ef_symtab;
- int ef_nsegs;
- Elf_Phdr * ef_segs[2];
- 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 */
-} *elf_file_t;
+#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_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_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;
+
+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 *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_Word 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);
+};
+
+struct elf_file {
+ elf_file_t ef_ef;
+ struct elf_file_ops *ef_ops;
+};
__BEGIN_DECLS
-int ef_open(const char *, elf_file_t, int);
-int ef_close(elf_file_t ef);
-int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
-int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
-int ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
-int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
-int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
-int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr);
-int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr);
-int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
+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 *data, int type, Elf_Off offset,
+ size_t len, void *dest);
__END_DECLS
#endif /* _EF_H_*/
diff --git a/usr.sbin/kldxref/ef_nop.c b/usr.sbin/kldxref/ef_nop.c
index 3fff5de..b1a798b 100644
--- a/usr.sbin/kldxref/ef_nop.c
+++ b/usr.sbin/kldxref/ef_nop.c
@@ -32,7 +32,8 @@
#include "ef.h"
int
-ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
+ef_reloc(struct elf_file *ef, const void *data, int type, Elf_Off offset,
+ size_t len, void *dest)
{
return (0);
diff --git a/usr.sbin/kldxref/ef_sparc64.c b/usr.sbin/kldxref/ef_sparc64.c
index bc728a4..78b40db 100644
--- a/usr.sbin/kldxref/ef_sparc64.c
+++ b/usr.sbin/kldxref/ef_sparc64.c
@@ -38,12 +38,15 @@
* Apply relocations to the values we got from the file.
*/
int
-ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
+ef_reloc(struct elf_file *ef, const void *data, int type, Elf_Off offset,
+ size_t len, void *dest)
{
const Elf_Rela *a;
Elf_Word w;
- for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
+ switch (type) {
+ case EF_RELOC_RELA:
+ a = data;
if (a->r_offset >= offset && a->r_offset < offset + len) {
switch (ELF_R_TYPE(a->r_info)) {
case R_SPARC_RELATIVE:
@@ -58,6 +61,7 @@ ef_reloc(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
break;
}
}
+ break;
}
return (0);
}
diff --git a/usr.sbin/kldxref/kldxref.c b/usr.sbin/kldxref/kldxref.c
index 0597cce..4206795 100644
--- a/usr.sbin/kldxref/kldxref.c
+++ b/usr.sbin/kldxref/kldxref.c
@@ -164,12 +164,12 @@ parse_entry(struct mod_metadata *md, const char *cval,
case MDT_DEPEND:
if (!dflag)
break;
- check(ef_seg_read(ef, data, sizeof(mdp), &mdp));
+ check(EF_SEG_READ(ef, data, sizeof(mdp), &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(EF_SEG_READ(ef, data, sizeof(mdv), &mdv));
record_int(MDT_VERSION);
record_string(cval);
record_int(mdv.mv_version);
@@ -202,18 +202,21 @@ read_kld(char *filename, char *kldname)
/* struct kld_info *kip;
struct mod_info *mip;*/
void **p, **orgp;
- int error, nmlen;
+ int error, eftype, nmlen;
long start, finish, entries;
- Elf_Sym *sym;
char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp;
if (verbose || dflag)
printf("%s\n", filename);
error = ef_open(filename, &ef, verbose);
- if (error)
+ if (error) {
+ if (verbose)
+ warnc(error, "elf_open(%s)", filename);
return error;
- if (ef.ef_type != EFT_KLD && ef.ef_type != EFT_KERNEL) {
- ef_close(&ef);
+ }
+ eftype = EF_GET_TYPE(&ef);
+ if (eftype != EFT_KLD && eftype != EFT_KERNEL) {
+ EF_CLOSE(&ef);
return 0;
}
if (!dflag) {
@@ -225,18 +228,17 @@ read_kld(char *filename, char *kldname)
/* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/
}
do {
- check(ef_lookup_symbol(&ef, "__start_set_" MDT_SETNAME, &sym));
- start = sym->st_value;
- check(ef_lookup_symbol(&ef, "__stop_set_" MDT_SETNAME, &sym));
- finish = sym->st_value;
- entries = (finish - start) / sizeof(void *);
- check(ef_seg_read_entry_rel(&ef, start, sizeof(*p) * entries,
+ check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish,
+ &entries));
+ check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries,
(void *)&p));
orgp = p;
while(entries--) {
- check(ef_seg_read_rel(&ef, (Elf_Off)*p, sizeof(md), &md));
+ check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md),
+ &md));
p++;
- check(ef_seg_read(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval));
+ check(EF_SEG_READ(&ef, (Elf_Off)md.md_cval,
+ sizeof(cval), cval));
cval[MAXMODNAME] = '\0';
parse_entry(&md, cval, &ef, kldname);
}
@@ -244,7 +246,7 @@ read_kld(char *filename, char *kldname)
warnc(error, "error while reading %s", filename);
free(orgp);
} while(0);
- ef_close(&ef);
+ EF_CLOSE(&ef);
return error;
}
OpenPOWER on IntegriCloud