kern_linker.c revision 83358
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 83358 2001-09-12 00:50:23Z peter $ 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> 4025537Sdfr#include <sys/module.h> 4125537Sdfr#include <sys/linker.h> 4240159Speter#include <sys/fcntl.h> 4340159Speter#include <sys/libkern.h> 4440159Speter#include <sys/namei.h> 4540159Speter#include <sys/vnode.h> 4640159Speter#include <sys/sysctl.h> 4725537Sdfr 4854655Seivind 4959603Sdfr#include "linker_if.h" 5059603Sdfr 5140961Speter#ifdef KLD_DEBUG 5240961Speterint kld_debug = 0; 5340961Speter#endif 5440961Speter 5583321Speter/*static char *linker_search_path(const char *name, struct mod_depend *verinfo);*/ 5659751Speterstatic const char *linker_basename(const char* path); 5783321Speterstatic int linker_load_module(const char *kldname, const char *modname, 5883321Speter struct linker_file *parent, struct mod_depend *verinfo, 5983321Speter struct linker_file **lfpp); 6059751Speter 6178161Speter/* Metadata from the static kernel */ 6278161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 6378161Speter 6459751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 6559751Speter 6640906Speterlinker_file_t linker_kernel_file; 6731324Sbde 6825537Sdfrstatic struct lock lock; /* lock for the file list */ 6925537Sdfrstatic linker_class_list_t classes; 7050068Sgrogstatic linker_file_list_t linker_files; 7125537Sdfrstatic int next_file_id = 1; 7225537Sdfr 7359751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 7460938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 7559751Speterstruct modlist { 7660938Sjake TAILQ_ENTRY(modlist) link; /* chain together all modules */ 7759751Speter linker_file_t container; 7859751Speter const char *name; 7974642Sbp int version; 8059751Speter}; 8159751Spetertypedef struct modlist *modlist_t; 8259751Speterstatic modlisthead_t found_modules; 8359751Speter 8459603Sdfrstatic char * 8559603Sdfrlinker_strdup(const char *str) 8659603Sdfr{ 8759603Sdfr char *result; 8859603Sdfr 8959603Sdfr if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 9059603Sdfr strcpy(result, str); 9159603Sdfr return(result); 9259603Sdfr} 9359603Sdfr 9425537Sdfrstatic void 9525537Sdfrlinker_init(void* arg) 9625537Sdfr{ 9725537Sdfr lockinit(&lock, PVM, "klink", 0, 0); 9825537Sdfr TAILQ_INIT(&classes); 9950068Sgrog TAILQ_INIT(&linker_files); 10025537Sdfr} 10125537Sdfr 10240159SpeterSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 10325537Sdfr 10425537Sdfrint 10559603Sdfrlinker_add_class(linker_class_t lc) 10625537Sdfr{ 10759603Sdfr kobj_class_compile((kobj_class_t) lc); 10859751Speter TAILQ_INSERT_TAIL(&classes, lc, link); 10925537Sdfr return 0; 11025537Sdfr} 11125537Sdfr 11225537Sdfrstatic void 11325537Sdfrlinker_file_sysinit(linker_file_t lf) 11425537Sdfr{ 11578161Speter struct sysinit** start, ** stop; 11625537Sdfr struct sysinit** sipp; 11725537Sdfr struct sysinit** xipp; 11825537Sdfr struct sysinit* save; 11925537Sdfr 12025537Sdfr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 12125537Sdfr lf->filename)); 12225537Sdfr 12378161Speter if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 12425537Sdfr return; 12525537Sdfr /* 12625537Sdfr * Perform a bubble sort of the system initialization objects by 12725537Sdfr * their subsystem (primary key) and order (secondary key). 12825537Sdfr * 12925537Sdfr * Since some things care about execution order, this is the 13025537Sdfr * operation which ensures continued function. 13125537Sdfr */ 13278161Speter for (sipp = start; sipp < stop; sipp++) { 13378161Speter for (xipp = sipp + 1; xipp < stop; xipp++) { 13462860Sbp if ((*sipp)->subsystem < (*xipp)->subsystem || 13541055Speter ((*sipp)->subsystem == (*xipp)->subsystem && 13641055Speter (*sipp)->order <= (*xipp)->order)) 13725537Sdfr continue; /* skip*/ 13825537Sdfr save = *sipp; 13925537Sdfr *sipp = *xipp; 14025537Sdfr *xipp = save; 14125537Sdfr } 14225537Sdfr } 14325537Sdfr 14425537Sdfr 14525537Sdfr /* 14625537Sdfr * Traverse the (now) ordered list of system initialization tasks. 14725537Sdfr * Perform each task, and continue on to the next task. 14825537Sdfr */ 14978161Speter for (sipp = start; sipp < stop; sipp++) { 15041055Speter if ((*sipp)->subsystem == SI_SUB_DUMMY) 15125537Sdfr continue; /* skip dummy task(s)*/ 15225537Sdfr 15348391Speter /* Call function */ 15448391Speter (*((*sipp)->func))((*sipp)->udata); 15525537Sdfr } 15625537Sdfr} 15725537Sdfr 15841055Speterstatic void 15941055Speterlinker_file_sysuninit(linker_file_t lf) 16041055Speter{ 16178161Speter struct sysinit** start, ** stop; 16241055Speter struct sysinit** sipp; 16341055Speter struct sysinit** xipp; 16441055Speter struct sysinit* save; 16541055Speter 16641055Speter KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 16741055Speter lf->filename)); 16841055Speter 16978161Speter if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, NULL) != 0) 17041055Speter return; 17141055Speter 17241055Speter /* 17341055Speter * Perform a reverse bubble sort of the system initialization objects 17441055Speter * by their subsystem (primary key) and order (secondary key). 17541055Speter * 17641055Speter * Since some things care about execution order, this is the 17741055Speter * operation which ensures continued function. 17841055Speter */ 17978161Speter for (sipp = start; sipp < stop; sipp++) { 18078161Speter for (xipp = sipp + 1; xipp < stop; xipp++) { 18162860Sbp if ((*sipp)->subsystem > (*xipp)->subsystem || 18241055Speter ((*sipp)->subsystem == (*xipp)->subsystem && 18341055Speter (*sipp)->order >= (*xipp)->order)) 18441055Speter continue; /* skip*/ 18541055Speter save = *sipp; 18641055Speter *sipp = *xipp; 18741055Speter *xipp = save; 18841055Speter } 18941055Speter } 19041055Speter 19141055Speter /* 19241055Speter * Traverse the (now) ordered list of system initialization tasks. 19341055Speter * Perform each task, and continue on to the next task. 19441055Speter */ 19578161Speter for (sipp = start; sipp < stop; sipp++) { 19641055Speter if ((*sipp)->subsystem == SI_SUB_DUMMY) 19741055Speter continue; /* skip dummy task(s)*/ 19841055Speter 19948391Speter /* Call function */ 20048391Speter (*((*sipp)->func))((*sipp)->udata); 20141055Speter } 20241055Speter} 20341055Speter 20444078Sdfrstatic void 20544078Sdfrlinker_file_register_sysctls(linker_file_t lf) 20644078Sdfr{ 20778161Speter struct sysctl_oid **start, **stop, **oidp; 20844078Sdfr 20944078Sdfr KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 21044078Sdfr lf->filename)); 21144078Sdfr 21278161Speter if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 21344078Sdfr return; 21444078Sdfr 21578161Speter for (oidp = start; oidp < stop; oidp++) 21678161Speter sysctl_register_oid(*oidp); 21744078Sdfr} 21844078Sdfr 21944078Sdfrstatic void 22044078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 22144078Sdfr{ 22278161Speter struct sysctl_oid **start, **stop, **oidp; 22344078Sdfr 22444078Sdfr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n", 22544078Sdfr lf->filename)); 22644078Sdfr 22778161Speter if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 22844078Sdfr return; 22944078Sdfr 23078161Speter for (oidp = start; oidp < stop; oidp++) 23178161Speter sysctl_unregister_oid(*oidp); 23244078Sdfr} 23344078Sdfr 23459751Speterstatic int 23559751Speterlinker_file_register_modules(linker_file_t lf) 23659751Speter{ 23774639Sbp int error; 23878161Speter struct mod_metadata **start, **stop; 23978161Speter struct mod_metadata **mdp; 24059751Speter const moduledata_t *moddata; 24159751Speter 24259751Speter KLD_DPF(FILE, ("linker_file_register_modules: registering modules in %s\n", 24359751Speter lf->filename)); 24459751Speter 24578161Speter if (linker_file_lookup_set(lf, "modmetadata_set", &start, &stop, 0) != 0) { 24678161Speter /* 24778161Speter * This fallback should be unnecessary, but if we get booted from 24878161Speter * boot2 instead of loader and we are missing our metadata then 24978161Speter * we have to try the best we can. 25078161Speter */ 25178161Speter if (lf == linker_kernel_file) { 25278161Speter start = SET_BEGIN(modmetadata_set); 25378161Speter stop = SET_LIMIT(modmetadata_set); 25478161Speter } else { 25578161Speter return 0; 25678161Speter } 25778161Speter } 25878161Speter for (mdp = start; mdp < stop; mdp++) { 25978161Speter if ((*mdp)->md_type != MDT_MODULE) 26074639Sbp continue; 26178161Speter moddata = (*mdp)->md_data; 26274639Sbp KLD_DPF(FILE, ("Registering module %s in %s\n", 26374639Sbp moddata->name, lf->filename)); 26474639Sbp if (module_lookupbyname(moddata->name) != NULL) { 26574639Sbp printf("Warning: module %s already exists\n", moddata->name); 26674639Sbp continue; /* or return a error ? */ 26759751Speter } 26874639Sbp error = module_register(moddata, lf); 26974639Sbp if (error) 27074639Sbp printf("Module %s failed to register: %d\n", moddata->name, error); 27159751Speter } 27274639Sbp return 0; 27359751Speter} 27459751Speter 27559751Speterstatic void 27659751Speterlinker_init_kernel_modules(void) 27759751Speter{ 27859751Speter linker_file_register_modules(linker_kernel_file); 27959751Speter} 28059751Speter 28159751SpeterSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0); 28259751Speter 28325537Sdfrint 28425537Sdfrlinker_load_file(const char* filename, linker_file_t* result) 28525537Sdfr{ 28625537Sdfr linker_class_t lc; 28725537Sdfr linker_file_t lf; 28842755Speter int foundfile, error = 0; 28925537Sdfr 29062261Sarchie /* Refuse to load modules if securelevel raised */ 29162261Sarchie if (securelevel > 0) 29262261Sarchie return EPERM; 29362261Sarchie 29425537Sdfr lf = linker_find_file_by_name(filename); 29525537Sdfr if (lf) { 29625537Sdfr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); 29725537Sdfr *result = lf; 29825537Sdfr lf->refs++; 29925537Sdfr goto out; 30025537Sdfr } 30125537Sdfr 30225537Sdfr lf = NULL; 30342755Speter foundfile = 0; 30471999Sphk TAILQ_FOREACH(lc, &classes, link) { 30580701Sjake KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 30680701Sjake filename)); 30759751Speter error = LINKER_LOAD_FILE(lc, filename, &lf); 30842755Speter /* 30942755Speter * If we got something other than ENOENT, then it exists but we cannot 31042755Speter * load it for some other reason. 31142755Speter */ 31242755Speter if (error != ENOENT) 31342755Speter foundfile = 1; 31425537Sdfr if (lf) { 31559751Speter linker_file_register_modules(lf); 31644549Sdfr linker_file_register_sysctls(lf); 31725537Sdfr linker_file_sysinit(lf); 31859751Speter lf->flags |= LINKER_FILE_LINKED; 31925537Sdfr 32025537Sdfr *result = lf; 32140861Speter error = 0; 32225537Sdfr goto out; 32325537Sdfr } 32425537Sdfr } 32542755Speter /* 32642755Speter * Less than ideal, but tells the user whether it failed to load or 32742755Speter * the module was not found. 32842755Speter */ 32942755Speter if (foundfile) 33042755Speter error = ENOEXEC; /* Format not recognised (or unloadable) */ 33142755Speter else 33242755Speter error = ENOENT; /* Nothing found */ 33325537Sdfr 33425537Sdfrout: 33525537Sdfr return error; 33625537Sdfr} 33725537Sdfr 33883321Speter/* XXX: function parameters are incomplete */ 33978413Sbrianint 34078413Sbrianlinker_reference_module(const char *modname, linker_file_t *result) 34178413Sbrian{ 34278413Sbrian 34383321Speter return linker_load_module(NULL, modname, NULL, NULL, result); 34478413Sbrian} 34578413Sbrian 34625537Sdfrlinker_file_t 34725537Sdfrlinker_find_file_by_name(const char* filename) 34825537Sdfr{ 34925537Sdfr linker_file_t lf = 0; 35040861Speter char *koname; 35125537Sdfr 35240861Speter koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 35340861Speter if (koname == NULL) 35440861Speter goto out; 35540861Speter sprintf(koname, "%s.ko", filename); 35640861Speter 35725537Sdfr lockmgr(&lock, LK_SHARED, 0, curproc); 35871999Sphk TAILQ_FOREACH(lf, &linker_files, link) { 35940861Speter if (!strcmp(lf->filename, koname)) 36040861Speter break; 36125537Sdfr if (!strcmp(lf->filename, filename)) 36225537Sdfr break; 36340861Speter } 36425537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 36525537Sdfr 36640861Speterout: 36740861Speter if (koname) 36840861Speter free(koname, M_LINKER); 36925537Sdfr return lf; 37025537Sdfr} 37125537Sdfr 37225537Sdfrlinker_file_t 37325537Sdfrlinker_find_file_by_id(int fileid) 37425537Sdfr{ 37525537Sdfr linker_file_t lf = 0; 37625537Sdfr 37725537Sdfr lockmgr(&lock, LK_SHARED, 0, curproc); 37871999Sphk TAILQ_FOREACH(lf, &linker_files, link) 37925537Sdfr if (lf->id == fileid) 38025537Sdfr break; 38125537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 38225537Sdfr 38325537Sdfr return lf; 38425537Sdfr} 38525537Sdfr 38625537Sdfrlinker_file_t 38759603Sdfrlinker_make_file(const char* pathname, linker_class_t lc) 38825537Sdfr{ 38925537Sdfr linker_file_t lf = 0; 39040159Speter const char *filename; 39125537Sdfr 39259751Speter filename = linker_basename(pathname); 39340159Speter 39425537Sdfr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 39545356Speter lockmgr(&lock, LK_EXCLUSIVE, 0, curproc); 39659603Sdfr lf = (linker_file_t) kobj_create((kobj_class_t) lc, M_LINKER, M_WAITOK); 39725537Sdfr if (!lf) 39825537Sdfr goto out; 39925537Sdfr 40025537Sdfr lf->refs = 1; 40125537Sdfr lf->userrefs = 0; 40243185Sdfr lf->flags = 0; 40359603Sdfr lf->filename = linker_strdup(filename); 40425537Sdfr lf->id = next_file_id++; 40525537Sdfr lf->ndeps = 0; 40625537Sdfr lf->deps = NULL; 40725537Sdfr STAILQ_INIT(&lf->common); 40825537Sdfr TAILQ_INIT(&lf->modules); 40925537Sdfr 41050068Sgrog TAILQ_INSERT_TAIL(&linker_files, lf, link); 41125537Sdfr 41225537Sdfrout: 41325537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 41425537Sdfr return lf; 41525537Sdfr} 41625537Sdfr 41725537Sdfrint 41825537Sdfrlinker_file_unload(linker_file_t file) 41925537Sdfr{ 42025537Sdfr module_t mod, next; 42159751Speter modlist_t ml, nextml; 42225537Sdfr struct common_symbol* cp; 42325537Sdfr int error = 0; 42425537Sdfr int i; 42525537Sdfr 42662261Sarchie /* Refuse to unload modules if securelevel raised */ 42762261Sarchie if (securelevel > 0) 42862261Sarchie return EPERM; 42962261Sarchie 43040159Speter KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 43145356Speter lockmgr(&lock, LK_EXCLUSIVE, 0, curproc); 43225537Sdfr if (file->refs == 1) { 43325537Sdfr KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); 43425537Sdfr /* 43525537Sdfr * Inform any modules associated with this file. 43625537Sdfr */ 43725537Sdfr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 43825537Sdfr next = module_getfnext(mod); 43925537Sdfr 44025537Sdfr /* 44125537Sdfr * Give the module a chance to veto the unload. 44225537Sdfr */ 44343301Sdillon if ((error = module_unload(mod)) != 0) { 44425537Sdfr KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", 44525537Sdfr mod)); 44625537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 44725537Sdfr goto out; 44825537Sdfr } 44925537Sdfr 45025537Sdfr module_release(mod); 45125537Sdfr } 45225537Sdfr } 45325537Sdfr 45425537Sdfr file->refs--; 45525537Sdfr if (file->refs > 0) { 45625537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 45725537Sdfr goto out; 45825537Sdfr } 45925537Sdfr 46059751Speter for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { 46159751Speter nextml = TAILQ_NEXT(ml, link); 46259751Speter if (ml->container == file) { 46359751Speter TAILQ_REMOVE(&found_modules, ml, link); 46459751Speter } 46559751Speter } 46659751Speter 46743185Sdfr /* Don't try to run SYSUNINITs if we are unloaded due to a link error */ 46844078Sdfr if (file->flags & LINKER_FILE_LINKED) { 46943185Sdfr linker_file_sysuninit(file); 47044078Sdfr linker_file_unregister_sysctls(file); 47144078Sdfr } 47241055Speter 47350068Sgrog TAILQ_REMOVE(&linker_files, file, link); 47425537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 47540159Speter 47659751Speter if (file->deps) { 47759751Speter for (i = 0; i < file->ndeps; i++) 47859751Speter linker_file_unload(file->deps[i]); 47959751Speter free(file->deps, M_LINKER); 48059751Speter file->deps = NULL; 48159751Speter } 48225537Sdfr 48325537Sdfr for (cp = STAILQ_FIRST(&file->common); cp; 48425537Sdfr cp = STAILQ_FIRST(&file->common)) { 48560938Sjake STAILQ_REMOVE(&file->common, cp, common_symbol, link); 48625537Sdfr free(cp, M_LINKER); 48725537Sdfr } 48825537Sdfr 48959603Sdfr LINKER_UNLOAD(file); 49059751Speter if (file->filename) { 49159751Speter free(file->filename, M_LINKER); 49259751Speter file->filename = NULL; 49359751Speter } 49459603Sdfr kobj_delete((kobj_t) file, M_LINKER); 49525537Sdfr 49625537Sdfrout: 49725537Sdfr return error; 49825537Sdfr} 49925537Sdfr 50025537Sdfrint 50125537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep) 50225537Sdfr{ 50325537Sdfr linker_file_t* newdeps; 50425537Sdfr 50525537Sdfr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), 50669781Sdwmalone M_LINKER, M_WAITOK | M_ZERO); 50725537Sdfr if (newdeps == NULL) 50825537Sdfr return ENOMEM; 50925537Sdfr 51025537Sdfr if (file->deps) { 51125537Sdfr bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); 51225537Sdfr free(file->deps, M_LINKER); 51325537Sdfr } 51425537Sdfr file->deps = newdeps; 51525537Sdfr file->deps[file->ndeps] = dep; 51625537Sdfr file->ndeps++; 51725537Sdfr 51825537Sdfr return 0; 51925537Sdfr} 52025537Sdfr 52178161Speter/* 52278161Speter * Locate a linker set and its contents. 52378161Speter * This is a helper function to avoid linker_if.h exposure elsewhere. 52478161Speter * Note: firstp and lastp are really void *** 52578161Speter */ 52678161Speterint 52778161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 52878161Speter void *firstp, void *lastp, int *countp) 52978161Speter{ 53078161Speter 53178161Speter return LINKER_LOOKUP_SET(file, name, firstp, lastp, countp); 53278161Speter} 53378161Speter 53425537Sdfrcaddr_t 53525537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps) 53625537Sdfr{ 53743309Sdillon c_linker_sym_t sym; 53838275Sdfr linker_symval_t symval; 53925537Sdfr caddr_t address; 54025537Sdfr size_t common_size = 0; 54125537Sdfr int i; 54225537Sdfr 54340159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", 54425537Sdfr file, name, deps)); 54525537Sdfr 54659603Sdfr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 54759603Sdfr LINKER_SYMBOL_VALUES(file, sym, &symval); 54838275Sdfr if (symval.value == 0) 54925537Sdfr /* 55025537Sdfr * For commons, first look them up in the dependancies and 55125537Sdfr * only allocate space if not found there. 55225537Sdfr */ 55338275Sdfr common_size = symval.size; 55440159Speter else { 55540159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value)); 55638275Sdfr return symval.value; 55740159Speter } 55838275Sdfr } 55925537Sdfr 56042849Speter if (deps) { 56125537Sdfr for (i = 0; i < file->ndeps; i++) { 56225537Sdfr address = linker_file_lookup_symbol(file->deps[i], name, 0); 56340159Speter if (address) { 56440159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address)); 56525537Sdfr return address; 56640159Speter } 56725537Sdfr } 56842849Speter } 56942849Speter 57025537Sdfr if (common_size > 0) { 57125537Sdfr /* 57225537Sdfr * This is a common symbol which was not found in the 57325537Sdfr * dependancies. We maintain a simple common symbol table in 57425537Sdfr * the file object. 57525537Sdfr */ 57625537Sdfr struct common_symbol* cp; 57725537Sdfr 57872012Sphk STAILQ_FOREACH(cp, &file->common, link) 57940159Speter if (!strcmp(cp->name, name)) { 58040159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address)); 58125537Sdfr return cp->address; 58240159Speter } 58325537Sdfr 58425537Sdfr /* 58525537Sdfr * Round the symbol size up to align. 58625537Sdfr */ 58725537Sdfr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 58825537Sdfr cp = malloc(sizeof(struct common_symbol) 58925537Sdfr + common_size 59025537Sdfr + strlen(name) + 1, 59169781Sdwmalone M_LINKER, M_WAITOK | M_ZERO); 59240159Speter if (!cp) { 59340159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 59425537Sdfr return 0; 59540159Speter } 59625537Sdfr 59725537Sdfr cp->address = (caddr_t) (cp + 1); 59825537Sdfr cp->name = cp->address + common_size; 59925537Sdfr strcpy(cp->name, name); 60025537Sdfr bzero(cp->address, common_size); 60125537Sdfr STAILQ_INSERT_TAIL(&file->common, cp, link); 60225537Sdfr 60340159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address)); 60425537Sdfr return cp->address; 60525537Sdfr } 60625537Sdfr 60740159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 60825537Sdfr return 0; 60925537Sdfr} 61025537Sdfr 61140159Speter#ifdef DDB 61225537Sdfr/* 61340159Speter * DDB Helpers. DDB has to look across multiple files with their own 61440159Speter * symbol tables and string tables. 61540159Speter * 61640159Speter * Note that we do not obey list locking protocols here. We really don't 61740159Speter * need DDB to hang because somebody's got the lock held. We'll take the 61840159Speter * chance that the files list is inconsistant instead. 61940159Speter */ 62040159Speter 62140159Speterint 62243309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 62340159Speter{ 62440159Speter linker_file_t lf; 62540159Speter 62671999Sphk TAILQ_FOREACH(lf, &linker_files, link) { 62759603Sdfr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 62840159Speter return 0; 62940159Speter } 63040159Speter return ENOENT; 63140159Speter} 63240159Speter 63340159Speterint 63443309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 63540159Speter{ 63640159Speter linker_file_t lf; 63750272Sbde u_long off = (uintptr_t)value; 63840159Speter u_long diff, bestdiff; 63943309Sdillon c_linker_sym_t best; 64043309Sdillon c_linker_sym_t es; 64140159Speter 64240159Speter best = 0; 64340159Speter bestdiff = off; 64471999Sphk TAILQ_FOREACH(lf, &linker_files, link) { 64559603Sdfr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 64640159Speter continue; 64740159Speter if (es != 0 && diff < bestdiff) { 64840159Speter best = es; 64940159Speter bestdiff = diff; 65040159Speter } 65140159Speter if (bestdiff == 0) 65240159Speter break; 65340159Speter } 65440159Speter if (best) { 65540159Speter *sym = best; 65640159Speter *diffp = bestdiff; 65740159Speter return 0; 65840159Speter } else { 65940159Speter *sym = 0; 66040159Speter *diffp = off; 66140159Speter return ENOENT; 66240159Speter } 66340159Speter} 66440159Speter 66540159Speterint 66643309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 66740159Speter{ 66840159Speter linker_file_t lf; 66940159Speter 67071999Sphk TAILQ_FOREACH(lf, &linker_files, link) { 67159603Sdfr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 67240159Speter return 0; 67340159Speter } 67440159Speter return ENOENT; 67540159Speter} 67640159Speter 67740159Speter#endif 67840159Speter 67940159Speter/* 68025537Sdfr * Syscalls. 68125537Sdfr */ 68282749Sdillon/* 68382749Sdillon * MPSAFE 68482749Sdillon */ 68525537Sdfrint 68630994Sphkkldload(struct proc* p, struct kldload_args* uap) 68725537Sdfr{ 68883321Speter char *kldname, *modname; 68982749Sdillon char *pathname = NULL; 69025537Sdfr linker_file_t lf; 69125537Sdfr int error = 0; 69225537Sdfr 69330994Sphk p->p_retval[0] = -1; 69425537Sdfr 69562261Sarchie if (securelevel > 0) /* redundant, but that's OK */ 69625537Sdfr return EPERM; 69725537Sdfr 69882749Sdillon mtx_lock(&Giant); 69982749Sdillon 70046112Sphk if ((error = suser(p)) != 0) 70182749Sdillon goto out; 70225537Sdfr 70359751Speter pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 70459751Speter if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0) 70525537Sdfr goto out; 70625537Sdfr 70783321Speter /* 70883321Speter * If path do not contain qualified name or any dot in it (kldname.ko, or 70983321Speter * kldname.ver.ko) treat it as interface name. 71083321Speter */ 71183321Speter if (index(pathname, '/') || index(pathname, '.')) { 71283321Speter kldname = pathname; 71383321Speter modname = NULL; 71483321Speter } else { 71583321Speter kldname = NULL; 71683321Speter modname = pathname; 71759751Speter } 71883321Speter error = linker_load_module(kldname, modname, NULL, NULL, &lf); 71983321Speter if (error) 72042316Smsmith goto out; 72142316Smsmith 72225537Sdfr lf->userrefs++; 72330994Sphk p->p_retval[0] = lf->id; 72440159Speter 72525537Sdfrout: 72659751Speter if (pathname) 72759751Speter free(pathname, M_TEMP); 72882749Sdillon mtx_unlock(&Giant); 72982749Sdillon return (error); 73025537Sdfr} 73125537Sdfr 73282749Sdillon/* 73382749Sdillon * MPSAFE 73482749Sdillon */ 73525537Sdfrint 73630994Sphkkldunload(struct proc* p, struct kldunload_args* uap) 73725537Sdfr{ 73825537Sdfr linker_file_t lf; 73925537Sdfr int error = 0; 74025537Sdfr 74162261Sarchie if (securelevel > 0) /* redundant, but that's OK */ 74225537Sdfr return EPERM; 74325537Sdfr 74482749Sdillon mtx_lock(&Giant); 74582749Sdillon 74646112Sphk if ((error = suser(p)) != 0) 74782749Sdillon goto out; 74825537Sdfr 74925537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 75025537Sdfr if (lf) { 75125537Sdfr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 75225537Sdfr if (lf->userrefs == 0) { 75359751Speter printf("kldunload: attempt to unload file that was loaded by the kernel\n"); 75425537Sdfr error = EBUSY; 75525537Sdfr goto out; 75625537Sdfr } 75743084Speter lf->userrefs--; 75842837Speter error = linker_file_unload(lf); 75942837Speter if (error) 76043084Speter lf->userrefs++; 76182749Sdillon } else { 76225537Sdfr error = ENOENT; 76382749Sdillon } 76425537Sdfrout: 76582749Sdillon mtx_unlock(&Giant); 76682749Sdillon return (error); 76725537Sdfr} 76825537Sdfr 76982749Sdillon/* 77082749Sdillon * MPSAFE 77182749Sdillon */ 77225537Sdfrint 77330994Sphkkldfind(struct proc* p, struct kldfind_args* uap) 77425537Sdfr{ 77559751Speter char* pathname; 77659751Speter const char *filename; 77725537Sdfr linker_file_t lf; 77825537Sdfr int error = 0; 77925537Sdfr 78082749Sdillon mtx_lock(&Giant); 78182749Sdillon 78230994Sphk p->p_retval[0] = -1; 78325537Sdfr 78459751Speter pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 78559751Speter if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0) 78625537Sdfr goto out; 78725537Sdfr 78859751Speter filename = linker_basename(pathname); 78942316Smsmith 79059751Speter lf = linker_find_file_by_name(filename); 79125537Sdfr if (lf) 79230994Sphk p->p_retval[0] = lf->id; 79325537Sdfr else 79425537Sdfr error = ENOENT; 79540159Speter 79625537Sdfrout: 79759751Speter if (pathname) 79859751Speter free(pathname, M_TEMP); 79982749Sdillon mtx_unlock(&Giant); 80082749Sdillon return (error); 80125537Sdfr} 80225537Sdfr 80382749Sdillon/* 80482749Sdillon * MPSAFE 80582749Sdillon */ 80625537Sdfrint 80730994Sphkkldnext(struct proc* p, struct kldnext_args* uap) 80825537Sdfr{ 80925537Sdfr linker_file_t lf; 81025537Sdfr int error = 0; 81125537Sdfr 81282749Sdillon mtx_lock(&Giant); 81382749Sdillon 81425537Sdfr if (SCARG(uap, fileid) == 0) { 81550068Sgrog if (TAILQ_FIRST(&linker_files)) 81650068Sgrog p->p_retval[0] = TAILQ_FIRST(&linker_files)->id; 81725537Sdfr else 81830994Sphk p->p_retval[0] = 0; 81982749Sdillon goto out; 82025537Sdfr } 82140159Speter 82225537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 82325537Sdfr if (lf) { 82425537Sdfr if (TAILQ_NEXT(lf, link)) 82530994Sphk p->p_retval[0] = TAILQ_NEXT(lf, link)->id; 82625537Sdfr else 82730994Sphk p->p_retval[0] = 0; 82882749Sdillon } else { 82925537Sdfr error = ENOENT; 83082749Sdillon } 83182749Sdillonout: 83282749Sdillon mtx_unlock(&Giant); 83382749Sdillon return (error); 83425537Sdfr} 83525537Sdfr 83682749Sdillon/* 83782749Sdillon * MPSAFE 83882749Sdillon */ 83925537Sdfrint 84030994Sphkkldstat(struct proc* p, struct kldstat_args* uap) 84125537Sdfr{ 84225537Sdfr linker_file_t lf; 84325537Sdfr int error = 0; 84425537Sdfr int version; 84525537Sdfr struct kld_file_stat* stat; 84625537Sdfr int namelen; 84725537Sdfr 84882749Sdillon mtx_lock(&Giant); 84982749Sdillon 85025537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 85125537Sdfr if (!lf) { 85225537Sdfr error = ENOENT; 85325537Sdfr goto out; 85425537Sdfr } 85525537Sdfr 85625537Sdfr stat = SCARG(uap, stat); 85725537Sdfr 85825537Sdfr /* 85925537Sdfr * Check the version of the user's structure. 86025537Sdfr */ 86143301Sdillon if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 86225537Sdfr goto out; 86325537Sdfr if (version != sizeof(struct kld_file_stat)) { 86425537Sdfr error = EINVAL; 86525537Sdfr goto out; 86625537Sdfr } 86725537Sdfr 86825537Sdfr namelen = strlen(lf->filename) + 1; 86925537Sdfr if (namelen > MAXPATHLEN) 87025537Sdfr namelen = MAXPATHLEN; 87143301Sdillon if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) 87225537Sdfr goto out; 87343301Sdillon if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) 87425537Sdfr goto out; 87543301Sdillon if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) 87625537Sdfr goto out; 87743301Sdillon if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0) 87825537Sdfr goto out; 87943301Sdillon if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) 88025537Sdfr goto out; 88125537Sdfr 88230994Sphk p->p_retval[0] = 0; 88325537Sdfr 88425537Sdfrout: 88582749Sdillon mtx_unlock(&Giant); 88682749Sdillon return (error); 88725537Sdfr} 88825537Sdfr 88982749Sdillon/* 89082749Sdillon * MPSAFE 89182749Sdillon */ 89225537Sdfrint 89330994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap) 89425537Sdfr{ 89525537Sdfr linker_file_t lf; 89625537Sdfr int error = 0; 89725537Sdfr 89882749Sdillon mtx_lock(&Giant); 89925537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 90025537Sdfr if (lf) { 90125537Sdfr if (TAILQ_FIRST(&lf->modules)) 90230994Sphk p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules)); 90325537Sdfr else 90430994Sphk p->p_retval[0] = 0; 90582749Sdillon } else { 90625537Sdfr error = ENOENT; 90782749Sdillon } 90882749Sdillon mtx_unlock(&Giant); 90982749Sdillon return (error); 91025537Sdfr} 91140159Speter 91282749Sdillon/* 91382749Sdillon * MPSAFE 91482749Sdillon */ 91541090Speterint 91641090Speterkldsym(struct proc *p, struct kldsym_args *uap) 91741090Speter{ 91841090Speter char *symstr = NULL; 91943309Sdillon c_linker_sym_t sym; 92041090Speter linker_symval_t symval; 92141090Speter linker_file_t lf; 92241090Speter struct kld_sym_lookup lookup; 92341090Speter int error = 0; 92441090Speter 92582749Sdillon mtx_lock(&Giant); 92682749Sdillon 92743301Sdillon if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0) 92841090Speter goto out; 92941090Speter if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) { 93041090Speter error = EINVAL; 93141090Speter goto out; 93241090Speter } 93341090Speter 93441090Speter symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 93543301Sdillon if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 93641090Speter goto out; 93741090Speter 93841090Speter if (SCARG(uap, fileid) != 0) { 93941090Speter lf = linker_find_file_by_id(SCARG(uap, fileid)); 94041090Speter if (lf == NULL) { 94141090Speter error = ENOENT; 94241090Speter goto out; 94341090Speter } 94459603Sdfr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 94559603Sdfr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 94650272Sbde lookup.symvalue = (uintptr_t)symval.value; 94741090Speter lookup.symsize = symval.size; 94841090Speter error = copyout(&lookup, SCARG(uap, data), sizeof(lookup)); 94941090Speter } else 95041090Speter error = ENOENT; 95141090Speter } else { 95271999Sphk TAILQ_FOREACH(lf, &linker_files, link) { 95359603Sdfr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 95459603Sdfr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 95550272Sbde lookup.symvalue = (uintptr_t)symval.value; 95641090Speter lookup.symsize = symval.size; 95741090Speter error = copyout(&lookup, SCARG(uap, data), sizeof(lookup)); 95841090Speter break; 95941090Speter } 96041090Speter } 96141090Speter if (!lf) 96241090Speter error = ENOENT; 96341090Speter } 96441090Speterout: 96541090Speter if (symstr) 96641090Speter free(symstr, M_TEMP); 96782749Sdillon mtx_unlock(&Giant); 96882749Sdillon return (error); 96941090Speter} 97041090Speter 97140159Speter/* 97240159Speter * Preloaded module support 97340159Speter */ 97440159Speter 97559751Speterstatic modlist_t 97674642Sbpmodlist_lookup(const char *name, int ver) 97759751Speter{ 97859751Speter modlist_t mod; 97959751Speter 98071999Sphk TAILQ_FOREACH(mod, &found_modules, link) { 98174642Sbp if (strcmp(mod->name, name) == 0 && (ver == 0 || mod->version == ver)) 98259751Speter return mod; 98359751Speter } 98459751Speter return NULL; 98559751Speter} 98659751Speter 98774642Sbpstatic modlist_t 98883321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 98983321Speter{ 99083321Speter modlist_t mod, bestmod; 99183321Speter int ver; 99283321Speter 99383321Speter if (verinfo == NULL) 99483321Speter return modlist_lookup(name, 0); 99583321Speter bestmod = NULL; 99683321Speter for (mod = TAILQ_FIRST(&found_modules); mod; mod = TAILQ_NEXT(mod, link)) { 99783321Speter if (strcmp(mod->name, name) != 0) 99883321Speter continue; 99983321Speter ver = mod->version; 100083321Speter if (ver == verinfo->md_ver_preferred) 100183321Speter return mod; 100283321Speter if (ver >= verinfo->md_ver_minimum && 100383321Speter ver <= verinfo->md_ver_maximum && 100483321Speter ver > bestmod->version) 100583321Speter bestmod = mod; 100683321Speter } 100783321Speter return bestmod; 100883321Speter} 100983321Speter 101083321Speterstatic modlist_t 101178501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 101274642Sbp{ 101374642Sbp modlist_t mod; 101474642Sbp 101574642Sbp mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT); 101674642Sbp if (mod == NULL) 101774642Sbp panic("no memory for module list"); 101874642Sbp bzero(mod, sizeof(*mod)); 101974642Sbp mod->container = container; 102074642Sbp mod->name = modname; 102174642Sbp mod->version = version; 102274642Sbp TAILQ_INSERT_TAIL(&found_modules, mod, link); 102374642Sbp return mod; 102474642Sbp} 102574642Sbp 102659751Speter/* 102759751Speter * This routine is cheap and nasty but will work for data pointers. 102859751Speter */ 102959751Speterstatic void * 103078501Sdeslinker_reloc_ptr(linker_file_t lf, const void *offset) 103159751Speter{ 103259751Speter return lf->address + (uintptr_t)offset; 103359751Speter} 103459751Speter 103574642Sbp/* 103674642Sbp * Dereference MDT_VERSION metadata into module name and version 103774642Sbp */ 103840159Speterstatic void 103974642Sbplinker_mdt_version(linker_file_t lf, struct mod_metadata *mp, 104078501Sdes const char **modname, int *version) 104174642Sbp{ 104274642Sbp struct mod_version *mvp; 104374642Sbp 104474642Sbp if (modname) 104574642Sbp *modname = linker_reloc_ptr(lf, mp->md_cval); 104674642Sbp if (version) { 104774642Sbp mvp = linker_reloc_ptr(lf, mp->md_data); 104874642Sbp *version = mvp->mv_version; 104974642Sbp } 105074642Sbp} 105174642Sbp 105274642Sbp/* 105374642Sbp * Dereference MDT_DEPEND metadata into module name and mod_depend structure 105474642Sbp */ 105574642Sbpstatic void 105674642Sbplinker_mdt_depend(linker_file_t lf, struct mod_metadata *mp, 105778501Sdes const char **modname, struct mod_depend **verinfo) 105874642Sbp{ 105974642Sbp 106074642Sbp if (modname) 106174642Sbp *modname = linker_reloc_ptr(lf, mp->md_cval); 106274642Sbp if (verinfo) 106374642Sbp *verinfo = linker_reloc_ptr(lf, mp->md_data); 106474642Sbp} 106574642Sbp 106674642Sbpstatic void 106778161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 106878161Speter struct mod_metadata **stop, int preload) 106974642Sbp{ 107078161Speter struct mod_metadata *mp, **mdp; 107178501Sdes const char *modname; 107278161Speter int ver; 107374642Sbp 107478161Speter for (mdp = start; mdp < stop; mdp++) { 107574642Sbp if (preload) 107678161Speter mp = *mdp; 107774642Sbp else 107878161Speter mp = linker_reloc_ptr(lf, *mdp); 107974642Sbp if (mp->md_type != MDT_VERSION) 108074642Sbp continue; 108174642Sbp if (preload) { 108274642Sbp modname = mp->md_cval; 108374642Sbp ver = ((struct mod_version*)mp->md_data)->mv_version; 108474642Sbp } else 108574642Sbp linker_mdt_version(lf, mp, &modname, &ver); 108674642Sbp if (modlist_lookup(modname, ver) != NULL) { 108774642Sbp printf("module %s already present!\n", modname); 108874642Sbp /* XXX what can we do? this is a build error. :-( */ 108974642Sbp continue; 109074642Sbp } 109174642Sbp modlist_newmodule(modname, ver, lf); 109274642Sbp } 109374642Sbp} 109474642Sbp 109574642Sbpstatic void 109640159Speterlinker_preload(void* arg) 109740159Speter{ 109840159Speter caddr_t modptr; 109978501Sdes const char *modname, *nmodname; 110040162Speter char *modtype; 110140159Speter linker_file_t lf; 110240159Speter linker_class_t lc; 110374639Sbp int error; 110459751Speter linker_file_list_t loaded_files; 110559751Speter linker_file_list_t depended_files; 110664143Speter struct mod_metadata *mp, *nmp; 110778161Speter struct mod_metadata **start, **stop, **mdp, **nmdp; 110874642Sbp struct mod_depend *verinfo; 110978161Speter int nver; 111059751Speter int resolves; 111159751Speter modlist_t mod; 111278161Speter struct sysinit **si_start, **si_stop; 111340159Speter 111459751Speter TAILQ_INIT(&loaded_files); 111559751Speter TAILQ_INIT(&depended_files); 111659751Speter TAILQ_INIT(&found_modules); 111759751Speter error = 0; 111859751Speter 111940159Speter modptr = NULL; 112040159Speter while ((modptr = preload_search_next_name(modptr)) != NULL) { 112140159Speter modname = (char *)preload_search_info(modptr, MODINFO_NAME); 112240162Speter modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 112340159Speter if (modname == NULL) { 112440625Smsmith printf("Preloaded module at %p does not have a name!\n", modptr); 112540159Speter continue; 112640159Speter } 112740162Speter if (modtype == NULL) { 112840625Smsmith printf("Preloaded module at %p does not have a type!\n", modptr); 112940162Speter continue; 113040162Speter } 113140625Smsmith printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr); 113240159Speter lf = NULL; 113371999Sphk TAILQ_FOREACH(lc, &classes, link) { 113459751Speter error = LINKER_LINK_PRELOAD(lc, modname, &lf); 113540159Speter if (error) { 113640159Speter lf = NULL; 113740159Speter break; 113840159Speter } 113940159Speter } 114059751Speter if (lf) 114159751Speter TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 114259751Speter } 114340159Speter 114459751Speter /* 114559751Speter * First get a list of stuff in the kernel. 114659751Speter */ 114778161Speter if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, &stop, 114878161Speter NULL) == 0) 114978161Speter linker_addmodules(linker_kernel_file, start, stop, 1); 115059751Speter 115159751Speter /* 115259751Speter * this is a once-off kinky bubble sort 115359751Speter * resolve relocation dependency requirements 115459751Speter */ 115559751Speterrestart: 115671999Sphk TAILQ_FOREACH(lf, &loaded_files, loaded) { 115778161Speter error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); 115859751Speter /* 115959751Speter * First, look to see if we would successfully link with this stuff. 116059751Speter */ 116159751Speter resolves = 1; /* unless we know otherwise */ 116278161Speter if (!error) { 116378161Speter for (mdp = start; mdp < stop; mdp++) { 116478161Speter mp = linker_reloc_ptr(lf, *mdp); 116559751Speter if (mp->md_type != MDT_DEPEND) 116659751Speter continue; 116774642Sbp linker_mdt_depend(lf, mp, &modname, &verinfo); 116878161Speter for (nmdp = start; nmdp < stop; nmdp++) { 116978161Speter nmp = linker_reloc_ptr(lf, *nmdp); 117064143Speter if (nmp->md_type != MDT_VERSION) 117164143Speter continue; 117274642Sbp linker_mdt_version(lf, nmp, &nmodname, NULL); 117364143Speter nmodname = linker_reloc_ptr(lf, nmp->md_cval); 117464143Speter if (strcmp(modname, nmodname) == 0) 117564143Speter break; 117664143Speter } 117778161Speter if (nmdp < stop) /* it's a self reference */ 117864143Speter continue; 117983321Speter if (modlist_lookup2(modname, verinfo) == NULL) { 118059751Speter /* ok, the module isn't here yet, we are not finished */ 118159751Speter resolves = 0; 118259751Speter } 118359751Speter } 118459751Speter } 118559751Speter /* 118659751Speter * OK, if we found our modules, we can link. So, "provide" the 118759751Speter * modules inside and add it to the end of the link order list. 118859751Speter */ 118959751Speter if (resolves) { 119078161Speter if (!error) { 119178161Speter for (mdp = start; mdp < stop; mdp++) { 119278161Speter mp = linker_reloc_ptr(lf, *mdp); 119359751Speter if (mp->md_type != MDT_VERSION) 119459751Speter continue; 119574642Sbp linker_mdt_version(lf, mp, &modname, &nver); 119674642Sbp if (modlist_lookup(modname, nver) != NULL) { 119759751Speter printf("module %s already present!\n", modname); 119859751Speter linker_file_unload(lf); 119959751Speter TAILQ_REMOVE(&loaded_files, lf, loaded); 120059751Speter goto restart; /* we changed the tailq next ptr */ 120140159Speter } 120274642Sbp modlist_newmodule(modname, nver, lf); 120340159Speter } 120440159Speter } 120559751Speter TAILQ_REMOVE(&loaded_files, lf, loaded); 120659751Speter TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 120759751Speter /* 120859751Speter * Since we provided modules, we need to restart the sort so 120959751Speter * that the previous files that depend on us have a chance. 121059751Speter * Also, we've busted the tailq next pointer with the REMOVE. 121159751Speter */ 121259751Speter goto restart; 121340159Speter } 121440159Speter } 121559751Speter 121659751Speter /* 121759751Speter * At this point, we check to see what could not be resolved.. 121859751Speter */ 121971999Sphk TAILQ_FOREACH(lf, &loaded_files, loaded) { 122059751Speter printf("KLD file %s is missing dependencies\n", lf->filename); 122159751Speter linker_file_unload(lf); 122259751Speter TAILQ_REMOVE(&loaded_files, lf, loaded); 122359751Speter } 122459751Speter 122559751Speter /* 122659751Speter * We made it. Finish off the linking in the order we determined. 122759751Speter */ 122871999Sphk TAILQ_FOREACH(lf, &depended_files, loaded) { 122959751Speter if (linker_kernel_file) { 123059751Speter linker_kernel_file->refs++; 123159751Speter error = linker_file_add_dependancy(lf, linker_kernel_file); 123259751Speter if (error) 123359751Speter panic("cannot add dependency"); 123459751Speter } 123559751Speter lf->userrefs++; /* so we can (try to) kldunload it */ 123678161Speter error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); 123778161Speter if (!error) { 123878161Speter for (mdp = start; mdp < stop; mdp++) { 123978161Speter mp = linker_reloc_ptr(lf, *mdp); 124059751Speter if (mp->md_type != MDT_DEPEND) 124159751Speter continue; 124274642Sbp linker_mdt_depend(lf, mp, &modname, &verinfo); 124383321Speter mod = modlist_lookup2(modname, verinfo); 124459751Speter mod->container->refs++; 124559751Speter error = linker_file_add_dependancy(lf, mod->container); 124659751Speter if (error) 124759751Speter panic("cannot add dependency"); 124859751Speter } 124959751Speter } 125059751Speter 125178161Speter /* 125278161Speter * Now do relocation etc using the symbol search paths established by 125378161Speter * the dependencies 125478161Speter */ 125559751Speter error = LINKER_LINK_PRELOAD_FINISH(lf); 125659751Speter if (error) { 125759751Speter printf("KLD file %s - could not finalize loading\n", lf->filename); 125859751Speter linker_file_unload(lf); 125959751Speter continue; 126059751Speter } 126159751Speter 126274639Sbp linker_file_register_modules(lf); 126378161Speter if (linker_file_lookup_set(lf, "sysinit_set", &si_start, &si_stop, NULL) == 0) 126478161Speter sysinit_add(si_start, si_stop); 126559751Speter linker_file_register_sysctls(lf); 126659751Speter lf->flags |= LINKER_FILE_LINKED; 126759751Speter } 126859751Speter /* woohoo! we made it! */ 126940159Speter} 127040159Speter 127140159SpeterSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 127240159Speter 127340159Speter/* 127440159Speter * Search for a not-loaded module by name. 127540159Speter * 127640159Speter * Modules may be found in the following locations: 127740159Speter * 127840159Speter * - preloaded (result is just the module name) 127940159Speter * - on disk (result is full path to module) 128040159Speter * 128140159Speter * If the module name is qualified in any way (contains path, etc.) 128240159Speter * the we simply return a copy of it. 128340159Speter * 128440159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 128540159Speter * character as a separator to be consistent with the bootloader. 128640159Speter */ 128740159Speter 128883321Speterstatic char linker_hintfile[] = "linker.hints"; 128983358Speterstatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules;/modules"; 129040159Speter 129140159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 129240159Speter sizeof(linker_path), "module load search path"); 129340159Speter 129477843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 129570417Speter 129659751Speterstatic char *linker_ext_list[] = { 129783321Speter "", 129859751Speter ".ko", 129959751Speter NULL 130059751Speter}; 130159751Speter 130283321Speter/* 130383321Speter * Check if file actually exists either with or without extension listed 130483321Speter * in the linker_ext_list. 130583321Speter * (probably should be generic for the rest of the kernel) 130683321Speter */ 130759751Speterstatic char * 130883321Speterlinker_lookup_file(const char *path, int pathlen, 130983321Speter const char *name, int namelen, struct vattr *vap) 131040159Speter{ 131140159Speter struct nameidata nd; 131240159Speter struct proc *p = curproc; /* XXX */ 131383358Speter char *result, **cpp, *sep; 131483358Speter int error, len, extlen, reclen, flags; 131540159Speter enum vtype type; 131640159Speter 131783321Speter extlen = 0; 131883321Speter for (cpp = linker_ext_list; *cpp; cpp++) { 131983321Speter len = strlen(*cpp); 132083321Speter if (len > extlen) 132183321Speter extlen = len; 132283321Speter } 132383321Speter extlen++; /* trailing '\0' */ 132483358Speter sep = (path[pathlen - 1] != '/') ? "/" : ""; 132583321Speter 132683358Speter reclen = pathlen + strlen(sep) + namelen + extlen + 1; 132783358Speter result = malloc(reclen, M_LINKER, M_WAITOK); 132883321Speter for (cpp = linker_ext_list; *cpp; cpp++) { 132983358Speter snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 133083358Speter namelen, name, *cpp); 133183321Speter /* 133283321Speter * Attempt to open the file, and return the path if we succeed 133383321Speter * and it's a regular file. 133483321Speter */ 133583321Speter NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p); 133683321Speter flags = FREAD; 133783321Speter error = vn_open(&nd, &flags, 0); 133883321Speter if (error == 0) { 133983321Speter NDFREE(&nd, NDF_ONLY_PNBUF); 134083321Speter type = nd.ni_vp->v_type; 134183321Speter if (vap) 134283321Speter VOP_GETATTR(nd.ni_vp, vap, p->p_ucred, p); 134383321Speter VOP_UNLOCK(nd.ni_vp, 0, p); 134483321Speter vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 134583321Speter if (type == VREG) 134683321Speter return(result); 134783321Speter } 134883321Speter } 134983321Speter free(result, M_LINKER); 135083321Speter return(NULL); 135183321Speter} 135283321Speter 135383321Speter#define INT_ALIGN(base, ptr) ptr = \ 135483321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 135583321Speter 135683321Speter/* 135783321Speter * Lookup KLD which contains requested module in the "linker.hints" file. 135883321Speter * If version specification is available, then try to find the best KLD. 135983321Speter * Otherwise just find the latest one. 136083321Speter */ 136183321Speterstatic char * 136283321Speterlinker_hints_lookup(const char *path, int pathlen, 136383321Speter const char *modname, int modnamelen, 136483321Speter struct mod_depend *verinfo) 136583321Speter{ 136683321Speter struct proc *p = curproc; 136783321Speter struct ucred *cred = p ? p->p_ucred : NULL; 136883321Speter struct nameidata nd; 136983321Speter struct vattr vattr, mattr; 137083321Speter u_char *hints = NULL; 137183358Speter u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 137283321Speter int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 137383321Speter 137483321Speter result = NULL; 137583321Speter bestver = found = 0; 137683321Speter 137783358Speter sep = (path[pathlen - 1] != '/') ? "/" : ""; 137883358Speter reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 137983358Speter strlen(sep) + 1; 138083321Speter pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 138183358Speter snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, linker_hintfile); 138283321Speter 138383321Speter NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p); 138483321Speter flags = FREAD; 138583321Speter error = vn_open(&nd, &flags, 0); 138683321Speter if (error) 138783321Speter goto bad; 138883321Speter NDFREE(&nd, NDF_ONLY_PNBUF); 138983321Speter VOP_UNLOCK(nd.ni_vp, 0, p); 139083321Speter if (nd.ni_vp->v_type != VREG) 139183321Speter goto bad; 139283321Speter best = cp = NULL; 139383321Speter error = VOP_GETATTR(nd.ni_vp, &vattr, cred, p); 139483321Speter if (error) 139583321Speter goto bad; 139683321Speter /* 139783321Speter * XXX: we need to limit this number to some reasonable value 139883321Speter */ 139983321Speter if (vattr.va_size > 100 * 1024) { 140083321Speter printf("hints file too large %ld\n", (long)vattr.va_size); 140183321Speter goto bad; 140283321Speter } 140383321Speter hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 140483321Speter if (hints == NULL) 140583321Speter goto bad; 140683321Speter error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 140783321Speter UIO_SYSSPACE, IO_NODELOCKED, cred, &reclen, p); 140883321Speter if (error) 140983321Speter goto bad; 141083321Speter vn_close(nd.ni_vp, FREAD, cred, p); 141183321Speter nd.ni_vp = NULL; 141283321Speter if (reclen != 0) { 141383321Speter printf("can't read %d\n", reclen); 141483321Speter goto bad; 141583321Speter } 141683321Speter intp = (int*)hints; 141783321Speter ival = *intp++; 141883321Speter if (ival != LINKER_HINTS_VERSION) { 141983321Speter printf("hints file version mismatch %d\n", ival); 142083321Speter goto bad; 142183321Speter } 142283321Speter bufend = hints + vattr.va_size; 142383321Speter recptr = (u_char*)intp; 142483321Speter clen = blen = 0; 142583321Speter while (recptr < bufend && !found) { 142683321Speter intp = (int*)recptr; 142783321Speter reclen = *intp++; 142883321Speter ival = *intp++; 142983321Speter cp = (char*)intp; 143083321Speter switch (ival) { 143183321Speter case MDT_VERSION: 143283321Speter clen = *cp++; 143383321Speter if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 143483321Speter break; 143583321Speter cp += clen; 143683321Speter INT_ALIGN(hints, cp); 143783321Speter ival = *(int*)cp; 143883321Speter cp += sizeof(int); 143983321Speter clen = *cp++; 144083321Speter if (verinfo == NULL || ival == verinfo->md_ver_preferred) { 144183321Speter found = 1; 144283321Speter break; 144383321Speter } 144483321Speter if (ival >= verinfo->md_ver_minimum && 144583321Speter ival <= verinfo->md_ver_maximum && 144683321Speter ival > bestver) { 144783321Speter bestver = ival; 144883321Speter best = cp; 144983321Speter blen = clen; 145083321Speter } 145183321Speter break; 145283321Speter default: 145383321Speter break; 145483321Speter } 145583321Speter recptr += reclen + sizeof(int); 145683321Speter } 145783321Speter /* 145883321Speter * Finally check if KLD is in the place 145983321Speter */ 146083321Speter if (found) 146183321Speter result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 146283321Speter else if (best) 146383321Speter result = linker_lookup_file(path, pathlen, best, blen, &mattr); 146483321Speter if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) { 146583321Speter /* 146683321Speter * KLD is newer than hints file. What we should do now ? 146783321Speter */ 146883358Speter printf("warning: KLD '%s' is newer than the linker.hints file\n", 146983358Speter result); 147083321Speter } 147183321Speterbad: 147283321Speter if (hints) 147383321Speter free(hints, M_TEMP); 147483321Speter if (nd.ni_vp != NULL) 147583321Speter vn_close(nd.ni_vp, FREAD, cred, p); 147683321Speter /* 147783321Speter * If nothing found or hints is absent - fallback to the old way 147883321Speter * by using "kldname[.ko]" as module name. 147983321Speter */ 148083321Speter if (!found && !bestver && result == NULL) 148183321Speter result = linker_lookup_file(path, pathlen, modname, modnamelen, NULL); 148283321Speter return result; 148383321Speter} 148483321Speter 148583321Speter/* 148683321Speter * Lookup KLD which contains requested module in the all directories. 148783321Speter */ 148883321Speterstatic char * 148983321Speterlinker_search_module(const char *modname, int modnamelen, 149083321Speter struct mod_depend *verinfo) 149183321Speter{ 149283321Speter char *cp, *ep, *result; 149383321Speter 149483321Speter /* 149583321Speter * traverse the linker path 149683321Speter */ 149783321Speter for (cp = linker_path; *cp; cp = ep + 1) { 149883321Speter 149983321Speter /* find the end of this component */ 150083321Speter for (ep = cp; (*ep != 0) && (*ep != ';'); ep++) 150183321Speter ; 150283321Speter result = linker_hints_lookup(cp, ep - cp, modname, modnamelen, verinfo); 150383321Speter if (result != NULL) 150483321Speter return(result); 150583321Speter if (*ep == 0) 150683321Speter break; 150783321Speter } 150883321Speter return (NULL); 150983321Speter} 151083321Speter 151183321Speter/* 151283321Speter * Search for module in all directories listed in the linker_path. 151383321Speter */ 151483321Speterstatic char * 151583321Speterlinker_search_kld(const char *name) 151683321Speter{ 151783321Speter char *cp, *ep, *result, **cpp; 151883321Speter int extlen, len; 151983321Speter 152040159Speter /* qualified at all? */ 152154411Speter if (index(name, '/')) 152240159Speter return(linker_strdup(name)); 152340159Speter 152459751Speter extlen = 0; 152559751Speter for (cpp = linker_ext_list; *cpp; cpp++) { 152659751Speter len = strlen(*cpp); 152759751Speter if (len > extlen) 152859751Speter extlen = len; 152959751Speter } 153059751Speter extlen++; /* trailing '\0' */ 153159751Speter 153240159Speter /* traverse the linker path */ 153359751Speter len = strlen(name); 153483321Speter for (ep = linker_path; *ep; ep++) { 153583321Speter cp = ep; 153640159Speter /* find the end of this component */ 153783321Speter for (; *ep != 0 && *ep != ';'; ep++) 153840159Speter ; 153983321Speter result = linker_lookup_file(cp, ep - cp, name, len, NULL); 154083321Speter if (result != NULL) 154183321Speter return(result); 154240159Speter } 154340159Speter return(NULL); 154440159Speter} 154559751Speter 154659751Speterstatic const char * 154759751Speterlinker_basename(const char* path) 154859751Speter{ 154959751Speter const char *filename; 155059751Speter 155159751Speter filename = rindex(path, '/'); 155259751Speter if (filename == NULL) 155359751Speter return path; 155459751Speter if (filename[1]) 155559751Speter filename++; 155659751Speter return filename; 155759751Speter} 155859751Speter 155959751Speter/* 156059751Speter * Find a file which contains given module and load it, 156159751Speter * if "parent" is not NULL, register a reference to it. 156259751Speter */ 156359751Speterstatic int 156483321Speterlinker_load_module(const char *kldname, const char *modname, 156583321Speter struct linker_file *parent, struct mod_depend *verinfo, 156683321Speter struct linker_file **lfpp) 156759751Speter{ 156859751Speter linker_file_t lfdep; 156959751Speter const char *filename; 157059751Speter char *pathname; 157159751Speter int error; 157259751Speter 157383321Speter if (modname == NULL) { 157483321Speter /* 157583321Speter * We have to load KLD 157683321Speter */ 157783321Speter KASSERT(verinfo == NULL, ("linker_load_module: verinfo is not NULL")); 157883321Speter pathname = linker_search_kld(kldname); 157983321Speter } else { 158083321Speter if (modlist_lookup2(modname, verinfo) != NULL) 158183321Speter return (EEXIST); 158283321Speter if (kldname == NULL) { 158383321Speter /* 158483321Speter * Need to find a KLD with required module 158583321Speter */ 158683321Speter pathname = linker_search_module(modname, strlen(modname), verinfo); 158783321Speter } else 158883321Speter pathname = linker_strdup(kldname); 158983321Speter } 159083321Speter if (pathname == NULL) 159183321Speter return (ENOENT); 159283321Speter 159359751Speter /* 159483321Speter * Can't load more than one file with the same basename 159583321Speter * XXX: Actually it should be possible to have multiple KLDs 159683321Speter * with the same basename but different path because they can provide 159783321Speter * different versions of the same modules. 159859751Speter */ 159959751Speter filename = linker_basename(pathname); 160059751Speter if (linker_find_file_by_name(filename)) { 160159751Speter error = EEXIST; 160259751Speter goto out; 160359751Speter } 160459751Speter 160559751Speter do { 160659751Speter error = linker_load_file(pathname, &lfdep); 160759751Speter if (error) 160859751Speter break; 160983321Speter if (modname && verinfo && modlist_lookup2(modname, verinfo) == NULL) { 161083321Speter linker_file_unload(lfdep); 161183321Speter error = ENOENT; 161283321Speter break; 161383321Speter } 161459751Speter if (parent) { 161559751Speter error = linker_file_add_dependancy(parent, lfdep); 161659751Speter if (error) 161759751Speter break; 161859751Speter } 161983321Speter if (lfpp) 162083321Speter *lfpp = lfdep; 162159751Speter } while(0); 162259751Speterout: 162359751Speter if (pathname) 162459751Speter free(pathname, M_LINKER); 162559751Speter return error; 162659751Speter} 162759751Speter 162859751Speter/* 162959751Speter * This routine is responsible for finding dependencies of userland 163059751Speter * initiated kldload(2)'s of files. 163159751Speter */ 163259751Speterint 163359751Speterlinker_load_dependancies(linker_file_t lf) 163459751Speter{ 163559751Speter linker_file_t lfdep; 163678161Speter struct mod_metadata **start, **stop, **mdp, **nmdp; 163759751Speter struct mod_metadata *mp, *nmp; 163883321Speter struct mod_depend *verinfo; 163959751Speter modlist_t mod; 164078501Sdes const char *modname, *nmodname; 164178161Speter int ver, error = 0, count; 164259751Speter 164359751Speter /* 164459751Speter * All files are dependant on /kernel. 164559751Speter */ 164659751Speter if (linker_kernel_file) { 164759751Speter linker_kernel_file->refs++; 164859751Speter error = linker_file_add_dependancy(lf, linker_kernel_file); 164959751Speter if (error) 165059751Speter return error; 165159751Speter } 165259751Speter 165378161Speter if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, &count) != 0) 165474641Sbp return 0; 165578161Speter for (mdp = start; mdp < stop; mdp++) { 165678161Speter mp = linker_reloc_ptr(lf, *mdp); 165774641Sbp if (mp->md_type != MDT_VERSION) 165874641Sbp continue; 165974642Sbp linker_mdt_version(lf, mp, &modname, &ver); 166074642Sbp mod = modlist_lookup(modname, ver); 166174642Sbp if (mod != NULL) { 166274642Sbp printf("interface %s.%d already present in the KLD '%s'!\n", 166374642Sbp modname, ver, mod->container->filename); 166474641Sbp return EEXIST; 166559751Speter } 166659751Speter } 166774642Sbp 166878161Speter for (mdp = start; mdp < stop; mdp++) { 166978161Speter mp = linker_reloc_ptr(lf, *mdp); 167074641Sbp if (mp->md_type != MDT_DEPEND) 167174641Sbp continue; 167283321Speter linker_mdt_depend(lf, mp, &modname, &verinfo); 167374641Sbp nmodname = NULL; 167478161Speter for (nmdp = start; nmdp < stop; nmdp++) { 167578161Speter nmp = linker_reloc_ptr(lf, *nmdp); 167674641Sbp if (nmp->md_type != MDT_VERSION) 167759751Speter continue; 167874641Sbp nmodname = linker_reloc_ptr(lf, nmp->md_cval); 167974641Sbp if (strcmp(modname, nmodname) == 0) 168059751Speter break; 168159751Speter } 168278161Speter if (nmdp < stop) /* early exit, it's a self reference */ 168374641Sbp continue; 168483321Speter mod = modlist_lookup2(modname, verinfo); 168574641Sbp if (mod) { /* woohoo, it's loaded already */ 168674641Sbp lfdep = mod->container; 168774641Sbp lfdep->refs++; 168874641Sbp error = linker_file_add_dependancy(lf, lfdep); 168974641Sbp if (error) 169074641Sbp break; 169174641Sbp continue; 169274641Sbp } 169383321Speter error = linker_load_module(NULL, modname, lf, verinfo, NULL); 169474641Sbp if (error) { 169574641Sbp printf("KLD %s: depends on %s - not available\n", 169674641Sbp lf->filename, modname); 169774641Sbp break; 169874641Sbp } 169974641Sbp } 170059751Speter 170174641Sbp if (error) 170274641Sbp return error; 170378161Speter linker_addmodules(lf, start, stop, 0); 170459751Speter return error; 170559751Speter} 1706