1968bcca2SKa Ho Ng /*- 2968bcca2SKa Ho Ng * SPDX-License-Identifier: BSD-4-Clause 3968bcca2SKa Ho Ng * 4968bcca2SKa Ho Ng * Copyright (c) 2000, Boris Popov 5968bcca2SKa Ho Ng * All rights reserved. 6968bcca2SKa Ho Ng * 7968bcca2SKa Ho Ng * Redistribution and use in source and binary forms, with or without 8968bcca2SKa Ho Ng * modification, are permitted provided that the following conditions 9968bcca2SKa Ho Ng * are met: 10968bcca2SKa Ho Ng * 1. Redistributions of source code must retain the above copyright 11968bcca2SKa Ho Ng * notice, this list of conditions and the following disclaimer. 12968bcca2SKa Ho Ng * 2. Redistributions in binary form must reproduce the above copyright 13968bcca2SKa Ho Ng * notice, this list of conditions and the following disclaimer in the 14968bcca2SKa Ho Ng * documentation and/or other materials provided with the distribution. 15968bcca2SKa Ho Ng * 3. All advertising materials mentioning features or use of this software 16968bcca2SKa Ho Ng * must display the following acknowledgement: 17968bcca2SKa Ho Ng * This product includes software developed by Boris Popov. 18968bcca2SKa Ho Ng * 4. Neither the name of the author nor the names of any co-contributors 19968bcca2SKa Ho Ng * may be used to endorse or promote products derived from this software 20968bcca2SKa Ho Ng * without specific prior written permission. 21968bcca2SKa Ho Ng * 22968bcca2SKa Ho Ng * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23968bcca2SKa Ho Ng * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24968bcca2SKa Ho Ng * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25968bcca2SKa Ho Ng * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26968bcca2SKa Ho Ng * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27968bcca2SKa Ho Ng * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28968bcca2SKa Ho Ng * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29968bcca2SKa Ho Ng * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30968bcca2SKa Ho Ng * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31968bcca2SKa Ho Ng * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32968bcca2SKa Ho Ng * SUCH DAMAGE. 33968bcca2SKa Ho Ng */ 34968bcca2SKa Ho Ng 35968bcca2SKa Ho Ng #ifndef _KLDELF_H_ 36968bcca2SKa Ho Ng #define _KLDELF_H_ 37968bcca2SKa Ho Ng 38968bcca2SKa Ho Ng #include <sys/linker_set.h> 39968bcca2SKa Ho Ng #include <stdbool.h> 40968bcca2SKa Ho Ng 41968bcca2SKa Ho Ng #define EF_CLOSE(ef) \ 42968bcca2SKa Ho Ng (ef)->ef_ops->close((ef)->ef_ef) 43968bcca2SKa Ho Ng #define EF_SEG_READ_REL(ef, address, len, dest) \ 44968bcca2SKa Ho Ng (ef)->ef_ops->seg_read_rel((ef)->ef_ef, address, len, dest) 45968bcca2SKa Ho Ng #define EF_SEG_READ_STRING(ef, address, len, dest) \ 46968bcca2SKa Ho Ng (ef)->ef_ops->seg_read_string((ef)->ef_ef, address, len, dest) 47968bcca2SKa Ho Ng #define EF_SYMADDR(ef, symidx) \ 48968bcca2SKa Ho Ng (ef)->ef_ops->symaddr((ef)->ef_ef, symidx) 49968bcca2SKa Ho Ng #define EF_LOOKUP_SET(ef, name, startp, stopp, countp) \ 50968bcca2SKa Ho Ng (ef)->ef_ops->lookup_set((ef)->ef_ef, name, startp, stopp, countp) 51*72e15f76SKa Ho Ng #define EF_LOOKUP_SYMBOL(ef, name, sym, see_local) \ 52*72e15f76SKa Ho Ng (ef)->ef_ops->lookup_symbol((ef)->ef_ef, name, sym, see_local) 53968bcca2SKa Ho Ng 54968bcca2SKa Ho Ng /* XXX, should have a different name. */ 55968bcca2SKa Ho Ng typedef struct ef_file *elf_file_t; 56968bcca2SKa Ho Ng 57968bcca2SKa Ho Ng /* FreeBSD's headers define additional typedef's for ELF structures. */ 58968bcca2SKa Ho Ng typedef Elf64_Size GElf_Size; 59968bcca2SKa Ho Ng typedef Elf64_Hashelt GElf_Hashelt; 60968bcca2SKa Ho Ng 61968bcca2SKa Ho Ng struct elf_file; 62968bcca2SKa Ho Ng 63968bcca2SKa Ho Ng struct elf_file_ops { 64968bcca2SKa Ho Ng void (*close)(elf_file_t ef); 65968bcca2SKa Ho Ng int (*seg_read_rel)(elf_file_t ef, GElf_Addr address, size_t len, 66968bcca2SKa Ho Ng void *dest); 67968bcca2SKa Ho Ng int (*seg_read_string)(elf_file_t ef, GElf_Addr address, size_t len, 68968bcca2SKa Ho Ng char *dest); 69968bcca2SKa Ho Ng GElf_Addr (*symaddr)(elf_file_t ef, GElf_Size symidx); 70968bcca2SKa Ho Ng int (*lookup_set)(elf_file_t ef, const char *name, GElf_Addr *startp, 71968bcca2SKa Ho Ng GElf_Addr *stopp, long *countp); 72*72e15f76SKa Ho Ng int (*lookup_symbol)(elf_file_t ef, const char *name, GElf_Sym **sym, 73*72e15f76SKa Ho Ng bool see_local); 74968bcca2SKa Ho Ng }; 75968bcca2SKa Ho Ng 76968bcca2SKa Ho Ng typedef int (elf_reloc_t)(struct elf_file *ef, const void *reldata, 77968bcca2SKa Ho Ng Elf_Type reltype, GElf_Addr relbase, GElf_Addr dataoff, size_t len, 78968bcca2SKa Ho Ng void *dest); 79968bcca2SKa Ho Ng 80968bcca2SKa Ho Ng struct elf_reloc_data { 81968bcca2SKa Ho Ng unsigned char class; 82968bcca2SKa Ho Ng unsigned char data; 83968bcca2SKa Ho Ng GElf_Half machine; 84968bcca2SKa Ho Ng elf_reloc_t *reloc; 85968bcca2SKa Ho Ng }; 86968bcca2SKa Ho Ng 87968bcca2SKa Ho Ng #define ELF_RELOC(_class, _data, _machine, _reloc) \ 88968bcca2SKa Ho Ng static struct elf_reloc_data __CONCAT(elf_reloc_data_, __LINE__) = { \ 89968bcca2SKa Ho Ng .class = (_class), \ 90968bcca2SKa Ho Ng .data = (_data), \ 91968bcca2SKa Ho Ng .machine = (_machine), \ 92968bcca2SKa Ho Ng .reloc = (_reloc) \ 93968bcca2SKa Ho Ng }; \ 94968bcca2SKa Ho Ng DATA_SET(elf_reloc, __CONCAT(elf_reloc_data_, __LINE__)) 95968bcca2SKa Ho Ng 96968bcca2SKa Ho Ng struct elf_file { 97968bcca2SKa Ho Ng elf_file_t ef_ef; 98968bcca2SKa Ho Ng struct elf_file_ops *ef_ops; 99968bcca2SKa Ho Ng const char *ef_filename; 100968bcca2SKa Ho Ng Elf *ef_elf; 101968bcca2SKa Ho Ng elf_reloc_t *ef_reloc; 102968bcca2SKa Ho Ng GElf_Ehdr ef_hdr; 103968bcca2SKa Ho Ng size_t ef_pointer_size; 104968bcca2SKa Ho Ng int ef_fd; 105968bcca2SKa Ho Ng }; 106968bcca2SKa Ho Ng 107968bcca2SKa Ho Ng #define elf_machine(ef) ((ef)->ef_hdr.e_machine) 108968bcca2SKa Ho Ng #define elf_class(ef) ((ef)->ef_hdr.e_ident[EI_CLASS]) 109968bcca2SKa Ho Ng #define elf_encoding(ef) ((ef)->ef_hdr.e_ident[EI_DATA]) 110968bcca2SKa Ho Ng 111968bcca2SKa Ho Ng /* 112968bcca2SKa Ho Ng * "Generic" versions of module metadata structures. 113968bcca2SKa Ho Ng */ 114968bcca2SKa Ho Ng struct Gmod_depend { 115968bcca2SKa Ho Ng int md_ver_minimum; 116968bcca2SKa Ho Ng int md_ver_preferred; 117968bcca2SKa Ho Ng int md_ver_maximum; 118968bcca2SKa Ho Ng }; 119968bcca2SKa Ho Ng 120968bcca2SKa Ho Ng struct Gmod_version { 121968bcca2SKa Ho Ng int mv_version; 122968bcca2SKa Ho Ng }; 123968bcca2SKa Ho Ng 124968bcca2SKa Ho Ng struct Gmod_metadata { 125968bcca2SKa Ho Ng int md_version; /* structure version MDTV_* */ 126968bcca2SKa Ho Ng int md_type; /* type of entry MDT_* */ 127968bcca2SKa Ho Ng GElf_Addr md_data; /* specific data */ 128968bcca2SKa Ho Ng GElf_Addr md_cval; /* common string label */ 129968bcca2SKa Ho Ng }; 130968bcca2SKa Ho Ng 131968bcca2SKa Ho Ng struct Gmod_pnp_match_info 132968bcca2SKa Ho Ng { 133968bcca2SKa Ho Ng GElf_Addr descr; /* Description of the table */ 134968bcca2SKa Ho Ng GElf_Addr bus; /* Name of the bus for this table */ 135968bcca2SKa Ho Ng GElf_Addr table; /* Pointer to pnp table */ 136968bcca2SKa Ho Ng int entry_len; /* Length of each entry in the table (may be */ 137968bcca2SKa Ho Ng /* longer than descr describes). */ 138968bcca2SKa Ho Ng int num_entry; /* Number of entries in the table */ 139968bcca2SKa Ho Ng }; 140968bcca2SKa Ho Ng 141968bcca2SKa Ho Ng __BEGIN_DECLS 142968bcca2SKa Ho Ng 143968bcca2SKa Ho Ng /* 144968bcca2SKa Ho Ng * Attempt to parse an open ELF file as either an executable or DSO 145968bcca2SKa Ho Ng * (ef_open) or an object file (ef_obj_open). On success, these 146968bcca2SKa Ho Ng * routines initialize the 'ef_ef' and 'ef_ops' members of 'ef'. 147968bcca2SKa Ho Ng */ 148968bcca2SKa Ho Ng int ef_open(struct elf_file *ef, int verbose); 149968bcca2SKa Ho Ng int ef_obj_open(struct elf_file *ef, int verbose); 150968bcca2SKa Ho Ng 151968bcca2SKa Ho Ng /* 152968bcca2SKa Ho Ng * Direct operations on an ELF file regardless of type. Many of these 153968bcca2SKa Ho Ng * use libelf. 154968bcca2SKa Ho Ng */ 155968bcca2SKa Ho Ng 156968bcca2SKa Ho Ng /* 157968bcca2SKa Ho Ng * Open an ELF file with libelf. Populates fields other than ef_ef 158968bcca2SKa Ho Ng * and ef_ops in '*efile'. 159968bcca2SKa Ho Ng */ 160968bcca2SKa Ho Ng int elf_open_file(struct elf_file *efile, const char *filename, 161968bcca2SKa Ho Ng int verbose); 162968bcca2SKa Ho Ng 163968bcca2SKa Ho Ng /* Close an ELF file. */ 164968bcca2SKa Ho Ng void elf_close_file(struct elf_file *efile); 165968bcca2SKa Ho Ng 166968bcca2SKa Ho Ng /* Is an ELF file the same architecture as hdr? */ 167968bcca2SKa Ho Ng bool elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr); 168968bcca2SKa Ho Ng 169968bcca2SKa Ho Ng /* The size of a single object of 'type'. */ 170968bcca2SKa Ho Ng size_t elf_object_size(struct elf_file *efile, Elf_Type type); 171968bcca2SKa Ho Ng 172968bcca2SKa Ho Ng /* The size of a pointer in architecture of 'efile'. */ 173968bcca2SKa Ho Ng size_t elf_pointer_size(struct elf_file *efile); 174968bcca2SKa Ho Ng 175968bcca2SKa Ho Ng /* 176968bcca2SKa Ho Ng * Read and convert an array of a data type from an ELF file. This is 177968bcca2SKa Ho Ng * a wrapper around gelf_xlatetom() which reads an array of raw ELF 178968bcca2SKa Ho Ng * objects from the file and converts them into host structures using 179968bcca2SKa Ho Ng * native endianness. The data is returned in a dynamically-allocated 180968bcca2SKa Ho Ng * buffer. 181968bcca2SKa Ho Ng */ 182968bcca2SKa Ho Ng int elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, 183968bcca2SKa Ho Ng size_t len, void **out); 184968bcca2SKa Ho Ng 185968bcca2SKa Ho Ng /* Reads "raw" data from an ELF file without any translation. */ 186968bcca2SKa Ho Ng int elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, 187968bcca2SKa Ho Ng size_t len); 188968bcca2SKa Ho Ng 189968bcca2SKa Ho Ng /* 190968bcca2SKa Ho Ng * A wrapper around elf_read_raw_data which returns the data in a 191968bcca2SKa Ho Ng * dynamically-allocated buffer. 192968bcca2SKa Ho Ng */ 193968bcca2SKa Ho Ng int elf_read_raw_data_alloc(struct elf_file *efile, off_t offset, 194968bcca2SKa Ho Ng size_t len, void **out); 195968bcca2SKa Ho Ng 196968bcca2SKa Ho Ng /* Reads a single string at the given offset from an ELF file. */ 197968bcca2SKa Ho Ng int elf_read_raw_string(struct elf_file *efile, off_t offset, char *dst, 198968bcca2SKa Ho Ng size_t len); 199968bcca2SKa Ho Ng 200968bcca2SKa Ho Ng /* 201968bcca2SKa Ho Ng * Read relocated data from an ELF file and return it in a 202968bcca2SKa Ho Ng * dynamically-allocated buffer. Note that no translation 203968bcca2SKa Ho Ng * (byte-swapping for endianness, 32-vs-64) is performed on the 204968bcca2SKa Ho Ng * returned data, but any ELF relocations which affect the contents 205968bcca2SKa Ho Ng * are applied to the returned data. The address parameter gives the 206968bcca2SKa Ho Ng * address of the data buffer if the ELF file were loaded into memory 207968bcca2SKa Ho Ng * rather than a direct file offset. 208968bcca2SKa Ho Ng */ 209968bcca2SKa Ho Ng int elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, 210968bcca2SKa Ho Ng size_t len, void **buf); 211968bcca2SKa Ho Ng 212968bcca2SKa Ho Ng /* 213968bcca2SKa Ho Ng * Read the program headers from an ELF file and return them in a 214968bcca2SKa Ho Ng * dynamically-allocated array of GElf_Phdr objects. 215968bcca2SKa Ho Ng */ 216968bcca2SKa Ho Ng int elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, 217968bcca2SKa Ho Ng GElf_Phdr **phdrp); 218968bcca2SKa Ho Ng 219968bcca2SKa Ho Ng /* 220968bcca2SKa Ho Ng * Read the section headers from an ELF file and return them in a 221968bcca2SKa Ho Ng * dynamically-allocated array of GElf_Shdr objects. 222968bcca2SKa Ho Ng */ 223968bcca2SKa Ho Ng int elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, 224968bcca2SKa Ho Ng GElf_Shdr **shdrp); 225968bcca2SKa Ho Ng 226968bcca2SKa Ho Ng /* 227968bcca2SKa Ho Ng * Read the dynamic table from a section of an ELF file into a 228968bcca2SKa Ho Ng * dynamically-allocated array of GElf_Dyn objects. 229968bcca2SKa Ho Ng */ 230968bcca2SKa Ho Ng int elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp, 231968bcca2SKa Ho Ng GElf_Dyn **dynp); 232968bcca2SKa Ho Ng 233968bcca2SKa Ho Ng /* 234968bcca2SKa Ho Ng * Read a symbol table from a section of an ELF file into a 235968bcca2SKa Ho Ng * dynamically-allocated array of GElf_Sym objects. 236968bcca2SKa Ho Ng */ 237968bcca2SKa Ho Ng int elf_read_symbols(struct elf_file *efile, int section_index, 238968bcca2SKa Ho Ng size_t *nsymp, GElf_Sym **symp); 239968bcca2SKa Ho Ng 240968bcca2SKa Ho Ng /* 241968bcca2SKa Ho Ng * Read a string table described by a section header of an ELF file 242968bcca2SKa Ho Ng * into a dynamically-allocated buffer. 243968bcca2SKa Ho Ng */ 244968bcca2SKa Ho Ng int elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr, 245968bcca2SKa Ho Ng long *strcnt, char **strtab); 246968bcca2SKa Ho Ng 247968bcca2SKa Ho Ng /* 248968bcca2SKa Ho Ng * Read a table of relocation objects from a section of an ELF file 249968bcca2SKa Ho Ng * into a dynamically-allocated array of GElf_Rel objects. 250968bcca2SKa Ho Ng */ 251968bcca2SKa Ho Ng int elf_read_rel(struct elf_file *efile, int section_index, long *nrelp, 252968bcca2SKa Ho Ng GElf_Rel **relp); 253968bcca2SKa Ho Ng 254968bcca2SKa Ho Ng /* 255968bcca2SKa Ho Ng * Read a table of relocation-with-addend objects from a section of an 256968bcca2SKa Ho Ng * ELF file into a dynamically-allocated array of GElf_Rela objects. 257968bcca2SKa Ho Ng */ 258968bcca2SKa Ho Ng int elf_read_rela(struct elf_file *efile, int section_index, long *nrelap, 259968bcca2SKa Ho Ng GElf_Rela **relap); 260968bcca2SKa Ho Ng 261968bcca2SKa Ho Ng /* 262968bcca2SKa Ho Ng * Read a string from an ELF file and return it in the provided 263968bcca2SKa Ho Ng * buffer. If the string is longer than the buffer, this fails with 264968bcca2SKa Ho Ng * EFAULT. The address parameter gives the address of the data buffer 265968bcca2SKa Ho Ng * if the ELF file were loaded into memory rather than a direct file 266968bcca2SKa Ho Ng * offset. 267968bcca2SKa Ho Ng */ 268968bcca2SKa Ho Ng int elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst, 269968bcca2SKa Ho Ng size_t len); 270968bcca2SKa Ho Ng 271968bcca2SKa Ho Ng /* Return the address extracted from a target pointer stored at 'p'. */ 272968bcca2SKa Ho Ng GElf_Addr elf_address_from_pointer(struct elf_file *efile, const void *p); 273968bcca2SKa Ho Ng 274968bcca2SKa Ho Ng /* 275968bcca2SKa Ho Ng * Read a linker set and return an array of addresses extracted from the 276968bcca2SKa Ho Ng * relocated pointers in the linker set. 277968bcca2SKa Ho Ng */ 278968bcca2SKa Ho Ng int elf_read_linker_set(struct elf_file *efile, const char *name, 279968bcca2SKa Ho Ng GElf_Addr **buf, long *countp); 280968bcca2SKa Ho Ng 281968bcca2SKa Ho Ng /* 282968bcca2SKa Ho Ng * Read and convert a target 'struct mod_depend' into a host 283968bcca2SKa Ho Ng * 'struct Gmod_depend'. 284968bcca2SKa Ho Ng */ 285968bcca2SKa Ho Ng int elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr, 286968bcca2SKa Ho Ng struct Gmod_depend *mdp); 287968bcca2SKa Ho Ng 288968bcca2SKa Ho Ng /* 289968bcca2SKa Ho Ng * Read and convert a target 'struct mod_version' into a host 290968bcca2SKa Ho Ng * 'struct Gmod_version'. 291968bcca2SKa Ho Ng */ 292968bcca2SKa Ho Ng int elf_read_mod_version(struct elf_file *efile, GElf_Addr addr, 293968bcca2SKa Ho Ng struct Gmod_version *mdv); 294968bcca2SKa Ho Ng 295968bcca2SKa Ho Ng /* 296968bcca2SKa Ho Ng * Read and convert a target 'struct mod_metadata' into a host 297968bcca2SKa Ho Ng * 'struct Gmod_metadata'. 298968bcca2SKa Ho Ng */ 299968bcca2SKa Ho Ng int elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr, 300968bcca2SKa Ho Ng struct Gmod_metadata *md); 301968bcca2SKa Ho Ng 302968bcca2SKa Ho Ng /* 303968bcca2SKa Ho Ng * Read and convert a target 'struct mod_pnp_match_info' into a host 304968bcca2SKa Ho Ng * 'struct Gmod_pnp_match_info'. 305968bcca2SKa Ho Ng */ 306968bcca2SKa Ho Ng int elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr, 307968bcca2SKa Ho Ng struct Gmod_pnp_match_info *pnp); 308968bcca2SKa Ho Ng 309968bcca2SKa Ho Ng /* 310968bcca2SKa Ho Ng * Apply relocations to the values obtained from the file. `relbase' is the 311968bcca2SKa Ho Ng * target relocation address of the section, and `dataoff/len' is the region 312968bcca2SKa Ho Ng * that is to be relocated, and has been copied to *dest 313968bcca2SKa Ho Ng */ 314968bcca2SKa Ho Ng int elf_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype, 315968bcca2SKa Ho Ng GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest); 316968bcca2SKa Ho Ng 31743628a31SKa Ho Ng /* 31843628a31SKa Ho Ng * Find the symbol with the specified symbol name 'name' within the given 31943628a31SKa Ho Ng * 'efile'. 0 is returned when such a symbol is found, otherwise ENOENT is 32043628a31SKa Ho Ng * returned. 32143628a31SKa Ho Ng */ 32243628a31SKa Ho Ng int elf_lookup_symbol(struct elf_file *efile, const char *name, 323*72e15f76SKa Ho Ng GElf_Sym **sym, bool see_local); 32443628a31SKa Ho Ng 325968bcca2SKa Ho Ng __END_DECLS 326968bcca2SKa Ho Ng 327968bcca2SKa Ho Ng #endif /* _KLDELF_H_*/ 328