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: stable/9/usr.sbin/kldxref/ef.c 252043 2013-06-20 21:19:47Z delphij $
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 struct ef_file {
51 	char*		ef_name;
52 	struct elf_file *ef_efile;
53 	Elf_Phdr *	ef_ph;
54 	int		ef_fd;
55 	int		ef_type;
56 	Elf_Ehdr	ef_hdr;
57 	void*		ef_fpage;		/* First block of the file */
58 	int		ef_fplen;		/* length of first block */
59 	Elf_Dyn*	ef_dyn;			/* Symbol table etc. */
60 	Elf_Hashelt	ef_nbuckets;
61 	Elf_Hashelt	ef_nchains;
62 	Elf_Hashelt*	ef_buckets;
63 	Elf_Hashelt*	ef_chains;
64 	Elf_Hashelt*	ef_hashtab;
65 	Elf_Off		ef_stroff;
66 	caddr_t		ef_strtab;
67 	int		ef_strsz;
68 	Elf_Off		ef_symoff;
69 	Elf_Sym*	ef_symtab;
70 	int		ef_nsegs;
71 	Elf_Phdr *	ef_segs[2];
72 	int		ef_verbose;
73 	Elf_Rel *	ef_rel;			/* relocation table */
74 	int		ef_relsz;		/* number of entries */
75 	Elf_Rela *	ef_rela;		/* relocation table */
76 	int		ef_relasz;		/* number of entries */
77 };
78 
79 static void ef_print_phdr(Elf_Phdr *);
80 static u_long ef_get_offset(elf_file_t, Elf_Off);
81 static int ef_parse_dynamic(elf_file_t);
82 
83 static int ef_get_type(elf_file_t ef);
84 static int ef_close(elf_file_t ef);
85 static int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
86 static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
87 static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
88 static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
89     void *dest);
90 static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
91     void **ptr);
92 static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
93     void **ptr);
94 static Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx);
95 static int ef_lookup_set(elf_file_t ef, const char *name, long *startp,
96     long *stopp, long *countp);
97 static int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
98 
99 static struct elf_file_ops ef_file_ops = {
100 	ef_get_type,
101 	ef_close,
102 	ef_read,
103 	ef_read_entry,
104 	ef_seg_read,
105 	ef_seg_read_rel,
106 	ef_seg_read_entry,
107 	ef_seg_read_entry_rel,
108 	ef_symaddr,
109 	ef_lookup_set,
110 	ef_lookup_symbol
111 };
112 
113 static void
ef_print_phdr(Elf_Phdr * phdr)114 ef_print_phdr(Elf_Phdr *phdr)
115 {
116 
117 	if ((phdr->p_flags & PF_W) == 0) {
118 		printf("text=0x%lx ", (long)phdr->p_filesz);
119 	} else {
120 		printf("data=0x%lx", (long)phdr->p_filesz);
121 		if (phdr->p_filesz < phdr->p_memsz)
122 			printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz));
123 		printf(" ");
124 	}
125 }
126 
127 static u_long
ef_get_offset(elf_file_t ef,Elf_Off off)128 ef_get_offset(elf_file_t ef, Elf_Off off)
129 {
130 	Elf_Phdr *ph;
131 	int i;
132 
133 	for (i = 0; i < ef->ef_nsegs; i++) {
134 		ph = ef->ef_segs[i];
135 		if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) {
136 			return ph->p_offset + (off - ph->p_vaddr);
137 		}
138 	}
139 	return 0;
140 }
141 
142 static int
ef_get_type(elf_file_t ef)143 ef_get_type(elf_file_t ef)
144 {
145 
146 	return (ef->ef_type);
147 }
148 
149 /*
150  * next three functions copied from link_elf.c
151  */
152 static unsigned long
elf_hash(const char * name)153 elf_hash(const char *name)
154 {
155 	const unsigned char *p = (const unsigned char *) name;
156 	unsigned long h = 0;
157 	unsigned long g;
158 
159 	while (*p != '\0') {
160 		h = (h << 4) + *p++;
161 		if ((g = h & 0xf0000000) != 0)
162 			h ^= g >> 24;
163 		h &= ~g;
164 	}
165 	return h;
166 }
167 
168 static int
ef_lookup_symbol(elf_file_t ef,const char * name,Elf_Sym ** sym)169 ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
170 {
171 	unsigned long symnum;
172 	Elf_Sym* symp;
173 	char *strp;
174 	unsigned long hash;
175 
176 	/* First, search hashed global symbols */
177 	hash = elf_hash(name);
178 	symnum = ef->ef_buckets[hash % ef->ef_nbuckets];
179 
180 	while (symnum != STN_UNDEF) {
181 		if (symnum >= ef->ef_nchains) {
182 			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
183 			    ef->ef_name);
184 			return ENOENT;
185 		}
186 
187 		symp = ef->ef_symtab + symnum;
188 		if (symp->st_name == 0) {
189 			warnx("ef_lookup_symbol: file %s have corrupted symbol table\n",
190 			    ef->ef_name);
191 			return ENOENT;
192 		}
193 
194 		strp = ef->ef_strtab + symp->st_name;
195 
196 		if (strcmp(name, strp) == 0) {
197 			if (symp->st_shndx != SHN_UNDEF ||
198 			    (symp->st_value != 0 &&
199 				ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
200 				*sym = symp;
201 				return 0;
202 			} else
203 				return ENOENT;
204 		}
205 
206 		symnum = ef->ef_chains[symnum];
207 	}
208 
209 	return ENOENT;
210 }
211 
212 static int
ef_lookup_set(elf_file_t ef,const char * name,long * startp,long * stopp,long * countp)213 ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
214     long *countp)
215 {
216 	Elf_Sym *sym;
217 	char *setsym;
218 	int error, len;
219 
220 	len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
221 	setsym = malloc(len);
222 	if (setsym == NULL)
223 		return (ENOMEM);
224 
225 	/* get address of first entry */
226 	snprintf(setsym, len, "%s%s", "__start_set_", name);
227 	error = ef_lookup_symbol(ef, setsym, &sym);
228 	if (error)
229 		goto out;
230 	*startp = sym->st_value;
231 
232 	/* get address of last entry */
233 	snprintf(setsym, len, "%s%s", "__stop_set_", name);
234 	error = ef_lookup_symbol(ef, setsym, &sym);
235 	if (error)
236 		goto out;
237 	*stopp = sym->st_value;
238 
239 	/* and the number of entries */
240 	*countp = (*stopp - *startp) / sizeof(void *);
241 
242 out:
243 	free(setsym);
244 	return (error);
245 }
246 
247 static Elf_Addr
ef_symaddr(elf_file_t ef,Elf_Size symidx)248 ef_symaddr(elf_file_t ef, Elf_Size symidx)
249 {
250 	const Elf_Sym *sym;
251 
252 	if (symidx >= ef->ef_nchains)
253 		return (0);
254 	sym = ef->ef_symtab + symidx;
255 
256 	if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
257 	    sym->st_shndx != SHN_UNDEF && sym->st_value != 0)
258 		return (sym->st_value);
259 	return (0);
260 }
261 
262 static int
ef_parse_dynamic(elf_file_t ef)263 ef_parse_dynamic(elf_file_t ef)
264 {
265 	Elf_Dyn *dp;
266 	Elf_Hashelt hashhdr[2];
267 /*	int plttype = DT_REL;*/
268 	int error;
269 	Elf_Off rel_off;
270 	Elf_Off rela_off;
271 	int rel_sz;
272 	int rela_sz;
273 	int rel_entry;
274 	int rela_entry;
275 
276 	rel_off = rela_off = 0;
277 	rel_sz = rela_sz = 0;
278 	rel_entry = rela_entry = 0;
279 	for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) {
280 		switch (dp->d_tag) {
281 		case DT_HASH:
282 			error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr),
283 			    sizeof(hashhdr),  hashhdr);
284 			if (error) {
285 				warnx("can't read hash header (%lx)",
286 				    ef_get_offset(ef, dp->d_un.d_ptr));
287 				return error;
288 			}
289 			ef->ef_nbuckets = hashhdr[0];
290 			ef->ef_nchains = hashhdr[1];
291 			error = ef_read_entry(ef, -1,
292 			    (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt),
293 			    (void**)&ef->ef_hashtab);
294 			if (error) {
295 				warnx("can't read hash table");
296 				return error;
297 			}
298 			ef->ef_buckets = ef->ef_hashtab;
299 			ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets;
300 			break;
301 		case DT_STRTAB:
302 			ef->ef_stroff = dp->d_un.d_ptr;
303 			break;
304 		case DT_STRSZ:
305 			ef->ef_strsz = dp->d_un.d_val;
306 			break;
307 		case DT_SYMTAB:
308 			ef->ef_symoff = dp->d_un.d_ptr;
309 			break;
310 		case DT_SYMENT:
311 			if (dp->d_un.d_val != sizeof(Elf_Sym))
312 				return EFTYPE;
313 			break;
314 		case DT_REL:
315 			if (rel_off != 0)
316 				warnx("second DT_REL entry ignored");
317 			rel_off = dp->d_un.d_ptr;
318 			break;
319 		case DT_RELSZ:
320 			if (rel_sz != 0)
321 				warnx("second DT_RELSZ entry ignored");
322 			rel_sz = dp->d_un.d_val;
323 			break;
324 		case DT_RELENT:
325 			if (rel_entry != 0)
326 				warnx("second DT_RELENT entry ignored");
327 			rel_entry = dp->d_un.d_val;
328 			break;
329 		case DT_RELA:
330 			if (rela_off != 0)
331 				warnx("second DT_RELA entry ignored");
332 			rela_off = dp->d_un.d_ptr;
333 			break;
334 		case DT_RELASZ:
335 			if (rela_sz != 0)
336 				warnx("second DT_RELASZ entry ignored");
337 			rela_sz = dp->d_un.d_val;
338 			break;
339 		case DT_RELAENT:
340 			if (rela_entry != 0)
341 				warnx("second DT_RELAENT entry ignored");
342 			rela_entry = dp->d_un.d_val;
343 			break;
344 		}
345 	}
346 	if (ef->ef_symoff == 0) {
347 		warnx("%s: no .dynsym section found\n", ef->ef_name);
348 		return EFTYPE;
349 	}
350 	if (ef->ef_stroff == 0) {
351 		warnx("%s: no .dynstr section found\n", ef->ef_name);
352 		return EFTYPE;
353 	}
354 	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff),
355 	    ef->ef_nchains * sizeof(Elf_Sym),
356 		(void**)&ef->ef_symtab) != 0) {
357 		if (ef->ef_verbose)
358 			warnx("%s: can't load .dynsym section (0x%lx)",
359 			    ef->ef_name, (long)ef->ef_symoff);
360 		return EIO;
361 	}
362 	if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz,
363 		(void**)&ef->ef_strtab) != 0) {
364 		warnx("can't load .dynstr section");
365 		return EIO;
366 	}
367 	if (rel_off != 0) {
368 		if (rel_entry == 0) {
369 			warnx("%s: no DT_RELENT for DT_REL", ef->ef_name);
370 			return (EFTYPE);
371 		}
372 		if (rel_entry != sizeof(Elf_Rel)) {
373 			warnx("%s: inconsistent DT_RELENT value",
374 			    ef->ef_name);
375 			return (EFTYPE);
376 		}
377 		if (rel_sz % rel_entry != 0) {
378 			warnx("%s: inconsistent values for DT_RELSZ and "
379 			    "DT_RELENT", ef->ef_name);
380 			return (EFTYPE);
381 		}
382 		if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz,
383 		    (void **)&ef->ef_rel) != 0) {
384 			warnx("%s: cannot load DT_REL section", ef->ef_name);
385 			return (EIO);
386 		}
387 		ef->ef_relsz = rel_sz / rel_entry;
388 		if (ef->ef_verbose)
389 			warnx("%s: %d REL entries", ef->ef_name,
390 			    ef->ef_relsz);
391 	}
392 	if (rela_off != 0) {
393 		if (rela_entry == 0) {
394 			warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name);
395 			return (EFTYPE);
396 		}
397 		if (rela_entry != sizeof(Elf_Rela)) {
398 			warnx("%s: inconsistent DT_RELAENT value",
399 			    ef->ef_name);
400 			return (EFTYPE);
401 		}
402 		if (rela_sz % rela_entry != 0) {
403 			warnx("%s: inconsistent values for DT_RELASZ and "
404 			    "DT_RELAENT", ef->ef_name);
405 			return (EFTYPE);
406 		}
407 		if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz,
408 		    (void **)&ef->ef_rela) != 0) {
409 			warnx("%s: cannot load DT_RELA section", ef->ef_name);
410 			return (EIO);
411 		}
412 		ef->ef_relasz = rela_sz / rela_entry;
413 		if (ef->ef_verbose)
414 			warnx("%s: %d RELA entries", ef->ef_name,
415 			    ef->ef_relasz);
416 	}
417 	return 0;
418 }
419 
420 static int
ef_read(elf_file_t ef,Elf_Off offset,size_t len,void * dest)421 ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
422 {
423 	ssize_t r;
424 
425 	if (offset != (Elf_Off)-1) {
426 		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
427 			return EIO;
428 	}
429 
430 	r = read(ef->ef_fd, dest, len);
431 	if (r != -1 && (size_t)r == len)
432 		return 0;
433 	else
434 		return EIO;
435 }
436 
437 static int
ef_read_entry(elf_file_t ef,Elf_Off offset,size_t len,void ** ptr)438 ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
439 {
440 	int error;
441 
442 	*ptr = malloc(len);
443 	if (*ptr == NULL)
444 		return ENOMEM;
445 	error = ef_read(ef, offset, len, *ptr);
446 	if (error)
447 		free(*ptr);
448 	return error;
449 }
450 
451 static int
ef_seg_read(elf_file_t ef,Elf_Off offset,size_t len,void * dest)452 ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
453 {
454 	u_long ofs = ef_get_offset(ef, offset);
455 
456 	if (ofs == 0) {
457 		if (ef->ef_verbose)
458 			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
459 			    ef->ef_name, (long)offset, ofs);
460 		return EFAULT;
461 	}
462 	return ef_read(ef, ofs, len, dest);
463 }
464 
465 static int
ef_seg_read_rel(elf_file_t ef,Elf_Off offset,size_t len,void * dest)466 ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
467 {
468 	u_long ofs = ef_get_offset(ef, offset);
469 	const Elf_Rela *a;
470 	const Elf_Rel *r;
471 	int error;
472 
473 	if (ofs == 0) {
474 		if (ef->ef_verbose)
475 			warnx("ef_seg_read(%s): zero offset (%lx:%ld)",
476 			    ef->ef_name, (long)offset, ofs);
477 		return EFAULT;
478 	}
479 	if ((error = ef_read(ef, ofs, len, dest)) != 0)
480 		return (error);
481 
482 	for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) {
483 		error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len,
484 		    dest);
485 		if (error != 0)
486 			return (error);
487 	}
488 	for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) {
489 		error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len,
490 		    dest);
491 		if (error != 0)
492 			return (error);
493 	}
494 	return (0);
495 }
496 
497 static int
ef_seg_read_entry(elf_file_t ef,Elf_Off offset,size_t len,void ** ptr)498 ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
499 {
500 	int error;
501 
502 	*ptr = malloc(len);
503 	if (*ptr == NULL)
504 		return ENOMEM;
505 	error = ef_seg_read(ef, offset, len, *ptr);
506 	if (error)
507 		free(*ptr);
508 	return error;
509 }
510 
511 static int
ef_seg_read_entry_rel(elf_file_t ef,Elf_Off offset,size_t len,void ** ptr)512 ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
513 {
514 	int error;
515 
516 	*ptr = malloc(len);
517 	if (*ptr == NULL)
518 		return ENOMEM;
519 	error = ef_seg_read_rel(ef, offset, len, *ptr);
520 	if (error)
521 		free(*ptr);
522 	return error;
523 }
524 
525 int
ef_open(const char * filename,struct elf_file * efile,int verbose)526 ef_open(const char *filename, struct elf_file *efile, int verbose)
527 {
528 	elf_file_t ef;
529 	Elf_Ehdr *hdr;
530 	int fd;
531 	int error;
532 	int phlen, res;
533 	int nsegs;
534 	Elf_Phdr *phdr, *phdyn, *phlimit;
535 
536 	if (filename == NULL)
537 		return EFTYPE;
538 	if ((fd = open(filename, O_RDONLY)) == -1)
539 		return errno;
540 
541 	ef = malloc(sizeof(*ef));
542 	if (ef == NULL) {
543 		close(fd);
544 		return (ENOMEM);
545 	}
546 
547 	efile->ef_ef = ef;
548 	efile->ef_ops = &ef_file_ops;
549 
550 	bzero(ef, sizeof(*ef));
551 	ef->ef_verbose = verbose;
552 	ef->ef_fd = fd;
553 	ef->ef_name = strdup(filename);
554 	ef->ef_efile = efile;
555 	hdr = (Elf_Ehdr *)&ef->ef_hdr;
556 	do {
557 		res = read(fd, hdr, sizeof(*hdr));
558 		error = EFTYPE;
559 		if (res != sizeof(*hdr))
560 			break;
561 		if (!IS_ELF(*hdr))
562 			break;
563 		if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
564 		    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
565 		    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
566 		    hdr->e_version != EV_CURRENT ||
567 		    hdr->e_machine != ELF_TARG_MACH ||
568 		    hdr->e_phentsize != sizeof(Elf_Phdr))
569 			break;
570 		phlen = hdr->e_phnum * sizeof(Elf_Phdr);
571 		if (ef_read_entry(ef, hdr->e_phoff, phlen,
572 		    (void**)&ef->ef_ph) != 0)
573 			break;
574 		phdr = ef->ef_ph;
575 		phlimit = phdr + hdr->e_phnum;
576 		nsegs = 0;
577 		phdyn = NULL;
578 		while (phdr < phlimit) {
579 			if (verbose > 1)
580 				ef_print_phdr(phdr);
581 			switch (phdr->p_type) {
582 			case PT_LOAD:
583 				if (nsegs == 2) {
584 					warnx("%s: too many sections",
585 					    filename);
586 					break;
587 				}
588 				ef->ef_segs[nsegs++] = phdr;
589 				break;
590 			case PT_PHDR:
591 				break;
592 			case PT_DYNAMIC:
593 				phdyn = phdr;
594 				break;
595 			}
596 			phdr++;
597 		}
598 		if (verbose > 1)
599 			printf("\n");
600 		ef->ef_nsegs = nsegs;
601 		if (phdyn == NULL) {
602 			warnx("file isn't dynamically-linked");
603 			break;
604 		}
605 		if (ef_read_entry(ef, phdyn->p_offset,
606 			phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) {
607 			printf("ef_read_entry failed\n");
608 			break;
609 		}
610 		error = ef_parse_dynamic(ef);
611 		if (error)
612 			break;
613 		if (hdr->e_type == ET_DYN) {
614 			ef->ef_type = EFT_KLD;
615 /*			pad = (u_int)dest & PAGE_MASK;
616 			if (pad)
617 				dest += PAGE_SIZE - pad;*/
618 			error = 0;
619 		} else if (hdr->e_type == ET_EXEC) {
620 /*			dest = hdr->e_entry;
621 			if (dest == 0)
622 				break;*/
623 			ef->ef_type = EFT_KERNEL;
624 			error = 0;
625 		} else
626 			break;
627 	} while(0);
628 	if (error)
629 		ef_close(ef);
630 	return error;
631 }
632 
633 static int
ef_close(elf_file_t ef)634 ef_close(elf_file_t ef)
635 {
636 	close(ef->ef_fd);
637 /*	if (ef->ef_fpage)
638 		free(ef->ef_fpage);*/
639 	if (ef->ef_name)
640 		free(ef->ef_name);
641 	ef->ef_efile->ef_ops = NULL;
642 	ef->ef_efile->ef_ef = NULL;
643 	free(ef);
644 	return 0;
645 }
646