/*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: load_aout.c,v 1.13 1999/01/22 23:50:14 msmith Exp $ */ #include #include #include #include #include #include #include #include #include #define FREEBSD_AOUT #include #include "bootstrap.h" static int aout_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel); #if 0 static vm_offset_t aout_findkldident(struct loaded_module *mp, struct exec *ehdr); static int aout_fixupkldmod(struct loaded_module *mp, struct exec *ehdr); #endif char *aout_kerneltype = "a.out kernel"; char *aout_moduletype = "a.out module"; /* * Attempt to load the file (file) as an a.out module. It will be stored at * (dest), and a pointer to a module structure describing the loaded object * will be saved in (result). */ int aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) { struct loaded_module *mp, *kmp; struct exec ehdr; int fd; vm_offset_t addr; int err, kernel; u_int pad; char *s; mp = NULL; /* * Open the image, read and validate the a.out header */ if (filename == NULL) /* can't handle nameless */ return(EFTYPE); if ((fd = open(filename, O_RDONLY)) == -1) return(errno); if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) { err = EFTYPE; /* could be EIO, but may be small file */ goto oerr; } if (N_BADMAG(ehdr)) { err = EFTYPE; goto oerr; } /* * Check to see what sort of module we are. * * XXX should check N_GETMID() */ kmp = mod_findmodule(NULL, NULL); if ((N_GETFLAG(ehdr)) & EX_DYNAMIC) { /* Looks like a kld module */ if (kmp == NULL) { printf("aout_loadmodule: can't load module before kernel\n"); err = EPERM; goto oerr; } if (strcmp(aout_kerneltype, kmp->m_type)) { printf("aout_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type); err = EPERM; goto oerr; } /* Looks OK, got ahead */ kernel = 0; } else if (N_GETFLAG(ehdr) == 0) { /* Looks like a kernel */ if (kmp != NULL) { printf("aout_loadmodule: kernel already loaded\n"); err = EPERM; goto oerr; } /* * Calculate destination address based on kernel entrypoint * XXX this is i386-freebsd-aout specific */ dest = ehdr.a_entry & 0x100000; if (dest == 0) { printf("aout_loadmodule: not a kernel (maybe static binary?)\n"); err = EPERM; goto oerr; } kernel = 1; } else { err = EFTYPE; goto oerr; } /* * Ok, we think we should handle this. */ mp = mod_allocmodule(); if (kernel) setenv("kernelname", filename, 1); s = strrchr(filename, '/'); if (s) mp->m_name = strdup(s + 1); else mp->m_name = strdup(filename); mp->m_type = strdup(kernel ? aout_kerneltype : aout_moduletype); /* Page-align the load address */ addr = dest; pad = (u_int)addr & PAGE_MASK; if (pad != 0) { pad = PAGE_SIZE - pad; addr += pad; } mp->m_addr = addr; /* save the aligned load address */ if (kernel) printf("%s at %p\n", filename, (void *) addr); mp->m_size = aout_loadimage(mp, fd, addr, &ehdr, kernel); if (mp->m_size == 0) goto ioerr; #if 0 /* Handle KLD module data */ if (!kernel && ((err = aout_fixupkldmod(mp, &ehdr)) != 0)) goto oerr; #endif /* save exec header as metadata */ mod_addmetadata(mp, MODINFOMD_AOUTEXEC, sizeof(struct exec), &ehdr); /* Load OK, return module pointer */ *result = (struct loaded_module *)mp; err = 0; goto out; ioerr: err = EIO; oerr: mod_discard(mp); out: close(fd); return(err); } /* * With the file (fd) open on the image, and (ehdr) containing * the exec header, load the image at (addr) * * Fixup the a_bss field in (ehdr) to reflect the padding added to * align the symbol table. */ static int aout_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel) { u_int pad; vm_offset_t addr; int ss; vm_offset_t ssym, esym; addr = loadaddr; lseek(fd, N_TXTOFF(*ehdr), SEEK_SET); /* text segment */ printf(" text=0x%lx ", ehdr->a_text); if (archsw.arch_readin(fd, addr, ehdr->a_text) != ehdr->a_text) return(0); addr += ehdr->a_text; /* data segment */ printf("data=0x%lx ", ehdr->a_data); if (archsw.arch_readin(fd, addr, ehdr->a_data) != ehdr->a_data) return(0); addr += ehdr->a_data; /* For kernels, we pad the BSS to a page boundary */ if (kernel) { pad = (u_int)ehdr->a_bss & PAGE_MASK; if (pad != 0) { pad = PAGE_SIZE - pad; ehdr->a_bss += pad; } } printf("bss=0x%lx ", ehdr->a_bss); addr += ehdr->a_bss; /* symbol table size */ ssym = esym = addr; if(ehdr->a_syms!=NULL) { archsw.arch_copyin(&ehdr->a_syms, addr, sizeof(ehdr->a_syms)); addr += sizeof(ehdr->a_syms); /* symbol table */ printf("symbols=[0x%x+0x%lx", sizeof(ehdr->a_syms), ehdr->a_syms); if (archsw.arch_readin(fd, addr, ehdr->a_syms) != ehdr->a_syms) return(0); addr += ehdr->a_syms; /* string table */ read(fd, &ss, sizeof(ss)); archsw.arch_copyin(&ss, addr, sizeof(ss)); addr += sizeof(ss); ss -= sizeof(ss); printf("+0x%x+0x%x]", sizeof(ss), ss); if (archsw.arch_readin(fd, addr, ss) != ss) return(0); addr += ss; esym = addr; mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym); mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym); } else { printf("symbols=[none]"); } printf("\n"); return(addr - loadaddr); }