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 *
elf_find_reloc(const GElf_Ehdr * hdr)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
elf_open_file(struct elf_file * efile,const char * filename,int verbose)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
elf_close_file(struct elf_file * efile)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
elf_compatible(struct elf_file * efile,const GElf_Ehdr * hdr)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
elf_object_size(struct elf_file * efile,Elf_Type type)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
elf_object_count(struct elf_file * efile,Elf_Type type,size_t file_size)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
elf_read_raw_data(struct elf_file * efile,off_t offset,void * dst,size_t len)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
elf_read_raw_data_alloc(struct elf_file * efile,off_t offset,size_t len,void ** out)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
elf_read_raw_string(struct elf_file * efile,off_t offset,char * dst,size_t len)201785600d0SJohn Baldwin elf_read_raw_string(struct elf_file *efile, off_t offset, char *dst, size_t len)
202785600d0SJohn Baldwin {
203785600d0SJohn Baldwin ssize_t nread;
204785600d0SJohn Baldwin
205785600d0SJohn Baldwin nread = pread(efile->ef_fd, dst, len, offset);
206785600d0SJohn Baldwin if (nread == -1)
207785600d0SJohn Baldwin return (errno);
208785600d0SJohn Baldwin if (nread == 0)
209785600d0SJohn Baldwin return (EIO);
210785600d0SJohn Baldwin
211785600d0SJohn Baldwin /* A short read is ok so long as the data contains a terminator. */
212785600d0SJohn Baldwin if (strnlen(dst, nread) == nread)
213785600d0SJohn Baldwin return (EFAULT);
214785600d0SJohn Baldwin
215785600d0SJohn Baldwin return (0);
216785600d0SJohn Baldwin }
217785600d0SJohn Baldwin
218785600d0SJohn Baldwin int
elf_read_data(struct elf_file * efile,Elf_Type type,off_t offset,size_t len,void ** out)2190299afdfSJohn Baldwin elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len,
2200299afdfSJohn Baldwin void **out)
2210299afdfSJohn Baldwin {
2220299afdfSJohn Baldwin Elf_Data dst, src;
2230299afdfSJohn Baldwin void *buf;
2240299afdfSJohn Baldwin int error;
2250299afdfSJohn Baldwin
2260299afdfSJohn Baldwin buf = malloc(len);
2270299afdfSJohn Baldwin if (buf == NULL)
2280299afdfSJohn Baldwin return (ENOMEM);
2290299afdfSJohn Baldwin
2300299afdfSJohn Baldwin error = elf_read_raw_data(efile, offset, buf, len);
2310299afdfSJohn Baldwin if (error != 0) {
2320299afdfSJohn Baldwin free(buf);
2330299afdfSJohn Baldwin return (error);
2340299afdfSJohn Baldwin }
2350299afdfSJohn Baldwin
2360299afdfSJohn Baldwin memset(&dst, 0, sizeof(dst));
2370299afdfSJohn Baldwin memset(&src, 0, sizeof(src));
2380299afdfSJohn Baldwin
2390299afdfSJohn Baldwin src.d_buf = buf;
2400299afdfSJohn Baldwin src.d_size = len;
2410299afdfSJohn Baldwin src.d_type = type;
2420299afdfSJohn Baldwin src.d_version = efile->ef_hdr.e_version;
2430299afdfSJohn Baldwin
2440299afdfSJohn Baldwin dst.d_buf = buf;
2450299afdfSJohn Baldwin dst.d_size = len;
2460299afdfSJohn Baldwin dst.d_version = EV_CURRENT;
2470299afdfSJohn Baldwin
2480299afdfSJohn Baldwin if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
2490299afdfSJohn Baldwin NULL) {
2500299afdfSJohn Baldwin free(buf);
2510299afdfSJohn Baldwin return (ENXIO);
2520299afdfSJohn Baldwin }
2530299afdfSJohn Baldwin
2540299afdfSJohn Baldwin if (dst.d_size != len)
2550299afdfSJohn Baldwin warnx("elf_read_data: translation of type %u size mismatch",
2560299afdfSJohn Baldwin type);
2570299afdfSJohn Baldwin
2580299afdfSJohn Baldwin *out = buf;
2590299afdfSJohn Baldwin return (0);
2600299afdfSJohn Baldwin }
2610299afdfSJohn Baldwin
2620299afdfSJohn Baldwin int
elf_read_relocated_data(struct elf_file * efile,GElf_Addr address,size_t len,void ** buf)2630299afdfSJohn Baldwin elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len,
2640299afdfSJohn Baldwin void **buf)
2650299afdfSJohn Baldwin {
2660299afdfSJohn Baldwin int error;
2670299afdfSJohn Baldwin void *p;
2680299afdfSJohn Baldwin
2690299afdfSJohn Baldwin p = malloc(len);
2700299afdfSJohn Baldwin if (p == NULL)
2710299afdfSJohn Baldwin return (ENOMEM);
2720299afdfSJohn Baldwin error = EF_SEG_READ_REL(efile, address, len, p);
2730299afdfSJohn Baldwin if (error != 0) {
2740299afdfSJohn Baldwin free(p);
2750299afdfSJohn Baldwin return (error);
2760299afdfSJohn Baldwin }
2770299afdfSJohn Baldwin *buf = p;
2780299afdfSJohn Baldwin return (0);
2790299afdfSJohn Baldwin }
2800299afdfSJohn Baldwin
2810299afdfSJohn Baldwin int
elf_read_phdrs(struct elf_file * efile,size_t * nphdrp,GElf_Phdr ** phdrp)2820299afdfSJohn Baldwin elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp)
2830299afdfSJohn Baldwin {
2840299afdfSJohn Baldwin GElf_Phdr *phdr;
2850299afdfSJohn Baldwin size_t nphdr, i;
2860299afdfSJohn Baldwin int error;
2870299afdfSJohn Baldwin
2880299afdfSJohn Baldwin if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1)
2890299afdfSJohn Baldwin return (EFTYPE);
2900299afdfSJohn Baldwin
2910299afdfSJohn Baldwin phdr = calloc(nphdr, sizeof(*phdr));
2920299afdfSJohn Baldwin if (phdr == NULL)
2930299afdfSJohn Baldwin return (ENOMEM);
2940299afdfSJohn Baldwin
2950299afdfSJohn Baldwin for (i = 0; i < nphdr; i++) {
2960299afdfSJohn Baldwin if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) {
2970299afdfSJohn Baldwin error = EFTYPE;
2980299afdfSJohn Baldwin goto out;
2990299afdfSJohn Baldwin }
3000299afdfSJohn Baldwin }
3010299afdfSJohn Baldwin
3020299afdfSJohn Baldwin *nphdrp = nphdr;
3030299afdfSJohn Baldwin *phdrp = phdr;
3040299afdfSJohn Baldwin return (0);
3050299afdfSJohn Baldwin out:
3060299afdfSJohn Baldwin free(phdr);
3070299afdfSJohn Baldwin return (error);
3080299afdfSJohn Baldwin }
3090299afdfSJohn Baldwin
3100299afdfSJohn Baldwin int
elf_read_shdrs(struct elf_file * efile,size_t * nshdrp,GElf_Shdr ** shdrp)3110299afdfSJohn Baldwin elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp)
3120299afdfSJohn Baldwin {
3130299afdfSJohn Baldwin GElf_Shdr *shdr;
3140299afdfSJohn Baldwin Elf_Scn *scn;
3150299afdfSJohn Baldwin size_t nshdr, i;
3160299afdfSJohn Baldwin int error;
3170299afdfSJohn Baldwin
3180299afdfSJohn Baldwin if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1)
3190299afdfSJohn Baldwin return (EFTYPE);
3200299afdfSJohn Baldwin
3210299afdfSJohn Baldwin shdr = calloc(nshdr, sizeof(*shdr));
3220299afdfSJohn Baldwin if (shdr == NULL)
3230299afdfSJohn Baldwin return (ENOMEM);
3240299afdfSJohn Baldwin
3250299afdfSJohn Baldwin for (i = 0; i < nshdr; i++) {
3260299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, i);
3270299afdfSJohn Baldwin if (scn == NULL) {
3280299afdfSJohn Baldwin error = EFTYPE;
3290299afdfSJohn Baldwin goto out;
3300299afdfSJohn Baldwin }
3310299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr[i]) == NULL) {
3320299afdfSJohn Baldwin error = EFTYPE;
3330299afdfSJohn Baldwin goto out;
3340299afdfSJohn Baldwin }
3350299afdfSJohn Baldwin }
3360299afdfSJohn Baldwin
3370299afdfSJohn Baldwin *nshdrp = nshdr;
3380299afdfSJohn Baldwin *shdrp = shdr;
3390299afdfSJohn Baldwin return (0);
3400299afdfSJohn Baldwin out:
3410299afdfSJohn Baldwin free(shdr);
3420299afdfSJohn Baldwin return (error);
3430299afdfSJohn Baldwin }
3440299afdfSJohn Baldwin
3450299afdfSJohn Baldwin int
elf_read_dynamic(struct elf_file * efile,int section_index,size_t * ndynp,GElf_Dyn ** dynp)34697530894SBaptiste Daroussin elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp,
3470299afdfSJohn Baldwin GElf_Dyn **dynp)
3480299afdfSJohn Baldwin {
3490299afdfSJohn Baldwin GElf_Shdr shdr;
3500299afdfSJohn Baldwin Elf_Scn *scn;
3510299afdfSJohn Baldwin Elf_Data *data;
3520299afdfSJohn Baldwin GElf_Dyn *dyn;
3530299afdfSJohn Baldwin long i, ndyn;
3540299afdfSJohn Baldwin
3550299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index);
3560299afdfSJohn Baldwin if (scn == NULL)
3570299afdfSJohn Baldwin return (EINVAL);
3580299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL)
3590299afdfSJohn Baldwin return (EINVAL);
3600299afdfSJohn Baldwin data = elf_getdata(scn, NULL);
3610299afdfSJohn Baldwin if (data == NULL)
3620299afdfSJohn Baldwin return (EINVAL);
3630299afdfSJohn Baldwin
3640299afdfSJohn Baldwin ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size);
3650299afdfSJohn Baldwin dyn = calloc(ndyn, sizeof(*dyn));
3660299afdfSJohn Baldwin if (dyn == NULL)
3670299afdfSJohn Baldwin return (ENOMEM);
3680299afdfSJohn Baldwin
3690299afdfSJohn Baldwin for (i = 0; i < ndyn; i++) {
3700299afdfSJohn Baldwin if (gelf_getdyn(data, i, &dyn[i]) == NULL) {
3710299afdfSJohn Baldwin free(dyn);
3720299afdfSJohn Baldwin return (EINVAL);
3730299afdfSJohn Baldwin }
3740299afdfSJohn Baldwin }
3750299afdfSJohn Baldwin
3760299afdfSJohn Baldwin *ndynp = ndyn;
3770299afdfSJohn Baldwin *dynp = dyn;
3780299afdfSJohn Baldwin return (0);
3790299afdfSJohn Baldwin }
3800299afdfSJohn Baldwin
3810299afdfSJohn Baldwin int
elf_read_symbols(struct elf_file * efile,int section_index,size_t * nsymp,GElf_Sym ** symp)38297530894SBaptiste Daroussin elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp,
3830299afdfSJohn Baldwin GElf_Sym **symp)
3840299afdfSJohn Baldwin {
3850299afdfSJohn Baldwin GElf_Shdr shdr;
3860299afdfSJohn Baldwin Elf_Scn *scn;
3870299afdfSJohn Baldwin Elf_Data *data;
3880299afdfSJohn Baldwin GElf_Sym *sym;
38997530894SBaptiste Daroussin size_t i, nsym;
3900299afdfSJohn Baldwin
3910299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index);
3920299afdfSJohn Baldwin if (scn == NULL)
3930299afdfSJohn Baldwin return (EINVAL);
3940299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL)
3950299afdfSJohn Baldwin return (EINVAL);
3960299afdfSJohn Baldwin data = elf_getdata(scn, NULL);
3970299afdfSJohn Baldwin if (data == NULL)
3980299afdfSJohn Baldwin return (EINVAL);
3990299afdfSJohn Baldwin
4000299afdfSJohn Baldwin nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size);
4010299afdfSJohn Baldwin sym = calloc(nsym, sizeof(*sym));
4020299afdfSJohn Baldwin if (sym == NULL)
4030299afdfSJohn Baldwin return (ENOMEM);
4040299afdfSJohn Baldwin
4050299afdfSJohn Baldwin for (i = 0; i < nsym; i++) {
4060299afdfSJohn Baldwin if (gelf_getsym(data, i, &sym[i]) == NULL) {
4070299afdfSJohn Baldwin free(sym);
4080299afdfSJohn Baldwin return (EINVAL);
4090299afdfSJohn Baldwin }
4100299afdfSJohn Baldwin }
4110299afdfSJohn Baldwin
4120299afdfSJohn Baldwin *nsymp = nsym;
4130299afdfSJohn Baldwin *symp = sym;
4140299afdfSJohn Baldwin return (0);
4150299afdfSJohn Baldwin }
4160299afdfSJohn Baldwin
4170299afdfSJohn Baldwin int
elf_read_string_table(struct elf_file * efile,const GElf_Shdr * shdr,long * strcnt,char ** strtab)4180299afdfSJohn Baldwin elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
4190299afdfSJohn Baldwin long *strcnt, char **strtab)
4200299afdfSJohn Baldwin {
4210299afdfSJohn Baldwin int error;
4220299afdfSJohn Baldwin
4230299afdfSJohn Baldwin if (shdr->sh_type != SHT_STRTAB)
4240299afdfSJohn Baldwin return (EINVAL);
4250299afdfSJohn Baldwin error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size,
4260299afdfSJohn Baldwin (void **)strtab);
4270299afdfSJohn Baldwin if (error != 0)
4280299afdfSJohn Baldwin return (error);
4290299afdfSJohn Baldwin *strcnt = shdr->sh_size;
4300299afdfSJohn Baldwin return (0);
4310299afdfSJohn Baldwin }
4320299afdfSJohn Baldwin
4330299afdfSJohn Baldwin int
elf_read_rel(struct elf_file * efile,int section_index,long * nrelp,GElf_Rel ** relp)4340299afdfSJohn Baldwin elf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
4350299afdfSJohn Baldwin GElf_Rel **relp)
4360299afdfSJohn Baldwin {
4370299afdfSJohn Baldwin GElf_Shdr shdr;
4380299afdfSJohn Baldwin Elf_Scn *scn;
4390299afdfSJohn Baldwin Elf_Data *data;
4400299afdfSJohn Baldwin GElf_Rel *rel;
4410299afdfSJohn Baldwin long i, nrel;
4420299afdfSJohn Baldwin
4430299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index);
4440299afdfSJohn Baldwin if (scn == NULL)
4450299afdfSJohn Baldwin return (EINVAL);
4460299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL)
4470299afdfSJohn Baldwin return (EINVAL);
4480299afdfSJohn Baldwin data = elf_getdata(scn, NULL);
4490299afdfSJohn Baldwin if (data == NULL)
4500299afdfSJohn Baldwin return (EINVAL);
4510299afdfSJohn Baldwin
4520299afdfSJohn Baldwin nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size);
4530299afdfSJohn Baldwin rel = calloc(nrel, sizeof(*rel));
4540299afdfSJohn Baldwin if (rel == NULL)
4550299afdfSJohn Baldwin return (ENOMEM);
4560299afdfSJohn Baldwin
4570299afdfSJohn Baldwin for (i = 0; i < nrel; i++) {
4580299afdfSJohn Baldwin if (gelf_getrel(data, i, &rel[i]) == NULL) {
4590299afdfSJohn Baldwin free(rel);
4600299afdfSJohn Baldwin return (EINVAL);
4610299afdfSJohn Baldwin }
4620299afdfSJohn Baldwin }
4630299afdfSJohn Baldwin
4640299afdfSJohn Baldwin *nrelp = nrel;
4650299afdfSJohn Baldwin *relp = rel;
4660299afdfSJohn Baldwin return (0);
4670299afdfSJohn Baldwin }
4680299afdfSJohn Baldwin
4690299afdfSJohn Baldwin int
elf_read_rela(struct elf_file * efile,int section_index,long * nrelap,GElf_Rela ** relap)4700299afdfSJohn Baldwin elf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
4710299afdfSJohn Baldwin GElf_Rela **relap)
4720299afdfSJohn Baldwin {
4730299afdfSJohn Baldwin GElf_Shdr shdr;
4740299afdfSJohn Baldwin Elf_Scn *scn;
4750299afdfSJohn Baldwin Elf_Data *data;
4760299afdfSJohn Baldwin GElf_Rela *rela;
4770299afdfSJohn Baldwin long i, nrela;
4780299afdfSJohn Baldwin
4790299afdfSJohn Baldwin scn = elf_getscn(efile->ef_elf, section_index);
4800299afdfSJohn Baldwin if (scn == NULL)
4810299afdfSJohn Baldwin return (EINVAL);
4820299afdfSJohn Baldwin if (gelf_getshdr(scn, &shdr) == NULL)
4830299afdfSJohn Baldwin return (EINVAL);
4840299afdfSJohn Baldwin data = elf_getdata(scn, NULL);
4850299afdfSJohn Baldwin if (data == NULL)
4860299afdfSJohn Baldwin return (EINVAL);
4870299afdfSJohn Baldwin
4880299afdfSJohn Baldwin nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size);
4890299afdfSJohn Baldwin rela = calloc(nrela, sizeof(*rela));
4900299afdfSJohn Baldwin if (rela == NULL)
4910299afdfSJohn Baldwin return (ENOMEM);
4920299afdfSJohn Baldwin
4930299afdfSJohn Baldwin for (i = 0; i < nrela; i++) {
4940299afdfSJohn Baldwin if (gelf_getrela(data, i, &rela[i]) == NULL) {
4950299afdfSJohn Baldwin free(rela);
4960299afdfSJohn Baldwin return (EINVAL);
4970299afdfSJohn Baldwin }
4980299afdfSJohn Baldwin }
4990299afdfSJohn Baldwin
5000299afdfSJohn Baldwin *nrelap = nrela;
5010299afdfSJohn Baldwin *relap = rela;
5020299afdfSJohn Baldwin return (0);
5030299afdfSJohn Baldwin }
5040299afdfSJohn Baldwin
5050299afdfSJohn Baldwin size_t
elf_pointer_size(struct elf_file * efile)5060299afdfSJohn Baldwin elf_pointer_size(struct elf_file *efile)
5070299afdfSJohn Baldwin {
5080299afdfSJohn Baldwin return (efile->ef_pointer_size);
5090299afdfSJohn Baldwin }
5100299afdfSJohn Baldwin
5110299afdfSJohn Baldwin int
elf_int(struct elf_file * efile,const void * p)5120299afdfSJohn Baldwin elf_int(struct elf_file *efile, const void *p)
5130299afdfSJohn Baldwin {
5140299afdfSJohn Baldwin if (elf_encoding(efile) == ELFDATA2LSB)
5150299afdfSJohn Baldwin return (le32dec(p));
5160299afdfSJohn Baldwin else
5170299afdfSJohn Baldwin return (be32dec(p));
5180299afdfSJohn Baldwin }
5190299afdfSJohn Baldwin
5200299afdfSJohn Baldwin GElf_Addr
elf_address_from_pointer(struct elf_file * efile,const void * p)5210299afdfSJohn Baldwin elf_address_from_pointer(struct elf_file *efile, const void *p)
5220299afdfSJohn Baldwin {
5230299afdfSJohn Baldwin switch (elf_class(efile)) {
5240299afdfSJohn Baldwin case ELFCLASS32:
5250299afdfSJohn Baldwin if (elf_encoding(efile) == ELFDATA2LSB)
5260299afdfSJohn Baldwin return (le32dec(p));
5270299afdfSJohn Baldwin else
5280299afdfSJohn Baldwin return (be32dec(p));
5290299afdfSJohn Baldwin case ELFCLASS64:
5300299afdfSJohn Baldwin if (elf_encoding(efile) == ELFDATA2LSB)
5310299afdfSJohn Baldwin return (le64dec(p));
5320299afdfSJohn Baldwin else
5330299afdfSJohn Baldwin return (be64dec(p));
5340299afdfSJohn Baldwin default:
53552a19a90SCollin Funk __unreachable();
5360299afdfSJohn Baldwin }
5370299afdfSJohn Baldwin }
5380299afdfSJohn Baldwin
5390299afdfSJohn Baldwin int
elf_read_string(struct elf_file * efile,GElf_Addr address,void * dst,size_t len)5400299afdfSJohn Baldwin elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
5410299afdfSJohn Baldwin size_t len)
5420299afdfSJohn Baldwin {
5430299afdfSJohn Baldwin return (EF_SEG_READ_STRING(efile, address, len, dst));
5440299afdfSJohn Baldwin }
5450299afdfSJohn Baldwin
5460299afdfSJohn Baldwin int
elf_read_linker_set(struct elf_file * efile,const char * name,GElf_Addr ** bufp,long * countp)5470299afdfSJohn Baldwin elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp,
5480299afdfSJohn Baldwin long *countp)
5490299afdfSJohn Baldwin {
5500299afdfSJohn Baldwin GElf_Addr *buf, start, stop;
5510299afdfSJohn Baldwin char *p;
5520299afdfSJohn Baldwin void *raw;
5530299afdfSJohn Baldwin long i, count;
5540299afdfSJohn Baldwin int error;
5550299afdfSJohn Baldwin
5560299afdfSJohn Baldwin error = EF_LOOKUP_SET(efile, name, &start, &stop, &count);
5570299afdfSJohn Baldwin if (error != 0)
5580299afdfSJohn Baldwin return (error);
5590299afdfSJohn Baldwin
5600299afdfSJohn Baldwin error = elf_read_relocated_data(efile, start,
5610299afdfSJohn Baldwin count * elf_pointer_size(efile), &raw);
5620299afdfSJohn Baldwin if (error != 0)
5630299afdfSJohn Baldwin return (error);
5640299afdfSJohn Baldwin
5650299afdfSJohn Baldwin buf = calloc(count, sizeof(*buf));
5660299afdfSJohn Baldwin if (buf == NULL) {
5670299afdfSJohn Baldwin free(raw);
5680299afdfSJohn Baldwin return (ENOMEM);
5690299afdfSJohn Baldwin }
5700299afdfSJohn Baldwin
5710299afdfSJohn Baldwin p = raw;
5720299afdfSJohn Baldwin for (i = 0; i < count; i++) {
5730299afdfSJohn Baldwin buf[i] = elf_address_from_pointer(efile, p);
5740299afdfSJohn Baldwin p += elf_pointer_size(efile);
5750299afdfSJohn Baldwin }
5760299afdfSJohn Baldwin free(raw);
5770299afdfSJohn Baldwin
5780299afdfSJohn Baldwin *bufp = buf;
5790299afdfSJohn Baldwin *countp = count;
5800299afdfSJohn Baldwin return (0);
5810299afdfSJohn Baldwin }
5820299afdfSJohn Baldwin
5830299afdfSJohn Baldwin int
elf_read_mod_depend(struct elf_file * efile,GElf_Addr addr,struct Gmod_depend * mdp)5840299afdfSJohn Baldwin elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
5850299afdfSJohn Baldwin struct Gmod_depend *mdp)
5860299afdfSJohn Baldwin {
5870299afdfSJohn Baldwin int *p;
5880299afdfSJohn Baldwin int error;
5890299afdfSJohn Baldwin
5900299afdfSJohn Baldwin error = elf_read_relocated_data(efile, addr, sizeof(int) * 3,
5910299afdfSJohn Baldwin (void **)&p);
5920299afdfSJohn Baldwin if (error != 0)
5930299afdfSJohn Baldwin return (error);
5940299afdfSJohn Baldwin
5950299afdfSJohn Baldwin memset(mdp, 0, sizeof(*mdp));
5960299afdfSJohn Baldwin mdp->md_ver_minimum = elf_int(efile, p);
5970299afdfSJohn Baldwin mdp->md_ver_preferred = elf_int(efile, p + 1);
5980299afdfSJohn Baldwin mdp->md_ver_maximum = elf_int(efile, p + 2);
5990299afdfSJohn Baldwin free(p);
6000299afdfSJohn Baldwin return (0);
6010299afdfSJohn Baldwin }
6020299afdfSJohn Baldwin
6030299afdfSJohn Baldwin int
elf_read_mod_version(struct elf_file * efile,GElf_Addr addr,struct Gmod_version * mdv)6040299afdfSJohn Baldwin elf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
6050299afdfSJohn Baldwin struct Gmod_version *mdv)
6060299afdfSJohn Baldwin {
6070299afdfSJohn Baldwin int error, value;
6080299afdfSJohn Baldwin
6090299afdfSJohn Baldwin error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value);
6100299afdfSJohn Baldwin if (error != 0)
6110299afdfSJohn Baldwin return (error);
6120299afdfSJohn Baldwin
6130299afdfSJohn Baldwin memset(mdv, 0, sizeof(*mdv));
6140299afdfSJohn Baldwin mdv->mv_version = elf_int(efile, &value);
6150299afdfSJohn Baldwin return (0);
6160299afdfSJohn Baldwin }
6170299afdfSJohn Baldwin
6180299afdfSJohn Baldwin int
elf_read_mod_metadata(struct elf_file * efile,GElf_Addr addr,struct Gmod_metadata * md)6190299afdfSJohn Baldwin elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
6200299afdfSJohn Baldwin struct Gmod_metadata *md)
6210299afdfSJohn Baldwin {
6220299afdfSJohn Baldwin char *p;
6230299afdfSJohn Baldwin size_t len, offset, pointer_size;
6240299afdfSJohn Baldwin int error;
6250299afdfSJohn Baldwin
6260299afdfSJohn Baldwin pointer_size = elf_pointer_size(efile);
6270299afdfSJohn Baldwin len = 2 * sizeof(int);
6280299afdfSJohn Baldwin len = roundup(len, pointer_size);
6290299afdfSJohn Baldwin len += 2 * pointer_size;
6300299afdfSJohn Baldwin
6310299afdfSJohn Baldwin error = elf_read_relocated_data(efile, addr, len, (void **)&p);
6320299afdfSJohn Baldwin if (error != 0)
6330299afdfSJohn Baldwin return (error);
6340299afdfSJohn Baldwin
6350299afdfSJohn Baldwin memset(md, 0, sizeof(*md));
6360299afdfSJohn Baldwin offset = 0;
6370299afdfSJohn Baldwin md->md_version = elf_int(efile, p + offset);
6380299afdfSJohn Baldwin offset += sizeof(int);
6390299afdfSJohn Baldwin md->md_type = elf_int(efile, p + offset);
6400299afdfSJohn Baldwin offset += sizeof(int);
6410299afdfSJohn Baldwin offset = roundup(offset, pointer_size);
6420299afdfSJohn Baldwin md->md_data = elf_address_from_pointer(efile, p + offset);
6430299afdfSJohn Baldwin offset += pointer_size;
6440299afdfSJohn Baldwin md->md_cval = elf_address_from_pointer(efile, p + offset);
6450299afdfSJohn Baldwin free(p);
6460299afdfSJohn Baldwin return (0);
6470299afdfSJohn Baldwin }
6480299afdfSJohn Baldwin
6490299afdfSJohn Baldwin int
elf_read_mod_pnp_match_info(struct elf_file * efile,GElf_Addr addr,struct Gmod_pnp_match_info * pnp)6500299afdfSJohn Baldwin elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
6510299afdfSJohn Baldwin struct Gmod_pnp_match_info *pnp)
6520299afdfSJohn Baldwin {
6530299afdfSJohn Baldwin char *p;
6540299afdfSJohn Baldwin size_t len, offset, pointer_size;
6550299afdfSJohn Baldwin int error;
6560299afdfSJohn Baldwin
6570299afdfSJohn Baldwin pointer_size = elf_pointer_size(efile);
6580299afdfSJohn Baldwin len = 3 * pointer_size;
6590299afdfSJohn Baldwin len = roundup(len, pointer_size);
6600299afdfSJohn Baldwin len += 2 * sizeof(int);
6610299afdfSJohn Baldwin
6620299afdfSJohn Baldwin error = elf_read_relocated_data(efile, addr, len, (void **)&p);
6630299afdfSJohn Baldwin if (error != 0)
6640299afdfSJohn Baldwin return (error);
6650299afdfSJohn Baldwin
6660299afdfSJohn Baldwin memset(pnp, 0, sizeof(*pnp));
6670299afdfSJohn Baldwin offset = 0;
6680299afdfSJohn Baldwin pnp->descr = elf_address_from_pointer(efile, p + offset);
6690299afdfSJohn Baldwin offset += pointer_size;
6700299afdfSJohn Baldwin pnp->bus = elf_address_from_pointer(efile, p + offset);
6710299afdfSJohn Baldwin offset += pointer_size;
6720299afdfSJohn Baldwin pnp->table = elf_address_from_pointer(efile, p + offset);
6730299afdfSJohn Baldwin offset += pointer_size;
6740299afdfSJohn Baldwin offset = roundup(offset, pointer_size);
6750299afdfSJohn Baldwin pnp->entry_len = elf_int(efile, p + offset);
6760299afdfSJohn Baldwin offset += sizeof(int);
6770299afdfSJohn Baldwin pnp->num_entry = elf_int(efile, p + offset);
6780299afdfSJohn Baldwin free(p);
6790299afdfSJohn Baldwin return (0);
6800299afdfSJohn Baldwin }
6810299afdfSJohn Baldwin
6820299afdfSJohn Baldwin int
elf_reloc(struct elf_file * efile,const void * reldata,Elf_Type reltype,GElf_Addr relbase,GElf_Addr dataoff,size_t len,void * dest)6830299afdfSJohn Baldwin elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
6840299afdfSJohn Baldwin GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
6850299afdfSJohn Baldwin {
6860299afdfSJohn Baldwin return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len,
6870299afdfSJohn Baldwin dest));
6880299afdfSJohn Baldwin }
689