load_elf.c revision 247413
133965Sjdp/*- 260484Sobrien * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 333965Sjdp * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 433965Sjdp * All rights reserved. 533965Sjdp * 633965Sjdp * Redistribution and use in source and binary forms, with or without 733965Sjdp * modification, are permitted provided that the following conditions 833965Sjdp * are met: 933965Sjdp * 1. Redistributions of source code must retain the above copyright 1033965Sjdp * notice, this list of conditions and the following disclaimer. 1133965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer in the 1333965Sjdp * documentation and/or other materials provided with the distribution. 1433965Sjdp * 1533965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1633965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1733965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1833965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1933965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2033965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2133965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2233965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2333965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2433965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2533965Sjdp * SUCH DAMAGE. 2633965Sjdp */ 2733965Sjdp 2833965Sjdp#include <sys/cdefs.h> 2933965Sjdp__FBSDID("$FreeBSD: head/sys/boot/common/load_elf.c 247413 2013-02-27 19:59:41Z ian $"); 3033965Sjdp 3160484Sobrien#include <sys/param.h> 3233965Sjdp#include <sys/exec.h> 3333965Sjdp#include <sys/linker.h> 3433965Sjdp#include <sys/module.h> 3533965Sjdp#include <sys/stdint.h> 3633965Sjdp#include <string.h> 3733965Sjdp#include <machine/elf.h> 3833965Sjdp#include <stand.h> 3933965Sjdp#define FREEBSD_ELF 4033965Sjdp#include <link.h> 4133965Sjdp 4233965Sjdp#include "bootstrap.h" 4333965Sjdp 4433965Sjdp#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 4533965Sjdp 4638889Sjdp#if defined(__i386__) && __ELF_WORD_SIZE == 64 4738889Sjdp#undef ELF_TARG_CLASS 4833965Sjdp#undef ELF_TARG_MACH 4933965Sjdp#define ELF_TARG_CLASS ELFCLASS64 5033965Sjdp#define ELF_TARG_MACH EM_X86_64 5133965Sjdp#endif 5233965Sjdp 5333965Sjdptypedef struct elf_file { 5433965Sjdp Elf_Phdr *ph; 5533965Sjdp Elf_Ehdr *ehdr; 5633965Sjdp Elf_Sym *symtab; 5733965Sjdp Elf_Hashelt *hashtab; 5833965Sjdp Elf_Hashelt nbuckets; 5933965Sjdp Elf_Hashelt nchains; 6033965Sjdp Elf_Hashelt *buckets; 6133965Sjdp Elf_Hashelt *chains; 6233965Sjdp Elf_Rel *rel; 6333965Sjdp size_t relsz; 6433965Sjdp Elf_Rela *rela; 6533965Sjdp size_t relasz; 6633965Sjdp char *strtab; 6733965Sjdp size_t strsz; 6833965Sjdp int fd; 6933965Sjdp caddr_t firstpage; 7033965Sjdp size_t firstlen; 7133965Sjdp int kernel; 7233965Sjdp u_int64_t off; 7333965Sjdp} *elf_file_t; 7433965Sjdp 7533965Sjdpstatic int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr); 7633965Sjdpstatic int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); 7733965Sjdpstatic int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 7833965Sjdp Elf_Addr p, void *val, size_t len); 7933965Sjdpstatic int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef); 8033965Sjdpstatic symaddr_fn __elfN(symaddr); 8133965Sjdpstatic char *fake_modname(const char *name); 8233965Sjdp 8333965Sjdpconst char *__elfN(kerneltype) = "elf kernel"; 8433965Sjdpconst char *__elfN(moduletype) = "elf module"; 8533965Sjdp 8633965Sjdpu_int64_t __elfN(relocation_offset) = 0; 8733965Sjdp 8833965Sjdp/* 8933965Sjdp * Attempt to load the file (file) as an ELF module. It will be stored at 9033965Sjdp * (dest), and a pointer to a module structure describing the loaded object 9133965Sjdp * will be saved in (result). 9233965Sjdp */ 9333965Sjdpint 9433965Sjdp__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) 9533965Sjdp{ 9633965Sjdp struct preloaded_file *fp, *kfp; 9733965Sjdp struct elf_file ef; 9833965Sjdp Elf_Ehdr *ehdr; 9933965Sjdp int err; 10033965Sjdp ssize_t bytes_read; 10133965Sjdp 10233965Sjdp fp = NULL; 10333965Sjdp bzero(&ef, sizeof(struct elf_file)); 10433965Sjdp 10533965Sjdp /* 10633965Sjdp * Open the image, read and validate the ELF header 10733965Sjdp */ 10833965Sjdp if (filename == NULL) /* can't handle nameless */ 10933965Sjdp return(EFTYPE); 11033965Sjdp if ((ef.fd = open(filename, O_RDONLY)) == -1) 11133965Sjdp return(errno); 11233965Sjdp ef.firstpage = malloc(PAGE_SIZE); 11333965Sjdp if (ef.firstpage == NULL) { 11433965Sjdp close(ef.fd); 11533965Sjdp return(ENOMEM); 11633965Sjdp } 11733965Sjdp bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE); 11833965Sjdp ef.firstlen = (size_t)bytes_read; 11933965Sjdp if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) { 12033965Sjdp err = EFTYPE; /* could be EIO, but may be small file */ 12133965Sjdp goto oerr; 12233965Sjdp } 12333965Sjdp ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage; 12433965Sjdp 12533965Sjdp /* Is it ELF? */ 12633965Sjdp if (!IS_ELF(*ehdr)) { 12733965Sjdp err = EFTYPE; 12833965Sjdp goto oerr; 12933965Sjdp } 13033965Sjdp if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ 13133965Sjdp ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || 13260484Sobrien ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ 13360484Sobrien ehdr->e_version != EV_CURRENT || 13460484Sobrien ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ 13533965Sjdp err = EFTYPE; 13633965Sjdp goto oerr; 13733965Sjdp } 13833965Sjdp 13933965Sjdp 14033965Sjdp /* 14133965Sjdp * Check to see what sort of module we are. 14233965Sjdp */ 14333965Sjdp kfp = file_findfile(NULL, NULL); 14433965Sjdp if (ehdr->e_type == ET_DYN) { 14533965Sjdp /* Looks like a kld module */ 14633965Sjdp if (kfp == NULL) { 14733965Sjdp printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); 14833965Sjdp err = EPERM; 14933965Sjdp goto oerr; 15033965Sjdp } 15133965Sjdp if (strcmp(__elfN(kerneltype), kfp->f_type)) { 15233965Sjdp printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); 15333965Sjdp err = EPERM; 15433965Sjdp goto oerr; 15533965Sjdp } 15633965Sjdp /* Looks OK, got ahead */ 15733965Sjdp ef.kernel = 0; 15833965Sjdp 15933965Sjdp } else if (ehdr->e_type == ET_EXEC) { 16033965Sjdp /* Looks like a kernel */ 16133965Sjdp if (kfp != NULL) { 16233965Sjdp printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); 16333965Sjdp err = EPERM; 16433965Sjdp goto oerr; 16533965Sjdp } 16633965Sjdp /* 16733965Sjdp * Calculate destination address based on kernel entrypoint 16833965Sjdp */ 16933965Sjdp dest = (ehdr->e_entry & ~PAGE_MASK); 17033965Sjdp if (dest == 0) { 17133965Sjdp printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); 17233965Sjdp err = EPERM; 17333965Sjdp goto oerr; 17433965Sjdp } 17533965Sjdp ef.kernel = 1; 17633965Sjdp 17733965Sjdp } else { 17833965Sjdp err = EFTYPE; 17933965Sjdp goto oerr; 18033965Sjdp } 18133965Sjdp 18233965Sjdp if (archsw.arch_loadaddr != NULL) 18333965Sjdp dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); 18433965Sjdp else 18533965Sjdp dest = roundup(dest, PAGE_SIZE); 18633965Sjdp 18733965Sjdp /* 18833965Sjdp * Ok, we think we should handle this. 18933965Sjdp */ 19033965Sjdp fp = file_alloc(); 19133965Sjdp if (fp == NULL) { 19233965Sjdp printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); 19333965Sjdp err = EPERM; 19433965Sjdp goto out; 19533965Sjdp } 19633965Sjdp if (ef.kernel) 19733965Sjdp setenv("kernelname", filename, 1); 19833965Sjdp fp->f_name = strdup(filename); 19933965Sjdp fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype)); 20033965Sjdp 20133965Sjdp#ifdef ELF_VERBOSE 20233965Sjdp if (ef.kernel) 20333965Sjdp printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); 20433965Sjdp#else 20533965Sjdp printf("%s ", filename); 20633965Sjdp#endif 20733965Sjdp 20833965Sjdp fp->f_size = __elfN(loadimage)(fp, &ef, dest); 20933965Sjdp if (fp->f_size == 0 || fp->f_addr == 0) 21033965Sjdp goto ioerr; 21160484Sobrien 21233965Sjdp /* save exec header as metadata */ 21333965Sjdp file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); 21433965Sjdp 21533965Sjdp /* Load OK, return module pointer */ 21633965Sjdp *result = (struct preloaded_file *)fp; 21733965Sjdp err = 0; 21833965Sjdp goto out; 21933965Sjdp 22033965Sjdp ioerr: 22133965Sjdp err = EIO; 22233965Sjdp oerr: 22333965Sjdp file_discard(fp); 22433965Sjdp out: 22533965Sjdp if (ef.firstpage) 22633965Sjdp free(ef.firstpage); 22733965Sjdp close(ef.fd); 22833965Sjdp return(err); 22933965Sjdp} 23033965Sjdp 23133965Sjdp/* 23233965Sjdp * With the file (fd) open on the image, and (ehdr) containing 23333965Sjdp * the Elf header, load the image at (off) 23433965Sjdp */ 23533965Sjdpstatic int 23633965Sjdp__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) 23733965Sjdp{ 23833965Sjdp int i; 23933965Sjdp u_int j; 24033965Sjdp Elf_Ehdr *ehdr; 24133965Sjdp Elf_Phdr *phdr, *php; 24233965Sjdp Elf_Shdr *shdr; 24333965Sjdp int ret; 24433965Sjdp vm_offset_t firstaddr; 24533965Sjdp vm_offset_t lastaddr; 24633965Sjdp size_t chunk; 24733965Sjdp ssize_t result; 24833965Sjdp Elf_Addr ssym, esym; 24933965Sjdp Elf_Dyn *dp; 25033965Sjdp Elf_Addr adp; 25160484Sobrien int ndp; 25260484Sobrien int symstrindex; 25360484Sobrien int symtabindex; 25460484Sobrien Elf_Size size; 25560484Sobrien u_int fpcopy; 25660484Sobrien 25760484Sobrien dp = NULL; 25860484Sobrien shdr = NULL; 25933965Sjdp ret = 0; 26033965Sjdp firstaddr = lastaddr = 0; 26133965Sjdp ehdr = ef->ehdr; 26233965Sjdp if (ef->kernel) { 26333965Sjdp#if defined(__i386__) || defined(__amd64__) 26433965Sjdp#if __ELF_WORD_SIZE == 64 26533965Sjdp off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ 26633965Sjdp#else 26733965Sjdp off = - (off & 0xff000000u); /* i386 relocates after locore */ 26833965Sjdp#endif 26933965Sjdp#elif defined(__powerpc__) 27033965Sjdp /* 27133965Sjdp * On the purely virtual memory machines like e500, the kernel is 27233965Sjdp * linked against its final VA range, which is most often not 27333965Sjdp * available at the loader stage, but only after kernel initializes 27433965Sjdp * and completes its VM settings. In such cases we cannot use p_vaddr 27533965Sjdp * field directly to load ELF segments, but put them at some 27633965Sjdp * 'load-time' locations. 27733965Sjdp */ 27833965Sjdp if (off & 0xf0000000u) { 27933965Sjdp off = -(off & 0xf0000000u); 28060484Sobrien /* 28160484Sobrien * XXX the physical load address should not be hardcoded. Note 28233965Sjdp * that the Book-E kernel assumes that it's loaded at a 16MB 28333965Sjdp * boundary for now... 28433965Sjdp */ 28533965Sjdp off += 0x01000000; 28633965Sjdp ehdr->e_entry += off; 28733965Sjdp#ifdef ELF_VERBOSE 28833965Sjdp printf("Converted entry 0x%08x\n", ehdr->e_entry); 28933965Sjdp#endif 29033965Sjdp } else 29133965Sjdp off = 0; 29233965Sjdp#elif defined(__arm__) 29333965Sjdp /* 29433965Sjdp * The elf headers in some kernels specify virtual addresses in all 29533965Sjdp * header fields. More recently, the e_entry and p_paddr fields are the 29633965Sjdp * proper physical addresses. Even when the p_paddr fields are correct, 29733965Sjdp * the MI code below uses the p_vaddr fields with an offset added for 29833965Sjdp * loading (doing so is arguably wrong). To make loading work, we need 29933965Sjdp * an offset that represents the difference between physical and virtual 30033965Sjdp * addressing. ARM kernels are always linked at 0xC0000000. Depending 30133965Sjdp * on the headers, the offset value passed in may be physical or virtual 30233965Sjdp * (because it typically comes from e_entry), but we always replace 30333965Sjdp * whatever is passed in with the va<->pa offset. On the other hand, we 30433965Sjdp * only adjust the entry point if it's a virtual address to begin with. 30533965Sjdp */ 30633965Sjdp off = -0xc0000000u; 30733965Sjdp if ((ehdr->e_entry & 0xc0000000u) == 0xc0000000u) 30833965Sjdp ehdr->e_entry += off; 30933965Sjdp#ifdef ELF_VERBOSE 31033965Sjdp printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off); 31133965Sjdp#endif 31233965Sjdp#else 313 off = 0; /* other archs use direct mapped kernels */ 314#endif 315 __elfN(relocation_offset) = off; 316 } 317 ef->off = off; 318 319 if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { 320 printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n"); 321 goto out; 322 } 323 phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); 324 325 for (i = 0; i < ehdr->e_phnum; i++) { 326 /* We want to load PT_LOAD segments only.. */ 327 if (phdr[i].p_type != PT_LOAD) 328 continue; 329 330#ifdef ELF_VERBOSE 331 printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", 332 (long)phdr[i].p_filesz, (long)phdr[i].p_offset, 333 (long)(phdr[i].p_vaddr + off), 334 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 335#else 336 if ((phdr[i].p_flags & PF_W) == 0) { 337 printf("text=0x%lx ", (long)phdr[i].p_filesz); 338 } else { 339 printf("data=0x%lx", (long)phdr[i].p_filesz); 340 if (phdr[i].p_filesz < phdr[i].p_memsz) 341 printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); 342 printf(" "); 343 } 344#endif 345 fpcopy = 0; 346 if (ef->firstlen > phdr[i].p_offset) { 347 fpcopy = ef->firstlen - phdr[i].p_offset; 348 archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, 349 phdr[i].p_vaddr + off, fpcopy); 350 } 351 if (phdr[i].p_filesz > fpcopy) { 352 if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, 353 phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) { 354 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 355 "_loadimage: read failed\n"); 356 goto out; 357 } 358 } 359 /* clear space from oversized segments; eg: bss */ 360 if (phdr[i].p_filesz < phdr[i].p_memsz) { 361#ifdef ELF_VERBOSE 362 printf(" (bss: 0x%lx-0x%lx)", 363 (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), 364 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 365#endif 366 367 kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, 368 phdr[i].p_memsz - phdr[i].p_filesz); 369 } 370#ifdef ELF_VERBOSE 371 printf("\n"); 372#endif 373 374 if (archsw.arch_loadseg != NULL) 375 archsw.arch_loadseg(ehdr, phdr + i, off); 376 377 if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) 378 firstaddr = phdr[i].p_vaddr + off; 379 if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) 380 lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; 381 } 382 lastaddr = roundup(lastaddr, sizeof(long)); 383 384 /* 385 * Now grab the symbol tables. This isn't easy if we're reading a 386 * .gz file. I think the rule is going to have to be that you must 387 * strip a file to remove symbols before gzipping it so that we do not 388 * try to lseek() on it. 389 */ 390 chunk = ehdr->e_shnum * ehdr->e_shentsize; 391 if (chunk == 0 || ehdr->e_shoff == 0) 392 goto nosyms; 393 shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); 394 if (shdr == NULL) { 395 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) 396 "_loadimage: failed to read section headers"); 397 goto nosyms; 398 } 399 symtabindex = -1; 400 symstrindex = -1; 401 for (i = 0; i < ehdr->e_shnum; i++) { 402 if (shdr[i].sh_type != SHT_SYMTAB) 403 continue; 404 for (j = 0; j < ehdr->e_phnum; j++) { 405 if (phdr[j].p_type != PT_LOAD) 406 continue; 407 if (shdr[i].sh_offset >= phdr[j].p_offset && 408 (shdr[i].sh_offset + shdr[i].sh_size <= 409 phdr[j].p_offset + phdr[j].p_filesz)) { 410 shdr[i].sh_offset = 0; 411 shdr[i].sh_size = 0; 412 break; 413 } 414 } 415 if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) 416 continue; /* alread loaded in a PT_LOAD above */ 417 /* Save it for loading below */ 418 symtabindex = i; 419 symstrindex = shdr[i].sh_link; 420 } 421 if (symtabindex < 0 || symstrindex < 0) 422 goto nosyms; 423 424 /* Ok, committed to a load. */ 425#ifndef ELF_VERBOSE 426 printf("syms=["); 427#endif 428 ssym = lastaddr; 429 for (i = symtabindex; i >= 0; i = symstrindex) { 430#ifdef ELF_VERBOSE 431 char *secname; 432 433 switch(shdr[i].sh_type) { 434 case SHT_SYMTAB: /* Symbol table */ 435 secname = "symtab"; 436 break; 437 case SHT_STRTAB: /* String table */ 438 secname = "strtab"; 439 break; 440 default: 441 secname = "WHOA!!"; 442 break; 443 } 444#endif 445 446 size = shdr[i].sh_size; 447 archsw.arch_copyin(&size, lastaddr, sizeof(size)); 448 lastaddr += sizeof(size); 449 450#ifdef ELF_VERBOSE 451 printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, 452 (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, 453 (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size)); 454#else 455 if (i == symstrindex) 456 printf("+"); 457 printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); 458#endif 459 460 if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { 461 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); 462 lastaddr = ssym; 463 ssym = 0; 464 goto nosyms; 465 } 466 result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); 467 if (result < 0 || (size_t)result != shdr[i].sh_size) { 468 printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result, 469 (uintmax_t)shdr[i].sh_size); 470 lastaddr = ssym; 471 ssym = 0; 472 goto nosyms; 473 } 474 /* Reset offsets relative to ssym */ 475 lastaddr += shdr[i].sh_size; 476 lastaddr = roundup(lastaddr, sizeof(size)); 477 if (i == symtabindex) 478 symtabindex = -1; 479 else if (i == symstrindex) 480 symstrindex = -1; 481 } 482 esym = lastaddr; 483#ifndef ELF_VERBOSE 484 printf("]"); 485#endif 486 487 file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); 488 file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); 489 490nosyms: 491 printf("\n"); 492 493 ret = lastaddr - firstaddr; 494 fp->f_addr = firstaddr; 495 496 php = NULL; 497 for (i = 0; i < ehdr->e_phnum; i++) { 498 if (phdr[i].p_type == PT_DYNAMIC) { 499 php = phdr + i; 500 adp = php->p_vaddr; 501 file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp); 502 break; 503 } 504 } 505 506 if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ 507 goto out; 508 509 ndp = php->p_filesz / sizeof(Elf_Dyn); 510 if (ndp == 0) 511 goto out; 512 dp = malloc(php->p_filesz); 513 if (dp == NULL) 514 goto out; 515 archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); 516 517 ef->strsz = 0; 518 for (i = 0; i < ndp; i++) { 519 if (dp[i].d_tag == 0) 520 break; 521 switch (dp[i].d_tag) { 522 case DT_HASH: 523 ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off); 524 break; 525 case DT_STRTAB: 526 ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off); 527 break; 528 case DT_STRSZ: 529 ef->strsz = dp[i].d_un.d_val; 530 break; 531 case DT_SYMTAB: 532 ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off); 533 break; 534 case DT_REL: 535 ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off); 536 break; 537 case DT_RELSZ: 538 ef->relsz = dp[i].d_un.d_val; 539 break; 540 case DT_RELA: 541 ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off); 542 break; 543 case DT_RELASZ: 544 ef->relasz = dp[i].d_un.d_val; 545 break; 546 default: 547 break; 548 } 549 } 550 if (ef->hashtab == NULL || ef->symtab == NULL || 551 ef->strtab == NULL || ef->strsz == 0) 552 goto out; 553 COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); 554 COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); 555 ef->buckets = ef->hashtab + 2; 556 ef->chains = ef->buckets + ef->nbuckets; 557 if (__elfN(parse_modmetadata)(fp, ef) == 0) 558 goto out; 559 560 if (ef->kernel) /* kernel must not depend on anything */ 561 goto out; 562 563out: 564 if (dp) 565 free(dp); 566 if (shdr) 567 free(shdr); 568 return ret; 569} 570 571static char invalid_name[] = "bad"; 572 573char * 574fake_modname(const char *name) 575{ 576 const char *sp, *ep; 577 char *fp; 578 size_t len; 579 580 sp = strrchr(name, '/'); 581 if (sp) 582 sp++; 583 else 584 sp = name; 585 ep = strrchr(name, '.'); 586 if (ep) { 587 if (ep == name) { 588 sp = invalid_name; 589 ep = invalid_name + sizeof(invalid_name) - 1; 590 } 591 } else 592 ep = name + strlen(name); 593 len = ep - sp; 594 fp = malloc(len + 1); 595 if (fp == NULL) 596 return NULL; 597 memcpy(fp, sp, len); 598 fp[len] = '\0'; 599 return fp; 600} 601 602#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 603struct mod_metadata64 { 604 int md_version; /* structure version MDTV_* */ 605 int md_type; /* type of entry MDT_* */ 606 u_int64_t md_data; /* specific data */ 607 u_int64_t md_cval; /* common string label */ 608}; 609#endif 610 611int 612__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) 613{ 614 struct mod_metadata md; 615#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 616 struct mod_metadata64 md64; 617#endif 618 struct mod_depend *mdepend; 619 struct mod_version mver; 620 Elf_Sym sym; 621 char *s; 622 int error, modcnt, minfolen; 623 Elf_Addr v, p, p_stop; 624 625 if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0) 626 return 0; 627 p = sym.st_value + ef->off; 628 if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0) 629 return ENOENT; 630 p_stop = sym.st_value + ef->off; 631 632 modcnt = 0; 633 while (p < p_stop) { 634 COPYOUT(p, &v, sizeof(v)); 635 error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v)); 636 if (error == EOPNOTSUPP) 637 v += ef->off; 638 else if (error != 0) 639 return (error); 640#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 641 COPYOUT(v, &md64, sizeof(md64)); 642 error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); 643 if (error == EOPNOTSUPP) { 644 md64.md_cval += ef->off; 645 md64.md_data += ef->off; 646 } else if (error != 0) 647 return (error); 648 md.md_version = md64.md_version; 649 md.md_type = md64.md_type; 650 md.md_cval = (const char *)(uintptr_t)md64.md_cval; 651 md.md_data = (void *)(uintptr_t)md64.md_data; 652#else 653 COPYOUT(v, &md, sizeof(md)); 654 error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md)); 655 if (error == EOPNOTSUPP) { 656 md.md_cval += ef->off; 657 md.md_data += ef->off; 658 } else if (error != 0) 659 return (error); 660#endif 661 p += sizeof(Elf_Addr); 662 switch(md.md_type) { 663 case MDT_DEPEND: 664 if (ef->kernel) /* kernel must not depend on anything */ 665 break; 666 s = strdupout((vm_offset_t)md.md_cval); 667 minfolen = sizeof(*mdepend) + strlen(s) + 1; 668 mdepend = malloc(minfolen); 669 if (mdepend == NULL) 670 return ENOMEM; 671 COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend)); 672 strcpy((char*)(mdepend + 1), s); 673 free(s); 674 file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend); 675 free(mdepend); 676 break; 677 case MDT_VERSION: 678 s = strdupout((vm_offset_t)md.md_cval); 679 COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); 680 file_addmodule(fp, s, mver.mv_version, NULL); 681 free(s); 682 modcnt++; 683 break; 684 } 685 } 686 if (modcnt == 0) { 687 s = fake_modname(fp->f_name); 688 file_addmodule(fp, s, 1, NULL); 689 free(s); 690 } 691 return 0; 692} 693 694static unsigned long 695elf_hash(const char *name) 696{ 697 const unsigned char *p = (const unsigned char *) name; 698 unsigned long h = 0; 699 unsigned long g; 700 701 while (*p != '\0') { 702 h = (h << 4) + *p++; 703 if ((g = h & 0xf0000000) != 0) 704 h ^= g >> 24; 705 h &= ~g; 706 } 707 return h; 708} 709 710static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; 711int 712__elfN(lookup_symbol)(struct preloaded_file *fp, elf_file_t ef, const char* name, 713 Elf_Sym *symp) 714{ 715 Elf_Hashelt symnum; 716 Elf_Sym sym; 717 char *strp; 718 unsigned long hash; 719 720 hash = elf_hash(name); 721 COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); 722 723 while (symnum != STN_UNDEF) { 724 if (symnum >= ef->nchains) { 725 printf(__elfN(bad_symtable)); 726 return ENOENT; 727 } 728 729 COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); 730 if (sym.st_name == 0) { 731 printf(__elfN(bad_symtable)); 732 return ENOENT; 733 } 734 735 strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); 736 if (strcmp(name, strp) == 0) { 737 free(strp); 738 if (sym.st_shndx != SHN_UNDEF || 739 (sym.st_value != 0 && 740 ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { 741 *symp = sym; 742 return 0; 743 } 744 return ENOENT; 745 } 746 free(strp); 747 COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); 748 } 749 return ENOENT; 750} 751 752/* 753 * Apply any intra-module relocations to the value. p is the load address 754 * of the value and val/len is the value to be modified. This does NOT modify 755 * the image in-place, because this is done by kern_linker later on. 756 * 757 * Returns EOPNOTSUPP if no relocation method is supplied. 758 */ 759static int 760__elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, 761 Elf_Addr p, void *val, size_t len) 762{ 763 size_t n; 764 Elf_Rela a; 765 Elf_Rel r; 766 int error; 767 768 /* 769 * The kernel is already relocated, but we still want to apply 770 * offset adjustments. 771 */ 772 if (ef->kernel) 773 return (EOPNOTSUPP); 774 775 for (n = 0; n < ef->relsz / sizeof(r); n++) { 776 COPYOUT(ef->rel + n, &r, sizeof(r)); 777 778 error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL, 779 ef->off, p, val, len); 780 if (error != 0) 781 return (error); 782 } 783 for (n = 0; n < ef->relasz / sizeof(a); n++) { 784 COPYOUT(ef->rela + n, &a, sizeof(a)); 785 786 error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA, 787 ef->off, p, val, len); 788 if (error != 0) 789 return (error); 790 } 791 792 return (0); 793} 794 795static Elf_Addr 796__elfN(symaddr)(struct elf_file *ef, Elf_Size symidx) 797{ 798 799 /* Symbol lookup by index not required here. */ 800 return (0); 801} 802