diff --git a/usr.sbin/kldxref/ef.c b/usr.sbin/kldxref/ef.c index fd0782ff1dd0..1ef27f2bc54a 100644 --- a/usr.sbin/kldxref/ef.c +++ b/usr.sbin/kldxref/ef.c @@ -1,651 +1,660 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000, Boris Popov * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * 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 #include #include #include #include #include #include #include "ef.h" #define MAXSEGS 16 struct ef_file { char *ef_name; struct elf_file *ef_efile; GElf_Phdr *ef_ph; void *ef_fpage; /* First block of the file */ int ef_fplen; /* length of first block */ GElf_Hashelt ef_nbuckets; GElf_Hashelt ef_nchains; GElf_Hashelt *ef_buckets; GElf_Hashelt *ef_chains; GElf_Hashelt *ef_hashtab; caddr_t ef_strtab; long ef_strsz; GElf_Sym *ef_symtab; int ef_nsegs; GElf_Phdr *ef_segs[MAXSEGS]; int ef_verbose; 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(GElf_Phdr *); static GElf_Off ef_get_offset(elf_file_t, GElf_Addr); static void ef_close(elf_file_t ef); static int ef_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest); static int ef_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char *dest); 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, GElf_Sym **sym); static struct elf_file_ops ef_file_ops = { .close = ef_close, .seg_read_rel = ef_seg_read_rel, .seg_read_string = ef_seg_read_string, .symaddr = ef_symaddr, .lookup_set = ef_lookup_set, }; static void ef_print_phdr(GElf_Phdr *phdr) { if ((phdr->p_flags & PF_W) == 0) { printf("text=0x%jx ", (uintmax_t)phdr->p_filesz); } else { printf("data=0x%jx", (uintmax_t)phdr->p_filesz); if (phdr->p_filesz < phdr->p_memsz) printf("+0x%jx", (uintmax_t)(phdr->p_memsz - phdr->p_filesz)); printf(" "); } } static GElf_Off ef_get_offset(elf_file_t ef, GElf_Addr addr) { GElf_Phdr *ph; int i; for (i = 0; i < ef->ef_nsegs; i++) { ph = ef->ef_segs[i]; if (addr >= ph->p_vaddr && addr < ph->p_vaddr + ph->p_memsz) { return (ph->p_offset + (addr - ph->p_vaddr)); } } return (0); } /* * next two functions copied from link_elf.c */ static int ef_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym) { unsigned long hash, symnum; GElf_Sym *symp; char *strp; /* First, search hashed global symbols */ hash = elf_hash(name); symnum = ef->ef_buckets[hash % ef->ef_nbuckets]; while (symnum != STN_UNDEF) { if (symnum >= ef->ef_nchains) { warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", ef->ef_name); return (ENOENT); } symp = ef->ef_symtab + symnum; if (symp->st_name == 0) { warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", ef->ef_name); return (ENOENT); } strp = ef->ef_strtab + symp->st_name; if (strcmp(name, strp) == 0) { if (symp->st_shndx != SHN_UNDEF || (symp->st_value != 0 && GELF_ST_TYPE(symp->st_info) == STT_FUNC)) { *sym = symp; return (0); } else return (ENOENT); } symnum = ef->ef_chains[symnum]; } return (ENOENT); } static int ef_lookup_set(elf_file_t ef, const char *name, GElf_Addr *startp, GElf_Addr *stopp, long *countp) { GElf_Sym *sym; char *setsym; int error, len; len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ setsym = malloc(len); if (setsym == NULL) return (errno); /* get address of first entry */ snprintf(setsym, len, "%s%s", "__start_set_", name); error = ef_lookup_symbol(ef, setsym, &sym); if (error != 0) 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 != 0) goto out; *stopp = sym->st_value; /* and the number of entries */ *countp = (*stopp - *startp) / elf_pointer_size(ef->ef_efile); out: free(setsym); return (error); } static GElf_Addr ef_symaddr(elf_file_t ef, GElf_Size symidx) { const GElf_Sym *sym; if (symidx >= ef->ef_nchains) return (0); sym = ef->ef_symtab + symidx; 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, const GElf_Phdr *phdyn) { GElf_Shdr *shdr; GElf_Dyn *dyn, *dp; size_t i, ndyn, nshdr, nsym; int error; GElf_Off hash_off, sym_off, str_off; GElf_Off rel_off; GElf_Off rela_off; int rel_sz; int rela_sz; int dynamic_idx; /* * 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) { + /* + * PowerPC kernels contain additional sections + * beyond .dynamic in PT_DYNAMIC due to a linker + * script bug. Permit a section with a smaller + * size as a workaround. + */ if (shdr[i].sh_offset != phdyn->p_offset || - shdr[i].sh_size != phdyn->p_filesz) { + ((elf_machine(ef->ef_efile) == EM_PPC || + elf_machine(ef->ef_efile) == EM_PPC64) ? + shdr[i].sh_size > phdyn->p_filesz : + 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; for (i = 0; i < ndyn; i++) { dp = &dyn[i]; if (dp->d_tag == DT_NULL) break; switch (dp->d_tag) { case DT_HASH: 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: 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: 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 != 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"); 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"); else rel_sz = dp->d_un.d_val; break; case DT_RELENT: 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"); else rela_off = ef_get_offset(ef, dp->d_un.d_ptr); break; case DT_RELASZ: if (rela_sz != 0) warnx("second DT_RELSZ entry ignored"); else rela_sz = dp->d_un.d_val; break; case DT_RELAENT: if (dp->d_un.d_val != elf_object_size(ef->ef_efile, ELF_T_RELA)) { error = EFTYPE; goto out; } break; } } 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); error = EFTYPE; goto out; } if (str_off == 0) { warnx("%s: no .dynstr section found\n", ef->ef_name); error = EFTYPE; goto out; } if (rel_off == 0 && rela_off == 0) { warnx("%s: no ELF relocation table found\n", ef->ef_name); error = EFTYPE; goto out; } nsym = 0; 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; } /* * 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(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; } 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; } } 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; } error = 0; out: free(dyn); free(shdr); return (error); } static int ef_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest) { GElf_Off ofs; const GElf_Rela *a; const GElf_Rel *r; int error; ofs = ef_get_offset(ef, address); if (ofs == 0) { if (ef->ef_verbose) warnx("ef_seg_read_rel(%s): bad address (%jx)", ef->ef_name, (uintmax_t)address); return (EFAULT); } 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 = 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 = elf_reloc(ef->ef_efile, a, ELF_T_RELA, 0, address, len, dest); if (error != 0) return (error); } return (0); } static int ef_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char *dest) { GElf_Off ofs; int error; ofs = ef_get_offset(ef, address); if (ofs == 0) { if (ef->ef_verbose) warnx("ef_seg_read_string(%s): bad offset (%jx:%ju)", ef->ef_name, (uintmax_t)address, (uintmax_t)ofs); return (EFAULT); } 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); } int ef_open(struct elf_file *efile, int verbose) { elf_file_t ef; GElf_Ehdr *hdr; size_t i, nphdr, nsegs; int error; GElf_Phdr *phdr, *phdyn; 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) return (errno); efile->ef_ef = ef; efile->ef_ops = &ef_file_ops; bzero(ef, sizeof(*ef)); ef->ef_verbose = verbose; ef->ef_name = strdup(efile->ef_filename); ef->ef_efile = efile; 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) 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; } } 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 void ef_close(elf_file_t ef) { 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); } diff --git a/usr.sbin/kldxref/ef.h b/usr.sbin/kldxref/ef.h index 2909704bf2d1..25dc5216b169 100644 --- a/usr.sbin/kldxref/ef.h +++ b/usr.sbin/kldxref/ef.h @@ -1,310 +1,311 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000, Boris Popov * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * 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. */ #ifndef _EF_H_ #define _EF_H_ #include #include #define EF_CLOSE(ef) \ (ef)->ef_ops->close((ef)->ef_ef) #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) /* 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 { 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 ef, GElf_Addr address, size_t len, char *dest); 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_machine(ef) ((ef)->ef_hdr.e_machine) #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 /* * 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. The data is returned in a dynamically-allocated * buffer. */ int elf_read_data(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(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, size_t *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, size_t *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_*/