Module Name:    src
Committed By:   pgoyette
Date:           Tue Apr  3 08:29:44 UTC 2018

Modified Files:
        src/doc [pgoyette-compat]: COMPAT-branch-notes
        src/lib/libc/sys [pgoyette-compat]: modctl.2
        src/sbin/modstat [pgoyette-compat]: main.c
        src/sys/compat/common [pgoyette-compat]: Makefile.sysio compat_80_mod.c
            compat_mod.h files.common
        src/sys/compat/netbsd32 [pgoyette-compat]: netbsd32_module.c
        src/sys/kern [pgoyette-compat]: compat_stub.c sys_module.c
        src/sys/modules/compat_80 [pgoyette-compat]: Makefile
        src/sys/sys [pgoyette-compat]: compat_stub.h module.h
Added Files:
        src/sys/compat/common [pgoyette-compat]: kern_mod_80.c

Log Message:
Remove fixed allocation of modules' "required" lists (previously
limited to MAXMODDEPS entries).  Update the modctl(MODCTL_STAT)
syscall to return the required data in a new format, and retain
the previous data format in MODCTL_OSTAT.  Update the compat_80
and compat_netbsd32 modules as needed.


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.8 -r1.1.2.9 src/doc/COMPAT-branch-notes
cvs rdiff -u -r1.13 -r1.13.4.1 src/lib/libc/sys/modctl.2
cvs rdiff -u -r1.24.12.1 -r1.24.12.2 src/sbin/modstat/main.c
cvs rdiff -u -r1.7.18.19 -r1.7.18.20 src/sys/compat/common/Makefile.sysio
cvs rdiff -u -r1.1.2.6 -r1.1.2.7 src/sys/compat/common/compat_80_mod.c
cvs rdiff -u -r1.1.42.17 -r1.1.42.18 src/sys/compat/common/compat_mod.h
cvs rdiff -u -r1.1.2.29 -r1.1.2.30 src/sys/compat/common/files.common
cvs rdiff -u -r0 -r1.1.2.1 src/sys/compat/common/kern_mod_80.c
cvs rdiff -u -r1.6 -r1.6.2.1 src/sys/compat/netbsd32/netbsd32_module.c
cvs rdiff -u -r1.1.2.13 -r1.1.2.14 src/sys/kern/compat_stub.c
cvs rdiff -u -r1.23.2.5 -r1.23.2.6 src/sys/kern/sys_module.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/modules/compat_80/Makefile
cvs rdiff -u -r1.1.2.13 -r1.1.2.14 src/sys/sys/compat_stub.h
cvs rdiff -u -r1.41.14.7 -r1.41.14.8 src/sys/sys/module.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/doc/COMPAT-branch-notes
diff -u src/doc/COMPAT-branch-notes:1.1.2.8 src/doc/COMPAT-branch-notes:1.1.2.9
--- src/doc/COMPAT-branch-notes:1.1.2.8	Wed Mar 28 03:41:26 2018
+++ src/doc/COMPAT-branch-notes	Tue Apr  3 08:29:44 2018
@@ -27,6 +27,11 @@ DONE
    defopt/defflag lines in the config files* as needed, to insure that
    built-in dependencies get resolved.
 
+8. Fixed limits on the number of module depedencies and maximum
+   recursion level have been removed.  Previous code for reporting
+   module status to userland has been versioned and moved to the
+   compat_80 module.
+
 
 TODO
 ----

Index: src/lib/libc/sys/modctl.2
diff -u src/lib/libc/sys/modctl.2:1.13 src/lib/libc/sys/modctl.2:1.13.4.1
--- src/lib/libc/sys/modctl.2:1.13	Mon Jul  3 21:32:50 2017
+++ src/lib/libc/sys/modctl.2	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-.\"	$NetBSD: modctl.2,v 1.13 2017/07/03 21:32:50 wiz Exp $
+.\"	$NetBSD: modctl.2,v 1.13.4.1 2018/04/03 08:29:44 pgoyette Exp $
 .\"
 .\" Copyright (c) 2009 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -74,9 +74,19 @@ In this case, the
 argument should be a
 .Em struct iovec
 pointing to a suitable block of memory.
-The kernel will fill this block with an array of
+The kernel will fill this block with
+.Bl -bullet 
+.It
+a count of the number of modules loaded (including aliases),
+.It
+an array of
 .Em modstat_t
-structures, one per loaded module.
+structures, one per loaded module, and
+.It
+a series of NUL-terminated strings containing the modules'
+required modules lists.
+.El
+.Pp
 If the block is not large enough, the data returned will be truncated
 to fit.
 The kernel will then update the
@@ -146,9 +156,6 @@ contains the following elements, which a
 .Bl -tag -width aaaaaaaa
 .It Fa "char ms_name[MAXMODNAME]"
 The name of the module.
-.It Fa "char ms_required[MAXMODNAME * MAXMODDEPS]"
-The list of modules required by this module
-as a comma-delimited list of module names.
 .It Fa "modsrc_t ms_source"
 One of the following enumerated constants:
 .Bl -tag -compact -width "MODULE_SOURCE_FILESYS"
@@ -172,14 +179,13 @@ Device driver.
 Executable file format.
 .It Dv MODULE_CLASS_MISC
 Miscellaneous.
-.It Dv MODULE_CLASS_ANY
-Any module class.
-.\" XXX: is MODULE_CLASS_ANY ever returned by this interface?
 .El
 .It Fa "uint64_t ms_addr"
 The load address within the kernel.
+(This value is available only for privileged users.)
 .It Fa "u_int ms_size"
 Loaded size of the module.
+(This value is available only for privileged users.)
 .It Fa "u_int ms_refcnt"
 Current number of live references to this module.
 .It Fa "u_int ms_flags"
@@ -190,6 +196,8 @@ The "force" flag must be specified to re
 .It Dv MODFLAG_AUTO_LOADED
 The module was auto-loaded by the operating system.
 .El
