load_elf.c revision 78465
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/boot/common/load_elf.c 78465 2001-06-19 07:41:07Z peter $
28 */
29
30#include <sys/param.h>
31#include <sys/exec.h>
32#include <sys/reboot.h>
33#include <sys/linker.h>
34#include <sys/module.h>
35#include <string.h>
36#include <machine/bootinfo.h>
37#include <machine/elf.h>
38#include <stand.h>
39#define FREEBSD_ELF
40#include <link.h>
41
42#include "bootstrap.h"
43
44#define COPYOUT(s,d,l)	archsw.arch_copyout((vm_offset_t)(s), d, l)
45
46
47typedef struct elf_file {
48    Elf_Phdr 	*ph;
49    Elf_Ehdr	*ehdr;
50    Elf_Sym	*symtab;
51    Elf_Off	*hashtab;
52    Elf_Off	nbuckets;
53    Elf_Off	nchains;
54    Elf_Off*	buckets;
55    Elf_Off*	chains;
56    char	*strtab;
57    size_t	strsz;
58    int		fd;
59    caddr_t	firstpage;
60    size_t	firstlen;
61    int		kernel;
62    vm_offset_t	off;
63} *elf_file_t;
64
65static int elf_loadimage(struct preloaded_file *mp, elf_file_t ef, vm_offset_t loadaddr);
66static int elf_lookup_symbol(struct preloaded_file *mp, elf_file_t ef, const char* name,	Elf_Sym* sym);
67static int elf_parse_modmetadata(struct preloaded_file *mp, elf_file_t ef);
68static char	*fake_modname(const char *name);
69
70const char	*elf_kerneltype = "elf kernel";
71const char	*elf_moduletype = "elf module";
72
73/*
74 * Attempt to load the file (file) as an ELF module.  It will be stored at
75 * (dest), and a pointer to a module structure describing the loaded object
76 * will be saved in (result).
77 */
78int
79elf_loadfile(char *filename, vm_offset_t dest, struct preloaded_file **result)
80{
81    struct preloaded_file	*fp, *kfp;
82    struct elf_file		ef;
83    Elf_Ehdr 			*ehdr;
84    int				err;
85    u_int			pad;
86    char			*s;
87    ssize_t			bytes_read;
88
89    fp = NULL;
90    bzero(&ef, sizeof(struct elf_file));
91
92    /*
93     * Open the image, read and validate the ELF header
94     */
95    if (filename == NULL)	/* can't handle nameless */
96	return(EFTYPE);
97    if ((ef.fd = open(filename, O_RDONLY)) == -1)
98	return(errno);
99    ef.firstpage = malloc(PAGE_SIZE);
100    if (ef.firstpage == NULL) {
101	close(ef.fd);
102	return(ENOMEM);
103    }
104    bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE);
105    ef.firstlen = (size_t)bytes_read;
106    if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) {
107	err = EFTYPE;		/* could be EIO, but may be small file */
108	goto oerr;
109    }
110    ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage;
111
112    /* Is it ELF? */
113    if (!IS_ELF(*ehdr)) {
114	err = EFTYPE;
115	goto oerr;
116    }
117    if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||	/* Layout ? */
118	ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
119	ehdr->e_ident[EI_VERSION] != EV_CURRENT ||	/* Version ? */
120	ehdr->e_version != EV_CURRENT ||
121	ehdr->e_machine != ELF_TARG_MACH) {		/* Machine ? */
122	err = EFTYPE;
123	goto oerr;
124    }
125
126
127    /*
128     * Check to see what sort of module we are.
129     */
130    kfp = file_findfile(NULL, NULL);
131    if (ehdr->e_type == ET_DYN) {
132	/* Looks like a kld module */
133	if (kfp == NULL) {
134	    printf("elf_loadfile: can't load module before kernel\n");
135	    err = EPERM;
136	    goto oerr;
137	}
138	if (strcmp(elf_kerneltype, kfp->f_type)) {
139	    printf("elf_loadfile: can't load module with kernel type '%s'\n", kfp->f_type);
140	    err = EPERM;
141	    goto oerr;
142	}
143	/* Looks OK, got ahead */
144	ef.kernel = 0;
145
146	/* Page-align the load address */
147	pad = (u_int)dest & PAGE_MASK;
148	if (pad != 0) {
149	    pad = PAGE_SIZE - pad;
150	    dest += pad;
151	}
152    } else if (ehdr->e_type == ET_EXEC) {
153	/* Looks like a kernel */
154	if (kfp != NULL) {
155	    printf("elf_loadfile: kernel already loaded\n");
156	    err = EPERM;
157	    goto oerr;
158	}
159	/*
160	 * Calculate destination address based on kernel entrypoint
161	 */
162	dest = (vm_offset_t) ehdr->e_entry;
163	if (dest == 0) {
164	    printf("elf_loadfile: not a kernel (maybe static binary?)\n");
165	    err = EPERM;
166	    goto oerr;
167	}
168	ef.kernel = 1;
169
170    } else {
171	err = EFTYPE;
172	goto oerr;
173    }
174
175    /*
176     * Ok, we think we should handle this.
177     */
178    fp = file_alloc();
179    if (fp == NULL) {
180	    printf("elf_loadfile: cannot allocate module info\n");
181	    err = EPERM;
182	    goto out;
183    }
184    if (ef.kernel)
185	setenv("kernelname", filename, 1);
186    s = strrchr(filename, '/');
187    if (s)
188	fp->f_name = strdup(s + 1);
189    else
190	fp->f_name = strdup(filename);
191    fp->f_type = strdup(ef.kernel ? elf_kerneltype : elf_moduletype);
192
193#ifdef ELF_VERBOSE
194    if (ef.kernel)
195	printf("%s entry at %p\n", filename, (void *) dest);
196#else
197    printf("%s ", filename);
198#endif
199
200    fp->f_size = elf_loadimage(fp, &ef, dest);
201    if (fp->f_size == 0 || fp->f_addr == 0)
202	goto ioerr;
203
204    /* save exec header as metadata */
205    file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);
206
207    /* Load OK, return module pointer */
208    *result = (struct preloaded_file *)fp;
209    err = 0;
210    goto out;
211
212 ioerr:
213    err = EIO;
214 oerr:
215    file_discard(fp);
216 out:
217    if (ef.firstpage)
218	free(ef.firstpage);
219    close(ef.fd);
220    return(err);
221}
222
223/*
224 * With the file (fd) open on the image, and (ehdr) containing
225 * the Elf header, load the image at (off)
226 */
227static int
228elf_loadimage(struct preloaded_file *fp, elf_file_t ef, vm_offset_t off)
229{
230    int 	i;
231    u_int	j;
232    Elf_Ehdr	*ehdr;
233    Elf_Phdr	*phdr, *php;
234    Elf_Shdr	*shdr;
235    int		ret;
236    vm_offset_t firstaddr;
237    vm_offset_t lastaddr;
238    void	*buf;
239    size_t	resid, chunk;
240    ssize_t	result;
241    vm_offset_t	dest;
242    vm_offset_t	ssym, esym;
243    Elf_Dyn	*dp;
244    int		ndp;
245    char	*s;
246    int		symstrindex;
247    int		symtabindex;
248    long	size;
249    u_int	fpcopy;
250
251    dp = NULL;
252    shdr = NULL;
253    ret = 0;
254    firstaddr = lastaddr = 0;
255    ehdr = ef->ehdr;
256    if (ef->kernel) {
257#ifdef __i386__
258	off = - (off & 0xff000000u);	/* i386 relocates after locore */
259#else
260	off = 0;		/* alpha is direct mapped for kernels */
261#endif
262    }
263    ef->off = off;
264
265    if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
266	printf("elf_loadimage: program header not within first page\n");
267	goto out;
268    }
269    phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);
270
271    for (i = 0; i < ehdr->e_phnum; i++) {
272	/* We want to load PT_LOAD segments only.. */
273	if (phdr[i].p_type != PT_LOAD)
274	    continue;
275
276#ifdef ELF_VERBOSE
277	printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
278	    (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
279	    (long)(phdr[i].p_vaddr + off),
280	    (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
281#else
282	if ((phdr[i].p_flags & PF_W) == 0) {
283	    printf("text=0x%lx ", (long)phdr[i].p_filesz);
284	} else {
285	    printf("data=0x%lx", (long)phdr[i].p_filesz);
286	    if (phdr[i].p_filesz < phdr[i].p_memsz)
287		printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
288	    printf(" ");
289	}
290#endif
291	fpcopy = 0;
292	if (ef->firstlen > phdr[i].p_offset) {
293	    fpcopy = ef->firstlen - phdr[i].p_offset;
294	    archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
295			       phdr[i].p_vaddr + off, fpcopy);
296	}
297	if (phdr[i].p_filesz > fpcopy) {
298	    if (lseek(ef->fd, (off_t)(phdr[i].p_offset + fpcopy),
299		      SEEK_SET) == -1) {
300		printf("\nelf_loadexec: cannot seek\n");
301		goto out;
302	    }
303	    if (archsw.arch_readin(ef->fd, phdr[i].p_vaddr + off + fpcopy,
304		phdr[i].p_filesz - fpcopy) != (ssize_t)(phdr[i].p_filesz - fpcopy)) {
305		printf("\nelf_loadexec: archsw.readin failed\n");
306		goto out;
307	    }
308	}
309	/* clear space from oversized segments; eg: bss */
310	if (phdr[i].p_filesz < phdr[i].p_memsz) {
311#ifdef ELF_VERBOSE
312	    printf(" (bss: 0x%lx-0x%lx)",
313		(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
314		(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
315#endif
316
317	    /* no archsw.arch_bzero */
318	    buf = malloc(PAGE_SIZE);
319	    if (buf == NULL) {
320		printf("\nelf_loadimage: malloc() failed\n");
321		goto out;
322	    }
323	    bzero(buf, PAGE_SIZE);
324	    resid = phdr[i].p_memsz - phdr[i].p_filesz;
325	    dest = phdr[i].p_vaddr + off + phdr[i].p_filesz;
326	    while (resid > 0) {
327		chunk = min(PAGE_SIZE, resid);
328		archsw.arch_copyin(buf, dest, chunk);
329		resid -= chunk;
330		dest += chunk;
331	    }
332	    free(buf);
333	}
334#ifdef ELF_VERBOSE
335	printf("\n");
336#endif
337
338	if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
339	    firstaddr = phdr[i].p_vaddr + off;
340	if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
341	    lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
342    }
343    lastaddr = roundup(lastaddr, sizeof(long));
344
345    /*
346     * Now grab the symbol tables.  This isn't easy if we're reading a
347     * .gz file.  I think the rule is going to have to be that you must
348     * strip a file to remove symbols before gzipping it so that we do not
349     * try to lseek() on it.
350     */
351    chunk = ehdr->e_shnum * ehdr->e_shentsize;
352    if (chunk == 0 || ehdr->e_shoff == 0)
353	goto nosyms;
354    shdr = malloc(chunk);
355    if (shdr == NULL)
356	goto nosyms;
357    if (lseek(ef->fd, (off_t)ehdr->e_shoff, SEEK_SET) == -1) {
358	printf("\nelf_loadimage: cannot lseek() to section headers");
359	goto nosyms;
360    }
361    result = read(ef->fd, shdr, chunk);
362    if (result < 0 || (size_t)result != chunk) {
363	printf("\nelf_loadimage: read section headers failed");
364	goto nosyms;
365    }
366    symtabindex = -1;
367    symstrindex = -1;
368    for (i = 0; i < ehdr->e_shnum; i++) {
369	if (shdr[i].sh_type != SHT_SYMTAB)
370	    continue;
371	for (j = 0; j < ehdr->e_phnum; j++) {
372	    if (phdr[j].p_type != PT_LOAD)
373		continue;
374	    if (shdr[i].sh_offset >= phdr[j].p_offset &&
375		(shdr[i].sh_offset + shdr[i].sh_size <=
376		 phdr[j].p_offset + phdr[j].p_filesz)) {
377		shdr[i].sh_offset = 0;
378		shdr[i].sh_size = 0;
379		break;
380	    }
381	}
382	if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
383	    continue;		/* alread loaded in a PT_LOAD above */
384	/* Save it for loading below */
385	symtabindex = i;
386	symstrindex = shdr[i].sh_link;
387    }
388    if (symtabindex < 0 || symstrindex < 0)
389	goto nosyms;
390
391    /* Ok, committed to a load. */
392#ifndef ELF_VERBOSE
393    printf("syms=[");
394#endif
395    ssym = lastaddr;
396    for (i = symtabindex; i >= 0; i = symstrindex) {
397#ifdef ELF_VERBOSE
398	char	*secname;
399
400	switch(shdr[i].sh_type) {
401	    case SHT_SYMTAB:		/* Symbol table */
402		secname = "symtab";
403		break;
404	    case SHT_STRTAB:		/* String table */
405		secname = "strtab";
406		break;
407	    default:
408		secname = "WHOA!!";
409		break;
410	}
411#endif
412
413	size = shdr[i].sh_size;
414	archsw.arch_copyin(&size, lastaddr, sizeof(size));
415	lastaddr += sizeof(long);
416
417#ifdef ELF_VERBOSE
418	printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname,
419	    shdr[i].sh_size, shdr[i].sh_offset,
420	    lastaddr, lastaddr + shdr[i].sh_size);
421#else
422	if (i == symstrindex)
423	    printf("+");
424	printf("0x%lx+0x%lx", (long)sizeof(size), size);
425#endif
426
427	if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
428	    printf("\nelf_loadimage: could not seek for symbols - skipped!");
429	    lastaddr = ssym;
430	    ssym = 0;
431	    goto nosyms;
432	}
433	result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
434	if (result < 0 || (size_t)result != shdr[i].sh_size) {
435	    printf("\nelf_loadimage: could not read symbols - skipped!");
436	    lastaddr = ssym;
437	    ssym = 0;
438	    goto nosyms;
439	}
440	/* Reset offsets relative to ssym */
441	lastaddr += shdr[i].sh_size;
442	lastaddr = roundup(lastaddr, sizeof(long));
443	if (i == symtabindex)
444	    symtabindex = -1;
445	else if (i == symstrindex)
446	    symstrindex = -1;
447    }
448    esym = lastaddr;
449#ifndef ELF_VERBOSE
450    printf("]");
451#endif
452
453    file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
454    file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);
455
456nosyms:
457    printf("\n");
458
459    ret = lastaddr - firstaddr;
460    fp->f_addr = firstaddr;
461
462    php = NULL;
463    for (i = 0; i < ehdr->e_phnum; i++) {
464	if (phdr[i].p_type == PT_DYNAMIC) {
465	    php = phdr + i;
466	    dp = (Elf_Dyn *)(php->p_vaddr);
467	    file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(dp), &dp);
468	    dp = NULL;
469	    break;
470	}
471    }
472
473    if (php == NULL)	/* this is bad, we cannot get to symbols or _DYNAMIC */
474	goto out;
475
476    ndp = php->p_filesz / sizeof(Elf_Dyn);
477    if (ndp == 0)
478	goto out;
479    dp = malloc(php->p_filesz);
480    if (dp == NULL)
481	goto out;
482    archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);
483
484    ef->strsz = 0;
485    for (i = 0; i < ndp; i++) {
486	if (dp[i].d_tag == NULL)
487	    break;
488	switch (dp[i].d_tag) {
489	case DT_HASH:
490	    ef->hashtab = (Elf_Off*)(dp[i].d_un.d_ptr + off);
491	    break;
492	case DT_STRTAB:
493	    ef->strtab = (char *)(dp[i].d_un.d_ptr + off);
494	    break;
495	case DT_STRSZ:
496	    ef->strsz = dp[i].d_un.d_val;
497	    break;
498	case DT_SYMTAB:
499	    ef->symtab = (Elf_Sym*)(dp[i].d_un.d_ptr + off);
500	    break;
501	default:
502	    break;
503	}
504    }
505    if (ef->hashtab == NULL || ef->symtab == NULL ||
506	ef->strtab == NULL || ef->strsz == 0)
507	goto out;
508    COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
509    COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
510    ef->buckets = ef->hashtab + 2;
511    ef->chains = ef->buckets + ef->nbuckets;
512    if (elf_parse_modmetadata(fp, ef) == 0)
513	goto out;
514
515    if (ef->kernel)			/* kernel must not depend on anything */
516	goto out;
517
518    for (i = 0; i < ndp; i++) {
519        if (dp[i].d_tag == NULL)
520	    break;
521	if (dp[i].d_tag != DT_NEEDED)
522	    continue;
523	j = dp[i].d_un.d_ptr;
524	if (j < 1 || j > ef->strsz - 2)
525	    continue;
526	s = strdupout((vm_offset_t)&ef->strtab[j]);
527	file_addmetadata(fp, MODINFOMD_DEPLIST, strlen(s) + 1, s);
528	free(s);
529    }
530
531out:
532    if (dp)
533	free(dp);
534    if (shdr)
535	free(shdr);
536    return ret;
537}
538
539static char invalid_name[] = "bad";
540char *
541fake_modname(const char *name)
542{
543    char *sp, *ep;
544    size_t len;
545
546    sp = strrchr(name, '/');
547    if (sp)
548	sp++;
549    else
550	sp = name;
551    ep = strrchr(name, '.');
552    if (ep) {
553	    if (ep == name) {
554		sp = invalid_name;
555		ep = invalid_name + sizeof(invalid_name) - 1;
556	    }
557    } else
558	ep = name + strlen(name);
559    len = ep - sp;
560    ep = malloc(len + 1);
561    if (ep == NULL)
562	return NULL;
563    memcpy(ep, sp, len);
564    ep[len] = '\0';
565    return ep;
566}
567
568int
569elf_parse_modmetadata(struct preloaded_file *fp, elf_file_t ef)
570{
571    struct mod_metadata md;
572    Elf_Sym sym;
573    char *s, *v, **p, **p_stop;
574    int modcnt;
575
576    if (elf_lookup_symbol(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
577	return ENOENT;
578    p = (char **)(sym.st_value + ef->off);
579    if (elf_lookup_symbol(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
580	return ENOENT;
581    p_stop = (char **)(sym.st_value + ef->off);
582
583    modcnt = 0;
584    while (p < p_stop) {
585	COPYOUT(p++, &v, sizeof(v));
586	COPYOUT(v + ef->off, &md, sizeof(md));
587	switch(md.md_type) {
588	  case MDT_DEPEND:
589	    if (ef->kernel)		/* kernel must not depend on anything */
590	      break;
591	    s = strdupout((vm_offset_t)(md.md_cval + ef->off));
592	    file_addmetadata(fp, MODINFOMD_DEPLIST, strlen(s) + 1, s);
593	    free(s);
594	    break;
595	  case MDT_VERSION:
596	    s = strdupout((vm_offset_t)(md.md_cval + ef->off));
597	    file_addmodule(fp, s, NULL);
598	    free(s);
599	    modcnt++;
600	    break;
601	}
602    }
603    if (modcnt == 0) {
604	s = fake_modname(fp->f_name);
605	file_addmodule(fp, s, NULL);
606	free(s);
607    }
608    return 0;
609}
610
611static unsigned long
612elf_hash(const char *name)
613{
614    const unsigned char *p = (const unsigned char *) name;
615    unsigned long h = 0;
616    unsigned long g;
617
618    while (*p != '\0') {
619	h = (h << 4) + *p++;
620	if ((g = h & 0xf0000000) != 0)
621	    h ^= g >> 24;
622	h &= ~g;
623    }
624    return h;
625}
626
627static const char elf_bad_symtable[] = "elf_lookup_symbol: corrupt symbol table\n";
628int
629elf_lookup_symbol(struct preloaded_file *fp, elf_file_t ef, const char* name,
630		  Elf_Sym *symp)
631{
632    unsigned long symnum;
633    Elf_Sym sym;
634    char *strp;
635    unsigned long hash;
636
637    hash = elf_hash(name);
638    COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum));
639
640    while (symnum != STN_UNDEF) {
641	if (symnum >= ef->nchains) {
642	    printf(elf_bad_symtable);
643	    return ENOENT;
644	}
645
646	COPYOUT(ef->symtab + symnum, &sym, sizeof(sym));
647	if (sym.st_name == 0) {
648	    printf(elf_bad_symtable);
649	    return ENOENT;
650	}
651
652	strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name));
653	if (strcmp(name, strp) == 0) {
654	    free(strp);
655	    if (sym.st_shndx != SHN_UNDEF ||
656		(sym.st_value != 0 &&
657		 ELF_ST_TYPE(sym.st_info) == STT_FUNC)) {
658		*symp = sym;
659		return 0;
660	    }
661	    return ENOENT;
662	}
663	free(strp);
664	COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum));
665    }
666    return ENOENT;
667}
668