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
50134358Siedowsestruct ef_file {
51134358Siedowse	char*		ef_name;
52134358Siedowse	struct elf_file *ef_efile;
53134358Siedowse	Elf_Phdr *	ef_ph;
54134358Siedowse	int		ef_fd;
55134358Siedowse	int		ef_type;
56134358Siedowse	Elf_Ehdr	ef_hdr;
57134358Siedowse	void*		ef_fpage;		/* First block of the file */
58134358Siedowse	int		ef_fplen;		/* length of first block */
59134358Siedowse	Elf_Dyn*	ef_dyn;			/* Symbol table etc. */
60134358Siedowse	Elf_Hashelt	ef_nbuckets;
61134358Siedowse	Elf_Hashelt	ef_nchains;
62134358Siedowse	Elf_Hashelt*	ef_buckets;
63134358Siedowse	Elf_Hashelt*	ef_chains;
64134358Siedowse	Elf_Hashelt*	ef_hashtab;
65134358Siedowse	Elf_Off		ef_stroff;
66134358Siedowse	caddr_t		ef_strtab;
67134358Siedowse	int		ef_strsz;
68134358Siedowse	Elf_Off		ef_symoff;
69134358Siedowse	Elf_Sym*	ef_symtab;
70134358Siedowse	int		ef_nsegs;
71134358Siedowse	Elf_Phdr *	ef_segs[2];
72134358Siedowse	int		ef_verbose;
73134358Siedowse	Elf_Rel *	ef_rel;			/* relocation table */
74134358Siedowse	int		ef_relsz;		/* number of entries */
75134358Siedowse	Elf_Rela *	ef_rela;		/* relocation table */
76134358Siedowse	int		ef_relasz;		/* number of entries */
77134358Siedowse};
78134358Siedowse
7987551Smikehstatic void ef_print_phdr(Elf_Phdr *);
8087551Smikehstatic u_long ef_get_offset(elf_file_t, Elf_Off);
8187551Smikehstatic int ef_parse_dynamic(elf_file_t);
8287551Smikeh
83134358Siedowsestatic int ef_get_type(elf_file_t ef);
84134358Siedowsestatic int ef_close(elf_file_t ef);
85134358Siedowsestatic int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
86134358Siedowsestatic int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
87134358Siedowsestatic int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
88134358Siedowsestatic int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
89134358Siedowse    void *dest);
90134358Siedowsestatic int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
91134358Siedowse    void **ptr);
92134358Siedowsestatic int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
93134358Siedowse    void **ptr);
94153504Smarcelstatic Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx);
95134358Siedowsestatic int ef_lookup_set(elf_file_t ef, const char *name, long *startp,
96134358Siedowse    long *stopp, long *countp);
97134358Siedowsestatic int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
98134358Siedowse
99134358Siedowsestatic struct elf_file_ops ef_file_ops = {
100134358Siedowse	ef_get_type,
101134358Siedowse	ef_close,
102134358Siedowse	ef_read,
103134358Siedowse	ef_read_entry,
104134358Siedowse	ef_seg_read,
105134358Siedowse	ef_seg_read_rel,
106134358Siedowse	ef_seg_read_entry,
107134358Siedowse	ef_seg_read_entry_rel,
108134358Siedowse	ef_symaddr,
109134358Siedowse	ef_lookup_set,
110134358Siedowse	ef_lookup_symbol
111134358Siedowse};
112134358Siedowse
113134358Siedowsestatic void
11483322Speteref_print_phdr(Elf_Phdr *phdr)
11583322Speter{
11683322Speter
11783322Speter	if ((phdr->p_flags & PF_W) == 0) {
11883322Speter		printf("text=0x%lx ", (long)phdr->p_filesz);
11983322Speter	} else {
12083322Speter		printf("data=0x%lx", (long)phdr->p_filesz);
12183322Speter		if (phdr->p_filesz < phdr->p_memsz)
12283322Speter			printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz));
12383322Speter		printf(" ");
12483322Speter	}
12583322Speter}
12683322Speter
127134358Siedowsestatic u_long
12883322Speteref_get_offset(elf_file_t ef, Elf_Off off)
12983322Speter{
13083322Speter	Elf_Phdr *ph;
13183322Speter	int i;
13283322Speter
13383322Speter	for (i = 0; i < ef->ef_nsegs; i++) {
13483322Speter		ph = ef->ef_segs[i];
13583322Speter		if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
13683322Speter			return ph->p_offset + (off - ph->p_vaddr);
13783322Speter		}
13883322Speter	}
13983322Speter	return 0;
14083322Speter}
14183322Speter
142134358Siedowsestatic int
143134358Siedowseef_get_type(elf_file_t ef)
144134358Siedowse{
145134358Siedowse
146134358Siedowse	return (ef->ef_type);
147134358Siedowse}
148134358Siedowse
14983322Speter/*
15083322Speter * next three functions copied from link_elf.c
15183322Speter */
15283322Speterstatic unsigned long
15383322Speterelf_hash(const char *name)
15483322Speter{
15583322Speter	const unsigned char *p = (const unsigned char *) name;
15683322Speter	unsigned long h = 0;
15783322Speter	unsigned long g;
15883322Speter
15983322Speter	while (*p != '\0') {
16083322Speter		h = (h << 4) + *p++;
16183322Speter		if ((g = h & 0xf0000000) != 0)
16283322Speter			h ^= g >> 24;
16383322Speter		h &= ~g;
16483322Speter	}
16583322Speter	return h;
16683322Speter}
16783322Speter
168134358Siedowsestatic int
16983322Speteref_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
17083322Speter{
17183322Speter	unsigned long symnum;
17283322Speter	Elf_Sym* symp;
17383322Speter	char *strp;
17483322Speter	unsigned long hash;
17583322Speter
17683322Speter	/* First, search hashed global symbols */
17783322Speter	hash = elf_hash(name);
17883322Speter	symnum = ef->ef_buckets[hash % ef->ef_nbuckets];
17983322Speter
18083322Speter	while (symnum != STN_UNDEF) {
18183322Speter		if (symnum >= ef->ef_nchains) {
18283322Speter			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
18383322Speter			    ef->ef_name);
18483322Speter			return ENOENT;
18583322Speter		}
18683322Speter
18783322Speter		symp = ef->ef_symtab + symnum;
18883322Speter		if (symp->st_name == 0) {
18983322Speter			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
19083322Speter			    ef->ef_name);
19183322Speter			return ENOENT;
19283322Speter		}
19383322Speter
19483322Speter		strp = ef->ef_strtab + symp->st_name;
19583322Speter
19683322Speter		if (strcmp(name, strp) == 0) {
19783322Speter			if (symp->st_shndx != SHN_UNDEF ||
19883322Speter			    (symp->st_value != 0 &&
19983322Speter				ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
20083322Speter				*sym = symp;
20183322Speter				return 0;
20283322Speter			} else
20383322Speter				return ENOENT;
20483322Speter		}
20583322Speter
20683322Speter		symnum = ef->ef_chains[symnum];
20783322Speter	}
20883322Speter
20983322Speter	return ENOENT;
21083322Speter}
21183322Speter
212134358Siedowsestatic int
213134358Siedowseef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
214134358Siedowse    long *countp)
215134358Siedowse{
216134358Siedowse	Elf_Sym *sym;
217134358Siedowse	char *setsym;
218134358Siedowse	int error, len;
219134358Siedowse
220134358Siedowse	len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
221134358Siedowse	setsym = malloc(len);
222134358Siedowse	if (setsym == NULL)
223134358Siedowse		return (ENOMEM);
224134358Siedowse
225134358Siedowse	/* get address of first entry */
226134358Siedowse	snprintf(setsym, len, "%s%s", "__start_set_", name);
227134358Siedowse	error = ef_lookup_symbol(ef, setsym, &sym);
228134358Siedowse	if (error)
229134358Siedowse		goto out;
230134358Siedowse	*startp = sym->st_value;
231134358Siedowse
232134358Siedowse	/* get address of last entry */
233134358Siedowse	snprintf(setsym, len, "%s%s", "__stop_set_", name);
234134358Siedowse	error = ef_lookup_symbol(ef, setsym, &sym);
235134358Siedowse	if (error)
236134358Siedowse		goto out;
237134358Siedowse	*stopp = sym->st_value;
238134358Siedowse
239134358Siedowse	/* and the number of entries */
240134358Siedowse	*countp = (*stopp - *startp) / sizeof(void *);
241134358Siedowse
242134358Siedowseout:
243134358Siedowse	free(setsym);
244134358Siedowse	return (error);
245134358Siedowse}
246134358Siedowse
247134358Siedowsestatic Elf_Addr
248153504Smarcelef_symaddr(elf_file_t ef, Elf_Size symidx)
249134358Siedowse{
250134358Siedowse	const Elf_Sym *sym;
251134358Siedowse
252134358Siedowse	if (symidx >= ef->ef_nchains)
253134358Siedowse		return (0);
254134358Siedowse	sym = ef->ef_symtab + symidx;
255134358Siedowse
256134358Siedowse	if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
257134358Siedowse	    sym->st_shndx != SHN_UNDEF && sym->st_value != 0)
258134358Siedowse		return (sym->st_value);
259134358Siedowse	return (0);
260134358Siedowse}
261134358Siedowse
262134358Siedowsestatic int
26383322Speteref_parse_dynamic(elf_file_t ef)
26483322Speter{
26583322Speter	Elf_Dyn *dp;
26694414Speter	Elf_Hashelt hashhdr[2];
26783322Speter/*	int plttype = DT_REL;*/
26883322Speter	int error;
269109607Sjake	Elf_Off rel_off;
270109607Sjake	Elf_Off rela_off;
271109607Sjake	int rel_sz;
272109607Sjake	int rela_sz;
273109607Sjake	int rel_entry;
274109607Sjake	int rela_entry;
27583322Speter
276109607Sjake	rel_off = rela_off = 0;
277109607Sjake	rel_sz = rela_sz = 0;
278109607Sjake	rel_entry = rela_entry = 0;
27983322Speter	for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
28083322Speter		switch (dp->d_tag) {
28183322Speter		case DT_HASH:
28283322Speter			error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
28383322Speter			    sizeof(hashhdr),  hashhdr);
28483322Speter			if (error) {
28583322Speter				warnx("can't read hash header (%lx)",
28683322Speter				    ef_get_offset(ef, dp->d_un.d_ptr));
28783322Speter				return error;
28883322Speter			}
28983322Speter			ef->ef_nbuckets = hashhdr[0];
29083322Speter			ef->ef_nchains = hashhdr[1];
29183322Speter			error = ef_read_entry(ef, -1,
29294414Speter			    (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
29383322Speter			    (void**)&ef->ef_hashtab);
29483322Speter			if (error) {
29583322Speter				warnx("can't read hash table");
29683322Speter				return error;
29783322Speter			}
29883322Speter			ef->ef_buckets = ef->ef_hashtab;
29983322Speter			ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
30083322Speter			break;
30183322Speter		case DT_STRTAB:
30283322Speter			ef->ef_stroff = dp->d_un.d_ptr;
30383322Speter			break;
30483322Speter		case DT_STRSZ:
30583322Speter			ef->ef_strsz = dp->d_un.d_val;
30683322Speter			break;
30783322Speter		case DT_SYMTAB:
30883322Speter			ef->ef_symoff = dp->d_un.d_ptr;
30983322Speter			break;
31083322Speter		case DT_SYMENT:
31183322Speter			if (dp->d_un.d_val != sizeof(Elf_Sym))
31283322Speter				return EFTYPE;
31383322Speter			break;
314109607Sjake		case DT_REL:
315109607Sjake			if (rel_off != 0)
316109607Sjake				warnx("second DT_REL entry ignored");
317109607Sjake			rel_off = dp->d_un.d_ptr;
318109607Sjake			break;
319109607Sjake		case DT_RELSZ:
320109607Sjake			if (rel_sz != 0)
321109607Sjake				warnx("second DT_RELSZ entry ignored");
322109607Sjake			rel_sz = dp->d_un.d_val;
323109607Sjake			break;
324109607Sjake		case DT_RELENT:
325109607Sjake			if (rel_entry != 0)
326109607Sjake				warnx("second DT_RELENT entry ignored");
327109607Sjake			rel_entry = dp->d_un.d_val;
328109607Sjake			break;
329109607Sjake		case DT_RELA:
330109607Sjake			if (rela_off != 0)
331109607Sjake				warnx("second DT_RELA entry ignored");
332109607Sjake			rela_off = dp->d_un.d_ptr;
333109607Sjake			break;
334109607Sjake		case DT_RELASZ:
335109607Sjake			if (rela_sz != 0)
336109607Sjake				warnx("second DT_RELASZ entry ignored");
337109607Sjake			rela_sz = dp->d_un.d_val;
338109607Sjake			break;
339109607Sjake		case DT_RELAENT:
340109607Sjake			if (rela_entry != 0)
341109607Sjake				warnx("second DT_RELAENT entry ignored");
342109607Sjake			rela_entry = dp->d_un.d_val;
343109607Sjake			break;
34483322Speter		}
34583322Speter	}
34683322Speter	if (ef->ef_symoff == 0) {
34783322Speter		warnx("%s: no .dynsym section found\n", ef->ef_name);
34883322Speter		return EFTYPE;
34983322Speter	}
35083322Speter	if (ef->ef_stroff == 0) {
35183322Speter		warnx("%s: no .dynstr section found\n", ef->ef_name);
35283322Speter		return EFTYPE;
35383322Speter	}
35483322Speter	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
35583322Speter	    ef->ef_nchains * sizeof(Elf_Sym),
35683322Speter		(void**)&ef->ef_symtab) != 0) {
35783322Speter		if (ef->ef_verbose)
35883322Speter			warnx("%s: can't load .dynsym section (0x%lx)",
35983322Speter			    ef->ef_name, (long)ef->ef_symoff);
36083322Speter		return EIO;
36183322Speter	}
36283322Speter	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
36383322Speter		(void**)&ef->ef_strtab) != 0) {
36483322Speter		warnx("can't load .dynstr section");
36583322Speter		return EIO;
36683322Speter	}
367109607Sjake	if (rel_off != 0) {
368109607Sjake		if (rel_entry == 0) {
369109607Sjake			warnx("%s: no DT_RELENT for DT_REL", ef->ef_name);
370109607Sjake			return (EFTYPE);
371109607Sjake		}
372109607Sjake		if (rel_entry != sizeof(Elf_Rel)) {
373109607Sjake			warnx("%s: inconsistent DT_RELENT value",
374109607Sjake			    ef->ef_name);
375109607Sjake			return (EFTYPE);
376109607Sjake		}
377109607Sjake		if (rel_sz % rel_entry != 0) {
378109607Sjake			warnx("%s: inconsistent values for DT_RELSZ and "
379109607Sjake			    "DT_RELENT", ef->ef_name);
380109607Sjake			return (EFTYPE);
381109607Sjake		}
382109607Sjake		if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz,
383109607Sjake		    (void **)&ef->ef_rel) != 0) {
384109607Sjake			warnx("%s: cannot load DT_REL section", ef->ef_name);
385109607Sjake			return (EIO);
386109607Sjake		}
387109607Sjake		ef->ef_relsz = rel_sz / rel_entry;
388109607Sjake		if (ef->ef_verbose)
389109607Sjake			warnx("%s: %d REL entries", ef->ef_name,
390109607Sjake			    ef->ef_relsz);
391109607Sjake	}
392109607Sjake	if (rela_off != 0) {
393109607Sjake		if (rela_entry == 0) {
394109607Sjake			warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name);
395109607Sjake			return (EFTYPE);
396109607Sjake		}
397109607Sjake		if (rela_entry != sizeof(Elf_Rela)) {
398109607Sjake			warnx("%s: inconsistent DT_RELAENT value",
399109607Sjake			    ef->ef_name);
400109607Sjake			return (EFTYPE);
401109607Sjake		}
402109607Sjake		if (rela_sz % rela_entry != 0) {
403109607Sjake			warnx("%s: inconsistent values for DT_RELASZ and "
404109607Sjake			    "DT_RELAENT", ef->ef_name);
405109607Sjake			return (EFTYPE);
406109607Sjake		}
407109607Sjake		if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz,
408109607Sjake		    (void **)&ef->ef_rela) != 0) {
409109607Sjake			warnx("%s: cannot load DT_RELA section", ef->ef_name);
410109607Sjake			return (EIO);
411109607Sjake		}
412109607Sjake		ef->ef_relasz = rela_sz / rela_entry;
413109607Sjake		if (ef->ef_verbose)
414109607Sjake			warnx("%s: %d RELA entries", ef->ef_name,
415109607Sjake			    ef->ef_relasz);
416109607Sjake	}
41783322Speter	return 0;
41883322Speter}
41983322Speter
420134358Siedowsestatic int
42183322Speteref_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
42283322Speter{
42387551Smikeh	ssize_t r;
42483322Speter
42587551Smikeh	if (offset != (Elf_Off)-1) {
42683322Speter		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
42783322Speter			return EIO;
42883322Speter	}
42987551Smikeh
43087551Smikeh	r = read(ef->ef_fd, dest, len);
43187551Smikeh	if (r != -1 && (size_t)r == len)
43287551Smikeh		return 0;
43387551Smikeh	else
43487551Smikeh		return EIO;
43583322Speter}
43683322Speter
437134358Siedowsestatic int
43883322Speteref_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
43983322Speter{
44083322Speter	int error;
44183322Speter
44283322Speter	*ptr = malloc(len);
44383322Speter	if (*ptr == NULL)
44483322Speter		return ENOMEM;
44583322Speter	error = ef_read(ef, offset, len, *ptr);
44683322Speter	if (error)
44783322Speter		free(*ptr);
44883322Speter	return error;
44983322Speter}
45083322Speter
451134358Siedowsestatic int
45283322Speteref_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
45383322Speter{
45483322Speter	u_long ofs = ef_get_offset(ef, offset);
45583322Speter
45683322Speter	if (ofs == 0) {
45783322Speter		if (ef->ef_verbose)
45883322Speter			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
45983322Speter			    ef->ef_name, (long)offset, ofs);
46083322Speter		return EFAULT;
46183322Speter	}
46283322Speter	return ef_read(ef, ofs, len, dest);
46383322Speter}
46483322Speter
465134358Siedowsestatic int
466109607Sjakeef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
467109607Sjake{
468109607Sjake	u_long ofs = ef_get_offset(ef, offset);
469134358Siedowse	const Elf_Rela *a;
470134358Siedowse	const Elf_Rel *r;
471109607Sjake	int error;
472109607Sjake
473109607Sjake	if (ofs == 0) {
474109607Sjake		if (ef->ef_verbose)
475109607Sjake			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
476109607Sjake			    ef->ef_name, (long)offset, ofs);
477109607Sjake		return EFAULT;
478109607Sjake	}
479109607Sjake	if ((error = ef_read(ef, ofs, len, dest)) != 0)
480109607Sjake		return (error);
481134358Siedowse
482134358Siedowse	for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
483134450Siedowse		error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len,
484134358Siedowse		    dest);
485134358Siedowse		if (error != 0)
486134358Siedowse			return (error);
487134358Siedowse	}
488134358Siedowse	for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
489134450Siedowse		error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len,
490134358Siedowse		    dest);
491134358Siedowse		if (error != 0)
492134358Siedowse			return (error);
493134358Siedowse	}
494134358Siedowse	return (0);
495109607Sjake}
496109607Sjake
497134358Siedowsestatic int
49883322Speteref_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
49983322Speter{
50083322Speter	int error;
50183322Speter
50283322Speter	*ptr = malloc(len);
50383322Speter	if (*ptr == NULL)
50483322Speter		return ENOMEM;
50583322Speter	error = ef_seg_read(ef, offset, len, *ptr);
50683322Speter	if (error)
50783322Speter		free(*ptr);
50883322Speter	return error;
50983322Speter}
51083322Speter
511134358Siedowsestatic int
512109607Sjakeef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
513109607Sjake{
514109607Sjake	int error;
515109607Sjake
516109607Sjake	*ptr = malloc(len);
517109607Sjake	if (*ptr == NULL)
518109607Sjake		return ENOMEM;
519109607Sjake	error = ef_seg_read_rel(ef, offset, len, *ptr);
520109607Sjake	if (error)
521109607Sjake		free(*ptr);
522109607Sjake	return error;
523109607Sjake}
524109607Sjake
525109607Sjakeint
526134358Siedowseef_open(const char *filename, struct elf_file *efile, int verbose)
52783322Speter{
528134358Siedowse	elf_file_t ef;
52983322Speter	Elf_Ehdr *hdr;
53083322Speter	int fd;
53183322Speter	int error;
53283322Speter	int phlen, res;
53383322Speter	int nsegs;
534237415Seadler	Elf_Phdr *phdr, *phdyn, *phlimit;
53583322Speter
53683322Speter	if (filename == NULL)
53783322Speter		return EFTYPE;
53883322Speter	if ((fd = open(filename, O_RDONLY)) == -1)
53983322Speter		return errno;
540134358Siedowse
541134358Siedowse	ef = malloc(sizeof(*ef));
542134358Siedowse	if (ef == NULL) {
543134358Siedowse		close(fd);
544134358Siedowse		return (ENOMEM);
545134358Siedowse	}
546134358Siedowse
547134358Siedowse	efile->ef_ef = ef;
548134358Siedowse	efile->ef_ops = &ef_file_ops;
549134358Siedowse
550134358Siedowse	bzero(ef, sizeof(*ef));
551134358Siedowse	ef->ef_verbose = verbose;
55283322Speter	ef->ef_fd = fd;
55383322Speter	ef->ef_name = strdup(filename);
554134358Siedowse	ef->ef_efile = efile;
55583322Speter	hdr = (Elf_Ehdr *)&ef->ef_hdr;
55683322Speter	do {
55783322Speter		res = read(fd, hdr, sizeof(*hdr));
55883322Speter		error = EFTYPE;
55983322Speter		if (res != sizeof(*hdr))
56083322Speter			break;
56183322Speter		if (!IS_ELF(*hdr))
56283322Speter			break;
56383322Speter		if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
56483322Speter		    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
56583322Speter		    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
56683322Speter		    hdr->e_version != EV_CURRENT ||
56783322Speter		    hdr->e_machine != ELF_TARG_MACH ||
56883322Speter		    hdr->e_phentsize != sizeof(Elf_Phdr))
56983322Speter			break;
57083322Speter		phlen = hdr->e_phnum * sizeof(Elf_Phdr);
57183322Speter		if (ef_read_entry(ef, hdr->e_phoff, phlen,
57283322Speter		    (void**)&ef->ef_ph) != 0)
57383322Speter			break;
57483322Speter		phdr = ef->ef_ph;
57583322Speter		phlimit = phdr + hdr->e_phnum;
57683322Speter		nsegs = 0;
57783322Speter		phdyn = NULL;
57883322Speter		while (phdr < phlimit) {
57983322Speter			if (verbose > 1)
58083322Speter				ef_print_phdr(phdr);
58183322Speter			switch (phdr->p_type) {
58283322Speter			case PT_LOAD:
58383322Speter				if (nsegs == 2) {
58483322Speter					warnx("%s: too many sections",
58583322Speter					    filename);
58683322Speter					break;
58783322Speter				}
58883322Speter				ef->ef_segs[nsegs++] = phdr;
58983322Speter				break;
59083322Speter			case PT_PHDR:
59183322Speter				break;
59283322Speter			case PT_DYNAMIC:
59383322Speter				phdyn = phdr;
59483322Speter				break;
59583322Speter			}
59683322Speter			phdr++;
59783322Speter		}
59883322Speter		if (verbose > 1)
59983322Speter			printf("\n");
60083322Speter		ef->ef_nsegs = nsegs;
60183322Speter		if (phdyn == NULL) {
60283322Speter			warnx("file isn't dynamically-linked");
60383322Speter			break;
60483322Speter		}
60583322Speter		if (ef_read_entry(ef, phdyn->p_offset,
60683322Speter			phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) {
60783322Speter			printf("ef_read_entry failed\n");
60883322Speter			break;
60983322Speter		}
61083322Speter		error = ef_parse_dynamic(ef);
61183322Speter		if (error)
61283322Speter			break;
61383322Speter		if (hdr->e_type == ET_DYN) {
61483322Speter			ef->ef_type = EFT_KLD;
61583322Speter/*			pad = (u_int)dest & PAGE_MASK;
61683322Speter			if (pad)
61783322Speter				dest += PAGE_SIZE - pad;*/
61883322Speter			error = 0;
61983322Speter		} else if (hdr->e_type == ET_EXEC) {
62083322Speter/*			dest = hdr->e_entry;
62183322Speter			if (dest == 0)
62283322Speter				break;*/
62383322Speter			ef->ef_type = EFT_KERNEL;
62483322Speter			error = 0;
62583322Speter		} else
62683322Speter			break;
62783322Speter	} while(0);
628134358Siedowse	if (error)
62983322Speter		ef_close(ef);
63083322Speter	return error;
63183322Speter}
63283322Speter
633134358Siedowsestatic int
63483322Speteref_close(elf_file_t ef)
63583322Speter{
63683322Speter	close(ef->ef_fd);
63783322Speter/*	if (ef->ef_fpage)
63883322Speter		free(ef->ef_fpage);*/
63983322Speter	if (ef->ef_name)
64083322Speter		free(ef->ef_name);
641134358Siedowse	ef->ef_efile->ef_ops = NULL;
642134358Siedowse	ef->ef_efile->ef_ef = NULL;
643134358Siedowse	free(ef);
64483322Speter	return 0;
64583322Speter}
646