+.It Fa "uint_ms_reqoffset"
+The offset (in bytes) from the beginning of the required-module data.
 .El
 .Sh RETURN VALUES
 Upon successful completion, the value returned is 0.

Index: src/sbin/modstat/main.c
diff -u src/sbin/modstat/main.c:1.24.12.1 src/sbin/modstat/main.c:1.24.12.2
--- src/sbin/modstat/main.c:1.24.12.1	Sat Mar 10 10:33:40 2018
+++ src/sbin/modstat/main.c	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.24.12.1 2018/03/10 10:33:40 pgoyette Exp $	*/
+/*	$NetBSD: main.c,v 1.24.12.2 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: main.c,v 1.24.12.1 2018/03/10 10:33:40 pgoyette Exp $");
+__RCSID("$NetBSD: main.c,v 1.24.12.2 2018/04/03 08:29:44 pgoyette Exp $");
 #endif /* !lint */
 
 #include <sys/module.h>
@@ -81,6 +81,7 @@ main(int argc, char **argv)
 	int ch, rc, modauto = 1;
 	size_t maxnamelen = 16, i, modautolen;
 	char loadable = '\0';
+	const char *reqoff, *req;
 	bool address = false;
 
 	name = NULL;
@@ -177,29 +178,36 @@ main(int argc, char **argv)
 		len = iov.iov_len;
 	}
 
