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$"); 29116182Sobrien 3040159Speter#include "opt_ddb.h" 31227151Sfjoe#include "opt_kld.h" 32157144Sjkoshy#include "opt_hwpmc_hooks.h" 3340159Speter 3425537Sdfr#include <sys/param.h> 3525537Sdfr#include <sys/kernel.h> 3625537Sdfr#include <sys/systm.h> 3725537Sdfr#include <sys/malloc.h> 3825537Sdfr#include <sys/sysproto.h> 3925537Sdfr#include <sys/sysent.h> 40164033Srwatson#include <sys/priv.h> 4125537Sdfr#include <sys/proc.h> 4225537Sdfr#include <sys/lock.h> 4382749Sdillon#include <sys/mutex.h> 4492547Sarr#include <sys/sx.h> 4525537Sdfr#include <sys/module.h> 46159808Sjhb#include <sys/mount.h> 4725537Sdfr#include <sys/linker.h> 48254266Smarkj#include <sys/eventhandler.h> 4940159Speter#include <sys/fcntl.h> 50192895Sjamie#include <sys/jail.h> 5140159Speter#include <sys/libkern.h> 5240159Speter#include <sys/namei.h> 5340159Speter#include <sys/vnode.h> 54159588Sjhb#include <sys/syscallsubr.h> 5540159Speter#include <sys/sysctl.h> 5625537Sdfr 57196019Srwatson#include <net/vnet.h> 58196019Srwatson 59163606Srwatson#include <security/mac/mac_framework.h> 60163606Srwatson 6159603Sdfr#include "linker_if.h" 6259603Sdfr 63157144Sjkoshy#ifdef HWPMC_HOOKS 64157144Sjkoshy#include <sys/pmckern.h> 65157144Sjkoshy#endif 66157144Sjkoshy 6740961Speter#ifdef KLD_DEBUG 6840961Speterint kld_debug = 0; 69232999SaeSYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RW | CTLFLAG_TUN, 70232999Sae &kld_debug, 0, "Set various levels of KLD debug"); 71232997SaeTUNABLE_INT("debug.kld_debug", &kld_debug); 7240961Speter#endif 7340961Speter 7491040Sarr/* 7591040Sarr * static char *linker_search_path(const char *name, struct mod_depend 7691040Sarr * *verinfo); 7791040Sarr */ 7891040Sarrstatic const char *linker_basename(const char *path); 7959751Speter 80159800Sjhb/* 81159800Sjhb * Find a currently loaded file given its filename. 82159800Sjhb */ 83159800Sjhbstatic linker_file_t linker_find_file_by_name(const char* _filename); 84159800Sjhb 85159800Sjhb/* 86159800Sjhb * Find a currently loaded file given its file id. 87159800Sjhb */ 88159800Sjhbstatic linker_file_t linker_find_file_by_id(int _fileid); 89159800Sjhb 9078161Speter/* Metadata from the static kernel */ 9178161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 9278161Speter 9359751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 9459751Speter 9540906Speterlinker_file_t linker_kernel_file; 9631324Sbde 97159845Sjhbstatic struct sx kld_sx; /* kernel linker lock */ 9898452Sarr 99172862Sjb/* 100172862Sjb * Load counter used by clients to determine if a linker file has been 101172862Sjb * re-loaded. This counter is incremented for each file load. 102172862Sjb */ 103172862Sjbstatic int loadcnt; 104172862Sjb 10525537Sdfrstatic linker_class_list_t classes; 10650068Sgrogstatic linker_file_list_t linker_files; 10725537Sdfrstatic int next_file_id = 1; 10898452Sarrstatic int linker_no_more_classes = 0; 10925537Sdfr 11086553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 11191040Sarr linker_file_t lftmp; \ 11286553Sarr \ 113254810Smarkj if (!cold) \ 114254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); \ 11586553Sarrretry: \ 11691040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 11791040Sarr if (next_file_id == lftmp->id) { \ 11891040Sarr next_file_id++; \ 11991040Sarr goto retry; \ 12091040Sarr } \ 12191040Sarr } \ 12291040Sarr (a) = next_file_id; \ 12386553Sarr} while(0) 12486553Sarr 12586553Sarr 12659751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 12760938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 12859751Speterstruct modlist { 12991040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 13091040Sarr linker_file_t container; 13191040Sarr const char *name; 13291040Sarr int version; 13359751Speter}; 13491040Sarrtypedef struct modlist *modlist_t; 13591040Sarrstatic modlisthead_t found_modules; 13659751Speter 137159796Sjhbstatic int linker_file_add_dependency(linker_file_t file, 138159796Sjhb linker_file_t dep); 139159845Sjhbstatic caddr_t linker_file_lookup_symbol_internal(linker_file_t file, 140159845Sjhb const char* name, int deps); 141159796Sjhbstatic int linker_load_module(const char *kldname, 142159796Sjhb const char *modname, struct linker_file *parent, 143159796Sjhb struct mod_depend *verinfo, struct linker_file **lfpp); 144159796Sjhbstatic modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); 14594321Sbrian 14625537Sdfrstatic void 14791040Sarrlinker_init(void *arg) 14825537Sdfr{ 14991040Sarr 150159845Sjhb sx_init(&kld_sx, "kernel linker"); 15191040Sarr TAILQ_INIT(&classes); 15291040Sarr TAILQ_INIT(&linker_files); 15325537Sdfr} 15425537Sdfr 155177253SrwatsonSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 15625537Sdfr 15798452Sarrstatic void 15898452Sarrlinker_stop_class_add(void *arg) 15998452Sarr{ 16098452Sarr 16198452Sarr linker_no_more_classes = 1; 16298452Sarr} 16398452Sarr 164177253SrwatsonSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL); 16598452Sarr 16625537Sdfrint 16759603Sdfrlinker_add_class(linker_class_t lc) 16825537Sdfr{ 16991040Sarr 17098452Sarr /* 171144443Sjhb * We disallow any class registration past SI_ORDER_ANY 172144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 173144443Sjhb * ops from being freed. 17498452Sarr */ 17598452Sarr if (linker_no_more_classes == 1) 17698452Sarr return (EPERM); 17791040Sarr kobj_class_compile((kobj_class_t) lc); 178144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 17991040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 18091040Sarr return (0); 18125537Sdfr} 18225537Sdfr 18325537Sdfrstatic void 18425537Sdfrlinker_file_sysinit(linker_file_t lf) 18525537Sdfr{ 18691040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 18725537Sdfr 18891040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 18991040Sarr lf->filename)); 19025537Sdfr 191254811Smarkj sx_assert(&kld_sx, SA_XLOCKED); 192254811Smarkj 19391040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 19491040Sarr return; 19591040Sarr /* 19691040Sarr * Perform a bubble sort of the system initialization objects by 19791040Sarr * their subsystem (primary key) and order (secondary key). 198159840Sjhb * 19991040Sarr * Since some things care about execution order, this is the operation 20091040Sarr * which ensures continued function. 20191040Sarr */ 20291040Sarr for (sipp = start; sipp < stop; sipp++) { 20391040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 20491040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 20591040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 20691040Sarr (*sipp)->order <= (*xipp)->order)) 20791040Sarr continue; /* skip */ 20891040Sarr save = *sipp; 20991040Sarr *sipp = *xipp; 21091040Sarr *xipp = save; 21191040Sarr } 21225537Sdfr } 21325537Sdfr 21491040Sarr /* 21591040Sarr * Traverse the (now) ordered list of system initialization tasks. 21691040Sarr * Perform each task, and continue on to the next task. 21791040Sarr */ 218254811Smarkj sx_xunlock(&kld_sx); 219160142Sjhb mtx_lock(&Giant); 22091040Sarr for (sipp = start; sipp < stop; sipp++) { 22191040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 22291040Sarr continue; /* skip dummy task(s) */ 22325537Sdfr 22491040Sarr /* Call function */ 22591040Sarr (*((*sipp)->func)) ((*sipp)->udata); 22691040Sarr } 227160142Sjhb mtx_unlock(&Giant); 228254811Smarkj sx_xlock(&kld_sx); 22925537Sdfr} 23025537Sdfr 23141055Speterstatic void 23241055Speterlinker_file_sysuninit(linker_file_t lf) 23341055Speter{ 23491040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 23541055Speter 23691040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 23791040Sarr lf->filename)); 23841055Speter 239254811Smarkj sx_assert(&kld_sx, SA_XLOCKED); 240254811Smarkj 24191068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 24291040Sarr NULL) != 0) 24391040Sarr return; 24441055Speter 24591040Sarr /* 24691040Sarr * Perform a reverse bubble sort of the system initialization objects 24791040Sarr * by their subsystem (primary key) and order (secondary key). 248159840Sjhb * 24991040Sarr * Since some things care about execution order, this is the operation 25091040Sarr * which ensures continued function. 25191040Sarr */ 25291040Sarr for (sipp = start; sipp < stop; sipp++) { 25391040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 25491040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 25591040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 25691040Sarr (*sipp)->order >= (*xipp)->order)) 25791040Sarr continue; /* skip */ 25891040Sarr save = *sipp; 25991040Sarr *sipp = *xipp; 26091040Sarr *xipp = save; 26191040Sarr } 26241055Speter } 26341055Speter 26491040Sarr /* 26591040Sarr * Traverse the (now) ordered list of system initialization tasks. 26691040Sarr * Perform each task, and continue on to the next task. 26791040Sarr */ 268254811Smarkj sx_xunlock(&kld_sx); 269160142Sjhb mtx_lock(&Giant); 27091040Sarr for (sipp = start; sipp < stop; sipp++) { 27191040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 27291040Sarr continue; /* skip dummy task(s) */ 27341055Speter 27491040Sarr /* Call function */ 27591040Sarr (*((*sipp)->func)) ((*sipp)->udata); 27691040Sarr } 277160142Sjhb mtx_unlock(&Giant); 278254811Smarkj sx_xlock(&kld_sx); 27941055Speter} 28041055Speter 28144078Sdfrstatic void 28244078Sdfrlinker_file_register_sysctls(linker_file_t lf) 28344078Sdfr{ 28491040Sarr struct sysctl_oid **start, **stop, **oidp; 28544078Sdfr 28691040Sarr KLD_DPF(FILE, 28791040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 28891040Sarr lf->filename)); 28944078Sdfr 290254811Smarkj sx_assert(&kld_sx, SA_XLOCKED); 291254811Smarkj 29291040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 29391040Sarr return; 29444078Sdfr 295254811Smarkj sx_xunlock(&kld_sx); 296188232Sjhb sysctl_lock(); 29791040Sarr for (oidp = start; oidp < stop; oidp++) 29891040Sarr sysctl_register_oid(*oidp); 299188232Sjhb sysctl_unlock(); 300254811Smarkj sx_xlock(&kld_sx); 30144078Sdfr} 30244078Sdfr 30344078Sdfrstatic void 30444078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 30544078Sdfr{ 30691040Sarr struct sysctl_oid **start, **stop, **oidp; 30744078Sdfr 308233295Sae KLD_DPF(FILE, ("linker_file_unregister_sysctls: unregistering SYSCTLs" 30991040Sarr " for %s\n", lf->filename)); 31044078Sdfr 311254811Smarkj sx_assert(&kld_sx, SA_XLOCKED); 312254811Smarkj 31391040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 31491040Sarr return; 31544078Sdfr 316254811Smarkj sx_xunlock(&kld_sx); 317188232Sjhb sysctl_lock(); 31891040Sarr for (oidp = start; oidp < stop; oidp++) 31991040Sarr sysctl_unregister_oid(*oidp); 320188232Sjhb sysctl_unlock(); 321254811Smarkj sx_xlock(&kld_sx); 32244078Sdfr} 32344078Sdfr 32459751Speterstatic int 32559751Speterlinker_file_register_modules(linker_file_t lf) 32659751Speter{ 32791040Sarr struct mod_metadata **start, **stop, **mdp; 32891040Sarr const moduledata_t *moddata; 329146733Spjd int first_error, error; 33059751Speter 33191040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 33291040Sarr " in %s\n", lf->filename)); 33359751Speter 334254811Smarkj sx_assert(&kld_sx, SA_XLOCKED); 335254811Smarkj 33691068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 337159841Sjhb &stop, NULL) != 0) { 33891040Sarr /* 33991040Sarr * This fallback should be unnecessary, but if we get booted 34091040Sarr * from boot2 instead of loader and we are missing our 34191040Sarr * metadata then we have to try the best we can. 34291040Sarr */ 34391040Sarr if (lf == linker_kernel_file) { 34491040Sarr start = SET_BEGIN(modmetadata_set); 34591040Sarr stop = SET_LIMIT(modmetadata_set); 34691040Sarr } else 34791040Sarr return (0); 34878161Speter } 349146733Spjd first_error = 0; 35091040Sarr for (mdp = start; mdp < stop; mdp++) { 35191040Sarr if ((*mdp)->md_type != MDT_MODULE) 35291040Sarr continue; 35391040Sarr moddata = (*mdp)->md_data; 35491040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 35591040Sarr moddata->name, lf->filename)); 35691040Sarr error = module_register(moddata, lf); 357146730Spjd if (error) { 35891068Sarr printf("Module %s failed to register: %d\n", 35991040Sarr moddata->name, error); 360146733Spjd if (first_error == 0) 361146733Spjd first_error = error; 362146730Spjd } 36359751Speter } 364146733Spjd return (first_error); 36559751Speter} 36659751Speter 36759751Speterstatic void 36859751Speterlinker_init_kernel_modules(void) 36959751Speter{ 37091040Sarr 371254810Smarkj sx_xlock(&kld_sx); 37291040Sarr linker_file_register_modules(linker_kernel_file); 373254810Smarkj sx_xunlock(&kld_sx); 37459751Speter} 37559751Speter 376177253SrwatsonSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 377177253Srwatson 0); 37859751Speter 379101241Smuxstatic int 38091040Sarrlinker_load_file(const char *filename, linker_file_t *result) 38125537Sdfr{ 38291040Sarr linker_class_t lc; 38391040Sarr linker_file_t lf; 384234186Sjhb int foundfile, error, modules; 38525537Sdfr 38691040Sarr /* Refuse to load modules if securelevel raised */ 387192895Sjamie if (prison0.pr_securelevel > 0) 38891040Sarr return (EPERM); 38962261Sarchie 390254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 39191040Sarr lf = linker_find_file_by_name(filename); 39291040Sarr if (lf) { 39391040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 39491040Sarr " incrementing refs\n", filename)); 39591040Sarr *result = lf; 39691040Sarr lf->refs++; 397159585Sjhb return (0); 39891040Sarr } 39991040Sarr foundfile = 0; 400159585Sjhb error = 0; 40198452Sarr 40298452Sarr /* 40398452Sarr * We do not need to protect (lock) classes here because there is 40498452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 40598452Sarr * and there is no class deregistration mechanism at this time. 40698452Sarr */ 40791040Sarr TAILQ_FOREACH(lc, &classes, link) { 40891040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 40991040Sarr filename)); 41091040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 41191040Sarr /* 41291040Sarr * If we got something other than ENOENT, then it exists but 41391040Sarr * we cannot load it for some other reason. 41491040Sarr */ 41591040Sarr if (error != ENOENT) 41691040Sarr foundfile = 1; 41791040Sarr if (lf) { 418146730Spjd error = linker_file_register_modules(lf); 419146730Spjd if (error == EEXIST) { 420146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 421159585Sjhb return (error); 422146730Spjd } 423234186Sjhb modules = !TAILQ_EMPTY(&lf->modules); 42491040Sarr linker_file_register_sysctls(lf); 42591040Sarr linker_file_sysinit(lf); 42691040Sarr lf->flags |= LINKER_FILE_LINKED; 427234186Sjhb 428234186Sjhb /* 429234186Sjhb * If all of the modules in this file failed 430234186Sjhb * to load, unload the file and return an 431234186Sjhb * error of ENOEXEC. 432234186Sjhb */ 433234186Sjhb if (modules && TAILQ_EMPTY(&lf->modules)) { 434234186Sjhb linker_file_unload(lf, LINKER_UNLOAD_FORCE); 435234186Sjhb return (ENOEXEC); 436234186Sjhb } 437262039Savg EVENTHANDLER_INVOKE(kld_load, lf); 43891040Sarr *result = lf; 439159585Sjhb return (0); 44091040Sarr } 44191040Sarr } 44242755Speter /* 44391040Sarr * Less than ideal, but tells the user whether it failed to load or 44491040Sarr * the module was not found. 44542755Speter */ 446105337Ssam if (foundfile) { 447188440Sattilio 448105337Ssam /* 449188440Sattilio * If the file type has not been recognized by the last try 450188440Sattilio * printout a message before to fail. 451188440Sattilio */ 452188440Sattilio if (error == ENOSYS) 453188440Sattilio printf("linker_load_file: Unsupported file type\n"); 454188440Sattilio 455188440Sattilio /* 456105337Ssam * Format not recognized or otherwise unloadable. 457105337Ssam * When loading a module that is statically built into 458105337Ssam * the kernel EEXIST percolates back up as the return 459105337Ssam * value. Preserve this so that apps like sysinstall 460105337Ssam * can recognize this special case and not post bogus 461105337Ssam * dialog boxes. 462105337Ssam */ 463105337Ssam if (error != EEXIST) 464105337Ssam error = ENOEXEC; 465105337Ssam } else 46691068Sarr error = ENOENT; /* Nothing found */ 46791040Sarr return (error); 46825537Sdfr} 46925537Sdfr 47078413Sbrianint 47194321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 47294321Sbrian linker_file_t *result) 47378413Sbrian{ 47494321Sbrian modlist_t mod; 475159804Sjhb int error; 47694321Sbrian 477254810Smarkj sx_xlock(&kld_sx); 47894321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 47994321Sbrian *result = mod->container; 48094321Sbrian (*result)->refs++; 481254810Smarkj sx_xunlock(&kld_sx); 48294321Sbrian return (0); 48394321Sbrian } 48494321Sbrian 485159804Sjhb error = linker_load_module(NULL, modname, NULL, verinfo, result); 486254810Smarkj sx_xunlock(&kld_sx); 487159804Sjhb return (error); 48878413Sbrian} 48978413Sbrian 490159804Sjhbint 491159804Sjhblinker_release_module(const char *modname, struct mod_depend *verinfo, 492159804Sjhb linker_file_t lf) 493159804Sjhb{ 494159804Sjhb modlist_t mod; 495159804Sjhb int error; 496159804Sjhb 497254810Smarkj sx_xlock(&kld_sx); 498159804Sjhb if (lf == NULL) { 499159804Sjhb KASSERT(modname != NULL, 500159804Sjhb ("linker_release_module: no file or name")); 501159804Sjhb mod = modlist_lookup2(modname, verinfo); 502159804Sjhb if (mod == NULL) { 503254810Smarkj sx_xunlock(&kld_sx); 504159804Sjhb return (ESRCH); 505159804Sjhb } 506159804Sjhb lf = mod->container; 507159804Sjhb } else 508159804Sjhb KASSERT(modname == NULL && verinfo == NULL, 509159804Sjhb ("linker_release_module: both file and name")); 510159804Sjhb error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL); 511254810Smarkj sx_xunlock(&kld_sx); 512159804Sjhb return (error); 513159804Sjhb} 514159804Sjhb 515159800Sjhbstatic linker_file_t 51691040Sarrlinker_find_file_by_name(const char *filename) 51725537Sdfr{ 518159585Sjhb linker_file_t lf; 51991040Sarr char *koname; 52025537Sdfr 521111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 52291040Sarr sprintf(koname, "%s.ko", filename); 52340861Speter 524254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 52591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 52692032Sdwmalone if (strcmp(lf->filename, koname) == 0) 52791040Sarr break; 52892032Sdwmalone if (strcmp(lf->filename, filename) == 0) 52991040Sarr break; 53091040Sarr } 531159585Sjhb free(koname, M_LINKER); 53291040Sarr return (lf); 53325537Sdfr} 53425537Sdfr 535159800Sjhbstatic linker_file_t 53625537Sdfrlinker_find_file_by_id(int fileid) 53725537Sdfr{ 538159585Sjhb linker_file_t lf; 539159845Sjhb 540254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 54191040Sarr TAILQ_FOREACH(lf, &linker_files, link) 542166921Sjhb if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED) 54391040Sarr break; 54491040Sarr return (lf); 54525537Sdfr} 54625537Sdfr 547159797Sjhbint 548159797Sjhblinker_file_foreach(linker_predicate_t *predicate, void *context) 549159797Sjhb{ 550159797Sjhb linker_file_t lf; 551159797Sjhb int retval = 0; 552159797Sjhb 553254810Smarkj sx_xlock(&kld_sx); 554159797Sjhb TAILQ_FOREACH(lf, &linker_files, link) { 555159797Sjhb retval = predicate(lf, context); 556159797Sjhb if (retval != 0) 557159797Sjhb break; 558159797Sjhb } 559254810Smarkj sx_xunlock(&kld_sx); 560159797Sjhb return (retval); 561159797Sjhb} 562159797Sjhb 56325537Sdfrlinker_file_t 56491040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 56525537Sdfr{ 56691040Sarr linker_file_t lf; 56791040Sarr const char *filename; 56825537Sdfr 569254810Smarkj if (!cold) 570254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 57191040Sarr filename = linker_basename(pathname); 57240159Speter 573172862Sjb KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname)); 574111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 57591040Sarr if (lf == NULL) 576159585Sjhb return (NULL); 57791040Sarr lf->refs = 1; 57891040Sarr lf->userrefs = 0; 57991040Sarr lf->flags = 0; 580254396Smarkj lf->filename = strdup(filename, M_LINKER); 581254396Smarkj lf->pathname = strdup(pathname, M_LINKER); 58291040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 58391040Sarr lf->ndeps = 0; 58491040Sarr lf->deps = NULL; 585172862Sjb lf->loadcnt = ++loadcnt; 58691040Sarr STAILQ_INIT(&lf->common); 58791040Sarr TAILQ_INIT(&lf->modules); 58891040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 58991040Sarr return (lf); 59025537Sdfr} 59125537Sdfr 59225537Sdfrint 593132117Sphklinker_file_unload(linker_file_t file, int flags) 59425537Sdfr{ 59591040Sarr module_t mod, next; 59691040Sarr modlist_t ml, nextml; 59791040Sarr struct common_symbol *cp; 59891040Sarr int error, i; 59925537Sdfr 60091040Sarr /* Refuse to unload modules if securelevel raised. */ 601192895Sjamie if (prison0.pr_securelevel > 0) 60291040Sarr return (EPERM); 60325537Sdfr 604254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 60591040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 60691040Sarr 607159584Sjhb /* Easy case of just dropping a reference. */ 608159584Sjhb if (file->refs > 1) { 609159584Sjhb file->refs--; 610159584Sjhb return (0); 611159584Sjhb } 612159584Sjhb 613262039Savg /* Give eventhandlers a chance to prevent the unload. */ 614262039Savg error = 0; 615262039Savg EVENTHANDLER_INVOKE(kld_unload_try, file, &error); 616262039Savg if (error != 0) 617262039Savg return (EBUSY); 618262039Savg 619159584Sjhb KLD_DPF(FILE, ("linker_file_unload: file is unloading," 620159584Sjhb " informing modules\n")); 621159584Sjhb 622159584Sjhb /* 623185635Sjhb * Quiesce all the modules to give them a chance to veto the unload. 624159584Sjhb */ 625185635Sjhb MOD_SLOCK; 626185635Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; 627185635Sjhb mod = module_getfnext(mod)) { 628185635Sjhb 629185635Sjhb error = module_quiesce(mod); 630185635Sjhb if (error != 0 && flags != LINKER_UNLOAD_FORCE) { 631185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 632185635Sjhb " vetoed unload\n", module_getname(mod))); 633185635Sjhb /* 634185635Sjhb * XXX: Do we need to tell all the quiesced modules 635185635Sjhb * that they can resume work now via a new module 636185635Sjhb * event? 637185635Sjhb */ 638185635Sjhb MOD_SUNLOCK; 639185635Sjhb return (error); 640185635Sjhb } 641185635Sjhb } 642185635Sjhb MOD_SUNLOCK; 643185635Sjhb 644185635Sjhb /* 645185635Sjhb * Inform any modules associated with this file that they are 646234186Sjhb * being unloaded. 647185635Sjhb */ 648159584Sjhb MOD_XLOCK; 649159584Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 650159584Sjhb next = module_getfnext(mod); 651159584Sjhb MOD_XUNLOCK; 652159584Sjhb 65391040Sarr /* 654159584Sjhb * Give the module a chance to veto the unload. 65591040Sarr */ 656185635Sjhb if ((error = module_unload(mod)) != 0) { 657233276Sae#ifdef KLD_DEBUG 658233276Sae MOD_SLOCK; 659185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 660199457Sgonzo " failed unload\n", module_getname(mod))); 661233276Sae MOD_SUNLOCK; 662233276Sae#endif 663159584Sjhb return (error); 664159584Sjhb } 66592547Sarr MOD_XLOCK; 666159584Sjhb module_release(mod); 667159584Sjhb } 668159584Sjhb MOD_XUNLOCK; 66991040Sarr 670159586Sjhb TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml) { 671128057Speadar if (ml->container == file) { 67291040Sarr TAILQ_REMOVE(&found_modules, ml, link); 673128057Speadar free(ml, M_LINKER); 674128057Speadar } 67591040Sarr } 67625537Sdfr 677159840Sjhb /* 678159840Sjhb * Don't try to run SYSUNINITs if we are unloaded due to a 67991040Sarr * link error. 68091040Sarr */ 68191040Sarr if (file->flags & LINKER_FILE_LINKED) { 682188209Sjhb file->flags &= ~LINKER_FILE_LINKED; 68391040Sarr linker_file_sysuninit(file); 68491040Sarr linker_file_unregister_sysctls(file); 68525537Sdfr } 68691040Sarr TAILQ_REMOVE(&linker_files, file, link); 68725537Sdfr 68891040Sarr if (file->deps) { 68991040Sarr for (i = 0; i < file->ndeps; i++) 690132117Sphk linker_file_unload(file->deps[i], flags); 69191040Sarr free(file->deps, M_LINKER); 69291040Sarr file->deps = NULL; 69359751Speter } 694160245Sjhb while ((cp = STAILQ_FIRST(&file->common)) != NULL) { 695160245Sjhb STAILQ_REMOVE_HEAD(&file->common, link); 69691040Sarr free(cp, M_LINKER); 69791040Sarr } 69859751Speter 69991040Sarr LINKER_UNLOAD(file); 700262039Savg 701262039Savg EVENTHANDLER_INVOKE(kld_unload, file->filename, file->address, 702262039Savg file->size); 703262039Savg 70491040Sarr if (file->filename) { 70591040Sarr free(file->filename, M_LINKER); 70691040Sarr file->filename = NULL; 70791040Sarr } 708172862Sjb if (file->pathname) { 709172862Sjb free(file->pathname, M_LINKER); 710172862Sjb file->pathname = NULL; 711172862Sjb } 71291040Sarr kobj_delete((kobj_t) file, M_LINKER); 713159584Sjhb return (0); 71425537Sdfr} 71525537Sdfr 716179238Sjbint 717179238Sjblinker_ctf_get(linker_file_t file, linker_ctf_t *lc) 718179238Sjb{ 719179238Sjb return (LINKER_CTF_GET(file, lc)); 720179238Sjb} 721179238Sjb 722159796Sjhbstatic int 72386469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 72425537Sdfr{ 72591040Sarr linker_file_t *newdeps; 72625537Sdfr 727254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 728264370Skib file->deps = realloc(file->deps, (file->ndeps + 1) * sizeof(*newdeps), 729264370Skib M_LINKER, M_WAITOK | M_ZERO); 73091040Sarr file->deps[file->ndeps] = dep; 73191040Sarr file->ndeps++; 732199457Sgonzo KLD_DPF(FILE, ("linker_file_add_dependency:" 733199457Sgonzo " adding %s as dependency for %s\n", 734199457Sgonzo dep->filename, file->filename)); 73591040Sarr return (0); 73625537Sdfr} 73725537Sdfr 73878161Speter/* 73991040Sarr * Locate a linker set and its contents. This is a helper function to avoid 740159841Sjhb * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. 741159841Sjhb * This function is used in this file so we can avoid having lots of (void **) 742159841Sjhb * casts. 74378161Speter */ 74478161Speterint 74578161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 74691040Sarr void *firstp, void *lastp, int *countp) 74778161Speter{ 74878161Speter 749254811Smarkj sx_assert(&kld_sx, SA_LOCKED); 750254811Smarkj return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 75178161Speter} 75278161Speter 753173714Sjb/* 754173714Sjb * List all functions in a file. 755173714Sjb */ 756173714Sjbint 757173714Sjblinker_file_function_listall(linker_file_t lf, 758179238Sjb linker_function_nameval_callback_t callback_func, void *arg) 759173714Sjb{ 760173714Sjb return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); 761173714Sjb} 762173714Sjb 76325537Sdfrcaddr_t 76491040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 76525537Sdfr{ 766159845Sjhb caddr_t sym; 767159845Sjhb int locked; 768159845Sjhb 769254810Smarkj locked = sx_xlocked(&kld_sx); 770159845Sjhb if (!locked) 771254810Smarkj sx_xlock(&kld_sx); 772159845Sjhb sym = linker_file_lookup_symbol_internal(file, name, deps); 773159845Sjhb if (!locked) 774254810Smarkj sx_xunlock(&kld_sx); 775159845Sjhb return (sym); 776159845Sjhb} 777159845Sjhb 778159845Sjhbstatic caddr_t 779159845Sjhblinker_file_lookup_symbol_internal(linker_file_t file, const char *name, 780159845Sjhb int deps) 781159845Sjhb{ 78291040Sarr c_linker_sym_t sym; 78391040Sarr linker_symval_t symval; 78491040Sarr caddr_t address; 78591040Sarr size_t common_size = 0; 78692032Sdwmalone int i; 78725537Sdfr 788254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 789109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 79091040Sarr file, name, deps)); 79125537Sdfr 79291040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 79391040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 79491040Sarr if (symval.value == 0) 79591040Sarr /* 79691040Sarr * For commons, first look them up in the 79791040Sarr * dependencies and only allocate space if not found 79891040Sarr * there. 79991040Sarr */ 80091040Sarr common_size = symval.size; 80191040Sarr else { 80291040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 803109605Sjake ".value=%p\n", symval.value)); 80491040Sarr return (symval.value); 80591040Sarr } 80640159Speter } 80791040Sarr if (deps) { 80891040Sarr for (i = 0; i < file->ndeps; i++) { 809159845Sjhb address = linker_file_lookup_symbol_internal( 810159845Sjhb file->deps[i], name, 0); 81191040Sarr if (address) { 81291040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 813109605Sjake " deps value=%p\n", address)); 81491040Sarr return (address); 81591040Sarr } 81691040Sarr } 81725537Sdfr } 81891040Sarr if (common_size > 0) { 81991040Sarr /* 82091040Sarr * This is a common symbol which was not found in the 82191040Sarr * dependencies. We maintain a simple common symbol table in 82291040Sarr * the file object. 82391040Sarr */ 82491040Sarr struct common_symbol *cp; 82542849Speter 82691040Sarr STAILQ_FOREACH(cp, &file->common, link) { 82792032Sdwmalone if (strcmp(cp->name, name) == 0) { 82891040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 829109605Sjake " old common value=%p\n", cp->address)); 83091040Sarr return (cp->address); 83191040Sarr } 83291040Sarr } 83391040Sarr /* 83491040Sarr * Round the symbol size up to align. 83591040Sarr */ 83691040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 83791040Sarr cp = malloc(sizeof(struct common_symbol) 83891040Sarr + common_size + strlen(name) + 1, M_LINKER, 839111119Simp M_WAITOK | M_ZERO); 84091040Sarr cp->address = (caddr_t)(cp + 1); 84191040Sarr cp->name = cp->address + common_size; 84291040Sarr strcpy(cp->name, name); 84391040Sarr bzero(cp->address, common_size); 84491040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 84525537Sdfr 84691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 847109605Sjake " value=%p\n", cp->address)); 84891040Sarr return (cp->address); 84940159Speter } 85091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 85191040Sarr return (0); 85225537Sdfr} 85325537Sdfr 85425537Sdfr/* 855174132Srwatson * Both DDB and stack(9) rely on the kernel linker to provide forward and 856174132Srwatson * backward lookup of symbols. However, DDB and sometimes stack(9) need to 857174132Srwatson * do this in a lockfree manner. We provide a set of internal helper 858174132Srwatson * routines to perform these operations without locks, and then wrappers that 859174132Srwatson * optionally lock. 860159840Sjhb * 861174132Srwatson * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. 86240159Speter */ 863174132Srwatson#ifdef DDB 864174132Srwatsonstatic int 865174132Srwatsonlinker_debug_lookup(const char *symstr, c_linker_sym_t *sym) 86640159Speter{ 86791040Sarr linker_file_t lf; 86840159Speter 86991040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 87091040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 87191040Sarr return (0); 87291040Sarr } 87391040Sarr return (ENOENT); 87440159Speter} 875174132Srwatson#endif 87640159Speter 877174132Srwatsonstatic int 878174132Srwatsonlinker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 87940159Speter{ 88091040Sarr linker_file_t lf; 88191040Sarr c_linker_sym_t best, es; 88291040Sarr u_long diff, bestdiff, off; 88340159Speter 88491040Sarr best = 0; 88591040Sarr off = (uintptr_t)value; 88691040Sarr bestdiff = off; 88791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 88891040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 88991040Sarr continue; 89091040Sarr if (es != 0 && diff < bestdiff) { 89191040Sarr best = es; 89291040Sarr bestdiff = diff; 89391040Sarr } 89491040Sarr if (bestdiff == 0) 89591040Sarr break; 89640159Speter } 89791040Sarr if (best) { 89891040Sarr *sym = best; 89991040Sarr *diffp = bestdiff; 90091040Sarr return (0); 90191040Sarr } else { 90291040Sarr *sym = 0; 90391040Sarr *diffp = off; 90491040Sarr return (ENOENT); 90591040Sarr } 90640159Speter} 90740159Speter 908174132Srwatsonstatic int 909174132Srwatsonlinker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 91040159Speter{ 91191040Sarr linker_file_t lf; 91240159Speter 91391040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 91491040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 91591040Sarr return (0); 91691040Sarr } 91791040Sarr return (ENOENT); 91840159Speter} 919174132Srwatson 920174132Srwatsonstatic int 921174132Srwatsonlinker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, 922174132Srwatson long *offset) 923174132Srwatson{ 924174132Srwatson linker_symval_t symval; 925174132Srwatson c_linker_sym_t sym; 926174132Srwatson int error; 927174132Srwatson 928174132Srwatson *offset = 0; 929174132Srwatson error = linker_debug_search_symbol(value, &sym, offset); 930174132Srwatson if (error) 931174132Srwatson return (error); 932174132Srwatson error = linker_debug_symbol_values(sym, &symval); 933174132Srwatson if (error) 934174132Srwatson return (error); 935174132Srwatson strlcpy(buf, symval.name, buflen); 936174132Srwatson return (0); 937174132Srwatson} 938174132Srwatson 939174132Srwatson/* 940174132Srwatson * DDB Helpers. DDB has to look across multiple files with their own symbol 941174132Srwatson * tables and string tables. 942174132Srwatson * 943174132Srwatson * Note that we do not obey list locking protocols here. We really don't need 944174132Srwatson * DDB to hang because somebody's got the lock held. We'll take the chance 945174132Srwatson * that the files list is inconsistant instead. 946174132Srwatson */ 947212994Savg#ifdef DDB 948174132Srwatsonint 949174132Srwatsonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 950174132Srwatson{ 951174132Srwatson 952174132Srwatson return (linker_debug_lookup(symstr, sym)); 953174132Srwatson} 954212994Savg#endif 955174132Srwatson 956174132Srwatsonint 957174132Srwatsonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 958174132Srwatson{ 959174132Srwatson 960174132Srwatson return (linker_debug_search_symbol(value, sym, diffp)); 961174132Srwatson} 962174132Srwatson 963174132Srwatsonint 964174132Srwatsonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 965174132Srwatson{ 966174132Srwatson 967174132Srwatson return (linker_debug_symbol_values(sym, symval)); 968174132Srwatson} 969174132Srwatson 970174132Srwatsonint 971174132Srwatsonlinker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, 972174132Srwatson long *offset) 973174132Srwatson{ 974174132Srwatson 975174132Srwatson return (linker_debug_search_symbol_name(value, buf, buflen, offset)); 976174132Srwatson} 97740159Speter 97840159Speter/* 979174132Srwatson * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do 980174132Srwatson * obey locking protocols, and offer a significantly less complex interface. 981174132Srwatson */ 982174132Srwatsonint 983174132Srwatsonlinker_search_symbol_name(caddr_t value, char *buf, u_int buflen, 984174132Srwatson long *offset) 985174132Srwatson{ 986178380Spjd int error; 987174132Srwatson 988254810Smarkj sx_xlock(&kld_sx); 989174132Srwatson error = linker_debug_search_symbol_name(value, buf, buflen, offset); 990254810Smarkj sx_xunlock(&kld_sx); 991174132Srwatson return (error); 992174132Srwatson} 993174132Srwatson 994174132Srwatson/* 99525537Sdfr * Syscalls. 99625537Sdfr */ 99725537Sdfrint 998159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 99925537Sdfr{ 1000159588Sjhb const char *kldname, *modname; 100191040Sarr linker_file_t lf; 1002159588Sjhb int error; 100325537Sdfr 100493159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 1005159588Sjhb return (error); 100693159Sarr 1007164033Srwatson if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0) 1008159588Sjhb return (error); 100925537Sdfr 101091040Sarr /* 1011191917Szec * It is possible that kldloaded module will attach a new ifnet, 1012191816Szec * so vnet context must be set when this ocurs. 1013191816Szec */ 1014191816Szec CURVNET_SET(TD_TO_VNET(td)); 1015191816Szec 1016191816Szec /* 1017159841Sjhb * If file does not contain a qualified name or any dot in it 1018159841Sjhb * (kldname.ko, or kldname.ver.ko) treat it as an interface 101991040Sarr * name. 102091040Sarr */ 1021229272Sed if (strchr(file, '/') || strchr(file, '.')) { 1022159588Sjhb kldname = file; 102391040Sarr modname = NULL; 102491040Sarr } else { 102591040Sarr kldname = NULL; 1026159588Sjhb modname = file; 102791040Sarr } 1028159588Sjhb 1029254810Smarkj sx_xlock(&kld_sx); 103091040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 1031224156Srstone if (error) { 1032254810Smarkj sx_xunlock(&kld_sx); 1033224156Srstone goto done; 1034224156Srstone } 1035224156Srstone lf->userrefs++; 1036224156Srstone if (fileid != NULL) 1037224156Srstone *fileid = lf->id; 1038262039Savg sx_xunlock(&kld_sx); 1039254266Smarkj 1040224156Srstonedone: 1041191816Szec CURVNET_RESTORE(); 104291040Sarr return (error); 104325537Sdfr} 104425537Sdfr 1045159588Sjhbint 1046225617Skmacysys_kldload(struct thread *td, struct kldload_args *uap) 1047159588Sjhb{ 1048159588Sjhb char *pathname = NULL; 1049159596Smarcel int error, fileid; 1050159588Sjhb 1051159588Sjhb td->td_retval[0] = -1; 1052159588Sjhb 1053159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1054159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 1055159596Smarcel if (error == 0) { 1056159596Smarcel error = kern_kldload(td, pathname, &fileid); 1057159596Smarcel if (error == 0) 1058159596Smarcel td->td_retval[0] = fileid; 1059159596Smarcel } 1060159588Sjhb free(pathname, M_TEMP); 1061159588Sjhb return (error); 1062159588Sjhb} 1063159588Sjhb 1064159588Sjhbint 1065132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 106625537Sdfr{ 106791040Sarr linker_file_t lf; 106891040Sarr int error = 0; 106925537Sdfr 107093159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 1071159588Sjhb return (error); 107293159Sarr 1073164033Srwatson if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0) 1074159588Sjhb return (error); 107525537Sdfr 1076191816Szec CURVNET_SET(TD_TO_VNET(td)); 1077254810Smarkj sx_xlock(&kld_sx); 1078132117Sphk lf = linker_find_file_by_id(fileid); 107991040Sarr if (lf) { 108091040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 1081172862Sjb 1082262039Savg if (lf->userrefs == 0) { 1083132117Sphk /* 1084132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 1085132117Sphk */ 108691040Sarr printf("kldunload: attempt to unload file that was" 108791040Sarr " loaded by the kernel\n"); 1088159840Sjhb error = EBUSY; 1089159588Sjhb } else { 1090159588Sjhb lf->userrefs--; 1091159588Sjhb error = linker_file_unload(lf, flags); 1092159588Sjhb if (error) 1093159588Sjhb lf->userrefs++; 1094159588Sjhb } 109591040Sarr } else 109691040Sarr error = ENOENT; 1097262039Savg sx_xunlock(&kld_sx); 1098157144Sjkoshy 1099191816Szec CURVNET_RESTORE(); 110091068Sarr return (error); 110125537Sdfr} 110225537Sdfr 110325537Sdfrint 1104225617Skmacysys_kldunload(struct thread *td, struct kldunload_args *uap) 1105132117Sphk{ 1106132117Sphk 1107132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 1108132117Sphk} 1109132117Sphk 1110132117Sphkint 1111225617Skmacysys_kldunloadf(struct thread *td, struct kldunloadf_args *uap) 1112132117Sphk{ 1113132117Sphk 1114132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 1115132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 1116132117Sphk return (EINVAL); 1117132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 1118132117Sphk} 1119132117Sphk 1120132117Sphkint 1121225617Skmacysys_kldfind(struct thread *td, struct kldfind_args *uap) 112225537Sdfr{ 112391040Sarr char *pathname; 112491040Sarr const char *filename; 112591040Sarr linker_file_t lf; 1126159791Sjhb int error; 112725537Sdfr 1128107089Srwatson#ifdef MAC 1129172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1130107089Srwatson if (error) 1131107089Srwatson return (error); 1132107089Srwatson#endif 1133107089Srwatson 113491040Sarr td->td_retval[0] = -1; 113582749Sdillon 1136111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1137107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 113891040Sarr goto out; 113925537Sdfr 114091040Sarr filename = linker_basename(pathname); 1141254810Smarkj sx_xlock(&kld_sx); 114291040Sarr lf = linker_find_file_by_name(filename); 114391040Sarr if (lf) 114491040Sarr td->td_retval[0] = lf->id; 114591040Sarr else 114691040Sarr error = ENOENT; 1147254810Smarkj sx_xunlock(&kld_sx); 114825537Sdfrout: 1149159791Sjhb free(pathname, M_TEMP); 115091040Sarr return (error); 115125537Sdfr} 115225537Sdfr 115325537Sdfrint 1154225617Skmacysys_kldnext(struct thread *td, struct kldnext_args *uap) 115525537Sdfr{ 115691040Sarr linker_file_t lf; 115791040Sarr int error = 0; 115825537Sdfr 1159107089Srwatson#ifdef MAC 1160172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1161107089Srwatson if (error) 1162107089Srwatson return (error); 1163107089Srwatson#endif 1164107089Srwatson 1165254810Smarkj sx_xlock(&kld_sx); 1166166921Sjhb if (uap->fileid == 0) 1167166921Sjhb lf = TAILQ_FIRST(&linker_files); 1168166921Sjhb else { 1169166921Sjhb lf = linker_find_file_by_id(uap->fileid); 1170166921Sjhb if (lf == NULL) { 1171166921Sjhb error = ENOENT; 1172166921Sjhb goto out; 1173166921Sjhb } 1174166921Sjhb lf = TAILQ_NEXT(lf, link); 117591040Sarr } 1176166921Sjhb 1177166921Sjhb /* Skip partially loaded files. */ 1178166921Sjhb while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) 1179166921Sjhb lf = TAILQ_NEXT(lf, link); 1180166921Sjhb 1181166921Sjhb if (lf) 1182166921Sjhb td->td_retval[0] = lf->id; 1183166921Sjhb else 1184166921Sjhb td->td_retval[0] = 0; 118582749Sdillonout: 1186254810Smarkj sx_xunlock(&kld_sx); 118791040Sarr return (error); 118825537Sdfr} 118925537Sdfr 119025537Sdfrint 1191225617Skmacysys_kldstat(struct thread *td, struct kldstat_args *uap) 119225537Sdfr{ 1193159587Sjhb struct kld_file_stat stat; 1194220158Skib int error, version; 119525537Sdfr 1196159587Sjhb /* 1197159587Sjhb * Check the version of the user's structure. 1198159587Sjhb */ 1199220158Skib if ((error = copyin(&uap->stat->version, &version, sizeof(version))) 1200220158Skib != 0) 1201159587Sjhb return (error); 1202220158Skib if (version != sizeof(struct kld_file_stat_1) && 1203220158Skib version != sizeof(struct kld_file_stat)) 1204159587Sjhb return (EINVAL); 1205159587Sjhb 1206220158Skib error = kern_kldstat(td, uap->fileid, &stat); 1207220158Skib if (error != 0) 1208220158Skib return (error); 1209220158Skib return (copyout(&stat, uap->stat, version)); 1210220158Skib} 1211220158Skib 1212220158Skibint 1213220158Skibkern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat) 1214220158Skib{ 1215220158Skib linker_file_t lf; 1216220158Skib int namelen; 1217107089Srwatson#ifdef MAC 1218220158Skib int error; 1219220158Skib 1220172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1221107089Srwatson if (error) 1222107089Srwatson return (error); 1223107089Srwatson#endif 1224107089Srwatson 1225254810Smarkj sx_xlock(&kld_sx); 1226220158Skib lf = linker_find_file_by_id(fileid); 122791040Sarr if (lf == NULL) { 1228254810Smarkj sx_xunlock(&kld_sx); 1229159587Sjhb return (ENOENT); 123091040Sarr } 123125537Sdfr 1232172862Sjb /* Version 1 fields: */ 123391040Sarr namelen = strlen(lf->filename) + 1; 123491040Sarr if (namelen > MAXPATHLEN) 123591040Sarr namelen = MAXPATHLEN; 1236220158Skib bcopy(lf->filename, &stat->name[0], namelen); 1237220158Skib stat->refs = lf->refs; 1238220158Skib stat->id = lf->id; 1239220158Skib stat->address = lf->address; 1240220158Skib stat->size = lf->size; 1241220158Skib /* Version 2 fields: */ 1242220158Skib namelen = strlen(lf->pathname) + 1; 1243220158Skib if (namelen > MAXPATHLEN) 1244220158Skib namelen = MAXPATHLEN; 1245220158Skib bcopy(lf->pathname, &stat->pathname[0], namelen); 1246254810Smarkj sx_xunlock(&kld_sx); 124725537Sdfr 124891040Sarr td->td_retval[0] = 0; 1249220158Skib return (0); 125025537Sdfr} 125125537Sdfr 125225537Sdfrint 1253225617Skmacysys_kldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 125425537Sdfr{ 125591040Sarr linker_file_t lf; 125691040Sarr module_t mp; 125791040Sarr int error = 0; 125825537Sdfr 1259107089Srwatson#ifdef MAC 1260172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1261107089Srwatson if (error) 1262107089Srwatson return (error); 1263107089Srwatson#endif 1264107089Srwatson 1265254810Smarkj sx_xlock(&kld_sx); 1266107849Salfred lf = linker_find_file_by_id(uap->fileid); 126791040Sarr if (lf) { 126892547Sarr MOD_SLOCK; 126991040Sarr mp = TAILQ_FIRST(&lf->modules); 127091040Sarr if (mp != NULL) 127191040Sarr td->td_retval[0] = module_getid(mp); 127291040Sarr else 127391040Sarr td->td_retval[0] = 0; 127492547Sarr MOD_SUNLOCK; 127591040Sarr } else 127691040Sarr error = ENOENT; 1277254810Smarkj sx_xunlock(&kld_sx); 127891040Sarr return (error); 127925537Sdfr} 128040159Speter 128141090Speterint 1282225617Skmacysys_kldsym(struct thread *td, struct kldsym_args *uap) 128341090Speter{ 128491040Sarr char *symstr = NULL; 128591040Sarr c_linker_sym_t sym; 128691040Sarr linker_symval_t symval; 128791040Sarr linker_file_t lf; 128891040Sarr struct kld_sym_lookup lookup; 128991040Sarr int error = 0; 129041090Speter 1291107089Srwatson#ifdef MAC 1292172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1293107089Srwatson if (error) 1294107089Srwatson return (error); 1295107089Srwatson#endif 1296107089Srwatson 1297107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 1298159843Sjhb return (error); 129991068Sarr if (lookup.version != sizeof(lookup) || 1300159843Sjhb uap->cmd != KLDSYM_LOOKUP) 1301159843Sjhb return (EINVAL); 1302111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 130391040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 130491040Sarr goto out; 1305254810Smarkj sx_xlock(&kld_sx); 1306107849Salfred if (uap->fileid != 0) { 1307107849Salfred lf = linker_find_file_by_id(uap->fileid); 1308159843Sjhb if (lf == NULL) 130991040Sarr error = ENOENT; 1310159843Sjhb else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 131191040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 131291040Sarr lookup.symvalue = (uintptr_t) symval.value; 131391040Sarr lookup.symsize = symval.size; 1314107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 131591040Sarr } else 131691040Sarr error = ENOENT; 131791040Sarr } else { 131891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 131991040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 132091040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 132191040Sarr lookup.symvalue = (uintptr_t)symval.value; 132291040Sarr lookup.symsize = symval.size; 1323107849Salfred error = copyout(&lookup, uap->data, 132491040Sarr sizeof(lookup)); 132591068Sarr break; 132691040Sarr } 132791040Sarr } 132891040Sarr if (lf == NULL) 132991040Sarr error = ENOENT; 133041090Speter } 1331254810Smarkj sx_xunlock(&kld_sx); 133241090Speterout: 1333159843Sjhb free(symstr, M_TEMP); 133491040Sarr return (error); 133541090Speter} 133641090Speter 133740159Speter/* 133840159Speter * Preloaded module support 133940159Speter */ 134040159Speter 134159751Speterstatic modlist_t 134274642Sbpmodlist_lookup(const char *name, int ver) 134359751Speter{ 134491040Sarr modlist_t mod; 134559751Speter 134691040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 134792032Sdwmalone if (strcmp(mod->name, name) == 0 && 134892032Sdwmalone (ver == 0 || mod->version == ver)) 134991040Sarr return (mod); 135091040Sarr } 135191040Sarr return (NULL); 135259751Speter} 135359751Speter 135474642Sbpstatic modlist_t 135583321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 135683321Speter{ 135791040Sarr modlist_t mod, bestmod; 135892032Sdwmalone int ver; 135983321Speter 136091040Sarr if (verinfo == NULL) 136191040Sarr return (modlist_lookup(name, 0)); 136291040Sarr bestmod = NULL; 1363159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 136492032Sdwmalone if (strcmp(mod->name, name) != 0) 136591040Sarr continue; 136691040Sarr ver = mod->version; 136791040Sarr if (ver == verinfo->md_ver_preferred) 136891040Sarr return (mod); 136991040Sarr if (ver >= verinfo->md_ver_minimum && 137091068Sarr ver <= verinfo->md_ver_maximum && 1371120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 137291040Sarr bestmod = mod; 137391040Sarr } 137491040Sarr return (bestmod); 137583321Speter} 137683321Speter 137783321Speterstatic modlist_t 137878501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 137974642Sbp{ 138091040Sarr modlist_t mod; 138174642Sbp 138292705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 138391040Sarr if (mod == NULL) 138491040Sarr panic("no memory for module list"); 138591040Sarr mod->container = container; 138691040Sarr mod->name = modname; 138791040Sarr mod->version = version; 138891040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 138991040Sarr return (mod); 139074642Sbp} 139174642Sbp 139240159Speterstatic void 139378161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 139491040Sarr struct mod_metadata **stop, int preload) 139574642Sbp{ 139691040Sarr struct mod_metadata *mp, **mdp; 139791040Sarr const char *modname; 139891040Sarr int ver; 139974642Sbp 140091040Sarr for (mdp = start; mdp < stop; mdp++) { 1401109605Sjake mp = *mdp; 140291040Sarr if (mp->md_type != MDT_VERSION) 140391040Sarr continue; 1404109605Sjake modname = mp->md_cval; 1405109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 140691040Sarr if (modlist_lookup(modname, ver) != NULL) { 140791040Sarr printf("module %s already present!\n", modname); 140891040Sarr /* XXX what can we do? this is a build error. :-( */ 140991040Sarr continue; 141091040Sarr } 141191040Sarr modlist_newmodule(modname, ver, lf); 141274642Sbp } 141374642Sbp} 141474642Sbp 141574642Sbpstatic void 141691040Sarrlinker_preload(void *arg) 141740159Speter{ 141891040Sarr caddr_t modptr; 141991040Sarr const char *modname, *nmodname; 142091040Sarr char *modtype; 1421160244Sjhb linker_file_t lf, nlf; 142291040Sarr linker_class_t lc; 142392032Sdwmalone int error; 142491040Sarr linker_file_list_t loaded_files; 142591040Sarr linker_file_list_t depended_files; 142691040Sarr struct mod_metadata *mp, *nmp; 142791040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 142891040Sarr struct mod_depend *verinfo; 142991040Sarr int nver; 143091040Sarr int resolves; 143191040Sarr modlist_t mod; 143291040Sarr struct sysinit **si_start, **si_stop; 143340159Speter 143491040Sarr TAILQ_INIT(&loaded_files); 143591040Sarr TAILQ_INIT(&depended_files); 143691040Sarr TAILQ_INIT(&found_modules); 143791040Sarr error = 0; 143859751Speter 143991040Sarr modptr = NULL; 1440254810Smarkj sx_xlock(&kld_sx); 144191040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 144291040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 144391040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 144491040Sarr if (modname == NULL) { 144591040Sarr printf("Preloaded module at %p does not have a" 144691040Sarr " name!\n", modptr); 144791040Sarr continue; 144891040Sarr } 144991040Sarr if (modtype == NULL) { 145091040Sarr printf("Preloaded module at %p does not have a type!\n", 145191040Sarr modptr); 145291040Sarr continue; 145391040Sarr } 1454131398Sjhb if (bootverbose) 1455131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1456131398Sjhb modptr); 145740159Speter lf = NULL; 145891040Sarr TAILQ_FOREACH(lc, &classes, link) { 145991040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1460134364Siedowse if (!error) 146191040Sarr break; 1462134364Siedowse lf = NULL; 146391040Sarr } 146491040Sarr if (lf) 146591040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 146640159Speter } 146740159Speter 146891040Sarr /* 146991040Sarr * First get a list of stuff in the kernel. 147091040Sarr */ 147191040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 147291040Sarr &stop, NULL) == 0) 147391040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 147459751Speter 147559751Speter /* 1476167019Sjhb * This is a once-off kinky bubble sort to resolve relocation 1477167019Sjhb * dependency requirements. 147859751Speter */ 147991040Sarrrestart: 148091040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 148191040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 148291040Sarr &stop, NULL); 148391040Sarr /* 148491040Sarr * First, look to see if we would successfully link with this 148591040Sarr * stuff. 148691040Sarr */ 148791040Sarr resolves = 1; /* unless we know otherwise */ 148891040Sarr if (!error) { 148991040Sarr for (mdp = start; mdp < stop; mdp++) { 1490109605Sjake mp = *mdp; 149191040Sarr if (mp->md_type != MDT_DEPEND) 149291040Sarr continue; 1493109605Sjake modname = mp->md_cval; 1494109605Sjake verinfo = mp->md_data; 149591040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1496109605Sjake nmp = *nmdp; 149791040Sarr if (nmp->md_type != MDT_VERSION) 149891040Sarr continue; 1499109605Sjake nmodname = nmp->md_cval; 150092032Sdwmalone if (strcmp(modname, nmodname) == 0) 150191040Sarr break; 150291040Sarr } 150391040Sarr if (nmdp < stop) /* it's a self reference */ 150491040Sarr continue; 1505159840Sjhb 150691040Sarr /* 150791040Sarr * ok, the module isn't here yet, we 150891040Sarr * are not finished 150991040Sarr */ 151091068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 151191040Sarr resolves = 0; 151291040Sarr } 151364143Speter } 151491040Sarr /* 151591040Sarr * OK, if we found our modules, we can link. So, "provide" 151691040Sarr * the modules inside and add it to the end of the link order 151791040Sarr * list. 151891040Sarr */ 151991040Sarr if (resolves) { 152091040Sarr if (!error) { 152191040Sarr for (mdp = start; mdp < stop; mdp++) { 1522109605Sjake mp = *mdp; 152391040Sarr if (mp->md_type != MDT_VERSION) 152491040Sarr continue; 1525109605Sjake modname = mp->md_cval; 1526109605Sjake nver = ((struct mod_version *) 1527109605Sjake mp->md_data)->mv_version; 152891040Sarr if (modlist_lookup(modname, 152991040Sarr nver) != NULL) { 153091040Sarr printf("module %s already" 153191040Sarr " present!\n", modname); 1532160244Sjhb TAILQ_REMOVE(&loaded_files, 1533160244Sjhb lf, loaded); 1534132117Sphk linker_file_unload(lf, 1535132117Sphk LINKER_UNLOAD_FORCE); 153691040Sarr /* we changed tailq next ptr */ 153791068Sarr goto restart; 153891040Sarr } 153991040Sarr modlist_newmodule(modname, nver, lf); 154091040Sarr } 154191040Sarr } 154291040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 154391040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 154491040Sarr /* 154591040Sarr * Since we provided modules, we need to restart the 154691040Sarr * sort so that the previous files that depend on us 154791040Sarr * have a chance. Also, we've busted the tailq next 154891040Sarr * pointer with the REMOVE. 154991040Sarr */ 155091040Sarr goto restart; 155159751Speter } 155259751Speter } 155391040Sarr 155459751Speter /* 155591040Sarr * At this point, we check to see what could not be resolved.. 155659751Speter */ 1557160242Sjhb while ((lf = TAILQ_FIRST(&loaded_files)) != NULL) { 1558160242Sjhb TAILQ_REMOVE(&loaded_files, lf, loaded); 155991040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1560132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 156140159Speter } 156259751Speter 156378161Speter /* 156491040Sarr * We made it. Finish off the linking in the order we determined. 156578161Speter */ 1566160244Sjhb TAILQ_FOREACH_SAFE(lf, &depended_files, loaded, nlf) { 156791040Sarr if (linker_kernel_file) { 156891040Sarr linker_kernel_file->refs++; 156991040Sarr error = linker_file_add_dependency(lf, 157091040Sarr linker_kernel_file); 157191040Sarr if (error) 157291040Sarr panic("cannot add dependency"); 157391040Sarr } 157491040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 157591040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 157691040Sarr &stop, NULL); 157791040Sarr if (!error) { 157891040Sarr for (mdp = start; mdp < stop; mdp++) { 1579109605Sjake mp = *mdp; 158091040Sarr if (mp->md_type != MDT_DEPEND) 158191040Sarr continue; 1582109605Sjake modname = mp->md_cval; 1583109605Sjake verinfo = mp->md_data; 158491040Sarr mod = modlist_lookup2(modname, verinfo); 1585216988Strasz if (mod == NULL) { 1586216988Strasz printf("KLD file %s - cannot find " 1587216988Strasz "dependency \"%s\"\n", 1588216988Strasz lf->filename, modname); 1589216988Strasz goto fail; 1590216988Strasz } 1591151484Sjdp /* Don't count self-dependencies */ 1592151484Sjdp if (lf == mod->container) 1593151484Sjdp continue; 159491040Sarr mod->container->refs++; 159591040Sarr error = linker_file_add_dependency(lf, 159691040Sarr mod->container); 159791040Sarr if (error) 159891040Sarr panic("cannot add dependency"); 159991040Sarr } 160091040Sarr } 160191040Sarr /* 160291040Sarr * Now do relocation etc using the symbol search paths 160391040Sarr * established by the dependencies 160491040Sarr */ 160591040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 160691040Sarr if (error) { 160791040Sarr printf("KLD file %s - could not finalize loading\n", 160891040Sarr lf->filename); 1609216988Strasz goto fail; 161091040Sarr } 161191040Sarr linker_file_register_modules(lf); 161291040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 161391040Sarr &si_stop, NULL) == 0) 161491040Sarr sysinit_add(si_start, si_stop); 161591040Sarr linker_file_register_sysctls(lf); 161691040Sarr lf->flags |= LINKER_FILE_LINKED; 1617216988Strasz continue; 1618216988Straszfail: 1619216988Strasz TAILQ_REMOVE(&depended_files, lf, loaded); 1620216988Strasz linker_file_unload(lf, LINKER_UNLOAD_FORCE); 162159751Speter } 1622254810Smarkj sx_xunlock(&kld_sx); 162391040Sarr /* woohoo! we made it! */ 162440159Speter} 162540159Speter 1626177253SrwatsonSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 162740159Speter 162840159Speter/* 162940159Speter * Search for a not-loaded module by name. 1630159840Sjhb * 163140159Speter * Modules may be found in the following locations: 1632159840Sjhb * 163391040Sarr * - preloaded (result is just the module name) - on disk (result is full path 163491040Sarr * to module) 1635159840Sjhb * 163691040Sarr * If the module name is qualified in any way (contains path, etc.) the we 163791040Sarr * simply return a copy of it. 1638159840Sjhb * 163940159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 164040159Speter * character as a separator to be consistent with the bootloader. 164140159Speter */ 164240159Speter 164383321Speterstatic char linker_hintfile[] = "linker.hints"; 1644111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 164540159Speter 164640159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 164791040Sarr sizeof(linker_path), "module load search path"); 164840159Speter 164977843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 165070417Speter 165159751Speterstatic char *linker_ext_list[] = { 165283321Speter "", 165359751Speter ".ko", 165459751Speter NULL 165559751Speter}; 165659751Speter 165783321Speter/* 165891040Sarr * Check if file actually exists either with or without extension listed in 165991040Sarr * the linker_ext_list. (probably should be generic for the rest of the 166091040Sarr * kernel) 166183321Speter */ 166259751Speterstatic char * 166391040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 166491040Sarr int namelen, struct vattr *vap) 166540159Speter{ 166691040Sarr struct nameidata nd; 166791040Sarr struct thread *td = curthread; /* XXX */ 166891040Sarr char *result, **cpp, *sep; 1669241896Skib int error, len, extlen, reclen, flags; 167091040Sarr enum vtype type; 167140159Speter 167291040Sarr extlen = 0; 167391040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 167491040Sarr len = strlen(*cpp); 167591040Sarr if (len > extlen) 167691040Sarr extlen = len; 167791040Sarr } 167891040Sarr extlen++; /* trailing '\0' */ 167991040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 168083321Speter 168191040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1682111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 168391040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 168491040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 168591040Sarr namelen, name, *cpp); 168691040Sarr /* 168791040Sarr * Attempt to open the file, and return the path if 168891040Sarr * we succeed and it's a regular file. 168991040Sarr */ 1690241896Skib NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); 169191040Sarr flags = FREAD; 1692170152Skib error = vn_open(&nd, &flags, 0, NULL); 169391040Sarr if (error == 0) { 169491040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 169591040Sarr type = nd.ni_vp->v_type; 169691040Sarr if (vap) 1697182371Sattilio VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); 1698175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 169991406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 170091040Sarr if (type == VREG) 170191040Sarr return (result); 170291040Sarr } 170383321Speter } 170491040Sarr free(result, M_LINKER); 170591040Sarr return (NULL); 170683321Speter} 170783321Speter 170891040Sarr#define INT_ALIGN(base, ptr) ptr = \ 170983321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 171083321Speter 171183321Speter/* 171291040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 171391040Sarr * version specification is available, then try to find the best KLD. 171483321Speter * Otherwise just find the latest one. 171583321Speter */ 171683321Speterstatic char * 171791040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 171891040Sarr int modnamelen, struct mod_depend *verinfo) 171983321Speter{ 172091040Sarr struct thread *td = curthread; /* XXX */ 172191406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 172291040Sarr struct nameidata nd; 172391040Sarr struct vattr vattr, mattr; 172491040Sarr u_char *hints = NULL; 172591040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 1726231949Skib int error, ival, bestver, *intp, found, flags, clen, blen; 1727231949Skib ssize_t reclen; 172883321Speter 172991040Sarr result = NULL; 173091040Sarr bestver = found = 0; 173183321Speter 173291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 173391040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 173491040Sarr strlen(sep) + 1; 1735111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 173691040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 173791040Sarr linker_hintfile); 173883321Speter 1739241896Skib NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); 174091040Sarr flags = FREAD; 1741170152Skib error = vn_open(&nd, &flags, 0, NULL); 174291040Sarr if (error) 174391040Sarr goto bad; 174491040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 174591040Sarr if (nd.ni_vp->v_type != VREG) 174691040Sarr goto bad; 174791040Sarr best = cp = NULL; 1748182371Sattilio error = VOP_GETATTR(nd.ni_vp, &vattr, cred); 174991040Sarr if (error) 175091040Sarr goto bad; 175191040Sarr /* 175291040Sarr * XXX: we need to limit this number to some reasonable value 175391040Sarr */ 175491040Sarr if (vattr.va_size > 100 * 1024) { 175591040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 175691040Sarr goto bad; 175791040Sarr } 1758111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 175991040Sarr if (hints == NULL) 176091040Sarr goto bad; 176191068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1762101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 176391040Sarr if (error) 176491040Sarr goto bad; 1765175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 176691040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 176791040Sarr nd.ni_vp = NULL; 176891040Sarr if (reclen != 0) { 1769231949Skib printf("can't read %zd\n", reclen); 177091040Sarr goto bad; 177191040Sarr } 177291040Sarr intp = (int *)hints; 177383321Speter ival = *intp++; 177491040Sarr if (ival != LINKER_HINTS_VERSION) { 177591040Sarr printf("hints file version mismatch %d\n", ival); 177691040Sarr goto bad; 177783321Speter } 177891040Sarr bufend = hints + vattr.va_size; 177991040Sarr recptr = (u_char *)intp; 178091040Sarr clen = blen = 0; 178191040Sarr while (recptr < bufend && !found) { 178291040Sarr intp = (int *)recptr; 178391040Sarr reclen = *intp++; 178491040Sarr ival = *intp++; 178591040Sarr cp = (char *)intp; 178691040Sarr switch (ival) { 178791040Sarr case MDT_VERSION: 178891040Sarr clen = *cp++; 178991040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 179091040Sarr break; 179191040Sarr cp += clen; 179291040Sarr INT_ALIGN(hints, cp); 179391040Sarr ival = *(int *)cp; 179491040Sarr cp += sizeof(int); 179591040Sarr clen = *cp++; 179691040Sarr if (verinfo == NULL || 179791040Sarr ival == verinfo->md_ver_preferred) { 179891040Sarr found = 1; 179991040Sarr break; 180091040Sarr } 180191040Sarr if (ival >= verinfo->md_ver_minimum && 180291040Sarr ival <= verinfo->md_ver_maximum && 180391040Sarr ival > bestver) { 180491040Sarr bestver = ival; 180591040Sarr best = cp; 180691040Sarr blen = clen; 180791040Sarr } 180891040Sarr break; 180991040Sarr default: 181091040Sarr break; 181191040Sarr } 181291040Sarr recptr += reclen + sizeof(int); 181391040Sarr } 181483321Speter /* 181591040Sarr * Finally check if KLD is in the place 181683321Speter */ 181791040Sarr if (found) 181891040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 181991040Sarr else if (best) 182091040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 182191040Sarr 182291040Sarr /* 182391040Sarr * KLD is newer than hints file. What we should do now? 182491040Sarr */ 182591040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 182691040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 182791040Sarr " file\n", result); 182883321Speterbad: 1829105167Sphk free(pathbuf, M_LINKER); 183091040Sarr if (hints) 183191040Sarr free(hints, M_TEMP); 183299553Sjeff if (nd.ni_vp != NULL) { 1833175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 183491040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 183599553Sjeff } 183691040Sarr /* 183791040Sarr * If nothing found or hints is absent - fallback to the old 183891040Sarr * way by using "kldname[.ko]" as module name. 183991040Sarr */ 184091040Sarr if (!found && !bestver && result == NULL) 184191040Sarr result = linker_lookup_file(path, pathlen, modname, 184291040Sarr modnamelen, NULL); 184391040Sarr return (result); 184483321Speter} 184583321Speter 184683321Speter/* 184783321Speter * Lookup KLD which contains requested module in the all directories. 184883321Speter */ 184983321Speterstatic char * 185083321Speterlinker_search_module(const char *modname, int modnamelen, 185191040Sarr struct mod_depend *verinfo) 185283321Speter{ 185391040Sarr char *cp, *ep, *result; 185483321Speter 185591040Sarr /* 185691040Sarr * traverse the linker path 185791040Sarr */ 185891040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 185991040Sarr /* find the end of this component */ 186091040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 186191068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 186291068Sarr modnamelen, verinfo); 186391040Sarr if (result != NULL) 186491040Sarr return (result); 186591040Sarr if (*ep == 0) 186691040Sarr break; 186791040Sarr } 186891040Sarr return (NULL); 186983321Speter} 187083321Speter 187183321Speter/* 187283321Speter * Search for module in all directories listed in the linker_path. 187383321Speter */ 187483321Speterstatic char * 187583321Speterlinker_search_kld(const char *name) 187683321Speter{ 1877158972Sdelphij char *cp, *ep, *result; 1878158972Sdelphij int len; 187983321Speter 188091040Sarr /* qualified at all? */ 1881229272Sed if (strchr(name, '/')) 1882254396Smarkj return (strdup(name, M_LINKER)); 188340159Speter 188491040Sarr /* traverse the linker path */ 188591040Sarr len = strlen(name); 188691040Sarr for (ep = linker_path; *ep; ep++) { 188791040Sarr cp = ep; 188891040Sarr /* find the end of this component */ 188991040Sarr for (; *ep != 0 && *ep != ';'; ep++); 189091040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 189191040Sarr if (result != NULL) 189291040Sarr return (result); 189391040Sarr } 189491040Sarr return (NULL); 189540159Speter} 189659751Speter 189759751Speterstatic const char * 189891040Sarrlinker_basename(const char *path) 189959751Speter{ 190091040Sarr const char *filename; 190159751Speter 1902229272Sed filename = strrchr(path, '/'); 190391040Sarr if (filename == NULL) 190491040Sarr return path; 190591040Sarr if (filename[1]) 190691040Sarr filename++; 190791040Sarr return (filename); 190859751Speter} 190959751Speter 1910157144Sjkoshy#ifdef HWPMC_HOOKS 191159751Speter/* 1912157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1913157144Sjkoshy */ 1914157144Sjkoshyvoid * 1915157144Sjkoshylinker_hwpmc_list_objects(void) 1916157144Sjkoshy{ 1917195159Sattilio linker_file_t lf; 1918195159Sattilio struct pmckern_map_in *kobase; 1919195159Sattilio int i, nmappings; 1920157144Sjkoshy 1921195159Sattilio nmappings = 0; 1922254810Smarkj sx_slock(&kld_sx); 1923195159Sattilio TAILQ_FOREACH(lf, &linker_files, link) 1924195159Sattilio nmappings++; 1925157144Sjkoshy 1926195159Sattilio /* Allocate nmappings + 1 entries. */ 1927195159Sattilio kobase = malloc((nmappings + 1) * sizeof(struct pmckern_map_in), 1928184214Sdes M_LINKER, M_WAITOK | M_ZERO); 1929195159Sattilio i = 0; 1930195159Sattilio TAILQ_FOREACH(lf, &linker_files, link) { 1931157144Sjkoshy 1932195159Sattilio /* Save the info for this linker file. */ 1933195159Sattilio kobase[i].pm_file = lf->filename; 1934195159Sattilio kobase[i].pm_address = (uintptr_t)lf->address; 1935195159Sattilio i++; 1936157144Sjkoshy } 1937254810Smarkj sx_sunlock(&kld_sx); 1938157144Sjkoshy 1939195159Sattilio KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?")); 1940157144Sjkoshy 1941157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1942195159Sattilio KASSERT(kobase[i].pm_file == NULL, 1943157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1944157144Sjkoshy 1945195159Sattilio return ((void *)kobase); 1946157144Sjkoshy} 1947157144Sjkoshy#endif 1948157144Sjkoshy 1949157144Sjkoshy/* 195091040Sarr * Find a file which contains given module and load it, if "parent" is not 195191040Sarr * NULL, register a reference to it. 195259751Speter */ 1953159796Sjhbstatic int 195483321Speterlinker_load_module(const char *kldname, const char *modname, 195591040Sarr struct linker_file *parent, struct mod_depend *verinfo, 195691040Sarr struct linker_file **lfpp) 195759751Speter{ 195891040Sarr linker_file_t lfdep; 195991040Sarr const char *filename; 196091040Sarr char *pathname; 196191040Sarr int error; 196259751Speter 1963254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 196491040Sarr if (modname == NULL) { 196591040Sarr /* 196691040Sarr * We have to load KLD 196791040Sarr */ 196891068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 196991068Sarr " is not NULL")); 197091040Sarr pathname = linker_search_kld(kldname); 197191040Sarr } else { 197291040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 197391040Sarr return (EEXIST); 197494322Sbrian if (kldname != NULL) 1975254396Smarkj pathname = strdup(kldname, M_LINKER); 197695488Sbrian else if (rootvnode == NULL) 197794322Sbrian pathname = NULL; 197894322Sbrian else 197991040Sarr /* 198091040Sarr * Need to find a KLD with required module 198191040Sarr */ 198291040Sarr pathname = linker_search_module(modname, 198391040Sarr strlen(modname), verinfo); 198491040Sarr } 198591040Sarr if (pathname == NULL) 198691040Sarr return (ENOENT); 198791040Sarr 198883321Speter /* 198991040Sarr * Can't load more than one file with the same basename XXX: 199091040Sarr * Actually it should be possible to have multiple KLDs with 199191040Sarr * the same basename but different path because they can 199291040Sarr * provide different versions of the same modules. 199383321Speter */ 199491040Sarr filename = linker_basename(pathname); 1995159792Sjhb if (linker_find_file_by_name(filename)) 199691040Sarr error = EEXIST; 1997159792Sjhb else do { 199891040Sarr error = linker_load_file(pathname, &lfdep); 199991040Sarr if (error) 200091040Sarr break; 200191040Sarr if (modname && verinfo && 200291040Sarr modlist_lookup2(modname, verinfo) == NULL) { 2003132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 200491040Sarr error = ENOENT; 200591040Sarr break; 200691040Sarr } 200791040Sarr if (parent) { 200891040Sarr error = linker_file_add_dependency(parent, lfdep); 200991040Sarr if (error) 201091040Sarr break; 201191040Sarr } 201291040Sarr if (lfpp) 201391040Sarr *lfpp = lfdep; 201491040Sarr } while (0); 2015159791Sjhb free(pathname, M_LINKER); 201691040Sarr return (error); 201759751Speter} 201859751Speter 201959751Speter/* 202091040Sarr * This routine is responsible for finding dependencies of userland initiated 202191040Sarr * kldload(2)'s of files. 202259751Speter */ 202359751Speterint 202486469Siedowselinker_load_dependencies(linker_file_t lf) 202559751Speter{ 202691040Sarr linker_file_t lfdep; 202791040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 202891040Sarr struct mod_metadata *mp, *nmp; 202991040Sarr struct mod_depend *verinfo; 203091040Sarr modlist_t mod; 203191040Sarr const char *modname, *nmodname; 203292032Sdwmalone int ver, error = 0, count; 203359751Speter 203491040Sarr /* 203591040Sarr * All files are dependant on /kernel. 203691040Sarr */ 2037254810Smarkj sx_assert(&kld_sx, SA_XLOCKED); 203891040Sarr if (linker_kernel_file) { 203991040Sarr linker_kernel_file->refs++; 204091040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 204191040Sarr if (error) 204291040Sarr return (error); 204359751Speter } 204491040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 204591040Sarr &count) != 0) 204691040Sarr return (0); 204791040Sarr for (mdp = start; mdp < stop; mdp++) { 2048109605Sjake mp = *mdp; 204991040Sarr if (mp->md_type != MDT_VERSION) 205091040Sarr continue; 2051109605Sjake modname = mp->md_cval; 2052109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 205391040Sarr mod = modlist_lookup(modname, ver); 205491040Sarr if (mod != NULL) { 205591040Sarr printf("interface %s.%d already present in the KLD" 205691040Sarr " '%s'!\n", modname, ver, 205791040Sarr mod->container->filename); 205891040Sarr return (EEXIST); 205991040Sarr } 206091040Sarr } 206174642Sbp 206291040Sarr for (mdp = start; mdp < stop; mdp++) { 2063109605Sjake mp = *mdp; 206491040Sarr if (mp->md_type != MDT_DEPEND) 206591040Sarr continue; 2066109605Sjake modname = mp->md_cval; 2067109605Sjake verinfo = mp->md_data; 206891040Sarr nmodname = NULL; 206991040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 2070109605Sjake nmp = *nmdp; 207191040Sarr if (nmp->md_type != MDT_VERSION) 207291040Sarr continue; 2073109605Sjake nmodname = nmp->md_cval; 207492032Sdwmalone if (strcmp(modname, nmodname) == 0) 207591040Sarr break; 207691040Sarr } 207791040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 207891040Sarr continue; 207991040Sarr mod = modlist_lookup2(modname, verinfo); 208091040Sarr if (mod) { /* woohoo, it's loaded already */ 208191040Sarr lfdep = mod->container; 208291040Sarr lfdep->refs++; 208391040Sarr error = linker_file_add_dependency(lf, lfdep); 208491040Sarr if (error) 208591040Sarr break; 208691040Sarr continue; 208791040Sarr } 208891040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 208991040Sarr if (error) { 2090231931Sdelphij printf("KLD %s: depends on %s - not available or" 2091195803Srpaulo " version mismatch\n", lf->filename, modname); 209291040Sarr break; 209391040Sarr } 209459751Speter } 209559751Speter 209691040Sarr if (error) 209791040Sarr return (error); 209891040Sarr linker_addmodules(lf, start, stop, 0); 209991040Sarr return (error); 210059751Speter} 210185736Sgreen 210285736Sgreenstatic int 210385736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 210485736Sgreen{ 210585736Sgreen struct sysctl_req *req; 210685736Sgreen 210785736Sgreen req = opaque; 210885736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 210985736Sgreen} 211085736Sgreen 211185736Sgreen/* 211285736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 211385736Sgreen * in the kernel. 211485736Sgreen */ 211585736Sgreenstatic int 211685736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 211785736Sgreen{ 211885736Sgreen linker_file_t lf; 211985736Sgreen int error; 212085736Sgreen 2121107089Srwatson#ifdef MAC 2122172930Srwatson error = mac_kld_check_stat(req->td->td_ucred); 2123107089Srwatson if (error) 2124107089Srwatson return (error); 2125107089Srwatson#endif 2126126253Struckman error = sysctl_wire_old_buffer(req, 0); 2127126253Struckman if (error != 0) 2128126253Struckman return (error); 2129254810Smarkj sx_xlock(&kld_sx); 213085736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 213185736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 213285736Sgreen sysctl_kern_function_list_iterate, req); 213398452Sarr if (error) { 2134254810Smarkj sx_xunlock(&kld_sx); 213585736Sgreen return (error); 213698452Sarr } 213785736Sgreen } 2138254810Smarkj sx_xunlock(&kld_sx); 213985736Sgreen return (SYSCTL_OUT(req, "", 1)); 214085736Sgreen} 214185736Sgreen 2142217555SmdfSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLTYPE_OPAQUE | CTLFLAG_RD, 214391040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 2144