kern_linker.c revision 118094
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 118094 2003-07-27 17:04:56Z phk $"); 29116182Sobrien 3040159Speter#include "opt_ddb.h" 31107089Srwatson#include "opt_mac.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> 3925537Sdfr#include <sys/proc.h> 4025537Sdfr#include <sys/lock.h> 4182749Sdillon#include <sys/mutex.h> 4292547Sarr#include <sys/sx.h> 43107089Srwatson#include <sys/mac.h> 4425537Sdfr#include <sys/module.h> 4525537Sdfr#include <sys/linker.h> 4640159Speter#include <sys/fcntl.h> 4740159Speter#include <sys/libkern.h> 4840159Speter#include <sys/namei.h> 4940159Speter#include <sys/vnode.h> 5040159Speter#include <sys/sysctl.h> 5125537Sdfr 5259603Sdfr#include "linker_if.h" 5359603Sdfr 5440961Speter#ifdef KLD_DEBUG 5540961Speterint kld_debug = 0; 5640961Speter#endif 5740961Speter 5891040Sarr/* 5991040Sarr * static char *linker_search_path(const char *name, struct mod_depend 6091040Sarr * *verinfo); 6191040Sarr */ 6291040Sarrstatic const char *linker_basename(const char *path); 6359751Speter 6478161Speter/* Metadata from the static kernel */ 6578161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 6678161Speter 6759751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 6859751Speter 6940906Speterlinker_file_t linker_kernel_file; 7031324Sbde 7198452Sarrstatic struct mtx kld_mtx; /* kernel linker mutex */ 7298452Sarr 7325537Sdfrstatic linker_class_list_t classes; 7450068Sgrogstatic linker_file_list_t linker_files; 7525537Sdfrstatic int next_file_id = 1; 7698452Sarrstatic int linker_no_more_classes = 0; 7725537Sdfr 7886553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 7991040Sarr linker_file_t lftmp; \ 8086553Sarr \ 8186553Sarrretry: \ 8298452Sarr mtx_lock(&kld_mtx); \ 8391040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 8491040Sarr if (next_file_id == lftmp->id) { \ 8591040Sarr next_file_id++; \ 8698452Sarr mtx_unlock(&kld_mtx); \ 8791040Sarr goto retry; \ 8891040Sarr } \ 8991040Sarr } \ 9091040Sarr (a) = next_file_id; \ 9198452Sarr mtx_unlock(&kld_mtx); /* Hold for safe read of id variable */ \ 9286553Sarr} while(0) 9386553Sarr 9486553Sarr 9559751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 9660938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 9759751Speterstruct modlist { 9891040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 9991040Sarr linker_file_t container; 10091040Sarr const char *name; 10191040Sarr int version; 10259751Speter}; 10391040Sarrtypedef struct modlist *modlist_t; 10491040Sarrstatic modlisthead_t found_modules; 10559751Speter 10694321Sbrianstatic modlist_t modlist_lookup2(const char *name, 10794321Sbrian struct mod_depend *verinfo); 10894321Sbrian 10959603Sdfrstatic char * 11059603Sdfrlinker_strdup(const char *str) 11159603Sdfr{ 11291040Sarr char *result; 11359603Sdfr 114111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 11591040Sarr strcpy(result, str); 11691040Sarr return (result); 11759603Sdfr} 11859603Sdfr 11925537Sdfrstatic void 12091040Sarrlinker_init(void *arg) 12125537Sdfr{ 12291040Sarr 12398452Sarr mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF); 12491040Sarr TAILQ_INIT(&classes); 12591040Sarr TAILQ_INIT(&linker_files); 12625537Sdfr} 12725537Sdfr 12891040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0) 12925537Sdfr 13098452Sarrstatic void 13198452Sarrlinker_stop_class_add(void *arg) 13298452Sarr{ 13398452Sarr 13498452Sarr linker_no_more_classes = 1; 13598452Sarr} 13698452Sarr 13798452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL) 13898452Sarr 13925537Sdfrint 14059603Sdfrlinker_add_class(linker_class_t lc) 14125537Sdfr{ 14291040Sarr 14398452Sarr /* 14498452Sarr * We disallow any class registration passt SI_ORDER_ANY 14598452Sarr * of SI_SUB_KLD. 14698452Sarr */ 14798452Sarr if (linker_no_more_classes == 1) 14898452Sarr return (EPERM); 14991040Sarr kobj_class_compile((kobj_class_t) lc); 15091040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 15191040Sarr return (0); 15225537Sdfr} 15325537Sdfr 15425537Sdfrstatic void 15525537Sdfrlinker_file_sysinit(linker_file_t lf) 15625537Sdfr{ 15791040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 15825537Sdfr 15991040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 16091040Sarr lf->filename)); 16125537Sdfr 16291040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 16391040Sarr return; 16491040Sarr /* 16591040Sarr * Perform a bubble sort of the system initialization objects by 16691040Sarr * their subsystem (primary key) and order (secondary key). 16791040Sarr * 16891040Sarr * Since some things care about execution order, this is the operation 16991040Sarr * which ensures continued function. 17091040Sarr */ 17191040Sarr for (sipp = start; sipp < stop; sipp++) { 17291040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 17391040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 17491040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 17591040Sarr (*sipp)->order <= (*xipp)->order)) 17691040Sarr continue; /* skip */ 17791040Sarr save = *sipp; 17891040Sarr *sipp = *xipp; 17991040Sarr *xipp = save; 18091040Sarr } 18125537Sdfr } 18225537Sdfr 18391040Sarr /* 18491040Sarr * Traverse the (now) ordered list of system initialization tasks. 18591040Sarr * Perform each task, and continue on to the next task. 18691040Sarr */ 18791040Sarr for (sipp = start; sipp < stop; sipp++) { 18891040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 18991040Sarr continue; /* skip dummy task(s) */ 19025537Sdfr 19191040Sarr /* Call function */ 19291040Sarr (*((*sipp)->func)) ((*sipp)->udata); 19391040Sarr } 19425537Sdfr} 19525537Sdfr 19641055Speterstatic void 19741055Speterlinker_file_sysuninit(linker_file_t lf) 19841055Speter{ 19991040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 20041055Speter 20191040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 20291040Sarr lf->filename)); 20341055Speter 20491068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 20591040Sarr NULL) != 0) 20691040Sarr return; 20741055Speter 20891040Sarr /* 20991040Sarr * Perform a reverse bubble sort of the system initialization objects 21091040Sarr * by their subsystem (primary key) and order (secondary key). 21191040Sarr * 21291040Sarr * Since some things care about execution order, this is the operation 21391040Sarr * which ensures continued function. 21491040Sarr */ 21591040Sarr for (sipp = start; sipp < stop; sipp++) { 21691040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 21791040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 21891040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 21991040Sarr (*sipp)->order >= (*xipp)->order)) 22091040Sarr continue; /* skip */ 22191040Sarr save = *sipp; 22291040Sarr *sipp = *xipp; 22391040Sarr *xipp = save; 22491040Sarr } 22541055Speter } 22641055Speter 22791040Sarr /* 22891040Sarr * Traverse the (now) ordered list of system initialization tasks. 22991040Sarr * Perform each task, and continue on to the next task. 23091040Sarr */ 23191040Sarr for (sipp = start; sipp < stop; sipp++) { 23291040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 23391040Sarr continue; /* skip dummy task(s) */ 23441055Speter 23591040Sarr /* Call function */ 23691040Sarr (*((*sipp)->func)) ((*sipp)->udata); 23791040Sarr } 23841055Speter} 23941055Speter 24044078Sdfrstatic void 24144078Sdfrlinker_file_register_sysctls(linker_file_t lf) 24244078Sdfr{ 24391040Sarr struct sysctl_oid **start, **stop, **oidp; 24444078Sdfr 24591040Sarr KLD_DPF(FILE, 24691040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 24791040Sarr lf->filename)); 24844078Sdfr 24991040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 25091040Sarr return; 25144078Sdfr 25291040Sarr for (oidp = start; oidp < stop; oidp++) 25391040Sarr sysctl_register_oid(*oidp); 25444078Sdfr} 25544078Sdfr 25644078Sdfrstatic void 25744078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 25844078Sdfr{ 25991040Sarr struct sysctl_oid **start, **stop, **oidp; 26044078Sdfr 26191040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 26291040Sarr " for %s\n", lf->filename)); 26344078Sdfr 26491040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 26591040Sarr return; 26644078Sdfr 26791040Sarr for (oidp = start; oidp < stop; oidp++) 26891040Sarr sysctl_unregister_oid(*oidp); 26944078Sdfr} 27044078Sdfr 27159751Speterstatic int 27259751Speterlinker_file_register_modules(linker_file_t lf) 27359751Speter{ 27491040Sarr struct mod_metadata **start, **stop, **mdp; 27591040Sarr const moduledata_t *moddata; 27691040Sarr int error; 27759751Speter 27891040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 27991040Sarr " in %s\n", lf->filename)); 28059751Speter 28191068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 28291040Sarr &stop, 0) != 0) { 28391040Sarr /* 28491040Sarr * This fallback should be unnecessary, but if we get booted 28591040Sarr * from boot2 instead of loader and we are missing our 28691040Sarr * metadata then we have to try the best we can. 28791040Sarr */ 28891040Sarr if (lf == linker_kernel_file) { 28991040Sarr start = SET_BEGIN(modmetadata_set); 29091040Sarr stop = SET_LIMIT(modmetadata_set); 29191040Sarr } else 29291040Sarr return (0); 29378161Speter } 29491040Sarr for (mdp = start; mdp < stop; mdp++) { 29591040Sarr if ((*mdp)->md_type != MDT_MODULE) 29691040Sarr continue; 29791040Sarr moddata = (*mdp)->md_data; 29891040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 29991040Sarr moddata->name, lf->filename)); 30091040Sarr error = module_register(moddata, lf); 30191040Sarr if (error) 30291068Sarr printf("Module %s failed to register: %d\n", 30391040Sarr moddata->name, error); 30459751Speter } 30591040Sarr return (0); 30659751Speter} 30759751Speter 30859751Speterstatic void 30959751Speterlinker_init_kernel_modules(void) 31059751Speter{ 31191040Sarr 31291040Sarr linker_file_register_modules(linker_kernel_file); 31359751Speter} 31459751Speter 31591040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) 31659751Speter 317101241Smuxstatic int 31891040Sarrlinker_load_file(const char *filename, linker_file_t *result) 31925537Sdfr{ 32091040Sarr linker_class_t lc; 32191040Sarr linker_file_t lf; 32291040Sarr int foundfile, error = 0; 32325537Sdfr 32491040Sarr /* Refuse to load modules if securelevel raised */ 32591040Sarr if (securelevel > 0) 32691040Sarr return (EPERM); 32762261Sarchie 32891040Sarr lf = linker_find_file_by_name(filename); 32991040Sarr if (lf) { 33091040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 33191040Sarr " incrementing refs\n", filename)); 33291040Sarr *result = lf; 33391040Sarr lf->refs++; 33491040Sarr goto out; 33591040Sarr } 33691040Sarr lf = NULL; 33791040Sarr foundfile = 0; 33898452Sarr 33998452Sarr /* 34098452Sarr * We do not need to protect (lock) classes here because there is 34198452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 34298452Sarr * and there is no class deregistration mechanism at this time. 34398452Sarr */ 34491040Sarr TAILQ_FOREACH(lc, &classes, link) { 34591040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 34691040Sarr filename)); 34791040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 34891040Sarr /* 34991040Sarr * If we got something other than ENOENT, then it exists but 35091040Sarr * we cannot load it for some other reason. 35191040Sarr */ 35291040Sarr if (error != ENOENT) 35391040Sarr foundfile = 1; 35491040Sarr if (lf) { 35591040Sarr linker_file_register_modules(lf); 35691040Sarr linker_file_register_sysctls(lf); 35791040Sarr linker_file_sysinit(lf); 35891040Sarr lf->flags |= LINKER_FILE_LINKED; 35991040Sarr *result = lf; 36091040Sarr error = 0; 36191040Sarr goto out; 36291040Sarr } 36391040Sarr } 36442755Speter /* 36591040Sarr * Less than ideal, but tells the user whether it failed to load or 36691040Sarr * the module was not found. 36742755Speter */ 368105337Ssam if (foundfile) { 369105337Ssam /* 370105337Ssam * Format not recognized or otherwise unloadable. 371105337Ssam * When loading a module that is statically built into 372105337Ssam * the kernel EEXIST percolates back up as the return 373105337Ssam * value. Preserve this so that apps like sysinstall 374105337Ssam * can recognize this special case and not post bogus 375105337Ssam * dialog boxes. 376105337Ssam */ 377105337Ssam if (error != EEXIST) 378105337Ssam error = ENOEXEC; 379105337Ssam } else 38091068Sarr error = ENOENT; /* Nothing found */ 38125537Sdfrout: 38291040Sarr return (error); 38325537Sdfr} 38425537Sdfr 38578413Sbrianint 38694321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 38794321Sbrian linker_file_t *result) 38878413Sbrian{ 38994321Sbrian modlist_t mod; 39094321Sbrian 39194321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 39294321Sbrian *result = mod->container; 39394321Sbrian (*result)->refs++; 39494321Sbrian return (0); 39594321Sbrian } 39694321Sbrian 39794321Sbrian return (linker_load_module(NULL, modname, NULL, verinfo, result)); 39878413Sbrian} 39978413Sbrian 40025537Sdfrlinker_file_t 40191040Sarrlinker_find_file_by_name(const char *filename) 40225537Sdfr{ 40391040Sarr linker_file_t lf = 0; 40491040Sarr char *koname; 40525537Sdfr 406111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 40791040Sarr if (koname == NULL) 40891040Sarr goto out; 40991040Sarr sprintf(koname, "%s.ko", filename); 41040861Speter 41198452Sarr mtx_lock(&kld_mtx); 41291040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 41392032Sdwmalone if (strcmp(lf->filename, koname) == 0) 41491040Sarr break; 41592032Sdwmalone if (strcmp(lf->filename, filename) == 0) 41691040Sarr break; 41791040Sarr } 41898452Sarr mtx_unlock(&kld_mtx); 41940861Speterout: 42091040Sarr if (koname) 42191040Sarr free(koname, M_LINKER); 42291040Sarr return (lf); 42325537Sdfr} 42425537Sdfr 42525537Sdfrlinker_file_t 42625537Sdfrlinker_find_file_by_id(int fileid) 42725537Sdfr{ 42891040Sarr linker_file_t lf = 0; 42998452Sarr 43098452Sarr mtx_lock(&kld_mtx); 43191040Sarr TAILQ_FOREACH(lf, &linker_files, link) 43291040Sarr if (lf->id == fileid) 43391040Sarr break; 43498452Sarr mtx_unlock(&kld_mtx); 43591040Sarr return (lf); 43625537Sdfr} 43725537Sdfr 43825537Sdfrlinker_file_t 43991040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 44025537Sdfr{ 44191040Sarr linker_file_t lf; 44291040Sarr const char *filename; 44325537Sdfr 44491040Sarr lf = NULL; 44591040Sarr filename = linker_basename(pathname); 44640159Speter 44791040Sarr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 448111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 44991040Sarr if (lf == NULL) 45091040Sarr goto out; 45191040Sarr lf->refs = 1; 45291040Sarr lf->userrefs = 0; 45391040Sarr lf->flags = 0; 45491040Sarr lf->filename = linker_strdup(filename); 45591040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 45691040Sarr lf->ndeps = 0; 45791040Sarr lf->deps = NULL; 45891040Sarr STAILQ_INIT(&lf->common); 45991040Sarr TAILQ_INIT(&lf->modules); 46098452Sarr mtx_lock(&kld_mtx); 46191040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 46298452Sarr mtx_unlock(&kld_mtx); 46325537Sdfrout: 46491040Sarr return (lf); 46525537Sdfr} 46625537Sdfr 46725537Sdfrint 46825537Sdfrlinker_file_unload(linker_file_t file) 46925537Sdfr{ 47091040Sarr module_t mod, next; 47191040Sarr modlist_t ml, nextml; 47291040Sarr struct common_symbol *cp; 47391040Sarr int error, i; 47425537Sdfr 47591040Sarr error = 0; 47662261Sarchie 47791040Sarr /* Refuse to unload modules if securelevel raised. */ 47891040Sarr if (securelevel > 0) 47991040Sarr return (EPERM); 480107089Srwatson#ifdef MAC 481107089Srwatson error = mac_check_kld_unload(curthread->td_ucred); 482107089Srwatson if (error) 483107089Srwatson return (error); 484107089Srwatson#endif 48525537Sdfr 48691040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 48791040Sarr if (file->refs == 1) { 48891040Sarr KLD_DPF(FILE, ("linker_file_unload: file is unloading," 48991040Sarr " informing modules\n")); 49091040Sarr 49191040Sarr /* 49291040Sarr * Inform any modules associated with this file. 49391040Sarr */ 49492547Sarr MOD_XLOCK; 49591040Sarr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 49691040Sarr next = module_getfnext(mod); 49792547Sarr MOD_XUNLOCK; 49891040Sarr 49991040Sarr /* 50091040Sarr * Give the module a chance to veto the unload. 50191040Sarr */ 50291040Sarr if ((error = module_unload(mod)) != 0) { 503109605Sjake KLD_DPF(FILE, ("linker_file_unload: module %p" 50491040Sarr " vetoes unload\n", mod)); 50591040Sarr goto out; 50692547Sarr } else 50792547Sarr MOD_XLOCK; 50891040Sarr module_release(mod); 50991040Sarr } 51092547Sarr MOD_XUNLOCK; 51191040Sarr } 51291040Sarr file->refs--; 51391040Sarr if (file->refs > 0) { 51425537Sdfr goto out; 51591040Sarr } 51691040Sarr for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { 51791040Sarr nextml = TAILQ_NEXT(ml, link); 51891040Sarr if (ml->container == file) 51991040Sarr TAILQ_REMOVE(&found_modules, ml, link); 52091040Sarr } 52125537Sdfr 52291040Sarr /* 52391040Sarr * Don't try to run SYSUNINITs if we are unloaded due to a 52491040Sarr * link error. 52591040Sarr */ 52691040Sarr if (file->flags & LINKER_FILE_LINKED) { 52791040Sarr linker_file_sysuninit(file); 52891040Sarr linker_file_unregister_sysctls(file); 52925537Sdfr } 53098452Sarr mtx_lock(&kld_mtx); 53191040Sarr TAILQ_REMOVE(&linker_files, file, link); 53298452Sarr mtx_unlock(&kld_mtx); 53325537Sdfr 53491040Sarr if (file->deps) { 53591040Sarr for (i = 0; i < file->ndeps; i++) 53691040Sarr linker_file_unload(file->deps[i]); 53791040Sarr free(file->deps, M_LINKER); 53891040Sarr file->deps = NULL; 53959751Speter } 54091040Sarr for (cp = STAILQ_FIRST(&file->common); cp; 54191068Sarr cp = STAILQ_FIRST(&file->common)) { 54291040Sarr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 54391040Sarr free(cp, M_LINKER); 54491040Sarr } 54559751Speter 54691040Sarr LINKER_UNLOAD(file); 54791040Sarr if (file->filename) { 54891040Sarr free(file->filename, M_LINKER); 54991040Sarr file->filename = NULL; 55091040Sarr } 55191040Sarr kobj_delete((kobj_t) file, M_LINKER); 55225537Sdfrout: 55391040Sarr return (error); 55425537Sdfr} 55525537Sdfr 55625537Sdfrint 55786469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 55825537Sdfr{ 55991040Sarr linker_file_t *newdeps; 56025537Sdfr 56191040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 562111119Simp M_LINKER, M_WAITOK | M_ZERO); 56391040Sarr if (newdeps == NULL) 56491040Sarr return (ENOMEM); 56525537Sdfr 56691040Sarr if (file->deps) { 56791040Sarr bcopy(file->deps, newdeps, 56891040Sarr file->ndeps * sizeof(linker_file_t *)); 56991040Sarr free(file->deps, M_LINKER); 57091040Sarr } 57191040Sarr file->deps = newdeps; 57291040Sarr file->deps[file->ndeps] = dep; 57391040Sarr file->ndeps++; 57491040Sarr return (0); 57525537Sdfr} 57625537Sdfr 57778161Speter/* 57891040Sarr * Locate a linker set and its contents. This is a helper function to avoid 57991040Sarr * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** 58078161Speter */ 58178161Speterint 58278161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 58391040Sarr void *firstp, void *lastp, int *countp) 58478161Speter{ 58578161Speter 58691040Sarr return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 58778161Speter} 58878161Speter 58925537Sdfrcaddr_t 59091040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 59125537Sdfr{ 59291040Sarr c_linker_sym_t sym; 59391040Sarr linker_symval_t symval; 59491040Sarr caddr_t address; 59591040Sarr size_t common_size = 0; 59692032Sdwmalone int i; 59725537Sdfr 598109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 59991040Sarr file, name, deps)); 60025537Sdfr 60191040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 60291040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 60391040Sarr if (symval.value == 0) 60491040Sarr /* 60591040Sarr * For commons, first look them up in the 60691040Sarr * dependencies and only allocate space if not found 60791040Sarr * there. 60891040Sarr */ 60991040Sarr common_size = symval.size; 61091040Sarr else { 61191040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 612109605Sjake ".value=%p\n", symval.value)); 61391040Sarr return (symval.value); 61491040Sarr } 61540159Speter } 61691040Sarr if (deps) { 61791040Sarr for (i = 0; i < file->ndeps; i++) { 61891040Sarr address = linker_file_lookup_symbol(file->deps[i], 61991040Sarr name, 0); 62091040Sarr if (address) { 62191040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 622109605Sjake " deps value=%p\n", address)); 62391040Sarr return (address); 62491040Sarr } 62591040Sarr } 62625537Sdfr } 62791040Sarr if (common_size > 0) { 62891040Sarr /* 62991040Sarr * This is a common symbol which was not found in the 63091040Sarr * dependencies. We maintain a simple common symbol table in 63191040Sarr * the file object. 63291040Sarr */ 63391040Sarr struct common_symbol *cp; 63442849Speter 63591040Sarr STAILQ_FOREACH(cp, &file->common, link) { 63692032Sdwmalone if (strcmp(cp->name, name) == 0) { 63791040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 638109605Sjake " old common value=%p\n", cp->address)); 63991040Sarr return (cp->address); 64091040Sarr } 64191040Sarr } 64291040Sarr /* 64391040Sarr * Round the symbol size up to align. 64491040Sarr */ 64591040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 64691040Sarr cp = malloc(sizeof(struct common_symbol) 64791040Sarr + common_size + strlen(name) + 1, M_LINKER, 648111119Simp M_WAITOK | M_ZERO); 64991040Sarr if (cp == NULL) { 65091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 65191040Sarr return (0); 65291040Sarr } 65391040Sarr cp->address = (caddr_t)(cp + 1); 65491040Sarr cp->name = cp->address + common_size; 65591040Sarr strcpy(cp->name, name); 65691040Sarr bzero(cp->address, common_size); 65791040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 65825537Sdfr 65991040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 660109605Sjake " value=%p\n", cp->address)); 66191040Sarr return (cp->address); 66240159Speter } 66391040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 66491040Sarr return (0); 66525537Sdfr} 66625537Sdfr 66740159Speter#ifdef DDB 66825537Sdfr/* 66991040Sarr * DDB Helpers. DDB has to look across multiple files with their own symbol 67091040Sarr * tables and string tables. 67191040Sarr * 67291040Sarr * Note that we do not obey list locking protocols here. We really don't need 67391040Sarr * DDB to hang because somebody's got the lock held. We'll take the chance 67491040Sarr * that the files list is inconsistant instead. 67540159Speter */ 67640159Speter 67740159Speterint 67843309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 67940159Speter{ 68091040Sarr linker_file_t lf; 68140159Speter 68291040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 68391040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 68491040Sarr return (0); 68591040Sarr } 68691040Sarr return (ENOENT); 68740159Speter} 68840159Speter 68940159Speterint 69043309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 69140159Speter{ 69291040Sarr linker_file_t lf; 69391040Sarr c_linker_sym_t best, es; 69491040Sarr u_long diff, bestdiff, off; 69540159Speter 69691040Sarr best = 0; 69791040Sarr off = (uintptr_t)value; 69891040Sarr bestdiff = off; 69991040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 70091040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 70191040Sarr continue; 70291040Sarr if (es != 0 && diff < bestdiff) { 70391040Sarr best = es; 70491040Sarr bestdiff = diff; 70591040Sarr } 70691040Sarr if (bestdiff == 0) 70791040Sarr break; 70840159Speter } 70991040Sarr if (best) { 71091040Sarr *sym = best; 71191040Sarr *diffp = bestdiff; 71291040Sarr return (0); 71391040Sarr } else { 71491040Sarr *sym = 0; 71591040Sarr *diffp = off; 71691040Sarr return (ENOENT); 71791040Sarr } 71840159Speter} 71940159Speter 72040159Speterint 72143309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 72240159Speter{ 72391040Sarr linker_file_t lf; 72440159Speter 72591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 72691040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 72791040Sarr return (0); 72891040Sarr } 72991040Sarr return (ENOENT); 73040159Speter} 73140159Speter#endif 73240159Speter 73340159Speter/* 73425537Sdfr * Syscalls. 73525537Sdfr */ 73682749Sdillon/* 73782749Sdillon * MPSAFE 73882749Sdillon */ 73925537Sdfrint 74091040Sarrkldload(struct thread *td, struct kldload_args *uap) 74125537Sdfr{ 74291040Sarr char *kldname, *modname; 74391040Sarr char *pathname = NULL; 74491040Sarr linker_file_t lf; 74591040Sarr int error = 0; 74625537Sdfr 74791040Sarr td->td_retval[0] = -1; 74825537Sdfr 74991040Sarr mtx_lock(&Giant); 75082749Sdillon 75193159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 75293159Sarr goto out; 75393159Sarr 75493593Sjhb if ((error = suser(td)) != 0) 75591040Sarr goto out; 75625537Sdfr 757111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 758107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 75991040Sarr goto out; 76025537Sdfr 76191040Sarr /* 76291040Sarr * If path do not contain qualified name or any dot in it 76391040Sarr * (kldname.ko, or kldname.ver.ko) treat it as interface 76491040Sarr * name. 76591040Sarr */ 76691040Sarr if (index(pathname, '/') || index(pathname, '.')) { 76791040Sarr kldname = pathname; 76891040Sarr modname = NULL; 76991040Sarr } else { 77091040Sarr kldname = NULL; 77191040Sarr modname = pathname; 77291040Sarr } 77391040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 77491040Sarr if (error) 77591040Sarr goto out; 77642316Smsmith 77791040Sarr lf->userrefs++; 77891040Sarr td->td_retval[0] = lf->id; 77925537Sdfrout: 78091040Sarr if (pathname) 78191040Sarr free(pathname, M_TEMP); 78291040Sarr mtx_unlock(&Giant); 78391040Sarr return (error); 78425537Sdfr} 78525537Sdfr 78682749Sdillon/* 78782749Sdillon * MPSAFE 78882749Sdillon */ 78925537Sdfrint 79091040Sarrkldunload(struct thread *td, struct kldunload_args *uap) 79125537Sdfr{ 79291040Sarr linker_file_t lf; 79391040Sarr int error = 0; 79425537Sdfr 79591040Sarr mtx_lock(&Giant); 79682749Sdillon 79793159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 79893159Sarr goto out; 79993159Sarr 80093593Sjhb if ((error = suser(td)) != 0) 80191040Sarr goto out; 80225537Sdfr 803107849Salfred lf = linker_find_file_by_id(uap->fileid); 80491040Sarr if (lf) { 80591040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 80691040Sarr if (lf->userrefs == 0) { 80791040Sarr printf("kldunload: attempt to unload file that was" 80891040Sarr " loaded by the kernel\n"); 80991040Sarr error = EBUSY; 81091040Sarr goto out; 81191040Sarr } 81291068Sarr lf->userrefs--; 81391040Sarr error = linker_file_unload(lf); 81491040Sarr if (error) 81591040Sarr lf->userrefs++; 81691040Sarr } else 81791040Sarr error = ENOENT; 81825537Sdfrout: 81991068Sarr mtx_unlock(&Giant); 82091068Sarr return (error); 82125537Sdfr} 82225537Sdfr 82382749Sdillon/* 82482749Sdillon * MPSAFE 82582749Sdillon */ 82625537Sdfrint 82791040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 82825537Sdfr{ 82991040Sarr char *pathname; 83091040Sarr const char *filename; 83191040Sarr linker_file_t lf; 83291040Sarr int error = 0; 83325537Sdfr 834107089Srwatson#ifdef MAC 835107089Srwatson error = mac_check_kld_stat(td->td_ucred); 836107089Srwatson if (error) 837107089Srwatson return (error); 838107089Srwatson#endif 839107089Srwatson 84091040Sarr mtx_lock(&Giant); 84191040Sarr td->td_retval[0] = -1; 84282749Sdillon 843111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 844107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 84591040Sarr goto out; 84625537Sdfr 84791040Sarr filename = linker_basename(pathname); 84891040Sarr lf = linker_find_file_by_name(filename); 84991040Sarr if (lf) 85091040Sarr td->td_retval[0] = lf->id; 85191040Sarr else 85291040Sarr error = ENOENT; 85325537Sdfrout: 85491040Sarr if (pathname) 85591040Sarr free(pathname, M_TEMP); 85691040Sarr mtx_unlock(&Giant); 85791040Sarr return (error); 85825537Sdfr} 85925537Sdfr 86082749Sdillon/* 86182749Sdillon * MPSAFE 86282749Sdillon */ 86325537Sdfrint 86491040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 86525537Sdfr{ 86691040Sarr linker_file_t lf; 86791040Sarr int error = 0; 86825537Sdfr 869107089Srwatson#ifdef MAC 870107089Srwatson error = mac_check_kld_stat(td->td_ucred); 871107089Srwatson if (error) 872107089Srwatson return (error); 873107089Srwatson#endif 874107089Srwatson 87591040Sarr mtx_lock(&Giant); 87682749Sdillon 877107849Salfred if (uap->fileid == 0) { 87898452Sarr mtx_lock(&kld_mtx); 87991040Sarr if (TAILQ_FIRST(&linker_files)) 88091040Sarr td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; 88191040Sarr else 88291040Sarr td->td_retval[0] = 0; 88398452Sarr mtx_unlock(&kld_mtx); 88491040Sarr goto out; 88591040Sarr } 886107849Salfred lf = linker_find_file_by_id(uap->fileid); 88791040Sarr if (lf) { 88891040Sarr if (TAILQ_NEXT(lf, link)) 88991040Sarr td->td_retval[0] = TAILQ_NEXT(lf, link)->id; 89091040Sarr else 89191040Sarr td->td_retval[0] = 0; 89291040Sarr } else 89391040Sarr error = ENOENT; 89482749Sdillonout: 89591040Sarr mtx_unlock(&Giant); 89691040Sarr return (error); 89725537Sdfr} 89825537Sdfr 89982749Sdillon/* 90082749Sdillon * MPSAFE 90182749Sdillon */ 90225537Sdfrint 90391040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 90425537Sdfr{ 90591040Sarr linker_file_t lf; 90691040Sarr int error = 0; 90791040Sarr int namelen, version; 90891040Sarr struct kld_file_stat *stat; 90925537Sdfr 910107089Srwatson#ifdef MAC 911107089Srwatson error = mac_check_kld_stat(td->td_ucred); 912107089Srwatson if (error) 913107089Srwatson return (error); 914107089Srwatson#endif 915107089Srwatson 91691040Sarr mtx_lock(&Giant); 91782749Sdillon 918107849Salfred lf = linker_find_file_by_id(uap->fileid); 91991040Sarr if (lf == NULL) { 92091040Sarr error = ENOENT; 92191040Sarr goto out; 92291040Sarr } 923107849Salfred stat = uap->stat; 92425537Sdfr 92591040Sarr /* 92691040Sarr * Check the version of the user's structure. 92791040Sarr */ 92891040Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 92991040Sarr goto out; 93091040Sarr if (version != sizeof(struct kld_file_stat)) { 93191040Sarr error = EINVAL; 93291040Sarr goto out; 93391040Sarr } 93491040Sarr namelen = strlen(lf->filename) + 1; 93591040Sarr if (namelen > MAXPATHLEN) 93691040Sarr namelen = MAXPATHLEN; 93791040Sarr if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) 93891040Sarr goto out; 93991040Sarr if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) 94091040Sarr goto out; 94191040Sarr if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) 94291040Sarr goto out; 94391040Sarr if ((error = copyout(&lf->address, &stat->address, 94491040Sarr sizeof(caddr_t))) != 0) 94591040Sarr goto out; 94691040Sarr if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) 94791040Sarr goto out; 94825537Sdfr 94991040Sarr td->td_retval[0] = 0; 95025537Sdfrout: 95191040Sarr mtx_unlock(&Giant); 95291040Sarr return (error); 95325537Sdfr} 95425537Sdfr 95582749Sdillon/* 95682749Sdillon * MPSAFE 95782749Sdillon */ 95825537Sdfrint 95991040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 96025537Sdfr{ 96191040Sarr linker_file_t lf; 96291040Sarr module_t mp; 96391040Sarr int error = 0; 96425537Sdfr 965107089Srwatson#ifdef MAC 966107089Srwatson error = mac_check_kld_stat(td->td_ucred); 967107089Srwatson if (error) 968107089Srwatson return (error); 969107089Srwatson#endif 970107089Srwatson 97191040Sarr mtx_lock(&Giant); 972107849Salfred lf = linker_find_file_by_id(uap->fileid); 97391040Sarr if (lf) { 97492547Sarr MOD_SLOCK; 97591040Sarr mp = TAILQ_FIRST(&lf->modules); 97691040Sarr if (mp != NULL) 97791040Sarr td->td_retval[0] = module_getid(mp); 97891040Sarr else 97991040Sarr td->td_retval[0] = 0; 98092547Sarr MOD_SUNLOCK; 98191040Sarr } else 98291040Sarr error = ENOENT; 98391040Sarr mtx_unlock(&Giant); 98491040Sarr return (error); 98525537Sdfr} 98640159Speter 98782749Sdillon/* 98882749Sdillon * MPSAFE 98982749Sdillon */ 99041090Speterint 99183366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 99241090Speter{ 99391040Sarr char *symstr = NULL; 99491040Sarr c_linker_sym_t sym; 99591040Sarr linker_symval_t symval; 99691040Sarr linker_file_t lf; 99791040Sarr struct kld_sym_lookup lookup; 99891040Sarr int error = 0; 99941090Speter 1000107089Srwatson#ifdef MAC 1001107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1002107089Srwatson if (error) 1003107089Srwatson return (error); 1004107089Srwatson#endif 1005107089Srwatson 100691040Sarr mtx_lock(&Giant); 100782749Sdillon 1008107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 100991040Sarr goto out; 101091068Sarr if (lookup.version != sizeof(lookup) || 1011107849Salfred uap->cmd != KLDSYM_LOOKUP) { 101291040Sarr error = EINVAL; 101391040Sarr goto out; 101491040Sarr } 1015111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 101691040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 101791040Sarr goto out; 1018107849Salfred if (uap->fileid != 0) { 1019107849Salfred lf = linker_find_file_by_id(uap->fileid); 102091040Sarr if (lf == NULL) { 102191040Sarr error = ENOENT; 102291040Sarr goto out; 102391040Sarr } 102491040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 102591040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 102691040Sarr lookup.symvalue = (uintptr_t) symval.value; 102791040Sarr lookup.symsize = symval.size; 1028107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 102991040Sarr } else 103091040Sarr error = ENOENT; 103191040Sarr } else { 103298452Sarr mtx_lock(&kld_mtx); 103391040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 103491040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 103591040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 103691040Sarr lookup.symvalue = (uintptr_t)symval.value; 103791040Sarr lookup.symsize = symval.size; 1038107849Salfred error = copyout(&lookup, uap->data, 103991040Sarr sizeof(lookup)); 104091068Sarr break; 104191040Sarr } 104291040Sarr } 104398452Sarr mtx_unlock(&kld_mtx); 104491040Sarr if (lf == NULL) 104591040Sarr error = ENOENT; 104641090Speter } 104741090Speterout: 104891040Sarr if (symstr) 104991040Sarr free(symstr, M_TEMP); 105091040Sarr mtx_unlock(&Giant); 105191040Sarr return (error); 105241090Speter} 105341090Speter 105440159Speter/* 105540159Speter * Preloaded module support 105640159Speter */ 105740159Speter 105859751Speterstatic modlist_t 105974642Sbpmodlist_lookup(const char *name, int ver) 106059751Speter{ 106191040Sarr modlist_t mod; 106259751Speter 106391040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 106492032Sdwmalone if (strcmp(mod->name, name) == 0 && 106592032Sdwmalone (ver == 0 || mod->version == ver)) 106691040Sarr return (mod); 106791040Sarr } 106891040Sarr return (NULL); 106959751Speter} 107059751Speter 107174642Sbpstatic modlist_t 107283321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 107383321Speter{ 107491040Sarr modlist_t mod, bestmod; 107592032Sdwmalone int ver; 107683321Speter 107791040Sarr if (verinfo == NULL) 107891040Sarr return (modlist_lookup(name, 0)); 107991040Sarr bestmod = NULL; 108091040Sarr for (mod = TAILQ_FIRST(&found_modules); mod; 108191040Sarr mod = TAILQ_NEXT(mod, link)) { 108292032Sdwmalone if (strcmp(mod->name, name) != 0) 108391040Sarr continue; 108491040Sarr ver = mod->version; 108591040Sarr if (ver == verinfo->md_ver_preferred) 108691040Sarr return (mod); 108791040Sarr if (ver >= verinfo->md_ver_minimum && 108891068Sarr ver <= verinfo->md_ver_maximum && 108991068Sarr ver > bestmod->version) 109091040Sarr bestmod = mod; 109191040Sarr } 109291040Sarr return (bestmod); 109383321Speter} 109483321Speter 109583321Speterstatic modlist_t 109678501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 109774642Sbp{ 109891040Sarr modlist_t mod; 109974642Sbp 110092705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 110191040Sarr if (mod == NULL) 110291040Sarr panic("no memory for module list"); 110391040Sarr mod->container = container; 110491040Sarr mod->name = modname; 110591040Sarr mod->version = version; 110691040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 110791040Sarr return (mod); 110874642Sbp} 110974642Sbp 111040159Speterstatic void 111178161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 111291040Sarr struct mod_metadata **stop, int preload) 111374642Sbp{ 111491040Sarr struct mod_metadata *mp, **mdp; 111591040Sarr const char *modname; 111691040Sarr int ver; 111774642Sbp 111891040Sarr for (mdp = start; mdp < stop; mdp++) { 1119109605Sjake mp = *mdp; 112091040Sarr if (mp->md_type != MDT_VERSION) 112191040Sarr continue; 1122109605Sjake modname = mp->md_cval; 1123109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 112491040Sarr if (modlist_lookup(modname, ver) != NULL) { 112591040Sarr printf("module %s already present!\n", modname); 112691040Sarr /* XXX what can we do? this is a build error. :-( */ 112791040Sarr continue; 112891040Sarr } 112991040Sarr modlist_newmodule(modname, ver, lf); 113074642Sbp } 113174642Sbp} 113274642Sbp 113374642Sbpstatic void 113491040Sarrlinker_preload(void *arg) 113540159Speter{ 113691040Sarr caddr_t modptr; 113791040Sarr const char *modname, *nmodname; 113891040Sarr char *modtype; 113991040Sarr linker_file_t lf; 114091040Sarr linker_class_t lc; 114192032Sdwmalone int error; 114291040Sarr linker_file_list_t loaded_files; 114391040Sarr linker_file_list_t depended_files; 114491040Sarr struct mod_metadata *mp, *nmp; 114591040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 114691040Sarr struct mod_depend *verinfo; 114791040Sarr int nver; 114891040Sarr int resolves; 114991040Sarr modlist_t mod; 115091040Sarr struct sysinit **si_start, **si_stop; 115140159Speter 115291040Sarr TAILQ_INIT(&loaded_files); 115391040Sarr TAILQ_INIT(&depended_files); 115491040Sarr TAILQ_INIT(&found_modules); 115591040Sarr error = 0; 115659751Speter 115791040Sarr modptr = NULL; 115891040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 115991040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 116091040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 116191040Sarr if (modname == NULL) { 116291040Sarr printf("Preloaded module at %p does not have a" 116391040Sarr " name!\n", modptr); 116491040Sarr continue; 116591040Sarr } 116691040Sarr if (modtype == NULL) { 116791040Sarr printf("Preloaded module at %p does not have a type!\n", 116891040Sarr modptr); 116991040Sarr continue; 117091040Sarr } 117191040Sarr printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 117291040Sarr modptr); 117340159Speter lf = NULL; 117491040Sarr TAILQ_FOREACH(lc, &classes, link) { 117591040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 117691040Sarr if (error) { 117791040Sarr lf = NULL; 117891040Sarr break; 117991040Sarr } 118091040Sarr } 118191040Sarr if (lf) 118291040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 118340159Speter } 118440159Speter 118591040Sarr /* 118691040Sarr * First get a list of stuff in the kernel. 118791040Sarr */ 118891040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 118991040Sarr &stop, NULL) == 0) 119091040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 119159751Speter 119259751Speter /* 119391040Sarr * this is a once-off kinky bubble sort resolve relocation dependency 119491040Sarr * requirements 119559751Speter */ 119691040Sarrrestart: 119791040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 119891040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 119991040Sarr &stop, NULL); 120091040Sarr /* 120191040Sarr * First, look to see if we would successfully link with this 120291040Sarr * stuff. 120391040Sarr */ 120491040Sarr resolves = 1; /* unless we know otherwise */ 120591040Sarr if (!error) { 120691040Sarr for (mdp = start; mdp < stop; mdp++) { 1207109605Sjake mp = *mdp; 120891040Sarr if (mp->md_type != MDT_DEPEND) 120991040Sarr continue; 1210109605Sjake modname = mp->md_cval; 1211109605Sjake verinfo = mp->md_data; 121291040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1213109605Sjake nmp = *nmdp; 121491040Sarr if (nmp->md_type != MDT_VERSION) 121591040Sarr continue; 1216109605Sjake nmodname = nmp->md_cval; 121792032Sdwmalone if (strcmp(modname, nmodname) == 0) 121891040Sarr break; 121991040Sarr } 122091040Sarr if (nmdp < stop) /* it's a self reference */ 122191040Sarr continue; 122291040Sarr 122391040Sarr /* 122491040Sarr * ok, the module isn't here yet, we 122591040Sarr * are not finished 122691040Sarr */ 122791068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 122891040Sarr resolves = 0; 122991040Sarr } 123064143Speter } 123191040Sarr /* 123291040Sarr * OK, if we found our modules, we can link. So, "provide" 123391040Sarr * the modules inside and add it to the end of the link order 123491040Sarr * list. 123591040Sarr */ 123691040Sarr if (resolves) { 123791040Sarr if (!error) { 123891040Sarr for (mdp = start; mdp < stop; mdp++) { 1239109605Sjake mp = *mdp; 124091040Sarr if (mp->md_type != MDT_VERSION) 124191040Sarr continue; 1242109605Sjake modname = mp->md_cval; 1243109605Sjake nver = ((struct mod_version *) 1244109605Sjake mp->md_data)->mv_version; 124591040Sarr if (modlist_lookup(modname, 124691040Sarr nver) != NULL) { 124791040Sarr printf("module %s already" 124891040Sarr " present!\n", modname); 124991040Sarr linker_file_unload(lf); 125091040Sarr TAILQ_REMOVE(&loaded_files, 125191040Sarr lf, loaded); 125291040Sarr /* we changed tailq next ptr */ 125391068Sarr goto restart; 125491040Sarr } 125591040Sarr modlist_newmodule(modname, nver, lf); 125691040Sarr } 125791040Sarr } 125891040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 125991040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 126091040Sarr /* 126191040Sarr * Since we provided modules, we need to restart the 126291040Sarr * sort so that the previous files that depend on us 126391040Sarr * have a chance. Also, we've busted the tailq next 126491040Sarr * pointer with the REMOVE. 126591040Sarr */ 126691040Sarr goto restart; 126759751Speter } 126859751Speter } 126991040Sarr 127059751Speter /* 127191040Sarr * At this point, we check to see what could not be resolved.. 127259751Speter */ 127391040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 127491040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 127591040Sarr linker_file_unload(lf); 127691040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 127740159Speter } 127859751Speter 127978161Speter /* 128091040Sarr * We made it. Finish off the linking in the order we determined. 128178161Speter */ 128291040Sarr TAILQ_FOREACH(lf, &depended_files, loaded) { 128391040Sarr if (linker_kernel_file) { 128491040Sarr linker_kernel_file->refs++; 128591040Sarr error = linker_file_add_dependency(lf, 128691040Sarr linker_kernel_file); 128791040Sarr if (error) 128891040Sarr panic("cannot add dependency"); 128991040Sarr } 129091040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 129191040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 129291040Sarr &stop, NULL); 129391040Sarr if (!error) { 129491040Sarr for (mdp = start; mdp < stop; mdp++) { 1295109605Sjake mp = *mdp; 129691040Sarr if (mp->md_type != MDT_DEPEND) 129791040Sarr continue; 1298109605Sjake modname = mp->md_cval; 1299109605Sjake verinfo = mp->md_data; 130091040Sarr mod = modlist_lookup2(modname, verinfo); 130191040Sarr mod->container->refs++; 130291040Sarr error = linker_file_add_dependency(lf, 130391040Sarr mod->container); 130491040Sarr if (error) 130591040Sarr panic("cannot add dependency"); 130691040Sarr } 130791040Sarr } 130891040Sarr /* 130991040Sarr * Now do relocation etc using the symbol search paths 131091040Sarr * established by the dependencies 131191040Sarr */ 131291040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 131391040Sarr if (error) { 131491040Sarr printf("KLD file %s - could not finalize loading\n", 131591040Sarr lf->filename); 131691040Sarr linker_file_unload(lf); 131791040Sarr continue; 131891040Sarr } 131991040Sarr linker_file_register_modules(lf); 132091040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 132191040Sarr &si_stop, NULL) == 0) 132291040Sarr sysinit_add(si_start, si_stop); 132391040Sarr linker_file_register_sysctls(lf); 132491040Sarr lf->flags |= LINKER_FILE_LINKED; 132559751Speter } 132691040Sarr /* woohoo! we made it! */ 132740159Speter} 132840159Speter 132991040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0) 133040159Speter 133140159Speter/* 133240159Speter * Search for a not-loaded module by name. 133391040Sarr * 133440159Speter * Modules may be found in the following locations: 133591040Sarr * 133691040Sarr * - preloaded (result is just the module name) - on disk (result is full path 133791040Sarr * to module) 133891040Sarr * 133991040Sarr * If the module name is qualified in any way (contains path, etc.) the we 134091040Sarr * simply return a copy of it. 134191040Sarr * 134240159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 134340159Speter * character as a separator to be consistent with the bootloader. 134440159Speter */ 134540159Speter 134683321Speterstatic char linker_hintfile[] = "linker.hints"; 1347111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 134840159Speter 134940159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 135091040Sarr sizeof(linker_path), "module load search path"); 135140159Speter 135277843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 135370417Speter 135459751Speterstatic char *linker_ext_list[] = { 135583321Speter "", 135659751Speter ".ko", 135759751Speter NULL 135859751Speter}; 135959751Speter 136083321Speter/* 136191040Sarr * Check if file actually exists either with or without extension listed in 136291040Sarr * the linker_ext_list. (probably should be generic for the rest of the 136391040Sarr * kernel) 136483321Speter */ 136559751Speterstatic char * 136691040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 136791040Sarr int namelen, struct vattr *vap) 136840159Speter{ 136991040Sarr struct nameidata nd; 137091040Sarr struct thread *td = curthread; /* XXX */ 137191040Sarr char *result, **cpp, *sep; 137291040Sarr int error, len, extlen, reclen, flags; 137391040Sarr enum vtype type; 137440159Speter 137591040Sarr extlen = 0; 137691040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 137791040Sarr len = strlen(*cpp); 137891040Sarr if (len > extlen) 137991040Sarr extlen = len; 138091040Sarr } 138191040Sarr extlen++; /* trailing '\0' */ 138291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 138383321Speter 138491040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1385111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 138691040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 138791040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 138891040Sarr namelen, name, *cpp); 138991040Sarr /* 139091040Sarr * Attempt to open the file, and return the path if 139191040Sarr * we succeed and it's a regular file. 139291040Sarr */ 139391040Sarr NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); 139491040Sarr flags = FREAD; 1395118094Sphk error = vn_open(&nd, &flags, 0, -1); 139691040Sarr if (error == 0) { 139791040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 139891040Sarr type = nd.ni_vp->v_type; 139991040Sarr if (vap) 140091406Sjhb VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 140191040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 140291406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 140391040Sarr if (type == VREG) 140491040Sarr return (result); 140591040Sarr } 140683321Speter } 140791040Sarr free(result, M_LINKER); 140891040Sarr return (NULL); 140983321Speter} 141083321Speter 141191040Sarr#define INT_ALIGN(base, ptr) ptr = \ 141283321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 141383321Speter 141483321Speter/* 141591040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 141691040Sarr * version specification is available, then try to find the best KLD. 141783321Speter * Otherwise just find the latest one. 141883321Speter */ 141983321Speterstatic char * 142091040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 142191040Sarr int modnamelen, struct mod_depend *verinfo) 142283321Speter{ 142391040Sarr struct thread *td = curthread; /* XXX */ 142491406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 142591040Sarr struct nameidata nd; 142691040Sarr struct vattr vattr, mattr; 142791040Sarr u_char *hints = NULL; 142891040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 142991040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 143083321Speter 143191040Sarr result = NULL; 143291040Sarr bestver = found = 0; 143383321Speter 143491040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 143591040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 143691040Sarr strlen(sep) + 1; 1437111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 143891040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 143991040Sarr linker_hintfile); 144083321Speter 144191040Sarr NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); 144291040Sarr flags = FREAD; 1443118094Sphk error = vn_open(&nd, &flags, 0, -1); 144491040Sarr if (error) 144591040Sarr goto bad; 144691040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 144791040Sarr if (nd.ni_vp->v_type != VREG) 144891040Sarr goto bad; 144991040Sarr best = cp = NULL; 145091040Sarr error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td); 145191040Sarr if (error) 145291040Sarr goto bad; 145391040Sarr /* 145491040Sarr * XXX: we need to limit this number to some reasonable value 145591040Sarr */ 145691040Sarr if (vattr.va_size > 100 * 1024) { 145791040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 145891040Sarr goto bad; 145991040Sarr } 1460111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 146191040Sarr if (hints == NULL) 146291040Sarr goto bad; 146391068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1464101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 146591040Sarr if (error) 146691040Sarr goto bad; 146799553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 146891040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 146991040Sarr nd.ni_vp = NULL; 147091040Sarr if (reclen != 0) { 147191040Sarr printf("can't read %d\n", reclen); 147291040Sarr goto bad; 147391040Sarr } 147491040Sarr intp = (int *)hints; 147583321Speter ival = *intp++; 147691040Sarr if (ival != LINKER_HINTS_VERSION) { 147791040Sarr printf("hints file version mismatch %d\n", ival); 147891040Sarr goto bad; 147983321Speter } 148091040Sarr bufend = hints + vattr.va_size; 148191040Sarr recptr = (u_char *)intp; 148291040Sarr clen = blen = 0; 148391040Sarr while (recptr < bufend && !found) { 148491040Sarr intp = (int *)recptr; 148591040Sarr reclen = *intp++; 148691040Sarr ival = *intp++; 148791040Sarr cp = (char *)intp; 148891040Sarr switch (ival) { 148991040Sarr case MDT_VERSION: 149091040Sarr clen = *cp++; 149191040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 149291040Sarr break; 149391040Sarr cp += clen; 149491040Sarr INT_ALIGN(hints, cp); 149591040Sarr ival = *(int *)cp; 149691040Sarr cp += sizeof(int); 149791040Sarr clen = *cp++; 149891040Sarr if (verinfo == NULL || 149991040Sarr ival == verinfo->md_ver_preferred) { 150091040Sarr found = 1; 150191040Sarr break; 150291040Sarr } 150391040Sarr if (ival >= verinfo->md_ver_minimum && 150491040Sarr ival <= verinfo->md_ver_maximum && 150591040Sarr ival > bestver) { 150691040Sarr bestver = ival; 150791040Sarr best = cp; 150891040Sarr blen = clen; 150991040Sarr } 151091040Sarr break; 151191040Sarr default: 151291040Sarr break; 151391040Sarr } 151491040Sarr recptr += reclen + sizeof(int); 151591040Sarr } 151683321Speter /* 151791040Sarr * Finally check if KLD is in the place 151883321Speter */ 151991040Sarr if (found) 152091040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 152191040Sarr else if (best) 152291040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 152391040Sarr 152491040Sarr /* 152591040Sarr * KLD is newer than hints file. What we should do now? 152691040Sarr */ 152791040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 152891040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 152991040Sarr " file\n", result); 153083321Speterbad: 1531105167Sphk free(pathbuf, M_LINKER); 153291040Sarr if (hints) 153391040Sarr free(hints, M_TEMP); 153499553Sjeff if (nd.ni_vp != NULL) { 153599553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 153691040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 153799553Sjeff } 153891040Sarr /* 153991040Sarr * If nothing found or hints is absent - fallback to the old 154091040Sarr * way by using "kldname[.ko]" as module name. 154191040Sarr */ 154291040Sarr if (!found && !bestver && result == NULL) 154391040Sarr result = linker_lookup_file(path, pathlen, modname, 154491040Sarr modnamelen, NULL); 154591040Sarr return (result); 154683321Speter} 154783321Speter 154883321Speter/* 154983321Speter * Lookup KLD which contains requested module in the all directories. 155083321Speter */ 155183321Speterstatic char * 155283321Speterlinker_search_module(const char *modname, int modnamelen, 155391040Sarr struct mod_depend *verinfo) 155483321Speter{ 155591040Sarr char *cp, *ep, *result; 155683321Speter 155791040Sarr /* 155891040Sarr * traverse the linker path 155991040Sarr */ 156091040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 156191040Sarr /* find the end of this component */ 156291040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 156391068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 156491068Sarr modnamelen, verinfo); 156591040Sarr if (result != NULL) 156691040Sarr return (result); 156791040Sarr if (*ep == 0) 156891040Sarr break; 156991040Sarr } 157091040Sarr return (NULL); 157183321Speter} 157283321Speter 157383321Speter/* 157483321Speter * Search for module in all directories listed in the linker_path. 157583321Speter */ 157683321Speterstatic char * 157783321Speterlinker_search_kld(const char *name) 157883321Speter{ 157991040Sarr char *cp, *ep, *result, **cpp; 158091040Sarr int extlen, len; 158183321Speter 158291040Sarr /* qualified at all? */ 158391040Sarr if (index(name, '/')) 158491040Sarr return (linker_strdup(name)); 158540159Speter 158691040Sarr extlen = 0; 158791040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 158891040Sarr len = strlen(*cpp); 158991040Sarr if (len > extlen) 159091040Sarr extlen = len; 159191040Sarr } 159291040Sarr extlen++; /* trailing '\0' */ 159359751Speter 159491040Sarr /* traverse the linker path */ 159591040Sarr len = strlen(name); 159691040Sarr for (ep = linker_path; *ep; ep++) { 159791040Sarr cp = ep; 159891040Sarr /* find the end of this component */ 159991040Sarr for (; *ep != 0 && *ep != ';'; ep++); 160091040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 160191040Sarr if (result != NULL) 160291040Sarr return (result); 160391040Sarr } 160491040Sarr return (NULL); 160540159Speter} 160659751Speter 160759751Speterstatic const char * 160891040Sarrlinker_basename(const char *path) 160959751Speter{ 161091040Sarr const char *filename; 161159751Speter 161291040Sarr filename = rindex(path, '/'); 161391040Sarr if (filename == NULL) 161491040Sarr return path; 161591040Sarr if (filename[1]) 161691040Sarr filename++; 161791040Sarr return (filename); 161859751Speter} 161959751Speter 162059751Speter/* 162191040Sarr * Find a file which contains given module and load it, if "parent" is not 162291040Sarr * NULL, register a reference to it. 162359751Speter */ 1624101241Smuxint 162583321Speterlinker_load_module(const char *kldname, const char *modname, 162691040Sarr struct linker_file *parent, struct mod_depend *verinfo, 162791040Sarr struct linker_file **lfpp) 162859751Speter{ 162991040Sarr linker_file_t lfdep; 163091040Sarr const char *filename; 163191040Sarr char *pathname; 163291040Sarr int error; 163359751Speter 163491040Sarr if (modname == NULL) { 163591040Sarr /* 163691040Sarr * We have to load KLD 163791040Sarr */ 163891068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 163991068Sarr " is not NULL")); 164091040Sarr pathname = linker_search_kld(kldname); 164191040Sarr } else { 164291040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 164391040Sarr return (EEXIST); 164494322Sbrian if (kldname != NULL) 164594322Sbrian pathname = linker_strdup(kldname); 164695488Sbrian else if (rootvnode == NULL) 164794322Sbrian pathname = NULL; 164894322Sbrian else 164991040Sarr /* 165091040Sarr * Need to find a KLD with required module 165191040Sarr */ 165291040Sarr pathname = linker_search_module(modname, 165391040Sarr strlen(modname), verinfo); 165491040Sarr } 165591040Sarr if (pathname == NULL) 165691040Sarr return (ENOENT); 165791040Sarr 165883321Speter /* 165991040Sarr * Can't load more than one file with the same basename XXX: 166091040Sarr * Actually it should be possible to have multiple KLDs with 166191040Sarr * the same basename but different path because they can 166291040Sarr * provide different versions of the same modules. 166383321Speter */ 166491040Sarr filename = linker_basename(pathname); 166591040Sarr if (linker_find_file_by_name(filename)) { 166691040Sarr error = EEXIST; 166791040Sarr goto out; 166883321Speter } 166991040Sarr do { 167091040Sarr error = linker_load_file(pathname, &lfdep); 167191040Sarr if (error) 167291040Sarr break; 167391040Sarr if (modname && verinfo && 167491040Sarr modlist_lookup2(modname, verinfo) == NULL) { 167591040Sarr linker_file_unload(lfdep); 167691040Sarr error = ENOENT; 167791040Sarr break; 167891040Sarr } 167991040Sarr if (parent) { 168091040Sarr error = linker_file_add_dependency(parent, lfdep); 168191040Sarr if (error) 168291040Sarr break; 168391040Sarr } 168491040Sarr if (lfpp) 168591040Sarr *lfpp = lfdep; 168691040Sarr } while (0); 168759751Speterout: 168891040Sarr if (pathname) 168991040Sarr free(pathname, M_LINKER); 169091040Sarr return (error); 169159751Speter} 169259751Speter 169359751Speter/* 169491040Sarr * This routine is responsible for finding dependencies of userland initiated 169591040Sarr * kldload(2)'s of files. 169659751Speter */ 169759751Speterint 169886469Siedowselinker_load_dependencies(linker_file_t lf) 169959751Speter{ 170091040Sarr linker_file_t lfdep; 170191040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 170291040Sarr struct mod_metadata *mp, *nmp; 170391040Sarr struct mod_depend *verinfo; 170491040Sarr modlist_t mod; 170591040Sarr const char *modname, *nmodname; 170692032Sdwmalone int ver, error = 0, count; 170759751Speter 170891040Sarr /* 170991040Sarr * All files are dependant on /kernel. 171091040Sarr */ 171191040Sarr if (linker_kernel_file) { 171291040Sarr linker_kernel_file->refs++; 171391040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 171491040Sarr if (error) 171591040Sarr return (error); 171659751Speter } 171791040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 171891040Sarr &count) != 0) 171991040Sarr return (0); 172091040Sarr for (mdp = start; mdp < stop; mdp++) { 1721109605Sjake mp = *mdp; 172291040Sarr if (mp->md_type != MDT_VERSION) 172391040Sarr continue; 1724109605Sjake modname = mp->md_cval; 1725109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 172691040Sarr mod = modlist_lookup(modname, ver); 172791040Sarr if (mod != NULL) { 172891040Sarr printf("interface %s.%d already present in the KLD" 172991040Sarr " '%s'!\n", modname, ver, 173091040Sarr mod->container->filename); 173191040Sarr return (EEXIST); 173291040Sarr } 173391040Sarr } 173474642Sbp 173591040Sarr for (mdp = start; mdp < stop; mdp++) { 1736109605Sjake mp = *mdp; 173791040Sarr if (mp->md_type != MDT_DEPEND) 173891040Sarr continue; 1739109605Sjake modname = mp->md_cval; 1740109605Sjake verinfo = mp->md_data; 174191040Sarr nmodname = NULL; 174291040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1743109605Sjake nmp = *nmdp; 174491040Sarr if (nmp->md_type != MDT_VERSION) 174591040Sarr continue; 1746109605Sjake nmodname = nmp->md_cval; 174792032Sdwmalone if (strcmp(modname, nmodname) == 0) 174891040Sarr break; 174991040Sarr } 175091040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 175191040Sarr continue; 175291040Sarr mod = modlist_lookup2(modname, verinfo); 175391040Sarr if (mod) { /* woohoo, it's loaded already */ 175491040Sarr lfdep = mod->container; 175591040Sarr lfdep->refs++; 175691040Sarr error = linker_file_add_dependency(lf, lfdep); 175791040Sarr if (error) 175891040Sarr break; 175991040Sarr continue; 176091040Sarr } 176191040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 176291040Sarr if (error) { 176391040Sarr printf("KLD %s: depends on %s - not available\n", 176491040Sarr lf->filename, modname); 176591040Sarr break; 176691040Sarr } 176759751Speter } 176859751Speter 176991040Sarr if (error) 177091040Sarr return (error); 177191040Sarr linker_addmodules(lf, start, stop, 0); 177291040Sarr return (error); 177359751Speter} 177485736Sgreen 177585736Sgreenstatic int 177685736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 177785736Sgreen{ 177885736Sgreen struct sysctl_req *req; 177985736Sgreen 178085736Sgreen req = opaque; 178185736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 178285736Sgreen} 178385736Sgreen 178485736Sgreen/* 178585736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 178685736Sgreen * in the kernel. 178785736Sgreen */ 178885736Sgreenstatic int 178985736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 179085736Sgreen{ 179185736Sgreen linker_file_t lf; 179285736Sgreen int error; 179385736Sgreen 1794107089Srwatson#ifdef MAC 1795107089Srwatson error = mac_check_kld_stat(req->td->td_ucred); 1796107089Srwatson if (error) 1797107089Srwatson return (error); 1798107089Srwatson#endif 1799100488Struckman sysctl_wire_old_buffer(req, 0); 180098452Sarr mtx_lock(&kld_mtx); 180185736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 180285736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 180385736Sgreen sysctl_kern_function_list_iterate, req); 180498452Sarr if (error) { 180598452Sarr mtx_unlock(&kld_mtx); 180685736Sgreen return (error); 180798452Sarr } 180885736Sgreen } 180998452Sarr mtx_unlock(&kld_mtx); 181085736Sgreen return (SYSCTL_OUT(req, "", 1)); 181185736Sgreen} 181285736Sgreen 181385736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 181491040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 1815