kern_linker.c revision 100488
125537Sdfr/*-
259603Sdfr * Copyright (c) 1997-2000 Doug Rabson
325537Sdfr * All rights reserved.
425537Sdfr *
525537Sdfr * Redistribution and use in source and binary forms, with or without
625537Sdfr * modification, are permitted provided that the following conditions
725537Sdfr * are met:
825537Sdfr * 1. Redistributions of source code must retain the above copyright
925537Sdfr *    notice, this list of conditions and the following disclaimer.
1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1125537Sdfr *    notice, this list of conditions and the following disclaimer in the
1225537Sdfr *    documentation and/or other materials provided with the distribution.
1325537Sdfr *
1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1725537Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2425537Sdfr * SUCH DAMAGE.
2525537Sdfr *
2650477Speter * $FreeBSD: head/sys/kern/kern_linker.c 100488 2002-07-22 08:28:09Z truckman $
2725537Sdfr */
2825537Sdfr
2940159Speter#include "opt_ddb.h"
3040159Speter
3125537Sdfr#include <sys/param.h>
3225537Sdfr#include <sys/kernel.h>
3325537Sdfr#include <sys/systm.h>
3425537Sdfr#include <sys/malloc.h>
3525537Sdfr#include <sys/sysproto.h>
3625537Sdfr#include <sys/sysent.h>
3725537Sdfr#include <sys/proc.h>
3825537Sdfr#include <sys/lock.h>
3982749Sdillon#include <sys/mutex.h>
4092547Sarr#include <sys/sx.h>
4125537Sdfr#include <sys/module.h>
4225537Sdfr#include <sys/linker.h>
4340159Speter#include <sys/fcntl.h>
4440159Speter#include <sys/libkern.h>
4540159Speter#include <sys/namei.h>
4640159Speter#include <sys/vnode.h>
4740159Speter#include <sys/sysctl.h>
4825537Sdfr
4959603Sdfr#include "linker_if.h"
5059603Sdfr
5140961Speter#ifdef KLD_DEBUG
5240961Speterint kld_debug = 0;
5340961Speter#endif
5440961Speter
5591040Sarr/*
5691040Sarr * static char *linker_search_path(const char *name, struct mod_depend
5791040Sarr * *verinfo);
5891040Sarr */
5991040Sarrstatic const char 	*linker_basename(const char *path);
6091040Sarrstatic int 	linker_load_module(const char *kldname, const char *modname,
6191040Sarr		    struct linker_file *parent, struct mod_depend *verinfo,
6291040Sarr		    struct linker_file **lfpp);
6359751Speter
6478161Speter/* Metadata from the static kernel */
6578161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata);
6678161Speter
6759751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
6859751Speter
6940906Speterlinker_file_t linker_kernel_file;
7031324Sbde
7198452Sarrstatic struct mtx kld_mtx;	/* kernel linker mutex */
7298452Sarr
7325537Sdfrstatic linker_class_list_t classes;
7450068Sgrogstatic linker_file_list_t linker_files;
7525537Sdfrstatic int next_file_id = 1;
7698452Sarrstatic int linker_no_more_classes = 0;
7725537Sdfr
7886553Sarr#define	LINKER_GET_NEXT_FILE_ID(a) do {					\
7991040Sarr	linker_file_t lftmp;						\
8086553Sarr									\
8186553Sarrretry:									\
8298452Sarr	mtx_lock(&kld_mtx);						\
8391040Sarr	TAILQ_FOREACH(lftmp, &linker_files, link) {			\
8491040Sarr		if (next_file_id == lftmp->id) {			\
8591040Sarr			next_file_id++;					\
8698452Sarr			mtx_unlock(&kld_mtx);				\
8791040Sarr			goto retry;					\
8891040Sarr		}							\
8991040Sarr	}								\
9091040Sarr	(a) = next_file_id;						\
9198452Sarr	mtx_unlock(&kld_mtx);	/* Hold for safe read of id variable */	\
9286553Sarr} while(0)
9386553Sarr
9486553Sarr
9559751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */
9660938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t;
9759751Speterstruct modlist {
9891040Sarr	TAILQ_ENTRY(modlist) link;	/* chain together all modules */
9991040Sarr	linker_file_t   container;
10091040Sarr	const char 	*name;
10191040Sarr	int             version;
10259751Speter};
10391040Sarrtypedef struct modlist *modlist_t;
10491040Sarrstatic modlisthead_t found_modules;
10559751Speter
10694321Sbrianstatic modlist_t	modlist_lookup2(const char *name,
10794321Sbrian			    struct mod_depend *verinfo);
10894321Sbrian
10959603Sdfrstatic char *
11059603Sdfrlinker_strdup(const char *str)
11159603Sdfr{
11291040Sarr	char *result;
11359603Sdfr
11491040Sarr	if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
11591040Sarr		strcpy(result, str);
11691040Sarr	return (result);
11759603Sdfr}
11859603Sdfr
11925537Sdfrstatic void
12091040Sarrlinker_init(void *arg)
12125537Sdfr{
12291040Sarr
12398452Sarr	mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF);
12491040Sarr	TAILQ_INIT(&classes);
12591040Sarr	TAILQ_INIT(&linker_files);
12625537Sdfr}
12725537Sdfr
12891040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0)
12925537Sdfr
13098452Sarrstatic void
13198452Sarrlinker_stop_class_add(void *arg)
13298452Sarr{
13398452Sarr
13498452Sarr	linker_no_more_classes = 1;
13598452Sarr}
13698452Sarr
13798452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL)
13898452Sarr
13925537Sdfrint
14059603Sdfrlinker_add_class(linker_class_t lc)
14125537Sdfr{
14291040Sarr
14398452Sarr	/*
14498452Sarr	 * We disallow any class registration passt SI_ORDER_ANY
14598452Sarr	 * of SI_SUB_KLD.
14698452Sarr	 */
14798452Sarr	if (linker_no_more_classes == 1)
14898452Sarr		return (EPERM);
14991040Sarr	kobj_class_compile((kobj_class_t) lc);
15091040Sarr	TAILQ_INSERT_TAIL(&classes, lc, link);
15191040Sarr	return (0);
15225537Sdfr}
15325537Sdfr
15425537Sdfrstatic void
15525537Sdfrlinker_file_sysinit(linker_file_t lf)
15625537Sdfr{
15791040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
15825537Sdfr
15991040Sarr	KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
16091040Sarr	    lf->filename));
16125537Sdfr
16291040Sarr	if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
16391040Sarr		return;
16491040Sarr	/*
16591040Sarr	 * Perform a bubble sort of the system initialization objects by
16691040Sarr	 * their subsystem (primary key) and order (secondary key).
16791040Sarr	 *
16891040Sarr	 * Since some things care about execution order, this is the operation
16991040Sarr	 * which ensures continued function.
17091040Sarr	 */
17191040Sarr	for (sipp = start; sipp < stop; sipp++) {
17291040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
17391040Sarr			if ((*sipp)->subsystem < (*xipp)->subsystem ||
17491040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
17591040Sarr			    (*sipp)->order <= (*xipp)->order))
17691040Sarr				continue;	/* skip */
17791040Sarr			save = *sipp;
17891040Sarr			*sipp = *xipp;
17991040Sarr			*xipp = save;
18091040Sarr		}
18125537Sdfr	}
18225537Sdfr
18391040Sarr	/*
18491040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
18591040Sarr	 * Perform each task, and continue on to the next task.
18691040Sarr	 */
18791040Sarr	for (sipp = start; sipp < stop; sipp++) {
18891040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
18991040Sarr			continue;	/* skip dummy task(s) */
19025537Sdfr
19191040Sarr		/* Call function */
19291040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
19391040Sarr	}
19425537Sdfr}
19525537Sdfr
19641055Speterstatic void
19741055Speterlinker_file_sysuninit(linker_file_t lf)
19841055Speter{
19991040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
20041055Speter
20191040Sarr	KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
20291040Sarr	    lf->filename));
20341055Speter
20491068Sarr	if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop,
20591040Sarr	    NULL) != 0)
20691040Sarr		return;
20741055Speter
20891040Sarr	/*
20991040Sarr	 * Perform a reverse bubble sort of the system initialization objects
21091040Sarr	 * by their subsystem (primary key) and order (secondary key).
21191040Sarr	 *
21291040Sarr	 * Since some things care about execution order, this is the operation
21391040Sarr	 * which ensures continued function.
21491040Sarr	 */
21591040Sarr	for (sipp = start; sipp < stop; sipp++) {
21691040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
21791040Sarr			if ((*sipp)->subsystem > (*xipp)->subsystem ||
21891040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
21991040Sarr			    (*sipp)->order >= (*xipp)->order))
22091040Sarr				continue;	/* skip */
22191040Sarr			save = *sipp;
22291040Sarr			*sipp = *xipp;
22391040Sarr			*xipp = save;
22491040Sarr		}
22541055Speter	}
22641055Speter
22791040Sarr	/*
22891040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
22991040Sarr	 * Perform each task, and continue on to the next task.
23091040Sarr	 */
23191040Sarr	for (sipp = start; sipp < stop; sipp++) {
23291040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
23391040Sarr			continue;	/* skip dummy task(s) */
23441055Speter
23591040Sarr		/* Call function */
23691040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
23791040Sarr	}
23841055Speter}
23941055Speter
24044078Sdfrstatic void
24144078Sdfrlinker_file_register_sysctls(linker_file_t lf)
24244078Sdfr{
24391040Sarr	struct sysctl_oid **start, **stop, **oidp;
24444078Sdfr
24591040Sarr	KLD_DPF(FILE,
24691040Sarr	    ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
24791040Sarr	    lf->filename));
24844078Sdfr
24991040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
25091040Sarr		return;
25144078Sdfr
25291040Sarr	for (oidp = start; oidp < stop; oidp++)
25391040Sarr		sysctl_register_oid(*oidp);
25444078Sdfr}
25544078Sdfr
25644078Sdfrstatic void
25744078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
25844078Sdfr{
25991040Sarr	struct sysctl_oid **start, **stop, **oidp;
26044078Sdfr
26191040Sarr	KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs"
26291040Sarr	    " for %s\n", lf->filename));
26344078Sdfr
26491040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
26591040Sarr		return;
26644078Sdfr
26791040Sarr	for (oidp = start; oidp < stop; oidp++)
26891040Sarr		sysctl_unregister_oid(*oidp);
26944078Sdfr}
27044078Sdfr
27159751Speterstatic int
27259751Speterlinker_file_register_modules(linker_file_t lf)
27359751Speter{
27491040Sarr	struct mod_metadata **start, **stop, **mdp;
27591040Sarr	const moduledata_t *moddata;
27691040Sarr	int error;
27759751Speter
27891040Sarr	KLD_DPF(FILE, ("linker_file_register_modules: registering modules"
27991040Sarr	    " in %s\n", lf->filename));
28059751Speter
28191068Sarr	if (linker_file_lookup_set(lf, "modmetadata_set", &start,
28291040Sarr	    &stop, 0) != 0) {
28391040Sarr		/*
28491040Sarr		 * This fallback should be unnecessary, but if we get booted
28591040Sarr		 * from boot2 instead of loader and we are missing our
28691040Sarr		 * metadata then we have to try the best we can.
28791040Sarr		 */
28891040Sarr		if (lf == linker_kernel_file) {
28991040Sarr			start = SET_BEGIN(modmetadata_set);
29091040Sarr			stop = SET_LIMIT(modmetadata_set);
29191040Sarr		} else
29291040Sarr			return (0);
29378161Speter	}
29491040Sarr	for (mdp = start; mdp < stop; mdp++) {
29591040Sarr		if ((*mdp)->md_type != MDT_MODULE)
29691040Sarr			continue;
29791040Sarr		moddata = (*mdp)->md_data;
29891040Sarr		KLD_DPF(FILE, ("Registering module %s in %s\n",
29991040Sarr		    moddata->name, lf->filename));
30091040Sarr		error = module_register(moddata, lf);
30191040Sarr		if (error)
30291068Sarr			printf("Module %s failed to register: %d\n",
30391040Sarr			    moddata->name, error);
30459751Speter	}
30591040Sarr	return (0);
30659751Speter}
30759751Speter
30859751Speterstatic void
30959751Speterlinker_init_kernel_modules(void)
31059751Speter{
31191040Sarr
31291040Sarr	linker_file_register_modules(linker_kernel_file);
31359751Speter}
31459751Speter
31591040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0)
31659751Speter
31725537Sdfrint
31891040Sarrlinker_load_file(const char *filename, linker_file_t *result)
31925537Sdfr{
32091040Sarr	linker_class_t lc;
32191040Sarr	linker_file_t lf;
32291040Sarr	int foundfile, error = 0;
32325537Sdfr
32491040Sarr	/* Refuse to load modules if securelevel raised */
32591040Sarr	if (securelevel > 0)
32691040Sarr		return (EPERM);
32762261Sarchie
32891040Sarr	lf = linker_find_file_by_name(filename);
32991040Sarr	if (lf) {
33091040Sarr		KLD_DPF(FILE, ("linker_load_file: file %s is already loaded,"
33191040Sarr		    " incrementing refs\n", filename));
33291040Sarr		*result = lf;
33391040Sarr		lf->refs++;
33491040Sarr		goto out;
33591040Sarr	}
33691040Sarr	lf = NULL;
33791040Sarr	foundfile = 0;
33898452Sarr
33998452Sarr	/*
34098452Sarr	 * We do not need to protect (lock) classes here because there is
34198452Sarr	 * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY)
34298452Sarr	 * and there is no class deregistration mechanism at this time.
34398452Sarr	 */
34491040Sarr	TAILQ_FOREACH(lc, &classes, link) {
34591040Sarr		KLD_DPF(FILE, ("linker_load_file: trying to load %s\n",
34691040Sarr		    filename));
34791040Sarr		error = LINKER_LOAD_FILE(lc, filename, &lf);
34891040Sarr		/*
34991040Sarr		 * If we got something other than ENOENT, then it exists but
35091040Sarr		 * we cannot load it for some other reason.
35191040Sarr		 */
35291040Sarr		if (error != ENOENT)
35391040Sarr			foundfile = 1;
35491040Sarr		if (lf) {
35591040Sarr			linker_file_register_modules(lf);
35691040Sarr			linker_file_register_sysctls(lf);
35791040Sarr			linker_file_sysinit(lf);
35891040Sarr			lf->flags |= LINKER_FILE_LINKED;
35991040Sarr			*result = lf;
36091040Sarr			error = 0;
36191040Sarr			goto out;
36291040Sarr		}
36391040Sarr	}
36442755Speter	/*
36591040Sarr	 * Less than ideal, but tells the user whether it failed to load or
36691040Sarr	 * the module was not found.
36742755Speter	 */
36891040Sarr	if (foundfile)
36991068Sarr		/* Format not recognized (or unloadable). */
37091068Sarr		error = ENOEXEC;
37191040Sarr	else
37291068Sarr		error = ENOENT;		/* Nothing found */
37325537Sdfrout:
37491040Sarr	return (error);
37525537Sdfr}
37625537Sdfr
37778413Sbrianint
37894321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo,
37994321Sbrian    linker_file_t *result)
38078413Sbrian{
38194321Sbrian	modlist_t mod;
38294321Sbrian
38394321Sbrian	if ((mod = modlist_lookup2(modname, verinfo)) != NULL) {
38494321Sbrian		*result = mod->container;
38594321Sbrian		(*result)->refs++;
38694321Sbrian		return (0);
38794321Sbrian	}
38894321Sbrian
38994321Sbrian	return (linker_load_module(NULL, modname, NULL, verinfo, result));
39078413Sbrian}
39178413Sbrian
39225537Sdfrlinker_file_t
39391040Sarrlinker_find_file_by_name(const char *filename)
39425537Sdfr{
39591040Sarr	linker_file_t lf = 0;
39691040Sarr	char *koname;
39725537Sdfr
39891040Sarr	koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
39991040Sarr	if (koname == NULL)
40091040Sarr		goto out;
40191040Sarr	sprintf(koname, "%s.ko", filename);
40240861Speter
40398452Sarr	mtx_lock(&kld_mtx);
40491040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
40592032Sdwmalone		if (strcmp(lf->filename, koname) == 0)
40691040Sarr			break;
40792032Sdwmalone		if (strcmp(lf->filename, filename) == 0)
40891040Sarr			break;
40991040Sarr	}
41098452Sarr	mtx_unlock(&kld_mtx);
41140861Speterout:
41291040Sarr	if (koname)
41391040Sarr		free(koname, M_LINKER);
41491040Sarr	return (lf);
41525537Sdfr}
41625537Sdfr
41725537Sdfrlinker_file_t
41825537Sdfrlinker_find_file_by_id(int fileid)
41925537Sdfr{
42091040Sarr	linker_file_t lf = 0;
42198452Sarr
42298452Sarr	mtx_lock(&kld_mtx);
42391040Sarr	TAILQ_FOREACH(lf, &linker_files, link)
42491040Sarr		if (lf->id == fileid)
42591040Sarr			break;
42698452Sarr	mtx_unlock(&kld_mtx);
42791040Sarr	return (lf);
42825537Sdfr}
42925537Sdfr
43025537Sdfrlinker_file_t
43191040Sarrlinker_make_file(const char *pathname, linker_class_t lc)
43225537Sdfr{
43391040Sarr	linker_file_t lf;
43491040Sarr	const char *filename;
43525537Sdfr
43691040Sarr	lf = NULL;
43791040Sarr	filename = linker_basename(pathname);
43840159Speter
43991040Sarr	KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
44091040Sarr	lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
44191040Sarr	if (lf == NULL)
44291040Sarr		goto out;
44391040Sarr	lf->refs = 1;
44491040Sarr	lf->userrefs = 0;
44591040Sarr	lf->flags = 0;
44691040Sarr	lf->filename = linker_strdup(filename);
44791040Sarr	LINKER_GET_NEXT_FILE_ID(lf->id);
44891040Sarr	lf->ndeps = 0;
44991040Sarr	lf->deps = NULL;
45091040Sarr	STAILQ_INIT(&lf->common);
45191040Sarr	TAILQ_INIT(&lf->modules);
45298452Sarr	mtx_lock(&kld_mtx);
45391040Sarr	TAILQ_INSERT_TAIL(&linker_files, lf, link);
45498452Sarr	mtx_unlock(&kld_mtx);
45525537Sdfrout:
45691040Sarr	return (lf);
45725537Sdfr}
45825537Sdfr
45925537Sdfrint
46025537Sdfrlinker_file_unload(linker_file_t file)
46125537Sdfr{
46291040Sarr	module_t mod, next;
46391040Sarr	modlist_t ml, nextml;
46491040Sarr	struct common_symbol *cp;
46591040Sarr	int error, i;
46625537Sdfr
46791040Sarr	error = 0;
46862261Sarchie
46991040Sarr	/* Refuse to unload modules if securelevel raised. */
47091040Sarr	if (securelevel > 0)
47191040Sarr		return (EPERM);
47225537Sdfr
47391040Sarr	KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
47491040Sarr	if (file->refs == 1) {
47591040Sarr		KLD_DPF(FILE, ("linker_file_unload: file is unloading,"
47691040Sarr		    " informing modules\n"));
47791040Sarr
47891040Sarr		/*
47991040Sarr		 * Inform any modules associated with this file.
48091040Sarr		 */
48192547Sarr		MOD_XLOCK;
48291040Sarr		for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
48391040Sarr			next = module_getfnext(mod);
48492547Sarr			MOD_XUNLOCK;
48591040Sarr
48691040Sarr			/*
48791040Sarr			 * Give the module a chance to veto the unload.
48891040Sarr			 */
48991040Sarr			if ((error = module_unload(mod)) != 0) {
49091040Sarr				KLD_DPF(FILE, ("linker_file_unload: module %x"
49191040Sarr				    " vetoes unload\n", mod));
49291040Sarr				goto out;
49392547Sarr			} else
49492547Sarr				MOD_XLOCK;
49591040Sarr			module_release(mod);
49691040Sarr		}
49792547Sarr		MOD_XUNLOCK;
49891040Sarr	}
49991040Sarr	file->refs--;
50091040Sarr	if (file->refs > 0) {
50125537Sdfr		goto out;
50291040Sarr	}
50391040Sarr	for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
50491040Sarr		nextml = TAILQ_NEXT(ml, link);
50591040Sarr		if (ml->container == file)
50691040Sarr			TAILQ_REMOVE(&found_modules, ml, link);
50791040Sarr	}
50825537Sdfr
50991040Sarr	/*
51091040Sarr	 * Don't try to run SYSUNINITs if we are unloaded due to a
51191040Sarr	 * link error.
51291040Sarr	 */
51391040Sarr	if (file->flags & LINKER_FILE_LINKED) {
51491040Sarr		linker_file_sysuninit(file);
51591040Sarr		linker_file_unregister_sysctls(file);
51625537Sdfr	}
51798452Sarr	mtx_lock(&kld_mtx);
51891040Sarr	TAILQ_REMOVE(&linker_files, file, link);
51998452Sarr	mtx_unlock(&kld_mtx);
52025537Sdfr
52191040Sarr	if (file->deps) {
52291040Sarr		for (i = 0; i < file->ndeps; i++)
52391040Sarr			linker_file_unload(file->deps[i]);
52491040Sarr		free(file->deps, M_LINKER);
52591040Sarr		file->deps = NULL;
52659751Speter	}
52791040Sarr	for (cp = STAILQ_FIRST(&file->common); cp;
52891068Sarr	    cp = STAILQ_FIRST(&file->common)) {
52991040Sarr		STAILQ_REMOVE(&file->common, cp, common_symbol, link);
53091040Sarr		free(cp, M_LINKER);
53191040Sarr	}
53259751Speter
53391040Sarr	LINKER_UNLOAD(file);
53491040Sarr	if (file->filename) {
53591040Sarr		free(file->filename, M_LINKER);
53691040Sarr		file->filename = NULL;
53791040Sarr	}
53891040Sarr	kobj_delete((kobj_t) file, M_LINKER);
53925537Sdfrout:
54091040Sarr	return (error);
54125537Sdfr}
54225537Sdfr
54325537Sdfrint
54486469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep)
54525537Sdfr{
54691040Sarr	linker_file_t *newdeps;
54725537Sdfr
54891040Sarr	newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *),
54991040Sarr	    M_LINKER, M_WAITOK | M_ZERO);
55091040Sarr	if (newdeps == NULL)
55191040Sarr		return (ENOMEM);
55225537Sdfr
55391040Sarr	if (file->deps) {
55491040Sarr		bcopy(file->deps, newdeps,
55591040Sarr		    file->ndeps * sizeof(linker_file_t *));
55691040Sarr		free(file->deps, M_LINKER);
55791040Sarr	}
55891040Sarr	file->deps = newdeps;
55991040Sarr	file->deps[file->ndeps] = dep;
56091040Sarr	file->ndeps++;
56191040Sarr	return (0);
56225537Sdfr}
56325537Sdfr
56478161Speter/*
56591040Sarr * Locate a linker set and its contents.  This is a helper function to avoid
56691040Sarr * linker_if.h exposure elsewhere.  Note: firstp and lastp are really void ***
56778161Speter */
56878161Speterint
56978161Speterlinker_file_lookup_set(linker_file_t file, const char *name,
57091040Sarr    void *firstp, void *lastp, int *countp)
57178161Speter{
57278161Speter
57391040Sarr	return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp));
57478161Speter}
57578161Speter
57625537Sdfrcaddr_t
57791040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
57825537Sdfr{
57991040Sarr	c_linker_sym_t sym;
58091040Sarr	linker_symval_t symval;
58191040Sarr	caddr_t address;
58291040Sarr	size_t common_size = 0;
58392032Sdwmalone	int i;
58425537Sdfr
58591040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
58691040Sarr	    file, name, deps));
58725537Sdfr
58891040Sarr	if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
58991040Sarr		LINKER_SYMBOL_VALUES(file, sym, &symval);
59091040Sarr		if (symval.value == 0)
59191040Sarr			/*
59291040Sarr			 * For commons, first look them up in the
59391040Sarr			 * dependencies and only allocate space if not found
59491040Sarr			 * there.
59591040Sarr			 */
59691040Sarr			common_size = symval.size;
59791040Sarr		else {
59891040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol"
59991040Sarr			    ".value=%x\n", symval.value));
60091040Sarr			return (symval.value);
60191040Sarr		}
60240159Speter	}
60391040Sarr	if (deps) {
60491040Sarr		for (i = 0; i < file->ndeps; i++) {
60591040Sarr			address = linker_file_lookup_symbol(file->deps[i],
60691040Sarr			    name, 0);
60791040Sarr			if (address) {
60891040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
60991040Sarr				    " deps value=%x\n", address));
61091040Sarr				return (address);
61191040Sarr			}
61291040Sarr		}
61325537Sdfr	}
61491040Sarr	if (common_size > 0) {
61591040Sarr		/*
61691040Sarr		 * This is a common symbol which was not found in the
61791040Sarr		 * dependencies.  We maintain a simple common symbol table in
61891040Sarr		 * the file object.
61991040Sarr		 */
62091040Sarr		struct common_symbol *cp;
62142849Speter
62291040Sarr		STAILQ_FOREACH(cp, &file->common, link) {
62392032Sdwmalone			if (strcmp(cp->name, name) == 0) {
62491040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
62591040Sarr				    " old common value=%x\n", cp->address));
62691040Sarr				return (cp->address);
62791040Sarr			}
62891040Sarr		}
62991040Sarr		/*
63091040Sarr		 * Round the symbol size up to align.
63191040Sarr		 */
63291040Sarr		common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
63391040Sarr		cp = malloc(sizeof(struct common_symbol)
63491040Sarr		    + common_size + strlen(name) + 1, M_LINKER,
63591040Sarr		    M_WAITOK | M_ZERO);
63691040Sarr		if (cp == NULL) {
63791040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
63891040Sarr			return (0);
63991040Sarr		}
64091040Sarr		cp->address = (caddr_t)(cp + 1);
64191040Sarr		cp->name = cp->address + common_size;
64291040Sarr		strcpy(cp->name, name);
64391040Sarr		bzero(cp->address, common_size);
64491040Sarr		STAILQ_INSERT_TAIL(&file->common, cp, link);
64525537Sdfr
64691040Sarr		KLD_DPF(SYM, ("linker_file_lookup_symbol: new common"
64791040Sarr		    " value=%x\n", cp->address));
64891040Sarr		return (cp->address);
64940159Speter	}
65091040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
65191040Sarr	return (0);
65225537Sdfr}
65325537Sdfr
65440159Speter#ifdef DDB
65525537Sdfr/*
65691040Sarr * DDB Helpers.  DDB has to look across multiple files with their own symbol
65791040Sarr * tables and string tables.
65891040Sarr *
65991040Sarr * Note that we do not obey list locking protocols here.  We really don't need
66091040Sarr * DDB to hang because somebody's got the lock held.  We'll take the chance
66191040Sarr * that the files list is inconsistant instead.
66240159Speter */
66340159Speter
66440159Speterint
66543309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
66640159Speter{
66791040Sarr	linker_file_t lf;
66840159Speter
66991040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
67091040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
67191040Sarr			return (0);
67291040Sarr	}
67391040Sarr	return (ENOENT);
67440159Speter}
67540159Speter
67640159Speterint
67743309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
67840159Speter{
67991040Sarr	linker_file_t lf;
68091040Sarr	c_linker_sym_t best, es;
68191040Sarr	u_long diff, bestdiff, off;
68240159Speter
68391040Sarr	best = 0;
68491040Sarr	off = (uintptr_t)value;
68591040Sarr	bestdiff = off;
68691040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
68791040Sarr		if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
68891040Sarr			continue;
68991040Sarr		if (es != 0 && diff < bestdiff) {
69091040Sarr			best = es;
69191040Sarr			bestdiff = diff;
69291040Sarr		}
69391040Sarr		if (bestdiff == 0)
69491040Sarr			break;
69540159Speter	}
69691040Sarr	if (best) {
69791040Sarr		*sym = best;
69891040Sarr		*diffp = bestdiff;
69991040Sarr		return (0);
70091040Sarr	} else {
70191040Sarr		*sym = 0;
70291040Sarr		*diffp = off;
70391040Sarr		return (ENOENT);
70491040Sarr	}
70540159Speter}
70640159Speter
70740159Speterint
70843309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
70940159Speter{
71091040Sarr	linker_file_t lf;
71140159Speter
71291040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
71391040Sarr		if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
71491040Sarr			return (0);
71591040Sarr	}
71691040Sarr	return (ENOENT);
71740159Speter}
71840159Speter#endif
71940159Speter
72040159Speter/*
72125537Sdfr * Syscalls.
72225537Sdfr */
72382749Sdillon/*
72482749Sdillon * MPSAFE
72582749Sdillon */
72625537Sdfrint
72791040Sarrkldload(struct thread *td, struct kldload_args *uap)
72825537Sdfr{
72991040Sarr	char *kldname, *modname;
73091040Sarr	char *pathname = NULL;
73191040Sarr	linker_file_t lf;
73291040Sarr	int error = 0;
73325537Sdfr
73491040Sarr	td->td_retval[0] = -1;
73525537Sdfr
73691040Sarr	mtx_lock(&Giant);
73782749Sdillon
73893159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
73993159Sarr		goto out;
74093159Sarr
74193593Sjhb	if ((error = suser(td)) != 0)
74291040Sarr		goto out;
74325537Sdfr
74491040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
74591040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
74691040Sarr	    NULL)) != 0)
74791040Sarr		goto out;
74825537Sdfr
74991040Sarr	/*
75091040Sarr	 * If path do not contain qualified name or any dot in it
75191040Sarr	 * (kldname.ko, or kldname.ver.ko) treat it as interface
75291040Sarr	 * name.
75391040Sarr	 */
75491040Sarr	if (index(pathname, '/') || index(pathname, '.')) {
75591040Sarr		kldname = pathname;
75691040Sarr		modname = NULL;
75791040Sarr	} else {
75891040Sarr		kldname = NULL;
75991040Sarr		modname = pathname;
76091040Sarr	}
76191040Sarr	error = linker_load_module(kldname, modname, NULL, NULL, &lf);
76291040Sarr	if (error)
76391040Sarr		goto out;
76442316Smsmith
76591040Sarr	lf->userrefs++;
76691040Sarr	td->td_retval[0] = lf->id;
76725537Sdfrout:
76891040Sarr	if (pathname)
76991040Sarr		free(pathname, M_TEMP);
77091040Sarr	mtx_unlock(&Giant);
77191040Sarr	return (error);
77225537Sdfr}
77325537Sdfr
77482749Sdillon/*
77582749Sdillon * MPSAFE
77682749Sdillon */
77725537Sdfrint
77891040Sarrkldunload(struct thread *td, struct kldunload_args *uap)
77925537Sdfr{
78091040Sarr	linker_file_t lf;
78191040Sarr	int error = 0;
78225537Sdfr
78391040Sarr	mtx_lock(&Giant);
78482749Sdillon
78593159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
78693159Sarr		goto out;
78793159Sarr
78893593Sjhb	if ((error = suser(td)) != 0)
78991040Sarr		goto out;
79025537Sdfr
79191040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
79291040Sarr	if (lf) {
79391040Sarr		KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
79491040Sarr		if (lf->userrefs == 0) {
79591040Sarr			printf("kldunload: attempt to unload file that was"
79691040Sarr			    " loaded by the kernel\n");
79791040Sarr			error = EBUSY;
79891040Sarr			goto out;
79991040Sarr		}
80091068Sarr		lf->userrefs--;
80191040Sarr		error = linker_file_unload(lf);
80291040Sarr		if (error)
80391040Sarr			lf->userrefs++;
80491040Sarr	} else
80591040Sarr		error = ENOENT;
80625537Sdfrout:
80791068Sarr	mtx_unlock(&Giant);
80891068Sarr	return (error);
80925537Sdfr}
81025537Sdfr
81182749Sdillon/*
81282749Sdillon * MPSAFE
81382749Sdillon */
81425537Sdfrint
81591040Sarrkldfind(struct thread *td, struct kldfind_args *uap)
81625537Sdfr{
81791040Sarr	char *pathname;
81891040Sarr	const char *filename;
81991040Sarr	linker_file_t lf;
82091040Sarr	int error = 0;
82125537Sdfr
82291040Sarr	mtx_lock(&Giant);
82391040Sarr	td->td_retval[0] = -1;
82482749Sdillon
82591040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
82691040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
82791040Sarr	    NULL)) != 0)
82891040Sarr		goto out;
82925537Sdfr
83091040Sarr	filename = linker_basename(pathname);
83191040Sarr	lf = linker_find_file_by_name(filename);
83291040Sarr	if (lf)
83391040Sarr		td->td_retval[0] = lf->id;
83491040Sarr	else
83591040Sarr		error = ENOENT;
83625537Sdfrout:
83791040Sarr	if (pathname)
83891040Sarr		free(pathname, M_TEMP);
83991040Sarr	mtx_unlock(&Giant);
84091040Sarr	return (error);
84125537Sdfr}
84225537Sdfr
84382749Sdillon/*
84482749Sdillon * MPSAFE
84582749Sdillon */
84625537Sdfrint
84791040Sarrkldnext(struct thread *td, struct kldnext_args *uap)
84825537Sdfr{
84991040Sarr	linker_file_t lf;
85091040Sarr	int error = 0;
85125537Sdfr
85291040Sarr	mtx_lock(&Giant);
85382749Sdillon
85491040Sarr	if (SCARG(uap, fileid) == 0) {
85598452Sarr		mtx_lock(&kld_mtx);
85691040Sarr		if (TAILQ_FIRST(&linker_files))
85791040Sarr			td->td_retval[0] = TAILQ_FIRST(&linker_files)->id;
85891040Sarr		else
85991040Sarr			td->td_retval[0] = 0;
86098452Sarr		mtx_unlock(&kld_mtx);
86191040Sarr		goto out;
86291040Sarr	}
86391040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
86491040Sarr	if (lf) {
86591040Sarr		if (TAILQ_NEXT(lf, link))
86691040Sarr			td->td_retval[0] = TAILQ_NEXT(lf, link)->id;
86791040Sarr		else
86891040Sarr			td->td_retval[0] = 0;
86991040Sarr	} else
87091040Sarr		error = ENOENT;
87182749Sdillonout:
87291040Sarr	mtx_unlock(&Giant);
87391040Sarr	return (error);
87425537Sdfr}
87525537Sdfr
87682749Sdillon/*
87782749Sdillon * MPSAFE
87882749Sdillon */
87925537Sdfrint
88091040Sarrkldstat(struct thread *td, struct kldstat_args *uap)
88125537Sdfr{
88291040Sarr	linker_file_t lf;
88391040Sarr	int error = 0;
88491040Sarr	int namelen, version;
88591040Sarr	struct kld_file_stat *stat;
88625537Sdfr
88791040Sarr	mtx_lock(&Giant);
88882749Sdillon
88991040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
89091040Sarr	if (lf == NULL) {
89191040Sarr		error = ENOENT;
89291040Sarr		goto out;
89391040Sarr	}
89491040Sarr	stat = SCARG(uap, stat);
89525537Sdfr
89691040Sarr	/*
89791040Sarr	 * Check the version of the user's structure.
89891040Sarr	 */
89991040Sarr	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
90091040Sarr		goto out;
90191040Sarr	if (version != sizeof(struct kld_file_stat)) {
90291040Sarr		error = EINVAL;
90391040Sarr		goto out;
90491040Sarr	}
90591040Sarr	namelen = strlen(lf->filename) + 1;
90691040Sarr	if (namelen > MAXPATHLEN)
90791040Sarr		namelen = MAXPATHLEN;
90891040Sarr	if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
90991040Sarr		goto out;
91091040Sarr	if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
91191040Sarr		goto out;
91291040Sarr	if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
91391040Sarr		goto out;
91491040Sarr	if ((error = copyout(&lf->address, &stat->address,
91591040Sarr	    sizeof(caddr_t))) != 0)
91691040Sarr		goto out;
91791040Sarr	if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
91891040Sarr		goto out;
91925537Sdfr
92091040Sarr	td->td_retval[0] = 0;
92125537Sdfrout:
92291040Sarr	mtx_unlock(&Giant);
92391040Sarr	return (error);
92425537Sdfr}
92525537Sdfr
92682749Sdillon/*
92782749Sdillon * MPSAFE
92882749Sdillon */
92925537Sdfrint
93091040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
93125537Sdfr{
93291040Sarr	linker_file_t lf;
93391040Sarr	module_t mp;
93491040Sarr	int error = 0;
93525537Sdfr
93691040Sarr	mtx_lock(&Giant);
93791040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
93891040Sarr	if (lf) {
93992547Sarr		MOD_SLOCK;
94091040Sarr		mp = TAILQ_FIRST(&lf->modules);
94191040Sarr		if (mp != NULL)
94291040Sarr			td->td_retval[0] = module_getid(mp);
94391040Sarr		else
94491040Sarr			td->td_retval[0] = 0;
94592547Sarr		MOD_SUNLOCK;
94691040Sarr	} else
94791040Sarr		error = ENOENT;
94891040Sarr	mtx_unlock(&Giant);
94991040Sarr	return (error);
95025537Sdfr}
95140159Speter
95282749Sdillon/*
95382749Sdillon * MPSAFE
95482749Sdillon */
95541090Speterint
95683366Sjuliankldsym(struct thread *td, struct kldsym_args *uap)
95741090Speter{
95891040Sarr	char *symstr = NULL;
95991040Sarr	c_linker_sym_t sym;
96091040Sarr	linker_symval_t symval;
96191040Sarr	linker_file_t lf;
96291040Sarr	struct kld_sym_lookup lookup;
96391040Sarr	int error = 0;
96441090Speter
96591040Sarr	mtx_lock(&Giant);
96682749Sdillon
96791040Sarr	if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
96891040Sarr		goto out;
96991068Sarr	if (lookup.version != sizeof(lookup) ||
97091040Sarr	    SCARG(uap, cmd) != KLDSYM_LOOKUP) {
97191040Sarr		error = EINVAL;
97291040Sarr		goto out;
97391040Sarr	}
97491040Sarr	symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
97591040Sarr	if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
97691040Sarr		goto out;
97791040Sarr	if (SCARG(uap, fileid) != 0) {
97891040Sarr		lf = linker_find_file_by_id(SCARG(uap, fileid));
97991040Sarr		if (lf == NULL) {
98091040Sarr			error = ENOENT;
98191040Sarr			goto out;
98291040Sarr		}
98391040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
98491040Sarr		    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
98591040Sarr			lookup.symvalue = (uintptr_t) symval.value;
98691040Sarr			lookup.symsize = symval.size;
98791040Sarr			error = copyout(&lookup, SCARG(uap, data),
98891040Sarr			    sizeof(lookup));
98991040Sarr		} else
99091040Sarr			error = ENOENT;
99191040Sarr	} else {
99298452Sarr		mtx_lock(&kld_mtx);
99391040Sarr		TAILQ_FOREACH(lf, &linker_files, link) {
99491040Sarr			if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
99591040Sarr			    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
99691040Sarr				lookup.symvalue = (uintptr_t)symval.value;
99791040Sarr				lookup.symsize = symval.size;
99891040Sarr				error = copyout(&lookup, SCARG(uap, data),
99991040Sarr				    sizeof(lookup));
100091068Sarr				break;
100191040Sarr			}
100291040Sarr		}
100398452Sarr		mtx_unlock(&kld_mtx);
100491040Sarr		if (lf == NULL)
100591040Sarr			error = ENOENT;
100641090Speter	}
100741090Speterout:
100891040Sarr	if (symstr)
100991040Sarr		free(symstr, M_TEMP);
101091040Sarr	mtx_unlock(&Giant);
101191040Sarr	return (error);
101241090Speter}
101341090Speter
101440159Speter/*
101540159Speter * Preloaded module support
101640159Speter */
101740159Speter
101859751Speterstatic modlist_t
101974642Sbpmodlist_lookup(const char *name, int ver)
102059751Speter{
102191040Sarr	modlist_t mod;
102259751Speter
102391040Sarr	TAILQ_FOREACH(mod, &found_modules, link) {
102492032Sdwmalone		if (strcmp(mod->name, name) == 0 &&
102592032Sdwmalone		    (ver == 0 || mod->version == ver))
102691040Sarr			return (mod);
102791040Sarr	}
102891040Sarr	return (NULL);
102959751Speter}
103059751Speter
103174642Sbpstatic modlist_t
103283321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo)
103383321Speter{
103491040Sarr	modlist_t mod, bestmod;
103592032Sdwmalone	int ver;
103683321Speter
103791040Sarr	if (verinfo == NULL)
103891040Sarr		return (modlist_lookup(name, 0));
103991040Sarr	bestmod = NULL;
104091040Sarr	for (mod = TAILQ_FIRST(&found_modules); mod;
104191040Sarr	    mod = TAILQ_NEXT(mod, link)) {
104292032Sdwmalone		if (strcmp(mod->name, name) != 0)
104391040Sarr			continue;
104491040Sarr		ver = mod->version;
104591040Sarr		if (ver == verinfo->md_ver_preferred)
104691040Sarr			return (mod);
104791040Sarr		if (ver >= verinfo->md_ver_minimum &&
104891068Sarr		    ver <= verinfo->md_ver_maximum &&
104991068Sarr		    ver > bestmod->version)
105091040Sarr			bestmod = mod;
105191040Sarr	}
105291040Sarr	return (bestmod);
105383321Speter}
105483321Speter
105583321Speterstatic modlist_t
105678501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container)
105774642Sbp{
105891040Sarr	modlist_t mod;
105974642Sbp
106092705Sarr	mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO);
106191040Sarr	if (mod == NULL)
106291040Sarr		panic("no memory for module list");
106391040Sarr	mod->container = container;
106491040Sarr	mod->name = modname;
106591040Sarr	mod->version = version;
106691040Sarr	TAILQ_INSERT_TAIL(&found_modules, mod, link);
106791040Sarr	return (mod);
106874642Sbp}
106974642Sbp
107059751Speter/*
107159751Speter * This routine is cheap and nasty but will work for data pointers.
107259751Speter */
107359751Speterstatic void *
107478501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset)
107559751Speter{
107691040Sarr	return (lf->address + (uintptr_t)offset);
107759751Speter}
107859751Speter
107974642Sbp/*
108074642Sbp * Dereference MDT_VERSION metadata into module name and version
108174642Sbp */
108240159Speterstatic void
108374642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
108491040Sarr    const char **modname, int *version)
108574642Sbp{
108691040Sarr	struct mod_version *mvp;
108774642Sbp
108891040Sarr	if (modname)
108991040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
109091040Sarr	if (version) {
109191040Sarr		mvp = linker_reloc_ptr(lf, mp->md_data);
109291040Sarr		*version = mvp->mv_version;
109391040Sarr	}
109474642Sbp}
109574642Sbp
109674642Sbp/*
109774642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure
109874642Sbp */
109974642Sbpstatic void
110074642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
110191040Sarr    const char **modname, struct mod_depend **verinfo)
110274642Sbp{
110374642Sbp
110491040Sarr	if (modname)
110591040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
110691040Sarr	if (verinfo)
110791040Sarr		*verinfo = linker_reloc_ptr(lf, mp->md_data);
110874642Sbp}
110974642Sbp
111074642Sbpstatic void
111178161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start,
111291040Sarr    struct mod_metadata **stop, int preload)
111374642Sbp{
111491040Sarr	struct mod_metadata *mp, **mdp;
111591040Sarr	const char *modname;
111691040Sarr	int ver;
111774642Sbp
111891040Sarr	for (mdp = start; mdp < stop; mdp++) {
111991040Sarr		if (preload)
112091040Sarr			mp = *mdp;
112191040Sarr		else
112291040Sarr			mp = linker_reloc_ptr(lf, *mdp);
112391040Sarr		if (mp->md_type != MDT_VERSION)
112491040Sarr			continue;
112591040Sarr		if (preload) {
112691040Sarr			modname = mp->md_cval;
112791040Sarr			ver = ((struct mod_version *)mp->md_data)->mv_version;
112891040Sarr		} else
112991040Sarr	        	linker_mdt_version(lf, mp, &modname, &ver);
113091040Sarr		if (modlist_lookup(modname, ver) != NULL) {
113191040Sarr			printf("module %s already present!\n", modname);
113291040Sarr			/* XXX what can we do? this is a build error. :-( */
113391040Sarr			continue;
113491040Sarr		}
113591040Sarr		modlist_newmodule(modname, ver, lf);
113674642Sbp	}
113774642Sbp}
113874642Sbp
113974642Sbpstatic void
114091040Sarrlinker_preload(void *arg)
114140159Speter{
114291040Sarr	caddr_t modptr;
114391040Sarr	const char *modname, *nmodname;
114491040Sarr	char *modtype;
114591040Sarr	linker_file_t lf;
114691040Sarr	linker_class_t lc;
114792032Sdwmalone	int error;
114891040Sarr	linker_file_list_t loaded_files;
114991040Sarr	linker_file_list_t depended_files;
115091040Sarr	struct mod_metadata *mp, *nmp;
115191040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
115291040Sarr	struct mod_depend *verinfo;
115391040Sarr	int nver;
115491040Sarr	int resolves;
115591040Sarr	modlist_t mod;
115691040Sarr	struct sysinit **si_start, **si_stop;
115740159Speter
115891040Sarr	TAILQ_INIT(&loaded_files);
115991040Sarr	TAILQ_INIT(&depended_files);
116091040Sarr	TAILQ_INIT(&found_modules);
116191040Sarr	error = 0;
116259751Speter
116391040Sarr	modptr = NULL;
116491040Sarr	while ((modptr = preload_search_next_name(modptr)) != NULL) {
116591040Sarr		modname = (char *)preload_search_info(modptr, MODINFO_NAME);
116691040Sarr		modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
116791040Sarr		if (modname == NULL) {
116891040Sarr			printf("Preloaded module at %p does not have a"
116991040Sarr			    " name!\n", modptr);
117091040Sarr			continue;
117191040Sarr		}
117291040Sarr		if (modtype == NULL) {
117391040Sarr			printf("Preloaded module at %p does not have a type!\n",
117491040Sarr			    modptr);
117591040Sarr			continue;
117691040Sarr		}
117791040Sarr		printf("Preloaded %s \"%s\" at %p.\n", modtype, modname,
117891040Sarr		    modptr);
117940159Speter		lf = NULL;
118091040Sarr		TAILQ_FOREACH(lc, &classes, link) {
118191040Sarr			error = LINKER_LINK_PRELOAD(lc, modname, &lf);
118291040Sarr			if (error) {
118391040Sarr				lf = NULL;
118491040Sarr				break;
118591040Sarr			}
118691040Sarr		}
118791040Sarr		if (lf)
118891040Sarr			TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
118940159Speter	}
119040159Speter
119191040Sarr	/*
119291040Sarr	 * First get a list of stuff in the kernel.
119391040Sarr	 */
119491040Sarr	if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start,
119591040Sarr	    &stop, NULL) == 0)
119691040Sarr		linker_addmodules(linker_kernel_file, start, stop, 1);
119759751Speter
119859751Speter	/*
119991040Sarr	 * this is a once-off kinky bubble sort resolve relocation dependency
120091040Sarr	 * requirements
120159751Speter	 */
120291040Sarrrestart:
120391040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
120491040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
120591040Sarr		    &stop, NULL);
120691040Sarr		/*
120791040Sarr		 * First, look to see if we would successfully link with this
120891040Sarr		 * stuff.
120991040Sarr		 */
121091040Sarr		resolves = 1;	/* unless we know otherwise */
121191040Sarr		if (!error) {
121291040Sarr			for (mdp = start; mdp < stop; mdp++) {
121391040Sarr				mp = linker_reloc_ptr(lf, *mdp);
121491040Sarr				if (mp->md_type != MDT_DEPEND)
121591040Sarr					continue;
121691040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
121791040Sarr				for (nmdp = start; nmdp < stop; nmdp++) {
121891040Sarr					nmp = linker_reloc_ptr(lf, *nmdp);
121991040Sarr					if (nmp->md_type != MDT_VERSION)
122091040Sarr						continue;
122191040Sarr					linker_mdt_version(lf, nmp, &nmodname,
122291040Sarr					    NULL);
122391040Sarr					nmodname = linker_reloc_ptr(lf,
122491040Sarr					    nmp->md_cval);
122592032Sdwmalone					if (strcmp(modname, nmodname) == 0)
122691040Sarr						break;
122791040Sarr				}
122891040Sarr				if (nmdp < stop)   /* it's a self reference */
122991040Sarr					continue;
123091040Sarr
123191040Sarr				/*
123291040Sarr				 * ok, the module isn't here yet, we
123391040Sarr				 * are not finished
123491040Sarr				 */
123591068Sarr				if (modlist_lookup2(modname, verinfo) == NULL)
123691040Sarr					resolves = 0;
123791040Sarr			}
123864143Speter		}
123991040Sarr		/*
124091040Sarr		 * OK, if we found our modules, we can link.  So, "provide"
124191040Sarr		 * the modules inside and add it to the end of the link order
124291040Sarr		 * list.
124391040Sarr		 */
124491040Sarr		if (resolves) {
124591040Sarr			if (!error) {
124691040Sarr				for (mdp = start; mdp < stop; mdp++) {
124791040Sarr					mp = linker_reloc_ptr(lf, *mdp);
124891040Sarr					if (mp->md_type != MDT_VERSION)
124991040Sarr						continue;
125091040Sarr					linker_mdt_version(lf, mp,
125191040Sarr					    &modname, &nver);
125291040Sarr					if (modlist_lookup(modname,
125391040Sarr					    nver) != NULL) {
125491040Sarr						printf("module %s already"
125591040Sarr						    " present!\n", modname);
125691040Sarr						linker_file_unload(lf);
125791040Sarr						TAILQ_REMOVE(&loaded_files,
125891040Sarr						    lf, loaded);
125991040Sarr						/* we changed tailq next ptr */
126091068Sarr						goto restart;
126191040Sarr					}
126291040Sarr					modlist_newmodule(modname, nver, lf);
126391040Sarr				}
126491040Sarr			}
126591040Sarr			TAILQ_REMOVE(&loaded_files, lf, loaded);
126691040Sarr			TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
126791040Sarr			/*
126891040Sarr			 * Since we provided modules, we need to restart the
126991040Sarr			 * sort so that the previous files that depend on us
127091040Sarr			 * have a chance. Also, we've busted the tailq next
127191040Sarr			 * pointer with the REMOVE.
127291040Sarr			 */
127391040Sarr			goto restart;
127459751Speter		}
127559751Speter	}
127691040Sarr
127759751Speter	/*
127891040Sarr	 * At this point, we check to see what could not be resolved..
127959751Speter	 */
128091040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
128191040Sarr		printf("KLD file %s is missing dependencies\n", lf->filename);
128291040Sarr		linker_file_unload(lf);
128391040Sarr		TAILQ_REMOVE(&loaded_files, lf, loaded);
128440159Speter	}
128559751Speter
128678161Speter	/*
128791040Sarr	 * We made it. Finish off the linking in the order we determined.
128878161Speter	 */
128991040Sarr	TAILQ_FOREACH(lf, &depended_files, loaded) {
129091040Sarr		if (linker_kernel_file) {
129191040Sarr			linker_kernel_file->refs++;
129291040Sarr			error = linker_file_add_dependency(lf,
129391040Sarr			    linker_kernel_file);
129491040Sarr			if (error)
129591040Sarr				panic("cannot add dependency");
129691040Sarr		}
129791040Sarr		lf->userrefs++;	/* so we can (try to) kldunload it */
129891040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
129991040Sarr		    &stop, NULL);
130091040Sarr		if (!error) {
130191040Sarr			for (mdp = start; mdp < stop; mdp++) {
130291040Sarr				mp = linker_reloc_ptr(lf, *mdp);
130391040Sarr				if (mp->md_type != MDT_DEPEND)
130491040Sarr					continue;
130591040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
130691040Sarr				mod = modlist_lookup2(modname, verinfo);
130791040Sarr				mod->container->refs++;
130891040Sarr				error = linker_file_add_dependency(lf,
130991040Sarr				    mod->container);
131091040Sarr				if (error)
131191040Sarr					panic("cannot add dependency");
131291040Sarr			}
131391040Sarr		}
131491040Sarr		/*
131591040Sarr		 * Now do relocation etc using the symbol search paths
131691040Sarr		 * established by the dependencies
131791040Sarr		 */
131891040Sarr		error = LINKER_LINK_PRELOAD_FINISH(lf);
131991040Sarr		if (error) {
132091040Sarr			printf("KLD file %s - could not finalize loading\n",
132191040Sarr			    lf->filename);
132291040Sarr			linker_file_unload(lf);
132391040Sarr			continue;
132491040Sarr		}
132591040Sarr		linker_file_register_modules(lf);
132691040Sarr		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
132791040Sarr		    &si_stop, NULL) == 0)
132891040Sarr			sysinit_add(si_start, si_stop);
132991040Sarr		linker_file_register_sysctls(lf);
133091040Sarr		lf->flags |= LINKER_FILE_LINKED;
133159751Speter	}
133291040Sarr	/* woohoo! we made it! */
133340159Speter}
133440159Speter
133591040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0)
133640159Speter
133740159Speter/*
133840159Speter * Search for a not-loaded module by name.
133991040Sarr *
134040159Speter * Modules may be found in the following locations:
134191040Sarr *
134291040Sarr * - preloaded (result is just the module name) - on disk (result is full path
134391040Sarr * to module)
134491040Sarr *
134591040Sarr * If the module name is qualified in any way (contains path, etc.) the we
134691040Sarr * simply return a copy of it.
134791040Sarr *
134840159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
134940159Speter * character as a separator to be consistent with the bootloader.
135040159Speter */
135140159Speter
135283321Speterstatic char linker_hintfile[] = "linker.hints";
135383358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules";
135440159Speter
135540159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
135691040Sarr    sizeof(linker_path), "module load search path");
135740159Speter
135877843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path));
135970417Speter
136059751Speterstatic char *linker_ext_list[] = {
136183321Speter	"",
136259751Speter	".ko",
136359751Speter	NULL
136459751Speter};
136559751Speter
136683321Speter/*
136791040Sarr * Check if file actually exists either with or without extension listed in
136891040Sarr * the linker_ext_list. (probably should be generic for the rest of the
136991040Sarr * kernel)
137083321Speter */
137159751Speterstatic char *
137291040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name,
137391040Sarr    int namelen, struct vattr *vap)
137440159Speter{
137591040Sarr	struct nameidata nd;
137691040Sarr	struct thread *td = curthread;	/* XXX */
137791040Sarr	char *result, **cpp, *sep;
137891040Sarr	int error, len, extlen, reclen, flags;
137991040Sarr	enum vtype type;
138040159Speter
138191040Sarr	extlen = 0;
138291040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
138391040Sarr		len = strlen(*cpp);
138491040Sarr		if (len > extlen)
138591040Sarr			extlen = len;
138691040Sarr	}
138791040Sarr	extlen++;		/* trailing '\0' */
138891040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
138983321Speter
139091040Sarr	reclen = pathlen + strlen(sep) + namelen + extlen + 1;
139191040Sarr	result = malloc(reclen, M_LINKER, M_WAITOK);
139291040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
139391040Sarr		snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep,
139491040Sarr		    namelen, name, *cpp);
139591040Sarr		/*
139691040Sarr		 * Attempt to open the file, and return the path if
139791040Sarr		 * we succeed and it's a regular file.
139891040Sarr		 */
139991040Sarr		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td);
140091040Sarr		flags = FREAD;
140191040Sarr		error = vn_open(&nd, &flags, 0);
140291040Sarr		if (error == 0) {
140391040Sarr			NDFREE(&nd, NDF_ONLY_PNBUF);
140491040Sarr			type = nd.ni_vp->v_type;
140591040Sarr			if (vap)
140691406Sjhb				VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
140791040Sarr			VOP_UNLOCK(nd.ni_vp, 0, td);
140891406Sjhb			vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
140991040Sarr			if (type == VREG)
141091040Sarr				return (result);
141191040Sarr		}
141283321Speter	}
141391040Sarr	free(result, M_LINKER);
141491040Sarr	return (NULL);
141583321Speter}
141683321Speter
141791040Sarr#define	INT_ALIGN(base, ptr)	ptr =					\
141883321Speter	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
141983321Speter
142083321Speter/*
142191040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If
142291040Sarr * version specification is available, then try to find the best KLD.
142383321Speter * Otherwise just find the latest one.
142483321Speter */
142583321Speterstatic char *
142691040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname,
142791040Sarr    int modnamelen, struct mod_depend *verinfo)
142883321Speter{
142991040Sarr	struct thread *td = curthread;	/* XXX */
143091406Sjhb	struct ucred *cred = td ? td->td_ucred : NULL;
143191040Sarr	struct nameidata nd;
143291040Sarr	struct vattr vattr, mattr;
143391040Sarr	u_char *hints = NULL;
143491040Sarr	u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep;
143591040Sarr	int error, ival, bestver, *intp, reclen, found, flags, clen, blen;
143683321Speter
143791040Sarr	result = NULL;
143891040Sarr	bestver = found = 0;
143983321Speter
144091040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
144191040Sarr	reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen +
144291040Sarr	    strlen(sep) + 1;
144391040Sarr	pathbuf = malloc(reclen, M_LINKER, M_WAITOK);
144491040Sarr	snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep,
144591040Sarr	    linker_hintfile);
144683321Speter
144791040Sarr	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td);
144891040Sarr	flags = FREAD;
144991040Sarr	error = vn_open(&nd, &flags, 0);
145091040Sarr	if (error)
145191040Sarr		goto bad;
145291040Sarr	NDFREE(&nd, NDF_ONLY_PNBUF);
145391040Sarr	if (nd.ni_vp->v_type != VREG)
145491040Sarr		goto bad;
145591040Sarr	best = cp = NULL;
145691040Sarr	error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td);
145791040Sarr	if (error)
145891040Sarr		goto bad;
145991040Sarr	/*
146091040Sarr	 * XXX: we need to limit this number to some reasonable value
146191040Sarr	 */
146291040Sarr	if (vattr.va_size > 100 * 1024) {
146391040Sarr		printf("hints file too large %ld\n", (long)vattr.va_size);
146491040Sarr		goto bad;
146591040Sarr	}
146691040Sarr	hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
146791040Sarr	if (hints == NULL)
146891040Sarr		goto bad;
146991068Sarr	error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
147091040Sarr	    UIO_SYSSPACE, IO_NODELOCKED, cred, &reclen, td);
147191040Sarr	if (error)
147291040Sarr		goto bad;
147399553Sjeff	VOP_UNLOCK(nd.ni_vp, 0, td);
147491040Sarr	vn_close(nd.ni_vp, FREAD, cred, td);
147591040Sarr	nd.ni_vp = NULL;
147691040Sarr	if (reclen != 0) {
147791040Sarr		printf("can't read %d\n", reclen);
147891040Sarr		goto bad;
147991040Sarr	}
148091040Sarr	intp = (int *)hints;
148183321Speter	ival = *intp++;
148291040Sarr	if (ival != LINKER_HINTS_VERSION) {
148391040Sarr		printf("hints file version mismatch %d\n", ival);
148491040Sarr		goto bad;
148583321Speter	}
148691040Sarr	bufend = hints + vattr.va_size;
148791040Sarr	recptr = (u_char *)intp;
148891040Sarr	clen = blen = 0;
148991040Sarr	while (recptr < bufend && !found) {
149091040Sarr		intp = (int *)recptr;
149191040Sarr		reclen = *intp++;
149291040Sarr		ival = *intp++;
149391040Sarr		cp = (char *)intp;
149491040Sarr		switch (ival) {
149591040Sarr		case MDT_VERSION:
149691040Sarr			clen = *cp++;
149791040Sarr			if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
149891040Sarr				break;
149991040Sarr			cp += clen;
150091040Sarr			INT_ALIGN(hints, cp);
150191040Sarr			ival = *(int *)cp;
150291040Sarr			cp += sizeof(int);
150391040Sarr			clen = *cp++;
150491040Sarr			if (verinfo == NULL ||
150591040Sarr			    ival == verinfo->md_ver_preferred) {
150691040Sarr				found = 1;
150791040Sarr				break;
150891040Sarr			}
150991040Sarr			if (ival >= verinfo->md_ver_minimum &&
151091040Sarr			    ival <= verinfo->md_ver_maximum &&
151191040Sarr			    ival > bestver) {
151291040Sarr				bestver = ival;
151391040Sarr				best = cp;
151491040Sarr				blen = clen;
151591040Sarr			}
151691040Sarr			break;
151791040Sarr		default:
151891040Sarr			break;
151991040Sarr		}
152091040Sarr		recptr += reclen + sizeof(int);
152191040Sarr	}
152283321Speter	/*
152391040Sarr	 * Finally check if KLD is in the place
152483321Speter	 */
152591040Sarr	if (found)
152691040Sarr		result = linker_lookup_file(path, pathlen, cp, clen, &mattr);
152791040Sarr	else if (best)
152891040Sarr		result = linker_lookup_file(path, pathlen, best, blen, &mattr);
152991040Sarr
153091040Sarr	/*
153191040Sarr	 * KLD is newer than hints file. What we should do now?
153291040Sarr	 */
153391040Sarr	if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >))
153491040Sarr		printf("warning: KLD '%s' is newer than the linker.hints"
153591040Sarr		    " file\n", result);
153683321Speterbad:
153791040Sarr	if (hints)
153891040Sarr		free(hints, M_TEMP);
153999553Sjeff	if (nd.ni_vp != NULL) {
154099553Sjeff		VOP_UNLOCK(nd.ni_vp, 0, td);
154191040Sarr		vn_close(nd.ni_vp, FREAD, cred, td);
154299553Sjeff	}
154391040Sarr	/*
154491040Sarr	 * If nothing found or hints is absent - fallback to the old
154591040Sarr	 * way by using "kldname[.ko]" as module name.
154691040Sarr	 */
154791040Sarr	if (!found && !bestver && result == NULL)
154891040Sarr		result = linker_lookup_file(path, pathlen, modname,
154991040Sarr		    modnamelen, NULL);
155091040Sarr	return (result);
155183321Speter}
155283321Speter
155383321Speter/*
155483321Speter * Lookup KLD which contains requested module in the all directories.
155583321Speter */
155683321Speterstatic char *
155783321Speterlinker_search_module(const char *modname, int modnamelen,
155891040Sarr    struct mod_depend *verinfo)
155983321Speter{
156091040Sarr	char *cp, *ep, *result;
156183321Speter
156291040Sarr	/*
156391040Sarr	 * traverse the linker path
156491040Sarr	 */
156591040Sarr	for (cp = linker_path; *cp; cp = ep + 1) {
156691040Sarr		/* find the end of this component */
156791040Sarr		for (ep = cp; (*ep != 0) && (*ep != ';'); ep++);
156891068Sarr		result = linker_hints_lookup(cp, ep - cp, modname,
156991068Sarr		    modnamelen, verinfo);
157091040Sarr		if (result != NULL)
157191040Sarr			return (result);
157291040Sarr		if (*ep == 0)
157391040Sarr			break;
157491040Sarr	}
157591040Sarr	return (NULL);
157683321Speter}
157783321Speter
157883321Speter/*
157983321Speter * Search for module in all directories listed in the linker_path.
158083321Speter */
158183321Speterstatic char *
158283321Speterlinker_search_kld(const char *name)
158383321Speter{
158491040Sarr	char *cp, *ep, *result, **cpp;
158591040Sarr	int extlen, len;
158683321Speter
158791040Sarr	/* qualified at all? */
158891040Sarr	if (index(name, '/'))
158991040Sarr		return (linker_strdup(name));
159040159Speter
159191040Sarr	extlen = 0;
159291040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
159391040Sarr		len = strlen(*cpp);
159491040Sarr		if (len > extlen)
159591040Sarr			extlen = len;
159691040Sarr	}
159791040Sarr	extlen++;		/* trailing '\0' */
159859751Speter
159991040Sarr	/* traverse the linker path */
160091040Sarr	len = strlen(name);
160191040Sarr	for (ep = linker_path; *ep; ep++) {
160291040Sarr		cp = ep;
160391040Sarr		/* find the end of this component */
160491040Sarr		for (; *ep != 0 && *ep != ';'; ep++);
160591040Sarr		result = linker_lookup_file(cp, ep - cp, name, len, NULL);
160691040Sarr		if (result != NULL)
160791040Sarr			return (result);
160891040Sarr	}
160991040Sarr	return (NULL);
161040159Speter}
161159751Speter
161259751Speterstatic const char *
161391040Sarrlinker_basename(const char *path)
161459751Speter{
161591040Sarr	const char *filename;
161659751Speter
161791040Sarr	filename = rindex(path, '/');
161891040Sarr	if (filename == NULL)
161991040Sarr		return path;
162091040Sarr	if (filename[1])
162191040Sarr		filename++;
162291040Sarr	return (filename);
162359751Speter}
162459751Speter
162559751Speter/*
162691040Sarr * Find a file which contains given module and load it, if "parent" is not
162791040Sarr * NULL, register a reference to it.
162859751Speter */
162959751Speterstatic int
163083321Speterlinker_load_module(const char *kldname, const char *modname,
163191040Sarr    struct linker_file *parent, struct mod_depend *verinfo,
163291040Sarr    struct linker_file **lfpp)
163359751Speter{
163491040Sarr	linker_file_t lfdep;
163591040Sarr	const char *filename;
163691040Sarr	char *pathname;
163791040Sarr	int error;
163859751Speter
163991040Sarr	if (modname == NULL) {
164091040Sarr		/*
164191040Sarr 		 * We have to load KLD
164291040Sarr 		 */
164391068Sarr		KASSERT(verinfo == NULL, ("linker_load_module: verinfo"
164491068Sarr		    " is not NULL"));
164591040Sarr		pathname = linker_search_kld(kldname);
164691040Sarr	} else {
164791040Sarr		if (modlist_lookup2(modname, verinfo) != NULL)
164891040Sarr			return (EEXIST);
164994322Sbrian		if (kldname != NULL)
165094322Sbrian			pathname = linker_strdup(kldname);
165195488Sbrian		else if (rootvnode == NULL)
165294322Sbrian			pathname = NULL;
165394322Sbrian		else
165491040Sarr			/*
165591040Sarr			 * Need to find a KLD with required module
165691040Sarr			 */
165791040Sarr			pathname = linker_search_module(modname,
165891040Sarr			    strlen(modname), verinfo);
165991040Sarr	}
166091040Sarr	if (pathname == NULL)
166191040Sarr		return (ENOENT);
166291040Sarr
166383321Speter	/*
166491040Sarr	 * Can't load more than one file with the same basename XXX:
166591040Sarr	 * Actually it should be possible to have multiple KLDs with
166691040Sarr	 * the same basename but different path because they can
166791040Sarr	 * provide different versions of the same modules.
166883321Speter	 */
166991040Sarr	filename = linker_basename(pathname);
167091040Sarr	if (linker_find_file_by_name(filename)) {
167191040Sarr		error = EEXIST;
167291040Sarr		goto out;
167383321Speter	}
167491040Sarr	do {
167591040Sarr		error = linker_load_file(pathname, &lfdep);
167691040Sarr		if (error)
167791040Sarr			break;
167891040Sarr		if (modname && verinfo &&
167991040Sarr		    modlist_lookup2(modname, verinfo) == NULL) {
168091040Sarr			linker_file_unload(lfdep);
168191040Sarr			error = ENOENT;
168291040Sarr			break;
168391040Sarr		}
168491040Sarr		if (parent) {
168591040Sarr			error = linker_file_add_dependency(parent, lfdep);
168691040Sarr			if (error)
168791040Sarr				break;
168891040Sarr		}
168991040Sarr		if (lfpp)
169091040Sarr			*lfpp = lfdep;
169191040Sarr	} while (0);
169259751Speterout:
169391040Sarr	if (pathname)
169491040Sarr		free(pathname, M_LINKER);
169591040Sarr	return (error);
169659751Speter}
169759751Speter
169859751Speter/*
169991040Sarr * This routine is responsible for finding dependencies of userland initiated
170091040Sarr * kldload(2)'s of files.
170159751Speter */
170259751Speterint
170386469Siedowselinker_load_dependencies(linker_file_t lf)
170459751Speter{
170591040Sarr	linker_file_t lfdep;
170691040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
170791040Sarr	struct mod_metadata *mp, *nmp;
170891040Sarr	struct mod_depend *verinfo;
170991040Sarr	modlist_t mod;
171091040Sarr	const char *modname, *nmodname;
171192032Sdwmalone	int ver, error = 0, count;
171259751Speter
171391040Sarr	/*
171491040Sarr	 * All files are dependant on /kernel.
171591040Sarr	 */
171691040Sarr	if (linker_kernel_file) {
171791040Sarr		linker_kernel_file->refs++;
171891040Sarr		error = linker_file_add_dependency(lf, linker_kernel_file);
171991040Sarr		if (error)
172091040Sarr			return (error);
172159751Speter	}
172291040Sarr	if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop,
172391040Sarr	    &count) != 0)
172491040Sarr		return (0);
172591040Sarr	for (mdp = start; mdp < stop; mdp++) {
172691040Sarr		mp = linker_reloc_ptr(lf, *mdp);
172791040Sarr		if (mp->md_type != MDT_VERSION)
172891040Sarr			continue;
172991040Sarr		linker_mdt_version(lf, mp, &modname, &ver);
173091040Sarr		mod = modlist_lookup(modname, ver);
173191040Sarr		if (mod != NULL) {
173291040Sarr			printf("interface %s.%d already present in the KLD"
173391040Sarr			    " '%s'!\n", modname, ver,
173491040Sarr			    mod->container->filename);
173591040Sarr			return (EEXIST);
173691040Sarr		}
173791040Sarr	}
173874642Sbp
173991040Sarr	for (mdp = start; mdp < stop; mdp++) {
174091040Sarr		mp = linker_reloc_ptr(lf, *mdp);
174191040Sarr		if (mp->md_type != MDT_DEPEND)
174291040Sarr			continue;
174391040Sarr		linker_mdt_depend(lf, mp, &modname, &verinfo);
174491040Sarr		nmodname = NULL;
174591040Sarr		for (nmdp = start; nmdp < stop; nmdp++) {
174691040Sarr			nmp = linker_reloc_ptr(lf, *nmdp);
174791040Sarr			if (nmp->md_type != MDT_VERSION)
174891040Sarr				continue;
174991040Sarr			nmodname = linker_reloc_ptr(lf, nmp->md_cval);
175092032Sdwmalone			if (strcmp(modname, nmodname) == 0)
175191040Sarr				break;
175291040Sarr		}
175391040Sarr		if (nmdp < stop)/* early exit, it's a self reference */
175491040Sarr			continue;
175591040Sarr		mod = modlist_lookup2(modname, verinfo);
175691040Sarr		if (mod) {	/* woohoo, it's loaded already */
175791040Sarr			lfdep = mod->container;
175891040Sarr			lfdep->refs++;
175991040Sarr			error = linker_file_add_dependency(lf, lfdep);
176091040Sarr			if (error)
176191040Sarr				break;
176291040Sarr			continue;
176391040Sarr		}
176491040Sarr		error = linker_load_module(NULL, modname, lf, verinfo, NULL);
176591040Sarr		if (error) {
176691040Sarr			printf("KLD %s: depends on %s - not available\n",
176791040Sarr			    lf->filename, modname);
176891040Sarr			break;
176991040Sarr		}
177059751Speter	}
177159751Speter
177291040Sarr	if (error)
177391040Sarr		return (error);
177491040Sarr	linker_addmodules(lf, start, stop, 0);
177591040Sarr	return (error);
177659751Speter}
177785736Sgreen
177885736Sgreenstatic int
177985736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque)
178085736Sgreen{
178185736Sgreen	struct sysctl_req *req;
178285736Sgreen
178385736Sgreen	req = opaque;
178485736Sgreen	return (SYSCTL_OUT(req, name, strlen(name) + 1));
178585736Sgreen}
178685736Sgreen
178785736Sgreen/*
178885736Sgreen * Export a nul-separated, double-nul-terminated list of all function names
178985736Sgreen * in the kernel.
179085736Sgreen */
179185736Sgreenstatic int
179285736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS)
179385736Sgreen{
179485736Sgreen	linker_file_t lf;
179585736Sgreen	int error;
179685736Sgreen
1797100488Struckman	sysctl_wire_old_buffer(req, 0);
179898452Sarr	mtx_lock(&kld_mtx);
179985736Sgreen	TAILQ_FOREACH(lf, &linker_files, link) {
180085736Sgreen		error = LINKER_EACH_FUNCTION_NAME(lf,
180185736Sgreen		    sysctl_kern_function_list_iterate, req);
180298452Sarr		if (error) {
180398452Sarr			mtx_unlock(&kld_mtx);
180485736Sgreen			return (error);
180598452Sarr		}
180685736Sgreen	}
180798452Sarr	mtx_unlock(&kld_mtx);
180885736Sgreen	return (SYSCTL_OUT(req, "", 1));
180985736Sgreen}
181085736Sgreen
181185736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD,
181291040Sarr    NULL, 0, sysctl_kern_function_list, "", "kernel function list");
1813