xref: /freebsd/usr.sbin/kldxref/ef.c (revision 7cc42f6d)
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2000, Boris Popov
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by Boris Popov.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD$
35  */
36 
37 #include <sys/param.h>
38 #include <sys/linker.h>
39 
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <machine/elf.h>
48 #define FREEBSD_ELF
49 
50 #include "ef.h"
51 
52 #define	MAXSEGS 16
53 struct ef_file {
54 	char		*ef_name;
55 	struct elf_file *ef_efile;
56 	Elf_Phdr	*ef_ph;
57 	int		ef_fd;
58 	int		ef_type;
59 	Elf_Ehdr	ef_hdr;
60 	void		*ef_fpage;		/* First block of the file */
61 	int		ef_fplen;		/* length of first block */
62 	Elf_Dyn		*ef_dyn;		/* Symbol table etc. */
63 	Elf_Hashelt	ef_nbuckets;
64 	Elf_Hashelt	ef_nchains;
65 	Elf_Hashelt	*ef_buckets;
66 	Elf_Hashelt	*ef_chains;
67 	Elf_Hashelt	*ef_hashtab;
68 	Elf_Off		ef_stroff;
69 	caddr_t		ef_strtab;
70 	int		ef_strsz;
71 	Elf_Off		ef_symoff;
72 	Elf_Sym		*ef_symtab;
73 	int		ef_nsegs;
74 	Elf_Phdr	*ef_segs[MAXSEGS];
75 	int		ef_verbose;
76 	Elf_Rel		*ef_rel;		/* relocation table */
77 	int		ef_relsz;		/* number of entries */
78 	Elf_Rela	*ef_rela;		/* relocation table */
79 	int		ef_relasz;		/* number of entries */
80 };
81 
82 static void	ef_print_phdr(Elf_Phdr *);
83 static Elf_Off	ef_get_offset(elf_file_t, Elf_Off);
84 static int	ef_parse_dynamic(elf_file_t);
85 
86 static int	ef_get_type(elf_file_t ef);
87 static int	ef_close(elf_file_t ef);
88 static int	ef_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
89 static int	ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
90 		    void **ptr);
91 
92 static int	ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len,
93 		    void *dest);
94 static int	ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
95 		    void *dest);
96 static int	ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len,
97 		    char *dest);
98 static int	ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
99 		    void **ptr);
100 static int	ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
101 		    void **ptr);
102 
103 static Elf_Addr	ef_symaddr(elf_file_t ef, Elf_Size symidx);
104 static int	ef_lookup_set(elf_file_t ef, const char *name, long *startp,
105 		    long *stopp, long *countp);
106 static int	ef_lookup_symbol(elf_file_t ef, const char *name,
107 		    Elf_Sym **sym);
108 
109 static struct elf_file_ops ef_file_ops = {
110 	.get_type		= ef_get_type,
111 	.close			= ef_close,
112 	.read			= ef_read,
113 	.read_entry		= ef_read_entry,
114 	.seg_read		= ef_seg_read,
115 	.seg_read_rel		= ef_seg_read_rel,
116 	.seg_read_string	= ef_seg_read_string,
117 	.seg_read_entry		= ef_seg_read_entry,
118 	.seg_read_entry_rel	= ef_seg_read_entry_rel,
119 	.symaddr		= ef_symaddr,
120 	.lookup_set		= ef_lookup_set,
121 	.lookup_symbol		= ef_lookup_symbol
122 };
123 
124 static void
125 ef_print_phdr(Elf_Phdr *phdr)
126 {
127 
128 	if ((phdr->p_flags & PF_W) == 0) {
129 		printf("text=0x%jx ", (uintmax_t)phdr->p_filesz);
130 	} else {
131 		printf("data=0x%jx", (uintmax_t)phdr->p_filesz);
132 		if (phdr->p_filesz < phdr->p_memsz)
133 			printf("+0x%jx",
134 			    (uintmax_t)(phdr->p_memsz - phdr->p_filesz));
135 		printf(" ");
136 	}
137 }
138 
139 static Elf_Off
140 ef_get_offset(elf_file_t ef, Elf_Off off)
141 {
142 	Elf_Phdr *ph;
143 	int i;
144 
145 	for (i = 0; i < ef->ef_nsegs; i++) {
146 		ph = ef->ef_segs[i];
147 		if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
148 			return (ph->p_offset + (off - ph->p_vaddr));
149 		}
150 	}
151 	return (0);
152 }
153 
154 static int
155 ef_get_type(elf_file_t ef)
156 {
157 
158 	return (ef->ef_type);
159 }
160 
161 /*
162  * next three functions copied from link_elf.c
163  */
164 static unsigned long
165 elf_hash(const char *name)
166 {
167 	unsigned long h, g;
168 	const unsigned char *p;
169 
170 	h = 0;
171 	p = (const unsigned char *)name;
172 	while (*p != '\0') {
173 		h = (h << 4) + *p++;
174 		if ((g = h & 0xf0000000) != 0)
175 			h ^= g >> 24;
176 		h &= ~g;
177 	}
178 	return (h);
179 }
180 
181 static int
182 ef_lookup_symbol(elf_file_t ef, const char *name, Elf_Sym **sym)
183 {
184 	unsigned long hash, symnum;
185 	Elf_Sym *symp;
186 	char *strp;
187 
188 	/* First, search hashed global symbols */
189 	hash = elf_hash(name);
190 	symnum = ef->ef_buckets[hash % ef->ef_nbuckets];
191 
192 	while (symnum != STN_UNDEF) {
193 		if (symnum >= ef->ef_nchains) {
194 			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
195 			    ef->ef_name);
196 			return (ENOENT);
197 		}
198 
199 		symp = ef->ef_symtab + symnum;
200 		if (symp->st_name == 0) {
201 			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
202 			    ef->ef_name);
203 			return (ENOENT);
204 		}
205 
206 		strp = ef->ef_strtab + symp->st_name;
207 
208 		if (strcmp(name, strp) == 0) {
209 			if (symp->st_shndx != SHN_UNDEF ||
210 			    (symp->st_value != 0 &&
211 				ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
212 				*sym = symp;
213 				return (0);
214 			} else
215 				return (ENOENT);
216 		}
217 
218 		symnum = ef->ef_chains[symnum];
219 	}
220 
221 	return (ENOENT);
222 }
223 
224 static int
225 ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
226     long *countp)
227 {
228 	Elf_Sym *sym;
229 	char *setsym;
230 	int error, len;
231 
232 	len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
233 	setsym = malloc(len);
234 	if (setsym == NULL)
235 		return (errno);
236 
237 	/* get address of first entry */
238 	snprintf(setsym, len, "%s%s", "__start_set_", name);
239 	error = ef_lookup_symbol(ef, setsym, &sym);
240 	if (error != 0)
241 		goto out;
242 	*startp = sym->st_value;
243 
244 	/* get address of last entry */
245 	snprintf(setsym, len, "%s%s", "__stop_set_", name);
246 	error = ef_lookup_symbol(ef, setsym, &sym);
247 	if (error != 0)
248 		goto out;
249 	*stopp = sym->st_value;
250 
251 	/* and the number of entries */
252 	*countp = (*stopp - *startp) / sizeof(void *);
253 
254 out:
255 	free(setsym);
256 	return (error);
257 }
258 
259 static Elf_Addr
260 ef_symaddr(elf_file_t ef, Elf_Size symidx)
261 {
262 	const Elf_Sym *sym;
263 
264 	if (symidx >= ef->ef_nchains)
265 		return (0);
266 	sym = ef->ef_symtab + symidx;
267 
268 	if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
269 	    sym->st_shndx != SHN_UNDEF && sym->st_value != 0)
270 		return (sym->st_value);
271 	return (0);
272 }
273 
274 static int
275 ef_parse_dynamic(elf_file_t ef)
276 {
277 	Elf_Dyn *dp;
278 	Elf_Hashelt hashhdr[2];
279 	int error;
280 	Elf_Off rel_off;
281 	Elf_Off rela_off;
282 	int rel_sz;
283 	int rela_sz;
284 	int rel_entry;
285 	int rela_entry;
286 
287 	rel_off = rela_off = 0;
288 	rel_sz = rela_sz = 0;
289 	rel_entry = rela_entry = 0;
290 	for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
291 		switch (dp->d_tag) {
292 		case DT_HASH:
293 			error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
294 			    sizeof(hashhdr),  hashhdr);
295 			if (error != 0) {
296 				warnx("can't read hash header (%jx)",
297 				  (uintmax_t)ef_get_offset(ef, dp->d_un.d_ptr));
298 				return (error);
299 			}
300 			ef->ef_nbuckets = hashhdr[0];
301 			ef->ef_nchains = hashhdr[1];
302 			error = ef_read_entry(ef, -1,
303 			    (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
304 			    (void **)&ef->ef_hashtab);
305 			if (error != 0) {
306 				warnx("can't read hash table");
307 				return (error);
308 			}
309 			ef->ef_buckets = ef->ef_hashtab;
310 			ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
311 			break;
312 		case DT_STRTAB:
313 			ef->ef_stroff = dp->d_un.d_ptr;
314 			break;
315 		case DT_STRSZ:
316 			ef->ef_strsz = dp->d_un.d_val;
317 			break;
318 		case DT_SYMTAB:
319 			ef->ef_symoff = dp->d_un.d_ptr;
320 			break;
321 		case DT_SYMENT:
322 			if (dp->d_un.d_val != sizeof(Elf_Sym))
323 				return (EFTYPE);
324 			break;
325 		case DT_REL:
326 			if (rel_off != 0)
327 				warnx("second DT_REL entry ignored");
328 			rel_off = dp->d_un.d_ptr;
329 			break;
330 		case DT_RELSZ:
331 			if (rel_sz != 0)
332 				warnx("second DT_RELSZ entry ignored");
333 			rel_sz = dp->d_un.d_val;
334 			break;
335 		case DT_RELENT:
336 			if (rel_entry != 0)
337 				warnx("second DT_RELENT entry ignored");
338 			rel_entry = dp->d_un.d_val;
339 			break;
340 		case DT_RELA:
341 			if (rela_off != 0)
342 				warnx("second DT_RELA entry ignored");
343 			rela_off = dp->d_un.d_ptr;
344 			break;
345 		case DT_RELASZ:
346 			if (rela_sz != 0)
347 				warnx("second DT_RELASZ entry ignored");
348 			rela_sz = dp->d_un.d_val;
349 			break;
350 		case DT_RELAENT:
351 			if (rela_entry != 0)
352 				warnx("second DT_RELAENT entry ignored");
353 			rela_entry = dp->d_un.d_val;
354 			break;
355 		}
356 	}
357 	if (ef->ef_symoff == 0) {
358 		warnx("%s: no .dynsym section found\n", ef->ef_name);
359 		return (EFTYPE);
360 	}
361 	if (ef->ef_stroff == 0) {
362 		warnx("%s: no .dynstr section found\n", ef->ef_name);
363 		return (EFTYPE);
364 	}
365 	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
366 	    ef->ef_nchains * sizeof(Elf_Sym),
367 		(void **)&ef->ef_symtab) != 0) {
368 		if (ef->ef_verbose)
369 			warnx("%s: can't load .dynsym section (0x%jx)",
370 			    ef->ef_name, (uintmax_t)ef->ef_symoff);
371 		return (EIO);
372 	}
373 	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
374 		(void **)&ef->ef_strtab) != 0) {
375 		warnx("can't load .dynstr section");
376 		return (EIO);
377 	}
378 	if (rel_off != 0) {
379 		if (rel_entry == 0) {
380 			warnx("%s: no DT_RELENT for DT_REL", ef->ef_name);
381 			return (EFTYPE);
382 		}
383 		if (rel_entry != sizeof(Elf_Rel)) {
384 			warnx("%s: inconsistent DT_RELENT value",
385 			    ef->ef_name);
386 			return (EFTYPE);
387 		}
388 		if (rel_sz % rel_entry != 0) {
389 			warnx("%s: inconsistent values for DT_RELSZ and "
390 			    "DT_RELENT", ef->ef_name);
391 			return (EFTYPE);
392 		}
393 		if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz,
394 		    (void **)&ef->ef_rel) != 0) {
395 			warnx("%s: cannot load DT_REL section", ef->ef_name);
396 			return (EIO);
397 		}
398 		ef->ef_relsz = rel_sz / rel_entry;
399 		if (ef->ef_verbose)
400 			warnx("%s: %d REL entries", ef->ef_name,
401 			    ef->ef_relsz);
402 	}
403 	if (rela_off != 0) {
404 		if (rela_entry == 0) {
405 			warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name);
406 			return (EFTYPE);
407 		}
408 		if (rela_entry != sizeof(Elf_Rela)) {
409 			warnx("%s: inconsistent DT_RELAENT value",
410 			    ef->ef_name);
411 			return (EFTYPE);
412 		}
413 		if (rela_sz % rela_entry != 0) {
414 			warnx("%s: inconsistent values for DT_RELASZ and "
415 			    "DT_RELAENT", ef->ef_name);
416 			return (EFTYPE);
417 		}
418 		if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz,
419 		    (void **)&ef->ef_rela) != 0) {
420 			warnx("%s: cannot load DT_RELA section", ef->ef_name);
421 			return (EIO);
422 		}
423 		ef->ef_relasz = rela_sz / rela_entry;
424 		if (ef->ef_verbose)
425 			warnx("%s: %d RELA entries", ef->ef_name,
426 			    ef->ef_relasz);
427 	}
428 	return (0);
429 }
430 
431 static int
432 ef_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
433 {
434 	ssize_t r;
435 
436 	if (offset != (Elf_Off)-1) {
437 		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
438 			return (EIO);
439 	}
440 
441 	r = read(ef->ef_fd, dest, len);
442 	if (r != -1 && (size_t)r == len)
443 		return (0);
444 	else
445 		return (EIO);
446 }
447 
448 static int
449 ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
450 {
451 	int error;
452 
453 	*ptr = malloc(len);
454 	if (*ptr == NULL)
455 		return (errno);
456 	error = ef_read(ef, offset, len, *ptr);
457 	if (error != 0)
458 		free(*ptr);
459 	return (error);
460 }
461 
462 static int
463 ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
464 {
465 	Elf_Off ofs;
466 
467 	ofs = ef_get_offset(ef, offset);
468 	if (ofs == 0) {
469 		if (ef->ef_verbose)
470 			warnx("ef_seg_read(%s): zero offset (%jx:%ju)",
471 			    ef->ef_name, (uintmax_t)offset, (uintmax_t)ofs);
472 		return (EFAULT);
473 	}
474 	return (ef_read(ef, ofs, len, dest));
475 }
476 
477 static int
478 ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
479 {
480 	Elf_Off ofs;
481 	const Elf_Rela *a;
482 	const Elf_Rel *r;
483 	int error;
484 
485 	ofs = ef_get_offset(ef, offset);
486 	if (ofs == 0) {
487 		if (ef->ef_verbose)
488 			warnx("ef_seg_read_rel(%s): zero offset (%jx:%ju)",
489 			    ef->ef_name, (uintmax_t)offset, (uintmax_t)ofs);
490 		return (EFAULT);
491 	}
492 	if ((error = ef_read(ef, ofs, len, dest)) != 0)
493 		return (error);
494 
495 	for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
496 		error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len,
497 		    dest);
498 		if (error != 0)
499 			return (error);
500 	}
501 	for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
502 		error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len,
503 		    dest);
504 		if (error != 0)
505 			return (error);
506 	}
507 	return (0);
508 }
509 
510 static int
511 ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest)
512 {
513 	Elf_Off ofs;
514 	ssize_t r;
515 
516 	ofs = ef_get_offset(ef, offset);
517 	if (ofs == 0 || ofs == (Elf_Off)-1) {
518 		if (ef->ef_verbose)
519 			warnx("ef_seg_read_string(%s): bad offset (%jx:%ju)",
520 			    ef->ef_name, (uintmax_t)offset, (uintmax_t)ofs);
521 		return (EFAULT);
522 	}
523 
524 	r = pread(ef->ef_fd, dest, len, ofs);
525 	if (r < 0)
526 		return (errno);
527 	if (strnlen(dest, len) == len)
528 		return (EFAULT);
529 
530 	return (0);
531 }
532 
533 static int
534 ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
535 {
536 	int error;
537 
538 	*ptr = malloc(len);
539 	if (*ptr == NULL)
540 		return (errno);
541 	error = ef_seg_read(ef, offset, len, *ptr);
542 	if (error != 0)
543 		free(*ptr);
544 	return (error);
545 }
546 
547 static int
548 ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
549 {
550 	int error;
551 
552 	*ptr = malloc(len);
553 	if (*ptr == NULL)
554 		return (errno);
555 	error = ef_seg_read_rel(ef, offset, len, *ptr);
556 	if (error != 0)
557 		free(*ptr);
558 	return (error);
559 }
560 
561 int
562 ef_open(const char *filename, struct elf_file *efile, int verbose)
563 {
564 	elf_file_t ef;
565 	Elf_Ehdr *hdr;
566 	int fd;
567 	int error;
568 	int phlen, res;
569 	int nsegs;
570 	Elf_Phdr *phdr, *phdyn, *phlimit;
571 
572 	if (filename == NULL)
573 		return (EINVAL);
574 	if ((fd = open(filename, O_RDONLY)) == -1)
575 		return (errno);
576 
577 	ef = malloc(sizeof(*ef));
578 	if (ef == NULL) {
579 		close(fd);
580 		return (errno);
581 	}
582 
583 	efile->ef_ef = ef;
584 	efile->ef_ops = &ef_file_ops;
585 
586 	bzero(ef, sizeof(*ef));
587 	ef->ef_verbose = verbose;
588 	ef->ef_fd = fd;
589 	ef->ef_name = strdup(filename);
590 	ef->ef_efile = efile;
591 	hdr = (Elf_Ehdr *)&ef->ef_hdr;
592 	do {
593 		res = read(fd, hdr, sizeof(*hdr));
594 		error = EFTYPE;
595 		if (res != sizeof(*hdr))
596 			break;
597 		if (!IS_ELF(*hdr))
598 			break;
599 		if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
600 		    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
601 		    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
602 		    hdr->e_version != EV_CURRENT ||
603 		    hdr->e_machine != ELF_TARG_MACH ||
604 		    hdr->e_phentsize != sizeof(Elf_Phdr))
605 			break;
606 		phlen = hdr->e_phnum * sizeof(Elf_Phdr);
607 		if (ef_read_entry(ef, hdr->e_phoff, phlen,
608 		    (void **)&ef->ef_ph) != 0)
609 			break;
610 		phdr = ef->ef_ph;
611 		phlimit = phdr + hdr->e_phnum;
612 		nsegs = 0;
613 		phdyn = NULL;
614 		while (phdr < phlimit) {
615 			if (verbose > 1)
616 				ef_print_phdr(phdr);
617 			switch (phdr->p_type) {
618 			case PT_LOAD:
619 				if (nsegs < MAXSEGS)
620 					ef->ef_segs[nsegs] = phdr;
621 				nsegs++;
622 				break;
623 			case PT_PHDR:
624 				break;
625 			case PT_DYNAMIC:
626 				phdyn = phdr;
627 				break;
628 			}
629 			phdr++;
630 		}
631 		if (verbose > 1)
632 			printf("\n");
633 		if (phdyn == NULL) {
634 			warnx("Skipping %s: not dynamically-linked",
635 			    filename);
636 			break;
637 		} else if (nsegs > MAXSEGS) {
638 			warnx("%s: too many segments", filename);
639 			break;
640 		}
641 		ef->ef_nsegs = nsegs;
642 		if (ef_read_entry(ef, phdyn->p_offset,
643 			phdyn->p_filesz, (void **)&ef->ef_dyn) != 0) {
644 			printf("ef_read_entry failed\n");
645 			break;
646 		}
647 		error = ef_parse_dynamic(ef);
648 		if (error != 0)
649 			break;
650 		if (hdr->e_type == ET_DYN) {
651 			ef->ef_type = EFT_KLD;
652 			error = 0;
653 		} else if (hdr->e_type == ET_EXEC) {
654 			ef->ef_type = EFT_KERNEL;
655 			error = 0;
656 		} else
657 			break;
658 	} while(0);
659 	if (error != 0)
660 		ef_close(ef);
661 	return (error);
662 }
663 
664 static int
665 ef_close(elf_file_t ef)
666 {
667 
668 	close(ef->ef_fd);
669 	if (ef->ef_name)
670 		free(ef->ef_name);
671 	ef->ef_efile->ef_ops = NULL;
672 	ef->ef_efile->ef_ef = NULL;
673 	free(ef);
674 	return (0);
675 }
676