-	len = iov.iov_len / sizeof(modstat_t);
-	qsort(iov.iov_base, len, sizeof(modstat_t), modstatcmp);
-	for (i = 0, ms = iov.iov_base; i < len; i++, ms++) {
+	len = *(int *)iov.iov_base;
+	ms = (modstat_t *)((char *)iov.iov_base + sizeof(int));
+
+	qsort(ms, len, sizeof(modstat_t), modstatcmp);
+	for (i = 0; i < len; i++, ms++) {
 		size_t namelen = strlen(ms->ms_name);
 		if (maxnamelen < namelen)
 			maxnamelen = namelen;
 	}
+	ms = (modstat_t *)((char *)iov.iov_base + sizeof(int));
+	reqoff = (char *)(&ms[len]);
+
 	printf("%-*s %-8s %-8s %-4s %5s ",
 	    (int)maxnamelen, "NAME", "CLASS", "SOURCE", "FLAG", "REFS");
 	if (address)
 		printf("%-16s ", "ADDRESS");
 	printf("%7s %s \n", "SIZE", "REQUIRES");
-	for (ms = iov.iov_base; len != 0; ms++, len--) {
+
+	for (; len != 0; ms++, len--) {
 		const char *class;
 		const char *source;
 
+		if (ms->ms_reqoffset == 0)
+			req = "-";
+		else {
+			req = &reqoff[ms->ms_reqoffset];
+		}
 		if (name != NULL && strcmp(ms->ms_name, name) != 0) {
 			continue;
 		}
-		if (ms->ms_required[0] == '\0') {
-			ms->ms_required[0] = '-';
-			ms->ms_required[1] = '\0';
-		}
 		if (ms->ms_size == 0) {
 			sbuf[0] = '-';
 			sbuf[1] = '\0';
@@ -221,7 +229,7 @@ main(int argc, char **argv)
 		    ms->ms_refcnt);
 		if (address)
 			printf("%-16" PRIx64 " ", ms->ms_addr);
-		printf("%7s %s\n", sbuf, ms->ms_required);
+		printf("%7s %s\n", sbuf, (req));
 	}
 
 	exit(EXIT_SUCCESS);

Index: src/sys/compat/common/Makefile.sysio
diff -u src/sys/compat/common/Makefile.sysio:1.7.18.19 src/sys/compat/common/Makefile.sysio:1.7.18.20
--- src/sys/compat/common/Makefile.sysio:1.7.18.19	Thu Mar 29 23:23:03 2018
+++ src/sys/compat/common/Makefile.sysio	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile.sysio,v 1.7.18.19 2018/03/29 23:23:03 pgoyette Exp $
+#	$NetBSD: Makefile.sysio,v 1.7.18.20 2018/04/03 08:29:44 pgoyette Exp $
 
 # Sources for syscall and ioctl compatibility across the versions.
 
@@ -45,6 +45,9 @@ SRCS+=	kern_sa_60.c tty_60.c kern_time_6
 # Compatibility code for NetBSD 7.0
 SRCS+=	rtsock_70.c uipc_usrreq_70.c
 
+# Compatability code for NetBSD 8.0
+SRCS+=	kern_mod_80.c
+
 # More compatibility code for NetBSD 5.0
 .PATH:	${S}/opencrypto
 SRCS+=	ocryptodev.c

Index: src/sys/compat/common/compat_80_mod.c
diff -u src/sys/compat/common/compat_80_mod.c:1.1.2.6 src/sys/compat/common/compat_80_mod.c:1.1.2.7
--- src/sys/compat/common/compat_80_mod.c:1.1.2.6	Sat Mar 24 08:10:49 2018
+++ src/sys/compat/common/compat_80_mod.c	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: compat_80_mod.c,v 1.1.2.6 2018/03/24 08:10:49 pgoyette Exp $	*/
+/*	$NetBSD: compat_80_mod.c,v 1.1.2.7 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: compat_80_mod.c,v 1.1.2.6 2018/03/24 08:10:49 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: compat_80_mod.c,v 1.1.2.7 2018/04/03 08:29:44 pgoyette Exp $");
 
 #include <sys/systm.h>
 #include <sys/module.h>
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: compat_80_mo
 int compat_80_init(void)
 {
 
+	kern_mod_80_init();
 	raidframe_80_init();
 
 	return 0;
@@ -55,6 +56,7 @@ int compat_80_fini(void)
 {
 
 	raidframe_80_fini();
+	kern_mod_80_fini();
 
 	return 0;
 }

Index: src/sys/compat/common/compat_mod.h
diff -u src/sys/compat/common/compat_mod.h:1.1.42.17 src/sys/compat/common/compat_mod.h:1.1.42.18
--- src/sys/compat/common/compat_mod.h:1.1.42.17	Sat Mar 31 09:17:35 2018
+++ src/sys/compat/common/compat_mod.h	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: compat_mod.h,v 1.1.42.17 2018/03/31 09:17:35 pgoyette Exp $	*/
+/*	$NetBSD: compat_mod.h,v 1.1.42.18 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -42,6 +42,8 @@ void compat_sysctl_vfs(struct sysctllog 
 #ifdef COMPAT_80
 int compat_80_init(void);
 int compat_80_fini(void);
+void kern_mod_80_init(void);
+void kern_mod_80_fini(void);
 #endif
 
 #ifdef COMPAT_70

Index: src/sys/compat/common/files.common
diff -u src/sys/compat/common/files.common:1.1.2.29 src/sys/compat/common/files.common:1.1.2.30
--- src/sys/compat/common/files.common:1.1.2.29	Sat Mar 31 09:17:35 2018
+++ src/sys/compat/common/files.common	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: files.common,v 1.1.2.29 2018/03/31 09:17:35 pgoyette Exp $
+#	$NetBSD: files.common,v 1.1.2.30 2018/04/03 08:29:44 pgoyette Exp $
 
 #
 # Generic files, used by all compat options.
@@ -96,6 +96,7 @@ file	compat/common/uipc_usrreq_70.c		com
 
 # Compatability code for NetBSD 8.0
 file	compat/common/compat_80_mod.c		compat_80
+file	compat/common/kern_mod_80.c		compat_80
 
 #
 # Sources for sysv ipc compatibility across the versions.

Index: src/sys/compat/netbsd32/netbsd32_module.c
diff -u src/sys/compat/netbsd32/netbsd32_module.c:1.6 src/sys/compat/netbsd32/netbsd32_module.c:1.6.2.1
--- src/sys/compat/netbsd32/netbsd32_module.c:1.6	Thu Jan 18 13:31:21 2018
+++ src/sys/compat/netbsd32/netbsd32_module.c	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_module.c,v 1.6 2018/01/18 13:31:21 maxv Exp $	*/
+/*	$NetBSD: netbsd32_module.c,v 1.6.2.1 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_module.c,v 1.6 2018/01/18 13:31:21 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_module.c,v 1.6.2.1 2018/04/03 08:29:44 pgoyette Exp $");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
@@ -42,17 +42,37 @@ __KERNEL_RCSID(0, "$NetBSD: netbsd32_mod
 #include <compat/netbsd32/netbsd32_syscallargs.h>
 #include <compat/netbsd32/netbsd32_conv.h>
 
+#ifdef COMPAT_80
+static void
+copy_oalias(omodstat_t *oms, const char * const *aliasp, modinfo_t *mi,
+    module_t *mod)
+{
+
+	strlcpy(oms->oms_name, *aliasp, sizeof(oms->oms_name));
+	strlcpy(oms->oms_required, mi->mi_name, sizeof(oms->oms_required));
+	oms->oms_class = mi->mi_class;
+	oms->oms_source = mod->mod_source;
+	oms->oms_flags = mod->mod_flags | MODFLG_IS_ALIAS;
+}
+
 static int
-modctl32_handle_stat(struct netbsd32_iovec *iov, void *arg)
+modctl32_handle_ostat(int cmd, struct netbsd32_iovec *iov, void *arg)
 {
-	modstat_t *ms, *mso;
+	omodstat_t *oms, *omso;
 	modinfo_t *mi;
 	module_t *mod;
 	vaddr_t addr;
 	size_t size;
-	size_t mslen;
+	size_t omslen;
+	size_t used;
 	int error;
+	int omscnt;
 	bool stataddr;
+	const char * const *aliasp;
+	const char *suffix = "...";
+
+	if (cmd != MODCTL_OSTAT)
+		return EINVAL;
 
 	/* If not privileged, don't expose kernel addresses. */
 	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
@@ -60,34 +80,229 @@ modctl32_handle_stat(struct netbsd32_iov
 	stataddr = (error == 0);
 
 	kernconfig_lock();
-	mslen = (module_count+module_builtinlist+1) * sizeof(modstat_t);
-	mso = kmem_zalloc(mslen, KM_SLEEP);
-	ms = mso;
+	omscnt = 0;
 	TAILQ_FOREACH(mod, &module_list, mod_chain) {
+		omscnt++;
 		mi = mod->mod_info;
-		strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
+		if ((aliasp = *mi->mi_aliases) != NULL) {
+			while (*aliasp++ != NULL)
+			omscnt++;
+		}
+	}
+	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+		omscnt++;
+		mi = mod->mod_info;
+		if ((aliasp = *mi->mi_aliases) != NULL) {
+			while (*aliasp++ != NULL)
+			omscnt++;
+		}
+	}
+	omslen = omscnt * sizeof(omodstat_t);
+	omso = kmem_zalloc(omslen, KM_SLEEP);
+	oms = omso;
+	TAILQ_FOREACH(mod, &module_list, mod_chain) {
+		mi = mod->mod_info;
+		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
 		if (mi->mi_required != NULL) {
-			strlcpy(ms->ms_required, mi->mi_required,
-			    sizeof(ms->ms_required));
+			used = strlcpy(oms->oms_required, mi->mi_required,
+			    sizeof(oms->oms_required));
+			if (used >= sizeof(oms->oms_required)) { 
+				oms->oms_required[sizeof(oms->oms_required) -
+				    strlen(suffix) - 1] = '\0';
+				strlcat(oms->oms_required, suffix,
+				    sizeof(oms->oms_required));
+                        }
 		}
 		if (mod->mod_kobj != NULL && stataddr) {
 			kobj_stat(mod->mod_kobj, &addr, &size);
-			ms->ms_addr = addr;
-			ms->ms_size = size;
+			oms->oms_addr = addr;
+			oms->oms_size = size;
 		}
-		ms->ms_class = mi->mi_class;
-		ms->ms_refcnt = mod->mod_refcnt;
-		ms->ms_source = mod->mod_source;
-		ms->ms_flags = mod->mod_flags;
+		oms->oms_class = mi->mi_class;
+		oms->oms_refcnt = mod->mod_refcnt;
+		oms->oms_source = mod->mod_source;
+		oms->oms_flags = mod->mod_flags;
+		oms++;
+		aliasp = *mi->mi_aliases;
+		if (aliasp == NULL)
+			continue;
+		while (*aliasp) {
+			copy_oalias(oms, aliasp, mi, mod);
+			aliasp++;
+			oms++;
+		}
+	}
+	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+		mi = mod->mod_info;
+		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
+		if (mi->mi_required != NULL) {
+			used = strlcpy(oms->oms_required, mi->mi_required,
+			    sizeof(oms->oms_required));
+			if (used >= sizeof(oms->oms_required)) { 
+				oms->oms_required[sizeof(oms->oms_required) -
+				    strlen(suffix) - 1] = '\0';
+				strlcat(oms->oms_required, suffix,
+				    sizeof(oms->oms_required));
+                        }
+		}
+		if (mod->mod_kobj != NULL && stataddr) {
+			kobj_stat(mod->mod_kobj, &addr, &size);
+			oms->oms_addr = addr;
+			oms->oms_size = size;
+		}
+		oms->oms_class = mi->mi_class;
+		oms->oms_refcnt = -1;
+		KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL);
+		oms->oms_source = mod->mod_source;
+		oms++;
+		aliasp = *mi->mi_aliases;
+		if (aliasp == NULL)
+			continue;
+		while (*aliasp) {
+			copy_oalias(oms, aliasp, mi, mod);
+			aliasp++;
+			oms++;
+		}
+	}
+	kernconfig_unlock();
+	error = copyout(omso, NETBSD32PTR64(iov->iov_base),
+	    min(omslen - sizeof(modstat_t), iov->iov_len));
+	kmem_free(omso, omslen);
+	if (error == 0) {
+		iov->iov_len = omslen - sizeof(modstat_t);
+		error = copyout(iov, arg, sizeof(*iov));
+	}
+
+	return error;
+}
+#endif	/* COMPAT_80 */
+
+static void
+copy_alias(modstat_t *ms, const char * const *aliasp, modinfo_t *mi,
+    module_t *mod)
+{
+
+	strlcpy(ms->ms_name, *aliasp, sizeof(ms->ms_name));
+	ms->ms_class = mi->mi_class;
+	ms->ms_source = mod->mod_source;
+	ms->ms_flags = mod->mod_flags | MODFLG_IS_ALIAS;
+	ms->ms_reqoffset = 0;
+}
+
+static int
+modctl32_handle_stat(struct netbsd32_iovec *iov, void *arg)
+{
+	int ms_cnt;
+	modstat_t *ms, *mso;
+	size_t ms_len;
+	int req_cnt;
+	char *req, *reqo;
+	size_t req_len;
+	char *out_p;
+	size_t out_s;
+
+	modinfo_t *mi;
+	module_t *mod;
+	vaddr_t addr;
+	size_t size;
+	size_t used;
+	int off;
+	int error;
+	bool stataddr;
+	const char * const *aliasp;
+
+	/* If not privileged, don't expose kernel addresses. */
+	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
+	    0, (void *)(uintptr_t)MODCTL_STAT, NULL, NULL);
+	stataddr = (error == 0);
+
+	kernconfig_lock();
+	ms_cnt = 0;
+	req_len = 1;
+
+	/*
+	 * Count up the number of modstat_t needed, and total size of
+	 * require_module lists on both active and built-in lists
+	 */
+	TAILQ_FOREACH(mod, &module_list, mod_chain) {
+		ms_cnt++;
+		mi = mod->mod_info;
+		if ((aliasp = *mi->mi_aliases) != NULL) {
+			while (*aliasp++ != NULL)
+				ms_cnt++;
+		}
+		if (mi->mi_required != NULL) {
+			req_cnt++;
+			req_len += strlen(mi->mi_required) + 1;
+		}
+	}
+	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+	ms_cnt++;
+	mi = mod->mod_info;
+	if ((aliasp = *mi->mi_aliases) != NULL) {
+		while (*aliasp++ != NULL)
+			ms_cnt++;
+		}
+		if (mi->mi_required != NULL) {
+			req_cnt++;
+			req_len += strlen(mi->mi_required) + 1;
+		}
+	}
+
+	/* Allocate internal buffers to hold all the output data */
+	ms_len = ms_cnt * sizeof(modstat_t);
+	ms = kmem_zalloc(ms_len, KM_SLEEP);
+	req = kmem_zalloc(req_len, KM_SLEEP);
+
+	mso = ms;
+	reqo = req++;
+	off = 1;
+
+	/*
+	 * Load data into our internal buffers for both active and
+	 * build-in module lists
+	 */
+	TAILQ_FOREACH(mod, &module_list, mod_chain) {
+	mi = mod->mod_info;
+	strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
+	if (mi->mi_required != NULL) {
+		ms->ms_reqoffset = off;
+		used = strlcpy(req,  mi->mi_required, req_len - off);
+		KASSERTMSG(used < req_len - off, "reqlist grew!");
+		off = used + 1;
+		req += used + 1;
+	} else
+		ms->ms_reqoffset = 0;
+	if (mod->mod_kobj != NULL && stataddr) {
+		kobj_stat(mod->mod_kobj, &addr, &size);
+		ms->ms_addr = addr;
+		ms->ms_size = size;
+	}
+	ms->ms_class = mi->mi_class;
+	ms->ms_refcnt = mod->mod_refcnt;
+	ms->ms_source = mod->mod_source;
+	ms->ms_flags = mod->mod_flags;
+	ms++;
+	aliasp = *mi->mi_aliases;
+	if (aliasp == NULL)
+		continue;
+	while (*aliasp) {
+		copy_alias(ms, aliasp, mi, mod);
+		aliasp++;
 		ms++;
+		}
 	}
 	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
 		mi = mod->mod_info;
 		strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
 		if (mi->mi_required != NULL) {
-			strlcpy(ms->ms_required, mi->mi_required,
-			    sizeof(ms->ms_required));
-		}
+			ms->ms_reqoffset = off;
+			used = strlcpy(req,  mi->mi_required, req_len - off);
+			KASSERTMSG(used < req_len - off, "reqlist grew!");
+			off += used + 1;
+			req += used + 1;
+		} else
+			ms->ms_reqoffset = 0;
 		if (mod->mod_kobj != NULL && stataddr) {
 			kobj_stat(mod->mod_kobj, &addr, &size);
 			ms->ms_addr = addr;
@@ -98,19 +313,58 @@ modctl32_handle_stat(struct netbsd32_iov
 		KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL);
 		ms->ms_source = mod->mod_source;
 		ms++;
+		aliasp = *mi->mi_aliases;
+		if (aliasp == NULL)
+			continue;
+		while (*aliasp) {
+			copy_alias(ms, aliasp, mi, mod);
+			aliasp++;
+			ms++;
+		}
 	}
 	kernconfig_unlock();
