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.
This commit is contained in:
Ian Dowse 2004-08-27 00:51:21 +00:00
parent 8ae136ae71
commit 9772dc2aff
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=134358
5 changed files with 244 additions and 75 deletions

View File

@ -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;
}

View File

@ -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_*/

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}