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