kern_linker.c revision 94321
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 94321 2002-04-10 01:13:57Z brian $ 2725537Sdfr */ 2825537Sdfr 2940159Speter#include "opt_ddb.h" 3040159Speter 3125537Sdfr#include <sys/param.h> 3225537Sdfr#include <sys/kernel.h> 3325537Sdfr#include <sys/systm.h> 3425537Sdfr#include <sys/malloc.h> 3525537Sdfr#include <sys/sysproto.h> 3625537Sdfr#include <sys/sysent.h> 3725537Sdfr#include <sys/proc.h> 3825537Sdfr#include <sys/lock.h> 3982749Sdillon#include <sys/mutex.h> 4092547Sarr#include <sys/sx.h> 4125537Sdfr#include <sys/module.h> 4225537Sdfr#include <sys/linker.h> 4340159Speter#include <sys/fcntl.h> 4440159Speter#include <sys/libkern.h> 4540159Speter#include <sys/namei.h> 4640159Speter#include <sys/vnode.h> 4740159Speter#include <sys/sysctl.h> 4825537Sdfr 4959603Sdfr#include "linker_if.h" 5059603Sdfr 5140961Speter#ifdef KLD_DEBUG 5240961Speterint kld_debug = 0; 5340961Speter#endif 5440961Speter 5591040Sarr/* 5691040Sarr * static char *linker_search_path(const char *name, struct mod_depend 5791040Sarr * *verinfo); 5891040Sarr */ 5991040Sarrstatic const char *linker_basename(const char *path); 6091040Sarrstatic int linker_load_module(const char *kldname, const char *modname, 6191040Sarr struct linker_file *parent, struct mod_depend *verinfo, 6291040Sarr struct linker_file **lfpp); 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 7125537Sdfrstatic struct lock lock; /* lock for the file list */ 7225537Sdfrstatic linker_class_list_t classes; 7350068Sgrogstatic linker_file_list_t linker_files; 7425537Sdfrstatic int next_file_id = 1; 7525537Sdfr 7686553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 7791040Sarr linker_file_t lftmp; \ 7886553Sarr \ 7986553Sarrretry: \ 8091040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 8191040Sarr if (next_file_id == lftmp->id) { \ 8291040Sarr next_file_id++; \ 8391040Sarr goto retry; \ 8491040Sarr } \ 8591040Sarr } \ 8691040Sarr (a) = next_file_id; \ 8786553Sarr} while(0) 8886553Sarr 8986553Sarr 9059751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 9160938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 9259751Speterstruct modlist { 9391040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 9491040Sarr linker_file_t container; 9591040Sarr const char *name; 9691040Sarr int version; 9759751Speter}; 9891040Sarrtypedef struct modlist *modlist_t; 9991040Sarrstatic modlisthead_t found_modules; 10059751Speter 10194321Sbrianstatic modlist_t modlist_lookup2(const char *name, 10294321Sbrian struct mod_depend *verinfo); 10394321Sbrian 10459603Sdfrstatic char * 10559603Sdfrlinker_strdup(const char *str) 10659603Sdfr{ 10791040Sarr char *result; 10859603Sdfr 10991040Sarr if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 11091040Sarr strcpy(result, str); 11191040Sarr return (result); 11259603Sdfr} 11359603Sdfr 11425537Sdfrstatic void 11591040Sarrlinker_init(void *arg) 11625537Sdfr{ 11791040Sarr 11891040Sarr lockinit(&lock, PVM, "klink", 0, 0); 11991040Sarr TAILQ_INIT(&classes); 12091040Sarr TAILQ_INIT(&linker_files); 12125537Sdfr} 12225537Sdfr 12391040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0) 12425537Sdfr 12525537Sdfrint 12659603Sdfrlinker_add_class(linker_class_t lc) 12725537Sdfr{ 12891040Sarr 12991040Sarr kobj_class_compile((kobj_class_t) lc); 13091040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 13191040Sarr return (0); 13225537Sdfr} 13325537Sdfr 13425537Sdfrstatic void 13525537Sdfrlinker_file_sysinit(linker_file_t lf) 13625537Sdfr{ 13791040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 13825537Sdfr 13991040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 14091040Sarr lf->filename)); 14125537Sdfr 14291040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 14391040Sarr return; 14491040Sarr /* 14591040Sarr * Perform a bubble sort of the system initialization objects by 14691040Sarr * their subsystem (primary key) and order (secondary key). 14791040Sarr * 14891040Sarr * Since some things care about execution order, this is the operation 14991040Sarr * which ensures continued function. 15091040Sarr */ 15191040Sarr for (sipp = start; sipp < stop; sipp++) { 15291040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 15391040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 15491040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 15591040Sarr (*sipp)->order <= (*xipp)->order)) 15691040Sarr continue; /* skip */ 15791040Sarr save = *sipp; 15891040Sarr *sipp = *xipp; 15991040Sarr *xipp = save; 16091040Sarr } 16125537Sdfr } 16225537Sdfr 16391040Sarr /* 16491040Sarr * Traverse the (now) ordered list of system initialization tasks. 16591040Sarr * Perform each task, and continue on to the next task. 16691040Sarr */ 16791040Sarr for (sipp = start; sipp < stop; sipp++) { 16891040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 16991040Sarr continue; /* skip dummy task(s) */ 17025537Sdfr 17191040Sarr /* Call function */ 17291040Sarr (*((*sipp)->func)) ((*sipp)->udata); 17391040Sarr } 17425537Sdfr} 17525537Sdfr 17641055Speterstatic void 17741055Speterlinker_file_sysuninit(linker_file_t lf) 17841055Speter{ 17991040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 18041055Speter 18191040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 18291040Sarr lf->filename)); 18341055Speter 18491068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 18591040Sarr NULL) != 0) 18691040Sarr return; 18741055Speter 18891040Sarr /* 18991040Sarr * Perform a reverse bubble sort of the system initialization objects 19091040Sarr * by their subsystem (primary key) and order (secondary key). 19191040Sarr * 19291040Sarr * Since some things care about execution order, this is the operation 19391040Sarr * which ensures continued function. 19491040Sarr */ 19591040Sarr for (sipp = start; sipp < stop; sipp++) { 19691040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 19791040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 19891040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 19991040Sarr (*sipp)->order >= (*xipp)->order)) 20091040Sarr continue; /* skip */ 20191040Sarr save = *sipp; 20291040Sarr *sipp = *xipp; 20391040Sarr *xipp = save; 20491040Sarr } 20541055Speter } 20641055Speter 20791040Sarr /* 20891040Sarr * Traverse the (now) ordered list of system initialization tasks. 20991040Sarr * Perform each task, and continue on to the next task. 21091040Sarr */ 21191040Sarr for (sipp = start; sipp < stop; sipp++) { 21291040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 21391040Sarr continue; /* skip dummy task(s) */ 21441055Speter 21591040Sarr /* Call function */ 21691040Sarr (*((*sipp)->func)) ((*sipp)->udata); 21791040Sarr } 21841055Speter} 21941055Speter 22044078Sdfrstatic void 22144078Sdfrlinker_file_register_sysctls(linker_file_t lf) 22244078Sdfr{ 22391040Sarr struct sysctl_oid **start, **stop, **oidp; 22444078Sdfr 22591040Sarr KLD_DPF(FILE, 22691040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 22791040Sarr lf->filename)); 22844078Sdfr 22991040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 23091040Sarr return; 23144078Sdfr 23291040Sarr for (oidp = start; oidp < stop; oidp++) 23391040Sarr sysctl_register_oid(*oidp); 23444078Sdfr} 23544078Sdfr 23644078Sdfrstatic void 23744078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 23844078Sdfr{ 23991040Sarr struct sysctl_oid **start, **stop, **oidp; 24044078Sdfr 24191040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 24291040Sarr " for %s\n", lf->filename)); 24344078Sdfr 24491040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 24591040Sarr return; 24644078Sdfr 24791040Sarr for (oidp = start; oidp < stop; oidp++) 24891040Sarr sysctl_unregister_oid(*oidp); 24944078Sdfr} 25044078Sdfr 25159751Speterstatic int 25259751Speterlinker_file_register_modules(linker_file_t lf) 25359751Speter{ 25491040Sarr struct mod_metadata **start, **stop, **mdp; 25591040Sarr const moduledata_t *moddata; 25691040Sarr int error; 25759751Speter 25891040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 25991040Sarr " in %s\n", lf->filename)); 26059751Speter 26191068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 26291040Sarr &stop, 0) != 0) { 26391040Sarr /* 26491040Sarr * This fallback should be unnecessary, but if we get booted 26591040Sarr * from boot2 instead of loader and we are missing our 26691040Sarr * metadata then we have to try the best we can. 26791040Sarr */ 26891040Sarr if (lf == linker_kernel_file) { 26991040Sarr start = SET_BEGIN(modmetadata_set); 27091040Sarr stop = SET_LIMIT(modmetadata_set); 27191040Sarr } else 27291040Sarr return (0); 27378161Speter } 27491040Sarr for (mdp = start; mdp < stop; mdp++) { 27591040Sarr if ((*mdp)->md_type != MDT_MODULE) 27691040Sarr continue; 27791040Sarr moddata = (*mdp)->md_data; 27891040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 27991040Sarr moddata->name, lf->filename)); 28091040Sarr error = module_register(moddata, lf); 28191040Sarr if (error) 28291068Sarr printf("Module %s failed to register: %d\n", 28391040Sarr moddata->name, error); 28459751Speter } 28591040Sarr return (0); 28659751Speter} 28759751Speter 28859751Speterstatic void 28959751Speterlinker_init_kernel_modules(void) 29059751Speter{ 29191040Sarr 29291040Sarr linker_file_register_modules(linker_kernel_file); 29359751Speter} 29459751Speter 29591040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) 29659751Speter 29725537Sdfrint 29891040Sarrlinker_load_file(const char *filename, linker_file_t *result) 29925537Sdfr{ 30091040Sarr linker_class_t lc; 30191040Sarr linker_file_t lf; 30291040Sarr int foundfile, error = 0; 30325537Sdfr 30491040Sarr /* Refuse to load modules if securelevel raised */ 30591040Sarr if (securelevel > 0) 30691040Sarr return (EPERM); 30762261Sarchie 30891040Sarr lf = linker_find_file_by_name(filename); 30991040Sarr if (lf) { 31091040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 31191040Sarr " incrementing refs\n", filename)); 31291040Sarr *result = lf; 31391040Sarr lf->refs++; 31491040Sarr goto out; 31591040Sarr } 31691040Sarr lf = NULL; 31791040Sarr foundfile = 0; 31891040Sarr TAILQ_FOREACH(lc, &classes, link) { 31991040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 32091040Sarr filename)); 32191040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 32291040Sarr /* 32391040Sarr * If we got something other than ENOENT, then it exists but 32491040Sarr * we cannot load it for some other reason. 32591040Sarr */ 32691040Sarr if (error != ENOENT) 32791040Sarr foundfile = 1; 32891040Sarr if (lf) { 32991040Sarr linker_file_register_modules(lf); 33091040Sarr linker_file_register_sysctls(lf); 33191040Sarr linker_file_sysinit(lf); 33291040Sarr lf->flags |= LINKER_FILE_LINKED; 33391040Sarr *result = lf; 33491040Sarr error = 0; 33591040Sarr goto out; 33691040Sarr } 33791040Sarr } 33842755Speter /* 33991040Sarr * Less than ideal, but tells the user whether it failed to load or 34091040Sarr * the module was not found. 34142755Speter */ 34291040Sarr if (foundfile) 34391068Sarr /* Format not recognized (or unloadable). */ 34491068Sarr error = ENOEXEC; 34591040Sarr else 34691068Sarr error = ENOENT; /* Nothing found */ 34725537Sdfrout: 34891040Sarr return (error); 34925537Sdfr} 35025537Sdfr 35178413Sbrianint 35294321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 35394321Sbrian linker_file_t *result) 35478413Sbrian{ 35594321Sbrian modlist_t mod; 35694321Sbrian 35794321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 35894321Sbrian *result = mod->container; 35994321Sbrian (*result)->refs++; 36094321Sbrian return (0); 36194321Sbrian } 36294321Sbrian 36394321Sbrian return (linker_load_module(NULL, modname, NULL, verinfo, result)); 36478413Sbrian} 36578413Sbrian 36625537Sdfrlinker_file_t 36791040Sarrlinker_find_file_by_name(const char *filename) 36825537Sdfr{ 36991040Sarr linker_file_t lf = 0; 37091040Sarr char *koname; 37125537Sdfr 37291040Sarr koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 37391040Sarr if (koname == NULL) 37491040Sarr goto out; 37591040Sarr sprintf(koname, "%s.ko", filename); 37640861Speter 37791040Sarr lockmgr(&lock, LK_SHARED, 0, curthread); 37891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 37992032Sdwmalone if (strcmp(lf->filename, koname) == 0) 38091040Sarr break; 38192032Sdwmalone if (strcmp(lf->filename, filename) == 0) 38291040Sarr break; 38391040Sarr } 38491040Sarr lockmgr(&lock, LK_RELEASE, 0, curthread); 38540861Speterout: 38691040Sarr if (koname) 38791040Sarr free(koname, M_LINKER); 38891040Sarr return (lf); 38925537Sdfr} 39025537Sdfr 39125537Sdfrlinker_file_t 39225537Sdfrlinker_find_file_by_id(int fileid) 39325537Sdfr{ 39491040Sarr linker_file_t lf = 0; 39525537Sdfr 39691040Sarr lockmgr(&lock, LK_SHARED, 0, curthread); 39791040Sarr TAILQ_FOREACH(lf, &linker_files, link) 39891040Sarr if (lf->id == fileid) 39991040Sarr break; 40091040Sarr lockmgr(&lock, LK_RELEASE, 0, curthread); 40191040Sarr return (lf); 40225537Sdfr} 40325537Sdfr 40425537Sdfrlinker_file_t 40591040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 40625537Sdfr{ 40791040Sarr linker_file_t lf; 40891040Sarr const char *filename; 40925537Sdfr 41091040Sarr lf = NULL; 41191040Sarr filename = linker_basename(pathname); 41240159Speter 41391040Sarr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 41491040Sarr lockmgr(&lock, LK_EXCLUSIVE, 0, curthread); 41591040Sarr lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 41691040Sarr if (lf == NULL) 41791040Sarr goto out; 41891040Sarr lf->refs = 1; 41991040Sarr lf->userrefs = 0; 42091040Sarr lf->flags = 0; 42191040Sarr lf->filename = linker_strdup(filename); 42291040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 42391040Sarr lf->ndeps = 0; 42491040Sarr lf->deps = NULL; 42591040Sarr STAILQ_INIT(&lf->common); 42691040Sarr TAILQ_INIT(&lf->modules); 42791040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 42825537Sdfrout: 42991040Sarr lockmgr(&lock, LK_RELEASE, 0, curthread); 43091040Sarr return (lf); 43125537Sdfr} 43225537Sdfr 43325537Sdfrint 43425537Sdfrlinker_file_unload(linker_file_t file) 43525537Sdfr{ 43691040Sarr module_t mod, next; 43791040Sarr modlist_t ml, nextml; 43891040Sarr struct common_symbol *cp; 43991040Sarr int error, i; 44025537Sdfr 44191040Sarr error = 0; 44262261Sarchie 44391040Sarr /* Refuse to unload modules if securelevel raised. */ 44491040Sarr if (securelevel > 0) 44591040Sarr return (EPERM); 44625537Sdfr 44791040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 44891040Sarr lockmgr(&lock, LK_EXCLUSIVE, 0, curthread); 44991040Sarr if (file->refs == 1) { 45091040Sarr KLD_DPF(FILE, ("linker_file_unload: file is unloading," 45191040Sarr " informing modules\n")); 45291040Sarr 45391040Sarr /* 45491040Sarr * Inform any modules associated with this file. 45591040Sarr */ 45692547Sarr MOD_XLOCK; 45791040Sarr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 45891040Sarr next = module_getfnext(mod); 45992547Sarr MOD_XUNLOCK; 46091040Sarr 46191040Sarr /* 46291040Sarr * Give the module a chance to veto the unload. 46391040Sarr */ 46491040Sarr if ((error = module_unload(mod)) != 0) { 46591040Sarr KLD_DPF(FILE, ("linker_file_unload: module %x" 46691040Sarr " vetoes unload\n", mod)); 46791040Sarr lockmgr(&lock, LK_RELEASE, 0, curthread); 46891040Sarr goto out; 46992547Sarr } else 47092547Sarr MOD_XLOCK; 47191040Sarr module_release(mod); 47291040Sarr } 47392547Sarr MOD_XUNLOCK; 47491040Sarr } 47591040Sarr file->refs--; 47691040Sarr if (file->refs > 0) { 47783366Sjulian lockmgr(&lock, LK_RELEASE, 0, curthread); 47825537Sdfr goto out; 47991040Sarr } 48091040Sarr for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { 48191040Sarr nextml = TAILQ_NEXT(ml, link); 48291040Sarr if (ml->container == file) 48391040Sarr TAILQ_REMOVE(&found_modules, ml, link); 48491040Sarr } 48525537Sdfr 48691040Sarr /* 48791040Sarr * Don't try to run SYSUNINITs if we are unloaded due to a 48891040Sarr * link error. 48991040Sarr */ 49091040Sarr if (file->flags & LINKER_FILE_LINKED) { 49191040Sarr linker_file_sysuninit(file); 49291040Sarr linker_file_unregister_sysctls(file); 49325537Sdfr } 49491040Sarr TAILQ_REMOVE(&linker_files, file, link); 49583366Sjulian lockmgr(&lock, LK_RELEASE, 0, curthread); 49625537Sdfr 49791040Sarr if (file->deps) { 49891040Sarr for (i = 0; i < file->ndeps; i++) 49991040Sarr linker_file_unload(file->deps[i]); 50091040Sarr free(file->deps, M_LINKER); 50191040Sarr file->deps = NULL; 50259751Speter } 50391040Sarr for (cp = STAILQ_FIRST(&file->common); cp; 50491068Sarr cp = STAILQ_FIRST(&file->common)) { 50591040Sarr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 50691040Sarr free(cp, M_LINKER); 50791040Sarr } 50859751Speter 50991040Sarr LINKER_UNLOAD(file); 51091040Sarr if (file->filename) { 51191040Sarr free(file->filename, M_LINKER); 51291040Sarr file->filename = NULL; 51391040Sarr } 51491040Sarr kobj_delete((kobj_t) file, M_LINKER); 51525537Sdfrout: 51691040Sarr return (error); 51725537Sdfr} 51825537Sdfr 51925537Sdfrint 52086469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 52125537Sdfr{ 52291040Sarr linker_file_t *newdeps; 52325537Sdfr 52491040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 52591040Sarr M_LINKER, M_WAITOK | M_ZERO); 52691040Sarr if (newdeps == NULL) 52791040Sarr return (ENOMEM); 52825537Sdfr 52991040Sarr if (file->deps) { 53091040Sarr bcopy(file->deps, newdeps, 53191040Sarr file->ndeps * sizeof(linker_file_t *)); 53291040Sarr free(file->deps, M_LINKER); 53391040Sarr } 53491040Sarr file->deps = newdeps; 53591040Sarr file->deps[file->ndeps] = dep; 53691040Sarr file->ndeps++; 53791040Sarr return (0); 53825537Sdfr} 53925537Sdfr 54078161Speter/* 54191040Sarr * Locate a linker set and its contents. This is a helper function to avoid 54291040Sarr * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** 54378161Speter */ 54478161Speterint 54578161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 54691040Sarr void *firstp, void *lastp, int *countp) 54778161Speter{ 54878161Speter 54991040Sarr return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 55078161Speter} 55178161Speter 55225537Sdfrcaddr_t 55391040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 55425537Sdfr{ 55591040Sarr c_linker_sym_t sym; 55691040Sarr linker_symval_t symval; 55791040Sarr caddr_t address; 55891040Sarr size_t common_size = 0; 55992032Sdwmalone int i; 56025537Sdfr 56191040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", 56291040Sarr file, name, deps)); 56325537Sdfr 56491040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 56591040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 56691040Sarr if (symval.value == 0) 56791040Sarr /* 56891040Sarr * For commons, first look them up in the 56991040Sarr * dependencies and only allocate space if not found 57091040Sarr * there. 57191040Sarr */ 57291040Sarr common_size = symval.size; 57391040Sarr else { 57491040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 57591040Sarr ".value=%x\n", symval.value)); 57691040Sarr return (symval.value); 57791040Sarr } 57840159Speter } 57991040Sarr if (deps) { 58091040Sarr for (i = 0; i < file->ndeps; i++) { 58191040Sarr address = linker_file_lookup_symbol(file->deps[i], 58291040Sarr name, 0); 58391040Sarr if (address) { 58491040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 58591040Sarr " deps value=%x\n", address)); 58691040Sarr return (address); 58791040Sarr } 58891040Sarr } 58925537Sdfr } 59091040Sarr if (common_size > 0) { 59191040Sarr /* 59291040Sarr * This is a common symbol which was not found in the 59391040Sarr * dependencies. We maintain a simple common symbol table in 59491040Sarr * the file object. 59591040Sarr */ 59691040Sarr struct common_symbol *cp; 59742849Speter 59891040Sarr STAILQ_FOREACH(cp, &file->common, link) { 59992032Sdwmalone if (strcmp(cp->name, name) == 0) { 60091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 60191040Sarr " old common value=%x\n", cp->address)); 60291040Sarr return (cp->address); 60391040Sarr } 60491040Sarr } 60591040Sarr /* 60691040Sarr * Round the symbol size up to align. 60791040Sarr */ 60891040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 60991040Sarr cp = malloc(sizeof(struct common_symbol) 61091040Sarr + common_size + strlen(name) + 1, M_LINKER, 61191040Sarr M_WAITOK | M_ZERO); 61291040Sarr if (cp == NULL) { 61391040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 61491040Sarr return (0); 61591040Sarr } 61691040Sarr cp->address = (caddr_t)(cp + 1); 61791040Sarr cp->name = cp->address + common_size; 61891040Sarr strcpy(cp->name, name); 61991040Sarr bzero(cp->address, common_size); 62091040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 62125537Sdfr 62291040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 62391040Sarr " value=%x\n", cp->address)); 62491040Sarr return (cp->address); 62540159Speter } 62691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 62791040Sarr return (0); 62825537Sdfr} 62925537Sdfr 63040159Speter#ifdef DDB 63125537Sdfr/* 63291040Sarr * DDB Helpers. DDB has to look across multiple files with their own symbol 63391040Sarr * tables and string tables. 63491040Sarr * 63591040Sarr * Note that we do not obey list locking protocols here. We really don't need 63691040Sarr * DDB to hang because somebody's got the lock held. We'll take the chance 63791040Sarr * that the files list is inconsistant instead. 63840159Speter */ 63940159Speter 64040159Speterint 64143309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 64240159Speter{ 64391040Sarr linker_file_t lf; 64440159Speter 64591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 64691040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 64791040Sarr return (0); 64891040Sarr } 64991040Sarr return (ENOENT); 65040159Speter} 65140159Speter 65240159Speterint 65343309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 65440159Speter{ 65591040Sarr linker_file_t lf; 65691040Sarr c_linker_sym_t best, es; 65791040Sarr u_long diff, bestdiff, off; 65840159Speter 65991040Sarr best = 0; 66091040Sarr off = (uintptr_t)value; 66191040Sarr bestdiff = off; 66291040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 66391040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 66491040Sarr continue; 66591040Sarr if (es != 0 && diff < bestdiff) { 66691040Sarr best = es; 66791040Sarr bestdiff = diff; 66891040Sarr } 66991040Sarr if (bestdiff == 0) 67091040Sarr break; 67140159Speter } 67291040Sarr if (best) { 67391040Sarr *sym = best; 67491040Sarr *diffp = bestdiff; 67591040Sarr return (0); 67691040Sarr } else { 67791040Sarr *sym = 0; 67891040Sarr *diffp = off; 67991040Sarr return (ENOENT); 68091040Sarr } 68140159Speter} 68240159Speter 68340159Speterint 68443309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 68540159Speter{ 68691040Sarr linker_file_t lf; 68740159Speter 68891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 68991040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 69091040Sarr return (0); 69191040Sarr } 69291040Sarr return (ENOENT); 69340159Speter} 69440159Speter#endif 69540159Speter 69640159Speter/* 69725537Sdfr * Syscalls. 69825537Sdfr */ 69982749Sdillon/* 70082749Sdillon * MPSAFE 70182749Sdillon */ 70225537Sdfrint 70391040Sarrkldload(struct thread *td, struct kldload_args *uap) 70425537Sdfr{ 70591040Sarr char *kldname, *modname; 70691040Sarr char *pathname = NULL; 70791040Sarr linker_file_t lf; 70891040Sarr int error = 0; 70925537Sdfr 71091040Sarr td->td_retval[0] = -1; 71125537Sdfr 71291040Sarr mtx_lock(&Giant); 71382749Sdillon 71493159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 71593159Sarr goto out; 71693159Sarr 71793593Sjhb if ((error = suser(td)) != 0) 71891040Sarr goto out; 71925537Sdfr 72091040Sarr pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 72191040Sarr if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, 72291040Sarr NULL)) != 0) 72391040Sarr goto out; 72425537Sdfr 72591040Sarr /* 72691040Sarr * If path do not contain qualified name or any dot in it 72791040Sarr * (kldname.ko, or kldname.ver.ko) treat it as interface 72891040Sarr * name. 72991040Sarr */ 73091040Sarr if (index(pathname, '/') || index(pathname, '.')) { 73191040Sarr kldname = pathname; 73291040Sarr modname = NULL; 73391040Sarr } else { 73491040Sarr kldname = NULL; 73591040Sarr modname = pathname; 73691040Sarr } 73791040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 73891040Sarr if (error) 73991040Sarr goto out; 74042316Smsmith 74191040Sarr lf->userrefs++; 74291040Sarr td->td_retval[0] = lf->id; 74325537Sdfrout: 74491040Sarr if (pathname) 74591040Sarr free(pathname, M_TEMP); 74691040Sarr mtx_unlock(&Giant); 74791040Sarr return (error); 74825537Sdfr} 74925537Sdfr 75082749Sdillon/* 75182749Sdillon * MPSAFE 75282749Sdillon */ 75325537Sdfrint 75491040Sarrkldunload(struct thread *td, struct kldunload_args *uap) 75525537Sdfr{ 75691040Sarr linker_file_t lf; 75791040Sarr int error = 0; 75825537Sdfr 75991040Sarr mtx_lock(&Giant); 76082749Sdillon 76193159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 76293159Sarr goto out; 76393159Sarr 76493593Sjhb if ((error = suser(td)) != 0) 76591040Sarr goto out; 76625537Sdfr 76791040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 76891040Sarr if (lf) { 76991040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 77091040Sarr if (lf->userrefs == 0) { 77191040Sarr printf("kldunload: attempt to unload file that was" 77291040Sarr " loaded by the kernel\n"); 77391040Sarr error = EBUSY; 77491040Sarr goto out; 77591040Sarr } 77691068Sarr lf->userrefs--; 77791040Sarr error = linker_file_unload(lf); 77891040Sarr if (error) 77991040Sarr lf->userrefs++; 78091040Sarr } else 78191040Sarr error = ENOENT; 78225537Sdfrout: 78391068Sarr mtx_unlock(&Giant); 78491068Sarr return (error); 78525537Sdfr} 78625537Sdfr 78782749Sdillon/* 78882749Sdillon * MPSAFE 78982749Sdillon */ 79025537Sdfrint 79191040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 79225537Sdfr{ 79391040Sarr char *pathname; 79491040Sarr const char *filename; 79591040Sarr linker_file_t lf; 79691040Sarr int error = 0; 79725537Sdfr 79891040Sarr mtx_lock(&Giant); 79991040Sarr td->td_retval[0] = -1; 80082749Sdillon 80191040Sarr pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 80291040Sarr if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, 80391040Sarr NULL)) != 0) 80491040Sarr goto out; 80525537Sdfr 80691040Sarr filename = linker_basename(pathname); 80791040Sarr lf = linker_find_file_by_name(filename); 80891040Sarr if (lf) 80991040Sarr td->td_retval[0] = lf->id; 81091040Sarr else 81191040Sarr error = ENOENT; 81225537Sdfrout: 81391040Sarr if (pathname) 81491040Sarr free(pathname, M_TEMP); 81591040Sarr mtx_unlock(&Giant); 81691040Sarr return (error); 81725537Sdfr} 81825537Sdfr 81982749Sdillon/* 82082749Sdillon * MPSAFE 82182749Sdillon */ 82225537Sdfrint 82391040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 82425537Sdfr{ 82591040Sarr linker_file_t lf; 82691040Sarr int error = 0; 82725537Sdfr 82891040Sarr mtx_lock(&Giant); 82982749Sdillon 83091040Sarr if (SCARG(uap, fileid) == 0) { 83191040Sarr if (TAILQ_FIRST(&linker_files)) 83291040Sarr td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; 83391040Sarr else 83491040Sarr td->td_retval[0] = 0; 83591040Sarr goto out; 83691040Sarr } 83791040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 83891040Sarr if (lf) { 83991040Sarr if (TAILQ_NEXT(lf, link)) 84091040Sarr td->td_retval[0] = TAILQ_NEXT(lf, link)->id; 84191040Sarr else 84291040Sarr td->td_retval[0] = 0; 84391040Sarr } else 84491040Sarr error = ENOENT; 84582749Sdillonout: 84691040Sarr mtx_unlock(&Giant); 84791040Sarr return (error); 84825537Sdfr} 84925537Sdfr 85082749Sdillon/* 85182749Sdillon * MPSAFE 85282749Sdillon */ 85325537Sdfrint 85491040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 85525537Sdfr{ 85691040Sarr linker_file_t lf; 85791040Sarr int error = 0; 85891040Sarr int namelen, version; 85991040Sarr struct kld_file_stat *stat; 86025537Sdfr 86191040Sarr mtx_lock(&Giant); 86282749Sdillon 86391040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 86491040Sarr if (lf == NULL) { 86591040Sarr error = ENOENT; 86691040Sarr goto out; 86791040Sarr } 86891040Sarr stat = SCARG(uap, stat); 86925537Sdfr 87091040Sarr /* 87191040Sarr * Check the version of the user's structure. 87291040Sarr */ 87391040Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 87491040Sarr goto out; 87591040Sarr if (version != sizeof(struct kld_file_stat)) { 87691040Sarr error = EINVAL; 87791040Sarr goto out; 87891040Sarr } 87991040Sarr namelen = strlen(lf->filename) + 1; 88091040Sarr if (namelen > MAXPATHLEN) 88191040Sarr namelen = MAXPATHLEN; 88291040Sarr if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) 88391040Sarr goto out; 88491040Sarr if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) 88591040Sarr goto out; 88691040Sarr if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) 88791040Sarr goto out; 88891040Sarr if ((error = copyout(&lf->address, &stat->address, 88991040Sarr sizeof(caddr_t))) != 0) 89091040Sarr goto out; 89191040Sarr if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) 89291040Sarr goto out; 89325537Sdfr 89491040Sarr td->td_retval[0] = 0; 89525537Sdfrout: 89691040Sarr mtx_unlock(&Giant); 89791040Sarr return (error); 89825537Sdfr} 89925537Sdfr 90082749Sdillon/* 90182749Sdillon * MPSAFE 90282749Sdillon */ 90325537Sdfrint 90491040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 90525537Sdfr{ 90691040Sarr linker_file_t lf; 90791040Sarr module_t mp; 90891040Sarr int error = 0; 90925537Sdfr 91091040Sarr mtx_lock(&Giant); 91191040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 91291040Sarr if (lf) { 91392547Sarr MOD_SLOCK; 91491040Sarr mp = TAILQ_FIRST(&lf->modules); 91591040Sarr if (mp != NULL) 91691040Sarr td->td_retval[0] = module_getid(mp); 91791040Sarr else 91891040Sarr td->td_retval[0] = 0; 91992547Sarr MOD_SUNLOCK; 92091040Sarr } else 92191040Sarr error = ENOENT; 92291040Sarr mtx_unlock(&Giant); 92391040Sarr return (error); 92425537Sdfr} 92540159Speter 92682749Sdillon/* 92782749Sdillon * MPSAFE 92882749Sdillon */ 92941090Speterint 93083366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 93141090Speter{ 93291040Sarr char *symstr = NULL; 93391040Sarr c_linker_sym_t sym; 93491040Sarr linker_symval_t symval; 93591040Sarr linker_file_t lf; 93691040Sarr struct kld_sym_lookup lookup; 93791040Sarr int error = 0; 93841090Speter 93991040Sarr mtx_lock(&Giant); 94082749Sdillon 94191040Sarr if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0) 94291040Sarr goto out; 94391068Sarr if (lookup.version != sizeof(lookup) || 94491040Sarr SCARG(uap, cmd) != KLDSYM_LOOKUP) { 94591040Sarr error = EINVAL; 94691040Sarr goto out; 94791040Sarr } 94891040Sarr symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 94991040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 95091040Sarr goto out; 95191040Sarr if (SCARG(uap, fileid) != 0) { 95291040Sarr lf = linker_find_file_by_id(SCARG(uap, fileid)); 95391040Sarr if (lf == NULL) { 95491040Sarr error = ENOENT; 95591040Sarr goto out; 95691040Sarr } 95791040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 95891040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 95991040Sarr lookup.symvalue = (uintptr_t) symval.value; 96091040Sarr lookup.symsize = symval.size; 96191040Sarr error = copyout(&lookup, SCARG(uap, data), 96291040Sarr sizeof(lookup)); 96391040Sarr } else 96491040Sarr error = ENOENT; 96591040Sarr } else { 96691040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 96791040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 96891040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 96991040Sarr lookup.symvalue = (uintptr_t)symval.value; 97091040Sarr lookup.symsize = symval.size; 97191040Sarr error = copyout(&lookup, SCARG(uap, data), 97291040Sarr sizeof(lookup)); 97391068Sarr break; 97491040Sarr } 97591040Sarr } 97691040Sarr if (lf == NULL) 97791040Sarr error = ENOENT; 97841090Speter } 97941090Speterout: 98091040Sarr if (symstr) 98191040Sarr free(symstr, M_TEMP); 98291040Sarr mtx_unlock(&Giant); 98391040Sarr return (error); 98441090Speter} 98541090Speter 98640159Speter/* 98740159Speter * Preloaded module support 98840159Speter */ 98940159Speter 99059751Speterstatic modlist_t 99174642Sbpmodlist_lookup(const char *name, int ver) 99259751Speter{ 99391040Sarr modlist_t mod; 99459751Speter 99591040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 99692032Sdwmalone if (strcmp(mod->name, name) == 0 && 99792032Sdwmalone (ver == 0 || mod->version == ver)) 99891040Sarr return (mod); 99991040Sarr } 100091040Sarr return (NULL); 100159751Speter} 100259751Speter 100374642Sbpstatic modlist_t 100483321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 100583321Speter{ 100691040Sarr modlist_t mod, bestmod; 100792032Sdwmalone int ver; 100883321Speter 100991040Sarr if (verinfo == NULL) 101091040Sarr return (modlist_lookup(name, 0)); 101191040Sarr bestmod = NULL; 101291040Sarr for (mod = TAILQ_FIRST(&found_modules); mod; 101391040Sarr mod = TAILQ_NEXT(mod, link)) { 101492032Sdwmalone if (strcmp(mod->name, name) != 0) 101591040Sarr continue; 101691040Sarr ver = mod->version; 101791040Sarr if (ver == verinfo->md_ver_preferred) 101891040Sarr return (mod); 101991040Sarr if (ver >= verinfo->md_ver_minimum && 102091068Sarr ver <= verinfo->md_ver_maximum && 102191068Sarr ver > bestmod->version) 102291040Sarr bestmod = mod; 102391040Sarr } 102491040Sarr return (bestmod); 102583321Speter} 102683321Speter 102783321Speterstatic modlist_t 102878501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 102974642Sbp{ 103091040Sarr modlist_t mod; 103174642Sbp 103292705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 103391040Sarr if (mod == NULL) 103491040Sarr panic("no memory for module list"); 103591040Sarr mod->container = container; 103691040Sarr mod->name = modname; 103791040Sarr mod->version = version; 103891040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 103991040Sarr return (mod); 104074642Sbp} 104174642Sbp 104259751Speter/* 104359751Speter * This routine is cheap and nasty but will work for data pointers. 104459751Speter */ 104559751Speterstatic void * 104678501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset) 104759751Speter{ 104891040Sarr return (lf->address + (uintptr_t)offset); 104959751Speter} 105059751Speter 105174642Sbp/* 105274642Sbp * Dereference MDT_VERSION metadata into module name and version 105374642Sbp */ 105440159Speterstatic void 105574642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp, 105691040Sarr const char **modname, int *version) 105774642Sbp{ 105891040Sarr struct mod_version *mvp; 105974642Sbp 106091040Sarr if (modname) 106191040Sarr *modname = linker_reloc_ptr(lf, mp->md_cval); 106291040Sarr if (version) { 106391040Sarr mvp = linker_reloc_ptr(lf, mp->md_data); 106491040Sarr *version = mvp->mv_version; 106591040Sarr } 106674642Sbp} 106774642Sbp 106874642Sbp/* 106974642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure 107074642Sbp */ 107174642Sbpstatic void 107274642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp, 107391040Sarr const char **modname, struct mod_depend **verinfo) 107474642Sbp{ 107574642Sbp 107691040Sarr if (modname) 107791040Sarr *modname = linker_reloc_ptr(lf, mp->md_cval); 107891040Sarr if (verinfo) 107991040Sarr *verinfo = linker_reloc_ptr(lf, mp->md_data); 108074642Sbp} 108174642Sbp 108274642Sbpstatic void 108378161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 108491040Sarr struct mod_metadata **stop, int preload) 108574642Sbp{ 108691040Sarr struct mod_metadata *mp, **mdp; 108791040Sarr const char *modname; 108891040Sarr int ver; 108974642Sbp 109091040Sarr for (mdp = start; mdp < stop; mdp++) { 109191040Sarr if (preload) 109291040Sarr mp = *mdp; 109391040Sarr else 109491040Sarr mp = linker_reloc_ptr(lf, *mdp); 109591040Sarr if (mp->md_type != MDT_VERSION) 109691040Sarr continue; 109791040Sarr if (preload) { 109891040Sarr modname = mp->md_cval; 109991040Sarr ver = ((struct mod_version *)mp->md_data)->mv_version; 110091040Sarr } else 110191040Sarr linker_mdt_version(lf, mp, &modname, &ver); 110291040Sarr if (modlist_lookup(modname, ver) != NULL) { 110391040Sarr printf("module %s already present!\n", modname); 110491040Sarr /* XXX what can we do? this is a build error. :-( */ 110591040Sarr continue; 110691040Sarr } 110791040Sarr modlist_newmodule(modname, ver, lf); 110874642Sbp } 110974642Sbp} 111074642Sbp 111174642Sbpstatic void 111291040Sarrlinker_preload(void *arg) 111340159Speter{ 111491040Sarr caddr_t modptr; 111591040Sarr const char *modname, *nmodname; 111691040Sarr char *modtype; 111791040Sarr linker_file_t lf; 111891040Sarr linker_class_t lc; 111992032Sdwmalone int error; 112091040Sarr linker_file_list_t loaded_files; 112191040Sarr linker_file_list_t depended_files; 112291040Sarr struct mod_metadata *mp, *nmp; 112391040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 112491040Sarr struct mod_depend *verinfo; 112591040Sarr int nver; 112691040Sarr int resolves; 112791040Sarr modlist_t mod; 112891040Sarr struct sysinit **si_start, **si_stop; 112940159Speter 113091040Sarr TAILQ_INIT(&loaded_files); 113191040Sarr TAILQ_INIT(&depended_files); 113291040Sarr TAILQ_INIT(&found_modules); 113391040Sarr error = 0; 113459751Speter 113591040Sarr modptr = NULL; 113691040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 113791040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 113891040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 113991040Sarr if (modname == NULL) { 114091040Sarr printf("Preloaded module at %p does not have a" 114191040Sarr " name!\n", modptr); 114291040Sarr continue; 114391040Sarr } 114491040Sarr if (modtype == NULL) { 114591040Sarr printf("Preloaded module at %p does not have a type!\n", 114691040Sarr modptr); 114791040Sarr continue; 114891040Sarr } 114991040Sarr printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 115091040Sarr modptr); 115140159Speter lf = NULL; 115291040Sarr TAILQ_FOREACH(lc, &classes, link) { 115391040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 115491040Sarr if (error) { 115591040Sarr lf = NULL; 115691040Sarr break; 115791040Sarr } 115891040Sarr } 115991040Sarr if (lf) 116091040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 116140159Speter } 116240159Speter 116391040Sarr /* 116491040Sarr * First get a list of stuff in the kernel. 116591040Sarr */ 116691040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 116791040Sarr &stop, NULL) == 0) 116891040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 116959751Speter 117059751Speter /* 117191040Sarr * this is a once-off kinky bubble sort resolve relocation dependency 117291040Sarr * requirements 117359751Speter */ 117491040Sarrrestart: 117591040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 117691040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 117791040Sarr &stop, NULL); 117891040Sarr /* 117991040Sarr * First, look to see if we would successfully link with this 118091040Sarr * stuff. 118191040Sarr */ 118291040Sarr resolves = 1; /* unless we know otherwise */ 118391040Sarr if (!error) { 118491040Sarr for (mdp = start; mdp < stop; mdp++) { 118591040Sarr mp = linker_reloc_ptr(lf, *mdp); 118691040Sarr if (mp->md_type != MDT_DEPEND) 118791040Sarr continue; 118891040Sarr linker_mdt_depend(lf, mp, &modname, &verinfo); 118991040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 119091040Sarr nmp = linker_reloc_ptr(lf, *nmdp); 119191040Sarr if (nmp->md_type != MDT_VERSION) 119291040Sarr continue; 119391040Sarr linker_mdt_version(lf, nmp, &nmodname, 119491040Sarr NULL); 119591040Sarr nmodname = linker_reloc_ptr(lf, 119691040Sarr nmp->md_cval); 119792032Sdwmalone if (strcmp(modname, nmodname) == 0) 119891040Sarr break; 119991040Sarr } 120091040Sarr if (nmdp < stop) /* it's a self reference */ 120191040Sarr continue; 120291040Sarr 120391040Sarr /* 120491040Sarr * ok, the module isn't here yet, we 120591040Sarr * are not finished 120691040Sarr */ 120791068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 120891040Sarr resolves = 0; 120991040Sarr } 121064143Speter } 121191040Sarr /* 121291040Sarr * OK, if we found our modules, we can link. So, "provide" 121391040Sarr * the modules inside and add it to the end of the link order 121491040Sarr * list. 121591040Sarr */ 121691040Sarr if (resolves) { 121791040Sarr if (!error) { 121891040Sarr for (mdp = start; mdp < stop; mdp++) { 121991040Sarr mp = linker_reloc_ptr(lf, *mdp); 122091040Sarr if (mp->md_type != MDT_VERSION) 122191040Sarr continue; 122291040Sarr linker_mdt_version(lf, mp, 122391040Sarr &modname, &nver); 122491040Sarr if (modlist_lookup(modname, 122591040Sarr nver) != NULL) { 122691040Sarr printf("module %s already" 122791040Sarr " present!\n", modname); 122891040Sarr linker_file_unload(lf); 122991040Sarr TAILQ_REMOVE(&loaded_files, 123091040Sarr lf, loaded); 123191040Sarr /* we changed tailq next ptr */ 123291068Sarr goto restart; 123391040Sarr } 123491040Sarr modlist_newmodule(modname, nver, lf); 123591040Sarr } 123691040Sarr } 123791040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 123891040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 123991040Sarr /* 124091040Sarr * Since we provided modules, we need to restart the 124191040Sarr * sort so that the previous files that depend on us 124291040Sarr * have a chance. Also, we've busted the tailq next 124391040Sarr * pointer with the REMOVE. 124491040Sarr */ 124591040Sarr goto restart; 124659751Speter } 124759751Speter } 124891040Sarr 124959751Speter /* 125091040Sarr * At this point, we check to see what could not be resolved.. 125159751Speter */ 125291040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 125391040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 125491040Sarr linker_file_unload(lf); 125591040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 125640159Speter } 125759751Speter 125878161Speter /* 125991040Sarr * We made it. Finish off the linking in the order we determined. 126078161Speter */ 126191040Sarr TAILQ_FOREACH(lf, &depended_files, loaded) { 126291040Sarr if (linker_kernel_file) { 126391040Sarr linker_kernel_file->refs++; 126491040Sarr error = linker_file_add_dependency(lf, 126591040Sarr linker_kernel_file); 126691040Sarr if (error) 126791040Sarr panic("cannot add dependency"); 126891040Sarr } 126991040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 127091040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 127191040Sarr &stop, NULL); 127291040Sarr if (!error) { 127391040Sarr for (mdp = start; mdp < stop; mdp++) { 127491040Sarr mp = linker_reloc_ptr(lf, *mdp); 127591040Sarr if (mp->md_type != MDT_DEPEND) 127691040Sarr continue; 127791040Sarr linker_mdt_depend(lf, mp, &modname, &verinfo); 127891040Sarr mod = modlist_lookup2(modname, verinfo); 127991040Sarr mod->container->refs++; 128091040Sarr error = linker_file_add_dependency(lf, 128191040Sarr mod->container); 128291040Sarr if (error) 128391040Sarr panic("cannot add dependency"); 128491040Sarr } 128591040Sarr } 128691040Sarr /* 128791040Sarr * Now do relocation etc using the symbol search paths 128891040Sarr * established by the dependencies 128991040Sarr */ 129091040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 129191040Sarr if (error) { 129291040Sarr printf("KLD file %s - could not finalize loading\n", 129391040Sarr lf->filename); 129491040Sarr linker_file_unload(lf); 129591040Sarr continue; 129691040Sarr } 129791040Sarr linker_file_register_modules(lf); 129891040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 129991040Sarr &si_stop, NULL) == 0) 130091040Sarr sysinit_add(si_start, si_stop); 130191040Sarr linker_file_register_sysctls(lf); 130291040Sarr lf->flags |= LINKER_FILE_LINKED; 130359751Speter } 130491040Sarr /* woohoo! we made it! */ 130540159Speter} 130640159Speter 130791040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0) 130840159Speter 130940159Speter/* 131040159Speter * Search for a not-loaded module by name. 131191040Sarr * 131240159Speter * Modules may be found in the following locations: 131391040Sarr * 131491040Sarr * - preloaded (result is just the module name) - on disk (result is full path 131591040Sarr * to module) 131691040Sarr * 131791040Sarr * If the module name is qualified in any way (contains path, etc.) the we 131891040Sarr * simply return a copy of it. 131991040Sarr * 132040159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 132140159Speter * character as a separator to be consistent with the bootloader. 132240159Speter */ 132340159Speter 132483321Speterstatic char linker_hintfile[] = "linker.hints"; 132583358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules"; 132640159Speter 132740159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 132891040Sarr sizeof(linker_path), "module load search path"); 132940159Speter 133077843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 133170417Speter 133259751Speterstatic char *linker_ext_list[] = { 133383321Speter "", 133459751Speter ".ko", 133559751Speter NULL 133659751Speter}; 133759751Speter 133883321Speter/* 133991040Sarr * Check if file actually exists either with or without extension listed in 134091040Sarr * the linker_ext_list. (probably should be generic for the rest of the 134191040Sarr * kernel) 134283321Speter */ 134359751Speterstatic char * 134491040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 134591040Sarr int namelen, struct vattr *vap) 134640159Speter{ 134791040Sarr struct nameidata nd; 134891040Sarr struct thread *td = curthread; /* XXX */ 134991040Sarr char *result, **cpp, *sep; 135091040Sarr int error, len, extlen, reclen, flags; 135191040Sarr enum vtype type; 135240159Speter 135391040Sarr extlen = 0; 135491040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 135591040Sarr len = strlen(*cpp); 135691040Sarr if (len > extlen) 135791040Sarr extlen = len; 135891040Sarr } 135991040Sarr extlen++; /* trailing '\0' */ 136091040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 136183321Speter 136291040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 136391040Sarr result = malloc(reclen, M_LINKER, M_WAITOK); 136491040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 136591040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 136691040Sarr namelen, name, *cpp); 136791040Sarr /* 136891040Sarr * Attempt to open the file, and return the path if 136991040Sarr * we succeed and it's a regular file. 137091040Sarr */ 137191040Sarr NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); 137291040Sarr flags = FREAD; 137391040Sarr error = vn_open(&nd, &flags, 0); 137491040Sarr if (error == 0) { 137591040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 137691040Sarr type = nd.ni_vp->v_type; 137791040Sarr if (vap) 137891406Sjhb VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 137991040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 138091406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 138191040Sarr if (type == VREG) 138291040Sarr return (result); 138391040Sarr } 138483321Speter } 138591040Sarr free(result, M_LINKER); 138691040Sarr return (NULL); 138783321Speter} 138883321Speter 138991040Sarr#define INT_ALIGN(base, ptr) ptr = \ 139083321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 139183321Speter 139283321Speter/* 139391040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 139491040Sarr * version specification is available, then try to find the best KLD. 139583321Speter * Otherwise just find the latest one. 139691040Sarr * 139790483Srwatson * XXX: Vnode locking here is hosed; lock should be held for calls to 139890483Srwatson * VOP_GETATTR() and vn_rdwr(). 139983321Speter */ 140083321Speterstatic char * 140191040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 140291040Sarr int modnamelen, struct mod_depend *verinfo) 140383321Speter{ 140491040Sarr struct thread *td = curthread; /* XXX */ 140591406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 140691040Sarr struct nameidata nd; 140791040Sarr struct vattr vattr, mattr; 140891040Sarr u_char *hints = NULL; 140991040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 141091040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 141183321Speter 141291040Sarr result = NULL; 141391040Sarr bestver = found = 0; 141483321Speter 141591040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 141691040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 141791040Sarr strlen(sep) + 1; 141891040Sarr pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 141991040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 142091040Sarr linker_hintfile); 142183321Speter 142291040Sarr NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); 142391040Sarr flags = FREAD; 142491040Sarr error = vn_open(&nd, &flags, 0); 142591040Sarr if (error) 142691040Sarr goto bad; 142791040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 142891040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 142991040Sarr if (nd.ni_vp->v_type != VREG) 143091040Sarr goto bad; 143191040Sarr best = cp = NULL; 143291040Sarr error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td); 143391040Sarr if (error) 143491040Sarr goto bad; 143591040Sarr /* 143691040Sarr * XXX: we need to limit this number to some reasonable value 143791040Sarr */ 143891040Sarr if (vattr.va_size > 100 * 1024) { 143991040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 144091040Sarr goto bad; 144191040Sarr } 144291040Sarr hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 144391040Sarr if (hints == NULL) 144491040Sarr goto bad; 144591068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 144691040Sarr UIO_SYSSPACE, IO_NODELOCKED, cred, &reclen, td); 144791040Sarr if (error) 144891040Sarr goto bad; 144991040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 145091040Sarr nd.ni_vp = NULL; 145191040Sarr if (reclen != 0) { 145291040Sarr printf("can't read %d\n", reclen); 145391040Sarr goto bad; 145491040Sarr } 145591040Sarr intp = (int *)hints; 145683321Speter ival = *intp++; 145791040Sarr if (ival != LINKER_HINTS_VERSION) { 145891040Sarr printf("hints file version mismatch %d\n", ival); 145991040Sarr goto bad; 146083321Speter } 146191040Sarr bufend = hints + vattr.va_size; 146291040Sarr recptr = (u_char *)intp; 146391040Sarr clen = blen = 0; 146491040Sarr while (recptr < bufend && !found) { 146591040Sarr intp = (int *)recptr; 146691040Sarr reclen = *intp++; 146791040Sarr ival = *intp++; 146891040Sarr cp = (char *)intp; 146991040Sarr switch (ival) { 147091040Sarr case MDT_VERSION: 147191040Sarr clen = *cp++; 147291040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 147391040Sarr break; 147491040Sarr cp += clen; 147591040Sarr INT_ALIGN(hints, cp); 147691040Sarr ival = *(int *)cp; 147791040Sarr cp += sizeof(int); 147891040Sarr clen = *cp++; 147991040Sarr if (verinfo == NULL || 148091040Sarr ival == verinfo->md_ver_preferred) { 148191040Sarr found = 1; 148291040Sarr break; 148391040Sarr } 148491040Sarr if (ival >= verinfo->md_ver_minimum && 148591040Sarr ival <= verinfo->md_ver_maximum && 148691040Sarr ival > bestver) { 148791040Sarr bestver = ival; 148891040Sarr best = cp; 148991040Sarr blen = clen; 149091040Sarr } 149191040Sarr break; 149291040Sarr default: 149391040Sarr break; 149491040Sarr } 149591040Sarr recptr += reclen + sizeof(int); 149691040Sarr } 149783321Speter /* 149891040Sarr * Finally check if KLD is in the place 149983321Speter */ 150091040Sarr if (found) 150191040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 150291040Sarr else if (best) 150391040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 150491040Sarr 150591040Sarr /* 150691040Sarr * KLD is newer than hints file. What we should do now? 150791040Sarr */ 150891040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 150991040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 151091040Sarr " file\n", result); 151183321Speterbad: 151291040Sarr if (hints) 151391040Sarr free(hints, M_TEMP); 151491040Sarr if (nd.ni_vp != NULL) 151591040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 151691040Sarr /* 151791040Sarr * If nothing found or hints is absent - fallback to the old 151891040Sarr * way by using "kldname[.ko]" as module name. 151991040Sarr */ 152091040Sarr if (!found && !bestver && result == NULL) 152191040Sarr result = linker_lookup_file(path, pathlen, modname, 152291040Sarr modnamelen, NULL); 152391040Sarr return (result); 152483321Speter} 152583321Speter 152683321Speter/* 152783321Speter * Lookup KLD which contains requested module in the all directories. 152883321Speter */ 152983321Speterstatic char * 153083321Speterlinker_search_module(const char *modname, int modnamelen, 153191040Sarr struct mod_depend *verinfo) 153283321Speter{ 153391040Sarr char *cp, *ep, *result; 153483321Speter 153591040Sarr /* 153691040Sarr * traverse the linker path 153791040Sarr */ 153891040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 153991040Sarr /* find the end of this component */ 154091040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 154191068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 154291068Sarr modnamelen, verinfo); 154391040Sarr if (result != NULL) 154491040Sarr return (result); 154591040Sarr if (*ep == 0) 154691040Sarr break; 154791040Sarr } 154891040Sarr return (NULL); 154983321Speter} 155083321Speter 155183321Speter/* 155283321Speter * Search for module in all directories listed in the linker_path. 155383321Speter */ 155483321Speterstatic char * 155583321Speterlinker_search_kld(const char *name) 155683321Speter{ 155791040Sarr char *cp, *ep, *result, **cpp; 155891040Sarr int extlen, len; 155983321Speter 156091040Sarr /* qualified at all? */ 156191040Sarr if (index(name, '/')) 156291040Sarr return (linker_strdup(name)); 156340159Speter 156491040Sarr extlen = 0; 156591040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 156691040Sarr len = strlen(*cpp); 156791040Sarr if (len > extlen) 156891040Sarr extlen = len; 156991040Sarr } 157091040Sarr extlen++; /* trailing '\0' */ 157159751Speter 157291040Sarr /* traverse the linker path */ 157391040Sarr len = strlen(name); 157491040Sarr for (ep = linker_path; *ep; ep++) { 157591040Sarr cp = ep; 157691040Sarr /* find the end of this component */ 157791040Sarr for (; *ep != 0 && *ep != ';'; ep++); 157891040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 157991040Sarr if (result != NULL) 158091040Sarr return (result); 158191040Sarr } 158291040Sarr return (NULL); 158340159Speter} 158459751Speter 158559751Speterstatic const char * 158691040Sarrlinker_basename(const char *path) 158759751Speter{ 158891040Sarr const char *filename; 158959751Speter 159091040Sarr filename = rindex(path, '/'); 159191040Sarr if (filename == NULL) 159291040Sarr return path; 159391040Sarr if (filename[1]) 159491040Sarr filename++; 159591040Sarr return (filename); 159659751Speter} 159759751Speter 159859751Speter/* 159991040Sarr * Find a file which contains given module and load it, if "parent" is not 160091040Sarr * NULL, register a reference to it. 160159751Speter */ 160259751Speterstatic int 160383321Speterlinker_load_module(const char *kldname, const char *modname, 160491040Sarr struct linker_file *parent, struct mod_depend *verinfo, 160591040Sarr struct linker_file **lfpp) 160659751Speter{ 160791040Sarr linker_file_t lfdep; 160891040Sarr const char *filename; 160991040Sarr char *pathname; 161091040Sarr int error; 161159751Speter 161291040Sarr if (modname == NULL) { 161391040Sarr /* 161491040Sarr * We have to load KLD 161591040Sarr */ 161691068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 161791068Sarr " is not NULL")); 161891040Sarr pathname = linker_search_kld(kldname); 161991040Sarr } else { 162091040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 162191040Sarr return (EEXIST); 162291040Sarr if (kldname == NULL) 162391040Sarr /* 162491040Sarr * Need to find a KLD with required module 162591040Sarr */ 162691040Sarr pathname = linker_search_module(modname, 162791040Sarr strlen(modname), verinfo); 162891040Sarr else 162991040Sarr pathname = linker_strdup(kldname); 163091040Sarr } 163191040Sarr if (pathname == NULL) 163291040Sarr return (ENOENT); 163391040Sarr 163483321Speter /* 163591040Sarr * Can't load more than one file with the same basename XXX: 163691040Sarr * Actually it should be possible to have multiple KLDs with 163791040Sarr * the same basename but different path because they can 163891040Sarr * provide different versions of the same modules. 163983321Speter */ 164091040Sarr filename = linker_basename(pathname); 164191040Sarr if (linker_find_file_by_name(filename)) { 164291040Sarr error = EEXIST; 164391040Sarr goto out; 164483321Speter } 164591040Sarr do { 164691040Sarr error = linker_load_file(pathname, &lfdep); 164791040Sarr if (error) 164891040Sarr break; 164991040Sarr if (modname && verinfo && 165091040Sarr modlist_lookup2(modname, verinfo) == NULL) { 165191040Sarr linker_file_unload(lfdep); 165291040Sarr error = ENOENT; 165391040Sarr break; 165491040Sarr } 165591040Sarr if (parent) { 165691040Sarr error = linker_file_add_dependency(parent, lfdep); 165791040Sarr if (error) 165891040Sarr break; 165991040Sarr } 166091040Sarr if (lfpp) 166191040Sarr *lfpp = lfdep; 166291040Sarr } while (0); 166359751Speterout: 166491040Sarr if (pathname) 166591040Sarr free(pathname, M_LINKER); 166691040Sarr return (error); 166759751Speter} 166859751Speter 166959751Speter/* 167091040Sarr * This routine is responsible for finding dependencies of userland initiated 167191040Sarr * kldload(2)'s of files. 167259751Speter */ 167359751Speterint 167486469Siedowselinker_load_dependencies(linker_file_t lf) 167559751Speter{ 167691040Sarr linker_file_t lfdep; 167791040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 167891040Sarr struct mod_metadata *mp, *nmp; 167991040Sarr struct mod_depend *verinfo; 168091040Sarr modlist_t mod; 168191040Sarr const char *modname, *nmodname; 168292032Sdwmalone int ver, error = 0, count; 168359751Speter 168491040Sarr /* 168591040Sarr * All files are dependant on /kernel. 168691040Sarr */ 168791040Sarr if (linker_kernel_file) { 168891040Sarr linker_kernel_file->refs++; 168991040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 169091040Sarr if (error) 169191040Sarr return (error); 169259751Speter } 169391040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 169491040Sarr &count) != 0) 169591040Sarr return (0); 169691040Sarr for (mdp = start; mdp < stop; mdp++) { 169791040Sarr mp = linker_reloc_ptr(lf, *mdp); 169891040Sarr if (mp->md_type != MDT_VERSION) 169991040Sarr continue; 170091040Sarr linker_mdt_version(lf, mp, &modname, &ver); 170191040Sarr mod = modlist_lookup(modname, ver); 170291040Sarr if (mod != NULL) { 170391040Sarr printf("interface %s.%d already present in the KLD" 170491040Sarr " '%s'!\n", modname, ver, 170591040Sarr mod->container->filename); 170691040Sarr return (EEXIST); 170791040Sarr } 170891040Sarr } 170974642Sbp 171091040Sarr for (mdp = start; mdp < stop; mdp++) { 171191040Sarr mp = linker_reloc_ptr(lf, *mdp); 171291040Sarr if (mp->md_type != MDT_DEPEND) 171391040Sarr continue; 171491040Sarr linker_mdt_depend(lf, mp, &modname, &verinfo); 171591040Sarr nmodname = NULL; 171691040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 171791040Sarr nmp = linker_reloc_ptr(lf, *nmdp); 171891040Sarr if (nmp->md_type != MDT_VERSION) 171991040Sarr continue; 172091040Sarr nmodname = linker_reloc_ptr(lf, nmp->md_cval); 172192032Sdwmalone if (strcmp(modname, nmodname) == 0) 172291040Sarr break; 172391040Sarr } 172491040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 172591040Sarr continue; 172691040Sarr mod = modlist_lookup2(modname, verinfo); 172791040Sarr if (mod) { /* woohoo, it's loaded already */ 172891040Sarr lfdep = mod->container; 172991040Sarr lfdep->refs++; 173091040Sarr error = linker_file_add_dependency(lf, lfdep); 173191040Sarr if (error) 173291040Sarr break; 173391040Sarr continue; 173491040Sarr } 173591040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 173691040Sarr if (error) { 173791040Sarr printf("KLD %s: depends on %s - not available\n", 173891040Sarr lf->filename, modname); 173991040Sarr break; 174091040Sarr } 174159751Speter } 174259751Speter 174391040Sarr if (error) 174491040Sarr return (error); 174591040Sarr linker_addmodules(lf, start, stop, 0); 174691040Sarr return (error); 174759751Speter} 174885736Sgreen 174985736Sgreenstatic int 175085736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 175185736Sgreen{ 175285736Sgreen struct sysctl_req *req; 175385736Sgreen 175485736Sgreen req = opaque; 175585736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 175685736Sgreen} 175785736Sgreen 175885736Sgreen/* 175985736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 176085736Sgreen * in the kernel. 176185736Sgreen */ 176285736Sgreenstatic int 176385736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 176485736Sgreen{ 176585736Sgreen linker_file_t lf; 176685736Sgreen int error; 176785736Sgreen 176885736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 176985736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 177085736Sgreen sysctl_kern_function_list_iterate, req); 177185736Sgreen if (error) 177285736Sgreen return (error); 177385736Sgreen } 177485736Sgreen return (SYSCTL_OUT(req, "", 1)); 177585736Sgreen} 177685736Sgreen 177785736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 177891040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 1779