kern_linker.c revision 107089
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 107089 2002-11-19 22:12:42Z rwatson $
2725537Sdfr */
2825537Sdfr
2940159Speter#include "opt_ddb.h"
30107089Srwatson#include "opt_mac.h"
3140159Speter
3225537Sdfr#include <sys/param.h>
3325537Sdfr#include <sys/kernel.h>
3425537Sdfr#include <sys/systm.h>
3525537Sdfr#include <sys/malloc.h>
3625537Sdfr#include <sys/sysproto.h>
3725537Sdfr#include <sys/sysent.h>
3825537Sdfr#include <sys/proc.h>
3925537Sdfr#include <sys/lock.h>
4082749Sdillon#include <sys/mutex.h>
4192547Sarr#include <sys/sx.h>
42107089Srwatson#include <sys/mac.h>
4325537Sdfr#include <sys/module.h>
4425537Sdfr#include <sys/linker.h>
4540159Speter#include <sys/fcntl.h>
4640159Speter#include <sys/libkern.h>
4740159Speter#include <sys/namei.h>
4840159Speter#include <sys/vnode.h>
4940159Speter#include <sys/sysctl.h>
5025537Sdfr
5159603Sdfr#include "linker_if.h"
5259603Sdfr
5340961Speter#ifdef KLD_DEBUG
5440961Speterint kld_debug = 0;
5540961Speter#endif
5640961Speter
5791040Sarr/*
5891040Sarr * static char *linker_search_path(const char *name, struct mod_depend
5991040Sarr * *verinfo);
6091040Sarr */
6191040Sarrstatic const char 	*linker_basename(const char *path);
6259751Speter
6378161Speter/* Metadata from the static kernel */
6478161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata);
6578161Speter
6659751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
6759751Speter
6840906Speterlinker_file_t linker_kernel_file;
6931324Sbde
7098452Sarrstatic struct mtx kld_mtx;	/* kernel linker mutex */
7198452Sarr
7225537Sdfrstatic linker_class_list_t classes;
7350068Sgrogstatic linker_file_list_t linker_files;
7425537Sdfrstatic int next_file_id = 1;
7598452Sarrstatic int linker_no_more_classes = 0;
7625537Sdfr
7786553Sarr#define	LINKER_GET_NEXT_FILE_ID(a) do {					\
7891040Sarr	linker_file_t lftmp;						\
7986553Sarr									\
8086553Sarrretry:									\
8198452Sarr	mtx_lock(&kld_mtx);						\
8291040Sarr	TAILQ_FOREACH(lftmp, &linker_files, link) {			\
8391040Sarr		if (next_file_id == lftmp->id) {			\
8491040Sarr			next_file_id++;					\
8598452Sarr			mtx_unlock(&kld_mtx);				\
8691040Sarr			goto retry;					\
8791040Sarr		}							\
8891040Sarr	}								\
8991040Sarr	(a) = next_file_id;						\
9098452Sarr	mtx_unlock(&kld_mtx);	/* Hold for safe read of id variable */	\
9186553Sarr} while(0)
9286553Sarr
9386553Sarr
9459751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */
9560938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t;
9659751Speterstruct modlist {
9791040Sarr	TAILQ_ENTRY(modlist) link;	/* chain together all modules */
9891040Sarr	linker_file_t   container;
9991040Sarr	const char 	*name;
10091040Sarr	int             version;
10159751Speter};
10291040Sarrtypedef struct modlist *modlist_t;
10391040Sarrstatic modlisthead_t found_modules;
10459751Speter
10594321Sbrianstatic modlist_t	modlist_lookup2(const char *name,
10694321Sbrian			    struct mod_depend *verinfo);
10794321Sbrian
10859603Sdfrstatic char *
10959603Sdfrlinker_strdup(const char *str)
11059603Sdfr{
11191040Sarr	char *result;
11259603Sdfr
11391040Sarr	if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
11491040Sarr		strcpy(result, str);
11591040Sarr	return (result);
11659603Sdfr}
11759603Sdfr
11825537Sdfrstatic void
11991040Sarrlinker_init(void *arg)
12025537Sdfr{
12191040Sarr
12298452Sarr	mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF);
12391040Sarr	TAILQ_INIT(&classes);
12491040Sarr	TAILQ_INIT(&linker_files);
12525537Sdfr}
12625537Sdfr
12791040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0)
12825537Sdfr
12998452Sarrstatic void
13098452Sarrlinker_stop_class_add(void *arg)
13198452Sarr{
13298452Sarr
13398452Sarr	linker_no_more_classes = 1;
13498452Sarr}
13598452Sarr
13698452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL)
13798452Sarr
13825537Sdfrint
13959603Sdfrlinker_add_class(linker_class_t lc)
14025537Sdfr{
14191040Sarr
14298452Sarr	/*
14398452Sarr	 * We disallow any class registration passt SI_ORDER_ANY
14498452Sarr	 * of SI_SUB_KLD.
14598452Sarr	 */
14698452Sarr	if (linker_no_more_classes == 1)
14798452Sarr		return (EPERM);
14891040Sarr	kobj_class_compile((kobj_class_t) lc);
14991040Sarr	TAILQ_INSERT_TAIL(&classes, lc, link);
15091040Sarr	return (0);
15125537Sdfr}
15225537Sdfr
15325537Sdfrstatic void
15425537Sdfrlinker_file_sysinit(linker_file_t lf)
15525537Sdfr{
15691040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
15725537Sdfr
15891040Sarr	KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
15991040Sarr	    lf->filename));
16025537Sdfr
16191040Sarr	if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0)
16291040Sarr		return;
16391040Sarr	/*
16491040Sarr	 * Perform a bubble sort of the system initialization objects by
16591040Sarr	 * their subsystem (primary key) and order (secondary key).
16691040Sarr	 *
16791040Sarr	 * Since some things care about execution order, this is the operation
16891040Sarr	 * which ensures continued function.
16991040Sarr	 */
17091040Sarr	for (sipp = start; sipp < stop; sipp++) {
17191040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
17291040Sarr			if ((*sipp)->subsystem < (*xipp)->subsystem ||
17391040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
17491040Sarr			    (*sipp)->order <= (*xipp)->order))
17591040Sarr				continue;	/* skip */
17691040Sarr			save = *sipp;
17791040Sarr			*sipp = *xipp;
17891040Sarr			*xipp = save;
17991040Sarr		}
18025537Sdfr	}
18125537Sdfr
18291040Sarr	/*
18391040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
18491040Sarr	 * Perform each task, and continue on to the next task.
18591040Sarr	 */
18691040Sarr	for (sipp = start; sipp < stop; sipp++) {
18791040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
18891040Sarr			continue;	/* skip dummy task(s) */
18925537Sdfr
19091040Sarr		/* Call function */
19191040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
19291040Sarr	}
19325537Sdfr}
19425537Sdfr
19541055Speterstatic void
19641055Speterlinker_file_sysuninit(linker_file_t lf)
19741055Speter{
19891040Sarr	struct sysinit **start, **stop, **sipp, **xipp, *save;
19941055Speter
20091040Sarr	KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
20191040Sarr	    lf->filename));
20241055Speter
20391068Sarr	if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop,
20491040Sarr	    NULL) != 0)
20591040Sarr		return;
20641055Speter
20791040Sarr	/*
20891040Sarr	 * Perform a reverse bubble sort of the system initialization objects
20991040Sarr	 * by their subsystem (primary key) and order (secondary key).
21091040Sarr	 *
21191040Sarr	 * Since some things care about execution order, this is the operation
21291040Sarr	 * which ensures continued function.
21391040Sarr	 */
21491040Sarr	for (sipp = start; sipp < stop; sipp++) {
21591040Sarr		for (xipp = sipp + 1; xipp < stop; xipp++) {
21691040Sarr			if ((*sipp)->subsystem > (*xipp)->subsystem ||
21791040Sarr			    ((*sipp)->subsystem == (*xipp)->subsystem &&
21891040Sarr			    (*sipp)->order >= (*xipp)->order))
21991040Sarr				continue;	/* skip */
22091040Sarr			save = *sipp;
22191040Sarr			*sipp = *xipp;
22291040Sarr			*xipp = save;
22391040Sarr		}
22441055Speter	}
22541055Speter
22691040Sarr	/*
22791040Sarr	 * Traverse the (now) ordered list of system initialization tasks.
22891040Sarr	 * Perform each task, and continue on to the next task.
22991040Sarr	 */
23091040Sarr	for (sipp = start; sipp < stop; sipp++) {
23191040Sarr		if ((*sipp)->subsystem == SI_SUB_DUMMY)
23291040Sarr			continue;	/* skip dummy task(s) */
23341055Speter
23491040Sarr		/* Call function */
23591040Sarr		(*((*sipp)->func)) ((*sipp)->udata);
23691040Sarr	}
23741055Speter}
23841055Speter
23944078Sdfrstatic void
24044078Sdfrlinker_file_register_sysctls(linker_file_t lf)
24144078Sdfr{
24291040Sarr	struct sysctl_oid **start, **stop, **oidp;
24344078Sdfr
24491040Sarr	KLD_DPF(FILE,
24591040Sarr	    ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
24691040Sarr	    lf->filename));
24744078Sdfr
24891040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
24991040Sarr		return;
25044078Sdfr
25191040Sarr	for (oidp = start; oidp < stop; oidp++)
25291040Sarr		sysctl_register_oid(*oidp);
25344078Sdfr}
25444078Sdfr
25544078Sdfrstatic void
25644078Sdfrlinker_file_unregister_sysctls(linker_file_t lf)
25744078Sdfr{
25891040Sarr	struct sysctl_oid **start, **stop, **oidp;
25944078Sdfr
26091040Sarr	KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs"
26191040Sarr	    " for %s\n", lf->filename));
26244078Sdfr
26391040Sarr	if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
26491040Sarr		return;
26544078Sdfr
26691040Sarr	for (oidp = start; oidp < stop; oidp++)
26791040Sarr		sysctl_unregister_oid(*oidp);
26844078Sdfr}
26944078Sdfr
27059751Speterstatic int
27159751Speterlinker_file_register_modules(linker_file_t lf)
27259751Speter{
27391040Sarr	struct mod_metadata **start, **stop, **mdp;
27491040Sarr	const moduledata_t *moddata;
27591040Sarr	int error;
27659751Speter
27791040Sarr	KLD_DPF(FILE, ("linker_file_register_modules: registering modules"
27891040Sarr	    " in %s\n", lf->filename));
27959751Speter
28091068Sarr	if (linker_file_lookup_set(lf, "modmetadata_set", &start,
28191040Sarr	    &stop, 0) != 0) {
28291040Sarr		/*
28391040Sarr		 * This fallback should be unnecessary, but if we get booted
28491040Sarr		 * from boot2 instead of loader and we are missing our
28591040Sarr		 * metadata then we have to try the best we can.
28691040Sarr		 */
28791040Sarr		if (lf == linker_kernel_file) {
28891040Sarr			start = SET_BEGIN(modmetadata_set);
28991040Sarr			stop = SET_LIMIT(modmetadata_set);
29091040Sarr		} else
29191040Sarr			return (0);
29278161Speter	}
29391040Sarr	for (mdp = start; mdp < stop; mdp++) {
29491040Sarr		if ((*mdp)->md_type != MDT_MODULE)
29591040Sarr			continue;
29691040Sarr		moddata = (*mdp)->md_data;
29791040Sarr		KLD_DPF(FILE, ("Registering module %s in %s\n",
29891040Sarr		    moddata->name, lf->filename));
29991040Sarr		error = module_register(moddata, lf);
30091040Sarr		if (error)
30191068Sarr			printf("Module %s failed to register: %d\n",
30291040Sarr			    moddata->name, error);
30359751Speter	}
30491040Sarr	return (0);
30559751Speter}
30659751Speter
30759751Speterstatic void
30859751Speterlinker_init_kernel_modules(void)
30959751Speter{
31091040Sarr
31191040Sarr	linker_file_register_modules(linker_kernel_file);
31259751Speter}
31359751Speter
31491040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0)
31559751Speter
316101241Smuxstatic int
31791040Sarrlinker_load_file(const char *filename, linker_file_t *result)
31825537Sdfr{
31991040Sarr	linker_class_t lc;
32091040Sarr	linker_file_t lf;
32191040Sarr	int foundfile, error = 0;
32225537Sdfr
32391040Sarr	/* Refuse to load modules if securelevel raised */
32491040Sarr	if (securelevel > 0)
32591040Sarr		return (EPERM);
32662261Sarchie
32791040Sarr	lf = linker_find_file_by_name(filename);
32891040Sarr	if (lf) {
32991040Sarr		KLD_DPF(FILE, ("linker_load_file: file %s is already loaded,"
33091040Sarr		    " incrementing refs\n", filename));
33191040Sarr		*result = lf;
33291040Sarr		lf->refs++;
33391040Sarr		goto out;
33491040Sarr	}
33591040Sarr	lf = NULL;
33691040Sarr	foundfile = 0;
33798452Sarr
33898452Sarr	/*
33998452Sarr	 * We do not need to protect (lock) classes here because there is
34098452Sarr	 * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY)
34198452Sarr	 * and there is no class deregistration mechanism at this time.
34298452Sarr	 */
34391040Sarr	TAILQ_FOREACH(lc, &classes, link) {
34491040Sarr		KLD_DPF(FILE, ("linker_load_file: trying to load %s\n",
34591040Sarr		    filename));
34691040Sarr		error = LINKER_LOAD_FILE(lc, filename, &lf);
34791040Sarr		/*
34891040Sarr		 * If we got something other than ENOENT, then it exists but
34991040Sarr		 * we cannot load it for some other reason.
35091040Sarr		 */
35191040Sarr		if (error != ENOENT)
35291040Sarr			foundfile = 1;
35391040Sarr		if (lf) {
35491040Sarr			linker_file_register_modules(lf);
35591040Sarr			linker_file_register_sysctls(lf);
35691040Sarr			linker_file_sysinit(lf);
35791040Sarr			lf->flags |= LINKER_FILE_LINKED;
35891040Sarr			*result = lf;
35991040Sarr			error = 0;
36091040Sarr			goto out;
36191040Sarr		}
36291040Sarr	}
36342755Speter	/*
36491040Sarr	 * Less than ideal, but tells the user whether it failed to load or
36591040Sarr	 * the module was not found.
36642755Speter	 */
367105337Ssam	if (foundfile) {
368105337Ssam		/*
369105337Ssam		 * Format not recognized or otherwise unloadable.
370105337Ssam		 * When loading a module that is statically built into
371105337Ssam		 * the kernel EEXIST percolates back up as the return
372105337Ssam		 * value.  Preserve this so that apps like sysinstall
373105337Ssam		 * can recognize this special case and not post bogus
374105337Ssam		 * dialog boxes.
375105337Ssam		 */
376105337Ssam		if (error != EEXIST)
377105337Ssam			error = ENOEXEC;
378105337Ssam	} else
37991068Sarr		error = ENOENT;		/* Nothing found */
38025537Sdfrout:
38191040Sarr	return (error);
38225537Sdfr}
38325537Sdfr
38478413Sbrianint
38594321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo,
38694321Sbrian    linker_file_t *result)
38778413Sbrian{
38894321Sbrian	modlist_t mod;
38994321Sbrian
39094321Sbrian	if ((mod = modlist_lookup2(modname, verinfo)) != NULL) {
39194321Sbrian		*result = mod->container;
39294321Sbrian		(*result)->refs++;
39394321Sbrian		return (0);
39494321Sbrian	}
39594321Sbrian
39694321Sbrian	return (linker_load_module(NULL, modname, NULL, verinfo, result));
39778413Sbrian}
39878413Sbrian
39925537Sdfrlinker_file_t
40091040Sarrlinker_find_file_by_name(const char *filename)
40125537Sdfr{
40291040Sarr	linker_file_t lf = 0;
40391040Sarr	char *koname;
40425537Sdfr
40591040Sarr	koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
40691040Sarr	if (koname == NULL)
40791040Sarr		goto out;
40891040Sarr	sprintf(koname, "%s.ko", filename);
40940861Speter
41098452Sarr	mtx_lock(&kld_mtx);
41191040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
41292032Sdwmalone		if (strcmp(lf->filename, koname) == 0)
41391040Sarr			break;
41492032Sdwmalone		if (strcmp(lf->filename, filename) == 0)
41591040Sarr			break;
41691040Sarr	}
41798452Sarr	mtx_unlock(&kld_mtx);
41840861Speterout:
41991040Sarr	if (koname)
42091040Sarr		free(koname, M_LINKER);
42191040Sarr	return (lf);
42225537Sdfr}
42325537Sdfr
42425537Sdfrlinker_file_t
42525537Sdfrlinker_find_file_by_id(int fileid)
42625537Sdfr{
42791040Sarr	linker_file_t lf = 0;
42898452Sarr
42998452Sarr	mtx_lock(&kld_mtx);
43091040Sarr	TAILQ_FOREACH(lf, &linker_files, link)
43191040Sarr		if (lf->id == fileid)
43291040Sarr			break;
43398452Sarr	mtx_unlock(&kld_mtx);
43491040Sarr	return (lf);
43525537Sdfr}
43625537Sdfr
43725537Sdfrlinker_file_t
43891040Sarrlinker_make_file(const char *pathname, linker_class_t lc)
43925537Sdfr{
44091040Sarr	linker_file_t lf;
44191040Sarr	const char *filename;
44225537Sdfr
44391040Sarr	lf = NULL;
44491040Sarr	filename = linker_basename(pathname);
44540159Speter
44691040Sarr	KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
44791040Sarr	lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK);
44891040Sarr	if (lf == NULL)
44991040Sarr		goto out;
45091040Sarr	lf->refs = 1;
45191040Sarr	lf->userrefs = 0;
45291040Sarr	lf->flags = 0;
45391040Sarr	lf->filename = linker_strdup(filename);
45491040Sarr	LINKER_GET_NEXT_FILE_ID(lf->id);
45591040Sarr	lf->ndeps = 0;
45691040Sarr	lf->deps = NULL;
45791040Sarr	STAILQ_INIT(&lf->common);
45891040Sarr	TAILQ_INIT(&lf->modules);
45998452Sarr	mtx_lock(&kld_mtx);
46091040Sarr	TAILQ_INSERT_TAIL(&linker_files, lf, link);
46198452Sarr	mtx_unlock(&kld_mtx);
46225537Sdfrout:
46391040Sarr	return (lf);
46425537Sdfr}
46525537Sdfr
46625537Sdfrint
46725537Sdfrlinker_file_unload(linker_file_t file)
46825537Sdfr{
46991040Sarr	module_t mod, next;
47091040Sarr	modlist_t ml, nextml;
47191040Sarr	struct common_symbol *cp;
47291040Sarr	int error, i;
47325537Sdfr
47491040Sarr	error = 0;
47562261Sarchie
47691040Sarr	/* Refuse to unload modules if securelevel raised. */
47791040Sarr	if (securelevel > 0)
47891040Sarr		return (EPERM);
479107089Srwatson#ifdef MAC
480107089Srwatson	error = mac_check_kld_unload(curthread->td_ucred);
481107089Srwatson	if (error)
482107089Srwatson		return (error);
483107089Srwatson#endif
48425537Sdfr
48591040Sarr	KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
48691040Sarr	if (file->refs == 1) {
48791040Sarr		KLD_DPF(FILE, ("linker_file_unload: file is unloading,"
48891040Sarr		    " informing modules\n"));
48991040Sarr
49091040Sarr		/*
49191040Sarr		 * Inform any modules associated with this file.
49291040Sarr		 */
49392547Sarr		MOD_XLOCK;
49491040Sarr		for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
49591040Sarr			next = module_getfnext(mod);
49692547Sarr			MOD_XUNLOCK;
49791040Sarr
49891040Sarr			/*
49991040Sarr			 * Give the module a chance to veto the unload.
50091040Sarr			 */
50191040Sarr			if ((error = module_unload(mod)) != 0) {
50291040Sarr				KLD_DPF(FILE, ("linker_file_unload: module %x"
50391040Sarr				    " vetoes unload\n", mod));
50491040Sarr				goto out;
50592547Sarr			} else
50692547Sarr				MOD_XLOCK;
50791040Sarr			module_release(mod);
50891040Sarr		}
50992547Sarr		MOD_XUNLOCK;
51091040Sarr	}
51191040Sarr	file->refs--;
51291040Sarr	if (file->refs > 0) {
51325537Sdfr		goto out;
51491040Sarr	}
51591040Sarr	for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
51691040Sarr		nextml = TAILQ_NEXT(ml, link);
51791040Sarr		if (ml->container == file)
51891040Sarr			TAILQ_REMOVE(&found_modules, ml, link);
51991040Sarr	}
52025537Sdfr
52191040Sarr	/*
52291040Sarr	 * Don't try to run SYSUNINITs if we are unloaded due to a
52391040Sarr	 * link error.
52491040Sarr	 */
52591040Sarr	if (file->flags & LINKER_FILE_LINKED) {
52691040Sarr		linker_file_sysuninit(file);
52791040Sarr		linker_file_unregister_sysctls(file);
52825537Sdfr	}
52998452Sarr	mtx_lock(&kld_mtx);
53091040Sarr	TAILQ_REMOVE(&linker_files, file, link);
53198452Sarr	mtx_unlock(&kld_mtx);
53225537Sdfr
53391040Sarr	if (file->deps) {
53491040Sarr		for (i = 0; i < file->ndeps; i++)
53591040Sarr			linker_file_unload(file->deps[i]);
53691040Sarr		free(file->deps, M_LINKER);
53791040Sarr		file->deps = NULL;
53859751Speter	}
53991040Sarr	for (cp = STAILQ_FIRST(&file->common); cp;
54091068Sarr	    cp = STAILQ_FIRST(&file->common)) {
54191040Sarr		STAILQ_REMOVE(&file->common, cp, common_symbol, link);
54291040Sarr		free(cp, M_LINKER);
54391040Sarr	}
54459751Speter
54591040Sarr	LINKER_UNLOAD(file);
54691040Sarr	if (file->filename) {
54791040Sarr		free(file->filename, M_LINKER);
54891040Sarr		file->filename = NULL;
54991040Sarr	}
55091040Sarr	kobj_delete((kobj_t) file, M_LINKER);
55125537Sdfrout:
55291040Sarr	return (error);
55325537Sdfr}
55425537Sdfr
55525537Sdfrint
55686469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep)
55725537Sdfr{
55891040Sarr	linker_file_t *newdeps;
55925537Sdfr
56091040Sarr	newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *),
56191040Sarr	    M_LINKER, M_WAITOK | M_ZERO);
56291040Sarr	if (newdeps == NULL)
56391040Sarr		return (ENOMEM);
56425537Sdfr
56591040Sarr	if (file->deps) {
56691040Sarr		bcopy(file->deps, newdeps,
56791040Sarr		    file->ndeps * sizeof(linker_file_t *));
56891040Sarr		free(file->deps, M_LINKER);
56991040Sarr	}
57091040Sarr	file->deps = newdeps;
57191040Sarr	file->deps[file->ndeps] = dep;
57291040Sarr	file->ndeps++;
57391040Sarr	return (0);
57425537Sdfr}
57525537Sdfr
57678161Speter/*
57791040Sarr * Locate a linker set and its contents.  This is a helper function to avoid
57891040Sarr * linker_if.h exposure elsewhere.  Note: firstp and lastp are really void ***
57978161Speter */
58078161Speterint
58178161Speterlinker_file_lookup_set(linker_file_t file, const char *name,
58291040Sarr    void *firstp, void *lastp, int *countp)
58378161Speter{
58478161Speter
58591040Sarr	return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp));
58678161Speter}
58778161Speter
58825537Sdfrcaddr_t
58991040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps)
59025537Sdfr{
59191040Sarr	c_linker_sym_t sym;
59291040Sarr	linker_symval_t symval;
59391040Sarr	caddr_t address;
59491040Sarr	size_t common_size = 0;
59592032Sdwmalone	int i;
59625537Sdfr
59791040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
59891040Sarr	    file, name, deps));
59925537Sdfr
60091040Sarr	if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
60191040Sarr		LINKER_SYMBOL_VALUES(file, sym, &symval);
60291040Sarr		if (symval.value == 0)
60391040Sarr			/*
60491040Sarr			 * For commons, first look them up in the
60591040Sarr			 * dependencies and only allocate space if not found
60691040Sarr			 * there.
60791040Sarr			 */
60891040Sarr			common_size = symval.size;
60991040Sarr		else {
61091040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol"
61191040Sarr			    ".value=%x\n", symval.value));
61291040Sarr			return (symval.value);
61391040Sarr		}
61440159Speter	}
61591040Sarr	if (deps) {
61691040Sarr		for (i = 0; i < file->ndeps; i++) {
61791040Sarr			address = linker_file_lookup_symbol(file->deps[i],
61891040Sarr			    name, 0);
61991040Sarr			if (address) {
62091040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
62191040Sarr				    " deps value=%x\n", address));
62291040Sarr				return (address);
62391040Sarr			}
62491040Sarr		}
62525537Sdfr	}
62691040Sarr	if (common_size > 0) {
62791040Sarr		/*
62891040Sarr		 * This is a common symbol which was not found in the
62991040Sarr		 * dependencies.  We maintain a simple common symbol table in
63091040Sarr		 * the file object.
63191040Sarr		 */
63291040Sarr		struct common_symbol *cp;
63342849Speter
63491040Sarr		STAILQ_FOREACH(cp, &file->common, link) {
63592032Sdwmalone			if (strcmp(cp->name, name) == 0) {
63691040Sarr				KLD_DPF(SYM, ("linker_file_lookup_symbol:"
63791040Sarr				    " old common value=%x\n", cp->address));
63891040Sarr				return (cp->address);
63991040Sarr			}
64091040Sarr		}
64191040Sarr		/*
64291040Sarr		 * Round the symbol size up to align.
64391040Sarr		 */
64491040Sarr		common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
64591040Sarr		cp = malloc(sizeof(struct common_symbol)
64691040Sarr		    + common_size + strlen(name) + 1, M_LINKER,
64791040Sarr		    M_WAITOK | M_ZERO);
64891040Sarr		if (cp == NULL) {
64991040Sarr			KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
65091040Sarr			return (0);
65191040Sarr		}
65291040Sarr		cp->address = (caddr_t)(cp + 1);
65391040Sarr		cp->name = cp->address + common_size;
65491040Sarr		strcpy(cp->name, name);
65591040Sarr		bzero(cp->address, common_size);
65691040Sarr		STAILQ_INSERT_TAIL(&file->common, cp, link);
65725537Sdfr
65891040Sarr		KLD_DPF(SYM, ("linker_file_lookup_symbol: new common"
65991040Sarr		    " value=%x\n", cp->address));
66091040Sarr		return (cp->address);
66140159Speter	}
66291040Sarr	KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
66391040Sarr	return (0);
66425537Sdfr}
66525537Sdfr
66640159Speter#ifdef DDB
66725537Sdfr/*
66891040Sarr * DDB Helpers.  DDB has to look across multiple files with their own symbol
66991040Sarr * tables and string tables.
67091040Sarr *
67191040Sarr * Note that we do not obey list locking protocols here.  We really don't need
67291040Sarr * DDB to hang because somebody's got the lock held.  We'll take the chance
67391040Sarr * that the files list is inconsistant instead.
67440159Speter */
67540159Speter
67640159Speterint
67743309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
67840159Speter{
67991040Sarr	linker_file_t lf;
68040159Speter
68191040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
68291040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
68391040Sarr			return (0);
68491040Sarr	}
68591040Sarr	return (ENOENT);
68640159Speter}
68740159Speter
68840159Speterint
68943309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
69040159Speter{
69191040Sarr	linker_file_t lf;
69291040Sarr	c_linker_sym_t best, es;
69391040Sarr	u_long diff, bestdiff, off;
69440159Speter
69591040Sarr	best = 0;
69691040Sarr	off = (uintptr_t)value;
69791040Sarr	bestdiff = off;
69891040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
69991040Sarr		if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
70091040Sarr			continue;
70191040Sarr		if (es != 0 && diff < bestdiff) {
70291040Sarr			best = es;
70391040Sarr			bestdiff = diff;
70491040Sarr		}
70591040Sarr		if (bestdiff == 0)
70691040Sarr			break;
70740159Speter	}
70891040Sarr	if (best) {
70991040Sarr		*sym = best;
71091040Sarr		*diffp = bestdiff;
71191040Sarr		return (0);
71291040Sarr	} else {
71391040Sarr		*sym = 0;
71491040Sarr		*diffp = off;
71591040Sarr		return (ENOENT);
71691040Sarr	}
71740159Speter}
71840159Speter
71940159Speterint
72043309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
72140159Speter{
72291040Sarr	linker_file_t lf;
72340159Speter
72491040Sarr	TAILQ_FOREACH(lf, &linker_files, link) {
72591040Sarr		if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
72691040Sarr			return (0);
72791040Sarr	}
72891040Sarr	return (ENOENT);
72940159Speter}
73040159Speter#endif
73140159Speter
73240159Speter/*
73325537Sdfr * Syscalls.
73425537Sdfr */
73582749Sdillon/*
73682749Sdillon * MPSAFE
73782749Sdillon */
73825537Sdfrint
73991040Sarrkldload(struct thread *td, struct kldload_args *uap)
74025537Sdfr{
74191040Sarr	char *kldname, *modname;
74291040Sarr	char *pathname = NULL;
74391040Sarr	linker_file_t lf;
74491040Sarr	int error = 0;
74525537Sdfr
74691040Sarr	td->td_retval[0] = -1;
74725537Sdfr
74891040Sarr	mtx_lock(&Giant);
74982749Sdillon
75093159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
75193159Sarr		goto out;
75293159Sarr
75393593Sjhb	if ((error = suser(td)) != 0)
75491040Sarr		goto out;
75525537Sdfr
75691040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
75791040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
75891040Sarr	    NULL)) != 0)
75991040Sarr		goto out;
76025537Sdfr
76191040Sarr	/*
76291040Sarr	 * If path do not contain qualified name or any dot in it
76391040Sarr	 * (kldname.ko, or kldname.ver.ko) treat it as interface
76491040Sarr	 * name.
76591040Sarr	 */
76691040Sarr	if (index(pathname, '/') || index(pathname, '.')) {
76791040Sarr		kldname = pathname;
76891040Sarr		modname = NULL;
76991040Sarr	} else {
77091040Sarr		kldname = NULL;
77191040Sarr		modname = pathname;
77291040Sarr	}
77391040Sarr	error = linker_load_module(kldname, modname, NULL, NULL, &lf);
77491040Sarr	if (error)
77591040Sarr		goto out;
77642316Smsmith
77791040Sarr	lf->userrefs++;
77891040Sarr	td->td_retval[0] = lf->id;
77925537Sdfrout:
78091040Sarr	if (pathname)
78191040Sarr		free(pathname, M_TEMP);
78291040Sarr	mtx_unlock(&Giant);
78391040Sarr	return (error);
78425537Sdfr}
78525537Sdfr
78682749Sdillon/*
78782749Sdillon * MPSAFE
78882749Sdillon */
78925537Sdfrint
79091040Sarrkldunload(struct thread *td, struct kldunload_args *uap)
79125537Sdfr{
79291040Sarr	linker_file_t lf;
79391040Sarr	int error = 0;
79425537Sdfr
79591040Sarr	mtx_lock(&Giant);
79682749Sdillon
79793159Sarr	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
79893159Sarr		goto out;
79993159Sarr
80093593Sjhb	if ((error = suser(td)) != 0)
80191040Sarr		goto out;
80225537Sdfr
80391040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
80491040Sarr	if (lf) {
80591040Sarr		KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
80691040Sarr		if (lf->userrefs == 0) {
80791040Sarr			printf("kldunload: attempt to unload file that was"
80891040Sarr			    " loaded by the kernel\n");
80991040Sarr			error = EBUSY;
81091040Sarr			goto out;
81191040Sarr		}
81291068Sarr		lf->userrefs--;
81391040Sarr		error = linker_file_unload(lf);
81491040Sarr		if (error)
81591040Sarr			lf->userrefs++;
81691040Sarr	} else
81791040Sarr		error = ENOENT;
81825537Sdfrout:
81991068Sarr	mtx_unlock(&Giant);
82091068Sarr	return (error);
82125537Sdfr}
82225537Sdfr
82382749Sdillon/*
82482749Sdillon * MPSAFE
82582749Sdillon */
82625537Sdfrint
82791040Sarrkldfind(struct thread *td, struct kldfind_args *uap)
82825537Sdfr{
82991040Sarr	char *pathname;
83091040Sarr	const char *filename;
83191040Sarr	linker_file_t lf;
83291040Sarr	int error = 0;
83325537Sdfr
834107089Srwatson#ifdef MAC
835107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
836107089Srwatson	if (error)
837107089Srwatson		return (error);
838107089Srwatson#endif
839107089Srwatson
84091040Sarr	mtx_lock(&Giant);
84191040Sarr	td->td_retval[0] = -1;
84282749Sdillon
84391040Sarr	pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
84491040Sarr	if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN,
84591040Sarr	    NULL)) != 0)
84691040Sarr		goto out;
84725537Sdfr
84891040Sarr	filename = linker_basename(pathname);
84991040Sarr	lf = linker_find_file_by_name(filename);
85091040Sarr	if (lf)
85191040Sarr		td->td_retval[0] = lf->id;
85291040Sarr	else
85391040Sarr		error = ENOENT;
85425537Sdfrout:
85591040Sarr	if (pathname)
85691040Sarr		free(pathname, M_TEMP);
85791040Sarr	mtx_unlock(&Giant);
85891040Sarr	return (error);
85925537Sdfr}
86025537Sdfr
86182749Sdillon/*
86282749Sdillon * MPSAFE
86382749Sdillon */
86425537Sdfrint
86591040Sarrkldnext(struct thread *td, struct kldnext_args *uap)
86625537Sdfr{
86791040Sarr	linker_file_t lf;
86891040Sarr	int error = 0;
86925537Sdfr
870107089Srwatson#ifdef MAC
871107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
872107089Srwatson	if (error)
873107089Srwatson		return (error);
874107089Srwatson#endif
875107089Srwatson
87691040Sarr	mtx_lock(&Giant);
87782749Sdillon
87891040Sarr	if (SCARG(uap, fileid) == 0) {
87998452Sarr		mtx_lock(&kld_mtx);
88091040Sarr		if (TAILQ_FIRST(&linker_files))
88191040Sarr			td->td_retval[0] = TAILQ_FIRST(&linker_files)->id;
88291040Sarr		else
88391040Sarr			td->td_retval[0] = 0;
88498452Sarr		mtx_unlock(&kld_mtx);
88591040Sarr		goto out;
88691040Sarr	}
88791040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
88891040Sarr	if (lf) {
88991040Sarr		if (TAILQ_NEXT(lf, link))
89091040Sarr			td->td_retval[0] = TAILQ_NEXT(lf, link)->id;
89191040Sarr		else
89291040Sarr			td->td_retval[0] = 0;
89391040Sarr	} else
89491040Sarr		error = ENOENT;
89582749Sdillonout:
89691040Sarr	mtx_unlock(&Giant);
89791040Sarr	return (error);
89825537Sdfr}
89925537Sdfr
90082749Sdillon/*
90182749Sdillon * MPSAFE
90282749Sdillon */
90325537Sdfrint
90491040Sarrkldstat(struct thread *td, struct kldstat_args *uap)
90525537Sdfr{
90691040Sarr	linker_file_t lf;
90791040Sarr	int error = 0;
90891040Sarr	int namelen, version;
90991040Sarr	struct kld_file_stat *stat;
91025537Sdfr
911107089Srwatson#ifdef MAC
912107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
913107089Srwatson	if (error)
914107089Srwatson		return (error);
915107089Srwatson#endif
916107089Srwatson
91791040Sarr	mtx_lock(&Giant);
91882749Sdillon
91991040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
92091040Sarr	if (lf == NULL) {
92191040Sarr		error = ENOENT;
92291040Sarr		goto out;
92391040Sarr	}
92491040Sarr	stat = SCARG(uap, stat);
92525537Sdfr
92691040Sarr	/*
92791040Sarr	 * Check the version of the user's structure.
92891040Sarr	 */
92991040Sarr	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
93091040Sarr		goto out;
93191040Sarr	if (version != sizeof(struct kld_file_stat)) {
93291040Sarr		error = EINVAL;
93391040Sarr		goto out;
93491040Sarr	}
93591040Sarr	namelen = strlen(lf->filename) + 1;
93691040Sarr	if (namelen > MAXPATHLEN)
93791040Sarr		namelen = MAXPATHLEN;
93891040Sarr	if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
93991040Sarr		goto out;
94091040Sarr	if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
94191040Sarr		goto out;
94291040Sarr	if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
94391040Sarr		goto out;
94491040Sarr	if ((error = copyout(&lf->address, &stat->address,
94591040Sarr	    sizeof(caddr_t))) != 0)
94691040Sarr		goto out;
94791040Sarr	if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
94891040Sarr		goto out;
94925537Sdfr
95091040Sarr	td->td_retval[0] = 0;
95125537Sdfrout:
95291040Sarr	mtx_unlock(&Giant);
95391040Sarr	return (error);
95425537Sdfr}
95525537Sdfr
95682749Sdillon/*
95782749Sdillon * MPSAFE
95882749Sdillon */
95925537Sdfrint
96091040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap)
96125537Sdfr{
96291040Sarr	linker_file_t lf;
96391040Sarr	module_t mp;
96491040Sarr	int error = 0;
96525537Sdfr
966107089Srwatson#ifdef MAC
967107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
968107089Srwatson	if (error)
969107089Srwatson		return (error);
970107089Srwatson#endif
971107089Srwatson
97291040Sarr	mtx_lock(&Giant);
97391040Sarr	lf = linker_find_file_by_id(SCARG(uap, fileid));
97491040Sarr	if (lf) {
97592547Sarr		MOD_SLOCK;
97691040Sarr		mp = TAILQ_FIRST(&lf->modules);
97791040Sarr		if (mp != NULL)
97891040Sarr			td->td_retval[0] = module_getid(mp);
97991040Sarr		else
98091040Sarr			td->td_retval[0] = 0;
98192547Sarr		MOD_SUNLOCK;
98291040Sarr	} else
98391040Sarr		error = ENOENT;
98491040Sarr	mtx_unlock(&Giant);
98591040Sarr	return (error);
98625537Sdfr}
98740159Speter
98882749Sdillon/*
98982749Sdillon * MPSAFE
99082749Sdillon */
99141090Speterint
99283366Sjuliankldsym(struct thread *td, struct kldsym_args *uap)
99341090Speter{
99491040Sarr	char *symstr = NULL;
99591040Sarr	c_linker_sym_t sym;
99691040Sarr	linker_symval_t symval;
99791040Sarr	linker_file_t lf;
99891040Sarr	struct kld_sym_lookup lookup;
99991040Sarr	int error = 0;
100041090Speter
1001107089Srwatson#ifdef MAC
1002107089Srwatson	error = mac_check_kld_stat(td->td_ucred);
1003107089Srwatson	if (error)
1004107089Srwatson		return (error);
1005107089Srwatson#endif
1006107089Srwatson
100791040Sarr	mtx_lock(&Giant);
100882749Sdillon
100991040Sarr	if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
101091040Sarr		goto out;
101191068Sarr	if (lookup.version != sizeof(lookup) ||
101291040Sarr	    SCARG(uap, cmd) != KLDSYM_LOOKUP) {
101391040Sarr		error = EINVAL;
101491040Sarr		goto out;
101591040Sarr	}
101691040Sarr	symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
101791040Sarr	if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
101891040Sarr		goto out;
101991040Sarr	if (SCARG(uap, fileid) != 0) {
102091040Sarr		lf = linker_find_file_by_id(SCARG(uap, fileid));
102191040Sarr		if (lf == NULL) {
102291040Sarr			error = ENOENT;
102391040Sarr			goto out;
102491040Sarr		}
102591040Sarr		if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
102691040Sarr		    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
102791040Sarr			lookup.symvalue = (uintptr_t) symval.value;
102891040Sarr			lookup.symsize = symval.size;
102991040Sarr			error = copyout(&lookup, SCARG(uap, data),
103091040Sarr			    sizeof(lookup));
103191040Sarr		} else
103291040Sarr			error = ENOENT;
103391040Sarr	} else {
103498452Sarr		mtx_lock(&kld_mtx);
103591040Sarr		TAILQ_FOREACH(lf, &linker_files, link) {
103691040Sarr			if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
103791040Sarr			    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
103891040Sarr				lookup.symvalue = (uintptr_t)symval.value;
103991040Sarr				lookup.symsize = symval.size;
104091040Sarr				error = copyout(&lookup, SCARG(uap, data),
104191040Sarr				    sizeof(lookup));
104291068Sarr				break;
104391040Sarr			}
104491040Sarr		}
104598452Sarr		mtx_unlock(&kld_mtx);
104691040Sarr		if (lf == NULL)
104791040Sarr			error = ENOENT;
104841090Speter	}
104941090Speterout:
105091040Sarr	if (symstr)
105191040Sarr		free(symstr, M_TEMP);
105291040Sarr	mtx_unlock(&Giant);
105391040Sarr	return (error);
105441090Speter}
105541090Speter
105640159Speter/*
105740159Speter * Preloaded module support
105840159Speter */
105940159Speter
106059751Speterstatic modlist_t
106174642Sbpmodlist_lookup(const char *name, int ver)
106259751Speter{
106391040Sarr	modlist_t mod;
106459751Speter
106591040Sarr	TAILQ_FOREACH(mod, &found_modules, link) {
106692032Sdwmalone		if (strcmp(mod->name, name) == 0 &&
106792032Sdwmalone		    (ver == 0 || mod->version == ver))
106891040Sarr			return (mod);
106991040Sarr	}
107091040Sarr	return (NULL);
107159751Speter}
107259751Speter
107374642Sbpstatic modlist_t
107483321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo)
107583321Speter{
107691040Sarr	modlist_t mod, bestmod;
107792032Sdwmalone	int ver;
107883321Speter
107991040Sarr	if (verinfo == NULL)
108091040Sarr		return (modlist_lookup(name, 0));
108191040Sarr	bestmod = NULL;
108291040Sarr	for (mod = TAILQ_FIRST(&found_modules); mod;
108391040Sarr	    mod = TAILQ_NEXT(mod, link)) {
108492032Sdwmalone		if (strcmp(mod->name, name) != 0)
108591040Sarr			continue;
108691040Sarr		ver = mod->version;
108791040Sarr		if (ver == verinfo->md_ver_preferred)
108891040Sarr			return (mod);
108991040Sarr		if (ver >= verinfo->md_ver_minimum &&
109091068Sarr		    ver <= verinfo->md_ver_maximum &&
109191068Sarr		    ver > bestmod->version)
109291040Sarr			bestmod = mod;
109391040Sarr	}
109491040Sarr	return (bestmod);
109583321Speter}
109683321Speter
109783321Speterstatic modlist_t
109878501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container)
109974642Sbp{
110091040Sarr	modlist_t mod;
110174642Sbp
110292705Sarr	mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO);
110391040Sarr	if (mod == NULL)
110491040Sarr		panic("no memory for module list");
110591040Sarr	mod->container = container;
110691040Sarr	mod->name = modname;
110791040Sarr	mod->version = version;
110891040Sarr	TAILQ_INSERT_TAIL(&found_modules, mod, link);
110991040Sarr	return (mod);
111074642Sbp}
111174642Sbp
111259751Speter/*
111359751Speter * This routine is cheap and nasty but will work for data pointers.
111459751Speter */
111559751Speterstatic void *
111678501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset)
111759751Speter{
111891040Sarr	return (lf->address + (uintptr_t)offset);
111959751Speter}
112059751Speter
112174642Sbp/*
112274642Sbp * Dereference MDT_VERSION metadata into module name and version
112374642Sbp */
112440159Speterstatic void
112574642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
112691040Sarr    const char **modname, int *version)
112774642Sbp{
112891040Sarr	struct mod_version *mvp;
112974642Sbp
113091040Sarr	if (modname)
113191040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
113291040Sarr	if (version) {
113391040Sarr		mvp = linker_reloc_ptr(lf, mp->md_data);
113491040Sarr		*version = mvp->mv_version;
113591040Sarr	}
113674642Sbp}
113774642Sbp
113874642Sbp/*
113974642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure
114074642Sbp */
114174642Sbpstatic void
114274642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
114391040Sarr    const char **modname, struct mod_depend **verinfo)
114474642Sbp{
114574642Sbp
114691040Sarr	if (modname)
114791040Sarr		*modname = linker_reloc_ptr(lf, mp->md_cval);
114891040Sarr	if (verinfo)
114991040Sarr		*verinfo = linker_reloc_ptr(lf, mp->md_data);
115074642Sbp}
115174642Sbp
115274642Sbpstatic void
115378161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start,
115491040Sarr    struct mod_metadata **stop, int preload)
115574642Sbp{
115691040Sarr	struct mod_metadata *mp, **mdp;
115791040Sarr	const char *modname;
115891040Sarr	int ver;
115974642Sbp
116091040Sarr	for (mdp = start; mdp < stop; mdp++) {
116191040Sarr		if (preload)
116291040Sarr			mp = *mdp;
116391040Sarr		else
116491040Sarr			mp = linker_reloc_ptr(lf, *mdp);
116591040Sarr		if (mp->md_type != MDT_VERSION)
116691040Sarr			continue;
116791040Sarr		if (preload) {
116891040Sarr			modname = mp->md_cval;
116991040Sarr			ver = ((struct mod_version *)mp->md_data)->mv_version;
117091040Sarr		} else
117191040Sarr	        	linker_mdt_version(lf, mp, &modname, &ver);
117291040Sarr		if (modlist_lookup(modname, ver) != NULL) {
117391040Sarr			printf("module %s already present!\n", modname);
117491040Sarr			/* XXX what can we do? this is a build error. :-( */
117591040Sarr			continue;
117691040Sarr		}
117791040Sarr		modlist_newmodule(modname, ver, lf);
117874642Sbp	}
117974642Sbp}
118074642Sbp
118174642Sbpstatic void
118291040Sarrlinker_preload(void *arg)
118340159Speter{
118491040Sarr	caddr_t modptr;
118591040Sarr	const char *modname, *nmodname;
118691040Sarr	char *modtype;
118791040Sarr	linker_file_t lf;
118891040Sarr	linker_class_t lc;
118992032Sdwmalone	int error;
119091040Sarr	linker_file_list_t loaded_files;
119191040Sarr	linker_file_list_t depended_files;
119291040Sarr	struct mod_metadata *mp, *nmp;
119391040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
119491040Sarr	struct mod_depend *verinfo;
119591040Sarr	int nver;
119691040Sarr	int resolves;
119791040Sarr	modlist_t mod;
119891040Sarr	struct sysinit **si_start, **si_stop;
119940159Speter
120091040Sarr	TAILQ_INIT(&loaded_files);
120191040Sarr	TAILQ_INIT(&depended_files);
120291040Sarr	TAILQ_INIT(&found_modules);
120391040Sarr	error = 0;
120459751Speter
120591040Sarr	modptr = NULL;
120691040Sarr	while ((modptr = preload_search_next_name(modptr)) != NULL) {
120791040Sarr		modname = (char *)preload_search_info(modptr, MODINFO_NAME);
120891040Sarr		modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
120991040Sarr		if (modname == NULL) {
121091040Sarr			printf("Preloaded module at %p does not have a"
121191040Sarr			    " name!\n", modptr);
121291040Sarr			continue;
121391040Sarr		}
121491040Sarr		if (modtype == NULL) {
121591040Sarr			printf("Preloaded module at %p does not have a type!\n",
121691040Sarr			    modptr);
121791040Sarr			continue;
121891040Sarr		}
121991040Sarr		printf("Preloaded %s \"%s\" at %p.\n", modtype, modname,
122091040Sarr		    modptr);
122140159Speter		lf = NULL;
122291040Sarr		TAILQ_FOREACH(lc, &classes, link) {
122391040Sarr			error = LINKER_LINK_PRELOAD(lc, modname, &lf);
122491040Sarr			if (error) {
122591040Sarr				lf = NULL;
122691040Sarr				break;
122791040Sarr			}
122891040Sarr		}
122991040Sarr		if (lf)
123091040Sarr			TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
123140159Speter	}
123240159Speter
123391040Sarr	/*
123491040Sarr	 * First get a list of stuff in the kernel.
123591040Sarr	 */
123691040Sarr	if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start,
123791040Sarr	    &stop, NULL) == 0)
123891040Sarr		linker_addmodules(linker_kernel_file, start, stop, 1);
123959751Speter
124059751Speter	/*
124191040Sarr	 * this is a once-off kinky bubble sort resolve relocation dependency
124291040Sarr	 * requirements
124359751Speter	 */
124491040Sarrrestart:
124591040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
124691040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
124791040Sarr		    &stop, NULL);
124891040Sarr		/*
124991040Sarr		 * First, look to see if we would successfully link with this
125091040Sarr		 * stuff.
125191040Sarr		 */
125291040Sarr		resolves = 1;	/* unless we know otherwise */
125391040Sarr		if (!error) {
125491040Sarr			for (mdp = start; mdp < stop; mdp++) {
125591040Sarr				mp = linker_reloc_ptr(lf, *mdp);
125691040Sarr				if (mp->md_type != MDT_DEPEND)
125791040Sarr					continue;
125891040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
125991040Sarr				for (nmdp = start; nmdp < stop; nmdp++) {
126091040Sarr					nmp = linker_reloc_ptr(lf, *nmdp);
126191040Sarr					if (nmp->md_type != MDT_VERSION)
126291040Sarr						continue;
126391040Sarr					linker_mdt_version(lf, nmp, &nmodname,
126491040Sarr					    NULL);
126591040Sarr					nmodname = linker_reloc_ptr(lf,
126691040Sarr					    nmp->md_cval);
126792032Sdwmalone					if (strcmp(modname, nmodname) == 0)
126891040Sarr						break;
126991040Sarr				}
127091040Sarr				if (nmdp < stop)   /* it's a self reference */
127191040Sarr					continue;
127291040Sarr
127391040Sarr				/*
127491040Sarr				 * ok, the module isn't here yet, we
127591040Sarr				 * are not finished
127691040Sarr				 */
127791068Sarr				if (modlist_lookup2(modname, verinfo) == NULL)
127891040Sarr					resolves = 0;
127991040Sarr			}
128064143Speter		}
128191040Sarr		/*
128291040Sarr		 * OK, if we found our modules, we can link.  So, "provide"
128391040Sarr		 * the modules inside and add it to the end of the link order
128491040Sarr		 * list.
128591040Sarr		 */
128691040Sarr		if (resolves) {
128791040Sarr			if (!error) {
128891040Sarr				for (mdp = start; mdp < stop; mdp++) {
128991040Sarr					mp = linker_reloc_ptr(lf, *mdp);
129091040Sarr					if (mp->md_type != MDT_VERSION)
129191040Sarr						continue;
129291040Sarr					linker_mdt_version(lf, mp,
129391040Sarr					    &modname, &nver);
129491040Sarr					if (modlist_lookup(modname,
129591040Sarr					    nver) != NULL) {
129691040Sarr						printf("module %s already"
129791040Sarr						    " present!\n", modname);
129891040Sarr						linker_file_unload(lf);
129991040Sarr						TAILQ_REMOVE(&loaded_files,
130091040Sarr						    lf, loaded);
130191040Sarr						/* we changed tailq next ptr */
130291068Sarr						goto restart;
130391040Sarr					}
130491040Sarr					modlist_newmodule(modname, nver, lf);
130591040Sarr				}
130691040Sarr			}
130791040Sarr			TAILQ_REMOVE(&loaded_files, lf, loaded);
130891040Sarr			TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
130991040Sarr			/*
131091040Sarr			 * Since we provided modules, we need to restart the
131191040Sarr			 * sort so that the previous files that depend on us
131291040Sarr			 * have a chance. Also, we've busted the tailq next
131391040Sarr			 * pointer with the REMOVE.
131491040Sarr			 */
131591040Sarr			goto restart;
131659751Speter		}
131759751Speter	}
131891040Sarr
131959751Speter	/*
132091040Sarr	 * At this point, we check to see what could not be resolved..
132159751Speter	 */
132291040Sarr	TAILQ_FOREACH(lf, &loaded_files, loaded) {
132391040Sarr		printf("KLD file %s is missing dependencies\n", lf->filename);
132491040Sarr		linker_file_unload(lf);
132591040Sarr		TAILQ_REMOVE(&loaded_files, lf, loaded);
132640159Speter	}
132759751Speter
132878161Speter	/*
132991040Sarr	 * We made it. Finish off the linking in the order we determined.
133078161Speter	 */
133191040Sarr	TAILQ_FOREACH(lf, &depended_files, loaded) {
133291040Sarr		if (linker_kernel_file) {
133391040Sarr			linker_kernel_file->refs++;
133491040Sarr			error = linker_file_add_dependency(lf,
133591040Sarr			    linker_kernel_file);
133691040Sarr			if (error)
133791040Sarr				panic("cannot add dependency");
133891040Sarr		}
133991040Sarr		lf->userrefs++;	/* so we can (try to) kldunload it */
134091040Sarr		error = linker_file_lookup_set(lf, MDT_SETNAME, &start,
134191040Sarr		    &stop, NULL);
134291040Sarr		if (!error) {
134391040Sarr			for (mdp = start; mdp < stop; mdp++) {
134491040Sarr				mp = linker_reloc_ptr(lf, *mdp);
134591040Sarr				if (mp->md_type != MDT_DEPEND)
134691040Sarr					continue;
134791040Sarr				linker_mdt_depend(lf, mp, &modname, &verinfo);
134891040Sarr				mod = modlist_lookup2(modname, verinfo);
134991040Sarr				mod->container->refs++;
135091040Sarr				error = linker_file_add_dependency(lf,
135191040Sarr				    mod->container);
135291040Sarr				if (error)
135391040Sarr					panic("cannot add dependency");
135491040Sarr			}
135591040Sarr		}
135691040Sarr		/*
135791040Sarr		 * Now do relocation etc using the symbol search paths
135891040Sarr		 * established by the dependencies
135991040Sarr		 */
136091040Sarr		error = LINKER_LINK_PRELOAD_FINISH(lf);
136191040Sarr		if (error) {
136291040Sarr			printf("KLD file %s - could not finalize loading\n",
136391040Sarr			    lf->filename);
136491040Sarr			linker_file_unload(lf);
136591040Sarr			continue;
136691040Sarr		}
136791040Sarr		linker_file_register_modules(lf);
136891040Sarr		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
136991040Sarr		    &si_stop, NULL) == 0)
137091040Sarr			sysinit_add(si_start, si_stop);
137191040Sarr		linker_file_register_sysctls(lf);
137291040Sarr		lf->flags |= LINKER_FILE_LINKED;
137359751Speter	}
137491040Sarr	/* woohoo! we made it! */
137540159Speter}
137640159Speter
137791040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0)
137840159Speter
137940159Speter/*
138040159Speter * Search for a not-loaded module by name.
138191040Sarr *
138240159Speter * Modules may be found in the following locations:
138391040Sarr *
138491040Sarr * - preloaded (result is just the module name) - on disk (result is full path
138591040Sarr * to module)
138691040Sarr *
138791040Sarr * If the module name is qualified in any way (contains path, etc.) the we
138891040Sarr * simply return a copy of it.
138991040Sarr *
139040159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
139140159Speter * character as a separator to be consistent with the bootloader.
139240159Speter */
139340159Speter
139483321Speterstatic char linker_hintfile[] = "linker.hints";
139583358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules";
139640159Speter
139740159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
139891040Sarr    sizeof(linker_path), "module load search path");
139940159Speter
140077843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path));
140170417Speter
140259751Speterstatic char *linker_ext_list[] = {
140383321Speter	"",
140459751Speter	".ko",
140559751Speter	NULL
140659751Speter};
140759751Speter
140883321Speter/*
140991040Sarr * Check if file actually exists either with or without extension listed in
141091040Sarr * the linker_ext_list. (probably should be generic for the rest of the
141191040Sarr * kernel)
141283321Speter */
141359751Speterstatic char *
141491040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name,
141591040Sarr    int namelen, struct vattr *vap)
141640159Speter{
141791040Sarr	struct nameidata nd;
141891040Sarr	struct thread *td = curthread;	/* XXX */
141991040Sarr	char *result, **cpp, *sep;
142091040Sarr	int error, len, extlen, reclen, flags;
142191040Sarr	enum vtype type;
142240159Speter
142391040Sarr	extlen = 0;
142491040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
142591040Sarr		len = strlen(*cpp);
142691040Sarr		if (len > extlen)
142791040Sarr			extlen = len;
142891040Sarr	}
142991040Sarr	extlen++;		/* trailing '\0' */
143091040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
143183321Speter
143291040Sarr	reclen = pathlen + strlen(sep) + namelen + extlen + 1;
143391040Sarr	result = malloc(reclen, M_LINKER, M_WAITOK);
143491040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
143591040Sarr		snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep,
143691040Sarr		    namelen, name, *cpp);
143791040Sarr		/*
143891040Sarr		 * Attempt to open the file, and return the path if
143991040Sarr		 * we succeed and it's a regular file.
144091040Sarr		 */
144191040Sarr		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td);
144291040Sarr		flags = FREAD;
144391040Sarr		error = vn_open(&nd, &flags, 0);
144491040Sarr		if (error == 0) {
144591040Sarr			NDFREE(&nd, NDF_ONLY_PNBUF);
144691040Sarr			type = nd.ni_vp->v_type;
144791040Sarr			if (vap)
144891406Sjhb				VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
144991040Sarr			VOP_UNLOCK(nd.ni_vp, 0, td);
145091406Sjhb			vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
145191040Sarr			if (type == VREG)
145291040Sarr				return (result);
145391040Sarr		}
145483321Speter	}
145591040Sarr	free(result, M_LINKER);
145691040Sarr	return (NULL);
145783321Speter}
145883321Speter
145991040Sarr#define	INT_ALIGN(base, ptr)	ptr =					\
146083321Speter	(base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1))
146183321Speter
146283321Speter/*
146391040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If
146491040Sarr * version specification is available, then try to find the best KLD.
146583321Speter * Otherwise just find the latest one.
146683321Speter */
146783321Speterstatic char *
146891040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname,
146991040Sarr    int modnamelen, struct mod_depend *verinfo)
147083321Speter{
147191040Sarr	struct thread *td = curthread;	/* XXX */
147291406Sjhb	struct ucred *cred = td ? td->td_ucred : NULL;
147391040Sarr	struct nameidata nd;
147491040Sarr	struct vattr vattr, mattr;
147591040Sarr	u_char *hints = NULL;
147691040Sarr	u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep;
147791040Sarr	int error, ival, bestver, *intp, reclen, found, flags, clen, blen;
147883321Speter
147991040Sarr	result = NULL;
148091040Sarr	bestver = found = 0;
148183321Speter
148291040Sarr	sep = (path[pathlen - 1] != '/') ? "/" : "";
148391040Sarr	reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen +
148491040Sarr	    strlen(sep) + 1;
148591040Sarr	pathbuf = malloc(reclen, M_LINKER, M_WAITOK);
148691040Sarr	snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep,
148791040Sarr	    linker_hintfile);
148883321Speter
148991040Sarr	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td);
149091040Sarr	flags = FREAD;
149191040Sarr	error = vn_open(&nd, &flags, 0);
149291040Sarr	if (error)
149391040Sarr		goto bad;
149491040Sarr	NDFREE(&nd, NDF_ONLY_PNBUF);
149591040Sarr	if (nd.ni_vp->v_type != VREG)
149691040Sarr		goto bad;
149791040Sarr	best = cp = NULL;
149891040Sarr	error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td);
149991040Sarr	if (error)
150091040Sarr		goto bad;
150191040Sarr	/*
150291040Sarr	 * XXX: we need to limit this number to some reasonable value
150391040Sarr	 */
150491040Sarr	if (vattr.va_size > 100 * 1024) {
150591040Sarr		printf("hints file too large %ld\n", (long)vattr.va_size);
150691040Sarr		goto bad;
150791040Sarr	}
150891040Sarr	hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
150991040Sarr	if (hints == NULL)
151091040Sarr		goto bad;
151191068Sarr	error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
1512101941Srwatson	    UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td);
151391040Sarr	if (error)
151491040Sarr		goto bad;
151599553Sjeff	VOP_UNLOCK(nd.ni_vp, 0, td);
151691040Sarr	vn_close(nd.ni_vp, FREAD, cred, td);
151791040Sarr	nd.ni_vp = NULL;
151891040Sarr	if (reclen != 0) {
151991040Sarr		printf("can't read %d\n", reclen);
152091040Sarr		goto bad;
152191040Sarr	}
152291040Sarr	intp = (int *)hints;
152383321Speter	ival = *intp++;
152491040Sarr	if (ival != LINKER_HINTS_VERSION) {
152591040Sarr		printf("hints file version mismatch %d\n", ival);
152691040Sarr		goto bad;
152783321Speter	}
152891040Sarr	bufend = hints + vattr.va_size;
152991040Sarr	recptr = (u_char *)intp;
153091040Sarr	clen = blen = 0;
153191040Sarr	while (recptr < bufend && !found) {
153291040Sarr		intp = (int *)recptr;
153391040Sarr		reclen = *intp++;
153491040Sarr		ival = *intp++;
153591040Sarr		cp = (char *)intp;
153691040Sarr		switch (ival) {
153791040Sarr		case MDT_VERSION:
153891040Sarr			clen = *cp++;
153991040Sarr			if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
154091040Sarr				break;
154191040Sarr			cp += clen;
154291040Sarr			INT_ALIGN(hints, cp);
154391040Sarr			ival = *(int *)cp;
154491040Sarr			cp += sizeof(int);
154591040Sarr			clen = *cp++;
154691040Sarr			if (verinfo == NULL ||
154791040Sarr			    ival == verinfo->md_ver_preferred) {
154891040Sarr				found = 1;
154991040Sarr				break;
155091040Sarr			}
155191040Sarr			if (ival >= verinfo->md_ver_minimum &&
155291040Sarr			    ival <= verinfo->md_ver_maximum &&
155391040Sarr			    ival > bestver) {
155491040Sarr				bestver = ival;
155591040Sarr				best = cp;
155691040Sarr				blen = clen;
155791040Sarr			}
155891040Sarr			break;
155991040Sarr		default:
156091040Sarr			break;
156191040Sarr		}
156291040Sarr		recptr += reclen + sizeof(int);
156391040Sarr	}
156483321Speter	/*
156591040Sarr	 * Finally check if KLD is in the place
156683321Speter	 */
156791040Sarr	if (found)
156891040Sarr		result = linker_lookup_file(path, pathlen, cp, clen, &mattr);
156991040Sarr	else if (best)
157091040Sarr		result = linker_lookup_file(path, pathlen, best, blen, &mattr);
157191040Sarr
157291040Sarr	/*
157391040Sarr	 * KLD is newer than hints file. What we should do now?
157491040Sarr	 */
157591040Sarr	if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >))
157691040Sarr		printf("warning: KLD '%s' is newer than the linker.hints"
157791040Sarr		    " file\n", result);
157883321Speterbad:
1579105167Sphk	free(pathbuf, M_LINKER);
158091040Sarr	if (hints)
158191040Sarr		free(hints, M_TEMP);
158299553Sjeff	if (nd.ni_vp != NULL) {
158399553Sjeff		VOP_UNLOCK(nd.ni_vp, 0, td);
158491040Sarr		vn_close(nd.ni_vp, FREAD, cred, td);
158599553Sjeff	}
158691040Sarr	/*
158791040Sarr	 * If nothing found or hints is absent - fallback to the old
158891040Sarr	 * way by using "kldname[.ko]" as module name.
158991040Sarr	 */
159091040Sarr	if (!found && !bestver && result == NULL)
159191040Sarr		result = linker_lookup_file(path, pathlen, modname,
159291040Sarr		    modnamelen, NULL);
159391040Sarr	return (result);
159483321Speter}
159583321Speter
159683321Speter/*
159783321Speter * Lookup KLD which contains requested module in the all directories.
159883321Speter */
159983321Speterstatic char *
160083321Speterlinker_search_module(const char *modname, int modnamelen,
160191040Sarr    struct mod_depend *verinfo)
160283321Speter{
160391040Sarr	char *cp, *ep, *result;
160483321Speter
160591040Sarr	/*
160691040Sarr	 * traverse the linker path
160791040Sarr	 */
160891040Sarr	for (cp = linker_path; *cp; cp = ep + 1) {
160991040Sarr		/* find the end of this component */
161091040Sarr		for (ep = cp; (*ep != 0) && (*ep != ';'); ep++);
161191068Sarr		result = linker_hints_lookup(cp, ep - cp, modname,
161291068Sarr		    modnamelen, verinfo);
161391040Sarr		if (result != NULL)
161491040Sarr			return (result);
161591040Sarr		if (*ep == 0)
161691040Sarr			break;
161791040Sarr	}
161891040Sarr	return (NULL);
161983321Speter}
162083321Speter
162183321Speter/*
162283321Speter * Search for module in all directories listed in the linker_path.
162383321Speter */
162483321Speterstatic char *
162583321Speterlinker_search_kld(const char *name)
162683321Speter{
162791040Sarr	char *cp, *ep, *result, **cpp;
162891040Sarr	int extlen, len;
162983321Speter
163091040Sarr	/* qualified at all? */
163191040Sarr	if (index(name, '/'))
163291040Sarr		return (linker_strdup(name));
163340159Speter
163491040Sarr	extlen = 0;
163591040Sarr	for (cpp = linker_ext_list; *cpp; cpp++) {
163691040Sarr		len = strlen(*cpp);
163791040Sarr		if (len > extlen)
163891040Sarr			extlen = len;
163991040Sarr	}
164091040Sarr	extlen++;		/* trailing '\0' */
164159751Speter
164291040Sarr	/* traverse the linker path */
164391040Sarr	len = strlen(name);
164491040Sarr	for (ep = linker_path; *ep; ep++) {
164591040Sarr		cp = ep;
164691040Sarr		/* find the end of this component */
164791040Sarr		for (; *ep != 0 && *ep != ';'; ep++);
164891040Sarr		result = linker_lookup_file(cp, ep - cp, name, len, NULL);
164991040Sarr		if (result != NULL)
165091040Sarr			return (result);
165191040Sarr	}
165291040Sarr	return (NULL);
165340159Speter}
165459751Speter
165559751Speterstatic const char *
165691040Sarrlinker_basename(const char *path)
165759751Speter{
165891040Sarr	const char *filename;
165959751Speter
166091040Sarr	filename = rindex(path, '/');
166191040Sarr	if (filename == NULL)
166291040Sarr		return path;
166391040Sarr	if (filename[1])
166491040Sarr		filename++;
166591040Sarr	return (filename);
166659751Speter}
166759751Speter
166859751Speter/*
166991040Sarr * Find a file which contains given module and load it, if "parent" is not
167091040Sarr * NULL, register a reference to it.
167159751Speter */
1672101241Smuxint
167383321Speterlinker_load_module(const char *kldname, const char *modname,
167491040Sarr    struct linker_file *parent, struct mod_depend *verinfo,
167591040Sarr    struct linker_file **lfpp)
167659751Speter{
167791040Sarr	linker_file_t lfdep;
167891040Sarr	const char *filename;
167991040Sarr	char *pathname;
168091040Sarr	int error;
168159751Speter
168291040Sarr	if (modname == NULL) {
168391040Sarr		/*
168491040Sarr 		 * We have to load KLD
168591040Sarr 		 */
168691068Sarr		KASSERT(verinfo == NULL, ("linker_load_module: verinfo"
168791068Sarr		    " is not NULL"));
168891040Sarr		pathname = linker_search_kld(kldname);
168991040Sarr	} else {
169091040Sarr		if (modlist_lookup2(modname, verinfo) != NULL)
169191040Sarr			return (EEXIST);
169294322Sbrian		if (kldname != NULL)
169394322Sbrian			pathname = linker_strdup(kldname);
169495488Sbrian		else if (rootvnode == NULL)
169594322Sbrian			pathname = NULL;
169694322Sbrian		else
169791040Sarr			/*
169891040Sarr			 * Need to find a KLD with required module
169991040Sarr			 */
170091040Sarr			pathname = linker_search_module(modname,
170191040Sarr			    strlen(modname), verinfo);
170291040Sarr	}
170391040Sarr	if (pathname == NULL)
170491040Sarr		return (ENOENT);
170591040Sarr
170683321Speter	/*
170791040Sarr	 * Can't load more than one file with the same basename XXX:
170891040Sarr	 * Actually it should be possible to have multiple KLDs with
170991040Sarr	 * the same basename but different path because they can
171091040Sarr	 * provide different versions of the same modules.
171183321Speter	 */
171291040Sarr	filename = linker_basename(pathname);
171391040Sarr	if (linker_find_file_by_name(filename)) {
171491040Sarr		error = EEXIST;
171591040Sarr		goto out;
171683321Speter	}
171791040Sarr	do {
171891040Sarr		error = linker_load_file(pathname, &lfdep);
171991040Sarr		if (error)
172091040Sarr			break;
172191040Sarr		if (modname && verinfo &&
172291040Sarr		    modlist_lookup2(modname, verinfo) == NULL) {
172391040Sarr			linker_file_unload(lfdep);
172491040Sarr			error = ENOENT;
172591040Sarr			break;
172691040Sarr		}
172791040Sarr		if (parent) {
172891040Sarr			error = linker_file_add_dependency(parent, lfdep);
172991040Sarr			if (error)
173091040Sarr				break;
173191040Sarr		}
173291040Sarr		if (lfpp)
173391040Sarr			*lfpp = lfdep;
173491040Sarr	} while (0);
173559751Speterout:
173691040Sarr	if (pathname)
173791040Sarr		free(pathname, M_LINKER);
173891040Sarr	return (error);
173959751Speter}
174059751Speter
174159751Speter/*
174291040Sarr * This routine is responsible for finding dependencies of userland initiated
174391040Sarr * kldload(2)'s of files.
174459751Speter */
174559751Speterint
174686469Siedowselinker_load_dependencies(linker_file_t lf)
174759751Speter{
174891040Sarr	linker_file_t lfdep;
174991040Sarr	struct mod_metadata **start, **stop, **mdp, **nmdp;
175091040Sarr	struct mod_metadata *mp, *nmp;
175191040Sarr	struct mod_depend *verinfo;
175291040Sarr	modlist_t mod;
175391040Sarr	const char *modname, *nmodname;
175492032Sdwmalone	int ver, error = 0, count;
175559751Speter
175691040Sarr	/*
175791040Sarr	 * All files are dependant on /kernel.
175891040Sarr	 */
175991040Sarr	if (linker_kernel_file) {
176091040Sarr		linker_kernel_file->refs++;
176191040Sarr		error = linker_file_add_dependency(lf, linker_kernel_file);
176291040Sarr		if (error)
176391040Sarr			return (error);
176459751Speter	}
176591040Sarr	if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop,
176691040Sarr	    &count) != 0)
176791040Sarr		return (0);
176891040Sarr	for (mdp = start; mdp < stop; mdp++) {
176991040Sarr		mp = linker_reloc_ptr(lf, *mdp);
177091040Sarr		if (mp->md_type != MDT_VERSION)
177191040Sarr			continue;
177291040Sarr		linker_mdt_version(lf, mp, &modname, &ver);
177391040Sarr		mod = modlist_lookup(modname, ver);
177491040Sarr		if (mod != NULL) {
177591040Sarr			printf("interface %s.%d already present in the KLD"
177691040Sarr			    " '%s'!\n", modname, ver,
177791040Sarr			    mod->container->filename);
177891040Sarr			return (EEXIST);
177991040Sarr		}
178091040Sarr	}
178174642Sbp
178291040Sarr	for (mdp = start; mdp < stop; mdp++) {
178391040Sarr		mp = linker_reloc_ptr(lf, *mdp);
178491040Sarr		if (mp->md_type != MDT_DEPEND)
178591040Sarr			continue;
178691040Sarr		linker_mdt_depend(lf, mp, &modname, &verinfo);
178791040Sarr		nmodname = NULL;
178891040Sarr		for (nmdp = start; nmdp < stop; nmdp++) {
178991040Sarr			nmp = linker_reloc_ptr(lf, *nmdp);
179091040Sarr			if (nmp->md_type != MDT_VERSION)
179191040Sarr				continue;
179291040Sarr			nmodname = linker_reloc_ptr(lf, nmp->md_cval);
179392032Sdwmalone			if (strcmp(modname, nmodname) == 0)
179491040Sarr				break;
179591040Sarr		}
179691040Sarr		if (nmdp < stop)/* early exit, it's a self reference */
179791040Sarr			continue;
179891040Sarr		mod = modlist_lookup2(modname, verinfo);
179991040Sarr		if (mod) {	/* woohoo, it's loaded already */
180091040Sarr			lfdep = mod->container;
180191040Sarr			lfdep->refs++;
180291040Sarr			error = linker_file_add_dependency(lf, lfdep);
180391040Sarr			if (error)
180491040Sarr				break;
180591040Sarr			continue;
180691040Sarr		}
180791040Sarr		error = linker_load_module(NULL, modname, lf, verinfo, NULL);
180891040Sarr		if (error) {
180991040Sarr			printf("KLD %s: depends on %s - not available\n",
181091040Sarr			    lf->filename, modname);
181191040Sarr			break;
181291040Sarr		}
181359751Speter	}
181459751Speter
181591040Sarr	if (error)
181691040Sarr		return (error);
181791040Sarr	linker_addmodules(lf, start, stop, 0);
181891040Sarr	return (error);
181959751Speter}
182085736Sgreen
182185736Sgreenstatic int
182285736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque)
182385736Sgreen{
182485736Sgreen	struct sysctl_req *req;
182585736Sgreen
182685736Sgreen	req = opaque;
182785736Sgreen	return (SYSCTL_OUT(req, name, strlen(name) + 1));
182885736Sgreen}
182985736Sgreen
183085736Sgreen/*
183185736Sgreen * Export a nul-separated, double-nul-terminated list of all function names
183285736Sgreen * in the kernel.
183385736Sgreen */
183485736Sgreenstatic int
183585736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS)
183685736Sgreen{
183785736Sgreen	linker_file_t lf;
183885736Sgreen	int error;
183985736Sgreen
1840107089Srwatson#ifdef MAC
1841107089Srwatson	error = mac_check_kld_stat(req->td->td_ucred);
1842107089Srwatson	if (error)
1843107089Srwatson		return (error);
1844107089Srwatson#endif
1845100488Struckman	sysctl_wire_old_buffer(req, 0);
184698452Sarr	mtx_lock(&kld_mtx);
184785736Sgreen	TAILQ_FOREACH(lf, &linker_files, link) {
184885736Sgreen		error = LINKER_EACH_FUNCTION_NAME(lf,
184985736Sgreen		    sysctl_kern_function_list_iterate, req);
185098452Sarr		if (error) {
185198452Sarr			mtx_unlock(&kld_mtx);
185285736Sgreen			return (error);
185398452Sarr		}
185485736Sgreen	}
185598452Sarr	mtx_unlock(&kld_mtx);
185685736Sgreen	return (SYSCTL_OUT(req, "", 1));
185785736Sgreen}
185885736Sgreen
185985736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD,
186091040Sarr    NULL, 0, sysctl_kern_function_list, "", "kernel function list");
1861