-	error = copyout(mso, NETBSD32PTR64(iov->iov_base),
-	    min(mslen - sizeof(modstat_t), iov->iov_len));
-	kmem_free(mso, mslen);
+
+	/*
+	 * Now copyout our internal buffers back to userland
+	 */
+	out_p = NETBSD32PTR64(iov->iov_base);
+	out_s = iov->iov_len;
+	size = sizeof(ms_cnt);
+
+	/* Copy out the count of modstat_t */
+	if (out_s) {
+		size = min(sizeof(ms_cnt), out_s);
+		error = copyout(&ms_cnt, out_p, size);
+		out_p += size;
+		out_s -= size;
+	}
+	/* Copy out the modstat_t array */
+	if (out_s && error == 0) {
+		size = min(ms_len, out_s);
+		error = copyout(mso, out_p, size);
+		out_p += size;
+		out_s -= size;
+	}
+	/* Copy out the "required" strings */
+	if (out_s && error == 0) {
+		size = min(req_len, out_s);
+		error = copyout(reqo, out_p, size);
+		out_p += size;
+		out_s -= size;
+	}
+	kmem_free(mso, ms_len);
+	kmem_free(reqo, req_len);
+
+	/* Finally, update the userland copy of the iovec's length */
 	if (error == 0) {
-		iov->iov_len = mslen - sizeof(modstat_t);
+		iov->iov_len = ms_len + req_len + sizeof(ms_cnt);
 		error = copyout(iov, arg, sizeof(*iov));
 	}
 
 	return error;
 }
 
