xref: /freebsd/usr.sbin/kldxref/ef.c (revision 1eed250a)
19c6f9240SPeter Wemm /*
29c6f9240SPeter Wemm  * Copyright (c) 2000, Boris Popov
39c6f9240SPeter Wemm  * All rights reserved.
49c6f9240SPeter Wemm  *
59c6f9240SPeter Wemm  * Redistribution and use in source and binary forms, with or without
69c6f9240SPeter Wemm  * modification, are permitted provided that the following conditions
79c6f9240SPeter Wemm  * are met:
89c6f9240SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
99c6f9240SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
109c6f9240SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
119c6f9240SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
129c6f9240SPeter Wemm  *    documentation and/or other materials provided with the distribution.
139c6f9240SPeter Wemm  * 3. All advertising materials mentioning features or use of this software
149c6f9240SPeter Wemm  *    must display the following acknowledgement:
159c6f9240SPeter Wemm  *    This product includes software developed by Boris Popov.
169c6f9240SPeter Wemm  * 4. Neither the name of the author nor the names of any co-contributors
179c6f9240SPeter Wemm  *    may be used to endorse or promote products derived from this software
189c6f9240SPeter Wemm  *    without specific prior written permission.
199c6f9240SPeter Wemm  *
209c6f9240SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
219c6f9240SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229c6f9240SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239c6f9240SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
249c6f9240SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259c6f9240SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269c6f9240SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279c6f9240SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289c6f9240SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299c6f9240SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309c6f9240SPeter Wemm  * SUCH DAMAGE.
319c6f9240SPeter Wemm  *
329c6f9240SPeter Wemm  * $FreeBSD$
339c6f9240SPeter Wemm  */
349c6f9240SPeter Wemm 
359c6f9240SPeter Wemm #include <sys/param.h>
369c6f9240SPeter Wemm #include <sys/linker.h>
379c6f9240SPeter Wemm #include <string.h>
38754a3615SPeter Wemm #include <stdio.h>
39754a3615SPeter Wemm #include <stdlib.h>
40754a3615SPeter Wemm #include <unistd.h>
41754a3615SPeter Wemm #include <errno.h>
42754a3615SPeter Wemm #include <fcntl.h>
439c6f9240SPeter Wemm #include <machine/elf.h>
449c6f9240SPeter Wemm #define FREEBSD_ELF
459c6f9240SPeter Wemm #include <link.h>
469c6f9240SPeter Wemm 
479c6f9240SPeter Wemm #include <err.h>
489c6f9240SPeter Wemm 
499c6f9240SPeter Wemm #include "ef.h"
509c6f9240SPeter Wemm 
5187e5cd7cSMike Heffner static void ef_print_phdr(Elf_Phdr *);
5287e5cd7cSMike Heffner static u_long ef_get_offset(elf_file_t, Elf_Off);
5387e5cd7cSMike Heffner static int ef_parse_dynamic(elf_file_t);
5487e5cd7cSMike Heffner 
559c6f9240SPeter Wemm void
569c6f9240SPeter Wemm ef_print_phdr(Elf_Phdr *phdr)
579c6f9240SPeter Wemm {
589c6f9240SPeter Wemm 
599c6f9240SPeter Wemm 	if ((phdr->p_flags & PF_W) == 0) {
609c6f9240SPeter Wemm 		printf("text=0x%lx ", (long)phdr->p_filesz);
619c6f9240SPeter Wemm 	} else {
629c6f9240SPeter Wemm 		printf("data=0x%lx", (long)phdr->p_filesz);
639c6f9240SPeter Wemm 		if (phdr->p_filesz < phdr->p_memsz)
649c6f9240SPeter Wemm 			printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz));
659c6f9240SPeter Wemm 		printf(" ");
669c6f9240SPeter Wemm 	}
679c6f9240SPeter Wemm }
689c6f9240SPeter Wemm 
699c6f9240SPeter Wemm u_long
709c6f9240SPeter Wemm ef_get_offset(elf_file_t ef, Elf_Off off)
719c6f9240SPeter Wemm {
729c6f9240SPeter Wemm 	Elf_Phdr *ph;
739c6f9240SPeter Wemm 	int i;
749c6f9240SPeter Wemm 
759c6f9240SPeter Wemm 	for (i = 0; i < ef->ef_nsegs; i++) {
769c6f9240SPeter Wemm 		ph = ef->ef_segs[i];
779c6f9240SPeter Wemm 		if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
789c6f9240SPeter Wemm 			return ph->p_offset + (off - ph->p_vaddr);
799c6f9240SPeter Wemm 		}
809c6f9240SPeter Wemm 	}
819c6f9240SPeter Wemm 	return 0;
829c6f9240SPeter Wemm }
839c6f9240SPeter Wemm 
849c6f9240SPeter Wemm /*
859c6f9240SPeter Wemm  * next three functions copied from link_elf.c
869c6f9240SPeter Wemm  */
879c6f9240SPeter Wemm static unsigned long
889c6f9240SPeter Wemm elf_hash(const char *name)
899c6f9240SPeter Wemm {
909c6f9240SPeter Wemm 	const unsigned char *p = (const unsigned char *) name;
919c6f9240SPeter Wemm 	unsigned long h = 0;
929c6f9240SPeter Wemm 	unsigned long g;
939c6f9240SPeter Wemm 
949c6f9240SPeter Wemm 	while (*p != '\0') {
959c6f9240SPeter Wemm 		h = (h << 4) + *p++;
969c6f9240SPeter Wemm 		if ((g = h & 0xf0000000) != 0)
979c6f9240SPeter Wemm 			h ^= g >> 24;
989c6f9240SPeter Wemm 		h &= ~g;
999c6f9240SPeter Wemm 	}
1009c6f9240SPeter Wemm 	return h;
1019c6f9240SPeter Wemm }
1029c6f9240SPeter Wemm 
1039c6f9240SPeter Wemm int
1049c6f9240SPeter Wemm ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
1059c6f9240SPeter Wemm {
1069c6f9240SPeter Wemm 	unsigned long symnum;
1079c6f9240SPeter Wemm 	Elf_Sym* symp;
1089c6f9240SPeter Wemm 	char *strp;
1099c6f9240SPeter Wemm 	unsigned long hash;
1109c6f9240SPeter Wemm 
1119c6f9240SPeter Wemm 	/* First, search hashed global symbols */
1129c6f9240SPeter Wemm 	hash = elf_hash(name);
1139c6f9240SPeter Wemm 	symnum = ef->ef_buckets[hash % ef->ef_nbuckets];
1149c6f9240SPeter Wemm 
1159c6f9240SPeter Wemm 	while (symnum != STN_UNDEF) {
1169c6f9240SPeter Wemm 		if (symnum >= ef->ef_nchains) {
1179c6f9240SPeter Wemm 			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
1189c6f9240SPeter Wemm 			    ef->ef_name);
1199c6f9240SPeter Wemm 			return ENOENT;
1209c6f9240SPeter Wemm 		}
1219c6f9240SPeter Wemm 
1229c6f9240SPeter Wemm 		symp = ef->ef_symtab + symnum;
1239c6f9240SPeter Wemm 		if (symp->st_name == 0) {
1249c6f9240SPeter Wemm 			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
1259c6f9240SPeter Wemm 			    ef->ef_name);
1269c6f9240SPeter Wemm 			return ENOENT;
1279c6f9240SPeter Wemm 		}
1289c6f9240SPeter Wemm 
1299c6f9240SPeter Wemm 		strp = ef->ef_strtab + symp->st_name;
1309c6f9240SPeter Wemm 
1319c6f9240SPeter Wemm 		if (strcmp(name, strp) == 0) {
1329c6f9240SPeter Wemm 			if (symp->st_shndx != SHN_UNDEF ||
1339c6f9240SPeter Wemm 			    (symp->st_value != 0 &&
1349c6f9240SPeter Wemm 				ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
1359c6f9240SPeter Wemm 				*sym = symp;
1369c6f9240SPeter Wemm 				return 0;
1379c6f9240SPeter Wemm 			} else
1389c6f9240SPeter Wemm 				return ENOENT;
1399c6f9240SPeter Wemm 		}
1409c6f9240SPeter Wemm 
1419c6f9240SPeter Wemm 		symnum = ef->ef_chains[symnum];
1429c6f9240SPeter Wemm 	}
1439c6f9240SPeter Wemm 
1449c6f9240SPeter Wemm 	return ENOENT;
1459c6f9240SPeter Wemm }
1469c6f9240SPeter Wemm 
1479c6f9240SPeter Wemm int
1489c6f9240SPeter Wemm ef_parse_dynamic(elf_file_t ef)
1499c6f9240SPeter Wemm {
1509c6f9240SPeter Wemm 	Elf_Dyn *dp;
151f23aa297SPeter Wemm 	Elf_Hashelt hashhdr[2];
1529c6f9240SPeter Wemm /*	int plttype = DT_REL;*/
1539c6f9240SPeter Wemm 	int error;
1541eed250aSJake Burkholder 	Elf_Off rel_off;
1551eed250aSJake Burkholder 	Elf_Off rela_off;
1561eed250aSJake Burkholder 	int rel_sz;
1571eed250aSJake Burkholder 	int rela_sz;
1581eed250aSJake Burkholder 	int rel_entry;
1591eed250aSJake Burkholder 	int rela_entry;
1609c6f9240SPeter Wemm 
1611eed250aSJake Burkholder 	rel_off = rela_off = 0;
1621eed250aSJake Burkholder 	rel_sz = rela_sz = 0;
1631eed250aSJake Burkholder 	rel_entry = rela_entry = 0;
1649c6f9240SPeter Wemm 	for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
1659c6f9240SPeter Wemm 		switch (dp->d_tag) {
1669c6f9240SPeter Wemm 		case DT_HASH:
1679c6f9240SPeter Wemm 			error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
1689c6f9240SPeter Wemm 			    sizeof(hashhdr),  hashhdr);
1699c6f9240SPeter Wemm 			if (error) {
1709c6f9240SPeter Wemm 				warnx("can't read hash header (%lx)",
1719c6f9240SPeter Wemm 				    ef_get_offset(ef, dp->d_un.d_ptr));
1729c6f9240SPeter Wemm 				return error;
1739c6f9240SPeter Wemm 			}
1749c6f9240SPeter Wemm 			ef->ef_nbuckets = hashhdr[0];
1759c6f9240SPeter Wemm 			ef->ef_nchains = hashhdr[1];
1769c6f9240SPeter Wemm 			error = ef_read_entry(ef, -1,
177f23aa297SPeter Wemm 			    (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
1789c6f9240SPeter Wemm 			    (void**)&ef->ef_hashtab);
1799c6f9240SPeter Wemm 			if (error) {
1809c6f9240SPeter Wemm 				warnx("can't read hash table");
1819c6f9240SPeter Wemm 				return error;
1829c6f9240SPeter Wemm 			}
1839c6f9240SPeter Wemm 			ef->ef_buckets = ef->ef_hashtab;
1849c6f9240SPeter Wemm 			ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
1859c6f9240SPeter Wemm 			break;
1869c6f9240SPeter Wemm 		case DT_STRTAB:
1879c6f9240SPeter Wemm 			ef->ef_stroff = dp->d_un.d_ptr;
1889c6f9240SPeter Wemm 			break;
1899c6f9240SPeter Wemm 		case DT_STRSZ:
1909c6f9240SPeter Wemm 			ef->ef_strsz = dp->d_un.d_val;
1919c6f9240SPeter Wemm 			break;
1929c6f9240SPeter Wemm 		case DT_SYMTAB:
1939c6f9240SPeter Wemm 			ef->ef_symoff = dp->d_un.d_ptr;
1949c6f9240SPeter Wemm 			break;
1959c6f9240SPeter Wemm 		case DT_SYMENT:
1969c6f9240SPeter Wemm 			if (dp->d_un.d_val != sizeof(Elf_Sym))
1979c6f9240SPeter Wemm 				return EFTYPE;
1989c6f9240SPeter Wemm 			break;
1991eed250aSJake Burkholder 		case DT_REL:
2001eed250aSJake Burkholder 			if (rel_off != 0)
2011eed250aSJake Burkholder 				warnx("second DT_REL entry ignored");
2021eed250aSJake Burkholder 			rel_off = dp->d_un.d_ptr;
2031eed250aSJake Burkholder 			break;
2041eed250aSJake Burkholder 		case DT_RELSZ:
2051eed250aSJake Burkholder 			if (rel_sz != 0)
2061eed250aSJake Burkholder 				warnx("second DT_RELSZ entry ignored");
2071eed250aSJake Burkholder 			rel_sz = dp->d_un.d_val;
2081eed250aSJake Burkholder 			break;
2091eed250aSJake Burkholder 		case DT_RELENT:
2101eed250aSJake Burkholder 			if (rel_entry != 0)
2111eed250aSJake Burkholder 				warnx("second DT_RELENT entry ignored");
2121eed250aSJake Burkholder 			rel_entry = dp->d_un.d_val;
2131eed250aSJake Burkholder 			break;
2141eed250aSJake Burkholder 		case DT_RELA:
2151eed250aSJake Burkholder 			if (rela_off != 0)
2161eed250aSJake Burkholder 				warnx("second DT_RELA entry ignored");
2171eed250aSJake Burkholder 			rela_off = dp->d_un.d_ptr;
2181eed250aSJake Burkholder 			break;
2191eed250aSJake Burkholder 		case DT_RELASZ:
2201eed250aSJake Burkholder 			if (rela_sz != 0)
2211eed250aSJake Burkholder 				warnx("second DT_RELASZ entry ignored");
2221eed250aSJake Burkholder 			rela_sz = dp->d_un.d_val;
2231eed250aSJake Burkholder 			break;
2241eed250aSJake Burkholder 		case DT_RELAENT:
2251eed250aSJake Burkholder 			if (rela_entry != 0)
2261eed250aSJake Burkholder 				warnx("second DT_RELAENT entry ignored");
2271eed250aSJake Burkholder 			rela_entry = dp->d_un.d_val;
2281eed250aSJake Burkholder 			break;
2299c6f9240SPeter Wemm 		}
2309c6f9240SPeter Wemm 	}
2319c6f9240SPeter Wemm 	if (ef->ef_symoff == 0) {
2329c6f9240SPeter Wemm 		warnx("%s: no .dynsym section found\n", ef->ef_name);
2339c6f9240SPeter Wemm 		return EFTYPE;
2349c6f9240SPeter Wemm 	}
2359c6f9240SPeter Wemm 	if (ef->ef_stroff == 0) {
2369c6f9240SPeter Wemm 		warnx("%s: no .dynstr section found\n", ef->ef_name);
2379c6f9240SPeter Wemm 		return EFTYPE;
2389c6f9240SPeter Wemm 	}
2399c6f9240SPeter Wemm 	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
2409c6f9240SPeter Wemm 	    ef->ef_nchains * sizeof(Elf_Sym),
2419c6f9240SPeter Wemm 		(void**)&ef->ef_symtab) != 0) {
2429c6f9240SPeter Wemm 		if (ef->ef_verbose)
2439c6f9240SPeter Wemm 			warnx("%s: can't load .dynsym section (0x%lx)",
2449c6f9240SPeter Wemm 			    ef->ef_name, (long)ef->ef_symoff);
2459c6f9240SPeter Wemm 		return EIO;
2469c6f9240SPeter Wemm 	}
2479c6f9240SPeter Wemm 	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
2489c6f9240SPeter Wemm 		(void**)&ef->ef_strtab) != 0) {
2499c6f9240SPeter Wemm 		warnx("can't load .dynstr section");
2509c6f9240SPeter Wemm 		return EIO;
2519c6f9240SPeter Wemm 	}
2521eed250aSJake Burkholder 	if (rel_off != 0) {
2531eed250aSJake Burkholder 		if (rel_entry == 0) {
2541eed250aSJake Burkholder 			warnx("%s: no DT_RELENT for DT_REL", ef->ef_name);
2551eed250aSJake Burkholder 			return (EFTYPE);
2561eed250aSJake Burkholder 		}
2571eed250aSJake Burkholder 		if (rel_entry != sizeof(Elf_Rel)) {
2581eed250aSJake Burkholder 			warnx("%s: inconsistent DT_RELENT value",
2591eed250aSJake Burkholder 			    ef->ef_name);
2601eed250aSJake Burkholder 			return (EFTYPE);
2611eed250aSJake Burkholder 		}
2621eed250aSJake Burkholder 		if (rel_sz % rel_entry != 0) {
2631eed250aSJake Burkholder 			warnx("%s: inconsistent values for DT_RELSZ and "
2641eed250aSJake Burkholder 			    "DT_RELENT", ef->ef_name);
2651eed250aSJake Burkholder 			return (EFTYPE);
2661eed250aSJake Burkholder 		}
2671eed250aSJake Burkholder 		if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz,
2681eed250aSJake Burkholder 		    (void **)&ef->ef_rel) != 0) {
2691eed250aSJake Burkholder 			warnx("%s: cannot load DT_REL section", ef->ef_name);
2701eed250aSJake Burkholder 			return (EIO);
2711eed250aSJake Burkholder 		}
2721eed250aSJake Burkholder 		ef->ef_relsz = rel_sz / rel_entry;
2731eed250aSJake Burkholder 		if (ef->ef_verbose)
2741eed250aSJake Burkholder 			warnx("%s: %d REL entries", ef->ef_name,
2751eed250aSJake Burkholder 			    ef->ef_relsz);
2761eed250aSJake Burkholder 	}
2771eed250aSJake Burkholder 	if (rela_off != 0) {
2781eed250aSJake Burkholder 		if (rela_entry == 0) {
2791eed250aSJake Burkholder 			warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name);
2801eed250aSJake Burkholder 			return (EFTYPE);
2811eed250aSJake Burkholder 		}
2821eed250aSJake Burkholder 		if (rela_entry != sizeof(Elf_Rela)) {
2831eed250aSJake Burkholder 			warnx("%s: inconsistent DT_RELAENT value",
2841eed250aSJake Burkholder 			    ef->ef_name);
2851eed250aSJake Burkholder 			return (EFTYPE);
2861eed250aSJake Burkholder 		}
2871eed250aSJake Burkholder 		if (rela_sz % rela_entry != 0) {
2881eed250aSJake Burkholder 			warnx("%s: inconsistent values for DT_RELASZ and "
2891eed250aSJake Burkholder 			    "DT_RELAENT", ef->ef_name);
2901eed250aSJake Burkholder 			return (EFTYPE);
2911eed250aSJake Burkholder 		}
2921eed250aSJake Burkholder 		if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz,
2931eed250aSJake Burkholder 		    (void **)&ef->ef_rela) != 0) {
2941eed250aSJake Burkholder 			warnx("%s: cannot load DT_RELA section", ef->ef_name);
2951eed250aSJake Burkholder 			return (EIO);
2961eed250aSJake Burkholder 		}
2971eed250aSJake Burkholder 		ef->ef_relasz = rela_sz / rela_entry;
2981eed250aSJake Burkholder 		if (ef->ef_verbose)
2991eed250aSJake Burkholder 			warnx("%s: %d RELA entries", ef->ef_name,
3001eed250aSJake Burkholder 			    ef->ef_relasz);
3011eed250aSJake Burkholder 	}
3029c6f9240SPeter Wemm 	return 0;
3039c6f9240SPeter Wemm }
3049c6f9240SPeter Wemm 
3059c6f9240SPeter Wemm int
3069c6f9240SPeter Wemm ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
3079c6f9240SPeter Wemm {
30887e5cd7cSMike Heffner 	ssize_t r;
3099c6f9240SPeter Wemm 
31087e5cd7cSMike Heffner 	if (offset != (Elf_Off)-1) {
3119c6f9240SPeter Wemm 		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
3129c6f9240SPeter Wemm 			return EIO;
3139c6f9240SPeter Wemm 	}
31487e5cd7cSMike Heffner 
31587e5cd7cSMike Heffner 	r = read(ef->ef_fd, dest, len);
31687e5cd7cSMike Heffner 	if (r != -1 && (size_t)r == len)
31787e5cd7cSMike Heffner 		return 0;
31887e5cd7cSMike Heffner 	else
31987e5cd7cSMike Heffner 		return EIO;
3209c6f9240SPeter Wemm }
3219c6f9240SPeter Wemm 
3229c6f9240SPeter Wemm int
3239c6f9240SPeter Wemm ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
3249c6f9240SPeter Wemm {
3259c6f9240SPeter Wemm 	int error;
3269c6f9240SPeter Wemm 
3279c6f9240SPeter Wemm 	*ptr = malloc(len);
3289c6f9240SPeter Wemm 	if (*ptr == NULL)
3299c6f9240SPeter Wemm 		return ENOMEM;
3309c6f9240SPeter Wemm 	error = ef_read(ef, offset, len, *ptr);
3319c6f9240SPeter Wemm 	if (error)
3329c6f9240SPeter Wemm 		free(*ptr);
3339c6f9240SPeter Wemm 	return error;
3349c6f9240SPeter Wemm }
3359c6f9240SPeter Wemm 
3369c6f9240SPeter Wemm int
3379c6f9240SPeter Wemm ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
3389c6f9240SPeter Wemm {
3399c6f9240SPeter Wemm 	u_long ofs = ef_get_offset(ef, offset);
3409c6f9240SPeter Wemm 
3419c6f9240SPeter Wemm 	if (ofs == 0) {
3429c6f9240SPeter Wemm 		if (ef->ef_verbose)
3439c6f9240SPeter Wemm 			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
3449c6f9240SPeter Wemm 			    ef->ef_name, (long)offset, ofs);
3459c6f9240SPeter Wemm 		return EFAULT;
3469c6f9240SPeter Wemm 	}
3479c6f9240SPeter Wemm 	return ef_read(ef, ofs, len, dest);
3489c6f9240SPeter Wemm }
3499c6f9240SPeter Wemm 
3509c6f9240SPeter Wemm int
3511eed250aSJake Burkholder ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
3521eed250aSJake Burkholder {
3531eed250aSJake Burkholder 	u_long ofs = ef_get_offset(ef, offset);
3541eed250aSJake Burkholder 	int error;
3551eed250aSJake Burkholder 
3561eed250aSJake Burkholder 	if (ofs == 0) {
3571eed250aSJake Burkholder 		if (ef->ef_verbose)
3581eed250aSJake Burkholder 			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
3591eed250aSJake Burkholder 			    ef->ef_name, (long)offset, ofs);
3601eed250aSJake Burkholder 		return EFAULT;
3611eed250aSJake Burkholder 	}
3621eed250aSJake Burkholder 	if ((error = ef_read(ef, ofs, len, dest)) != 0)
3631eed250aSJake Burkholder 		return (error);
3641eed250aSJake Burkholder 	return (ef_reloc(ef, offset, len, dest));
3651eed250aSJake Burkholder }
3661eed250aSJake Burkholder 
3671eed250aSJake Burkholder int
3689c6f9240SPeter Wemm ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
3699c6f9240SPeter Wemm {
3709c6f9240SPeter Wemm 	int error;
3719c6f9240SPeter Wemm 
3729c6f9240SPeter Wemm 	*ptr = malloc(len);
3739c6f9240SPeter Wemm 	if (*ptr == NULL)
3749c6f9240SPeter Wemm 		return ENOMEM;
3759c6f9240SPeter Wemm 	error = ef_seg_read(ef, offset, len, *ptr);
3769c6f9240SPeter Wemm 	if (error)
3779c6f9240SPeter Wemm 		free(*ptr);
3789c6f9240SPeter Wemm 	return error;
3799c6f9240SPeter Wemm }
3809c6f9240SPeter Wemm 
3819c6f9240SPeter Wemm int
3821eed250aSJake Burkholder ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
3831eed250aSJake Burkholder {
3841eed250aSJake Burkholder 	int error;
3851eed250aSJake Burkholder 
3861eed250aSJake Burkholder 	*ptr = malloc(len);
3871eed250aSJake Burkholder 	if (*ptr == NULL)
3881eed250aSJake Burkholder 		return ENOMEM;
3891eed250aSJake Burkholder 	error = ef_seg_read_rel(ef, offset, len, *ptr);
3901eed250aSJake Burkholder 	if (error)
3911eed250aSJake Burkholder 		free(*ptr);
3921eed250aSJake Burkholder 	return error;
3931eed250aSJake Burkholder }
3941eed250aSJake Burkholder 
3951eed250aSJake Burkholder int
3969c6f9240SPeter Wemm ef_open(const char *filename, elf_file_t ef, int verbose)
3979c6f9240SPeter Wemm {
3989c6f9240SPeter Wemm 	Elf_Ehdr *hdr;
3999c6f9240SPeter Wemm 	int fd;
4009c6f9240SPeter Wemm 	int error;
4019c6f9240SPeter Wemm 	int phlen, res;
4029c6f9240SPeter Wemm 	int nsegs;
4039c6f9240SPeter Wemm 	Elf_Phdr *phdr, *phdyn, *phphdr, *phlimit;
4049c6f9240SPeter Wemm 
4059c6f9240SPeter Wemm 	bzero(ef, sizeof(*ef));
4069c6f9240SPeter Wemm 	if (filename == NULL)
4079c6f9240SPeter Wemm 		return EFTYPE;
4089c6f9240SPeter Wemm 	ef->ef_verbose = verbose;
4099c6f9240SPeter Wemm 	if ((fd = open(filename, O_RDONLY)) == -1)
4109c6f9240SPeter Wemm 		return errno;
4119c6f9240SPeter Wemm 	ef->ef_fd = fd;
4129c6f9240SPeter Wemm 	ef->ef_name = strdup(filename);
4139c6f9240SPeter Wemm 	hdr = (Elf_Ehdr *)&ef->ef_hdr;
4149c6f9240SPeter Wemm 	do {
4159c6f9240SPeter Wemm 		res = read(fd, hdr, sizeof(*hdr));
4169c6f9240SPeter Wemm 		error = EFTYPE;
4179c6f9240SPeter Wemm 		if (res != sizeof(*hdr))
4189c6f9240SPeter Wemm 			break;
4199c6f9240SPeter Wemm 		if (!IS_ELF(*hdr))
4209c6f9240SPeter Wemm 			break;
4219c6f9240SPeter Wemm 		if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
4229c6f9240SPeter Wemm 		    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
4239c6f9240SPeter Wemm 		    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
4249c6f9240SPeter Wemm 		    hdr->e_version != EV_CURRENT ||
4259c6f9240SPeter Wemm 		    hdr->e_machine != ELF_TARG_MACH ||
4269c6f9240SPeter Wemm 		    hdr->e_phentsize != sizeof(Elf_Phdr))
4279c6f9240SPeter Wemm 			break;
4289c6f9240SPeter Wemm 		phlen = hdr->e_phnum * sizeof(Elf_Phdr);
4299c6f9240SPeter Wemm 		if (ef_read_entry(ef, hdr->e_phoff, phlen,
4309c6f9240SPeter Wemm 		    (void**)&ef->ef_ph) != 0)
4319c6f9240SPeter Wemm 			break;
4329c6f9240SPeter Wemm 		phdr = ef->ef_ph;
4339c6f9240SPeter Wemm 		phlimit = phdr + hdr->e_phnum;
4349c6f9240SPeter Wemm 		nsegs = 0;
4359c6f9240SPeter Wemm 		phdyn = NULL;
4369c6f9240SPeter Wemm 		phphdr = NULL;
4379c6f9240SPeter Wemm 		while (phdr < phlimit) {
4389c6f9240SPeter Wemm 			if (verbose > 1)
4399c6f9240SPeter Wemm 				ef_print_phdr(phdr);
4409c6f9240SPeter Wemm 			switch (phdr->p_type) {
4419c6f9240SPeter Wemm 			case PT_LOAD:
4429c6f9240SPeter Wemm 				if (nsegs == 2) {
4439c6f9240SPeter Wemm 					warnx("%s: too many sections",
4449c6f9240SPeter Wemm 					    filename);
4459c6f9240SPeter Wemm 					break;
4469c6f9240SPeter Wemm 				}
4479c6f9240SPeter Wemm 				ef->ef_segs[nsegs++] = phdr;
4489c6f9240SPeter Wemm 				break;
4499c6f9240SPeter Wemm 			case PT_PHDR:
4509c6f9240SPeter Wemm 				phphdr = phdr;
4519c6f9240SPeter Wemm 				break;
4529c6f9240SPeter Wemm 			case PT_DYNAMIC:
4539c6f9240SPeter Wemm 				phdyn = phdr;
4549c6f9240SPeter Wemm 				break;
4559c6f9240SPeter Wemm 			}
4569c6f9240SPeter Wemm 			phdr++;
4579c6f9240SPeter Wemm 		}
4589c6f9240SPeter Wemm 		if (verbose > 1)
4599c6f9240SPeter Wemm 			printf("\n");
4609c6f9240SPeter Wemm 		ef->ef_nsegs = nsegs;
4619c6f9240SPeter Wemm 		if (phdyn == NULL) {
4629c6f9240SPeter Wemm 			warnx("file isn't dynamically-linked");
4639c6f9240SPeter Wemm 			break;
4649c6f9240SPeter Wemm 		}
4659c6f9240SPeter Wemm 		if (ef_read_entry(ef, phdyn->p_offset,
4669c6f9240SPeter Wemm 			phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) {
4679c6f9240SPeter Wemm 			printf("ef_read_entry failed\n");
4689c6f9240SPeter Wemm 			break;
4699c6f9240SPeter Wemm 		}
4709c6f9240SPeter Wemm 		error = ef_parse_dynamic(ef);
4719c6f9240SPeter Wemm 		if (error)
4729c6f9240SPeter Wemm 			break;
4739c6f9240SPeter Wemm 		if (hdr->e_type == ET_DYN) {
4749c6f9240SPeter Wemm 			ef->ef_type = EFT_KLD;
4759c6f9240SPeter Wemm /*			pad = (u_int)dest & PAGE_MASK;
4769c6f9240SPeter Wemm 			if (pad)
4779c6f9240SPeter Wemm 				dest += PAGE_SIZE - pad;*/
4789c6f9240SPeter Wemm 			error = 0;
4799c6f9240SPeter Wemm 		} else if (hdr->e_type == ET_EXEC) {
4809c6f9240SPeter Wemm /*			dest = hdr->e_entry;
4819c6f9240SPeter Wemm 			if (dest == 0)
4829c6f9240SPeter Wemm 				break;*/
4839c6f9240SPeter Wemm 			ef->ef_type = EFT_KERNEL;
4849c6f9240SPeter Wemm 			error = 0;
4859c6f9240SPeter Wemm 		} else
4869c6f9240SPeter Wemm 			break;
4879c6f9240SPeter Wemm 	} while(0);
4889c6f9240SPeter Wemm 	if (error) {
4899c6f9240SPeter Wemm 		ef_close(ef);
4909c6f9240SPeter Wemm 		if (ef->ef_verbose)
4919c6f9240SPeter Wemm 			warnc(error, "elf_open(%s)", filename);
4929c6f9240SPeter Wemm 	}
4939c6f9240SPeter Wemm 	return error;
4949c6f9240SPeter Wemm }
4959c6f9240SPeter Wemm 
4969c6f9240SPeter Wemm int
4979c6f9240SPeter Wemm ef_close(elf_file_t ef)
4989c6f9240SPeter Wemm {
4999c6f9240SPeter Wemm 	close(ef->ef_fd);
5009c6f9240SPeter Wemm /*	if (ef->ef_fpage)
5019c6f9240SPeter Wemm 		free(ef->ef_fpage);*/
5029c6f9240SPeter Wemm 	if (ef->ef_name)
5039c6f9240SPeter Wemm 		free(ef->ef_name);
5049c6f9240SPeter Wemm 	return 0;
5059c6f9240SPeter Wemm }
506