kern_linker.c revision 188232
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 188232 2009-02-06 14:51:32Z jhb $"); 29116182Sobrien 3040159Speter#include "opt_ddb.h" 31157144Sjkoshy#include "opt_hwpmc_hooks.h" 32107089Srwatson#include "opt_mac.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> 4840159Speter#include <sys/fcntl.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> 54185895Szec#include <sys/vimage.h> 5525537Sdfr 56163606Srwatson#include <security/mac/mac_framework.h> 57163606Srwatson 5859603Sdfr#include "linker_if.h" 5959603Sdfr 60157144Sjkoshy#ifdef HWPMC_HOOKS 61157144Sjkoshy#include <sys/pmckern.h> 62157144Sjkoshy#endif 63157144Sjkoshy 6440961Speter#ifdef KLD_DEBUG 6540961Speterint kld_debug = 0; 6640961Speter#endif 6740961Speter 68160142Sjhb#define KLD_LOCK() sx_xlock(&kld_sx) 69160142Sjhb#define KLD_UNLOCK() sx_xunlock(&kld_sx) 70159845Sjhb#define KLD_LOCKED() sx_xlocked(&kld_sx) 71160142Sjhb#define KLD_LOCK_ASSERT() do { \ 72160142Sjhb if (!cold) \ 73160142Sjhb sx_assert(&kld_sx, SX_XLOCKED); \ 74160142Sjhb} while (0) 75159845Sjhb 7691040Sarr/* 7791040Sarr * static char *linker_search_path(const char *name, struct mod_depend 7891040Sarr * *verinfo); 7991040Sarr */ 8091040Sarrstatic const char *linker_basename(const char *path); 8159751Speter 82159800Sjhb/* 83159800Sjhb * Find a currently loaded file given its filename. 84159800Sjhb */ 85159800Sjhbstatic linker_file_t linker_find_file_by_name(const char* _filename); 86159800Sjhb 87159800Sjhb/* 88159800Sjhb * Find a currently loaded file given its file id. 89159800Sjhb */ 90159800Sjhbstatic linker_file_t linker_find_file_by_id(int _fileid); 91159800Sjhb 9278161Speter/* Metadata from the static kernel */ 9378161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 9478161Speter 9559751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 9659751Speter 9740906Speterlinker_file_t linker_kernel_file; 9831324Sbde 99159845Sjhbstatic struct sx kld_sx; /* kernel linker lock */ 10098452Sarr 101172862Sjb/* 102172862Sjb * Load counter used by clients to determine if a linker file has been 103172862Sjb * re-loaded. This counter is incremented for each file load. 104172862Sjb */ 105172862Sjbstatic int loadcnt; 106172862Sjb 10725537Sdfrstatic linker_class_list_t classes; 10850068Sgrogstatic linker_file_list_t linker_files; 10925537Sdfrstatic int next_file_id = 1; 11098452Sarrstatic int linker_no_more_classes = 0; 11125537Sdfr 11286553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 11391040Sarr linker_file_t lftmp; \ 11486553Sarr \ 115159845Sjhb KLD_LOCK_ASSERT(); \ 11686553Sarrretry: \ 11791040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 11891040Sarr if (next_file_id == lftmp->id) { \ 11991040Sarr next_file_id++; \ 12091040Sarr goto retry; \ 12191040Sarr } \ 12291040Sarr } \ 12391040Sarr (a) = next_file_id; \ 12486553Sarr} while(0) 12586553Sarr 12686553Sarr 12759751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 12860938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 12959751Speterstruct modlist { 13091040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 13191040Sarr linker_file_t container; 13291040Sarr const char *name; 13391040Sarr int version; 13459751Speter}; 13591040Sarrtypedef struct modlist *modlist_t; 13691040Sarrstatic modlisthead_t found_modules; 13759751Speter 138159796Sjhbstatic int linker_file_add_dependency(linker_file_t file, 139159796Sjhb linker_file_t dep); 140159845Sjhbstatic caddr_t linker_file_lookup_symbol_internal(linker_file_t file, 141159845Sjhb const char* name, int deps); 142159796Sjhbstatic int linker_load_module(const char *kldname, 143159796Sjhb const char *modname, struct linker_file *parent, 144159796Sjhb struct mod_depend *verinfo, struct linker_file **lfpp); 145159796Sjhbstatic modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); 14694321Sbrian 14759603Sdfrstatic char * 14859603Sdfrlinker_strdup(const char *str) 14959603Sdfr{ 15091040Sarr char *result; 15159603Sdfr 152111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 15391040Sarr strcpy(result, str); 15491040Sarr return (result); 15559603Sdfr} 15659603Sdfr 15725537Sdfrstatic void 15891040Sarrlinker_init(void *arg) 15925537Sdfr{ 16091040Sarr 161159845Sjhb sx_init(&kld_sx, "kernel linker"); 16291040Sarr TAILQ_INIT(&classes); 16391040Sarr TAILQ_INIT(&linker_files); 16425537Sdfr} 16525537Sdfr 166177253SrwatsonSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 16725537Sdfr 16898452Sarrstatic void 16998452Sarrlinker_stop_class_add(void *arg) 17098452Sarr{ 17198452Sarr 17298452Sarr linker_no_more_classes = 1; 17398452Sarr} 17498452Sarr 175177253SrwatsonSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL); 17698452Sarr 17725537Sdfrint 17859603Sdfrlinker_add_class(linker_class_t lc) 17925537Sdfr{ 18091040Sarr 18198452Sarr /* 182144443Sjhb * We disallow any class registration past SI_ORDER_ANY 183144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 184144443Sjhb * ops from being freed. 18598452Sarr */ 18698452Sarr if (linker_no_more_classes == 1) 18798452Sarr return (EPERM); 18891040Sarr kobj_class_compile((kobj_class_t) lc); 189144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 19091040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 19191040Sarr return (0); 19225537Sdfr} 19325537Sdfr 19425537Sdfrstatic void 19525537Sdfrlinker_file_sysinit(linker_file_t lf) 19625537Sdfr{ 19791040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 19825537Sdfr 19991040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 20091040Sarr lf->filename)); 20125537Sdfr 20291040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 20391040Sarr return; 20491040Sarr /* 20591040Sarr * Perform a bubble sort of the system initialization objects by 20691040Sarr * their subsystem (primary key) and order (secondary key). 207159840Sjhb * 20891040Sarr * Since some things care about execution order, this is the operation 20991040Sarr * which ensures continued function. 21091040Sarr */ 21191040Sarr for (sipp = start; sipp < stop; sipp++) { 21291040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 21391040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 21491040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 21591040Sarr (*sipp)->order <= (*xipp)->order)) 21691040Sarr continue; /* skip */ 21791040Sarr save = *sipp; 21891040Sarr *sipp = *xipp; 21991040Sarr *xipp = save; 22091040Sarr } 22125537Sdfr } 22225537Sdfr 22391040Sarr /* 22491040Sarr * Traverse the (now) ordered list of system initialization tasks. 22591040Sarr * Perform each task, and continue on to the next task. 22691040Sarr */ 227160142Sjhb mtx_lock(&Giant); 22891040Sarr for (sipp = start; sipp < stop; sipp++) { 22991040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 23091040Sarr continue; /* skip dummy task(s) */ 23125537Sdfr 23291040Sarr /* Call function */ 23391040Sarr (*((*sipp)->func)) ((*sipp)->udata); 23491040Sarr } 235160142Sjhb mtx_unlock(&Giant); 23625537Sdfr} 23725537Sdfr 23841055Speterstatic void 23941055Speterlinker_file_sysuninit(linker_file_t lf) 24041055Speter{ 24191040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 24241055Speter 24391040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 24491040Sarr lf->filename)); 24541055Speter 24691068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 24791040Sarr NULL) != 0) 24891040Sarr return; 24941055Speter 25091040Sarr /* 25191040Sarr * Perform a reverse bubble sort of the system initialization objects 25291040Sarr * by their subsystem (primary key) and order (secondary key). 253159840Sjhb * 25491040Sarr * Since some things care about execution order, this is the operation 25591040Sarr * which ensures continued function. 25691040Sarr */ 25791040Sarr for (sipp = start; sipp < stop; sipp++) { 25891040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 25991040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 26091040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 26191040Sarr (*sipp)->order >= (*xipp)->order)) 26291040Sarr continue; /* skip */ 26391040Sarr save = *sipp; 26491040Sarr *sipp = *xipp; 26591040Sarr *xipp = save; 26691040Sarr } 26741055Speter } 26841055Speter 26991040Sarr /* 27091040Sarr * Traverse the (now) ordered list of system initialization tasks. 27191040Sarr * Perform each task, and continue on to the next task. 27291040Sarr */ 273160142Sjhb mtx_lock(&Giant); 27491040Sarr for (sipp = start; sipp < stop; sipp++) { 27591040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 27691040Sarr continue; /* skip dummy task(s) */ 27741055Speter 27891040Sarr /* Call function */ 27991040Sarr (*((*sipp)->func)) ((*sipp)->udata); 28091040Sarr } 281160142Sjhb mtx_unlock(&Giant); 28241055Speter} 28341055Speter 28444078Sdfrstatic void 28544078Sdfrlinker_file_register_sysctls(linker_file_t lf) 28644078Sdfr{ 28791040Sarr struct sysctl_oid **start, **stop, **oidp; 28844078Sdfr 28991040Sarr KLD_DPF(FILE, 29091040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 29191040Sarr lf->filename)); 29244078Sdfr 29391040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 29491040Sarr return; 29544078Sdfr 296188232Sjhb sysctl_lock(); 29791040Sarr for (oidp = start; oidp < stop; oidp++) 29891040Sarr sysctl_register_oid(*oidp); 299188232Sjhb sysctl_unlock(); 30044078Sdfr} 30144078Sdfr 30244078Sdfrstatic void 30344078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 30444078Sdfr{ 30591040Sarr struct sysctl_oid **start, **stop, **oidp; 30644078Sdfr 30791040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 30891040Sarr " for %s\n", lf->filename)); 30944078Sdfr 31091040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 31191040Sarr return; 31244078Sdfr 313188232Sjhb sysctl_lock(); 31491040Sarr for (oidp = start; oidp < stop; oidp++) 31591040Sarr sysctl_unregister_oid(*oidp); 316188232Sjhb sysctl_unlock(); 31744078Sdfr} 31844078Sdfr 31959751Speterstatic int 32059751Speterlinker_file_register_modules(linker_file_t lf) 32159751Speter{ 32291040Sarr struct mod_metadata **start, **stop, **mdp; 32391040Sarr const moduledata_t *moddata; 324146733Spjd int first_error, error; 32559751Speter 32691040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 32791040Sarr " in %s\n", lf->filename)); 32859751Speter 32991068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 330159841Sjhb &stop, NULL) != 0) { 33191040Sarr /* 33291040Sarr * This fallback should be unnecessary, but if we get booted 33391040Sarr * from boot2 instead of loader and we are missing our 33491040Sarr * metadata then we have to try the best we can. 33591040Sarr */ 33691040Sarr if (lf == linker_kernel_file) { 33791040Sarr start = SET_BEGIN(modmetadata_set); 33891040Sarr stop = SET_LIMIT(modmetadata_set); 33991040Sarr } else 34091040Sarr return (0); 34178161Speter } 342146733Spjd first_error = 0; 34391040Sarr for (mdp = start; mdp < stop; mdp++) { 34491040Sarr if ((*mdp)->md_type != MDT_MODULE) 34591040Sarr continue; 34691040Sarr moddata = (*mdp)->md_data; 34791040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 34891040Sarr moddata->name, lf->filename)); 34991040Sarr error = module_register(moddata, lf); 350146730Spjd if (error) { 35191068Sarr printf("Module %s failed to register: %d\n", 35291040Sarr moddata->name, error); 353146733Spjd if (first_error == 0) 354146733Spjd first_error = error; 355146730Spjd } 35659751Speter } 357146733Spjd return (first_error); 35859751Speter} 35959751Speter 36059751Speterstatic void 36159751Speterlinker_init_kernel_modules(void) 36259751Speter{ 36391040Sarr 36491040Sarr linker_file_register_modules(linker_kernel_file); 36559751Speter} 36659751Speter 367177253SrwatsonSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 368177253Srwatson 0); 36959751Speter 370101241Smuxstatic int 37191040Sarrlinker_load_file(const char *filename, linker_file_t *result) 37225537Sdfr{ 37391040Sarr linker_class_t lc; 37491040Sarr linker_file_t lf; 375159585Sjhb int foundfile, error; 37625537Sdfr 37791040Sarr /* Refuse to load modules if securelevel raised */ 37891040Sarr if (securelevel > 0) 37991040Sarr return (EPERM); 38062261Sarchie 381159845Sjhb KLD_LOCK_ASSERT(); 38291040Sarr lf = linker_find_file_by_name(filename); 38391040Sarr if (lf) { 38491040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 38591040Sarr " incrementing refs\n", filename)); 38691040Sarr *result = lf; 38791040Sarr lf->refs++; 388159585Sjhb return (0); 38991040Sarr } 39091040Sarr foundfile = 0; 391159585Sjhb error = 0; 39298452Sarr 39398452Sarr /* 39498452Sarr * We do not need to protect (lock) classes here because there is 39598452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 39698452Sarr * and there is no class deregistration mechanism at this time. 39798452Sarr */ 39891040Sarr TAILQ_FOREACH(lc, &classes, link) { 39991040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 40091040Sarr filename)); 40191040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 40291040Sarr /* 40391040Sarr * If we got something other than ENOENT, then it exists but 40491040Sarr * we cannot load it for some other reason. 40591040Sarr */ 40691040Sarr if (error != ENOENT) 40791040Sarr foundfile = 1; 40891040Sarr if (lf) { 409146730Spjd error = linker_file_register_modules(lf); 410146730Spjd if (error == EEXIST) { 411146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 412159585Sjhb return (error); 413146730Spjd } 414166921Sjhb KLD_UNLOCK(); 41591040Sarr linker_file_register_sysctls(lf); 41691040Sarr linker_file_sysinit(lf); 417166921Sjhb KLD_LOCK(); 41891040Sarr lf->flags |= LINKER_FILE_LINKED; 41991040Sarr *result = lf; 420159585Sjhb return (0); 42191040Sarr } 42291040Sarr } 42342755Speter /* 42491040Sarr * Less than ideal, but tells the user whether it failed to load or 42591040Sarr * the module was not found. 42642755Speter */ 427105337Ssam if (foundfile) { 428105337Ssam /* 429105337Ssam * Format not recognized or otherwise unloadable. 430105337Ssam * When loading a module that is statically built into 431105337Ssam * the kernel EEXIST percolates back up as the return 432105337Ssam * value. Preserve this so that apps like sysinstall 433105337Ssam * can recognize this special case and not post bogus 434105337Ssam * dialog boxes. 435105337Ssam */ 436105337Ssam if (error != EEXIST) 437105337Ssam error = ENOEXEC; 438105337Ssam } else 43991068Sarr error = ENOENT; /* Nothing found */ 44091040Sarr return (error); 44125537Sdfr} 44225537Sdfr 44378413Sbrianint 44494321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 44594321Sbrian linker_file_t *result) 44678413Sbrian{ 44794321Sbrian modlist_t mod; 448159804Sjhb int error; 44994321Sbrian 450159845Sjhb KLD_LOCK(); 45194321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 45294321Sbrian *result = mod->container; 45394321Sbrian (*result)->refs++; 454159845Sjhb KLD_UNLOCK(); 45594321Sbrian return (0); 45694321Sbrian } 45794321Sbrian 458159804Sjhb error = linker_load_module(NULL, modname, NULL, verinfo, result); 459159845Sjhb KLD_UNLOCK(); 460159804Sjhb return (error); 46178413Sbrian} 46278413Sbrian 463159804Sjhbint 464159804Sjhblinker_release_module(const char *modname, struct mod_depend *verinfo, 465159804Sjhb linker_file_t lf) 466159804Sjhb{ 467159804Sjhb modlist_t mod; 468159804Sjhb int error; 469159804Sjhb 470159845Sjhb KLD_LOCK(); 471159804Sjhb if (lf == NULL) { 472159804Sjhb KASSERT(modname != NULL, 473159804Sjhb ("linker_release_module: no file or name")); 474159804Sjhb mod = modlist_lookup2(modname, verinfo); 475159804Sjhb if (mod == NULL) { 476159845Sjhb KLD_UNLOCK(); 477159804Sjhb return (ESRCH); 478159804Sjhb } 479159804Sjhb lf = mod->container; 480159804Sjhb } else 481159804Sjhb KASSERT(modname == NULL && verinfo == NULL, 482159804Sjhb ("linker_release_module: both file and name")); 483159804Sjhb error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL); 484159845Sjhb KLD_UNLOCK(); 485159804Sjhb return (error); 486159804Sjhb} 487159804Sjhb 488159800Sjhbstatic linker_file_t 48991040Sarrlinker_find_file_by_name(const char *filename) 49025537Sdfr{ 491159585Sjhb linker_file_t lf; 49291040Sarr char *koname; 49325537Sdfr 494111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 49591040Sarr sprintf(koname, "%s.ko", filename); 49640861Speter 497159845Sjhb KLD_LOCK_ASSERT(); 49891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 49992032Sdwmalone if (strcmp(lf->filename, koname) == 0) 50091040Sarr break; 50192032Sdwmalone if (strcmp(lf->filename, filename) == 0) 50291040Sarr break; 50391040Sarr } 504159585Sjhb free(koname, M_LINKER); 50591040Sarr return (lf); 50625537Sdfr} 50725537Sdfr 508159800Sjhbstatic linker_file_t 50925537Sdfrlinker_find_file_by_id(int fileid) 51025537Sdfr{ 511159585Sjhb linker_file_t lf; 512159845Sjhb 513159845Sjhb KLD_LOCK_ASSERT(); 51491040Sarr TAILQ_FOREACH(lf, &linker_files, link) 515166921Sjhb if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED) 51691040Sarr break; 51791040Sarr return (lf); 51825537Sdfr} 51925537Sdfr 520159797Sjhbint 521159797Sjhblinker_file_foreach(linker_predicate_t *predicate, void *context) 522159797Sjhb{ 523159797Sjhb linker_file_t lf; 524159797Sjhb int retval = 0; 525159797Sjhb 526159845Sjhb KLD_LOCK(); 527159797Sjhb TAILQ_FOREACH(lf, &linker_files, link) { 528159797Sjhb retval = predicate(lf, context); 529159797Sjhb if (retval != 0) 530159797Sjhb break; 531159797Sjhb } 532159845Sjhb KLD_UNLOCK(); 533159797Sjhb return (retval); 534159797Sjhb} 535159797Sjhb 53625537Sdfrlinker_file_t 53791040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 53825537Sdfr{ 53991040Sarr linker_file_t lf; 54091040Sarr const char *filename; 54125537Sdfr 542159845Sjhb KLD_LOCK_ASSERT(); 54391040Sarr filename = linker_basename(pathname); 54440159Speter 545172862Sjb KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname)); 546111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 54791040Sarr if (lf == NULL) 548159585Sjhb return (NULL); 54991040Sarr lf->refs = 1; 55091040Sarr lf->userrefs = 0; 55191040Sarr lf->flags = 0; 55291040Sarr lf->filename = linker_strdup(filename); 553172862Sjb lf->pathname = linker_strdup(pathname); 55491040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 55591040Sarr lf->ndeps = 0; 55691040Sarr lf->deps = NULL; 557172862Sjb lf->loadcnt = ++loadcnt; 558172862Sjb lf->sdt_probes = NULL; 559172862Sjb lf->sdt_nprobes = 0; 56091040Sarr STAILQ_INIT(&lf->common); 56191040Sarr TAILQ_INIT(&lf->modules); 56291040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 56391040Sarr return (lf); 56425537Sdfr} 56525537Sdfr 56625537Sdfrint 567132117Sphklinker_file_unload(linker_file_t file, int flags) 56825537Sdfr{ 56991040Sarr module_t mod, next; 57091040Sarr modlist_t ml, nextml; 57191040Sarr struct common_symbol *cp; 57291040Sarr int error, i; 57325537Sdfr 57491040Sarr /* Refuse to unload modules if securelevel raised. */ 57591040Sarr if (securelevel > 0) 57691040Sarr return (EPERM); 57725537Sdfr 578159845Sjhb KLD_LOCK_ASSERT(); 57991040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 58091040Sarr 581159584Sjhb /* Easy case of just dropping a reference. */ 582159584Sjhb if (file->refs > 1) { 583159584Sjhb file->refs--; 584159584Sjhb return (0); 585159584Sjhb } 586159584Sjhb 587159584Sjhb KLD_DPF(FILE, ("linker_file_unload: file is unloading," 588159584Sjhb " informing modules\n")); 589159584Sjhb 590159584Sjhb /* 591185635Sjhb * Quiesce all the modules to give them a chance to veto the unload. 592159584Sjhb */ 593185635Sjhb MOD_SLOCK; 594185635Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; 595185635Sjhb mod = module_getfnext(mod)) { 596185635Sjhb 597185635Sjhb error = module_quiesce(mod); 598185635Sjhb if (error != 0 && flags != LINKER_UNLOAD_FORCE) { 599185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 600185635Sjhb " vetoed unload\n", module_getname(mod))); 601185635Sjhb /* 602185635Sjhb * XXX: Do we need to tell all the quiesced modules 603185635Sjhb * that they can resume work now via a new module 604185635Sjhb * event? 605185635Sjhb */ 606185635Sjhb MOD_SUNLOCK; 607185635Sjhb return (error); 608185635Sjhb } 609185635Sjhb } 610185635Sjhb MOD_SUNLOCK; 611185635Sjhb 612185635Sjhb /* 613185635Sjhb * Inform any modules associated with this file that they are 614185635Sjhb * being be unloaded. 615185635Sjhb */ 616159584Sjhb MOD_XLOCK; 617159584Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 618159584Sjhb next = module_getfnext(mod); 619159584Sjhb MOD_XUNLOCK; 620159584Sjhb 62191040Sarr /* 622159584Sjhb * Give the module a chance to veto the unload. 62391040Sarr */ 624185635Sjhb if ((error = module_unload(mod)) != 0) { 625185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 626185635Sjhb " failed unload\n", mod)); 627159584Sjhb return (error); 628159584Sjhb } 62992547Sarr MOD_XLOCK; 630159584Sjhb module_release(mod); 631159584Sjhb } 632159584Sjhb MOD_XUNLOCK; 63391040Sarr 634159586Sjhb TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml) { 635128057Speadar if (ml->container == file) { 63691040Sarr TAILQ_REMOVE(&found_modules, ml, link); 637128057Speadar free(ml, M_LINKER); 638128057Speadar } 63991040Sarr } 64025537Sdfr 641159840Sjhb /* 642159840Sjhb * Don't try to run SYSUNINITs if we are unloaded due to a 64391040Sarr * link error. 64491040Sarr */ 64591040Sarr if (file->flags & LINKER_FILE_LINKED) { 646188209Sjhb file->flags &= ~LINKER_FILE_LINKED; 647188209Sjhb KLD_UNLOCK(); 64891040Sarr linker_file_sysuninit(file); 64991040Sarr linker_file_unregister_sysctls(file); 650188209Sjhb KLD_LOCK(); 65125537Sdfr } 65291040Sarr TAILQ_REMOVE(&linker_files, file, link); 65325537Sdfr 65491040Sarr if (file->deps) { 65591040Sarr for (i = 0; i < file->ndeps; i++) 656132117Sphk linker_file_unload(file->deps[i], flags); 65791040Sarr free(file->deps, M_LINKER); 65891040Sarr file->deps = NULL; 65959751Speter } 660160245Sjhb while ((cp = STAILQ_FIRST(&file->common)) != NULL) { 661160245Sjhb STAILQ_REMOVE_HEAD(&file->common, link); 66291040Sarr free(cp, M_LINKER); 66391040Sarr } 66459751Speter 66591040Sarr LINKER_UNLOAD(file); 66691040Sarr if (file->filename) { 66791040Sarr free(file->filename, M_LINKER); 66891040Sarr file->filename = NULL; 66991040Sarr } 670172862Sjb if (file->pathname) { 671172862Sjb free(file->pathname, M_LINKER); 672172862Sjb file->pathname = NULL; 673172862Sjb } 67491040Sarr kobj_delete((kobj_t) file, M_LINKER); 675159584Sjhb return (0); 67625537Sdfr} 67725537Sdfr 678179238Sjbint 679179238Sjblinker_ctf_get(linker_file_t file, linker_ctf_t *lc) 680179238Sjb{ 681179238Sjb return (LINKER_CTF_GET(file, lc)); 682179238Sjb} 683179238Sjb 684159796Sjhbstatic int 68586469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 68625537Sdfr{ 68791040Sarr linker_file_t *newdeps; 68825537Sdfr 689159845Sjhb KLD_LOCK_ASSERT(); 69091040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 691111119Simp M_LINKER, M_WAITOK | M_ZERO); 69291040Sarr if (newdeps == NULL) 69391040Sarr return (ENOMEM); 69425537Sdfr 69591040Sarr if (file->deps) { 69691040Sarr bcopy(file->deps, newdeps, 69791040Sarr file->ndeps * sizeof(linker_file_t *)); 69891040Sarr free(file->deps, M_LINKER); 69991040Sarr } 70091040Sarr file->deps = newdeps; 70191040Sarr file->deps[file->ndeps] = dep; 70291040Sarr file->ndeps++; 70391040Sarr return (0); 70425537Sdfr} 70525537Sdfr 70678161Speter/* 70791040Sarr * Locate a linker set and its contents. This is a helper function to avoid 708159841Sjhb * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. 709159841Sjhb * This function is used in this file so we can avoid having lots of (void **) 710159841Sjhb * casts. 71178161Speter */ 71278161Speterint 71378161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 71491040Sarr void *firstp, void *lastp, int *countp) 71578161Speter{ 716159845Sjhb int error, locked; 71778161Speter 718159845Sjhb locked = KLD_LOCKED(); 719159845Sjhb if (!locked) 720159845Sjhb KLD_LOCK(); 721159845Sjhb error = LINKER_LOOKUP_SET(file, name, firstp, lastp, countp); 722159845Sjhb if (!locked) 723159845Sjhb KLD_UNLOCK(); 724159845Sjhb return (error); 72578161Speter} 72678161Speter 727173714Sjb/* 728173714Sjb * List all functions in a file. 729173714Sjb */ 730173714Sjbint 731173714Sjblinker_file_function_listall(linker_file_t lf, 732179238Sjb linker_function_nameval_callback_t callback_func, void *arg) 733173714Sjb{ 734173714Sjb return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); 735173714Sjb} 736173714Sjb 73725537Sdfrcaddr_t 73891040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 73925537Sdfr{ 740159845Sjhb caddr_t sym; 741159845Sjhb int locked; 742159845Sjhb 743159845Sjhb locked = KLD_LOCKED(); 744159845Sjhb if (!locked) 745159845Sjhb KLD_LOCK(); 746159845Sjhb sym = linker_file_lookup_symbol_internal(file, name, deps); 747159845Sjhb if (!locked) 748159845Sjhb KLD_UNLOCK(); 749159845Sjhb return (sym); 750159845Sjhb} 751159845Sjhb 752159845Sjhbstatic caddr_t 753159845Sjhblinker_file_lookup_symbol_internal(linker_file_t file, const char *name, 754159845Sjhb int deps) 755159845Sjhb{ 75691040Sarr c_linker_sym_t sym; 75791040Sarr linker_symval_t symval; 75891040Sarr caddr_t address; 75991040Sarr size_t common_size = 0; 76092032Sdwmalone int i; 76125537Sdfr 762159845Sjhb KLD_LOCK_ASSERT(); 763109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 76491040Sarr file, name, deps)); 76525537Sdfr 76691040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 76791040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 76891040Sarr if (symval.value == 0) 76991040Sarr /* 77091040Sarr * For commons, first look them up in the 77191040Sarr * dependencies and only allocate space if not found 77291040Sarr * there. 77391040Sarr */ 77491040Sarr common_size = symval.size; 77591040Sarr else { 77691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 777109605Sjake ".value=%p\n", symval.value)); 77891040Sarr return (symval.value); 77991040Sarr } 78040159Speter } 78191040Sarr if (deps) { 78291040Sarr for (i = 0; i < file->ndeps; i++) { 783159845Sjhb address = linker_file_lookup_symbol_internal( 784159845Sjhb file->deps[i], name, 0); 78591040Sarr if (address) { 78691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 787109605Sjake " deps value=%p\n", address)); 78891040Sarr return (address); 78991040Sarr } 79091040Sarr } 79125537Sdfr } 79291040Sarr if (common_size > 0) { 79391040Sarr /* 79491040Sarr * This is a common symbol which was not found in the 79591040Sarr * dependencies. We maintain a simple common symbol table in 79691040Sarr * the file object. 79791040Sarr */ 79891040Sarr struct common_symbol *cp; 79942849Speter 80091040Sarr STAILQ_FOREACH(cp, &file->common, link) { 80192032Sdwmalone if (strcmp(cp->name, name) == 0) { 80291040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 803109605Sjake " old common value=%p\n", cp->address)); 80491040Sarr return (cp->address); 80591040Sarr } 80691040Sarr } 80791040Sarr /* 80891040Sarr * Round the symbol size up to align. 80991040Sarr */ 81091040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 81191040Sarr cp = malloc(sizeof(struct common_symbol) 81291040Sarr + common_size + strlen(name) + 1, M_LINKER, 813111119Simp M_WAITOK | M_ZERO); 81491040Sarr cp->address = (caddr_t)(cp + 1); 81591040Sarr cp->name = cp->address + common_size; 81691040Sarr strcpy(cp->name, name); 81791040Sarr bzero(cp->address, common_size); 81891040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 81925537Sdfr 82091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 821109605Sjake " value=%p\n", cp->address)); 82291040Sarr return (cp->address); 82340159Speter } 82491040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 82591040Sarr return (0); 82625537Sdfr} 82725537Sdfr 82825537Sdfr/* 829174132Srwatson * Both DDB and stack(9) rely on the kernel linker to provide forward and 830174132Srwatson * backward lookup of symbols. However, DDB and sometimes stack(9) need to 831174132Srwatson * do this in a lockfree manner. We provide a set of internal helper 832174132Srwatson * routines to perform these operations without locks, and then wrappers that 833174132Srwatson * optionally lock. 834159840Sjhb * 835174132Srwatson * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. 83640159Speter */ 837174132Srwatson#ifdef DDB 838174132Srwatsonstatic int 839174132Srwatsonlinker_debug_lookup(const char *symstr, c_linker_sym_t *sym) 84040159Speter{ 84191040Sarr linker_file_t lf; 84240159Speter 84391040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 84491040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 84591040Sarr return (0); 84691040Sarr } 84791040Sarr return (ENOENT); 84840159Speter} 849174132Srwatson#endif 85040159Speter 851174132Srwatsonstatic int 852174132Srwatsonlinker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 85340159Speter{ 85491040Sarr linker_file_t lf; 85591040Sarr c_linker_sym_t best, es; 85691040Sarr u_long diff, bestdiff, off; 85740159Speter 85891040Sarr best = 0; 85991040Sarr off = (uintptr_t)value; 86091040Sarr bestdiff = off; 86191040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 86291040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 86391040Sarr continue; 86491040Sarr if (es != 0 && diff < bestdiff) { 86591040Sarr best = es; 86691040Sarr bestdiff = diff; 86791040Sarr } 86891040Sarr if (bestdiff == 0) 86991040Sarr break; 87040159Speter } 87191040Sarr if (best) { 87291040Sarr *sym = best; 87391040Sarr *diffp = bestdiff; 87491040Sarr return (0); 87591040Sarr } else { 87691040Sarr *sym = 0; 87791040Sarr *diffp = off; 87891040Sarr return (ENOENT); 87991040Sarr } 88040159Speter} 88140159Speter 882174132Srwatsonstatic int 883174132Srwatsonlinker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 88440159Speter{ 88591040Sarr linker_file_t lf; 88640159Speter 88791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 88891040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 88991040Sarr return (0); 89091040Sarr } 89191040Sarr return (ENOENT); 89240159Speter} 893174132Srwatson 894174132Srwatsonstatic int 895174132Srwatsonlinker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, 896174132Srwatson long *offset) 897174132Srwatson{ 898174132Srwatson linker_symval_t symval; 899174132Srwatson c_linker_sym_t sym; 900174132Srwatson int error; 901174132Srwatson 902174132Srwatson *offset = 0; 903174132Srwatson error = linker_debug_search_symbol(value, &sym, offset); 904174132Srwatson if (error) 905174132Srwatson return (error); 906174132Srwatson error = linker_debug_symbol_values(sym, &symval); 907174132Srwatson if (error) 908174132Srwatson return (error); 909174132Srwatson strlcpy(buf, symval.name, buflen); 910174132Srwatson return (0); 911174132Srwatson} 912174132Srwatson 913174132Srwatson#ifdef DDB 914174132Srwatson/* 915174132Srwatson * DDB Helpers. DDB has to look across multiple files with their own symbol 916174132Srwatson * tables and string tables. 917174132Srwatson * 918174132Srwatson * Note that we do not obey list locking protocols here. We really don't need 919174132Srwatson * DDB to hang because somebody's got the lock held. We'll take the chance 920174132Srwatson * that the files list is inconsistant instead. 921174132Srwatson */ 922174132Srwatsonint 923174132Srwatsonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 924174132Srwatson{ 925174132Srwatson 926174132Srwatson return (linker_debug_lookup(symstr, sym)); 927174132Srwatson} 928174132Srwatson 929174132Srwatsonint 930174132Srwatsonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 931174132Srwatson{ 932174132Srwatson 933174132Srwatson return (linker_debug_search_symbol(value, sym, diffp)); 934174132Srwatson} 935174132Srwatson 936174132Srwatsonint 937174132Srwatsonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 938174132Srwatson{ 939174132Srwatson 940174132Srwatson return (linker_debug_symbol_values(sym, symval)); 941174132Srwatson} 942174132Srwatson 943174132Srwatsonint 944174132Srwatsonlinker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, 945174132Srwatson long *offset) 946174132Srwatson{ 947174132Srwatson 948174132Srwatson return (linker_debug_search_symbol_name(value, buf, buflen, offset)); 949174132Srwatson} 95040159Speter#endif 95140159Speter 95240159Speter/* 953174132Srwatson * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do 954174132Srwatson * obey locking protocols, and offer a significantly less complex interface. 955174132Srwatson */ 956174132Srwatsonint 957174132Srwatsonlinker_search_symbol_name(caddr_t value, char *buf, u_int buflen, 958174132Srwatson long *offset) 959174132Srwatson{ 960178380Spjd int error; 961174132Srwatson 962178380Spjd KLD_LOCK(); 963174132Srwatson error = linker_debug_search_symbol_name(value, buf, buflen, offset); 964178380Spjd KLD_UNLOCK(); 965174132Srwatson return (error); 966174132Srwatson} 967174132Srwatson 968174132Srwatson/* 96925537Sdfr * Syscalls. 97025537Sdfr */ 97125537Sdfrint 972159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 97325537Sdfr{ 974157144Sjkoshy#ifdef HWPMC_HOOKS 975157144Sjkoshy struct pmckern_map_in pkm; 976157144Sjkoshy#endif 977159588Sjhb const char *kldname, *modname; 97891040Sarr linker_file_t lf; 979159588Sjhb int error; 98025537Sdfr 98193159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 982159588Sjhb return (error); 98393159Sarr 984164033Srwatson if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0) 985159588Sjhb return (error); 98625537Sdfr 98791040Sarr /* 988159841Sjhb * If file does not contain a qualified name or any dot in it 989159841Sjhb * (kldname.ko, or kldname.ver.ko) treat it as an interface 99091040Sarr * name. 99191040Sarr */ 992159588Sjhb if (index(file, '/') || index(file, '.')) { 993159588Sjhb kldname = file; 99491040Sarr modname = NULL; 99591040Sarr } else { 99691040Sarr kldname = NULL; 997159588Sjhb modname = file; 99891040Sarr } 999159588Sjhb 1000159845Sjhb KLD_LOCK(); 100191040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 100291040Sarr if (error) 1003159588Sjhb goto unlock; 1004157144Sjkoshy#ifdef HWPMC_HOOKS 1005157144Sjkoshy pkm.pm_file = lf->filename; 1006157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 1007157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 1008157144Sjkoshy#endif 100991040Sarr lf->userrefs++; 1010159588Sjhb if (fileid != NULL) 1011159588Sjhb *fileid = lf->id; 1012159588Sjhbunlock: 1013159845Sjhb KLD_UNLOCK(); 101491040Sarr return (error); 101525537Sdfr} 101625537Sdfr 1017159588Sjhbint 1018159588Sjhbkldload(struct thread *td, struct kldload_args *uap) 1019159588Sjhb{ 1020159588Sjhb char *pathname = NULL; 1021159596Smarcel int error, fileid; 1022159588Sjhb 1023159588Sjhb td->td_retval[0] = -1; 1024159588Sjhb 1025159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1026159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 1027159596Smarcel if (error == 0) { 1028159596Smarcel error = kern_kldload(td, pathname, &fileid); 1029159596Smarcel if (error == 0) 1030159596Smarcel td->td_retval[0] = fileid; 1031159596Smarcel } 1032159588Sjhb free(pathname, M_TEMP); 1033159588Sjhb return (error); 1034159588Sjhb} 1035159588Sjhb 1036159588Sjhbint 1037132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 103825537Sdfr{ 1039157144Sjkoshy#ifdef HWPMC_HOOKS 1040157144Sjkoshy struct pmckern_map_out pkm; 1041157144Sjkoshy#endif 104291040Sarr linker_file_t lf; 104391040Sarr int error = 0; 104425537Sdfr 104593159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 1046159588Sjhb return (error); 104793159Sarr 1048164033Srwatson if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0) 1049159588Sjhb return (error); 105025537Sdfr 1051159845Sjhb KLD_LOCK(); 1052132117Sphk lf = linker_find_file_by_id(fileid); 105391040Sarr if (lf) { 105491040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 1055172862Sjb 1056172862Sjb /* Check if there are DTrace probes enabled on this file. */ 1057172862Sjb if (lf->nenabled > 0) { 1058172862Sjb printf("kldunload: attempt to unload file that has" 1059172862Sjb " DTrace probes enabled\n"); 1060172862Sjb error = EBUSY; 1061172862Sjb } else if (lf->userrefs == 0) { 1062132117Sphk /* 1063132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 1064132117Sphk */ 106591040Sarr printf("kldunload: attempt to unload file that was" 106691040Sarr " loaded by the kernel\n"); 1067159840Sjhb error = EBUSY; 1068159588Sjhb } else { 1069157144Sjkoshy#ifdef HWPMC_HOOKS 1070159588Sjhb /* Save data needed by hwpmc(4) before unloading. */ 1071159588Sjhb pkm.pm_address = (uintptr_t) lf->address; 1072159588Sjhb pkm.pm_size = lf->size; 1073157144Sjkoshy#endif 1074159588Sjhb lf->userrefs--; 1075159588Sjhb error = linker_file_unload(lf, flags); 1076159588Sjhb if (error) 1077159588Sjhb lf->userrefs++; 1078159588Sjhb } 107991040Sarr } else 108091040Sarr error = ENOENT; 1081157144Sjkoshy 1082157144Sjkoshy#ifdef HWPMC_HOOKS 1083157144Sjkoshy if (error == 0) 1084157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 1085157144Sjkoshy#endif 1086159845Sjhb KLD_UNLOCK(); 108791068Sarr return (error); 108825537Sdfr} 108925537Sdfr 109025537Sdfrint 1091132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 1092132117Sphk{ 1093132117Sphk 1094132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 1095132117Sphk} 1096132117Sphk 1097132117Sphkint 1098132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 1099132117Sphk{ 1100132117Sphk 1101132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 1102132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 1103132117Sphk return (EINVAL); 1104132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 1105132117Sphk} 1106132117Sphk 1107132117Sphkint 110891040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 110925537Sdfr{ 111091040Sarr char *pathname; 111191040Sarr const char *filename; 111291040Sarr linker_file_t lf; 1113159791Sjhb int error; 111425537Sdfr 1115107089Srwatson#ifdef MAC 1116172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1117107089Srwatson if (error) 1118107089Srwatson return (error); 1119107089Srwatson#endif 1120107089Srwatson 112191040Sarr td->td_retval[0] = -1; 112282749Sdillon 1123111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1124107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 112591040Sarr goto out; 112625537Sdfr 112791040Sarr filename = linker_basename(pathname); 1128159845Sjhb KLD_LOCK(); 112991040Sarr lf = linker_find_file_by_name(filename); 113091040Sarr if (lf) 113191040Sarr td->td_retval[0] = lf->id; 113291040Sarr else 113391040Sarr error = ENOENT; 1134159845Sjhb KLD_UNLOCK(); 113525537Sdfrout: 1136159791Sjhb free(pathname, M_TEMP); 113791040Sarr return (error); 113825537Sdfr} 113925537Sdfr 114025537Sdfrint 114191040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 114225537Sdfr{ 114391040Sarr linker_file_t lf; 114491040Sarr int error = 0; 114525537Sdfr 1146107089Srwatson#ifdef MAC 1147172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1148107089Srwatson if (error) 1149107089Srwatson return (error); 1150107089Srwatson#endif 1151107089Srwatson 1152159845Sjhb KLD_LOCK(); 1153166921Sjhb if (uap->fileid == 0) 1154166921Sjhb lf = TAILQ_FIRST(&linker_files); 1155166921Sjhb else { 1156166921Sjhb lf = linker_find_file_by_id(uap->fileid); 1157166921Sjhb if (lf == NULL) { 1158166921Sjhb error = ENOENT; 1159166921Sjhb goto out; 1160166921Sjhb } 1161166921Sjhb lf = TAILQ_NEXT(lf, link); 116291040Sarr } 1163166921Sjhb 1164166921Sjhb /* Skip partially loaded files. */ 1165166921Sjhb while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) 1166166921Sjhb lf = TAILQ_NEXT(lf, link); 1167166921Sjhb 1168166921Sjhb if (lf) 1169166921Sjhb td->td_retval[0] = lf->id; 1170166921Sjhb else 1171166921Sjhb td->td_retval[0] = 0; 117282749Sdillonout: 1173159845Sjhb KLD_UNLOCK(); 117491040Sarr return (error); 117525537Sdfr} 117625537Sdfr 117725537Sdfrint 117891040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 117925537Sdfr{ 1180159587Sjhb struct kld_file_stat stat; 118191040Sarr linker_file_t lf; 1182172862Sjb int error, namelen, version, version_num; 118325537Sdfr 1184159587Sjhb /* 1185159587Sjhb * Check the version of the user's structure. 1186159587Sjhb */ 1187172862Sjb if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0) 1188159587Sjhb return (error); 1189172862Sjb if (version == sizeof(struct kld_file_stat_1)) 1190172862Sjb version_num = 1; 1191172862Sjb else if (version == sizeof(struct kld_file_stat)) 1192172862Sjb version_num = 2; 1193172862Sjb else 1194159587Sjhb return (EINVAL); 1195159587Sjhb 1196107089Srwatson#ifdef MAC 1197172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1198107089Srwatson if (error) 1199107089Srwatson return (error); 1200107089Srwatson#endif 1201107089Srwatson 1202159845Sjhb KLD_LOCK(); 1203107849Salfred lf = linker_find_file_by_id(uap->fileid); 120491040Sarr if (lf == NULL) { 1205159845Sjhb KLD_UNLOCK(); 1206159587Sjhb return (ENOENT); 120791040Sarr } 120825537Sdfr 1209172862Sjb /* Version 1 fields: */ 121091040Sarr namelen = strlen(lf->filename) + 1; 121191040Sarr if (namelen > MAXPATHLEN) 121291040Sarr namelen = MAXPATHLEN; 1213159587Sjhb bcopy(lf->filename, &stat.name[0], namelen); 1214159587Sjhb stat.refs = lf->refs; 1215159587Sjhb stat.id = lf->id; 1216159587Sjhb stat.address = lf->address; 1217159587Sjhb stat.size = lf->size; 1218172862Sjb if (version_num > 1) { 1219172862Sjb /* Version 2 fields: */ 1220172862Sjb namelen = strlen(lf->pathname) + 1; 1221172862Sjb if (namelen > MAXPATHLEN) 1222172862Sjb namelen = MAXPATHLEN; 1223172862Sjb bcopy(lf->pathname, &stat.pathname[0], namelen); 1224172862Sjb } 1225159845Sjhb KLD_UNLOCK(); 122625537Sdfr 122791040Sarr td->td_retval[0] = 0; 1228159587Sjhb 1229172862Sjb return (copyout(&stat, uap->stat, version)); 123025537Sdfr} 123125537Sdfr 123225537Sdfrint 123391040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 123425537Sdfr{ 123591040Sarr linker_file_t lf; 123691040Sarr module_t mp; 123791040Sarr int error = 0; 123825537Sdfr 1239107089Srwatson#ifdef MAC 1240172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1241107089Srwatson if (error) 1242107089Srwatson return (error); 1243107089Srwatson#endif 1244107089Srwatson 1245159845Sjhb KLD_LOCK(); 1246107849Salfred lf = linker_find_file_by_id(uap->fileid); 124791040Sarr if (lf) { 124892547Sarr MOD_SLOCK; 124991040Sarr mp = TAILQ_FIRST(&lf->modules); 125091040Sarr if (mp != NULL) 125191040Sarr td->td_retval[0] = module_getid(mp); 125291040Sarr else 125391040Sarr td->td_retval[0] = 0; 125492547Sarr MOD_SUNLOCK; 125591040Sarr } else 125691040Sarr error = ENOENT; 1257159845Sjhb KLD_UNLOCK(); 125891040Sarr return (error); 125925537Sdfr} 126040159Speter 126141090Speterint 126283366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 126341090Speter{ 126491040Sarr char *symstr = NULL; 126591040Sarr c_linker_sym_t sym; 126691040Sarr linker_symval_t symval; 126791040Sarr linker_file_t lf; 126891040Sarr struct kld_sym_lookup lookup; 126991040Sarr int error = 0; 127041090Speter 1271107089Srwatson#ifdef MAC 1272172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1273107089Srwatson if (error) 1274107089Srwatson return (error); 1275107089Srwatson#endif 1276107089Srwatson 1277107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 1278159843Sjhb return (error); 127991068Sarr if (lookup.version != sizeof(lookup) || 1280159843Sjhb uap->cmd != KLDSYM_LOOKUP) 1281159843Sjhb return (EINVAL); 1282111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 128391040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 128491040Sarr goto out; 1285159845Sjhb KLD_LOCK(); 1286107849Salfred if (uap->fileid != 0) { 1287107849Salfred lf = linker_find_file_by_id(uap->fileid); 1288159843Sjhb if (lf == NULL) 128991040Sarr error = ENOENT; 1290159843Sjhb else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 129191040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 129291040Sarr lookup.symvalue = (uintptr_t) symval.value; 129391040Sarr lookup.symsize = symval.size; 1294107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 129591040Sarr } else 129691040Sarr error = ENOENT; 129791040Sarr } else { 129891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 129991040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 130091040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 130191040Sarr lookup.symvalue = (uintptr_t)symval.value; 130291040Sarr lookup.symsize = symval.size; 1303107849Salfred error = copyout(&lookup, uap->data, 130491040Sarr sizeof(lookup)); 130591068Sarr break; 130691040Sarr } 130791040Sarr } 1308185895Szec#ifndef VIMAGE_GLOBALS 1309185895Szec /* 1310185895Szec * If the symbol is not found in global namespace, 1311185895Szec * try to look it up in the current vimage namespace. 1312185895Szec */ 1313185895Szec if (lf == NULL) { 1314185895Szec CURVNET_SET(TD_TO_VNET(td)); 1315185895Szec error = vi_symlookup(&lookup, symstr); 1316185895Szec CURVNET_RESTORE(); 1317185895Szec if (error == 0) 1318185895Szec error = copyout(&lookup, uap->data, 1319185895Szec sizeof(lookup)); 1320185895Szec } 1321185895Szec#else 132291040Sarr if (lf == NULL) 132391040Sarr error = ENOENT; 1324185895Szec#endif 132541090Speter } 1326159845Sjhb KLD_UNLOCK(); 132741090Speterout: 1328159843Sjhb free(symstr, M_TEMP); 132991040Sarr return (error); 133041090Speter} 133141090Speter 133240159Speter/* 133340159Speter * Preloaded module support 133440159Speter */ 133540159Speter 133659751Speterstatic modlist_t 133774642Sbpmodlist_lookup(const char *name, int ver) 133859751Speter{ 133991040Sarr modlist_t mod; 134059751Speter 134191040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 134292032Sdwmalone if (strcmp(mod->name, name) == 0 && 134392032Sdwmalone (ver == 0 || mod->version == ver)) 134491040Sarr return (mod); 134591040Sarr } 134691040Sarr return (NULL); 134759751Speter} 134859751Speter 134974642Sbpstatic modlist_t 135083321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 135183321Speter{ 135291040Sarr modlist_t mod, bestmod; 135392032Sdwmalone int ver; 135483321Speter 135591040Sarr if (verinfo == NULL) 135691040Sarr return (modlist_lookup(name, 0)); 135791040Sarr bestmod = NULL; 1358159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 135992032Sdwmalone if (strcmp(mod->name, name) != 0) 136091040Sarr continue; 136191040Sarr ver = mod->version; 136291040Sarr if (ver == verinfo->md_ver_preferred) 136391040Sarr return (mod); 136491040Sarr if (ver >= verinfo->md_ver_minimum && 136591068Sarr ver <= verinfo->md_ver_maximum && 1366120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 136791040Sarr bestmod = mod; 136891040Sarr } 136991040Sarr return (bestmod); 137083321Speter} 137183321Speter 137283321Speterstatic modlist_t 137378501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 137474642Sbp{ 137591040Sarr modlist_t mod; 137674642Sbp 137792705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 137891040Sarr if (mod == NULL) 137991040Sarr panic("no memory for module list"); 138091040Sarr mod->container = container; 138191040Sarr mod->name = modname; 138291040Sarr mod->version = version; 138391040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 138491040Sarr return (mod); 138574642Sbp} 138674642Sbp 138740159Speterstatic void 138878161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 138991040Sarr struct mod_metadata **stop, int preload) 139074642Sbp{ 139191040Sarr struct mod_metadata *mp, **mdp; 139291040Sarr const char *modname; 139391040Sarr int ver; 139474642Sbp 139591040Sarr for (mdp = start; mdp < stop; mdp++) { 1396109605Sjake mp = *mdp; 139791040Sarr if (mp->md_type != MDT_VERSION) 139891040Sarr continue; 1399109605Sjake modname = mp->md_cval; 1400109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 140191040Sarr if (modlist_lookup(modname, ver) != NULL) { 140291040Sarr printf("module %s already present!\n", modname); 140391040Sarr /* XXX what can we do? this is a build error. :-( */ 140491040Sarr continue; 140591040Sarr } 140691040Sarr modlist_newmodule(modname, ver, lf); 140774642Sbp } 140874642Sbp} 140974642Sbp 141074642Sbpstatic void 141191040Sarrlinker_preload(void *arg) 141240159Speter{ 141391040Sarr caddr_t modptr; 141491040Sarr const char *modname, *nmodname; 141591040Sarr char *modtype; 1416160244Sjhb linker_file_t lf, nlf; 141791040Sarr linker_class_t lc; 141892032Sdwmalone int error; 141991040Sarr linker_file_list_t loaded_files; 142091040Sarr linker_file_list_t depended_files; 142191040Sarr struct mod_metadata *mp, *nmp; 142291040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 142391040Sarr struct mod_depend *verinfo; 142491040Sarr int nver; 142591040Sarr int resolves; 142691040Sarr modlist_t mod; 142791040Sarr struct sysinit **si_start, **si_stop; 142840159Speter 142991040Sarr TAILQ_INIT(&loaded_files); 143091040Sarr TAILQ_INIT(&depended_files); 143191040Sarr TAILQ_INIT(&found_modules); 143291040Sarr error = 0; 143359751Speter 143491040Sarr modptr = NULL; 143591040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 143691040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 143791040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 143891040Sarr if (modname == NULL) { 143991040Sarr printf("Preloaded module at %p does not have a" 144091040Sarr " name!\n", modptr); 144191040Sarr continue; 144291040Sarr } 144391040Sarr if (modtype == NULL) { 144491040Sarr printf("Preloaded module at %p does not have a type!\n", 144591040Sarr modptr); 144691040Sarr continue; 144791040Sarr } 1448131398Sjhb if (bootverbose) 1449131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1450131398Sjhb modptr); 145140159Speter lf = NULL; 145291040Sarr TAILQ_FOREACH(lc, &classes, link) { 145391040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1454134364Siedowse if (!error) 145591040Sarr break; 1456134364Siedowse lf = NULL; 145791040Sarr } 145891040Sarr if (lf) 145991040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 146040159Speter } 146140159Speter 146291040Sarr /* 146391040Sarr * First get a list of stuff in the kernel. 146491040Sarr */ 146591040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 146691040Sarr &stop, NULL) == 0) 146791040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 146859751Speter 146959751Speter /* 1470167019Sjhb * This is a once-off kinky bubble sort to resolve relocation 1471167019Sjhb * dependency requirements. 147259751Speter */ 147391040Sarrrestart: 147491040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 147591040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 147691040Sarr &stop, NULL); 147791040Sarr /* 147891040Sarr * First, look to see if we would successfully link with this 147991040Sarr * stuff. 148091040Sarr */ 148191040Sarr resolves = 1; /* unless we know otherwise */ 148291040Sarr if (!error) { 148391040Sarr for (mdp = start; mdp < stop; mdp++) { 1484109605Sjake mp = *mdp; 148591040Sarr if (mp->md_type != MDT_DEPEND) 148691040Sarr continue; 1487109605Sjake modname = mp->md_cval; 1488109605Sjake verinfo = mp->md_data; 148991040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1490109605Sjake nmp = *nmdp; 149191040Sarr if (nmp->md_type != MDT_VERSION) 149291040Sarr continue; 1493109605Sjake nmodname = nmp->md_cval; 149492032Sdwmalone if (strcmp(modname, nmodname) == 0) 149591040Sarr break; 149691040Sarr } 149791040Sarr if (nmdp < stop) /* it's a self reference */ 149891040Sarr continue; 1499159840Sjhb 150091040Sarr /* 150191040Sarr * ok, the module isn't here yet, we 150291040Sarr * are not finished 150391040Sarr */ 150491068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 150591040Sarr resolves = 0; 150691040Sarr } 150764143Speter } 150891040Sarr /* 150991040Sarr * OK, if we found our modules, we can link. So, "provide" 151091040Sarr * the modules inside and add it to the end of the link order 151191040Sarr * list. 151291040Sarr */ 151391040Sarr if (resolves) { 151491040Sarr if (!error) { 151591040Sarr for (mdp = start; mdp < stop; mdp++) { 1516109605Sjake mp = *mdp; 151791040Sarr if (mp->md_type != MDT_VERSION) 151891040Sarr continue; 1519109605Sjake modname = mp->md_cval; 1520109605Sjake nver = ((struct mod_version *) 1521109605Sjake mp->md_data)->mv_version; 152291040Sarr if (modlist_lookup(modname, 152391040Sarr nver) != NULL) { 152491040Sarr printf("module %s already" 152591040Sarr " present!\n", modname); 1526160244Sjhb TAILQ_REMOVE(&loaded_files, 1527160244Sjhb lf, loaded); 1528132117Sphk linker_file_unload(lf, 1529132117Sphk LINKER_UNLOAD_FORCE); 153091040Sarr /* we changed tailq next ptr */ 153191068Sarr goto restart; 153291040Sarr } 153391040Sarr modlist_newmodule(modname, nver, lf); 153491040Sarr } 153591040Sarr } 153691040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 153791040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 153891040Sarr /* 153991040Sarr * Since we provided modules, we need to restart the 154091040Sarr * sort so that the previous files that depend on us 154191040Sarr * have a chance. Also, we've busted the tailq next 154291040Sarr * pointer with the REMOVE. 154391040Sarr */ 154491040Sarr goto restart; 154559751Speter } 154659751Speter } 154791040Sarr 154859751Speter /* 154991040Sarr * At this point, we check to see what could not be resolved.. 155059751Speter */ 1551160242Sjhb while ((lf = TAILQ_FIRST(&loaded_files)) != NULL) { 1552160242Sjhb TAILQ_REMOVE(&loaded_files, lf, loaded); 155391040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1554132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 155540159Speter } 155659751Speter 155778161Speter /* 155891040Sarr * We made it. Finish off the linking in the order we determined. 155978161Speter */ 1560160244Sjhb TAILQ_FOREACH_SAFE(lf, &depended_files, loaded, nlf) { 156191040Sarr if (linker_kernel_file) { 156291040Sarr linker_kernel_file->refs++; 156391040Sarr error = linker_file_add_dependency(lf, 156491040Sarr linker_kernel_file); 156591040Sarr if (error) 156691040Sarr panic("cannot add dependency"); 156791040Sarr } 156891040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 156991040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 157091040Sarr &stop, NULL); 157191040Sarr if (!error) { 157291040Sarr for (mdp = start; mdp < stop; mdp++) { 1573109605Sjake mp = *mdp; 157491040Sarr if (mp->md_type != MDT_DEPEND) 157591040Sarr continue; 1576109605Sjake modname = mp->md_cval; 1577109605Sjake verinfo = mp->md_data; 157891040Sarr mod = modlist_lookup2(modname, verinfo); 1579151484Sjdp /* Don't count self-dependencies */ 1580151484Sjdp if (lf == mod->container) 1581151484Sjdp continue; 158291040Sarr mod->container->refs++; 158391040Sarr error = linker_file_add_dependency(lf, 158491040Sarr mod->container); 158591040Sarr if (error) 158691040Sarr panic("cannot add dependency"); 158791040Sarr } 158891040Sarr } 158991040Sarr /* 159091040Sarr * Now do relocation etc using the symbol search paths 159191040Sarr * established by the dependencies 159291040Sarr */ 159391040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 159491040Sarr if (error) { 1595160244Sjhb TAILQ_REMOVE(&depended_files, lf, loaded); 159691040Sarr printf("KLD file %s - could not finalize loading\n", 159791040Sarr lf->filename); 1598132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 159991040Sarr continue; 160091040Sarr } 160191040Sarr linker_file_register_modules(lf); 160291040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 160391040Sarr &si_stop, NULL) == 0) 160491040Sarr sysinit_add(si_start, si_stop); 160591040Sarr linker_file_register_sysctls(lf); 160691040Sarr lf->flags |= LINKER_FILE_LINKED; 160759751Speter } 160891040Sarr /* woohoo! we made it! */ 160940159Speter} 161040159Speter 1611177253SrwatsonSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 161240159Speter 161340159Speter/* 161440159Speter * Search for a not-loaded module by name. 1615159840Sjhb * 161640159Speter * Modules may be found in the following locations: 1617159840Sjhb * 161891040Sarr * - preloaded (result is just the module name) - on disk (result is full path 161991040Sarr * to module) 1620159840Sjhb * 162191040Sarr * If the module name is qualified in any way (contains path, etc.) the we 162291040Sarr * simply return a copy of it. 1623159840Sjhb * 162440159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 162540159Speter * character as a separator to be consistent with the bootloader. 162640159Speter */ 162740159Speter 162883321Speterstatic char linker_hintfile[] = "linker.hints"; 1629111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 163040159Speter 163140159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 163291040Sarr sizeof(linker_path), "module load search path"); 163340159Speter 163477843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 163570417Speter 163659751Speterstatic char *linker_ext_list[] = { 163783321Speter "", 163859751Speter ".ko", 163959751Speter NULL 164059751Speter}; 164159751Speter 164283321Speter/* 164391040Sarr * Check if file actually exists either with or without extension listed in 164491040Sarr * the linker_ext_list. (probably should be generic for the rest of the 164591040Sarr * kernel) 164683321Speter */ 164759751Speterstatic char * 164891040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 164991040Sarr int namelen, struct vattr *vap) 165040159Speter{ 165191040Sarr struct nameidata nd; 165291040Sarr struct thread *td = curthread; /* XXX */ 165391040Sarr char *result, **cpp, *sep; 1654159808Sjhb int error, len, extlen, reclen, flags, vfslocked; 165591040Sarr enum vtype type; 165640159Speter 165791040Sarr extlen = 0; 165891040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 165991040Sarr len = strlen(*cpp); 166091040Sarr if (len > extlen) 166191040Sarr extlen = len; 166291040Sarr } 166391040Sarr extlen++; /* trailing '\0' */ 166491040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 166583321Speter 166691040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1667111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 166891040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 166991040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 167091040Sarr namelen, name, *cpp); 167191040Sarr /* 167291040Sarr * Attempt to open the file, and return the path if 167391040Sarr * we succeed and it's a regular file. 167491040Sarr */ 1675159808Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); 167691040Sarr flags = FREAD; 1677170152Skib error = vn_open(&nd, &flags, 0, NULL); 167891040Sarr if (error == 0) { 1679159808Sjhb vfslocked = NDHASGIANT(&nd); 168091040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 168191040Sarr type = nd.ni_vp->v_type; 168291040Sarr if (vap) 1683182371Sattilio VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); 1684175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 168591406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 1686159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 168791040Sarr if (type == VREG) 168891040Sarr return (result); 168991040Sarr } 169083321Speter } 169191040Sarr free(result, M_LINKER); 169291040Sarr return (NULL); 169383321Speter} 169483321Speter 169591040Sarr#define INT_ALIGN(base, ptr) ptr = \ 169683321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 169783321Speter 169883321Speter/* 169991040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 170091040Sarr * version specification is available, then try to find the best KLD. 170183321Speter * Otherwise just find the latest one. 170283321Speter */ 170383321Speterstatic char * 170491040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 170591040Sarr int modnamelen, struct mod_depend *verinfo) 170683321Speter{ 170791040Sarr struct thread *td = curthread; /* XXX */ 170891406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 170991040Sarr struct nameidata nd; 171091040Sarr struct vattr vattr, mattr; 171191040Sarr u_char *hints = NULL; 171291040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 171391040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 1714159808Sjhb int vfslocked = 0; 171583321Speter 171691040Sarr result = NULL; 171791040Sarr bestver = found = 0; 171883321Speter 171991040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 172091040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 172191040Sarr strlen(sep) + 1; 1722111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 172391040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 172491040Sarr linker_hintfile); 172583321Speter 1726159808Sjhb NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); 172791040Sarr flags = FREAD; 1728170152Skib error = vn_open(&nd, &flags, 0, NULL); 172991040Sarr if (error) 173091040Sarr goto bad; 1731159808Sjhb vfslocked = NDHASGIANT(&nd); 173291040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 173391040Sarr if (nd.ni_vp->v_type != VREG) 173491040Sarr goto bad; 173591040Sarr best = cp = NULL; 1736182371Sattilio error = VOP_GETATTR(nd.ni_vp, &vattr, cred); 173791040Sarr if (error) 173891040Sarr goto bad; 173991040Sarr /* 174091040Sarr * XXX: we need to limit this number to some reasonable value 174191040Sarr */ 174291040Sarr if (vattr.va_size > 100 * 1024) { 174391040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 174491040Sarr goto bad; 174591040Sarr } 1746111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 174791040Sarr if (hints == NULL) 174891040Sarr goto bad; 174991068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1750101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 175191040Sarr if (error) 175291040Sarr goto bad; 1753175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 175491040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1755159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 175691040Sarr nd.ni_vp = NULL; 175791040Sarr if (reclen != 0) { 175891040Sarr printf("can't read %d\n", reclen); 175991040Sarr goto bad; 176091040Sarr } 176191040Sarr intp = (int *)hints; 176283321Speter ival = *intp++; 176391040Sarr if (ival != LINKER_HINTS_VERSION) { 176491040Sarr printf("hints file version mismatch %d\n", ival); 176591040Sarr goto bad; 176683321Speter } 176791040Sarr bufend = hints + vattr.va_size; 176891040Sarr recptr = (u_char *)intp; 176991040Sarr clen = blen = 0; 177091040Sarr while (recptr < bufend && !found) { 177191040Sarr intp = (int *)recptr; 177291040Sarr reclen = *intp++; 177391040Sarr ival = *intp++; 177491040Sarr cp = (char *)intp; 177591040Sarr switch (ival) { 177691040Sarr case MDT_VERSION: 177791040Sarr clen = *cp++; 177891040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 177991040Sarr break; 178091040Sarr cp += clen; 178191040Sarr INT_ALIGN(hints, cp); 178291040Sarr ival = *(int *)cp; 178391040Sarr cp += sizeof(int); 178491040Sarr clen = *cp++; 178591040Sarr if (verinfo == NULL || 178691040Sarr ival == verinfo->md_ver_preferred) { 178791040Sarr found = 1; 178891040Sarr break; 178991040Sarr } 179091040Sarr if (ival >= verinfo->md_ver_minimum && 179191040Sarr ival <= verinfo->md_ver_maximum && 179291040Sarr ival > bestver) { 179391040Sarr bestver = ival; 179491040Sarr best = cp; 179591040Sarr blen = clen; 179691040Sarr } 179791040Sarr break; 179891040Sarr default: 179991040Sarr break; 180091040Sarr } 180191040Sarr recptr += reclen + sizeof(int); 180291040Sarr } 180383321Speter /* 180491040Sarr * Finally check if KLD is in the place 180583321Speter */ 180691040Sarr if (found) 180791040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 180891040Sarr else if (best) 180991040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 181091040Sarr 181191040Sarr /* 181291040Sarr * KLD is newer than hints file. What we should do now? 181391040Sarr */ 181491040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 181591040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 181691040Sarr " file\n", result); 181783321Speterbad: 1818105167Sphk free(pathbuf, M_LINKER); 181991040Sarr if (hints) 182091040Sarr free(hints, M_TEMP); 182199553Sjeff if (nd.ni_vp != NULL) { 1822175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 182391040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1824159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 182599553Sjeff } 182691040Sarr /* 182791040Sarr * If nothing found or hints is absent - fallback to the old 182891040Sarr * way by using "kldname[.ko]" as module name. 182991040Sarr */ 183091040Sarr if (!found && !bestver && result == NULL) 183191040Sarr result = linker_lookup_file(path, pathlen, modname, 183291040Sarr modnamelen, NULL); 183391040Sarr return (result); 183483321Speter} 183583321Speter 183683321Speter/* 183783321Speter * Lookup KLD which contains requested module in the all directories. 183883321Speter */ 183983321Speterstatic char * 184083321Speterlinker_search_module(const char *modname, int modnamelen, 184191040Sarr struct mod_depend *verinfo) 184283321Speter{ 184391040Sarr char *cp, *ep, *result; 184483321Speter 184591040Sarr /* 184691040Sarr * traverse the linker path 184791040Sarr */ 184891040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 184991040Sarr /* find the end of this component */ 185091040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 185191068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 185291068Sarr modnamelen, verinfo); 185391040Sarr if (result != NULL) 185491040Sarr return (result); 185591040Sarr if (*ep == 0) 185691040Sarr break; 185791040Sarr } 185891040Sarr return (NULL); 185983321Speter} 186083321Speter 186183321Speter/* 186283321Speter * Search for module in all directories listed in the linker_path. 186383321Speter */ 186483321Speterstatic char * 186583321Speterlinker_search_kld(const char *name) 186683321Speter{ 1867158972Sdelphij char *cp, *ep, *result; 1868158972Sdelphij int len; 186983321Speter 187091040Sarr /* qualified at all? */ 187191040Sarr if (index(name, '/')) 187291040Sarr return (linker_strdup(name)); 187340159Speter 187491040Sarr /* traverse the linker path */ 187591040Sarr len = strlen(name); 187691040Sarr for (ep = linker_path; *ep; ep++) { 187791040Sarr cp = ep; 187891040Sarr /* find the end of this component */ 187991040Sarr for (; *ep != 0 && *ep != ';'; ep++); 188091040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 188191040Sarr if (result != NULL) 188291040Sarr return (result); 188391040Sarr } 188491040Sarr return (NULL); 188540159Speter} 188659751Speter 188759751Speterstatic const char * 188891040Sarrlinker_basename(const char *path) 188959751Speter{ 189091040Sarr const char *filename; 189159751Speter 189291040Sarr filename = rindex(path, '/'); 189391040Sarr if (filename == NULL) 189491040Sarr return path; 189591040Sarr if (filename[1]) 189691040Sarr filename++; 189791040Sarr return (filename); 189859751Speter} 189959751Speter 1900157144Sjkoshy#ifdef HWPMC_HOOKS 1901157144Sjkoshy 1902159797Sjhbstruct hwpmc_context { 1903159797Sjhb int nobjects; 1904159797Sjhb int nmappings; 1905159797Sjhb struct pmckern_map_in *kobase; 1906159797Sjhb}; 1907159797Sjhb 1908159797Sjhbstatic int 1909159797Sjhblinker_hwpmc_list_object(linker_file_t lf, void *arg) 1910159797Sjhb{ 1911159797Sjhb struct hwpmc_context *hc; 1912159797Sjhb 1913159797Sjhb hc = arg; 1914159797Sjhb 1915159797Sjhb /* If we run out of mappings, fail. */ 1916159797Sjhb if (hc->nobjects >= hc->nmappings) 1917159797Sjhb return (1); 1918159797Sjhb 1919159797Sjhb /* Save the info for this linker file. */ 1920159797Sjhb hc->kobase[hc->nobjects].pm_file = lf->filename; 1921159797Sjhb hc->kobase[hc->nobjects].pm_address = (uintptr_t)lf->address; 1922159797Sjhb hc->nobjects++; 1923159797Sjhb return (0); 1924159797Sjhb} 1925159797Sjhb 192659751Speter/* 1927157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1928157144Sjkoshy */ 1929157144Sjkoshyvoid * 1930157144Sjkoshylinker_hwpmc_list_objects(void) 1931157144Sjkoshy{ 1932159797Sjhb struct hwpmc_context hc; 1933157144Sjkoshy 1934159797Sjhb hc.nmappings = 15; /* a reasonable default */ 1935157144Sjkoshy 1936157144Sjkoshy retry: 1937157144Sjkoshy /* allocate nmappings+1 entries */ 1938184214Sdes hc.kobase = malloc((hc.nmappings + 1) * sizeof(struct pmckern_map_in), 1939184214Sdes M_LINKER, M_WAITOK | M_ZERO); 1940157144Sjkoshy 1941159797Sjhb hc.nobjects = 0; 1942159797Sjhb if (linker_file_foreach(linker_hwpmc_list_object, &hc) != 0) { 1943159797Sjhb hc.nmappings = hc.nobjects; 1944184205Sdes free(hc.kobase, M_LINKER); 1945157144Sjkoshy goto retry; 1946157144Sjkoshy } 1947157144Sjkoshy 1948159797Sjhb KASSERT(hc.nobjects > 0, ("linker_hpwmc_list_objects: no kernel " 1949159797Sjhb "objects?")); 1950157144Sjkoshy 1951157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1952159797Sjhb KASSERT(hc.kobase[hc.nobjects].pm_file == NULL, 1953157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1954157144Sjkoshy 1955159797Sjhb return ((void *)hc.kobase); 1956157144Sjkoshy} 1957157144Sjkoshy#endif 1958157144Sjkoshy 1959157144Sjkoshy/* 196091040Sarr * Find a file which contains given module and load it, if "parent" is not 196191040Sarr * NULL, register a reference to it. 196259751Speter */ 1963159796Sjhbstatic int 196483321Speterlinker_load_module(const char *kldname, const char *modname, 196591040Sarr struct linker_file *parent, struct mod_depend *verinfo, 196691040Sarr struct linker_file **lfpp) 196759751Speter{ 196891040Sarr linker_file_t lfdep; 196991040Sarr const char *filename; 197091040Sarr char *pathname; 197191040Sarr int error; 197259751Speter 1973159845Sjhb KLD_LOCK_ASSERT(); 197491040Sarr if (modname == NULL) { 197591040Sarr /* 197691040Sarr * We have to load KLD 197791040Sarr */ 197891068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 197991068Sarr " is not NULL")); 198091040Sarr pathname = linker_search_kld(kldname); 198191040Sarr } else { 198291040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 198391040Sarr return (EEXIST); 198494322Sbrian if (kldname != NULL) 198594322Sbrian pathname = linker_strdup(kldname); 198695488Sbrian else if (rootvnode == NULL) 198794322Sbrian pathname = NULL; 198894322Sbrian else 198991040Sarr /* 199091040Sarr * Need to find a KLD with required module 199191040Sarr */ 199291040Sarr pathname = linker_search_module(modname, 199391040Sarr strlen(modname), verinfo); 199491040Sarr } 199591040Sarr if (pathname == NULL) 199691040Sarr return (ENOENT); 199791040Sarr 199883321Speter /* 199991040Sarr * Can't load more than one file with the same basename XXX: 200091040Sarr * Actually it should be possible to have multiple KLDs with 200191040Sarr * the same basename but different path because they can 200291040Sarr * provide different versions of the same modules. 200383321Speter */ 200491040Sarr filename = linker_basename(pathname); 2005159792Sjhb if (linker_find_file_by_name(filename)) 200691040Sarr error = EEXIST; 2007159792Sjhb else do { 200891040Sarr error = linker_load_file(pathname, &lfdep); 200991040Sarr if (error) 201091040Sarr break; 201191040Sarr if (modname && verinfo && 201291040Sarr modlist_lookup2(modname, verinfo) == NULL) { 2013132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 201491040Sarr error = ENOENT; 201591040Sarr break; 201691040Sarr } 201791040Sarr if (parent) { 201891040Sarr error = linker_file_add_dependency(parent, lfdep); 201991040Sarr if (error) 202091040Sarr break; 202191040Sarr } 202291040Sarr if (lfpp) 202391040Sarr *lfpp = lfdep; 202491040Sarr } while (0); 2025159791Sjhb free(pathname, M_LINKER); 202691040Sarr return (error); 202759751Speter} 202859751Speter 202959751Speter/* 203091040Sarr * This routine is responsible for finding dependencies of userland initiated 203191040Sarr * kldload(2)'s of files. 203259751Speter */ 203359751Speterint 203486469Siedowselinker_load_dependencies(linker_file_t lf) 203559751Speter{ 203691040Sarr linker_file_t lfdep; 203791040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 203891040Sarr struct mod_metadata *mp, *nmp; 203991040Sarr struct mod_depend *verinfo; 204091040Sarr modlist_t mod; 204191040Sarr const char *modname, *nmodname; 204292032Sdwmalone int ver, error = 0, count; 204359751Speter 204491040Sarr /* 204591040Sarr * All files are dependant on /kernel. 204691040Sarr */ 2047159845Sjhb KLD_LOCK_ASSERT(); 204891040Sarr if (linker_kernel_file) { 204991040Sarr linker_kernel_file->refs++; 205091040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 205191040Sarr if (error) 205291040Sarr return (error); 205359751Speter } 205491040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 205591040Sarr &count) != 0) 205691040Sarr return (0); 205791040Sarr for (mdp = start; mdp < stop; mdp++) { 2058109605Sjake mp = *mdp; 205991040Sarr if (mp->md_type != MDT_VERSION) 206091040Sarr continue; 2061109605Sjake modname = mp->md_cval; 2062109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 206391040Sarr mod = modlist_lookup(modname, ver); 206491040Sarr if (mod != NULL) { 206591040Sarr printf("interface %s.%d already present in the KLD" 206691040Sarr " '%s'!\n", modname, ver, 206791040Sarr mod->container->filename); 206891040Sarr return (EEXIST); 206991040Sarr } 207091040Sarr } 207174642Sbp 207291040Sarr for (mdp = start; mdp < stop; mdp++) { 2073109605Sjake mp = *mdp; 207491040Sarr if (mp->md_type != MDT_DEPEND) 207591040Sarr continue; 2076109605Sjake modname = mp->md_cval; 2077109605Sjake verinfo = mp->md_data; 207891040Sarr nmodname = NULL; 207991040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 2080109605Sjake nmp = *nmdp; 208191040Sarr if (nmp->md_type != MDT_VERSION) 208291040Sarr continue; 2083109605Sjake nmodname = nmp->md_cval; 208492032Sdwmalone if (strcmp(modname, nmodname) == 0) 208591040Sarr break; 208691040Sarr } 208791040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 208891040Sarr continue; 208991040Sarr mod = modlist_lookup2(modname, verinfo); 209091040Sarr if (mod) { /* woohoo, it's loaded already */ 209191040Sarr lfdep = mod->container; 209291040Sarr lfdep->refs++; 209391040Sarr error = linker_file_add_dependency(lf, lfdep); 209491040Sarr if (error) 209591040Sarr break; 209691040Sarr continue; 209791040Sarr } 209891040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 209991040Sarr if (error) { 210091040Sarr printf("KLD %s: depends on %s - not available\n", 210191040Sarr lf->filename, modname); 210291040Sarr break; 210391040Sarr } 210459751Speter } 210559751Speter 210691040Sarr if (error) 210791040Sarr return (error); 210891040Sarr linker_addmodules(lf, start, stop, 0); 210991040Sarr return (error); 211059751Speter} 211185736Sgreen 211285736Sgreenstatic int 211385736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 211485736Sgreen{ 211585736Sgreen struct sysctl_req *req; 211685736Sgreen 211785736Sgreen req = opaque; 211885736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 211985736Sgreen} 212085736Sgreen 212185736Sgreen/* 212285736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 212385736Sgreen * in the kernel. 212485736Sgreen */ 212585736Sgreenstatic int 212685736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 212785736Sgreen{ 212885736Sgreen linker_file_t lf; 212985736Sgreen int error; 213085736Sgreen 2131107089Srwatson#ifdef MAC 2132172930Srwatson error = mac_kld_check_stat(req->td->td_ucred); 2133107089Srwatson if (error) 2134107089Srwatson return (error); 2135107089Srwatson#endif 2136126253Struckman error = sysctl_wire_old_buffer(req, 0); 2137126253Struckman if (error != 0) 2138126253Struckman return (error); 2139159845Sjhb KLD_LOCK(); 214085736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 214185736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 214285736Sgreen sysctl_kern_function_list_iterate, req); 214398452Sarr if (error) { 2144159845Sjhb KLD_UNLOCK(); 214585736Sgreen return (error); 214698452Sarr } 214785736Sgreen } 2148159845Sjhb KLD_UNLOCK(); 214985736Sgreen return (SYSCTL_OUT(req, "", 1)); 215085736Sgreen} 215185736Sgreen 215285736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 215391040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 2154