diff options
author | iedowse <iedowse@FreeBSD.org> | 2004-08-27 00:51:21 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2004-08-27 00:51:21 +0000 |
commit | ca4083743c48cec21ba5c9a25cbce859b03dd5ee (patch) | |
tree | cafc6d44f1ca4971ce6a150dd1e2a3b9b970cf2c /usr.sbin | |
parent | 878483bef2ba8584138f0acac5145affaba34958 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | usr.sbin/kldxref/ef.c | 181 | ||||
-rw-r--r-- | usr.sbin/kldxref/ef.h | 93 | ||||
-rw-r--r-- | usr.sbin/kldxref/ef_nop.c | 3 | ||||
-rw-r--r-- | usr.sbin/kldxref/ef_sparc64.c | 8 | ||||
-rw-r--r-- | usr.sbin/kldxref/kldxref.c | 34 |
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; } |