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