kern_linker.c revision 157144
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 157144 2006-03-26 12:20:54Z jkoshy $"); 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> 4025537Sdfr#include <sys/proc.h> 4125537Sdfr#include <sys/lock.h> 4282749Sdillon#include <sys/mutex.h> 4392547Sarr#include <sys/sx.h> 44107089Srwatson#include <sys/mac.h> 4525537Sdfr#include <sys/module.h> 4625537Sdfr#include <sys/linker.h> 4740159Speter#include <sys/fcntl.h> 4840159Speter#include <sys/libkern.h> 4940159Speter#include <sys/namei.h> 5040159Speter#include <sys/vnode.h> 5140159Speter#include <sys/sysctl.h> 5225537Sdfr 5359603Sdfr#include "linker_if.h" 5459603Sdfr 55157144Sjkoshy#ifdef HWPMC_HOOKS 56157144Sjkoshy#include <sys/pmckern.h> 57157144Sjkoshy#endif 58157144Sjkoshy 5940961Speter#ifdef KLD_DEBUG 6040961Speterint kld_debug = 0; 6140961Speter#endif 6240961Speter 6391040Sarr/* 6491040Sarr * static char *linker_search_path(const char *name, struct mod_depend 6591040Sarr * *verinfo); 6691040Sarr */ 6791040Sarrstatic const char *linker_basename(const char *path); 6859751Speter 6978161Speter/* Metadata from the static kernel */ 7078161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 7178161Speter 7259751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 7359751Speter 7440906Speterlinker_file_t linker_kernel_file; 7531324Sbde 7698452Sarrstatic struct mtx kld_mtx; /* kernel linker mutex */ 7798452Sarr 7825537Sdfrstatic linker_class_list_t classes; 7950068Sgrogstatic linker_file_list_t linker_files; 8025537Sdfrstatic int next_file_id = 1; 8198452Sarrstatic int linker_no_more_classes = 0; 8225537Sdfr 8386553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 8491040Sarr linker_file_t lftmp; \ 8586553Sarr \ 8686553Sarrretry: \ 8798452Sarr mtx_lock(&kld_mtx); \ 8891040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 8991040Sarr if (next_file_id == lftmp->id) { \ 9091040Sarr next_file_id++; \ 9198452Sarr mtx_unlock(&kld_mtx); \ 9291040Sarr goto retry; \ 9391040Sarr } \ 9491040Sarr } \ 9591040Sarr (a) = next_file_id; \ 9698452Sarr mtx_unlock(&kld_mtx); /* Hold for safe read of id variable */ \ 9786553Sarr} while(0) 9886553Sarr 9986553Sarr 10059751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 10160938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 10259751Speterstruct modlist { 10391040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 10491040Sarr linker_file_t container; 10591040Sarr const char *name; 10691040Sarr int version; 10759751Speter}; 10891040Sarrtypedef struct modlist *modlist_t; 10991040Sarrstatic modlisthead_t found_modules; 11059751Speter 11194321Sbrianstatic modlist_t modlist_lookup2(const char *name, 11294321Sbrian struct mod_depend *verinfo); 11394321Sbrian 11459603Sdfrstatic char * 11559603Sdfrlinker_strdup(const char *str) 11659603Sdfr{ 11791040Sarr char *result; 11859603Sdfr 119111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 12091040Sarr strcpy(result, str); 12191040Sarr return (result); 12259603Sdfr} 12359603Sdfr 12425537Sdfrstatic void 12591040Sarrlinker_init(void *arg) 12625537Sdfr{ 12791040Sarr 12898452Sarr mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF); 12991040Sarr TAILQ_INIT(&classes); 13091040Sarr TAILQ_INIT(&linker_files); 13125537Sdfr} 13225537Sdfr 13391040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0) 13425537Sdfr 13598452Sarrstatic void 13698452Sarrlinker_stop_class_add(void *arg) 13798452Sarr{ 13898452Sarr 13998452Sarr linker_no_more_classes = 1; 14098452Sarr} 14198452Sarr 14298452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL) 14398452Sarr 14425537Sdfrint 14559603Sdfrlinker_add_class(linker_class_t lc) 14625537Sdfr{ 14791040Sarr 14898452Sarr /* 149144443Sjhb * We disallow any class registration past SI_ORDER_ANY 150144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 151144443Sjhb * ops from being freed. 15298452Sarr */ 15398452Sarr if (linker_no_more_classes == 1) 15498452Sarr return (EPERM); 15591040Sarr kobj_class_compile((kobj_class_t) lc); 156144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 15791040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 15891040Sarr return (0); 15925537Sdfr} 16025537Sdfr 16125537Sdfrstatic void 16225537Sdfrlinker_file_sysinit(linker_file_t lf) 16325537Sdfr{ 16491040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 16525537Sdfr 16691040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 16791040Sarr lf->filename)); 16825537Sdfr 16991040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 17091040Sarr return; 17191040Sarr /* 17291040Sarr * Perform a bubble sort of the system initialization objects by 17391040Sarr * their subsystem (primary key) and order (secondary key). 17491040Sarr * 17591040Sarr * Since some things care about execution order, this is the operation 17691040Sarr * which ensures continued function. 17791040Sarr */ 17891040Sarr for (sipp = start; sipp < stop; sipp++) { 17991040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 18091040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 18191040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 18291040Sarr (*sipp)->order <= (*xipp)->order)) 18391040Sarr continue; /* skip */ 18491040Sarr save = *sipp; 18591040Sarr *sipp = *xipp; 18691040Sarr *xipp = save; 18791040Sarr } 18825537Sdfr } 18925537Sdfr 19091040Sarr /* 19191040Sarr * Traverse the (now) ordered list of system initialization tasks. 19291040Sarr * Perform each task, and continue on to the next task. 19391040Sarr */ 19491040Sarr for (sipp = start; sipp < stop; sipp++) { 19591040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 19691040Sarr continue; /* skip dummy task(s) */ 19725537Sdfr 19891040Sarr /* Call function */ 19991040Sarr (*((*sipp)->func)) ((*sipp)->udata); 20091040Sarr } 20125537Sdfr} 20225537Sdfr 20341055Speterstatic void 20441055Speterlinker_file_sysuninit(linker_file_t lf) 20541055Speter{ 20691040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 20741055Speter 20891040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 20991040Sarr lf->filename)); 21041055Speter 21191068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 21291040Sarr NULL) != 0) 21391040Sarr return; 21441055Speter 21591040Sarr /* 21691040Sarr * Perform a reverse bubble sort of the system initialization objects 21791040Sarr * by their subsystem (primary key) and order (secondary key). 21891040Sarr * 21991040Sarr * Since some things care about execution order, this is the operation 22091040Sarr * which ensures continued function. 22191040Sarr */ 22291040Sarr for (sipp = start; sipp < stop; sipp++) { 22391040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 22491040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 22591040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 22691040Sarr (*sipp)->order >= (*xipp)->order)) 22791040Sarr continue; /* skip */ 22891040Sarr save = *sipp; 22991040Sarr *sipp = *xipp; 23091040Sarr *xipp = save; 23191040Sarr } 23241055Speter } 23341055Speter 23491040Sarr /* 23591040Sarr * Traverse the (now) ordered list of system initialization tasks. 23691040Sarr * Perform each task, and continue on to the next task. 23791040Sarr */ 23891040Sarr for (sipp = start; sipp < stop; sipp++) { 23991040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 24091040Sarr continue; /* skip dummy task(s) */ 24141055Speter 24291040Sarr /* Call function */ 24391040Sarr (*((*sipp)->func)) ((*sipp)->udata); 24491040Sarr } 24541055Speter} 24641055Speter 24744078Sdfrstatic void 24844078Sdfrlinker_file_register_sysctls(linker_file_t lf) 24944078Sdfr{ 25091040Sarr struct sysctl_oid **start, **stop, **oidp; 25144078Sdfr 25291040Sarr KLD_DPF(FILE, 25391040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 25491040Sarr lf->filename)); 25544078Sdfr 25691040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 25791040Sarr return; 25844078Sdfr 25991040Sarr for (oidp = start; oidp < stop; oidp++) 26091040Sarr sysctl_register_oid(*oidp); 26144078Sdfr} 26244078Sdfr 26344078Sdfrstatic void 26444078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 26544078Sdfr{ 26691040Sarr struct sysctl_oid **start, **stop, **oidp; 26744078Sdfr 26891040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 26991040Sarr " for %s\n", lf->filename)); 27044078Sdfr 27191040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 27291040Sarr return; 27344078Sdfr 27491040Sarr for (oidp = start; oidp < stop; oidp++) 27591040Sarr sysctl_unregister_oid(*oidp); 27644078Sdfr} 27744078Sdfr 27859751Speterstatic int 27959751Speterlinker_file_register_modules(linker_file_t lf) 28059751Speter{ 28191040Sarr struct mod_metadata **start, **stop, **mdp; 28291040Sarr const moduledata_t *moddata; 283146733Spjd int first_error, error; 28459751Speter 28591040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 28691040Sarr " in %s\n", lf->filename)); 28759751Speter 28891068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 28991040Sarr &stop, 0) != 0) { 29091040Sarr /* 29191040Sarr * This fallback should be unnecessary, but if we get booted 29291040Sarr * from boot2 instead of loader and we are missing our 29391040Sarr * metadata then we have to try the best we can. 29491040Sarr */ 29591040Sarr if (lf == linker_kernel_file) { 29691040Sarr start = SET_BEGIN(modmetadata_set); 29791040Sarr stop = SET_LIMIT(modmetadata_set); 29891040Sarr } else 29991040Sarr return (0); 30078161Speter } 301146733Spjd first_error = 0; 30291040Sarr for (mdp = start; mdp < stop; mdp++) { 30391040Sarr if ((*mdp)->md_type != MDT_MODULE) 30491040Sarr continue; 30591040Sarr moddata = (*mdp)->md_data; 30691040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 30791040Sarr moddata->name, lf->filename)); 30891040Sarr error = module_register(moddata, lf); 309146730Spjd if (error) { 31091068Sarr printf("Module %s failed to register: %d\n", 31191040Sarr moddata->name, error); 312146733Spjd if (first_error == 0) 313146733Spjd first_error = error; 314146730Spjd } 31559751Speter } 316146733Spjd return (first_error); 31759751Speter} 31859751Speter 31959751Speterstatic void 32059751Speterlinker_init_kernel_modules(void) 32159751Speter{ 32291040Sarr 32391040Sarr linker_file_register_modules(linker_kernel_file); 32459751Speter} 32559751Speter 32691040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) 32759751Speter 328101241Smuxstatic int 32991040Sarrlinker_load_file(const char *filename, linker_file_t *result) 33025537Sdfr{ 33191040Sarr linker_class_t lc; 33291040Sarr linker_file_t lf; 33391040Sarr int foundfile, error = 0; 33425537Sdfr 33591040Sarr /* Refuse to load modules if securelevel raised */ 33691040Sarr if (securelevel > 0) 33791040Sarr return (EPERM); 33862261Sarchie 33991040Sarr lf = linker_find_file_by_name(filename); 34091040Sarr if (lf) { 34191040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 34291040Sarr " incrementing refs\n", filename)); 34391040Sarr *result = lf; 34491040Sarr lf->refs++; 34591040Sarr goto out; 34691040Sarr } 34791040Sarr lf = NULL; 34891040Sarr foundfile = 0; 34998452Sarr 35098452Sarr /* 35198452Sarr * We do not need to protect (lock) classes here because there is 35298452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 35398452Sarr * and there is no class deregistration mechanism at this time. 35498452Sarr */ 35591040Sarr TAILQ_FOREACH(lc, &classes, link) { 35691040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 35791040Sarr filename)); 35891040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 35991040Sarr /* 36091040Sarr * If we got something other than ENOENT, then it exists but 36191040Sarr * we cannot load it for some other reason. 36291040Sarr */ 36391040Sarr if (error != ENOENT) 36491040Sarr foundfile = 1; 36591040Sarr if (lf) { 366146730Spjd error = linker_file_register_modules(lf); 367146730Spjd if (error == EEXIST) { 368146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 369146730Spjd goto out; 370146730Spjd } 37191040Sarr linker_file_register_sysctls(lf); 37291040Sarr linker_file_sysinit(lf); 37391040Sarr lf->flags |= LINKER_FILE_LINKED; 37491040Sarr *result = lf; 37591040Sarr error = 0; 37691040Sarr goto out; 37791040Sarr } 37891040Sarr } 37942755Speter /* 38091040Sarr * Less than ideal, but tells the user whether it failed to load or 38191040Sarr * the module was not found. 38242755Speter */ 383105337Ssam if (foundfile) { 384105337Ssam /* 385105337Ssam * Format not recognized or otherwise unloadable. 386105337Ssam * When loading a module that is statically built into 387105337Ssam * the kernel EEXIST percolates back up as the return 388105337Ssam * value. Preserve this so that apps like sysinstall 389105337Ssam * can recognize this special case and not post bogus 390105337Ssam * dialog boxes. 391105337Ssam */ 392105337Ssam if (error != EEXIST) 393105337Ssam error = ENOEXEC; 394105337Ssam } else 39591068Sarr error = ENOENT; /* Nothing found */ 39625537Sdfrout: 39791040Sarr return (error); 39825537Sdfr} 39925537Sdfr 40078413Sbrianint 40194321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 40294321Sbrian linker_file_t *result) 40378413Sbrian{ 40494321Sbrian modlist_t mod; 40594321Sbrian 40694321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 40794321Sbrian *result = mod->container; 40894321Sbrian (*result)->refs++; 40994321Sbrian return (0); 41094321Sbrian } 41194321Sbrian 41294321Sbrian return (linker_load_module(NULL, modname, NULL, verinfo, result)); 41378413Sbrian} 41478413Sbrian 41525537Sdfrlinker_file_t 41691040Sarrlinker_find_file_by_name(const char *filename) 41725537Sdfr{ 41891040Sarr linker_file_t lf = 0; 41991040Sarr char *koname; 42025537Sdfr 421111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 42291040Sarr if (koname == NULL) 42391040Sarr goto out; 42491040Sarr sprintf(koname, "%s.ko", filename); 42540861Speter 42698452Sarr mtx_lock(&kld_mtx); 42791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 42892032Sdwmalone if (strcmp(lf->filename, koname) == 0) 42991040Sarr break; 43092032Sdwmalone if (strcmp(lf->filename, filename) == 0) 43191040Sarr break; 43291040Sarr } 43398452Sarr mtx_unlock(&kld_mtx); 43440861Speterout: 43591040Sarr if (koname) 43691040Sarr free(koname, M_LINKER); 43791040Sarr return (lf); 43825537Sdfr} 43925537Sdfr 44025537Sdfrlinker_file_t 44125537Sdfrlinker_find_file_by_id(int fileid) 44225537Sdfr{ 44391040Sarr linker_file_t lf = 0; 44498452Sarr 44598452Sarr mtx_lock(&kld_mtx); 44691040Sarr TAILQ_FOREACH(lf, &linker_files, link) 44791040Sarr if (lf->id == fileid) 44891040Sarr break; 44998452Sarr mtx_unlock(&kld_mtx); 45091040Sarr return (lf); 45125537Sdfr} 45225537Sdfr 45325537Sdfrlinker_file_t 45491040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 45525537Sdfr{ 45691040Sarr linker_file_t lf; 45791040Sarr const char *filename; 45825537Sdfr 45991040Sarr lf = NULL; 46091040Sarr filename = linker_basename(pathname); 46140159Speter 46291040Sarr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 463111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 46491040Sarr if (lf == NULL) 46591040Sarr goto out; 46691040Sarr lf->refs = 1; 46791040Sarr lf->userrefs = 0; 46891040Sarr lf->flags = 0; 46991040Sarr lf->filename = linker_strdup(filename); 47091040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 47191040Sarr lf->ndeps = 0; 47291040Sarr lf->deps = NULL; 47391040Sarr STAILQ_INIT(&lf->common); 47491040Sarr TAILQ_INIT(&lf->modules); 47598452Sarr mtx_lock(&kld_mtx); 47691040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 47798452Sarr mtx_unlock(&kld_mtx); 47825537Sdfrout: 47991040Sarr return (lf); 48025537Sdfr} 48125537Sdfr 48225537Sdfrint 483132117Sphklinker_file_unload(linker_file_t file, int flags) 48425537Sdfr{ 48591040Sarr module_t mod, next; 48691040Sarr modlist_t ml, nextml; 48791040Sarr struct common_symbol *cp; 48891040Sarr int error, i; 48925537Sdfr 49091040Sarr error = 0; 49162261Sarchie 49291040Sarr /* Refuse to unload modules if securelevel raised. */ 49391040Sarr if (securelevel > 0) 49491040Sarr return (EPERM); 495107089Srwatson#ifdef MAC 496107089Srwatson error = mac_check_kld_unload(curthread->td_ucred); 497107089Srwatson if (error) 498107089Srwatson return (error); 499107089Srwatson#endif 50025537Sdfr 50191040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 50291040Sarr if (file->refs == 1) { 50391040Sarr KLD_DPF(FILE, ("linker_file_unload: file is unloading," 50491040Sarr " informing modules\n")); 50591040Sarr 50691040Sarr /* 50791040Sarr * Inform any modules associated with this file. 50891040Sarr */ 50992547Sarr MOD_XLOCK; 51091040Sarr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 51191040Sarr next = module_getfnext(mod); 51292547Sarr MOD_XUNLOCK; 51391040Sarr 51491040Sarr /* 51591040Sarr * Give the module a chance to veto the unload. 51691040Sarr */ 517132117Sphk if ((error = module_unload(mod, flags)) != 0) { 518109605Sjake KLD_DPF(FILE, ("linker_file_unload: module %p" 51991040Sarr " vetoes unload\n", mod)); 52091040Sarr goto out; 52192547Sarr } else 52292547Sarr MOD_XLOCK; 52391040Sarr module_release(mod); 52491040Sarr } 52592547Sarr MOD_XUNLOCK; 52691040Sarr } 52791040Sarr file->refs--; 52891040Sarr if (file->refs > 0) { 52925537Sdfr goto out; 53091040Sarr } 53191040Sarr for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { 53291040Sarr nextml = TAILQ_NEXT(ml, link); 533128057Speadar if (ml->container == file) { 53491040Sarr TAILQ_REMOVE(&found_modules, ml, link); 535128057Speadar free(ml, M_LINKER); 536128057Speadar } 53791040Sarr } 53825537Sdfr 53991040Sarr /* 54091040Sarr * Don't try to run SYSUNINITs if we are unloaded due to a 54191040Sarr * link error. 54291040Sarr */ 54391040Sarr if (file->flags & LINKER_FILE_LINKED) { 54491040Sarr linker_file_sysuninit(file); 54591040Sarr linker_file_unregister_sysctls(file); 54625537Sdfr } 54798452Sarr mtx_lock(&kld_mtx); 54891040Sarr TAILQ_REMOVE(&linker_files, file, link); 54998452Sarr mtx_unlock(&kld_mtx); 55025537Sdfr 55191040Sarr if (file->deps) { 55291040Sarr for (i = 0; i < file->ndeps; i++) 553132117Sphk linker_file_unload(file->deps[i], flags); 55491040Sarr free(file->deps, M_LINKER); 55591040Sarr file->deps = NULL; 55659751Speter } 55791040Sarr for (cp = STAILQ_FIRST(&file->common); cp; 55891068Sarr cp = STAILQ_FIRST(&file->common)) { 55991040Sarr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 56091040Sarr free(cp, M_LINKER); 56191040Sarr } 56259751Speter 56391040Sarr LINKER_UNLOAD(file); 56491040Sarr if (file->filename) { 56591040Sarr free(file->filename, M_LINKER); 56691040Sarr file->filename = NULL; 56791040Sarr } 56891040Sarr kobj_delete((kobj_t) file, M_LINKER); 56925537Sdfrout: 57091040Sarr return (error); 57125537Sdfr} 57225537Sdfr 57325537Sdfrint 57486469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 57525537Sdfr{ 57691040Sarr linker_file_t *newdeps; 57725537Sdfr 57891040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 579111119Simp M_LINKER, M_WAITOK | M_ZERO); 58091040Sarr if (newdeps == NULL) 58191040Sarr return (ENOMEM); 58225537Sdfr 58391040Sarr if (file->deps) { 58491040Sarr bcopy(file->deps, newdeps, 58591040Sarr file->ndeps * sizeof(linker_file_t *)); 58691040Sarr free(file->deps, M_LINKER); 58791040Sarr } 58891040Sarr file->deps = newdeps; 58991040Sarr file->deps[file->ndeps] = dep; 59091040Sarr file->ndeps++; 59191040Sarr return (0); 59225537Sdfr} 59325537Sdfr 59478161Speter/* 59591040Sarr * Locate a linker set and its contents. This is a helper function to avoid 59691040Sarr * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** 59778161Speter */ 59878161Speterint 59978161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 60091040Sarr void *firstp, void *lastp, int *countp) 60178161Speter{ 60278161Speter 60391040Sarr return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 60478161Speter} 60578161Speter 60625537Sdfrcaddr_t 60791040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 60825537Sdfr{ 60991040Sarr c_linker_sym_t sym; 61091040Sarr linker_symval_t symval; 61191040Sarr caddr_t address; 61291040Sarr size_t common_size = 0; 61392032Sdwmalone int i; 61425537Sdfr 615109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 61691040Sarr file, name, deps)); 61725537Sdfr 61891040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 61991040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 62091040Sarr if (symval.value == 0) 62191040Sarr /* 62291040Sarr * For commons, first look them up in the 62391040Sarr * dependencies and only allocate space if not found 62491040Sarr * there. 62591040Sarr */ 62691040Sarr common_size = symval.size; 62791040Sarr else { 62891040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 629109605Sjake ".value=%p\n", symval.value)); 63091040Sarr return (symval.value); 63191040Sarr } 63240159Speter } 63391040Sarr if (deps) { 63491040Sarr for (i = 0; i < file->ndeps; i++) { 63591040Sarr address = linker_file_lookup_symbol(file->deps[i], 63691040Sarr name, 0); 63791040Sarr if (address) { 63891040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 639109605Sjake " deps value=%p\n", address)); 64091040Sarr return (address); 64191040Sarr } 64291040Sarr } 64325537Sdfr } 64491040Sarr if (common_size > 0) { 64591040Sarr /* 64691040Sarr * This is a common symbol which was not found in the 64791040Sarr * dependencies. We maintain a simple common symbol table in 64891040Sarr * the file object. 64991040Sarr */ 65091040Sarr struct common_symbol *cp; 65142849Speter 65291040Sarr STAILQ_FOREACH(cp, &file->common, link) { 65392032Sdwmalone if (strcmp(cp->name, name) == 0) { 65491040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 655109605Sjake " old common value=%p\n", cp->address)); 65691040Sarr return (cp->address); 65791040Sarr } 65891040Sarr } 65991040Sarr /* 66091040Sarr * Round the symbol size up to align. 66191040Sarr */ 66291040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 66391040Sarr cp = malloc(sizeof(struct common_symbol) 66491040Sarr + common_size + strlen(name) + 1, M_LINKER, 665111119Simp M_WAITOK | M_ZERO); 66691040Sarr if (cp == NULL) { 66791040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 66891040Sarr return (0); 66991040Sarr } 67091040Sarr cp->address = (caddr_t)(cp + 1); 67191040Sarr cp->name = cp->address + common_size; 67291040Sarr strcpy(cp->name, name); 67391040Sarr bzero(cp->address, common_size); 67491040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 67525537Sdfr 67691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 677109605Sjake " value=%p\n", cp->address)); 67891040Sarr return (cp->address); 67940159Speter } 68091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 68191040Sarr return (0); 68225537Sdfr} 68325537Sdfr 68440159Speter#ifdef DDB 68525537Sdfr/* 68691040Sarr * DDB Helpers. DDB has to look across multiple files with their own symbol 68791040Sarr * tables and string tables. 68891040Sarr * 68991040Sarr * Note that we do not obey list locking protocols here. We really don't need 69091040Sarr * DDB to hang because somebody's got the lock held. We'll take the chance 69191040Sarr * that the files list is inconsistant instead. 69240159Speter */ 69340159Speter 69440159Speterint 69543309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 69640159Speter{ 69791040Sarr linker_file_t lf; 69840159Speter 69991040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 70091040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 70191040Sarr return (0); 70291040Sarr } 70391040Sarr return (ENOENT); 70440159Speter} 70540159Speter 70640159Speterint 70743309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 70840159Speter{ 70991040Sarr linker_file_t lf; 71091040Sarr c_linker_sym_t best, es; 71191040Sarr u_long diff, bestdiff, off; 71240159Speter 71391040Sarr best = 0; 71491040Sarr off = (uintptr_t)value; 71591040Sarr bestdiff = off; 71691040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 71791040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 71891040Sarr continue; 71991040Sarr if (es != 0 && diff < bestdiff) { 72091040Sarr best = es; 72191040Sarr bestdiff = diff; 72291040Sarr } 72391040Sarr if (bestdiff == 0) 72491040Sarr break; 72540159Speter } 72691040Sarr if (best) { 72791040Sarr *sym = best; 72891040Sarr *diffp = bestdiff; 72991040Sarr return (0); 73091040Sarr } else { 73191040Sarr *sym = 0; 73291040Sarr *diffp = off; 73391040Sarr return (ENOENT); 73491040Sarr } 73540159Speter} 73640159Speter 73740159Speterint 73843309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 73940159Speter{ 74091040Sarr linker_file_t lf; 74140159Speter 74291040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 74391040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 74491040Sarr return (0); 74591040Sarr } 74691040Sarr return (ENOENT); 74740159Speter} 74840159Speter#endif 74940159Speter 75040159Speter/* 75125537Sdfr * Syscalls. 75225537Sdfr */ 75382749Sdillon/* 75482749Sdillon * MPSAFE 75582749Sdillon */ 75625537Sdfrint 75791040Sarrkldload(struct thread *td, struct kldload_args *uap) 75825537Sdfr{ 759157144Sjkoshy#ifdef HWPMC_HOOKS 760157144Sjkoshy struct pmckern_map_in pkm; 761157144Sjkoshy#endif 76291040Sarr char *kldname, *modname; 76391040Sarr char *pathname = NULL; 76491040Sarr linker_file_t lf; 76591040Sarr int error = 0; 76625537Sdfr 76791040Sarr td->td_retval[0] = -1; 76825537Sdfr 76991040Sarr mtx_lock(&Giant); 77082749Sdillon 77193159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 77293159Sarr goto out; 77393159Sarr 77493593Sjhb if ((error = suser(td)) != 0) 77591040Sarr goto out; 77625537Sdfr 777111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 778107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 77991040Sarr goto out; 78025537Sdfr 78191040Sarr /* 78291040Sarr * If path do not contain qualified name or any dot in it 78391040Sarr * (kldname.ko, or kldname.ver.ko) treat it as interface 78491040Sarr * name. 78591040Sarr */ 78691040Sarr if (index(pathname, '/') || index(pathname, '.')) { 78791040Sarr kldname = pathname; 78891040Sarr modname = NULL; 78991040Sarr } else { 79091040Sarr kldname = NULL; 79191040Sarr modname = pathname; 79291040Sarr } 79391040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 79491040Sarr if (error) 79591040Sarr goto out; 79642316Smsmith 797157144Sjkoshy#ifdef HWPMC_HOOKS 798157144Sjkoshy pkm.pm_file = lf->filename; 799157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 800157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 801157144Sjkoshy#endif 80291040Sarr lf->userrefs++; 80391040Sarr td->td_retval[0] = lf->id; 80425537Sdfrout: 80591040Sarr if (pathname) 80691040Sarr free(pathname, M_TEMP); 80791040Sarr mtx_unlock(&Giant); 80891040Sarr return (error); 80925537Sdfr} 81025537Sdfr 81182749Sdillon/* 81282749Sdillon * MPSAFE 81382749Sdillon */ 814132117Sphkstatic int 815132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 81625537Sdfr{ 817157144Sjkoshy#ifdef HWPMC_HOOKS 818157144Sjkoshy struct pmckern_map_out pkm; 819157144Sjkoshy#endif 82091040Sarr linker_file_t lf; 82191040Sarr int error = 0; 82225537Sdfr 82391040Sarr mtx_lock(&Giant); 82482749Sdillon 82593159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 82693159Sarr goto out; 82793159Sarr 82893593Sjhb if ((error = suser(td)) != 0) 82991040Sarr goto out; 83025537Sdfr 831132117Sphk lf = linker_find_file_by_id(fileid); 83291040Sarr if (lf) { 83391040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 83491040Sarr if (lf->userrefs == 0) { 835132117Sphk /* 836132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 837132117Sphk */ 83891040Sarr printf("kldunload: attempt to unload file that was" 83991040Sarr " loaded by the kernel\n"); 84091040Sarr error = EBUSY; 84191040Sarr goto out; 84291040Sarr } 84391068Sarr lf->userrefs--; 844157144Sjkoshy#ifdef HWPMC_HOOKS 845157144Sjkoshy /* Save data needed by hwpmc(4) before unloading the kld. */ 846157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 847157144Sjkoshy pkm.pm_size = lf->size; 848157144Sjkoshy#endif 849132117Sphk error = linker_file_unload(lf, flags); 85091040Sarr if (error) 85191040Sarr lf->userrefs++; 85291040Sarr } else 85391040Sarr error = ENOENT; 854157144Sjkoshy 855157144Sjkoshy#ifdef HWPMC_HOOKS 856157144Sjkoshy if (error == 0) 857157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 858157144Sjkoshy#endif 85925537Sdfrout: 86091068Sarr mtx_unlock(&Giant); 86191068Sarr return (error); 86225537Sdfr} 86325537Sdfr 86482749Sdillon/* 86582749Sdillon * MPSAFE 86682749Sdillon */ 86725537Sdfrint 868132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 869132117Sphk{ 870132117Sphk 871132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 872132117Sphk} 873132117Sphk 874132117Sphk/* 875132117Sphk * MPSAFE 876132117Sphk */ 877132117Sphkint 878132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 879132117Sphk{ 880132117Sphk 881132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 882132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 883132117Sphk return (EINVAL); 884132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 885132117Sphk} 886132117Sphk 887132117Sphk/* 888132117Sphk * MPSAFE 889132117Sphk */ 890132117Sphkint 89191040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 89225537Sdfr{ 89391040Sarr char *pathname; 89491040Sarr const char *filename; 89591040Sarr linker_file_t lf; 89691040Sarr int error = 0; 89725537Sdfr 898107089Srwatson#ifdef MAC 899107089Srwatson error = mac_check_kld_stat(td->td_ucred); 900107089Srwatson if (error) 901107089Srwatson return (error); 902107089Srwatson#endif 903107089Srwatson 90491040Sarr mtx_lock(&Giant); 90591040Sarr td->td_retval[0] = -1; 90682749Sdillon 907111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 908107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 90991040Sarr goto out; 91025537Sdfr 91191040Sarr filename = linker_basename(pathname); 91291040Sarr lf = linker_find_file_by_name(filename); 91391040Sarr if (lf) 91491040Sarr td->td_retval[0] = lf->id; 91591040Sarr else 91691040Sarr error = ENOENT; 91725537Sdfrout: 91891040Sarr if (pathname) 91991040Sarr free(pathname, M_TEMP); 92091040Sarr mtx_unlock(&Giant); 92191040Sarr return (error); 92225537Sdfr} 92325537Sdfr 92482749Sdillon/* 92582749Sdillon * MPSAFE 92682749Sdillon */ 92725537Sdfrint 92891040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 92925537Sdfr{ 93091040Sarr linker_file_t lf; 93191040Sarr int error = 0; 93225537Sdfr 933107089Srwatson#ifdef MAC 934107089Srwatson error = mac_check_kld_stat(td->td_ucred); 935107089Srwatson if (error) 936107089Srwatson return (error); 937107089Srwatson#endif 938107089Srwatson 93991040Sarr mtx_lock(&Giant); 94082749Sdillon 941107849Salfred if (uap->fileid == 0) { 94298452Sarr mtx_lock(&kld_mtx); 94391040Sarr if (TAILQ_FIRST(&linker_files)) 94491040Sarr td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; 94591040Sarr else 94691040Sarr td->td_retval[0] = 0; 94798452Sarr mtx_unlock(&kld_mtx); 94891040Sarr goto out; 94991040Sarr } 950107849Salfred lf = linker_find_file_by_id(uap->fileid); 95191040Sarr if (lf) { 95291040Sarr if (TAILQ_NEXT(lf, link)) 95391040Sarr td->td_retval[0] = TAILQ_NEXT(lf, link)->id; 95491040Sarr else 95591040Sarr td->td_retval[0] = 0; 95691040Sarr } else 95791040Sarr error = ENOENT; 95882749Sdillonout: 95991040Sarr mtx_unlock(&Giant); 96091040Sarr return (error); 96125537Sdfr} 96225537Sdfr 96382749Sdillon/* 96482749Sdillon * MPSAFE 96582749Sdillon */ 96625537Sdfrint 96791040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 96825537Sdfr{ 96991040Sarr linker_file_t lf; 97091040Sarr int error = 0; 97191040Sarr int namelen, version; 97291040Sarr struct kld_file_stat *stat; 97325537Sdfr 974107089Srwatson#ifdef MAC 975107089Srwatson error = mac_check_kld_stat(td->td_ucred); 976107089Srwatson if (error) 977107089Srwatson return (error); 978107089Srwatson#endif 979107089Srwatson 98091040Sarr mtx_lock(&Giant); 98182749Sdillon 982107849Salfred lf = linker_find_file_by_id(uap->fileid); 98391040Sarr if (lf == NULL) { 98491040Sarr error = ENOENT; 98591040Sarr goto out; 98691040Sarr } 987107849Salfred stat = uap->stat; 98825537Sdfr 98991040Sarr /* 99091040Sarr * Check the version of the user's structure. 99191040Sarr */ 99291040Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 99391040Sarr goto out; 99491040Sarr if (version != sizeof(struct kld_file_stat)) { 99591040Sarr error = EINVAL; 99691040Sarr goto out; 99791040Sarr } 99891040Sarr namelen = strlen(lf->filename) + 1; 99991040Sarr if (namelen > MAXPATHLEN) 100091040Sarr namelen = MAXPATHLEN; 100191040Sarr if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) 100291040Sarr goto out; 100391040Sarr if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) 100491040Sarr goto out; 100591040Sarr if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) 100691040Sarr goto out; 100791040Sarr if ((error = copyout(&lf->address, &stat->address, 100891040Sarr sizeof(caddr_t))) != 0) 100991040Sarr goto out; 101091040Sarr if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) 101191040Sarr goto out; 101225537Sdfr 101391040Sarr td->td_retval[0] = 0; 101425537Sdfrout: 101591040Sarr mtx_unlock(&Giant); 101691040Sarr return (error); 101725537Sdfr} 101825537Sdfr 101982749Sdillon/* 102082749Sdillon * MPSAFE 102182749Sdillon */ 102225537Sdfrint 102391040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 102425537Sdfr{ 102591040Sarr linker_file_t lf; 102691040Sarr module_t mp; 102791040Sarr int error = 0; 102825537Sdfr 1029107089Srwatson#ifdef MAC 1030107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1031107089Srwatson if (error) 1032107089Srwatson return (error); 1033107089Srwatson#endif 1034107089Srwatson 103591040Sarr mtx_lock(&Giant); 1036107849Salfred lf = linker_find_file_by_id(uap->fileid); 103791040Sarr if (lf) { 103892547Sarr MOD_SLOCK; 103991040Sarr mp = TAILQ_FIRST(&lf->modules); 104091040Sarr if (mp != NULL) 104191040Sarr td->td_retval[0] = module_getid(mp); 104291040Sarr else 104391040Sarr td->td_retval[0] = 0; 104492547Sarr MOD_SUNLOCK; 104591040Sarr } else 104691040Sarr error = ENOENT; 104791040Sarr mtx_unlock(&Giant); 104891040Sarr return (error); 104925537Sdfr} 105040159Speter 105182749Sdillon/* 105282749Sdillon * MPSAFE 105382749Sdillon */ 105441090Speterint 105583366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 105641090Speter{ 105791040Sarr char *symstr = NULL; 105891040Sarr c_linker_sym_t sym; 105991040Sarr linker_symval_t symval; 106091040Sarr linker_file_t lf; 106191040Sarr struct kld_sym_lookup lookup; 106291040Sarr int error = 0; 106341090Speter 1064107089Srwatson#ifdef MAC 1065107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1066107089Srwatson if (error) 1067107089Srwatson return (error); 1068107089Srwatson#endif 1069107089Srwatson 107091040Sarr mtx_lock(&Giant); 107182749Sdillon 1072107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 107391040Sarr goto out; 107491068Sarr if (lookup.version != sizeof(lookup) || 1075107849Salfred uap->cmd != KLDSYM_LOOKUP) { 107691040Sarr error = EINVAL; 107791040Sarr goto out; 107891040Sarr } 1079111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 108091040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 108191040Sarr goto out; 1082107849Salfred if (uap->fileid != 0) { 1083107849Salfred lf = linker_find_file_by_id(uap->fileid); 108491040Sarr if (lf == NULL) { 108591040Sarr error = ENOENT; 108691040Sarr goto out; 108791040Sarr } 108891040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 108991040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 109091040Sarr lookup.symvalue = (uintptr_t) symval.value; 109191040Sarr lookup.symsize = symval.size; 1092107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 109391040Sarr } else 109491040Sarr error = ENOENT; 109591040Sarr } else { 109698452Sarr mtx_lock(&kld_mtx); 109791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 109891040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 109991040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 110091040Sarr lookup.symvalue = (uintptr_t)symval.value; 110191040Sarr lookup.symsize = symval.size; 1102107849Salfred error = copyout(&lookup, uap->data, 110391040Sarr sizeof(lookup)); 110491068Sarr break; 110591040Sarr } 110691040Sarr } 110798452Sarr mtx_unlock(&kld_mtx); 110891040Sarr if (lf == NULL) 110991040Sarr error = ENOENT; 111041090Speter } 111141090Speterout: 111291040Sarr if (symstr) 111391040Sarr free(symstr, M_TEMP); 111491040Sarr mtx_unlock(&Giant); 111591040Sarr return (error); 111641090Speter} 111741090Speter 111840159Speter/* 111940159Speter * Preloaded module support 112040159Speter */ 112140159Speter 112259751Speterstatic modlist_t 112374642Sbpmodlist_lookup(const char *name, int ver) 112459751Speter{ 112591040Sarr modlist_t mod; 112659751Speter 112791040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 112892032Sdwmalone if (strcmp(mod->name, name) == 0 && 112992032Sdwmalone (ver == 0 || mod->version == ver)) 113091040Sarr return (mod); 113191040Sarr } 113291040Sarr return (NULL); 113359751Speter} 113459751Speter 113574642Sbpstatic modlist_t 113683321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 113783321Speter{ 113891040Sarr modlist_t mod, bestmod; 113992032Sdwmalone int ver; 114083321Speter 114191040Sarr if (verinfo == NULL) 114291040Sarr return (modlist_lookup(name, 0)); 114391040Sarr bestmod = NULL; 114491040Sarr for (mod = TAILQ_FIRST(&found_modules); mod; 114591040Sarr mod = TAILQ_NEXT(mod, link)) { 114692032Sdwmalone if (strcmp(mod->name, name) != 0) 114791040Sarr continue; 114891040Sarr ver = mod->version; 114991040Sarr if (ver == verinfo->md_ver_preferred) 115091040Sarr return (mod); 115191040Sarr if (ver >= verinfo->md_ver_minimum && 115291068Sarr ver <= verinfo->md_ver_maximum && 1153120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 115491040Sarr bestmod = mod; 115591040Sarr } 115691040Sarr return (bestmod); 115783321Speter} 115883321Speter 115983321Speterstatic modlist_t 116078501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 116174642Sbp{ 116291040Sarr modlist_t mod; 116374642Sbp 116492705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 116591040Sarr if (mod == NULL) 116691040Sarr panic("no memory for module list"); 116791040Sarr mod->container = container; 116891040Sarr mod->name = modname; 116991040Sarr mod->version = version; 117091040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 117191040Sarr return (mod); 117274642Sbp} 117374642Sbp 117440159Speterstatic void 117578161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 117691040Sarr struct mod_metadata **stop, int preload) 117774642Sbp{ 117891040Sarr struct mod_metadata *mp, **mdp; 117991040Sarr const char *modname; 118091040Sarr int ver; 118174642Sbp 118291040Sarr for (mdp = start; mdp < stop; mdp++) { 1183109605Sjake mp = *mdp; 118491040Sarr if (mp->md_type != MDT_VERSION) 118591040Sarr continue; 1186109605Sjake modname = mp->md_cval; 1187109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 118891040Sarr if (modlist_lookup(modname, ver) != NULL) { 118991040Sarr printf("module %s already present!\n", modname); 119091040Sarr /* XXX what can we do? this is a build error. :-( */ 119191040Sarr continue; 119291040Sarr } 119391040Sarr modlist_newmodule(modname, ver, lf); 119474642Sbp } 119574642Sbp} 119674642Sbp 119774642Sbpstatic void 119891040Sarrlinker_preload(void *arg) 119940159Speter{ 120091040Sarr caddr_t modptr; 120191040Sarr const char *modname, *nmodname; 120291040Sarr char *modtype; 120391040Sarr linker_file_t lf; 120491040Sarr linker_class_t lc; 120592032Sdwmalone int error; 120691040Sarr linker_file_list_t loaded_files; 120791040Sarr linker_file_list_t depended_files; 120891040Sarr struct mod_metadata *mp, *nmp; 120991040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 121091040Sarr struct mod_depend *verinfo; 121191040Sarr int nver; 121291040Sarr int resolves; 121391040Sarr modlist_t mod; 121491040Sarr struct sysinit **si_start, **si_stop; 121540159Speter 121691040Sarr TAILQ_INIT(&loaded_files); 121791040Sarr TAILQ_INIT(&depended_files); 121891040Sarr TAILQ_INIT(&found_modules); 121991040Sarr error = 0; 122059751Speter 122191040Sarr modptr = NULL; 122291040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 122391040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 122491040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 122591040Sarr if (modname == NULL) { 122691040Sarr printf("Preloaded module at %p does not have a" 122791040Sarr " name!\n", modptr); 122891040Sarr continue; 122991040Sarr } 123091040Sarr if (modtype == NULL) { 123191040Sarr printf("Preloaded module at %p does not have a type!\n", 123291040Sarr modptr); 123391040Sarr continue; 123491040Sarr } 1235131398Sjhb if (bootverbose) 1236131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1237131398Sjhb modptr); 123840159Speter lf = NULL; 123991040Sarr TAILQ_FOREACH(lc, &classes, link) { 124091040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1241134364Siedowse if (!error) 124291040Sarr break; 1243134364Siedowse lf = NULL; 124491040Sarr } 124591040Sarr if (lf) 124691040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 124740159Speter } 124840159Speter 124991040Sarr /* 125091040Sarr * First get a list of stuff in the kernel. 125191040Sarr */ 125291040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 125391040Sarr &stop, NULL) == 0) 125491040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 125559751Speter 125659751Speter /* 125791040Sarr * this is a once-off kinky bubble sort resolve relocation dependency 125891040Sarr * requirements 125959751Speter */ 126091040Sarrrestart: 126191040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 126291040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 126391040Sarr &stop, NULL); 126491040Sarr /* 126591040Sarr * First, look to see if we would successfully link with this 126691040Sarr * stuff. 126791040Sarr */ 126891040Sarr resolves = 1; /* unless we know otherwise */ 126991040Sarr if (!error) { 127091040Sarr for (mdp = start; mdp < stop; mdp++) { 1271109605Sjake mp = *mdp; 127291040Sarr if (mp->md_type != MDT_DEPEND) 127391040Sarr continue; 1274109605Sjake modname = mp->md_cval; 1275109605Sjake verinfo = mp->md_data; 127691040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1277109605Sjake nmp = *nmdp; 127891040Sarr if (nmp->md_type != MDT_VERSION) 127991040Sarr continue; 1280109605Sjake nmodname = nmp->md_cval; 128192032Sdwmalone if (strcmp(modname, nmodname) == 0) 128291040Sarr break; 128391040Sarr } 128491040Sarr if (nmdp < stop) /* it's a self reference */ 128591040Sarr continue; 128691040Sarr 128791040Sarr /* 128891040Sarr * ok, the module isn't here yet, we 128991040Sarr * are not finished 129091040Sarr */ 129191068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 129291040Sarr resolves = 0; 129391040Sarr } 129464143Speter } 129591040Sarr /* 129691040Sarr * OK, if we found our modules, we can link. So, "provide" 129791040Sarr * the modules inside and add it to the end of the link order 129891040Sarr * list. 129991040Sarr */ 130091040Sarr if (resolves) { 130191040Sarr if (!error) { 130291040Sarr for (mdp = start; mdp < stop; mdp++) { 1303109605Sjake mp = *mdp; 130491040Sarr if (mp->md_type != MDT_VERSION) 130591040Sarr continue; 1306109605Sjake modname = mp->md_cval; 1307109605Sjake nver = ((struct mod_version *) 1308109605Sjake mp->md_data)->mv_version; 130991040Sarr if (modlist_lookup(modname, 131091040Sarr nver) != NULL) { 131191040Sarr printf("module %s already" 131291040Sarr " present!\n", modname); 1313132117Sphk linker_file_unload(lf, 1314132117Sphk LINKER_UNLOAD_FORCE); 131591040Sarr TAILQ_REMOVE(&loaded_files, 131691040Sarr lf, loaded); 131791040Sarr /* we changed tailq next ptr */ 131891068Sarr goto restart; 131991040Sarr } 132091040Sarr modlist_newmodule(modname, nver, lf); 132191040Sarr } 132291040Sarr } 132391040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 132491040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 132591040Sarr /* 132691040Sarr * Since we provided modules, we need to restart the 132791040Sarr * sort so that the previous files that depend on us 132891040Sarr * have a chance. Also, we've busted the tailq next 132991040Sarr * pointer with the REMOVE. 133091040Sarr */ 133191040Sarr goto restart; 133259751Speter } 133359751Speter } 133491040Sarr 133559751Speter /* 133691040Sarr * At this point, we check to see what could not be resolved.. 133759751Speter */ 133891040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 133991040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1340132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 134191040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 134240159Speter } 134359751Speter 134478161Speter /* 134591040Sarr * We made it. Finish off the linking in the order we determined. 134678161Speter */ 134791040Sarr TAILQ_FOREACH(lf, &depended_files, loaded) { 134891040Sarr if (linker_kernel_file) { 134991040Sarr linker_kernel_file->refs++; 135091040Sarr error = linker_file_add_dependency(lf, 135191040Sarr linker_kernel_file); 135291040Sarr if (error) 135391040Sarr panic("cannot add dependency"); 135491040Sarr } 135591040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 135691040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 135791040Sarr &stop, NULL); 135891040Sarr if (!error) { 135991040Sarr for (mdp = start; mdp < stop; mdp++) { 1360109605Sjake mp = *mdp; 136191040Sarr if (mp->md_type != MDT_DEPEND) 136291040Sarr continue; 1363109605Sjake modname = mp->md_cval; 1364109605Sjake verinfo = mp->md_data; 136591040Sarr mod = modlist_lookup2(modname, verinfo); 1366151484Sjdp /* Don't count self-dependencies */ 1367151484Sjdp if (lf == mod->container) 1368151484Sjdp continue; 136991040Sarr mod->container->refs++; 137091040Sarr error = linker_file_add_dependency(lf, 137191040Sarr mod->container); 137291040Sarr if (error) 137391040Sarr panic("cannot add dependency"); 137491040Sarr } 137591040Sarr } 137691040Sarr /* 137791040Sarr * Now do relocation etc using the symbol search paths 137891040Sarr * established by the dependencies 137991040Sarr */ 138091040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 138191040Sarr if (error) { 138291040Sarr printf("KLD file %s - could not finalize loading\n", 138391040Sarr lf->filename); 1384132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 138591040Sarr continue; 138691040Sarr } 138791040Sarr linker_file_register_modules(lf); 138891040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 138991040Sarr &si_stop, NULL) == 0) 139091040Sarr sysinit_add(si_start, si_stop); 139191040Sarr linker_file_register_sysctls(lf); 139291040Sarr lf->flags |= LINKER_FILE_LINKED; 139359751Speter } 139491040Sarr /* woohoo! we made it! */ 139540159Speter} 139640159Speter 139791040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0) 139840159Speter 139940159Speter/* 140040159Speter * Search for a not-loaded module by name. 140191040Sarr * 140240159Speter * Modules may be found in the following locations: 140391040Sarr * 140491040Sarr * - preloaded (result is just the module name) - on disk (result is full path 140591040Sarr * to module) 140691040Sarr * 140791040Sarr * If the module name is qualified in any way (contains path, etc.) the we 140891040Sarr * simply return a copy of it. 140991040Sarr * 141040159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 141140159Speter * character as a separator to be consistent with the bootloader. 141240159Speter */ 141340159Speter 141483321Speterstatic char linker_hintfile[] = "linker.hints"; 1415111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 141640159Speter 141740159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 141891040Sarr sizeof(linker_path), "module load search path"); 141940159Speter 142077843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 142170417Speter 142259751Speterstatic char *linker_ext_list[] = { 142383321Speter "", 142459751Speter ".ko", 142559751Speter NULL 142659751Speter}; 142759751Speter 142883321Speter/* 142991040Sarr * Check if file actually exists either with or without extension listed in 143091040Sarr * the linker_ext_list. (probably should be generic for the rest of the 143191040Sarr * kernel) 143283321Speter */ 143359751Speterstatic char * 143491040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 143591040Sarr int namelen, struct vattr *vap) 143640159Speter{ 143791040Sarr struct nameidata nd; 143891040Sarr struct thread *td = curthread; /* XXX */ 143991040Sarr char *result, **cpp, *sep; 144091040Sarr int error, len, extlen, reclen, flags; 144191040Sarr enum vtype type; 144240159Speter 144391040Sarr extlen = 0; 144491040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 144591040Sarr len = strlen(*cpp); 144691040Sarr if (len > extlen) 144791040Sarr extlen = len; 144891040Sarr } 144991040Sarr extlen++; /* trailing '\0' */ 145091040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 145183321Speter 145291040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1453111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 145491040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 145591040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 145691040Sarr namelen, name, *cpp); 145791040Sarr /* 145891040Sarr * Attempt to open the file, and return the path if 145991040Sarr * we succeed and it's a regular file. 146091040Sarr */ 146191040Sarr NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); 146291040Sarr flags = FREAD; 1463118094Sphk error = vn_open(&nd, &flags, 0, -1); 146491040Sarr if (error == 0) { 146591040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 146691040Sarr type = nd.ni_vp->v_type; 146791040Sarr if (vap) 146891406Sjhb VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 146991040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 147091406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 147191040Sarr if (type == VREG) 147291040Sarr return (result); 147391040Sarr } 147483321Speter } 147591040Sarr free(result, M_LINKER); 147691040Sarr return (NULL); 147783321Speter} 147883321Speter 147991040Sarr#define INT_ALIGN(base, ptr) ptr = \ 148083321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 148183321Speter 148283321Speter/* 148391040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 148491040Sarr * version specification is available, then try to find the best KLD. 148583321Speter * Otherwise just find the latest one. 148683321Speter */ 148783321Speterstatic char * 148891040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 148991040Sarr int modnamelen, struct mod_depend *verinfo) 149083321Speter{ 149191040Sarr struct thread *td = curthread; /* XXX */ 149291406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 149391040Sarr struct nameidata nd; 149491040Sarr struct vattr vattr, mattr; 149591040Sarr u_char *hints = NULL; 149691040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 149791040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 149883321Speter 149991040Sarr result = NULL; 150091040Sarr bestver = found = 0; 150183321Speter 150291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 150391040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 150491040Sarr strlen(sep) + 1; 1505111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 150691040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 150791040Sarr linker_hintfile); 150883321Speter 150991040Sarr NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); 151091040Sarr flags = FREAD; 1511118094Sphk error = vn_open(&nd, &flags, 0, -1); 151291040Sarr if (error) 151391040Sarr goto bad; 151491040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 151591040Sarr if (nd.ni_vp->v_type != VREG) 151691040Sarr goto bad; 151791040Sarr best = cp = NULL; 151891040Sarr error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td); 151991040Sarr if (error) 152091040Sarr goto bad; 152191040Sarr /* 152291040Sarr * XXX: we need to limit this number to some reasonable value 152391040Sarr */ 152491040Sarr if (vattr.va_size > 100 * 1024) { 152591040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 152691040Sarr goto bad; 152791040Sarr } 1528111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 152991040Sarr if (hints == NULL) 153091040Sarr goto bad; 153191068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1532101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 153391040Sarr if (error) 153491040Sarr goto bad; 153599553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 153691040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 153791040Sarr nd.ni_vp = NULL; 153891040Sarr if (reclen != 0) { 153991040Sarr printf("can't read %d\n", reclen); 154091040Sarr goto bad; 154191040Sarr } 154291040Sarr intp = (int *)hints; 154383321Speter ival = *intp++; 154491040Sarr if (ival != LINKER_HINTS_VERSION) { 154591040Sarr printf("hints file version mismatch %d\n", ival); 154691040Sarr goto bad; 154783321Speter } 154891040Sarr bufend = hints + vattr.va_size; 154991040Sarr recptr = (u_char *)intp; 155091040Sarr clen = blen = 0; 155191040Sarr while (recptr < bufend && !found) { 155291040Sarr intp = (int *)recptr; 155391040Sarr reclen = *intp++; 155491040Sarr ival = *intp++; 155591040Sarr cp = (char *)intp; 155691040Sarr switch (ival) { 155791040Sarr case MDT_VERSION: 155891040Sarr clen = *cp++; 155991040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 156091040Sarr break; 156191040Sarr cp += clen; 156291040Sarr INT_ALIGN(hints, cp); 156391040Sarr ival = *(int *)cp; 156491040Sarr cp += sizeof(int); 156591040Sarr clen = *cp++; 156691040Sarr if (verinfo == NULL || 156791040Sarr ival == verinfo->md_ver_preferred) { 156891040Sarr found = 1; 156991040Sarr break; 157091040Sarr } 157191040Sarr if (ival >= verinfo->md_ver_minimum && 157291040Sarr ival <= verinfo->md_ver_maximum && 157391040Sarr ival > bestver) { 157491040Sarr bestver = ival; 157591040Sarr best = cp; 157691040Sarr blen = clen; 157791040Sarr } 157891040Sarr break; 157991040Sarr default: 158091040Sarr break; 158191040Sarr } 158291040Sarr recptr += reclen + sizeof(int); 158391040Sarr } 158483321Speter /* 158591040Sarr * Finally check if KLD is in the place 158683321Speter */ 158791040Sarr if (found) 158891040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 158991040Sarr else if (best) 159091040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 159191040Sarr 159291040Sarr /* 159391040Sarr * KLD is newer than hints file. What we should do now? 159491040Sarr */ 159591040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 159691040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 159791040Sarr " file\n", result); 159883321Speterbad: 1599105167Sphk free(pathbuf, M_LINKER); 160091040Sarr if (hints) 160191040Sarr free(hints, M_TEMP); 160299553Sjeff if (nd.ni_vp != NULL) { 160399553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 160491040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 160599553Sjeff } 160691040Sarr /* 160791040Sarr * If nothing found or hints is absent - fallback to the old 160891040Sarr * way by using "kldname[.ko]" as module name. 160991040Sarr */ 161091040Sarr if (!found && !bestver && result == NULL) 161191040Sarr result = linker_lookup_file(path, pathlen, modname, 161291040Sarr modnamelen, NULL); 161391040Sarr return (result); 161483321Speter} 161583321Speter 161683321Speter/* 161783321Speter * Lookup KLD which contains requested module in the all directories. 161883321Speter */ 161983321Speterstatic char * 162083321Speterlinker_search_module(const char *modname, int modnamelen, 162191040Sarr struct mod_depend *verinfo) 162283321Speter{ 162391040Sarr char *cp, *ep, *result; 162483321Speter 162591040Sarr /* 162691040Sarr * traverse the linker path 162791040Sarr */ 162891040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 162991040Sarr /* find the end of this component */ 163091040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 163191068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 163291068Sarr modnamelen, verinfo); 163391040Sarr if (result != NULL) 163491040Sarr return (result); 163591040Sarr if (*ep == 0) 163691040Sarr break; 163791040Sarr } 163891040Sarr return (NULL); 163983321Speter} 164083321Speter 164183321Speter/* 164283321Speter * Search for module in all directories listed in the linker_path. 164383321Speter */ 164483321Speterstatic char * 164583321Speterlinker_search_kld(const char *name) 164683321Speter{ 164791040Sarr char *cp, *ep, *result, **cpp; 164891040Sarr int extlen, len; 164983321Speter 165091040Sarr /* qualified at all? */ 165191040Sarr if (index(name, '/')) 165291040Sarr return (linker_strdup(name)); 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' */ 166159751Speter 166291040Sarr /* traverse the linker path */ 166391040Sarr len = strlen(name); 166491040Sarr for (ep = linker_path; *ep; ep++) { 166591040Sarr cp = ep; 166691040Sarr /* find the end of this component */ 166791040Sarr for (; *ep != 0 && *ep != ';'; ep++); 166891040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 166991040Sarr if (result != NULL) 167091040Sarr return (result); 167191040Sarr } 167291040Sarr return (NULL); 167340159Speter} 167459751Speter 167559751Speterstatic const char * 167691040Sarrlinker_basename(const char *path) 167759751Speter{ 167891040Sarr const char *filename; 167959751Speter 168091040Sarr filename = rindex(path, '/'); 168191040Sarr if (filename == NULL) 168291040Sarr return path; 168391040Sarr if (filename[1]) 168491040Sarr filename++; 168591040Sarr return (filename); 168659751Speter} 168759751Speter 1688157144Sjkoshy#ifdef HWPMC_HOOKS 1689157144Sjkoshy 169059751Speter/* 1691157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1692157144Sjkoshy */ 1693157144Sjkoshyvoid * 1694157144Sjkoshylinker_hwpmc_list_objects(void) 1695157144Sjkoshy{ 1696157144Sjkoshy int nobjects, nmappings; 1697157144Sjkoshy linker_file_t lf; 1698157144Sjkoshy struct pmckern_map_in *ko, *kobase; 1699157144Sjkoshy 1700157144Sjkoshy nmappings = 15; /* a reasonable default */ 1701157144Sjkoshy 1702157144Sjkoshy retry: 1703157144Sjkoshy /* allocate nmappings+1 entries */ 1704157144Sjkoshy MALLOC(kobase, struct pmckern_map_in *, 1705157144Sjkoshy (nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, 1706157144Sjkoshy M_WAITOK | M_ZERO); 1707157144Sjkoshy 1708157144Sjkoshy nobjects = 0; 1709157144Sjkoshy mtx_lock(&kld_mtx); 1710157144Sjkoshy TAILQ_FOREACH(lf, &linker_files, link) 1711157144Sjkoshy nobjects++; 1712157144Sjkoshy 1713157144Sjkoshy KASSERT(nobjects > 0, ("linker_hpwmc_list_objects: no kernel " 1714157144Sjkoshy "objects?")); 1715157144Sjkoshy 1716157144Sjkoshy if (nobjects > nmappings) { 1717157144Sjkoshy nmappings = nobjects; 1718157144Sjkoshy FREE(kobase, M_LINKER); 1719157144Sjkoshy mtx_unlock(&kld_mtx); 1720157144Sjkoshy goto retry; 1721157144Sjkoshy } 1722157144Sjkoshy 1723157144Sjkoshy ko = kobase; 1724157144Sjkoshy TAILQ_FOREACH(lf, &linker_files, link) { 1725157144Sjkoshy ko->pm_file = lf->filename; 1726157144Sjkoshy ko->pm_address = (uintptr_t) lf->address; 1727157144Sjkoshy ko++; 1728157144Sjkoshy } 1729157144Sjkoshy 1730157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1731157144Sjkoshy KASSERT(ko->pm_file == NULL, 1732157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1733157144Sjkoshy 1734157144Sjkoshy mtx_unlock(&kld_mtx); 1735157144Sjkoshy 1736157144Sjkoshy return ((void *) kobase); 1737157144Sjkoshy} 1738157144Sjkoshy#endif 1739157144Sjkoshy 1740157144Sjkoshy/* 174191040Sarr * Find a file which contains given module and load it, if "parent" is not 174291040Sarr * NULL, register a reference to it. 174359751Speter */ 1744101241Smuxint 174583321Speterlinker_load_module(const char *kldname, const char *modname, 174691040Sarr struct linker_file *parent, struct mod_depend *verinfo, 174791040Sarr struct linker_file **lfpp) 174859751Speter{ 174991040Sarr linker_file_t lfdep; 175091040Sarr const char *filename; 175191040Sarr char *pathname; 175291040Sarr int error; 175359751Speter 175491040Sarr if (modname == NULL) { 175591040Sarr /* 175691040Sarr * We have to load KLD 175791040Sarr */ 175891068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 175991068Sarr " is not NULL")); 176091040Sarr pathname = linker_search_kld(kldname); 176191040Sarr } else { 176291040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 176391040Sarr return (EEXIST); 176494322Sbrian if (kldname != NULL) 176594322Sbrian pathname = linker_strdup(kldname); 176695488Sbrian else if (rootvnode == NULL) 176794322Sbrian pathname = NULL; 176894322Sbrian else 176991040Sarr /* 177091040Sarr * Need to find a KLD with required module 177191040Sarr */ 177291040Sarr pathname = linker_search_module(modname, 177391040Sarr strlen(modname), verinfo); 177491040Sarr } 177591040Sarr if (pathname == NULL) 177691040Sarr return (ENOENT); 177791040Sarr 177883321Speter /* 177991040Sarr * Can't load more than one file with the same basename XXX: 178091040Sarr * Actually it should be possible to have multiple KLDs with 178191040Sarr * the same basename but different path because they can 178291040Sarr * provide different versions of the same modules. 178383321Speter */ 178491040Sarr filename = linker_basename(pathname); 178591040Sarr if (linker_find_file_by_name(filename)) { 178691040Sarr error = EEXIST; 178791040Sarr goto out; 178883321Speter } 178991040Sarr do { 179091040Sarr error = linker_load_file(pathname, &lfdep); 179191040Sarr if (error) 179291040Sarr break; 179391040Sarr if (modname && verinfo && 179491040Sarr modlist_lookup2(modname, verinfo) == NULL) { 1795132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 179691040Sarr error = ENOENT; 179791040Sarr break; 179891040Sarr } 179991040Sarr if (parent) { 180091040Sarr error = linker_file_add_dependency(parent, lfdep); 180191040Sarr if (error) 180291040Sarr break; 180391040Sarr } 180491040Sarr if (lfpp) 180591040Sarr *lfpp = lfdep; 180691040Sarr } while (0); 180759751Speterout: 180891040Sarr if (pathname) 180991040Sarr free(pathname, M_LINKER); 181091040Sarr return (error); 181159751Speter} 181259751Speter 181359751Speter/* 181491040Sarr * This routine is responsible for finding dependencies of userland initiated 181591040Sarr * kldload(2)'s of files. 181659751Speter */ 181759751Speterint 181886469Siedowselinker_load_dependencies(linker_file_t lf) 181959751Speter{ 182091040Sarr linker_file_t lfdep; 182191040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 182291040Sarr struct mod_metadata *mp, *nmp; 182391040Sarr struct mod_depend *verinfo; 182491040Sarr modlist_t mod; 182591040Sarr const char *modname, *nmodname; 182692032Sdwmalone int ver, error = 0, count; 182759751Speter 182891040Sarr /* 182991040Sarr * All files are dependant on /kernel. 183091040Sarr */ 183191040Sarr if (linker_kernel_file) { 183291040Sarr linker_kernel_file->refs++; 183391040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 183491040Sarr if (error) 183591040Sarr return (error); 183659751Speter } 183791040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 183891040Sarr &count) != 0) 183991040Sarr return (0); 184091040Sarr for (mdp = start; mdp < stop; mdp++) { 1841109605Sjake mp = *mdp; 184291040Sarr if (mp->md_type != MDT_VERSION) 184391040Sarr continue; 1844109605Sjake modname = mp->md_cval; 1845109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 184691040Sarr mod = modlist_lookup(modname, ver); 184791040Sarr if (mod != NULL) { 184891040Sarr printf("interface %s.%d already present in the KLD" 184991040Sarr " '%s'!\n", modname, ver, 185091040Sarr mod->container->filename); 185191040Sarr return (EEXIST); 185291040Sarr } 185391040Sarr } 185474642Sbp 185591040Sarr for (mdp = start; mdp < stop; mdp++) { 1856109605Sjake mp = *mdp; 185791040Sarr if (mp->md_type != MDT_DEPEND) 185891040Sarr continue; 1859109605Sjake modname = mp->md_cval; 1860109605Sjake verinfo = mp->md_data; 186191040Sarr nmodname = NULL; 186291040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1863109605Sjake nmp = *nmdp; 186491040Sarr if (nmp->md_type != MDT_VERSION) 186591040Sarr continue; 1866109605Sjake nmodname = nmp->md_cval; 186792032Sdwmalone if (strcmp(modname, nmodname) == 0) 186891040Sarr break; 186991040Sarr } 187091040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 187191040Sarr continue; 187291040Sarr mod = modlist_lookup2(modname, verinfo); 187391040Sarr if (mod) { /* woohoo, it's loaded already */ 187491040Sarr lfdep = mod->container; 187591040Sarr lfdep->refs++; 187691040Sarr error = linker_file_add_dependency(lf, lfdep); 187791040Sarr if (error) 187891040Sarr break; 187991040Sarr continue; 188091040Sarr } 188191040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 188291040Sarr if (error) { 188391040Sarr printf("KLD %s: depends on %s - not available\n", 188491040Sarr lf->filename, modname); 188591040Sarr break; 188691040Sarr } 188759751Speter } 188859751Speter 188991040Sarr if (error) 189091040Sarr return (error); 189191040Sarr linker_addmodules(lf, start, stop, 0); 189291040Sarr return (error); 189359751Speter} 189485736Sgreen 189585736Sgreenstatic int 189685736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 189785736Sgreen{ 189885736Sgreen struct sysctl_req *req; 189985736Sgreen 190085736Sgreen req = opaque; 190185736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 190285736Sgreen} 190385736Sgreen 190485736Sgreen/* 190585736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 190685736Sgreen * in the kernel. 190785736Sgreen */ 190885736Sgreenstatic int 190985736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 191085736Sgreen{ 191185736Sgreen linker_file_t lf; 191285736Sgreen int error; 191385736Sgreen 1914107089Srwatson#ifdef MAC 1915107089Srwatson error = mac_check_kld_stat(req->td->td_ucred); 1916107089Srwatson if (error) 1917107089Srwatson return (error); 1918107089Srwatson#endif 1919126253Struckman error = sysctl_wire_old_buffer(req, 0); 1920126253Struckman if (error != 0) 1921126253Struckman return (error); 192298452Sarr mtx_lock(&kld_mtx); 192385736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 192485736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 192585736Sgreen sysctl_kern_function_list_iterate, req); 192698452Sarr if (error) { 192798452Sarr mtx_unlock(&kld_mtx); 192885736Sgreen return (error); 192998452Sarr } 193085736Sgreen } 193198452Sarr mtx_unlock(&kld_mtx); 193285736Sgreen return (SYSCTL_OUT(req, "", 1)); 193385736Sgreen} 193485736Sgreen 193585736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 193691040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 1937