kern_linker.c revision 199457
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 199457 2009-11-17 21:56:12Z gonzo $"); 29116182Sobrien 3040159Speter#include "opt_ddb.h" 31157144Sjkoshy#include "opt_hwpmc_hooks.h" 3240159Speter 3325537Sdfr#include <sys/param.h> 3425537Sdfr#include <sys/kernel.h> 3525537Sdfr#include <sys/systm.h> 3625537Sdfr#include <sys/malloc.h> 3725537Sdfr#include <sys/sysproto.h> 3825537Sdfr#include <sys/sysent.h> 39164033Srwatson#include <sys/priv.h> 4025537Sdfr#include <sys/proc.h> 4125537Sdfr#include <sys/lock.h> 4282749Sdillon#include <sys/mutex.h> 4392547Sarr#include <sys/sx.h> 4425537Sdfr#include <sys/module.h> 45159808Sjhb#include <sys/mount.h> 4625537Sdfr#include <sys/linker.h> 4740159Speter#include <sys/fcntl.h> 48192895Sjamie#include <sys/jail.h> 4940159Speter#include <sys/libkern.h> 5040159Speter#include <sys/namei.h> 5140159Speter#include <sys/vnode.h> 52159588Sjhb#include <sys/syscallsubr.h> 5340159Speter#include <sys/sysctl.h> 5425537Sdfr 55196019Srwatson#include <net/vnet.h> 56196019Srwatson 57163606Srwatson#include <security/mac/mac_framework.h> 58163606Srwatson 5959603Sdfr#include "linker_if.h" 6059603Sdfr 61157144Sjkoshy#ifdef HWPMC_HOOKS 62157144Sjkoshy#include <sys/pmckern.h> 63157144Sjkoshy#endif 64157144Sjkoshy 6540961Speter#ifdef KLD_DEBUG 6640961Speterint kld_debug = 0; 67199457SgonzoSYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RW, 68199457Sgonzo &kld_debug, 0, "Set various levels of KLD debug"); 6940961Speter#endif 7040961Speter 71160142Sjhb#define KLD_LOCK() sx_xlock(&kld_sx) 72160142Sjhb#define KLD_UNLOCK() sx_xunlock(&kld_sx) 73159845Sjhb#define KLD_LOCKED() sx_xlocked(&kld_sx) 74160142Sjhb#define KLD_LOCK_ASSERT() do { \ 75160142Sjhb if (!cold) \ 76160142Sjhb sx_assert(&kld_sx, SX_XLOCKED); \ 77160142Sjhb} while (0) 78159845Sjhb 7991040Sarr/* 8091040Sarr * static char *linker_search_path(const char *name, struct mod_depend 8191040Sarr * *verinfo); 8291040Sarr */ 8391040Sarrstatic const char *linker_basename(const char *path); 8459751Speter 85159800Sjhb/* 86159800Sjhb * Find a currently loaded file given its filename. 87159800Sjhb */ 88159800Sjhbstatic linker_file_t linker_find_file_by_name(const char* _filename); 89159800Sjhb 90159800Sjhb/* 91159800Sjhb * Find a currently loaded file given its file id. 92159800Sjhb */ 93159800Sjhbstatic linker_file_t linker_find_file_by_id(int _fileid); 94159800Sjhb 9578161Speter/* Metadata from the static kernel */ 9678161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 9778161Speter 9859751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 9959751Speter 10040906Speterlinker_file_t linker_kernel_file; 10131324Sbde 102159845Sjhbstatic struct sx kld_sx; /* kernel linker lock */ 10398452Sarr 104172862Sjb/* 105172862Sjb * Load counter used by clients to determine if a linker file has been 106172862Sjb * re-loaded. This counter is incremented for each file load. 107172862Sjb */ 108172862Sjbstatic int loadcnt; 109172862Sjb 11025537Sdfrstatic linker_class_list_t classes; 11150068Sgrogstatic linker_file_list_t linker_files; 11225537Sdfrstatic int next_file_id = 1; 11398452Sarrstatic int linker_no_more_classes = 0; 11425537Sdfr 11586553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 11691040Sarr linker_file_t lftmp; \ 11786553Sarr \ 118159845Sjhb KLD_LOCK_ASSERT(); \ 11986553Sarrretry: \ 12091040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 12191040Sarr if (next_file_id == lftmp->id) { \ 12291040Sarr next_file_id++; \ 12391040Sarr goto retry; \ 12491040Sarr } \ 12591040Sarr } \ 12691040Sarr (a) = next_file_id; \ 12786553Sarr} while(0) 12886553Sarr 12986553Sarr 13059751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 13160938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 13259751Speterstruct modlist { 13391040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 13491040Sarr linker_file_t container; 13591040Sarr const char *name; 13691040Sarr int version; 13759751Speter}; 13891040Sarrtypedef struct modlist *modlist_t; 13991040Sarrstatic modlisthead_t found_modules; 14059751Speter 141159796Sjhbstatic int linker_file_add_dependency(linker_file_t file, 142159796Sjhb linker_file_t dep); 143159845Sjhbstatic caddr_t linker_file_lookup_symbol_internal(linker_file_t file, 144159845Sjhb const char* name, int deps); 145159796Sjhbstatic int linker_load_module(const char *kldname, 146159796Sjhb const char *modname, struct linker_file *parent, 147159796Sjhb struct mod_depend *verinfo, struct linker_file **lfpp); 148159796Sjhbstatic modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); 14994321Sbrian 15059603Sdfrstatic char * 15159603Sdfrlinker_strdup(const char *str) 15259603Sdfr{ 15391040Sarr char *result; 15459603Sdfr 155111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 15691040Sarr strcpy(result, str); 15791040Sarr return (result); 15859603Sdfr} 15959603Sdfr 16025537Sdfrstatic void 16191040Sarrlinker_init(void *arg) 16225537Sdfr{ 16391040Sarr 164159845Sjhb sx_init(&kld_sx, "kernel linker"); 16591040Sarr TAILQ_INIT(&classes); 16691040Sarr TAILQ_INIT(&linker_files); 16725537Sdfr} 16825537Sdfr 169177253SrwatsonSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 17025537Sdfr 17198452Sarrstatic void 17298452Sarrlinker_stop_class_add(void *arg) 17398452Sarr{ 17498452Sarr 17598452Sarr linker_no_more_classes = 1; 17698452Sarr} 17798452Sarr 178177253SrwatsonSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL); 17998452Sarr 18025537Sdfrint 18159603Sdfrlinker_add_class(linker_class_t lc) 18225537Sdfr{ 18391040Sarr 18498452Sarr /* 185144443Sjhb * We disallow any class registration past SI_ORDER_ANY 186144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 187144443Sjhb * ops from being freed. 18898452Sarr */ 18998452Sarr if (linker_no_more_classes == 1) 19098452Sarr return (EPERM); 19191040Sarr kobj_class_compile((kobj_class_t) lc); 192144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 19391040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 19491040Sarr return (0); 19525537Sdfr} 19625537Sdfr 19725537Sdfrstatic void 19825537Sdfrlinker_file_sysinit(linker_file_t lf) 19925537Sdfr{ 20091040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 20125537Sdfr 20291040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 20391040Sarr lf->filename)); 20425537Sdfr 20591040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 20691040Sarr return; 20791040Sarr /* 20891040Sarr * Perform a bubble sort of the system initialization objects by 20991040Sarr * their subsystem (primary key) and order (secondary key). 210159840Sjhb * 21191040Sarr * Since some things care about execution order, this is the operation 21291040Sarr * which ensures continued function. 21391040Sarr */ 21491040Sarr for (sipp = start; sipp < stop; sipp++) { 21591040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 21691040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 21791040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 21891040Sarr (*sipp)->order <= (*xipp)->order)) 21991040Sarr continue; /* skip */ 22091040Sarr save = *sipp; 22191040Sarr *sipp = *xipp; 22291040Sarr *xipp = save; 22391040Sarr } 22425537Sdfr } 22525537Sdfr 22691040Sarr /* 22791040Sarr * Traverse the (now) ordered list of system initialization tasks. 22891040Sarr * Perform each task, and continue on to the next task. 22991040Sarr */ 230160142Sjhb mtx_lock(&Giant); 23191040Sarr for (sipp = start; sipp < stop; sipp++) { 23291040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 23391040Sarr continue; /* skip dummy task(s) */ 23425537Sdfr 23591040Sarr /* Call function */ 23691040Sarr (*((*sipp)->func)) ((*sipp)->udata); 23791040Sarr } 238160142Sjhb mtx_unlock(&Giant); 23925537Sdfr} 24025537Sdfr 24141055Speterstatic void 24241055Speterlinker_file_sysuninit(linker_file_t lf) 24341055Speter{ 24491040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 24541055Speter 24691040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 24791040Sarr lf->filename)); 24841055Speter 24991068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 25091040Sarr NULL) != 0) 25191040Sarr return; 25241055Speter 25391040Sarr /* 25491040Sarr * Perform a reverse bubble sort of the system initialization objects 25591040Sarr * by their subsystem (primary key) and order (secondary key). 256159840Sjhb * 25791040Sarr * Since some things care about execution order, this is the operation 25891040Sarr * which ensures continued function. 25991040Sarr */ 26091040Sarr for (sipp = start; sipp < stop; sipp++) { 26191040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 26291040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 26391040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 26491040Sarr (*sipp)->order >= (*xipp)->order)) 26591040Sarr continue; /* skip */ 26691040Sarr save = *sipp; 26791040Sarr *sipp = *xipp; 26891040Sarr *xipp = save; 26991040Sarr } 27041055Speter } 27141055Speter 27291040Sarr /* 27391040Sarr * Traverse the (now) ordered list of system initialization tasks. 27491040Sarr * Perform each task, and continue on to the next task. 27591040Sarr */ 276160142Sjhb mtx_lock(&Giant); 27791040Sarr for (sipp = start; sipp < stop; sipp++) { 27891040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 27991040Sarr continue; /* skip dummy task(s) */ 28041055Speter 28191040Sarr /* Call function */ 28291040Sarr (*((*sipp)->func)) ((*sipp)->udata); 28391040Sarr } 284160142Sjhb mtx_unlock(&Giant); 28541055Speter} 28641055Speter 28744078Sdfrstatic void 28844078Sdfrlinker_file_register_sysctls(linker_file_t lf) 28944078Sdfr{ 29091040Sarr struct sysctl_oid **start, **stop, **oidp; 29144078Sdfr 29291040Sarr KLD_DPF(FILE, 29391040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 29491040Sarr lf->filename)); 29544078Sdfr 29691040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 29791040Sarr return; 29844078Sdfr 299188232Sjhb sysctl_lock(); 30091040Sarr for (oidp = start; oidp < stop; oidp++) 30191040Sarr sysctl_register_oid(*oidp); 302188232Sjhb sysctl_unlock(); 30344078Sdfr} 30444078Sdfr 30544078Sdfrstatic void 30644078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 30744078Sdfr{ 30891040Sarr struct sysctl_oid **start, **stop, **oidp; 30944078Sdfr 31091040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 31191040Sarr " for %s\n", lf->filename)); 31244078Sdfr 31391040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 31491040Sarr return; 31544078Sdfr 316188232Sjhb sysctl_lock(); 31791040Sarr for (oidp = start; oidp < stop; oidp++) 31891040Sarr sysctl_unregister_oid(*oidp); 319188232Sjhb sysctl_unlock(); 32044078Sdfr} 32144078Sdfr 32259751Speterstatic int 32359751Speterlinker_file_register_modules(linker_file_t lf) 32459751Speter{ 32591040Sarr struct mod_metadata **start, **stop, **mdp; 32691040Sarr const moduledata_t *moddata; 327146733Spjd int first_error, error; 32859751Speter 32991040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 33091040Sarr " in %s\n", lf->filename)); 33159751Speter 33291068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 333159841Sjhb &stop, NULL) != 0) { 33491040Sarr /* 33591040Sarr * This fallback should be unnecessary, but if we get booted 33691040Sarr * from boot2 instead of loader and we are missing our 33791040Sarr * metadata then we have to try the best we can. 33891040Sarr */ 33991040Sarr if (lf == linker_kernel_file) { 34091040Sarr start = SET_BEGIN(modmetadata_set); 34191040Sarr stop = SET_LIMIT(modmetadata_set); 34291040Sarr } else 34391040Sarr return (0); 34478161Speter } 345146733Spjd first_error = 0; 34691040Sarr for (mdp = start; mdp < stop; mdp++) { 34791040Sarr if ((*mdp)->md_type != MDT_MODULE) 34891040Sarr continue; 34991040Sarr moddata = (*mdp)->md_data; 35091040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 35191040Sarr moddata->name, lf->filename)); 35291040Sarr error = module_register(moddata, lf); 353146730Spjd if (error) { 35491068Sarr printf("Module %s failed to register: %d\n", 35591040Sarr moddata->name, error); 356146733Spjd if (first_error == 0) 357146733Spjd first_error = error; 358146730Spjd } 35959751Speter } 360146733Spjd return (first_error); 36159751Speter} 36259751Speter 36359751Speterstatic void 36459751Speterlinker_init_kernel_modules(void) 36559751Speter{ 36691040Sarr 36791040Sarr linker_file_register_modules(linker_kernel_file); 36859751Speter} 36959751Speter 370177253SrwatsonSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 371177253Srwatson 0); 37259751Speter 373101241Smuxstatic int 37491040Sarrlinker_load_file(const char *filename, linker_file_t *result) 37525537Sdfr{ 37691040Sarr linker_class_t lc; 37791040Sarr linker_file_t lf; 378159585Sjhb int foundfile, error; 37925537Sdfr 38091040Sarr /* Refuse to load modules if securelevel raised */ 381192895Sjamie if (prison0.pr_securelevel > 0) 38291040Sarr return (EPERM); 38362261Sarchie 384159845Sjhb KLD_LOCK_ASSERT(); 38591040Sarr lf = linker_find_file_by_name(filename); 38691040Sarr if (lf) { 38791040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 38891040Sarr " incrementing refs\n", filename)); 38991040Sarr *result = lf; 39091040Sarr lf->refs++; 391159585Sjhb return (0); 39291040Sarr } 39391040Sarr foundfile = 0; 394159585Sjhb error = 0; 39598452Sarr 39698452Sarr /* 39798452Sarr * We do not need to protect (lock) classes here because there is 39898452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 39998452Sarr * and there is no class deregistration mechanism at this time. 40098452Sarr */ 40191040Sarr TAILQ_FOREACH(lc, &classes, link) { 40291040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 40391040Sarr filename)); 40491040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 40591040Sarr /* 40691040Sarr * If we got something other than ENOENT, then it exists but 40791040Sarr * we cannot load it for some other reason. 40891040Sarr */ 40991040Sarr if (error != ENOENT) 41091040Sarr foundfile = 1; 41191040Sarr if (lf) { 412146730Spjd error = linker_file_register_modules(lf); 413146730Spjd if (error == EEXIST) { 414146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 415159585Sjhb return (error); 416146730Spjd } 417166921Sjhb KLD_UNLOCK(); 41891040Sarr linker_file_register_sysctls(lf); 41991040Sarr linker_file_sysinit(lf); 420166921Sjhb KLD_LOCK(); 42191040Sarr lf->flags |= LINKER_FILE_LINKED; 42291040Sarr *result = lf; 423159585Sjhb return (0); 42491040Sarr } 42591040Sarr } 42642755Speter /* 42791040Sarr * Less than ideal, but tells the user whether it failed to load or 42891040Sarr * the module was not found. 42942755Speter */ 430105337Ssam if (foundfile) { 431188440Sattilio 432105337Ssam /* 433188440Sattilio * If the file type has not been recognized by the last try 434188440Sattilio * printout a message before to fail. 435188440Sattilio */ 436188440Sattilio if (error == ENOSYS) 437188440Sattilio printf("linker_load_file: Unsupported file type\n"); 438188440Sattilio 439188440Sattilio /* 440105337Ssam * Format not recognized or otherwise unloadable. 441105337Ssam * When loading a module that is statically built into 442105337Ssam * the kernel EEXIST percolates back up as the return 443105337Ssam * value. Preserve this so that apps like sysinstall 444105337Ssam * can recognize this special case and not post bogus 445105337Ssam * dialog boxes. 446105337Ssam */ 447105337Ssam if (error != EEXIST) 448105337Ssam error = ENOEXEC; 449105337Ssam } else 45091068Sarr error = ENOENT; /* Nothing found */ 45191040Sarr return (error); 45225537Sdfr} 45325537Sdfr 45478413Sbrianint 45594321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 45694321Sbrian linker_file_t *result) 45778413Sbrian{ 45894321Sbrian modlist_t mod; 459159804Sjhb int error; 46094321Sbrian 461159845Sjhb KLD_LOCK(); 46294321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 46394321Sbrian *result = mod->container; 46494321Sbrian (*result)->refs++; 465159845Sjhb KLD_UNLOCK(); 46694321Sbrian return (0); 46794321Sbrian } 46894321Sbrian 469159804Sjhb error = linker_load_module(NULL, modname, NULL, verinfo, result); 470159845Sjhb KLD_UNLOCK(); 471159804Sjhb return (error); 47278413Sbrian} 47378413Sbrian 474159804Sjhbint 475159804Sjhblinker_release_module(const char *modname, struct mod_depend *verinfo, 476159804Sjhb linker_file_t lf) 477159804Sjhb{ 478159804Sjhb modlist_t mod; 479159804Sjhb int error; 480159804Sjhb 481159845Sjhb KLD_LOCK(); 482159804Sjhb if (lf == NULL) { 483159804Sjhb KASSERT(modname != NULL, 484159804Sjhb ("linker_release_module: no file or name")); 485159804Sjhb mod = modlist_lookup2(modname, verinfo); 486159804Sjhb if (mod == NULL) { 487159845Sjhb KLD_UNLOCK(); 488159804Sjhb return (ESRCH); 489159804Sjhb } 490159804Sjhb lf = mod->container; 491159804Sjhb } else 492159804Sjhb KASSERT(modname == NULL && verinfo == NULL, 493159804Sjhb ("linker_release_module: both file and name")); 494159804Sjhb error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL); 495159845Sjhb KLD_UNLOCK(); 496159804Sjhb return (error); 497159804Sjhb} 498159804Sjhb 499159800Sjhbstatic linker_file_t 50091040Sarrlinker_find_file_by_name(const char *filename) 50125537Sdfr{ 502159585Sjhb linker_file_t lf; 50391040Sarr char *koname; 50425537Sdfr 505111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 50691040Sarr sprintf(koname, "%s.ko", filename); 50740861Speter 508159845Sjhb KLD_LOCK_ASSERT(); 50991040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 51092032Sdwmalone if (strcmp(lf->filename, koname) == 0) 51191040Sarr break; 51292032Sdwmalone if (strcmp(lf->filename, filename) == 0) 51391040Sarr break; 51491040Sarr } 515159585Sjhb free(koname, M_LINKER); 51691040Sarr return (lf); 51725537Sdfr} 51825537Sdfr 519159800Sjhbstatic linker_file_t 52025537Sdfrlinker_find_file_by_id(int fileid) 52125537Sdfr{ 522159585Sjhb linker_file_t lf; 523159845Sjhb 524159845Sjhb KLD_LOCK_ASSERT(); 52591040Sarr TAILQ_FOREACH(lf, &linker_files, link) 526166921Sjhb if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED) 52791040Sarr break; 52891040Sarr return (lf); 52925537Sdfr} 53025537Sdfr 531159797Sjhbint 532159797Sjhblinker_file_foreach(linker_predicate_t *predicate, void *context) 533159797Sjhb{ 534159797Sjhb linker_file_t lf; 535159797Sjhb int retval = 0; 536159797Sjhb 537159845Sjhb KLD_LOCK(); 538159797Sjhb TAILQ_FOREACH(lf, &linker_files, link) { 539159797Sjhb retval = predicate(lf, context); 540159797Sjhb if (retval != 0) 541159797Sjhb break; 542159797Sjhb } 543159845Sjhb KLD_UNLOCK(); 544159797Sjhb return (retval); 545159797Sjhb} 546159797Sjhb 54725537Sdfrlinker_file_t 54891040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 54925537Sdfr{ 55091040Sarr linker_file_t lf; 55191040Sarr const char *filename; 55225537Sdfr 553159845Sjhb KLD_LOCK_ASSERT(); 55491040Sarr filename = linker_basename(pathname); 55540159Speter 556172862Sjb KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname)); 557111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 55891040Sarr if (lf == NULL) 559159585Sjhb return (NULL); 56091040Sarr lf->refs = 1; 56191040Sarr lf->userrefs = 0; 56291040Sarr lf->flags = 0; 56391040Sarr lf->filename = linker_strdup(filename); 564172862Sjb lf->pathname = linker_strdup(pathname); 56591040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 56691040Sarr lf->ndeps = 0; 56791040Sarr lf->deps = NULL; 568172862Sjb lf->loadcnt = ++loadcnt; 569172862Sjb lf->sdt_probes = NULL; 570172862Sjb lf->sdt_nprobes = 0; 57191040Sarr STAILQ_INIT(&lf->common); 57291040Sarr TAILQ_INIT(&lf->modules); 57391040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 57491040Sarr return (lf); 57525537Sdfr} 57625537Sdfr 57725537Sdfrint 578132117Sphklinker_file_unload(linker_file_t file, int flags) 57925537Sdfr{ 58091040Sarr module_t mod, next; 58191040Sarr modlist_t ml, nextml; 58291040Sarr struct common_symbol *cp; 58391040Sarr int error, i; 58425537Sdfr 58591040Sarr /* Refuse to unload modules if securelevel raised. */ 586192895Sjamie if (prison0.pr_securelevel > 0) 58791040Sarr return (EPERM); 58825537Sdfr 589159845Sjhb KLD_LOCK_ASSERT(); 59091040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 59191040Sarr 592159584Sjhb /* Easy case of just dropping a reference. */ 593159584Sjhb if (file->refs > 1) { 594159584Sjhb file->refs--; 595159584Sjhb return (0); 596159584Sjhb } 597159584Sjhb 598159584Sjhb KLD_DPF(FILE, ("linker_file_unload: file is unloading," 599159584Sjhb " informing modules\n")); 600159584Sjhb 601159584Sjhb /* 602185635Sjhb * Quiesce all the modules to give them a chance to veto the unload. 603159584Sjhb */ 604185635Sjhb MOD_SLOCK; 605185635Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; 606185635Sjhb mod = module_getfnext(mod)) { 607185635Sjhb 608185635Sjhb error = module_quiesce(mod); 609185635Sjhb if (error != 0 && flags != LINKER_UNLOAD_FORCE) { 610185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 611185635Sjhb " vetoed unload\n", module_getname(mod))); 612185635Sjhb /* 613185635Sjhb * XXX: Do we need to tell all the quiesced modules 614185635Sjhb * that they can resume work now via a new module 615185635Sjhb * event? 616185635Sjhb */ 617185635Sjhb MOD_SUNLOCK; 618185635Sjhb return (error); 619185635Sjhb } 620185635Sjhb } 621185635Sjhb MOD_SUNLOCK; 622185635Sjhb 623185635Sjhb /* 624185635Sjhb * Inform any modules associated with this file that they are 625185635Sjhb * being be unloaded. 626185635Sjhb */ 627159584Sjhb MOD_XLOCK; 628159584Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 629159584Sjhb next = module_getfnext(mod); 630159584Sjhb MOD_XUNLOCK; 631159584Sjhb 63291040Sarr /* 633159584Sjhb * Give the module a chance to veto the unload. 63491040Sarr */ 635185635Sjhb if ((error = module_unload(mod)) != 0) { 636185635Sjhb KLD_DPF(FILE, ("linker_file_unload: module %s" 637199457Sgonzo " failed unload\n", module_getname(mod))); 638159584Sjhb return (error); 639159584Sjhb } 64092547Sarr MOD_XLOCK; 641159584Sjhb module_release(mod); 642159584Sjhb } 643159584Sjhb MOD_XUNLOCK; 64491040Sarr 645159586Sjhb TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml) { 646128057Speadar if (ml->container == file) { 64791040Sarr TAILQ_REMOVE(&found_modules, ml, link); 648128057Speadar free(ml, M_LINKER); 649128057Speadar } 65091040Sarr } 65125537Sdfr 652159840Sjhb /* 653159840Sjhb * Don't try to run SYSUNINITs if we are unloaded due to a 65491040Sarr * link error. 65591040Sarr */ 65691040Sarr if (file->flags & LINKER_FILE_LINKED) { 657188209Sjhb file->flags &= ~LINKER_FILE_LINKED; 658188209Sjhb KLD_UNLOCK(); 65991040Sarr linker_file_sysuninit(file); 66091040Sarr linker_file_unregister_sysctls(file); 661188209Sjhb KLD_LOCK(); 66225537Sdfr } 66391040Sarr TAILQ_REMOVE(&linker_files, file, link); 66425537Sdfr 66591040Sarr if (file->deps) { 66691040Sarr for (i = 0; i < file->ndeps; i++) 667132117Sphk linker_file_unload(file->deps[i], flags); 66891040Sarr free(file->deps, M_LINKER); 66991040Sarr file->deps = NULL; 67059751Speter } 671160245Sjhb while ((cp = STAILQ_FIRST(&file->common)) != NULL) { 672160245Sjhb STAILQ_REMOVE_HEAD(&file->common, link); 67391040Sarr free(cp, M_LINKER); 67491040Sarr } 67559751Speter 67691040Sarr LINKER_UNLOAD(file); 67791040Sarr if (file->filename) { 67891040Sarr free(file->filename, M_LINKER); 67991040Sarr file->filename = NULL; 68091040Sarr } 681172862Sjb if (file->pathname) { 682172862Sjb free(file->pathname, M_LINKER); 683172862Sjb file->pathname = NULL; 684172862Sjb } 68591040Sarr kobj_delete((kobj_t) file, M_LINKER); 686159584Sjhb return (0); 68725537Sdfr} 68825537Sdfr 689179238Sjbint 690179238Sjblinker_ctf_get(linker_file_t file, linker_ctf_t *lc) 691179238Sjb{ 692179238Sjb return (LINKER_CTF_GET(file, lc)); 693179238Sjb} 694179238Sjb 695159796Sjhbstatic int 69686469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 69725537Sdfr{ 69891040Sarr linker_file_t *newdeps; 69925537Sdfr 700159845Sjhb KLD_LOCK_ASSERT(); 70191040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 702111119Simp M_LINKER, M_WAITOK | M_ZERO); 70391040Sarr if (newdeps == NULL) 70491040Sarr return (ENOMEM); 70525537Sdfr 70691040Sarr if (file->deps) { 70791040Sarr bcopy(file->deps, newdeps, 70891040Sarr file->ndeps * sizeof(linker_file_t *)); 70991040Sarr free(file->deps, M_LINKER); 71091040Sarr } 71191040Sarr file->deps = newdeps; 71291040Sarr file->deps[file->ndeps] = dep; 71391040Sarr file->ndeps++; 714199457Sgonzo KLD_DPF(FILE, ("linker_file_add_dependency:" 715199457Sgonzo " adding %s as dependency for %s\n", 716199457Sgonzo dep->filename, file->filename)); 71791040Sarr return (0); 71825537Sdfr} 71925537Sdfr 72078161Speter/* 72191040Sarr * Locate a linker set and its contents. This is a helper function to avoid 722159841Sjhb * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. 723159841Sjhb * This function is used in this file so we can avoid having lots of (void **) 724159841Sjhb * casts. 72578161Speter */ 72678161Speterint 72778161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 72891040Sarr void *firstp, void *lastp, int *countp) 72978161Speter{ 730159845Sjhb int error, locked; 73178161Speter 732159845Sjhb locked = KLD_LOCKED(); 733159845Sjhb if (!locked) 734159845Sjhb KLD_LOCK(); 735159845Sjhb error = LINKER_LOOKUP_SET(file, name, firstp, lastp, countp); 736159845Sjhb if (!locked) 737159845Sjhb KLD_UNLOCK(); 738159845Sjhb return (error); 73978161Speter} 74078161Speter 741173714Sjb/* 742173714Sjb * List all functions in a file. 743173714Sjb */ 744173714Sjbint 745173714Sjblinker_file_function_listall(linker_file_t lf, 746179238Sjb linker_function_nameval_callback_t callback_func, void *arg) 747173714Sjb{ 748173714Sjb return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); 749173714Sjb} 750173714Sjb 75125537Sdfrcaddr_t 75291040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 75325537Sdfr{ 754159845Sjhb caddr_t sym; 755159845Sjhb int locked; 756159845Sjhb 757159845Sjhb locked = KLD_LOCKED(); 758159845Sjhb if (!locked) 759159845Sjhb KLD_LOCK(); 760159845Sjhb sym = linker_file_lookup_symbol_internal(file, name, deps); 761159845Sjhb if (!locked) 762159845Sjhb KLD_UNLOCK(); 763159845Sjhb return (sym); 764159845Sjhb} 765159845Sjhb 766159845Sjhbstatic caddr_t 767159845Sjhblinker_file_lookup_symbol_internal(linker_file_t file, const char *name, 768159845Sjhb int deps) 769159845Sjhb{ 77091040Sarr c_linker_sym_t sym; 77191040Sarr linker_symval_t symval; 77291040Sarr caddr_t address; 77391040Sarr size_t common_size = 0; 77492032Sdwmalone int i; 77525537Sdfr 776159845Sjhb KLD_LOCK_ASSERT(); 777109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 77891040Sarr file, name, deps)); 77925537Sdfr 78091040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 78191040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 78291040Sarr if (symval.value == 0) 78391040Sarr /* 78491040Sarr * For commons, first look them up in the 78591040Sarr * dependencies and only allocate space if not found 78691040Sarr * there. 78791040Sarr */ 78891040Sarr common_size = symval.size; 78991040Sarr else { 79091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 791109605Sjake ".value=%p\n", symval.value)); 79291040Sarr return (symval.value); 79391040Sarr } 79440159Speter } 79591040Sarr if (deps) { 79691040Sarr for (i = 0; i < file->ndeps; i++) { 797159845Sjhb address = linker_file_lookup_symbol_internal( 798159845Sjhb file->deps[i], name, 0); 79991040Sarr if (address) { 80091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 801109605Sjake " deps value=%p\n", address)); 80291040Sarr return (address); 80391040Sarr } 80491040Sarr } 80525537Sdfr } 80691040Sarr if (common_size > 0) { 80791040Sarr /* 80891040Sarr * This is a common symbol which was not found in the 80991040Sarr * dependencies. We maintain a simple common symbol table in 81091040Sarr * the file object. 81191040Sarr */ 81291040Sarr struct common_symbol *cp; 81342849Speter 81491040Sarr STAILQ_FOREACH(cp, &file->common, link) { 81592032Sdwmalone if (strcmp(cp->name, name) == 0) { 81691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 817109605Sjake " old common value=%p\n", cp->address)); 81891040Sarr return (cp->address); 81991040Sarr } 82091040Sarr } 82191040Sarr /* 82291040Sarr * Round the symbol size up to align. 82391040Sarr */ 82491040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 82591040Sarr cp = malloc(sizeof(struct common_symbol) 82691040Sarr + common_size + strlen(name) + 1, M_LINKER, 827111119Simp M_WAITOK | M_ZERO); 82891040Sarr cp->address = (caddr_t)(cp + 1); 82991040Sarr cp->name = cp->address + common_size; 83091040Sarr strcpy(cp->name, name); 83191040Sarr bzero(cp->address, common_size); 83291040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 83325537Sdfr 83491040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 835109605Sjake " value=%p\n", cp->address)); 83691040Sarr return (cp->address); 83740159Speter } 83891040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 83991040Sarr return (0); 84025537Sdfr} 84125537Sdfr 84225537Sdfr/* 843174132Srwatson * Both DDB and stack(9) rely on the kernel linker to provide forward and 844174132Srwatson * backward lookup of symbols. However, DDB and sometimes stack(9) need to 845174132Srwatson * do this in a lockfree manner. We provide a set of internal helper 846174132Srwatson * routines to perform these operations without locks, and then wrappers that 847174132Srwatson * optionally lock. 848159840Sjhb * 849174132Srwatson * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. 85040159Speter */ 851174132Srwatson#ifdef DDB 852174132Srwatsonstatic int 853174132Srwatsonlinker_debug_lookup(const char *symstr, c_linker_sym_t *sym) 85440159Speter{ 85591040Sarr linker_file_t lf; 85640159Speter 85791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 85891040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 85991040Sarr return (0); 86091040Sarr } 86191040Sarr return (ENOENT); 86240159Speter} 863174132Srwatson#endif 86440159Speter 865174132Srwatsonstatic int 866174132Srwatsonlinker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 86740159Speter{ 86891040Sarr linker_file_t lf; 86991040Sarr c_linker_sym_t best, es; 87091040Sarr u_long diff, bestdiff, off; 87140159Speter 87291040Sarr best = 0; 87391040Sarr off = (uintptr_t)value; 87491040Sarr bestdiff = off; 87591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 87691040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 87791040Sarr continue; 87891040Sarr if (es != 0 && diff < bestdiff) { 87991040Sarr best = es; 88091040Sarr bestdiff = diff; 88191040Sarr } 88291040Sarr if (bestdiff == 0) 88391040Sarr break; 88440159Speter } 88591040Sarr if (best) { 88691040Sarr *sym = best; 88791040Sarr *diffp = bestdiff; 88891040Sarr return (0); 88991040Sarr } else { 89091040Sarr *sym = 0; 89191040Sarr *diffp = off; 89291040Sarr return (ENOENT); 89391040Sarr } 89440159Speter} 89540159Speter 896174132Srwatsonstatic int 897174132Srwatsonlinker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 89840159Speter{ 89991040Sarr linker_file_t lf; 90040159Speter 90191040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 90291040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 90391040Sarr return (0); 90491040Sarr } 90591040Sarr return (ENOENT); 90640159Speter} 907174132Srwatson 908174132Srwatsonstatic int 909174132Srwatsonlinker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, 910174132Srwatson long *offset) 911174132Srwatson{ 912174132Srwatson linker_symval_t symval; 913174132Srwatson c_linker_sym_t sym; 914174132Srwatson int error; 915174132Srwatson 916174132Srwatson *offset = 0; 917174132Srwatson error = linker_debug_search_symbol(value, &sym, offset); 918174132Srwatson if (error) 919174132Srwatson return (error); 920174132Srwatson error = linker_debug_symbol_values(sym, &symval); 921174132Srwatson if (error) 922174132Srwatson return (error); 923174132Srwatson strlcpy(buf, symval.name, buflen); 924174132Srwatson return (0); 925174132Srwatson} 926174132Srwatson 927174132Srwatson#ifdef DDB 928174132Srwatson/* 929174132Srwatson * DDB Helpers. DDB has to look across multiple files with their own symbol 930174132Srwatson * tables and string tables. 931174132Srwatson * 932174132Srwatson * Note that we do not obey list locking protocols here. We really don't need 933174132Srwatson * DDB to hang because somebody's got the lock held. We'll take the chance 934174132Srwatson * that the files list is inconsistant instead. 935174132Srwatson */ 936174132Srwatsonint 937174132Srwatsonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 938174132Srwatson{ 939174132Srwatson 940174132Srwatson return (linker_debug_lookup(symstr, sym)); 941174132Srwatson} 942174132Srwatson 943174132Srwatsonint 944174132Srwatsonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 945174132Srwatson{ 946174132Srwatson 947174132Srwatson return (linker_debug_search_symbol(value, sym, diffp)); 948174132Srwatson} 949174132Srwatson 950174132Srwatsonint 951174132Srwatsonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 952174132Srwatson{ 953174132Srwatson 954174132Srwatson return (linker_debug_symbol_values(sym, symval)); 955174132Srwatson} 956174132Srwatson 957174132Srwatsonint 958174132Srwatsonlinker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, 959174132Srwatson long *offset) 960174132Srwatson{ 961174132Srwatson 962174132Srwatson return (linker_debug_search_symbol_name(value, buf, buflen, offset)); 963174132Srwatson} 96440159Speter#endif 96540159Speter 96640159Speter/* 967174132Srwatson * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do 968174132Srwatson * obey locking protocols, and offer a significantly less complex interface. 969174132Srwatson */ 970174132Srwatsonint 971174132Srwatsonlinker_search_symbol_name(caddr_t value, char *buf, u_int buflen, 972174132Srwatson long *offset) 973174132Srwatson{ 974178380Spjd int error; 975174132Srwatson 976178380Spjd KLD_LOCK(); 977174132Srwatson error = linker_debug_search_symbol_name(value, buf, buflen, offset); 978178380Spjd KLD_UNLOCK(); 979174132Srwatson return (error); 980174132Srwatson} 981174132Srwatson 982174132Srwatson/* 98325537Sdfr * Syscalls. 98425537Sdfr */ 98525537Sdfrint 986159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 98725537Sdfr{ 988157144Sjkoshy#ifdef HWPMC_HOOKS 989157144Sjkoshy struct pmckern_map_in pkm; 990157144Sjkoshy#endif 991159588Sjhb const char *kldname, *modname; 99291040Sarr linker_file_t lf; 993159588Sjhb int error; 99425537Sdfr 99593159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 996159588Sjhb return (error); 99793159Sarr 998164033Srwatson if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0) 999159588Sjhb return (error); 100025537Sdfr 100191040Sarr /* 1002191917Szec * It is possible that kldloaded module will attach a new ifnet, 1003191816Szec * so vnet context must be set when this ocurs. 1004191816Szec */ 1005191816Szec CURVNET_SET(TD_TO_VNET(td)); 1006191816Szec 1007191816Szec /* 1008159841Sjhb * If file does not contain a qualified name or any dot in it 1009159841Sjhb * (kldname.ko, or kldname.ver.ko) treat it as an interface 101091040Sarr * name. 101191040Sarr */ 1012159588Sjhb if (index(file, '/') || index(file, '.')) { 1013159588Sjhb kldname = file; 101491040Sarr modname = NULL; 101591040Sarr } else { 101691040Sarr kldname = NULL; 1017159588Sjhb modname = file; 101891040Sarr } 1019159588Sjhb 1020159845Sjhb KLD_LOCK(); 102191040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 102291040Sarr if (error) 1023159588Sjhb goto unlock; 1024157144Sjkoshy#ifdef HWPMC_HOOKS 1025157144Sjkoshy pkm.pm_file = lf->filename; 1026157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 1027157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 1028157144Sjkoshy#endif 102991040Sarr lf->userrefs++; 1030159588Sjhb if (fileid != NULL) 1031159588Sjhb *fileid = lf->id; 1032159588Sjhbunlock: 1033159845Sjhb KLD_UNLOCK(); 1034191816Szec CURVNET_RESTORE(); 103591040Sarr return (error); 103625537Sdfr} 103725537Sdfr 1038159588Sjhbint 1039159588Sjhbkldload(struct thread *td, struct kldload_args *uap) 1040159588Sjhb{ 1041159588Sjhb char *pathname = NULL; 1042159596Smarcel int error, fileid; 1043159588Sjhb 1044159588Sjhb td->td_retval[0] = -1; 1045159588Sjhb 1046159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1047159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 1048159596Smarcel if (error == 0) { 1049159596Smarcel error = kern_kldload(td, pathname, &fileid); 1050159596Smarcel if (error == 0) 1051159596Smarcel td->td_retval[0] = fileid; 1052159596Smarcel } 1053159588Sjhb free(pathname, M_TEMP); 1054159588Sjhb return (error); 1055159588Sjhb} 1056159588Sjhb 1057159588Sjhbint 1058132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 105925537Sdfr{ 1060157144Sjkoshy#ifdef HWPMC_HOOKS 1061157144Sjkoshy struct pmckern_map_out pkm; 1062157144Sjkoshy#endif 106391040Sarr linker_file_t lf; 106491040Sarr int error = 0; 106525537Sdfr 106693159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 1067159588Sjhb return (error); 106893159Sarr 1069164033Srwatson if ((error = priv_check(td, PRIV_KLD_UNLOAD)) != 0) 1070159588Sjhb return (error); 107125537Sdfr 1072191816Szec CURVNET_SET(TD_TO_VNET(td)); 1073159845Sjhb KLD_LOCK(); 1074132117Sphk lf = linker_find_file_by_id(fileid); 107591040Sarr if (lf) { 107691040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 1077172862Sjb 1078172862Sjb /* Check if there are DTrace probes enabled on this file. */ 1079172862Sjb if (lf->nenabled > 0) { 1080172862Sjb printf("kldunload: attempt to unload file that has" 1081172862Sjb " DTrace probes enabled\n"); 1082172862Sjb error = EBUSY; 1083172862Sjb } else if (lf->userrefs == 0) { 1084132117Sphk /* 1085132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 1086132117Sphk */ 108791040Sarr printf("kldunload: attempt to unload file that was" 108891040Sarr " loaded by the kernel\n"); 1089159840Sjhb error = EBUSY; 1090159588Sjhb } else { 1091157144Sjkoshy#ifdef HWPMC_HOOKS 1092159588Sjhb /* Save data needed by hwpmc(4) before unloading. */ 1093159588Sjhb pkm.pm_address = (uintptr_t) lf->address; 1094159588Sjhb pkm.pm_size = lf->size; 1095157144Sjkoshy#endif 1096159588Sjhb lf->userrefs--; 1097159588Sjhb error = linker_file_unload(lf, flags); 1098159588Sjhb if (error) 1099159588Sjhb lf->userrefs++; 1100159588Sjhb } 110191040Sarr } else 110291040Sarr error = ENOENT; 1103157144Sjkoshy 1104157144Sjkoshy#ifdef HWPMC_HOOKS 1105157144Sjkoshy if (error == 0) 1106157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 1107157144Sjkoshy#endif 1108159845Sjhb KLD_UNLOCK(); 1109191816Szec CURVNET_RESTORE(); 111091068Sarr return (error); 111125537Sdfr} 111225537Sdfr 111325537Sdfrint 1114132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 1115132117Sphk{ 1116132117Sphk 1117132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 1118132117Sphk} 1119132117Sphk 1120132117Sphkint 1121132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 1122132117Sphk{ 1123132117Sphk 1124132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 1125132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 1126132117Sphk return (EINVAL); 1127132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 1128132117Sphk} 1129132117Sphk 1130132117Sphkint 113191040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 113225537Sdfr{ 113391040Sarr char *pathname; 113491040Sarr const char *filename; 113591040Sarr linker_file_t lf; 1136159791Sjhb int error; 113725537Sdfr 1138107089Srwatson#ifdef MAC 1139172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1140107089Srwatson if (error) 1141107089Srwatson return (error); 1142107089Srwatson#endif 1143107089Srwatson 114491040Sarr td->td_retval[0] = -1; 114582749Sdillon 1146111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 1147107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 114891040Sarr goto out; 114925537Sdfr 115091040Sarr filename = linker_basename(pathname); 1151159845Sjhb KLD_LOCK(); 115291040Sarr lf = linker_find_file_by_name(filename); 115391040Sarr if (lf) 115491040Sarr td->td_retval[0] = lf->id; 115591040Sarr else 115691040Sarr error = ENOENT; 1157159845Sjhb KLD_UNLOCK(); 115825537Sdfrout: 1159159791Sjhb free(pathname, M_TEMP); 116091040Sarr return (error); 116125537Sdfr} 116225537Sdfr 116325537Sdfrint 116491040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 116525537Sdfr{ 116691040Sarr linker_file_t lf; 116791040Sarr int error = 0; 116825537Sdfr 1169107089Srwatson#ifdef MAC 1170172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1171107089Srwatson if (error) 1172107089Srwatson return (error); 1173107089Srwatson#endif 1174107089Srwatson 1175159845Sjhb KLD_LOCK(); 1176166921Sjhb if (uap->fileid == 0) 1177166921Sjhb lf = TAILQ_FIRST(&linker_files); 1178166921Sjhb else { 1179166921Sjhb lf = linker_find_file_by_id(uap->fileid); 1180166921Sjhb if (lf == NULL) { 1181166921Sjhb error = ENOENT; 1182166921Sjhb goto out; 1183166921Sjhb } 1184166921Sjhb lf = TAILQ_NEXT(lf, link); 118591040Sarr } 1186166921Sjhb 1187166921Sjhb /* Skip partially loaded files. */ 1188166921Sjhb while (lf != NULL && !(lf->flags & LINKER_FILE_LINKED)) 1189166921Sjhb lf = TAILQ_NEXT(lf, link); 1190166921Sjhb 1191166921Sjhb if (lf) 1192166921Sjhb td->td_retval[0] = lf->id; 1193166921Sjhb else 1194166921Sjhb td->td_retval[0] = 0; 119582749Sdillonout: 1196159845Sjhb KLD_UNLOCK(); 119791040Sarr return (error); 119825537Sdfr} 119925537Sdfr 120025537Sdfrint 120191040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 120225537Sdfr{ 1203159587Sjhb struct kld_file_stat stat; 120491040Sarr linker_file_t lf; 1205172862Sjb int error, namelen, version, version_num; 120625537Sdfr 1207159587Sjhb /* 1208159587Sjhb * Check the version of the user's structure. 1209159587Sjhb */ 1210172862Sjb if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0) 1211159587Sjhb return (error); 1212172862Sjb if (version == sizeof(struct kld_file_stat_1)) 1213172862Sjb version_num = 1; 1214172862Sjb else if (version == sizeof(struct kld_file_stat)) 1215172862Sjb version_num = 2; 1216172862Sjb else 1217159587Sjhb return (EINVAL); 1218159587Sjhb 1219107089Srwatson#ifdef MAC 1220172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1221107089Srwatson if (error) 1222107089Srwatson return (error); 1223107089Srwatson#endif 1224107089Srwatson 1225159845Sjhb KLD_LOCK(); 1226107849Salfred lf = linker_find_file_by_id(uap->fileid); 122791040Sarr if (lf == NULL) { 1228159845Sjhb KLD_UNLOCK(); 1229159587Sjhb return (ENOENT); 123091040Sarr } 123125537Sdfr 1232172862Sjb /* Version 1 fields: */ 123391040Sarr namelen = strlen(lf->filename) + 1; 123491040Sarr if (namelen > MAXPATHLEN) 123591040Sarr namelen = MAXPATHLEN; 1236159587Sjhb bcopy(lf->filename, &stat.name[0], namelen); 1237159587Sjhb stat.refs = lf->refs; 1238159587Sjhb stat.id = lf->id; 1239159587Sjhb stat.address = lf->address; 1240159587Sjhb stat.size = lf->size; 1241172862Sjb if (version_num > 1) { 1242172862Sjb /* Version 2 fields: */ 1243172862Sjb namelen = strlen(lf->pathname) + 1; 1244172862Sjb if (namelen > MAXPATHLEN) 1245172862Sjb namelen = MAXPATHLEN; 1246172862Sjb bcopy(lf->pathname, &stat.pathname[0], namelen); 1247172862Sjb } 1248159845Sjhb KLD_UNLOCK(); 124925537Sdfr 125091040Sarr td->td_retval[0] = 0; 1251159587Sjhb 1252172862Sjb return (copyout(&stat, uap->stat, version)); 125325537Sdfr} 125425537Sdfr 125525537Sdfrint 125691040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 125725537Sdfr{ 125891040Sarr linker_file_t lf; 125991040Sarr module_t mp; 126091040Sarr int error = 0; 126125537Sdfr 1262107089Srwatson#ifdef MAC 1263172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1264107089Srwatson if (error) 1265107089Srwatson return (error); 1266107089Srwatson#endif 1267107089Srwatson 1268159845Sjhb KLD_LOCK(); 1269107849Salfred lf = linker_find_file_by_id(uap->fileid); 127091040Sarr if (lf) { 127192547Sarr MOD_SLOCK; 127291040Sarr mp = TAILQ_FIRST(&lf->modules); 127391040Sarr if (mp != NULL) 127491040Sarr td->td_retval[0] = module_getid(mp); 127591040Sarr else 127691040Sarr td->td_retval[0] = 0; 127792547Sarr MOD_SUNLOCK; 127891040Sarr } else 127991040Sarr error = ENOENT; 1280159845Sjhb KLD_UNLOCK(); 128191040Sarr return (error); 128225537Sdfr} 128340159Speter 128441090Speterint 128583366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 128641090Speter{ 128791040Sarr char *symstr = NULL; 128891040Sarr c_linker_sym_t sym; 128991040Sarr linker_symval_t symval; 129091040Sarr linker_file_t lf; 129191040Sarr struct kld_sym_lookup lookup; 129291040Sarr int error = 0; 129341090Speter 1294107089Srwatson#ifdef MAC 1295172930Srwatson error = mac_kld_check_stat(td->td_ucred); 1296107089Srwatson if (error) 1297107089Srwatson return (error); 1298107089Srwatson#endif 1299107089Srwatson 1300107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 1301159843Sjhb return (error); 130291068Sarr if (lookup.version != sizeof(lookup) || 1303159843Sjhb uap->cmd != KLDSYM_LOOKUP) 1304159843Sjhb return (EINVAL); 1305111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 130691040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 130791040Sarr goto out; 1308159845Sjhb KLD_LOCK(); 1309107849Salfred if (uap->fileid != 0) { 1310107849Salfred lf = linker_find_file_by_id(uap->fileid); 1311159843Sjhb if (lf == NULL) 131291040Sarr error = ENOENT; 1313159843Sjhb else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 131491040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 131591040Sarr lookup.symvalue = (uintptr_t) symval.value; 131691040Sarr lookup.symsize = symval.size; 1317107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 131891040Sarr } else 131991040Sarr error = ENOENT; 132091040Sarr } else { 132191040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 132291040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 132391040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 132491040Sarr lookup.symvalue = (uintptr_t)symval.value; 132591040Sarr lookup.symsize = symval.size; 1326107849Salfred error = copyout(&lookup, uap->data, 132791040Sarr sizeof(lookup)); 132891068Sarr break; 132991040Sarr } 133091040Sarr } 133191040Sarr if (lf == NULL) 133291040Sarr error = ENOENT; 133341090Speter } 1334159845Sjhb KLD_UNLOCK(); 133541090Speterout: 1336159843Sjhb free(symstr, M_TEMP); 133791040Sarr return (error); 133841090Speter} 133941090Speter 134040159Speter/* 134140159Speter * Preloaded module support 134240159Speter */ 134340159Speter 134459751Speterstatic modlist_t 134574642Sbpmodlist_lookup(const char *name, int ver) 134659751Speter{ 134791040Sarr modlist_t mod; 134859751Speter 134991040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 135092032Sdwmalone if (strcmp(mod->name, name) == 0 && 135192032Sdwmalone (ver == 0 || mod->version == ver)) 135291040Sarr return (mod); 135391040Sarr } 135491040Sarr return (NULL); 135559751Speter} 135659751Speter 135774642Sbpstatic modlist_t 135883321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 135983321Speter{ 136091040Sarr modlist_t mod, bestmod; 136192032Sdwmalone int ver; 136283321Speter 136391040Sarr if (verinfo == NULL) 136491040Sarr return (modlist_lookup(name, 0)); 136591040Sarr bestmod = NULL; 1366159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 136792032Sdwmalone if (strcmp(mod->name, name) != 0) 136891040Sarr continue; 136991040Sarr ver = mod->version; 137091040Sarr if (ver == verinfo->md_ver_preferred) 137191040Sarr return (mod); 137291040Sarr if (ver >= verinfo->md_ver_minimum && 137391068Sarr ver <= verinfo->md_ver_maximum && 1374120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 137591040Sarr bestmod = mod; 137691040Sarr } 137791040Sarr return (bestmod); 137883321Speter} 137983321Speter 138083321Speterstatic modlist_t 138178501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 138274642Sbp{ 138391040Sarr modlist_t mod; 138474642Sbp 138592705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 138691040Sarr if (mod == NULL) 138791040Sarr panic("no memory for module list"); 138891040Sarr mod->container = container; 138991040Sarr mod->name = modname; 139091040Sarr mod->version = version; 139191040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 139291040Sarr return (mod); 139374642Sbp} 139474642Sbp 139540159Speterstatic void 139678161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 139791040Sarr struct mod_metadata **stop, int preload) 139874642Sbp{ 139991040Sarr struct mod_metadata *mp, **mdp; 140091040Sarr const char *modname; 140191040Sarr int ver; 140274642Sbp 140391040Sarr for (mdp = start; mdp < stop; mdp++) { 1404109605Sjake mp = *mdp; 140591040Sarr if (mp->md_type != MDT_VERSION) 140691040Sarr continue; 1407109605Sjake modname = mp->md_cval; 1408109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 140991040Sarr if (modlist_lookup(modname, ver) != NULL) { 141091040Sarr printf("module %s already present!\n", modname); 141191040Sarr /* XXX what can we do? this is a build error. :-( */ 141291040Sarr continue; 141391040Sarr } 141491040Sarr modlist_newmodule(modname, ver, lf); 141574642Sbp } 141674642Sbp} 141774642Sbp 141874642Sbpstatic void 141991040Sarrlinker_preload(void *arg) 142040159Speter{ 142191040Sarr caddr_t modptr; 142291040Sarr const char *modname, *nmodname; 142391040Sarr char *modtype; 1424160244Sjhb linker_file_t lf, nlf; 142591040Sarr linker_class_t lc; 142692032Sdwmalone int error; 142791040Sarr linker_file_list_t loaded_files; 142891040Sarr linker_file_list_t depended_files; 142991040Sarr struct mod_metadata *mp, *nmp; 143091040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 143191040Sarr struct mod_depend *verinfo; 143291040Sarr int nver; 143391040Sarr int resolves; 143491040Sarr modlist_t mod; 143591040Sarr struct sysinit **si_start, **si_stop; 143640159Speter 143791040Sarr TAILQ_INIT(&loaded_files); 143891040Sarr TAILQ_INIT(&depended_files); 143991040Sarr TAILQ_INIT(&found_modules); 144091040Sarr error = 0; 144159751Speter 144291040Sarr modptr = NULL; 144391040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 144491040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 144591040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 144691040Sarr if (modname == NULL) { 144791040Sarr printf("Preloaded module at %p does not have a" 144891040Sarr " name!\n", modptr); 144991040Sarr continue; 145091040Sarr } 145191040Sarr if (modtype == NULL) { 145291040Sarr printf("Preloaded module at %p does not have a type!\n", 145391040Sarr modptr); 145491040Sarr continue; 145591040Sarr } 1456131398Sjhb if (bootverbose) 1457131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1458131398Sjhb modptr); 145940159Speter lf = NULL; 146091040Sarr TAILQ_FOREACH(lc, &classes, link) { 146191040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1462134364Siedowse if (!error) 146391040Sarr break; 1464134364Siedowse lf = NULL; 146591040Sarr } 146691040Sarr if (lf) 146791040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 146840159Speter } 146940159Speter 147091040Sarr /* 147191040Sarr * First get a list of stuff in the kernel. 147291040Sarr */ 147391040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 147491040Sarr &stop, NULL) == 0) 147591040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 147659751Speter 147759751Speter /* 1478167019Sjhb * This is a once-off kinky bubble sort to resolve relocation 1479167019Sjhb * dependency requirements. 148059751Speter */ 148191040Sarrrestart: 148291040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 148391040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 148491040Sarr &stop, NULL); 148591040Sarr /* 148691040Sarr * First, look to see if we would successfully link with this 148791040Sarr * stuff. 148891040Sarr */ 148991040Sarr resolves = 1; /* unless we know otherwise */ 149091040Sarr if (!error) { 149191040Sarr for (mdp = start; mdp < stop; mdp++) { 1492109605Sjake mp = *mdp; 149391040Sarr if (mp->md_type != MDT_DEPEND) 149491040Sarr continue; 1495109605Sjake modname = mp->md_cval; 1496109605Sjake verinfo = mp->md_data; 149791040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1498109605Sjake nmp = *nmdp; 149991040Sarr if (nmp->md_type != MDT_VERSION) 150091040Sarr continue; 1501109605Sjake nmodname = nmp->md_cval; 150292032Sdwmalone if (strcmp(modname, nmodname) == 0) 150391040Sarr break; 150491040Sarr } 150591040Sarr if (nmdp < stop) /* it's a self reference */ 150691040Sarr continue; 1507159840Sjhb 150891040Sarr /* 150991040Sarr * ok, the module isn't here yet, we 151091040Sarr * are not finished 151191040Sarr */ 151291068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 151391040Sarr resolves = 0; 151491040Sarr } 151564143Speter } 151691040Sarr /* 151791040Sarr * OK, if we found our modules, we can link. So, "provide" 151891040Sarr * the modules inside and add it to the end of the link order 151991040Sarr * list. 152091040Sarr */ 152191040Sarr if (resolves) { 152291040Sarr if (!error) { 152391040Sarr for (mdp = start; mdp < stop; mdp++) { 1524109605Sjake mp = *mdp; 152591040Sarr if (mp->md_type != MDT_VERSION) 152691040Sarr continue; 1527109605Sjake modname = mp->md_cval; 1528109605Sjake nver = ((struct mod_version *) 1529109605Sjake mp->md_data)->mv_version; 153091040Sarr if (modlist_lookup(modname, 153191040Sarr nver) != NULL) { 153291040Sarr printf("module %s already" 153391040Sarr " present!\n", modname); 1534160244Sjhb TAILQ_REMOVE(&loaded_files, 1535160244Sjhb lf, loaded); 1536132117Sphk linker_file_unload(lf, 1537132117Sphk LINKER_UNLOAD_FORCE); 153891040Sarr /* we changed tailq next ptr */ 153991068Sarr goto restart; 154091040Sarr } 154191040Sarr modlist_newmodule(modname, nver, lf); 154291040Sarr } 154391040Sarr } 154491040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 154591040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 154691040Sarr /* 154791040Sarr * Since we provided modules, we need to restart the 154891040Sarr * sort so that the previous files that depend on us 154991040Sarr * have a chance. Also, we've busted the tailq next 155091040Sarr * pointer with the REMOVE. 155191040Sarr */ 155291040Sarr goto restart; 155359751Speter } 155459751Speter } 155591040Sarr 155659751Speter /* 155791040Sarr * At this point, we check to see what could not be resolved.. 155859751Speter */ 1559160242Sjhb while ((lf = TAILQ_FIRST(&loaded_files)) != NULL) { 1560160242Sjhb TAILQ_REMOVE(&loaded_files, lf, loaded); 156191040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1562132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 156340159Speter } 156459751Speter 156578161Speter /* 156691040Sarr * We made it. Finish off the linking in the order we determined. 156778161Speter */ 1568160244Sjhb TAILQ_FOREACH_SAFE(lf, &depended_files, loaded, nlf) { 156991040Sarr if (linker_kernel_file) { 157091040Sarr linker_kernel_file->refs++; 157191040Sarr error = linker_file_add_dependency(lf, 157291040Sarr linker_kernel_file); 157391040Sarr if (error) 157491040Sarr panic("cannot add dependency"); 157591040Sarr } 157691040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 157791040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 157891040Sarr &stop, NULL); 157991040Sarr if (!error) { 158091040Sarr for (mdp = start; mdp < stop; mdp++) { 1581109605Sjake mp = *mdp; 158291040Sarr if (mp->md_type != MDT_DEPEND) 158391040Sarr continue; 1584109605Sjake modname = mp->md_cval; 1585109605Sjake verinfo = mp->md_data; 158691040Sarr mod = modlist_lookup2(modname, verinfo); 1587151484Sjdp /* Don't count self-dependencies */ 1588151484Sjdp if (lf == mod->container) 1589151484Sjdp continue; 159091040Sarr mod->container->refs++; 159191040Sarr error = linker_file_add_dependency(lf, 159291040Sarr mod->container); 159391040Sarr if (error) 159491040Sarr panic("cannot add dependency"); 159591040Sarr } 159691040Sarr } 159791040Sarr /* 159891040Sarr * Now do relocation etc using the symbol search paths 159991040Sarr * established by the dependencies 160091040Sarr */ 160191040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 160291040Sarr if (error) { 1603160244Sjhb TAILQ_REMOVE(&depended_files, lf, loaded); 160491040Sarr printf("KLD file %s - could not finalize loading\n", 160591040Sarr lf->filename); 1606132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 160791040Sarr continue; 160891040Sarr } 160991040Sarr linker_file_register_modules(lf); 161091040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 161191040Sarr &si_stop, NULL) == 0) 161291040Sarr sysinit_add(si_start, si_stop); 161391040Sarr linker_file_register_sysctls(lf); 161491040Sarr lf->flags |= LINKER_FILE_LINKED; 161559751Speter } 161691040Sarr /* woohoo! we made it! */ 161740159Speter} 161840159Speter 1619177253SrwatsonSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 162040159Speter 162140159Speter/* 162240159Speter * Search for a not-loaded module by name. 1623159840Sjhb * 162440159Speter * Modules may be found in the following locations: 1625159840Sjhb * 162691040Sarr * - preloaded (result is just the module name) - on disk (result is full path 162791040Sarr * to module) 1628159840Sjhb * 162991040Sarr * If the module name is qualified in any way (contains path, etc.) the we 163091040Sarr * simply return a copy of it. 1631159840Sjhb * 163240159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 163340159Speter * character as a separator to be consistent with the bootloader. 163440159Speter */ 163540159Speter 163683321Speterstatic char linker_hintfile[] = "linker.hints"; 1637111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 163840159Speter 163940159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 164091040Sarr sizeof(linker_path), "module load search path"); 164140159Speter 164277843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 164370417Speter 164459751Speterstatic char *linker_ext_list[] = { 164583321Speter "", 164659751Speter ".ko", 164759751Speter NULL 164859751Speter}; 164959751Speter 165083321Speter/* 165191040Sarr * Check if file actually exists either with or without extension listed in 165291040Sarr * the linker_ext_list. (probably should be generic for the rest of the 165391040Sarr * kernel) 165483321Speter */ 165559751Speterstatic char * 165691040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 165791040Sarr int namelen, struct vattr *vap) 165840159Speter{ 165991040Sarr struct nameidata nd; 166091040Sarr struct thread *td = curthread; /* XXX */ 166191040Sarr char *result, **cpp, *sep; 1662159808Sjhb int error, len, extlen, reclen, flags, vfslocked; 166391040Sarr enum vtype type; 166440159Speter 166591040Sarr extlen = 0; 166691040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 166791040Sarr len = strlen(*cpp); 166891040Sarr if (len > extlen) 166991040Sarr extlen = len; 167091040Sarr } 167191040Sarr extlen++; /* trailing '\0' */ 167291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 167383321Speter 167491040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1675111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 167691040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 167791040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 167891040Sarr namelen, name, *cpp); 167991040Sarr /* 168091040Sarr * Attempt to open the file, and return the path if 168191040Sarr * we succeed and it's a regular file. 168291040Sarr */ 1683159808Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); 168491040Sarr flags = FREAD; 1685170152Skib error = vn_open(&nd, &flags, 0, NULL); 168691040Sarr if (error == 0) { 1687159808Sjhb vfslocked = NDHASGIANT(&nd); 168891040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 168991040Sarr type = nd.ni_vp->v_type; 169091040Sarr if (vap) 1691182371Sattilio VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); 1692175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 169391406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 1694159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 169591040Sarr if (type == VREG) 169691040Sarr return (result); 169791040Sarr } 169883321Speter } 169991040Sarr free(result, M_LINKER); 170091040Sarr return (NULL); 170183321Speter} 170283321Speter 170391040Sarr#define INT_ALIGN(base, ptr) ptr = \ 170483321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 170583321Speter 170683321Speter/* 170791040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 170891040Sarr * version specification is available, then try to find the best KLD. 170983321Speter * Otherwise just find the latest one. 171083321Speter */ 171183321Speterstatic char * 171291040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 171391040Sarr int modnamelen, struct mod_depend *verinfo) 171483321Speter{ 171591040Sarr struct thread *td = curthread; /* XXX */ 171691406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 171791040Sarr struct nameidata nd; 171891040Sarr struct vattr vattr, mattr; 171991040Sarr u_char *hints = NULL; 172091040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 172191040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 1722159808Sjhb int vfslocked = 0; 172383321Speter 172491040Sarr result = NULL; 172591040Sarr bestver = found = 0; 172683321Speter 172791040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 172891040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 172991040Sarr strlen(sep) + 1; 1730111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 173191040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 173291040Sarr linker_hintfile); 173383321Speter 1734159808Sjhb NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); 173591040Sarr flags = FREAD; 1736170152Skib error = vn_open(&nd, &flags, 0, NULL); 173791040Sarr if (error) 173891040Sarr goto bad; 1739159808Sjhb vfslocked = NDHASGIANT(&nd); 174091040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 174191040Sarr if (nd.ni_vp->v_type != VREG) 174291040Sarr goto bad; 174391040Sarr best = cp = NULL; 1744182371Sattilio error = VOP_GETATTR(nd.ni_vp, &vattr, cred); 174591040Sarr if (error) 174691040Sarr goto bad; 174791040Sarr /* 174891040Sarr * XXX: we need to limit this number to some reasonable value 174991040Sarr */ 175091040Sarr if (vattr.va_size > 100 * 1024) { 175191040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 175291040Sarr goto bad; 175391040Sarr } 1754111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 175591040Sarr if (hints == NULL) 175691040Sarr goto bad; 175791068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1758101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 175991040Sarr if (error) 176091040Sarr goto bad; 1761175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 176291040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1763159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 176491040Sarr nd.ni_vp = NULL; 176591040Sarr if (reclen != 0) { 176691040Sarr printf("can't read %d\n", reclen); 176791040Sarr goto bad; 176891040Sarr } 176991040Sarr intp = (int *)hints; 177083321Speter ival = *intp++; 177191040Sarr if (ival != LINKER_HINTS_VERSION) { 177291040Sarr printf("hints file version mismatch %d\n", ival); 177391040Sarr goto bad; 177483321Speter } 177591040Sarr bufend = hints + vattr.va_size; 177691040Sarr recptr = (u_char *)intp; 177791040Sarr clen = blen = 0; 177891040Sarr while (recptr < bufend && !found) { 177991040Sarr intp = (int *)recptr; 178091040Sarr reclen = *intp++; 178191040Sarr ival = *intp++; 178291040Sarr cp = (char *)intp; 178391040Sarr switch (ival) { 178491040Sarr case MDT_VERSION: 178591040Sarr clen = *cp++; 178691040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 178791040Sarr break; 178891040Sarr cp += clen; 178991040Sarr INT_ALIGN(hints, cp); 179091040Sarr ival = *(int *)cp; 179191040Sarr cp += sizeof(int); 179291040Sarr clen = *cp++; 179391040Sarr if (verinfo == NULL || 179491040Sarr ival == verinfo->md_ver_preferred) { 179591040Sarr found = 1; 179691040Sarr break; 179791040Sarr } 179891040Sarr if (ival >= verinfo->md_ver_minimum && 179991040Sarr ival <= verinfo->md_ver_maximum && 180091040Sarr ival > bestver) { 180191040Sarr bestver = ival; 180291040Sarr best = cp; 180391040Sarr blen = clen; 180491040Sarr } 180591040Sarr break; 180691040Sarr default: 180791040Sarr break; 180891040Sarr } 180991040Sarr recptr += reclen + sizeof(int); 181091040Sarr } 181183321Speter /* 181291040Sarr * Finally check if KLD is in the place 181383321Speter */ 181491040Sarr if (found) 181591040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 181691040Sarr else if (best) 181791040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 181891040Sarr 181991040Sarr /* 182091040Sarr * KLD is newer than hints file. What we should do now? 182191040Sarr */ 182291040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 182391040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 182491040Sarr " file\n", result); 182583321Speterbad: 1826105167Sphk free(pathbuf, M_LINKER); 182791040Sarr if (hints) 182891040Sarr free(hints, M_TEMP); 182999553Sjeff if (nd.ni_vp != NULL) { 1830175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 183191040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1832159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 183399553Sjeff } 183491040Sarr /* 183591040Sarr * If nothing found or hints is absent - fallback to the old 183691040Sarr * way by using "kldname[.ko]" as module name. 183791040Sarr */ 183891040Sarr if (!found && !bestver && result == NULL) 183991040Sarr result = linker_lookup_file(path, pathlen, modname, 184091040Sarr modnamelen, NULL); 184191040Sarr return (result); 184283321Speter} 184383321Speter 184483321Speter/* 184583321Speter * Lookup KLD which contains requested module in the all directories. 184683321Speter */ 184783321Speterstatic char * 184883321Speterlinker_search_module(const char *modname, int modnamelen, 184991040Sarr struct mod_depend *verinfo) 185083321Speter{ 185191040Sarr char *cp, *ep, *result; 185283321Speter 185391040Sarr /* 185491040Sarr * traverse the linker path 185591040Sarr */ 185691040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 185791040Sarr /* find the end of this component */ 185891040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 185991068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 186091068Sarr modnamelen, verinfo); 186191040Sarr if (result != NULL) 186291040Sarr return (result); 186391040Sarr if (*ep == 0) 186491040Sarr break; 186591040Sarr } 186691040Sarr return (NULL); 186783321Speter} 186883321Speter 186983321Speter/* 187083321Speter * Search for module in all directories listed in the linker_path. 187183321Speter */ 187283321Speterstatic char * 187383321Speterlinker_search_kld(const char *name) 187483321Speter{ 1875158972Sdelphij char *cp, *ep, *result; 1876158972Sdelphij int len; 187783321Speter 187891040Sarr /* qualified at all? */ 187991040Sarr if (index(name, '/')) 188091040Sarr return (linker_strdup(name)); 188140159Speter 188291040Sarr /* traverse the linker path */ 188391040Sarr len = strlen(name); 188491040Sarr for (ep = linker_path; *ep; ep++) { 188591040Sarr cp = ep; 188691040Sarr /* find the end of this component */ 188791040Sarr for (; *ep != 0 && *ep != ';'; ep++); 188891040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 188991040Sarr if (result != NULL) 189091040Sarr return (result); 189191040Sarr } 189291040Sarr return (NULL); 189340159Speter} 189459751Speter 189559751Speterstatic const char * 189691040Sarrlinker_basename(const char *path) 189759751Speter{ 189891040Sarr const char *filename; 189959751Speter 190091040Sarr filename = rindex(path, '/'); 190191040Sarr if (filename == NULL) 190291040Sarr return path; 190391040Sarr if (filename[1]) 190491040Sarr filename++; 190591040Sarr return (filename); 190659751Speter} 190759751Speter 1908157144Sjkoshy#ifdef HWPMC_HOOKS 190959751Speter/* 1910157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1911157144Sjkoshy */ 1912157144Sjkoshyvoid * 1913157144Sjkoshylinker_hwpmc_list_objects(void) 1914157144Sjkoshy{ 1915195159Sattilio linker_file_t lf; 1916195159Sattilio struct pmckern_map_in *kobase; 1917195159Sattilio int i, nmappings; 1918157144Sjkoshy 1919195159Sattilio nmappings = 0; 1920195159Sattilio KLD_LOCK(); 1921195159Sattilio TAILQ_FOREACH(lf, &linker_files, link) 1922195159Sattilio nmappings++; 1923157144Sjkoshy 1924195159Sattilio /* Allocate nmappings + 1 entries. */ 1925195159Sattilio kobase = malloc((nmappings + 1) * sizeof(struct pmckern_map_in), 1926184214Sdes M_LINKER, M_WAITOK | M_ZERO); 1927195159Sattilio i = 0; 1928195159Sattilio TAILQ_FOREACH(lf, &linker_files, link) { 1929157144Sjkoshy 1930195159Sattilio /* Save the info for this linker file. */ 1931195159Sattilio kobase[i].pm_file = lf->filename; 1932195159Sattilio kobase[i].pm_address = (uintptr_t)lf->address; 1933195159Sattilio i++; 1934157144Sjkoshy } 1935195159Sattilio KLD_UNLOCK(); 1936157144Sjkoshy 1937195159Sattilio KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?")); 1938157144Sjkoshy 1939157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1940195159Sattilio KASSERT(kobase[i].pm_file == NULL, 1941157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1942157144Sjkoshy 1943195159Sattilio return ((void *)kobase); 1944157144Sjkoshy} 1945157144Sjkoshy#endif 1946157144Sjkoshy 1947157144Sjkoshy/* 194891040Sarr * Find a file which contains given module and load it, if "parent" is not 194991040Sarr * NULL, register a reference to it. 195059751Speter */ 1951159796Sjhbstatic int 195283321Speterlinker_load_module(const char *kldname, const char *modname, 195391040Sarr struct linker_file *parent, struct mod_depend *verinfo, 195491040Sarr struct linker_file **lfpp) 195559751Speter{ 195691040Sarr linker_file_t lfdep; 195791040Sarr const char *filename; 195891040Sarr char *pathname; 195991040Sarr int error; 196059751Speter 1961159845Sjhb KLD_LOCK_ASSERT(); 196291040Sarr if (modname == NULL) { 196391040Sarr /* 196491040Sarr * We have to load KLD 196591040Sarr */ 196691068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 196791068Sarr " is not NULL")); 196891040Sarr pathname = linker_search_kld(kldname); 196991040Sarr } else { 197091040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 197191040Sarr return (EEXIST); 197294322Sbrian if (kldname != NULL) 197394322Sbrian pathname = linker_strdup(kldname); 197495488Sbrian else if (rootvnode == NULL) 197594322Sbrian pathname = NULL; 197694322Sbrian else 197791040Sarr /* 197891040Sarr * Need to find a KLD with required module 197991040Sarr */ 198091040Sarr pathname = linker_search_module(modname, 198191040Sarr strlen(modname), verinfo); 198291040Sarr } 198391040Sarr if (pathname == NULL) 198491040Sarr return (ENOENT); 198591040Sarr 198683321Speter /* 198791040Sarr * Can't load more than one file with the same basename XXX: 198891040Sarr * Actually it should be possible to have multiple KLDs with 198991040Sarr * the same basename but different path because they can 199091040Sarr * provide different versions of the same modules. 199183321Speter */ 199291040Sarr filename = linker_basename(pathname); 1993159792Sjhb if (linker_find_file_by_name(filename)) 199491040Sarr error = EEXIST; 1995159792Sjhb else do { 199691040Sarr error = linker_load_file(pathname, &lfdep); 199791040Sarr if (error) 199891040Sarr break; 199991040Sarr if (modname && verinfo && 200091040Sarr modlist_lookup2(modname, verinfo) == NULL) { 2001132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 200291040Sarr error = ENOENT; 200391040Sarr break; 200491040Sarr } 200591040Sarr if (parent) { 200691040Sarr error = linker_file_add_dependency(parent, lfdep); 200791040Sarr if (error) 200891040Sarr break; 200991040Sarr } 201091040Sarr if (lfpp) 201191040Sarr *lfpp = lfdep; 201291040Sarr } while (0); 2013159791Sjhb free(pathname, M_LINKER); 201491040Sarr return (error); 201559751Speter} 201659751Speter 201759751Speter/* 201891040Sarr * This routine is responsible for finding dependencies of userland initiated 201991040Sarr * kldload(2)'s of files. 202059751Speter */ 202159751Speterint 202286469Siedowselinker_load_dependencies(linker_file_t lf) 202359751Speter{ 202491040Sarr linker_file_t lfdep; 202591040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 202691040Sarr struct mod_metadata *mp, *nmp; 202791040Sarr struct mod_depend *verinfo; 202891040Sarr modlist_t mod; 202991040Sarr const char *modname, *nmodname; 203092032Sdwmalone int ver, error = 0, count; 203159751Speter 203291040Sarr /* 203391040Sarr * All files are dependant on /kernel. 203491040Sarr */ 2035159845Sjhb KLD_LOCK_ASSERT(); 203691040Sarr if (linker_kernel_file) { 203791040Sarr linker_kernel_file->refs++; 203891040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 203991040Sarr if (error) 204091040Sarr return (error); 204159751Speter } 204291040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 204391040Sarr &count) != 0) 204491040Sarr return (0); 204591040Sarr for (mdp = start; mdp < stop; mdp++) { 2046109605Sjake mp = *mdp; 204791040Sarr if (mp->md_type != MDT_VERSION) 204891040Sarr continue; 2049109605Sjake modname = mp->md_cval; 2050109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 205191040Sarr mod = modlist_lookup(modname, ver); 205291040Sarr if (mod != NULL) { 205391040Sarr printf("interface %s.%d already present in the KLD" 205491040Sarr " '%s'!\n", modname, ver, 205591040Sarr mod->container->filename); 205691040Sarr return (EEXIST); 205791040Sarr } 205891040Sarr } 205974642Sbp 206091040Sarr for (mdp = start; mdp < stop; mdp++) { 2061109605Sjake mp = *mdp; 206291040Sarr if (mp->md_type != MDT_DEPEND) 206391040Sarr continue; 2064109605Sjake modname = mp->md_cval; 2065109605Sjake verinfo = mp->md_data; 206691040Sarr nmodname = NULL; 206791040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 2068109605Sjake nmp = *nmdp; 206991040Sarr if (nmp->md_type != MDT_VERSION) 207091040Sarr continue; 2071109605Sjake nmodname = nmp->md_cval; 207292032Sdwmalone if (strcmp(modname, nmodname) == 0) 207391040Sarr break; 207491040Sarr } 207591040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 207691040Sarr continue; 207791040Sarr mod = modlist_lookup2(modname, verinfo); 207891040Sarr if (mod) { /* woohoo, it's loaded already */ 207991040Sarr lfdep = mod->container; 208091040Sarr lfdep->refs++; 208191040Sarr error = linker_file_add_dependency(lf, lfdep); 208291040Sarr if (error) 208391040Sarr break; 208491040Sarr continue; 208591040Sarr } 208691040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 208791040Sarr if (error) { 2088195803Srpaulo printf("KLD %s: depends on %s - not available or" 2089195803Srpaulo " version mismatch\n", lf->filename, modname); 209091040Sarr break; 209191040Sarr } 209259751Speter } 209359751Speter 209491040Sarr if (error) 209591040Sarr return (error); 209691040Sarr linker_addmodules(lf, start, stop, 0); 209791040Sarr return (error); 209859751Speter} 209985736Sgreen 210085736Sgreenstatic int 210185736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 210285736Sgreen{ 210385736Sgreen struct sysctl_req *req; 210485736Sgreen 210585736Sgreen req = opaque; 210685736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 210785736Sgreen} 210885736Sgreen 210985736Sgreen/* 211085736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 211185736Sgreen * in the kernel. 211285736Sgreen */ 211385736Sgreenstatic int 211485736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 211585736Sgreen{ 211685736Sgreen linker_file_t lf; 211785736Sgreen int error; 211885736Sgreen 2119107089Srwatson#ifdef MAC 2120172930Srwatson error = mac_kld_check_stat(req->td->td_ucred); 2121107089Srwatson if (error) 2122107089Srwatson return (error); 2123107089Srwatson#endif 2124126253Struckman error = sysctl_wire_old_buffer(req, 0); 2125126253Struckman if (error != 0) 2126126253Struckman return (error); 2127159845Sjhb KLD_LOCK(); 212885736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 212985736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 213085736Sgreen sysctl_kern_function_list_iterate, req); 213198452Sarr if (error) { 2132159845Sjhb KLD_UNLOCK(); 213385736Sgreen return (error); 213498452Sarr } 213585736Sgreen } 2136159845Sjhb KLD_UNLOCK(); 213785736Sgreen return (SYSCTL_OUT(req, "", 1)); 213885736Sgreen} 213985736Sgreen 214085736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 214191040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 2142