183322Speter/*
283322Speter * Copyright (c) 2000, Boris Popov
383322Speter * All rights reserved.
483322Speter *
583322Speter * Redistribution and use in source and binary forms, with or without
683322Speter * modification, are permitted provided that the following conditions
783322Speter * are met:
883322Speter * 1. Redistributions of source code must retain the above copyright
983322Speter *    notice, this list of conditions and the following disclaimer.
1083322Speter * 2. Redistributions in binary form must reproduce the above copyright
1183322Speter *    notice, this list of conditions and the following disclaimer in the
1283322Speter *    documentation and/or other materials provided with the distribution.
1383322Speter * 3. All advertising materials mentioning features or use of this software
1483322Speter *    must display the following acknowledgement:
1583322Speter *    This product includes software developed by Boris Popov.
1683322Speter * 4. Neither the name of the author nor the names of any co-contributors
1783322Speter *    may be used to endorse or promote products derived from this software
1883322Speter *    without specific prior written permission.
1983322Speter *
2083322Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2183322Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2283322Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2383322Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2483322Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2583322Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2683322Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2783322Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2883322Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2983322Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3083322Speter * SUCH DAMAGE.
3183322Speter *
3283322Speter * $FreeBSD$
3383322Speter */
3483322Speter
3583322Speter#include <sys/param.h>
3683322Speter#include <sys/linker.h>
3783322Speter#include <string.h>
38100272Speter#include <stdio.h>
39100272Speter#include <stdlib.h>
40100272Speter#include <unistd.h>
41100272Speter#include <errno.h>
42100272Speter#include <fcntl.h>
4383322Speter#include <machine/elf.h>
4483322Speter#define FREEBSD_ELF
4583322Speter
4683322Speter#include <err.h>
4783322Speter
4883322Speter#include "ef.h"
4983322Speter
50269014Semaste#define	MAXSEGS 2
51134358Siedowsestruct ef_file {
52134358Siedowse	char*		ef_name;
53134358Siedowse	struct elf_file *ef_efile;
54134358Siedowse	Elf_Phdr *	ef_ph;
55134358Siedowse	int		ef_fd;
56134358Siedowse	int		ef_type;
57134358Siedowse	Elf_Ehdr	ef_hdr;
58134358Siedowse	void*		ef_fpage;		/* First block of the file */
59134358Siedowse	int		ef_fplen;		/* length of first block */
60134358Siedowse	Elf_Dyn*	ef_dyn;			/* Symbol table etc. */
61134358Siedowse	Elf_Hashelt	ef_nbuckets;
62134358Siedowse	Elf_Hashelt	ef_nchains;
63134358Siedowse	Elf_Hashelt*	ef_buckets;
64134358Siedowse	Elf_Hashelt*	ef_chains;
65134358Siedowse	Elf_Hashelt*	ef_hashtab;
66134358Siedowse	Elf_Off		ef_stroff;
67134358Siedowse	caddr_t		ef_strtab;
68134358Siedowse	int		ef_strsz;
69134358Siedowse	Elf_Off		ef_symoff;
70134358Siedowse	Elf_Sym*	ef_symtab;
71134358Siedowse	int		ef_nsegs;
72269014Semaste	Elf_Phdr *	ef_segs[MAXSEGS];
73134358Siedowse	int		ef_verbose;
74134358Siedowse	Elf_Rel *	ef_rel;			/* relocation table */
75134358Siedowse	int		ef_relsz;		/* number of entries */
76134358Siedowse	Elf_Rela *	ef_rela;		/* relocation table */
77134358Siedowse	int		ef_relasz;		/* number of entries */
78134358Siedowse};
79134358Siedowse
8087551Smikehstatic void ef_print_phdr(Elf_Phdr *);
8187551Smikehstatic u_long ef_get_offset(elf_file_t, Elf_Off);
8287551Smikehstatic int ef_parse_dynamic(elf_file_t);
8387551Smikeh
84134358Siedowsestatic int ef_get_type(elf_file_t ef);
85134358Siedowsestatic int ef_close(elf_file_t ef);
86134358Siedowsestatic int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
87134358Siedowsestatic int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
88134358Siedowsestatic int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
89134358Siedowsestatic int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
90134358Siedowse    void *dest);
91134358Siedowsestatic int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
92134358Siedowse    void **ptr);
93134358Siedowsestatic int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
94134358Siedowse    void **ptr);
95153504Smarcelstatic Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx);
96134358Siedowsestatic int ef_lookup_set(elf_file_t ef, const char *name, long *startp,
97134358Siedowse    long *stopp, long *countp);
98134358Siedowsestatic int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
99134358Siedowse
100134358Siedowsestatic struct elf_file_ops ef_file_ops = {
101134358Siedowse	ef_get_type,
102134358Siedowse	ef_close,
103134358Siedowse	ef_read,
104134358Siedowse	ef_read_entry,
105134358Siedowse	ef_seg_read,
106134358Siedowse	ef_seg_read_rel,
107134358Siedowse	ef_seg_read_entry,
108134358Siedowse	ef_seg_read_entry_rel,
109134358Siedowse	ef_symaddr,
110134358Siedowse	ef_lookup_set,
111134358Siedowse	ef_lookup_symbol
112134358Siedowse};
113134358Siedowse
114134358Siedowsestatic void
11583322Speteref_print_phdr(Elf_Phdr *phdr)
11683322Speter{
11783322Speter
11883322Speter	if ((phdr->p_flags & PF_W) == 0) {
11983322Speter		printf("text=0x%lx ", (long)phdr->p_filesz);
12083322Speter	} else {
12183322Speter		printf("data=0x%lx", (long)phdr->p_filesz);
12283322Speter		if (phdr->p_filesz < phdr->p_memsz)
12383322Speter			printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz));
12483322Speter		printf(" ");
12583322Speter	}
12683322Speter}
12783322Speter
128134358Siedowsestatic u_long
12983322Speteref_get_offset(elf_file_t ef, Elf_Off off)
13083322Speter{
13183322Speter	Elf_Phdr *ph;
13283322Speter	int i;
13383322Speter
13483322Speter	for (i = 0; i < ef->ef_nsegs; i++) {
13583322Speter		ph = ef->ef_segs[i];
13683322Speter		if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
13783322Speter			return ph->p_offset + (off - ph->p_vaddr);
13883322Speter		}
13983322Speter	}
14083322Speter	return 0;
14183322Speter}
14283322Speter
143134358Siedowsestatic int
144134358Siedowseef_get_type(elf_file_t ef)
145134358Siedowse{
146134358Siedowse
147134358Siedowse	return (ef->ef_type);
148134358Siedowse}
149134358Siedowse
15083322Speter/*
15183322Speter * next three functions copied from link_elf.c
15283322Speter */
15383322Speterstatic unsigned long
15483322Speterelf_hash(const char *name)
15583322Speter{
15683322Speter	const unsigned char *p = (const unsigned char *) name;
15783322Speter	unsigned long h = 0;
15883322Speter	unsigned long g;
15983322Speter
16083322Speter	while (*p != '\0') {
16183322Speter		h = (h << 4) + *p++;
16283322Speter		if ((g = h & 0xf0000000) != 0)
16383322Speter			h ^= g >> 24;
16483322Speter		h &= ~g;
16583322Speter	}
16683322Speter	return h;
16783322Speter}
16883322Speter
169134358Siedowsestatic int
17083322Speteref_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
17183322Speter{
17283322Speter	unsigned long symnum;
17383322Speter	Elf_Sym* symp;
17483322Speter	char *strp;
17583322Speter	unsigned long hash;
17683322Speter
17783322Speter	/* First, search hashed global symbols */
17883322Speter	hash = elf_hash(name);
17983322Speter	symnum = ef->ef_buckets[hash % ef->ef_nbuckets];
18083322Speter
18183322Speter	while (symnum != STN_UNDEF) {
18283322Speter		if (symnum >= ef->ef_nchains) {
18383322Speter			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
18483322Speter			    ef->ef_name);
18583322Speter			return ENOENT;
18683322Speter		}
18783322Speter
18883322Speter		symp = ef->ef_symtab + symnum;
18983322Speter		if (symp->st_name == 0) {
19083322Speter			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
19183322Speter			    ef->ef_name);
19283322Speter			return ENOENT;
19383322Speter		}
19483322Speter
19583322Speter		strp = ef->ef_strtab + symp->st_name;
19683322Speter
19783322Speter		if (strcmp(name, strp) == 0) {
19883322Speter			if (symp->st_shndx != SHN_UNDEF ||
19983322Speter			    (symp->st_value != 0 &&
20083322Speter				ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
20183322Speter				*sym = symp;
20283322Speter				return 0;
20383322Speter			} else
20483322Speter				return ENOENT;
20583322Speter		}
20683322Speter
20783322Speter		symnum = ef->ef_chains[symnum];
20883322Speter	}
20983322Speter
21083322Speter	return ENOENT;
21183322Speter}
21283322Speter
213134358Siedowsestatic int
214134358Siedowseef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
215134358Siedowse    long *countp)
216134358Siedowse{
217134358Siedowse	Elf_Sym *sym;
218134358Siedowse	char *setsym;
219134358Siedowse	int error, len;
220134358Siedowse
221134358Siedowse	len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
222134358Siedowse	setsym = malloc(len);
223134358Siedowse	if (setsym == NULL)
224134358Siedowse		return (ENOMEM);
225134358Siedowse
226134358Siedowse	/* get address of first entry */
227134358Siedowse	snprintf(setsym, len, "%s%s", "__start_set_", name);
228134358Siedowse	error = ef_lookup_symbol(ef, setsym, &sym);
229134358Siedowse	if (error)
230134358Siedowse		goto out;
231134358Siedowse	*startp = sym->st_value;
232134358Siedowse
233134358Siedowse	/* get address of last entry */
234134358Siedowse	snprintf(setsym, len, "%s%s", "__stop_set_", name);
235134358Siedowse	error = ef_lookup_symbol(ef, setsym, &sym);
236134358Siedowse	if (error)
237134358Siedowse		goto out;
238134358Siedowse	*stopp = sym->st_value;
239134358Siedowse
240134358Siedowse	/* and the number of entries */
241134358Siedowse	*countp = (*stopp - *startp) / sizeof(void *);
242134358Siedowse
243134358Siedowseout:
244134358Siedowse	free(setsym);
245134358Siedowse	return (error);
246134358Siedowse}
247134358Siedowse
248134358Siedowsestatic Elf_Addr
249153504Smarcelef_symaddr(elf_file_t ef, Elf_Size symidx)
250134358Siedowse{
251134358Siedowse	const Elf_Sym *sym;
252134358Siedowse
253134358Siedowse	if (symidx >= ef->ef_nchains)
254134358Siedowse		return (0);
255134358Siedowse	sym = ef->ef_symtab + symidx;
256134358Siedowse
257134358Siedowse	if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
258134358Siedowse	    sym->st_shndx != SHN_UNDEF && sym->st_value != 0)
259134358Siedowse		return (sym->st_value);
260134358Siedowse	return (0);
261134358Siedowse}
262134358Siedowse
263134358Siedowsestatic int
26483322Speteref_parse_dynamic(elf_file_t ef)
26583322Speter{
26683322Speter	Elf_Dyn *dp;
26794414Speter	Elf_Hashelt hashhdr[2];
26883322Speter/*	int plttype = DT_REL;*/
26983322Speter	int error;
270109607Sjake	Elf_Off rel_off;
271109607Sjake	Elf_Off rela_off;
272109607Sjake	int rel_sz;
273109607Sjake	int rela_sz;
274109607Sjake	int rel_entry;
275109607Sjake	int rela_entry;
27683322Speter
277109607Sjake	rel_off = rela_off = 0;
278109607Sjake	rel_sz = rela_sz = 0;
279109607Sjake	rel_entry = rela_entry = 0;
28083322Speter	for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
28183322Speter		switch (dp->d_tag) {
28283322Speter		case DT_HASH:
28383322Speter			error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
28483322Speter			    sizeof(hashhdr),  hashhdr);
28583322Speter			if (error) {
28683322Speter				warnx("can't read hash header (%lx)",
28783322Speter				    ef_get_offset(ef, dp->d_un.d_ptr));
28883322Speter				return error;
28983322Speter			}
29083322Speter			ef->ef_nbuckets = hashhdr[0];
29183322Speter			ef->ef_nchains = hashhdr[1];
29283322Speter			error = ef_read_entry(ef, -1,
29394414Speter			    (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
29483322Speter			    (void**)&ef->ef_hashtab);
29583322Speter			if (error) {
29683322Speter				warnx("can't read hash table");
29783322Speter				return error;
29883322Speter			}
29983322Speter			ef->ef_buckets = ef->ef_hashtab;
30083322Speter			ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
30183322Speter			break;
30283322Speter		case DT_STRTAB:
30383322Speter			ef->ef_stroff = dp->d_un.d_ptr;
30483322Speter			break;
30583322Speter		case DT_STRSZ:
30683322Speter			ef->ef_strsz = dp->d_un.d_val;
30783322Speter			break;
30883322Speter		case DT_SYMTAB:
30983322Speter			ef->ef_symoff = dp->d_un.d_ptr;
31083322Speter			break;
31183322Speter		case DT_SYMENT:
31283322Speter			if (dp->d_un.d_val != sizeof(Elf_Sym))
31383322Speter				return EFTYPE;
31483322Speter			break;
315109607Sjake		case DT_REL:
316109607Sjake			if (rel_off != 0)
317109607Sjake				warnx("second DT_REL entry ignored");
318109607Sjake			rel_off = dp->d_un.d_ptr;
319109607Sjake			break;
320109607Sjake		case DT_RELSZ:
321109607Sjake			if (rel_sz != 0)
322109607Sjake				warnx("second DT_RELSZ entry ignored");
323109607Sjake			rel_sz = dp->d_un.d_val;
324109607Sjake			break;
325109607Sjake		case DT_RELENT:
326109607Sjake			if (rel_entry != 0)
327109607Sjake				warnx("second DT_RELENT entry ignored");
328109607Sjake			rel_entry = dp->d_un.d_val;
329109607Sjake			break;
330109607Sjake		case DT_RELA:
331109607Sjake			if (rela_off != 0)
332109607Sjake				warnx("second DT_RELA entry ignored");
333109607Sjake			rela_off = dp->d_un.d_ptr;
334109607Sjake			break;
335109607Sjake		case DT_RELASZ:
336109607Sjake			if (rela_sz != 0)
337109607Sjake				warnx("second DT_RELASZ entry ignored");
338109607Sjake			rela_sz = dp->d_un.d_val;
339109607Sjake			break;
340109607Sjake		case DT_RELAENT:
341109607Sjake			if (rela_entry != 0)
342109607Sjake				warnx("second DT_RELAENT entry ignored");
343109607Sjake			rela_entry = dp->d_un.d_val;
344109607Sjake			break;
34583322Speter		}
34683322Speter	}
34783322Speter	if (ef->ef_symoff == 0) {
34883322Speter		warnx("%s: no .dynsym section found\n", ef->ef_name);
34983322Speter		return EFTYPE;
35083322Speter	}
35183322Speter	if (ef->ef_stroff == 0) {
35283322Speter		warnx("%s: no .dynstr section found\n", ef->ef_name);
35383322Speter		return EFTYPE;
35483322Speter	}
35583322Speter	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
35683322Speter	    ef->ef_nchains * sizeof(Elf_Sym),
35783322Speter		(void**)&ef->ef_symtab) != 0) {
35883322Speter		if (ef->ef_verbose)
35983322Speter			warnx("%s: can't load .dynsym section (0x%lx)",
36083322Speter			    ef->ef_name, (long)ef->ef_symoff);
36183322Speter		return EIO;
36283322Speter	}
36383322Speter	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
36483322Speter		(void**)&ef->ef_strtab) != 0) {
36583322Speter		warnx("can't load .dynstr section");
36683322Speter		return EIO;
36783322Speter	}
368109607Sjake	if (rel_off != 0) {
369109607Sjake		if (rel_entry == 0) {
370109607Sjake			warnx("%s: no DT_RELENT for DT_REL", ef->ef_name);
371109607Sjake			return (EFTYPE);
372109607Sjake		}
373109607Sjake		if (rel_entry != sizeof(Elf_Rel)) {
374109607Sjake			warnx("%s: inconsistent DT_RELENT value",
375109607Sjake			    ef->ef_name);
376109607Sjake			return (EFTYPE);
377109607Sjake		}
378109607Sjake		if (rel_sz % rel_entry != 0) {
379109607Sjake			warnx("%s: inconsistent values for DT_RELSZ and "
380109607Sjake			    "DT_RELENT", ef->ef_name);
381109607Sjake			return (EFTYPE);
382109607Sjake		}
383109607Sjake		if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz,
384109607Sjake		    (void **)&ef->ef_rel) != 0) {
385109607Sjake			warnx("%s: cannot load DT_REL section", ef->ef_name);
386109607Sjake			return (EIO);
387109607Sjake		}
388109607Sjake		ef->ef_relsz = rel_sz / rel_entry;
389109607Sjake		if (ef->ef_verbose)
390109607Sjake			warnx("%s: %d REL entries", ef->ef_name,
391109607Sjake			    ef->ef_relsz);
392109607Sjake	}
393109607Sjake	if (rela_off != 0) {
394109607Sjake		if (rela_entry == 0) {
395109607Sjake			warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name);
396109607Sjake			return (EFTYPE);
397109607Sjake		}
398109607Sjake		if (rela_entry != sizeof(Elf_Rela)) {
399109607Sjake			warnx("%s: inconsistent DT_RELAENT value",
400109607Sjake			    ef->ef_name);
401109607Sjake			return (EFTYPE);
402109607Sjake		}
403109607Sjake		if (rela_sz % rela_entry != 0) {
404109607Sjake			warnx("%s: inconsistent values for DT_RELASZ and "
405109607Sjake			    "DT_RELAENT", ef->ef_name);
406109607Sjake			return (EFTYPE);
407109607Sjake		}
408109607Sjake		if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz,
409109607Sjake		    (void **)&ef->ef_rela) != 0) {
410109607Sjake			warnx("%s: cannot load DT_RELA section", ef->ef_name);
411109607Sjake			return (EIO);
412109607Sjake		}
413109607Sjake		ef->ef_relasz = rela_sz / rela_entry;
414109607Sjake		if (ef->ef_verbose)
415109607Sjake			warnx("%s: %d RELA entries", ef->ef_name,
416109607Sjake			    ef->ef_relasz);
417109607Sjake	}
41883322Speter	return 0;
41983322Speter}
42083322Speter
421134358Siedowsestatic int
42283322Speteref_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
42383322Speter{
42487551Smikeh	ssize_t r;
42583322Speter
42687551Smikeh	if (offset != (Elf_Off)-1) {
42783322Speter		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
42883322Speter			return EIO;
42983322Speter	}
43087551Smikeh
43187551Smikeh	r = read(ef->ef_fd, dest, len);
43287551Smikeh	if (r != -1 && (size_t)r == len)
43387551Smikeh		return 0;
43487551Smikeh	else
43587551Smikeh		return EIO;
43683322Speter}
43783322Speter
438134358Siedowsestatic int
43983322Speteref_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
44083322Speter{
44183322Speter	int error;
44283322Speter
44383322Speter	*ptr = malloc(len);
44483322Speter	if (*ptr == NULL)
44583322Speter		return ENOMEM;
44683322Speter	error = ef_read(ef, offset, len, *ptr);
44783322Speter	if (error)
44883322Speter		free(*ptr);
44983322Speter	return error;
45083322Speter}
45183322Speter
452134358Siedowsestatic int
45383322Speteref_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
45483322Speter{
45583322Speter	u_long ofs = ef_get_offset(ef, offset);
45683322Speter
45783322Speter	if (ofs == 0) {
45883322Speter		if (ef->ef_verbose)
45983322Speter			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
46083322Speter			    ef->ef_name, (long)offset, ofs);
46183322Speter		return EFAULT;
46283322Speter	}
46383322Speter	return ef_read(ef, ofs, len, dest);
46483322Speter}
46583322Speter
466134358Siedowsestatic int
467109607Sjakeef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
468109607Sjake{
469109607Sjake	u_long ofs = ef_get_offset(ef, offset);
470134358Siedowse	const Elf_Rela *a;
471134358Siedowse	const Elf_Rel *r;
472109607Sjake	int error;
473109607Sjake
474109607Sjake	if (ofs == 0) {
475109607Sjake		if (ef->ef_verbose)
476109607Sjake			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
477109607Sjake			    ef->ef_name, (long)offset, ofs);
478109607Sjake		return EFAULT;
479109607Sjake	}
480109607Sjake	if ((error = ef_read(ef, ofs, len, dest)) != 0)
481109607Sjake		return (error);
482134358Siedowse
483134358Siedowse	for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
484134450Siedowse		error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len,
485134358Siedowse		    dest);
486134358Siedowse		if (error != 0)
487134358Siedowse			return (error);
488134358Siedowse	}
489134358Siedowse	for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
490134450Siedowse		error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len,
491134358Siedowse		    dest);
492134358Siedowse		if (error != 0)
493134358Siedowse			return (error);
494134358Siedowse	}
495134358Siedowse	return (0);
496109607Sjake}
497109607Sjake
498134358Siedowsestatic int
49983322Speteref_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
50083322Speter{
50183322Speter	int error;
50283322Speter
50383322Speter	*ptr = malloc(len);
50483322Speter	if (*ptr == NULL)
50583322Speter		return ENOMEM;
50683322Speter	error = ef_seg_read(ef, offset, len, *ptr);
50783322Speter	if (error)
50883322Speter		free(*ptr);
50983322Speter	return error;
51083322Speter}
51183322Speter
512134358Siedowsestatic int
513109607Sjakeef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
514109607Sjake{
515109607Sjake	int error;
516109607Sjake
517109607Sjake	*ptr = malloc(len);
518109607Sjake	if (*ptr == NULL)
519109607Sjake		return ENOMEM;
520109607Sjake	error = ef_seg_read_rel(ef, offset, len, *ptr);
521109607Sjake	if (error)
522109607Sjake		free(*ptr);
523109607Sjake	return error;
524109607Sjake}
525109607Sjake
526109607Sjakeint
527134358Siedowseef_open(const char *filename, struct elf_file *efile, int verbose)
52883322Speter{
529134358Siedowse	elf_file_t ef;
53083322Speter	Elf_Ehdr *hdr;
53183322Speter	int fd;
53283322Speter	int error;
53383322Speter	int phlen, res;
53483322Speter	int nsegs;
535237258Seadler	Elf_Phdr *phdr, *phdyn, *phlimit;
53683322Speter
53783322Speter	if (filename == NULL)
53883322Speter		return EFTYPE;
53983322Speter	if ((fd = open(filename, O_RDONLY)) == -1)
54083322Speter		return errno;
541134358Siedowse
542134358Siedowse	ef = malloc(sizeof(*ef));
543134358Siedowse	if (ef == NULL) {
544134358Siedowse		close(fd);
545134358Siedowse		return (ENOMEM);
546134358Siedowse	}
547134358Siedowse
548134358Siedowse	efile->ef_ef = ef;
549134358Siedowse	efile->ef_ops = &ef_file_ops;
550134358Siedowse
551134358Siedowse	bzero(ef, sizeof(*ef));
552134358Siedowse	ef->ef_verbose = verbose;
55383322Speter	ef->ef_fd = fd;
55483322Speter	ef->ef_name = strdup(filename);
555134358Siedowse	ef->ef_efile = efile;
55683322Speter	hdr = (Elf_Ehdr *)&ef->ef_hdr;
55783322Speter	do {
55883322Speter		res = read(fd, hdr, sizeof(*hdr));
55983322Speter		error = EFTYPE;
56083322Speter		if (res != sizeof(*hdr))
56183322Speter			break;
56283322Speter		if (!IS_ELF(*hdr))
56383322Speter			break;
56483322Speter		if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
56583322Speter		    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
56683322Speter		    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
56783322Speter		    hdr->e_version != EV_CURRENT ||
56883322Speter		    hdr->e_machine != ELF_TARG_MACH ||
56983322Speter		    hdr->e_phentsize != sizeof(Elf_Phdr))
57083322Speter			break;
57183322Speter		phlen = hdr->e_phnum * sizeof(Elf_Phdr);
57283322Speter		if (ef_read_entry(ef, hdr->e_phoff, phlen,
57383322Speter		    (void**)&ef->ef_ph) != 0)
57483322Speter			break;
57583322Speter		phdr = ef->ef_ph;
57683322Speter		phlimit = phdr + hdr->e_phnum;
57783322Speter		nsegs = 0;
57883322Speter		phdyn = NULL;
57983322Speter		while (phdr < phlimit) {
58083322Speter			if (verbose > 1)
58183322Speter				ef_print_phdr(phdr);
58283322Speter			switch (phdr->p_type) {
58383322Speter			case PT_LOAD:
584269014Semaste				if (nsegs < MAXSEGS)
585269014Semaste					ef->ef_segs[nsegs] = phdr;
586269014Semaste				nsegs++;
58783322Speter				break;
58883322Speter			case PT_PHDR:
58983322Speter				break;
59083322Speter			case PT_DYNAMIC:
59183322Speter				phdyn = phdr;
59283322Speter				break;
59383322Speter			}
59483322Speter			phdr++;
59583322Speter		}
59683322Speter		if (verbose > 1)
59783322Speter			printf("\n");
59883322Speter		if (phdyn == NULL) {
599242277Skientzle			warnx("Skipping %s: not dynamically-linked",
600242277Skientzle			    filename);
60183322Speter			break;
602269014Semaste		} else if (nsegs > MAXSEGS) {
603269014Semaste			warnx("%s: too many sections", filename);
604269014Semaste			break;
60583322Speter		}
606269014Semaste		ef->ef_nsegs = nsegs;
60783322Speter		if (ef_read_entry(ef, phdyn->p_offset,
60883322Speter			phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) {
60983322Speter			printf("ef_read_entry failed\n");
61083322Speter			break;
61183322Speter		}
61283322Speter		error = ef_parse_dynamic(ef);
61383322Speter		if (error)
61483322Speter			break;
61583322Speter		if (hdr->e_type == ET_DYN) {
61683322Speter			ef->ef_type = EFT_KLD;
61783322Speter/*			pad = (u_int)dest & PAGE_MASK;
61883322Speter			if (pad)
61983322Speter				dest += PAGE_SIZE - pad;*/
62083322Speter			error = 0;
62183322Speter		} else if (hdr->e_type == ET_EXEC) {
62283322Speter/*			dest = hdr->e_entry;
62383322Speter			if (dest == 0)
62483322Speter				break;*/
62583322Speter			ef->ef_type = EFT_KERNEL;
62683322Speter			error = 0;
62783322Speter		} else
62883322Speter			break;
62983322Speter	} while(0);
630134358Siedowse	if (error)
63183322Speter		ef_close(ef);
63283322Speter	return error;
63383322Speter}
63483322Speter
635134358Siedowsestatic int
63683322Speteref_close(elf_file_t ef)
63783322Speter{
63883322Speter	close(ef->ef_fd);
63983322Speter/*	if (ef->ef_fpage)
64083322Speter		free(ef->ef_fpage);*/
64183322Speter	if (ef->ef_name)
64283322Speter		free(ef->ef_name);
643134358Siedowse	ef->ef_efile->ef_ops = NULL;
644134358Siedowse	ef->ef_efile->ef_ef = NULL;
645134358Siedowse	free(ef);
64683322Speter	return 0;
64783322Speter}
648