xref: /freebsd/usr.sbin/kldxref/elf.c (revision 78258ee0)
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