kern_linker.c revision 185895
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 185895 2008-12-10 23:12:39Z zec $"); 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 296159845Sjhb mtx_lock(&Giant); 29791040Sarr for (oidp = start; oidp < stop; oidp++) 29891040Sarr sysctl_register_oid(*oidp); 299159845Sjhb mtx_unlock(&Giant); 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 313159845Sjhb mtx_lock(&Giant); 31491040Sarr for (oidp = start; oidp < stop; oidp++) 31591040Sarr sysctl_unregister_oid(*oidp); 316159845Sjhb mtx_unlock(&Giant); 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) { 64691040Sarr linker_file_sysuninit(file); 64791040Sarr linker_file_unregister_sysctls(file); 64825537Sdfr } 64991040Sarr TAILQ_REMOVE(&linker_files, file, link); 65025537Sdfr 65191040Sarr if (file->deps) { 65291040Sarr for (i = 0; i < file->ndeps; i++) 653132117Sphk linker_file_unload(file->deps[i], flags); 65491040Sarr free(file->deps, M_LINKER); 65591040Sarr file->deps = NULL; 65659751Speter } 657160245Sjhb while ((cp = STAILQ_FIRST(&file->common)) != NULL) { 658160245Sjhb STAILQ_REMOVE_HEAD(&file->common, link); 65991040Sarr free(cp, M_LINKER); 66091040Sarr } 66159751Speter 66291040Sarr LINKER_UNLOAD(file); 66391040Sarr if (file->filename) { 66491040Sarr free(file->filename, M_LINKER); 66591040Sarr file->filename = NULL; 66691040Sarr } 667172862Sjb if (file->pathname) { 668172862Sjb free(file->pathname, M_LINKER); 669172862Sjb file->pathname = NULL; 670172862Sjb } 67191040Sarr kobj_delete((kobj_t) file, M_LINKER); 672159584Sjhb return (0); 67325537Sdfr} 67425537Sdfr 675179238Sjbint 676179238Sjblinker_ctf_get(linker_file_t file, linker_ctf_t *lc) 677179238Sjb{ 678179238Sjb return (LINKER_CTF_GET(file, lc)); 679179238Sjb} 680179238Sjb 681159796Sjhbstatic int 68286469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 68325537Sdfr{ 68491040Sarr linker_file_t *newdeps; 68525537Sdfr 686159845Sjhb KLD_LOCK_ASSERT(); 68791040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 688111119Simp M_LINKER, M_WAITOK | M_ZERO); 68991040Sarr if (newdeps == NULL) 69091040Sarr return (ENOMEM); 69125537Sdfr 69291040Sarr if (file->deps) { 69391040Sarr bcopy(file->deps, newdeps, 69491040Sarr file->ndeps * sizeof(linker_file_t *)); 69591040Sarr free(file->deps, M_LINKER); 69691040Sarr } 69791040Sarr file->deps = newdeps; 69891040Sarr file->deps[file->ndeps] = dep; 69991040Sarr file->ndeps++; 70091040Sarr return (0); 70125537Sdfr} 70225537Sdfr 70378161Speter/* 70491040Sarr * Locate a linker set and its contents. This is a helper function to avoid 705159841Sjhb * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. 706159841Sjhb * This function is used in this file so we can avoid having lots of (void **) 707159841Sjhb * casts. 70878161Speter */ 70978161Speterint 71078161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 71191040Sarr void *firstp, void *lastp, int *countp) 71278161Speter{ 713159845Sjhb int error, locked; 71478161Speter 715159845Sjhb locked = KLD_LOCKED(); 716159845Sjhb if (!locked) 717159845Sjhb KLD_LOCK(); 718159845Sjhb error = LINKER_LOOKUP_SET(file, name, firstp, lastp, countp); 719159845Sjhb if (!locked) 720159845Sjhb KLD_UNLOCK(); 721159845Sjhb return (error); 72278161Speter} 72378161Speter 724173714Sjb/* 725173714Sjb * List all functions in a file. 726173714Sjb */ 727173714Sjbint 728173714Sjblinker_file_function_listall(linker_file_t lf, 729179238Sjb linker_function_nameval_callback_t callback_func, void *arg) 730173714Sjb{ 731173714Sjb return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); 732173714Sjb} 733173714Sjb 73425537Sdfrcaddr_t 73591040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 73625537Sdfr{ 737159845Sjhb caddr_t sym; 738159845Sjhb int locked; 739159845Sjhb 740159845Sjhb locked = KLD_LOCKED(); 741159845Sjhb if (!locked) 742159845Sjhb KLD_LOCK(); 743159845Sjhb sym = linker_file_lookup_symbol_internal(file, name, deps); 744159845Sjhb if (!locked) 745159845Sjhb KLD_UNLOCK(); 746159845Sjhb return (sym); 747159845Sjhb} 748159845Sjhb 749159845Sjhbstatic caddr_t 750159845Sjhblinker_file_lookup_symbol_internal(linker_file_t file, const char *name, 751159845Sjhb int deps) 752159845Sjhb{ 75391040Sarr c_linker_sym_t sym; 75491040Sarr linker_symval_t symval; 75591040Sarr caddr_t address; 75691040Sarr size_t common_size = 0; 75792032Sdwmalone int i; 75825537Sdfr 759159845Sjhb KLD_LOCK_ASSERT(); 760109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 76191040Sarr file, name, deps)); 76225537Sdfr 76391040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 76491040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 76591040Sarr if (symval.value == 0) 76691040Sarr /* 76791040Sarr * For commons, first look them up in the 76891040Sarr * dependencies and only allocate space if not found 76991040Sarr * there. 77091040Sarr */ 77191040Sarr common_size = symval.size; 77291040Sarr else { 77391040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 774109605Sjake ".value=%p\n", symval.value)); 77591040Sarr return (symval.value); 77691040Sarr } 77740159Speter } 77891040Sarr if (deps) { 77991040Sarr for (i = 0; i < file->ndeps; i++) { 780159845Sjhb address = linker_file_lookup_symbol_internal( 781159845Sjhb file->deps[i], name, 0); 78291040Sarr if (address) { 78391040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 784109605Sjake " deps value=%p\n", address)); 78591040Sarr return (address); 78691040Sarr } 78791040Sarr } 78825537Sdfr } 78991040Sarr if (common_size > 0) { 79091040Sarr /* 79191040Sarr * This is a common symbol which was not found in the 79291040Sarr * dependencies. We maintain a simple common symbol table in 79391040Sarr * the file object. 79491040Sarr */ 79591040Sarr struct common_symbol *cp; 79642849Speter 79791040Sarr STAILQ_FOREACH(cp, &file->common, link) { 79892032Sdwmalone if (strcmp(cp->name, name) == 0) { 79991040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 800109605Sjake " old common value=%p\n", cp->address)); 80191040Sarr return (cp->address); 80291040Sarr } 80391040Sarr } 80491040Sarr /* 80591040Sarr * Round the symbol size up to align. 80691040Sarr */ 80791040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 80891040Sarr cp = malloc(sizeof(struct common_symbol) 80991040Sarr + common_size + strlen(name) + 1, M_LINKER, 810111119Simp M_WAITOK | M_ZERO); 81191040Sarr cp->address = (caddr_t)(cp + 1); 81291040Sarr cp->name = cp->address + common_size; 81391040Sarr strcpy(cp->name, name); 81491040Sarr bzero(cp->address, common_size); 81591040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 81625537Sdfr 81791040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 818109605Sjake " value=%p\n", cp->address)); 81991040Sarr return (cp->address); 82040159Speter } 82191040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 82291040Sarr return (0); 82325537Sdfr} 82425537Sdfr 82525537Sdfr/* 826174132Srwatson * Both DDB and stack(9) rely on the kernel linker to provide forward and 827174132Srwatson * backward lookup of symbols. However, DDB and sometimes stack(9) need to 828174132Srwatson * do this in a lockfree manner. We provide a set of internal helper 829174132Srwatson * routines to perform these operations without locks, and then wrappers that 830174132Srwatson * optionally lock. 831159840Sjhb * 832174132Srwatson * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. 83340159Speter */ 834174132Srwatson#ifdef DDB 835174132Srwatsonstatic int 836174132Srwatsonlinker_debug_lookup(const char *symstr, c_linker_sym_t *sym) 83740159Speter{ 83891040Sarr linker_file_t lf; 83940159Speter 84091040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 84191040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 84291040Sarr return (0); 84391040Sarr } 84491040Sarr return (ENOENT); 84540159Speter} 846174132Srwatson#endif 84740159Speter 848174132Srwatsonstatic int 849174132Srwatsonlinker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 85040159Speter{ 85191040Sarr linker_file_t lf; 85291040Sarr c_linker_sym_t best, es; 85391040Sarr u_long diff, bestdiff, off; 85440159Speter 85591040Sarr best = 0; 85691040Sarr off = (uintptr_t)value; 85791040Sarr bestdiff = off; 85891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 85991040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 86091040Sarr continue; 86191040Sarr if (es != 0 && diff < bestdiff) { 86291040Sarr best = es; 86391040Sarr bestdiff = diff; 86491040Sarr } 86591040Sarr if (bestdiff == 0) 86691040Sarr break; 86740159Speter } 86891040Sarr if (best) { 86991040Sarr *sym = best; 87091040Sarr *diffp = bestdiff; 87191040Sarr return (0); 87291040Sarr } else { 87391040Sarr *sym = 0; 87491040Sarr *diffp = off; 87591040Sarr return (ENOENT); 87691040Sarr } 87740159Speter} 87840159Speter 879174132Srwatsonstatic int 880174132Srwatsonlinker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 88140159Speter{ 88291040Sarr linker_file_t lf; 88340159Speter 88491040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 88591040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 88691040Sarr return (0); 88791040Sarr } 88891040Sarr return (ENOENT); 88940159Speter} 890174132Srwatson 891174132Srwatsonstatic int 892174132Srwatsonlinker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, 893174132Srwatson long *offset) 894174132Srwatson{ 895174132Srwatson linker_symval_t symval; 896174132Srwatson c_linker_sym_t sym; 897174132Srwatson int error; 898174132Srwatson 899174132Srwatson *offset = 0; 900174132Srwatson error = linker_debug_search_symbol(value, &sym, offset); 901174132Srwatson if (error) 902174132Srwatson return (error); 903174132Srwatson error = linker_debug_symbol_values(sym, &symval); 904174132Srwatson if (error) 905174132Srwatson return (error); 906174132Srwatson strlcpy(buf, symval.name, buflen); 907174132Srwatson return (0); 908174132Srwatson} 909174132Srwatson 910174132Srwatson#ifdef DDB 911174132Srwatson/* 912174132Srwatson * DDB Helpers. DDB has to look across multiple files with their own symbol 913174132Srwatson * tables and string tables. 914174132Srwatson * 915174132Srwatson * Note that we do not obey list locking protocols here. We really don't need 916174132Srwatson * DDB to hang because somebody's got the lock held. We'll take the chance 917174132Srwatson * that the files list is inconsistant instead. 918174132Srwatson */ 919174132Srwatsonint 920174132Srwatsonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 921174132Srwatson{ 922174132Srwatson 923174132Srwatson return (linker_debug_lookup(symstr, sym)); 924174132Srwatson} 925174132Srwatson 926174132Srwatsonint 927174132Srwatsonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 928174132Srwatson{ 929174132Srwatson 930174132Srwatson return (linker_debug_search_symbol(value, sym, diffp)); 931174132Srwatson} 932174132Srwatson 933174132Srwatsonint 934174132Srwatsonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 935174132Srwatson{ 936174132Srwatson 937174132Srwatson return (linker_debug_symbol_values(sym, symval)); 938174132Srwatson} 939174132Srwatson 940174132Srwatsonint 941174132Srwatsonlinker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, 942174132Srwatson long *offset) 943174132Srwatson{ 944174132Srwatson 945174132Srwatson return (linker_debug_search_symbol_name(value, buf, buflen, offset)); 946174132Srwatson} 94740159Speter#endif 94840159Speter 94940159Speter/* 950174132Srwatson * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do 951174132Srwatson * obey locking protocols, and offer a significantly less complex interface. 952174132Srwatson */ 953174132Srwatsonint 954174132Srwatsonlinker_search_symbol_name(caddr_t value, char *buf, u_int buflen, 955174132Srwatson long *offset) 956174132Srwatson{ 957178380Spjd int error; 958174132Srwatson 959178380Spjd KLD_LOCK(); 960174132Srwatson error = linker_debug_search_symbol_name(value, buf, buflen, offset); 961178380Spjd KLD_UNLOCK(); 962174132Srwatson return (error); 963174132Srwatson} 964174132Srwatson 965174132Srwatson/* 96625537Sdfr * Syscalls. 96725537Sdfr */ 96825537Sdfrint 969159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 97025537Sdfr{ 971157144Sjkoshy#ifdef HWPMC_HOOKS 972157144Sjkoshy struct pmckern_map_in pkm; 973157144Sjkoshy#endif 974159588Sjhb const char *kldname, *modname; 97591040Sarr linker_file_t lf; 976159588Sjhb int error; 97725537Sdfr 97893159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 979159588Sjhb return (error); 98093159Sarr 981164033Srwatson if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0) 982159588Sjhb return (error); 98325537Sdfr 98491040Sarr /* 985159841Sjhb * If file does not contain a qualified name or any dot in it 986159841Sjhb * (kldname.ko, or kldname.ver.ko) treat it as an interface 98791040Sarr * name. 98891040Sarr */ 989159588Sjhb if (index(file, '/') || index(file, '.')) { 990159588Sjhb kldname = file; 99191040Sarr modname = NULL; 99291040Sarr } else { 99391040Sarr kldname = NULL; 994159588Sjhb modname = file; 99591040Sarr } 996159588Sjhb 997159845Sjhb KLD_LOCK(); 99891040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 99991040Sarr if (error) 1000159588Sjhb goto unlock; 1001157144Sjkoshy#ifdef HWPMC_HOOKS 1002157144Sjkoshy pkm.pm_file = lf->filename; 1003157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 1004157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 1005157144Sjkoshy#endif 100691040Sarr lf->userrefs++; 1007159588Sjhb if (fileid != NULL) 1008159588Sjhb *fileid = lf->id; 1009159588Sjhbunlock: 1010159845Sjhb KLD_UNLOCK(); 101191040Sarr return (error); 101225537Sdfr} 101325537Sdfr 1014159588Sjhbint 1015159588Sjhbkldload(struct thread *td, struct kldload_args *uap) 1016159588Sjhb{ 1017159588Sjhb char *pathname = NULL; 1018159596Smarcel int error, fileid; 1019159588Sjhb 1020159588Sjhb td->td_retval[0] = -1; 1021159588Sjhb 1022159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1023159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 1024159596Smarcel if (error == 0) { 1025159596Smarcel error = kern_kldload(td, pathname, &fileid); 1026159596Smarcel if (error == 0) 1027159596Smarcel td->td_retval[0] = fileid; 1028159596Smarcel } 1029159588Sjhb free(pathname, M_TEMP); 1030159588Sjhb return (error); 1031159588Sjhb} 1032159588Sjhb 1033159588Sjhbint 1034132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 103525537Sdfr{ 1036157144Sjkoshy#ifdef HWPMC_HOOKS 1037157144Sjkoshy struct pmckern_map_out pkm; 1038157144Sjkoshy#endif 103991040Sarr linker_file_t lf; 104091040Sarr int error = 0; 104125537Sdfr 104293159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 1043159588Sjhb return (error); 104493159Sarr 1045164033Srwatson if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0) 1046159588Sjhb return (error); 104725537Sdfr 1048159845Sjhb KLD_LOCK(); 1049132117Sphk lf = linker_find_file_by_id(fileid); 105091040Sarr if (lf) { 105191040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 1052172862Sjb 1053172862Sjb /* Check if there are DTrace probes enabled on this file. */ 1054172862Sjb if (lf->nenabled > 0) { 1055172862Sjb printf("kldunload: attempt to unload file that has" 1056172862Sjb " DTrace probes enabled\n"); 1057172862Sjb error = EBUSY; 1058172862Sjb } else if (lf->userrefs == 0) { 1059132117Sphk /* 1060132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 1061132117Sphk */ 106291040Sarr printf("kldunload: attempt to unload file that was" 106391040Sarr " loaded by the kernel\n"); 1064159840Sjhb error = EBUSY; 1065159588Sjhb } else { 1066157144Sjkoshy#ifdef HWPMC_HOOKS 1067159588Sjhb /* Save data needed by hwpmc(4) before unloading. */ 1068159588Sjhb pkm.pm_address = (uintptr_t) lf->address; 1069159588Sjhb pkm.pm_size = lf->size; 1070157144Sjkoshy#endif 1071159588Sjhb lf->userrefs--; 1072159588Sjhb error = linker_file_unload(lf, flags); 1073159588Sjhb if (error) 1074159588Sjhb lf->userrefs++; 1075159588Sjhb } 107691040Sarr } else 107791040Sarr error = ENOENT; 1078157144Sjkoshy 1079157144Sjkoshy#ifdef HWPMC_HOOKS 1080157144Sjkoshy if (error == 0) 1081157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 1082157144Sjkoshy#endif 1083159845Sjhb KLD_UNLOCK(); 108491068Sarr return (error); 108525537Sdfr} 108625537Sdfr 108725537Sdfrint 1088132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 1089132117Sphk{ 1090132117Sphk 1091132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 1092132117Sphk} 1093132117Sphk 1094132117Sphkint 1095132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 1096132117Sphk{ 1097132117Sphk 1098132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 1099132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 1100132117Sphk return (EINVAL); 1101132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 1102132117Sphk} 1103132117Sphk 1104132117Sphkint 110591040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 110625537Sdfr{ 110791040Sarr char *pathname; 110891040Sarr const char *filename; 110991040Sarr linker_file_t lf; 1110159791Sjhb int error; 111125537Sdfr 1112107089Srwatson#ifdef MAC 1113172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1114107089Srwatson if (error) 1115107089Srwatson return (error); 1116107089Srwatson#endif 1117107089Srwatson 111891040Sarr td->td_retval[0] = -1; 111982749Sdillon 1120111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1121107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 112291040Sarr goto out; 112325537Sdfr 112491040Sarr filename = linker_basename(pathname); 1125159845Sjhb KLD_LOCK(); 112691040Sarr lf = linker_find_file_by_name(filename); 112791040Sarr if (lf) 112891040Sarr td->td_retval[0] = lf->id; 112991040Sarr else 113091040Sarr error = ENOENT; 1131159845Sjhb KLD_UNLOCK(); 113225537Sdfrout: 1133159791Sjhb free(pathname, M_TEMP); 113491040Sarr return (error); 113525537Sdfr} 113625537Sdfr 113725537Sdfrint 113891040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 113925537Sdfr{ 114091040Sarr linker_file_t lf; 114191040Sarr int error = 0; 114225537Sdfr 1143107089Srwatson#ifdef MAC 1144172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1145107089Srwatson if (error) 1146107089Srwatson return (error); 1147107089Srwatson#endif 1148107089Srwatson 1149159845Sjhb KLD_LOCK(); 1150166921Sjhb if (uap->fileid == 0) 1151166921Sjhb lf = TAILQ_FIRST(&linker_files); 1152166921Sjhb else { 1153166921Sjhb lf = linker_find_file_by_id(uap->fileid); 1154166921Sjhb if (lf == NULL) { 1155166921Sjhb error = ENOENT; 1156166921Sjhb goto out; 1157166921Sjhb } 1158166921Sjhb lf = TAILQ_NEXT(lf, link); 115991040Sarr } 1160166921Sjhb 1161166921Sjhb /* Skip partially loaded files. */ 1162166921Sjhb while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) 1163166921Sjhb lf = TAILQ_NEXT(lf, link); 1164166921Sjhb 1165166921Sjhb if (lf) 1166166921Sjhb td->td_retval[0] = lf->id; 1167166921Sjhb else 1168166921Sjhb td->td_retval[0] = 0; 116982749Sdillonout: 1170159845Sjhb KLD_UNLOCK(); 117191040Sarr return (error); 117225537Sdfr} 117325537Sdfr 117425537Sdfrint 117591040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 117625537Sdfr{ 1177159587Sjhb struct kld_file_stat stat; 117891040Sarr linker_file_t lf; 1179172862Sjb int error, namelen, version, version_num; 118025537Sdfr 1181159587Sjhb /* 1182159587Sjhb * Check the version of the user's structure. 1183159587Sjhb */ 1184172862Sjb if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0) 1185159587Sjhb return (error); 1186172862Sjb if (version == sizeof(struct kld_file_stat_1)) 1187172862Sjb version_num = 1; 1188172862Sjb else if (version == sizeof(struct kld_file_stat)) 1189172862Sjb version_num = 2; 1190172862Sjb else 1191159587Sjhb return (EINVAL); 1192159587Sjhb 1193107089Srwatson#ifdef MAC 1194172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1195107089Srwatson if (error) 1196107089Srwatson return (error); 1197107089Srwatson#endif 1198107089Srwatson 1199159845Sjhb KLD_LOCK(); 1200107849Salfred lf = linker_find_file_by_id(uap->fileid); 120191040Sarr if (lf == NULL) { 1202159845Sjhb KLD_UNLOCK(); 1203159587Sjhb return (ENOENT); 120491040Sarr } 120525537Sdfr 1206172862Sjb /* Version 1 fields: */ 120791040Sarr namelen = strlen(lf->filename) + 1; 120891040Sarr if (namelen > MAXPATHLEN) 120991040Sarr namelen = MAXPATHLEN; 1210159587Sjhb bcopy(lf->filename, &stat.name[0], namelen); 1211159587Sjhb stat.refs = lf->refs; 1212159587Sjhb stat.id = lf->id; 1213159587Sjhb stat.address = lf->address; 1214159587Sjhb stat.size = lf->size; 1215172862Sjb if (version_num > 1) { 1216172862Sjb /* Version 2 fields: */ 1217172862Sjb namelen = strlen(lf->pathname) + 1; 1218172862Sjb if (namelen > MAXPATHLEN) 1219172862Sjb namelen = MAXPATHLEN; 1220172862Sjb bcopy(lf->pathname, &stat.pathname[0], namelen); 1221172862Sjb } 1222159845Sjhb KLD_UNLOCK(); 122325537Sdfr 122491040Sarr td->td_retval[0] = 0; 1225159587Sjhb 1226172862Sjb return (copyout(&stat, uap->stat, version)); 122725537Sdfr} 122825537Sdfr 122925537Sdfrint 123091040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 123125537Sdfr{ 123291040Sarr linker_file_t lf; 123391040Sarr module_t mp; 123491040Sarr int error = 0; 123525537Sdfr 1236107089Srwatson#ifdef MAC 1237172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1238107089Srwatson if (error) 1239107089Srwatson return (error); 1240107089Srwatson#endif 1241107089Srwatson 1242159845Sjhb KLD_LOCK(); 1243107849Salfred lf = linker_find_file_by_id(uap->fileid); 124491040Sarr if (lf) { 124592547Sarr MOD_SLOCK; 124691040Sarr mp = TAILQ_FIRST(&lf->modules); 124791040Sarr if (mp != NULL) 124891040Sarr td->td_retval[0] = module_getid(mp); 124991040Sarr else 125091040Sarr td->td_retval[0] = 0; 125192547Sarr MOD_SUNLOCK; 125291040Sarr } else 125391040Sarr error = ENOENT; 1254159845Sjhb KLD_UNLOCK(); 125591040Sarr return (error); 125625537Sdfr} 125740159Speter 125841090Speterint 125983366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 126041090Speter{ 126191040Sarr char *symstr = NULL; 126291040Sarr c_linker_sym_t sym; 126391040Sarr linker_symval_t symval; 126491040Sarr linker_file_t lf; 126591040Sarr struct kld_sym_lookup lookup; 126691040Sarr int error = 0; 126741090Speter 1268107089Srwatson#ifdef MAC 1269172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1270107089Srwatson if (error) 1271107089Srwatson return (error); 1272107089Srwatson#endif 1273107089Srwatson 1274107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 1275159843Sjhb return (error); 127691068Sarr if (lookup.version != sizeof(lookup) || 1277159843Sjhb uap->cmd != KLDSYM_LOOKUP) 1278159843Sjhb return (EINVAL); 1279111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 128091040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 128191040Sarr goto out; 1282159845Sjhb KLD_LOCK(); 1283107849Salfred if (uap->fileid != 0) { 1284107849Salfred lf = linker_find_file_by_id(uap->fileid); 1285159843Sjhb if (lf == NULL) 128691040Sarr error = ENOENT; 1287159843Sjhb else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 128891040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 128991040Sarr lookup.symvalue = (uintptr_t) symval.value; 129091040Sarr lookup.symsize = symval.size; 1291107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 129291040Sarr } else 129391040Sarr error = ENOENT; 129491040Sarr } else { 129591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 129691040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 129791040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 129891040Sarr lookup.symvalue = (uintptr_t)symval.value; 129991040Sarr lookup.symsize = symval.size; 1300107849Salfred error = copyout(&lookup, uap->data, 130191040Sarr sizeof(lookup)); 130291068Sarr break; 130391040Sarr } 130491040Sarr } 1305185895Szec#ifndef VIMAGE_GLOBALS 1306185895Szec /* 1307185895Szec * If the symbol is not found in global namespace, 1308185895Szec * try to look it up in the current vimage namespace. 1309185895Szec */ 1310185895Szec if (lf == NULL) { 1311185895Szec CURVNET_SET(TD_TO_VNET(td)); 1312185895Szec error = vi_symlookup(&lookup, symstr); 1313185895Szec CURVNET_RESTORE(); 1314185895Szec if (error == 0) 1315185895Szec error = copyout(&lookup, uap->data, 1316185895Szec sizeof(lookup)); 1317185895Szec } 1318185895Szec#else 131991040Sarr if (lf == NULL) 132091040Sarr error = ENOENT; 1321185895Szec#endif 132241090Speter } 1323159845Sjhb KLD_UNLOCK(); 132441090Speterout: 1325159843Sjhb free(symstr, M_TEMP); 132691040Sarr return (error); 132741090Speter} 132841090Speter 132940159Speter/* 133040159Speter * Preloaded module support 133140159Speter */ 133240159Speter 133359751Speterstatic modlist_t 133474642Sbpmodlist_lookup(const char *name, int ver) 133559751Speter{ 133691040Sarr modlist_t mod; 133759751Speter 133891040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 133992032Sdwmalone if (strcmp(mod->name, name) == 0 && 134092032Sdwmalone (ver == 0 || mod->version == ver)) 134191040Sarr return (mod); 134291040Sarr } 134391040Sarr return (NULL); 134459751Speter} 134559751Speter 134674642Sbpstatic modlist_t 134783321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 134883321Speter{ 134991040Sarr modlist_t mod, bestmod; 135092032Sdwmalone int ver; 135183321Speter 135291040Sarr if (verinfo == NULL) 135391040Sarr return (modlist_lookup(name, 0)); 135491040Sarr bestmod = NULL; 1355159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 135692032Sdwmalone if (strcmp(mod->name, name) != 0) 135791040Sarr continue; 135891040Sarr ver = mod->version; 135991040Sarr if (ver == verinfo->md_ver_preferred) 136091040Sarr return (mod); 136191040Sarr if (ver >= verinfo->md_ver_minimum && 136291068Sarr ver <= verinfo->md_ver_maximum && 1363120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 136491040Sarr bestmod = mod; 136591040Sarr } 136691040Sarr return (bestmod); 136783321Speter} 136883321Speter 136983321Speterstatic modlist_t 137078501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 137174642Sbp{ 137291040Sarr modlist_t mod; 137374642Sbp 137492705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 137591040Sarr if (mod == NULL) 137691040Sarr panic("no memory for module list"); 137791040Sarr mod->container = container; 137891040Sarr mod->name = modname; 137991040Sarr mod->version = version; 138091040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 138191040Sarr return (mod); 138274642Sbp} 138374642Sbp 138440159Speterstatic void 138578161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 138691040Sarr struct mod_metadata **stop, int preload) 138774642Sbp{ 138891040Sarr struct mod_metadata *mp, **mdp; 138991040Sarr const char *modname; 139091040Sarr int ver; 139174642Sbp 139291040Sarr for (mdp = start; mdp < stop; mdp++) { 1393109605Sjake mp = *mdp; 139491040Sarr if (mp->md_type != MDT_VERSION) 139591040Sarr continue; 1396109605Sjake modname = mp->md_cval; 1397109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 139891040Sarr if (modlist_lookup(modname, ver) != NULL) { 139991040Sarr printf("module %s already present!\n", modname); 140091040Sarr /* XXX what can we do? this is a build error. :-( */ 140191040Sarr continue; 140291040Sarr } 140391040Sarr modlist_newmodule(modname, ver, lf); 140474642Sbp } 140574642Sbp} 140674642Sbp 140774642Sbpstatic void 140891040Sarrlinker_preload(void *arg) 140940159Speter{ 141091040Sarr caddr_t modptr; 141191040Sarr const char *modname, *nmodname; 141291040Sarr char *modtype; 1413160244Sjhb linker_file_t lf, nlf; 141491040Sarr linker_class_t lc; 141592032Sdwmalone int error; 141691040Sarr linker_file_list_t loaded_files; 141791040Sarr linker_file_list_t depended_files; 141891040Sarr struct mod_metadata *mp, *nmp; 141991040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 142091040Sarr struct mod_depend *verinfo; 142191040Sarr int nver; 142291040Sarr int resolves; 142391040Sarr modlist_t mod; 142491040Sarr struct sysinit **si_start, **si_stop; 142540159Speter 142691040Sarr TAILQ_INIT(&loaded_files); 142791040Sarr TAILQ_INIT(&depended_files); 142891040Sarr TAILQ_INIT(&found_modules); 142991040Sarr error = 0; 143059751Speter 143191040Sarr modptr = NULL; 143291040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 143391040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 143491040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 143591040Sarr if (modname == NULL) { 143691040Sarr printf("Preloaded module at %p does not have a" 143791040Sarr " name!\n", modptr); 143891040Sarr continue; 143991040Sarr } 144091040Sarr if (modtype == NULL) { 144191040Sarr printf("Preloaded module at %p does not have a type!\n", 144291040Sarr modptr); 144391040Sarr continue; 144491040Sarr } 1445131398Sjhb if (bootverbose) 1446131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1447131398Sjhb modptr); 144840159Speter lf = NULL; 144991040Sarr TAILQ_FOREACH(lc, &classes, link) { 145091040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1451134364Siedowse if (!error) 145291040Sarr break; 1453134364Siedowse lf = NULL; 145491040Sarr } 145591040Sarr if (lf) 145691040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 145740159Speter } 145840159Speter 145991040Sarr /* 146091040Sarr * First get a list of stuff in the kernel. 146191040Sarr */ 146291040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 146391040Sarr &stop, NULL) == 0) 146491040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 146559751Speter 146659751Speter /* 1467167019Sjhb * This is a once-off kinky bubble sort to resolve relocation 1468167019Sjhb * dependency requirements. 146959751Speter */ 147091040Sarrrestart: 147191040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 147291040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 147391040Sarr &stop, NULL); 147491040Sarr /* 147591040Sarr * First, look to see if we would successfully link with this 147691040Sarr * stuff. 147791040Sarr */ 147891040Sarr resolves = 1; /* unless we know otherwise */ 147991040Sarr if (!error) { 148091040Sarr for (mdp = start; mdp < stop; mdp++) { 1481109605Sjake mp = *mdp; 148291040Sarr if (mp->md_type != MDT_DEPEND) 148391040Sarr continue; 1484109605Sjake modname = mp->md_cval; 1485109605Sjake verinfo = mp->md_data; 148691040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1487109605Sjake nmp = *nmdp; 148891040Sarr if (nmp->md_type != MDT_VERSION) 148991040Sarr continue; 1490109605Sjake nmodname = nmp->md_cval; 149192032Sdwmalone if (strcmp(modname, nmodname) == 0) 149291040Sarr break; 149391040Sarr } 149491040Sarr if (nmdp < stop) /* it's a self reference */ 149591040Sarr continue; 1496159840Sjhb 149791040Sarr /* 149891040Sarr * ok, the module isn't here yet, we 149991040Sarr * are not finished 150091040Sarr */ 150191068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 150291040Sarr resolves = 0; 150391040Sarr } 150464143Speter } 150591040Sarr /* 150691040Sarr * OK, if we found our modules, we can link. So, "provide" 150791040Sarr * the modules inside and add it to the end of the link order 150891040Sarr * list. 150991040Sarr */ 151091040Sarr if (resolves) { 151191040Sarr if (!error) { 151291040Sarr for (mdp = start; mdp < stop; mdp++) { 1513109605Sjake mp = *mdp; 151491040Sarr if (mp->md_type != MDT_VERSION) 151591040Sarr continue; 1516109605Sjake modname = mp->md_cval; 1517109605Sjake nver = ((struct mod_version *) 1518109605Sjake mp->md_data)->mv_version; 151991040Sarr if (modlist_lookup(modname, 152091040Sarr nver) != NULL) { 152191040Sarr printf("module %s already" 152291040Sarr " present!\n", modname); 1523160244Sjhb TAILQ_REMOVE(&loaded_files, 1524160244Sjhb lf, loaded); 1525132117Sphk linker_file_unload(lf, 1526132117Sphk LINKER_UNLOAD_FORCE); 152791040Sarr /* we changed tailq next ptr */ 152891068Sarr goto restart; 152991040Sarr } 153091040Sarr modlist_newmodule(modname, nver, lf); 153191040Sarr } 153291040Sarr } 153391040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 153491040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 153591040Sarr /* 153691040Sarr * Since we provided modules, we need to restart the 153791040Sarr * sort so that the previous files that depend on us 153891040Sarr * have a chance. Also, we've busted the tailq next 153991040Sarr * pointer with the REMOVE. 154091040Sarr */ 154191040Sarr goto restart; 154259751Speter } 154359751Speter } 154491040Sarr 154559751Speter /* 154691040Sarr * At this point, we check to see what could not be resolved.. 154759751Speter */ 1548160242Sjhb while ((lf = TAILQ_FIRST(&loaded_files)) != NULL) { 1549160242Sjhb TAILQ_REMOVE(&loaded_files, lf, loaded); 155091040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1551132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 155240159Speter } 155359751Speter 155478161Speter /* 155591040Sarr * We made it. Finish off the linking in the order we determined. 155678161Speter */ 1557160244Sjhb TAILQ_FOREACH_SAFE(lf, &depended_files, loaded, nlf) { 155891040Sarr if (linker_kernel_file) { 155991040Sarr linker_kernel_file->refs++; 156091040Sarr error = linker_file_add_dependency(lf, 156191040Sarr linker_kernel_file); 156291040Sarr if (error) 156391040Sarr panic("cannot add dependency"); 156491040Sarr } 156591040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 156691040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 156791040Sarr &stop, NULL); 156891040Sarr if (!error) { 156991040Sarr for (mdp = start; mdp < stop; mdp++) { 1570109605Sjake mp = *mdp; 157191040Sarr if (mp->md_type != MDT_DEPEND) 157291040Sarr continue; 1573109605Sjake modname = mp->md_cval; 1574109605Sjake verinfo = mp->md_data; 157591040Sarr mod = modlist_lookup2(modname, verinfo); 1576151484Sjdp /* Don't count self-dependencies */ 1577151484Sjdp if (lf == mod->container) 1578151484Sjdp continue; 157991040Sarr mod->container->refs++; 158091040Sarr error = linker_file_add_dependency(lf, 158191040Sarr mod->container); 158291040Sarr if (error) 158391040Sarr panic("cannot add dependency"); 158491040Sarr } 158591040Sarr } 158691040Sarr /* 158791040Sarr * Now do relocation etc using the symbol search paths 158891040Sarr * established by the dependencies 158991040Sarr */ 159091040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 159191040Sarr if (error) { 1592160244Sjhb TAILQ_REMOVE(&depended_files, lf, loaded); 159391040Sarr printf("KLD file %s - could not finalize loading\n", 159491040Sarr lf->filename); 1595132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 159691040Sarr continue; 159791040Sarr } 159891040Sarr linker_file_register_modules(lf); 159991040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 160091040Sarr &si_stop, NULL) == 0) 160191040Sarr sysinit_add(si_start, si_stop); 160291040Sarr linker_file_register_sysctls(lf); 160391040Sarr lf->flags |= LINKER_FILE_LINKED; 160459751Speter } 160591040Sarr /* woohoo! we made it! */ 160640159Speter} 160740159Speter 1608177253SrwatsonSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 160940159Speter 161040159Speter/* 161140159Speter * Search for a not-loaded module by name. 1612159840Sjhb * 161340159Speter * Modules may be found in the following locations: 1614159840Sjhb * 161591040Sarr * - preloaded (result is just the module name) - on disk (result is full path 161691040Sarr * to module) 1617159840Sjhb * 161891040Sarr * If the module name is qualified in any way (contains path, etc.) the we 161991040Sarr * simply return a copy of it. 1620159840Sjhb * 162140159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 162240159Speter * character as a separator to be consistent with the bootloader. 162340159Speter */ 162440159Speter 162583321Speterstatic char linker_hintfile[] = "linker.hints"; 1626111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 162740159Speter 162840159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 162991040Sarr sizeof(linker_path), "module load search path"); 163040159Speter 163177843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 163270417Speter 163359751Speterstatic char *linker_ext_list[] = { 163483321Speter "", 163559751Speter ".ko", 163659751Speter NULL 163759751Speter}; 163859751Speter 163983321Speter/* 164091040Sarr * Check if file actually exists either with or without extension listed in 164191040Sarr * the linker_ext_list. (probably should be generic for the rest of the 164291040Sarr * kernel) 164383321Speter */ 164459751Speterstatic char * 164591040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 164691040Sarr int namelen, struct vattr *vap) 164740159Speter{ 164891040Sarr struct nameidata nd; 164991040Sarr struct thread *td = curthread; /* XXX */ 165091040Sarr char *result, **cpp, *sep; 1651159808Sjhb int error, len, extlen, reclen, flags, vfslocked; 165291040Sarr enum vtype type; 165340159Speter 165491040Sarr extlen = 0; 165591040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 165691040Sarr len = strlen(*cpp); 165791040Sarr if (len > extlen) 165891040Sarr extlen = len; 165991040Sarr } 166091040Sarr extlen++; /* trailing '\0' */ 166191040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 166283321Speter 166391040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1664111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 166591040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 166691040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 166791040Sarr namelen, name, *cpp); 166891040Sarr /* 166991040Sarr * Attempt to open the file, and return the path if 167091040Sarr * we succeed and it's a regular file. 167191040Sarr */ 1672159808Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); 167391040Sarr flags = FREAD; 1674170152Skib error = vn_open(&nd, &flags, 0, NULL); 167591040Sarr if (error == 0) { 1676159808Sjhb vfslocked = NDHASGIANT(&nd); 167791040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 167891040Sarr type = nd.ni_vp->v_type; 167991040Sarr if (vap) 1680182371Sattilio VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); 1681175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 168291406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 1683159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 168491040Sarr if (type == VREG) 168591040Sarr return (result); 168691040Sarr } 168783321Speter } 168891040Sarr free(result, M_LINKER); 168991040Sarr return (NULL); 169083321Speter} 169183321Speter 169291040Sarr#define INT_ALIGN(base, ptr) ptr = \ 169383321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 169483321Speter 169583321Speter/* 169691040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 169791040Sarr * version specification is available, then try to find the best KLD. 169883321Speter * Otherwise just find the latest one. 169983321Speter */ 170083321Speterstatic char * 170191040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 170291040Sarr int modnamelen, struct mod_depend *verinfo) 170383321Speter{ 170491040Sarr struct thread *td = curthread; /* XXX */ 170591406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 170691040Sarr struct nameidata nd; 170791040Sarr struct vattr vattr, mattr; 170891040Sarr u_char *hints = NULL; 170991040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 171091040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 1711159808Sjhb int vfslocked = 0; 171283321Speter 171391040Sarr result = NULL; 171491040Sarr bestver = found = 0; 171583321Speter 171691040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 171791040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 171891040Sarr strlen(sep) + 1; 1719111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 172091040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 172191040Sarr linker_hintfile); 172283321Speter 1723159808Sjhb NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); 172491040Sarr flags = FREAD; 1725170152Skib error = vn_open(&nd, &flags, 0, NULL); 172691040Sarr if (error) 172791040Sarr goto bad; 1728159808Sjhb vfslocked = NDHASGIANT(&nd); 172991040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 173091040Sarr if (nd.ni_vp->v_type != VREG) 173191040Sarr goto bad; 173291040Sarr best = cp = NULL; 1733182371Sattilio error = VOP_GETATTR(nd.ni_vp, &vattr, cred); 173491040Sarr if (error) 173591040Sarr goto bad; 173691040Sarr /* 173791040Sarr * XXX: we need to limit this number to some reasonable value 173891040Sarr */ 173991040Sarr if (vattr.va_size > 100 * 1024) { 174091040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 174191040Sarr goto bad; 174291040Sarr } 1743111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 174491040Sarr if (hints == NULL) 174591040Sarr goto bad; 174691068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1747101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 174891040Sarr if (error) 174991040Sarr goto bad; 1750175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 175191040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1752159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 175391040Sarr nd.ni_vp = NULL; 175491040Sarr if (reclen != 0) { 175591040Sarr printf("can't read %d\n", reclen); 175691040Sarr goto bad; 175791040Sarr } 175891040Sarr intp = (int *)hints; 175983321Speter ival = *intp++; 176091040Sarr if (ival != LINKER_HINTS_VERSION) { 176191040Sarr printf("hints file version mismatch %d\n", ival); 176291040Sarr goto bad; 176383321Speter } 176491040Sarr bufend = hints + vattr.va_size; 176591040Sarr recptr = (u_char *)intp; 176691040Sarr clen = blen = 0; 176791040Sarr while (recptr < bufend && !found) { 176891040Sarr intp = (int *)recptr; 176991040Sarr reclen = *intp++; 177091040Sarr ival = *intp++; 177191040Sarr cp = (char *)intp; 177291040Sarr switch (ival) { 177391040Sarr case MDT_VERSION: 177491040Sarr clen = *cp++; 177591040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 177691040Sarr break; 177791040Sarr cp += clen; 177891040Sarr INT_ALIGN(hints, cp); 177991040Sarr ival = *(int *)cp; 178091040Sarr cp += sizeof(int); 178191040Sarr clen = *cp++; 178291040Sarr if (verinfo == NULL || 178391040Sarr ival == verinfo->md_ver_preferred) { 178491040Sarr found = 1; 178591040Sarr break; 178691040Sarr } 178791040Sarr if (ival >= verinfo->md_ver_minimum && 178891040Sarr ival <= verinfo->md_ver_maximum && 178991040Sarr ival > bestver) { 179091040Sarr bestver = ival; 179191040Sarr best = cp; 179291040Sarr blen = clen; 179391040Sarr } 179491040Sarr break; 179591040Sarr default: 179691040Sarr break; 179791040Sarr } 179891040Sarr recptr += reclen + sizeof(int); 179991040Sarr } 180083321Speter /* 180191040Sarr * Finally check if KLD is in the place 180283321Speter */ 180391040Sarr if (found) 180491040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 180591040Sarr else if (best) 180691040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 180791040Sarr 180891040Sarr /* 180991040Sarr * KLD is newer than hints file. What we should do now? 181091040Sarr */ 181191040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 181291040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 181391040Sarr " file\n", result); 181483321Speterbad: 1815105167Sphk free(pathbuf, M_LINKER); 181691040Sarr if (hints) 181791040Sarr free(hints, M_TEMP); 181899553Sjeff if (nd.ni_vp != NULL) { 1819175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 182091040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1821159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 182299553Sjeff } 182391040Sarr /* 182491040Sarr * If nothing found or hints is absent - fallback to the old 182591040Sarr * way by using "kldname[.ko]" as module name. 182691040Sarr */ 182791040Sarr if (!found && !bestver && result == NULL) 182891040Sarr result = linker_lookup_file(path, pathlen, modname, 182991040Sarr modnamelen, NULL); 183091040Sarr return (result); 183183321Speter} 183283321Speter 183383321Speter/* 183483321Speter * Lookup KLD which contains requested module in the all directories. 183583321Speter */ 183683321Speterstatic char * 183783321Speterlinker_search_module(const char *modname, int modnamelen, 183891040Sarr struct mod_depend *verinfo) 183983321Speter{ 184091040Sarr char *cp, *ep, *result; 184183321Speter 184291040Sarr /* 184391040Sarr * traverse the linker path 184491040Sarr */ 184591040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 184691040Sarr /* find the end of this component */ 184791040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 184891068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 184991068Sarr modnamelen, verinfo); 185091040Sarr if (result != NULL) 185191040Sarr return (result); 185291040Sarr if (*ep == 0) 185391040Sarr break; 185491040Sarr } 185591040Sarr return (NULL); 185683321Speter} 185783321Speter 185883321Speter/* 185983321Speter * Search for module in all directories listed in the linker_path. 186083321Speter */ 186183321Speterstatic char * 186283321Speterlinker_search_kld(const char *name) 186383321Speter{ 1864158972Sdelphij char *cp, *ep, *result; 1865158972Sdelphij int len; 186683321Speter 186791040Sarr /* qualified at all? */ 186891040Sarr if (index(name, '/')) 186991040Sarr return (linker_strdup(name)); 187040159Speter 187191040Sarr /* traverse the linker path */ 187291040Sarr len = strlen(name); 187391040Sarr for (ep = linker_path; *ep; ep++) { 187491040Sarr cp = ep; 187591040Sarr /* find the end of this component */ 187691040Sarr for (; *ep != 0 && *ep != ';'; ep++); 187791040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 187891040Sarr if (result != NULL) 187991040Sarr return (result); 188091040Sarr } 188191040Sarr return (NULL); 188240159Speter} 188359751Speter 188459751Speterstatic const char * 188591040Sarrlinker_basename(const char *path) 188659751Speter{ 188791040Sarr const char *filename; 188859751Speter 188991040Sarr filename = rindex(path, '/'); 189091040Sarr if (filename == NULL) 189191040Sarr return path; 189291040Sarr if (filename[1]) 189391040Sarr filename++; 189491040Sarr return (filename); 189559751Speter} 189659751Speter 1897157144Sjkoshy#ifdef HWPMC_HOOKS 1898157144Sjkoshy 1899159797Sjhbstruct hwpmc_context { 1900159797Sjhb int nobjects; 1901159797Sjhb int nmappings; 1902159797Sjhb struct pmckern_map_in *kobase; 1903159797Sjhb}; 1904159797Sjhb 1905159797Sjhbstatic int 1906159797Sjhblinker_hwpmc_list_object(linker_file_t lf, void *arg) 1907159797Sjhb{ 1908159797Sjhb struct hwpmc_context *hc; 1909159797Sjhb 1910159797Sjhb hc = arg; 1911159797Sjhb 1912159797Sjhb /* If we run out of mappings, fail. */ 1913159797Sjhb if (hc->nobjects >= hc->nmappings) 1914159797Sjhb return (1); 1915159797Sjhb 1916159797Sjhb /* Save the info for this linker file. */ 1917159797Sjhb hc->kobase[hc->nobjects].pm_file = lf->filename; 1918159797Sjhb hc->kobase[hc->nobjects].pm_address = (uintptr_t)lf->address; 1919159797Sjhb hc->nobjects++; 1920159797Sjhb return (0); 1921159797Sjhb} 1922159797Sjhb 192359751Speter/* 1924157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1925157144Sjkoshy */ 1926157144Sjkoshyvoid * 1927157144Sjkoshylinker_hwpmc_list_objects(void) 1928157144Sjkoshy{ 1929159797Sjhb struct hwpmc_context hc; 1930157144Sjkoshy 1931159797Sjhb hc.nmappings = 15; /* a reasonable default */ 1932157144Sjkoshy 1933157144Sjkoshy retry: 1934157144Sjkoshy /* allocate nmappings+1 entries */ 1935184214Sdes hc.kobase = malloc((hc.nmappings + 1) * sizeof(struct pmckern_map_in), 1936184214Sdes M_LINKER, M_WAITOK | M_ZERO); 1937157144Sjkoshy 1938159797Sjhb hc.nobjects = 0; 1939159797Sjhb if (linker_file_foreach(linker_hwpmc_list_object, &hc) != 0) { 1940159797Sjhb hc.nmappings = hc.nobjects; 1941184205Sdes free(hc.kobase, M_LINKER); 1942157144Sjkoshy goto retry; 1943157144Sjkoshy } 1944157144Sjkoshy 1945159797Sjhb KASSERT(hc.nobjects > 0, ("linker_hpwmc_list_objects: no kernel " 1946159797Sjhb "objects?")); 1947157144Sjkoshy 1948157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1949159797Sjhb KASSERT(hc.kobase[hc.nobjects].pm_file == NULL, 1950157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1951157144Sjkoshy 1952159797Sjhb return ((void *)hc.kobase); 1953157144Sjkoshy} 1954157144Sjkoshy#endif 1955157144Sjkoshy 1956157144Sjkoshy/* 195791040Sarr * Find a file which contains given module and load it, if "parent" is not 195891040Sarr * NULL, register a reference to it. 195959751Speter */ 1960159796Sjhbstatic int 196183321Speterlinker_load_module(const char *kldname, const char *modname, 196291040Sarr struct linker_file *parent, struct mod_depend *verinfo, 196391040Sarr struct linker_file **lfpp) 196459751Speter{ 196591040Sarr linker_file_t lfdep; 196691040Sarr const char *filename; 196791040Sarr char *pathname; 196891040Sarr int error; 196959751Speter 1970159845Sjhb KLD_LOCK_ASSERT(); 197191040Sarr if (modname == NULL) { 197291040Sarr /* 197391040Sarr * We have to load KLD 197491040Sarr */ 197591068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 197691068Sarr " is not NULL")); 197791040Sarr pathname = linker_search_kld(kldname); 197891040Sarr } else { 197991040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 198091040Sarr return (EEXIST); 198194322Sbrian if (kldname != NULL) 198294322Sbrian pathname = linker_strdup(kldname); 198395488Sbrian else if (rootvnode == NULL) 198494322Sbrian pathname = NULL; 198594322Sbrian else 198691040Sarr /* 198791040Sarr * Need to find a KLD with required module 198891040Sarr */ 198991040Sarr pathname = linker_search_module(modname, 199091040Sarr strlen(modname), verinfo); 199191040Sarr } 199291040Sarr if (pathname == NULL) 199391040Sarr return (ENOENT); 199491040Sarr 199583321Speter /* 199691040Sarr * Can't load more than one file with the same basename XXX: 199791040Sarr * Actually it should be possible to have multiple KLDs with 199891040Sarr * the same basename but different path because they can 199991040Sarr * provide different versions of the same modules. 200083321Speter */ 200191040Sarr filename = linker_basename(pathname); 2002159792Sjhb if (linker_find_file_by_name(filename)) 200391040Sarr error = EEXIST; 2004159792Sjhb else do { 200591040Sarr error = linker_load_file(pathname, &lfdep); 200691040Sarr if (error) 200791040Sarr break; 200891040Sarr if (modname && verinfo && 200991040Sarr modlist_lookup2(modname, verinfo) == NULL) { 2010132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 201191040Sarr error = ENOENT; 201291040Sarr break; 201391040Sarr } 201491040Sarr if (parent) { 201591040Sarr error = linker_file_add_dependency(parent, lfdep); 201691040Sarr if (error) 201791040Sarr break; 201891040Sarr } 201991040Sarr if (lfpp) 202091040Sarr *lfpp = lfdep; 202191040Sarr } while (0); 2022159791Sjhb free(pathname, M_LINKER); 202391040Sarr return (error); 202459751Speter} 202559751Speter 202659751Speter/* 202791040Sarr * This routine is responsible for finding dependencies of userland initiated 202891040Sarr * kldload(2)'s of files. 202959751Speter */ 203059751Speterint 203186469Siedowselinker_load_dependencies(linker_file_t lf) 203259751Speter{ 203391040Sarr linker_file_t lfdep; 203491040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 203591040Sarr struct mod_metadata *mp, *nmp; 203691040Sarr struct mod_depend *verinfo; 203791040Sarr modlist_t mod; 203891040Sarr const char *modname, *nmodname; 203992032Sdwmalone int ver, error = 0, count; 204059751Speter 204191040Sarr /* 204291040Sarr * All files are dependant on /kernel. 204391040Sarr */ 2044159845Sjhb KLD_LOCK_ASSERT(); 204591040Sarr if (linker_kernel_file) { 204691040Sarr linker_kernel_file->refs++; 204791040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 204891040Sarr if (error) 204991040Sarr return (error); 205059751Speter } 205191040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 205291040Sarr &count) != 0) 205391040Sarr return (0); 205491040Sarr for (mdp = start; mdp < stop; mdp++) { 2055109605Sjake mp = *mdp; 205691040Sarr if (mp->md_type != MDT_VERSION) 205791040Sarr continue; 2058109605Sjake modname = mp->md_cval; 2059109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 206091040Sarr mod = modlist_lookup(modname, ver); 206191040Sarr if (mod != NULL) { 206291040Sarr printf("interface %s.%d already present in the KLD" 206391040Sarr " '%s'!\n", modname, ver, 206491040Sarr mod->container->filename); 206591040Sarr return (EEXIST); 206691040Sarr } 206791040Sarr } 206874642Sbp 206991040Sarr for (mdp = start; mdp < stop; mdp++) { 2070109605Sjake mp = *mdp; 207191040Sarr if (mp->md_type != MDT_DEPEND) 207291040Sarr continue; 2073109605Sjake modname = mp->md_cval; 2074109605Sjake verinfo = mp->md_data; 207591040Sarr nmodname = NULL; 207691040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 2077109605Sjake nmp = *nmdp; 207891040Sarr if (nmp->md_type != MDT_VERSION) 207991040Sarr continue; 2080109605Sjake nmodname = nmp->md_cval; 208192032Sdwmalone if (strcmp(modname, nmodname) == 0) 208291040Sarr break; 208391040Sarr } 208491040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 208591040Sarr continue; 208691040Sarr mod = modlist_lookup2(modname, verinfo); 208791040Sarr if (mod) { /* woohoo, it's loaded already */ 208891040Sarr lfdep = mod->container; 208991040Sarr lfdep->refs++; 209091040Sarr error = linker_file_add_dependency(lf, lfdep); 209191040Sarr if (error) 209291040Sarr break; 209391040Sarr continue; 209491040Sarr } 209591040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 209691040Sarr if (error) { 209791040Sarr printf("KLD %s: depends on %s - not available\n", 209891040Sarr lf->filename, modname); 209991040Sarr break; 210091040Sarr } 210159751Speter } 210259751Speter 210391040Sarr if (error) 210491040Sarr return (error); 210591040Sarr linker_addmodules(lf, start, stop, 0); 210691040Sarr return (error); 210759751Speter} 210885736Sgreen 210985736Sgreenstatic int 211085736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 211185736Sgreen{ 211285736Sgreen struct sysctl_req *req; 211385736Sgreen 211485736Sgreen req = opaque; 211585736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 211685736Sgreen} 211785736Sgreen 211885736Sgreen/* 211985736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 212085736Sgreen * in the kernel. 212185736Sgreen */ 212285736Sgreenstatic int 212385736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 212485736Sgreen{ 212585736Sgreen linker_file_t lf; 212685736Sgreen int error; 212785736Sgreen 2128107089Srwatson#ifdef MAC 2129172930Srwatson error = mac_kld_check_stat(req->td->td_ucred); 2130107089Srwatson if (error) 2131107089Srwatson return (error); 2132107089Srwatson#endif 2133126253Struckman error = sysctl_wire_old_buffer(req, 0); 2134126253Struckman if (error != 0) 2135126253Struckman return (error); 2136159845Sjhb KLD_LOCK(); 213785736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 213885736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 213985736Sgreen sysctl_kern_function_list_iterate, req); 214098452Sarr if (error) { 2141159845Sjhb KLD_UNLOCK(); 214285736Sgreen return (error); 214398452Sarr } 214485736Sgreen } 2145159845Sjhb KLD_UNLOCK(); 214685736Sgreen return (SYSCTL_OUT(req, "", 1)); 214785736Sgreen} 214885736Sgreen 214985736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 215091040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 2151