Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / boot / common / load_elf.c
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: src/sys/boot/common/load_elf.c,v 1.29 2003/08/25 23:30:41 obrien Exp $
28  * $DragonFly: src/sys/boot/common/load_elf.c,v 1.5 2005/02/20 16:30:39 swildner Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/exec.h>
33 #include <sys/linker.h>
34 #include <sys/module.h>
35 #include <string.h>
36 #include <machine/elf.h>
37 #include <stand.h>
38 #define FREEBSD_ELF
39 #include <link.h>
40
41 #include "bootstrap.h"
42
43 #define COPYOUT(s,d,l)  archsw.arch_copyout((vm_offset_t)(s), d, l)
44
45 #if defined(__i386__) && __ELF_WORD_SIZE == 64
46 #undef ELF_TARG_CLASS
47 #undef ELF_TARG_MACH
48 #define ELF_TARG_CLASS  ELFCLASS64
49 #define ELF_TARG_MACH   EM_X86_64
50 #endif
51
52 typedef struct elf_file {
53     Elf_Phdr    *ph;
54     Elf_Ehdr    *ehdr;
55     Elf_Sym     *symtab;
56     Elf_Hashelt *hashtab;
57     Elf_Hashelt nbuckets;
58     Elf_Hashelt nchains;
59     Elf_Hashelt *buckets;
60     Elf_Hashelt *chains;
61     Elf_Rela    *rela;
62     size_t      relasz;
63     char        *strtab;
64     size_t      strsz;
65     int         fd;
66     caddr_t     firstpage;
67     size_t      firstlen;
68     int         kernel;
69     u_int64_t   off;
70 } *elf_file_t;
71
72 static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr);
73 static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym);
74 #ifdef __sparc__
75 static void __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
76     void *p, void *val, size_t len);
77 #endif
78 static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef);
79 static char     *fake_modname(const char *name);
80
81 const char      *__elfN(kerneltype) = "elf kernel";
82 const char      *__elfN(moduletype) = "elf module";
83
84 /*
85  * Attempt to load the file (file) as an ELF module.  It will be stored at
86  * (dest), and a pointer to a module structure describing the loaded object
87  * will be saved in (result).
88  */
89 int
90 __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
91 {
92     struct preloaded_file       *fp, *kfp;
93     struct elf_file             ef;
94     Elf_Ehdr                    *ehdr;
95     int                         err;
96     u_int                       pad;
97     ssize_t                     bytes_read;
98
99     fp = NULL;
100     bzero(&ef, sizeof(struct elf_file));
101     
102     /*
103      * Open the image, read and validate the ELF header 
104      */
105     if (filename == NULL)       /* can't handle nameless */
106         return(EFTYPE);
107     if ((ef.fd = open(filename, O_RDONLY)) == -1)
108         return(errno);
109     ef.firstpage = malloc(PAGE_SIZE);
110     if (ef.firstpage == NULL) {
111         close(ef.fd);
112         return(ENOMEM);
113     }
114     bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE);
115     ef.firstlen = (size_t)bytes_read;
116     if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) {
117         err = EFTYPE;           /* could be EIO, but may be small file */
118         goto oerr;
119     }
120     ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage;
121
122     /* Is it ELF? */
123     if (!IS_ELF(*ehdr)) {
124         err = EFTYPE;
125         goto oerr;
126     }
127     if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||    /* Layout ? */
128         ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
129         ehdr->e_ident[EI_VERSION] != EV_CURRENT ||      /* Version ? */
130         ehdr->e_version != EV_CURRENT ||
131         ehdr->e_machine != ELF_TARG_MACH) {             /* Machine ? */
132         err = EFTYPE;
133         goto oerr;
134     }
135
136
137     /*
138      * Check to see what sort of module we are.
139      */
140     kfp = file_findfile(NULL, NULL);
141     if (ehdr->e_type == ET_DYN) {
142         /* Looks like a kld module */
143         if (kfp == NULL) {
144             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
145             err = EPERM;
146             goto oerr;
147         }
148         if (strcmp(__elfN(kerneltype), kfp->f_type)) {
149             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type);
150             err = EPERM;
151             goto oerr;
152         }
153         /* Looks OK, got ahead */
154         ef.kernel = 0;
155
156         /* Page-align the load address */
157         pad = (u_int)dest & PAGE_MASK;
158         if (pad != 0) {
159             pad = PAGE_SIZE - pad;
160             dest += pad;
161         }
162     } else if (ehdr->e_type == ET_EXEC) {
163         /* Looks like a kernel */
164         if (kfp != NULL) {
165             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
166             err = EPERM;
167             goto oerr;
168         }
169         /* 
170          * Calculate destination address based on kernel entrypoint     
171          */
172         dest = ehdr->e_entry;
173         if (dest == 0) {
174             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n");
175             err = EPERM;
176             goto oerr;
177         }
178         ef.kernel = 1;
179
180     } else {
181         err = EFTYPE;
182         goto oerr;
183     }
184
185     /* 
186      * Ok, we think we should handle this.
187      */
188     fp = file_alloc();
189     if (fp == NULL) {
190             printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n");
191             err = EPERM;
192             goto out;
193     }
194     if (ef.kernel)
195         setenv("kernelname", filename, 1);
196     fp->f_name = strdup(filename);
197     fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype));
198
199 #ifdef ELF_VERBOSE
200     if (ef.kernel)
201         printf("%s entry at 0x%jx\n", filename, (uintmax_t)dest);
202 #else
203     printf("%s ", filename);
204 #endif
205
206     fp->f_size = __elfN(loadimage)(fp, &ef, dest);
207     if (fp->f_size == 0 || fp->f_addr == 0)
208         goto ioerr;
209
210     /* save exec header as metadata */
211     file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr);
212
213     /* Load OK, return module pointer */
214     *result = (struct preloaded_file *)fp;
215     err = 0;
216     goto out;
217     
218  ioerr:
219     err = EIO;
220  oerr:
221     file_discard(fp);
222  out:
223     if (ef.firstpage)
224         free(ef.firstpage);
225     close(ef.fd);
226     return(err);
227 }
228
229 /*
230  * With the file (fd) open on the image, and (ehdr) containing
231  * the Elf header, load the image at (off)
232  */
233 static int
234 __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
235 {
236     int         i;
237     u_int       j;
238     Elf_Ehdr    *ehdr;
239     Elf_Phdr    *phdr, *php;
240     Elf_Shdr    *shdr;
241     int         ret;
242     vm_offset_t firstaddr;
243     vm_offset_t lastaddr;
244     void        *buf;
245     size_t      resid, chunk;
246     ssize_t     result;
247     vm_offset_t dest;
248     Elf_Addr    ssym, esym;
249     Elf_Dyn     *dp;
250     Elf_Addr    adp;
251     int         ndp;
252     int         symstrindex;
253     int         symtabindex;
254     Elf_Size    size;
255     u_int       fpcopy;
256
257     dp = NULL;
258     shdr = NULL;
259     ret = 0;
260     firstaddr = lastaddr = 0;
261     ehdr = ef->ehdr;
262     if (ef->kernel) {
263 #ifdef __i386__
264 #if __ELF_WORD_SIZE == 64
265         off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
266 #else
267         off = - (off & 0xff000000u);    /* i386 relocates after locore */
268 #endif
269 #endif
270     }
271     ef->off = off;
272
273     if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) {
274         printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n");
275         goto out;
276     }
277     phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff);
278
279     for (i = 0; i < ehdr->e_phnum; i++) {
280         /* We want to load PT_LOAD segments only.. */
281         if (phdr[i].p_type != PT_LOAD)
282             continue;
283
284 #ifdef ELF_VERBOSE
285         printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
286             (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
287             (long)(phdr[i].p_vaddr + off),
288             (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
289 #else
290         if ((phdr[i].p_flags & PF_W) == 0) {
291             printf("text=0x%lx ", (long)phdr[i].p_filesz);
292         } else {
293             printf("data=0x%lx", (long)phdr[i].p_filesz);
294             if (phdr[i].p_filesz < phdr[i].p_memsz)
295                 printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz));
296             printf(" ");
297         }
298 #endif
299         fpcopy = 0;
300         if (ef->firstlen > phdr[i].p_offset) {
301             fpcopy = ef->firstlen - phdr[i].p_offset;
302             archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
303                                phdr[i].p_vaddr + off, fpcopy);
304         }
305         if (phdr[i].p_filesz > fpcopy) {
306             if (lseek(ef->fd, (off_t)(phdr[i].p_offset + fpcopy),
307                       SEEK_SET) == -1) {
308                 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadexec: cannot seek\n");
309                 goto out;
310             }
311             if (archsw.arch_readin(ef->fd, phdr[i].p_vaddr + off + fpcopy,
312                 phdr[i].p_filesz - fpcopy) != (ssize_t)(phdr[i].p_filesz - fpcopy)) {
313                 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadexec: archsw.readin failed\n");
314                 goto out;
315             }
316         }
317         /* clear space from oversized segments; eg: bss */
318         if (phdr[i].p_filesz < phdr[i].p_memsz) {
319 #ifdef ELF_VERBOSE
320             printf(" (bss: 0x%lx-0x%lx)",
321                 (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
322                 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
323 #endif
324
325             /* no archsw.arch_bzero */
326             buf = malloc(PAGE_SIZE);
327             if (buf == NULL) {
328                 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: malloc() failed\n");
329                 goto out;
330             }
331             bzero(buf, PAGE_SIZE);
332             resid = phdr[i].p_memsz - phdr[i].p_filesz;
333             dest = phdr[i].p_vaddr + off + phdr[i].p_filesz;
334             while (resid > 0) {
335                 chunk = min(PAGE_SIZE, resid);
336                 archsw.arch_copyin(buf, dest, chunk);
337                 resid -= chunk;
338                 dest += chunk;
339             }
340             free(buf);
341         }
342 #ifdef ELF_VERBOSE
343         printf("\n");
344 #endif
345
346         if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off))
347             firstaddr = phdr[i].p_vaddr + off;
348         if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz))
349             lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
350     }
351     lastaddr = roundup(lastaddr, sizeof(long));
352
353     /*
354      * Now grab the symbol tables.  This isn't easy if we're reading a
355      * .gz file.  I think the rule is going to have to be that you must
356      * strip a file to remove symbols before gzipping it so that we do not
357      * try to lseek() on it.
358      */
359     chunk = ehdr->e_shnum * ehdr->e_shentsize;
360     if (chunk == 0 || ehdr->e_shoff == 0)
361         goto nosyms;
362     shdr = malloc(chunk);
363     if (shdr == NULL)
364         goto nosyms;
365     if (lseek(ef->fd, (off_t)ehdr->e_shoff, SEEK_SET) == -1) {
366         printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: cannot lseek() to section headers");
367         goto nosyms;
368     }
369     result = read(ef->fd, shdr, chunk);
370     if (result < 0 || (size_t)result != chunk) {
371         printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: read section headers failed");
372         goto nosyms;
373     }
374     symtabindex = -1;
375     symstrindex = -1;
376     for (i = 0; i < ehdr->e_shnum; i++) {
377         if (shdr[i].sh_type != SHT_SYMTAB)
378             continue;
379         for (j = 0; j < ehdr->e_phnum; j++) {
380             if (phdr[j].p_type != PT_LOAD)
381                 continue;
382             if (shdr[i].sh_offset >= phdr[j].p_offset &&
383                 (shdr[i].sh_offset + shdr[i].sh_size <=
384                  phdr[j].p_offset + phdr[j].p_filesz)) {
385                 shdr[i].sh_offset = 0;
386                 shdr[i].sh_size = 0;
387                 break;
388             }
389         }
390         if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
391             continue;           /* alread loaded in a PT_LOAD above */
392         /* Save it for loading below */
393         symtabindex = i;
394         symstrindex = shdr[i].sh_link;
395     }
396     if (symtabindex < 0 || symstrindex < 0)
397         goto nosyms;
398
399     /* Ok, committed to a load. */
400 #ifndef ELF_VERBOSE
401     printf("syms=[");
402 #endif
403     ssym = lastaddr;
404     for (i = symtabindex; i >= 0; i = symstrindex) {
405 #ifdef ELF_VERBOSE
406         char    *secname;
407
408         switch(shdr[i].sh_type) {
409             case SHT_SYMTAB:            /* Symbol table */
410                 secname = "symtab";
411                 break;
412             case SHT_STRTAB:            /* String table */
413                 secname = "strtab";
414                 break;
415             default:
416                 secname = "WHOA!!";
417                 break;
418         }
419 #endif
420
421         size = shdr[i].sh_size;
422         archsw.arch_copyin(&size, lastaddr, sizeof(size));
423         lastaddr += sizeof(size);
424
425 #ifdef ELF_VERBOSE
426         printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname,
427             shdr[i].sh_size, shdr[i].sh_offset,
428             lastaddr, lastaddr + shdr[i].sh_size);
429 #else
430         if (i == symstrindex)
431             printf("+");
432         printf("0x%lx+0x%lx", (long)sizeof(size), (long)size);
433 #endif
434
435         if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) {
436             printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!");
437             lastaddr = ssym;
438             ssym = 0;
439             goto nosyms;
440         }
441         result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size);
442         if (result < 0 || (size_t)result != shdr[i].sh_size) {
443             printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped!");
444             lastaddr = ssym;
445             ssym = 0;
446             goto nosyms;
447         }
448         /* Reset offsets relative to ssym */
449         lastaddr += shdr[i].sh_size;
450         lastaddr = roundup(lastaddr, sizeof(size));
451         if (i == symtabindex)
452             symtabindex = -1;
453         else if (i == symstrindex)
454             symstrindex = -1;
455     }
456     esym = lastaddr;
457 #ifndef ELF_VERBOSE
458     printf("]");
459 #endif
460
461     file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
462     file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);
463
464 nosyms:
465     printf("\n");
466
467     ret = lastaddr - firstaddr;
468     fp->f_addr = firstaddr;
469
470     php = NULL;
471     for (i = 0; i < ehdr->e_phnum; i++) {
472         if (phdr[i].p_type == PT_DYNAMIC) {
473             php = phdr + i;
474             adp = php->p_vaddr;
475             file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp);
476             break;
477         }
478     }
479
480     if (php == NULL)    /* this is bad, we cannot get to symbols or _DYNAMIC */
481         goto out;
482
483     ndp = php->p_filesz / sizeof(Elf_Dyn);
484     if (ndp == 0)
485         goto out;
486     dp = malloc(php->p_filesz);
487     if (dp == NULL)
488         goto out;
489     archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz);
490
491     ef->strsz = 0;
492     for (i = 0; i < ndp; i++) {
493         if (dp[i].d_tag == NULL)
494             break;
495         switch (dp[i].d_tag) {
496         case DT_HASH:
497             ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off);
498             break;
499         case DT_STRTAB:
500             ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off);
501             break;
502         case DT_STRSZ:
503             ef->strsz = dp[i].d_un.d_val;
504             break;
505         case DT_SYMTAB:
506             ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off);
507             break;
508         case DT_RELA:
509             ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off);
510             break;
511         case DT_RELASZ:
512             ef->relasz = dp[i].d_un.d_val;
513             break;
514         default:
515             break;
516         }
517     }
518     if (ef->hashtab == NULL || ef->symtab == NULL ||
519         ef->strtab == NULL || ef->strsz == 0)
520         goto out;
521     COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets));
522     COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
523     ef->buckets = ef->hashtab + 2;
524     ef->chains = ef->buckets + ef->nbuckets;
525     if (__elfN(parse_modmetadata)(fp, ef) == 0)
526         goto out;
527
528     if (ef->kernel)                     /* kernel must not depend on anything */
529         goto out;
530
531 out:
532     if (dp)
533         free(dp);
534     if (shdr)
535         free(shdr);
536     return ret;
537 }
538
539 static char invalid_name[] = "bad";
540
541 char *
542 fake_modname(const char *name)
543 {
544     const char *sp, *ep;
545     char *fp;
546     size_t len;
547
548     sp = strrchr(name, '/');
549     if (sp)
550         sp++;
551     else
552         sp = name;
553     ep = strrchr(name, '.');
554     if (ep) {
555             if (ep == name) {
556                 sp = invalid_name;
557                 ep = invalid_name + sizeof(invalid_name) - 1;
558             } 
559     } else
560         ep = name + strlen(name);
561     len = ep - sp;
562     fp = malloc(len + 1);
563     if (fp == NULL)
564         return NULL;
565     memcpy(fp, sp, len);
566     fp[len] = '\0';
567     return fp;
568 }
569
570 #if defined(__i386__) && __ELF_WORD_SIZE == 64
571 struct mod_metadata64 {
572         int             md_version;     /* structure version MDTV_* */  
573         int             md_type;        /* type of entry MDT_* */
574         u_int64_t       md_data;        /* specific data */
575         u_int64_t       md_cval;        /* common string label */
576 };
577 #endif
578
579 int
580 __elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
581 {
582     struct mod_metadata md;
583 #if defined(__i386__) && __ELF_WORD_SIZE == 64
584     struct mod_metadata64 md64;
585 #endif
586     struct mod_depend *mdepend;
587     struct mod_version mver;
588     Elf_Sym sym;
589     char *s;
590     int modcnt, minfolen;
591     Elf_Addr v, p, p_stop;
592
593     if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
594         return ENOENT;
595     p = sym.st_value + ef->off;
596     if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
597         return ENOENT;
598     p_stop = sym.st_value + ef->off;
599
600     modcnt = 0;
601     while (p < p_stop) {
602         COPYOUT(p, &v, sizeof(v));
603 #ifdef __sparc64__
604         __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v));
605 #else
606         v += ef->off;
607 #endif
608 #if defined(__i386__) && __ELF_WORD_SIZE == 64
609         COPYOUT(v, &md64, sizeof(md64));
610         md.md_version = md64.md_version;
611         md.md_type = md64.md_type;
612         md.md_cval = (const char *)(uintptr_t)(md64.md_cval + ef->off);
613         md.md_data = (void *)(uintptr_t)(md64.md_data + ef->off);
614 #else
615         COPYOUT(v, &md, sizeof(md));
616 #ifdef __sparc64__
617         __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md));
618 #else
619         md.md_cval += ef->off;
620         md.md_data = (uint8_t *)md.md_data + ef->off;
621 #endif
622 #endif
623         p += sizeof(Elf_Addr);
624         switch(md.md_type) {
625           case MDT_DEPEND:
626             if (ef->kernel)             /* kernel must not depend on anything */
627               break;
628             s = strdupout((vm_offset_t)md.md_cval);
629             minfolen = sizeof(*mdepend) + strlen(s) + 1;
630             mdepend = malloc(minfolen);
631             if (mdepend == NULL)
632                 return ENOMEM;
633             COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend));
634             strcpy((char*)(mdepend + 1), s);
635             free(s);
636             file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend);
637             free(mdepend);
638             break;
639           case MDT_VERSION:
640             s = strdupout((vm_offset_t)md.md_cval);
641             COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
642             file_addmodule(fp, s, mver.mv_version, NULL);
643             free(s);
644             modcnt++;
645             break;
646         }
647     }
648     if (modcnt == 0) {
649         s = fake_modname(fp->f_name);
650         file_addmodule(fp, s, 1, NULL);
651         free(s);
652     }
653     return 0;
654 }
655
656 static unsigned long
657 elf_hash(const char *name)
658 {
659     const unsigned char *p = (const unsigned char *) name;
660     unsigned long h = 0;
661     unsigned long g;
662
663     while (*p != '\0') {
664         h = (h << 4) + *p++;
665         if ((g = h & 0xf0000000) != 0)
666             h ^= g >> 24;
667         h &= ~g;
668     }
669     return h;
670 }
671
672 static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n";
673 int
674 __elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name,
675                   Elf_Sym *symp)
676 {
677     Elf_Hashelt symnum;
678     Elf_Sym sym;
679     char *strp;
680     unsigned long hash;
681
682     hash = elf_hash(name);
683     COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum));
684
685     while (symnum != STN_UNDEF) {
686         if (symnum >= ef->nchains) {
687             printf(__elfN(bad_symtable));
688             return ENOENT;
689         }
690
691         COPYOUT(ef->symtab + symnum, &sym, sizeof(sym));
692         if (sym.st_name == 0) {
693             printf(__elfN(bad_symtable));
694             return ENOENT;
695         }
696
697         strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name));
698         if (strcmp(name, strp) == 0) {
699             free(strp);
700             if (sym.st_shndx != SHN_UNDEF ||
701                 (sym.st_value != 0 &&
702                  ELF_ST_TYPE(sym.st_info) == STT_FUNC)) {
703                 *symp = sym;
704                 return 0;
705             }
706             return ENOENT;
707         }
708         free(strp);
709         COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum));
710     }
711     return ENOENT;
712 }
713
714 #ifdef __sparc__
715 /*
716  * Apply any intra-module relocations to the value. *p is the load address
717  * of the value and val/len is the value to be modified. This does NOT modify
718  * the image in-place, because this is done by kern_linker later on.
719  */
720 static void
721 __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
722     void *p, void *val, size_t len)
723 {
724         Elf_Addr off = (Elf_Addr)p - ef->off, word;
725         size_t n;
726         Elf_Rela r;
727
728         for (n = 0; n < ef->relasz / sizeof(r); n++) {
729                 COPYOUT(ef->rela + n, &r, sizeof(r));
730
731                 if (r.r_offset >= off && r.r_offset < off + len &&
732                     ELF_R_TYPE(r.r_info) == R_SPARC_RELATIVE) {
733                         word = ef->off + r.r_addend;
734                         bcopy(&word, (char *)val + (r.r_offset - off),
735                             sizeof(word));
736                 }
737         }
738 }
739 #endif