kern_linker.c revision 94321
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 94321 2002-04-10 01:13:57Z brian $
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
7125537Sdfrstatic struct lock lock;	/* lock for the file list */
7225537Sdfrstatic linker_class_list_t classes;
7350068Sgrogstatic linker_file_list_t linker_files;
7425537Sdfrstatic int next_file_id = 1;
7525537Sdfr
7686553Sarr#define	LINKER_GET_NEXT_FILE_ID(a) do {					\
7791040Sarr	linker_file_t lftmp;						\
7886553Sarr									\
7986553Sarrretry:									\
8091040Sarr	TAILQ_FOREACH(lftmp, &linker_files, link) {			\
8191040Sarr		if (next_file_id == lftmp->id) {			\
8291040Sarr			next_file_id++;					\
8391040Sarr			goto retry;					\
8491040Sarr		}							\
8591040Sarr	}								\
8691040Sarr	(a) = next_file_id;						\
8786553Sarr} while(0)
8886553Sarr
8986553Sarr
9059751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */
9160938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t;
9259751Speterstruct modlist {
9391040Sarr	TAILQ_ENTRY(modlist) link;	/* chain together all modules */
9491040Sarr	linker_file_t   container;
9591040Sarr	const char 	*name;
9691040Sarr	int             version;
9759751Speter};
9891040Sarrtypedef struct modlist *modlist_t;
9991040Sarrstatic modlisthead_t found_modules;
10059751Speter
10194321Sbrianstatic modlist_t	modlist_lookup2(const char *name,
10294321Sbrian			    struct mod_depend *verinfo);
10394321Sbrian
10459603Sdfrstatic char *
10559603Sdfrlinker_strdup(const char *str)
10659603Sdfr{
10791040Sarr	char *result;
10859603Sdfr
10991040Sarr	if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
11091040Sarr		strcpy(result, str);
11191040Sarr	return (result);
11259603Sdfr}
11359603Sdfr
11425537Sdfrstatic void
11591040Sarrlinker_init(void *arg)
11625537Sdfr{
11791040Sarr
11891040Sarr	lockinit(&lock, PVM, "klink", 0, 0);
11991040Sarr	TAILQ_INIT(&classes);
12091040Sarr	TAILQ_INIT(&linker_files);
12125537Sdfr}
12225537Sdfr
12391040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0)
12425537Sdfr
12525537Sdfrint
12659603Sdfrlinker_add_class(linker_class_t lc)
12725537Sdfr{
12891040Sarr
12991040Sarr	kobj_class_compile((kobj_class_t) lc);
13091040Sarr	TAILQ_INSERT_TAIL(&classes, lc, link);
13191040Sarr	return (0);
13225537Sdfr}
13325537Sdfr
13425537Sdfrstatic void
13525537Sdfrlinker_file_sysinit(linker_file_t lf)
13625537Sdfr{
13791040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
13825537Sdfr
13991040Sarr	KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
14091040Sarr	    lf->filename));
14125537Sdfr
14291040Sarr	if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
14391040Sarr		return;
14491040Sarr	/*
14591040Sarr	 * Perform a bubble sort of the system initialization objects by
14691040Sarr	 * their subsystem (primary key) and order (secondary key).
14791040Sarr	 *
14891040Sarr	 * Since some things care about execution order, this is the operation
14991040Sarr	 * which ensures continued function.
15091040Sarr	 */
15191040Sarr	for (sipp = start; sipp < stop; sipp++) {
15291040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
15391040Sarr			if ((*sipp)->subsystem < (*xipp)->subsystem ||
15491040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
15591040Sarr			    (*sipp)->order <= (*xipp)->order))
15691040Sarr				continue;	/* skip */
15791040Sarr			save = *sipp;
15891040Sarr			*sipp = *xipp;
15991040Sarr			*xipp = save;
16091040Sarr		}
16125537Sdfr	}
16225537Sdfr
16391040Sarr	/*
16491040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
16591040Sarr	 * Perform each task, and continue on to the next task.
16691040Sarr	 */
16791040Sarr	for (sipp = start; sipp < stop; sipp++) {
16891040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
16991040Sarr			continue;	/* skip dummy task(s) */
17025537Sdfr
17191040Sarr		/* Call function */
17291040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
17391040Sarr	}
17425537Sdfr}
17525537Sdfr
17641055Speterstatic void
17741055Speterlinker_file_sysuninit(linker_file_t lf)
17841055Speter{
17991040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
18041055Speter
18191040Sarr	KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
18291040Sarr	    lf->filename));
18341055Speter
18491068Sarr	if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop,
18591040Sarr	    NULL) != 0)
18691040Sarr		return;
18741055Speter
18891040Sarr	/*
18991040Sarr	 * Perform a reverse bubble sort of the system initialization objects
19091040Sarr	 * by their subsystem (primary key) and order (secondary key).
19191040Sarr	 *
19291040Sarr	 * Since some things care about execution order, this is the operation
19391040Sarr	 * which ensures continued function.
19491040Sarr	 */
19591040Sarr	for (sipp = start; sipp < stop; sipp++) {
19691040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
19791040Sarr			if ((*sipp)->subsystem > (*xipp)->subsystem ||
19891040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
19991040Sarr			    (*sipp)->order >= (*xipp)->order))
20091040Sarr				continue;	/* skip */
20191040Sarr			save = *sipp;
20291040Sarr			*sipp = *xipp;
20391040Sarr			*xipp = save;
20491040Sarr		}
20541055Speter	}
20641055Speter
20791040Sarr	/*
20891040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
20991040Sarr	 * Perform each task, and continue on to the next task.
21091040Sarr	 */
21191040Sarr	for (sipp = start; sipp < stop; sipp++) {
21291040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
21391040Sarr			continue;	/* skip dummy task(s) */
21441055Speter
21591040Sarr		/* Call function */
21691040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
21791040Sarr	}
21841055Speter}
21941055Speter
22044078Sdfrstatic void
22144078Sdfrlinker_file_register_sysctls(linker_file_t lf)
22244078Sdfr{
22391040Sarr	struct sysctl_oid **start, **stop, **oidp;
22444078Sdfr
22591040Sarr	KLD_DPF(FILE,
22691040Sarr	    ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
22791040Sarr	    lf->filename));
22844078Sdfr
22991040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
23091040Sarr		return;
23144078Sdfr
23291040Sarr	for (oidp = start; oidp < stop; oidp++)
23391040Sarr		sysctl_register_oid(*oidp);
23444078Sdfr}
23544078Sdfr
23644078Sdfrstatic void
23744078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
23844078Sdfr{
23991040Sarr	struct sysctl_oid **start, **stop, **oidp;
24044078Sdfr
24191040Sarr	KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs"
24291040Sarr	    " for %s\n", lf->filename));
24344078Sdfr
24491040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
24591040Sarr		return;
24644078Sdfr
24791040Sarr	for (oidp = start; oidp < stop; oidp++)
24891040Sarr		sysctl_unregister_oid(*oidp);
24944078Sdfr}
25044078Sdfr
25159751Speterstatic int
25259751Speterlinker_file_register_modules(linker_file_t lf)
25359751Speter{
25491040Sarr	struct mod_metadata **start, **stop, **mdp;
25591040Sarr	const moduledata_t *moddata;
25691040Sarr	int error;
25759751Speter
25891040Sarr	KLD_DPF(FILE, ("linker_file_register_modules: registering modules"
25991040Sarr	    " in %s\n", lf->filename));
26059751Speter
26191068Sarr	if (linker_file_lookup_set(lf, "modmetadata_set", &start,
26291040Sarr	    &stop, 0) != 0) {
26391040Sarr		/*
26491040Sarr		 * This fallback should be unnecessary, but if we get booted
26591040Sarr		 * from boot2 instead of loader and we are missing our
26691040Sarr		 * metadata then we have to try the best we can.
26791040Sarr		 */
26891040Sarr		if (lf == linker_kernel_file) {
26991040Sarr			start = SET_BEGIN(modmetadata_set);
27091040Sarr			stop = SET_LIMIT(modmetadata_set);
27191040Sarr		} else
27291040Sarr			return (0);
27378161Speter	}
27491040Sarr	for (mdp = start; mdp < stop; mdp++) {
27591040Sarr		if ((*mdp)->md_type != MDT_MODULE)
27691040Sarr			continue;
27791040Sarr		moddata = (*mdp)->md_data;
27891040Sarr		KLD_DPF(FILE, ("Registering module %s in %s\n",
27991040Sarr		    moddata->name, lf->filename));
28091040Sarr		error = module_register(moddata, lf);
28191040Sarr		if (error)
28291068Sarr			printf("Module %s failed to register: %d\n",
28391040Sarr			    moddata->name, error);
28459751Speter	}
28591040Sarr	return (0);
28659751Speter}
28759751Speter
28859751Speterstatic void
28959751Speterlinker_init_kernel_modules(void)
29059751Speter{
29191040Sarr
29291040Sarr	linker_file_register_modules(linker_kernel_file);
29359751Speter}
29459751Speter
29591040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0)
29659751Speter
29725537Sdfrint
29891040Sarrlinker_load_file(const char *filename, linker_file_t *result)
29925537Sdfr{
30091040Sarr	linker_class_t lc;
30191040Sarr	linker_file_t lf;
30291040Sarr	int foundfile, error = 0;
30325537Sdfr
30491040Sarr	/* Refuse to load modules if securelevel raised */
30591040Sarr	if (securelevel > 0)
30691040Sarr		return (EPERM);
30762261Sarchie
30891040Sarr	lf = linker_find_file_by_name(filename);
30991040Sarr	if (lf) {
31091040Sarr		KLD_DPF(FILE, ("linker_load_file: file %s is already loaded,"
31191040Sarr		    " incrementing refs\n", filename));
31291040Sarr		*result = lf;
31391040Sarr		lf->refs++;
31491040Sarr		goto out;
31591040Sarr	}
31691040Sarr	lf = NULL;
31791040Sarr	foundfile = 0;
31891040Sarr	TAILQ_FOREACH(lc, &classes, link) {
31991040Sarr		KLD_DPF(FILE, ("linker_load_file: trying to load %s\n",
32091040Sarr		    filename));
32191040Sarr		error = LINKER_LOAD_FILE(lc, filename, &lf);
32291040Sarr		/*
32391040Sarr		 * If we got something other than ENOENT, then it exists but
32491040Sarr		 * we cannot load it for some other reason.
32591040Sarr		 */
32691040Sarr		if (error != ENOENT)
32791040Sarr			foundfile = 1;
32891040Sarr		if (lf) {
32991040Sarr			linker_file_register_modules(lf);
33091040Sarr			linker_file_register_sysctls(lf);
33191040Sarr			linker_file_sysinit(lf);
33291040Sarr			lf->flags |= LINKER_FILE_LINKED;
33391040Sarr			*result = lf;
33491040Sarr			error = 0;
33591040Sarr			goto out;
33691040Sarr		}
33791040Sarr	}
33842755Speter	/*
33991040Sarr	 * Less than ideal, but tells the user whether it failed to load or
34091040Sarr	 * the module was not found.
34142755Speter	 */
34291040Sarr	if (foundfile)
34391068Sarr		/* Format not recognized (or unloadable). */
34491068Sarr		error = ENOEXEC;
34591040Sarr	else
34691068Sarr		error = ENOENT;		/* Nothing found */
34725537Sdfrout:
34891040Sarr	return (error);
34925537Sdfr}
35025537Sdfr
35178413Sbrianint
35294321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo,
35394321Sbrian    linker_file_t *result)
35478413Sbrian{
35594321Sbrian	modlist_t mod;
35694321Sbrian
35794321Sbrian	if ((mod = modlist_lookup2(modname, verinfo)) != NULL) {
35894321Sbrian		*result = mod->container;
35994321Sbrian		(*result)->refs++;
36094321Sbrian		return (0);
36194321Sbrian	}
36294321Sbrian
36394321Sbrian	return (linker_load_module(NULL, modname, NULL, verinfo, result));
36478413Sbrian}
36578413Sbrian
36625537Sdfrlinker_file_t
36791040Sarrlinker_find_file_by_name(const char *filename)
36825537Sdfr{
36991040Sarr	linker_file_t lf = 0;
37091040Sarr	char *koname;
37125537Sdfr
37291040Sarr	koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
37391040Sarr	if (koname == NULL)
37491040Sarr		goto out;
37591040Sarr	sprintf(koname, "%s.ko", filename);
37640861Speter
37791040Sarr	lockmgr(&lock, LK_SHARED, 0, curthread);
37891040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
37992032Sdwmalone		if (strcmp(lf->filename, koname) == 0)
38091040Sarr			break;
38192032Sdwmalone		if (strcmp(lf->filename, filename) == 0)
38291040Sarr			break;
38391040Sarr	}
38491040Sarr	lockmgr(&lock, LK_RELEASE, 0, curthread);
38540861Speterout:
38691040Sarr	if (koname)
38791040Sarr		free(koname, M_LINKER);
38891040Sarr	return (lf);
38925537Sdfr}
39025537Sdfr
39125537Sdfrlinker_file_t
39225537Sdfrlinker_find_file_by_id(int fileid)
39325537Sdfr{
39491040Sarr	linker_file_t lf = 0;
39525537Sdfr
39691040Sarr	lockmgr(&lock, LK_SHARED, 0, curthread);
39791040Sarr	TAILQ_FOREACH(lf, &linker_files, link)
39891040Sarr		if (lf->id == fileid)
39991040Sarr			break;
40091040Sarr	lockmgr(&lock, LK_RELEASE, 0, curthread);
40191040Sarr	return (lf);
40225537Sdfr}
40325537Sdfr
40425537Sdfrlinker_file_t
40591040Sarrlinker_make_file(const char *pathname, linker_class_t lc)
40625537Sdfr{
40791040Sarr	linker_file_t lf;
40891040Sarr	const char *filename;
40925537Sdfr
41091040Sarr	lf = NULL;
41191040Sarr	filename = linker_basename(pathname);
41240159Speter
41391040Sarr	KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
41491040Sarr	lockmgr(&lock, LK_EXCLUSIVE, 0, curthread);
41591040Sarr	lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
41691040Sarr	if (lf == NULL)
41791040Sarr		goto out;
41891040Sarr	lf->refs = 1;
41991040Sarr	lf->userrefs = 0;
42091040Sarr	lf->flags = 0;
42191040Sarr	lf->filename = linker_strdup(filename);
42291040Sarr	LINKER_GET_NEXT_FILE_ID(lf->id);
42391040Sarr	lf->ndeps = 0;
42491040Sarr	lf->deps = NULL;
42591040Sarr	STAILQ_INIT(&lf->common);
42691040Sarr	TAILQ_INIT(&lf->modules);
42791040Sarr	TAILQ_INSERT_TAIL(&linker_files, lf, link);
42825537Sdfrout:
42991040Sarr	lockmgr(&lock, LK_RELEASE, 0, curthread);
43091040Sarr	return (lf);
43125537Sdfr}
43225537Sdfr
43325537Sdfrint
43425537Sdfrlinker_file_unload(linker_file_t file)
43525537Sdfr{
43691040Sarr	module_t mod, next;
43791040Sarr	modlist_t ml, nextml;
43891040Sarr	struct common_symbol *cp;
43991040Sarr	int error, i;
44025537Sdfr
44191040Sarr	error = 0;
44262261Sarchie
44391040Sarr	/* Refuse to unload modules if securelevel raised. */
44491040Sarr	if (securelevel > 0)
44591040Sarr		return (EPERM);
44625537Sdfr
44791040Sarr	KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
44891040Sarr	lockmgr(&lock, LK_EXCLUSIVE, 0, curthread);
44991040Sarr	if (file->refs == 1) {
45091040Sarr		KLD_DPF(FILE, ("linker_file_unload: file is unloading,"
45191040Sarr		    " informing modules\n"));
45291040Sarr
45391040Sarr		/*
45491040Sarr		 * Inform any modules associated with this file.
45591040Sarr		 */
45692547Sarr		MOD_XLOCK;
45791040Sarr		for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
45891040Sarr			next = module_getfnext(mod);
45992547Sarr			MOD_XUNLOCK;
46091040Sarr
46191040Sarr			/*
46291040Sarr			 * Give the module a chance to veto the unload.
46391040Sarr			 */
46491040Sarr			if ((error = module_unload(mod)) != 0) {
46591040Sarr				KLD_DPF(FILE, ("linker_file_unload: module %x"
46691040Sarr				    " vetoes unload\n", mod));
46791040Sarr				lockmgr(&lock, LK_RELEASE, 0, curthread);
46891040Sarr				goto out;
46992547Sarr			} else
47092547Sarr				MOD_XLOCK;
47191040Sarr			module_release(mod);
47291040Sarr		}
47392547Sarr		MOD_XUNLOCK;
47491040Sarr	}
47591040Sarr	file->refs--;
47691040Sarr	if (file->refs > 0) {
47783366Sjulian		lockmgr(&lock, LK_RELEASE, 0, curthread);
47825537Sdfr		goto out;
47991040Sarr	}
48091040Sarr	for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
48191040Sarr		nextml = TAILQ_NEXT(ml, link);
48291040Sarr		if (ml->container == file)
48391040Sarr			TAILQ_REMOVE(&found_modules, ml, link);
48491040Sarr	}
48525537Sdfr
48691040Sarr	/*
48791040Sarr	 * Don't try to run SYSUNINITs if we are unloaded due to a
48891040Sarr	 * link error.
48991040Sarr	 */
49091040Sarr	if (file->flags & LINKER_FILE_LINKED) {
49191040Sarr		linker_file_sysuninit(file);
49291040Sarr		linker_file_unregister_sysctls(file);
49325537Sdfr	}
49491040Sarr	TAILQ_REMOVE(&linker_files, file, link);
49583366Sjulian	lockmgr(&lock, LK_RELEASE, 0, curthread);
49625537Sdfr
49791040Sarr	if (file->deps) {
49891040Sarr		for (i = 0; i < file->ndeps; i++)
49991040Sarr			linker_file_unload(file->deps[i]);
50091040Sarr		free(file->deps, M_LINKER);
50191040Sarr		file->deps = NULL;
50259751Speter	}
50391040Sarr	for (cp = STAILQ_FIRST(&file->common); cp;
50491068Sarr	    cp = STAILQ_FIRST(&file->common)) {
50591040Sarr		STAILQ_REMOVE(&file->common, cp, common_symbol, link);
50691040Sarr		free(cp, M_LINKER);
50791040Sarr	}
50859751Speter
50991040Sarr	LINKER_UNLOAD(file);
51091040Sarr	if (file->filename) {
51191040Sarr		free(file->filename, M_LINKER);
51291040Sarr		file->filename = NULL;
51391040Sarr	}
51491040Sarr	kobj_delete((kobj_t) file, M_LINKER);
51525537Sdfrout:
51691040Sarr	return (error);
51725537Sdfr}
51825537Sdfr
51925537Sdfrint
52086469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep)
52125537Sdfr{
52291040Sarr	linker_file_t *newdeps;
52325537Sdfr
52491040Sarr	newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *),
52591040Sarr	    M_LINKER, M_WAITOK | M_ZERO);
52691040Sarr	if (newdeps == NULL)
52791040Sarr		return (ENOMEM);
52825537Sdfr
52991040Sarr	if (file->deps) {
53091040Sarr		bcopy(file->deps, newdeps,
53191040Sarr		    file->ndeps * sizeof(linker_file_t *));
53291040Sarr		free(file->deps, M_LINKER);
53391040Sarr	}
53491040Sarr	file->deps = newdeps;
53591040Sarr	file->deps[file->ndeps] = dep;
53691040Sarr	file->ndeps++;
53791040Sarr	return (0);
53825537Sdfr}
53925537Sdfr
54078161Speter/*
54191040Sarr * Locate a linker set and its contents.  This is a helper function to avoid
54291040Sarr * linker_if.h exposure elsewhere.  Note: firstp and lastp are really void ***
54378161Speter */
54478161Speterint
54578161Speterlinker_file_lookup_set(linker_file_t file, const char *name,
54691040Sarr    void *firstp, void *lastp, int *countp)
54778161Speter{
54878161Speter
54991040Sarr	return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp));
55078161Speter}
55178161Speter
55225537Sdfrcaddr_t
55391040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
55425537Sdfr{
55591040Sarr	c_linker_sym_t sym;
55691040Sarr	linker_symval_t symval;
55791040Sarr	caddr_t address;
55891040Sarr	size_t common_size = 0;
55992032Sdwmalone	int i;
56025537Sdfr
56191040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
56291040Sarr	    file, name, deps));
56325537Sdfr
56491040Sarr	if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
56591040Sarr		LINKER_SYMBOL_VALUES(file, sym, &symval);
56691040Sarr		if (symval.value == 0)
56791040Sarr			/*
56891040Sarr			 * For commons, first look them up in the
56991040Sarr			 * dependencies and only allocate space if not found
57091040Sarr			 * there.
57191040Sarr			 */
57291040Sarr			common_size = symval.size;
57391040Sarr		else {
57491040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol"
57591040Sarr			    ".value=%x\n", symval.value));
57691040Sarr			return (symval.value);
57791040Sarr		}
57840159Speter	}
57991040Sarr	if (deps) {
58091040Sarr		for (i = 0; i < file->ndeps; i++) {
58191040Sarr			address = linker_file_lookup_symbol(file->deps[i],
58291040Sarr			    name, 0);
58391040Sarr			if (address) {
58491040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
58591040Sarr				    " deps value=%x\n", address));
58691040Sarr				return (address);
58791040Sarr			}
58891040Sarr		}
58925537Sdfr	}
59091040Sarr	if (common_size > 0) {
59191040Sarr		/*
59291040Sarr		 * This is a common symbol which was not found in the
59391040Sarr		 * dependencies.  We maintain a simple common symbol table in
59491040Sarr		 * the file object.
59591040Sarr		 */
59691040Sarr		struct common_symbol *cp;
59742849Speter
59891040Sarr		STAILQ_FOREACH(cp, &file->common, link) {
59992032Sdwmalone			if (strcmp(cp->name, name) == 0) {
60091040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
60191040Sarr				    " old common value=%x\n", cp->address));
60291040Sarr				return (cp->address);
60391040Sarr			}
60491040Sarr		}
60591040Sarr		/*
60691040Sarr		 * Round the symbol size up to align.
60791040Sarr		 */
60891040Sarr		common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
60991040Sarr		cp = malloc(sizeof(struct common_symbol)
61091040Sarr		    + common_size + strlen(name) + 1, M_LINKER,
61191040Sarr		    M_WAITOK | M_ZERO);
61291040Sarr		if (cp == NULL) {
61391040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
61491040Sarr			return (0);
61591040Sarr		}
61691040Sarr		cp->address = (caddr_t)(cp + 1);
61791040Sarr		cp->name = cp->address + common_size;
61891040Sarr		strcpy(cp->name, name);
61991040Sarr		bzero(cp->address, common_size);
62091040Sarr		STAILQ_INSERT_TAIL(&file->common, cp, link);
62125537Sdfr
62291040Sarr		KLD_DPF(SYM, ("linker_file_lookup_symbol: new common"
62391040Sarr		    " value=%x\n", cp->address));
62491040Sarr		return (cp->address);
62540159Speter	}
62691040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
62791040Sarr	return (0);
62825537Sdfr}
62925537Sdfr
63040159Speter#ifdef DDB
63125537Sdfr/*
63291040Sarr * DDB Helpers.  DDB has to look across multiple files with their own symbol
63391040Sarr * tables and string tables.
63491040Sarr *
63591040Sarr * Note that we do not obey list locking protocols here.  We really don't need
63691040Sarr * DDB to hang because somebody's got the lock held.  We'll take the chance
63791040Sarr * that the files list is inconsistant instead.
63840159Speter */
63940159Speter
64040159Speterint
64143309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
64240159Speter{
64391040Sarr	linker_file_t lf;
64440159Speter
64591040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
64691040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
64791040Sarr			return (0);
64891040Sarr	}
64991040Sarr	return (ENOENT);
65040159Speter}
65140159Speter
65240159Speterint
65343309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
65440159Speter{
65591040Sarr	linker_file_t lf;
65691040Sarr	c_linker_sym_t best, es;
65791040Sarr	u_long diff, bestdiff, off;
65840159Speter
65991040Sarr	best = 0;
66091040Sarr	off = (uintptr_t)value;
66191040Sarr	bestdiff = off;
66291040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
66391040Sarr		if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
66491040Sarr			continue;
66591040Sarr		if (es != 0 && diff < bestdiff) {
66691040Sarr			best = es;
66791040Sarr			bestdiff = diff;
66891040Sarr		}
66991040Sarr		if (bestdiff == 0)
67091040Sarr			break;
67140159Speter	}
67291040Sarr	if (best) {
67391040Sarr		*sym = best;
67491040Sarr		*diffp = bestdiff;
67591040Sarr		return (0);
67691040Sarr	} else {
67791040Sarr		*sym = 0;
67891040Sarr		*diffp = off;
67991040Sarr		return (ENOENT);
68091040Sarr	}
68140159Speter}
68240159Speter
68340159Speterint
68443309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
68540159Speter{
68691040Sarr	linker_file_t lf;
68740159Speter
68891040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
68991040Sarr		if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
69091040Sarr			return (0);
69191040Sarr	}
69291040Sarr	return (ENOENT);
69340159Speter}
69440159Speter#endif
69540159Speter
69640159Speter/*
69725537Sdfr * Syscalls.
69825537Sdfr */
69982749Sdillon/*
70082749Sdillon * MPSAFE
70182749Sdillon */
70225537Sdfrint
70391040Sarrkldload(struct thread *td, struct kldload_args *uap)
70425537Sdfr{
70591040Sarr	char *kldname, *modname;
70691040Sarr	char *pathname = NULL;
70791040Sarr	linker_file_t lf;
70891040Sarr	int error = 0;
70925537Sdfr
71091040Sarr	td->td_retval[0] = -1;
71125537Sdfr
71291040Sarr	mtx_lock(&Giant);
71382749Sdillon
71493159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
71593159Sarr		goto out;
71693159Sarr
71793593Sjhb	if ((error = suser(td)) != 0)
71891040Sarr		goto out;
71925537Sdfr
72091040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
72191040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
72291040Sarr	    NULL)) != 0)
72391040Sarr		goto out;
72425537Sdfr
72591040Sarr	/*
72691040Sarr	 * If path do not contain qualified name or any dot in it
72791040Sarr	 * (kldname.ko, or kldname.ver.ko) treat it as interface
72891040Sarr	 * name.
72991040Sarr	 */
73091040Sarr	if (index(pathname, '/') || index(pathname, '.')) {
73191040Sarr		kldname = pathname;
73291040Sarr		modname = NULL;
73391040Sarr	} else {
73491040Sarr		kldname = NULL;
73591040Sarr		modname = pathname;
73691040Sarr	}
73791040Sarr	error = linker_load_module(kldname, modname, NULL, NULL, &lf);
73891040Sarr	if (error)
73991040Sarr		goto out;
74042316Smsmith
74191040Sarr	lf->userrefs++;
74291040Sarr	td->td_retval[0] = lf->id;
74325537Sdfrout:
74491040Sarr	if (pathname)
74591040Sarr		free(pathname, M_TEMP);
74691040Sarr	mtx_unlock(&Giant);
74791040Sarr	return (error);
74825537Sdfr}
74925537Sdfr
75082749Sdillon/*
75182749Sdillon * MPSAFE
75282749Sdillon */
75325537Sdfrint
75491040Sarrkldunload(struct thread *td, struct kldunload_args *uap)
75525537Sdfr{
75691040Sarr	linker_file_t lf;
75791040Sarr	int error = 0;
75825537Sdfr
75991040Sarr	mtx_lock(&Giant);
76082749Sdillon
76193159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
76293159Sarr		goto out;
76393159Sarr
76493593Sjhb	if ((error = suser(td)) != 0)
76591040Sarr		goto out;
76625537Sdfr
76791040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
76891040Sarr	if (lf) {
76991040Sarr		KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
77091040Sarr		if (lf->userrefs == 0) {
77191040Sarr			printf("kldunload: attempt to unload file that was"
77291040Sarr			    " loaded by the kernel\n");
77391040Sarr			error = EBUSY;
77491040Sarr			goto out;
77591040Sarr		}
77691068Sarr		lf->userrefs--;
77791040Sarr		error = linker_file_unload(lf);
77891040Sarr		if (error)
77991040Sarr			lf->userrefs++;
78091040Sarr	} else
78191040Sarr		error = ENOENT;
78225537Sdfrout:
78391068Sarr	mtx_unlock(&Giant);
78491068Sarr	return (error);
78525537Sdfr}
78625537Sdfr
78782749Sdillon/*
78882749Sdillon * MPSAFE
78982749Sdillon */
79025537Sdfrint
79191040Sarrkldfind(struct thread *td, struct kldfind_args *uap)
79225537Sdfr{
79391040Sarr	char *pathname;
79491040Sarr	const char *filename;
79591040Sarr	linker_file_t lf;
79691040Sarr	int error = 0;
79725537Sdfr
79891040Sarr	mtx_lock(&Giant);
79991040Sarr	td->td_retval[0] = -1;
80082749Sdillon
80191040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
80291040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
80391040Sarr	    NULL)) != 0)
80491040Sarr		goto out;
80525537Sdfr
80691040Sarr	filename = linker_basename(pathname);
80791040Sarr	lf = linker_find_file_by_name(filename);
80891040Sarr	if (lf)
80991040Sarr		td->td_retval[0] = lf->id;
81091040Sarr	else
81191040Sarr		error = ENOENT;
81225537Sdfrout:
81391040Sarr	if (pathname)
81491040Sarr		free(pathname, M_TEMP);
81591040Sarr	mtx_unlock(&Giant);
81691040Sarr	return (error);
81725537Sdfr}
81825537Sdfr
81982749Sdillon/*
82082749Sdillon * MPSAFE
82182749Sdillon */
82225537Sdfrint
82391040Sarrkldnext(struct thread *td, struct kldnext_args *uap)
82425537Sdfr{
82591040Sarr	linker_file_t lf;
82691040Sarr	int error = 0;
82725537Sdfr
82891040Sarr	mtx_lock(&Giant);
82982749Sdillon
83091040Sarr	if (SCARG(uap, fileid) == 0) {
83191040Sarr		if (TAILQ_FIRST(&linker_files))
83291040Sarr			td->td_retval[0] = TAILQ_FIRST(&linker_files)->id;
83391040Sarr		else
83491040Sarr			td->td_retval[0] = 0;
83591040Sarr		goto out;
83691040Sarr	}
83791040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
83891040Sarr	if (lf) {
83991040Sarr		if (TAILQ_NEXT(lf, link))
84091040Sarr			td->td_retval[0] = TAILQ_NEXT(lf, link)->id;
84191040Sarr		else
84291040Sarr			td->td_retval[0] = 0;
84391040Sarr	} else
84491040Sarr		error = ENOENT;
84582749Sdillonout:
84691040Sarr	mtx_unlock(&Giant);
84791040Sarr	return (error);
84825537Sdfr}
84925537Sdfr
85082749Sdillon/*
85182749Sdillon * MPSAFE
85282749Sdillon */
85325537Sdfrint
85491040Sarrkldstat(struct thread *td, struct kldstat_args *uap)
85525537Sdfr{
85691040Sarr	linker_file_t lf;
85791040Sarr	int error = 0;
85891040Sarr	int namelen, version;
85991040Sarr	struct kld_file_stat *stat;
86025537Sdfr
86191040Sarr	mtx_lock(&Giant);
86282749Sdillon
86391040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
86491040Sarr	if (lf == NULL) {
86591040Sarr		error = ENOENT;
86691040Sarr		goto out;
86791040Sarr	}
86891040Sarr	stat = SCARG(uap, stat);
86925537Sdfr
87091040Sarr	/*
87191040Sarr	 * Check the version of the user's structure.
87291040Sarr	 */
87391040Sarr	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
87491040Sarr		goto out;
87591040Sarr	if (version != sizeof(struct kld_file_stat)) {
87691040Sarr		error = EINVAL;
87791040Sarr		goto out;
87891040Sarr	}
87991040Sarr	namelen = strlen(lf->filename) + 1;
88091040Sarr	if (namelen > MAXPATHLEN)
88191040Sarr		namelen = MAXPATHLEN;
88291040Sarr	if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
88391040Sarr		goto out;
88491040Sarr	if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
88591040Sarr		goto out;
88691040Sarr	if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
88791040Sarr		goto out;
88891040Sarr	if ((error = copyout(&lf->address, &stat->address,
88991040Sarr	    sizeof(caddr_t))) != 0)
89091040Sarr		goto out;
89191040Sarr	if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
89291040Sarr		goto out;
89325537Sdfr
89491040Sarr	td->td_retval[0] = 0;
89525537Sdfrout:
89691040Sarr	mtx_unlock(&Giant);
89791040Sarr	return (error);
89825537Sdfr}
89925537Sdfr
90082749Sdillon/*
90182749Sdillon * MPSAFE
90282749Sdillon */
90325537Sdfrint
90491040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
90525537Sdfr{
90691040Sarr	linker_file_t lf;
90791040Sarr	module_t mp;
90891040Sarr	int error = 0;
90925537Sdfr
91091040Sarr	mtx_lock(&Giant);
91191040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
91291040Sarr	if (lf) {
91392547Sarr		MOD_SLOCK;
91491040Sarr		mp = TAILQ_FIRST(&lf->modules);
91591040Sarr		if (mp != NULL)
91691040Sarr			td->td_retval[0] = module_getid(mp);
91791040Sarr		else
91891040Sarr			td->td_retval[0] = 0;
91992547Sarr		MOD_SUNLOCK;
92091040Sarr	} else
92191040Sarr		error = ENOENT;
92291040Sarr	mtx_unlock(&Giant);
92391040Sarr	return (error);
92425537Sdfr}
92540159Speter
92682749Sdillon/*
92782749Sdillon * MPSAFE
92882749Sdillon */
92941090Speterint
93083366Sjuliankldsym(struct thread *td, struct kldsym_args *uap)
93141090Speter{
93291040Sarr	char *symstr = NULL;
93391040Sarr	c_linker_sym_t sym;
93491040Sarr	linker_symval_t symval;
93591040Sarr	linker_file_t lf;
93691040Sarr	struct kld_sym_lookup lookup;
93791040Sarr	int error = 0;
93841090Speter
93991040Sarr	mtx_lock(&Giant);
94082749Sdillon
94191040Sarr	if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
94291040Sarr		goto out;
94391068Sarr	if (lookup.version != sizeof(lookup) ||
94491040Sarr	    SCARG(uap, cmd) != KLDSYM_LOOKUP) {
94591040Sarr		error = EINVAL;
94691040Sarr		goto out;
94791040Sarr	}
94891040Sarr	symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
94991040Sarr	if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
95091040Sarr		goto out;
95191040Sarr	if (SCARG(uap, fileid) != 0) {
95291040Sarr		lf = linker_find_file_by_id(SCARG(uap, fileid));
95391040Sarr		if (lf == NULL) {
95491040Sarr			error = ENOENT;
95591040Sarr			goto out;
95691040Sarr		}
95791040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
95891040Sarr		    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
95991040Sarr			lookup.symvalue = (uintptr_t) symval.value;
96091040Sarr			lookup.symsize = symval.size;
96191040Sarr			error = copyout(&lookup, SCARG(uap, data),
96291040Sarr			    sizeof(lookup));
96391040Sarr		} else
96491040Sarr			error = ENOENT;
96591040Sarr	} else {
96691040Sarr		TAILQ_FOREACH(lf, &linker_files, link) {
96791040Sarr			if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
96891040Sarr			    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
96991040Sarr				lookup.symvalue = (uintptr_t)symval.value;
97091040Sarr				lookup.symsize = symval.size;
97191040Sarr				error = copyout(&lookup, SCARG(uap, data),
97291040Sarr				    sizeof(lookup));
97391068Sarr				break;
97491040Sarr			}
97591040Sarr		}
97691040Sarr		if (lf == NULL)
97791040Sarr			error = ENOENT;
97841090Speter	}
97941090Speterout:
98091040Sarr	if (symstr)
98191040Sarr		free(symstr, M_TEMP);
98291040Sarr	mtx_unlock(&Giant);
98391040Sarr	return (error);
98441090Speter}
98541090Speter
98640159Speter/*
98740159Speter * Preloaded module support
98840159Speter */
98940159Speter
99059751Speterstatic modlist_t
99174642Sbpmodlist_lookup(const char *name, int ver)
99259751Speter{
99391040Sarr	modlist_t mod;
99459751Speter
99591040Sarr	TAILQ_FOREACH(mod, &found_modules, link) {
99692032Sdwmalone		if (strcmp(mod->name, name) == 0 &&
99792032Sdwmalone		    (ver == 0 || mod->version == ver))
99891040Sarr			return (mod);
99991040Sarr	}
100091040Sarr	return (NULL);
100159751Speter}
100259751Speter
100374642Sbpstatic modlist_t
100483321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo)
100583321Speter{
100691040Sarr	modlist_t mod, bestmod;
100792032Sdwmalone	int ver;
100883321Speter
100991040Sarr	if (verinfo == NULL)
101091040Sarr		return (modlist_lookup(name, 0));
101191040Sarr	bestmod = NULL;
101291040Sarr	for (mod = TAILQ_FIRST(&found_modules); mod;
101391040Sarr	    mod = TAILQ_NEXT(mod, link)) {
101492032Sdwmalone		if (strcmp(mod->name, name) != 0)
101591040Sarr			continue;
101691040Sarr		ver = mod->version;
101791040Sarr		if (ver == verinfo->md_ver_preferred)
101891040Sarr			return (mod);
101991040Sarr		if (ver >= verinfo->md_ver_minimum &&
102091068Sarr		    ver <= verinfo->md_ver_maximum &&
102191068Sarr		    ver > bestmod->version)
102291040Sarr			bestmod = mod;
102391040Sarr	}
102491040Sarr	return (bestmod);
102583321Speter}
102683321Speter
102783321Speterstatic modlist_t
102878501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container)
102974642Sbp{
103091040Sarr	modlist_t mod;
103174642Sbp
103292705Sarr	mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO);
103391040Sarr	if (mod == NULL)
103491040Sarr		panic("no memory for module list");
103591040Sarr	mod->container = container;
103691040Sarr	mod->name = modname;
103791040Sarr	mod->version = version;
103891040Sarr	TAILQ_INSERT_TAIL(&found_modules, mod, link);
103991040Sarr	return (mod);
104074642Sbp}
104174642Sbp
104259751Speter/*
104359751Speter * This routine is cheap and nasty but will work for data pointers.
104459751Speter */
104559751Speterstatic void *
104678501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset)
104759751Speter{
104891040Sarr	return (lf->address + (uintptr_t)offset);
104959751Speter}
105059751Speter
105174642Sbp/*
105274642Sbp * Dereference MDT_VERSION metadata into module name and version
105374642Sbp */
105440159Speterstatic void
105574642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
105691040Sarr    const char **modname, int *version)
105774642Sbp{
105891040Sarr	struct mod_version *mvp;
105974642Sbp
106091040Sarr	if (modname)
106191040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
106291040Sarr	if (version) {
106391040Sarr		mvp = linker_reloc_ptr(lf, mp->md_data);
106491040Sarr		*version = mvp->mv_version;
106591040Sarr	}
106674642Sbp}
106774642Sbp
106874642Sbp/*
106974642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure
107074642Sbp */
107174642Sbpstatic void
107274642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
107391040Sarr    const char **modname, struct mod_depend **verinfo)
107474642Sbp{
107574642Sbp
107691040Sarr	if (modname)
107791040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
107891040Sarr	if (verinfo)
107991040Sarr		*verinfo = linker_reloc_ptr(lf, mp->md_data);
108074642Sbp}
108174642Sbp
108274642Sbpstatic void
108378161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start,
108491040Sarr    struct mod_metadata **stop, int preload)
108574642Sbp{
108691040Sarr	struct mod_metadata *mp, **mdp;
108791040Sarr	const char *modname;
108891040Sarr	int ver;
108974642Sbp
109091040Sarr	for (mdp = start; mdp < stop; mdp++) {
109191040Sarr		if (preload)
109291040Sarr			mp = *mdp;
109391040Sarr		else
109491040Sarr			mp = linker_reloc_ptr(lf, *mdp);
109591040Sarr		if (mp->md_type != MDT_VERSION)
109691040Sarr			continue;
109791040Sarr		if (preload) {
109891040Sarr			modname = mp->md_cval;
109991040Sarr			ver = ((struct mod_version *)mp->md_data)->mv_version;
110091040Sarr		} else
110191040Sarr	        	linker_mdt_version(lf, mp, &modname, &ver);
110291040Sarr		if (modlist_lookup(modname, ver) != NULL) {
110391040Sarr			printf("module %s already present!\n", modname);
110491040Sarr			/* XXX what can we do? this is a build error. :-( */
110591040Sarr			continue;
110691040Sarr		}
110791040Sarr		modlist_newmodule(modname, ver, lf);
110874642Sbp	}
110974642Sbp}
111074642Sbp
111174642Sbpstatic void
111291040Sarrlinker_preload(void *arg)
111340159Speter{
111491040Sarr	caddr_t modptr;
111591040Sarr	const char *modname, *nmodname;
111691040Sarr	char *modtype;
111791040Sarr	linker_file_t lf;
111891040Sarr	linker_class_t lc;
111992032Sdwmalone	int error;
112091040Sarr	linker_file_list_t loaded_files;
112191040Sarr	linker_file_list_t depended_files;
112291040Sarr	struct mod_metadata *mp, *nmp;
112391040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
112491040Sarr	struct mod_depend *verinfo;
112591040Sarr	int nver;
112691040Sarr	int resolves;
112791040Sarr	modlist_t mod;
112891040Sarr	struct sysinit **si_start, **si_stop;
112940159Speter
113091040Sarr	TAILQ_INIT(&loaded_files);
113191040Sarr	TAILQ_INIT(&depended_files);
113291040Sarr	TAILQ_INIT(&found_modules);
113391040Sarr	error = 0;
113459751Speter
113591040Sarr	modptr = NULL;
113691040Sarr	while ((modptr = preload_search_next_name(modptr)) != NULL) {
113791040Sarr		modname = (char *)preload_search_info(modptr, MODINFO_NAME);
113891040Sarr		modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
113991040Sarr		if (modname == NULL) {
114091040Sarr			printf("Preloaded module at %p does not have a"
114191040Sarr			    " name!\n", modptr);
114291040Sarr			continue;
114391040Sarr		}
114491040Sarr		if (modtype == NULL) {
114591040Sarr			printf("Preloaded module at %p does not have a type!\n",
114691040Sarr			    modptr);
114791040Sarr			continue;
114891040Sarr		}
114991040Sarr		printf("Preloaded %s \"%s\" at %p.\n", modtype, modname,
115091040Sarr		    modptr);
115140159Speter		lf = NULL;
115291040Sarr		TAILQ_FOREACH(lc, &classes, link) {
115391040Sarr			error = LINKER_LINK_PRELOAD(lc, modname, &lf);
115491040Sarr			if (error) {
115591040Sarr				lf = NULL;
115691040Sarr				break;
115791040Sarr			}
115891040Sarr		}
115991040Sarr		if (lf)
116091040Sarr			TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
116140159Speter	}
116240159Speter
116391040Sarr	/*
116491040Sarr	 * First get a list of stuff in the kernel.
116591040Sarr	 */
116691040Sarr	if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start,
116791040Sarr	    &stop, NULL) == 0)
116891040Sarr		linker_addmodules(linker_kernel_file, start, stop, 1);
116959751Speter
117059751Speter	/*
117191040Sarr	 * this is a once-off kinky bubble sort resolve relocation dependency
117291040Sarr	 * requirements
117359751Speter	 */
117491040Sarrrestart:
117591040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
117691040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
117791040Sarr		    &stop, NULL);
117891040Sarr		/*
117991040Sarr		 * First, look to see if we would successfully link with this
118091040Sarr		 * stuff.
118191040Sarr		 */
118291040Sarr		resolves = 1;	/* unless we know otherwise */
118391040Sarr		if (!error) {
118491040Sarr			for (mdp = start; mdp < stop; mdp++) {
118591040Sarr				mp = linker_reloc_ptr(lf, *mdp);
118691040Sarr				if (mp->md_type != MDT_DEPEND)
118791040Sarr					continue;
118891040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
118991040Sarr				for (nmdp = start; nmdp < stop; nmdp++) {
119091040Sarr					nmp = linker_reloc_ptr(lf, *nmdp);
119191040Sarr					if (nmp->md_type != MDT_VERSION)
119291040Sarr						continue;
119391040Sarr					linker_mdt_version(lf, nmp, &nmodname,
119491040Sarr					    NULL);
119591040Sarr					nmodname = linker_reloc_ptr(lf,
119691040Sarr					    nmp->md_cval);
119792032Sdwmalone					if (strcmp(modname, nmodname) == 0)
119891040Sarr						break;
119991040Sarr				}
120091040Sarr				if (nmdp < stop)   /* it's a self reference */
120191040Sarr					continue;
120291040Sarr
120391040Sarr				/*
120491040Sarr				 * ok, the module isn't here yet, we
120591040Sarr				 * are not finished
120691040Sarr				 */
120791068Sarr				if (modlist_lookup2(modname, verinfo) == NULL)
120891040Sarr					resolves = 0;
120991040Sarr			}
121064143Speter		}
121191040Sarr		/*
121291040Sarr		 * OK, if we found our modules, we can link.  So, "provide"
121391040Sarr		 * the modules inside and add it to the end of the link order
121491040Sarr		 * list.
121591040Sarr		 */
121691040Sarr		if (resolves) {
121791040Sarr			if (!error) {
121891040Sarr				for (mdp = start; mdp < stop; mdp++) {
121991040Sarr					mp = linker_reloc_ptr(lf, *mdp);
122091040Sarr					if (mp->md_type != MDT_VERSION)
122191040Sarr						continue;
122291040Sarr					linker_mdt_version(lf, mp,
122391040Sarr					    &modname, &nver);
122491040Sarr					if (modlist_lookup(modname,
122591040Sarr					    nver) != NULL) {
122691040Sarr						printf("module %s already"
122791040Sarr						    " present!\n", modname);
122891040Sarr						linker_file_unload(lf);
122991040Sarr						TAILQ_REMOVE(&loaded_files,
123091040Sarr						    lf, loaded);
123191040Sarr						/* we changed tailq next ptr */
123291068Sarr						goto restart;
123391040Sarr					}
123491040Sarr					modlist_newmodule(modname, nver, lf);
123591040Sarr				}
123691040Sarr			}
123791040Sarr			TAILQ_REMOVE(&loaded_files, lf, loaded);
123891040Sarr			TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
123991040Sarr			/*
124091040Sarr			 * Since we provided modules, we need to restart the
124191040Sarr			 * sort so that the previous files that depend on us
124291040Sarr			 * have a chance. Also, we've busted the tailq next
124391040Sarr			 * pointer with the REMOVE.
124491040Sarr			 */
124591040Sarr			goto restart;
124659751Speter		}
124759751Speter	}
124891040Sarr
124959751Speter	/*
125091040Sarr	 * At this point, we check to see what could not be resolved..
125159751Speter	 */
125291040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
125391040Sarr		printf("KLD file %s is missing dependencies\n", lf->filename);
125491040Sarr		linker_file_unload(lf);
125591040Sarr		TAILQ_REMOVE(&loaded_files, lf, loaded);
125640159Speter	}
125759751Speter
125878161Speter	/*
125991040Sarr	 * We made it. Finish off the linking in the order we determined.
126078161Speter	 */
126191040Sarr	TAILQ_FOREACH(lf, &depended_files, loaded) {
126291040Sarr		if (linker_kernel_file) {
126391040Sarr			linker_kernel_file->refs++;
126491040Sarr			error = linker_file_add_dependency(lf,
126591040Sarr			    linker_kernel_file);
126691040Sarr			if (error)
126791040Sarr				panic("cannot add dependency");
126891040Sarr		}
126991040Sarr		lf->userrefs++;	/* so we can (try to) kldunload it */
127091040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
127191040Sarr		    &stop, NULL);
127291040Sarr		if (!error) {
127391040Sarr			for (mdp = start; mdp < stop; mdp++) {
127491040Sarr				mp = linker_reloc_ptr(lf, *mdp);
127591040Sarr				if (mp->md_type != MDT_DEPEND)
127691040Sarr					continue;
127791040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
127891040Sarr				mod = modlist_lookup2(modname, verinfo);
127991040Sarr				mod->container->refs++;
128091040Sarr				error = linker_file_add_dependency(lf,
128191040Sarr				    mod->container);
128291040Sarr				if (error)
128391040Sarr					panic("cannot add dependency");
128491040Sarr			}
128591040Sarr		}
128691040Sarr		/*
128791040Sarr		 * Now do relocation etc using the symbol search paths
128891040Sarr		 * established by the dependencies
128991040Sarr		 */
129091040Sarr		error = LINKER_LINK_PRELOAD_FINISH(lf);
129191040Sarr		if (error) {
129291040Sarr			printf("KLD file %s - could not finalize loading\n",
129391040Sarr			    lf->filename);
129491040Sarr			linker_file_unload(lf);
129591040Sarr			continue;
129691040Sarr		}
129791040Sarr		linker_file_register_modules(lf);
129891040Sarr		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
129991040Sarr		    &si_stop, NULL) == 0)
130091040Sarr			sysinit_add(si_start, si_stop);
130191040Sarr		linker_file_register_sysctls(lf);
130291040Sarr		lf->flags |= LINKER_FILE_LINKED;
130359751Speter	}
130491040Sarr	/* woohoo! we made it! */
130540159Speter}
130640159Speter
130791040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0)
130840159Speter
130940159Speter/*
131040159Speter * Search for a not-loaded module by name.
131191040Sarr *
131240159Speter * Modules may be found in the following locations:
131391040Sarr *
131491040Sarr * - preloaded (result is just the module name) - on disk (result is full path
131591040Sarr * to module)
131691040Sarr *
131791040Sarr * If the module name is qualified in any way (contains path, etc.) the we
131891040Sarr * simply return a copy of it.
131991040Sarr *
132040159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
132140159Speter * character as a separator to be consistent with the bootloader.
132240159Speter */
132340159Speter
132483321Speterstatic char linker_hintfile[] = "linker.hints";
132583358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules";
132640159Speter
132740159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
132891040Sarr    sizeof(linker_path), "module load search path");
132940159Speter
133077843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path));
133170417Speter
133259751Speterstatic char *linker_ext_list[] = {
133383321Speter	"",
133459751Speter	".ko",
133559751Speter	NULL
133659751Speter};
133759751Speter
133883321Speter/*
133991040Sarr * Check if file actually exists either with or without extension listed in
134091040Sarr * the linker_ext_list. (probably should be generic for the rest of the
134191040Sarr * kernel)
134283321Speter */
134359751Speterstatic char *
134491040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name,
134591040Sarr    int namelen, struct vattr *vap)
134640159Speter{
134791040Sarr	struct nameidata nd;
134891040Sarr	struct thread *td = curthread;	/* XXX */
134991040Sarr	char *result, **cpp, *sep;
135091040Sarr	int error, len, extlen, reclen, flags;
135191040Sarr	enum vtype type;
135240159Speter
135391040Sarr	extlen = 0;
135491040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
135591040Sarr		len = strlen(*cpp);
135691040Sarr		if (len > extlen)
135791040Sarr			extlen = len;
135891040Sarr	}
135991040Sarr	extlen++;		/* trailing '\0' */
136091040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
136183321Speter
136291040Sarr	reclen = pathlen + strlen(sep) + namelen + extlen + 1;
136391040Sarr	result = malloc(reclen, M_LINKER, M_WAITOK);
136491040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
136591040Sarr		snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep,
136691040Sarr		    namelen, name, *cpp);
136791040Sarr		/*
136891040Sarr		 * Attempt to open the file, and return the path if
136991040Sarr		 * we succeed and it's a regular file.
137091040Sarr		 */
137191040Sarr		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td);
137291040Sarr		flags = FREAD;
137391040Sarr		error = vn_open(&nd, &flags, 0);
137491040Sarr		if (error == 0) {
137591040Sarr			NDFREE(&nd, NDF_ONLY_PNBUF);
137691040Sarr			type = nd.ni_vp->v_type;
137791040Sarr			if (vap)
137891406Sjhb				VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
137991040Sarr			VOP_UNLOCK(nd.ni_vp, 0, td);
138091406Sjhb			vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
138191040Sarr			if (type == VREG)
138291040Sarr				return (result);
138391040Sarr		}
138483321Speter	}
138591040Sarr	free(result, M_LINKER);
138691040Sarr	return (NULL);
138783321Speter}
138883321Speter
138991040Sarr#define	INT_ALIGN(base, ptr)	ptr =					\
139083321Speter	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
139183321Speter
139283321Speter/*
139391040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If
139491040Sarr * version specification is available, then try to find the best KLD.
139583321Speter * Otherwise just find the latest one.
139691040Sarr *
139790483Srwatson * XXX: Vnode locking here is hosed; lock should be held for calls to
139890483Srwatson * VOP_GETATTR() and vn_rdwr().
139983321Speter */
140083321Speterstatic char *
140191040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname,
140291040Sarr    int modnamelen, struct mod_depend *verinfo)
140383321Speter{
140491040Sarr	struct thread *td = curthread;	/* XXX */
140591406Sjhb	struct ucred *cred = td ? td->td_ucred : NULL;
140691040Sarr	struct nameidata nd;
140791040Sarr	struct vattr vattr, mattr;
140891040Sarr	u_char *hints = NULL;
140991040Sarr	u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep;
141091040Sarr	int error, ival, bestver, *intp, reclen, found, flags, clen, blen;
141183321Speter
141291040Sarr	result = NULL;
141391040Sarr	bestver = found = 0;
141483321Speter
141591040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
141691040Sarr	reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen +
141791040Sarr	    strlen(sep) + 1;
141891040Sarr	pathbuf = malloc(reclen, M_LINKER, M_WAITOK);
141991040Sarr	snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep,
142091040Sarr	    linker_hintfile);
142183321Speter
142291040Sarr	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td);
142391040Sarr	flags = FREAD;
142491040Sarr	error = vn_open(&nd, &flags, 0);
142591040Sarr	if (error)
142691040Sarr		goto bad;
142791040Sarr	NDFREE(&nd, NDF_ONLY_PNBUF);
142891040Sarr	VOP_UNLOCK(nd.ni_vp, 0, td);
142991040Sarr	if (nd.ni_vp->v_type != VREG)
143091040Sarr		goto bad;
143191040Sarr	best = cp = NULL;
143291040Sarr	error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td);
143391040Sarr	if (error)
143491040Sarr		goto bad;
143591040Sarr	/*
143691040Sarr	 * XXX: we need to limit this number to some reasonable value
143791040Sarr	 */
143891040Sarr	if (vattr.va_size > 100 * 1024) {
143991040Sarr		printf("hints file too large %ld\n", (long)vattr.va_size);
144091040Sarr		goto bad;
144191040Sarr	}
144291040Sarr	hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
144391040Sarr	if (hints == NULL)
144491040Sarr		goto bad;
144591068Sarr	error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
144691040Sarr	    UIO_SYSSPACE, IO_NODELOCKED, cred, &reclen, td);
144791040Sarr	if (error)
144891040Sarr		goto bad;
144991040Sarr	vn_close(nd.ni_vp, FREAD, cred, td);
145091040Sarr	nd.ni_vp = NULL;
145191040Sarr	if (reclen != 0) {
145291040Sarr		printf("can't read %d\n", reclen);
145391040Sarr		goto bad;
145491040Sarr	}
145591040Sarr	intp = (int *)hints;
145683321Speter	ival = *intp++;
145791040Sarr	if (ival != LINKER_HINTS_VERSION) {
145891040Sarr		printf("hints file version mismatch %d\n", ival);
145991040Sarr		goto bad;
146083321Speter	}
146191040Sarr	bufend = hints + vattr.va_size;
146291040Sarr	recptr = (u_char *)intp;
146391040Sarr	clen = blen = 0;
146491040Sarr	while (recptr < bufend && !found) {
146591040Sarr		intp = (int *)recptr;
146691040Sarr		reclen = *intp++;
146791040Sarr		ival = *intp++;
146891040Sarr		cp = (char *)intp;
146991040Sarr		switch (ival) {
147091040Sarr		case MDT_VERSION:
147191040Sarr			clen = *cp++;
147291040Sarr			if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
147391040Sarr				break;
147491040Sarr			cp += clen;
147591040Sarr			INT_ALIGN(hints, cp);
147691040Sarr			ival = *(int *)cp;
147791040Sarr			cp += sizeof(int);
147891040Sarr			clen = *cp++;
147991040Sarr			if (verinfo == NULL ||
148091040Sarr			    ival == verinfo->md_ver_preferred) {
148191040Sarr				found = 1;
148291040Sarr				break;
148391040Sarr			}
148491040Sarr			if (ival >= verinfo->md_ver_minimum &&
148591040Sarr			    ival <= verinfo->md_ver_maximum &&
148691040Sarr			    ival > bestver) {
148791040Sarr				bestver = ival;
148891040Sarr				best = cp;
148991040Sarr				blen = clen;
149091040Sarr			}
149191040Sarr			break;
149291040Sarr		default:
149391040Sarr			break;
149491040Sarr		}
149591040Sarr		recptr += reclen + sizeof(int);
149691040Sarr	}
149783321Speter	/*
149891040Sarr	 * Finally check if KLD is in the place
149983321Speter	 */
150091040Sarr	if (found)
150191040Sarr		result = linker_lookup_file(path, pathlen, cp, clen, &mattr);
150291040Sarr	else if (best)
150391040Sarr		result = linker_lookup_file(path, pathlen, best, blen, &mattr);
150491040Sarr
150591040Sarr	/*
150691040Sarr	 * KLD is newer than hints file. What we should do now?
150791040Sarr	 */
150891040Sarr	if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >))
150991040Sarr		printf("warning: KLD '%s' is newer than the linker.hints"
151091040Sarr		    " file\n", result);
151183321Speterbad:
151291040Sarr	if (hints)
151391040Sarr		free(hints, M_TEMP);
151491040Sarr	if (nd.ni_vp != NULL)
151591040Sarr		vn_close(nd.ni_vp, FREAD, cred, td);
151691040Sarr	/*
151791040Sarr	 * If nothing found or hints is absent - fallback to the old
151891040Sarr	 * way by using "kldname[.ko]" as module name.
151991040Sarr	 */
152091040Sarr	if (!found && !bestver && result == NULL)
152191040Sarr		result = linker_lookup_file(path, pathlen, modname,
152291040Sarr		    modnamelen, NULL);
152391040Sarr	return (result);
152483321Speter}
152583321Speter
152683321Speter/*
152783321Speter * Lookup KLD which contains requested module in the all directories.
152883321Speter */
152983321Speterstatic char *
153083321Speterlinker_search_module(const char *modname, int modnamelen,
153191040Sarr    struct mod_depend *verinfo)
153283321Speter{
153391040Sarr	char *cp, *ep, *result;
153483321Speter
153591040Sarr	/*
153691040Sarr	 * traverse the linker path
153791040Sarr	 */
153891040Sarr	for (cp = linker_path; *cp; cp = ep + 1) {
153991040Sarr		/* find the end of this component */
154091040Sarr		for (ep = cp; (*ep != 0) && (*ep != ';'); ep++);
154191068Sarr		result = linker_hints_lookup(cp, ep - cp, modname,
154291068Sarr		    modnamelen, verinfo);
154391040Sarr		if (result != NULL)
154491040Sarr			return (result);
154591040Sarr		if (*ep == 0)
154691040Sarr			break;
154791040Sarr	}
154891040Sarr	return (NULL);
154983321Speter}
155083321Speter
155183321Speter/*
155283321Speter * Search for module in all directories listed in the linker_path.
155383321Speter */
155483321Speterstatic char *
155583321Speterlinker_search_kld(const char *name)
155683321Speter{
155791040Sarr	char *cp, *ep, *result, **cpp;
155891040Sarr	int extlen, len;
155983321Speter
156091040Sarr	/* qualified at all? */
156191040Sarr	if (index(name, '/'))
156291040Sarr		return (linker_strdup(name));
156340159Speter
156491040Sarr	extlen = 0;
156591040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
156691040Sarr		len = strlen(*cpp);
156791040Sarr		if (len > extlen)
156891040Sarr			extlen = len;
156991040Sarr	}
157091040Sarr	extlen++;		/* trailing '\0' */
157159751Speter
157291040Sarr	/* traverse the linker path */
157391040Sarr	len = strlen(name);
157491040Sarr	for (ep = linker_path; *ep; ep++) {
157591040Sarr		cp = ep;
157691040Sarr		/* find the end of this component */
157791040Sarr		for (; *ep != 0 && *ep != ';'; ep++);
157891040Sarr		result = linker_lookup_file(cp, ep - cp, name, len, NULL);
157991040Sarr		if (result != NULL)
158091040Sarr			return (result);
158191040Sarr	}
158291040Sarr	return (NULL);
158340159Speter}
158459751Speter
158559751Speterstatic const char *
158691040Sarrlinker_basename(const char *path)
158759751Speter{
158891040Sarr	const char *filename;
158959751Speter
159091040Sarr	filename = rindex(path, '/');
159191040Sarr	if (filename == NULL)
159291040Sarr		return path;
159391040Sarr	if (filename[1])
159491040Sarr		filename++;
159591040Sarr	return (filename);
159659751Speter}
159759751Speter
159859751Speter/*
159991040Sarr * Find a file which contains given module and load it, if "parent" is not
160091040Sarr * NULL, register a reference to it.
160159751Speter */
160259751Speterstatic int
160383321Speterlinker_load_module(const char *kldname, const char *modname,
160491040Sarr    struct linker_file *parent, struct mod_depend *verinfo,
160591040Sarr    struct linker_file **lfpp)
160659751Speter{
160791040Sarr	linker_file_t lfdep;
160891040Sarr	const char *filename;
160991040Sarr	char *pathname;
161091040Sarr	int error;
161159751Speter
161291040Sarr	if (modname == NULL) {
161391040Sarr		/*
161491040Sarr 		 * We have to load KLD
161591040Sarr 		 */
161691068Sarr		KASSERT(verinfo == NULL, ("linker_load_module: verinfo"
161791068Sarr		    " is not NULL"));
161891040Sarr		pathname = linker_search_kld(kldname);
161991040Sarr	} else {
162091040Sarr		if (modlist_lookup2(modname, verinfo) != NULL)
162191040Sarr			return (EEXIST);
162291040Sarr		if (kldname == NULL)
162391040Sarr			/*
162491040Sarr			 * Need to find a KLD with required module
162591040Sarr			 */
162691040Sarr			pathname = linker_search_module(modname,
162791040Sarr			    strlen(modname), verinfo);
162891040Sarr		else
162991040Sarr			pathname = linker_strdup(kldname);
163091040Sarr	}
163191040Sarr	if (pathname == NULL)
163291040Sarr		return (ENOENT);
163391040Sarr
163483321Speter	/*
163591040Sarr	 * Can't load more than one file with the same basename XXX:
163691040Sarr	 * Actually it should be possible to have multiple KLDs with
163791040Sarr	 * the same basename but different path because they can
163891040Sarr	 * provide different versions of the same modules.
163983321Speter	 */
164091040Sarr	filename = linker_basename(pathname);
164191040Sarr	if (linker_find_file_by_name(filename)) {
164291040Sarr		error = EEXIST;
164391040Sarr		goto out;
164483321Speter	}
164591040Sarr	do {
164691040Sarr		error = linker_load_file(pathname, &lfdep);
164791040Sarr		if (error)
164891040Sarr			break;
164991040Sarr		if (modname && verinfo &&
165091040Sarr		    modlist_lookup2(modname, verinfo) == NULL) {
165191040Sarr			linker_file_unload(lfdep);
165291040Sarr			error = ENOENT;
165391040Sarr			break;
165491040Sarr		}
165591040Sarr		if (parent) {
165691040Sarr			error = linker_file_add_dependency(parent, lfdep);
165791040Sarr			if (error)
165891040Sarr				break;
165991040Sarr		}
166091040Sarr		if (lfpp)
166191040Sarr			*lfpp = lfdep;
166291040Sarr	} while (0);
166359751Speterout:
166491040Sarr	if (pathname)
166591040Sarr		free(pathname, M_LINKER);
166691040Sarr	return (error);
166759751Speter}
166859751Speter
166959751Speter/*
167091040Sarr * This routine is responsible for finding dependencies of userland initiated
167191040Sarr * kldload(2)'s of files.
167259751Speter */
167359751Speterint
167486469Siedowselinker_load_dependencies(linker_file_t lf)
167559751Speter{
167691040Sarr	linker_file_t lfdep;
167791040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
167891040Sarr	struct mod_metadata *mp, *nmp;
167991040Sarr	struct mod_depend *verinfo;
168091040Sarr	modlist_t mod;
168191040Sarr	const char *modname, *nmodname;
168292032Sdwmalone	int ver, error = 0, count;
168359751Speter
168491040Sarr	/*
168591040Sarr	 * All files are dependant on /kernel.
168691040Sarr	 */
168791040Sarr	if (linker_kernel_file) {
168891040Sarr		linker_kernel_file->refs++;
168991040Sarr		error = linker_file_add_dependency(lf, linker_kernel_file);
169091040Sarr		if (error)
169191040Sarr			return (error);
169259751Speter	}
169391040Sarr	if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop,
169491040Sarr	    &count) != 0)
169591040Sarr		return (0);
169691040Sarr	for (mdp = start; mdp < stop; mdp++) {
169791040Sarr		mp = linker_reloc_ptr(lf, *mdp);
169891040Sarr		if (mp->md_type != MDT_VERSION)
169991040Sarr			continue;
170091040Sarr		linker_mdt_version(lf, mp, &modname, &ver);
170191040Sarr		mod = modlist_lookup(modname, ver);
170291040Sarr		if (mod != NULL) {
170391040Sarr			printf("interface %s.%d already present in the KLD"
170491040Sarr			    " '%s'!\n", modname, ver,
170591040Sarr			    mod->container->filename);
170691040Sarr			return (EEXIST);
170791040Sarr		}
170891040Sarr	}
170974642Sbp
171091040Sarr	for (mdp = start; mdp < stop; mdp++) {
171191040Sarr		mp = linker_reloc_ptr(lf, *mdp);
171291040Sarr		if (mp->md_type != MDT_DEPEND)
171391040Sarr			continue;
171491040Sarr		linker_mdt_depend(lf, mp, &modname, &verinfo);
171591040Sarr		nmodname = NULL;
171691040Sarr		for (nmdp = start; nmdp < stop; nmdp++) {
171791040Sarr			nmp = linker_reloc_ptr(lf, *nmdp);
171891040Sarr			if (nmp->md_type != MDT_VERSION)
171991040Sarr				continue;
172091040Sarr			nmodname = linker_reloc_ptr(lf, nmp->md_cval);
172192032Sdwmalone			if (strcmp(modname, nmodname) == 0)
172291040Sarr				break;
172391040Sarr		}
172491040Sarr		if (nmdp < stop)/* early exit, it's a self reference */
172591040Sarr			continue;
172691040Sarr		mod = modlist_lookup2(modname, verinfo);
172791040Sarr		if (mod) {	/* woohoo, it's loaded already */
172891040Sarr			lfdep = mod->container;
172991040Sarr			lfdep->refs++;
173091040Sarr			error = linker_file_add_dependency(lf, lfdep);
173191040Sarr			if (error)
173291040Sarr				break;
173391040Sarr			continue;
173491040Sarr		}
173591040Sarr		error = linker_load_module(NULL, modname, lf, verinfo, NULL);
173691040Sarr		if (error) {
173791040Sarr			printf("KLD %s: depends on %s - not available\n",
173891040Sarr			    lf->filename, modname);
173991040Sarr			break;
174091040Sarr		}
174159751Speter	}
174259751Speter
174391040Sarr	if (error)
174491040Sarr		return (error);
174591040Sarr	linker_addmodules(lf, start, stop, 0);
174691040Sarr	return (error);
174759751Speter}
174885736Sgreen
174985736Sgreenstatic int
175085736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque)
175185736Sgreen{
175285736Sgreen	struct sysctl_req *req;
175385736Sgreen
175485736Sgreen	req = opaque;
175585736Sgreen	return (SYSCTL_OUT(req, name, strlen(name) + 1));
175685736Sgreen}
175785736Sgreen
175885736Sgreen/*
175985736Sgreen * Export a nul-separated, double-nul-terminated list of all function names
176085736Sgreen * in the kernel.
176185736Sgreen */
176285736Sgreenstatic int
176385736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS)
176485736Sgreen{
176585736Sgreen	linker_file_t lf;
176685736Sgreen	int error;
176785736Sgreen
176885736Sgreen	TAILQ_FOREACH(lf, &linker_files, link) {
176985736Sgreen		error = LINKER_EACH_FUNCTION_NAME(lf,
177085736Sgreen		    sysctl_kern_function_list_iterate, req);
177185736Sgreen		if (error)
177285736Sgreen			return (error);
177385736Sgreen	}
177485736Sgreen	return (SYSCTL_OUT(req, "", 1));
177585736Sgreen}
177685736Sgreen
177785736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD,
177891040Sarr    NULL, 0, sysctl_kern_function_list, "", "kernel function list");
1779