]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/kldxref/ef.c
Merge branch 'releng/11.3' into releng-CDN/11.3
[FreeBSD/FreeBSD.git] / usr.sbin / kldxref / ef.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }