10299afdfSJohn Baldwin /*- 20299afdfSJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 30299afdfSJohn Baldwin * 40299afdfSJohn Baldwin * Copyright (c) 2021-2023 John Baldwin <jhb@FreeBSD.org> 50299afdfSJohn Baldwin * 60299afdfSJohn Baldwin * This software was developed by SRI International and the University 70299afdfSJohn Baldwin * of Cambridge Computer Laboratory (Department of Computer Science 80299afdfSJohn Baldwin * and Technology) under Defense Advanced Research Projects Agency 90299afdfSJohn Baldwin * (DARPA) contract HR0011-18-C-0016 ("ECATS"), as part of the DARPA 1078258ee0SJohn Baldwin * SSITH research programme and under DARPA Contract No. HR001123C0031 110299afdfSJohn Baldwin * ("MTSS"). 120299afdfSJohn Baldwin * 130299afdfSJohn Baldwin * Redistribution and use in source and binary forms, with or without 140299afdfSJohn Baldwin * modification, are permitted provided that the following conditions 150299afdfSJohn Baldwin * are met: 160299afdfSJohn Baldwin * 1. Redistributions of source code must retain the above copyright 170299afdfSJohn Baldwin * notice, this list of conditions and the following disclaimer. 180299afdfSJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 190299afdfSJohn Baldwin * notice, this list of conditions and the following disclaimer in the 200299afdfSJohn Baldwin * documentation and/or other materials provided with the distribution. 210299afdfSJohn Baldwin * 220299afdfSJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 230299afdfSJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 240299afdfSJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 250299afdfSJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 260299afdfSJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 270299afdfSJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 280299afdfSJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 290299afdfSJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 300299afdfSJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 310299afdfSJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 320299afdfSJohn Baldwin * SUCH DAMAGE. 330299afdfSJohn Baldwin */ 340299afdfSJohn Baldwin 350299afdfSJohn Baldwin #include <sys/param.h> 360299afdfSJohn Baldwin #include <sys/endian.h> 370299afdfSJohn Baldwin 380299afdfSJohn Baldwin #include <err.h> 390299afdfSJohn Baldwin #include <errno.h> 400299afdfSJohn Baldwin #include <fcntl.h> 410299afdfSJohn Baldwin #include <gelf.h> 420299afdfSJohn Baldwin #include <libelf.h> 430299afdfSJohn Baldwin #include <stdlib.h> 440299afdfSJohn Baldwin #include <string.h> 450299afdfSJohn Baldwin #include <unistd.h> 460299afdfSJohn Baldwin 470299afdfSJohn Baldwin #include "ef.h" 480299afdfSJohn Baldwin 490299afdfSJohn Baldwin SET_DECLARE(elf_reloc, struct elf_reloc_data); 500299afdfSJohn Baldwin 510299afdfSJohn Baldwin static elf_reloc_t * 520299afdfSJohn Baldwin elf_find_reloc(const GElf_Ehdr *hdr) 530299afdfSJohn Baldwin { 540299afdfSJohn Baldwin struct elf_reloc_data **erd; 550299afdfSJohn Baldwin 560299afdfSJohn Baldwin SET_FOREACH(erd, elf_reloc) { 570299afdfSJohn Baldwin if (hdr->e_ident[EI_CLASS] == (*erd)->class && 580299afdfSJohn Baldwin hdr->e_ident[EI_DATA] == (*erd)->data && 590299afdfSJohn Baldwin hdr->e_machine == (*erd)->machine) 600299afdfSJohn Baldwin return ((*erd)->reloc); 610299afdfSJohn Baldwin } 620299afdfSJohn Baldwin return (NULL); 630299afdfSJohn Baldwin } 640299afdfSJohn Baldwin 650299afdfSJohn Baldwin int 660299afdfSJohn Baldwin elf_open_file(struct elf_file *efile, const char *filename, int verbose) 670299afdfSJohn Baldwin { 680299afdfSJohn Baldwin int error; 690299afdfSJohn Baldwin 700299afdfSJohn Baldwin memset(efile, 0, sizeof(*efile)); 710299afdfSJohn Baldwin efile->ef_filename = filename; 720299afdfSJohn Baldwin efile->ef_fd = open(filename, O_RDONLY); 730299afdfSJohn Baldwin if (efile->ef_fd == -1) { 740299afdfSJohn Baldwin if (verbose) 750299afdfSJohn Baldwin warn("open(%s)", filename); 760299afdfSJohn Baldwin return (errno); 770299afdfSJohn Baldwin } 780299afdfSJohn Baldwin 790299afdfSJohn Baldwin efile->ef_elf = elf_begin(efile->ef_fd, ELF_C_READ, NULL); 800299afdfSJohn Baldwin if (efile->ef_elf == NULL) { 810299afdfSJohn Baldwin if (verbose) 820299afdfSJohn Baldwin warnx("elf_begin(%s): %s", filename, elf_errmsg(0)); 830299afdfSJohn Baldwin elf_close_file(efile); 840299afdfSJohn Baldwin return (EINVAL); 850299afdfSJohn Baldwin } 860299afdfSJohn Baldwin 870299afdfSJohn Baldwin if (elf_kind(efile->ef_elf) != ELF_K_ELF) { 880299afdfSJohn Baldwin if (verbose) 890299afdfSJohn Baldwin warnx("%s: not an ELF file", filename); 900299afdfSJohn Baldwin elf_close_file(efile); 910299afdfSJohn Baldwin return (EINVAL); 920299afdfSJohn Baldwin } 930299afdfSJohn Baldwin 940299afdfSJohn Baldwin if (gelf_getehdr(efile->ef_elf, &efile->ef_hdr) == NULL) { 950299afdfSJohn Baldwin if (verbose) 960299afdfSJohn Baldwin warnx("gelf_getehdr(%s): %s", filename, elf_errmsg(0)); 970299afdfSJohn Baldwin elf_close_file(efile); 980299afdfSJohn Baldwin return (EINVAL); 990299afdfSJohn Baldwin } 1000299afdfSJohn Baldwin 1010299afdfSJohn Baldwin efile->ef_reloc = elf_find_reloc(&efile->ef_hdr); 1020299afdfSJohn Baldwin if (efile->ef_reloc == NULL) { 1030299afdfSJohn Baldwin if (verbose) 1040299afdfSJohn Baldwin warnx("%s: unsupported architecture", filename); 1050299afdfSJohn Baldwin elf_close_file(efile); 1060299afdfSJohn Baldwin return (EFTYPE); 1070299afdfSJohn Baldwin } 1080299afdfSJohn Baldwin 1090299afdfSJohn Baldwin error = ef_open(efile, verbose); 1100299afdfSJohn Baldwin if (error != 0) { 1110299afdfSJohn Baldwin error = ef_obj_open(efile, verbose); 1120299afdfSJohn Baldwin if (error != 0) { 1130299afdfSJohn Baldwin if (verbose) 1140299afdfSJohn Baldwin warnc(error, "%s: not a valid DSO or object file", 1150299afdfSJohn Baldwin filename); 1160299afdfSJohn Baldwin elf_close_file(efile); 1170299afdfSJohn Baldwin return (error); 1180299afdfSJohn Baldwin } 1190299afdfSJohn Baldwin } 1200299afdfSJohn Baldwin 1210299afdfSJohn Baldwin efile->ef_pointer_size = elf_object_size(efile, ELF_T_ADDR); 1220299afdfSJohn Baldwin 1230299afdfSJohn Baldwin return (0); 1240299afdfSJohn Baldwin } 1250299afdfSJohn Baldwin 1260299afdfSJohn Baldwin void 1270299afdfSJohn Baldwin elf_close_file(struct elf_file *efile) 1280299afdfSJohn Baldwin { 1290299afdfSJohn Baldwin if (efile->ef_ops != NULL) { 1300299afdfSJohn Baldwin EF_CLOSE(efile); 1310299afdfSJohn Baldwin } 1320299afdfSJohn Baldwin if (efile->ef_elf != NULL) { 1330299afdfSJohn Baldwin elf_end(efile->ef_elf); 1340299afdfSJohn Baldwin efile->ef_elf = NULL; 1350299afdfSJohn Baldwin } 1360299afdfSJohn Baldwin if (efile->ef_fd > 0) { 1370299afdfSJohn Baldwin close(efile->ef_fd); 1380299afdfSJohn Baldwin efile->ef_fd = -1; 1390299afdfSJohn Baldwin } 1400299afdfSJohn Baldwin } 1410299afdfSJohn Baldwin 1420299afdfSJohn Baldwin bool 1430299afdfSJohn Baldwin elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr) 1440299afdfSJohn Baldwin { 1450299afdfSJohn Baldwin if (efile->ef_hdr.e_ident[EI_CLASS] != hdr->e_ident[EI_CLASS] || 1460299afdfSJohn Baldwin efile->ef_hdr.e_ident[EI_DATA] != hdr->e_ident[EI_DATA] || 1470299afdfSJohn Baldwin efile->ef_hdr.e_machine != hdr->e_machine) 1480299afdfSJohn Baldwin return (false); 1490299afdfSJohn Baldwin return (true); 1500299afdfSJohn Baldwin } 1510299afdfSJohn Baldwin 1520299afdfSJohn Baldwin size_t 1530299afdfSJohn Baldwin elf_object_size(struct elf_file *efile, Elf_Type type) 1540299afdfSJohn Baldwin { 1550299afdfSJohn Baldwin return (gelf_fsize(efile->ef_elf, type, 1, efile->ef_hdr.e_version)); 1560299afdfSJohn Baldwin } 1570299afdfSJohn Baldwin 1580299afdfSJohn Baldwin /* 1590299afdfSJohn Baldwin * The number of objects of 'type' in region of the file of size 1600299afdfSJohn Baldwin * 'file_size'. 1610299afdfSJohn Baldwin */ 1620299afdfSJohn Baldwin static size_t 1630299afdfSJohn Baldwin elf_object_count(struct elf_file *efile, Elf_Type type, size_t file_size) 1640299afdfSJohn Baldwin { 1650299afdfSJohn Baldwin return (file_size / elf_object_size(efile, type)); 1660299afdfSJohn Baldwin } 1670299afdfSJohn Baldwin 1680299afdfSJohn Baldwin int 1690299afdfSJohn Baldwin elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, size_t len) 1700299afdfSJohn Baldwin { 1710299afdfSJohn Baldwin ssize_t nread; 1720299afdfSJohn Baldwin 173ed96fd7fSJohn Baldwin nread = pread(efile->ef_fd, dst, len, offset); 1740299afdfSJohn Baldwin if (nread == -1) 1750299afdfSJohn Baldwin return (errno); 1760299afdfSJohn Baldwin if (nread != len) 1770299afdfSJohn Baldwin return (EIO); 1780299afdfSJohn Baldwin return (0); 1790299afdfSJohn Baldwin } 1800299afdfSJohn Baldwin 1810299afdfSJohn Baldwin int 1820299afdfSJohn Baldwin elf_read_raw_data_alloc(struct elf_file *efile, off_t offset, size_t len, 1830299afdfSJohn Baldwin void **out) 1840299afdfSJohn Baldwin { 1850299afdfSJohn Baldwin void *buf; 1860299afdfSJohn Baldwin int error; 1870299afdfSJohn Baldwin 1880299afdfSJohn Baldwin buf = malloc(len); 1890299afdfSJohn Baldwin if (buf == NULL) 1900299afdfSJohn Baldwin return (ENOMEM); 1910299afdfSJohn Baldwin error = elf_read_raw_data(efile, offset, buf, len); 1920299afdfSJohn Baldwin if (error != 0) { 1930299afdfSJohn Baldwin free(buf); 1940299afdfSJohn Baldwin return (error); 1950299afdfSJohn Baldwin } 1960299afdfSJohn Baldwin *out = buf; 1970299afdfSJohn Baldwin return (0); 1980299afdfSJohn Baldwin } 1990299afdfSJohn Baldwin 2000299afdfSJohn Baldwin int 2010299afdfSJohn Baldwin elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len, 2020299afdfSJohn Baldwin void **out) 2030299afdfSJohn Baldwin { 2040299afdfSJohn Baldwin Elf_Data dst, src; 2050299afdfSJohn Baldwin void *buf; 2060299afdfSJohn Baldwin int error; 2070299afdfSJohn Baldwin 2080299afdfSJohn Baldwin buf = malloc(len); 2090299afdfSJohn Baldwin if (buf == NULL) 2100299afdfSJohn Baldwin return (ENOMEM); 2110299afdfSJohn Baldwin 2120299afdfSJohn Baldwin error = elf_read_raw_data(efile, offset, buf, len); 2130299afdfSJohn Baldwin if (error != 0) { 2140299afdfSJohn Baldwin free(buf); 2150299afdfSJohn Baldwin return (error); 2160299afdfSJohn Baldwin } 2170299afdfSJohn Baldwin 2180299afdfSJohn Baldwin memset(&dst, 0, sizeof(dst)); 2190299afdfSJohn Baldwin memset(&src, 0, sizeof(src)); 2200299afdfSJohn Baldwin 2210299afdfSJohn Baldwin src.d_buf = buf; 2220299afdfSJohn Baldwin src.d_size = len; 2230299afdfSJohn Baldwin src.d_type = type; 2240299afdfSJohn Baldwin src.d_version = efile->ef_hdr.e_version; 2250299afdfSJohn Baldwin 2260299afdfSJohn Baldwin dst.d_buf = buf; 2270299afdfSJohn Baldwin dst.d_size = len; 2280299afdfSJohn Baldwin dst.d_version = EV_CURRENT; 2290299afdfSJohn Baldwin 2300299afdfSJohn Baldwin if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) == 2310299afdfSJohn Baldwin NULL) { 2320299afdfSJohn Baldwin free(buf); 2330299afdfSJohn Baldwin return (ENXIO); 2340299afdfSJohn Baldwin } 2350299afdfSJohn Baldwin 2360299afdfSJohn Baldwin if (dst.d_size != len) 2370299afdfSJohn Baldwin warnx("elf_read_data: translation of type %u size mismatch", 2380299afdfSJohn Baldwin type); 2390299afdfSJohn Baldwin 2400299afdfSJohn Baldwin *out = buf; 2410299afdfSJohn Baldwin return (0); 2420299afdfSJohn Baldwin } 2430299afdfSJohn Baldwin 2440299afdfSJohn Baldwin int 2450299afdfSJohn Baldwin elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len, 2460299afdfSJohn Baldwin void **buf) 2470299afdfSJohn Baldwin { 2480299afdfSJohn Baldwin int error; 2490299afdfSJohn Baldwin void *p; 2500299afdfSJohn Baldwin 2510299afdfSJohn Baldwin p = malloc(len); 2520299afdfSJohn Baldwin if (p == NULL) 2530299afdfSJohn Baldwin return (ENOMEM); 2540299afdfSJohn Baldwin error = EF_SEG_READ_REL(efile, address, len, p); 2550299afdfSJohn Baldwin if (error != 0) { 2560299afdfSJohn Baldwin free(p); 2570299afdfSJohn Baldwin return (error); 2580299afdfSJohn Baldwin } 2590299afdfSJohn Baldwin *buf = p; 2600299afdfSJohn Baldwin return (0); 2610299afdfSJohn Baldwin } 2620299afdfSJohn Baldwin 2630299afdfSJohn Baldwin int 2640299afdfSJohn Baldwin elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp) 2650299afdfSJohn Baldwin { 2660299afdfSJohn Baldwin GElf_Phdr *phdr; 2670299afdfSJohn Baldwin size_t nphdr, i; 2680299afdfSJohn Baldwin int error; 2690299afdfSJohn Baldwin 2700299afdfSJohn Baldwin if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1) 2710299afdfSJohn Baldwin return (EFTYPE); 2720299afdfSJohn Baldwin 2730299afdfSJohn Baldwin phdr = calloc(nphdr, sizeof(*phdr)); 2740299afdfSJohn Baldwin if (phdr == NULL) 2750299afdfSJohn Baldwin return (ENOMEM); 2760299afdfSJohn Baldwin 2770299afdfSJohn Baldwin for (i = 0; i < nphdr; i++) { 2780299afdfSJohn Baldwin if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) { 2790299afdfSJohn Baldwin error = EFTYPE; 2800299afdfSJohn Baldwin goto out; 2810299afdfSJohn Baldwin } 2820299afdfSJohn Baldwin } 2830299afdfSJohn Baldwin 2840299afdfSJohn Baldwin *nphdrp = nphdr; 2850299afdfSJohn Baldwin *phdrp = phdr; 2860299afdfSJohn Baldwin return (0); 2870299afdfSJohn Baldwin out: 2880299afdfSJohn Baldwin free(phdr); 2890299afdfSJohn Baldwin return (error); 2900299afdfSJohn Baldwin } 2910299afdfSJohn Baldwin 2920299afdfSJohn Baldwin int 2930299afdfSJohn Baldwin elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp) 2940299afdfSJohn Baldwin { 2950299afdfSJohn Baldwin GElf_Shdr *shdr; 2960299afdfSJohn Baldwin Elf_Scn *scn; 2970299afdfSJohn Baldwin size_t nshdr, i; 2980299afdfSJohn Baldwin int error; 2990299afdfSJohn Baldwin 3000299afdfSJohn Baldwin if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1) 3010299afdfSJohn Baldwin return (EFTYPE); 3020299afdfSJohn Baldwin 3030299afdfSJohn Baldwin shdr = calloc(nshdr, sizeof(*shdr)); 3040299afdfSJohn Baldwin if (shdr == NULL) 3050299afdfSJohn Baldwin return (ENOMEM); 3060299afdfSJohn Baldwin 3070299afdfSJohn Baldwin for (i = 0; i < nshdr; i++) { 3080299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, i); 3090299afdfSJohn Baldwin if (scn == NULL) { 3100299afdfSJohn Baldwin error = EFTYPE; 3110299afdfSJohn Baldwin goto out; 3120299afdfSJohn Baldwin } 3130299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr[i]) == NULL) { 3140299afdfSJohn Baldwin error = EFTYPE; 3150299afdfSJohn Baldwin goto out; 3160299afdfSJohn Baldwin } 3170299afdfSJohn Baldwin } 3180299afdfSJohn Baldwin 3190299afdfSJohn Baldwin *nshdrp = nshdr; 3200299afdfSJohn Baldwin *shdrp = shdr; 3210299afdfSJohn Baldwin return (0); 3220299afdfSJohn Baldwin out: 3230299afdfSJohn Baldwin free(shdr); 3240299afdfSJohn Baldwin return (error); 3250299afdfSJohn Baldwin } 3260299afdfSJohn Baldwin 3270299afdfSJohn Baldwin int 32897530894SBaptiste Daroussin elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp, 3290299afdfSJohn Baldwin GElf_Dyn **dynp) 3300299afdfSJohn Baldwin { 3310299afdfSJohn Baldwin GElf_Shdr shdr; 3320299afdfSJohn Baldwin Elf_Scn *scn; 3330299afdfSJohn Baldwin Elf_Data *data; 3340299afdfSJohn Baldwin GElf_Dyn *dyn; 3350299afdfSJohn Baldwin long i, ndyn; 3360299afdfSJohn Baldwin 3370299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index); 3380299afdfSJohn Baldwin if (scn == NULL) 3390299afdfSJohn Baldwin return (EINVAL); 3400299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL) 3410299afdfSJohn Baldwin return (EINVAL); 3420299afdfSJohn Baldwin data = elf_getdata(scn, NULL); 3430299afdfSJohn Baldwin if (data == NULL) 3440299afdfSJohn Baldwin return (EINVAL); 3450299afdfSJohn Baldwin 3460299afdfSJohn Baldwin ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size); 3470299afdfSJohn Baldwin dyn = calloc(ndyn, sizeof(*dyn)); 3480299afdfSJohn Baldwin if (dyn == NULL) 3490299afdfSJohn Baldwin return (ENOMEM); 3500299afdfSJohn Baldwin 3510299afdfSJohn Baldwin for (i = 0; i < ndyn; i++) { 3520299afdfSJohn Baldwin if (gelf_getdyn(data, i, &dyn[i]) == NULL) { 3530299afdfSJohn Baldwin free(dyn); 3540299afdfSJohn Baldwin return (EINVAL); 3550299afdfSJohn Baldwin } 3560299afdfSJohn Baldwin } 3570299afdfSJohn Baldwin 3580299afdfSJohn Baldwin *ndynp = ndyn; 3590299afdfSJohn Baldwin *dynp = dyn; 3600299afdfSJohn Baldwin return (0); 3610299afdfSJohn Baldwin } 3620299afdfSJohn Baldwin 3630299afdfSJohn Baldwin int 36497530894SBaptiste Daroussin elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp, 3650299afdfSJohn Baldwin GElf_Sym **symp) 3660299afdfSJohn Baldwin { 3670299afdfSJohn Baldwin GElf_Shdr shdr; 3680299afdfSJohn Baldwin Elf_Scn *scn; 3690299afdfSJohn Baldwin Elf_Data *data; 3700299afdfSJohn Baldwin GElf_Sym *sym; 37197530894SBaptiste Daroussin size_t i, nsym; 3720299afdfSJohn Baldwin 3730299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index); 3740299afdfSJohn Baldwin if (scn == NULL) 3750299afdfSJohn Baldwin return (EINVAL); 3760299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL) 3770299afdfSJohn Baldwin return (EINVAL); 3780299afdfSJohn Baldwin data = elf_getdata(scn, NULL); 3790299afdfSJohn Baldwin if (data == NULL) 3800299afdfSJohn Baldwin return (EINVAL); 3810299afdfSJohn Baldwin 3820299afdfSJohn Baldwin nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size); 3830299afdfSJohn Baldwin sym = calloc(nsym, sizeof(*sym)); 3840299afdfSJohn Baldwin if (sym == NULL) 3850299afdfSJohn Baldwin return (ENOMEM); 3860299afdfSJohn Baldwin 3870299afdfSJohn Baldwin for (i = 0; i < nsym; i++) { 3880299afdfSJohn Baldwin if (gelf_getsym(data, i, &sym[i]) == NULL) { 3890299afdfSJohn Baldwin free(sym); 3900299afdfSJohn Baldwin return (EINVAL); 3910299afdfSJohn Baldwin } 3920299afdfSJohn Baldwin } 3930299afdfSJohn Baldwin 3940299afdfSJohn Baldwin *nsymp = nsym; 3950299afdfSJohn Baldwin *symp = sym; 3960299afdfSJohn Baldwin return (0); 3970299afdfSJohn Baldwin } 3980299afdfSJohn Baldwin 3990299afdfSJohn Baldwin int 4000299afdfSJohn Baldwin elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr, 4010299afdfSJohn Baldwin long *strcnt, char **strtab) 4020299afdfSJohn Baldwin { 4030299afdfSJohn Baldwin int error; 4040299afdfSJohn Baldwin 4050299afdfSJohn Baldwin if (shdr->sh_type != SHT_STRTAB) 4060299afdfSJohn Baldwin return (EINVAL); 4070299afdfSJohn Baldwin error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size, 4080299afdfSJohn Baldwin (void **)strtab); 4090299afdfSJohn Baldwin if (error != 0) 4100299afdfSJohn Baldwin return (error); 4110299afdfSJohn Baldwin *strcnt = shdr->sh_size; 4120299afdfSJohn Baldwin return (0); 4130299afdfSJohn Baldwin } 4140299afdfSJohn Baldwin 4150299afdfSJohn Baldwin int 4160299afdfSJohn Baldwin elf_read_rel(struct elf_file *efile, int section_index, long *nrelp, 4170299afdfSJohn Baldwin GElf_Rel **relp) 4180299afdfSJohn Baldwin { 4190299afdfSJohn Baldwin GElf_Shdr shdr; 4200299afdfSJohn Baldwin Elf_Scn *scn; 4210299afdfSJohn Baldwin Elf_Data *data; 4220299afdfSJohn Baldwin GElf_Rel *rel; 4230299afdfSJohn Baldwin long i, nrel; 4240299afdfSJohn Baldwin 4250299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index); 4260299afdfSJohn Baldwin if (scn == NULL) 4270299afdfSJohn Baldwin return (EINVAL); 4280299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL) 4290299afdfSJohn Baldwin return (EINVAL); 4300299afdfSJohn Baldwin data = elf_getdata(scn, NULL); 4310299afdfSJohn Baldwin if (data == NULL) 4320299afdfSJohn Baldwin return (EINVAL); 4330299afdfSJohn Baldwin 4340299afdfSJohn Baldwin nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size); 4350299afdfSJohn Baldwin rel = calloc(nrel, sizeof(*rel)); 4360299afdfSJohn Baldwin if (rel == NULL) 4370299afdfSJohn Baldwin return (ENOMEM); 4380299afdfSJohn Baldwin 4390299afdfSJohn Baldwin for (i = 0; i < nrel; i++) { 4400299afdfSJohn Baldwin if (gelf_getrel(data, i, &rel[i]) == NULL) { 4410299afdfSJohn Baldwin free(rel); 4420299afdfSJohn Baldwin return (EINVAL); 4430299afdfSJohn Baldwin } 4440299afdfSJohn Baldwin } 4450299afdfSJohn Baldwin 4460299afdfSJohn Baldwin *nrelp = nrel; 4470299afdfSJohn Baldwin *relp = rel; 4480299afdfSJohn Baldwin return (0); 4490299afdfSJohn Baldwin } 4500299afdfSJohn Baldwin 4510299afdfSJohn Baldwin int 4520299afdfSJohn Baldwin elf_read_rela(struct elf_file *efile, int section_index, long *nrelap, 4530299afdfSJohn Baldwin GElf_Rela **relap) 4540299afdfSJohn Baldwin { 4550299afdfSJohn Baldwin GElf_Shdr shdr; 4560299afdfSJohn Baldwin Elf_Scn *scn; 4570299afdfSJohn Baldwin Elf_Data *data; 4580299afdfSJohn Baldwin GElf_Rela *rela; 4590299afdfSJohn Baldwin long i, nrela; 4600299afdfSJohn Baldwin 4610299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index); 4620299afdfSJohn Baldwin if (scn == NULL) 4630299afdfSJohn Baldwin return (EINVAL); 4640299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL) 4650299afdfSJohn Baldwin return (EINVAL); 4660299afdfSJohn Baldwin data = elf_getdata(scn, NULL); 4670299afdfSJohn Baldwin if (data == NULL) 4680299afdfSJohn Baldwin return (EINVAL); 4690299afdfSJohn Baldwin 4700299afdfSJohn Baldwin nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size); 4710299afdfSJohn Baldwin rela = calloc(nrela, sizeof(*rela)); 4720299afdfSJohn Baldwin if (rela == NULL) 4730299afdfSJohn Baldwin return (ENOMEM); 4740299afdfSJohn Baldwin 4750299afdfSJohn Baldwin for (i = 0; i < nrela; i++) { 4760299afdfSJohn Baldwin if (gelf_getrela(data, i, &rela[i]) == NULL) { 4770299afdfSJohn Baldwin free(rela); 4780299afdfSJohn Baldwin return (EINVAL); 4790299afdfSJohn Baldwin } 4800299afdfSJohn Baldwin } 4810299afdfSJohn Baldwin 4820299afdfSJohn Baldwin *nrelap = nrela; 4830299afdfSJohn Baldwin *relap = rela; 4840299afdfSJohn Baldwin return (0); 4850299afdfSJohn Baldwin } 4860299afdfSJohn Baldwin 4870299afdfSJohn Baldwin size_t 4880299afdfSJohn Baldwin elf_pointer_size(struct elf_file *efile) 4890299afdfSJohn Baldwin { 4900299afdfSJohn Baldwin return (efile->ef_pointer_size); 4910299afdfSJohn Baldwin } 4920299afdfSJohn Baldwin 4930299afdfSJohn Baldwin int 4940299afdfSJohn Baldwin elf_int(struct elf_file *efile, const void *p) 4950299afdfSJohn Baldwin { 4960299afdfSJohn Baldwin if (elf_encoding(efile) == ELFDATA2LSB) 4970299afdfSJohn Baldwin return (le32dec(p)); 4980299afdfSJohn Baldwin else 4990299afdfSJohn Baldwin return (be32dec(p)); 5000299afdfSJohn Baldwin } 5010299afdfSJohn Baldwin 5020299afdfSJohn Baldwin GElf_Addr 5030299afdfSJohn Baldwin elf_address_from_pointer(struct elf_file *efile, const void *p) 5040299afdfSJohn Baldwin { 5050299afdfSJohn Baldwin switch (elf_class(efile)) { 5060299afdfSJohn Baldwin case ELFCLASS32: 5070299afdfSJohn Baldwin if (elf_encoding(efile) == ELFDATA2LSB) 5080299afdfSJohn Baldwin return (le32dec(p)); 5090299afdfSJohn Baldwin else 5100299afdfSJohn Baldwin return (be32dec(p)); 5110299afdfSJohn Baldwin case ELFCLASS64: 5120299afdfSJohn Baldwin if (elf_encoding(efile) == ELFDATA2LSB) 5130299afdfSJohn Baldwin return (le64dec(p)); 5140299afdfSJohn Baldwin else 5150299afdfSJohn Baldwin return (be64dec(p)); 5160299afdfSJohn Baldwin default: 5170299afdfSJohn Baldwin __builtin_unreachable(); 5180299afdfSJohn Baldwin } 5190299afdfSJohn Baldwin } 5200299afdfSJohn Baldwin 5210299afdfSJohn Baldwin int 5220299afdfSJohn Baldwin elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst, 5230299afdfSJohn Baldwin size_t len) 5240299afdfSJohn Baldwin { 5250299afdfSJohn Baldwin return (EF_SEG_READ_STRING(efile, address, len, dst)); 5260299afdfSJohn Baldwin } 5270299afdfSJohn Baldwin 5280299afdfSJohn Baldwin int 5290299afdfSJohn Baldwin elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp, 5300299afdfSJohn Baldwin long *countp) 5310299afdfSJohn Baldwin { 5320299afdfSJohn Baldwin GElf_Addr *buf, start, stop; 5330299afdfSJohn Baldwin char *p; 5340299afdfSJohn Baldwin void *raw; 5350299afdfSJohn Baldwin long i, count; 5360299afdfSJohn Baldwin int error; 5370299afdfSJohn Baldwin 5380299afdfSJohn Baldwin error = EF_LOOKUP_SET(efile, name, &start, &stop, &count); 5390299afdfSJohn Baldwin if (error != 0) 5400299afdfSJohn Baldwin return (error); 5410299afdfSJohn Baldwin 5420299afdfSJohn Baldwin error = elf_read_relocated_data(efile, start, 5430299afdfSJohn Baldwin count * elf_pointer_size(efile), &raw); 5440299afdfSJohn Baldwin if (error != 0) 5450299afdfSJohn Baldwin return (error); 5460299afdfSJohn Baldwin 5470299afdfSJohn Baldwin buf = calloc(count, sizeof(*buf)); 5480299afdfSJohn Baldwin if (buf == NULL) { 5490299afdfSJohn Baldwin free(raw); 5500299afdfSJohn Baldwin return (ENOMEM); 5510299afdfSJohn Baldwin } 5520299afdfSJohn Baldwin 5530299afdfSJohn Baldwin p = raw; 5540299afdfSJohn Baldwin for (i = 0; i < count; i++) { 5550299afdfSJohn Baldwin buf[i] = elf_address_from_pointer(efile, p); 5560299afdfSJohn Baldwin p += elf_pointer_size(efile); 5570299afdfSJohn Baldwin } 5580299afdfSJohn Baldwin free(raw); 5590299afdfSJohn Baldwin 5600299afdfSJohn Baldwin *bufp = buf; 5610299afdfSJohn Baldwin *countp = count; 5620299afdfSJohn Baldwin return (0); 5630299afdfSJohn Baldwin } 5640299afdfSJohn Baldwin 5650299afdfSJohn Baldwin int 5660299afdfSJohn Baldwin elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr, 5670299afdfSJohn Baldwin struct Gmod_depend *mdp) 5680299afdfSJohn Baldwin { 5690299afdfSJohn Baldwin int *p; 5700299afdfSJohn Baldwin int error; 5710299afdfSJohn Baldwin 5720299afdfSJohn Baldwin error = elf_read_relocated_data(efile, addr, sizeof(int) * 3, 5730299afdfSJohn Baldwin (void **)&p); 5740299afdfSJohn Baldwin if (error != 0) 5750299afdfSJohn Baldwin return (error); 5760299afdfSJohn Baldwin 5770299afdfSJohn Baldwin memset(mdp, 0, sizeof(*mdp)); 5780299afdfSJohn Baldwin mdp->md_ver_minimum = elf_int(efile, p); 5790299afdfSJohn Baldwin mdp->md_ver_preferred = elf_int(efile, p + 1); 5800299afdfSJohn Baldwin mdp->md_ver_maximum = elf_int(efile, p + 2); 5810299afdfSJohn Baldwin free(p); 5820299afdfSJohn Baldwin return (0); 5830299afdfSJohn Baldwin } 5840299afdfSJohn Baldwin 5850299afdfSJohn Baldwin int 5860299afdfSJohn Baldwin elf_read_mod_version(struct elf_file *efile, GElf_Addr addr, 5870299afdfSJohn Baldwin struct Gmod_version *mdv) 5880299afdfSJohn Baldwin { 5890299afdfSJohn Baldwin int error, value; 5900299afdfSJohn Baldwin 5910299afdfSJohn Baldwin error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value); 5920299afdfSJohn Baldwin if (error != 0) 5930299afdfSJohn Baldwin return (error); 5940299afdfSJohn Baldwin 5950299afdfSJohn Baldwin memset(mdv, 0, sizeof(*mdv)); 5960299afdfSJohn Baldwin mdv->mv_version = elf_int(efile, &value); 5970299afdfSJohn Baldwin return (0); 5980299afdfSJohn Baldwin } 5990299afdfSJohn Baldwin 6000299afdfSJohn Baldwin int 6010299afdfSJohn Baldwin elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr, 6020299afdfSJohn Baldwin struct Gmod_metadata *md) 6030299afdfSJohn Baldwin { 6040299afdfSJohn Baldwin char *p; 6050299afdfSJohn Baldwin size_t len, offset, pointer_size; 6060299afdfSJohn Baldwin int error; 6070299afdfSJohn Baldwin 6080299afdfSJohn Baldwin pointer_size = elf_pointer_size(efile); 6090299afdfSJohn Baldwin len = 2 * sizeof(int); 6100299afdfSJohn Baldwin len = roundup(len, pointer_size); 6110299afdfSJohn Baldwin len += 2 * pointer_size; 6120299afdfSJohn Baldwin 6130299afdfSJohn Baldwin error = elf_read_relocated_data(efile, addr, len, (void **)&p); 6140299afdfSJohn Baldwin if (error != 0) 6150299afdfSJohn Baldwin return (error); 6160299afdfSJohn Baldwin 6170299afdfSJohn Baldwin memset(md, 0, sizeof(*md)); 6180299afdfSJohn Baldwin offset = 0; 6190299afdfSJohn Baldwin md->md_version = elf_int(efile, p + offset); 6200299afdfSJohn Baldwin offset += sizeof(int); 6210299afdfSJohn Baldwin md->md_type = elf_int(efile, p + offset); 6220299afdfSJohn Baldwin offset += sizeof(int); 6230299afdfSJohn Baldwin offset = roundup(offset, pointer_size); 6240299afdfSJohn Baldwin md->md_data = elf_address_from_pointer(efile, p + offset); 6250299afdfSJohn Baldwin offset += pointer_size; 6260299afdfSJohn Baldwin md->md_cval = elf_address_from_pointer(efile, p + offset); 6270299afdfSJohn Baldwin free(p); 6280299afdfSJohn Baldwin return (0); 6290299afdfSJohn Baldwin } 6300299afdfSJohn Baldwin 6310299afdfSJohn Baldwin int 6320299afdfSJohn Baldwin elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr, 6330299afdfSJohn Baldwin struct Gmod_pnp_match_info *pnp) 6340299afdfSJohn Baldwin { 6350299afdfSJohn Baldwin char *p; 6360299afdfSJohn Baldwin size_t len, offset, pointer_size; 6370299afdfSJohn Baldwin int error; 6380299afdfSJohn Baldwin 6390299afdfSJohn Baldwin pointer_size = elf_pointer_size(efile); 6400299afdfSJohn Baldwin len = 3 * pointer_size; 6410299afdfSJohn Baldwin len = roundup(len, pointer_size); 6420299afdfSJohn Baldwin len += 2 * sizeof(int); 6430299afdfSJohn Baldwin 6440299afdfSJohn Baldwin error = elf_read_relocated_data(efile, addr, len, (void **)&p); 6450299afdfSJohn Baldwin if (error != 0) 6460299afdfSJohn Baldwin return (error); 6470299afdfSJohn Baldwin 6480299afdfSJohn Baldwin memset(pnp, 0, sizeof(*pnp)); 6490299afdfSJohn Baldwin offset = 0; 6500299afdfSJohn Baldwin pnp->descr = elf_address_from_pointer(efile, p + offset); 6510299afdfSJohn Baldwin offset += pointer_size; 6520299afdfSJohn Baldwin pnp->bus = elf_address_from_pointer(efile, p + offset); 6530299afdfSJohn Baldwin offset += pointer_size; 6540299afdfSJohn Baldwin pnp->table = elf_address_from_pointer(efile, p + offset); 6550299afdfSJohn Baldwin offset += pointer_size; 6560299afdfSJohn Baldwin offset = roundup(offset, pointer_size); 6570299afdfSJohn Baldwin pnp->entry_len = elf_int(efile, p + offset); 6580299afdfSJohn Baldwin offset += sizeof(int); 6590299afdfSJohn Baldwin pnp->num_entry = elf_int(efile, p + offset); 6600299afdfSJohn Baldwin free(p); 6610299afdfSJohn Baldwin return (0); 6620299afdfSJohn Baldwin } 6630299afdfSJohn Baldwin 6640299afdfSJohn Baldwin int 6650299afdfSJohn Baldwin elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype, 6660299afdfSJohn Baldwin GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest) 6670299afdfSJohn Baldwin { 6680299afdfSJohn Baldwin return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len, 6690299afdfSJohn Baldwin dest)); 6700299afdfSJohn Baldwin } 671