/*- * 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 _KLDELF_H_ #define _KLDELF_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) #define EF_LOOKUP_SYMBOL(ef, name, sym, see_local) \ (ef)->ef_ops->lookup_symbol((ef)->ef_ef, name, sym, see_local) /* 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); int (*lookup_symbol)(elf_file_t ef, const char *name, GElf_Sym **sym, bool see_local); }; 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); /* Reads a single string at the given offset from an ELF file. */ int elf_read_raw_string(struct elf_file *efile, off_t offset, char *dst, size_t len); /* * 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); /* * Find the symbol with the specified symbol name 'name' within the given * 'efile'. 0 is returned when such a symbol is found, otherwise ENOENT is * returned. */ int elf_lookup_symbol(struct elf_file *efile, const char *name, GElf_Sym **sym, bool see_local); __END_DECLS #endif /* _KLDELF_H_*/