summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/conf/Makefile.i3869
-rw-r--r--sys/conf/Makefile.powerpc9
-rw-r--r--sys/conf/files3
-rw-r--r--sys/i386/conf/Makefile.i3869
-rw-r--r--sys/kern/init_sysent.c55
-rw-r--r--sys/kern/kern_linker.c562
-rw-r--r--sys/kern/kern_module.c304
-rw-r--r--sys/kern/link_aout.c448
-rw-r--r--sys/kern/syscalls.c55
-rw-r--r--sys/kern/syscalls.master58
-rw-r--r--sys/sys/linker.h207
-rw-r--r--sys/sys/module.h107
-rw-r--r--sys/sys/syscall-hide.h10
-rw-r--r--sys/sys/syscall.h12
-rw-r--r--sys/sys/sysproto.h42
15 files changed, 1885 insertions, 5 deletions
diff --git a/sys/conf/Makefile.i386 b/sys/conf/Makefile.i386
index 2718b5cea838..340a05f3b436 100644
--- a/sys/conf/Makefile.i386
+++ b/sys/conf/Makefile.i386
@@ -1,7 +1,7 @@
# Makefile.i386 -- with config changes.
# Copyright 1990 W. Jolitz
# from: @(#)Makefile.i386 7.1 5/10/91
-# $Id: Makefile.i386,v 1.94 1997/04/22 06:55:21 jdp Exp $
+# $Id: Makefile.i386,v 1.95 1997/04/27 20:01:47 peter Exp $
#
# Makefile for FreeBSD
#
@@ -17,6 +17,7 @@
#
BINFORMAT?= aout
+#BINFORMAT?= aoutkld
#BINFORMAT?= elf
.if exists(./@/.)
@@ -70,6 +71,12 @@ SYSTEM_LD_TAIL= @echo rearranging symbols; \
symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \
size $@; chmod 755 $@
.endif
+.if ${BINFORMAT} == aoutkld
+SYSTEM_LD= @${LD} -Bforcedynamic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
+SYSTEM_LD_TAIL= @echo rearranging symbols; \
+ symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \
+ size $@; chmod 755 $@
+.endif
.if ${BINFORMAT} == elf
SYSTEM_LD= @${LD} -Bstatic -Ttext ${LOAD_ADDRESS} -e btext -o $@ -X ${SYSTEM_OBJS} vers.o
SYSTEM_LD_TAIL= @size $@; chmod 755 $@
diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc
index 2718b5cea838..340a05f3b436 100644
--- a/sys/conf/Makefile.powerpc
+++ b/sys/conf/Makefile.powerpc
@@ -1,7 +1,7 @@
# Makefile.i386 -- with config changes.
# Copyright 1990 W. Jolitz
# from: @(#)Makefile.i386 7.1 5/10/91
-# $Id: Makefile.i386,v 1.94 1997/04/22 06:55:21 jdp Exp $
+# $Id: Makefile.i386,v 1.95 1997/04/27 20:01:47 peter Exp $
#
# Makefile for FreeBSD
#
@@ -17,6 +17,7 @@
#
BINFORMAT?= aout
+#BINFORMAT?= aoutkld
#BINFORMAT?= elf
.if exists(./@/.)
@@ -70,6 +71,12 @@ SYSTEM_LD_TAIL= @echo rearranging symbols; \
symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \
size $@; chmod 755 $@
.endif
+.if ${BINFORMAT} == aoutkld
+SYSTEM_LD= @${LD} -Bforcedynamic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
+SYSTEM_LD_TAIL= @echo rearranging symbols; \
+ symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \
+ size $@; chmod 755 $@
+.endif
.if ${BINFORMAT} == elf
SYSTEM_LD= @${LD} -Bstatic -Ttext ${LOAD_ADDRESS} -e btext -o $@ -X ${SYSTEM_OBJS} vers.o
SYSTEM_LD_TAIL= @size $@; chmod 755 $@
diff --git a/sys/conf/files b/sys/conf/files
index 91ea29c2fb7f..91a0663d33ac 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -48,6 +48,9 @@ kern/init_main.c standard
kern/init_smp.c optional smp
kern/init_sysent.c standard
kern/init_sysvec.c standard
+kern/kern_module.c standard
+kern/kern_linker.c standard
+kern/link_aout.c standard
kern/kern_acct.c standard
kern/kern_clock.c standard
kern/kern_conf.c standard
diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386
index 2718b5cea838..340a05f3b436 100644
--- a/sys/i386/conf/Makefile.i386
+++ b/sys/i386/conf/Makefile.i386
@@ -1,7 +1,7 @@
# Makefile.i386 -- with config changes.
# Copyright 1990 W. Jolitz
# from: @(#)Makefile.i386 7.1 5/10/91
-# $Id: Makefile.i386,v 1.94 1997/04/22 06:55:21 jdp Exp $
+# $Id: Makefile.i386,v 1.95 1997/04/27 20:01:47 peter Exp $
#
# Makefile for FreeBSD
#
@@ -17,6 +17,7 @@
#
BINFORMAT?= aout
+#BINFORMAT?= aoutkld
#BINFORMAT?= elf
.if exists(./@/.)
@@ -70,6 +71,12 @@ SYSTEM_LD_TAIL= @echo rearranging symbols; \
symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \
size $@; chmod 755 $@
.endif
+.if ${BINFORMAT} == aoutkld
+SYSTEM_LD= @${LD} -Bforcedynamic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
+SYSTEM_LD_TAIL= @echo rearranging symbols; \
+ symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \
+ size $@; chmod 755 $@
+.endif
.if ${BINFORMAT} == elf
SYSTEM_LD= @${LD} -Bstatic -Ttext ${LOAD_ADDRESS} -e btext -o $@ -X ${SYSTEM_OBJS} vers.o
SYSTEM_LD_TAIL= @size $@; chmod 755 $@
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 21291c9e1b2c..a221ecf7a952 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -287,4 +287,59 @@ struct sysent sysent[] = {
{ 0, (sy_call_t *)nosys }, /* 252 = poll */
{ 0, (sy_call_t *)issetugid }, /* 253 = issetugid */
{ 3, (sy_call_t *)lchown }, /* 254 = lchown */
+ { 0, (sy_call_t *)nosys }, /* 255 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 256 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 257 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 258 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 259 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 260 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 261 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 262 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 263 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 264 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 265 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 266 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 267 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 268 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 269 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 270 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 271 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 272 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 273 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 274 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 275 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 276 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 277 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 278 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 279 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 280 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 281 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 282 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 283 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 284 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 285 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 286 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 287 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 288 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 289 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 290 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 291 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 292 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 293 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 294 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 295 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 296 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 297 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 298 = nosys */
+ { 0, (sy_call_t *)nosys }, /* 299 = nosys */
+ { 1, (sy_call_t *)modnext }, /* 300 = modnext */
+ { 2, (sy_call_t *)modstat }, /* 301 = modstat */
+ { 1, (sy_call_t *)modfnext }, /* 302 = modfnext */
+ { 1, (sy_call_t *)modfind }, /* 303 = modfind */
+ { 1, (sy_call_t *)kldload }, /* 304 = kldload */
+ { 1, (sy_call_t *)kldunload }, /* 305 = kldunload */
+ { 1, (sy_call_t *)kldfind }, /* 306 = kldfind */
+ { 1, (sy_call_t *)kldnext }, /* 307 = kldnext */
+ { 2, (sy_call_t *)kldstat }, /* 308 = kldstat */
+ { 1, (sy_call_t *)kldfirstmod }, /* 309 = kldfirstmod */
};
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
new file mode 100644
index 000000000000..2a4e6cdfb2f9
--- /dev/null
+++ b/sys/kern/kern_linker.c
@@ -0,0 +1,562 @@
+/*-
+ * Copyright (c) 1997 Doug Rabson
+ * 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$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <machine/cpu.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+
+static struct lock lock; /* lock for the file list */
+static linker_class_list_t classes;
+static linker_file_list_t files;
+static int next_file_id = 1;
+
+static void
+linker_init(void* arg)
+{
+ lockinit(&lock, PVM, "klink", 0, 0);
+ TAILQ_INIT(&classes);
+ TAILQ_INIT(&files);
+}
+
+SYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0);
+
+int
+linker_add_class(const char* desc, void* priv,
+ struct linker_class_ops* ops)
+{
+ linker_class_t lc;
+
+ lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
+ if (!lc)
+ return ENOMEM;
+
+ lc->desc = desc;
+ lc->priv = priv;
+ lc->ops = ops;
+ TAILQ_INSERT_HEAD(&classes, lc, link);
+
+ return 0;
+}
+
+static void
+linker_file_sysinit(linker_file_t lf)
+{
+ struct linker_set* sysinits;
+ struct sysinit** sipp;
+ struct sysinit** xipp;
+ struct sysinit* save;
+ int rval[2]; /* SI_TYPE_KTHREAD support*/
+
+ linker_current_file = lf;
+
+ KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
+ lf->filename));
+
+ sysinits = (struct linker_set*)
+ linker_file_lookup_symbol(lf, "sysinit_set", 0);
+ if (!sysinits)
+ return;
+
+ /*
+ * Perform a bubble sort of the system initialization objects by
+ * their subsystem (primary key) and order (secondary key).
+ *
+ * Since some things care about execution order, this is the
+ * operation which ensures continued function.
+ */
+ for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
+ for( xipp = sipp + 1; *xipp; xipp++) {
+ if( (*sipp)->subsystem < (*xipp)->subsystem ||
+ ( (*sipp)->subsystem == (*xipp)->subsystem &&
+ (*sipp)->order < (*xipp)->order))
+ continue; /* skip*/
+ save = *sipp;
+ *sipp = *xipp;
+ *xipp = save;
+ }
+ }
+
+
+ /*
+ * Traverse the (now) ordered list of system initialization tasks.
+ * Perform each task, and continue on to the next task.
+ *
+ * The last item on the list is expected to be the scheduler,
+ * which will not return.
+ */
+ for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
+ if( (*sipp)->subsystem == SI_SUB_DUMMY)
+ continue; /* skip dummy task(s)*/
+
+ switch( (*sipp)->type) {
+ case SI_TYPE_DEFAULT:
+ /* no special processing*/
+ (*((*sipp)->func))( (*sipp)->udata);
+ break;
+
+ case SI_TYPE_KTHREAD:
+ /* kernel thread*/
+ if (fork(&proc0, NULL, rval))
+ panic("fork kernel process");
+ cpu_set_fork_handler(pfind(rval[0]), (*sipp)->func, (*sipp)->udata);
+ break;
+
+ default:
+ panic( "linker_file_sysinit: unrecognized init type");
+ }
+ }
+}
+
+int
+linker_load_file(const char* filename, linker_file_t* result)
+{
+ linker_class_t lc;
+ linker_file_t lf;
+ int error = 0;
+
+ lf = linker_find_file_by_name(filename);
+ if (lf) {
+ KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
+ *result = lf;
+ lf->refs++;
+ goto out;
+ }
+
+ lf = NULL;
+ for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
+ KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
+ filename, lc->desc));
+ if (error = lc->ops->load_file(filename, &lf))
+ goto out;
+ if (lf) {
+ linker_file_sysinit(lf);
+
+ *result = lf;
+ goto out;
+ }
+ }
+
+ error = ENOEXEC; /* format not recognised */
+
+out:
+ return error;
+}
+
+linker_file_t
+linker_find_file_by_name(const char* filename)
+{
+ linker_file_t lf = 0;
+
+ lockmgr(&lock, LK_SHARED, 0, curproc);
+ for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
+ if (!strcmp(lf->filename, filename))
+ break;
+ lockmgr(&lock, LK_RELEASE, 0, curproc);
+
+ return lf;
+}
+
+linker_file_t
+linker_find_file_by_id(int fileid)
+{
+ linker_file_t lf = 0;
+
+ lockmgr(&lock, LK_SHARED, 0, curproc);
+ for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
+ if (lf->id == fileid)
+ break;
+ lockmgr(&lock, LK_RELEASE, 0, curproc);
+
+ return lf;
+}
+
+linker_file_t
+linker_make_file(const char* filename, void* priv, struct linker_file_ops* ops)
+{
+ linker_file_t lf = 0;
+ int namelen;
+
+ KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
+ lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
+ namelen = strlen(filename) + 1;
+ lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
+ if (!lf)
+ goto out;
+
+ lf->refs = 1;
+ lf->userrefs = 0;
+ lf->filename = (char*) (lf + 1);
+ strcpy(lf->filename, filename);
+ lf->id = next_file_id++;
+ lf->ndeps = 0;
+ lf->deps = NULL;
+ STAILQ_INIT(&lf->common);
+ TAILQ_INIT(&lf->modules);
+
+ lf->priv = priv;
+ lf->ops = ops;
+ TAILQ_INSERT_TAIL(&files, lf, link);
+
+out:
+ lockmgr(&lock, LK_RELEASE, 0, curproc);
+ return lf;
+}
+
+int
+linker_file_unload(linker_file_t file)
+{
+ module_t mod, next;
+ struct common_symbol* cp;
+ int error = 0;
+ int i;
+
+ KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs));
+ lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
+ if (file->refs == 1) {
+ KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
+ /*
+ * Inform any modules associated with this file.
+ */
+ for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
+ next = module_getfnext(mod);
+
+ /*
+ * Give the module a chance to veto the unload.
+ */
+ if (error = module_unload(mod)) {
+ KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
+ mod));
+ lockmgr(&lock, LK_RELEASE, 0, curproc);
+ goto out;
+ }
+
+ module_release(mod);
+ }
+ }
+
+ file->refs--;
+ if (file->refs > 0) {
+ lockmgr(&lock, LK_RELEASE, 0, curproc);
+ goto out;
+ }
+
+ TAILQ_REMOVE(&files, file, link);
+ lockmgr(&lock, LK_RELEASE, 0, curproc);
+
+ for (i = 0; i < file->ndeps; i++)
+ linker_file_unload(file->deps[i]);
+ free(file->deps, M_LINKER);
+
+ for (cp = STAILQ_FIRST(&file->common); cp;
+ cp = STAILQ_FIRST(&file->common)) {
+ STAILQ_REMOVE(&file->common, cp, common_symbol, link);
+ free(cp, M_LINKER);
+ }
+
+ file->ops->unload(file);
+ free(file, M_LINKER);
+
+out:
+ return error;
+}
+
+int
+linker_file_add_dependancy(linker_file_t file, linker_file_t dep)
+{
+ linker_file_t* newdeps;
+
+ newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
+ M_LINKER, M_WAITOK);
+ if (newdeps == NULL)
+ return ENOMEM;
+
+ if (file->deps) {
+ bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
+ free(file->deps, M_LINKER);
+ }
+ file->deps = newdeps;
+ file->deps[file->ndeps] = dep;
+ file->ndeps++;
+
+ return 0;
+}
+
+caddr_t
+linker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
+{
+ caddr_t address;
+ size_t size;
+ size_t common_size = 0;
+ int i;
+
+ KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d",
+ file, name, deps));
+
+ if (file->ops->lookup_symbol(file, name, &address, &size) == 0)
+ if (address == 0)
+ /*
+ * For commons, first look them up in the dependancies and
+ * only allocate space if not found there.
+ */
+ common_size = size;
+ else
+ return address;
+
+ if (deps)
+ for (i = 0; i < file->ndeps; i++) {
+ address = linker_file_lookup_symbol(file->deps[i], name, 0);
+ if (address)
+ return address;
+ }
+
+ if (common_size > 0) {
+ /*
+ * This is a common symbol which was not found in the
+ * dependancies. We maintain a simple common symbol table in
+ * the file object.
+ */
+ struct common_symbol* cp;
+
+ for (cp = STAILQ_FIRST(&file->common); cp;
+ cp = STAILQ_NEXT(cp, link))
+ if (!strcmp(cp->name, name))
+ return cp->address;
+
+ /*
+ * Round the symbol size up to align.
+ */
+ common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
+ cp = malloc(sizeof(struct common_symbol)
+ + common_size
+ + strlen(name) + 1,
+ M_LINKER, M_WAITOK);
+ if (!cp)
+ return 0;
+
+ cp->address = (caddr_t) (cp + 1);
+ cp->name = cp->address + common_size;
+ strcpy(cp->name, name);
+ bzero(cp->address, common_size);
+ STAILQ_INSERT_TAIL(&file->common, cp, link);
+
+ return cp->address;
+ }
+
+ return 0;
+}
+
+/*
+ * Syscalls.
+ */
+
+int
+kldload(struct proc* p, struct kldload_args* uap, int* retval)
+{
+ char* filename = NULL;
+ linker_file_t lf;
+ int error = 0;
+
+ *retval = -1;
+
+ if (securelevel > 0)
+ return EPERM;
+
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return error;
+
+ filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
+ goto out;
+
+ if (error = linker_load_file(uap->file, &lf))
+ goto out;
+
+ lf->userrefs++;
+ *retval = lf->id;
+
+out:
+ if (filename)
+ free(filename, M_TEMP);
+ return error;
+}
+
+int
+kldunload(struct proc* p, struct kldunload_args* uap, int* retval)
+{
+ linker_file_t lf;
+ int error = 0;
+
+ if (securelevel > 0)
+ return EPERM;
+
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return error;
+
+ lf = linker_find_file_by_id(SCARG(uap, fileid));
+ if (lf) {
+ KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
+ if (lf->userrefs == 0) {
+ printf("linkerunload: attempt to unload file which was not loaded by user\n");
+ error = EBUSY;
+ goto out;
+ }
+ lf->userrefs--;
+ error = linker_file_unload(lf);
+ } else
+ error = ENOENT;
+
+out:
+ return error;
+}
+
+int
+kldfind(struct proc* p, struct kldfind_args* uap, int* retval)
+{
+ char* filename = NULL;
+ linker_file_t lf;
+ int error = 0;
+
+ *retval = -1;
+
+ filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
+ goto out;
+
+ lf = linker_find_file_by_name(filename);
+ if (lf)
+ *retval = lf->id;
+ else
+ error = ENOENT;
+
+out:
+ if (filename)
+ free(filename, M_TEMP);
+ return error;
+}
+
+int
+kldnext(struct proc* p, struct kldnext_args* uap, int* retval)
+{
+ linker_file_t lf;
+ int error = 0;
+
+ if (SCARG(uap, fileid) == 0) {
+ if (TAILQ_FIRST(&files))
+ *retval = TAILQ_FIRST(&files)->id;
+ else
+ *retval = 0;
+ return 0;
+ }
+
+ lf = linker_find_file_by_id(SCARG(uap, fileid));
+ if (lf) {
+ if (TAILQ_NEXT(lf, link))
+ *retval = TAILQ_NEXT(lf, link)->id;
+ else
+ *retval = 0;
+ } else
+ error = ENOENT;
+
+ return error;
+}
+
+int
+kldstat(struct proc* p, struct kldstat_args* uap, int* retval)
+{
+ linker_file_t lf;
+ int error = 0;
+ int version;
+ struct kld_file_stat* stat;
+ int namelen;
+
+ lf = linker_find_file_by_id(SCARG(uap, fileid));
+ if (!lf) {
+ error = ENOENT;
+ goto out;
+ }
+
+ stat = SCARG(uap, stat);
+
+ /*
+ * Check the version of the user's structure.
+ */
+ if (error = copyin(&stat->version, &version, sizeof(version)))
+ goto out;
+ if (version != sizeof(struct kld_file_stat)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ namelen = strlen(lf->filename) + 1;
+ if (namelen > MAXPATHLEN)
+ namelen = MAXPATHLEN;
+ if (error = copyout(lf->filename, &stat->name[0], namelen))
+ goto out;
+ if (error = copyout(&lf->refs, &stat->refs, sizeof(int)))
+ goto out;
+ if (error = copyout(&lf->id, &stat->id, sizeof(int)))
+ goto out;
+ if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t)))
+ goto out;
+ if (error = copyout(&lf->size, &stat->size, sizeof(size_t)))
+ goto out;
+
+ *retval = 0;
+
+out:
+ return error;
+}
+
+int
+kldfirstmod(struct proc* p, struct kldfirstmod_args* uap, int* retval)
+{
+ linker_file_t lf;
+ int error = 0;
+
+ lf = linker_find_file_by_id(SCARG(uap, fileid));
+ if (lf) {
+ if (TAILQ_FIRST(&lf->modules))
+ *retval = module_getid(TAILQ_FIRST(&lf->modules));
+ else
+ *retval = 0;
+ } else
+ error = ENOENT;
+
+ return error;
+}
diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c
new file mode 100644
index 000000000000..8a4048afd101
--- /dev/null
+++ b/sys/kern/kern_module.c
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 1997 Doug Rabson
+ * 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$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/module.h>
+#include <sys/linker.h>
+
+#define M_MODULE M_TEMP /* XXX */
+
+typedef TAILQ_HEAD(, module) modulelist_t;
+struct module {
+ TAILQ_ENTRY(module) link; /* chain together all modules */
+ TAILQ_ENTRY(module) flink; /* all modules in a file */
+ struct linker_file* file; /* file which contains this module */
+ int refs; /* reference count */
+ int id; /* unique id number */
+ char *name; /* module name */
+ modeventhand_t handler; /* event handler */
+ void *arg; /* argument for handler */
+};
+
+#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
+
+static modulelist_t modules;
+static int nextid = 1;
+
+static void module_shutdown(int, void*);
+
+static void
+module_init(void* arg)
+{
+ TAILQ_INIT(&modules);
+ at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC);
+}
+
+SYSINIT(module, SI_SUB_KMEM, SI_ORDER_ANY, module_init, 0);
+
+static void
+module_shutdown(int arg1, void* arg2)
+{
+ module_t mod;
+ int error;
+
+ for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
+ MOD_EVENT(mod, MOD_SHUTDOWN);
+}
+
+void
+module_register_static(void *arg)
+{
+ moduledata_t* data = (moduledata_t*) arg;
+ int error;
+
+ if (error = module_register(data->name, data->evhand, data->priv))
+ printf("module_register_static: module_register(%s, %x, %x) returned %d",
+ data->name, data->evhand, data->priv, error);
+}
+
+int
+module_register(const char* name, modeventhand_t handler, void* arg)
+{
+ size_t namelen;
+ module_t newmod;
+ int error;
+
+ namelen = strlen(name) + 1;
+ newmod = (module_t) malloc(sizeof(struct module) + namelen,
+ M_MODULE, M_WAITOK);
+ if (newmod == 0)
+ return ENOMEM;
+
+ newmod->refs = 1;
+ newmod->id = nextid++;
+ newmod->name = (char *) (newmod + 1);
+ strcpy(newmod->name, name);
+ newmod->handler = handler;
+ newmod->arg = arg;
+ TAILQ_INSERT_TAIL(&modules, newmod, link);
+
+ if (linker_current_file) {
+ TAILQ_INSERT_TAIL(&linker_current_file->modules, newmod, flink);
+ newmod->file = linker_current_file;
+ } else
+ newmod->file = 0;
+
+ if (error = MOD_EVENT(newmod, MOD_LOAD)) {
+ module_release(newmod);
+ return error;
+ }
+
+ return 0;
+}
+
+void
+module_reference(module_t mod)
+{
+ MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
+
+ mod->refs++;
+}
+
+void
+module_release(module_t mod)
+{
+ if (mod->refs <= 0)
+ panic("module_release: bad reference count");
+
+ MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
+
+ mod->refs--;
+ if (mod->refs == 0) {
+ TAILQ_REMOVE(&modules, mod, link);
+ if (mod->file) {
+ TAILQ_REMOVE(&mod->file->modules, mod, flink);
+ }
+ free(mod, M_MODULE);
+ }
+}
+
+module_t
+module_lookupbyname(const char* name)
+{
+ module_t mod;
+
+ for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
+ if (!strcmp(mod->name, name))
+ return mod;
+ }
+
+ return 0;
+}
+
+module_t
+module_lookupbyid(int modid)
+{
+ module_t mod;
+
+ for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
+ if (mod->id == modid)
+ return mod;
+ }
+
+ return 0;
+}
+
+int
+module_unload(module_t mod)
+{
+ return MOD_EVENT(mod, MOD_UNLOAD);
+}
+
+int
+module_getid(module_t mod)
+{
+ return mod->id;
+}
+
+module_t
+module_getfnext(module_t mod)
+{
+ return TAILQ_NEXT(mod, flink);
+}
+
+/*
+ * Syscalls.
+ */
+int
+modnext(struct proc* p, struct modnext_args* uap, int* retval)
+{
+ module_t mod;
+
+ *retval = -1;
+ if (SCARG(uap, modid) == 0) {
+ mod = TAILQ_FIRST(&modules);
+ if (mod) {
+ *retval = mod->id;
+ return 0;
+ } else
+ return ENOENT;
+ }
+
+ mod = module_lookupbyid(SCARG(uap, modid));
+ if (!mod)
+ return ENOENT;
+
+ if (TAILQ_NEXT(mod, link))
+ *retval = TAILQ_NEXT(mod, link)->id;
+ else
+ *retval = 0;
+ return 0;
+}
+
+int
+modfnext(struct proc* p, struct modfnext_args* uap, int* retval)
+{
+ module_t mod;
+
+ *retval = -1;
+
+ mod = module_lookupbyid(SCARG(uap, modid));
+ if (!mod)
+ return ENOENT;
+
+ if (TAILQ_NEXT(mod, flink))
+ *retval = TAILQ_NEXT(mod, flink)->id;
+ else
+ *retval = 0;
+ return 0;
+}
+
+int
+modstat(struct proc* p, struct modstat_args* uap, int* retval)
+{
+ module_t mod;
+ int error = 0;
+ int namelen;
+ int version;
+ struct module_stat* stat;
+
+ mod = module_lookupbyid(SCARG(uap, modid));
+ if (!mod)
+ return ENOENT;
+
+ stat = SCARG(uap, stat);
+
+ /*
+ * Check the version of the user's structure.
+ */
+ if (error = copyin(&stat->version, &version, sizeof(version)))
+ goto out;
+ if (version != sizeof(struct module_stat)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ namelen = strlen(mod->name) + 1;
+ if (namelen > MAXMODNAME)
+ namelen = MAXMODNAME;
+ if (error = copyout(mod->name, &stat->name[0], namelen))
+ goto out;
+
+ if (error = copyout(&mod->refs, &stat->refs, sizeof(int)))
+ goto out;
+ if (error = copyout(&mod->id, &stat->id, sizeof(int)))
+ goto out;
+
+ *retval = 0;
+
+out:
+ return error;
+}
+
+int
+modfind(struct proc* p, struct modfind_args* uap, int* retval)
+{
+ int error = 0;
+ char name[MAXMODNAME];
+ module_t mod;
+
+ if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0))
+ goto out;
+
+ mod = module_lookupbyname(name);
+ if (!mod)
+ error = ENOENT;
+ else
+ *retval = mod->id;
+
+out:
+ return error;
+}
diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c
new file mode 100644
index 000000000000..5fd3f878284e
--- /dev/null
+++ b/sys/kern/link_aout.c
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1997 Doug Rabson
+ * 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$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/sysproto.h>
+#include <sys/proc.h>
+#include <sys/namei.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/linker.h>
+#include <a.out.h>
+#include <link.h>
+#include <machine/reloc.h>
+#include <sys/imgact_aout.h>
+
+static int link_aout_load_file(const char*, linker_file_t*);
+
+static int link_aout_lookup_symbol(linker_file_t, const char*,
+ caddr_t*, size_t*);
+static void link_aout_unload(linker_file_t);
+
+static struct linker_class_ops link_aout_class_ops = {
+ link_aout_load_file,
+};
+
+static struct linker_file_ops link_aout_file_ops = {
+ link_aout_lookup_symbol,
+ link_aout_unload,
+};
+
+typedef struct aout_file {
+ char* address; /* Load address */
+ struct _dynamic* dynamic; /* Symbol table etc. */
+} *aout_file_t;
+
+static int load_dependancies(linker_file_t lf);
+static int relocate_file(linker_file_t lf);
+
+/*
+ * The kernel symbol table starts here.
+ */
+extern struct _dynamic _DYNAMIC;
+
+static void
+link_aout_init(void* arg)
+{
+ struct _dynamic* dp = &_DYNAMIC;
+
+ linker_add_class("a.out", NULL, &link_aout_class_ops);
+
+ if (dp) {
+ aout_file_t af;
+
+ af = malloc(sizeof(struct aout_file), M_LINKER, M_NOWAIT);
+ if (af == NULL)
+ panic("link_aout_init: Can't create linker structures for kernel");
+
+ af->address = 0;
+ af->dynamic = dp;
+ linker_kernel_file =
+ linker_make_file(kernelname, af, &link_aout_file_ops);
+ if (linker_kernel_file == NULL)
+ panic("link_aout_init: Can't create linker structures for kernel");
+ /*
+ * XXX there must be a better way of getting these constants.
+ */
+ linker_kernel_file->address = (caddr_t) 0xf0100000;
+ linker_kernel_file->size = -0xf0100000;
+ linker_current_file = linker_kernel_file;
+ }
+}
+
+SYSINIT(link_aout, SI_SUB_KMEM, SI_ORDER_THIRD, link_aout_init, 0);
+
+int
+link_aout_load_file(const char* filename, linker_file_t* result)
+{
+ struct nameidata nd;
+ struct vnode* file;
+ struct proc* p = curproc; /* XXX */
+ int error = 0;
+ int resid;
+ struct iovec aiov;
+ struct uio auio;
+ struct exec header;
+ aout_file_t af;
+ linker_file_t lf;
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p);
+ error = vn_open(&nd, FREAD, 0);
+ if (error)
+ return error;
+
+ /*
+ * Read the a.out header from the file.
+ */
+ error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0,
+ UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+ if (error)
+ goto out;
+
+ if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC))
+ goto out;
+
+ /*
+ * We have an a.out file, so make some space to read it in.
+ */
+ af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
+ af->address = malloc(header.a_text + header.a_data + header.a_bss,
+ M_LINKER, M_WAITOK);
+
+ /*
+ * Read the text and data sections and zero the bss.
+ */
+ error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) af->address,
+ header.a_text + header.a_data, 0,
+ UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+ if (error)
+ goto out;
+ bzero(af->address + header.a_text + header.a_data, header.a_bss);
+
+ /*
+ * Assume _DYNAMIC is the first data item.
+ */
+ af->dynamic = (struct _dynamic*) (af->address + header.a_text);
+ if (af->dynamic->d_version != LD_VERSION_BSD) {
+ free(af->address, M_LINKER);
+ free(af, M_LINKER);
+ goto out;
+ }
+ (long) af->dynamic->d_un.d_sdt += af->address;
+
+ lf = linker_make_file(filename, af, &link_aout_file_ops);
+ if (lf == NULL) {
+ free(af->address, M_LINKER);
+ free(af, M_LINKER);
+ error = ENOMEM;
+ goto out;
+ }
+ lf->address = af->address;
+ lf->size = header.a_text + header.a_data + header.a_bss;
+
+ if ((error = load_dependancies(lf)) != 0
+ || (error = relocate_file(lf)) != 0) {
+ linker_file_unload(lf);
+ goto out;
+ }
+
+ *result = lf;
+
+out:
+ VOP_UNLOCK(nd.ni_vp, 0, p);
+ vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
+
+ return error;
+}
+
+void
+link_aout_unload(linker_file_t file)
+{
+ aout_file_t af = file->priv;
+
+ if (af) {
+ if (af->address)
+ free(af->address, M_LINKER);
+ free(af, M_LINKER);
+ }
+}
+
+#define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
+
+static int
+load_dependancies(linker_file_t lf)
+{
+ aout_file_t af = lf->priv;
+ linker_file_t lfdep;
+ long off;
+ struct sod* sodp;
+ char* name;
+ char* filename = 0;
+ int error = 0;
+
+ /*
+ * All files are dependant on /kernel.
+ */
+ linker_kernel_file->refs++;
+ linker_file_add_dependancy(lf, linker_kernel_file);
+
+ off = LD_NEED(af->dynamic);
+
+ /*
+ * Load the dependancies.
+ */
+ while (off != 0) {
+ sodp = AOUT_RELOC(af, struct sod, off);
+ name = AOUT_RELOC(af, char, sodp->sod_name);
+
+ /*
+ * Prepend pathname if dep is not an absolute filename.
+ */
+ if (name[0] != '/') {
+ char* p;
+ filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ p = lf->filename + strlen(lf->filename) - 1;
+ while (p >= lf->filename && *p != '/')
+ p--;
+ if (p >= lf->filename) {
+ strncpy(filename, lf->filename, p - lf->filename);
+ filename[p - lf->filename] = '\0';
+ strcat(filename, "/");
+ strcat(filename, name);
+ name = filename;
+ }
+ }
+ error = linker_load_file(name, &lfdep);
+ if (error)
+ goto out;
+ error = linker_file_add_dependancy(lf, lfdep);
+ if (error)
+ goto out;
+ off = sodp->sod_next;
+ }
+
+out:
+ if (filename)
+ free(filename, M_TEMP);
+ return error;
+}
+
+/*
+ * XXX i386 dependant.
+ */
+static long
+read_relocation(struct relocation_info* r, char* addr)
+{
+ int length = r->r_length;
+ if (length == 0)
+ return *(u_char*) addr;
+ else if (length == 1)
+ return *(u_short*) addr;
+ else if (length == 2)
+ return *(u_int*) addr;
+ else
+ printf("link_aout: unsupported relocation size %d\n", r->r_length);
+ return 0;
+}
+
+static void
+write_relocation(struct relocation_info* r, char* addr, long value)
+{
+ int length = r->r_length;
+ if (length == 0)
+ *(u_char*) addr = value;
+ else if (length == 1)
+ *(u_short*) addr = value;
+ else if (length == 2)
+ *(u_int*) addr = value;
+ else
+ printf("link_aout: unsupported relocation size %d\n", r->r_length);
+}
+
+static int
+relocate_file(linker_file_t lf)
+{
+ aout_file_t af = lf->priv;
+ struct relocation_info* rel;
+ struct relocation_info* erel;
+ struct relocation_info* r;
+ struct nzlist* symbolbase;
+ char* stringbase;
+ struct nzlist* np;
+ char* sym;
+ long relocation;
+
+ rel = AOUT_RELOC(af, struct relocation_info, LD_REL(af->dynamic));
+ erel = AOUT_RELOC(af, struct relocation_info,
+ LD_REL(af->dynamic) + LD_RELSZ(af->dynamic));
+ symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
+ stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
+
+ for (r = rel; r < erel; r++) {
+ char* addr;
+
+ if (r->r_address == 0)
+ break;
+
+ addr = AOUT_RELOC(af, char, r->r_address);
+ if (r->r_extern) {
+ np = &symbolbase[r->r_symbolnum];
+ sym = &stringbase[np->nz_strx];
+
+ if (sym[0] != '_') {
+ printf("link_aout: bad symbol name %s\n", sym);
+ relocation = 0;
+ } else
+ relocation = (long)
+ linker_file_lookup_symbol(lf, sym + 1,
+ np->nz_type != (N_SETV+N_EXT));
+ if (!relocation) {
+ printf("link_aout: symbol %s not found\n", sym);
+ return ENOENT;
+ }
+
+ relocation += read_relocation(r, addr);
+
+ if (r->r_jmptable) {
+ printf("link_aout: can't cope with jump table relocations\n");
+ continue;
+ }
+
+ if (r->r_pcrel)
+ relocation -= (long) af->address;
+
+ if (r->r_copy) {
+ printf("link_aout: can't cope with copy relocations\n");
+ continue;
+ }
+
+ write_relocation(r, addr, relocation);
+ } else {
+ write_relocation(r, addr,
+ (long)(read_relocation(r, addr) + af->address));
+ }
+
+ }
+
+ return 0;
+}
+
+static long
+symbol_hash_value(aout_file_t af, const char* name)
+{
+ long hashval;
+ const char* p;
+
+ hashval = '_'; /* fake a starting '_' for C symbols */
+ for (p = name; *p; p++)
+ hashval = (hashval << 1) + *p;
+
+ return (hashval & 0x7fffffff) % LD_BUCKETS(af->dynamic);
+}
+
+int
+link_aout_lookup_symbol(linker_file_t file, const char* name,
+ caddr_t* address, size_t* size)
+{
+ aout_file_t af = file->priv;
+ int buckets;
+ long hashval;
+ struct rrs_hash* hashbase;
+ struct nzlist* symbolbase;
+ char* stringbase;
+ struct rrs_hash* hp;
+ struct nzlist* np;
+ char* cp;
+
+ if (LD_BUCKETS(af->dynamic) == 0)
+ return NULL;
+
+ hashbase = AOUT_RELOC(af, struct rrs_hash, LD_HASH(af->dynamic));
+ symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
+ stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
+
+restart:
+ hashval = symbol_hash_value(af, name);
+ hp = &hashbase[hashval];
+ if (hp->rh_symbolnum == -1)
+ return ENOENT;
+
+ while (hp) {
+ np = (struct nzlist *) &symbolbase[hp->rh_symbolnum];
+ cp = stringbase + np->nz_strx;
+ /*
+ * Note: we fake the leading '_' for C symbols.
+ */
+ if (cp[0] == '_' && !strcmp(cp + 1, name))
+ break;
+
+ if (hp->rh_next == 0)
+ hp = NULL;
+ else
+ hp = &hashbase[hp->rh_next];
+ }
+
+ if (hp == NULL)
+ /*
+ * Not found.
+ */
+ return ENOENT;
+
+ /*
+ * Check for an aliased symbol, whatever that is.
+ */
+ if (np->nz_type == N_INDR+N_EXT) {
+ name = stringbase + (++np)->nz_strx + 1; /* +1 for '_' */
+ goto restart;
+ }
+
+ /*
+ * Check this is an actual definition of the symbol.
+ */
+ if (np->nz_value == 0)
+ return ENOENT;
+
+ if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
+ if (np->nz_other == AUX_FUNC)
+ /* weak function */
+ return ENOENT;
+ *address = 0;
+ *size = np->nz_value;
+ } else {
+ *address = AOUT_RELOC(af, char, np->nz_value);
+ *size = np->nz_size;
+ }
+
+ return 0;
+}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index a3cd101dd7b3..b0b5d0889cd9 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -276,4 +276,59 @@ char *syscallnames[] = {
"#252", /* 252 = poll */
"issetugid", /* 253 = issetugid */
"lchown", /* 254 = lchown */
+ "#255", /* 255 = nosys */
+ "#256", /* 256 = nosys */
+ "#257", /* 257 = nosys */
+ "#258", /* 258 = nosys */
+ "#259", /* 259 = nosys */
+ "#260", /* 260 = nosys */
+ "#261", /* 261 = nosys */
+ "#262", /* 262 = nosys */
+ "#263", /* 263 = nosys */
+ "#264", /* 264 = nosys */
+ "#265", /* 265 = nosys */
+ "#266", /* 266 = nosys */
+ "#267", /* 267 = nosys */
+ "#268", /* 268 = nosys */
+ "#269", /* 269 = nosys */
+ "#270", /* 270 = nosys */
+ "#271", /* 271 = nosys */
+ "#272", /* 272 = nosys */
+ "#273", /* 273 = nosys */
+ "#274", /* 274 = nosys */
+ "#275", /* 275 = nosys */
+ "#276", /* 276 = nosys */
+ "#277", /* 277 = nosys */
+ "#278", /* 278 = nosys */
+ "#279", /* 279 = nosys */
+ "#280", /* 280 = nosys */
+ "#281", /* 281 = nosys */
+ "#282", /* 282 = nosys */
+ "#283", /* 283 = nosys */
+ "#284", /* 284 = nosys */
+ "#285", /* 285 = nosys */
+ "#286", /* 286 = nosys */
+ "#287", /* 287 = nosys */
+ "#288", /* 288 = nosys */
+ "#289", /* 289 = nosys */
+ "#290", /* 290 = nosys */
+ "#291", /* 291 = nosys */
+ "#292", /* 292 = nosys */
+ "#293", /* 293 = nosys */
+ "#294", /* 294 = nosys */
+ "#295", /* 295 = nosys */
+ "#296", /* 296 = nosys */
+ "#297", /* 297 = nosys */
+ "#298", /* 298 = nosys */
+ "#299", /* 299 = nosys */
+ "modnext", /* 300 = modnext */
+ "modstat", /* 301 = modstat */
+ "modfnext", /* 302 = modfnext */
+ "modfind", /* 303 = modfind */
+ "kldload", /* 304 = kldload */
+ "kldunload", /* 305 = kldunload */
+ "kldfind", /* 306 = kldfind */
+ "kldnext", /* 307 = kldnext */
+ "kldstat", /* 308 = kldstat */
+ "kldfirstmod", /* 309 = kldfirstmod */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index fc02d31b4401..dcd916b794e2 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
- $Id: syscalls.master,v 1.34 1997/03/31 12:14:48 peter Exp $
+ $Id: syscalls.master,v 1.35 1997/03/31 14:52:50 peter Exp $
; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94
;
; System call name/number master file.
@@ -393,3 +393,59 @@
252 UNIMPL NOHIDE poll (OpenBSD)
253 STD BSD { int issetugid(void); }
254 STD BSD { int lchown(char *path, int uid, int gid); }
+255 UNIMPL NOHIDE nosys
+256 UNIMPL NOHIDE nosys
+257 UNIMPL NOHIDE nosys
+258 UNIMPL NOHIDE nosys
+259 UNIMPL NOHIDE nosys
+260 UNIMPL NOHIDE nosys
+261 UNIMPL NOHIDE nosys
+262 UNIMPL NOHIDE nosys
+263 UNIMPL NOHIDE nosys
+264 UNIMPL NOHIDE nosys
+265 UNIMPL NOHIDE nosys
+266 UNIMPL NOHIDE nosys
+267 UNIMPL NOHIDE nosys
+268 UNIMPL NOHIDE nosys
+269 UNIMPL NOHIDE nosys
+270 UNIMPL NOHIDE nosys
+271 UNIMPL NOHIDE nosys
+272 UNIMPL NOHIDE nosys
+273 UNIMPL NOHIDE nosys
+274 UNIMPL NOHIDE nosys
+275 UNIMPL NOHIDE nosys
+276 UNIMPL NOHIDE nosys
+277 UNIMPL NOHIDE nosys
+278 UNIMPL NOHIDE nosys
+279 UNIMPL NOHIDE nosys
+280 UNIMPL NOHIDE nosys
+281 UNIMPL NOHIDE nosys
+282 UNIMPL NOHIDE nosys
+283 UNIMPL NOHIDE nosys
+284 UNIMPL NOHIDE nosys
+285 UNIMPL NOHIDE nosys
+286 UNIMPL NOHIDE nosys
+287 UNIMPL NOHIDE nosys
+288 UNIMPL NOHIDE nosys
+289 UNIMPL NOHIDE nosys
+290 UNIMPL NOHIDE nosys
+291 UNIMPL NOHIDE nosys
+292 UNIMPL NOHIDE nosys
+293 UNIMPL NOHIDE nosys
+294 UNIMPL NOHIDE nosys
+295 UNIMPL NOHIDE nosys
+296 UNIMPL NOHIDE nosys
+297 UNIMPL NOHIDE nosys
+298 UNIMPL NOHIDE nosys
+299 UNIMPL NOHIDE nosys
+; syscall numbers for FreeBSD
+300 STD BSD { int modnext(int modid); }
+301 STD BSD { int modstat(int modid, struct module_stat* stat); }
+302 STD BSD { int modfnext(int modid); }
+303 STD BSD { int modfind(char *name); }
+304 STD BSD { int kldload(const char *file); }
+305 STD BSD { int kldunload(int fileid); }
+306 STD BSD { int kldfind(const char *file); }
+307 STD BSD { int kldnext(int fileid); }
+308 STD BSD { int kldstat(int fileid, struct kld_file_stat* stat); }
+309 STD BSD { int kldfirstmod(int fileid); }
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
new file mode 100644
index 000000000000..d1862424e0f2
--- /dev/null
+++ b/sys/sys/linker.h
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 1997 Doug Rabson
+ * 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$
+ */
+
+#ifndef _SYS_LINKER_H_
+#define _SYS_LINKER_H_
+
+#ifdef KERNEL
+
+#define M_LINKER M_TEMP /* XXX */
+
+/*
+ * Object representing a file which has been loaded by the linker.
+ */
+typedef struct linker_file* linker_file_t;
+typedef TAILQ_HEAD(, linker_file) linker_file_list_t;
+
+struct linker_file_ops {
+ /*
+ * Lookup a symbol in the file's symbol table. If the symbol is
+ * not found then return ENOENT, otherwise zero. If the symbol
+ * found is a common symbol, return with *address set to zero and
+ * *size set to the size of the common space required. Otherwise
+ * set *address the value of the symbol.
+ */
+ int (*lookup_symbol)(linker_file_t, const char* name,
+ caddr_t* address, size_t* size);
+
+ /*
+ * Unload a file, releasing dependancies and freeing storage.
+ */
+ void (*unload)(linker_file_t);
+};
+
+struct common_symbol {
+ STAILQ_ENTRY(common_symbol) link;
+ char* name;
+ caddr_t address;
+};
+
+struct linker_file {
+ int refs; /* reference count */
+ int userrefs; /* modload(2) count */
+ TAILQ_ENTRY(linker_file) link; /* list of all loaded files */
+ char* filename; /* file which was loaded */
+ int id; /* unique id */
+ caddr_t address; /* load address */
+ size_t size; /* size of file */
+ int ndeps; /* number of dependancies */
+ linker_file_t* deps; /* list of dependancies */
+ STAILQ_HEAD(, common_symbol) common; /* list of common symbols */
+ TAILQ_HEAD(, module) modules; /* modules in this file */
+ void* priv; /* implementation data */
+
+ struct linker_file_ops* ops;
+};
+
+/*
+ * Object implementing a class of file (a.out, elf, etc.)
+ */
+typedef struct linker_class *linker_class_t;
+typedef TAILQ_HEAD(, linker_class) linker_class_list_t;
+
+struct linker_class_ops {
+ /*
+ * Load a file, returning the new linker_file_t in *result. If
+ * the class does not recognise the file type, zero should be
+ * returned, without modifying *result. If the file is
+ * recognised, the file should be loaded, *result set to the new
+ * file and zero returned. If some other error is detected an
+ * appropriate errno should be returned.
+ */
+ int (*load_file)(const char* filename, linker_file_t* result);
+};
+
+struct linker_class {
+ TAILQ_ENTRY(linker_class) link; /* list of all file classes */
+ const char* desc; /* description (e.g. "a.out") */
+ void* priv; /* implementation data */
+
+ struct linker_class_ops *ops;
+};
+
+/*
+ * The file representing the currently running kernel. This contains
+ * the global symbol table.
+ */
+linker_file_t linker_kernel_file;
+
+/*
+ * The file which is currently loading. Used to register modules with
+ * the files which contain them.
+ */
+linker_file_t linker_current_file;
+
+/*
+ * Add a new file class to the linker.
+ */
+int linker_add_class(const char* desc, void* priv,
+ struct linker_class_ops* ops);
+
+/*
+ * Load a file, trying each file class until one succeeds.
+ */
+int linker_load_file(const char* filename, linker_file_t* result);
+
+/*
+ * Find a currently loaded file given its filename.
+ */
+linker_file_t linker_find_file_by_name(const char* filename);
+
+/*
+ * Find a currently loaded file given its file id.
+ */
+linker_file_t linker_find_file_by_id(int fileid);
+
+/*
+ * Called from a class handler when a file is laoded.
+ */
+linker_file_t linker_make_file(const char* filename, void* priv,
+ struct linker_file_ops* ops);
+
+/*
+ * Unload a file, freeing up memory.
+ */
+int linker_file_unload(linker_file_t file);
+
+/*
+ * Add a dependancy to a file.
+ */
+int linker_file_add_dependancy(linker_file_t file, linker_file_t dep);
+
+/*
+ * Lookup a symbol in a file. If deps is TRUE, look in dependancies
+ * if not found in file.
+ */
+caddr_t linker_file_lookup_symbol(linker_file_t file, const char* name,
+ int deps);
+
+#ifdef KLD_DEBUG
+
+extern int kld_debug;
+#define KLD_DEBUG_FILE 1 /* file load/unload */
+#define KLD_DEBUG_SYM 2 /* symbol lookup */
+
+#define KLD_DPF(cat, args) \
+ do { \
+ if (KLD_debug & KLD_DEBUG_##cat) printf args; \
+ } while (0)
+
+#else
+
+#define KLD_DPF(cat, args)
+
+#endif
+
+#endif /* KERNEL */
+
+struct kld_file_stat {
+ int version; /* set to sizeof(linker_file_stat) */
+ char name[MAXPATHLEN];
+ int refs;
+ int id;
+ caddr_t address; /* load address */
+ size_t size; /* size in bytes */
+};
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int kldload(const char* file);
+int kldunload(int fileid);
+int kldfind(const char* file);
+int kldnext(int fileid);
+int kldstat(int fileid, struct kld_file_stat* stat);
+int kldfirstmod(int fileid);
+__END_DECLS
+
+#endif
+
+#endif /* !_SYS_KLD_H_ */
diff --git a/sys/sys/module.h b/sys/sys/module.h
new file mode 100644
index 000000000000..643621204d3f
--- /dev/null
+++ b/sys/sys/module.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1997 Doug Rabson
+ * 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$
+ */
+
+#ifndef _SYS_MODULE_H_
+#define _SYS_MODULE_H_
+
+#ifdef KERNEL
+
+typedef enum {
+ MOD_LOAD,
+ MOD_UNLOAD,
+ MOD_SHUTDOWN
+} modeventtype_t;
+
+struct module;
+typedef struct module *module_t;
+
+typedef int (*modeventhand_t)(module_t mod, modeventtype_t what, void *arg);
+
+/*
+ * Struct for registering modules statically via SYSINIT.
+ */
+typedef struct moduledata {
+ char* name; /* module name */
+ modeventhand_t evhand; /* event handler */
+ void* priv; /* extra data */
+} moduledata_t;
+
+#define DECLARE_MODULE(name, data, sub, order) \
+SYSINIT(name##module, sub, order, module_register_static, &data)
+
+void module_register_static(void *data);
+int module_register(const char *name, modeventhand_t callback, void *arg);
+module_t module_lookupbyname(const char *name);
+module_t module_lookupbyid(int modid);
+void module_reference(module_t mod);
+void module_release(module_t mod);
+int module_unload(module_t mod);
+int module_getid(module_t mod);
+module_t module_getfnext(module_t mod);
+
+#ifdef MOD_DEBUG
+
+extern int mod_debug;
+#define MOD_DEBUG_REFS 1
+
+#define MOD_DPF(cat, args) \
+ do { \
+ if (mod_debug & MOD_DEBUG_##cat) printf args; \
+ } while (0)
+
+#else
+
+#define MOD_DPF(cat, args)
+
+#endif
+
+#endif /* KERNEL */
+
+#define MAXMODNAME 32
+
+struct module_stat {
+ int version; /* set to sizeof(struct module_stat) */
+ char name[MAXMODNAME];
+ int refs;
+ int id;
+};
+
+#ifndef KERNEL
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int modnext(int modid);
+int modfnext(int modid);
+int modstat(int modid, struct module_stat* stat);
+int modfind(char *name);
+__END_DECLS
+
+#endif
+
+#endif /* !_SYS_MODULE_H_ */
diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h
index 99f9f46dcd81..6d6aacd63b7b 100644
--- a/sys/sys/syscall-hide.h
+++ b/sys/sys/syscall-hide.h
@@ -214,3 +214,13 @@ HIDE_BSD(minherit)
HIDE_BSD(rfork)
HIDE_BSD(issetugid)
HIDE_BSD(lchown)
+HIDE_BSD(modnext)
+HIDE_BSD(modstat)
+HIDE_BSD(modfnext)
+HIDE_BSD(modfind)
+HIDE_BSD(kldload)
+HIDE_BSD(kldunload)
+HIDE_BSD(kldfind)
+HIDE_BSD(kldnext)
+HIDE_BSD(kldstat)
+HIDE_BSD(kldfirstmod)
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 1ae2aa1417c2..90e4254149bf 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -208,4 +208,14 @@
#define SYS_rfork 251
#define SYS_issetugid 253
#define SYS_lchown 254
-#define SYS_MAXSYSCALL 255
+#define SYS_modnext 300
+#define SYS_modstat 301
+#define SYS_modfnext 302
+#define SYS_modfind 303
+#define SYS_kldload 304
+#define SYS_kldunload 305
+#define SYS_kldfind 306
+#define SYS_kldnext 307
+#define SYS_kldstat 308
+#define SYS_kldfirstmod 309
+#define SYS_MAXSYSCALL 310
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index ba02baf6a677..f278eb945141 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -733,6 +733,38 @@ struct lchown_args {
int uid;
int gid;
};
+struct modnext_args {
+ int modid;
+};
+struct modstat_args {
+ int modid;
+ struct module_stat * stat;
+};
+struct modfnext_args {
+ int modid;
+};
+struct modfind_args {
+ char * name;
+};
+struct kldload_args {
+ const char * file;
+};
+struct kldunload_args {
+ int fileid;
+};
+struct kldfind_args {
+ const char * file;
+};
+struct kldnext_args {
+ int fileid;
+};
+struct kldstat_args {
+ int fileid;
+ struct kld_file_stat * stat;
+};
+struct kldfirstmod_args {
+ int fileid;
+};
int nosys __P((struct proc *, struct nosys_args *, int []));
void exit __P((struct proc *, struct rexit_args *, int [])) __dead2;
int fork __P((struct proc *, struct fork_args *, int []));
@@ -905,6 +937,16 @@ int minherit __P((struct proc *, struct minherit_args *, int []));
int rfork __P((struct proc *, struct rfork_args *, int []));
int issetugid __P((struct proc *, struct issetugid_args *, int []));
int lchown __P((struct proc *, struct lchown_args *, int []));
+int modnext __P((struct proc *, struct modnext_args *, int []));
+int modstat __P((struct proc *, struct modstat_args *, int []));
+int modfnext __P((struct proc *, struct modfnext_args *, int []));
+int modfind __P((struct proc *, struct modfind_args *, int []));
+int kldload __P((struct proc *, struct kldload_args *, int []));
+int kldunload __P((struct proc *, struct kldunload_args *, int []));
+int kldfind __P((struct proc *, struct kldfind_args *, int []));
+int kldnext __P((struct proc *, struct kldnext_args *, int []));
+int kldstat __P((struct proc *, struct kldstat_args *, int []));
+int kldfirstmod __P((struct proc *, struct kldfirstmod_args *, int []));
#ifdef COMPAT_43