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