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/kldxref/ef.c | |
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/kldxref/ef.c')
-rw-r--r-- | usr.sbin/kldxref/ef.c | 181 |
1 files changed, 162 insertions, 19 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; } |