kern_linker.c revision 105167
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 105167 2002-10-15 18:58:38Z phk $
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);
6059751Speter
6178161Speter/* Metadata from the static kernel */
6278161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata);
6378161Speter
6459751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
6559751Speter
6640906Speterlinker_file_t linker_kernel_file;
6731324Sbde
6898452Sarrstatic struct mtx kld_mtx;	/* kernel linker mutex */
6998452Sarr
7025537Sdfrstatic linker_class_list_t classes;
7150068Sgrogstatic linker_file_list_t linker_files;
7225537Sdfrstatic int next_file_id = 1;
7398452Sarrstatic int linker_no_more_classes = 0;
7425537Sdfr
7586553Sarr#define	LINKER_GET_NEXT_FILE_ID(a) do {					\
7691040Sarr	linker_file_t lftmp;						\
7786553Sarr									\
7886553Sarrretry:									\
7998452Sarr	mtx_lock(&kld_mtx);						\
8091040Sarr	TAILQ_FOREACH(lftmp, &linker_files, link) {			\
8191040Sarr		if (next_file_id == lftmp->id) {			\
8291040Sarr			next_file_id++;					\
8398452Sarr			mtx_unlock(&kld_mtx);				\
8491040Sarr			goto retry;					\
8591040Sarr		}							\
8691040Sarr	}								\
8791040Sarr	(a) = next_file_id;						\
8898452Sarr	mtx_unlock(&kld_mtx);	/* Hold for safe read of id variable */	\
8986553Sarr} while(0)
9086553Sarr
9186553Sarr
9259751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */
9360938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t;
9459751Speterstruct modlist {
9591040Sarr	TAILQ_ENTRY(modlist) link;	/* chain together all modules */
9691040Sarr	linker_file_t   container;
9791040Sarr	const char 	*name;
9891040Sarr	int             version;
9959751Speter};
10091040Sarrtypedef struct modlist *modlist_t;
10191040Sarrstatic modlisthead_t found_modules;
10259751Speter
10394321Sbrianstatic modlist_t	modlist_lookup2(const char *name,
10494321Sbrian			    struct mod_depend *verinfo);
10594321Sbrian
10659603Sdfrstatic char *
10759603Sdfrlinker_strdup(const char *str)
10859603Sdfr{
10991040Sarr	char *result;
11059603Sdfr
11191040Sarr	if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
11291040Sarr		strcpy(result, str);
11391040Sarr	return (result);
11459603Sdfr}
11559603Sdfr
11625537Sdfrstatic void
11791040Sarrlinker_init(void *arg)
11825537Sdfr{
11991040Sarr
12098452Sarr	mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF);
12191040Sarr	TAILQ_INIT(&classes);
12291040Sarr	TAILQ_INIT(&linker_files);
12325537Sdfr}
12425537Sdfr
12591040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0)
12625537Sdfr
12798452Sarrstatic void
12898452Sarrlinker_stop_class_add(void *arg)
12998452Sarr{
13098452Sarr
13198452Sarr	linker_no_more_classes = 1;
13298452Sarr}
13398452Sarr
13498452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL)
13598452Sarr
13625537Sdfrint
13759603Sdfrlinker_add_class(linker_class_t lc)
13825537Sdfr{
13991040Sarr
14098452Sarr	/*
14198452Sarr	 * We disallow any class registration passt SI_ORDER_ANY
14298452Sarr	 * of SI_SUB_KLD.
14398452Sarr	 */
14498452Sarr	if (linker_no_more_classes == 1)
14598452Sarr		return (EPERM);
14691040Sarr	kobj_class_compile((kobj_class_t) lc);
14791040Sarr	TAILQ_INSERT_TAIL(&classes, lc, link);
14891040Sarr	return (0);
14925537Sdfr}
15025537Sdfr
15125537Sdfrstatic void
15225537Sdfrlinker_file_sysinit(linker_file_t lf)
15325537Sdfr{
15491040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
15525537Sdfr
15691040Sarr	KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
15791040Sarr	    lf->filename));
15825537Sdfr
15991040Sarr	if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
16091040Sarr		return;
16191040Sarr	/*
16291040Sarr	 * Perform a bubble sort of the system initialization objects by
16391040Sarr	 * their subsystem (primary key) and order (secondary key).
16491040Sarr	 *
16591040Sarr	 * Since some things care about execution order, this is the operation
16691040Sarr	 * which ensures continued function.
16791040Sarr	 */
16891040Sarr	for (sipp = start; sipp < stop; sipp++) {
16991040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
17091040Sarr			if ((*sipp)->subsystem < (*xipp)->subsystem ||
17191040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
17291040Sarr			    (*sipp)->order <= (*xipp)->order))
17391040Sarr				continue;	/* skip */
17491040Sarr			save = *sipp;
17591040Sarr			*sipp = *xipp;
17691040Sarr			*xipp = save;
17791040Sarr		}
17825537Sdfr	}
17925537Sdfr
18091040Sarr	/*
18191040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
18291040Sarr	 * Perform each task, and continue on to the next task.
18391040Sarr	 */
18491040Sarr	for (sipp = start; sipp < stop; sipp++) {
18591040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
18691040Sarr			continue;	/* skip dummy task(s) */
18725537Sdfr
18891040Sarr		/* Call function */
18991040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
19091040Sarr	}
19125537Sdfr}
19225537Sdfr
19341055Speterstatic void
19441055Speterlinker_file_sysuninit(linker_file_t lf)
19541055Speter{
19691040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
19741055Speter
19891040Sarr	KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
19991040Sarr	    lf->filename));
20041055Speter
20191068Sarr	if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop,
20291040Sarr	    NULL) != 0)
20391040Sarr		return;
20441055Speter
20591040Sarr	/*
20691040Sarr	 * Perform a reverse bubble sort of the system initialization objects
20791040Sarr	 * by their subsystem (primary key) and order (secondary key).
20891040Sarr	 *
20991040Sarr	 * Since some things care about execution order, this is the operation
21091040Sarr	 * which ensures continued function.
21191040Sarr	 */
21291040Sarr	for (sipp = start; sipp < stop; sipp++) {
21391040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
21491040Sarr			if ((*sipp)->subsystem > (*xipp)->subsystem ||
21591040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
21691040Sarr			    (*sipp)->order >= (*xipp)->order))
21791040Sarr				continue;	/* skip */
21891040Sarr			save = *sipp;
21991040Sarr			*sipp = *xipp;
22091040Sarr			*xipp = save;
22191040Sarr		}
22241055Speter	}
22341055Speter
22491040Sarr	/*
22591040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
22691040Sarr	 * Perform each task, and continue on to the next task.
22791040Sarr	 */
22891040Sarr	for (sipp = start; sipp < stop; sipp++) {
22991040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
23091040Sarr			continue;	/* skip dummy task(s) */
23141055Speter
23291040Sarr		/* Call function */
23391040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
23491040Sarr	}
23541055Speter}
23641055Speter
23744078Sdfrstatic void
23844078Sdfrlinker_file_register_sysctls(linker_file_t lf)
23944078Sdfr{
24091040Sarr	struct sysctl_oid **start, **stop, **oidp;
24144078Sdfr
24291040Sarr	KLD_DPF(FILE,
24391040Sarr	    ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
24491040Sarr	    lf->filename));
24544078Sdfr
24691040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
24791040Sarr		return;
24844078Sdfr
24991040Sarr	for (oidp = start; oidp < stop; oidp++)
25091040Sarr		sysctl_register_oid(*oidp);
25144078Sdfr}
25244078Sdfr
25344078Sdfrstatic void
25444078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
25544078Sdfr{
25691040Sarr	struct sysctl_oid **start, **stop, **oidp;
25744078Sdfr
25891040Sarr	KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs"
25991040Sarr	    " for %s\n", lf->filename));
26044078Sdfr
26191040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
26291040Sarr		return;
26344078Sdfr
26491040Sarr	for (oidp = start; oidp < stop; oidp++)
26591040Sarr		sysctl_unregister_oid(*oidp);
26644078Sdfr}
26744078Sdfr
26859751Speterstatic int
26959751Speterlinker_file_register_modules(linker_file_t lf)
27059751Speter{
27191040Sarr	struct mod_metadata **start, **stop, **mdp;
27291040Sarr	const moduledata_t *moddata;
27391040Sarr	int error;
27459751Speter
27591040Sarr	KLD_DPF(FILE, ("linker_file_register_modules: registering modules"
27691040Sarr	    " in %s\n", lf->filename));
27759751Speter
27891068Sarr	if (linker_file_lookup_set(lf, "modmetadata_set", &start,
27991040Sarr	    &stop, 0) != 0) {
28091040Sarr		/*
28191040Sarr		 * This fallback should be unnecessary, but if we get booted
28291040Sarr		 * from boot2 instead of loader and we are missing our
28391040Sarr		 * metadata then we have to try the best we can.
28491040Sarr		 */
28591040Sarr		if (lf == linker_kernel_file) {
28691040Sarr			start = SET_BEGIN(modmetadata_set);
28791040Sarr			stop = SET_LIMIT(modmetadata_set);
28891040Sarr		} else
28991040Sarr			return (0);
29078161Speter	}
29191040Sarr	for (mdp = start; mdp < stop; mdp++) {
29291040Sarr		if ((*mdp)->md_type != MDT_MODULE)
29391040Sarr			continue;
29491040Sarr		moddata = (*mdp)->md_data;
29591040Sarr		KLD_DPF(FILE, ("Registering module %s in %s\n",
29691040Sarr		    moddata->name, lf->filename));
29791040Sarr		error = module_register(moddata, lf);
29891040Sarr		if (error)
29991068Sarr			printf("Module %s failed to register: %d\n",
30091040Sarr			    moddata->name, error);
30159751Speter	}
30291040Sarr	return (0);
30359751Speter}
30459751Speter
30559751Speterstatic void
30659751Speterlinker_init_kernel_modules(void)
30759751Speter{
30891040Sarr
30991040Sarr	linker_file_register_modules(linker_kernel_file);
31059751Speter}
31159751Speter
31291040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0)
31359751Speter
314101241Smuxstatic int
31591040Sarrlinker_load_file(const char *filename, linker_file_t *result)
31625537Sdfr{
31791040Sarr	linker_class_t lc;
31891040Sarr	linker_file_t lf;
31991040Sarr	int foundfile, error = 0;
32025537Sdfr
32191040Sarr	/* Refuse to load modules if securelevel raised */
32291040Sarr	if (securelevel > 0)
32391040Sarr		return (EPERM);
32462261Sarchie
32591040Sarr	lf = linker_find_file_by_name(filename);
32691040Sarr	if (lf) {
32791040Sarr		KLD_DPF(FILE, ("linker_load_file: file %s is already loaded,"
32891040Sarr		    " incrementing refs\n", filename));
32991040Sarr		*result = lf;
33091040Sarr		lf->refs++;
33191040Sarr		goto out;
33291040Sarr	}
33391040Sarr	lf = NULL;
33491040Sarr	foundfile = 0;
33598452Sarr
33698452Sarr	/*
33798452Sarr	 * We do not need to protect (lock) classes here because there is
33898452Sarr	 * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY)
33998452Sarr	 * and there is no class deregistration mechanism at this time.
34098452Sarr	 */
34191040Sarr	TAILQ_FOREACH(lc, &classes, link) {
34291040Sarr		KLD_DPF(FILE, ("linker_load_file: trying to load %s\n",
34391040Sarr		    filename));
34491040Sarr		error = LINKER_LOAD_FILE(lc, filename, &lf);
34591040Sarr		/*
34691040Sarr		 * If we got something other than ENOENT, then it exists but
34791040Sarr		 * we cannot load it for some other reason.
34891040Sarr		 */
34991040Sarr		if (error != ENOENT)
35091040Sarr			foundfile = 1;
35191040Sarr		if (lf) {
35291040Sarr			linker_file_register_modules(lf);
35391040Sarr			linker_file_register_sysctls(lf);
35491040Sarr			linker_file_sysinit(lf);
35591040Sarr			lf->flags |= LINKER_FILE_LINKED;
35691040Sarr			*result = lf;
35791040Sarr			error = 0;
35891040Sarr			goto out;
35991040Sarr		}
36091040Sarr	}
36142755Speter	/*
36291040Sarr	 * Less than ideal, but tells the user whether it failed to load or
36391040Sarr	 * the module was not found.
36442755Speter	 */
36591040Sarr	if (foundfile)
36691068Sarr		/* Format not recognized (or unloadable). */
36791068Sarr		error = ENOEXEC;
36891040Sarr	else
36991068Sarr		error = ENOENT;		/* Nothing found */
37025537Sdfrout:
37191040Sarr	return (error);
37225537Sdfr}
37325537Sdfr
37478413Sbrianint
37594321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo,
37694321Sbrian    linker_file_t *result)
37778413Sbrian{
37894321Sbrian	modlist_t mod;
37994321Sbrian
38094321Sbrian	if ((mod = modlist_lookup2(modname, verinfo)) != NULL) {
38194321Sbrian		*result = mod->container;
38294321Sbrian		(*result)->refs++;
38394321Sbrian		return (0);
38494321Sbrian	}
38594321Sbrian
38694321Sbrian	return (linker_load_module(NULL, modname, NULL, verinfo, result));
38778413Sbrian}
38878413Sbrian
38925537Sdfrlinker_file_t
39091040Sarrlinker_find_file_by_name(const char *filename)
39125537Sdfr{
39291040Sarr	linker_file_t lf = 0;
39391040Sarr	char *koname;
39425537Sdfr
39591040Sarr	koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
39691040Sarr	if (koname == NULL)
39791040Sarr		goto out;
39891040Sarr	sprintf(koname, "%s.ko", filename);
39940861Speter
40098452Sarr	mtx_lock(&kld_mtx);
40191040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
40292032Sdwmalone		if (strcmp(lf->filename, koname) == 0)
40391040Sarr			break;
40492032Sdwmalone		if (strcmp(lf->filename, filename) == 0)
40591040Sarr			break;
40691040Sarr	}
40798452Sarr	mtx_unlock(&kld_mtx);
40840861Speterout:
40991040Sarr	if (koname)
41091040Sarr		free(koname, M_LINKER);
41191040Sarr	return (lf);
41225537Sdfr}
41325537Sdfr
41425537Sdfrlinker_file_t
41525537Sdfrlinker_find_file_by_id(int fileid)
41625537Sdfr{
41791040Sarr	linker_file_t lf = 0;
41898452Sarr
41998452Sarr	mtx_lock(&kld_mtx);
42091040Sarr	TAILQ_FOREACH(lf, &linker_files, link)
42191040Sarr		if (lf->id == fileid)
42291040Sarr			break;
42398452Sarr	mtx_unlock(&kld_mtx);
42491040Sarr	return (lf);
42525537Sdfr}
42625537Sdfr
42725537Sdfrlinker_file_t
42891040Sarrlinker_make_file(const char *pathname, linker_class_t lc)
42925537Sdfr{
43091040Sarr	linker_file_t lf;
43191040Sarr	const char *filename;
43225537Sdfr
43391040Sarr	lf = NULL;
43491040Sarr	filename = linker_basename(pathname);
43540159Speter
43691040Sarr	KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
43791040Sarr	lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
43891040Sarr	if (lf == NULL)
43991040Sarr		goto out;
44091040Sarr	lf->refs = 1;
44191040Sarr	lf->userrefs = 0;
44291040Sarr	lf->flags = 0;
44391040Sarr	lf->filename = linker_strdup(filename);
44491040Sarr	LINKER_GET_NEXT_FILE_ID(lf->id);
44591040Sarr	lf->ndeps = 0;
44691040Sarr	lf->deps = NULL;
44791040Sarr	STAILQ_INIT(&lf->common);
44891040Sarr	TAILQ_INIT(&lf->modules);
44998452Sarr	mtx_lock(&kld_mtx);
45091040Sarr	TAILQ_INSERT_TAIL(&linker_files, lf, link);
45198452Sarr	mtx_unlock(&kld_mtx);
45225537Sdfrout:
45391040Sarr	return (lf);
45425537Sdfr}
45525537Sdfr
45625537Sdfrint
45725537Sdfrlinker_file_unload(linker_file_t file)
45825537Sdfr{
45991040Sarr	module_t mod, next;
46091040Sarr	modlist_t ml, nextml;
46191040Sarr	struct common_symbol *cp;
46291040Sarr	int error, i;
46325537Sdfr
46491040Sarr	error = 0;
46562261Sarchie
46691040Sarr	/* Refuse to unload modules if securelevel raised. */
46791040Sarr	if (securelevel > 0)
46891040Sarr		return (EPERM);
46925537Sdfr
47091040Sarr	KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
47191040Sarr	if (file->refs == 1) {
47291040Sarr		KLD_DPF(FILE, ("linker_file_unload: file is unloading,"
47391040Sarr		    " informing modules\n"));
47491040Sarr
47591040Sarr		/*
47691040Sarr		 * Inform any modules associated with this file.
47791040Sarr		 */
47892547Sarr		MOD_XLOCK;
47991040Sarr		for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
48091040Sarr			next = module_getfnext(mod);
48192547Sarr			MOD_XUNLOCK;
48291040Sarr
48391040Sarr			/*
48491040Sarr			 * Give the module a chance to veto the unload.
48591040Sarr			 */
48691040Sarr			if ((error = module_unload(mod)) != 0) {
48791040Sarr				KLD_DPF(FILE, ("linker_file_unload: module %x"
48891040Sarr				    " vetoes unload\n", mod));
48991040Sarr				goto out;
49092547Sarr			} else
49192547Sarr				MOD_XLOCK;
49291040Sarr			module_release(mod);
49391040Sarr		}
49492547Sarr		MOD_XUNLOCK;
49591040Sarr	}
49691040Sarr	file->refs--;
49791040Sarr	if (file->refs > 0) {
49825537Sdfr		goto out;
49991040Sarr	}
50091040Sarr	for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
50191040Sarr		nextml = TAILQ_NEXT(ml, link);
50291040Sarr		if (ml->container == file)
50391040Sarr			TAILQ_REMOVE(&found_modules, ml, link);
50491040Sarr	}
50525537Sdfr
50691040Sarr	/*
50791040Sarr	 * Don't try to run SYSUNINITs if we are unloaded due to a
50891040Sarr	 * link error.
50991040Sarr	 */
51091040Sarr	if (file->flags & LINKER_FILE_LINKED) {
51191040Sarr		linker_file_sysuninit(file);
51291040Sarr		linker_file_unregister_sysctls(file);
51325537Sdfr	}
51498452Sarr	mtx_lock(&kld_mtx);
51591040Sarr	TAILQ_REMOVE(&linker_files, file, link);
51698452Sarr	mtx_unlock(&kld_mtx);
51725537Sdfr
51891040Sarr	if (file->deps) {
51991040Sarr		for (i = 0; i < file->ndeps; i++)
52091040Sarr			linker_file_unload(file->deps[i]);
52191040Sarr		free(file->deps, M_LINKER);
52291040Sarr		file->deps = NULL;
52359751Speter	}
52491040Sarr	for (cp = STAILQ_FIRST(&file->common); cp;
52591068Sarr	    cp = STAILQ_FIRST(&file->common)) {
52691040Sarr		STAILQ_REMOVE(&file->common, cp, common_symbol, link);
52791040Sarr		free(cp, M_LINKER);
52891040Sarr	}
52959751Speter
53091040Sarr	LINKER_UNLOAD(file);
53191040Sarr	if (file->filename) {
53291040Sarr		free(file->filename, M_LINKER);
53391040Sarr		file->filename = NULL;
53491040Sarr	}
53591040Sarr	kobj_delete((kobj_t) file, M_LINKER);
53625537Sdfrout:
53791040Sarr	return (error);
53825537Sdfr}
53925537Sdfr
54025537Sdfrint
54186469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep)
54225537Sdfr{
54391040Sarr	linker_file_t *newdeps;
54425537Sdfr
54591040Sarr	newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *),
54691040Sarr	    M_LINKER, M_WAITOK | M_ZERO);
54791040Sarr	if (newdeps == NULL)
54891040Sarr		return (ENOMEM);
54925537Sdfr
55091040Sarr	if (file->deps) {
55191040Sarr		bcopy(file->deps, newdeps,
55291040Sarr		    file->ndeps * sizeof(linker_file_t *));
55391040Sarr		free(file->deps, M_LINKER);
55491040Sarr	}
55591040Sarr	file->deps = newdeps;
55691040Sarr	file->deps[file->ndeps] = dep;
55791040Sarr	file->ndeps++;
55891040Sarr	return (0);
55925537Sdfr}
56025537Sdfr
56178161Speter/*
56291040Sarr * Locate a linker set and its contents.  This is a helper function to avoid
56391040Sarr * linker_if.h exposure elsewhere.  Note: firstp and lastp are really void ***
56478161Speter */
56578161Speterint
56678161Speterlinker_file_lookup_set(linker_file_t file, const char *name,
56791040Sarr    void *firstp, void *lastp, int *countp)
56878161Speter{
56978161Speter
57091040Sarr	return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp));
57178161Speter}
57278161Speter
57325537Sdfrcaddr_t
57491040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
57525537Sdfr{
57691040Sarr	c_linker_sym_t sym;
57791040Sarr	linker_symval_t symval;
57891040Sarr	caddr_t address;
57991040Sarr	size_t common_size = 0;
58092032Sdwmalone	int i;
58125537Sdfr
58291040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
58391040Sarr	    file, name, deps));
58425537Sdfr
58591040Sarr	if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
58691040Sarr		LINKER_SYMBOL_VALUES(file, sym, &symval);
58791040Sarr		if (symval.value == 0)
58891040Sarr			/*
58991040Sarr			 * For commons, first look them up in the
59091040Sarr			 * dependencies and only allocate space if not found
59191040Sarr			 * there.
59291040Sarr			 */
59391040Sarr			common_size = symval.size;
59491040Sarr		else {
59591040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol"
59691040Sarr			    ".value=%x\n", symval.value));
59791040Sarr			return (symval.value);
59891040Sarr		}
59940159Speter	}
60091040Sarr	if (deps) {
60191040Sarr		for (i = 0; i < file->ndeps; i++) {
60291040Sarr			address = linker_file_lookup_symbol(file->deps[i],
60391040Sarr			    name, 0);
60491040Sarr			if (address) {
60591040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
60691040Sarr				    " deps value=%x\n", address));
60791040Sarr				return (address);
60891040Sarr			}
60991040Sarr		}
61025537Sdfr	}
61191040Sarr	if (common_size > 0) {
61291040Sarr		/*
61391040Sarr		 * This is a common symbol which was not found in the
61491040Sarr		 * dependencies.  We maintain a simple common symbol table in
61591040Sarr		 * the file object.
61691040Sarr		 */
61791040Sarr		struct common_symbol *cp;
61842849Speter
61991040Sarr		STAILQ_FOREACH(cp, &file->common, link) {
62092032Sdwmalone			if (strcmp(cp->name, name) == 0) {
62191040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
62291040Sarr				    " old common value=%x\n", cp->address));
62391040Sarr				return (cp->address);
62491040Sarr			}
62591040Sarr		}
62691040Sarr		/*
62791040Sarr		 * Round the symbol size up to align.
62891040Sarr		 */
62991040Sarr		common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
63091040Sarr		cp = malloc(sizeof(struct common_symbol)
63191040Sarr		    + common_size + strlen(name) + 1, M_LINKER,
63291040Sarr		    M_WAITOK | M_ZERO);
63391040Sarr		if (cp == NULL) {
63491040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
63591040Sarr			return (0);
63691040Sarr		}
63791040Sarr		cp->address = (caddr_t)(cp + 1);
63891040Sarr		cp->name = cp->address + common_size;
63991040Sarr		strcpy(cp->name, name);
64091040Sarr		bzero(cp->address, common_size);
64191040Sarr		STAILQ_INSERT_TAIL(&file->common, cp, link);
64225537Sdfr
64391040Sarr		KLD_DPF(SYM, ("linker_file_lookup_symbol: new common"
64491040Sarr		    " value=%x\n", cp->address));
64591040Sarr		return (cp->address);
64640159Speter	}
64791040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
64891040Sarr	return (0);
64925537Sdfr}
65025537Sdfr
65140159Speter#ifdef DDB
65225537Sdfr/*
65391040Sarr * DDB Helpers.  DDB has to look across multiple files with their own symbol
65491040Sarr * tables and string tables.
65591040Sarr *
65691040Sarr * Note that we do not obey list locking protocols here.  We really don't need
65791040Sarr * DDB to hang because somebody's got the lock held.  We'll take the chance
65891040Sarr * that the files list is inconsistant instead.
65940159Speter */
66040159Speter
66140159Speterint
66243309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
66340159Speter{
66491040Sarr	linker_file_t lf;
66540159Speter
66691040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
66791040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
66891040Sarr			return (0);
66991040Sarr	}
67091040Sarr	return (ENOENT);
67140159Speter}
67240159Speter
67340159Speterint
67443309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
67540159Speter{
67691040Sarr	linker_file_t lf;
67791040Sarr	c_linker_sym_t best, es;
67891040Sarr	u_long diff, bestdiff, off;
67940159Speter
68091040Sarr	best = 0;
68191040Sarr	off = (uintptr_t)value;
68291040Sarr	bestdiff = off;
68391040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
68491040Sarr		if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
68591040Sarr			continue;
68691040Sarr		if (es != 0 && diff < bestdiff) {
68791040Sarr			best = es;
68891040Sarr			bestdiff = diff;
68991040Sarr		}
69091040Sarr		if (bestdiff == 0)
69191040Sarr			break;
69240159Speter	}
69391040Sarr	if (best) {
69491040Sarr		*sym = best;
69591040Sarr		*diffp = bestdiff;
69691040Sarr		return (0);
69791040Sarr	} else {
69891040Sarr		*sym = 0;
69991040Sarr		*diffp = off;
70091040Sarr		return (ENOENT);
70191040Sarr	}
70240159Speter}
70340159Speter
70440159Speterint
70543309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
70640159Speter{
70791040Sarr	linker_file_t lf;
70840159Speter
70991040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
71091040Sarr		if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
71191040Sarr			return (0);
71291040Sarr	}
71391040Sarr	return (ENOENT);
71440159Speter}
71540159Speter#endif
71640159Speter
71740159Speter/*
71825537Sdfr * Syscalls.
71925537Sdfr */
72082749Sdillon/*
72182749Sdillon * MPSAFE
72282749Sdillon */
72325537Sdfrint
72491040Sarrkldload(struct thread *td, struct kldload_args *uap)
72525537Sdfr{
72691040Sarr	char *kldname, *modname;
72791040Sarr	char *pathname = NULL;
72891040Sarr	linker_file_t lf;
72991040Sarr	int error = 0;
73025537Sdfr
73191040Sarr	td->td_retval[0] = -1;
73225537Sdfr
73391040Sarr	mtx_lock(&Giant);
73482749Sdillon
73593159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
73693159Sarr		goto out;
73793159Sarr
73893593Sjhb	if ((error = suser(td)) != 0)
73991040Sarr		goto out;
74025537Sdfr
74191040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
74291040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
74391040Sarr	    NULL)) != 0)
74491040Sarr		goto out;
74525537Sdfr
74691040Sarr	/*
74791040Sarr	 * If path do not contain qualified name or any dot in it
74891040Sarr	 * (kldname.ko, or kldname.ver.ko) treat it as interface
74991040Sarr	 * name.
75091040Sarr	 */
75191040Sarr	if (index(pathname, '/') || index(pathname, '.')) {
75291040Sarr		kldname = pathname;
75391040Sarr		modname = NULL;
75491040Sarr	} else {
75591040Sarr		kldname = NULL;
75691040Sarr		modname = pathname;
75791040Sarr	}
75891040Sarr	error = linker_load_module(kldname, modname, NULL, NULL, &lf);
75991040Sarr	if (error)
76091040Sarr		goto out;
76142316Smsmith
76291040Sarr	lf->userrefs++;
76391040Sarr	td->td_retval[0] = lf->id;
76425537Sdfrout:
76591040Sarr	if (pathname)
76691040Sarr		free(pathname, M_TEMP);
76791040Sarr	mtx_unlock(&Giant);
76891040Sarr	return (error);
76925537Sdfr}
77025537Sdfr
77182749Sdillon/*
77282749Sdillon * MPSAFE
77382749Sdillon */
77425537Sdfrint
77591040Sarrkldunload(struct thread *td, struct kldunload_args *uap)
77625537Sdfr{
77791040Sarr	linker_file_t lf;
77891040Sarr	int error = 0;
77925537Sdfr
78091040Sarr	mtx_lock(&Giant);
78182749Sdillon
78293159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
78393159Sarr		goto out;
78493159Sarr
78593593Sjhb	if ((error = suser(td)) != 0)
78691040Sarr		goto out;
78725537Sdfr
78891040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
78991040Sarr	if (lf) {
79091040Sarr		KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
79191040Sarr		if (lf->userrefs == 0) {
79291040Sarr			printf("kldunload: attempt to unload file that was"
79391040Sarr			    " loaded by the kernel\n");
79491040Sarr			error = EBUSY;
79591040Sarr			goto out;
79691040Sarr		}
79791068Sarr		lf->userrefs--;
79891040Sarr		error = linker_file_unload(lf);
79991040Sarr		if (error)
80091040Sarr			lf->userrefs++;
80191040Sarr	} else
80291040Sarr		error = ENOENT;
80325537Sdfrout:
80491068Sarr	mtx_unlock(&Giant);
80591068Sarr	return (error);
80625537Sdfr}
80725537Sdfr
80882749Sdillon/*
80982749Sdillon * MPSAFE
81082749Sdillon */
81125537Sdfrint
81291040Sarrkldfind(struct thread *td, struct kldfind_args *uap)
81325537Sdfr{
81491040Sarr	char *pathname;
81591040Sarr	const char *filename;
81691040Sarr	linker_file_t lf;
81791040Sarr	int error = 0;
81825537Sdfr
81991040Sarr	mtx_lock(&Giant);
82091040Sarr	td->td_retval[0] = -1;
82182749Sdillon
82291040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
82391040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
82491040Sarr	    NULL)) != 0)
82591040Sarr		goto out;
82625537Sdfr
82791040Sarr	filename = linker_basename(pathname);
82891040Sarr	lf = linker_find_file_by_name(filename);
82991040Sarr	if (lf)
83091040Sarr		td->td_retval[0] = lf->id;
83191040Sarr	else
83291040Sarr		error = ENOENT;
83325537Sdfrout:
83491040Sarr	if (pathname)
83591040Sarr		free(pathname, M_TEMP);
83691040Sarr	mtx_unlock(&Giant);
83791040Sarr	return (error);
83825537Sdfr}
83925537Sdfr
84082749Sdillon/*
84182749Sdillon * MPSAFE
84282749Sdillon */
84325537Sdfrint
84491040Sarrkldnext(struct thread *td, struct kldnext_args *uap)
84525537Sdfr{
84691040Sarr	linker_file_t lf;
84791040Sarr	int error = 0;
84825537Sdfr
84991040Sarr	mtx_lock(&Giant);
85082749Sdillon
85191040Sarr	if (SCARG(uap, fileid) == 0) {
85298452Sarr		mtx_lock(&kld_mtx);
85391040Sarr		if (TAILQ_FIRST(&linker_files))
85491040Sarr			td->td_retval[0] = TAILQ_FIRST(&linker_files)->id;
85591040Sarr		else
85691040Sarr			td->td_retval[0] = 0;
85798452Sarr		mtx_unlock(&kld_mtx);
85891040Sarr		goto out;
85991040Sarr	}
86091040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
86191040Sarr	if (lf) {
86291040Sarr		if (TAILQ_NEXT(lf, link))
86391040Sarr			td->td_retval[0] = TAILQ_NEXT(lf, link)->id;
86491040Sarr		else
86591040Sarr			td->td_retval[0] = 0;
86691040Sarr	} else
86791040Sarr		error = ENOENT;
86882749Sdillonout:
86991040Sarr	mtx_unlock(&Giant);
87091040Sarr	return (error);
87125537Sdfr}
87225537Sdfr
87382749Sdillon/*
87482749Sdillon * MPSAFE
87582749Sdillon */
87625537Sdfrint
87791040Sarrkldstat(struct thread *td, struct kldstat_args *uap)
87825537Sdfr{
87991040Sarr	linker_file_t lf;
88091040Sarr	int error = 0;
88191040Sarr	int namelen, version;
88291040Sarr	struct kld_file_stat *stat;
88325537Sdfr
88491040Sarr	mtx_lock(&Giant);
88582749Sdillon
88691040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
88791040Sarr	if (lf == NULL) {
88891040Sarr		error = ENOENT;
88991040Sarr		goto out;
89091040Sarr	}
89191040Sarr	stat = SCARG(uap, stat);
89225537Sdfr
89391040Sarr	/*
89491040Sarr	 * Check the version of the user's structure.
89591040Sarr	 */
89691040Sarr	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
89791040Sarr		goto out;
89891040Sarr	if (version != sizeof(struct kld_file_stat)) {
89991040Sarr		error = EINVAL;
90091040Sarr		goto out;
90191040Sarr	}
90291040Sarr	namelen = strlen(lf->filename) + 1;
90391040Sarr	if (namelen > MAXPATHLEN)
90491040Sarr		namelen = MAXPATHLEN;
90591040Sarr	if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
90691040Sarr		goto out;
90791040Sarr	if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
90891040Sarr		goto out;
90991040Sarr	if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
91091040Sarr		goto out;
91191040Sarr	if ((error = copyout(&lf->address, &stat->address,
91291040Sarr	    sizeof(caddr_t))) != 0)
91391040Sarr		goto out;
91491040Sarr	if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
91591040Sarr		goto out;
91625537Sdfr
91791040Sarr	td->td_retval[0] = 0;
91825537Sdfrout:
91991040Sarr	mtx_unlock(&Giant);
92091040Sarr	return (error);
92125537Sdfr}
92225537Sdfr
92382749Sdillon/*
92482749Sdillon * MPSAFE
92582749Sdillon */
92625537Sdfrint
92791040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
92825537Sdfr{
92991040Sarr	linker_file_t lf;
93091040Sarr	module_t mp;
93191040Sarr	int error = 0;
93225537Sdfr
93391040Sarr	mtx_lock(&Giant);
93491040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
93591040Sarr	if (lf) {
93692547Sarr		MOD_SLOCK;
93791040Sarr		mp = TAILQ_FIRST(&lf->modules);
93891040Sarr		if (mp != NULL)
93991040Sarr			td->td_retval[0] = module_getid(mp);
94091040Sarr		else
94191040Sarr			td->td_retval[0] = 0;
94292547Sarr		MOD_SUNLOCK;
94391040Sarr	} else
94491040Sarr		error = ENOENT;
94591040Sarr	mtx_unlock(&Giant);
94691040Sarr	return (error);
94725537Sdfr}
94840159Speter
94982749Sdillon/*
95082749Sdillon * MPSAFE
95182749Sdillon */
95241090Speterint
95383366Sjuliankldsym(struct thread *td, struct kldsym_args *uap)
95441090Speter{
95591040Sarr	char *symstr = NULL;
95691040Sarr	c_linker_sym_t sym;
95791040Sarr	linker_symval_t symval;
95891040Sarr	linker_file_t lf;
95991040Sarr	struct kld_sym_lookup lookup;
96091040Sarr	int error = 0;
96141090Speter
96291040Sarr	mtx_lock(&Giant);
96382749Sdillon
96491040Sarr	if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
96591040Sarr		goto out;
96691068Sarr	if (lookup.version != sizeof(lookup) ||
96791040Sarr	    SCARG(uap, cmd) != KLDSYM_LOOKUP) {
96891040Sarr		error = EINVAL;
96991040Sarr		goto out;
97091040Sarr	}
97191040Sarr	symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
97291040Sarr	if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
97391040Sarr		goto out;
97491040Sarr	if (SCARG(uap, fileid) != 0) {
97591040Sarr		lf = linker_find_file_by_id(SCARG(uap, fileid));
97691040Sarr		if (lf == NULL) {
97791040Sarr			error = ENOENT;
97891040Sarr			goto out;
97991040Sarr		}
98091040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
98191040Sarr		    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
98291040Sarr			lookup.symvalue = (uintptr_t) symval.value;
98391040Sarr			lookup.symsize = symval.size;
98491040Sarr			error = copyout(&lookup, SCARG(uap, data),
98591040Sarr			    sizeof(lookup));
98691040Sarr		} else
98791040Sarr			error = ENOENT;
98891040Sarr	} else {
98998452Sarr		mtx_lock(&kld_mtx);
99091040Sarr		TAILQ_FOREACH(lf, &linker_files, link) {
99191040Sarr			if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
99291040Sarr			    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
99391040Sarr				lookup.symvalue = (uintptr_t)symval.value;
99491040Sarr				lookup.symsize = symval.size;
99591040Sarr				error = copyout(&lookup, SCARG(uap, data),
99691040Sarr				    sizeof(lookup));
99791068Sarr				break;
99891040Sarr			}
99991040Sarr		}
100098452Sarr		mtx_unlock(&kld_mtx);
100191040Sarr		if (lf == NULL)
100291040Sarr			error = ENOENT;
100341090Speter	}
100441090Speterout:
100591040Sarr	if (symstr)
100691040Sarr		free(symstr, M_TEMP);
100791040Sarr	mtx_unlock(&Giant);
100891040Sarr	return (error);
100941090Speter}
101041090Speter
101140159Speter/*
101240159Speter * Preloaded module support
101340159Speter */
101440159Speter
101559751Speterstatic modlist_t
101674642Sbpmodlist_lookup(const char *name, int ver)
101759751Speter{
101891040Sarr	modlist_t mod;
101959751Speter
102091040Sarr	TAILQ_FOREACH(mod, &found_modules, link) {
102192032Sdwmalone		if (strcmp(mod->name, name) == 0 &&
102292032Sdwmalone		    (ver == 0 || mod->version == ver))
102391040Sarr			return (mod);
102491040Sarr	}
102591040Sarr	return (NULL);
102659751Speter}
102759751Speter
102874642Sbpstatic modlist_t
102983321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo)
103083321Speter{
103191040Sarr	modlist_t mod, bestmod;
103292032Sdwmalone	int ver;
103383321Speter
103491040Sarr	if (verinfo == NULL)
103591040Sarr		return (modlist_lookup(name, 0));
103691040Sarr	bestmod = NULL;
103791040Sarr	for (mod = TAILQ_FIRST(&found_modules); mod;
103891040Sarr	    mod = TAILQ_NEXT(mod, link)) {
103992032Sdwmalone		if (strcmp(mod->name, name) != 0)
104091040Sarr			continue;
104191040Sarr		ver = mod->version;
104291040Sarr		if (ver == verinfo->md_ver_preferred)
104391040Sarr			return (mod);
104491040Sarr		if (ver >= verinfo->md_ver_minimum &&
104591068Sarr		    ver <= verinfo->md_ver_maximum &&
104691068Sarr		    ver > bestmod->version)
104791040Sarr			bestmod = mod;
104891040Sarr	}
104991040Sarr	return (bestmod);
105083321Speter}
105183321Speter
105283321Speterstatic modlist_t
105378501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container)
105474642Sbp{
105591040Sarr	modlist_t mod;
105674642Sbp
105792705Sarr	mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO);
105891040Sarr	if (mod == NULL)
105991040Sarr		panic("no memory for module list");
106091040Sarr	mod->container = container;
106191040Sarr	mod->name = modname;
106291040Sarr	mod->version = version;
106391040Sarr	TAILQ_INSERT_TAIL(&found_modules, mod, link);
106491040Sarr	return (mod);
106574642Sbp}
106674642Sbp
106759751Speter/*
106859751Speter * This routine is cheap and nasty but will work for data pointers.
106959751Speter */
107059751Speterstatic void *
107178501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset)
107259751Speter{
107391040Sarr	return (lf->address + (uintptr_t)offset);
107459751Speter}
107559751Speter
107674642Sbp/*
107774642Sbp * Dereference MDT_VERSION metadata into module name and version
107874642Sbp */
107940159Speterstatic void
108074642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
108191040Sarr    const char **modname, int *version)
108274642Sbp{
108391040Sarr	struct mod_version *mvp;
108474642Sbp
108591040Sarr	if (modname)
108691040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
108791040Sarr	if (version) {
108891040Sarr		mvp = linker_reloc_ptr(lf, mp->md_data);
108991040Sarr		*version = mvp->mv_version;
109091040Sarr	}
109174642Sbp}
109274642Sbp
109374642Sbp/*
109474642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure
109574642Sbp */
109674642Sbpstatic void
109774642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
109891040Sarr    const char **modname, struct mod_depend **verinfo)
109974642Sbp{
110074642Sbp
110191040Sarr	if (modname)
110291040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
110391040Sarr	if (verinfo)
110491040Sarr		*verinfo = linker_reloc_ptr(lf, mp->md_data);
110574642Sbp}
110674642Sbp
110774642Sbpstatic void
110878161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start,
110991040Sarr    struct mod_metadata **stop, int preload)
111074642Sbp{
111191040Sarr	struct mod_metadata *mp, **mdp;
111291040Sarr	const char *modname;
111391040Sarr	int ver;
111474642Sbp
111591040Sarr	for (mdp = start; mdp < stop; mdp++) {
111691040Sarr		if (preload)
111791040Sarr			mp = *mdp;
111891040Sarr		else
111991040Sarr			mp = linker_reloc_ptr(lf, *mdp);
112091040Sarr		if (mp->md_type != MDT_VERSION)
112191040Sarr			continue;
112291040Sarr		if (preload) {
112391040Sarr			modname = mp->md_cval;
112491040Sarr			ver = ((struct mod_version *)mp->md_data)->mv_version;
112591040Sarr		} else
112691040Sarr	        	linker_mdt_version(lf, mp, &modname, &ver);
112791040Sarr		if (modlist_lookup(modname, ver) != NULL) {
112891040Sarr			printf("module %s already present!\n", modname);
112991040Sarr			/* XXX what can we do? this is a build error. :-( */
113091040Sarr			continue;
113191040Sarr		}
113291040Sarr		modlist_newmodule(modname, ver, lf);
113374642Sbp	}
113474642Sbp}
113574642Sbp
113674642Sbpstatic void
113791040Sarrlinker_preload(void *arg)
113840159Speter{
113991040Sarr	caddr_t modptr;
114091040Sarr	const char *modname, *nmodname;
114191040Sarr	char *modtype;
114291040Sarr	linker_file_t lf;
114391040Sarr	linker_class_t lc;
114492032Sdwmalone	int error;
114591040Sarr	linker_file_list_t loaded_files;
114691040Sarr	linker_file_list_t depended_files;
114791040Sarr	struct mod_metadata *mp, *nmp;
114891040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
114991040Sarr	struct mod_depend *verinfo;
115091040Sarr	int nver;
115191040Sarr	int resolves;
115291040Sarr	modlist_t mod;
115391040Sarr	struct sysinit **si_start, **si_stop;
115440159Speter
115591040Sarr	TAILQ_INIT(&loaded_files);
115691040Sarr	TAILQ_INIT(&depended_files);
115791040Sarr	TAILQ_INIT(&found_modules);
115891040Sarr	error = 0;
115959751Speter
116091040Sarr	modptr = NULL;
116191040Sarr	while ((modptr = preload_search_next_name(modptr)) != NULL) {
116291040Sarr		modname = (char *)preload_search_info(modptr, MODINFO_NAME);
116391040Sarr		modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
116491040Sarr		if (modname == NULL) {
116591040Sarr			printf("Preloaded module at %p does not have a"
116691040Sarr			    " name!\n", modptr);
116791040Sarr			continue;
116891040Sarr		}
116991040Sarr		if (modtype == NULL) {
117091040Sarr			printf("Preloaded module at %p does not have a type!\n",
117191040Sarr			    modptr);
117291040Sarr			continue;
117391040Sarr		}
117491040Sarr		printf("Preloaded %s \"%s\" at %p.\n", modtype, modname,
117591040Sarr		    modptr);
117640159Speter		lf = NULL;
117791040Sarr		TAILQ_FOREACH(lc, &classes, link) {
117891040Sarr			error = LINKER_LINK_PRELOAD(lc, modname, &lf);
117991040Sarr			if (error) {
118091040Sarr				lf = NULL;
118191040Sarr				break;
118291040Sarr			}
118391040Sarr		}
118491040Sarr		if (lf)
118591040Sarr			TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
118640159Speter	}
118740159Speter
118891040Sarr	/*
118991040Sarr	 * First get a list of stuff in the kernel.
119091040Sarr	 */
119191040Sarr	if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start,
119291040Sarr	    &stop, NULL) == 0)
119391040Sarr		linker_addmodules(linker_kernel_file, start, stop, 1);
119459751Speter
119559751Speter	/*
119691040Sarr	 * this is a once-off kinky bubble sort resolve relocation dependency
119791040Sarr	 * requirements
119859751Speter	 */
119991040Sarrrestart:
120091040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
120191040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
120291040Sarr		    &stop, NULL);
120391040Sarr		/*
120491040Sarr		 * First, look to see if we would successfully link with this
120591040Sarr		 * stuff.
120691040Sarr		 */
120791040Sarr		resolves = 1;	/* unless we know otherwise */
120891040Sarr		if (!error) {
120991040Sarr			for (mdp = start; mdp < stop; mdp++) {
121091040Sarr				mp = linker_reloc_ptr(lf, *mdp);
121191040Sarr				if (mp->md_type != MDT_DEPEND)
121291040Sarr					continue;
121391040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
121491040Sarr				for (nmdp = start; nmdp < stop; nmdp++) {
121591040Sarr					nmp = linker_reloc_ptr(lf, *nmdp);
121691040Sarr					if (nmp->md_type != MDT_VERSION)
121791040Sarr						continue;
121891040Sarr					linker_mdt_version(lf, nmp, &nmodname,
121991040Sarr					    NULL);
122091040Sarr					nmodname = linker_reloc_ptr(lf,
122191040Sarr					    nmp->md_cval);
122292032Sdwmalone					if (strcmp(modname, nmodname) == 0)
122391040Sarr						break;
122491040Sarr				}
122591040Sarr				if (nmdp < stop)   /* it's a self reference */
122691040Sarr					continue;
122791040Sarr
122891040Sarr				/*
122991040Sarr				 * ok, the module isn't here yet, we
123091040Sarr				 * are not finished
123191040Sarr				 */
123291068Sarr				if (modlist_lookup2(modname, verinfo) == NULL)
123391040Sarr					resolves = 0;
123491040Sarr			}
123564143Speter		}
123691040Sarr		/*
123791040Sarr		 * OK, if we found our modules, we can link.  So, "provide"
123891040Sarr		 * the modules inside and add it to the end of the link order
123991040Sarr		 * list.
124091040Sarr		 */
124191040Sarr		if (resolves) {
124291040Sarr			if (!error) {
124391040Sarr				for (mdp = start; mdp < stop; mdp++) {
124491040Sarr					mp = linker_reloc_ptr(lf, *mdp);
124591040Sarr					if (mp->md_type != MDT_VERSION)
124691040Sarr						continue;
124791040Sarr					linker_mdt_version(lf, mp,
124891040Sarr					    &modname, &nver);
124991040Sarr					if (modlist_lookup(modname,
125091040Sarr					    nver) != NULL) {
125191040Sarr						printf("module %s already"
125291040Sarr						    " present!\n", modname);
125391040Sarr						linker_file_unload(lf);
125491040Sarr						TAILQ_REMOVE(&loaded_files,
125591040Sarr						    lf, loaded);
125691040Sarr						/* we changed tailq next ptr */
125791068Sarr						goto restart;
125891040Sarr					}
125991040Sarr					modlist_newmodule(modname, nver, lf);
126091040Sarr				}
126191040Sarr			}
126291040Sarr			TAILQ_REMOVE(&loaded_files, lf, loaded);
126391040Sarr			TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
126491040Sarr			/*
126591040Sarr			 * Since we provided modules, we need to restart the
126691040Sarr			 * sort so that the previous files that depend on us
126791040Sarr			 * have a chance. Also, we've busted the tailq next
126891040Sarr			 * pointer with the REMOVE.
126991040Sarr			 */
127091040Sarr			goto restart;
127159751Speter		}
127259751Speter	}
127391040Sarr
127459751Speter	/*
127591040Sarr	 * At this point, we check to see what could not be resolved..
127659751Speter	 */
127791040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
127891040Sarr		printf("KLD file %s is missing dependencies\n", lf->filename);
127991040Sarr		linker_file_unload(lf);
128091040Sarr		TAILQ_REMOVE(&loaded_files, lf, loaded);
128140159Speter	}
128259751Speter
128378161Speter	/*
128491040Sarr	 * We made it. Finish off the linking in the order we determined.
128578161Speter	 */
128691040Sarr	TAILQ_FOREACH(lf, &depended_files, loaded) {
128791040Sarr		if (linker_kernel_file) {
128891040Sarr			linker_kernel_file->refs++;
128991040Sarr			error = linker_file_add_dependency(lf,
129091040Sarr			    linker_kernel_file);
129191040Sarr			if (error)
129291040Sarr				panic("cannot add dependency");
129391040Sarr		}
129491040Sarr		lf->userrefs++;	/* so we can (try to) kldunload it */
129591040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
129691040Sarr		    &stop, NULL);
129791040Sarr		if (!error) {
129891040Sarr			for (mdp = start; mdp < stop; mdp++) {
129991040Sarr				mp = linker_reloc_ptr(lf, *mdp);
130091040Sarr				if (mp->md_type != MDT_DEPEND)
130191040Sarr					continue;
130291040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
130391040Sarr				mod = modlist_lookup2(modname, verinfo);
130491040Sarr				mod->container->refs++;
130591040Sarr				error = linker_file_add_dependency(lf,
130691040Sarr				    mod->container);
130791040Sarr				if (error)
130891040Sarr					panic("cannot add dependency");
130991040Sarr			}
131091040Sarr		}
131191040Sarr		/*
131291040Sarr		 * Now do relocation etc using the symbol search paths
131391040Sarr		 * established by the dependencies
131491040Sarr		 */
131591040Sarr		error = LINKER_LINK_PRELOAD_FINISH(lf);
131691040Sarr		if (error) {
131791040Sarr			printf("KLD file %s - could not finalize loading\n",
131891040Sarr			    lf->filename);
131991040Sarr			linker_file_unload(lf);
132091040Sarr			continue;
132191040Sarr		}
132291040Sarr		linker_file_register_modules(lf);
132391040Sarr		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
132491040Sarr		    &si_stop, NULL) == 0)
132591040Sarr			sysinit_add(si_start, si_stop);
132691040Sarr		linker_file_register_sysctls(lf);
132791040Sarr		lf->flags |= LINKER_FILE_LINKED;
132859751Speter	}
132991040Sarr	/* woohoo! we made it! */
133040159Speter}
133140159Speter
133291040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0)
133340159Speter
133440159Speter/*
133540159Speter * Search for a not-loaded module by name.
133691040Sarr *
133740159Speter * Modules may be found in the following locations:
133891040Sarr *
133991040Sarr * - preloaded (result is just the module name) - on disk (result is full path
134091040Sarr * to module)
134191040Sarr *
134291040Sarr * If the module name is qualified in any way (contains path, etc.) the we
134391040Sarr * simply return a copy of it.
134491040Sarr *
134540159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
134640159Speter * character as a separator to be consistent with the bootloader.
134740159Speter */
134840159Speter
134983321Speterstatic char linker_hintfile[] = "linker.hints";
135083358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules";
135140159Speter
135240159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
135391040Sarr    sizeof(linker_path), "module load search path");
135440159Speter
135577843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path));
135670417Speter
135759751Speterstatic char *linker_ext_list[] = {
135883321Speter	"",
135959751Speter	".ko",
136059751Speter	NULL
136159751Speter};
136259751Speter
136383321Speter/*
136491040Sarr * Check if file actually exists either with or without extension listed in
136591040Sarr * the linker_ext_list. (probably should be generic for the rest of the
136691040Sarr * kernel)
136783321Speter */
136859751Speterstatic char *
136991040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name,
137091040Sarr    int namelen, struct vattr *vap)
137140159Speter{
137291040Sarr	struct nameidata nd;
137391040Sarr	struct thread *td = curthread;	/* XXX */
137491040Sarr	char *result, **cpp, *sep;
137591040Sarr	int error, len, extlen, reclen, flags;
137691040Sarr	enum vtype type;
137740159Speter
137891040Sarr	extlen = 0;
137991040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
138091040Sarr		len = strlen(*cpp);
138191040Sarr		if (len > extlen)
138291040Sarr			extlen = len;
138391040Sarr	}
138491040Sarr	extlen++;		/* trailing '\0' */
138591040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
138683321Speter
138791040Sarr	reclen = pathlen + strlen(sep) + namelen + extlen + 1;
138891040Sarr	result = malloc(reclen, M_LINKER, M_WAITOK);
138991040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
139091040Sarr		snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep,
139191040Sarr		    namelen, name, *cpp);
139291040Sarr		/*
139391040Sarr		 * Attempt to open the file, and return the path if
139491040Sarr		 * we succeed and it's a regular file.
139591040Sarr		 */
139691040Sarr		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td);
139791040Sarr		flags = FREAD;
139891040Sarr		error = vn_open(&nd, &flags, 0);
139991040Sarr		if (error == 0) {
140091040Sarr			NDFREE(&nd, NDF_ONLY_PNBUF);
140191040Sarr			type = nd.ni_vp->v_type;
140291040Sarr			if (vap)
140391406Sjhb				VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
140491040Sarr			VOP_UNLOCK(nd.ni_vp, 0, td);
140591406Sjhb			vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
140691040Sarr			if (type == VREG)
140791040Sarr				return (result);
140891040Sarr		}
140983321Speter	}
141091040Sarr	free(result, M_LINKER);
141191040Sarr	return (NULL);
141283321Speter}
141383321Speter
141491040Sarr#define	INT_ALIGN(base, ptr)	ptr =					\
141583321Speter	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
141683321Speter
141783321Speter/*
141891040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If
141991040Sarr * version specification is available, then try to find the best KLD.
142083321Speter * Otherwise just find the latest one.
142183321Speter */
142283321Speterstatic char *
142391040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname,
142491040Sarr    int modnamelen, struct mod_depend *verinfo)
142583321Speter{
142691040Sarr	struct thread *td = curthread;	/* XXX */
142791406Sjhb	struct ucred *cred = td ? td->td_ucred : NULL;
142891040Sarr	struct nameidata nd;
142991040Sarr	struct vattr vattr, mattr;
143091040Sarr	u_char *hints = NULL;
143191040Sarr	u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep;
143291040Sarr	int error, ival, bestver, *intp, reclen, found, flags, clen, blen;
143383321Speter
143491040Sarr	result = NULL;
143591040Sarr	bestver = found = 0;
143683321Speter
143791040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
143891040Sarr	reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen +
143991040Sarr	    strlen(sep) + 1;
144091040Sarr	pathbuf = malloc(reclen, M_LINKER, M_WAITOK);
144191040Sarr	snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep,
144291040Sarr	    linker_hintfile);
144383321Speter
144491040Sarr	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td);
144591040Sarr	flags = FREAD;
144691040Sarr	error = vn_open(&nd, &flags, 0);
144791040Sarr	if (error)
144891040Sarr		goto bad;
144991040Sarr	NDFREE(&nd, NDF_ONLY_PNBUF);
145091040Sarr	if (nd.ni_vp->v_type != VREG)
145191040Sarr		goto bad;
145291040Sarr	best = cp = NULL;
145391040Sarr	error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td);
145491040Sarr	if (error)
145591040Sarr		goto bad;
145691040Sarr	/*
145791040Sarr	 * XXX: we need to limit this number to some reasonable value
145891040Sarr	 */
145991040Sarr	if (vattr.va_size > 100 * 1024) {
146091040Sarr		printf("hints file too large %ld\n", (long)vattr.va_size);
146191040Sarr		goto bad;
146291040Sarr	}
146391040Sarr	hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
146491040Sarr	if (hints == NULL)
146591040Sarr		goto bad;
146691068Sarr	error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
1467101941Srwatson	    UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td);
146891040Sarr	if (error)
146991040Sarr		goto bad;
147099553Sjeff	VOP_UNLOCK(nd.ni_vp, 0, td);
147191040Sarr	vn_close(nd.ni_vp, FREAD, cred, td);
147291040Sarr	nd.ni_vp = NULL;
147391040Sarr	if (reclen != 0) {
147491040Sarr		printf("can't read %d\n", reclen);
147591040Sarr		goto bad;
147691040Sarr	}
147791040Sarr	intp = (int *)hints;
147883321Speter	ival = *intp++;
147991040Sarr	if (ival != LINKER_HINTS_VERSION) {
148091040Sarr		printf("hints file version mismatch %d\n", ival);
148191040Sarr		goto bad;
148283321Speter	}
148391040Sarr	bufend = hints + vattr.va_size;
148491040Sarr	recptr = (u_char *)intp;
148591040Sarr	clen = blen = 0;
148691040Sarr	while (recptr < bufend && !found) {
148791040Sarr		intp = (int *)recptr;
148891040Sarr		reclen = *intp++;
148991040Sarr		ival = *intp++;
149091040Sarr		cp = (char *)intp;
149191040Sarr		switch (ival) {
149291040Sarr		case MDT_VERSION:
149391040Sarr			clen = *cp++;
149491040Sarr			if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
149591040Sarr				break;
149691040Sarr			cp += clen;
149791040Sarr			INT_ALIGN(hints, cp);
149891040Sarr			ival = *(int *)cp;
149991040Sarr			cp += sizeof(int);
150091040Sarr			clen = *cp++;
150191040Sarr			if (verinfo == NULL ||
150291040Sarr			    ival == verinfo->md_ver_preferred) {
150391040Sarr				found = 1;
150491040Sarr				break;
150591040Sarr			}
150691040Sarr			if (ival >= verinfo->md_ver_minimum &&
150791040Sarr			    ival <= verinfo->md_ver_maximum &&
150891040Sarr			    ival > bestver) {
150991040Sarr				bestver = ival;
151091040Sarr				best = cp;
151191040Sarr				blen = clen;
151291040Sarr			}
151391040Sarr			break;
151491040Sarr		default:
151591040Sarr			break;
151691040Sarr		}
151791040Sarr		recptr += reclen + sizeof(int);
151891040Sarr	}
151983321Speter	/*
152091040Sarr	 * Finally check if KLD is in the place
152183321Speter	 */
152291040Sarr	if (found)
152391040Sarr		result = linker_lookup_file(path, pathlen, cp, clen, &mattr);
152491040Sarr	else if (best)
152591040Sarr		result = linker_lookup_file(path, pathlen, best, blen, &mattr);
152691040Sarr
152791040Sarr	/*
152891040Sarr	 * KLD is newer than hints file. What we should do now?
152991040Sarr	 */
153091040Sarr	if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >))
153191040Sarr		printf("warning: KLD '%s' is newer than the linker.hints"
153291040Sarr		    " file\n", result);
153383321Speterbad:
1534105167Sphk	free(pathbuf, M_LINKER);
153591040Sarr	if (hints)
153691040Sarr		free(hints, M_TEMP);
153799553Sjeff	if (nd.ni_vp != NULL) {
153899553Sjeff		VOP_UNLOCK(nd.ni_vp, 0, td);
153991040Sarr		vn_close(nd.ni_vp, FREAD, cred, td);
154099553Sjeff	}
154191040Sarr	/*
154291040Sarr	 * If nothing found or hints is absent - fallback to the old
154391040Sarr	 * way by using "kldname[.ko]" as module name.
154491040Sarr	 */
154591040Sarr	if (!found && !bestver && result == NULL)
154691040Sarr		result = linker_lookup_file(path, pathlen, modname,
154791040Sarr		    modnamelen, NULL);
154891040Sarr	return (result);
154983321Speter}
155083321Speter
155183321Speter/*
155283321Speter * Lookup KLD which contains requested module in the all directories.
155383321Speter */
155483321Speterstatic char *
155583321Speterlinker_search_module(const char *modname, int modnamelen,
155691040Sarr    struct mod_depend *verinfo)
155783321Speter{
155891040Sarr	char *cp, *ep, *result;
155983321Speter
156091040Sarr	/*
156191040Sarr	 * traverse the linker path
156291040Sarr	 */
156391040Sarr	for (cp = linker_path; *cp; cp = ep + 1) {
156491040Sarr		/* find the end of this component */
156591040Sarr		for (ep = cp; (*ep != 0) && (*ep != ';'); ep++);
156691068Sarr		result = linker_hints_lookup(cp, ep - cp, modname,
156791068Sarr		    modnamelen, verinfo);
156891040Sarr		if (result != NULL)
156991040Sarr			return (result);
157091040Sarr		if (*ep == 0)
157191040Sarr			break;
157291040Sarr	}
157391040Sarr	return (NULL);
157483321Speter}
157583321Speter
157683321Speter/*
157783321Speter * Search for module in all directories listed in the linker_path.
157883321Speter */
157983321Speterstatic char *
158083321Speterlinker_search_kld(const char *name)
158183321Speter{
158291040Sarr	char *cp, *ep, *result, **cpp;
158391040Sarr	int extlen, len;
158483321Speter
158591040Sarr	/* qualified at all? */
158691040Sarr	if (index(name, '/'))
158791040Sarr		return (linker_strdup(name));
158840159Speter
158991040Sarr	extlen = 0;
159091040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
159191040Sarr		len = strlen(*cpp);
159291040Sarr		if (len > extlen)
159391040Sarr			extlen = len;
159491040Sarr	}
159591040Sarr	extlen++;		/* trailing '\0' */
159659751Speter
159791040Sarr	/* traverse the linker path */
159891040Sarr	len = strlen(name);
159991040Sarr	for (ep = linker_path; *ep; ep++) {
160091040Sarr		cp = ep;
160191040Sarr		/* find the end of this component */
160291040Sarr		for (; *ep != 0 && *ep != ';'; ep++);
160391040Sarr		result = linker_lookup_file(cp, ep - cp, name, len, NULL);
160491040Sarr		if (result != NULL)
160591040Sarr			return (result);
160691040Sarr	}
160791040Sarr	return (NULL);
160840159Speter}
160959751Speter
161059751Speterstatic const char *
161191040Sarrlinker_basename(const char *path)
161259751Speter{
161391040Sarr	const char *filename;
161459751Speter
161591040Sarr	filename = rindex(path, '/');
161691040Sarr	if (filename == NULL)
161791040Sarr		return path;
161891040Sarr	if (filename[1])
161991040Sarr		filename++;
162091040Sarr	return (filename);
162159751Speter}
162259751Speter
162359751Speter/*
162491040Sarr * Find a file which contains given module and load it, if "parent" is not
162591040Sarr * NULL, register a reference to it.
162659751Speter */
1627101241Smuxint
162883321Speterlinker_load_module(const char *kldname, const char *modname,
162991040Sarr    struct linker_file *parent, struct mod_depend *verinfo,
163091040Sarr    struct linker_file **lfpp)
163159751Speter{
163291040Sarr	linker_file_t lfdep;
163391040Sarr	const char *filename;
163491040Sarr	char *pathname;
163591040Sarr	int error;
163659751Speter
163791040Sarr	if (modname == NULL) {
163891040Sarr		/*
163991040Sarr 		 * We have to load KLD
164091040Sarr 		 */
164191068Sarr		KASSERT(verinfo == NULL, ("linker_load_module: verinfo"
164291068Sarr		    " is not NULL"));
164391040Sarr		pathname = linker_search_kld(kldname);
164491040Sarr	} else {
164591040Sarr		if (modlist_lookup2(modname, verinfo) != NULL)
164691040Sarr			return (EEXIST);
164794322Sbrian		if (kldname != NULL)
164894322Sbrian			pathname = linker_strdup(kldname);
164995488Sbrian		else if (rootvnode == NULL)
165094322Sbrian			pathname = NULL;
165194322Sbrian		else
165291040Sarr			/*
165391040Sarr			 * Need to find a KLD with required module
165491040Sarr			 */
165591040Sarr			pathname = linker_search_module(modname,
165691040Sarr			    strlen(modname), verinfo);
165791040Sarr	}
165891040Sarr	if (pathname == NULL)
165991040Sarr		return (ENOENT);
166091040Sarr
166183321Speter	/*
166291040Sarr	 * Can't load more than one file with the same basename XXX:
166391040Sarr	 * Actually it should be possible to have multiple KLDs with
166491040Sarr	 * the same basename but different path because they can
166591040Sarr	 * provide different versions of the same modules.
166683321Speter	 */
166791040Sarr	filename = linker_basename(pathname);
166891040Sarr	if (linker_find_file_by_name(filename)) {
166991040Sarr		error = EEXIST;
167091040Sarr		goto out;
167183321Speter	}
167291040Sarr	do {
167391040Sarr		error = linker_load_file(pathname, &lfdep);
167491040Sarr		if (error)
167591040Sarr			break;
167691040Sarr		if (modname && verinfo &&
167791040Sarr		    modlist_lookup2(modname, verinfo) == NULL) {
167891040Sarr			linker_file_unload(lfdep);
167991040Sarr			error = ENOENT;
168091040Sarr			break;
168191040Sarr		}
168291040Sarr		if (parent) {
168391040Sarr			error = linker_file_add_dependency(parent, lfdep);
168491040Sarr			if (error)
168591040Sarr				break;
168691040Sarr		}
168791040Sarr		if (lfpp)
168891040Sarr			*lfpp = lfdep;
168991040Sarr	} while (0);
169059751Speterout:
169191040Sarr	if (pathname)
169291040Sarr		free(pathname, M_LINKER);
169391040Sarr	return (error);
169459751Speter}
169559751Speter
169659751Speter/*
169791040Sarr * This routine is responsible for finding dependencies of userland initiated
169891040Sarr * kldload(2)'s of files.
169959751Speter */
170059751Speterint
170186469Siedowselinker_load_dependencies(linker_file_t lf)
170259751Speter{
170391040Sarr	linker_file_t lfdep;
170491040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
170591040Sarr	struct mod_metadata *mp, *nmp;
170691040Sarr	struct mod_depend *verinfo;
170791040Sarr	modlist_t mod;
170891040Sarr	const char *modname, *nmodname;
170992032Sdwmalone	int ver, error = 0, count;
171059751Speter
171191040Sarr	/*
171291040Sarr	 * All files are dependant on /kernel.
171391040Sarr	 */
171491040Sarr	if (linker_kernel_file) {
171591040Sarr		linker_kernel_file->refs++;
171691040Sarr		error = linker_file_add_dependency(lf, linker_kernel_file);
171791040Sarr		if (error)
171891040Sarr			return (error);
171959751Speter	}
172091040Sarr	if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop,
172191040Sarr	    &count) != 0)
172291040Sarr		return (0);
172391040Sarr	for (mdp = start; mdp < stop; mdp++) {
172491040Sarr		mp = linker_reloc_ptr(lf, *mdp);
172591040Sarr		if (mp->md_type != MDT_VERSION)
172691040Sarr			continue;
172791040Sarr		linker_mdt_version(lf, mp, &modname, &ver);
172891040Sarr		mod = modlist_lookup(modname, ver);
172991040Sarr		if (mod != NULL) {
173091040Sarr			printf("interface %s.%d already present in the KLD"
173191040Sarr			    " '%s'!\n", modname, ver,
173291040Sarr			    mod->container->filename);
173391040Sarr			return (EEXIST);
173491040Sarr		}
173591040Sarr	}
173674642Sbp
173791040Sarr	for (mdp = start; mdp < stop; mdp++) {
173891040Sarr		mp = linker_reloc_ptr(lf, *mdp);
173991040Sarr		if (mp->md_type != MDT_DEPEND)
174091040Sarr			continue;
174191040Sarr		linker_mdt_depend(lf, mp, &modname, &verinfo);
174291040Sarr		nmodname = NULL;
174391040Sarr		for (nmdp = start; nmdp < stop; nmdp++) {
174491040Sarr			nmp = linker_reloc_ptr(lf, *nmdp);
174591040Sarr			if (nmp->md_type != MDT_VERSION)
174691040Sarr				continue;
174791040Sarr			nmodname = linker_reloc_ptr(lf, nmp->md_cval);
174892032Sdwmalone			if (strcmp(modname, nmodname) == 0)
174991040Sarr				break;
175091040Sarr		}
175191040Sarr		if (nmdp < stop)/* early exit, it's a self reference */
175291040Sarr			continue;
175391040Sarr		mod = modlist_lookup2(modname, verinfo);
175491040Sarr		if (mod) {	/* woohoo, it's loaded already */
175591040Sarr			lfdep = mod->container;
175691040Sarr			lfdep->refs++;
175791040Sarr			error = linker_file_add_dependency(lf, lfdep);
175891040Sarr			if (error)
175991040Sarr				break;
176091040Sarr			continue;
176191040Sarr		}
176291040Sarr		error = linker_load_module(NULL, modname, lf, verinfo, NULL);
176391040Sarr		if (error) {
176491040Sarr			printf("KLD %s: depends on %s - not available\n",
176591040Sarr			    lf->filename, modname);
176691040Sarr			break;
176791040Sarr		}
176859751Speter	}
176959751Speter
177091040Sarr	if (error)
177191040Sarr		return (error);
177291040Sarr	linker_addmodules(lf, start, stop, 0);
177391040Sarr	return (error);
177459751Speter}
177585736Sgreen
177685736Sgreenstatic int
177785736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque)
177885736Sgreen{
177985736Sgreen	struct sysctl_req *req;
178085736Sgreen
178185736Sgreen	req = opaque;
178285736Sgreen	return (SYSCTL_OUT(req, name, strlen(name) + 1));
178385736Sgreen}
178485736Sgreen
178585736Sgreen/*
178685736Sgreen * Export a nul-separated, double-nul-terminated list of all function names
178785736Sgreen * in the kernel.
178885736Sgreen */
178985736Sgreenstatic int
179085736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS)
179185736Sgreen{
179285736Sgreen	linker_file_t lf;
179385736Sgreen	int error;
179485736Sgreen
1795100488Struckman	sysctl_wire_old_buffer(req, 0);
179698452Sarr	mtx_lock(&kld_mtx);
179785736Sgreen	TAILQ_FOREACH(lf, &linker_files, link) {
179885736Sgreen		error = LINKER_EACH_FUNCTION_NAME(lf,
179985736Sgreen		    sysctl_kern_function_list_iterate, req);
180098452Sarr		if (error) {
180198452Sarr			mtx_unlock(&kld_mtx);
180285736Sgreen			return (error);
180398452Sarr		}
180485736Sgreen	}
180598452Sarr	mtx_unlock(&kld_mtx);
180685736Sgreen	return (SYSCTL_OUT(req, "", 1));
180785736Sgreen}
180885736Sgreen
180985736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD,
181091040Sarr    NULL, 0, sysctl_kern_function_list, "", "kernel function list");
1811