+
 int
 netbsd32_modctl(struct lwp *lwp, const struct netbsd32_modctl_args *uap,
 	register_t *result)
@@ -146,6 +400,16 @@ netbsd32_modctl(struct lwp *lwp, const s
 		}
 		break;
 
+#ifdef COMPAT_80
+	case MODCTL_OSTAT:
+		error = copyin(arg, &iov, sizeof(iov));
+		if (error != 0) {
+			break;
+		}
+		error = modctl32_handle_ostat(SCARG(uap, cmd), &iov, arg);
+		break;
+#endif
+
 	case MODCTL_STAT:
 		error = copyin(arg, &iov, sizeof(iov));
 		if (error != 0) {

Index: src/sys/kern/compat_stub.c
diff -u src/sys/kern/compat_stub.c:1.1.2.13 src/sys/kern/compat_stub.c:1.1.2.14
--- src/sys/kern/compat_stub.c:1.1.2.13	Fri Mar 30 10:09:08 2018
+++ src/sys/kern/compat_stub.c	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: compat_stub.c,v 1.1.2.13 2018/03/30 10:09:08 pgoyette Exp $	*/
+/* $NetBSD: compat_stub.c,v 1.1.2.14 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -148,3 +148,8 @@ int (*if43_20_cvtcmd)(int) = (void *)eno
 void (*rtsock14_oifmsg)(struct ifnet *) = (void *)voidop;
 int (*rtsock14_iflist)(struct ifnet *, struct rt_walkarg *,
     struct rt_addrinfo *, size_t) = (void *)enosys;
+
+/*
+ * modctl handler for old style OSTAT
+ */
+int (*compat_modstat_80)(int, struct iovec *, void *) = (void *)enosys;

Index: src/sys/kern/sys_module.c
diff -u src/sys/kern/sys_module.c:1.23.2.5 src/sys/kern/sys_module.c:1.23.2.6
--- src/sys/kern/sys_module.c:1.23.2.5	Sun Apr  1 23:06:11 2018
+++ src/sys/kern/sys_module.c	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_module.c,v 1.23.2.5 2018/04/01 23:06:11 pgoyette Exp $	*/
+/*	$NetBSD: sys_module.c,v 1.23.2.6 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_module.c,v 1.23.2.5 2018/04/01 23:06:11 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_module.c,v 1.23.2.6 2018/04/03 08:29:44 pgoyette Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_modular.h"
@@ -47,6 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: sys_module.c
 #include <sys/module.h>
 #include <sys/syscall.h>
 #include <sys/syscallargs.h>
+#include <sys/compat_stub.h>
 
 /*
  * Arbitrary limit to avoid DoS for excessive memory allocation.
@@ -116,27 +117,33 @@ copy_alias(modstat_t *ms, const char * c
 {
 
 	strlcpy(ms->ms_name, *aliasp, sizeof(ms->ms_name));
-	strlcpy(ms->ms_required, mi->mi_name, sizeof(ms->ms_required));
 	ms->ms_class = mi->mi_class;
 	ms->ms_source = mod->mod_source;
 	ms->ms_flags = mod->mod_flags | MODFLG_IS_ALIAS;
+	ms->ms_reqoffset = 0;
 }
 
 static int
 handle_modctl_stat(struct iovec *iov, void *arg)
 {
+	int ms_cnt;
 	modstat_t *ms, *mso;
+	size_t ms_len;
+	int req_cnt;
+	char *req, *reqo;
+	size_t req_len;
+	char *out_p;
+	size_t out_s;
+
 	modinfo_t *mi;
 	module_t *mod;
 	vaddr_t addr;
 	size_t size;
-	size_t mslen;
 	size_t used;
+	int off;
 	int error;
-	int mscnt;
 	bool stataddr;
 	const char * const *aliasp;
-	const char *suffix = "...";
 
 	/* If not privileged, don't expose kernel addresses. */
 	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
@@ -144,31 +151,62 @@ handle_modctl_stat(struct iovec *iov, vo
 	stataddr = (error == 0);
 
 	kernconfig_lock();
-	mscnt = 0;
+	ms_cnt = 0;
+	req_len = 1;
+
+	/*
+	 * Count up the number of modstat_t needed, and total size of
+	 * require_module lists on both active and built-in lists
+	 */
 	TAILQ_FOREACH(mod, &module_list, mod_chain) {
-		mscnt++;
+		ms_cnt++;
 		mi = mod->mod_info;
 		if ((aliasp = *mi->mi_aliases) != NULL) {
 			while (*aliasp++ != NULL)
-				mslen++;
+				ms_cnt++;
+		}
+		if (mi->mi_required != NULL) {
+			req_cnt++;
+			req_len += strlen(mi->mi_required) + 1;
+		}
+	}
+	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+		ms_cnt++;
+		mi = mod->mod_info;
+		if ((aliasp = *mi->mi_aliases) != NULL) {
+			while (*aliasp++ != NULL)
+				ms_cnt++;
+		}
+		if (mi->mi_required != NULL) {
+			req_cnt++;
+			req_len += strlen(mi->mi_required) + 1;
 		}
 	}
-	mslen = (mscnt+module_builtinlist+1) * sizeof(modstat_t);
-	mso = kmem_zalloc(mslen, KM_SLEEP);
-	ms = mso;
+
+	/* Allocate internal buffers to hold all the output data */
+	ms_len = ms_cnt * sizeof(modstat_t);
+	ms = kmem_zalloc(ms_len, KM_SLEEP);
+	req = kmem_zalloc(req_len, KM_SLEEP);
+
+	mso = ms;
+	reqo = req++;
+	off = 1;
+
+	/*
+	 * Load data into our internal buffers for both active and
+	 * build-in module lists
+	 */
 	TAILQ_FOREACH(mod, &module_list, mod_chain) {
 		mi = mod->mod_info;
 		strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
 		if (mi->mi_required != NULL) {
-			used = strlcpy(ms->ms_required, mi->mi_required,
-			    sizeof(ms->ms_required));
-			if (used >= sizeof(ms->ms_required)) {
-				ms->ms_required[sizeof(ms->ms_required) -
-				    strlen(suffix) - 1] = '\0';
-				strlcat(ms->ms_required, suffix,
-				    sizeof(ms->ms_required));
-			}
-		}
+			ms->ms_reqoffset = off;
+			used = strlcpy(req,  mi->mi_required, req_len - off);
+			KASSERTMSG(used < req_len - off, "reqlist grew!");
+			off += used + 1;
+			req += used + 1;
+		} else
+			ms->ms_reqoffset = 0;
 		if (mod->mod_kobj != NULL && stataddr) {
 			kobj_stat(mod->mod_kobj, &addr, &size);
 			ms->ms_addr = addr;
@@ -192,13 +230,13 @@ handle_modctl_stat(struct iovec *iov, vo
 		mi = mod->mod_info;
 		strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
 		if (mi->mi_required != NULL) {
-			*ms->ms_required = '\0';
-			used = strlcat(ms->ms_required, mi->mi_required,
-			    sizeof(ms->ms_required) - 6);
-			if (used > sizeof(ms->ms_required) - 6)
-				strlcat(ms->ms_required, ", ...",
-				    sizeof(ms->ms_required));
-		}
+			ms->ms_reqoffset = off;
+			used = strlcpy(req,  mi->mi_required, req_len - off);
+			KASSERTMSG(used < req_len - off, "reqlist grew!");
+			off += used + 1;
+			req += used + 1;
+		} else
+			ms->ms_reqoffset = 0;
 		if (mod->mod_kobj != NULL && stataddr) {
 			kobj_stat(mod->mod_kobj, &addr, &size);
 			ms->ms_addr = addr;
@@ -219,11 +257,41 @@ handle_modctl_stat(struct iovec *iov, vo
 		}
 	}
 	kernconfig_unlock();
-	error = copyout(mso, iov->iov_base,
-	    min(mslen - sizeof(modstat_t), iov->iov_len));
-	kmem_free(mso, mslen);
+
+	/*
+	 * Now copyout our internal buffers back to userland
+	 */
+	out_p = iov->iov_base;
+	out_s = iov->iov_len;
+	size = sizeof(ms_cnt);
+
+	/* Copy out the count of modstat_t */
+	if (out_s) {
+		size = min(sizeof(ms_cnt), out_s);
+		error = copyout(&ms_cnt, out_p, size);
+		out_p += size;
+		out_s -= size;
+	}
+	/* Copy out the modstat_t array */
+	if (out_s && error == 0) {
+		size = min(ms_len, out_s);
+		error = copyout(mso, out_p, size);
+		out_p += size;
+		out_s -= size;
+	}
+	/* Copy out the "required" strings */
+	if (out_s && error == 0) {
+		size = min(req_len, out_s);
+		error = copyout(reqo, out_p, size);
+		out_p += size;
+		out_s -= size;
+	}
+	kmem_free(mso, ms_len);
+	kmem_free(reqo, req_len);
+
+	/* Finally, update the userland copy of the iovec's length */
 	if (error == 0) {
-		iov->iov_len = mslen - sizeof(modstat_t);
+		iov->iov_len = ms_len + req_len + sizeof(ms_cnt);
 		error = copyout(iov, arg, sizeof(*iov));
 	}
 
@@ -286,7 +354,6 @@ sys_modctl(struct lwp *l, const struct s
 			     (void *)(uintptr_t)MODCTL_LOAD,
 			     (void *)loadtype, NULL);
 			break;
-
 		default:
 			error = EINVAL;
 			break;
@@ -295,7 +362,9 @@ sys_modctl(struct lwp *l, const struct s
 		break;
 
 	default:
-		error = EINVAL;
+		error = (*compat_modstat_80)(SCARG(uap, cmd), &iov, arg);
+		if (error == ENOSYS)
+			error = EINVAL;
 		break;
 	}
 

Index: src/sys/modules/compat_80/Makefile
diff -u src/sys/modules/compat_80/Makefile:1.1.2.2 src/sys/modules/compat_80/Makefile:1.1.2.3
--- src/sys/modules/compat_80/Makefile:1.1.2.2	Sat Mar 24 01:59:16 2018
+++ src/sys/modules/compat_80/Makefile	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.1.2.2 2018/03/24 01:59:16 pgoyette Exp $
+#	$NetBSD: Makefile,v 1.1.2.3 2018/04/03 08:29:44 pgoyette Exp $
 
 .include "../Makefile.inc"
 
@@ -9,6 +9,7 @@ KMOD=	compat_80
 CPPFLAGS+=	-DCOMPAT_80
 
 SRCS+=	compat_80_mod.c
+SRCS+=	kern_mod_80.c
 
 .PATH:	${S}/dev/raidframe
 

Index: src/sys/sys/compat_stub.h
diff -u src/sys/sys/compat_stub.h:1.1.2.13 src/sys/sys/compat_stub.h:1.1.2.14
--- src/sys/sys/compat_stub.h:1.1.2.13	Fri Mar 30 10:09:08 2018
+++ src/sys/sys/compat_stub.h	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: compat_stub.h,v 1.1.2.13 2018/03/30 10:09:08 pgoyette Exp $	*/
+/* $NetBSD: compat_stub.h,v 1.1.2.14 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -171,4 +171,10 @@ extern void (*rtsock14_oifmsg)(struct if
 extern int (*rtsock14_iflist)(struct ifnet *, struct rt_walkarg *,
     struct rt_addrinfo *, size_t);
 
+/*
+ * modctl handler for old style OSTAT
+ */
+struct iovec;
+
+extern int (*compat_modstat_80)(int, struct iovec *, void *);
 #endif	/* _SYS_COMPAT_STUB_H */

Index: src/sys/sys/module.h
diff -u src/sys/sys/module.h:1.41.14.7 src/sys/sys/module.h:1.41.14.8
--- src/sys/sys/module.h:1.41.14.7	Sun Apr  1 23:06:11 2018
+++ src/sys/sys/module.h	Tue Apr  3 08:29:44 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: module.h,v 1.41.14.7 2018/04/01 23:06:11 pgoyette Exp $	*/
+/*	$NetBSD: module.h,v 1.41.14.8 2018/04/03 08:29:44 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -240,24 +240,41 @@ typedef struct modctl_load {
 typedef enum modctl {
 	MODCTL_LOAD,		/* modctl_load_t *ml */
 	MODCTL_UNLOAD,		/* char *name */
-	MODCTL_STAT,		/* struct iovec *buffer */
-	MODCTL_EXISTS		/* enum: 0: load, 1: autoload */
+	MODCTL_OSTAT,		/* struct iovec *buffer */
+	MODCTL_EXISTS,		/* enum: 0: load, 1: autoload */
+	MODCTL_STAT		/* struct iovec *buffer */
 } modctl_t;
 
 /*
  * This structure intentionally has the same layout for 32 and 64
  * bit builds.
  */
+typedef struct omodstat {
+	char		oms_name[MAXMODNAME];
+	char		oms_required[MAXMODNAME * MAXMODDEPS];
+	uint64_t	oms_addr;
+	modsrc_t	oms_source;
+	modclass_t	oms_class;
+	u_int		oms_size;
+	u_int		oms_refcnt;
+	u_int		oms_flags;
+	u_int		oms_reserved[3];
+} omodstat_t;
+
+/*
+ * This structure is used with the newer version of MODCTL_STAT, which
+ * exports strings of arbitrary length for the list of required modules.
+ */
 typedef struct modstat {
 	char		ms_name[MAXMODNAME];
-	char		ms_required[MAXMODNAME * MAXMODDEPS];
 	uint64_t	ms_addr;
 	modsrc_t	ms_source;
 	modclass_t	ms_class;
 	u_int		ms_size;
 	u_int		ms_refcnt;
 	u_int		ms_flags;
-	u_int		ms_reserved[3];
+	u_int		ms_reqoffset;	/* offset to module's required list
+					   from beginning of iovec buffer! */
 } modstat_t;
 
 int	modctl(int, void *);

Added files:

Index: src/sys/compat/common/kern_mod_80.c
diff -u /dev/null src/sys/compat/common/kern_mod_80.c:1.1.2.1
--- /dev/null	Tue Apr  3 08:29:44 2018
+++ src/sys/compat/common/kern_mod_80.c	Tue Apr  3 08:29:44 2018
@@ -0,0 +1,203 @@
+/*	$NetBSD: kern_mod_80.c,v 1.1.2.1 2018/04/03 08:29:44 pgoyette Exp $	*/
+
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * System calls relating to loadable modules.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: kern_mod_80.c,v 1.1.2.1 2018/04/03 08:29:44 pgoyette Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_modular.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/namei.h>
+#include <sys/kauth.h>
+#include <sys/kmem.h>
+#include <sys/kobj.h>
+#include <sys/module.h>
+#include <sys/syscall.h>
+#include <sys/syscallargs.h>
+#include <sys/compat_stub.h>
+
+#include <compat/common/compat_mod.h>
+
+static void
+copy_oalias(omodstat_t *oms, const char * const *aliasp, modinfo_t *mi,
+    module_t *mod)
+{
+
+	strlcpy(oms->oms_name, *aliasp, sizeof(oms->oms_name));
+	strlcpy(oms->oms_required, mi->mi_name, sizeof(oms->oms_required));
+	oms->oms_class = mi->mi_class;
+	oms->oms_source = mod->mod_source;
+	oms->oms_flags = mod->mod_flags | MODFLG_IS_ALIAS;
+}
+
+static int
+compat_80_modstat(int cmd, struct iovec *iov, void *arg)
+{
+	omodstat_t *oms, *omso;
+	modinfo_t *mi;
+	module_t *mod;
+	vaddr_t addr;
+	size_t size;
+	size_t omslen;
+	size_t used;
+	int error;
+	int omscnt;
+	bool stataddr;
+	const char * const *aliasp;
+	const char *suffix = "...";
+
+	if (cmd != MODCTL_OSTAT)
+		return EINVAL;
+
+	error = copyin(arg, iov, sizeof(*iov));
+	if (error != 0) {
+		return error;
+	}
+
+	/* If not privileged, don't expose kernel addresses. */
+	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
+	    0, (void *)(uintptr_t)MODCTL_STAT, NULL, NULL);
+	stataddr = (error == 0);
+
+	kernconfig_lock();
+	omscnt = 0;
+	TAILQ_FOREACH(mod, &module_list, mod_chain) {
+		omscnt++;
+		mi = mod->mod_info;
+		if ((aliasp = *mi->mi_aliases) != NULL) {
+			while (*aliasp++ != NULL)
+				omscnt++;
+		}
+	}
+	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+		omscnt++;
+		mi = mod->mod_info;
+		if ((aliasp = *mi->mi_aliases) != NULL) {
+			while (*aliasp++ != NULL)
+				omscnt++;
+		}
+	}
+	omslen = omscnt * sizeof(omodstat_t);
+	omso = kmem_zalloc(omslen, KM_SLEEP);
+	oms = omso;
+	TAILQ_FOREACH(mod, &module_list, mod_chain) {
+		mi = mod->mod_info;
+		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
+		if (mi->mi_required != NULL) {
+			used = strlcpy(oms->oms_required, mi->mi_required,
+			    sizeof(oms->oms_required));
+			if (used >= sizeof(oms->oms_required)) {
+				oms->oms_required[sizeof(oms->oms_required) -
+				    strlen(suffix) - 1] = '\0';
+				strlcat(oms->oms_required, suffix,
+				    sizeof(oms->oms_required));
+			}
+		}
+		if (mod->mod_kobj != NULL && stataddr) {
+			kobj_stat(mod->mod_kobj, &addr, &size);
+			oms->oms_addr = addr;
+			oms->oms_size = size;
+		}
+		oms->oms_class = mi->mi_class;
+		oms->oms_refcnt = mod->mod_refcnt;
+		oms->oms_source = mod->mod_source;
+		oms->oms_flags = mod->mod_flags;
+		oms++;
+		aliasp = *mi->mi_aliases;
+		if (aliasp == NULL)
+			continue;
+		while (*aliasp) {
+			copy_oalias(oms, aliasp, mi, mod);
+			aliasp++;
+			oms++;
+		}
+	}
+	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
+		mi = mod->mod_info;
+		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
+		if (mi->mi_required != NULL) {
+			used = strlcpy(oms->oms_required, mi->mi_required,
+			    sizeof(oms->oms_required));
+			if (used >= sizeof(oms->oms_required)) {
+				oms->oms_required[sizeof(oms->oms_required) -
+				    strlen(suffix) - 1] = '\0';
+				strlcat(oms->oms_required, suffix,
+				    sizeof(oms->oms_required));
+			}
+		}
+		if (mod->mod_kobj != NULL && stataddr) {
+			kobj_stat(mod->mod_kobj, &addr, &size);
+			oms->oms_addr = addr;
+			oms->oms_size = size;
+		}
+		oms->oms_class = mi->mi_class;
+		oms->oms_refcnt = -1;
+		KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL);
+		oms->oms_source = mod->mod_source;
+		oms++;
+		aliasp = *mi->mi_aliases;
+		if (aliasp == NULL)
+			continue;
+		while (*aliasp) {
+			copy_oalias(oms, aliasp, mi, mod);
+			aliasp++;
+			oms++;
+		}
+	}
+	kernconfig_unlock();
+	error = copyout(omso, iov->iov_base, min(omslen, iov->iov_len));
+	kmem_free(omso, omslen);
+	if (error == 0) {
+		iov->iov_len = omslen;
+		error = copyout(iov, arg, sizeof(*iov));
+	}
+
+	return error;
+}
+
+void
+kern_mod_80_init(void)
+{
+
+	compat_modstat_80 = compat_80_modstat;
+}
+
+void
+kern_mod_80_fini(void)
+{
+
+	compat_modstat_80 = (void *)enosys;
+}

Reply via email to