summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorEric Jackson <ericj@cvs.openbsd.org>2002-01-08 21:28:39 +0000
committerEric Jackson <ericj@cvs.openbsd.org>2002-01-08 21:28:39 +0000
commitb66e1d01583c979cfe0970d100ab100930407df3 (patch)
treea84ac0fac912a7e280de4aa48792d21c97b71605 /sbin
parenta4c50765d8e419c8282f7ac625d630914db21b43 (diff)
add support in modload for ELF
from NetBSD miod@ ok.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/modload/Makefile47
-rw-r--r--sbin/modload/a.out.c256
-rw-r--r--sbin/modload/elf.c494
-rw-r--r--sbin/modload/modload.876
-rw-r--r--sbin/modload/modload.c499
-rw-r--r--sbin/modload/modload.h72
-rw-r--r--sbin/modload/pathnames.h3
7 files changed, 1119 insertions, 328 deletions
diff --git a/sbin/modload/Makefile b/sbin/modload/Makefile
index deaf5656476..17f271c7c27 100644
--- a/sbin/modload/Makefile
+++ b/sbin/modload/Makefile
@@ -1,40 +1,17 @@
-# $OpenBSD: Makefile,v 1.3 1997/09/21 11:36:58 deraadt 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.
+# $OpenBSD: Makefile,v 1.4 2002/01/08 21:28:38 ericj Exp $
PROG= modload
MAN= modload.8
+SRCS= modload.c
+
+.include <bsd.own.mk> # for ELF_TOOLCHAIN
+
+.if (${ELF_TOOLCHAIN:L} == "yes")
+SRCS+= elf.c
+.else
+SRCS+= a.out.c
+CFLAGS+= -DUSE_AOUT
+.endif
+
.include <bsd.prog.mk>
diff --git a/sbin/modload/a.out.c b/sbin/modload/a.out.c
new file mode 100644
index 00000000000..9ead89161a7
--- /dev/null
+++ b/sbin/modload/a.out.c
@@ -0,0 +1,256 @@
+/* $OpenBSD: a.out.c,v 1.1 2002/01/08 21:28:38 ericj Exp $ */
+/* $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 <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/lkm.h>
+
+#include <a.out.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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)
+ * <target> 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 00000000000..4ff43facc46
--- /dev/null
+++ b/sbin/modload/elf.c
@@ -0,0 +1,494 @@
+/* $OpenBSD: elf.c,v 1.1 2002/01/08 21:28:38 ericj Exp $ */
+/* $NetBSD: elf.c,v 1.8 2002/01/03 21:45:58 jdolecek Exp $ */
+
+/*
+ * Copyright (c) 1998 Johan Danielsson <joda@pdc.kth.se>
+ * 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 <sys/param.h>
+
+#if defined(__alpha__) || defined(__arch64__) || defined(__x86_64__)
+#define ELFSIZE 64
+#else
+#define ELFSIZE 32
+#endif
+#include <sys/exec_elf.h>
+#ifndef ELF_HDR_SIZE
+#define ELF_HDR_SIZE sizeof(Elf_Ehdr)
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/lkm.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "modload.h"
+
+char *strtab;
+
+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 */
+ unsigned long 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 *shstrtab, 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)
+ && (shdr.sh_type != SHT_STRTAB)
+ && (shdr.sh_type != SHT_SYMTAB)
+ && (shdr.sh_type != SHT_DYNSYM)) {
+ /* 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 = shstrtab + 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);
+ }
+}
+
+/* get the symbol table sections and free the rest of them */
+static void
+get_symtab(struct elf_section **symtab)
+{
+ struct elf_section *head, *cur, *prev;
+
+ head = NULL;
+ prev = NULL;
+ cur = *symtab;
+ while (cur) {
+ if ((cur->type == SHT_SYMTAB) || (cur->type == SHT_DYNSYM)) {
+ if (head == NULL) {
+ head = cur;
+ }
+ if (prev != NULL) {
+ prev->next = cur;
+ }
+ prev = cur;
+ cur = cur->next;
+ } else {
+ struct elf_section *p = cur;
+ cur = cur->next;
+ p->next = NULL;
+ free(p);
+ }
+ }
+
+ if (prev) {
+ prev->next = NULL;
+ }
+ *symtab = head;
+}
+
+/* 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 section header's string table */
+static char *
+read_shstring_table(int fd, Elf_Ehdr *ehdr)
+{
+ Elf_Shdr shdr;
+ char *shstrtab;
+
+ read_section_header(fd, ehdr, ehdr->e_shstrndx, &shdr);
+
+ shstrtab = malloc(shdr.sh_size);
+ if (shstrtab == 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, shstrtab, shdr.sh_size) != shdr.sh_size)
+ err(1, "read");
+ return shstrtab;
+}
+
+/* read string table */
+static char *
+read_string_table(int fd, struct elf_section *head, int *strtablen)
+{
+ char *string_table=NULL;
+
+ while (head) {
+ if ((strcmp(head->name, ".strtab") == 0 )
+ && (head->type == SHT_STRTAB)) {
+ string_table = malloc(head->size);
+ if (string_table == NULL)
+ errx(1, "failed to allocate %lu bytes",
+ (u_long)head->size);
+ if (lseek(fd, head->offset, SEEK_SET) < 0)
+ err(1, "lseek");
+ if (read(fd, string_table, head->size) != head->size)
+ err(1, "read");
+ *strtablen = head->size;
+ break;
+ } else {
+ head = head->next;
+ }
+ }
+ return string_table;
+}
+
+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, ELFMAG, SELFMAG) != 0 ||
+ ehdr->e_ident[EI_CLASS] != ELFCLASS)
+ 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 *shstrtab, *strtab;
+ struct elf_section *head, *s, *symtab;
+
+ if (read_elf_header(fd, &ehdr) < 0)
+ return -1;
+ shstrtab = read_shstring_table(fd, &ehdr);
+ read_sections(fd, &ehdr, shstrtab, &head);
+
+ for (s = head; s; s = s->next) {
+ if ((s->type == SHT_STRTAB) && (s->type == SHT_SYMTAB)
+ && (s->type == SHT_DYNSYM)) {
+ continue;
+ }
+ 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) {
+ data_offset = roundup(off, s->align);
+ if (debug)
+ fprintf(stderr, ".data section forced to "
+ "offset %p (was %p)\n",
+ (void*)data_offset,
+ s->addr);
+ /* later remove size of compressed hole from off */
+ data_hole = (ssize_t)s->addr - data_offset;
+ }
+ off = (ssize_t)s->addr + s->size;
+ }
+ off -= data_hole;
+
+ /* XXX round to pagesize? */
+ *modsize = roundup(off, sysconf(_SC_PAGESIZE));
+ free(shstrtab);
+
+ /* get string table length */
+ strtab = read_string_table(fd, head, strtablen);
+ free(strtab);
+
+ /* get symbol table sections */
+ get_symtab(&head);
+ symtab = head;
+ resrvp->sym_symsize = 0;
+ while (symtab) {
+ resrvp->sym_symsize += symtab->size;
+ symtab = symtab->next;
+ }
+ resrvp->sym_size = resrvp->sym_symsize + *strtablen;
+ free_sections(head);
+
+ 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
+ * <target> 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 *shstrtab;
+ struct elf_section *head, *s;
+ char buf[10 * BUFSIZ];
+ void *addr = NULL;
+
+ if (read_elf_header(fd, &ehdr) < 0)
+ return NULL;
+
+ shstrtab = read_shstring_table(fd, &ehdr);
+ read_sections(fd, &ehdr, shstrtab, &head);
+
+ for (s = head; s; s = s->next) {
+ if ((s->type != SHT_STRTAB) && (s->type != SHT_SYMTAB)
+ && (s->type != SHT_DYNSYM)) {
+ if (debug)
+ fprintf(stderr, "loading `%s': addr = %p, "
+ "size = %#lx\n",
+ s->name, s->addr, (u_long)s->size);
+ if (s->type == 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;
+ }
+ }
+ }
+ if (zero_size)
+ loadspace(zero_size);
+
+ free_sections(head);
+ free(shstrtab);
+ return (void*)ehdr.e_entry;
+}
+
+extern int devfd, modfd;
+
+void
+elf_mod_symload(strtablen)
+ int strtablen;
+{
+ Elf_Ehdr ehdr;
+ char *shstrtab;
+ struct elf_section *head, *s;
+ char *symbuf, *strbuf;
+
+ /*
+ * Seek to the text offset to start loading...
+ */
+ if (lseek(modfd, 0, SEEK_SET) == -1)
+ err(12, "lseek");
+ if (read_elf_header(modfd, &ehdr) < 0)
+ return;
+
+ shstrtab = read_shstring_table(modfd, &ehdr);
+ read_sections(modfd, &ehdr, shstrtab, &head);
+
+ for (s = head; s; s = s->next) {
+ struct elf_section *p = s;
+
+ if ((p->type == SHT_SYMTAB) || (p->type == SHT_DYNSYM)) {
+ if (debug)
+ fprintf(stderr, "loading `%s': addr = %p, "
+ "size = %#lx\n",
+ s->name, s->addr, (u_long)s->size);
+ /*
+ * Seek to the file offset to start loading it...
+ */
+ if (lseek(modfd, p->offset, SEEK_SET) == -1)
+ err(12, "lseek");
+ symbuf = malloc(p->size);
+ if (symbuf == 0)
+ err(13, "malloc");
+ if (read(modfd, symbuf, p->size) != p->size)
+ err(14, "read");
+
+ loadsym(symbuf, p->size);
+ free(symbuf);
+ }
+ }
+
+ for (s = head; s; s = s->next) {
+ struct elf_section *p = s;
+
+ if ((p->type == SHT_STRTAB)
+ && (strcmp(p->name, ".strtab") == 0 )) {
+ if (debug)
+ fprintf(stderr, "loading `%s': addr = %p, "
+ "size = %#lx\n",
+ s->name, s->addr, (u_long)s->size);
+ /*
+ * Seek to the file offset to start loading it...
+ */
+ if (lseek(modfd, p->offset, SEEK_SET) == -1)
+ err(12, "lseek");
+ strbuf = malloc(p->size);
+ if (strbuf == 0)
+ err(13, "malloc");
+ if (read(modfd, strbuf, p->size) != p->size)
+ err(14, "read");
+
+ loadsym(strbuf, p->size);
+ free(strbuf);
+ }
+ }
+
+ free(shstrtab);
+ free_sections(head);
+ return;
+}
diff --git a/sbin/modload/modload.8 b/sbin/modload/modload.8
index 2b0278674d4..f63d3dd6cf1 100644
--- a/sbin/modload/modload.8
+++ b/sbin/modload/modload.8
@@ -1,5 +1,5 @@
-.\" $OpenBSD: modload.8,v 1.18 2001/09/17 11:45:20 assar Exp $
-.\" $NetBSD: modload.8,v 1.5 1995/03/18 14:56:43 cgd Exp $
+.\" $OpenBSD: modload.8,v 1.19 2002/01/08 21:28:38 ericj Exp $
+.\" $NetBSD: modload.8,v 1.17 2001/11/16 11:57:16 wiz Exp $
.\"
.\" Copyright (c) 1993 Christopher G. Demetriou
.\" All rights reserved.
@@ -12,8 +12,13 @@
.\" 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
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the
+.\" NetBSD Project. See http://www.netbsd.org/ for
+.\" information about NetBSD.
+.\" 4. 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
@@ -26,15 +31,17 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 7, 1993
+.\" <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
+.\"
+.Dd April 30, 1999
.Dt MODLOAD 8
.Os
.Sh NAME
.Nm modload
.Nd load a kernel module
.Sh SYNOPSIS
-.Nm modload
-.Op Fl dvsqu
+.Nm ""
+.Op Fl dnvsS
.Op Fl A Ar kernel
.Op Fl e Ar entry
.Op Fl p Ar postinstall
@@ -46,25 +53,25 @@ The
utility loads a loadable kernel module into a running system.
The input file is an object file (.o file).
.Pp
-The options are as follows:
+The options to
+.Nm
+are as follows:
.Bl -tag -width Ds
.It Fl d
-Debug.
-Used to debug
+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
-Do not load symbols from the kernel module.
-.It Fl q
-Be very quiet.
-.It Fl u
-Delete the loaded module
-.Pq Ar output_file
-after loading.
-If the output file was not specified, this option causes the
-temporary file to be kept rather than deleted.
+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.
@@ -77,12 +84,14 @@ This is passed by
to
.Xr ld 1
when the module is linked.
-The default module entry point name is
-.Dq xxxinit .
+The default module entry point name is `xxxinit'.
+If `xxxinit' cannot be found, an attempt to use `<module_name>_lkmentry'
+will be made, where <module_name> is the filename being loaded without
+the `.o'.
.It Fl p Ar postinstall
Specify the name of a shell script or program that will
-be executed if the module is successfully loaded.
-It is always passed the module ID (in decimal) and module
+be executed if the module is successfully loaded. It
+is always passed the module id (in decimal) and module
type (in hexadecimal) as the first two arguments.
For loadable drivers, the third argument is
the block or character major device number.
@@ -91,12 +100,6 @@ call number.
.It Fl o Ar output_file
Specify the name of the output file that is produced by
the linker.
-If this option is not specified, a file in the
-.Pa /tmp
-directory
-is used with the name generated from the module name with a
-.Dq .out
-extension.
.El
.Sh FILES
.Bl -tag -width /usr/include/sys/lkm.h -compact
@@ -105,13 +108,12 @@ default file passed to the linker to resolve external
references in the module
.It Pa /usr/include/sys/lkm.h
file containing definitions of module types
-.\" .It Pa output file.
-.\" default output file name
.El
.Sh DIAGNOSTICS
The
.Nm
-utility exits 0 on success or with a non-zero status if an error occurred.
+utility exits with a status of 0 on success
+and with a nonzero status if an error occurs.
.Sh SEE ALSO
.Xr ld 1 ,
.Xr lkm 4 ,
@@ -124,7 +126,15 @@ command was designed to be similar in functionality
to the corresponding command in
.Tn "SunOS 4.1.3" .
.Sh AUTHORS
-Terrence R. Lambert <terry@cs.weber.edu>
+.An Terrence R. Lambert Aq terry@cs.weber.edu
.Sh BUGS
+.Bl -bullet
+.It
The loadable device driver framework can
only reserve either a character or block device entry, not both.
+.It
+Loading the symbol table is expensive in terms of space:
+it presently duplicates all the kernel symbols for each lkm loaded
+with
+.Fl s .
+.El
diff --git a/sbin/modload/modload.c b/sbin/modload/modload.c
index ee634bebeba..ae3e07580bd 100644
--- a/sbin/modload/modload.c
+++ b/sbin/modload/modload.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: modload.c,v 1.28 2002/01/07 19:38:28 ericj Exp $ */
-/* $NetBSD: modload.c,v 1.13 1995/05/28 05:21:58 jtc Exp $ */
+/* $OpenBSD: modload.c,v 1.29 2002/01/08 21:28:38 ericj Exp $ */
+/* $NetBSD: modload.c,v 1.30 2001/11/08 15:33:15 christos Exp $ */
/*
* Copyright (c) 1993 Terrence R. Lambert.
@@ -39,97 +39,85 @@
#include <sys/mount.h>
#include <sys/lkm.h>
#include <sys/stat.h>
-#include <sys/wait.h>
-#include <a.out.h>
+#include <sys/file.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <nlist.h>
#include "pathnames.h"
-#define min(a, b) ((a) < (b) ? (a) : (b))
+#define TRUE 1
+#define FALSE 0
-/*
- * 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)
- * <target> object file
- */
+#include "modload.h"
+
+#ifndef DFLT_ENTRY
+#define DFLT_ENTRY "xxxinit"
+#endif /* !DFLT_ENTRY */
+#ifndef DFLT_ENTRYEXT
+#define DFLT_ENTRYEXT "_lkmentry"
+#endif /* !DFLT_ENTRYEXT */
int debug = 0;
int verbose = 0;
-int symtab = 1;
-int quiet = 0;
-int dounlink = 0;
-
-#if defined(__alpha) || defined(__mips)
-#define LDSYMTABLE "-R"
-#define LDTEXTSTART "-Ttext"
-#define LDSYMPREFIX ""
-#else
-#define LDSYMTABLE "-A"
-#define LDTEXTSTART "-T"
-#define LDSYMPREFIX "_"
-#define MAGICCHECK
-#endif
-
-void
-linkcmd(kernel, entry, outfile, address, object)
- char *kernel, *entry, *outfile;
- u_int address; /* XXX */
- char *object;
+char *out = NULL;
+int symtab = 0;
+int Sflag;
+
+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 addrbuf[32], entrybuf[_POSIX2_LINE_MAX];
- pid_t pid;
- int status;
+ char cmdbuf[1024];
+ int error = 0;
- snprintf(entrybuf, sizeof entrybuf, "%s%s", LDSYMPREFIX, entry);
- snprintf(addrbuf, sizeof addrbuf, "%x", address);
+ linkcmd(cmdbuf, sizeof(cmdbuf),
+ kernel, entry, outfile, address, object);
if (debug)
- printf("%s %s %s -e %s -o %s %s %s %s\n",
- _PATH_LD, LDSYMTABLE, kernel, entrybuf,
- outfile, LDTEXTSTART, addrbuf, object);
-
- if ((pid = fork()) < 0)
- err(18, "fork");
-
- if (pid == 0) {
- execl(_PATH_LD, "ld", LDSYMTABLE, kernel, "-e", entrybuf, "-o",
- outfile, LDTEXTSTART, addrbuf, object, (char *)NULL);
- exit(128 + errno);
- }
-
- waitpid(pid, &status, 0);
-
- if (WIFSIGNALED(status)) {
- errx(1, "%s got signal: %s", _PATH_LD,
- sys_siglist[WTERMSIG(status)]);
- }
+ fprintf(stderr, "%s\n", cmdbuf);
- if (WEXITSTATUS(status) > 128) {
- errno = WEXITSTATUS(status) - 128;
- err(1, "exec(%s)", _PATH_LD);
+ switch (system(cmdbuf)) {
+ case 0: /* SUCCESS! */
+ break;
+ case 1: /* uninformitive error */
+ /*
+ * Someone needs to fix the return values from the NetBSD
+ * ld program -- it's totally uninformative.
+ *
+ * No such file (4 on SunOS)
+ * Can't write output (2 on SunOS)
+ * Undefined symbol (1 on SunOS)
+ * etc.
+ */
+ case 127: /* can't load shell */
+ case 32512:
+ default:
+ error = 1;
+ break;
}
- if (WEXITSTATUS(status) != 0)
- errx(1, "%s: return code %d", _PATH_LD, WEXITSTATUS(status));
+ return error;
}
static void
-usage()
+usage(void)
{
- fprintf(stderr, "usage: modload [-dvsqu] [-A <kernel>] [-e <entry]\n");
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "modload [-d] [-v] [-n] [-s] [-S] "
+ "[-A <kernel>] [-e <entry>]\n");
fprintf(stderr,
- "\t[-p <postinstall>] [-o <output file>] <input file>\n");
+ " [-p <postinstall>] [-o <output file>] <input file>\n");
exit(1);
}
@@ -137,59 +125,131 @@ 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;
-char modout[MAXPATHLEN];
-/*
- * Must be safe for two calls. One in case of the -p option, and one from
- * the atexit() call...
- */
-void
-cleanup()
+static void
+cleanup(void)
{
+
if (fileopen & PART_RESRV) {
/*
* Free up kernel memory
*/
if (ioctl(devfd, LMUNRESRV, 0) == -1)
warn("can't release slot 0x%08x memory", resrv.slot);
- fileopen &= ~PART_RESRV;
}
- if (fileopen & DEV_OPEN) {
+ if (fileopen & DEV_OPEN)
close(devfd);
- fileopen &= ~DEV_OPEN;
- }
- if (fileopen & MOD_OPEN) {
+ if (fileopen & MOD_OPEN)
close(modfd);
- fileopen &= ~MOD_OPEN;
+
+ if (fileopen & OUTFILE_CREAT)
+ unlink(out);
+}
+
+static int
+verify_entry(const char *entry, char *filename)
+{
+ struct nlist names[2];
+ int n;
+ char *s;
+
+ memset(names, 0, sizeof(names));
+ s = malloc(strlen(entry) + 2);
+ sprintf(s, "_%s", entry); /* safe */
+#ifdef _AOUT_INCLUDE_
+ names[0].n_un.n_name = s;
+#else
+ names[0].n_name = s;
+#endif
+
+ n = nlist(filename, names);
+ if (n == -1)
+ err(1, "nlist %s", 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;
}
+}
- if (dounlink && unlink(modout) != 0) {
- err(17, "unlink(%s)", modout);
- dounlink = 0;
+/*
+ * Transfer symbol table to kernel memory in chunks
+ * of MODIOBUF size at a time.
+ */
+void
+loadsym(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, LMLOADSYMS, &ldbuf) == -1)
+ err(11, "error loading buffer");
+ len -= n;
+ p += n;
}
}
+/* Transfer some empty space. */
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char **argv)
{
+ int c;
char *kname = _PATH_UNIX;
- char *entry = NULL, *post = NULL, *out = NULL, *modobj, *p;
- struct exec info_buf;
+ char *entry = DFLT_ENTRY;
+ char *post = NULL;
+ char *modobj;
+ char modout[80], *p;
struct stat stb;
- u_int modsize; /* XXX */
- u_long modentry; /* XXX */
- int strtablen, c;
- struct lmc_loadbuf ldbuf;
- int sz, bytesleft, old = 0;
- char buf[MODIOBUF];
+ int strtablen;
+ size_t modsize; /* XXX */
+ void* modentry; /* XXX */
+ int noready = 0, old = 0;
- while ((c = getopt(argc, argv, "dvsuqA:e:p:o:")) != -1) {
+ while ((c = getopt(argc, argv, "dnvsA:Se:p:o:")) != -1) {
switch (c) {
case 'd':
debug = 1;
@@ -197,12 +257,6 @@ main(argc, argv)
case 'v':
verbose = 1;
break; /* verbose */
- case 'u':
- dounlink = 1;
- break; /* unlink tmp file */
- case 'q':
- quiet = 1;
- break; /* be quiet */
case 'A':
kname = optarg;
break; /* kernel */
@@ -215,11 +269,21 @@ main(argc, argv)
case 'o':
out = optarg;
break; /* output file */
+ case 'n':
+ noready = 1;
+ break;
case 's':
- symtab = 0;
+ symtab = 1;
break;
- default:
+ case 'S':
+ Sflag = 1;
+ break;
+ case '?':
usage();
+ /* NOTREACHED */
+ default:
+ printf("default!\n");
+ break;
}
}
argc -= optind;
@@ -241,65 +305,64 @@ main(argc, argv)
err(3, _PATH_LKM);
fileopen |= DEV_OPEN;
- p = strrchr(modobj, '.');
- if (!p || p[1] != 'o' || p[2] != '\0')
+ strncpy(modout, modobj, sizeof(modout) - 1);
+ modout[sizeof(modout) - 1] = '\0';
+
+ p = strrchr(modout, '.');
+ if (!p || strcmp(p, ".o"))
errx(2, "module object must end in .o");
- if (out == NULL) {
- p = strrchr(modobj, '/');
- if (p)
- p++; /* skip over '/' */
- else
- p = modobj;
- snprintf(modout, sizeof modout, "%s%s.XXXXXXXX.o",
- _PATH_TMP, p);
- if ((modfd = mkstemps(modout, strlen(".o"))) == -1)
- err(1, "creating %s", modout);
- close(modfd);
+ *p = '\0';
+ if (out == NULL)
out = modout;
+
+ /*
+ * Verify that the entry point for the module exists.
+ */
+ if (verify_entry(entry, modobj)) {
/*
- * reverse meaning of -u - if we've generated a /tmp
- * file, remove it automatically...
+ * Try <modobj>_init if entry is DFLT_ENTRY.
*/
- dounlink = !dounlink;
- }
-
- if (!entry) { /* calculate default entry point */
- entry = strrchr(modobj, '/');
- if (entry)
- entry++; /* skip over '/' */
- else
- entry = modobj;
- entry = strdup(entry); /* so we can modify it */
- if (!entry)
- errx(1, "Could not allocate memory");
- entry[strlen(entry) - 2] = '\0'; /* chop off .o */
+ if (strcmp(entry, DFLT_ENTRY) == 0) {
+ if ((p = strrchr(modout, '/')))
+ p++;
+ else
+ p = modout;
+ entry = malloc(strlen(p) + strlen(DFLT_ENTRYEXT) + 1);
+ sprintf(entry, "%s%s", p, DFLT_ENTRYEXT); /* safe */
+ if (verify_entry(entry, modobj))
+ errx(1, "entry point _%s not found in %s",
+ entry, modobj);
+ } else
+ errx(1, "entry point _%s not found in %s", entry,
+ modobj);
}
-
/*
* Prelink to get file size
*/
- linkcmd(kname, entry, out, 0, modobj);
-
- /*
- * Pre-open the 0-linked module to get the size information
- */
- if ((modfd = open(out, O_RDONLY)) == -1)
+ if (prelink(kname, entry, out, 0, modobj))
+ errx(1, "can't prelink `%s' creating `%s'", modobj, out);
+ 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, "%s", out);
fileopen |= MOD_OPEN;
/*
- * Get the load module post load size... do this by reading the
- * header and doing page counts.
+ * stat for filesize to figure out string table size
*/
- if (read(modfd, &info_buf, sizeof(struct exec)) == -1)
- err(3, "read `%s'", out);
+ if (fstat(modfd, &stb) == -1)
+ err(3, "fstat `%s'", out);
/*
- * stat for filesize to figure out string table size
+ * work out various sizes and fill in resrv bits
*/
- if (fstat(modfd, &stb) == -1)
- err(3, "fstat `%s'", out);
+ 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.
@@ -307,19 +370,6 @@ main(argc, argv)
close(modfd);
fileopen &= ~MOD_OPEN;
-#ifdef MAGICCHECK
- /*
- * Magic number...
- */
- if (N_BADMAG(info_buf))
- errx(4, "not an a.out format file");
-#endif
-
- /*
- * 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.
@@ -328,116 +378,52 @@ 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");
+ if (symtab) {
+ warn("not loading symbols: kernel does not support "
+ "symbol table loading");
+ }
doold:
- symtab = 0;
- if (ioctl(devfd, LMRESERV_O, &resrv) == -1)
- err(9, "can't reserve memory");
- old = 1;
+ symtab = 0;
+ if (ioctl(devfd, LMRESERV_O, &resrv) == -1)
+ err(9, "can't reserve memory");
+ old = TRUE;
}
fileopen |= PART_RESRV;
/*
* Relink at kernel load address
*/
- linkcmd(kname, entry, out, resrv.addr, modobj);
+ 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)) == -1)
+ if ((modfd = open(out, O_RDONLY, 0)) == -1)
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);
-
- /*
- * Get the entry point (for initialization)
- */
- modentry = info_buf.a_entry; /* place to call */
-
- /*
- * 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);
- if (read(modfd, buf, sz) != sz)
- err(14, "read");
- 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");
+ modentry = mod_load(modfd);
+ if (debug)
+ (void)fprintf(stderr, "modentry = %p\n", modentry);
- /*
- * Read and load the symbol table entries.
- */
- for (bytesleft = info_buf.a_syms; bytesleft > 0;
- bytesleft -= sz) {
- sz = min(bytesleft, MODIOBUF);
- if (read(modfd, buf, sz) != sz)
- err(14, "read");
- ldbuf.cnt = sz;
- ldbuf.data = buf;
- if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1)
- err(11, "error transferring sym buffer");
- }
-
- /*
- * Read the string table and load it.
- */
- for (bytesleft = strtablen; bytesleft > 0;
- bytesleft -= sz) {
- sz = min(bytesleft, MODIOBUF);
- if (read(modfd, buf, sz) != sz)
- err(14, "read");
- ldbuf.cnt = sz;
- ldbuf.data = buf;
- if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1)
- err(11, "error transferring stringtable buffer");
- }
- }
+ if (symtab)
+ mod_symload(strtablen);
/*
* 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
@@ -450,8 +436,8 @@ main(argc, argv)
close(modfd);
/*
* PART_RESRV is not true since the kernel cleans
- * up after a failed LMREADY
- */
+ * up after a failed LMREADY.
+ */
fileopen &= ~(MOD_OPEN|PART_RESRV);
/* try using oldstyle */
warn("module failed to load using new version; "
@@ -465,8 +451,7 @@ main(argc, argv)
* Success!
*/
fileopen &= ~PART_RESRV; /* loaded */
- if (!quiet)
- printf("Module loaded as ID %d\n", resrv.slot);
+ printf("Module loaded as ID %d\n", resrv.slot);
/*
* Execute the post-install program, if specified.
@@ -474,26 +459,24 @@ main(argc, argv)
if (post) {
struct lmc_stat sbuf;
char name[MAXLKMNAME] = "";
- char id[16], type[16], offset[32];
+ char id[16], type[16], offset[16];
sbuf.id = resrv.slot;
sbuf.name = name;
if (ioctl(devfd, LMSTAT, &sbuf) == -1)
err(15, "error fetching module stats for post-install");
- sprintf(id, "%d", sbuf.id);
- sprintf(type, "0x%x", sbuf.type);
- sprintf(offset, "%lu", sbuf.offset);
+ (void)snprintf(id, sizeof(id), "%d", sbuf.id);
+ (void)snprintf(type, sizeof(type), "0x%x", sbuf.type);
+ (void)snprintf(offset, sizeof(offset), "%ld",
+ (long)sbuf.offset);
/*
* XXX
* The modload docs say that drivers can install bdevsw &
* cdevsw, but the interface only supports one at a time.
*/
-
- cleanup();
-
execl(post, post, id, type, offset, (char *)NULL);
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 00000000000..80ba2f315be
--- /dev/null
+++ b/sbin/modload/modload.h
@@ -0,0 +1,72 @@
+/* $OpenBSD: modload.h,v 1.1 2002/01/08 21:28:38 ericj Exp $ */
+/* $NetBSD: modload.h,v 1.2 2001/11/08 15:33:15 christos 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);
+void loadsym(void*, size_t);
+
+extern int debug;
+extern int verbose;
+
+#endif /* __modload_h__ */
diff --git a/sbin/modload/pathnames.h b/sbin/modload/pathnames.h
index d13af489d7a..be006c41653 100644
--- a/sbin/modload/pathnames.h
+++ b/sbin/modload/pathnames.h
@@ -1,7 +1,6 @@
-/* $OpenBSD: pathnames.h,v 1.3 1996/08/05 11:01:18 mickey Exp $ */
+/* $OpenBSD: pathnames.h,v 1.4 2002/01/08 21:28:38 ericj Exp $ */
/* $NetBSD: pathnames.h,v 1.2 1995/03/18 14:56:46 cgd Exp $ */
#include <paths.h>
#define _PATH_LKM "/dev/lkm"
-#define _PATH_LD "/usr/bin/ld"