kern_linker.c revision 159800
125537Sdfr/*- 259603Sdfr * Copyright (c) 1997-2000 Doug Rabson 325537Sdfr * All rights reserved. 425537Sdfr * 525537Sdfr * Redistribution and use in source and binary forms, with or without 625537Sdfr * modification, are permitted provided that the following conditions 725537Sdfr * are met: 825537Sdfr * 1. Redistributions of source code must retain the above copyright 925537Sdfr * notice, this list of conditions and the following disclaimer. 1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1125537Sdfr * notice, this list of conditions and the following disclaimer in the 1225537Sdfr * documentation and/or other materials provided with the distribution. 1325537Sdfr * 1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1725537Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2425537Sdfr * SUCH DAMAGE. 2525537Sdfr */ 2625537Sdfr 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_linker.c 159800 2006-06-20 20:41:15Z jhb $"); 29116182Sobrien 3040159Speter#include "opt_ddb.h" 31157144Sjkoshy#include "opt_hwpmc_hooks.h" 32107089Srwatson#include "opt_mac.h" 3340159Speter 3425537Sdfr#include <sys/param.h> 3525537Sdfr#include <sys/kernel.h> 3625537Sdfr#include <sys/systm.h> 3725537Sdfr#include <sys/malloc.h> 3825537Sdfr#include <sys/sysproto.h> 3925537Sdfr#include <sys/sysent.h> 4025537Sdfr#include <sys/proc.h> 4125537Sdfr#include <sys/lock.h> 4282749Sdillon#include <sys/mutex.h> 4392547Sarr#include <sys/sx.h> 44107089Srwatson#include <sys/mac.h> 4525537Sdfr#include <sys/module.h> 4625537Sdfr#include <sys/linker.h> 4740159Speter#include <sys/fcntl.h> 4840159Speter#include <sys/libkern.h> 4940159Speter#include <sys/namei.h> 5040159Speter#include <sys/vnode.h> 51159588Sjhb#include <sys/syscallsubr.h> 5240159Speter#include <sys/sysctl.h> 5325537Sdfr 5459603Sdfr#include "linker_if.h" 5559603Sdfr 56157144Sjkoshy#ifdef HWPMC_HOOKS 57157144Sjkoshy#include <sys/pmckern.h> 58157144Sjkoshy#endif 59157144Sjkoshy 6040961Speter#ifdef KLD_DEBUG 6140961Speterint kld_debug = 0; 6240961Speter#endif 6340961Speter 6491040Sarr/* 6591040Sarr * static char *linker_search_path(const char *name, struct mod_depend 6691040Sarr * *verinfo); 6791040Sarr */ 6891040Sarrstatic const char *linker_basename(const char *path); 6959751Speter 70159800Sjhb/* 71159800Sjhb * Find a currently loaded file given its filename. 72159800Sjhb */ 73159800Sjhbstatic linker_file_t linker_find_file_by_name(const char* _filename); 74159800Sjhb 75159800Sjhb/* 76159800Sjhb * Find a currently loaded file given its file id. 77159800Sjhb */ 78159800Sjhbstatic linker_file_t linker_find_file_by_id(int _fileid); 79159800Sjhb 8078161Speter/* Metadata from the static kernel */ 8178161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 8278161Speter 8359751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 8459751Speter 8540906Speterlinker_file_t linker_kernel_file; 8631324Sbde 8798452Sarrstatic struct mtx kld_mtx; /* kernel linker mutex */ 8898452Sarr 8925537Sdfrstatic linker_class_list_t classes; 9050068Sgrogstatic linker_file_list_t linker_files; 9125537Sdfrstatic int next_file_id = 1; 9298452Sarrstatic int linker_no_more_classes = 0; 9325537Sdfr 9486553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 9591040Sarr linker_file_t lftmp; \ 9686553Sarr \ 9786553Sarrretry: \ 9898452Sarr mtx_lock(&kld_mtx); \ 9991040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 10091040Sarr if (next_file_id == lftmp->id) { \ 10191040Sarr next_file_id++; \ 10298452Sarr mtx_unlock(&kld_mtx); \ 10391040Sarr goto retry; \ 10491040Sarr } \ 10591040Sarr } \ 10691040Sarr (a) = next_file_id; \ 10798452Sarr mtx_unlock(&kld_mtx); /* Hold for safe read of id variable */ \ 10886553Sarr} while(0) 10986553Sarr 11086553Sarr 11159751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 11260938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 11359751Speterstruct modlist { 11491040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 11591040Sarr linker_file_t container; 11691040Sarr const char *name; 11791040Sarr int version; 11859751Speter}; 11991040Sarrtypedef struct modlist *modlist_t; 12091040Sarrstatic modlisthead_t found_modules; 12159751Speter 122159796Sjhbstatic int linker_file_add_dependency(linker_file_t file, 123159796Sjhb linker_file_t dep); 124159796Sjhbstatic int linker_load_module(const char *kldname, 125159796Sjhb const char *modname, struct linker_file *parent, 126159796Sjhb struct mod_depend *verinfo, struct linker_file **lfpp); 127159796Sjhbstatic modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); 12894321Sbrian 12959603Sdfrstatic char * 13059603Sdfrlinker_strdup(const char *str) 13159603Sdfr{ 13291040Sarr char *result; 13359603Sdfr 134111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 13591040Sarr strcpy(result, str); 13691040Sarr return (result); 13759603Sdfr} 13859603Sdfr 13925537Sdfrstatic void 14091040Sarrlinker_init(void *arg) 14125537Sdfr{ 14291040Sarr 14398452Sarr mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF); 14491040Sarr TAILQ_INIT(&classes); 14591040Sarr TAILQ_INIT(&linker_files); 14625537Sdfr} 14725537Sdfr 14891040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0) 14925537Sdfr 15098452Sarrstatic void 15198452Sarrlinker_stop_class_add(void *arg) 15298452Sarr{ 15398452Sarr 15498452Sarr linker_no_more_classes = 1; 15598452Sarr} 15698452Sarr 15798452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL) 15898452Sarr 15925537Sdfrint 16059603Sdfrlinker_add_class(linker_class_t lc) 16125537Sdfr{ 16291040Sarr 16398452Sarr /* 164144443Sjhb * We disallow any class registration past SI_ORDER_ANY 165144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 166144443Sjhb * ops from being freed. 16798452Sarr */ 16898452Sarr if (linker_no_more_classes == 1) 16998452Sarr return (EPERM); 17091040Sarr kobj_class_compile((kobj_class_t) lc); 171144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 17291040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 17391040Sarr return (0); 17425537Sdfr} 17525537Sdfr 17625537Sdfrstatic void 17725537Sdfrlinker_file_sysinit(linker_file_t lf) 17825537Sdfr{ 17991040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 18025537Sdfr 18191040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 18291040Sarr lf->filename)); 18325537Sdfr 18491040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 18591040Sarr return; 18691040Sarr /* 18791040Sarr * Perform a bubble sort of the system initialization objects by 18891040Sarr * their subsystem (primary key) and order (secondary key). 18991040Sarr * 19091040Sarr * Since some things care about execution order, this is the operation 19191040Sarr * which ensures continued function. 19291040Sarr */ 19391040Sarr for (sipp = start; sipp < stop; sipp++) { 19491040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 19591040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 19691040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 19791040Sarr (*sipp)->order <= (*xipp)->order)) 19891040Sarr continue; /* skip */ 19991040Sarr save = *sipp; 20091040Sarr *sipp = *xipp; 20191040Sarr *xipp = save; 20291040Sarr } 20325537Sdfr } 20425537Sdfr 20591040Sarr /* 20691040Sarr * Traverse the (now) ordered list of system initialization tasks. 20791040Sarr * Perform each task, and continue on to the next task. 20891040Sarr */ 20991040Sarr for (sipp = start; sipp < stop; sipp++) { 21091040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 21191040Sarr continue; /* skip dummy task(s) */ 21225537Sdfr 21391040Sarr /* Call function */ 21491040Sarr (*((*sipp)->func)) ((*sipp)->udata); 21591040Sarr } 21625537Sdfr} 21725537Sdfr 21841055Speterstatic void 21941055Speterlinker_file_sysuninit(linker_file_t lf) 22041055Speter{ 22191040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 22241055Speter 22391040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 22491040Sarr lf->filename)); 22541055Speter 22691068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 22791040Sarr NULL) != 0) 22891040Sarr return; 22941055Speter 23091040Sarr /* 23191040Sarr * Perform a reverse bubble sort of the system initialization objects 23291040Sarr * by their subsystem (primary key) and order (secondary key). 23391040Sarr * 23491040Sarr * Since some things care about execution order, this is the operation 23591040Sarr * which ensures continued function. 23691040Sarr */ 23791040Sarr for (sipp = start; sipp < stop; sipp++) { 23891040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 23991040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 24091040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 24191040Sarr (*sipp)->order >= (*xipp)->order)) 24291040Sarr continue; /* skip */ 24391040Sarr save = *sipp; 24491040Sarr *sipp = *xipp; 24591040Sarr *xipp = save; 24691040Sarr } 24741055Speter } 24841055Speter 24991040Sarr /* 25091040Sarr * Traverse the (now) ordered list of system initialization tasks. 25191040Sarr * Perform each task, and continue on to the next task. 25291040Sarr */ 25391040Sarr for (sipp = start; sipp < stop; sipp++) { 25491040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 25591040Sarr continue; /* skip dummy task(s) */ 25641055Speter 25791040Sarr /* Call function */ 25891040Sarr (*((*sipp)->func)) ((*sipp)->udata); 25991040Sarr } 26041055Speter} 26141055Speter 26244078Sdfrstatic void 26344078Sdfrlinker_file_register_sysctls(linker_file_t lf) 26444078Sdfr{ 26591040Sarr struct sysctl_oid **start, **stop, **oidp; 26644078Sdfr 26791040Sarr KLD_DPF(FILE, 26891040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 26991040Sarr lf->filename)); 27044078Sdfr 27191040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 27291040Sarr return; 27344078Sdfr 27491040Sarr for (oidp = start; oidp < stop; oidp++) 27591040Sarr sysctl_register_oid(*oidp); 27644078Sdfr} 27744078Sdfr 27844078Sdfrstatic void 27944078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 28044078Sdfr{ 28191040Sarr struct sysctl_oid **start, **stop, **oidp; 28244078Sdfr 28391040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 28491040Sarr " for %s\n", lf->filename)); 28544078Sdfr 28691040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 28791040Sarr return; 28844078Sdfr 28991040Sarr for (oidp = start; oidp < stop; oidp++) 29091040Sarr sysctl_unregister_oid(*oidp); 29144078Sdfr} 29244078Sdfr 29359751Speterstatic int 29459751Speterlinker_file_register_modules(linker_file_t lf) 29559751Speter{ 29691040Sarr struct mod_metadata **start, **stop, **mdp; 29791040Sarr const moduledata_t *moddata; 298146733Spjd int first_error, error; 29959751Speter 30091040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 30191040Sarr " in %s\n", lf->filename)); 30259751Speter 30391068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 30491040Sarr &stop, 0) != 0) { 30591040Sarr /* 30691040Sarr * This fallback should be unnecessary, but if we get booted 30791040Sarr * from boot2 instead of loader and we are missing our 30891040Sarr * metadata then we have to try the best we can. 30991040Sarr */ 31091040Sarr if (lf == linker_kernel_file) { 31191040Sarr start = SET_BEGIN(modmetadata_set); 31291040Sarr stop = SET_LIMIT(modmetadata_set); 31391040Sarr } else 31491040Sarr return (0); 31578161Speter } 316146733Spjd first_error = 0; 31791040Sarr for (mdp = start; mdp < stop; mdp++) { 31891040Sarr if ((*mdp)->md_type != MDT_MODULE) 31991040Sarr continue; 32091040Sarr moddata = (*mdp)->md_data; 32191040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 32291040Sarr moddata->name, lf->filename)); 32391040Sarr error = module_register(moddata, lf); 324146730Spjd if (error) { 32591068Sarr printf("Module %s failed to register: %d\n", 32691040Sarr moddata->name, error); 327146733Spjd if (first_error == 0) 328146733Spjd first_error = error; 329146730Spjd } 33059751Speter } 331146733Spjd return (first_error); 33259751Speter} 33359751Speter 33459751Speterstatic void 33559751Speterlinker_init_kernel_modules(void) 33659751Speter{ 33791040Sarr 33891040Sarr linker_file_register_modules(linker_kernel_file); 33959751Speter} 34059751Speter 34191040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) 34259751Speter 343101241Smuxstatic int 34491040Sarrlinker_load_file(const char *filename, linker_file_t *result) 34525537Sdfr{ 34691040Sarr linker_class_t lc; 34791040Sarr linker_file_t lf; 348159585Sjhb int foundfile, error; 34925537Sdfr 35091040Sarr /* Refuse to load modules if securelevel raised */ 35191040Sarr if (securelevel > 0) 35291040Sarr return (EPERM); 35362261Sarchie 35491040Sarr lf = linker_find_file_by_name(filename); 35591040Sarr if (lf) { 35691040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 35791040Sarr " incrementing refs\n", filename)); 35891040Sarr *result = lf; 35991040Sarr lf->refs++; 360159585Sjhb return (0); 36191040Sarr } 36291040Sarr foundfile = 0; 363159585Sjhb error = 0; 36498452Sarr 36598452Sarr /* 36698452Sarr * We do not need to protect (lock) classes here because there is 36798452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 36898452Sarr * and there is no class deregistration mechanism at this time. 36998452Sarr */ 37091040Sarr TAILQ_FOREACH(lc, &classes, link) { 37191040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 37291040Sarr filename)); 37391040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 37491040Sarr /* 37591040Sarr * If we got something other than ENOENT, then it exists but 37691040Sarr * we cannot load it for some other reason. 37791040Sarr */ 37891040Sarr if (error != ENOENT) 37991040Sarr foundfile = 1; 38091040Sarr if (lf) { 381146730Spjd error = linker_file_register_modules(lf); 382146730Spjd if (error == EEXIST) { 383146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 384159585Sjhb return (error); 385146730Spjd } 38691040Sarr linker_file_register_sysctls(lf); 38791040Sarr linker_file_sysinit(lf); 38891040Sarr lf->flags |= LINKER_FILE_LINKED; 38991040Sarr *result = lf; 390159585Sjhb return (0); 39191040Sarr } 39291040Sarr } 39342755Speter /* 39491040Sarr * Less than ideal, but tells the user whether it failed to load or 39591040Sarr * the module was not found. 39642755Speter */ 397105337Ssam if (foundfile) { 398105337Ssam /* 399105337Ssam * Format not recognized or otherwise unloadable. 400105337Ssam * When loading a module that is statically built into 401105337Ssam * the kernel EEXIST percolates back up as the return 402105337Ssam * value. Preserve this so that apps like sysinstall 403105337Ssam * can recognize this special case and not post bogus 404105337Ssam * dialog boxes. 405105337Ssam */ 406105337Ssam if (error != EEXIST) 407105337Ssam error = ENOEXEC; 408105337Ssam } else 40991068Sarr error = ENOENT; /* Nothing found */ 41091040Sarr return (error); 41125537Sdfr} 41225537Sdfr 41378413Sbrianint 41494321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 41594321Sbrian linker_file_t *result) 41678413Sbrian{ 41794321Sbrian modlist_t mod; 41894321Sbrian 41994321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 42094321Sbrian *result = mod->container; 42194321Sbrian (*result)->refs++; 42294321Sbrian return (0); 42394321Sbrian } 42494321Sbrian 42594321Sbrian return (linker_load_module(NULL, modname, NULL, verinfo, result)); 42678413Sbrian} 42778413Sbrian 428159800Sjhbstatic linker_file_t 42991040Sarrlinker_find_file_by_name(const char *filename) 43025537Sdfr{ 431159585Sjhb linker_file_t lf; 43291040Sarr char *koname; 43325537Sdfr 434111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 43591040Sarr sprintf(koname, "%s.ko", filename); 43640861Speter 43798452Sarr mtx_lock(&kld_mtx); 43891040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 43992032Sdwmalone if (strcmp(lf->filename, koname) == 0) 44091040Sarr break; 44192032Sdwmalone if (strcmp(lf->filename, filename) == 0) 44291040Sarr break; 44391040Sarr } 44498452Sarr mtx_unlock(&kld_mtx); 445159585Sjhb free(koname, M_LINKER); 44691040Sarr return (lf); 44725537Sdfr} 44825537Sdfr 449159800Sjhbstatic linker_file_t 45025537Sdfrlinker_find_file_by_id(int fileid) 45125537Sdfr{ 452159585Sjhb linker_file_t lf; 45398452Sarr 45498452Sarr mtx_lock(&kld_mtx); 45591040Sarr TAILQ_FOREACH(lf, &linker_files, link) 45691040Sarr if (lf->id == fileid) 45791040Sarr break; 45898452Sarr mtx_unlock(&kld_mtx); 45991040Sarr return (lf); 46025537Sdfr} 46125537Sdfr 462159797Sjhbint 463159797Sjhblinker_file_foreach(linker_predicate_t *predicate, void *context) 464159797Sjhb{ 465159797Sjhb linker_file_t lf; 466159797Sjhb int retval = 0; 467159797Sjhb 468159797Sjhb mtx_lock(&Giant); 469159797Sjhb TAILQ_FOREACH(lf, &linker_files, link) { 470159797Sjhb retval = predicate(lf, context); 471159797Sjhb if (retval != 0) 472159797Sjhb break; 473159797Sjhb } 474159797Sjhb mtx_unlock(&Giant); 475159797Sjhb return (retval); 476159797Sjhb} 477159797Sjhb 47825537Sdfrlinker_file_t 47991040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 48025537Sdfr{ 48191040Sarr linker_file_t lf; 48291040Sarr const char *filename; 48325537Sdfr 48491040Sarr filename = linker_basename(pathname); 48540159Speter 48691040Sarr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 487111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 48891040Sarr if (lf == NULL) 489159585Sjhb return (NULL); 49091040Sarr lf->refs = 1; 49191040Sarr lf->userrefs = 0; 49291040Sarr lf->flags = 0; 49391040Sarr lf->filename = linker_strdup(filename); 49491040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 49591040Sarr lf->ndeps = 0; 49691040Sarr lf->deps = NULL; 49791040Sarr STAILQ_INIT(&lf->common); 49891040Sarr TAILQ_INIT(&lf->modules); 49998452Sarr mtx_lock(&kld_mtx); 50091040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 50198452Sarr mtx_unlock(&kld_mtx); 50291040Sarr return (lf); 50325537Sdfr} 50425537Sdfr 50525537Sdfrint 506132117Sphklinker_file_unload(linker_file_t file, int flags) 50725537Sdfr{ 50891040Sarr module_t mod, next; 50991040Sarr modlist_t ml, nextml; 51091040Sarr struct common_symbol *cp; 51191040Sarr int error, i; 51225537Sdfr 51391040Sarr /* Refuse to unload modules if securelevel raised. */ 51491040Sarr if (securelevel > 0) 51591040Sarr return (EPERM); 516107089Srwatson#ifdef MAC 517107089Srwatson error = mac_check_kld_unload(curthread->td_ucred); 518107089Srwatson if (error) 519107089Srwatson return (error); 520107089Srwatson#endif 52125537Sdfr 52291040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 52391040Sarr 524159584Sjhb /* Easy case of just dropping a reference. */ 525159584Sjhb if (file->refs > 1) { 526159584Sjhb file->refs--; 527159584Sjhb return (0); 528159584Sjhb } 529159584Sjhb 530159584Sjhb KLD_DPF(FILE, ("linker_file_unload: file is unloading," 531159584Sjhb " informing modules\n")); 532159584Sjhb 533159584Sjhb /* 534159584Sjhb * Inform any modules associated with this file. 535159584Sjhb */ 536159584Sjhb MOD_XLOCK; 537159584Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 538159584Sjhb next = module_getfnext(mod); 539159584Sjhb MOD_XUNLOCK; 540159584Sjhb 54191040Sarr /* 542159584Sjhb * Give the module a chance to veto the unload. 54391040Sarr */ 544159584Sjhb if ((error = module_unload(mod, flags)) != 0) { 545159584Sjhb KLD_DPF(FILE, ("linker_file_unload: module %p" 546159584Sjhb " vetoes unload\n", mod)); 547159584Sjhb return (error); 548159584Sjhb } 54992547Sarr MOD_XLOCK; 550159584Sjhb module_release(mod); 551159584Sjhb } 552159584Sjhb MOD_XUNLOCK; 55391040Sarr 554159586Sjhb TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml) { 555128057Speadar if (ml->container == file) { 55691040Sarr TAILQ_REMOVE(&found_modules, ml, link); 557128057Speadar free(ml, M_LINKER); 558128057Speadar } 55991040Sarr } 56025537Sdfr 56191040Sarr /* 56291040Sarr * Don't try to run SYSUNINITs if we are unloaded due to a 56391040Sarr * link error. 56491040Sarr */ 56591040Sarr if (file->flags & LINKER_FILE_LINKED) { 56691040Sarr linker_file_sysuninit(file); 56791040Sarr linker_file_unregister_sysctls(file); 56825537Sdfr } 56998452Sarr mtx_lock(&kld_mtx); 57091040Sarr TAILQ_REMOVE(&linker_files, file, link); 57198452Sarr mtx_unlock(&kld_mtx); 57225537Sdfr 57391040Sarr if (file->deps) { 57491040Sarr for (i = 0; i < file->ndeps; i++) 575132117Sphk linker_file_unload(file->deps[i], flags); 57691040Sarr free(file->deps, M_LINKER); 57791040Sarr file->deps = NULL; 57859751Speter } 57991040Sarr for (cp = STAILQ_FIRST(&file->common); cp; 58091068Sarr cp = STAILQ_FIRST(&file->common)) { 58191040Sarr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 58291040Sarr free(cp, M_LINKER); 58391040Sarr } 58459751Speter 58591040Sarr LINKER_UNLOAD(file); 58691040Sarr if (file->filename) { 58791040Sarr free(file->filename, M_LINKER); 58891040Sarr file->filename = NULL; 58991040Sarr } 59091040Sarr kobj_delete((kobj_t) file, M_LINKER); 591159584Sjhb return (0); 59225537Sdfr} 59325537Sdfr 594159796Sjhbstatic int 59586469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 59625537Sdfr{ 59791040Sarr linker_file_t *newdeps; 59825537Sdfr 59991040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 600111119Simp M_LINKER, M_WAITOK | M_ZERO); 60191040Sarr if (newdeps == NULL) 60291040Sarr return (ENOMEM); 60325537Sdfr 60491040Sarr if (file->deps) { 60591040Sarr bcopy(file->deps, newdeps, 60691040Sarr file->ndeps * sizeof(linker_file_t *)); 60791040Sarr free(file->deps, M_LINKER); 60891040Sarr } 60991040Sarr file->deps = newdeps; 61091040Sarr file->deps[file->ndeps] = dep; 61191040Sarr file->ndeps++; 61291040Sarr return (0); 61325537Sdfr} 61425537Sdfr 61578161Speter/* 61691040Sarr * Locate a linker set and its contents. This is a helper function to avoid 61791040Sarr * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** 61878161Speter */ 61978161Speterint 62078161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 62191040Sarr void *firstp, void *lastp, int *countp) 62278161Speter{ 62378161Speter 62491040Sarr return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 62578161Speter} 62678161Speter 62725537Sdfrcaddr_t 62891040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 62925537Sdfr{ 63091040Sarr c_linker_sym_t sym; 63191040Sarr linker_symval_t symval; 63291040Sarr caddr_t address; 63391040Sarr size_t common_size = 0; 63492032Sdwmalone int i; 63525537Sdfr 636109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 63791040Sarr file, name, deps)); 63825537Sdfr 63991040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 64091040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 64191040Sarr if (symval.value == 0) 64291040Sarr /* 64391040Sarr * For commons, first look them up in the 64491040Sarr * dependencies and only allocate space if not found 64591040Sarr * there. 64691040Sarr */ 64791040Sarr common_size = symval.size; 64891040Sarr else { 64991040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 650109605Sjake ".value=%p\n", symval.value)); 65191040Sarr return (symval.value); 65291040Sarr } 65340159Speter } 65491040Sarr if (deps) { 65591040Sarr for (i = 0; i < file->ndeps; i++) { 65691040Sarr address = linker_file_lookup_symbol(file->deps[i], 65791040Sarr name, 0); 65891040Sarr if (address) { 65991040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 660109605Sjake " deps value=%p\n", address)); 66191040Sarr return (address); 66291040Sarr } 66391040Sarr } 66425537Sdfr } 66591040Sarr if (common_size > 0) { 66691040Sarr /* 66791040Sarr * This is a common symbol which was not found in the 66891040Sarr * dependencies. We maintain a simple common symbol table in 66991040Sarr * the file object. 67091040Sarr */ 67191040Sarr struct common_symbol *cp; 67242849Speter 67391040Sarr STAILQ_FOREACH(cp, &file->common, link) { 67492032Sdwmalone if (strcmp(cp->name, name) == 0) { 67591040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 676109605Sjake " old common value=%p\n", cp->address)); 67791040Sarr return (cp->address); 67891040Sarr } 67991040Sarr } 68091040Sarr /* 68191040Sarr * Round the symbol size up to align. 68291040Sarr */ 68391040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 68491040Sarr cp = malloc(sizeof(struct common_symbol) 68591040Sarr + common_size + strlen(name) + 1, M_LINKER, 686111119Simp M_WAITOK | M_ZERO); 68791040Sarr cp->address = (caddr_t)(cp + 1); 68891040Sarr cp->name = cp->address + common_size; 68991040Sarr strcpy(cp->name, name); 69091040Sarr bzero(cp->address, common_size); 69191040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 69225537Sdfr 69391040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 694109605Sjake " value=%p\n", cp->address)); 69591040Sarr return (cp->address); 69640159Speter } 69791040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 69891040Sarr return (0); 69925537Sdfr} 70025537Sdfr 70140159Speter#ifdef DDB 70225537Sdfr/* 70391040Sarr * DDB Helpers. DDB has to look across multiple files with their own symbol 70491040Sarr * tables and string tables. 70591040Sarr * 70691040Sarr * Note that we do not obey list locking protocols here. We really don't need 70791040Sarr * DDB to hang because somebody's got the lock held. We'll take the chance 70891040Sarr * that the files list is inconsistant instead. 70940159Speter */ 71040159Speter 71140159Speterint 71243309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 71340159Speter{ 71491040Sarr linker_file_t lf; 71540159Speter 71691040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 71791040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 71891040Sarr return (0); 71991040Sarr } 72091040Sarr return (ENOENT); 72140159Speter} 72240159Speter 72340159Speterint 72443309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 72540159Speter{ 72691040Sarr linker_file_t lf; 72791040Sarr c_linker_sym_t best, es; 72891040Sarr u_long diff, bestdiff, off; 72940159Speter 73091040Sarr best = 0; 73191040Sarr off = (uintptr_t)value; 73291040Sarr bestdiff = off; 73391040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 73491040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 73591040Sarr continue; 73691040Sarr if (es != 0 && diff < bestdiff) { 73791040Sarr best = es; 73891040Sarr bestdiff = diff; 73991040Sarr } 74091040Sarr if (bestdiff == 0) 74191040Sarr break; 74240159Speter } 74391040Sarr if (best) { 74491040Sarr *sym = best; 74591040Sarr *diffp = bestdiff; 74691040Sarr return (0); 74791040Sarr } else { 74891040Sarr *sym = 0; 74991040Sarr *diffp = off; 75091040Sarr return (ENOENT); 75191040Sarr } 75240159Speter} 75340159Speter 75440159Speterint 75543309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 75640159Speter{ 75791040Sarr linker_file_t lf; 75840159Speter 75991040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 76091040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 76191040Sarr return (0); 76291040Sarr } 76391040Sarr return (ENOENT); 76440159Speter} 76540159Speter#endif 76640159Speter 76740159Speter/* 76825537Sdfr * Syscalls. 76925537Sdfr */ 77082749Sdillon/* 77182749Sdillon * MPSAFE 77282749Sdillon */ 77325537Sdfrint 774159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 77525537Sdfr{ 776157144Sjkoshy#ifdef HWPMC_HOOKS 777157144Sjkoshy struct pmckern_map_in pkm; 778157144Sjkoshy#endif 779159588Sjhb const char *kldname, *modname; 78091040Sarr linker_file_t lf; 781159588Sjhb int error; 78225537Sdfr 78393159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 784159588Sjhb return (error); 78593159Sarr 78693593Sjhb if ((error = suser(td)) != 0) 787159588Sjhb return (error); 78825537Sdfr 78991040Sarr /* 790159588Sjhb * If file does not contain qualified name or any dot in it 79191040Sarr * (kldname.ko, or kldname.ver.ko) treat it as interface 79291040Sarr * name. 79391040Sarr */ 794159588Sjhb if (index(file, '/') || index(file, '.')) { 795159588Sjhb kldname = file; 79691040Sarr modname = NULL; 79791040Sarr } else { 79891040Sarr kldname = NULL; 799159588Sjhb modname = file; 80091040Sarr } 801159588Sjhb 802159588Sjhb mtx_lock(&Giant); 80391040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 80491040Sarr if (error) 805159588Sjhb goto unlock; 80642316Smsmith 807157144Sjkoshy#ifdef HWPMC_HOOKS 808157144Sjkoshy pkm.pm_file = lf->filename; 809157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 810157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 811157144Sjkoshy#endif 81291040Sarr lf->userrefs++; 813159588Sjhb if (fileid != NULL) 814159588Sjhb *fileid = lf->id; 815159588Sjhbunlock: 81691040Sarr mtx_unlock(&Giant); 81791040Sarr return (error); 81825537Sdfr} 81925537Sdfr 820159588Sjhbint 821159588Sjhbkldload(struct thread *td, struct kldload_args *uap) 822159588Sjhb{ 823159588Sjhb char *pathname = NULL; 824159596Smarcel int error, fileid; 825159588Sjhb 826159588Sjhb td->td_retval[0] = -1; 827159588Sjhb 828159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 829159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 830159596Smarcel if (error == 0) { 831159596Smarcel error = kern_kldload(td, pathname, &fileid); 832159596Smarcel if (error == 0) 833159596Smarcel td->td_retval[0] = fileid; 834159596Smarcel } 835159588Sjhb free(pathname, M_TEMP); 836159588Sjhb return (error); 837159588Sjhb} 838159588Sjhb 83982749Sdillon/* 84082749Sdillon * MPSAFE 84182749Sdillon */ 842159588Sjhbint 843132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 84425537Sdfr{ 845157144Sjkoshy#ifdef HWPMC_HOOKS 846157144Sjkoshy struct pmckern_map_out pkm; 847157144Sjkoshy#endif 84891040Sarr linker_file_t lf; 84991040Sarr int error = 0; 85025537Sdfr 85193159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 852159588Sjhb return (error); 85393159Sarr 85493593Sjhb if ((error = suser(td)) != 0) 855159588Sjhb return (error); 85625537Sdfr 857159588Sjhb mtx_lock(&Giant); 858132117Sphk lf = linker_find_file_by_id(fileid); 85991040Sarr if (lf) { 86091040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 86191040Sarr if (lf->userrefs == 0) { 862132117Sphk /* 863132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 864132117Sphk */ 86591040Sarr printf("kldunload: attempt to unload file that was" 86691040Sarr " loaded by the kernel\n"); 867159588Sjhb error = EBUSY; 868159588Sjhb } else { 869157144Sjkoshy#ifdef HWPMC_HOOKS 870159588Sjhb /* Save data needed by hwpmc(4) before unloading. */ 871159588Sjhb pkm.pm_address = (uintptr_t) lf->address; 872159588Sjhb pkm.pm_size = lf->size; 873157144Sjkoshy#endif 874159588Sjhb lf->userrefs--; 875159588Sjhb error = linker_file_unload(lf, flags); 876159588Sjhb if (error) 877159588Sjhb lf->userrefs++; 878159588Sjhb } 87991040Sarr } else 88091040Sarr error = ENOENT; 881157144Sjkoshy 882157144Sjkoshy#ifdef HWPMC_HOOKS 883157144Sjkoshy if (error == 0) 884157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 885157144Sjkoshy#endif 88691068Sarr mtx_unlock(&Giant); 88791068Sarr return (error); 88825537Sdfr} 88925537Sdfr 89082749Sdillon/* 89182749Sdillon * MPSAFE 89282749Sdillon */ 89325537Sdfrint 894132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 895132117Sphk{ 896132117Sphk 897132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 898132117Sphk} 899132117Sphk 900132117Sphk/* 901132117Sphk * MPSAFE 902132117Sphk */ 903132117Sphkint 904132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 905132117Sphk{ 906132117Sphk 907132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 908132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 909132117Sphk return (EINVAL); 910132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 911132117Sphk} 912132117Sphk 913132117Sphk/* 914132117Sphk * MPSAFE 915132117Sphk */ 916132117Sphkint 91791040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 91825537Sdfr{ 91991040Sarr char *pathname; 92091040Sarr const char *filename; 92191040Sarr linker_file_t lf; 922159791Sjhb int error; 92325537Sdfr 924107089Srwatson#ifdef MAC 925107089Srwatson error = mac_check_kld_stat(td->td_ucred); 926107089Srwatson if (error) 927107089Srwatson return (error); 928107089Srwatson#endif 929107089Srwatson 93091040Sarr mtx_lock(&Giant); 93191040Sarr td->td_retval[0] = -1; 93282749Sdillon 933111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 934107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 93591040Sarr goto out; 93625537Sdfr 93791040Sarr filename = linker_basename(pathname); 93891040Sarr lf = linker_find_file_by_name(filename); 93991040Sarr if (lf) 94091040Sarr td->td_retval[0] = lf->id; 94191040Sarr else 94291040Sarr error = ENOENT; 94325537Sdfrout: 944159791Sjhb free(pathname, M_TEMP); 94591040Sarr mtx_unlock(&Giant); 94691040Sarr return (error); 94725537Sdfr} 94825537Sdfr 94982749Sdillon/* 95082749Sdillon * MPSAFE 95182749Sdillon */ 95225537Sdfrint 95391040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 95425537Sdfr{ 95591040Sarr linker_file_t lf; 95691040Sarr int error = 0; 95725537Sdfr 958107089Srwatson#ifdef MAC 959107089Srwatson error = mac_check_kld_stat(td->td_ucred); 960107089Srwatson if (error) 961107089Srwatson return (error); 962107089Srwatson#endif 963107089Srwatson 96491040Sarr mtx_lock(&Giant); 96582749Sdillon 966107849Salfred if (uap->fileid == 0) { 96798452Sarr mtx_lock(&kld_mtx); 96891040Sarr if (TAILQ_FIRST(&linker_files)) 96991040Sarr td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; 97091040Sarr else 97191040Sarr td->td_retval[0] = 0; 97298452Sarr mtx_unlock(&kld_mtx); 97391040Sarr goto out; 97491040Sarr } 975107849Salfred lf = linker_find_file_by_id(uap->fileid); 97691040Sarr if (lf) { 97791040Sarr if (TAILQ_NEXT(lf, link)) 97891040Sarr td->td_retval[0] = TAILQ_NEXT(lf, link)->id; 97991040Sarr else 98091040Sarr td->td_retval[0] = 0; 98191040Sarr } else 98291040Sarr error = ENOENT; 98382749Sdillonout: 98491040Sarr mtx_unlock(&Giant); 98591040Sarr return (error); 98625537Sdfr} 98725537Sdfr 98882749Sdillon/* 98982749Sdillon * MPSAFE 99082749Sdillon */ 99125537Sdfrint 99291040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 99325537Sdfr{ 994159587Sjhb struct kld_file_stat stat; 99591040Sarr linker_file_t lf; 996159587Sjhb int error, namelen; 99725537Sdfr 998159587Sjhb /* 999159587Sjhb * Check the version of the user's structure. 1000159587Sjhb */ 1001159587Sjhb error = copyin(uap->stat, &stat, sizeof(struct kld_file_stat)); 1002159587Sjhb if (error) 1003159587Sjhb return (error); 1004159587Sjhb if (stat.version != sizeof(struct kld_file_stat)) 1005159587Sjhb return (EINVAL); 1006159587Sjhb 1007107089Srwatson#ifdef MAC 1008107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1009107089Srwatson if (error) 1010107089Srwatson return (error); 1011107089Srwatson#endif 1012107089Srwatson 101391040Sarr mtx_lock(&Giant); 101482749Sdillon 1015107849Salfred lf = linker_find_file_by_id(uap->fileid); 101691040Sarr if (lf == NULL) { 1017159587Sjhb mtx_unlock(&Giant); 1018159587Sjhb return (ENOENT); 101991040Sarr } 102025537Sdfr 102191040Sarr namelen = strlen(lf->filename) + 1; 102291040Sarr if (namelen > MAXPATHLEN) 102391040Sarr namelen = MAXPATHLEN; 1024159587Sjhb bcopy(lf->filename, &stat.name[0], namelen); 1025159587Sjhb stat.refs = lf->refs; 1026159587Sjhb stat.id = lf->id; 1027159587Sjhb stat.address = lf->address; 1028159587Sjhb stat.size = lf->size; 1029159587Sjhb mtx_unlock(&Giant); 103025537Sdfr 103191040Sarr td->td_retval[0] = 0; 1032159587Sjhb 1033159587Sjhb return (copyout(&stat, uap->stat, sizeof(struct kld_file_stat))); 103425537Sdfr} 103525537Sdfr 103682749Sdillon/* 103782749Sdillon * MPSAFE 103882749Sdillon */ 103925537Sdfrint 104091040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 104125537Sdfr{ 104291040Sarr linker_file_t lf; 104391040Sarr module_t mp; 104491040Sarr int error = 0; 104525537Sdfr 1046107089Srwatson#ifdef MAC 1047107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1048107089Srwatson if (error) 1049107089Srwatson return (error); 1050107089Srwatson#endif 1051107089Srwatson 105291040Sarr mtx_lock(&Giant); 1053107849Salfred lf = linker_find_file_by_id(uap->fileid); 105491040Sarr if (lf) { 105592547Sarr MOD_SLOCK; 105691040Sarr mp = TAILQ_FIRST(&lf->modules); 105791040Sarr if (mp != NULL) 105891040Sarr td->td_retval[0] = module_getid(mp); 105991040Sarr else 106091040Sarr td->td_retval[0] = 0; 106192547Sarr MOD_SUNLOCK; 106291040Sarr } else 106391040Sarr error = ENOENT; 106491040Sarr mtx_unlock(&Giant); 106591040Sarr return (error); 106625537Sdfr} 106740159Speter 106882749Sdillon/* 106982749Sdillon * MPSAFE 107082749Sdillon */ 107141090Speterint 107283366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 107341090Speter{ 107491040Sarr char *symstr = NULL; 107591040Sarr c_linker_sym_t sym; 107691040Sarr linker_symval_t symval; 107791040Sarr linker_file_t lf; 107891040Sarr struct kld_sym_lookup lookup; 107991040Sarr int error = 0; 108041090Speter 1081107089Srwatson#ifdef MAC 1082107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1083107089Srwatson if (error) 1084107089Srwatson return (error); 1085107089Srwatson#endif 1086107089Srwatson 108791040Sarr mtx_lock(&Giant); 108882749Sdillon 1089107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 109091040Sarr goto out; 109191068Sarr if (lookup.version != sizeof(lookup) || 1092107849Salfred uap->cmd != KLDSYM_LOOKUP) { 109391040Sarr error = EINVAL; 109491040Sarr goto out; 109591040Sarr } 1096111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 109791040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 109891040Sarr goto out; 1099107849Salfred if (uap->fileid != 0) { 1100107849Salfred lf = linker_find_file_by_id(uap->fileid); 110191040Sarr if (lf == NULL) { 110291040Sarr error = ENOENT; 110391040Sarr goto out; 110491040Sarr } 110591040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 110691040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 110791040Sarr lookup.symvalue = (uintptr_t) symval.value; 110891040Sarr lookup.symsize = symval.size; 1109107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 111091040Sarr } else 111191040Sarr error = ENOENT; 111291040Sarr } else { 111398452Sarr mtx_lock(&kld_mtx); 111491040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 111591040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 111691040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 111791040Sarr lookup.symvalue = (uintptr_t)symval.value; 111891040Sarr lookup.symsize = symval.size; 1119107849Salfred error = copyout(&lookup, uap->data, 112091040Sarr sizeof(lookup)); 112191068Sarr break; 112291040Sarr } 112391040Sarr } 112498452Sarr mtx_unlock(&kld_mtx); 112591040Sarr if (lf == NULL) 112691040Sarr error = ENOENT; 112741090Speter } 112841090Speterout: 112991040Sarr if (symstr) 113091040Sarr free(symstr, M_TEMP); 113191040Sarr mtx_unlock(&Giant); 113291040Sarr return (error); 113341090Speter} 113441090Speter 113540159Speter/* 113640159Speter * Preloaded module support 113740159Speter */ 113840159Speter 113959751Speterstatic modlist_t 114074642Sbpmodlist_lookup(const char *name, int ver) 114159751Speter{ 114291040Sarr modlist_t mod; 114359751Speter 114491040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 114592032Sdwmalone if (strcmp(mod->name, name) == 0 && 114692032Sdwmalone (ver == 0 || mod->version == ver)) 114791040Sarr return (mod); 114891040Sarr } 114991040Sarr return (NULL); 115059751Speter} 115159751Speter 115274642Sbpstatic modlist_t 115383321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 115483321Speter{ 115591040Sarr modlist_t mod, bestmod; 115692032Sdwmalone int ver; 115783321Speter 115891040Sarr if (verinfo == NULL) 115991040Sarr return (modlist_lookup(name, 0)); 116091040Sarr bestmod = NULL; 1161159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 116292032Sdwmalone if (strcmp(mod->name, name) != 0) 116391040Sarr continue; 116491040Sarr ver = mod->version; 116591040Sarr if (ver == verinfo->md_ver_preferred) 116691040Sarr return (mod); 116791040Sarr if (ver >= verinfo->md_ver_minimum && 116891068Sarr ver <= verinfo->md_ver_maximum && 1169120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 117091040Sarr bestmod = mod; 117191040Sarr } 117291040Sarr return (bestmod); 117383321Speter} 117483321Speter 117583321Speterstatic modlist_t 117678501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 117774642Sbp{ 117891040Sarr modlist_t mod; 117974642Sbp 118092705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 118191040Sarr if (mod == NULL) 118291040Sarr panic("no memory for module list"); 118391040Sarr mod->container = container; 118491040Sarr mod->name = modname; 118591040Sarr mod->version = version; 118691040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 118791040Sarr return (mod); 118874642Sbp} 118974642Sbp 119040159Speterstatic void 119178161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 119291040Sarr struct mod_metadata **stop, int preload) 119374642Sbp{ 119491040Sarr struct mod_metadata *mp, **mdp; 119591040Sarr const char *modname; 119691040Sarr int ver; 119774642Sbp 119891040Sarr for (mdp = start; mdp < stop; mdp++) { 1199109605Sjake mp = *mdp; 120091040Sarr if (mp->md_type != MDT_VERSION) 120191040Sarr continue; 1202109605Sjake modname = mp->md_cval; 1203109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 120491040Sarr if (modlist_lookup(modname, ver) != NULL) { 120591040Sarr printf("module %s already present!\n", modname); 120691040Sarr /* XXX what can we do? this is a build error. :-( */ 120791040Sarr continue; 120891040Sarr } 120991040Sarr modlist_newmodule(modname, ver, lf); 121074642Sbp } 121174642Sbp} 121274642Sbp 121374642Sbpstatic void 121491040Sarrlinker_preload(void *arg) 121540159Speter{ 121691040Sarr caddr_t modptr; 121791040Sarr const char *modname, *nmodname; 121891040Sarr char *modtype; 121991040Sarr linker_file_t lf; 122091040Sarr linker_class_t lc; 122192032Sdwmalone int error; 122291040Sarr linker_file_list_t loaded_files; 122391040Sarr linker_file_list_t depended_files; 122491040Sarr struct mod_metadata *mp, *nmp; 122591040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 122691040Sarr struct mod_depend *verinfo; 122791040Sarr int nver; 122891040Sarr int resolves; 122991040Sarr modlist_t mod; 123091040Sarr struct sysinit **si_start, **si_stop; 123140159Speter 123291040Sarr TAILQ_INIT(&loaded_files); 123391040Sarr TAILQ_INIT(&depended_files); 123491040Sarr TAILQ_INIT(&found_modules); 123591040Sarr error = 0; 123659751Speter 123791040Sarr modptr = NULL; 123891040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 123991040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 124091040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 124191040Sarr if (modname == NULL) { 124291040Sarr printf("Preloaded module at %p does not have a" 124391040Sarr " name!\n", modptr); 124491040Sarr continue; 124591040Sarr } 124691040Sarr if (modtype == NULL) { 124791040Sarr printf("Preloaded module at %p does not have a type!\n", 124891040Sarr modptr); 124991040Sarr continue; 125091040Sarr } 1251131398Sjhb if (bootverbose) 1252131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1253131398Sjhb modptr); 125440159Speter lf = NULL; 125591040Sarr TAILQ_FOREACH(lc, &classes, link) { 125691040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1257134364Siedowse if (!error) 125891040Sarr break; 1259134364Siedowse lf = NULL; 126091040Sarr } 126191040Sarr if (lf) 126291040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 126340159Speter } 126440159Speter 126591040Sarr /* 126691040Sarr * First get a list of stuff in the kernel. 126791040Sarr */ 126891040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 126991040Sarr &stop, NULL) == 0) 127091040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 127159751Speter 127259751Speter /* 127391040Sarr * this is a once-off kinky bubble sort resolve relocation dependency 127491040Sarr * requirements 127559751Speter */ 127691040Sarrrestart: 127791040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 127891040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 127991040Sarr &stop, NULL); 128091040Sarr /* 128191040Sarr * First, look to see if we would successfully link with this 128291040Sarr * stuff. 128391040Sarr */ 128491040Sarr resolves = 1; /* unless we know otherwise */ 128591040Sarr if (!error) { 128691040Sarr for (mdp = start; mdp < stop; mdp++) { 1287109605Sjake mp = *mdp; 128891040Sarr if (mp->md_type != MDT_DEPEND) 128991040Sarr continue; 1290109605Sjake modname = mp->md_cval; 1291109605Sjake verinfo = mp->md_data; 129291040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1293109605Sjake nmp = *nmdp; 129491040Sarr if (nmp->md_type != MDT_VERSION) 129591040Sarr continue; 1296109605Sjake nmodname = nmp->md_cval; 129792032Sdwmalone if (strcmp(modname, nmodname) == 0) 129891040Sarr break; 129991040Sarr } 130091040Sarr if (nmdp < stop) /* it's a self reference */ 130191040Sarr continue; 130291040Sarr 130391040Sarr /* 130491040Sarr * ok, the module isn't here yet, we 130591040Sarr * are not finished 130691040Sarr */ 130791068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 130891040Sarr resolves = 0; 130991040Sarr } 131064143Speter } 131191040Sarr /* 131291040Sarr * OK, if we found our modules, we can link. So, "provide" 131391040Sarr * the modules inside and add it to the end of the link order 131491040Sarr * list. 131591040Sarr */ 131691040Sarr if (resolves) { 131791040Sarr if (!error) { 131891040Sarr for (mdp = start; mdp < stop; mdp++) { 1319109605Sjake mp = *mdp; 132091040Sarr if (mp->md_type != MDT_VERSION) 132191040Sarr continue; 1322109605Sjake modname = mp->md_cval; 1323109605Sjake nver = ((struct mod_version *) 1324109605Sjake mp->md_data)->mv_version; 132591040Sarr if (modlist_lookup(modname, 132691040Sarr nver) != NULL) { 132791040Sarr printf("module %s already" 132891040Sarr " present!\n", modname); 1329132117Sphk linker_file_unload(lf, 1330132117Sphk LINKER_UNLOAD_FORCE); 133191040Sarr TAILQ_REMOVE(&loaded_files, 133291040Sarr lf, loaded); 133391040Sarr /* we changed tailq next ptr */ 133491068Sarr goto restart; 133591040Sarr } 133691040Sarr modlist_newmodule(modname, nver, lf); 133791040Sarr } 133891040Sarr } 133991040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 134091040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 134191040Sarr /* 134291040Sarr * Since we provided modules, we need to restart the 134391040Sarr * sort so that the previous files that depend on us 134491040Sarr * have a chance. Also, we've busted the tailq next 134591040Sarr * pointer with the REMOVE. 134691040Sarr */ 134791040Sarr goto restart; 134859751Speter } 134959751Speter } 135091040Sarr 135159751Speter /* 135291040Sarr * At this point, we check to see what could not be resolved.. 135359751Speter */ 135491040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 135591040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1356132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 135791040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 135840159Speter } 135959751Speter 136078161Speter /* 136191040Sarr * We made it. Finish off the linking in the order we determined. 136278161Speter */ 136391040Sarr TAILQ_FOREACH(lf, &depended_files, loaded) { 136491040Sarr if (linker_kernel_file) { 136591040Sarr linker_kernel_file->refs++; 136691040Sarr error = linker_file_add_dependency(lf, 136791040Sarr linker_kernel_file); 136891040Sarr if (error) 136991040Sarr panic("cannot add dependency"); 137091040Sarr } 137191040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 137291040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 137391040Sarr &stop, NULL); 137491040Sarr if (!error) { 137591040Sarr for (mdp = start; mdp < stop; mdp++) { 1376109605Sjake mp = *mdp; 137791040Sarr if (mp->md_type != MDT_DEPEND) 137891040Sarr continue; 1379109605Sjake modname = mp->md_cval; 1380109605Sjake verinfo = mp->md_data; 138191040Sarr mod = modlist_lookup2(modname, verinfo); 1382151484Sjdp /* Don't count self-dependencies */ 1383151484Sjdp if (lf == mod->container) 1384151484Sjdp continue; 138591040Sarr mod->container->refs++; 138691040Sarr error = linker_file_add_dependency(lf, 138791040Sarr mod->container); 138891040Sarr if (error) 138991040Sarr panic("cannot add dependency"); 139091040Sarr } 139191040Sarr } 139291040Sarr /* 139391040Sarr * Now do relocation etc using the symbol search paths 139491040Sarr * established by the dependencies 139591040Sarr */ 139691040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 139791040Sarr if (error) { 139891040Sarr printf("KLD file %s - could not finalize loading\n", 139991040Sarr lf->filename); 1400132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 140191040Sarr continue; 140291040Sarr } 140391040Sarr linker_file_register_modules(lf); 140491040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 140591040Sarr &si_stop, NULL) == 0) 140691040Sarr sysinit_add(si_start, si_stop); 140791040Sarr linker_file_register_sysctls(lf); 140891040Sarr lf->flags |= LINKER_FILE_LINKED; 140959751Speter } 141091040Sarr /* woohoo! we made it! */ 141140159Speter} 141240159Speter 141391040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0) 141440159Speter 141540159Speter/* 141640159Speter * Search for a not-loaded module by name. 141791040Sarr * 141840159Speter * Modules may be found in the following locations: 141991040Sarr * 142091040Sarr * - preloaded (result is just the module name) - on disk (result is full path 142191040Sarr * to module) 142291040Sarr * 142391040Sarr * If the module name is qualified in any way (contains path, etc.) the we 142491040Sarr * simply return a copy of it. 142591040Sarr * 142640159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 142740159Speter * character as a separator to be consistent with the bootloader. 142840159Speter */ 142940159Speter 143083321Speterstatic char linker_hintfile[] = "linker.hints"; 1431111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 143240159Speter 143340159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 143491040Sarr sizeof(linker_path), "module load search path"); 143540159Speter 143677843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 143770417Speter 143859751Speterstatic char *linker_ext_list[] = { 143983321Speter "", 144059751Speter ".ko", 144159751Speter NULL 144259751Speter}; 144359751Speter 144483321Speter/* 144591040Sarr * Check if file actually exists either with or without extension listed in 144691040Sarr * the linker_ext_list. (probably should be generic for the rest of the 144791040Sarr * kernel) 144883321Speter */ 144959751Speterstatic char * 145091040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 145191040Sarr int namelen, struct vattr *vap) 145240159Speter{ 145391040Sarr struct nameidata nd; 145491040Sarr struct thread *td = curthread; /* XXX */ 145591040Sarr char *result, **cpp, *sep; 145691040Sarr int error, len, extlen, reclen, flags; 145791040Sarr enum vtype type; 145840159Speter 145991040Sarr extlen = 0; 146091040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 146191040Sarr len = strlen(*cpp); 146291040Sarr if (len > extlen) 146391040Sarr extlen = len; 146491040Sarr } 146591040Sarr extlen++; /* trailing '\0' */ 146691040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 146783321Speter 146891040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1469111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 147091040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 147191040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 147291040Sarr namelen, name, *cpp); 147391040Sarr /* 147491040Sarr * Attempt to open the file, and return the path if 147591040Sarr * we succeed and it's a regular file. 147691040Sarr */ 147791040Sarr NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); 147891040Sarr flags = FREAD; 1479118094Sphk error = vn_open(&nd, &flags, 0, -1); 148091040Sarr if (error == 0) { 148191040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 148291040Sarr type = nd.ni_vp->v_type; 148391040Sarr if (vap) 148491406Sjhb VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 148591040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 148691406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 148791040Sarr if (type == VREG) 148891040Sarr return (result); 148991040Sarr } 149083321Speter } 149191040Sarr free(result, M_LINKER); 149291040Sarr return (NULL); 149383321Speter} 149483321Speter 149591040Sarr#define INT_ALIGN(base, ptr) ptr = \ 149683321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 149783321Speter 149883321Speter/* 149991040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 150091040Sarr * version specification is available, then try to find the best KLD. 150183321Speter * Otherwise just find the latest one. 150283321Speter */ 150383321Speterstatic char * 150491040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 150591040Sarr int modnamelen, struct mod_depend *verinfo) 150683321Speter{ 150791040Sarr struct thread *td = curthread; /* XXX */ 150891406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 150991040Sarr struct nameidata nd; 151091040Sarr struct vattr vattr, mattr; 151191040Sarr u_char *hints = NULL; 151291040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 151391040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 151483321Speter 151591040Sarr result = NULL; 151691040Sarr bestver = found = 0; 151783321Speter 151891040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 151991040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 152091040Sarr strlen(sep) + 1; 1521111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 152291040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 152391040Sarr linker_hintfile); 152483321Speter 152591040Sarr NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); 152691040Sarr flags = FREAD; 1527118094Sphk error = vn_open(&nd, &flags, 0, -1); 152891040Sarr if (error) 152991040Sarr goto bad; 153091040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 153191040Sarr if (nd.ni_vp->v_type != VREG) 153291040Sarr goto bad; 153391040Sarr best = cp = NULL; 153491040Sarr error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td); 153591040Sarr if (error) 153691040Sarr goto bad; 153791040Sarr /* 153891040Sarr * XXX: we need to limit this number to some reasonable value 153991040Sarr */ 154091040Sarr if (vattr.va_size > 100 * 1024) { 154191040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 154291040Sarr goto bad; 154391040Sarr } 1544111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 154591040Sarr if (hints == NULL) 154691040Sarr goto bad; 154791068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1548101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 154991040Sarr if (error) 155091040Sarr goto bad; 155199553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 155291040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 155391040Sarr nd.ni_vp = NULL; 155491040Sarr if (reclen != 0) { 155591040Sarr printf("can't read %d\n", reclen); 155691040Sarr goto bad; 155791040Sarr } 155891040Sarr intp = (int *)hints; 155983321Speter ival = *intp++; 156091040Sarr if (ival != LINKER_HINTS_VERSION) { 156191040Sarr printf("hints file version mismatch %d\n", ival); 156291040Sarr goto bad; 156383321Speter } 156491040Sarr bufend = hints + vattr.va_size; 156591040Sarr recptr = (u_char *)intp; 156691040Sarr clen = blen = 0; 156791040Sarr while (recptr < bufend && !found) { 156891040Sarr intp = (int *)recptr; 156991040Sarr reclen = *intp++; 157091040Sarr ival = *intp++; 157191040Sarr cp = (char *)intp; 157291040Sarr switch (ival) { 157391040Sarr case MDT_VERSION: 157491040Sarr clen = *cp++; 157591040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 157691040Sarr break; 157791040Sarr cp += clen; 157891040Sarr INT_ALIGN(hints, cp); 157991040Sarr ival = *(int *)cp; 158091040Sarr cp += sizeof(int); 158191040Sarr clen = *cp++; 158291040Sarr if (verinfo == NULL || 158391040Sarr ival == verinfo->md_ver_preferred) { 158491040Sarr found = 1; 158591040Sarr break; 158691040Sarr } 158791040Sarr if (ival >= verinfo->md_ver_minimum && 158891040Sarr ival <= verinfo->md_ver_maximum && 158991040Sarr ival > bestver) { 159091040Sarr bestver = ival; 159191040Sarr best = cp; 159291040Sarr blen = clen; 159391040Sarr } 159491040Sarr break; 159591040Sarr default: 159691040Sarr break; 159791040Sarr } 159891040Sarr recptr += reclen + sizeof(int); 159991040Sarr } 160083321Speter /* 160191040Sarr * Finally check if KLD is in the place 160283321Speter */ 160391040Sarr if (found) 160491040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 160591040Sarr else if (best) 160691040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 160791040Sarr 160891040Sarr /* 160991040Sarr * KLD is newer than hints file. What we should do now? 161091040Sarr */ 161191040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 161291040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 161391040Sarr " file\n", result); 161483321Speterbad: 1615105167Sphk free(pathbuf, M_LINKER); 161691040Sarr if (hints) 161791040Sarr free(hints, M_TEMP); 161899553Sjeff if (nd.ni_vp != NULL) { 161999553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 162091040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 162199553Sjeff } 162291040Sarr /* 162391040Sarr * If nothing found or hints is absent - fallback to the old 162491040Sarr * way by using "kldname[.ko]" as module name. 162591040Sarr */ 162691040Sarr if (!found && !bestver && result == NULL) 162791040Sarr result = linker_lookup_file(path, pathlen, modname, 162891040Sarr modnamelen, NULL); 162991040Sarr return (result); 163083321Speter} 163183321Speter 163283321Speter/* 163383321Speter * Lookup KLD which contains requested module in the all directories. 163483321Speter */ 163583321Speterstatic char * 163683321Speterlinker_search_module(const char *modname, int modnamelen, 163791040Sarr struct mod_depend *verinfo) 163883321Speter{ 163991040Sarr char *cp, *ep, *result; 164083321Speter 164191040Sarr /* 164291040Sarr * traverse the linker path 164391040Sarr */ 164491040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 164591040Sarr /* find the end of this component */ 164691040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 164791068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 164891068Sarr modnamelen, verinfo); 164991040Sarr if (result != NULL) 165091040Sarr return (result); 165191040Sarr if (*ep == 0) 165291040Sarr break; 165391040Sarr } 165491040Sarr return (NULL); 165583321Speter} 165683321Speter 165783321Speter/* 165883321Speter * Search for module in all directories listed in the linker_path. 165983321Speter */ 166083321Speterstatic char * 166183321Speterlinker_search_kld(const char *name) 166283321Speter{ 1663158972Sdelphij char *cp, *ep, *result; 1664158972Sdelphij int len; 166583321Speter 166691040Sarr /* qualified at all? */ 166791040Sarr if (index(name, '/')) 166891040Sarr return (linker_strdup(name)); 166940159Speter 167091040Sarr /* traverse the linker path */ 167191040Sarr len = strlen(name); 167291040Sarr for (ep = linker_path; *ep; ep++) { 167391040Sarr cp = ep; 167491040Sarr /* find the end of this component */ 167591040Sarr for (; *ep != 0 && *ep != ';'; ep++); 167691040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 167791040Sarr if (result != NULL) 167891040Sarr return (result); 167991040Sarr } 168091040Sarr return (NULL); 168140159Speter} 168259751Speter 168359751Speterstatic const char * 168491040Sarrlinker_basename(const char *path) 168559751Speter{ 168691040Sarr const char *filename; 168759751Speter 168891040Sarr filename = rindex(path, '/'); 168991040Sarr if (filename == NULL) 169091040Sarr return path; 169191040Sarr if (filename[1]) 169291040Sarr filename++; 169391040Sarr return (filename); 169459751Speter} 169559751Speter 1696157144Sjkoshy#ifdef HWPMC_HOOKS 1697157144Sjkoshy 1698159797Sjhbstruct hwpmc_context { 1699159797Sjhb int nobjects; 1700159797Sjhb int nmappings; 1701159797Sjhb struct pmckern_map_in *kobase; 1702159797Sjhb}; 1703159797Sjhb 1704159797Sjhbstatic int 1705159797Sjhblinker_hwpmc_list_object(linker_file_t lf, void *arg) 1706159797Sjhb{ 1707159797Sjhb struct hwpmc_context *hc; 1708159797Sjhb 1709159797Sjhb hc = arg; 1710159797Sjhb 1711159797Sjhb /* If we run out of mappings, fail. */ 1712159797Sjhb if (hc->nobjects >= hc->nmappings) 1713159797Sjhb return (1); 1714159797Sjhb 1715159797Sjhb /* Save the info for this linker file. */ 1716159797Sjhb hc->kobase[hc->nobjects].pm_file = lf->filename; 1717159797Sjhb hc->kobase[hc->nobjects].pm_address = (uintptr_t)lf->address; 1718159797Sjhb hc->nobjects++; 1719159797Sjhb return (0); 1720159797Sjhb} 1721159797Sjhb 172259751Speter/* 1723157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1724157144Sjkoshy */ 1725157144Sjkoshyvoid * 1726157144Sjkoshylinker_hwpmc_list_objects(void) 1727157144Sjkoshy{ 1728159797Sjhb struct hwpmc_context hc; 1729157144Sjkoshy 1730159797Sjhb hc.nmappings = 15; /* a reasonable default */ 1731157144Sjkoshy 1732157144Sjkoshy retry: 1733157144Sjkoshy /* allocate nmappings+1 entries */ 1734159797Sjhb MALLOC(hc.kobase, struct pmckern_map_in *, 1735159797Sjhb (hc.nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, 1736157144Sjkoshy M_WAITOK | M_ZERO); 1737157144Sjkoshy 1738159797Sjhb hc.nobjects = 0; 1739159797Sjhb if (linker_file_foreach(linker_hwpmc_list_object, &hc) != 0) { 1740159797Sjhb hc.nmappings = hc.nobjects; 1741159797Sjhb FREE(hc.kobase, M_LINKER); 1742157144Sjkoshy goto retry; 1743157144Sjkoshy } 1744157144Sjkoshy 1745159797Sjhb KASSERT(hc.nobjects > 0, ("linker_hpwmc_list_objects: no kernel " 1746159797Sjhb "objects?")); 1747157144Sjkoshy 1748157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1749159797Sjhb KASSERT(hc.kobase[hc.nobjects].pm_file == NULL, 1750157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1751157144Sjkoshy 1752159797Sjhb return ((void *)hc.kobase); 1753157144Sjkoshy} 1754157144Sjkoshy#endif 1755157144Sjkoshy 1756157144Sjkoshy/* 175791040Sarr * Find a file which contains given module and load it, if "parent" is not 175891040Sarr * NULL, register a reference to it. 175959751Speter */ 1760159796Sjhbstatic int 176183321Speterlinker_load_module(const char *kldname, const char *modname, 176291040Sarr struct linker_file *parent, struct mod_depend *verinfo, 176391040Sarr struct linker_file **lfpp) 176459751Speter{ 176591040Sarr linker_file_t lfdep; 176691040Sarr const char *filename; 176791040Sarr char *pathname; 176891040Sarr int error; 176959751Speter 177091040Sarr if (modname == NULL) { 177191040Sarr /* 177291040Sarr * We have to load KLD 177391040Sarr */ 177491068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 177591068Sarr " is not NULL")); 177691040Sarr pathname = linker_search_kld(kldname); 177791040Sarr } else { 177891040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 177991040Sarr return (EEXIST); 178094322Sbrian if (kldname != NULL) 178194322Sbrian pathname = linker_strdup(kldname); 178295488Sbrian else if (rootvnode == NULL) 178394322Sbrian pathname = NULL; 178494322Sbrian else 178591040Sarr /* 178691040Sarr * Need to find a KLD with required module 178791040Sarr */ 178891040Sarr pathname = linker_search_module(modname, 178991040Sarr strlen(modname), verinfo); 179091040Sarr } 179191040Sarr if (pathname == NULL) 179291040Sarr return (ENOENT); 179391040Sarr 179483321Speter /* 179591040Sarr * Can't load more than one file with the same basename XXX: 179691040Sarr * Actually it should be possible to have multiple KLDs with 179791040Sarr * the same basename but different path because they can 179891040Sarr * provide different versions of the same modules. 179983321Speter */ 180091040Sarr filename = linker_basename(pathname); 1801159792Sjhb if (linker_find_file_by_name(filename)) 180291040Sarr error = EEXIST; 1803159792Sjhb else do { 180491040Sarr error = linker_load_file(pathname, &lfdep); 180591040Sarr if (error) 180691040Sarr break; 180791040Sarr if (modname && verinfo && 180891040Sarr modlist_lookup2(modname, verinfo) == NULL) { 1809132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 181091040Sarr error = ENOENT; 181191040Sarr break; 181291040Sarr } 181391040Sarr if (parent) { 181491040Sarr error = linker_file_add_dependency(parent, lfdep); 181591040Sarr if (error) 181691040Sarr break; 181791040Sarr } 181891040Sarr if (lfpp) 181991040Sarr *lfpp = lfdep; 182091040Sarr } while (0); 1821159791Sjhb free(pathname, M_LINKER); 182291040Sarr return (error); 182359751Speter} 182459751Speter 182559751Speter/* 182691040Sarr * This routine is responsible for finding dependencies of userland initiated 182791040Sarr * kldload(2)'s of files. 182859751Speter */ 182959751Speterint 183086469Siedowselinker_load_dependencies(linker_file_t lf) 183159751Speter{ 183291040Sarr linker_file_t lfdep; 183391040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 183491040Sarr struct mod_metadata *mp, *nmp; 183591040Sarr struct mod_depend *verinfo; 183691040Sarr modlist_t mod; 183791040Sarr const char *modname, *nmodname; 183892032Sdwmalone int ver, error = 0, count; 183959751Speter 184091040Sarr /* 184191040Sarr * All files are dependant on /kernel. 184291040Sarr */ 184391040Sarr if (linker_kernel_file) { 184491040Sarr linker_kernel_file->refs++; 184591040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 184691040Sarr if (error) 184791040Sarr return (error); 184859751Speter } 184991040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 185091040Sarr &count) != 0) 185191040Sarr return (0); 185291040Sarr for (mdp = start; mdp < stop; mdp++) { 1853109605Sjake mp = *mdp; 185491040Sarr if (mp->md_type != MDT_VERSION) 185591040Sarr continue; 1856109605Sjake modname = mp->md_cval; 1857109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 185891040Sarr mod = modlist_lookup(modname, ver); 185991040Sarr if (mod != NULL) { 186091040Sarr printf("interface %s.%d already present in the KLD" 186191040Sarr " '%s'!\n", modname, ver, 186291040Sarr mod->container->filename); 186391040Sarr return (EEXIST); 186491040Sarr } 186591040Sarr } 186674642Sbp 186791040Sarr for (mdp = start; mdp < stop; mdp++) { 1868109605Sjake mp = *mdp; 186991040Sarr if (mp->md_type != MDT_DEPEND) 187091040Sarr continue; 1871109605Sjake modname = mp->md_cval; 1872109605Sjake verinfo = mp->md_data; 187391040Sarr nmodname = NULL; 187491040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1875109605Sjake nmp = *nmdp; 187691040Sarr if (nmp->md_type != MDT_VERSION) 187791040Sarr continue; 1878109605Sjake nmodname = nmp->md_cval; 187992032Sdwmalone if (strcmp(modname, nmodname) == 0) 188091040Sarr break; 188191040Sarr } 188291040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 188391040Sarr continue; 188491040Sarr mod = modlist_lookup2(modname, verinfo); 188591040Sarr if (mod) { /* woohoo, it's loaded already */ 188691040Sarr lfdep = mod->container; 188791040Sarr lfdep->refs++; 188891040Sarr error = linker_file_add_dependency(lf, lfdep); 188991040Sarr if (error) 189091040Sarr break; 189191040Sarr continue; 189291040Sarr } 189391040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 189491040Sarr if (error) { 189591040Sarr printf("KLD %s: depends on %s - not available\n", 189691040Sarr lf->filename, modname); 189791040Sarr break; 189891040Sarr } 189959751Speter } 190059751Speter 190191040Sarr if (error) 190291040Sarr return (error); 190391040Sarr linker_addmodules(lf, start, stop, 0); 190491040Sarr return (error); 190559751Speter} 190685736Sgreen 190785736Sgreenstatic int 190885736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 190985736Sgreen{ 191085736Sgreen struct sysctl_req *req; 191185736Sgreen 191285736Sgreen req = opaque; 191385736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 191485736Sgreen} 191585736Sgreen 191685736Sgreen/* 191785736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 191885736Sgreen * in the kernel. 191985736Sgreen */ 192085736Sgreenstatic int 192185736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 192285736Sgreen{ 192385736Sgreen linker_file_t lf; 192485736Sgreen int error; 192585736Sgreen 1926107089Srwatson#ifdef MAC 1927107089Srwatson error = mac_check_kld_stat(req->td->td_ucred); 1928107089Srwatson if (error) 1929107089Srwatson return (error); 1930107089Srwatson#endif 1931126253Struckman error = sysctl_wire_old_buffer(req, 0); 1932126253Struckman if (error != 0) 1933126253Struckman return (error); 193498452Sarr mtx_lock(&kld_mtx); 193585736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 193685736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 193785736Sgreen sysctl_kern_function_list_iterate, req); 193898452Sarr if (error) { 193998452Sarr mtx_unlock(&kld_mtx); 194085736Sgreen return (error); 194198452Sarr } 194285736Sgreen } 194398452Sarr mtx_unlock(&kld_mtx); 194485736Sgreen return (SYSCTL_OUT(req, "", 1)); 194585736Sgreen} 194685736Sgreen 194785736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 194891040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 1949