1160383Snetchild/*-
2160383Snetchild * SPDX-License-Identifier: BSD-2-Clause
3172150Sariff *
4160383Snetchild * Copyright (c) 2021-2023 John Baldwin <jhb@FreeBSD.org>
5160383Snetchild *
6160383Snetchild * This software was developed by SRI International and the University
7160383Snetchild * of Cambridge Computer Laboratory (Department of Computer Science
8160383Snetchild * and Technology) under Defense Advanced Research Projects Agency
9160383Snetchild * (DARPA) contract HR0011-18-C-0016 ("ECATS"), as part of the DARPA
10160383Snetchild * SSITH research programme and under DARPA Contract No. HR001123C0031
11160383Snetchild * ("MTSS").
12160383Snetchild *
13160383Snetchild * Redistribution and use in source and binary forms, with or without
14160383Snetchild * modification, are permitted provided that the following conditions
15160383Snetchild * are met:
16160383Snetchild * 1. Redistributions of source code must retain the above copyright
17160383Snetchild *    notice, this list of conditions and the following disclaimer.
18160383Snetchild * 2. Redistributions in binary form must reproduce the above copyright
19160383Snetchild *    notice, this list of conditions and the following disclaimer in the
20160383Snetchild *    documentation and/or other materials provided with the distribution.
21160383Snetchild *
22160383Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23160383Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24160383Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25160383Snetchild * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26160383Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27160383Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28160383Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29160383Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30160383Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31160383Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32160383Snetchild * SUCH DAMAGE.
33160383Snetchild */
34160383Snetchild
35160383Snetchild#include <sys/param.h>
36160383Snetchild#include <sys/endian.h>
37160383Snetchild
38160383Snetchild#include <err.h>
39160383Snetchild#include <errno.h>
40160383Snetchild#include <fcntl.h>
41172150Sariff#include <gelf.h>
42160383Snetchild#include <libelf.h>
43160383Snetchild#include <stdlib.h>
44160383Snetchild#include <string.h>
45160383Snetchild#include <unistd.h>
46160383Snetchild
47160383Snetchild#include "ef.h"
48193640Sariff
49193640SariffSET_DECLARE(elf_reloc, struct elf_reloc_data);
50193640Sariff
51193640Sariffstatic elf_reloc_t *
52160383Snetchildelf_find_reloc(const GElf_Ehdr *hdr)
53160383Snetchild{
54160383Snetchild	struct elf_reloc_data **erd;
55160383Snetchild
56229981Spfg	SET_FOREACH(erd, elf_reloc) {
57160383Snetchild		if (hdr->e_ident[EI_CLASS] == (*erd)->class &&
58160383Snetchild		    hdr->e_ident[EI_DATA] == (*erd)->data &&
59160383Snetchild		    hdr->e_machine == (*erd)->machine)
60160383Snetchild			return ((*erd)->reloc);
61160383Snetchild	}
62160383Snetchild	return (NULL);
63160383Snetchild}
64160383Snetchild
65160383Snetchildint
66160383Snetchildelf_open_file(struct elf_file *efile, const char *filename, int verbose)
67160383Snetchild{
68160383Snetchild	int error;
69160383Snetchild
70160383Snetchild	memset(efile, 0, sizeof(*efile));
71160383Snetchild	efile->ef_filename = filename;
72160383Snetchild	efile->ef_fd = open(filename, O_RDONLY);
73160383Snetchild	if (efile->ef_fd == -1) {
74160383Snetchild		if (verbose)
75160383Snetchild			warn("open(%s)", filename);
76160383Snetchild		return (errno);
77160383Snetchild	}
78160383Snetchild
79160383Snetchild	efile->ef_elf = elf_begin(efile->ef_fd, ELF_C_READ, NULL);
80160383Snetchild	if (efile->ef_elf == NULL) {
81160383Snetchild		if (verbose)
82160383Snetchild			warnx("elf_begin(%s): %s", filename, elf_errmsg(0));
83160383Snetchild		elf_close_file(efile);
84160383Snetchild		return (EINVAL);
85160383Snetchild	}
86160383Snetchild
87160383Snetchild	if (elf_kind(efile->ef_elf) != ELF_K_ELF) {
88160383Snetchild		if (verbose)
89160383Snetchild			warnx("%s: not an ELF file", filename);
90160383Snetchild		elf_close_file(efile);
91160383Snetchild		return (EINVAL);
92160383Snetchild	}
93160383Snetchild
94160383Snetchild	if (gelf_getehdr(efile->ef_elf, &efile->ef_hdr) == NULL) {
95160383Snetchild		if (verbose)
96160383Snetchild			warnx("gelf_getehdr(%s): %s", filename, elf_errmsg(0));
97160383Snetchild		elf_close_file(efile);
98160383Snetchild		return (EINVAL);
99160383Snetchild	}
100160383Snetchild
101160383Snetchild	efile->ef_reloc = elf_find_reloc(&efile->ef_hdr);
102160383Snetchild	if (efile->ef_reloc == NULL) {
103160383Snetchild		if (verbose)
104160383Snetchild			warnx("%s: unsupported architecture", filename);
105160383Snetchild		elf_close_file(efile);
106160383Snetchild		return (EFTYPE);
107160383Snetchild	}
108160383Snetchild
109160383Snetchild	error = ef_open(efile, verbose);
110160383Snetchild	if (error != 0) {
111160383Snetchild		error = ef_obj_open(efile, verbose);
112172150Sariff		if (error != 0) {
113172150Sariff			if (verbose)
114172150Sariff				warnc(error, "%s: not a valid DSO or object file",
115160383Snetchild				    filename);
116160383Snetchild			elf_close_file(efile);
117160383Snetchild			return (error);
118160383Snetchild		}
119160383Snetchild	}
120160383Snetchild
121160383Snetchild	efile->ef_pointer_size = elf_object_size(efile, ELF_T_ADDR);
122160383Snetchild
123160383Snetchild	return (0);
124160383Snetchild}
125160383Snetchild
126160383Snetchildvoid
127160383Snetchildelf_close_file(struct elf_file *efile)
128160383Snetchild{
129160383Snetchild	if (efile->ef_ops != NULL) {
130160383Snetchild		EF_CLOSE(efile);
131160383Snetchild	}
132160383Snetchild	if (efile->ef_elf != NULL) {
133160383Snetchild		elf_end(efile->ef_elf);
134160383Snetchild		efile->ef_elf = NULL;
135160383Snetchild	}
136160383Snetchild	if (efile->ef_fd > 0) {
137160383Snetchild		close(efile->ef_fd);
138160383Snetchild		efile->ef_fd = -1;
139160383Snetchild	}
140160383Snetchild}
141160383Snetchild
142160383Snetchildbool
143160383Snetchildelf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr)
144160383Snetchild{
145160383Snetchild	if (efile->ef_hdr.e_ident[EI_CLASS] != hdr->e_ident[EI_CLASS] ||
146160383Snetchild	    efile->ef_hdr.e_ident[EI_DATA] != hdr->e_ident[EI_DATA] ||
147160383Snetchild	    efile->ef_hdr.e_machine != hdr->e_machine)
148160383Snetchild		return (false);
149160383Snetchild	return (true);
150160383Snetchild}
151160383Snetchild
152160383Snetchildsize_t
153160383Snetchildelf_object_size(struct elf_file *efile, Elf_Type type)
154160383Snetchild{
155160383Snetchild	return (gelf_fsize(efile->ef_elf, type, 1, efile->ef_hdr.e_version));
156160383Snetchild}
157160383Snetchild
158160383Snetchild/*
159160383Snetchild * The number of objects of 'type' in region of the file of size
160165833Snetchild * 'file_size'.
161230137Sjoel */
162160383Snetchildstatic size_t
163160383Snetchildelf_object_count(struct elf_file *efile, Elf_Type type, size_t file_size)
164160383Snetchild{
165160383Snetchild	return (file_size / elf_object_size(efile, type));
166160383Snetchild}
167160383Snetchild
168160383Snetchildint
169160383Snetchildelf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, size_t len)
170160383Snetchild{
171160383Snetchild	ssize_t nread;
172160383Snetchild
173160383Snetchild	nread = pread(efile->ef_fd, dst, len, offset);
174160383Snetchild	if (nread == -1)
175160383Snetchild		return (errno);
176160383Snetchild	if (nread != len)
177160383Snetchild		return (EIO);
178160383Snetchild	return (0);
179160383Snetchild}
180160383Snetchild
181160383Snetchildint
182160383Snetchildelf_read_raw_data_alloc(struct elf_file *efile, off_t offset, size_t len,
183160383Snetchild    void **out)
184160383Snetchild{
185229981Spfg	void *buf;
186160383Snetchild	int error;
187160383Snetchild
188160383Snetchild	buf = malloc(len);
189160383Snetchild	if (buf == NULL)
190160383Snetchild		return (ENOMEM);
191160383Snetchild	error = elf_read_raw_data(efile, offset, buf, len);
192160383Snetchild	if (error != 0) {
193160383Snetchild		free(buf);
194160383Snetchild		return (error);
195160383Snetchild	}
196160383Snetchild	*out = buf;
197160383Snetchild	return (0);
198160383Snetchild}
199160383Snetchild
200160383Snetchildint
201160383Snetchildelf_read_raw_string(struct elf_file *efile, off_t offset, char *dst, size_t len)
202160383Snetchild{
203160383Snetchild	ssize_t nread;
204160383Snetchild
205160383Snetchild	nread = pread(efile->ef_fd, dst, len, offset);
206160383Snetchild	if (nread == -1)
207160383Snetchild		return (errno);
208160383Snetchild	if (nread == 0)
209160383Snetchild		return (EIO);
210160383Snetchild
211160383Snetchild	/* A short read is ok so long as the data contains a terminator. */
212160383Snetchild	if (strnlen(dst, nread) == nread)
213160383Snetchild		return (EFAULT);
214160383Snetchild
215160383Snetchild	return (0);
216160383Snetchild}
217160383Snetchild
218160383Snetchildint
219160383Snetchildelf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len,
220160383Snetchild    void **out)
221229981Spfg{
222229981Spfg	Elf_Data dst, src;
223229981Spfg	void *buf;
224229981Spfg	int error;
225229981Spfg
226160383Snetchild	buf = malloc(len);
227229981Spfg	if (buf == NULL)
228229981Spfg		return (ENOMEM);
229229981Spfg
230229981Spfg	error = elf_read_raw_data(efile, offset, buf, len);
231229981Spfg	if (error != 0) {
232229981Spfg		free(buf);
233229981Spfg		return (error);
234229981Spfg	}
235160383Snetchild
236160383Snetchild	memset(&dst, 0, sizeof(dst));
237160383Snetchild	memset(&src, 0, sizeof(src));
238160383Snetchild
239160383Snetchild	src.d_buf = buf;
240160383Snetchild	src.d_size = len;
241160383Snetchild	src.d_type = type;
242160383Snetchild	src.d_version = efile->ef_hdr.e_version;
243160383Snetchild
244160383Snetchild	dst.d_buf = buf;
245160383Snetchild	dst.d_size = len;
246160383Snetchild	dst.d_version = EV_CURRENT;
247172150Sariff
248172150Sariff	if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
249172150Sariff	    NULL) {
250165833Snetchild		free(buf);
251160383Snetchild		return (ENXIO);
252160383Snetchild	}
253160383Snetchild
254160383Snetchild	if (dst.d_size != len)
255160383Snetchild		warnx("elf_read_data: translation of type %u size mismatch",
256161055Snetchild		    type);
257160383Snetchild
258160383Snetchild	*out = buf;
259160383Snetchild	return (0);
260160383Snetchild}
261160383Snetchild
262160383Snetchildint
263160383Snetchildelf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len,
264160383Snetchild    void **buf)
265160383Snetchild{
266172150Sariff	int error;
267172150Sariff	void *p;
268160383Snetchild
269160383Snetchild	p = malloc(len);
270160383Snetchild	if (p == NULL)
271160383Snetchild		return (ENOMEM);
272160383Snetchild	error = EF_SEG_READ_REL(efile, address, len, p);
273160383Snetchild	if (error != 0) {
274160383Snetchild		free(p);
275160383Snetchild		return (error);
276160383Snetchild	}
277160383Snetchild	*buf = p;
278160383Snetchild	return (0);
279161054Snetchild}
280160383Snetchild
281160383Snetchildint
282160383Snetchildelf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp)
283160383Snetchild{
284160383Snetchild	GElf_Phdr *phdr;
285172150Sariff	size_t nphdr, i;
286160383Snetchild	int error;
287160383Snetchild
288160383Snetchild	if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1)
289160383Snetchild		return (EFTYPE);
290160383Snetchild
291160383Snetchild	phdr = calloc(nphdr, sizeof(*phdr));
292160383Snetchild	if (phdr == NULL)
293160383Snetchild		return (ENOMEM);
294160383Snetchild
295160383Snetchild	for (i = 0; i < nphdr; i++) {
296160383Snetchild		if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) {
297160383Snetchild			error = EFTYPE;
298160383Snetchild			goto out;
299160383Snetchild		}
300160383Snetchild	}
301160383Snetchild
302160383Snetchild	*nphdrp = nphdr;
303160383Snetchild	*phdrp = phdr;
304160383Snetchild	return (0);
305160383Snetchildout:
306160383Snetchild	free(phdr);
307160383Snetchild	return (error);
308160383Snetchild}
309160383Snetchild
310160383Snetchildint
311160383Snetchildelf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp)
312165833Snetchild{
313160383Snetchild	GElf_Shdr *shdr;
314160383Snetchild	Elf_Scn *scn;
315160383Snetchild	size_t nshdr, i;
316160383Snetchild	int error;
317160383Snetchild
318160383Snetchild	if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1)
319160383Snetchild		return (EFTYPE);
320160383Snetchild
321160383Snetchild	shdr = calloc(nshdr, sizeof(*shdr));
322160383Snetchild	if (shdr == NULL)
323160383Snetchild		return (ENOMEM);
324160383Snetchild
325160383Snetchild	for (i = 0; i < nshdr; i++) {
326160383Snetchild		scn = elf_getscn(efile->ef_elf, i);
327160383Snetchild		if (scn == NULL) {
328160383Snetchild			error = EFTYPE;
329160383Snetchild			goto out;
330160383Snetchild		}
331160383Snetchild		if (gelf_getshdr(scn, &shdr[i]) == NULL) {
332160383Snetchild			error = EFTYPE;
333160383Snetchild			goto out;
334160383Snetchild		}
335160383Snetchild	}
336172150Sariff
337160383Snetchild	*nshdrp = nshdr;
338160383Snetchild	*shdrp = shdr;
339160383Snetchild	return (0);
340160383Snetchildout:
341160383Snetchild	free(shdr);
342160383Snetchild	return (error);
343160383Snetchild}
344160383Snetchild
345160383Snetchildint
346160383Snetchildelf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp,
347160383Snetchild    GElf_Dyn **dynp)
348160383Snetchild{
349160383Snetchild	GElf_Shdr shdr;
350160383Snetchild	Elf_Scn *scn;
351172150Sariff	Elf_Data *data;
352160383Snetchild	GElf_Dyn *dyn;
353160383Snetchild	long i, ndyn;
354172150Sariff
355172150Sariff	scn = elf_getscn(efile->ef_elf, section_index);
356160383Snetchild	if (scn == NULL)
357160383Snetchild		return (EINVAL);
358160383Snetchild	if (gelf_getshdr(scn, &shdr) == NULL)
359160383Snetchild		return (EINVAL);
360160383Snetchild	data = elf_getdata(scn, NULL);
361160383Snetchild	if (data == NULL)
362160383Snetchild		return (EINVAL);
363160383Snetchild
364160383Snetchild	ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size);
365160383Snetchild	dyn = calloc(ndyn, sizeof(*dyn));
366160383Snetchild	if (dyn == NULL)
367160383Snetchild		return (ENOMEM);
368160383Snetchild
369160383Snetchild	for (i = 0; i < ndyn; i++) {
370160383Snetchild		if (gelf_getdyn(data, i, &dyn[i]) == NULL) {
371160383Snetchild			free(dyn);
372160383Snetchild			return (EINVAL);
373172150Sariff		}
374172150Sariff	}
375160383Snetchild
376160383Snetchild	*ndynp = ndyn;
377160383Snetchild	*dynp = dyn;
378160383Snetchild	return (0);
379160383Snetchild}
380160383Snetchild
381160383Snetchildint
382160383Snetchildelf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp,
383160383Snetchild    GElf_Sym **symp)
384160383Snetchild{
385160383Snetchild	GElf_Shdr shdr;
386160383Snetchild	Elf_Scn *scn;
387160383Snetchild	Elf_Data *data;
388160383Snetchild	GElf_Sym *sym;
389160383Snetchild	size_t i, nsym;
390160383Snetchild
391160383Snetchild	scn = elf_getscn(efile->ef_elf, section_index);
392160383Snetchild	if (scn == NULL)
393160383Snetchild		return (EINVAL);
394160383Snetchild	if (gelf_getshdr(scn, &shdr) == NULL)
395160383Snetchild		return (EINVAL);
396160383Snetchild	data = elf_getdata(scn, NULL);
397160383Snetchild	if (data == NULL)
398160383Snetchild		return (EINVAL);
399160383Snetchild
400160383Snetchild	nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size);
401165833Snetchild	sym = calloc(nsym, sizeof(*sym));
402160383Snetchild	if (sym == NULL)
403160383Snetchild		return (ENOMEM);
404160383Snetchild
405160383Snetchild	for (i = 0; i < nsym; i++) {
406160383Snetchild		if (gelf_getsym(data, i, &sym[i]) == NULL) {
407160383Snetchild			free(sym);
408160383Snetchild			return (EINVAL);
409160383Snetchild		}
410160383Snetchild	}
411160383Snetchild
412160383Snetchild	*nsymp = nsym;
413160383Snetchild	*symp = sym;
414166919Sariff	return (0);
415160383Snetchild}
416160383Snetchild
417160383Snetchildint
418160383Snetchildelf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
419160383Snetchild    long *strcnt, char **strtab)
420160383Snetchild{
421160383Snetchild	int error;
422160383Snetchild
423160383Snetchild	if (shdr->sh_type != SHT_STRTAB)
424160383Snetchild		return (EINVAL);
425160383Snetchild	error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size,
426172150Sariff	    (void **)strtab);
427172150Sariff	if (error != 0)
428172150Sariff		return (error);
429172150Sariff	*strcnt = shdr->sh_size;
430172150Sariff	return (0);
431172150Sariff}
432172150Sariff
433172150Sariffint
434172150Sariffelf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
435172150Sariff    GElf_Rel **relp)
436172150Sariff{
437172150Sariff	GElf_Shdr shdr;
438172150Sariff	Elf_Scn *scn;
439172150Sariff	Elf_Data *data;
440172150Sariff	GElf_Rel *rel;
441172150Sariff	long i, nrel;
442172150Sariff
443172150Sariff	scn = elf_getscn(efile->ef_elf, section_index);
444172150Sariff	if (scn == NULL)
445172150Sariff		return (EINVAL);
446172150Sariff	if (gelf_getshdr(scn, &shdr) == NULL)
447172150Sariff		return (EINVAL);
448172150Sariff	data = elf_getdata(scn, NULL);
449172150Sariff	if (data == NULL)
450172150Sariff		return (EINVAL);
451172150Sariff
452172150Sariff	nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size);
453172150Sariff	rel = calloc(nrel, sizeof(*rel));
454172150Sariff	if (rel == NULL)
455160383Snetchild		return (ENOMEM);
456160383Snetchild
457160383Snetchild	for (i = 0; i < nrel; i++) {
458160383Snetchild		if (gelf_getrel(data, i, &rel[i]) == NULL) {
459160383Snetchild			free(rel);
460160383Snetchild			return (EINVAL);
461160383Snetchild		}
462160383Snetchild	}
463160383Snetchild
464160383Snetchild	*nrelp = nrel;
465160383Snetchild	*relp = rel;
466160383Snetchild	return (0);
467165833Snetchild}
468160383Snetchild
469160383Snetchildint
470160383Snetchildelf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
471160383Snetchild    GElf_Rela **relap)
472160383Snetchild{
473160383Snetchild	GElf_Shdr shdr;
474160383Snetchild	Elf_Scn *scn;
475160383Snetchild	Elf_Data *data;
476160383Snetchild	GElf_Rela *rela;
477160383Snetchild	long i, nrela;
478160383Snetchild
479160383Snetchild	scn = elf_getscn(efile->ef_elf, section_index);
480160383Snetchild	if (scn == NULL)
481160383Snetchild		return (EINVAL);
482160383Snetchild	if (gelf_getshdr(scn, &shdr) == NULL)
483160383Snetchild		return (EINVAL);
484160383Snetchild	data = elf_getdata(scn, NULL);
485160383Snetchild	if (data == NULL)
486160383Snetchild		return (EINVAL);
487160383Snetchild
488160383Snetchild	nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size);
489160383Snetchild	rela = calloc(nrela, sizeof(*rela));
490172150Sariff	if (rela == NULL)
491160383Snetchild		return (ENOMEM);
492160383Snetchild
493160383Snetchild	for (i = 0; i < nrela; i++) {
494160383Snetchild		if (gelf_getrela(data, i, &rela[i]) == NULL) {
495160383Snetchild			free(rela);
496160383Snetchild			return (EINVAL);
497160383Snetchild		}
498160383Snetchild	}
499160383Snetchild
500160383Snetchild	*nrelap = nrela;
501160383Snetchild	*relap = rela;
502160383Snetchild	return (0);
503160383Snetchild}
504160383Snetchild
505160383Snetchildsize_t
506160383Snetchildelf_pointer_size(struct elf_file *efile)
507160383Snetchild{
508160383Snetchild	return (efile->ef_pointer_size);
509160383Snetchild}
510160383Snetchild
511160383Snetchildint
512160383Snetchildelf_int(struct elf_file *efile, const void *p)
513160383Snetchild{
514160383Snetchild	if (elf_encoding(efile) == ELFDATA2LSB)
515160383Snetchild		return (le32dec(p));
516160383Snetchild	else
517165833Snetchild		return (be32dec(p));
518165833Snetchild}
519165833Snetchild
520165833SnetchildGElf_Addr
521160383Snetchildelf_address_from_pointer(struct elf_file *efile, const void *p)
522160383Snetchild{
523160383Snetchild	switch (elf_class(efile)) {
524160383Snetchild	case ELFCLASS32:
525160383Snetchild		if (elf_encoding(efile) == ELFDATA2LSB)
526160383Snetchild			return (le32dec(p));
527160383Snetchild		else
528160383Snetchild			return (be32dec(p));
529160383Snetchild	case ELFCLASS64:
530160383Snetchild		if (elf_encoding(efile) == ELFDATA2LSB)
531160383Snetchild			return (le64dec(p));
532160383Snetchild		else
533160383Snetchild			return (be64dec(p));
534160383Snetchild	default:
535160383Snetchild		__unreachable();
536160383Snetchild	}
537160383Snetchild}
538160383Snetchild
539160383Snetchildint
540160383Snetchildelf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
541160383Snetchild    size_t len)
542160383Snetchild{
543160383Snetchild	return (EF_SEG_READ_STRING(efile, address, len, dst));
544160383Snetchild}
545160383Snetchild
546160383Snetchildint
547160383Snetchildelf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp,
548160383Snetchild    long *countp)
549160383Snetchild{
550160383Snetchild	GElf_Addr *buf, start, stop;
551160383Snetchild	char *p;
552160383Snetchild	void *raw;
553160383Snetchild	long i, count;
554160383Snetchild	int error;
555160383Snetchild
556160383Snetchild	error = EF_LOOKUP_SET(efile, name, &start, &stop, &count);
557160383Snetchild	if (error != 0)
558160383Snetchild		return (error);
559165833Snetchild
560160383Snetchild	error = elf_read_relocated_data(efile, start,
561160383Snetchild	    count * elf_pointer_size(efile), &raw);
562160383Snetchild	if (error != 0)
563160383Snetchild		return (error);
564160383Snetchild
565165833Snetchild	buf = calloc(count, sizeof(*buf));
566160383Snetchild	if (buf == NULL) {
567160383Snetchild		free(raw);
568160383Snetchild		return (ENOMEM);
569160383Snetchild	}
570160383Snetchild
571160383Snetchild	p = raw;
572165833Snetchild	for (i = 0; i < count; i++) {
573165833Snetchild		buf[i] = elf_address_from_pointer(efile, p);
574160383Snetchild		p += elf_pointer_size(efile);
575160383Snetchild	}
576160383Snetchild	free(raw);
577160383Snetchild
578160383Snetchild	*bufp = buf;
579160383Snetchild	*countp = count;
580160383Snetchild	return (0);
581172150Sariff}
582172150Sariff
583172150Sariffint
584172150Sariffelf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
585160383Snetchild    struct Gmod_depend *mdp)
586160383Snetchild{
587160383Snetchild	int *p;
588160383Snetchild	int error;
589160383Snetchild
590160383Snetchild	error = elf_read_relocated_data(efile, addr, sizeof(int) * 3,
591160383Snetchild	    (void **)&p);
592160383Snetchild	if (error != 0)
593165833Snetchild		return (error);
594160383Snetchild
595160383Snetchild	memset(mdp, 0, sizeof(*mdp));
596160383Snetchild	mdp->md_ver_minimum = elf_int(efile, p);
597165833Snetchild	mdp->md_ver_preferred = elf_int(efile, p + 1);
598160383Snetchild	mdp->md_ver_maximum = elf_int(efile, p + 2);
599160383Snetchild	free(p);
600160383Snetchild	return (0);
601160383Snetchild}
602160383Snetchild
603160383Snetchildint
604160383Snetchildelf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
605160383Snetchild    struct Gmod_version *mdv)
606160383Snetchild{
607160383Snetchild	int error, value;
608160383Snetchild
609160383Snetchild	error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value);
610160383Snetchild	if (error != 0)
611160383Snetchild		return (error);
612160383Snetchild
613160383Snetchild	memset(mdv, 0, sizeof(*mdv));
614160383Snetchild	mdv->mv_version = elf_int(efile, &value);
615160383Snetchild	return (0);
616160383Snetchild}
617160383Snetchild
618160383Snetchildint
619160383Snetchildelf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
620160383Snetchild    struct Gmod_metadata *md)
621160383Snetchild{
622160383Snetchild	char *p;
623160383Snetchild	size_t len, offset, pointer_size;
624160383Snetchild	int error;
625160383Snetchild
626160383Snetchild	pointer_size = elf_pointer_size(efile);
627160383Snetchild	len = 2 * sizeof(int);
628160383Snetchild	len = roundup(len, pointer_size);
629160383Snetchild	len += 2 * pointer_size;
630160383Snetchild
631160383Snetchild	error = elf_read_relocated_data(efile, addr, len, (void **)&p);
632160383Snetchild	if (error != 0)
633160383Snetchild		return (error);
634160383Snetchild
635160383Snetchild	memset(md, 0, sizeof(*md));
636160383Snetchild	offset = 0;
637160383Snetchild	md->md_version = elf_int(efile, p + offset);
638160383Snetchild	offset += sizeof(int);
639160383Snetchild	md->md_type = elf_int(efile, p + offset);
640160383Snetchild	offset += sizeof(int);
641160383Snetchild	offset = roundup(offset, pointer_size);
642160383Snetchild	md->md_data = elf_address_from_pointer(efile, p + offset);
643160383Snetchild	offset += pointer_size;
644229981Spfg 	md->md_cval = elf_address_from_pointer(efile, p + offset);
645160383Snetchild	free(p);
646160383Snetchild	return (0);
647160383Snetchild}
648160383Snetchild
649160383Snetchildint
650160383Snetchildelf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
651160383Snetchild    struct Gmod_pnp_match_info *pnp)
652160383Snetchild{
653229981Spfg	char *p;
654172150Sariff	size_t len, offset, pointer_size;
655172150Sariff	int error;
656229981Spfg
657229981Spfg	pointer_size = elf_pointer_size(efile);
658172150Sariff	len = 3 * pointer_size;
659172150Sariff	len = roundup(len, pointer_size);
660160383Snetchild	len += 2 * sizeof(int);
661160383Snetchild
662160383Snetchild	error = elf_read_relocated_data(efile, addr, len, (void **)&p);
663160383Snetchild	if (error != 0)
664160383Snetchild		return (error);
665160383Snetchild
666160383Snetchild	memset(pnp, 0, sizeof(*pnp));
667160383Snetchild	offset = 0;
668160383Snetchild	pnp->descr = elf_address_from_pointer(efile, p + offset);
669160383Snetchild	offset += pointer_size;
670160383Snetchild	pnp->bus = elf_address_from_pointer(efile, p + offset);
671160383Snetchild	offset += pointer_size;
672160383Snetchild	pnp->table = elf_address_from_pointer(efile, p + offset);
673160383Snetchild	offset += pointer_size;
674160383Snetchild	offset = roundup(offset, pointer_size);
675160383Snetchild	pnp->entry_len = elf_int(efile, p + offset);
676160383Snetchild	offset += sizeof(int);
677160383Snetchild	pnp->num_entry = elf_int(efile, p + offset);
678160383Snetchild	free(p);
679172150Sariff	return (0);
680229981Spfg}
681172150Sariff
682172150Sariffint
683229981Spfgelf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
684160383Snetchild    GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
685160383Snetchild{
686160383Snetchild	return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len,
687160383Snetchild	    dest));
688160383Snetchild}
689160383Snetchild