kern_linker.c revision 196019
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 */ 2625537Sdfr 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_linker.c 196019 2009-08-01 19:26:27Z rwatson $"); 29116182Sobrien 3040159Speter#include "opt_ddb.h" 31157144Sjkoshy#include "opt_hwpmc_hooks.h" 3240159Speter 3325537Sdfr#include <sys/param.h> 3425537Sdfr#include <sys/kernel.h> 3525537Sdfr#include <sys/systm.h> 3625537Sdfr#include <sys/malloc.h> 3725537Sdfr#include <sys/sysproto.h> 3825537Sdfr#include <sys/sysent.h> 39164033Srwatson#include <sys/priv.h> 4025537Sdfr#include <sys/proc.h> 4125537Sdfr#include <sys/lock.h> 4282749Sdillon#include <sys/mutex.h> 4392547Sarr#include <sys/sx.h> 4425537Sdfr#include <sys/module.h> 45159808Sjhb#include <sys/mount.h> 4625537Sdfr#include <sys/linker.h> 4740159Speter#include <sys/fcntl.h> 48192895Sjamie#include <sys/jail.h> 4940159Speter#include <sys/libkern.h> 5040159Speter#include <sys/namei.h> 5140159Speter#include <sys/vnode.h> 52159588Sjhb#include <sys/syscallsubr.h> 5340159Speter#include <sys/sysctl.h> 5425537Sdfr 55196019Srwatson#include <net/vnet.h> 56196019Srwatson 57163606Srwatson#include <security/mac/mac_framework.h> 58163606Srwatson 5959603Sdfr#include "linker_if.h" 6059603Sdfr 61157144Sjkoshy#ifdef HWPMC_HOOKS 62157144Sjkoshy#include <sys/pmckern.h> 63157144Sjkoshy#endif 64157144Sjkoshy 6540961Speter#ifdef KLD_DEBUG 6640961Speterint kld_debug = 0; 6740961Speter#endif 6840961Speter 69160142Sjhb#define KLD_LOCK() sx_xlock(&kld_sx) 70160142Sjhb#define KLD_UNLOCK() sx_xunlock(&kld_sx) 71159845Sjhb#define KLD_LOCKED() sx_xlocked(&kld_sx) 72160142Sjhb#define KLD_LOCK_ASSERT() do { \ 73160142Sjhb if (!cold) \ 74160142Sjhb sx_assert(&kld_sx, SX_XLOCKED); \ 75160142Sjhb} while (0) 76159845Sjhb 7791040Sarr/* 7891040Sarr * static char *linker_search_path(const char *name, struct mod_depend 7991040Sarr * *verinfo); 8091040Sarr */ 8191040Sarrstatic const char *linker_basename(const char *path); 8259751Speter 83159800Sjhb/* 84159800Sjhb * Find a currently loaded file given its filename. 85159800Sjhb */ 86159800Sjhbstatic linker_file_t linker_find_file_by_name(const char* _filename); 87159800Sjhb 88159800Sjhb/* 89159800Sjhb * Find a currently loaded file given its file id. 90159800Sjhb */ 91159800Sjhbstatic linker_file_t linker_find_file_by_id(int _fileid); 92159800Sjhb 9378161Speter/* Metadata from the static kernel */ 9478161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 9578161Speter 9659751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 9759751Speter 9840906Speterlinker_file_t linker_kernel_file; 9931324Sbde 100159845Sjhbstatic struct sx kld_sx; /* kernel linker lock */ 10198452Sarr 102172862Sjb/* 103172862Sjb * Load counter used by clients to determine if a linker file has been 104172862Sjb * re-loaded. This counter is incremented for each file load. 105172862Sjb */ 106172862Sjbstatic int loadcnt; 107172862Sjb 10825537Sdfrstatic linker_class_list_t classes; 10950068Sgrogstatic linker_file_list_t linker_files; 11025537Sdfrstatic int next_file_id = 1; 11198452Sarrstatic int linker_no_more_classes = 0; 11225537Sdfr 11386553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 11491040Sarr linker_file_t lftmp; \ 11586553Sarr \ 116159845Sjhb KLD_LOCK_ASSERT(); \ 11786553Sarrretry: \ 11891040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 11991040Sarr if (next_file_id == lftmp->id) { \ 12091040Sarr next_file_id++; \ 12191040Sarr goto retry; \ 12291040Sarr } \ 12391040Sarr } \ 12491040Sarr (a) = next_file_id; \ 12586553Sarr} while(0) 12686553Sarr 12786553Sarr 12859751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 12960938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 13059751Speterstruct modlist { 13191040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 13291040Sarr linker_file_t container; 13391040Sarr const char *name; 13491040Sarr int version; 13559751Speter}; 13691040Sarrtypedef struct modlist *modlist_t; 13791040Sarrstatic modlisthead_t found_modules; 13859751Speter 139159796Sjhbstatic int linker_file_add_dependency(linker_file_t file, 140159796Sjhb linker_file_t dep); 141159845Sjhbstatic caddr_t linker_file_lookup_symbol_internal(linker_file_t file, 142159845Sjhb const char* name, int deps); 143159796Sjhbstatic int linker_load_module(const char *kldname, 144159796Sjhb const char *modname, struct linker_file *parent, 145159796Sjhb struct mod_depend *verinfo, struct linker_file **lfpp); 146159796Sjhbstatic modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); 14794321Sbrian 14859603Sdfrstatic char * 14959603Sdfrlinker_strdup(const char *str) 15059603Sdfr{ 15191040Sarr char *result; 15259603Sdfr 153111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 15491040Sarr strcpy(result, str); 15591040Sarr return (result); 15659603Sdfr} 15759603Sdfr 15825537Sdfrstatic void 15991040Sarrlinker_init(void *arg) 16025537Sdfr{ 16191040Sarr 162159845Sjhb sx_init(&kld_sx, "kernel linker"); 16391040Sarr TAILQ_INIT(&classes); 16491040Sarr TAILQ_INIT(&linker_files); 16525537Sdfr} 16625537Sdfr 167177253SrwatsonSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 16825537Sdfr 16998452Sarrstatic void 17098452Sarrlinker_stop_class_add(void *arg) 17198452Sarr{ 17298452Sarr 17398452Sarr linker_no_more_classes = 1; 17498452Sarr} 17598452Sarr 176177253SrwatsonSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL); 17798452Sarr 17825537Sdfrint 17959603Sdfrlinker_add_class(linker_class_t lc) 18025537Sdfr{ 18191040Sarr 18298452Sarr /* 183144443Sjhb * We disallow any class registration past SI_ORDER_ANY 184144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 185144443Sjhb * ops from being freed. 18698452Sarr */ 18798452Sarr if (linker_no_more_classes == 1) 18898452Sarr return (EPERM); 18991040Sarr kobj_class_compile((kobj_class_t) lc); 190144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 19191040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 19291040Sarr return (0); 19325537Sdfr} 19425537Sdfr 19525537Sdfrstatic void 19625537Sdfrlinker_file_sysinit(linker_file_t lf) 19725537Sdfr{ 19891040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 19925537Sdfr 20091040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 20191040Sarr lf->filename)); 20225537Sdfr 20391040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 20491040Sarr return; 20591040Sarr /* 20691040Sarr * Perform a bubble sort of the system initialization objects by 20791040Sarr * their subsystem (primary key) and order (secondary key). 208159840Sjhb * 20991040Sarr * Since some things care about execution order, this is the operation 21091040Sarr * which ensures continued function. 21191040Sarr */ 21291040Sarr for (sipp = start; sipp < stop; sipp++) { 21391040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 21491040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 21591040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 21691040Sarr (*sipp)->order <= (*xipp)->order)) 21791040Sarr continue; /* skip */ 21891040Sarr save = *sipp; 21991040Sarr *sipp = *xipp; 22091040Sarr *xipp = save; 22191040Sarr } 22225537Sdfr } 22325537Sdfr 22491040Sarr /* 22591040Sarr * Traverse the (now) ordered list of system initialization tasks. 22691040Sarr * Perform each task, and continue on to the next task. 22791040Sarr */ 228160142Sjhb mtx_lock(&Giant); 22991040Sarr for (sipp = start; sipp < stop; sipp++) { 23091040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 23191040Sarr continue; /* skip dummy task(s) */ 23225537Sdfr 23391040Sarr /* Call function */ 23491040Sarr (*((*sipp)->func)) ((*sipp)->udata); 23591040Sarr } 236160142Sjhb mtx_unlock(&Giant); 23725537Sdfr} 23825537Sdfr 23941055Speterstatic void 24041055Speterlinker_file_sysuninit(linker_file_t lf) 24141055Speter{ 24291040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 24341055Speter 24491040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 24591040Sarr lf->filename)); 24641055Speter 24791068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 24891040Sarr NULL) != 0) 24991040Sarr return; 25041055Speter 25191040Sarr /* 25291040Sarr * Perform a reverse bubble sort of the system initialization objects 25391040Sarr * by their subsystem (primary key) and order (secondary key). 254159840Sjhb * 25591040Sarr * Since some things care about execution order, this is the operation 25691040Sarr * which ensures continued function. 25791040Sarr */ 25891040Sarr for (sipp = start; sipp < stop; sipp++) { 25991040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 26091040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 26191040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 26291040Sarr (*sipp)->order >= (*xipp)->order)) 26391040Sarr continue; /* skip */ 26491040Sarr save = *sipp; 26591040Sarr *sipp = *xipp; 26691040Sarr *xipp = save; 26791040Sarr } 26841055Speter } 26941055Speter 27091040Sarr /* 27191040Sarr * Traverse the (now) ordered list of system initialization tasks. 27291040Sarr * Perform each task, and continue on to the next task. 27391040Sarr */ 274160142Sjhb mtx_lock(&Giant); 27591040Sarr for (sipp = start; sipp < stop; sipp++) { 27691040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 27791040Sarr continue; /* skip dummy task(s) */ 27841055Speter 27991040Sarr /* Call function */ 28091040Sarr (*((*sipp)->func)) ((*sipp)->udata); 28191040Sarr } 282160142Sjhb mtx_unlock(&Giant); 28341055Speter} 28441055Speter 28544078Sdfrstatic void 28644078Sdfrlinker_file_register_sysctls(linker_file_t lf) 28744078Sdfr{ 28891040Sarr struct sysctl_oid **start, **stop, **oidp; 28944078Sdfr 29091040Sarr KLD_DPF(FILE, 29191040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 29291040Sarr lf->filename)); 29344078Sdfr 29491040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 29591040Sarr return; 29644078Sdfr 297188232Sjhb sysctl_lock(); 29891040Sarr for (oidp = start; oidp < stop; oidp++) 29991040Sarr sysctl_register_oid(*oidp); 300188232Sjhb sysctl_unlock(); 30144078Sdfr} 30244078Sdfr 30344078Sdfrstatic void 30444078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 30544078Sdfr{ 30691040Sarr struct sysctl_oid **start, **stop, **oidp; 30744078Sdfr 30891040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 30991040Sarr " for %s\n", lf->filename)); 31044078Sdfr 31191040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 31291040Sarr return; 31344078Sdfr 314188232Sjhb sysctl_lock(); 31591040Sarr for (oidp = start; oidp < stop; oidp++) 31691040Sarr sysctl_unregister_oid(*oidp); 317188232Sjhb sysctl_unlock(); 31844078Sdfr} 31944078Sdfr 32059751Speterstatic int 32159751Speterlinker_file_register_modules(linker_file_t lf) 32259751Speter{ 32391040Sarr struct mod_metadata **start, **stop, **mdp; 32491040Sarr const moduledata_t *moddata; 325146733Spjd int first_error, error; 32659751Speter 32791040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 32891040Sarr " in %s\n", lf->filename)); 32959751Speter 33091068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 331159841Sjhb &stop, NULL) != 0) { 33291040Sarr /* 33391040Sarr * This fallback should be unnecessary, but if we get booted 33491040Sarr * from boot2 instead of loader and we are missing our 33591040Sarr * metadata then we have to try the best we can. 33691040Sarr */ 33791040Sarr if (lf == linker_kernel_file) { 33891040Sarr start = SET_BEGIN(modmetadata_set); 33991040Sarr stop = SET_LIMIT(modmetadata_set); 34091040Sarr } else 34191040Sarr return (0); 34278161Speter } 343146733Spjd first_error = 0; 34491040Sarr for (mdp = start; mdp < stop; mdp++) { 34591040Sarr if ((*mdp)->md_type != MDT_MODULE) 34691040Sarr continue; 34791040Sarr moddata = (*mdp)->md_data; 34891040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 34991040Sarr moddata->name, lf->filename)); 35091040Sarr error = module_register(moddata, lf); 351146730Spjd if (error) { 35291068Sarr printf("Module %s failed to register: %d\n", 35391040Sarr moddata->name, error); 354146733Spjd if (first_error == 0) 355146733Spjd first_error = error; 356146730Spjd } 35759751Speter } 358146733Spjd return (first_error); 35959751Speter} 36059751Speter 36159751Speterstatic void 36259751Speterlinker_init_kernel_modules(void) 36359751Speter{ 36491040Sarr 36591040Sarr linker_file_register_modules(linker_kernel_file); 36659751Speter} 36759751Speter 368177253SrwatsonSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 369177253Srwatson 0); 37059751Speter 371101241Smuxstatic int 37291040Sarrlinker_load_file(const char *filename, linker_file_t *result) 37325537Sdfr{ 37491040Sarr linker_class_t lc; 37591040Sarr linker_file_t lf; 376159585Sjhb int foundfile, error; 37725537Sdfr 37891040Sarr /* Refuse to load modules if securelevel raised */ 379192895Sjamie if (prison0.pr_securelevel > 0) 38091040Sarr return (EPERM); 38162261Sarchie 382159845Sjhb KLD_LOCK_ASSERT(); 38391040Sarr lf = linker_find_file_by_name(filename); 38491040Sarr if (lf) { 38591040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 38691040Sarr " incrementing refs\n", filename)); 38791040Sarr *result = lf; 38891040Sarr lf->refs++; 389159585Sjhb return (0); 39091040Sarr } 39191040Sarr foundfile = 0; 392159585Sjhb error = 0; 39398452Sarr 39498452Sarr /* 39598452Sarr * We do not need to protect (lock) classes here because there is 39698452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 39798452Sarr * and there is no class deregistration mechanism at this time. 39898452Sarr */ 39991040Sarr TAILQ_FOREACH(lc, &classes, link) { 40091040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 40191040Sarr filename)); 40291040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 40391040Sarr /* 40491040Sarr * If we got something other than ENOENT, then it exists but 40591040Sarr * we cannot load it for some other reason. 40691040Sarr */ 40791040Sarr if (error != ENOENT) 40891040Sarr foundfile = 1; 40991040Sarr if (lf) { 410146730Spjd error = linker_file_register_modules(lf); 411146730Spjd if (error == EEXIST) { 412146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 413159585Sjhb return (error); 414146730Spjd } 415166921Sjhb KLD_UNLOCK(); 41691040Sarr linker_file_register_sysctls(lf); 41791040Sarr linker_file_sysinit(lf); 418166921Sjhb KLD_LOCK(); 41991040Sarr lf->flags |= LINKER_FILE_LINKED; 42091040Sarr *result = lf; 421159585Sjhb return (0); 42291040Sarr } 42391040Sarr } 42442755Speter /* 42591040Sarr * Less than ideal, but tells the user whether it failed to load or 42691040Sarr * the module was not found. 42742755Speter */ 428105337Ssam if (foundfile) { 429188440Sattilio 430105337Ssam /* 431188440Sattilio * If the file type has not been recognized by the last try 432188440Sattilio * printout a message before to fail. 433188440Sattilio */ 434188440Sattilio if (error == ENOSYS) 435188440Sattilio printf("linker_load_file: Unsupported file type\n"); 436188440Sattilio 437188440Sattilio /* 438105337Ssam * Format not recognized or otherwise unloadable. 439105337Ssam * When loading a module that is statically built into 440105337Ssam * the kernel EEXIST percolates back up as the return 441105337Ssam * value. Preserve this so that apps like sysinstall 442105337Ssam * can recognize this special case and not post bogus 443105337Ssam * dialog boxes. 444105337Ssam */ 445105337Ssam if (error != EEXIST) 446105337Ssam error = ENOEXEC; 447105337Ssam } else 44891068Sarr error = ENOENT; /* Nothing found */ 44991040Sarr return (error); 45025537Sdfr} 45125537Sdfr 45278413Sbrianint 45394321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 45494321Sbrian linker_file_t *result) 45578413Sbrian{ 45694321Sbrian modlist_t mod; 457159804Sjhb int error; 45894321Sbrian 459159845Sjhb KLD_LOCK(); 46094321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 46194321Sbrian *result = mod->container; 46294321Sbrian (*result)->refs++; 463159845Sjhb KLD_UNLOCK(); 46494321Sbrian return (0); 46594321Sbrian } 46694321Sbrian 467159804Sjhb error = linker_load_module(NULL, modname, NULL, verinfo, result); 468159845Sjhb KLD_UNLOCK(); 469159804Sjhb return (error); 47078413Sbrian} 47178413Sbrian 472159804Sjhbint 473159804Sjhblinker_release_module(const char *modname, struct mod_depend *verinfo, 474159804Sjhb linker_file_t lf) 475159804Sjhb{ 476159804Sjhb modlist_t mod; 477159804Sjhb int error; 478159804Sjhb 479159845Sjhb KLD_LOCK(); 480159804Sjhb if (lf == NULL) { 481159804Sjhb KASSERT(modname != NULL, 482159804Sjhb ("linker_release_module: no file or name")); 483159804Sjhb mod = modlist_lookup2(modname, verinfo); 484159804Sjhb if (mod == NULL) { 485159845Sjhb KLD_UNLOCK(); 486159804Sjhb return (ESRCH); 487159804Sjhb } 488159804Sjhb lf = mod->container; 489159804Sjhb } else 490159804Sjhb KASSERT(modname == NULL && verinfo == NULL, 491159804Sjhb ("linker_release_module: both file and name")); 492159804Sjhb error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL); 493159845Sjhb KLD_UNLOCK(); 494159804Sjhb return (error); 495159804Sjhb} 496159804Sjhb 497159800Sjhbstatic linker_file_t 49891040Sarrlinker_find_file_by_name(const char *filename) 49925537Sdfr{ 500159585Sjhb linker_file_t lf; 50191040Sarr char *koname; 50225537Sdfr 503111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 50491040Sarr sprintf(koname, "%s.ko", filename); 50540861Speter 506159845Sjhb KLD_LOCK_ASSERT(); 50791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 50892032Sdwmalone if (strcmp(lf->filename, koname) == 0) 50991040Sarr break; 51092032Sdwmalone if (strcmp(lf->filename, filename) == 0) 51191040Sarr break; 51291040Sarr } 513159585Sjhb free(koname, M_LINKER); 51491040Sarr return (lf); 51525537Sdfr} 51625537Sdfr 517159800Sjhbstatic linker_file_t 51825537Sdfrlinker_find_file_by_id(int fileid) 51925537Sdfr{ 520159585Sjhb linker_file_t lf; 521159845Sjhb 522159845Sjhb KLD_LOCK_ASSERT(); 52391040Sarr TAILQ_FOREACH(lf, &linker_files, link) 524166921Sjhb if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED) 52591040Sarr break; 52691040Sarr return (lf); 52725537Sdfr} 52825537Sdfr 529159797Sjhbint 530159797Sjhblinker_file_foreach(linker_predicate_t *predicate, void *context) 531159797Sjhb{ 532159797Sjhb linker_file_t lf; 533159797Sjhb int retval = 0; 534159797Sjhb 535159845Sjhb KLD_LOCK(); 536159797Sjhb TAILQ_FOREACH(lf, &linker_files, link) { 537159797Sjhb retval = predicate(lf, context); 538159797Sjhb if (retval != 0) 539159797Sjhb break; 540159797Sjhb } 541159845Sjhb KLD_UNLOCK(); 542159797Sjhb return (retval); 543159797Sjhb} 544159797Sjhb 54525537Sdfrlinker_file_t 54691040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 54725537Sdfr{ 54891040Sarr linker_file_t lf; 54991040Sarr const char *filename; 55025537Sdfr 551159845Sjhb KLD_LOCK_ASSERT(); 55291040Sarr filename = linker_basename(pathname); 55340159Speter 554172862Sjb KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname)); 555111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 55691040Sarr if (lf == NULL) 557159585Sjhb return (NULL); 55891040Sarr lf->refs = 1; 55991040Sarr lf->userrefs = 0; 56091040Sarr lf->flags = 0; 56191040Sarr lf->filename = linker_strdup(filename); 562172862Sjb lf->pathname = linker_strdup(pathname); 56391040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 56491040Sarr lf->ndeps = 0; 56591040Sarr lf->deps = NULL; 566172862Sjb lf->loadcnt = ++loadcnt; 567172862Sjb lf->sdt_probes = NULL; 568172862Sjb lf->sdt_nprobes = 0; 56991040Sarr STAILQ_INIT(&lf->common); 57091040Sarr TAILQ_INIT(&lf->modules); 57191040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 57291040Sarr return (lf); 57325537Sdfr} 57425537Sdfr 57525537Sdfrint 576132117Sphklinker_file_unload(linker_file_t file, int flags) 57725537Sdfr{ 57891040Sarr module_t mod, next; 57991040Sarr modlist_t ml, nextml; 58091040Sarr struct common_symbol *cp; 58191040Sarr int error, i; 58225537Sdfr 58391040Sarr /* Refuse to unload modules if securelevel raised. */ 584192895Sjamie if (prison0.pr_securelevel > 0) 58591040Sarr return (EPERM); 58625537Sdfr 587159845Sjhb KLD_LOCK_ASSERT(); 58891040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 58991040Sarr 590159584Sjhb /* Easy case of just dropping a reference. */ 591159584Sjhb if (file->refs > 1) { 592159584Sjhb file->refs--; 593159584Sjhb return (0); 594159584Sjhb } 595159584Sjhb 596159584Sjhb KLD_DPF(FILE, ("linker_file_unload: file is unloading," 597159584Sjhb " informing modules\n")); 598159584Sjhb 599159584Sjhb /* 600185635Sjhb * Quiesce all the modules to give them a chance to veto the unload. 601159584Sjhb */ 602185635Sjhb MOD_SLOCK; 603185635Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; 604185635Sjhb mod = module_getfnext(mod)) { 605185635Sjhb 606185635Sjhb error = module_quiesce(mod); 607185635Sjhb if (error != 0 && flags != LINKER_UNLOAD_FORCE) { 608185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 609185635Sjhb " vetoed unload\n", module_getname(mod))); 610185635Sjhb /* 611185635Sjhb * XXX: Do we need to tell all the quiesced modules 612185635Sjhb * that they can resume work now via a new module 613185635Sjhb * event? 614185635Sjhb */ 615185635Sjhb MOD_SUNLOCK; 616185635Sjhb return (error); 617185635Sjhb } 618185635Sjhb } 619185635Sjhb MOD_SUNLOCK; 620185635Sjhb 621185635Sjhb /* 622185635Sjhb * Inform any modules associated with this file that they are 623185635Sjhb * being be unloaded. 624185635Sjhb */ 625159584Sjhb MOD_XLOCK; 626159584Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 627159584Sjhb next = module_getfnext(mod); 628159584Sjhb MOD_XUNLOCK; 629159584Sjhb 63091040Sarr /* 631159584Sjhb * Give the module a chance to veto the unload. 63291040Sarr */ 633185635Sjhb if ((error = module_unload(mod)) != 0) { 634185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 635185635Sjhb " failed unload\n", mod)); 636159584Sjhb return (error); 637159584Sjhb } 63892547Sarr MOD_XLOCK; 639159584Sjhb module_release(mod); 640159584Sjhb } 641159584Sjhb MOD_XUNLOCK; 64291040Sarr 643159586Sjhb TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml) { 644128057Speadar if (ml->container == file) { 64591040Sarr TAILQ_REMOVE(&found_modules, ml, link); 646128057Speadar free(ml, M_LINKER); 647128057Speadar } 64891040Sarr } 64925537Sdfr 650159840Sjhb /* 651159840Sjhb * Don't try to run SYSUNINITs if we are unloaded due to a 65291040Sarr * link error. 65391040Sarr */ 65491040Sarr if (file->flags & LINKER_FILE_LINKED) { 655188209Sjhb file->flags &= ~LINKER_FILE_LINKED; 656188209Sjhb KLD_UNLOCK(); 65791040Sarr linker_file_sysuninit(file); 65891040Sarr linker_file_unregister_sysctls(file); 659188209Sjhb KLD_LOCK(); 66025537Sdfr } 66191040Sarr TAILQ_REMOVE(&linker_files, file, link); 66225537Sdfr 66391040Sarr if (file->deps) { 66491040Sarr for (i = 0; i < file->ndeps; i++) 665132117Sphk linker_file_unload(file->deps[i], flags); 66691040Sarr free(file->deps, M_LINKER); 66791040Sarr file->deps = NULL; 66859751Speter } 669160245Sjhb while ((cp = STAILQ_FIRST(&file->common)) != NULL) { 670160245Sjhb STAILQ_REMOVE_HEAD(&file->common, link); 67191040Sarr free(cp, M_LINKER); 67291040Sarr } 67359751Speter 67491040Sarr LINKER_UNLOAD(file); 67591040Sarr if (file->filename) { 67691040Sarr free(file->filename, M_LINKER); 67791040Sarr file->filename = NULL; 67891040Sarr } 679172862Sjb if (file->pathname) { 680172862Sjb free(file->pathname, M_LINKER); 681172862Sjb file->pathname = NULL; 682172862Sjb } 68391040Sarr kobj_delete((kobj_t) file, M_LINKER); 684159584Sjhb return (0); 68525537Sdfr} 68625537Sdfr 687179238Sjbint 688179238Sjblinker_ctf_get(linker_file_t file, linker_ctf_t *lc) 689179238Sjb{ 690179238Sjb return (LINKER_CTF_GET(file, lc)); 691179238Sjb} 692179238Sjb 693159796Sjhbstatic int 69486469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 69525537Sdfr{ 69691040Sarr linker_file_t *newdeps; 69725537Sdfr 698159845Sjhb KLD_LOCK_ASSERT(); 69991040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 700111119Simp M_LINKER, M_WAITOK | M_ZERO); 70191040Sarr if (newdeps == NULL) 70291040Sarr return (ENOMEM); 70325537Sdfr 70491040Sarr if (file->deps) { 70591040Sarr bcopy(file->deps, newdeps, 70691040Sarr file->ndeps * sizeof(linker_file_t *)); 70791040Sarr free(file->deps, M_LINKER); 70891040Sarr } 70991040Sarr file->deps = newdeps; 71091040Sarr file->deps[file->ndeps] = dep; 71191040Sarr file->ndeps++; 71291040Sarr return (0); 71325537Sdfr} 71425537Sdfr 71578161Speter/* 71691040Sarr * Locate a linker set and its contents. This is a helper function to avoid 717159841Sjhb * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. 718159841Sjhb * This function is used in this file so we can avoid having lots of (void **) 719159841Sjhb * casts. 72078161Speter */ 72178161Speterint 72278161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 72391040Sarr void *firstp, void *lastp, int *countp) 72478161Speter{ 725159845Sjhb int error, locked; 72678161Speter 727159845Sjhb locked = KLD_LOCKED(); 728159845Sjhb if (!locked) 729159845Sjhb KLD_LOCK(); 730159845Sjhb error = LINKER_LOOKUP_SET(file, name, firstp, lastp, countp); 731159845Sjhb if (!locked) 732159845Sjhb KLD_UNLOCK(); 733159845Sjhb return (error); 73478161Speter} 73578161Speter 736173714Sjb/* 737173714Sjb * List all functions in a file. 738173714Sjb */ 739173714Sjbint 740173714Sjblinker_file_function_listall(linker_file_t lf, 741179238Sjb linker_function_nameval_callback_t callback_func, void *arg) 742173714Sjb{ 743173714Sjb return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); 744173714Sjb} 745173714Sjb 74625537Sdfrcaddr_t 74791040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 74825537Sdfr{ 749159845Sjhb caddr_t sym; 750159845Sjhb int locked; 751159845Sjhb 752159845Sjhb locked = KLD_LOCKED(); 753159845Sjhb if (!locked) 754159845Sjhb KLD_LOCK(); 755159845Sjhb sym = linker_file_lookup_symbol_internal(file, name, deps); 756159845Sjhb if (!locked) 757159845Sjhb KLD_UNLOCK(); 758159845Sjhb return (sym); 759159845Sjhb} 760159845Sjhb 761159845Sjhbstatic caddr_t 762159845Sjhblinker_file_lookup_symbol_internal(linker_file_t file, const char *name, 763159845Sjhb int deps) 764159845Sjhb{ 76591040Sarr c_linker_sym_t sym; 76691040Sarr linker_symval_t symval; 76791040Sarr caddr_t address; 76891040Sarr size_t common_size = 0; 76992032Sdwmalone int i; 77025537Sdfr 771159845Sjhb KLD_LOCK_ASSERT(); 772109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 77391040Sarr file, name, deps)); 77425537Sdfr 77591040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 77691040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 77791040Sarr if (symval.value == 0) 77891040Sarr /* 77991040Sarr * For commons, first look them up in the 78091040Sarr * dependencies and only allocate space if not found 78191040Sarr * there. 78291040Sarr */ 78391040Sarr common_size = symval.size; 78491040Sarr else { 78591040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 786109605Sjake ".value=%p\n", symval.value)); 78791040Sarr return (symval.value); 78891040Sarr } 78940159Speter } 79091040Sarr if (deps) { 79191040Sarr for (i = 0; i < file->ndeps; i++) { 792159845Sjhb address = linker_file_lookup_symbol_internal( 793159845Sjhb file->deps[i], name, 0); 79491040Sarr if (address) { 79591040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 796109605Sjake " deps value=%p\n", address)); 79791040Sarr return (address); 79891040Sarr } 79991040Sarr } 80025537Sdfr } 80191040Sarr if (common_size > 0) { 80291040Sarr /* 80391040Sarr * This is a common symbol which was not found in the 80491040Sarr * dependencies. We maintain a simple common symbol table in 80591040Sarr * the file object. 80691040Sarr */ 80791040Sarr struct common_symbol *cp; 80842849Speter 80991040Sarr STAILQ_FOREACH(cp, &file->common, link) { 81092032Sdwmalone if (strcmp(cp->name, name) == 0) { 81191040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 812109605Sjake " old common value=%p\n", cp->address)); 81391040Sarr return (cp->address); 81491040Sarr } 81591040Sarr } 81691040Sarr /* 81791040Sarr * Round the symbol size up to align. 81891040Sarr */ 81991040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 82091040Sarr cp = malloc(sizeof(struct common_symbol) 82191040Sarr + common_size + strlen(name) + 1, M_LINKER, 822111119Simp M_WAITOK | M_ZERO); 82391040Sarr cp->address = (caddr_t)(cp + 1); 82491040Sarr cp->name = cp->address + common_size; 82591040Sarr strcpy(cp->name, name); 82691040Sarr bzero(cp->address, common_size); 82791040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 82825537Sdfr 82991040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 830109605Sjake " value=%p\n", cp->address)); 83191040Sarr return (cp->address); 83240159Speter } 83391040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 83491040Sarr return (0); 83525537Sdfr} 83625537Sdfr 83725537Sdfr/* 838174132Srwatson * Both DDB and stack(9) rely on the kernel linker to provide forward and 839174132Srwatson * backward lookup of symbols. However, DDB and sometimes stack(9) need to 840174132Srwatson * do this in a lockfree manner. We provide a set of internal helper 841174132Srwatson * routines to perform these operations without locks, and then wrappers that 842174132Srwatson * optionally lock. 843159840Sjhb * 844174132Srwatson * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. 84540159Speter */ 846174132Srwatson#ifdef DDB 847174132Srwatsonstatic int 848174132Srwatsonlinker_debug_lookup(const char *symstr, c_linker_sym_t *sym) 84940159Speter{ 85091040Sarr linker_file_t lf; 85140159Speter 85291040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 85391040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 85491040Sarr return (0); 85591040Sarr } 85691040Sarr return (ENOENT); 85740159Speter} 858174132Srwatson#endif 85940159Speter 860174132Srwatsonstatic int 861174132Srwatsonlinker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 86240159Speter{ 86391040Sarr linker_file_t lf; 86491040Sarr c_linker_sym_t best, es; 86591040Sarr u_long diff, bestdiff, off; 86640159Speter 86791040Sarr best = 0; 86891040Sarr off = (uintptr_t)value; 86991040Sarr bestdiff = off; 87091040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 87191040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 87291040Sarr continue; 87391040Sarr if (es != 0 && diff < bestdiff) { 87491040Sarr best = es; 87591040Sarr bestdiff = diff; 87691040Sarr } 87791040Sarr if (bestdiff == 0) 87891040Sarr break; 87940159Speter } 88091040Sarr if (best) { 88191040Sarr *sym = best; 88291040Sarr *diffp = bestdiff; 88391040Sarr return (0); 88491040Sarr } else { 88591040Sarr *sym = 0; 88691040Sarr *diffp = off; 88791040Sarr return (ENOENT); 88891040Sarr } 88940159Speter} 89040159Speter 891174132Srwatsonstatic int 892174132Srwatsonlinker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 89340159Speter{ 89491040Sarr linker_file_t lf; 89540159Speter 89691040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 89791040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 89891040Sarr return (0); 89991040Sarr } 90091040Sarr return (ENOENT); 90140159Speter} 902174132Srwatson 903174132Srwatsonstatic int 904174132Srwatsonlinker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, 905174132Srwatson long *offset) 906174132Srwatson{ 907174132Srwatson linker_symval_t symval; 908174132Srwatson c_linker_sym_t sym; 909174132Srwatson int error; 910174132Srwatson 911174132Srwatson *offset = 0; 912174132Srwatson error = linker_debug_search_symbol(value, &sym, offset); 913174132Srwatson if (error) 914174132Srwatson return (error); 915174132Srwatson error = linker_debug_symbol_values(sym, &symval); 916174132Srwatson if (error) 917174132Srwatson return (error); 918174132Srwatson strlcpy(buf, symval.name, buflen); 919174132Srwatson return (0); 920174132Srwatson} 921174132Srwatson 922174132Srwatson#ifdef DDB 923174132Srwatson/* 924174132Srwatson * DDB Helpers. DDB has to look across multiple files with their own symbol 925174132Srwatson * tables and string tables. 926174132Srwatson * 927174132Srwatson * Note that we do not obey list locking protocols here. We really don't need 928174132Srwatson * DDB to hang because somebody's got the lock held. We'll take the chance 929174132Srwatson * that the files list is inconsistant instead. 930174132Srwatson */ 931174132Srwatsonint 932174132Srwatsonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 933174132Srwatson{ 934174132Srwatson 935174132Srwatson return (linker_debug_lookup(symstr, sym)); 936174132Srwatson} 937174132Srwatson 938174132Srwatsonint 939174132Srwatsonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 940174132Srwatson{ 941174132Srwatson 942174132Srwatson return (linker_debug_search_symbol(value, sym, diffp)); 943174132Srwatson} 944174132Srwatson 945174132Srwatsonint 946174132Srwatsonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 947174132Srwatson{ 948174132Srwatson 949174132Srwatson return (linker_debug_symbol_values(sym, symval)); 950174132Srwatson} 951174132Srwatson 952174132Srwatsonint 953174132Srwatsonlinker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, 954174132Srwatson long *offset) 955174132Srwatson{ 956174132Srwatson 957174132Srwatson return (linker_debug_search_symbol_name(value, buf, buflen, offset)); 958174132Srwatson} 95940159Speter#endif 96040159Speter 96140159Speter/* 962174132Srwatson * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do 963174132Srwatson * obey locking protocols, and offer a significantly less complex interface. 964174132Srwatson */ 965174132Srwatsonint 966174132Srwatsonlinker_search_symbol_name(caddr_t value, char *buf, u_int buflen, 967174132Srwatson long *offset) 968174132Srwatson{ 969178380Spjd int error; 970174132Srwatson 971178380Spjd KLD_LOCK(); 972174132Srwatson error = linker_debug_search_symbol_name(value, buf, buflen, offset); 973178380Spjd KLD_UNLOCK(); 974174132Srwatson return (error); 975174132Srwatson} 976174132Srwatson 977174132Srwatson/* 97825537Sdfr * Syscalls. 97925537Sdfr */ 98025537Sdfrint 981159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 98225537Sdfr{ 983157144Sjkoshy#ifdef HWPMC_HOOKS 984157144Sjkoshy struct pmckern_map_in pkm; 985157144Sjkoshy#endif 986159588Sjhb const char *kldname, *modname; 98791040Sarr linker_file_t lf; 988159588Sjhb int error; 98925537Sdfr 99093159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 991159588Sjhb return (error); 99293159Sarr 993164033Srwatson if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0) 994159588Sjhb return (error); 99525537Sdfr 99691040Sarr /* 997191917Szec * It is possible that kldloaded module will attach a new ifnet, 998191816Szec * so vnet context must be set when this ocurs. 999191816Szec */ 1000191816Szec CURVNET_SET(TD_TO_VNET(td)); 1001191816Szec 1002191816Szec /* 1003159841Sjhb * If file does not contain a qualified name or any dot in it 1004159841Sjhb * (kldname.ko, or kldname.ver.ko) treat it as an interface 100591040Sarr * name. 100691040Sarr */ 1007159588Sjhb if (index(file, '/') || index(file, '.')) { 1008159588Sjhb kldname = file; 100991040Sarr modname = NULL; 101091040Sarr } else { 101191040Sarr kldname = NULL; 1012159588Sjhb modname = file; 101391040Sarr } 1014159588Sjhb 1015159845Sjhb KLD_LOCK(); 101691040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 101791040Sarr if (error) 1018159588Sjhb goto unlock; 1019157144Sjkoshy#ifdef HWPMC_HOOKS 1020157144Sjkoshy pkm.pm_file = lf->filename; 1021157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 1022157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 1023157144Sjkoshy#endif 102491040Sarr lf->userrefs++; 1025159588Sjhb if (fileid != NULL) 1026159588Sjhb *fileid = lf->id; 1027159588Sjhbunlock: 1028159845Sjhb KLD_UNLOCK(); 1029191816Szec CURVNET_RESTORE(); 103091040Sarr return (error); 103125537Sdfr} 103225537Sdfr 1033159588Sjhbint 1034159588Sjhbkldload(struct thread *td, struct kldload_args *uap) 1035159588Sjhb{ 1036159588Sjhb char *pathname = NULL; 1037159596Smarcel int error, fileid; 1038159588Sjhb 1039159588Sjhb td->td_retval[0] = -1; 1040159588Sjhb 1041159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1042159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 1043159596Smarcel if (error == 0) { 1044159596Smarcel error = kern_kldload(td, pathname, &fileid); 1045159596Smarcel if (error == 0) 1046159596Smarcel td->td_retval[0] = fileid; 1047159596Smarcel } 1048159588Sjhb free(pathname, M_TEMP); 1049159588Sjhb return (error); 1050159588Sjhb} 1051159588Sjhb 1052159588Sjhbint 1053132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 105425537Sdfr{ 1055157144Sjkoshy#ifdef HWPMC_HOOKS 1056157144Sjkoshy struct pmckern_map_out pkm; 1057157144Sjkoshy#endif 105891040Sarr linker_file_t lf; 105991040Sarr int error = 0; 106025537Sdfr 106193159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 1062159588Sjhb return (error); 106393159Sarr 1064164033Srwatson if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0) 1065159588Sjhb return (error); 106625537Sdfr 1067191816Szec CURVNET_SET(TD_TO_VNET(td)); 1068159845Sjhb KLD_LOCK(); 1069132117Sphk lf = linker_find_file_by_id(fileid); 107091040Sarr if (lf) { 107191040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 1072172862Sjb 1073172862Sjb /* Check if there are DTrace probes enabled on this file. */ 1074172862Sjb if (lf->nenabled > 0) { 1075172862Sjb printf("kldunload: attempt to unload file that has" 1076172862Sjb " DTrace probes enabled\n"); 1077172862Sjb error = EBUSY; 1078172862Sjb } else if (lf->userrefs == 0) { 1079132117Sphk /* 1080132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 1081132117Sphk */ 108291040Sarr printf("kldunload: attempt to unload file that was" 108391040Sarr " loaded by the kernel\n"); 1084159840Sjhb error = EBUSY; 1085159588Sjhb } else { 1086157144Sjkoshy#ifdef HWPMC_HOOKS 1087159588Sjhb /* Save data needed by hwpmc(4) before unloading. */ 1088159588Sjhb pkm.pm_address = (uintptr_t) lf->address; 1089159588Sjhb pkm.pm_size = lf->size; 1090157144Sjkoshy#endif 1091159588Sjhb lf->userrefs--; 1092159588Sjhb error = linker_file_unload(lf, flags); 1093159588Sjhb if (error) 1094159588Sjhb lf->userrefs++; 1095159588Sjhb } 109691040Sarr } else 109791040Sarr error = ENOENT; 1098157144Sjkoshy 1099157144Sjkoshy#ifdef HWPMC_HOOKS 1100157144Sjkoshy if (error == 0) 1101157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 1102157144Sjkoshy#endif 1103159845Sjhb KLD_UNLOCK(); 1104191816Szec CURVNET_RESTORE(); 110591068Sarr return (error); 110625537Sdfr} 110725537Sdfr 110825537Sdfrint 1109132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 1110132117Sphk{ 1111132117Sphk 1112132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 1113132117Sphk} 1114132117Sphk 1115132117Sphkint 1116132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 1117132117Sphk{ 1118132117Sphk 1119132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 1120132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 1121132117Sphk return (EINVAL); 1122132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 1123132117Sphk} 1124132117Sphk 1125132117Sphkint 112691040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 112725537Sdfr{ 112891040Sarr char *pathname; 112991040Sarr const char *filename; 113091040Sarr linker_file_t lf; 1131159791Sjhb int error; 113225537Sdfr 1133107089Srwatson#ifdef MAC 1134172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1135107089Srwatson if (error) 1136107089Srwatson return (error); 1137107089Srwatson#endif 1138107089Srwatson 113991040Sarr td->td_retval[0] = -1; 114082749Sdillon 1141111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1142107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 114391040Sarr goto out; 114425537Sdfr 114591040Sarr filename = linker_basename(pathname); 1146159845Sjhb KLD_LOCK(); 114791040Sarr lf = linker_find_file_by_name(filename); 114891040Sarr if (lf) 114991040Sarr td->td_retval[0] = lf->id; 115091040Sarr else 115191040Sarr error = ENOENT; 1152159845Sjhb KLD_UNLOCK(); 115325537Sdfrout: 1154159791Sjhb free(pathname, M_TEMP); 115591040Sarr return (error); 115625537Sdfr} 115725537Sdfr 115825537Sdfrint 115991040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 116025537Sdfr{ 116191040Sarr linker_file_t lf; 116291040Sarr int error = 0; 116325537Sdfr 1164107089Srwatson#ifdef MAC 1165172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1166107089Srwatson if (error) 1167107089Srwatson return (error); 1168107089Srwatson#endif 1169107089Srwatson 1170159845Sjhb KLD_LOCK(); 1171166921Sjhb if (uap->fileid == 0) 1172166921Sjhb lf = TAILQ_FIRST(&linker_files); 1173166921Sjhb else { 1174166921Sjhb lf = linker_find_file_by_id(uap->fileid); 1175166921Sjhb if (lf == NULL) { 1176166921Sjhb error = ENOENT; 1177166921Sjhb goto out; 1178166921Sjhb } 1179166921Sjhb lf = TAILQ_NEXT(lf, link); 118091040Sarr } 1181166921Sjhb 1182166921Sjhb /* Skip partially loaded files. */ 1183166921Sjhb while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) 1184166921Sjhb lf = TAILQ_NEXT(lf, link); 1185166921Sjhb 1186166921Sjhb if (lf) 1187166921Sjhb td->td_retval[0] = lf->id; 1188166921Sjhb else 1189166921Sjhb td->td_retval[0] = 0; 119082749Sdillonout: 1191159845Sjhb KLD_UNLOCK(); 119291040Sarr return (error); 119325537Sdfr} 119425537Sdfr 119525537Sdfrint 119691040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 119725537Sdfr{ 1198159587Sjhb struct kld_file_stat stat; 119991040Sarr linker_file_t lf; 1200172862Sjb int error, namelen, version, version_num; 120125537Sdfr 1202159587Sjhb /* 1203159587Sjhb * Check the version of the user's structure. 1204159587Sjhb */ 1205172862Sjb if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0) 1206159587Sjhb return (error); 1207172862Sjb if (version == sizeof(struct kld_file_stat_1)) 1208172862Sjb version_num = 1; 1209172862Sjb else if (version == sizeof(struct kld_file_stat)) 1210172862Sjb version_num = 2; 1211172862Sjb else 1212159587Sjhb return (EINVAL); 1213159587Sjhb 1214107089Srwatson#ifdef MAC 1215172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1216107089Srwatson if (error) 1217107089Srwatson return (error); 1218107089Srwatson#endif 1219107089Srwatson 1220159845Sjhb KLD_LOCK(); 1221107849Salfred lf = linker_find_file_by_id(uap->fileid); 122291040Sarr if (lf == NULL) { 1223159845Sjhb KLD_UNLOCK(); 1224159587Sjhb return (ENOENT); 122591040Sarr } 122625537Sdfr 1227172862Sjb /* Version 1 fields: */ 122891040Sarr namelen = strlen(lf->filename) + 1; 122991040Sarr if (namelen > MAXPATHLEN) 123091040Sarr namelen = MAXPATHLEN; 1231159587Sjhb bcopy(lf->filename, &stat.name[0], namelen); 1232159587Sjhb stat.refs = lf->refs; 1233159587Sjhb stat.id = lf->id; 1234159587Sjhb stat.address = lf->address; 1235159587Sjhb stat.size = lf->size; 1236172862Sjb if (version_num > 1) { 1237172862Sjb /* Version 2 fields: */ 1238172862Sjb namelen = strlen(lf->pathname) + 1; 1239172862Sjb if (namelen > MAXPATHLEN) 1240172862Sjb namelen = MAXPATHLEN; 1241172862Sjb bcopy(lf->pathname, &stat.pathname[0], namelen); 1242172862Sjb } 1243159845Sjhb KLD_UNLOCK(); 124425537Sdfr 124591040Sarr td->td_retval[0] = 0; 1246159587Sjhb 1247172862Sjb return (copyout(&stat, uap->stat, version)); 124825537Sdfr} 124925537Sdfr 125025537Sdfrint 125191040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 125225537Sdfr{ 125391040Sarr linker_file_t lf; 125491040Sarr module_t mp; 125591040Sarr int error = 0; 125625537Sdfr 1257107089Srwatson#ifdef MAC 1258172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1259107089Srwatson if (error) 1260107089Srwatson return (error); 1261107089Srwatson#endif 1262107089Srwatson 1263159845Sjhb KLD_LOCK(); 1264107849Salfred lf = linker_find_file_by_id(uap->fileid); 126591040Sarr if (lf) { 126692547Sarr MOD_SLOCK; 126791040Sarr mp = TAILQ_FIRST(&lf->modules); 126891040Sarr if (mp != NULL) 126991040Sarr td->td_retval[0] = module_getid(mp); 127091040Sarr else 127191040Sarr td->td_retval[0] = 0; 127292547Sarr MOD_SUNLOCK; 127391040Sarr } else 127491040Sarr error = ENOENT; 1275159845Sjhb KLD_UNLOCK(); 127691040Sarr return (error); 127725537Sdfr} 127840159Speter 127941090Speterint 128083366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 128141090Speter{ 128291040Sarr char *symstr = NULL; 128391040Sarr c_linker_sym_t sym; 128491040Sarr linker_symval_t symval; 128591040Sarr linker_file_t lf; 128691040Sarr struct kld_sym_lookup lookup; 128791040Sarr int error = 0; 128841090Speter 1289107089Srwatson#ifdef MAC 1290172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1291107089Srwatson if (error) 1292107089Srwatson return (error); 1293107089Srwatson#endif 1294107089Srwatson 1295107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 1296159843Sjhb return (error); 129791068Sarr if (lookup.version != sizeof(lookup) || 1298159843Sjhb uap->cmd != KLDSYM_LOOKUP) 1299159843Sjhb return (EINVAL); 1300111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 130191040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 130291040Sarr goto out; 1303159845Sjhb KLD_LOCK(); 1304107849Salfred if (uap->fileid != 0) { 1305107849Salfred lf = linker_find_file_by_id(uap->fileid); 1306159843Sjhb if (lf == NULL) 130791040Sarr error = ENOENT; 1308159843Sjhb else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 130991040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 131091040Sarr lookup.symvalue = (uintptr_t) symval.value; 131191040Sarr lookup.symsize = symval.size; 1312107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 131391040Sarr } else 131491040Sarr error = ENOENT; 131591040Sarr } else { 131691040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 131791040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 131891040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 131991040Sarr lookup.symvalue = (uintptr_t)symval.value; 132091040Sarr lookup.symsize = symval.size; 1321107849Salfred error = copyout(&lookup, uap->data, 132291040Sarr sizeof(lookup)); 132391068Sarr break; 132491040Sarr } 132591040Sarr } 132691040Sarr if (lf == NULL) 132791040Sarr error = ENOENT; 132841090Speter } 1329159845Sjhb KLD_UNLOCK(); 133041090Speterout: 1331159843Sjhb free(symstr, M_TEMP); 133291040Sarr return (error); 133341090Speter} 133441090Speter 133540159Speter/* 133640159Speter * Preloaded module support 133740159Speter */ 133840159Speter 133959751Speterstatic modlist_t 134074642Sbpmodlist_lookup(const char *name, int ver) 134159751Speter{ 134291040Sarr modlist_t mod; 134359751Speter 134491040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 134592032Sdwmalone if (strcmp(mod->name, name) == 0 && 134692032Sdwmalone (ver == 0 || mod->version == ver)) 134791040Sarr return (mod); 134891040Sarr } 134991040Sarr return (NULL); 135059751Speter} 135159751Speter 135274642Sbpstatic modlist_t 135383321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 135483321Speter{ 135591040Sarr modlist_t mod, bestmod; 135692032Sdwmalone int ver; 135783321Speter 135891040Sarr if (verinfo == NULL) 135991040Sarr return (modlist_lookup(name, 0)); 136091040Sarr bestmod = NULL; 1361159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 136292032Sdwmalone if (strcmp(mod->name, name) != 0) 136391040Sarr continue; 136491040Sarr ver = mod->version; 136591040Sarr if (ver == verinfo->md_ver_preferred) 136691040Sarr return (mod); 136791040Sarr if (ver >= verinfo->md_ver_minimum && 136891068Sarr ver <= verinfo->md_ver_maximum && 1369120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 137091040Sarr bestmod = mod; 137191040Sarr } 137291040Sarr return (bestmod); 137383321Speter} 137483321Speter 137583321Speterstatic modlist_t 137678501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 137774642Sbp{ 137891040Sarr modlist_t mod; 137974642Sbp 138092705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 138191040Sarr if (mod == NULL) 138291040Sarr panic("no memory for module list"); 138391040Sarr mod->container = container; 138491040Sarr mod->name = modname; 138591040Sarr mod->version = version; 138691040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 138791040Sarr return (mod); 138874642Sbp} 138974642Sbp 139040159Speterstatic void 139178161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 139291040Sarr struct mod_metadata **stop, int preload) 139374642Sbp{ 139491040Sarr struct mod_metadata *mp, **mdp; 139591040Sarr const char *modname; 139691040Sarr int ver; 139774642Sbp 139891040Sarr for (mdp = start; mdp < stop; mdp++) { 1399109605Sjake mp = *mdp; 140091040Sarr if (mp->md_type != MDT_VERSION) 140191040Sarr continue; 1402109605Sjake modname = mp->md_cval; 1403109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 140491040Sarr if (modlist_lookup(modname, ver) != NULL) { 140591040Sarr printf("module %s already present!\n", modname); 140691040Sarr /* XXX what can we do? this is a build error. :-( */ 140791040Sarr continue; 140891040Sarr } 140991040Sarr modlist_newmodule(modname, ver, lf); 141074642Sbp } 141174642Sbp} 141274642Sbp 141374642Sbpstatic void 141491040Sarrlinker_preload(void *arg) 141540159Speter{ 141691040Sarr caddr_t modptr; 141791040Sarr const char *modname, *nmodname; 141891040Sarr char *modtype; 1419160244Sjhb linker_file_t lf, nlf; 142091040Sarr linker_class_t lc; 142192032Sdwmalone int error; 142291040Sarr linker_file_list_t loaded_files; 142391040Sarr linker_file_list_t depended_files; 142491040Sarr struct mod_metadata *mp, *nmp; 142591040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 142691040Sarr struct mod_depend *verinfo; 142791040Sarr int nver; 142891040Sarr int resolves; 142991040Sarr modlist_t mod; 143091040Sarr struct sysinit **si_start, **si_stop; 143140159Speter 143291040Sarr TAILQ_INIT(&loaded_files); 143391040Sarr TAILQ_INIT(&depended_files); 143491040Sarr TAILQ_INIT(&found_modules); 143591040Sarr error = 0; 143659751Speter 143791040Sarr modptr = NULL; 143891040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 143991040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 144091040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 144191040Sarr if (modname == NULL) { 144291040Sarr printf("Preloaded module at %p does not have a" 144391040Sarr " name!\n", modptr); 144491040Sarr continue; 144591040Sarr } 144691040Sarr if (modtype == NULL) { 144791040Sarr printf("Preloaded module at %p does not have a type!\n", 144891040Sarr modptr); 144991040Sarr continue; 145091040Sarr } 1451131398Sjhb if (bootverbose) 1452131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1453131398Sjhb modptr); 145440159Speter lf = NULL; 145591040Sarr TAILQ_FOREACH(lc, &classes, link) { 145691040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1457134364Siedowse if (!error) 145891040Sarr break; 1459134364Siedowse lf = NULL; 146091040Sarr } 146191040Sarr if (lf) 146291040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 146340159Speter } 146440159Speter 146591040Sarr /* 146691040Sarr * First get a list of stuff in the kernel. 146791040Sarr */ 146891040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 146991040Sarr &stop, NULL) == 0) 147091040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 147159751Speter 147259751Speter /* 1473167019Sjhb * This is a once-off kinky bubble sort to resolve relocation 1474167019Sjhb * dependency requirements. 147559751Speter */ 147691040Sarrrestart: 147791040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 147891040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 147991040Sarr &stop, NULL); 148091040Sarr /* 148191040Sarr * First, look to see if we would successfully link with this 148291040Sarr * stuff. 148391040Sarr */ 148491040Sarr resolves = 1; /* unless we know otherwise */ 148591040Sarr if (!error) { 148691040Sarr for (mdp = start; mdp < stop; mdp++) { 1487109605Sjake mp = *mdp; 148891040Sarr if (mp->md_type != MDT_DEPEND) 148991040Sarr continue; 1490109605Sjake modname = mp->md_cval; 1491109605Sjake verinfo = mp->md_data; 149291040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1493109605Sjake nmp = *nmdp; 149491040Sarr if (nmp->md_type != MDT_VERSION) 149591040Sarr continue; 1496109605Sjake nmodname = nmp->md_cval; 149792032Sdwmalone if (strcmp(modname, nmodname) == 0) 149891040Sarr break; 149991040Sarr } 150091040Sarr if (nmdp < stop) /* it's a self reference */ 150191040Sarr continue; 1502159840Sjhb 150391040Sarr /* 150491040Sarr * ok, the module isn't here yet, we 150591040Sarr * are not finished 150691040Sarr */ 150791068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 150891040Sarr resolves = 0; 150991040Sarr } 151064143Speter } 151191040Sarr /* 151291040Sarr * OK, if we found our modules, we can link. So, "provide" 151391040Sarr * the modules inside and add it to the end of the link order 151491040Sarr * list. 151591040Sarr */ 151691040Sarr if (resolves) { 151791040Sarr if (!error) { 151891040Sarr for (mdp = start; mdp < stop; mdp++) { 1519109605Sjake mp = *mdp; 152091040Sarr if (mp->md_type != MDT_VERSION) 152191040Sarr continue; 1522109605Sjake modname = mp->md_cval; 1523109605Sjake nver = ((struct mod_version *) 1524109605Sjake mp->md_data)->mv_version; 152591040Sarr if (modlist_lookup(modname, 152691040Sarr nver) != NULL) { 152791040Sarr printf("module %s already" 152891040Sarr " present!\n", modname); 1529160244Sjhb TAILQ_REMOVE(&loaded_files, 1530160244Sjhb lf, loaded); 1531132117Sphk linker_file_unload(lf, 1532132117Sphk LINKER_UNLOAD_FORCE); 153391040Sarr /* we changed tailq next ptr */ 153491068Sarr goto restart; 153591040Sarr } 153691040Sarr modlist_newmodule(modname, nver, lf); 153791040Sarr } 153891040Sarr } 153991040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 154091040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 154191040Sarr /* 154291040Sarr * Since we provided modules, we need to restart the 154391040Sarr * sort so that the previous files that depend on us 154491040Sarr * have a chance. Also, we've busted the tailq next 154591040Sarr * pointer with the REMOVE. 154691040Sarr */ 154791040Sarr goto restart; 154859751Speter } 154959751Speter } 155091040Sarr 155159751Speter /* 155291040Sarr * At this point, we check to see what could not be resolved.. 155359751Speter */ 1554160242Sjhb while ((lf = TAILQ_FIRST(&loaded_files)) != NULL) { 1555160242Sjhb TAILQ_REMOVE(&loaded_files, lf, loaded); 155691040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1557132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 155840159Speter } 155959751Speter 156078161Speter /* 156191040Sarr * We made it. Finish off the linking in the order we determined. 156278161Speter */ 1563160244Sjhb TAILQ_FOREACH_SAFE(lf, &depended_files, loaded, nlf) { 156491040Sarr if (linker_kernel_file) { 156591040Sarr linker_kernel_file->refs++; 156691040Sarr error = linker_file_add_dependency(lf, 156791040Sarr linker_kernel_file); 156891040Sarr if (error) 156991040Sarr panic("cannot add dependency"); 157091040Sarr } 157191040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 157291040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 157391040Sarr &stop, NULL); 157491040Sarr if (!error) { 157591040Sarr for (mdp = start; mdp < stop; mdp++) { 1576109605Sjake mp = *mdp; 157791040Sarr if (mp->md_type != MDT_DEPEND) 157891040Sarr continue; 1579109605Sjake modname = mp->md_cval; 1580109605Sjake verinfo = mp->md_data; 158191040Sarr mod = modlist_lookup2(modname, verinfo); 1582151484Sjdp /* Don't count self-dependencies */ 1583151484Sjdp if (lf == mod->container) 1584151484Sjdp continue; 158591040Sarr mod->container->refs++; 158691040Sarr error = linker_file_add_dependency(lf, 158791040Sarr mod->container); 158891040Sarr if (error) 158991040Sarr panic("cannot add dependency"); 159091040Sarr } 159191040Sarr } 159291040Sarr /* 159391040Sarr * Now do relocation etc using the symbol search paths 159491040Sarr * established by the dependencies 159591040Sarr */ 159691040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 159791040Sarr if (error) { 1598160244Sjhb TAILQ_REMOVE(&depended_files, lf, loaded); 159991040Sarr printf("KLD file %s - could not finalize loading\n", 160091040Sarr lf->filename); 1601132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 160291040Sarr continue; 160391040Sarr } 160491040Sarr linker_file_register_modules(lf); 160591040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 160691040Sarr &si_stop, NULL) == 0) 160791040Sarr sysinit_add(si_start, si_stop); 160891040Sarr linker_file_register_sysctls(lf); 160991040Sarr lf->flags |= LINKER_FILE_LINKED; 161059751Speter } 161191040Sarr /* woohoo! we made it! */ 161240159Speter} 161340159Speter 1614177253SrwatsonSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 161540159Speter 161640159Speter/* 161740159Speter * Search for a not-loaded module by name. 1618159840Sjhb * 161940159Speter * Modules may be found in the following locations: 1620159840Sjhb * 162191040Sarr * - preloaded (result is just the module name) - on disk (result is full path 162291040Sarr * to module) 1623159840Sjhb * 162491040Sarr * If the module name is qualified in any way (contains path, etc.) the we 162591040Sarr * simply return a copy of it. 1626159840Sjhb * 162740159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 162840159Speter * character as a separator to be consistent with the bootloader. 162940159Speter */ 163040159Speter 163183321Speterstatic char linker_hintfile[] = "linker.hints"; 1632111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 163340159Speter 163440159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 163591040Sarr sizeof(linker_path), "module load search path"); 163640159Speter 163777843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 163870417Speter 163959751Speterstatic char *linker_ext_list[] = { 164083321Speter "", 164159751Speter ".ko", 164259751Speter NULL 164359751Speter}; 164459751Speter 164583321Speter/* 164691040Sarr * Check if file actually exists either with or without extension listed in 164791040Sarr * the linker_ext_list. (probably should be generic for the rest of the 164891040Sarr * kernel) 164983321Speter */ 165059751Speterstatic char * 165191040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 165291040Sarr int namelen, struct vattr *vap) 165340159Speter{ 165491040Sarr struct nameidata nd; 165591040Sarr struct thread *td = curthread; /* XXX */ 165691040Sarr char *result, **cpp, *sep; 1657159808Sjhb int error, len, extlen, reclen, flags, vfslocked; 165891040Sarr enum vtype type; 165940159Speter 166091040Sarr extlen = 0; 166191040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 166291040Sarr len = strlen(*cpp); 166391040Sarr if (len > extlen) 166491040Sarr extlen = len; 166591040Sarr } 166691040Sarr extlen++; /* trailing '\0' */ 166791040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 166883321Speter 166991040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1670111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 167191040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 167291040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 167391040Sarr namelen, name, *cpp); 167491040Sarr /* 167591040Sarr * Attempt to open the file, and return the path if 167691040Sarr * we succeed and it's a regular file. 167791040Sarr */ 1678159808Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); 167991040Sarr flags = FREAD; 1680170152Skib error = vn_open(&nd, &flags, 0, NULL); 168191040Sarr if (error == 0) { 1682159808Sjhb vfslocked = NDHASGIANT(&nd); 168391040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 168491040Sarr type = nd.ni_vp->v_type; 168591040Sarr if (vap) 1686182371Sattilio VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); 1687175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 168891406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 1689159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 169091040Sarr if (type == VREG) 169191040Sarr return (result); 169291040Sarr } 169383321Speter } 169491040Sarr free(result, M_LINKER); 169591040Sarr return (NULL); 169683321Speter} 169783321Speter 169891040Sarr#define INT_ALIGN(base, ptr) ptr = \ 169983321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 170083321Speter 170183321Speter/* 170291040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 170391040Sarr * version specification is available, then try to find the best KLD. 170483321Speter * Otherwise just find the latest one. 170583321Speter */ 170683321Speterstatic char * 170791040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 170891040Sarr int modnamelen, struct mod_depend *verinfo) 170983321Speter{ 171091040Sarr struct thread *td = curthread; /* XXX */ 171191406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 171291040Sarr struct nameidata nd; 171391040Sarr struct vattr vattr, mattr; 171491040Sarr u_char *hints = NULL; 171591040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 171691040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 1717159808Sjhb int vfslocked = 0; 171883321Speter 171991040Sarr result = NULL; 172091040Sarr bestver = found = 0; 172183321Speter 172291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 172391040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 172491040Sarr strlen(sep) + 1; 1725111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 172691040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 172791040Sarr linker_hintfile); 172883321Speter 1729159808Sjhb NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); 173091040Sarr flags = FREAD; 1731170152Skib error = vn_open(&nd, &flags, 0, NULL); 173291040Sarr if (error) 173391040Sarr goto bad; 1734159808Sjhb vfslocked = NDHASGIANT(&nd); 173591040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 173691040Sarr if (nd.ni_vp->v_type != VREG) 173791040Sarr goto bad; 173891040Sarr best = cp = NULL; 1739182371Sattilio error = VOP_GETATTR(nd.ni_vp, &vattr, cred); 174091040Sarr if (error) 174191040Sarr goto bad; 174291040Sarr /* 174391040Sarr * XXX: we need to limit this number to some reasonable value 174491040Sarr */ 174591040Sarr if (vattr.va_size > 100 * 1024) { 174691040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 174791040Sarr goto bad; 174891040Sarr } 1749111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 175091040Sarr if (hints == NULL) 175191040Sarr goto bad; 175291068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1753101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 175491040Sarr if (error) 175591040Sarr goto bad; 1756175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 175791040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1758159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 175991040Sarr nd.ni_vp = NULL; 176091040Sarr if (reclen != 0) { 176191040Sarr printf("can't read %d\n", reclen); 176291040Sarr goto bad; 176391040Sarr } 176491040Sarr intp = (int *)hints; 176583321Speter ival = *intp++; 176691040Sarr if (ival != LINKER_HINTS_VERSION) { 176791040Sarr printf("hints file version mismatch %d\n", ival); 176891040Sarr goto bad; 176983321Speter } 177091040Sarr bufend = hints + vattr.va_size; 177191040Sarr recptr = (u_char *)intp; 177291040Sarr clen = blen = 0; 177391040Sarr while (recptr < bufend && !found) { 177491040Sarr intp = (int *)recptr; 177591040Sarr reclen = *intp++; 177691040Sarr ival = *intp++; 177791040Sarr cp = (char *)intp; 177891040Sarr switch (ival) { 177991040Sarr case MDT_VERSION: 178091040Sarr clen = *cp++; 178191040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 178291040Sarr break; 178391040Sarr cp += clen; 178491040Sarr INT_ALIGN(hints, cp); 178591040Sarr ival = *(int *)cp; 178691040Sarr cp += sizeof(int); 178791040Sarr clen = *cp++; 178891040Sarr if (verinfo == NULL || 178991040Sarr ival == verinfo->md_ver_preferred) { 179091040Sarr found = 1; 179191040Sarr break; 179291040Sarr } 179391040Sarr if (ival >= verinfo->md_ver_minimum && 179491040Sarr ival <= verinfo->md_ver_maximum && 179591040Sarr ival > bestver) { 179691040Sarr bestver = ival; 179791040Sarr best = cp; 179891040Sarr blen = clen; 179991040Sarr } 180091040Sarr break; 180191040Sarr default: 180291040Sarr break; 180391040Sarr } 180491040Sarr recptr += reclen + sizeof(int); 180591040Sarr } 180683321Speter /* 180791040Sarr * Finally check if KLD is in the place 180883321Speter */ 180991040Sarr if (found) 181091040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 181191040Sarr else if (best) 181291040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 181391040Sarr 181491040Sarr /* 181591040Sarr * KLD is newer than hints file. What we should do now? 181691040Sarr */ 181791040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 181891040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 181991040Sarr " file\n", result); 182083321Speterbad: 1821105167Sphk free(pathbuf, M_LINKER); 182291040Sarr if (hints) 182391040Sarr free(hints, M_TEMP); 182499553Sjeff if (nd.ni_vp != NULL) { 1825175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 182691040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1827159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 182899553Sjeff } 182991040Sarr /* 183091040Sarr * If nothing found or hints is absent - fallback to the old 183191040Sarr * way by using "kldname[.ko]" as module name. 183291040Sarr */ 183391040Sarr if (!found && !bestver && result == NULL) 183491040Sarr result = linker_lookup_file(path, pathlen, modname, 183591040Sarr modnamelen, NULL); 183691040Sarr return (result); 183783321Speter} 183883321Speter 183983321Speter/* 184083321Speter * Lookup KLD which contains requested module in the all directories. 184183321Speter */ 184283321Speterstatic char * 184383321Speterlinker_search_module(const char *modname, int modnamelen, 184491040Sarr struct mod_depend *verinfo) 184583321Speter{ 184691040Sarr char *cp, *ep, *result; 184783321Speter 184891040Sarr /* 184991040Sarr * traverse the linker path 185091040Sarr */ 185191040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 185291040Sarr /* find the end of this component */ 185391040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 185491068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 185591068Sarr modnamelen, verinfo); 185691040Sarr if (result != NULL) 185791040Sarr return (result); 185891040Sarr if (*ep == 0) 185991040Sarr break; 186091040Sarr } 186191040Sarr return (NULL); 186283321Speter} 186383321Speter 186483321Speter/* 186583321Speter * Search for module in all directories listed in the linker_path. 186683321Speter */ 186783321Speterstatic char * 186883321Speterlinker_search_kld(const char *name) 186983321Speter{ 1870158972Sdelphij char *cp, *ep, *result; 1871158972Sdelphij int len; 187283321Speter 187391040Sarr /* qualified at all? */ 187491040Sarr if (index(name, '/')) 187591040Sarr return (linker_strdup(name)); 187640159Speter 187791040Sarr /* traverse the linker path */ 187891040Sarr len = strlen(name); 187991040Sarr for (ep = linker_path; *ep; ep++) { 188091040Sarr cp = ep; 188191040Sarr /* find the end of this component */ 188291040Sarr for (; *ep != 0 && *ep != ';'; ep++); 188391040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 188491040Sarr if (result != NULL) 188591040Sarr return (result); 188691040Sarr } 188791040Sarr return (NULL); 188840159Speter} 188959751Speter 189059751Speterstatic const char * 189191040Sarrlinker_basename(const char *path) 189259751Speter{ 189391040Sarr const char *filename; 189459751Speter 189591040Sarr filename = rindex(path, '/'); 189691040Sarr if (filename == NULL) 189791040Sarr return path; 189891040Sarr if (filename[1]) 189991040Sarr filename++; 190091040Sarr return (filename); 190159751Speter} 190259751Speter 1903157144Sjkoshy#ifdef HWPMC_HOOKS 190459751Speter/* 1905157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1906157144Sjkoshy */ 1907157144Sjkoshyvoid * 1908157144Sjkoshylinker_hwpmc_list_objects(void) 1909157144Sjkoshy{ 1910195159Sattilio linker_file_t lf; 1911195159Sattilio struct pmckern_map_in *kobase; 1912195159Sattilio int i, nmappings; 1913157144Sjkoshy 1914195159Sattilio nmappings = 0; 1915195159Sattilio KLD_LOCK(); 1916195159Sattilio TAILQ_FOREACH(lf, &linker_files, link) 1917195159Sattilio nmappings++; 1918157144Sjkoshy 1919195159Sattilio /* Allocate nmappings + 1 entries. */ 1920195159Sattilio kobase = malloc((nmappings + 1) * sizeof(struct pmckern_map_in), 1921184214Sdes M_LINKER, M_WAITOK | M_ZERO); 1922195159Sattilio i = 0; 1923195159Sattilio TAILQ_FOREACH(lf, &linker_files, link) { 1924157144Sjkoshy 1925195159Sattilio /* Save the info for this linker file. */ 1926195159Sattilio kobase[i].pm_file = lf->filename; 1927195159Sattilio kobase[i].pm_address = (uintptr_t)lf->address; 1928195159Sattilio i++; 1929157144Sjkoshy } 1930195159Sattilio KLD_UNLOCK(); 1931157144Sjkoshy 1932195159Sattilio KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?")); 1933157144Sjkoshy 1934157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1935195159Sattilio KASSERT(kobase[i].pm_file == NULL, 1936157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1937157144Sjkoshy 1938195159Sattilio return ((void *)kobase); 1939157144Sjkoshy} 1940157144Sjkoshy#endif 1941157144Sjkoshy 1942157144Sjkoshy/* 194391040Sarr * Find a file which contains given module and load it, if "parent" is not 194491040Sarr * NULL, register a reference to it. 194559751Speter */ 1946159796Sjhbstatic int 194783321Speterlinker_load_module(const char *kldname, const char *modname, 194891040Sarr struct linker_file *parent, struct mod_depend *verinfo, 194991040Sarr struct linker_file **lfpp) 195059751Speter{ 195191040Sarr linker_file_t lfdep; 195291040Sarr const char *filename; 195391040Sarr char *pathname; 195491040Sarr int error; 195559751Speter 1956159845Sjhb KLD_LOCK_ASSERT(); 195791040Sarr if (modname == NULL) { 195891040Sarr /* 195991040Sarr * We have to load KLD 196091040Sarr */ 196191068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 196291068Sarr " is not NULL")); 196391040Sarr pathname = linker_search_kld(kldname); 196491040Sarr } else { 196591040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 196691040Sarr return (EEXIST); 196794322Sbrian if (kldname != NULL) 196894322Sbrian pathname = linker_strdup(kldname); 196995488Sbrian else if (rootvnode == NULL) 197094322Sbrian pathname = NULL; 197194322Sbrian else 197291040Sarr /* 197391040Sarr * Need to find a KLD with required module 197491040Sarr */ 197591040Sarr pathname = linker_search_module(modname, 197691040Sarr strlen(modname), verinfo); 197791040Sarr } 197891040Sarr if (pathname == NULL) 197991040Sarr return (ENOENT); 198091040Sarr 198183321Speter /* 198291040Sarr * Can't load more than one file with the same basename XXX: 198391040Sarr * Actually it should be possible to have multiple KLDs with 198491040Sarr * the same basename but different path because they can 198591040Sarr * provide different versions of the same modules. 198683321Speter */ 198791040Sarr filename = linker_basename(pathname); 1988159792Sjhb if (linker_find_file_by_name(filename)) 198991040Sarr error = EEXIST; 1990159792Sjhb else do { 199191040Sarr error = linker_load_file(pathname, &lfdep); 199291040Sarr if (error) 199391040Sarr break; 199491040Sarr if (modname && verinfo && 199591040Sarr modlist_lookup2(modname, verinfo) == NULL) { 1996132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 199791040Sarr error = ENOENT; 199891040Sarr break; 199991040Sarr } 200091040Sarr if (parent) { 200191040Sarr error = linker_file_add_dependency(parent, lfdep); 200291040Sarr if (error) 200391040Sarr break; 200491040Sarr } 200591040Sarr if (lfpp) 200691040Sarr *lfpp = lfdep; 200791040Sarr } while (0); 2008159791Sjhb free(pathname, M_LINKER); 200991040Sarr return (error); 201059751Speter} 201159751Speter 201259751Speter/* 201391040Sarr * This routine is responsible for finding dependencies of userland initiated 201491040Sarr * kldload(2)'s of files. 201559751Speter */ 201659751Speterint 201786469Siedowselinker_load_dependencies(linker_file_t lf) 201859751Speter{ 201991040Sarr linker_file_t lfdep; 202091040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 202191040Sarr struct mod_metadata *mp, *nmp; 202291040Sarr struct mod_depend *verinfo; 202391040Sarr modlist_t mod; 202491040Sarr const char *modname, *nmodname; 202592032Sdwmalone int ver, error = 0, count; 202659751Speter 202791040Sarr /* 202891040Sarr * All files are dependant on /kernel. 202991040Sarr */ 2030159845Sjhb KLD_LOCK_ASSERT(); 203191040Sarr if (linker_kernel_file) { 203291040Sarr linker_kernel_file->refs++; 203391040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 203491040Sarr if (error) 203591040Sarr return (error); 203659751Speter } 203791040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 203891040Sarr &count) != 0) 203991040Sarr return (0); 204091040Sarr for (mdp = start; mdp < stop; mdp++) { 2041109605Sjake mp = *mdp; 204291040Sarr if (mp->md_type != MDT_VERSION) 204391040Sarr continue; 2044109605Sjake modname = mp->md_cval; 2045109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 204691040Sarr mod = modlist_lookup(modname, ver); 204791040Sarr if (mod != NULL) { 204891040Sarr printf("interface %s.%d already present in the KLD" 204991040Sarr " '%s'!\n", modname, ver, 205091040Sarr mod->container->filename); 205191040Sarr return (EEXIST); 205291040Sarr } 205391040Sarr } 205474642Sbp 205591040Sarr for (mdp = start; mdp < stop; mdp++) { 2056109605Sjake mp = *mdp; 205791040Sarr if (mp->md_type != MDT_DEPEND) 205891040Sarr continue; 2059109605Sjake modname = mp->md_cval; 2060109605Sjake verinfo = mp->md_data; 206191040Sarr nmodname = NULL; 206291040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 2063109605Sjake nmp = *nmdp; 206491040Sarr if (nmp->md_type != MDT_VERSION) 206591040Sarr continue; 2066109605Sjake nmodname = nmp->md_cval; 206792032Sdwmalone if (strcmp(modname, nmodname) == 0) 206891040Sarr break; 206991040Sarr } 207091040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 207191040Sarr continue; 207291040Sarr mod = modlist_lookup2(modname, verinfo); 207391040Sarr if (mod) { /* woohoo, it's loaded already */ 207491040Sarr lfdep = mod->container; 207591040Sarr lfdep->refs++; 207691040Sarr error = linker_file_add_dependency(lf, lfdep); 207791040Sarr if (error) 207891040Sarr break; 207991040Sarr continue; 208091040Sarr } 208191040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 208291040Sarr if (error) { 2083195803Srpaulo printf("KLD %s: depends on %s - not available or" 2084195803Srpaulo " version mismatch\n", lf->filename, modname); 208591040Sarr break; 208691040Sarr } 208759751Speter } 208859751Speter 208991040Sarr if (error) 209091040Sarr return (error); 209191040Sarr linker_addmodules(lf, start, stop, 0); 209291040Sarr return (error); 209359751Speter} 209485736Sgreen 209585736Sgreenstatic int 209685736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 209785736Sgreen{ 209885736Sgreen struct sysctl_req *req; 209985736Sgreen 210085736Sgreen req = opaque; 210185736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 210285736Sgreen} 210385736Sgreen 210485736Sgreen/* 210585736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 210685736Sgreen * in the kernel. 210785736Sgreen */ 210885736Sgreenstatic int 210985736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 211085736Sgreen{ 211185736Sgreen linker_file_t lf; 211285736Sgreen int error; 211385736Sgreen 2114107089Srwatson#ifdef MAC 2115172930Srwatson error = mac_kld_check_stat(req->td->td_ucred); 2116107089Srwatson if (error) 2117107089Srwatson return (error); 2118107089Srwatson#endif 2119126253Struckman error = sysctl_wire_old_buffer(req, 0); 2120126253Struckman if (error != 0) 2121126253Struckman return (error); 2122159845Sjhb KLD_LOCK(); 212385736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 212485736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 212585736Sgreen sysctl_kern_function_list_iterate, req); 212698452Sarr if (error) { 2127159845Sjhb KLD_UNLOCK(); 212885736Sgreen return (error); 212998452Sarr } 213085736Sgreen } 2131159845Sjhb KLD_UNLOCK(); 213285736Sgreen return (SYSCTL_OUT(req, "", 1)); 213385736Sgreen} 213485736Sgreen 213585736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 213691040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 2137