kern_linker.c revision 107089
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 * 2650477Speter * $FreeBSD: head/sys/kern/kern_linker.c 107089 2002-11-19 22:12:42Z rwatson $ 2725537Sdfr */ 2825537Sdfr 2940159Speter#include "opt_ddb.h" 30107089Srwatson#include "opt_mac.h" 3140159Speter 3225537Sdfr#include <sys/param.h> 3325537Sdfr#include <sys/kernel.h> 3425537Sdfr#include <sys/systm.h> 3525537Sdfr#include <sys/malloc.h> 3625537Sdfr#include <sys/sysproto.h> 3725537Sdfr#include <sys/sysent.h> 3825537Sdfr#include <sys/proc.h> 3925537Sdfr#include <sys/lock.h> 4082749Sdillon#include <sys/mutex.h> 4192547Sarr#include <sys/sx.h> 42107089Srwatson#include <sys/mac.h> 4325537Sdfr#include <sys/module.h> 4425537Sdfr#include <sys/linker.h> 4540159Speter#include <sys/fcntl.h> 4640159Speter#include <sys/libkern.h> 4740159Speter#include <sys/namei.h> 4840159Speter#include <sys/vnode.h> 4940159Speter#include <sys/sysctl.h> 5025537Sdfr 5159603Sdfr#include "linker_if.h" 5259603Sdfr 5340961Speter#ifdef KLD_DEBUG 5440961Speterint kld_debug = 0; 5540961Speter#endif 5640961Speter 5791040Sarr/* 5891040Sarr * static char *linker_search_path(const char *name, struct mod_depend 5991040Sarr * *verinfo); 6091040Sarr */ 6191040Sarrstatic const char *linker_basename(const char *path); 6259751Speter 6378161Speter/* Metadata from the static kernel */ 6478161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 6578161Speter 6659751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 6759751Speter 6840906Speterlinker_file_t linker_kernel_file; 6931324Sbde 7098452Sarrstatic struct mtx kld_mtx; /* kernel linker mutex */ 7198452Sarr 7225537Sdfrstatic linker_class_list_t classes; 7350068Sgrogstatic linker_file_list_t linker_files; 7425537Sdfrstatic int next_file_id = 1; 7598452Sarrstatic int linker_no_more_classes = 0; 7625537Sdfr 7786553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 7891040Sarr linker_file_t lftmp; \ 7986553Sarr \ 8086553Sarrretry: \ 8198452Sarr mtx_lock(&kld_mtx); \ 8291040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 8391040Sarr if (next_file_id == lftmp->id) { \ 8491040Sarr next_file_id++; \ 8598452Sarr mtx_unlock(&kld_mtx); \ 8691040Sarr goto retry; \ 8791040Sarr } \ 8891040Sarr } \ 8991040Sarr (a) = next_file_id; \ 9098452Sarr mtx_unlock(&kld_mtx); /* Hold for safe read of id variable */ \ 9186553Sarr} while(0) 9286553Sarr 9386553Sarr 9459751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 9560938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 9659751Speterstruct modlist { 9791040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 9891040Sarr linker_file_t container; 9991040Sarr const char *name; 10091040Sarr int version; 10159751Speter}; 10291040Sarrtypedef struct modlist *modlist_t; 10391040Sarrstatic modlisthead_t found_modules; 10459751Speter 10594321Sbrianstatic modlist_t modlist_lookup2(const char *name, 10694321Sbrian struct mod_depend *verinfo); 10794321Sbrian 10859603Sdfrstatic char * 10959603Sdfrlinker_strdup(const char *str) 11059603Sdfr{ 11191040Sarr char *result; 11259603Sdfr 11391040Sarr if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 11491040Sarr strcpy(result, str); 11591040Sarr return (result); 11659603Sdfr} 11759603Sdfr 11825537Sdfrstatic void 11991040Sarrlinker_init(void *arg) 12025537Sdfr{ 12191040Sarr 12298452Sarr mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF); 12391040Sarr TAILQ_INIT(&classes); 12491040Sarr TAILQ_INIT(&linker_files); 12525537Sdfr} 12625537Sdfr 12791040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0) 12825537Sdfr 12998452Sarrstatic void 13098452Sarrlinker_stop_class_add(void *arg) 13198452Sarr{ 13298452Sarr 13398452Sarr linker_no_more_classes = 1; 13498452Sarr} 13598452Sarr 13698452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL) 13798452Sarr 13825537Sdfrint 13959603Sdfrlinker_add_class(linker_class_t lc) 14025537Sdfr{ 14191040Sarr 14298452Sarr /* 14398452Sarr * We disallow any class registration passt SI_ORDER_ANY 14498452Sarr * of SI_SUB_KLD. 14598452Sarr */ 14698452Sarr if (linker_no_more_classes == 1) 14798452Sarr return (EPERM); 14891040Sarr kobj_class_compile((kobj_class_t) lc); 14991040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 15091040Sarr return (0); 15125537Sdfr} 15225537Sdfr 15325537Sdfrstatic void 15425537Sdfrlinker_file_sysinit(linker_file_t lf) 15525537Sdfr{ 15691040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 15725537Sdfr 15891040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 15991040Sarr lf->filename)); 16025537Sdfr 16191040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 16291040Sarr return; 16391040Sarr /* 16491040Sarr * Perform a bubble sort of the system initialization objects by 16591040Sarr * their subsystem (primary key) and order (secondary key). 16691040Sarr * 16791040Sarr * Since some things care about execution order, this is the operation 16891040Sarr * which ensures continued function. 16991040Sarr */ 17091040Sarr for (sipp = start; sipp < stop; sipp++) { 17191040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 17291040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 17391040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 17491040Sarr (*sipp)->order <= (*xipp)->order)) 17591040Sarr continue; /* skip */ 17691040Sarr save = *sipp; 17791040Sarr *sipp = *xipp; 17891040Sarr *xipp = save; 17991040Sarr } 18025537Sdfr } 18125537Sdfr 18291040Sarr /* 18391040Sarr * Traverse the (now) ordered list of system initialization tasks. 18491040Sarr * Perform each task, and continue on to the next task. 18591040Sarr */ 18691040Sarr for (sipp = start; sipp < stop; sipp++) { 18791040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 18891040Sarr continue; /* skip dummy task(s) */ 18925537Sdfr 19091040Sarr /* Call function */ 19191040Sarr (*((*sipp)->func)) ((*sipp)->udata); 19291040Sarr } 19325537Sdfr} 19425537Sdfr 19541055Speterstatic void 19641055Speterlinker_file_sysuninit(linker_file_t lf) 19741055Speter{ 19891040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 19941055Speter 20091040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 20191040Sarr lf->filename)); 20241055Speter 20391068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 20491040Sarr NULL) != 0) 20591040Sarr return; 20641055Speter 20791040Sarr /* 20891040Sarr * Perform a reverse bubble sort of the system initialization objects 20991040Sarr * by their subsystem (primary key) and order (secondary key). 21091040Sarr * 21191040Sarr * Since some things care about execution order, this is the operation 21291040Sarr * which ensures continued function. 21391040Sarr */ 21491040Sarr for (sipp = start; sipp < stop; sipp++) { 21591040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 21691040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 21791040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 21891040Sarr (*sipp)->order >= (*xipp)->order)) 21991040Sarr continue; /* skip */ 22091040Sarr save = *sipp; 22191040Sarr *sipp = *xipp; 22291040Sarr *xipp = save; 22391040Sarr } 22441055Speter } 22541055Speter 22691040Sarr /* 22791040Sarr * Traverse the (now) ordered list of system initialization tasks. 22891040Sarr * Perform each task, and continue on to the next task. 22991040Sarr */ 23091040Sarr for (sipp = start; sipp < stop; sipp++) { 23191040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 23291040Sarr continue; /* skip dummy task(s) */ 23341055Speter 23491040Sarr /* Call function */ 23591040Sarr (*((*sipp)->func)) ((*sipp)->udata); 23691040Sarr } 23741055Speter} 23841055Speter 23944078Sdfrstatic void 24044078Sdfrlinker_file_register_sysctls(linker_file_t lf) 24144078Sdfr{ 24291040Sarr struct sysctl_oid **start, **stop, **oidp; 24344078Sdfr 24491040Sarr KLD_DPF(FILE, 24591040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 24691040Sarr lf->filename)); 24744078Sdfr 24891040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 24991040Sarr return; 25044078Sdfr 25191040Sarr for (oidp = start; oidp < stop; oidp++) 25291040Sarr sysctl_register_oid(*oidp); 25344078Sdfr} 25444078Sdfr 25544078Sdfrstatic void 25644078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 25744078Sdfr{ 25891040Sarr struct sysctl_oid **start, **stop, **oidp; 25944078Sdfr 26091040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 26191040Sarr " for %s\n", lf->filename)); 26244078Sdfr 26391040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 26491040Sarr return; 26544078Sdfr 26691040Sarr for (oidp = start; oidp < stop; oidp++) 26791040Sarr sysctl_unregister_oid(*oidp); 26844078Sdfr} 26944078Sdfr 27059751Speterstatic int 27159751Speterlinker_file_register_modules(linker_file_t lf) 27259751Speter{ 27391040Sarr struct mod_metadata **start, **stop, **mdp; 27491040Sarr const moduledata_t *moddata; 27591040Sarr int error; 27659751Speter 27791040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 27891040Sarr " in %s\n", lf->filename)); 27959751Speter 28091068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 28191040Sarr &stop, 0) != 0) { 28291040Sarr /* 28391040Sarr * This fallback should be unnecessary, but if we get booted 28491040Sarr * from boot2 instead of loader and we are missing our 28591040Sarr * metadata then we have to try the best we can. 28691040Sarr */ 28791040Sarr if (lf == linker_kernel_file) { 28891040Sarr start = SET_BEGIN(modmetadata_set); 28991040Sarr stop = SET_LIMIT(modmetadata_set); 29091040Sarr } else 29191040Sarr return (0); 29278161Speter } 29391040Sarr for (mdp = start; mdp < stop; mdp++) { 29491040Sarr if ((*mdp)->md_type != MDT_MODULE) 29591040Sarr continue; 29691040Sarr moddata = (*mdp)->md_data; 29791040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 29891040Sarr moddata->name, lf->filename)); 29991040Sarr error = module_register(moddata, lf); 30091040Sarr if (error) 30191068Sarr printf("Module %s failed to register: %d\n", 30291040Sarr moddata->name, error); 30359751Speter } 30491040Sarr return (0); 30559751Speter} 30659751Speter 30759751Speterstatic void 30859751Speterlinker_init_kernel_modules(void) 30959751Speter{ 31091040Sarr 31191040Sarr linker_file_register_modules(linker_kernel_file); 31259751Speter} 31359751Speter 31491040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) 31559751Speter 316101241Smuxstatic int 31791040Sarrlinker_load_file(const char *filename, linker_file_t *result) 31825537Sdfr{ 31991040Sarr linker_class_t lc; 32091040Sarr linker_file_t lf; 32191040Sarr int foundfile, error = 0; 32225537Sdfr 32391040Sarr /* Refuse to load modules if securelevel raised */ 32491040Sarr if (securelevel > 0) 32591040Sarr return (EPERM); 32662261Sarchie 32791040Sarr lf = linker_find_file_by_name(filename); 32891040Sarr if (lf) { 32991040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 33091040Sarr " incrementing refs\n", filename)); 33191040Sarr *result = lf; 33291040Sarr lf->refs++; 33391040Sarr goto out; 33491040Sarr } 33591040Sarr lf = NULL; 33691040Sarr foundfile = 0; 33798452Sarr 33898452Sarr /* 33998452Sarr * We do not need to protect (lock) classes here because there is 34098452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 34198452Sarr * and there is no class deregistration mechanism at this time. 34298452Sarr */ 34391040Sarr TAILQ_FOREACH(lc, &classes, link) { 34491040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 34591040Sarr filename)); 34691040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 34791040Sarr /* 34891040Sarr * If we got something other than ENOENT, then it exists but 34991040Sarr * we cannot load it for some other reason. 35091040Sarr */ 35191040Sarr if (error != ENOENT) 35291040Sarr foundfile = 1; 35391040Sarr if (lf) { 35491040Sarr linker_file_register_modules(lf); 35591040Sarr linker_file_register_sysctls(lf); 35691040Sarr linker_file_sysinit(lf); 35791040Sarr lf->flags |= LINKER_FILE_LINKED; 35891040Sarr *result = lf; 35991040Sarr error = 0; 36091040Sarr goto out; 36191040Sarr } 36291040Sarr } 36342755Speter /* 36491040Sarr * Less than ideal, but tells the user whether it failed to load or 36591040Sarr * the module was not found. 36642755Speter */ 367105337Ssam if (foundfile) { 368105337Ssam /* 369105337Ssam * Format not recognized or otherwise unloadable. 370105337Ssam * When loading a module that is statically built into 371105337Ssam * the kernel EEXIST percolates back up as the return 372105337Ssam * value. Preserve this so that apps like sysinstall 373105337Ssam * can recognize this special case and not post bogus 374105337Ssam * dialog boxes. 375105337Ssam */ 376105337Ssam if (error != EEXIST) 377105337Ssam error = ENOEXEC; 378105337Ssam } else 37991068Sarr error = ENOENT; /* Nothing found */ 38025537Sdfrout: 38191040Sarr return (error); 38225537Sdfr} 38325537Sdfr 38478413Sbrianint 38594321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 38694321Sbrian linker_file_t *result) 38778413Sbrian{ 38894321Sbrian modlist_t mod; 38994321Sbrian 39094321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 39194321Sbrian *result = mod->container; 39294321Sbrian (*result)->refs++; 39394321Sbrian return (0); 39494321Sbrian } 39594321Sbrian 39694321Sbrian return (linker_load_module(NULL, modname, NULL, verinfo, result)); 39778413Sbrian} 39878413Sbrian 39925537Sdfrlinker_file_t 40091040Sarrlinker_find_file_by_name(const char *filename) 40125537Sdfr{ 40291040Sarr linker_file_t lf = 0; 40391040Sarr char *koname; 40425537Sdfr 40591040Sarr koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 40691040Sarr if (koname == NULL) 40791040Sarr goto out; 40891040Sarr sprintf(koname, "%s.ko", filename); 40940861Speter 41098452Sarr mtx_lock(&kld_mtx); 41191040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 41292032Sdwmalone if (strcmp(lf->filename, koname) == 0) 41391040Sarr break; 41492032Sdwmalone if (strcmp(lf->filename, filename) == 0) 41591040Sarr break; 41691040Sarr } 41798452Sarr mtx_unlock(&kld_mtx); 41840861Speterout: 41991040Sarr if (koname) 42091040Sarr free(koname, M_LINKER); 42191040Sarr return (lf); 42225537Sdfr} 42325537Sdfr 42425537Sdfrlinker_file_t 42525537Sdfrlinker_find_file_by_id(int fileid) 42625537Sdfr{ 42791040Sarr linker_file_t lf = 0; 42898452Sarr 42998452Sarr mtx_lock(&kld_mtx); 43091040Sarr TAILQ_FOREACH(lf, &linker_files, link) 43191040Sarr if (lf->id == fileid) 43291040Sarr break; 43398452Sarr mtx_unlock(&kld_mtx); 43491040Sarr return (lf); 43525537Sdfr} 43625537Sdfr 43725537Sdfrlinker_file_t 43891040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 43925537Sdfr{ 44091040Sarr linker_file_t lf; 44191040Sarr const char *filename; 44225537Sdfr 44391040Sarr lf = NULL; 44491040Sarr filename = linker_basename(pathname); 44540159Speter 44691040Sarr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 44791040Sarr lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 44891040Sarr if (lf == NULL) 44991040Sarr goto out; 45091040Sarr lf->refs = 1; 45191040Sarr lf->userrefs = 0; 45291040Sarr lf->flags = 0; 45391040Sarr lf->filename = linker_strdup(filename); 45491040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 45591040Sarr lf->ndeps = 0; 45691040Sarr lf->deps = NULL; 45791040Sarr STAILQ_INIT(&lf->common); 45891040Sarr TAILQ_INIT(&lf->modules); 45998452Sarr mtx_lock(&kld_mtx); 46091040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 46198452Sarr mtx_unlock(&kld_mtx); 46225537Sdfrout: 46391040Sarr return (lf); 46425537Sdfr} 46525537Sdfr 46625537Sdfrint 46725537Sdfrlinker_file_unload(linker_file_t file) 46825537Sdfr{ 46991040Sarr module_t mod, next; 47091040Sarr modlist_t ml, nextml; 47191040Sarr struct common_symbol *cp; 47291040Sarr int error, i; 47325537Sdfr 47491040Sarr error = 0; 47562261Sarchie 47691040Sarr /* Refuse to unload modules if securelevel raised. */ 47791040Sarr if (securelevel > 0) 47891040Sarr return (EPERM); 479107089Srwatson#ifdef MAC 480107089Srwatson error = mac_check_kld_unload(curthread->td_ucred); 481107089Srwatson if (error) 482107089Srwatson return (error); 483107089Srwatson#endif 48425537Sdfr 48591040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 48691040Sarr if (file->refs == 1) { 48791040Sarr KLD_DPF(FILE, ("linker_file_unload: file is unloading," 48891040Sarr " informing modules\n")); 48991040Sarr 49091040Sarr /* 49191040Sarr * Inform any modules associated with this file. 49291040Sarr */ 49392547Sarr MOD_XLOCK; 49491040Sarr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 49591040Sarr next = module_getfnext(mod); 49692547Sarr MOD_XUNLOCK; 49791040Sarr 49891040Sarr /* 49991040Sarr * Give the module a chance to veto the unload. 50091040Sarr */ 50191040Sarr if ((error = module_unload(mod)) != 0) { 50291040Sarr KLD_DPF(FILE, ("linker_file_unload: module %x" 50391040Sarr " vetoes unload\n", mod)); 50491040Sarr goto out; 50592547Sarr } else 50692547Sarr MOD_XLOCK; 50791040Sarr module_release(mod); 50891040Sarr } 50992547Sarr MOD_XUNLOCK; 51091040Sarr } 51191040Sarr file->refs--; 51291040Sarr if (file->refs > 0) { 51325537Sdfr goto out; 51491040Sarr } 51591040Sarr for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { 51691040Sarr nextml = TAILQ_NEXT(ml, link); 51791040Sarr if (ml->container == file) 51891040Sarr TAILQ_REMOVE(&found_modules, ml, link); 51991040Sarr } 52025537Sdfr 52191040Sarr /* 52291040Sarr * Don't try to run SYSUNINITs if we are unloaded due to a 52391040Sarr * link error. 52491040Sarr */ 52591040Sarr if (file->flags & LINKER_FILE_LINKED) { 52691040Sarr linker_file_sysuninit(file); 52791040Sarr linker_file_unregister_sysctls(file); 52825537Sdfr } 52998452Sarr mtx_lock(&kld_mtx); 53091040Sarr TAILQ_REMOVE(&linker_files, file, link); 53198452Sarr mtx_unlock(&kld_mtx); 53225537Sdfr 53391040Sarr if (file->deps) { 53491040Sarr for (i = 0; i < file->ndeps; i++) 53591040Sarr linker_file_unload(file->deps[i]); 53691040Sarr free(file->deps, M_LINKER); 53791040Sarr file->deps = NULL; 53859751Speter } 53991040Sarr for (cp = STAILQ_FIRST(&file->common); cp; 54091068Sarr cp = STAILQ_FIRST(&file->common)) { 54191040Sarr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 54291040Sarr free(cp, M_LINKER); 54391040Sarr } 54459751Speter 54591040Sarr LINKER_UNLOAD(file); 54691040Sarr if (file->filename) { 54791040Sarr free(file->filename, M_LINKER); 54891040Sarr file->filename = NULL; 54991040Sarr } 55091040Sarr kobj_delete((kobj_t) file, M_LINKER); 55125537Sdfrout: 55291040Sarr return (error); 55325537Sdfr} 55425537Sdfr 55525537Sdfrint 55686469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 55725537Sdfr{ 55891040Sarr linker_file_t *newdeps; 55925537Sdfr 56091040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 56191040Sarr M_LINKER, M_WAITOK | M_ZERO); 56291040Sarr if (newdeps == NULL) 56391040Sarr return (ENOMEM); 56425537Sdfr 56591040Sarr if (file->deps) { 56691040Sarr bcopy(file->deps, newdeps, 56791040Sarr file->ndeps * sizeof(linker_file_t *)); 56891040Sarr free(file->deps, M_LINKER); 56991040Sarr } 57091040Sarr file->deps = newdeps; 57191040Sarr file->deps[file->ndeps] = dep; 57291040Sarr file->ndeps++; 57391040Sarr return (0); 57425537Sdfr} 57525537Sdfr 57678161Speter/* 57791040Sarr * Locate a linker set and its contents. This is a helper function to avoid 57891040Sarr * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** 57978161Speter */ 58078161Speterint 58178161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 58291040Sarr void *firstp, void *lastp, int *countp) 58378161Speter{ 58478161Speter 58591040Sarr return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 58678161Speter} 58778161Speter 58825537Sdfrcaddr_t 58991040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 59025537Sdfr{ 59191040Sarr c_linker_sym_t sym; 59291040Sarr linker_symval_t symval; 59391040Sarr caddr_t address; 59491040Sarr size_t common_size = 0; 59592032Sdwmalone int i; 59625537Sdfr 59791040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", 59891040Sarr file, name, deps)); 59925537Sdfr 60091040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 60191040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 60291040Sarr if (symval.value == 0) 60391040Sarr /* 60491040Sarr * For commons, first look them up in the 60591040Sarr * dependencies and only allocate space if not found 60691040Sarr * there. 60791040Sarr */ 60891040Sarr common_size = symval.size; 60991040Sarr else { 61091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 61191040Sarr ".value=%x\n", symval.value)); 61291040Sarr return (symval.value); 61391040Sarr } 61440159Speter } 61591040Sarr if (deps) { 61691040Sarr for (i = 0; i < file->ndeps; i++) { 61791040Sarr address = linker_file_lookup_symbol(file->deps[i], 61891040Sarr name, 0); 61991040Sarr if (address) { 62091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 62191040Sarr " deps value=%x\n", address)); 62291040Sarr return (address); 62391040Sarr } 62491040Sarr } 62525537Sdfr } 62691040Sarr if (common_size > 0) { 62791040Sarr /* 62891040Sarr * This is a common symbol which was not found in the 62991040Sarr * dependencies. We maintain a simple common symbol table in 63091040Sarr * the file object. 63191040Sarr */ 63291040Sarr struct common_symbol *cp; 63342849Speter 63491040Sarr STAILQ_FOREACH(cp, &file->common, link) { 63592032Sdwmalone if (strcmp(cp->name, name) == 0) { 63691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 63791040Sarr " old common value=%x\n", cp->address)); 63891040Sarr return (cp->address); 63991040Sarr } 64091040Sarr } 64191040Sarr /* 64291040Sarr * Round the symbol size up to align. 64391040Sarr */ 64491040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 64591040Sarr cp = malloc(sizeof(struct common_symbol) 64691040Sarr + common_size + strlen(name) + 1, M_LINKER, 64791040Sarr M_WAITOK | M_ZERO); 64891040Sarr if (cp == NULL) { 64991040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 65091040Sarr return (0); 65191040Sarr } 65291040Sarr cp->address = (caddr_t)(cp + 1); 65391040Sarr cp->name = cp->address + common_size; 65491040Sarr strcpy(cp->name, name); 65591040Sarr bzero(cp->address, common_size); 65691040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 65725537Sdfr 65891040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 65991040Sarr " value=%x\n", cp->address)); 66091040Sarr return (cp->address); 66140159Speter } 66291040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 66391040Sarr return (0); 66425537Sdfr} 66525537Sdfr 66640159Speter#ifdef DDB 66725537Sdfr/* 66891040Sarr * DDB Helpers. DDB has to look across multiple files with their own symbol 66991040Sarr * tables and string tables. 67091040Sarr * 67191040Sarr * Note that we do not obey list locking protocols here. We really don't need 67291040Sarr * DDB to hang because somebody's got the lock held. We'll take the chance 67391040Sarr * that the files list is inconsistant instead. 67440159Speter */ 67540159Speter 67640159Speterint 67743309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 67840159Speter{ 67991040Sarr linker_file_t lf; 68040159Speter 68191040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 68291040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 68391040Sarr return (0); 68491040Sarr } 68591040Sarr return (ENOENT); 68640159Speter} 68740159Speter 68840159Speterint 68943309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 69040159Speter{ 69191040Sarr linker_file_t lf; 69291040Sarr c_linker_sym_t best, es; 69391040Sarr u_long diff, bestdiff, off; 69440159Speter 69591040Sarr best = 0; 69691040Sarr off = (uintptr_t)value; 69791040Sarr bestdiff = off; 69891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 69991040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 70091040Sarr continue; 70191040Sarr if (es != 0 && diff < bestdiff) { 70291040Sarr best = es; 70391040Sarr bestdiff = diff; 70491040Sarr } 70591040Sarr if (bestdiff == 0) 70691040Sarr break; 70740159Speter } 70891040Sarr if (best) { 70991040Sarr *sym = best; 71091040Sarr *diffp = bestdiff; 71191040Sarr return (0); 71291040Sarr } else { 71391040Sarr *sym = 0; 71491040Sarr *diffp = off; 71591040Sarr return (ENOENT); 71691040Sarr } 71740159Speter} 71840159Speter 71940159Speterint 72043309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 72140159Speter{ 72291040Sarr linker_file_t lf; 72340159Speter 72491040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 72591040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 72691040Sarr return (0); 72791040Sarr } 72891040Sarr return (ENOENT); 72940159Speter} 73040159Speter#endif 73140159Speter 73240159Speter/* 73325537Sdfr * Syscalls. 73425537Sdfr */ 73582749Sdillon/* 73682749Sdillon * MPSAFE 73782749Sdillon */ 73825537Sdfrint 73991040Sarrkldload(struct thread *td, struct kldload_args *uap) 74025537Sdfr{ 74191040Sarr char *kldname, *modname; 74291040Sarr char *pathname = NULL; 74391040Sarr linker_file_t lf; 74491040Sarr int error = 0; 74525537Sdfr 74691040Sarr td->td_retval[0] = -1; 74725537Sdfr 74891040Sarr mtx_lock(&Giant); 74982749Sdillon 75093159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 75193159Sarr goto out; 75293159Sarr 75393593Sjhb if ((error = suser(td)) != 0) 75491040Sarr goto out; 75525537Sdfr 75691040Sarr pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 75791040Sarr if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, 75891040Sarr 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 80391040Sarr lf = linker_find_file_by_id(SCARG(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 84391040Sarr pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 84491040Sarr if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, 84591040Sarr NULL)) != 0) 84691040Sarr goto out; 84725537Sdfr 84891040Sarr filename = linker_basename(pathname); 84991040Sarr lf = linker_find_file_by_name(filename); 85091040Sarr if (lf) 85191040Sarr td->td_retval[0] = lf->id; 85291040Sarr else 85391040Sarr error = ENOENT; 85425537Sdfrout: 85591040Sarr if (pathname) 85691040Sarr free(pathname, M_TEMP); 85791040Sarr mtx_unlock(&Giant); 85891040Sarr return (error); 85925537Sdfr} 86025537Sdfr 86182749Sdillon/* 86282749Sdillon * MPSAFE 86382749Sdillon */ 86425537Sdfrint 86591040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 86625537Sdfr{ 86791040Sarr linker_file_t lf; 86891040Sarr int error = 0; 86925537Sdfr 870107089Srwatson#ifdef MAC 871107089Srwatson error = mac_check_kld_stat(td->td_ucred); 872107089Srwatson if (error) 873107089Srwatson return (error); 874107089Srwatson#endif 875107089Srwatson 87691040Sarr mtx_lock(&Giant); 87782749Sdillon 87891040Sarr if (SCARG(uap, fileid) == 0) { 87998452Sarr mtx_lock(&kld_mtx); 88091040Sarr if (TAILQ_FIRST(&linker_files)) 88191040Sarr td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; 88291040Sarr else 88391040Sarr td->td_retval[0] = 0; 88498452Sarr mtx_unlock(&kld_mtx); 88591040Sarr goto out; 88691040Sarr } 88791040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 88891040Sarr if (lf) { 88991040Sarr if (TAILQ_NEXT(lf, link)) 89091040Sarr td->td_retval[0] = TAILQ_NEXT(lf, link)->id; 89191040Sarr else 89291040Sarr td->td_retval[0] = 0; 89391040Sarr } else 89491040Sarr error = ENOENT; 89582749Sdillonout: 89691040Sarr mtx_unlock(&Giant); 89791040Sarr return (error); 89825537Sdfr} 89925537Sdfr 90082749Sdillon/* 90182749Sdillon * MPSAFE 90282749Sdillon */ 90325537Sdfrint 90491040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 90525537Sdfr{ 90691040Sarr linker_file_t lf; 90791040Sarr int error = 0; 90891040Sarr int namelen, version; 90991040Sarr struct kld_file_stat *stat; 91025537Sdfr 911107089Srwatson#ifdef MAC 912107089Srwatson error = mac_check_kld_stat(td->td_ucred); 913107089Srwatson if (error) 914107089Srwatson return (error); 915107089Srwatson#endif 916107089Srwatson 91791040Sarr mtx_lock(&Giant); 91882749Sdillon 91991040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 92091040Sarr if (lf == NULL) { 92191040Sarr error = ENOENT; 92291040Sarr goto out; 92391040Sarr } 92491040Sarr stat = SCARG(uap, stat); 92525537Sdfr 92691040Sarr /* 92791040Sarr * Check the version of the user's structure. 92891040Sarr */ 92991040Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 93091040Sarr goto out; 93191040Sarr if (version != sizeof(struct kld_file_stat)) { 93291040Sarr error = EINVAL; 93391040Sarr goto out; 93491040Sarr } 93591040Sarr namelen = strlen(lf->filename) + 1; 93691040Sarr if (namelen > MAXPATHLEN) 93791040Sarr namelen = MAXPATHLEN; 93891040Sarr if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) 93991040Sarr goto out; 94091040Sarr if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) 94191040Sarr goto out; 94291040Sarr if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) 94391040Sarr goto out; 94491040Sarr if ((error = copyout(&lf->address, &stat->address, 94591040Sarr sizeof(caddr_t))) != 0) 94691040Sarr goto out; 94791040Sarr if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) 94891040Sarr goto out; 94925537Sdfr 95091040Sarr td->td_retval[0] = 0; 95125537Sdfrout: 95291040Sarr mtx_unlock(&Giant); 95391040Sarr return (error); 95425537Sdfr} 95525537Sdfr 95682749Sdillon/* 95782749Sdillon * MPSAFE 95882749Sdillon */ 95925537Sdfrint 96091040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 96125537Sdfr{ 96291040Sarr linker_file_t lf; 96391040Sarr module_t mp; 96491040Sarr int error = 0; 96525537Sdfr 966107089Srwatson#ifdef MAC 967107089Srwatson error = mac_check_kld_stat(td->td_ucred); 968107089Srwatson if (error) 969107089Srwatson return (error); 970107089Srwatson#endif 971107089Srwatson 97291040Sarr mtx_lock(&Giant); 97391040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 97491040Sarr if (lf) { 97592547Sarr MOD_SLOCK; 97691040Sarr mp = TAILQ_FIRST(&lf->modules); 97791040Sarr if (mp != NULL) 97891040Sarr td->td_retval[0] = module_getid(mp); 97991040Sarr else 98091040Sarr td->td_retval[0] = 0; 98192547Sarr MOD_SUNLOCK; 98291040Sarr } else 98391040Sarr error = ENOENT; 98491040Sarr mtx_unlock(&Giant); 98591040Sarr return (error); 98625537Sdfr} 98740159Speter 98882749Sdillon/* 98982749Sdillon * MPSAFE 99082749Sdillon */ 99141090Speterint 99283366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 99341090Speter{ 99491040Sarr char *symstr = NULL; 99591040Sarr c_linker_sym_t sym; 99691040Sarr linker_symval_t symval; 99791040Sarr linker_file_t lf; 99891040Sarr struct kld_sym_lookup lookup; 99991040Sarr int error = 0; 100041090Speter 1001107089Srwatson#ifdef MAC 1002107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1003107089Srwatson if (error) 1004107089Srwatson return (error); 1005107089Srwatson#endif 1006107089Srwatson 100791040Sarr mtx_lock(&Giant); 100882749Sdillon 100991040Sarr if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0) 101091040Sarr goto out; 101191068Sarr if (lookup.version != sizeof(lookup) || 101291040Sarr SCARG(uap, cmd) != KLDSYM_LOOKUP) { 101391040Sarr error = EINVAL; 101491040Sarr goto out; 101591040Sarr } 101691040Sarr symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 101791040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 101891040Sarr goto out; 101991040Sarr if (SCARG(uap, fileid) != 0) { 102091040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 102191040Sarr if (lf == NULL) { 102291040Sarr error = ENOENT; 102391040Sarr goto out; 102491040Sarr } 102591040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 102691040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 102791040Sarr lookup.symvalue = (uintptr_t) symval.value; 102891040Sarr lookup.symsize = symval.size; 102991040Sarr error = copyout(&lookup, SCARG(uap, data), 103091040Sarr sizeof(lookup)); 103191040Sarr } else 103291040Sarr error = ENOENT; 103391040Sarr } else { 103498452Sarr mtx_lock(&kld_mtx); 103591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 103691040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 103791040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 103891040Sarr lookup.symvalue = (uintptr_t)symval.value; 103991040Sarr lookup.symsize = symval.size; 104091040Sarr error = copyout(&lookup, SCARG(uap, data), 104191040Sarr sizeof(lookup)); 104291068Sarr break; 104391040Sarr } 104491040Sarr } 104598452Sarr mtx_unlock(&kld_mtx); 104691040Sarr if (lf == NULL) 104791040Sarr error = ENOENT; 104841090Speter } 104941090Speterout: 105091040Sarr if (symstr) 105191040Sarr free(symstr, M_TEMP); 105291040Sarr mtx_unlock(&Giant); 105391040Sarr return (error); 105441090Speter} 105541090Speter 105640159Speter/* 105740159Speter * Preloaded module support 105840159Speter */ 105940159Speter 106059751Speterstatic modlist_t 106174642Sbpmodlist_lookup(const char *name, int ver) 106259751Speter{ 106391040Sarr modlist_t mod; 106459751Speter 106591040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 106692032Sdwmalone if (strcmp(mod->name, name) == 0 && 106792032Sdwmalone (ver == 0 || mod->version == ver)) 106891040Sarr return (mod); 106991040Sarr } 107091040Sarr return (NULL); 107159751Speter} 107259751Speter 107374642Sbpstatic modlist_t 107483321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 107583321Speter{ 107691040Sarr modlist_t mod, bestmod; 107792032Sdwmalone int ver; 107883321Speter 107991040Sarr if (verinfo == NULL) 108091040Sarr return (modlist_lookup(name, 0)); 108191040Sarr bestmod = NULL; 108291040Sarr for (mod = TAILQ_FIRST(&found_modules); mod; 108391040Sarr mod = TAILQ_NEXT(mod, link)) { 108492032Sdwmalone if (strcmp(mod->name, name) != 0) 108591040Sarr continue; 108691040Sarr ver = mod->version; 108791040Sarr if (ver == verinfo->md_ver_preferred) 108891040Sarr return (mod); 108991040Sarr if (ver >= verinfo->md_ver_minimum && 109091068Sarr ver <= verinfo->md_ver_maximum && 109191068Sarr ver > bestmod->version) 109291040Sarr bestmod = mod; 109391040Sarr } 109491040Sarr return (bestmod); 109583321Speter} 109683321Speter 109783321Speterstatic modlist_t 109878501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 109974642Sbp{ 110091040Sarr modlist_t mod; 110174642Sbp 110292705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 110391040Sarr if (mod == NULL) 110491040Sarr panic("no memory for module list"); 110591040Sarr mod->container = container; 110691040Sarr mod->name = modname; 110791040Sarr mod->version = version; 110891040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 110991040Sarr return (mod); 111074642Sbp} 111174642Sbp 111259751Speter/* 111359751Speter * This routine is cheap and nasty but will work for data pointers. 111459751Speter */ 111559751Speterstatic void * 111678501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset) 111759751Speter{ 111891040Sarr return (lf->address + (uintptr_t)offset); 111959751Speter} 112059751Speter 112174642Sbp/* 112274642Sbp * Dereference MDT_VERSION metadata into module name and version 112374642Sbp */ 112440159Speterstatic void 112574642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp, 112691040Sarr const char **modname, int *version) 112774642Sbp{ 112891040Sarr struct mod_version *mvp; 112974642Sbp 113091040Sarr if (modname) 113191040Sarr *modname = linker_reloc_ptr(lf, mp->md_cval); 113291040Sarr if (version) { 113391040Sarr mvp = linker_reloc_ptr(lf, mp->md_data); 113491040Sarr *version = mvp->mv_version; 113591040Sarr } 113674642Sbp} 113774642Sbp 113874642Sbp/* 113974642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure 114074642Sbp */ 114174642Sbpstatic void 114274642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp, 114391040Sarr const char **modname, struct mod_depend **verinfo) 114474642Sbp{ 114574642Sbp 114691040Sarr if (modname) 114791040Sarr *modname = linker_reloc_ptr(lf, mp->md_cval); 114891040Sarr if (verinfo) 114991040Sarr *verinfo = linker_reloc_ptr(lf, mp->md_data); 115074642Sbp} 115174642Sbp 115274642Sbpstatic void 115378161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 115491040Sarr struct mod_metadata **stop, int preload) 115574642Sbp{ 115691040Sarr struct mod_metadata *mp, **mdp; 115791040Sarr const char *modname; 115891040Sarr int ver; 115974642Sbp 116091040Sarr for (mdp = start; mdp < stop; mdp++) { 116191040Sarr if (preload) 116291040Sarr mp = *mdp; 116391040Sarr else 116491040Sarr mp = linker_reloc_ptr(lf, *mdp); 116591040Sarr if (mp->md_type != MDT_VERSION) 116691040Sarr continue; 116791040Sarr if (preload) { 116891040Sarr modname = mp->md_cval; 116991040Sarr ver = ((struct mod_version *)mp->md_data)->mv_version; 117091040Sarr } else 117191040Sarr linker_mdt_version(lf, mp, &modname, &ver); 117291040Sarr if (modlist_lookup(modname, ver) != NULL) { 117391040Sarr printf("module %s already present!\n", modname); 117491040Sarr /* XXX what can we do? this is a build error. :-( */ 117591040Sarr continue; 117691040Sarr } 117791040Sarr modlist_newmodule(modname, ver, lf); 117874642Sbp } 117974642Sbp} 118074642Sbp 118174642Sbpstatic void 118291040Sarrlinker_preload(void *arg) 118340159Speter{ 118491040Sarr caddr_t modptr; 118591040Sarr const char *modname, *nmodname; 118691040Sarr char *modtype; 118791040Sarr linker_file_t lf; 118891040Sarr linker_class_t lc; 118992032Sdwmalone int error; 119091040Sarr linker_file_list_t loaded_files; 119191040Sarr linker_file_list_t depended_files; 119291040Sarr struct mod_metadata *mp, *nmp; 119391040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 119491040Sarr struct mod_depend *verinfo; 119591040Sarr int nver; 119691040Sarr int resolves; 119791040Sarr modlist_t mod; 119891040Sarr struct sysinit **si_start, **si_stop; 119940159Speter 120091040Sarr TAILQ_INIT(&loaded_files); 120191040Sarr TAILQ_INIT(&depended_files); 120291040Sarr TAILQ_INIT(&found_modules); 120391040Sarr error = 0; 120459751Speter 120591040Sarr modptr = NULL; 120691040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 120791040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 120891040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 120991040Sarr if (modname == NULL) { 121091040Sarr printf("Preloaded module at %p does not have a" 121191040Sarr " name!\n", modptr); 121291040Sarr continue; 121391040Sarr } 121491040Sarr if (modtype == NULL) { 121591040Sarr printf("Preloaded module at %p does not have a type!\n", 121691040Sarr modptr); 121791040Sarr continue; 121891040Sarr } 121991040Sarr printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 122091040Sarr modptr); 122140159Speter lf = NULL; 122291040Sarr TAILQ_FOREACH(lc, &classes, link) { 122391040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 122491040Sarr if (error) { 122591040Sarr lf = NULL; 122691040Sarr break; 122791040Sarr } 122891040Sarr } 122991040Sarr if (lf) 123091040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 123140159Speter } 123240159Speter 123391040Sarr /* 123491040Sarr * First get a list of stuff in the kernel. 123591040Sarr */ 123691040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 123791040Sarr &stop, NULL) == 0) 123891040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 123959751Speter 124059751Speter /* 124191040Sarr * this is a once-off kinky bubble sort resolve relocation dependency 124291040Sarr * requirements 124359751Speter */ 124491040Sarrrestart: 124591040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 124691040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 124791040Sarr &stop, NULL); 124891040Sarr /* 124991040Sarr * First, look to see if we would successfully link with this 125091040Sarr * stuff. 125191040Sarr */ 125291040Sarr resolves = 1; /* unless we know otherwise */ 125391040Sarr if (!error) { 125491040Sarr for (mdp = start; mdp < stop; mdp++) { 125591040Sarr mp = linker_reloc_ptr(lf, *mdp); 125691040Sarr if (mp->md_type != MDT_DEPEND) 125791040Sarr continue; 125891040Sarr linker_mdt_depend(lf, mp, &modname, &verinfo); 125991040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 126091040Sarr nmp = linker_reloc_ptr(lf, *nmdp); 126191040Sarr if (nmp->md_type != MDT_VERSION) 126291040Sarr continue; 126391040Sarr linker_mdt_version(lf, nmp, &nmodname, 126491040Sarr NULL); 126591040Sarr nmodname = linker_reloc_ptr(lf, 126691040Sarr nmp->md_cval); 126792032Sdwmalone if (strcmp(modname, nmodname) == 0) 126891040Sarr break; 126991040Sarr } 127091040Sarr if (nmdp < stop) /* it's a self reference */ 127191040Sarr continue; 127291040Sarr 127391040Sarr /* 127491040Sarr * ok, the module isn't here yet, we 127591040Sarr * are not finished 127691040Sarr */ 127791068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 127891040Sarr resolves = 0; 127991040Sarr } 128064143Speter } 128191040Sarr /* 128291040Sarr * OK, if we found our modules, we can link. So, "provide" 128391040Sarr * the modules inside and add it to the end of the link order 128491040Sarr * list. 128591040Sarr */ 128691040Sarr if (resolves) { 128791040Sarr if (!error) { 128891040Sarr for (mdp = start; mdp < stop; mdp++) { 128991040Sarr mp = linker_reloc_ptr(lf, *mdp); 129091040Sarr if (mp->md_type != MDT_VERSION) 129191040Sarr continue; 129291040Sarr linker_mdt_version(lf, mp, 129391040Sarr &modname, &nver); 129491040Sarr if (modlist_lookup(modname, 129591040Sarr nver) != NULL) { 129691040Sarr printf("module %s already" 129791040Sarr " present!\n", modname); 129891040Sarr linker_file_unload(lf); 129991040Sarr TAILQ_REMOVE(&loaded_files, 130091040Sarr lf, loaded); 130191040Sarr /* we changed tailq next ptr */ 130291068Sarr goto restart; 130391040Sarr } 130491040Sarr modlist_newmodule(modname, nver, lf); 130591040Sarr } 130691040Sarr } 130791040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 130891040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 130991040Sarr /* 131091040Sarr * Since we provided modules, we need to restart the 131191040Sarr * sort so that the previous files that depend on us 131291040Sarr * have a chance. Also, we've busted the tailq next 131391040Sarr * pointer with the REMOVE. 131491040Sarr */ 131591040Sarr goto restart; 131659751Speter } 131759751Speter } 131891040Sarr 131959751Speter /* 132091040Sarr * At this point, we check to see what could not be resolved.. 132159751Speter */ 132291040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 132391040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 132491040Sarr linker_file_unload(lf); 132591040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 132640159Speter } 132759751Speter 132878161Speter /* 132991040Sarr * We made it. Finish off the linking in the order we determined. 133078161Speter */ 133191040Sarr TAILQ_FOREACH(lf, &depended_files, loaded) { 133291040Sarr if (linker_kernel_file) { 133391040Sarr linker_kernel_file->refs++; 133491040Sarr error = linker_file_add_dependency(lf, 133591040Sarr linker_kernel_file); 133691040Sarr if (error) 133791040Sarr panic("cannot add dependency"); 133891040Sarr } 133991040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 134091040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 134191040Sarr &stop, NULL); 134291040Sarr if (!error) { 134391040Sarr for (mdp = start; mdp < stop; mdp++) { 134491040Sarr mp = linker_reloc_ptr(lf, *mdp); 134591040Sarr if (mp->md_type != MDT_DEPEND) 134691040Sarr continue; 134791040Sarr linker_mdt_depend(lf, mp, &modname, &verinfo); 134891040Sarr mod = modlist_lookup2(modname, verinfo); 134991040Sarr mod->container->refs++; 135091040Sarr error = linker_file_add_dependency(lf, 135191040Sarr mod->container); 135291040Sarr if (error) 135391040Sarr panic("cannot add dependency"); 135491040Sarr } 135591040Sarr } 135691040Sarr /* 135791040Sarr * Now do relocation etc using the symbol search paths 135891040Sarr * established by the dependencies 135991040Sarr */ 136091040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 136191040Sarr if (error) { 136291040Sarr printf("KLD file %s - could not finalize loading\n", 136391040Sarr lf->filename); 136491040Sarr linker_file_unload(lf); 136591040Sarr continue; 136691040Sarr } 136791040Sarr linker_file_register_modules(lf); 136891040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 136991040Sarr &si_stop, NULL) == 0) 137091040Sarr sysinit_add(si_start, si_stop); 137191040Sarr linker_file_register_sysctls(lf); 137291040Sarr lf->flags |= LINKER_FILE_LINKED; 137359751Speter } 137491040Sarr /* woohoo! we made it! */ 137540159Speter} 137640159Speter 137791040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0) 137840159Speter 137940159Speter/* 138040159Speter * Search for a not-loaded module by name. 138191040Sarr * 138240159Speter * Modules may be found in the following locations: 138391040Sarr * 138491040Sarr * - preloaded (result is just the module name) - on disk (result is full path 138591040Sarr * to module) 138691040Sarr * 138791040Sarr * If the module name is qualified in any way (contains path, etc.) the we 138891040Sarr * simply return a copy of it. 138991040Sarr * 139040159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 139140159Speter * character as a separator to be consistent with the bootloader. 139240159Speter */ 139340159Speter 139483321Speterstatic char linker_hintfile[] = "linker.hints"; 139583358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules"; 139640159Speter 139740159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 139891040Sarr sizeof(linker_path), "module load search path"); 139940159Speter 140077843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 140170417Speter 140259751Speterstatic char *linker_ext_list[] = { 140383321Speter "", 140459751Speter ".ko", 140559751Speter NULL 140659751Speter}; 140759751Speter 140883321Speter/* 140991040Sarr * Check if file actually exists either with or without extension listed in 141091040Sarr * the linker_ext_list. (probably should be generic for the rest of the 141191040Sarr * kernel) 141283321Speter */ 141359751Speterstatic char * 141491040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 141591040Sarr int namelen, struct vattr *vap) 141640159Speter{ 141791040Sarr struct nameidata nd; 141891040Sarr struct thread *td = curthread; /* XXX */ 141991040Sarr char *result, **cpp, *sep; 142091040Sarr int error, len, extlen, reclen, flags; 142191040Sarr enum vtype type; 142240159Speter 142391040Sarr extlen = 0; 142491040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 142591040Sarr len = strlen(*cpp); 142691040Sarr if (len > extlen) 142791040Sarr extlen = len; 142891040Sarr } 142991040Sarr extlen++; /* trailing '\0' */ 143091040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 143183321Speter 143291040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 143391040Sarr result = malloc(reclen, M_LINKER, M_WAITOK); 143491040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 143591040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 143691040Sarr namelen, name, *cpp); 143791040Sarr /* 143891040Sarr * Attempt to open the file, and return the path if 143991040Sarr * we succeed and it's a regular file. 144091040Sarr */ 144191040Sarr NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); 144291040Sarr flags = FREAD; 144391040Sarr error = vn_open(&nd, &flags, 0); 144491040Sarr if (error == 0) { 144591040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 144691040Sarr type = nd.ni_vp->v_type; 144791040Sarr if (vap) 144891406Sjhb VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 144991040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 145091406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 145191040Sarr if (type == VREG) 145291040Sarr return (result); 145391040Sarr } 145483321Speter } 145591040Sarr free(result, M_LINKER); 145691040Sarr return (NULL); 145783321Speter} 145883321Speter 145991040Sarr#define INT_ALIGN(base, ptr) ptr = \ 146083321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 146183321Speter 146283321Speter/* 146391040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 146491040Sarr * version specification is available, then try to find the best KLD. 146583321Speter * Otherwise just find the latest one. 146683321Speter */ 146783321Speterstatic char * 146891040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 146991040Sarr int modnamelen, struct mod_depend *verinfo) 147083321Speter{ 147191040Sarr struct thread *td = curthread; /* XXX */ 147291406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 147391040Sarr struct nameidata nd; 147491040Sarr struct vattr vattr, mattr; 147591040Sarr u_char *hints = NULL; 147691040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 147791040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 147883321Speter 147991040Sarr result = NULL; 148091040Sarr bestver = found = 0; 148183321Speter 148291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 148391040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 148491040Sarr strlen(sep) + 1; 148591040Sarr pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 148691040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 148791040Sarr linker_hintfile); 148883321Speter 148991040Sarr NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); 149091040Sarr flags = FREAD; 149191040Sarr error = vn_open(&nd, &flags, 0); 149291040Sarr if (error) 149391040Sarr goto bad; 149491040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 149591040Sarr if (nd.ni_vp->v_type != VREG) 149691040Sarr goto bad; 149791040Sarr best = cp = NULL; 149891040Sarr error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td); 149991040Sarr if (error) 150091040Sarr goto bad; 150191040Sarr /* 150291040Sarr * XXX: we need to limit this number to some reasonable value 150391040Sarr */ 150491040Sarr if (vattr.va_size > 100 * 1024) { 150591040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 150691040Sarr goto bad; 150791040Sarr } 150891040Sarr hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 150991040Sarr if (hints == NULL) 151091040Sarr goto bad; 151191068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1512101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 151391040Sarr if (error) 151491040Sarr goto bad; 151599553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 151691040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 151791040Sarr nd.ni_vp = NULL; 151891040Sarr if (reclen != 0) { 151991040Sarr printf("can't read %d\n", reclen); 152091040Sarr goto bad; 152191040Sarr } 152291040Sarr intp = (int *)hints; 152383321Speter ival = *intp++; 152491040Sarr if (ival != LINKER_HINTS_VERSION) { 152591040Sarr printf("hints file version mismatch %d\n", ival); 152691040Sarr goto bad; 152783321Speter } 152891040Sarr bufend = hints + vattr.va_size; 152991040Sarr recptr = (u_char *)intp; 153091040Sarr clen = blen = 0; 153191040Sarr while (recptr < bufend && !found) { 153291040Sarr intp = (int *)recptr; 153391040Sarr reclen = *intp++; 153491040Sarr ival = *intp++; 153591040Sarr cp = (char *)intp; 153691040Sarr switch (ival) { 153791040Sarr case MDT_VERSION: 153891040Sarr clen = *cp++; 153991040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 154091040Sarr break; 154191040Sarr cp += clen; 154291040Sarr INT_ALIGN(hints, cp); 154391040Sarr ival = *(int *)cp; 154491040Sarr cp += sizeof(int); 154591040Sarr clen = *cp++; 154691040Sarr if (verinfo == NULL || 154791040Sarr ival == verinfo->md_ver_preferred) { 154891040Sarr found = 1; 154991040Sarr break; 155091040Sarr } 155191040Sarr if (ival >= verinfo->md_ver_minimum && 155291040Sarr ival <= verinfo->md_ver_maximum && 155391040Sarr ival > bestver) { 155491040Sarr bestver = ival; 155591040Sarr best = cp; 155691040Sarr blen = clen; 155791040Sarr } 155891040Sarr break; 155991040Sarr default: 156091040Sarr break; 156191040Sarr } 156291040Sarr recptr += reclen + sizeof(int); 156391040Sarr } 156483321Speter /* 156591040Sarr * Finally check if KLD is in the place 156683321Speter */ 156791040Sarr if (found) 156891040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 156991040Sarr else if (best) 157091040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 157191040Sarr 157291040Sarr /* 157391040Sarr * KLD is newer than hints file. What we should do now? 157491040Sarr */ 157591040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 157691040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 157791040Sarr " file\n", result); 157883321Speterbad: 1579105167Sphk free(pathbuf, M_LINKER); 158091040Sarr if (hints) 158191040Sarr free(hints, M_TEMP); 158299553Sjeff if (nd.ni_vp != NULL) { 158399553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 158491040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 158599553Sjeff } 158691040Sarr /* 158791040Sarr * If nothing found or hints is absent - fallback to the old 158891040Sarr * way by using "kldname[.ko]" as module name. 158991040Sarr */ 159091040Sarr if (!found && !bestver && result == NULL) 159191040Sarr result = linker_lookup_file(path, pathlen, modname, 159291040Sarr modnamelen, NULL); 159391040Sarr return (result); 159483321Speter} 159583321Speter 159683321Speter/* 159783321Speter * Lookup KLD which contains requested module in the all directories. 159883321Speter */ 159983321Speterstatic char * 160083321Speterlinker_search_module(const char *modname, int modnamelen, 160191040Sarr struct mod_depend *verinfo) 160283321Speter{ 160391040Sarr char *cp, *ep, *result; 160483321Speter 160591040Sarr /* 160691040Sarr * traverse the linker path 160791040Sarr */ 160891040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 160991040Sarr /* find the end of this component */ 161091040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 161191068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 161291068Sarr modnamelen, verinfo); 161391040Sarr if (result != NULL) 161491040Sarr return (result); 161591040Sarr if (*ep == 0) 161691040Sarr break; 161791040Sarr } 161891040Sarr return (NULL); 161983321Speter} 162083321Speter 162183321Speter/* 162283321Speter * Search for module in all directories listed in the linker_path. 162383321Speter */ 162483321Speterstatic char * 162583321Speterlinker_search_kld(const char *name) 162683321Speter{ 162791040Sarr char *cp, *ep, *result, **cpp; 162891040Sarr int extlen, len; 162983321Speter 163091040Sarr /* qualified at all? */ 163191040Sarr if (index(name, '/')) 163291040Sarr return (linker_strdup(name)); 163340159Speter 163491040Sarr extlen = 0; 163591040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 163691040Sarr len = strlen(*cpp); 163791040Sarr if (len > extlen) 163891040Sarr extlen = len; 163991040Sarr } 164091040Sarr extlen++; /* trailing '\0' */ 164159751Speter 164291040Sarr /* traverse the linker path */ 164391040Sarr len = strlen(name); 164491040Sarr for (ep = linker_path; *ep; ep++) { 164591040Sarr cp = ep; 164691040Sarr /* find the end of this component */ 164791040Sarr for (; *ep != 0 && *ep != ';'; ep++); 164891040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 164991040Sarr if (result != NULL) 165091040Sarr return (result); 165191040Sarr } 165291040Sarr return (NULL); 165340159Speter} 165459751Speter 165559751Speterstatic const char * 165691040Sarrlinker_basename(const char *path) 165759751Speter{ 165891040Sarr const char *filename; 165959751Speter 166091040Sarr filename = rindex(path, '/'); 166191040Sarr if (filename == NULL) 166291040Sarr return path; 166391040Sarr if (filename[1]) 166491040Sarr filename++; 166591040Sarr return (filename); 166659751Speter} 166759751Speter 166859751Speter/* 166991040Sarr * Find a file which contains given module and load it, if "parent" is not 167091040Sarr * NULL, register a reference to it. 167159751Speter */ 1672101241Smuxint 167383321Speterlinker_load_module(const char *kldname, const char *modname, 167491040Sarr struct linker_file *parent, struct mod_depend *verinfo, 167591040Sarr struct linker_file **lfpp) 167659751Speter{ 167791040Sarr linker_file_t lfdep; 167891040Sarr const char *filename; 167991040Sarr char *pathname; 168091040Sarr int error; 168159751Speter 168291040Sarr if (modname == NULL) { 168391040Sarr /* 168491040Sarr * We have to load KLD 168591040Sarr */ 168691068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 168791068Sarr " is not NULL")); 168891040Sarr pathname = linker_search_kld(kldname); 168991040Sarr } else { 169091040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 169191040Sarr return (EEXIST); 169294322Sbrian if (kldname != NULL) 169394322Sbrian pathname = linker_strdup(kldname); 169495488Sbrian else if (rootvnode == NULL) 169594322Sbrian pathname = NULL; 169694322Sbrian else 169791040Sarr /* 169891040Sarr * Need to find a KLD with required module 169991040Sarr */ 170091040Sarr pathname = linker_search_module(modname, 170191040Sarr strlen(modname), verinfo); 170291040Sarr } 170391040Sarr if (pathname == NULL) 170491040Sarr return (ENOENT); 170591040Sarr 170683321Speter /* 170791040Sarr * Can't load more than one file with the same basename XXX: 170891040Sarr * Actually it should be possible to have multiple KLDs with 170991040Sarr * the same basename but different path because they can 171091040Sarr * provide different versions of the same modules. 171183321Speter */ 171291040Sarr filename = linker_basename(pathname); 171391040Sarr if (linker_find_file_by_name(filename)) { 171491040Sarr error = EEXIST; 171591040Sarr goto out; 171683321Speter } 171791040Sarr do { 171891040Sarr error = linker_load_file(pathname, &lfdep); 171991040Sarr if (error) 172091040Sarr break; 172191040Sarr if (modname && verinfo && 172291040Sarr modlist_lookup2(modname, verinfo) == NULL) { 172391040Sarr linker_file_unload(lfdep); 172491040Sarr error = ENOENT; 172591040Sarr break; 172691040Sarr } 172791040Sarr if (parent) { 172891040Sarr error = linker_file_add_dependency(parent, lfdep); 172991040Sarr if (error) 173091040Sarr break; 173191040Sarr } 173291040Sarr if (lfpp) 173391040Sarr *lfpp = lfdep; 173491040Sarr } while (0); 173559751Speterout: 173691040Sarr if (pathname) 173791040Sarr free(pathname, M_LINKER); 173891040Sarr return (error); 173959751Speter} 174059751Speter 174159751Speter/* 174291040Sarr * This routine is responsible for finding dependencies of userland initiated 174391040Sarr * kldload(2)'s of files. 174459751Speter */ 174559751Speterint 174686469Siedowselinker_load_dependencies(linker_file_t lf) 174759751Speter{ 174891040Sarr linker_file_t lfdep; 174991040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 175091040Sarr struct mod_metadata *mp, *nmp; 175191040Sarr struct mod_depend *verinfo; 175291040Sarr modlist_t mod; 175391040Sarr const char *modname, *nmodname; 175492032Sdwmalone int ver, error = 0, count; 175559751Speter 175691040Sarr /* 175791040Sarr * All files are dependant on /kernel. 175891040Sarr */ 175991040Sarr if (linker_kernel_file) { 176091040Sarr linker_kernel_file->refs++; 176191040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 176291040Sarr if (error) 176391040Sarr return (error); 176459751Speter } 176591040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 176691040Sarr &count) != 0) 176791040Sarr return (0); 176891040Sarr for (mdp = start; mdp < stop; mdp++) { 176991040Sarr mp = linker_reloc_ptr(lf, *mdp); 177091040Sarr if (mp->md_type != MDT_VERSION) 177191040Sarr continue; 177291040Sarr linker_mdt_version(lf, mp, &modname, &ver); 177391040Sarr mod = modlist_lookup(modname, ver); 177491040Sarr if (mod != NULL) { 177591040Sarr printf("interface %s.%d already present in the KLD" 177691040Sarr " '%s'!\n", modname, ver, 177791040Sarr mod->container->filename); 177891040Sarr return (EEXIST); 177991040Sarr } 178091040Sarr } 178174642Sbp 178291040Sarr for (mdp = start; mdp < stop; mdp++) { 178391040Sarr mp = linker_reloc_ptr(lf, *mdp); 178491040Sarr if (mp->md_type != MDT_DEPEND) 178591040Sarr continue; 178691040Sarr linker_mdt_depend(lf, mp, &modname, &verinfo); 178791040Sarr nmodname = NULL; 178891040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 178991040Sarr nmp = linker_reloc_ptr(lf, *nmdp); 179091040Sarr if (nmp->md_type != MDT_VERSION) 179191040Sarr continue; 179291040Sarr nmodname = linker_reloc_ptr(lf, nmp->md_cval); 179392032Sdwmalone if (strcmp(modname, nmodname) == 0) 179491040Sarr break; 179591040Sarr } 179691040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 179791040Sarr continue; 179891040Sarr mod = modlist_lookup2(modname, verinfo); 179991040Sarr if (mod) { /* woohoo, it's loaded already */ 180091040Sarr lfdep = mod->container; 180191040Sarr lfdep->refs++; 180291040Sarr error = linker_file_add_dependency(lf, lfdep); 180391040Sarr if (error) 180491040Sarr break; 180591040Sarr continue; 180691040Sarr } 180791040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 180891040Sarr if (error) { 180991040Sarr printf("KLD %s: depends on %s - not available\n", 181091040Sarr lf->filename, modname); 181191040Sarr break; 181291040Sarr } 181359751Speter } 181459751Speter 181591040Sarr if (error) 181691040Sarr return (error); 181791040Sarr linker_addmodules(lf, start, stop, 0); 181891040Sarr return (error); 181959751Speter} 182085736Sgreen 182185736Sgreenstatic int 182285736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 182385736Sgreen{ 182485736Sgreen struct sysctl_req *req; 182585736Sgreen 182685736Sgreen req = opaque; 182785736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 182885736Sgreen} 182985736Sgreen 183085736Sgreen/* 183185736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 183285736Sgreen * in the kernel. 183385736Sgreen */ 183485736Sgreenstatic int 183585736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 183685736Sgreen{ 183785736Sgreen linker_file_t lf; 183885736Sgreen int error; 183985736Sgreen 1840107089Srwatson#ifdef MAC 1841107089Srwatson error = mac_check_kld_stat(req->td->td_ucred); 1842107089Srwatson if (error) 1843107089Srwatson return (error); 1844107089Srwatson#endif 1845100488Struckman sysctl_wire_old_buffer(req, 0); 184698452Sarr mtx_lock(&kld_mtx); 184785736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 184885736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 184985736Sgreen sysctl_kern_function_list_iterate, req); 185098452Sarr if (error) { 185198452Sarr mtx_unlock(&kld_mtx); 185285736Sgreen return (error); 185398452Sarr } 185485736Sgreen } 185598452Sarr mtx_unlock(&kld_mtx); 185685736Sgreen return (SYSCTL_OUT(req, "", 1)); 185785736Sgreen} 185885736Sgreen 185985736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 186091040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 1861