diff --git a/sbin/modload/Makefile b/sbin/modload/Makefile index 020980d59ac1..8e2c32d33fc4 100644 --- a/sbin/modload/Makefile +++ b/sbin/modload/Makefile @@ -1,40 +1,17 @@ -# $NetBSD: Makefile,v 1.6 1995/03/18 14:56:41 cgd Exp $ -# -# Makefile for modload -# -# 25 May 93 Terry Lambert Original -# -# Copyright (c) 1993 Terrence R. Lambert. -# 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by Terrence R. Lambert. -# 4. The name Terrence R. Lambert may not be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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. +# $NetBSD: Makefile,v 1.7 1999/06/13 12:54:40 mrg Exp $ +WARNS= 1 PROG= modload +SRCS= modload.c MAN= modload.8 +.include # for OBJECT_FMT + +.if (${OBJECT_FMT} == "ELF") +SRCS+= elf.c +.else +SRCS+= a.out.c +CFLAGS+=-DUSE_AOUT +.endif + .include diff --git a/sbin/modload/a.out.c b/sbin/modload/a.out.c new file mode 100644 index 000000000000..eecddd87fbed --- /dev/null +++ b/sbin/modload/a.out.c @@ -0,0 +1,256 @@ +/* $NetBSD: a.out.c,v 1.1 1999/06/13 12:54:40 mrg Exp $ */ + +/* + * Copyright (c) 1993 Terrence R. Lambert. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Terrence R. Lambert. + * 4. The name Terrence R. Lambert may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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. + */ + +#include +__RCSID("$NetBSD: a.out.c,v 1.1 1999/06/13 12:54:40 mrg Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "modload.h" + +/* + * Expected linker options: + * + * -A executable to link against + * -e entry point + * -o output file + * -T address to link to in hex (assumes it's a page boundry) + * object file + */ + +#define LINKCMD "ld -A %s -e _%s -o %s -T %p %s" + +void +a_out_linkcmd(char *buf, + size_t len, + const char *kernel, + const char *entry, + const char *outfile, + const void *address, + const char *object) +{ + ssize_t n; + + n = snprintf(buf, len, LINKCMD, kernel, entry, + outfile, address, object); + if (n >= len) + errx(1, "link command longer than %lu bytes", (u_long)len); +} + +static int +a_out_read_header(int fd, struct exec *info_buf) +{ + ssize_t n; + + n = read(fd, info_buf, sizeof(*info_buf)); + if (n < 0) + err(1, "failed reading %lu bytes", (u_long)sizeof(*info_buf)); + if (n != sizeof(*info_buf)) { + if (debug) + fprintf(stderr, "failed to read %lu bytes", + (u_long)sizeof(*info_buf)); + return -1; + } + + /* + * Magic number... + */ + if (N_BADMAG(*info_buf)) + errx(4, "not an a.out format file"); + return 0; +} + +extern int symtab; + +int +a_out_mod_sizes(fd, modsize, strtablen, resrvp, sp) + int fd; + size_t *modsize; + int *strtablen; + struct lmc_resrv *resrvp; + struct stat *sp; +{ + struct exec info_buf; + + if (a_out_read_header(fd, &info_buf) < 0) + return -1; + + /* + * Calculate the size of the module + */ + *modsize = info_buf.a_text + info_buf.a_data + info_buf.a_bss; + + *strtablen = sp->st_size - N_STROFF(info_buf); + + if (symtab) { + /* + * XXX TODO: grovel through symbol table looking for + * just the symbol table stuff from the new module, + * and skip the stuff from the kernel. + */ + resrvp->sym_size = info_buf.a_syms + *strtablen; + resrvp->sym_symsize = info_buf.a_syms; + } else + resrvp->sym_size = resrvp->sym_symsize = 0; + + return (0); +} + +void * +a_out_mod_load(int fd) +{ + struct exec info_buf; + size_t b; + ssize_t n; + char buf[10 * BUFSIZ]; + + /* + * Get the load module post load size... do this by reading the + * header and doing page counts. + */ + if (a_out_read_header(fd, &info_buf) < 0) + return NULL; + + /* + * Seek to the text offset to start loading... + */ + if (lseek(fd, N_TXTOFF(info_buf), 0) == -1) + err(12, "lseek"); + + /* + * Transfer the relinked module to kernel memory in chunks of + * MODIOBUF size at a time. + */ + b = info_buf.a_text + info_buf.a_data; + while (b) { + n = read(fd, buf, MIN(b, sizeof(buf))); + if (n < 0) + err(1, "while reading from prelinked module"); + if (n == 0) + errx(1, "EOF while reading from prelinked module"); + + loadbuf(buf, n); + b -= n; + } + return (void*)info_buf.a_entry; +} + +extern int devfd, modfd; +extern struct lmc_resrv resrv; + +void +a_out_mod_symload(strtablen) + int strtablen; +{ + struct exec info_buf; + struct lmc_loadbuf ldbuf; + struct nlist *nlp; + char buf[10 * BUFSIZ]; + char *symbuf; + int bytesleft, sz; + int numsyms; /* XXX unused? */ + + if (a_out_read_header(modfd, &info_buf) < 0) + return; + + /* + * Seek to the symbol table to start loading it... + */ + if (lseek(modfd, N_SYMOFF(info_buf), SEEK_SET) == -1) + err(12, "lseek"); + + /* + * Transfer the symbol table entries. First, read them all in, + * then adjust their string table pointers, then + * copy in bulk. Then copy the string table itself. + */ + + symbuf = malloc(info_buf.a_syms); + if (symbuf == 0) + err(13, "malloc"); + + if (read(modfd, symbuf, info_buf.a_syms) != info_buf.a_syms) + err(14, "read"); + numsyms = info_buf.a_syms / sizeof(struct nlist); + + for (nlp = (struct nlist *)symbuf; + (char *)nlp < symbuf + info_buf.a_syms; nlp++) { + register int strx; + + strx = nlp->n_un.n_strx; + if (strx != 0) { + /* + * If a valid name, set the name ptr to point at the + * loaded address for the string in the string table. + */ + if (strx > strtablen) + nlp->n_un.n_name = 0; + else + nlp->n_un.n_name = (char *)(strx + + resrv.sym_addr + info_buf.a_syms); + } + } + /* + * we've fixed the symbol table entries, now load them + */ + for (bytesleft = info_buf.a_syms; bytesleft > 0; bytesleft -= sz) { + sz = MIN(bytesleft, MODIOBUF); + ldbuf.cnt = sz; + ldbuf.data = symbuf; + if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) + err(11, "error transferring sym buffer"); + symbuf += sz; + } + + free(symbuf - info_buf.a_syms); + /* and now read the string table and load it. */ + for (bytesleft = strtablen; bytesleft > 0; bytesleft -= sz) { + sz = MIN(bytesleft, MODIOBUF); + read(modfd, buf, sz); + ldbuf.cnt = sz; + ldbuf.data = buf; + if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) + err(11, "error transferring stringtable buffer"); + } +} diff --git a/sbin/modload/elf.c b/sbin/modload/elf.c new file mode 100644 index 000000000000..f5bccb3c2118 --- /dev/null +++ b/sbin/modload/elf.c @@ -0,0 +1,341 @@ +/* $NetBSD: elf.c,v 1.1 1999/06/13 12:54:40 mrg Exp $ */ + +/* + * Copyright (c) 1998 Johan Danielsson + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#include +__RCSID("$NetBSD: elf.c,v 1.1 1999/06/13 12:54:40 mrg Exp $"); + +#include + +#if defined(__alpha__) || defined(__arch64__) +#define ELFSIZE 64 +#else +#define ELFSIZE 32 +#endif +#include +#ifndef ELF_HDR_SIZE +#define ELF_HDR_SIZE sizeof(Elf_Ehdr) +#endif +#include + +#include +#include +#include +#include +#include +#include + +#include "modload.h" + +static void +read_section_header(int fd, Elf_Ehdr *ehdr, int num, Elf_Shdr *shdr) +{ + + if (lseek(fd, ehdr->e_shoff + num * ehdr->e_shentsize, SEEK_SET) < 0) + err(1, "lseek"); + if (read(fd, shdr, sizeof(*shdr)) != sizeof(*shdr)) + err(1, "read"); +} + +struct elf_section { + char *name; /* name of section; points into string table */ + enum Elf_s_sht type; /* type of section */ + void *addr; /* load address of section */ + off_t offset; /* offset in file */ + size_t size; /* size of section */ + size_t align; + struct elf_section *next; +}; + +/* adds the section `s' at the correct (sorted by address) place in + the list ponted to by head; *head may be NULL */ +static void +add_section(struct elf_section **head, struct elf_section *s) +{ + struct elf_section *p, **q; + q = head; + p = *head; + + while (1) { + if (p == NULL || p->addr > s->addr) { + s->next = p; + *q = s; + return; + } + q = &p->next; + p = p->next; + } +} + +/* make a linked list of all sections containing ALLOCatable data */ +static void +read_sections(int fd, Elf_Ehdr *ehdr, char *strtab, struct elf_section **head) +{ + int i; + Elf_Shdr shdr; + *head = NULL; + /* scan through section headers */ + for (i = 0; i < ehdr->e_shnum; i++) { + struct elf_section *s; + read_section_header(fd, ehdr, i, &shdr); + if ((shdr.sh_flags & SHF_ALLOC) == 0) + /* skip non-ALLOC sections */ + continue; + s = malloc(sizeof(*s)); + if (s == NULL) + errx(1, "failed to allocate %lu bytes", (u_long)sizeof(*s)); + s->name = strtab + shdr.sh_name; + s->type = shdr.sh_type; + s->addr = (void*)shdr.sh_addr; + s->offset = shdr.sh_offset; + s->size = shdr.sh_size; + s->align = shdr.sh_addralign; + add_section(head, s); + } +} + +/* free a list of section headers */ +static void +free_sections(struct elf_section *head) +{ + + while (head) { + struct elf_section *p = head; + head = head->next; + free(p); + } +} + +/* read string table */ +static char * +read_string_table(int fd, Elf_Ehdr *ehdr) +{ + Elf_Shdr shdr; + char *strtab; + read_section_header(fd, ehdr, ehdr->e_shstrndx, &shdr); + strtab = malloc(shdr.sh_size); + if (strtab == NULL) + errx(1, "failed to allocate %lu bytes", (u_long)shdr.sh_size); + if (lseek(fd, shdr.sh_offset, SEEK_SET) < 0) + err(1, "lseek"); + if (read(fd, strtab, shdr.sh_size) != shdr.sh_size) + err(1, "read"); + return strtab; +} + +static int +read_elf_header(int fd, Elf_Ehdr *ehdr) +{ + ssize_t n; + + n = read(fd, ehdr, sizeof(*ehdr)); + if (n < 0) + err(1, "failed reading %lu bytes", (u_long)sizeof(*ehdr)); + if (n != sizeof(*ehdr)) { + if (debug) + warnx("failed to read %lu bytes", (u_long)sizeof(*ehdr)); + return -1; + } + if (memcmp(ehdr->e_ident, Elf_e_ident, Elf_e_siz) != 0) + errx(4, "not in ELF%u format", ELFSIZE); + if (ehdr->e_ehsize != ELF_HDR_SIZE) + errx(4, "file has ELF%u identity, but wrong header size", + ELFSIZE); + + return 0; +} + +/* offset of data segment; this is horrible, but keeps the size of the + module to a minimum */ +static ssize_t data_offset; + +/* return size needed by the module */ +int +elf_mod_sizes(fd, modsize, strtablen, resrvp, sp) + int fd; + size_t *modsize; + int *strtablen; + struct lmc_resrv *resrvp; + struct stat *sp; +{ + Elf_Ehdr ehdr; + ssize_t off = 0; + size_t data_hole = 0; + char *strtab; + struct elf_section *head, *s; + + if (read_elf_header(fd, &ehdr) < 0) + return -1; + strtab = read_string_table(fd, &ehdr); + read_sections(fd, &ehdr, strtab, &head); + + for (s = head; s && s->next; s = s->next) { + if (debug) + fprintf(stderr, + "%s: addr = %p size = %#lx align = %#lx\n", + s->name, s->addr, (u_long)s->size, (u_long)s->align); + /* XXX try to get rid of the hole before the data + section that GNU-ld likes to put there */ + if (strcmp(s->name, ".data") == 0 && s->addr > (void*)off) { + if (debug) + fprintf(stderr, ".data section forced to " + "offset %p (was %p)\n", + (void*)off, + s->addr); + data_offset = off; + /* later remove size of compressed hole from off */ + data_hole = (ssize_t)s->addr - off; + } + off = (ssize_t)s->addr + s->size; + } + off -= data_hole; + + /* cleanup */ + free_sections(head); + free(strtab); + + /* XXX round to pagesize? */ +#define ROUND(V, S) (((V) + (S) - 1) & ~((S) - 1)) + *modsize = ROUND(off, sysconf(_SC_PAGESIZE)); + + /* + * XXX no symbol table support + */ + *strtablen = 0; + resrvp->sym_size = resrvp->sym_symsize = 0; + + return (0); +} + +/* + * Expected linker options: + * + * -R executable to link against + * -e entry point + * -o output file + * -Ttext address to link text segment to in hex (assumes it's + * a page boundry) + * -Tdata address to link data segment to in hex + * object file */ + +#define LINKCMD "ld -R %s -e %s -o %s -Ttext %p %s" +#define LINKCMD2 "ld -R %s -e %s -o %s -Ttext %p -Tdata %p %s" + +/* make a link command; XXX if data_offset above is non-zero, force + data address to be at start of text + offset */ +void +elf_linkcmd(char *buf, + size_t len, + const char *kernel, + const char *entry, + const char *outfile, + const void *address, + const char *object) +{ + ssize_t n; + + if (data_offset == NULL) + n = snprintf(buf, len, LINKCMD, kernel, entry, + outfile, address, object); + else + n = snprintf(buf, len, LINKCMD2, kernel, entry, + outfile, address, + (const char*)address + data_offset, object); + if (n >= len) + errx(1, "link command longer than %lu bytes", (u_long)len); +} + +/* load a prelinked module; returns entry point */ +void * +elf_mod_load(int fd) +{ + Elf_Ehdr ehdr; + size_t zero_size = 0; + size_t b; + ssize_t n; + char *strtab; + struct elf_section *head, *s; + char buf[10 * BUFSIZ]; + void *addr = NULL; + + if (read_elf_header(fd, &ehdr) < 0) + return NULL; + + strtab = read_string_table(fd, &ehdr); + read_sections(fd, &ehdr, strtab, &head); + + for (s = head; s; s = s->next) { + if (debug) + fprintf(stderr, "loading `%s': addr = %p, " + "size = %#lx\n", + s->name, s->addr, (u_long)s->size); + if (s->type == Elf_sht_nobits) + /* skip some space */ + zero_size += s->size; + else { + if (addr != NULL) { + /* if there is a gap in the prelinked + module, transfer some empty + space... */ + zero_size += (char*)s->addr - (char*)addr; + } + if (zero_size) { + loadspace(zero_size); + zero_size = 0; + } + b = s->size; + if (lseek(fd, s->offset, SEEK_SET) == -1) + err(1, "lseek"); + while (b) { + n = read(fd, buf, MIN(b, sizeof(buf))); + if (n == 0) + errx(1, "unexpected EOF"); + if (n < 0) + err(1, "read"); + loadbuf(buf, n); + b -= n; + } + addr = (char*)s->addr + s->size; + } + } + /* any trailing zero_space will be filled with zeros by the + LKM framework */ + + free_sections(head); + free(strtab); + return (void*)ehdr.e_entry; +} + +void +elf_mod_symload(strtablen) + int strtablen; +{ + + warnx("ELF can not load symbols"); +} diff --git a/sbin/modload/modload.8 b/sbin/modload/modload.8 index e1133c894a6e..41623bcec40d 100644 --- a/sbin/modload/modload.8 +++ b/sbin/modload/modload.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: modload.8,v 1.11 1999/04/30 18:32:01 ross Exp $ +.\" $NetBSD: modload.8,v 1.12 1999/06/13 12:54:40 mrg Exp $ .\" .\" Copyright (c) 1993 Christopher G. Demetriou .\" All rights reserved. @@ -33,7 +33,7 @@ .Nd load a kernel module .Sh SYNOPSIS .Nm "" -.Op Fl dvs +.Op Fl dnvsS .Op Fl A Ar kernel .Op Fl e Ar entry .Op Fl p Ar postinstall @@ -53,10 +53,17 @@ are as follows: Debug. Used to debug .Nm itself. +.It Fl n +Do everything, except calling the module entry point (and any +post-install program). .It Fl v Print comments about the loading process. .It Fl s Load the symbol table. +.It Fl S +Do not remove the temporary object file. By default, the +.Xr ld 1 +output is removed after being loaded into the kernel. .It Fl A Ar kernel Specify the file that is passed to the linker to resolve module references to external symbols. diff --git a/sbin/modload/modload.c b/sbin/modload/modload.c index aba435922972..7ee9dadb7def 100644 --- a/sbin/modload/modload.c +++ b/sbin/modload/modload.c @@ -1,4 +1,4 @@ -/* $NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $ */ +/* $NetBSD: modload.c,v 1.25 1999/06/13 12:54:40 mrg Exp $ */ /* * Copyright (c) 1993 Terrence R. Lambert. @@ -34,7 +34,7 @@ #include #ifndef lint -__RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $"); +__RCSID("$NetBSD: modload.c,v 1.25 1999/06/13 12:54:40 mrg Exp $"); #endif /* not lint */ #include @@ -44,7 +44,6 @@ __RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $"); #include #include #include -#include #include #include #include @@ -57,6 +56,8 @@ __RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $"); #define TRUE 1 #define FALSE 0 +#include "modload.h" + #ifndef DFLT_ENTRY #define DFLT_ENTRY "xxxinit" #endif /* !DFLT_ENTRY */ @@ -64,46 +65,30 @@ __RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $"); #define DFLT_ENTRYEXT "_lkmentry" #endif /* !DFLT_ENTRYEXT */ -/* - * Expected linker options: - * - * -A executable to link against - * -e entry point - * -o output file - * -T address to link to in hex (assumes it's a page boundry) - * object file - */ -#ifdef __alpha__ -#define LINKCMD "ld -R %s -e %s -o %s -Ttext %x %s" -#else -#define LINKCMD "ld -A %s -e _%s -o %s -T %x %s" -#endif - -void cleanup __P((void)); -int linkcmd __P((char *, char *, char *, u_int, char *)); -int main __P((int, char *[])); -void usage __P((void)); -int verify_entry __P((char *, char *)); - int debug = 0; int verbose = 0; +char *out = NULL; int symtab = 0; +int Sflag; -int -linkcmd(kernel, entry, outfile, address, object) - char *kernel, *entry, *outfile; - u_int address; /* XXX */ - char *object; +static void cleanup __P((void)); + +/* prelink the module */ +static int +prelink(const char *kernel, + const char *entry, + const char *outfile, + const void *address, + const char *object) { char cmdbuf[1024]; int error = 0; - if (snprintf(cmdbuf, sizeof(cmdbuf), LINKCMD, kernel, entry, outfile, - address, object) >= sizeof(cmdbuf)) - errx(1, "link command too long"); + linkcmd(cmdbuf, sizeof(cmdbuf), + kernel, entry, outfile, address, object); if (debug) - printf("%s\n", cmdbuf); + fprintf(stderr, "%s\n", cmdbuf); switch (system(cmdbuf)) { case 0: /* SUCCESS! */ @@ -128,14 +113,14 @@ linkcmd(kernel, entry, outfile, address, object) return error; } -void -usage() +static void +usage(void) { fprintf(stderr, "usage:\n"); - fprintf(stderr, "modload [-d] [-v] [-A ] [-e ] [-e ]\n"); fprintf(stderr, - "[-p ] [-o ] \n"); + " [-p ] [-o ] \n"); exit(1); } @@ -143,12 +128,15 @@ int fileopen = 0; #define DEV_OPEN 0x01 #define MOD_OPEN 0x02 #define PART_RESRV 0x04 +#define OUTFILE_CREAT 0x08 + int devfd, modfd; struct lmc_resrv resrv; -void -cleanup() +static void +cleanup(void) { + if (fileopen & PART_RESRV) { /* * Free up kernel memory @@ -162,11 +150,13 @@ cleanup() if (fileopen & MOD_OPEN) close(modfd); + + if (fileopen & OUTFILE_CREAT) + unlink(out); } -int -verify_entry(entry, filename) - char *entry, *filename; +static int +verify_entry(char *entry, char *filename) { struct nlist names[2]; int n; @@ -188,31 +178,58 @@ verify_entry(entry, filename) return n; } +/* + * Transfer data to kernel memory in chunks + * of MODIOBUF size at a time. + */ +void +loadbuf(void *buf, size_t len) +{ + struct lmc_loadbuf ldbuf; + size_t n; + char *p = buf; + + while(len) { + n = MIN(len, MODIOBUF); + ldbuf.cnt = n; + ldbuf.data = p; + if(ioctl(devfd, LMLOADBUF, &ldbuf) == -1) + err(11, "error loading buffer"); + len -= n; + p += n; + } +} + +/* Transfer some empty space. */ +void +loadspace(size_t len) +{ + char buf[MODIOBUF]; + size_t n; + memset(buf, 0, sizeof(buf)); + while(len) { + n = MIN(len, sizeof(buf)); + loadbuf(buf, n); + len -= n; + } +} + int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char **argv) { int c; char *kname = _PATH_UNIX; char *entry = DFLT_ENTRY; char *post = NULL; - char *out = NULL; char *modobj; char modout[80], *p; - struct exec info_buf; struct stat stb; - u_int modsize; /* XXX */ - u_int modentry; /* XXX */ - struct nlist *nlp; - int strtablen, numsyms; + int strtablen; + size_t modsize; /* XXX */ + void* modentry; /* XXX */ + int noready = 0, old = 0; - struct lmc_loadbuf ldbuf; - int sz, bytesleft, old = FALSE; - char buf[MODIOBUF]; - char *symbuf; - - while ((c = getopt(argc, argv, "dvsA:e:p:o:")) != -1) { + while ((c = getopt(argc, argv, "dnvsAS:e:p:o:")) != -1) { switch (c) { case 'd': debug = 1; @@ -232,11 +249,18 @@ main(argc, argv) case 'o': out = optarg; break; /* output file */ + case 'n': + noready = 1; + break; case 's': symtab = 1; break; + case 'S': + Sflag = 1; + break; case '?': usage(); + /* NOTREACHED */ default: printf("default!\n"); break; @@ -261,7 +285,8 @@ main(argc, argv) err(3, _PATH_LKM); fileopen |= DEV_OPEN; - strcpy(modout, modobj); + strncpy(modout, modobj, sizeof(modout) - 1); + modout[sizeof(modout) - 1] = '\0'; p = strrchr(modout, '.'); if (!p || strcmp(p, ".o")) @@ -282,7 +307,7 @@ main(argc, argv) p++; else p = modout; - entry = (char *)malloc(strlen(p) + + entry = malloc(strlen(p) + strlen(DFLT_ENTRYEXT) + 1); strcpy(entry, p); strcat(entry, DFLT_ENTRYEXT); @@ -297,45 +322,36 @@ main(argc, argv) /* * Prelink to get file size */ - if (linkcmd(kname, entry, out, 0, modobj)) + if (prelink(kname, entry, out, 0, modobj)) errx(1, "can't prelink `%s' creating `%s'", modobj, out); - - /* - * Pre-open the 0-linked module to get the size information - */ + if (Sflag == 0) + fileopen |= OUTFILE_CREAT; + + /* + * Pre-open the 0-linked module to get the size information + */ if ((modfd = open(out, O_RDONLY, 0)) == -1) - err(4, out); + err(4, "%s", out); fileopen |= MOD_OPEN; - /* - * Get the load module post load size... do this by reading the - * header and doing page counts. - */ - if (read(modfd, &info_buf, sizeof(struct exec)) == -1) - err(3, "read `%s'", out); /* * stat for filesize to figure out string table size */ if (fstat(modfd, &stb) == -1) err(3, "fstat `%s'", out); + /* + * work out various sizes and fill in resrv bits + */ + if (mod_sizes(modfd, &modsize, &strtablen, &resrv, &stb) != 0) + err(1, "can't get module sizes"); + /* * Close the dummy module -- we have our sizing information. */ close(modfd); fileopen &= ~MOD_OPEN; - /* - * Magic number... - */ - if (N_BADMAG(info_buf)) - errx(4, "not an a.out format file"); - - /* - * Calculate the size of the module - */ - modsize = info_buf.a_text + info_buf.a_data + info_buf.a_bss; - /* * Reserve the required amount of kernel memory -- this may fail * to be successful. @@ -344,16 +360,9 @@ main(argc, argv) resrv.name = modout; /* objname w/o ".o" */ resrv.slot = -1; /* returned */ resrv.addr = 0; /* returned */ - strtablen = stb.st_size - N_STROFF(info_buf); - if (symtab) { - /* XXX TODO: grovel through symbol table looking - for just the symbol table stuff from the new module, - and skip the stuff from the kernel. */ - resrv.sym_size = info_buf.a_syms + strtablen; - resrv.sym_symsize = info_buf.a_syms; - } else - resrv.sym_size = resrv.sym_symsize = 0; + if (verbose) + warnx("reserving %lu bytes of memory", (unsigned long)modsize); if (ioctl(devfd, LMRESERV, &resrv) == -1) { if (symtab) warn("not loading symbols: kernel does not support symbol table loading"); @@ -368,118 +377,32 @@ main(argc, argv) /* * Relink at kernel load address */ - if (linkcmd(kname, entry, out, resrv.addr, modobj)) - errx(1, "can't link `%s' creating `%s' bound to 0x%08lx", - modobj, out, (long) resrv.addr); + if (prelink(kname, entry, out, (void*)resrv.addr, modobj)) + errx(1, "can't link `%s' creating `%s' bound to %p", + modobj, out, (void*)resrv.addr); /* * Open the relinked module to load it... */ if ((modfd = open(out, O_RDONLY, 0)) == -1) - err(4, out); + err(4, "%s", out); fileopen |= MOD_OPEN; - /* - * Reread the header to get the actual entry point *after* the - * relink. - */ - if (read(modfd, &info_buf, sizeof(struct exec)) == -1) - err(3, "read `%s'", out); + modentry = mod_load(modfd); + if (debug) + fprintf(stderr, "modentry = %p\n", modentry); - /* - * Get the entry point (for initialization) - */ - modentry = info_buf.a_entry; /* place to call */ + if (symtab) + mod_symload(strtablen); - /* - * Seek to the text offset to start loading... - */ - if (lseek(modfd, N_TXTOFF(info_buf), 0) == -1) - err(12, "lseek"); - - /* - * Transfer the relinked module to kernel memory in chunks of - * MODIOBUF size at a time. - */ - for (bytesleft = info_buf.a_text + info_buf.a_data; - bytesleft > 0; - bytesleft -= sz) { - sz = MIN(bytesleft, MODIOBUF); - read(modfd, buf, sz); - ldbuf.cnt = sz; - ldbuf.data = buf; - if (ioctl(devfd, LMLOADBUF, &ldbuf) == -1) - err(11, "error transferring buffer"); - } - - - if (symtab) { - /* - * Seek to the symbol table to start loading it... - */ - if (lseek(modfd, N_SYMOFF(info_buf), SEEK_SET) == -1) - err(12, "lseek"); - - /* - * Transfer the symbol table entries. First, read them all in, - * then adjust their string table pointers, then - * copy in bulk. Then copy the string table itself. - */ - - symbuf = malloc(info_buf.a_syms); - if (symbuf == 0) - err(13, "malloc"); - - if (read(modfd, symbuf, info_buf.a_syms) != info_buf.a_syms) - err(14, "read"); - numsyms = info_buf.a_syms / sizeof(struct nlist); - for (nlp = (struct nlist *)symbuf; - (char *)nlp < symbuf + info_buf.a_syms; - nlp++) { - register int strx; - strx = nlp->n_un.n_strx; - if (strx != 0) { - /* If a valid name, set the name ptr to point at the - * loaded address for the string in the string table. - */ - if (strx > strtablen) - nlp->n_un.n_name = 0; - else - nlp->n_un.n_name = - (char *)(strx + resrv.sym_addr + info_buf.a_syms); - } - } - /* - * we've fixed the symbol table entries, now load them - */ - for (bytesleft = info_buf.a_syms; - bytesleft > 0; - bytesleft -= sz) { - sz = MIN(bytesleft, MODIOBUF); - ldbuf.cnt = sz; - ldbuf.data = symbuf; - if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) - err(11, "error transferring sym buffer"); - symbuf += sz; - } - free(symbuf - info_buf.a_syms); - /* and now read the string table and load it. */ - for (bytesleft = strtablen; - bytesleft > 0; - bytesleft -= sz) { - sz = MIN(bytesleft, MODIOBUF); - read(modfd, buf, sz); - ldbuf.cnt = sz; - ldbuf.data = buf; - if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) - err(11, "error transferring stringtable buffer"); - } - } /* * Save ourselves before disaster (potentitally) strikes... */ sync(); + if (noready) + return 0; + /* * Trigger the module as loaded by calling the entry procedure; * this will do all necessary table fixup to ensure that state @@ -528,5 +451,5 @@ main(argc, argv) err(16, "can't exec `%s'", post); } - return 0; + exit (0); } diff --git a/sbin/modload/modload.h b/sbin/modload/modload.h new file mode 100644 index 000000000000..de06f013655a --- /dev/null +++ b/sbin/modload/modload.h @@ -0,0 +1,70 @@ +/* $NetBSD: modload.h,v 1.1 1999/06/13 12:54:40 mrg Exp $ */ + +/* + * Copyright (c) 1993 Terrence R. Lambert. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Terrence R. Lambert. + * 4. The name Terrence R. Lambert may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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. + */ + +#ifndef __modload_h__ +#define __modload_h__ + +int elf_mod_sizes __P((int, size_t *, int *, struct lmc_resrv *, + struct stat *)); +void *elf_mod_load __P((int)); +void elf_linkcmd __P((char*, size_t, const char*, const char*, + const char*, const void*, const char*)); +void elf_mod_symload __P((int)); + +int a_out_mod_sizes __P((int, size_t *, int *, struct lmc_resrv *, + struct stat *)); +void *a_out_mod_load __P((int)); +void a_out_linkcmd __P((char*, size_t, const char*, const char*, + const char*, const void*, const char*)); +void a_out_mod_symload __P((int)); + +#ifndef USE_AOUT +#define mod_sizes elf_mod_sizes +#define mod_load elf_mod_load +#define mod_symload elf_mod_symload +#define linkcmd elf_linkcmd +#else +#define mod_sizes a_out_mod_sizes +#define mod_load a_out_mod_load +#define mod_symload a_out_mod_symload +#define linkcmd a_out_linkcmd +#endif + +void loadbuf(void*, size_t); +void loadspace(size_t); + +extern int debug; +extern int verbose; + +#endif /* __modload_h__ */