kern_linker.c revision 159808
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 159808 2006-06-20 21:31:38Z 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> 46159808Sjhb#include <sys/mount.h> 4725537Sdfr#include <sys/linker.h> 4840159Speter#include <sys/fcntl.h> 4940159Speter#include <sys/libkern.h> 5040159Speter#include <sys/namei.h> 5140159Speter#include <sys/vnode.h> 52159588Sjhb#include <sys/syscallsubr.h> 5340159Speter#include <sys/sysctl.h> 5425537Sdfr 5559603Sdfr#include "linker_if.h" 5659603Sdfr 57157144Sjkoshy#ifdef HWPMC_HOOKS 58157144Sjkoshy#include <sys/pmckern.h> 59157144Sjkoshy#endif 60157144Sjkoshy 6140961Speter#ifdef KLD_DEBUG 6240961Speterint kld_debug = 0; 6340961Speter#endif 6440961Speter 6591040Sarr/* 6691040Sarr * static char *linker_search_path(const char *name, struct mod_depend 6791040Sarr * *verinfo); 6891040Sarr */ 6991040Sarrstatic const char *linker_basename(const char *path); 7059751Speter 71159800Sjhb/* 72159800Sjhb * Find a currently loaded file given its filename. 73159800Sjhb */ 74159800Sjhbstatic linker_file_t linker_find_file_by_name(const char* _filename); 75159800Sjhb 76159800Sjhb/* 77159800Sjhb * Find a currently loaded file given its file id. 78159800Sjhb */ 79159800Sjhbstatic linker_file_t linker_find_file_by_id(int _fileid); 80159800Sjhb 8178161Speter/* Metadata from the static kernel */ 8278161SpeterSET_DECLARE(modmetadata_set, struct mod_metadata); 8378161Speter 8459751SpeterMALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); 8559751Speter 8640906Speterlinker_file_t linker_kernel_file; 8731324Sbde 8898452Sarrstatic struct mtx kld_mtx; /* kernel linker mutex */ 8998452Sarr 9025537Sdfrstatic linker_class_list_t classes; 9150068Sgrogstatic linker_file_list_t linker_files; 9225537Sdfrstatic int next_file_id = 1; 9398452Sarrstatic int linker_no_more_classes = 0; 9425537Sdfr 9586553Sarr#define LINKER_GET_NEXT_FILE_ID(a) do { \ 9691040Sarr linker_file_t lftmp; \ 9786553Sarr \ 9886553Sarrretry: \ 9998452Sarr mtx_lock(&kld_mtx); \ 10091040Sarr TAILQ_FOREACH(lftmp, &linker_files, link) { \ 10191040Sarr if (next_file_id == lftmp->id) { \ 10291040Sarr next_file_id++; \ 10398452Sarr mtx_unlock(&kld_mtx); \ 10491040Sarr goto retry; \ 10591040Sarr } \ 10691040Sarr } \ 10791040Sarr (a) = next_file_id; \ 10898452Sarr mtx_unlock(&kld_mtx); /* Hold for safe read of id variable */ \ 10986553Sarr} while(0) 11086553Sarr 11186553Sarr 11259751Speter/* XXX wrong name; we're looking at version provision tags here, not modules */ 11360938Sjaketypedef TAILQ_HEAD(, modlist) modlisthead_t; 11459751Speterstruct modlist { 11591040Sarr TAILQ_ENTRY(modlist) link; /* chain together all modules */ 11691040Sarr linker_file_t container; 11791040Sarr const char *name; 11891040Sarr int version; 11959751Speter}; 12091040Sarrtypedef struct modlist *modlist_t; 12191040Sarrstatic modlisthead_t found_modules; 12259751Speter 123159796Sjhbstatic int linker_file_add_dependency(linker_file_t file, 124159796Sjhb linker_file_t dep); 125159796Sjhbstatic int linker_load_module(const char *kldname, 126159796Sjhb const char *modname, struct linker_file *parent, 127159796Sjhb struct mod_depend *verinfo, struct linker_file **lfpp); 128159796Sjhbstatic modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); 12994321Sbrian 13059603Sdfrstatic char * 13159603Sdfrlinker_strdup(const char *str) 13259603Sdfr{ 13391040Sarr char *result; 13459603Sdfr 135111119Simp if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 13691040Sarr strcpy(result, str); 13791040Sarr return (result); 13859603Sdfr} 13959603Sdfr 14025537Sdfrstatic void 14191040Sarrlinker_init(void *arg) 14225537Sdfr{ 14391040Sarr 14498452Sarr mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF); 14591040Sarr TAILQ_INIT(&classes); 14691040Sarr TAILQ_INIT(&linker_files); 14725537Sdfr} 14825537Sdfr 14991040SarrSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0) 15025537Sdfr 15198452Sarrstatic void 15298452Sarrlinker_stop_class_add(void *arg) 15398452Sarr{ 15498452Sarr 15598452Sarr linker_no_more_classes = 1; 15698452Sarr} 15798452Sarr 15898452SarrSYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL) 15998452Sarr 16025537Sdfrint 16159603Sdfrlinker_add_class(linker_class_t lc) 16225537Sdfr{ 16391040Sarr 16498452Sarr /* 165144443Sjhb * We disallow any class registration past SI_ORDER_ANY 166144443Sjhb * of SI_SUB_KLD. We bump the reference count to keep the 167144443Sjhb * ops from being freed. 16898452Sarr */ 16998452Sarr if (linker_no_more_classes == 1) 17098452Sarr return (EPERM); 17191040Sarr kobj_class_compile((kobj_class_t) lc); 172144443Sjhb ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ 17391040Sarr TAILQ_INSERT_TAIL(&classes, lc, link); 17491040Sarr return (0); 17525537Sdfr} 17625537Sdfr 17725537Sdfrstatic void 17825537Sdfrlinker_file_sysinit(linker_file_t lf) 17925537Sdfr{ 18091040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 18125537Sdfr 18291040Sarr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 18391040Sarr lf->filename)); 18425537Sdfr 18591040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) 18691040Sarr return; 18791040Sarr /* 18891040Sarr * Perform a bubble sort of the system initialization objects by 18991040Sarr * their subsystem (primary key) and order (secondary key). 19091040Sarr * 19191040Sarr * Since some things care about execution order, this is the operation 19291040Sarr * which ensures continued function. 19391040Sarr */ 19491040Sarr for (sipp = start; sipp < stop; sipp++) { 19591040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 19691040Sarr if ((*sipp)->subsystem < (*xipp)->subsystem || 19791040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 19891040Sarr (*sipp)->order <= (*xipp)->order)) 19991040Sarr continue; /* skip */ 20091040Sarr save = *sipp; 20191040Sarr *sipp = *xipp; 20291040Sarr *xipp = save; 20391040Sarr } 20425537Sdfr } 20525537Sdfr 20691040Sarr /* 20791040Sarr * Traverse the (now) ordered list of system initialization tasks. 20891040Sarr * Perform each task, and continue on to the next task. 20991040Sarr */ 21091040Sarr for (sipp = start; sipp < stop; sipp++) { 21191040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 21291040Sarr continue; /* skip dummy task(s) */ 21325537Sdfr 21491040Sarr /* Call function */ 21591040Sarr (*((*sipp)->func)) ((*sipp)->udata); 21691040Sarr } 21725537Sdfr} 21825537Sdfr 21941055Speterstatic void 22041055Speterlinker_file_sysuninit(linker_file_t lf) 22141055Speter{ 22291040Sarr struct sysinit **start, **stop, **sipp, **xipp, *save; 22341055Speter 22491040Sarr KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", 22591040Sarr lf->filename)); 22641055Speter 22791068Sarr if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, 22891040Sarr NULL) != 0) 22991040Sarr return; 23041055Speter 23191040Sarr /* 23291040Sarr * Perform a reverse bubble sort of the system initialization objects 23391040Sarr * by their subsystem (primary key) and order (secondary key). 23491040Sarr * 23591040Sarr * Since some things care about execution order, this is the operation 23691040Sarr * which ensures continued function. 23791040Sarr */ 23891040Sarr for (sipp = start; sipp < stop; sipp++) { 23991040Sarr for (xipp = sipp + 1; xipp < stop; xipp++) { 24091040Sarr if ((*sipp)->subsystem > (*xipp)->subsystem || 24191040Sarr ((*sipp)->subsystem == (*xipp)->subsystem && 24291040Sarr (*sipp)->order >= (*xipp)->order)) 24391040Sarr continue; /* skip */ 24491040Sarr save = *sipp; 24591040Sarr *sipp = *xipp; 24691040Sarr *xipp = save; 24791040Sarr } 24841055Speter } 24941055Speter 25091040Sarr /* 25191040Sarr * Traverse the (now) ordered list of system initialization tasks. 25291040Sarr * Perform each task, and continue on to the next task. 25391040Sarr */ 25491040Sarr for (sipp = start; sipp < stop; sipp++) { 25591040Sarr if ((*sipp)->subsystem == SI_SUB_DUMMY) 25691040Sarr continue; /* skip dummy task(s) */ 25741055Speter 25891040Sarr /* Call function */ 25991040Sarr (*((*sipp)->func)) ((*sipp)->udata); 26091040Sarr } 26141055Speter} 26241055Speter 26344078Sdfrstatic void 26444078Sdfrlinker_file_register_sysctls(linker_file_t lf) 26544078Sdfr{ 26691040Sarr struct sysctl_oid **start, **stop, **oidp; 26744078Sdfr 26891040Sarr KLD_DPF(FILE, 26991040Sarr ("linker_file_register_sysctls: registering SYSCTLs for %s\n", 27091040Sarr lf->filename)); 27144078Sdfr 27291040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 27391040Sarr return; 27444078Sdfr 27591040Sarr for (oidp = start; oidp < stop; oidp++) 27691040Sarr sysctl_register_oid(*oidp); 27744078Sdfr} 27844078Sdfr 27944078Sdfrstatic void 28044078Sdfrlinker_file_unregister_sysctls(linker_file_t lf) 28144078Sdfr{ 28291040Sarr struct sysctl_oid **start, **stop, **oidp; 28344078Sdfr 28491040Sarr KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" 28591040Sarr " for %s\n", lf->filename)); 28644078Sdfr 28791040Sarr if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) 28891040Sarr return; 28944078Sdfr 29091040Sarr for (oidp = start; oidp < stop; oidp++) 29191040Sarr sysctl_unregister_oid(*oidp); 29244078Sdfr} 29344078Sdfr 29459751Speterstatic int 29559751Speterlinker_file_register_modules(linker_file_t lf) 29659751Speter{ 29791040Sarr struct mod_metadata **start, **stop, **mdp; 29891040Sarr const moduledata_t *moddata; 299146733Spjd int first_error, error; 30059751Speter 30191040Sarr KLD_DPF(FILE, ("linker_file_register_modules: registering modules" 30291040Sarr " in %s\n", lf->filename)); 30359751Speter 30491068Sarr if (linker_file_lookup_set(lf, "modmetadata_set", &start, 30591040Sarr &stop, 0) != 0) { 30691040Sarr /* 30791040Sarr * This fallback should be unnecessary, but if we get booted 30891040Sarr * from boot2 instead of loader and we are missing our 30991040Sarr * metadata then we have to try the best we can. 31091040Sarr */ 31191040Sarr if (lf == linker_kernel_file) { 31291040Sarr start = SET_BEGIN(modmetadata_set); 31391040Sarr stop = SET_LIMIT(modmetadata_set); 31491040Sarr } else 31591040Sarr return (0); 31678161Speter } 317146733Spjd first_error = 0; 31891040Sarr for (mdp = start; mdp < stop; mdp++) { 31991040Sarr if ((*mdp)->md_type != MDT_MODULE) 32091040Sarr continue; 32191040Sarr moddata = (*mdp)->md_data; 32291040Sarr KLD_DPF(FILE, ("Registering module %s in %s\n", 32391040Sarr moddata->name, lf->filename)); 32491040Sarr error = module_register(moddata, lf); 325146730Spjd if (error) { 32691068Sarr printf("Module %s failed to register: %d\n", 32791040Sarr moddata->name, error); 328146733Spjd if (first_error == 0) 329146733Spjd first_error = error; 330146730Spjd } 33159751Speter } 332146733Spjd return (first_error); 33359751Speter} 33459751Speter 33559751Speterstatic void 33659751Speterlinker_init_kernel_modules(void) 33759751Speter{ 33891040Sarr 33991040Sarr linker_file_register_modules(linker_kernel_file); 34059751Speter} 34159751Speter 34291040SarrSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0) 34359751Speter 344101241Smuxstatic int 34591040Sarrlinker_load_file(const char *filename, linker_file_t *result) 34625537Sdfr{ 34791040Sarr linker_class_t lc; 34891040Sarr linker_file_t lf; 349159585Sjhb int foundfile, error; 35025537Sdfr 35191040Sarr /* Refuse to load modules if securelevel raised */ 35291040Sarr if (securelevel > 0) 35391040Sarr return (EPERM); 35462261Sarchie 35591040Sarr lf = linker_find_file_by_name(filename); 35691040Sarr if (lf) { 35791040Sarr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," 35891040Sarr " incrementing refs\n", filename)); 35991040Sarr *result = lf; 36091040Sarr lf->refs++; 361159585Sjhb return (0); 36291040Sarr } 36391040Sarr foundfile = 0; 364159585Sjhb error = 0; 36598452Sarr 36698452Sarr /* 36798452Sarr * We do not need to protect (lock) classes here because there is 36898452Sarr * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) 36998452Sarr * and there is no class deregistration mechanism at this time. 37098452Sarr */ 37191040Sarr TAILQ_FOREACH(lc, &classes, link) { 37291040Sarr KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", 37391040Sarr filename)); 37491040Sarr error = LINKER_LOAD_FILE(lc, filename, &lf); 37591040Sarr /* 37691040Sarr * If we got something other than ENOENT, then it exists but 37791040Sarr * we cannot load it for some other reason. 37891040Sarr */ 37991040Sarr if (error != ENOENT) 38091040Sarr foundfile = 1; 38191040Sarr if (lf) { 382146730Spjd error = linker_file_register_modules(lf); 383146730Spjd if (error == EEXIST) { 384146730Spjd linker_file_unload(lf, LINKER_UNLOAD_FORCE); 385159585Sjhb return (error); 386146730Spjd } 38791040Sarr linker_file_register_sysctls(lf); 38891040Sarr linker_file_sysinit(lf); 38991040Sarr lf->flags |= LINKER_FILE_LINKED; 39091040Sarr *result = lf; 391159585Sjhb return (0); 39291040Sarr } 39391040Sarr } 39442755Speter /* 39591040Sarr * Less than ideal, but tells the user whether it failed to load or 39691040Sarr * the module was not found. 39742755Speter */ 398105337Ssam if (foundfile) { 399105337Ssam /* 400105337Ssam * Format not recognized or otherwise unloadable. 401105337Ssam * When loading a module that is statically built into 402105337Ssam * the kernel EEXIST percolates back up as the return 403105337Ssam * value. Preserve this so that apps like sysinstall 404105337Ssam * can recognize this special case and not post bogus 405105337Ssam * dialog boxes. 406105337Ssam */ 407105337Ssam if (error != EEXIST) 408105337Ssam error = ENOEXEC; 409105337Ssam } else 41091068Sarr error = ENOENT; /* Nothing found */ 41191040Sarr return (error); 41225537Sdfr} 41325537Sdfr 41478413Sbrianint 41594321Sbrianlinker_reference_module(const char *modname, struct mod_depend *verinfo, 41694321Sbrian linker_file_t *result) 41778413Sbrian{ 41894321Sbrian modlist_t mod; 419159804Sjhb int error; 42094321Sbrian 421159804Sjhb mtx_lock(&Giant); 42294321Sbrian if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { 42394321Sbrian *result = mod->container; 42494321Sbrian (*result)->refs++; 425159804Sjhb mtx_unlock(&Giant); 42694321Sbrian return (0); 42794321Sbrian } 42894321Sbrian 429159804Sjhb error = linker_load_module(NULL, modname, NULL, verinfo, result); 430159804Sjhb mtx_unlock(&Giant); 431159804Sjhb return (error); 43278413Sbrian} 43378413Sbrian 434159804Sjhbint 435159804Sjhblinker_release_module(const char *modname, struct mod_depend *verinfo, 436159804Sjhb linker_file_t lf) 437159804Sjhb{ 438159804Sjhb modlist_t mod; 439159804Sjhb int error; 440159804Sjhb 441159804Sjhb mtx_lock(&Giant); 442159804Sjhb if (lf == NULL) { 443159804Sjhb KASSERT(modname != NULL, 444159804Sjhb ("linker_release_module: no file or name")); 445159804Sjhb mod = modlist_lookup2(modname, verinfo); 446159804Sjhb if (mod == NULL) { 447159804Sjhb mtx_unlock(&Giant); 448159804Sjhb return (ESRCH); 449159804Sjhb } 450159804Sjhb lf = mod->container; 451159804Sjhb } else 452159804Sjhb KASSERT(modname == NULL && verinfo == NULL, 453159804Sjhb ("linker_release_module: both file and name")); 454159804Sjhb error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL); 455159804Sjhb mtx_unlock(&Giant); 456159804Sjhb return (error); 457159804Sjhb} 458159804Sjhb 459159800Sjhbstatic linker_file_t 46091040Sarrlinker_find_file_by_name(const char *filename) 46125537Sdfr{ 462159585Sjhb linker_file_t lf; 46391040Sarr char *koname; 46425537Sdfr 465111119Simp koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 46691040Sarr sprintf(koname, "%s.ko", filename); 46740861Speter 46898452Sarr mtx_lock(&kld_mtx); 46991040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 47092032Sdwmalone if (strcmp(lf->filename, koname) == 0) 47191040Sarr break; 47292032Sdwmalone if (strcmp(lf->filename, filename) == 0) 47391040Sarr break; 47491040Sarr } 47598452Sarr mtx_unlock(&kld_mtx); 476159585Sjhb free(koname, M_LINKER); 47791040Sarr return (lf); 47825537Sdfr} 47925537Sdfr 480159800Sjhbstatic linker_file_t 48125537Sdfrlinker_find_file_by_id(int fileid) 48225537Sdfr{ 483159585Sjhb linker_file_t lf; 48498452Sarr 48598452Sarr mtx_lock(&kld_mtx); 48691040Sarr TAILQ_FOREACH(lf, &linker_files, link) 48791040Sarr if (lf->id == fileid) 48891040Sarr break; 48998452Sarr mtx_unlock(&kld_mtx); 49091040Sarr return (lf); 49125537Sdfr} 49225537Sdfr 493159797Sjhbint 494159797Sjhblinker_file_foreach(linker_predicate_t *predicate, void *context) 495159797Sjhb{ 496159797Sjhb linker_file_t lf; 497159797Sjhb int retval = 0; 498159797Sjhb 499159797Sjhb mtx_lock(&Giant); 500159797Sjhb TAILQ_FOREACH(lf, &linker_files, link) { 501159797Sjhb retval = predicate(lf, context); 502159797Sjhb if (retval != 0) 503159797Sjhb break; 504159797Sjhb } 505159797Sjhb mtx_unlock(&Giant); 506159797Sjhb return (retval); 507159797Sjhb} 508159797Sjhb 50925537Sdfrlinker_file_t 51091040Sarrlinker_make_file(const char *pathname, linker_class_t lc) 51125537Sdfr{ 51291040Sarr linker_file_t lf; 51391040Sarr const char *filename; 51425537Sdfr 51591040Sarr filename = linker_basename(pathname); 51640159Speter 51791040Sarr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 518111119Simp lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); 51991040Sarr if (lf == NULL) 520159585Sjhb return (NULL); 52191040Sarr lf->refs = 1; 52291040Sarr lf->userrefs = 0; 52391040Sarr lf->flags = 0; 52491040Sarr lf->filename = linker_strdup(filename); 52591040Sarr LINKER_GET_NEXT_FILE_ID(lf->id); 52691040Sarr lf->ndeps = 0; 52791040Sarr lf->deps = NULL; 52891040Sarr STAILQ_INIT(&lf->common); 52991040Sarr TAILQ_INIT(&lf->modules); 53098452Sarr mtx_lock(&kld_mtx); 53191040Sarr TAILQ_INSERT_TAIL(&linker_files, lf, link); 53298452Sarr mtx_unlock(&kld_mtx); 53391040Sarr return (lf); 53425537Sdfr} 53525537Sdfr 53625537Sdfrint 537132117Sphklinker_file_unload(linker_file_t file, int flags) 53825537Sdfr{ 53991040Sarr module_t mod, next; 54091040Sarr modlist_t ml, nextml; 54191040Sarr struct common_symbol *cp; 54291040Sarr int error, i; 54325537Sdfr 54491040Sarr /* Refuse to unload modules if securelevel raised. */ 54591040Sarr if (securelevel > 0) 54691040Sarr return (EPERM); 547107089Srwatson#ifdef MAC 548107089Srwatson error = mac_check_kld_unload(curthread->td_ucred); 549107089Srwatson if (error) 550107089Srwatson return (error); 551107089Srwatson#endif 55225537Sdfr 55391040Sarr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 55491040Sarr 555159584Sjhb /* Easy case of just dropping a reference. */ 556159584Sjhb if (file->refs > 1) { 557159584Sjhb file->refs--; 558159584Sjhb return (0); 559159584Sjhb } 560159584Sjhb 561159584Sjhb KLD_DPF(FILE, ("linker_file_unload: file is unloading," 562159584Sjhb " informing modules\n")); 563159584Sjhb 564159584Sjhb /* 565159584Sjhb * Inform any modules associated with this file. 566159584Sjhb */ 567159584Sjhb MOD_XLOCK; 568159584Sjhb for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 569159584Sjhb next = module_getfnext(mod); 570159584Sjhb MOD_XUNLOCK; 571159584Sjhb 57291040Sarr /* 573159584Sjhb * Give the module a chance to veto the unload. 57491040Sarr */ 575159584Sjhb if ((error = module_unload(mod, flags)) != 0) { 576159584Sjhb KLD_DPF(FILE, ("linker_file_unload: module %p" 577159584Sjhb " vetoes unload\n", mod)); 578159584Sjhb return (error); 579159584Sjhb } 58092547Sarr MOD_XLOCK; 581159584Sjhb module_release(mod); 582159584Sjhb } 583159584Sjhb MOD_XUNLOCK; 58491040Sarr 585159586Sjhb TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml) { 586128057Speadar if (ml->container == file) { 58791040Sarr TAILQ_REMOVE(&found_modules, ml, link); 588128057Speadar free(ml, M_LINKER); 589128057Speadar } 59091040Sarr } 59125537Sdfr 59291040Sarr /* 59391040Sarr * Don't try to run SYSUNINITs if we are unloaded due to a 59491040Sarr * link error. 59591040Sarr */ 59691040Sarr if (file->flags & LINKER_FILE_LINKED) { 59791040Sarr linker_file_sysuninit(file); 59891040Sarr linker_file_unregister_sysctls(file); 59925537Sdfr } 60098452Sarr mtx_lock(&kld_mtx); 60191040Sarr TAILQ_REMOVE(&linker_files, file, link); 60298452Sarr mtx_unlock(&kld_mtx); 60325537Sdfr 60491040Sarr if (file->deps) { 60591040Sarr for (i = 0; i < file->ndeps; i++) 606132117Sphk linker_file_unload(file->deps[i], flags); 60791040Sarr free(file->deps, M_LINKER); 60891040Sarr file->deps = NULL; 60959751Speter } 61091040Sarr for (cp = STAILQ_FIRST(&file->common); cp; 61191068Sarr cp = STAILQ_FIRST(&file->common)) { 61291040Sarr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 61391040Sarr free(cp, M_LINKER); 61491040Sarr } 61559751Speter 61691040Sarr LINKER_UNLOAD(file); 61791040Sarr if (file->filename) { 61891040Sarr free(file->filename, M_LINKER); 61991040Sarr file->filename = NULL; 62091040Sarr } 62191040Sarr kobj_delete((kobj_t) file, M_LINKER); 622159584Sjhb return (0); 62325537Sdfr} 62425537Sdfr 625159796Sjhbstatic int 62686469Siedowselinker_file_add_dependency(linker_file_t file, linker_file_t dep) 62725537Sdfr{ 62891040Sarr linker_file_t *newdeps; 62925537Sdfr 63091040Sarr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), 631111119Simp M_LINKER, M_WAITOK | M_ZERO); 63291040Sarr if (newdeps == NULL) 63391040Sarr return (ENOMEM); 63425537Sdfr 63591040Sarr if (file->deps) { 63691040Sarr bcopy(file->deps, newdeps, 63791040Sarr file->ndeps * sizeof(linker_file_t *)); 63891040Sarr free(file->deps, M_LINKER); 63991040Sarr } 64091040Sarr file->deps = newdeps; 64191040Sarr file->deps[file->ndeps] = dep; 64291040Sarr file->ndeps++; 64391040Sarr return (0); 64425537Sdfr} 64525537Sdfr 64678161Speter/* 64791040Sarr * Locate a linker set and its contents. This is a helper function to avoid 64891040Sarr * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** 64978161Speter */ 65078161Speterint 65178161Speterlinker_file_lookup_set(linker_file_t file, const char *name, 65291040Sarr void *firstp, void *lastp, int *countp) 65378161Speter{ 65478161Speter 65591040Sarr return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); 65678161Speter} 65778161Speter 65825537Sdfrcaddr_t 65991040Sarrlinker_file_lookup_symbol(linker_file_t file, const char *name, int deps) 66025537Sdfr{ 66191040Sarr c_linker_sym_t sym; 66291040Sarr linker_symval_t symval; 66391040Sarr caddr_t address; 66491040Sarr size_t common_size = 0; 66592032Sdwmalone int i; 66625537Sdfr 667109605Sjake KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", 66891040Sarr file, name, deps)); 66925537Sdfr 67091040Sarr if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { 67191040Sarr LINKER_SYMBOL_VALUES(file, sym, &symval); 67291040Sarr if (symval.value == 0) 67391040Sarr /* 67491040Sarr * For commons, first look them up in the 67591040Sarr * dependencies and only allocate space if not found 67691040Sarr * there. 67791040Sarr */ 67891040Sarr common_size = symval.size; 67991040Sarr else { 68091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" 681109605Sjake ".value=%p\n", symval.value)); 68291040Sarr return (symval.value); 68391040Sarr } 68440159Speter } 68591040Sarr if (deps) { 68691040Sarr for (i = 0; i < file->ndeps; i++) { 68791040Sarr address = linker_file_lookup_symbol(file->deps[i], 68891040Sarr name, 0); 68991040Sarr if (address) { 69091040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 691109605Sjake " deps value=%p\n", address)); 69291040Sarr return (address); 69391040Sarr } 69491040Sarr } 69525537Sdfr } 69691040Sarr if (common_size > 0) { 69791040Sarr /* 69891040Sarr * This is a common symbol which was not found in the 69991040Sarr * dependencies. We maintain a simple common symbol table in 70091040Sarr * the file object. 70191040Sarr */ 70291040Sarr struct common_symbol *cp; 70342849Speter 70491040Sarr STAILQ_FOREACH(cp, &file->common, link) { 70592032Sdwmalone if (strcmp(cp->name, name) == 0) { 70691040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol:" 707109605Sjake " old common value=%p\n", cp->address)); 70891040Sarr return (cp->address); 70991040Sarr } 71091040Sarr } 71191040Sarr /* 71291040Sarr * Round the symbol size up to align. 71391040Sarr */ 71491040Sarr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 71591040Sarr cp = malloc(sizeof(struct common_symbol) 71691040Sarr + common_size + strlen(name) + 1, M_LINKER, 717111119Simp M_WAITOK | M_ZERO); 71891040Sarr cp->address = (caddr_t)(cp + 1); 71991040Sarr cp->name = cp->address + common_size; 72091040Sarr strcpy(cp->name, name); 72191040Sarr bzero(cp->address, common_size); 72291040Sarr STAILQ_INSERT_TAIL(&file->common, cp, link); 72325537Sdfr 72491040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" 725109605Sjake " value=%p\n", cp->address)); 72691040Sarr return (cp->address); 72740159Speter } 72891040Sarr KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 72991040Sarr return (0); 73025537Sdfr} 73125537Sdfr 73240159Speter#ifdef DDB 73325537Sdfr/* 73491040Sarr * DDB Helpers. DDB has to look across multiple files with their own symbol 73591040Sarr * tables and string tables. 73691040Sarr * 73791040Sarr * Note that we do not obey list locking protocols here. We really don't need 73891040Sarr * DDB to hang because somebody's got the lock held. We'll take the chance 73991040Sarr * that the files list is inconsistant instead. 74040159Speter */ 74140159Speter 74240159Speterint 74343309Sdillonlinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) 74440159Speter{ 74591040Sarr linker_file_t lf; 74640159Speter 74791040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 74891040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) 74991040Sarr return (0); 75091040Sarr } 75191040Sarr return (ENOENT); 75240159Speter} 75340159Speter 75440159Speterint 75543309Sdillonlinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) 75640159Speter{ 75791040Sarr linker_file_t lf; 75891040Sarr c_linker_sym_t best, es; 75991040Sarr u_long diff, bestdiff, off; 76040159Speter 76191040Sarr best = 0; 76291040Sarr off = (uintptr_t)value; 76391040Sarr bestdiff = off; 76491040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 76591040Sarr if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) 76691040Sarr continue; 76791040Sarr if (es != 0 && diff < bestdiff) { 76891040Sarr best = es; 76991040Sarr bestdiff = diff; 77091040Sarr } 77191040Sarr if (bestdiff == 0) 77291040Sarr break; 77340159Speter } 77491040Sarr if (best) { 77591040Sarr *sym = best; 77691040Sarr *diffp = bestdiff; 77791040Sarr return (0); 77891040Sarr } else { 77991040Sarr *sym = 0; 78091040Sarr *diffp = off; 78191040Sarr return (ENOENT); 78291040Sarr } 78340159Speter} 78440159Speter 78540159Speterint 78643309Sdillonlinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) 78740159Speter{ 78891040Sarr linker_file_t lf; 78940159Speter 79091040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 79191040Sarr if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) 79291040Sarr return (0); 79391040Sarr } 79491040Sarr return (ENOENT); 79540159Speter} 79640159Speter#endif 79740159Speter 79840159Speter/* 79925537Sdfr * Syscalls. 80025537Sdfr */ 80182749Sdillon/* 80282749Sdillon * MPSAFE 80382749Sdillon */ 80425537Sdfrint 805159588Sjhbkern_kldload(struct thread *td, const char *file, int *fileid) 80625537Sdfr{ 807157144Sjkoshy#ifdef HWPMC_HOOKS 808157144Sjkoshy struct pmckern_map_in pkm; 809157144Sjkoshy#endif 810159588Sjhb const char *kldname, *modname; 81191040Sarr linker_file_t lf; 812159588Sjhb int error; 81325537Sdfr 81493159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 815159588Sjhb return (error); 81693159Sarr 81793593Sjhb if ((error = suser(td)) != 0) 818159588Sjhb return (error); 81925537Sdfr 82091040Sarr /* 821159588Sjhb * If file does not contain qualified name or any dot in it 82291040Sarr * (kldname.ko, or kldname.ver.ko) treat it as interface 82391040Sarr * name. 82491040Sarr */ 825159588Sjhb if (index(file, '/') || index(file, '.')) { 826159588Sjhb kldname = file; 82791040Sarr modname = NULL; 82891040Sarr } else { 82991040Sarr kldname = NULL; 830159588Sjhb modname = file; 83191040Sarr } 832159588Sjhb 833159588Sjhb mtx_lock(&Giant); 83491040Sarr error = linker_load_module(kldname, modname, NULL, NULL, &lf); 83591040Sarr if (error) 836159588Sjhb goto unlock; 83742316Smsmith 838157144Sjkoshy#ifdef HWPMC_HOOKS 839157144Sjkoshy pkm.pm_file = lf->filename; 840157144Sjkoshy pkm.pm_address = (uintptr_t) lf->address; 841157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_LOAD, (void *) &pkm); 842157144Sjkoshy#endif 84391040Sarr lf->userrefs++; 844159588Sjhb if (fileid != NULL) 845159588Sjhb *fileid = lf->id; 846159588Sjhbunlock: 84791040Sarr mtx_unlock(&Giant); 84891040Sarr return (error); 84925537Sdfr} 85025537Sdfr 851159588Sjhbint 852159588Sjhbkldload(struct thread *td, struct kldload_args *uap) 853159588Sjhb{ 854159588Sjhb char *pathname = NULL; 855159596Smarcel int error, fileid; 856159588Sjhb 857159588Sjhb td->td_retval[0] = -1; 858159588Sjhb 859159588Sjhb pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 860159588Sjhb error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL); 861159596Smarcel if (error == 0) { 862159596Smarcel error = kern_kldload(td, pathname, &fileid); 863159596Smarcel if (error == 0) 864159596Smarcel td->td_retval[0] = fileid; 865159596Smarcel } 866159588Sjhb free(pathname, M_TEMP); 867159588Sjhb return (error); 868159588Sjhb} 869159588Sjhb 87082749Sdillon/* 87182749Sdillon * MPSAFE 87282749Sdillon */ 873159588Sjhbint 874132117Sphkkern_kldunload(struct thread *td, int fileid, int flags) 87525537Sdfr{ 876157144Sjkoshy#ifdef HWPMC_HOOKS 877157144Sjkoshy struct pmckern_map_out pkm; 878157144Sjkoshy#endif 87991040Sarr linker_file_t lf; 88091040Sarr int error = 0; 88125537Sdfr 88293159Sarr if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 883159588Sjhb return (error); 88493159Sarr 88593593Sjhb if ((error = suser(td)) != 0) 886159588Sjhb return (error); 88725537Sdfr 888159588Sjhb mtx_lock(&Giant); 889132117Sphk lf = linker_find_file_by_id(fileid); 89091040Sarr if (lf) { 89191040Sarr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 89291040Sarr if (lf->userrefs == 0) { 893132117Sphk /* 894132117Sphk * XXX: maybe LINKER_UNLOAD_FORCE should override ? 895132117Sphk */ 89691040Sarr printf("kldunload: attempt to unload file that was" 89791040Sarr " loaded by the kernel\n"); 898159588Sjhb error = EBUSY; 899159588Sjhb } else { 900157144Sjkoshy#ifdef HWPMC_HOOKS 901159588Sjhb /* Save data needed by hwpmc(4) before unloading. */ 902159588Sjhb pkm.pm_address = (uintptr_t) lf->address; 903159588Sjhb pkm.pm_size = lf->size; 904157144Sjkoshy#endif 905159588Sjhb lf->userrefs--; 906159588Sjhb error = linker_file_unload(lf, flags); 907159588Sjhb if (error) 908159588Sjhb lf->userrefs++; 909159588Sjhb } 91091040Sarr } else 91191040Sarr error = ENOENT; 912157144Sjkoshy 913157144Sjkoshy#ifdef HWPMC_HOOKS 914157144Sjkoshy if (error == 0) 915157144Sjkoshy PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); 916157144Sjkoshy#endif 91791068Sarr mtx_unlock(&Giant); 91891068Sarr return (error); 91925537Sdfr} 92025537Sdfr 92182749Sdillon/* 92282749Sdillon * MPSAFE 92382749Sdillon */ 92425537Sdfrint 925132117Sphkkldunload(struct thread *td, struct kldunload_args *uap) 926132117Sphk{ 927132117Sphk 928132117Sphk return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL)); 929132117Sphk} 930132117Sphk 931132117Sphk/* 932132117Sphk * MPSAFE 933132117Sphk */ 934132117Sphkint 935132117Sphkkldunloadf(struct thread *td, struct kldunloadf_args *uap) 936132117Sphk{ 937132117Sphk 938132117Sphk if (uap->flags != LINKER_UNLOAD_NORMAL && 939132117Sphk uap->flags != LINKER_UNLOAD_FORCE) 940132117Sphk return (EINVAL); 941132117Sphk return (kern_kldunload(td, uap->fileid, uap->flags)); 942132117Sphk} 943132117Sphk 944132117Sphk/* 945132117Sphk * MPSAFE 946132117Sphk */ 947132117Sphkint 94891040Sarrkldfind(struct thread *td, struct kldfind_args *uap) 94925537Sdfr{ 95091040Sarr char *pathname; 95191040Sarr const char *filename; 95291040Sarr linker_file_t lf; 953159791Sjhb int error; 95425537Sdfr 955107089Srwatson#ifdef MAC 956107089Srwatson error = mac_check_kld_stat(td->td_ucred); 957107089Srwatson if (error) 958107089Srwatson return (error); 959107089Srwatson#endif 960107089Srwatson 96191040Sarr mtx_lock(&Giant); 96291040Sarr td->td_retval[0] = -1; 96382749Sdillon 964111119Simp pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 965107855Salfred if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) 96691040Sarr goto out; 96725537Sdfr 96891040Sarr filename = linker_basename(pathname); 96991040Sarr lf = linker_find_file_by_name(filename); 97091040Sarr if (lf) 97191040Sarr td->td_retval[0] = lf->id; 97291040Sarr else 97391040Sarr error = ENOENT; 97425537Sdfrout: 975159791Sjhb free(pathname, M_TEMP); 97691040Sarr mtx_unlock(&Giant); 97791040Sarr return (error); 97825537Sdfr} 97925537Sdfr 98082749Sdillon/* 98182749Sdillon * MPSAFE 98282749Sdillon */ 98325537Sdfrint 98491040Sarrkldnext(struct thread *td, struct kldnext_args *uap) 98525537Sdfr{ 98691040Sarr linker_file_t lf; 98791040Sarr int error = 0; 98825537Sdfr 989107089Srwatson#ifdef MAC 990107089Srwatson error = mac_check_kld_stat(td->td_ucred); 991107089Srwatson if (error) 992107089Srwatson return (error); 993107089Srwatson#endif 994107089Srwatson 99591040Sarr mtx_lock(&Giant); 99682749Sdillon 997107849Salfred if (uap->fileid == 0) { 99898452Sarr mtx_lock(&kld_mtx); 99991040Sarr if (TAILQ_FIRST(&linker_files)) 100091040Sarr td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; 100191040Sarr else 100291040Sarr td->td_retval[0] = 0; 100398452Sarr mtx_unlock(&kld_mtx); 100491040Sarr goto out; 100591040Sarr } 1006107849Salfred lf = linker_find_file_by_id(uap->fileid); 100791040Sarr if (lf) { 100891040Sarr if (TAILQ_NEXT(lf, link)) 100991040Sarr td->td_retval[0] = TAILQ_NEXT(lf, link)->id; 101091040Sarr else 101191040Sarr td->td_retval[0] = 0; 101291040Sarr } else 101391040Sarr error = ENOENT; 101482749Sdillonout: 101591040Sarr mtx_unlock(&Giant); 101691040Sarr return (error); 101725537Sdfr} 101825537Sdfr 101982749Sdillon/* 102082749Sdillon * MPSAFE 102182749Sdillon */ 102225537Sdfrint 102391040Sarrkldstat(struct thread *td, struct kldstat_args *uap) 102425537Sdfr{ 1025159587Sjhb struct kld_file_stat stat; 102691040Sarr linker_file_t lf; 1027159587Sjhb int error, namelen; 102825537Sdfr 1029159587Sjhb /* 1030159587Sjhb * Check the version of the user's structure. 1031159587Sjhb */ 1032159587Sjhb error = copyin(uap->stat, &stat, sizeof(struct kld_file_stat)); 1033159587Sjhb if (error) 1034159587Sjhb return (error); 1035159587Sjhb if (stat.version != sizeof(struct kld_file_stat)) 1036159587Sjhb return (EINVAL); 1037159587Sjhb 1038107089Srwatson#ifdef MAC 1039107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1040107089Srwatson if (error) 1041107089Srwatson return (error); 1042107089Srwatson#endif 1043107089Srwatson 104491040Sarr mtx_lock(&Giant); 104582749Sdillon 1046107849Salfred lf = linker_find_file_by_id(uap->fileid); 104791040Sarr if (lf == NULL) { 1048159587Sjhb mtx_unlock(&Giant); 1049159587Sjhb return (ENOENT); 105091040Sarr } 105125537Sdfr 105291040Sarr namelen = strlen(lf->filename) + 1; 105391040Sarr if (namelen > MAXPATHLEN) 105491040Sarr namelen = MAXPATHLEN; 1055159587Sjhb bcopy(lf->filename, &stat.name[0], namelen); 1056159587Sjhb stat.refs = lf->refs; 1057159587Sjhb stat.id = lf->id; 1058159587Sjhb stat.address = lf->address; 1059159587Sjhb stat.size = lf->size; 1060159587Sjhb mtx_unlock(&Giant); 106125537Sdfr 106291040Sarr td->td_retval[0] = 0; 1063159587Sjhb 1064159587Sjhb return (copyout(&stat, uap->stat, sizeof(struct kld_file_stat))); 106525537Sdfr} 106625537Sdfr 106782749Sdillon/* 106882749Sdillon * MPSAFE 106982749Sdillon */ 107025537Sdfrint 107191040Sarrkldfirstmod(struct thread *td, struct kldfirstmod_args *uap) 107225537Sdfr{ 107391040Sarr linker_file_t lf; 107491040Sarr module_t mp; 107591040Sarr int error = 0; 107625537Sdfr 1077107089Srwatson#ifdef MAC 1078107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1079107089Srwatson if (error) 1080107089Srwatson return (error); 1081107089Srwatson#endif 1082107089Srwatson 108391040Sarr mtx_lock(&Giant); 1084107849Salfred lf = linker_find_file_by_id(uap->fileid); 108591040Sarr if (lf) { 108692547Sarr MOD_SLOCK; 108791040Sarr mp = TAILQ_FIRST(&lf->modules); 108891040Sarr if (mp != NULL) 108991040Sarr td->td_retval[0] = module_getid(mp); 109091040Sarr else 109191040Sarr td->td_retval[0] = 0; 109292547Sarr MOD_SUNLOCK; 109391040Sarr } else 109491040Sarr error = ENOENT; 109591040Sarr mtx_unlock(&Giant); 109691040Sarr return (error); 109725537Sdfr} 109840159Speter 109982749Sdillon/* 110082749Sdillon * MPSAFE 110182749Sdillon */ 110241090Speterint 110383366Sjuliankldsym(struct thread *td, struct kldsym_args *uap) 110441090Speter{ 110591040Sarr char *symstr = NULL; 110691040Sarr c_linker_sym_t sym; 110791040Sarr linker_symval_t symval; 110891040Sarr linker_file_t lf; 110991040Sarr struct kld_sym_lookup lookup; 111091040Sarr int error = 0; 111141090Speter 1112107089Srwatson#ifdef MAC 1113107089Srwatson error = mac_check_kld_stat(td->td_ucred); 1114107089Srwatson if (error) 1115107089Srwatson return (error); 1116107089Srwatson#endif 1117107089Srwatson 111891040Sarr mtx_lock(&Giant); 111982749Sdillon 1120107849Salfred if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) 112191040Sarr goto out; 112291068Sarr if (lookup.version != sizeof(lookup) || 1123107849Salfred uap->cmd != KLDSYM_LOOKUP) { 112491040Sarr error = EINVAL; 112591040Sarr goto out; 112691040Sarr } 1127111119Simp symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 112891040Sarr if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) 112991040Sarr goto out; 1130107849Salfred if (uap->fileid != 0) { 1131107849Salfred lf = linker_find_file_by_id(uap->fileid); 113291040Sarr if (lf == NULL) { 113391040Sarr error = ENOENT; 113491040Sarr goto out; 113591040Sarr } 113691040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 113791040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 113891040Sarr lookup.symvalue = (uintptr_t) symval.value; 113991040Sarr lookup.symsize = symval.size; 1140107855Salfred error = copyout(&lookup, uap->data, sizeof(lookup)); 114191040Sarr } else 114291040Sarr error = ENOENT; 114391040Sarr } else { 114498452Sarr mtx_lock(&kld_mtx); 114591040Sarr TAILQ_FOREACH(lf, &linker_files, link) { 114691040Sarr if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && 114791040Sarr LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { 114891040Sarr lookup.symvalue = (uintptr_t)symval.value; 114991040Sarr lookup.symsize = symval.size; 1150107849Salfred error = copyout(&lookup, uap->data, 115191040Sarr sizeof(lookup)); 115291068Sarr break; 115391040Sarr } 115491040Sarr } 115598452Sarr mtx_unlock(&kld_mtx); 115691040Sarr if (lf == NULL) 115791040Sarr error = ENOENT; 115841090Speter } 115941090Speterout: 116091040Sarr if (symstr) 116191040Sarr free(symstr, M_TEMP); 116291040Sarr mtx_unlock(&Giant); 116391040Sarr return (error); 116441090Speter} 116541090Speter 116640159Speter/* 116740159Speter * Preloaded module support 116840159Speter */ 116940159Speter 117059751Speterstatic modlist_t 117174642Sbpmodlist_lookup(const char *name, int ver) 117259751Speter{ 117391040Sarr modlist_t mod; 117459751Speter 117591040Sarr TAILQ_FOREACH(mod, &found_modules, link) { 117692032Sdwmalone if (strcmp(mod->name, name) == 0 && 117792032Sdwmalone (ver == 0 || mod->version == ver)) 117891040Sarr return (mod); 117991040Sarr } 118091040Sarr return (NULL); 118159751Speter} 118259751Speter 118374642Sbpstatic modlist_t 118483321Spetermodlist_lookup2(const char *name, struct mod_depend *verinfo) 118583321Speter{ 118691040Sarr modlist_t mod, bestmod; 118792032Sdwmalone int ver; 118883321Speter 118991040Sarr if (verinfo == NULL) 119091040Sarr return (modlist_lookup(name, 0)); 119191040Sarr bestmod = NULL; 1192159586Sjhb TAILQ_FOREACH(mod, &found_modules, link) { 119392032Sdwmalone if (strcmp(mod->name, name) != 0) 119491040Sarr continue; 119591040Sarr ver = mod->version; 119691040Sarr if (ver == verinfo->md_ver_preferred) 119791040Sarr return (mod); 119891040Sarr if (ver >= verinfo->md_ver_minimum && 119991068Sarr ver <= verinfo->md_ver_maximum && 1200120382Sfjoe (bestmod == NULL || ver > bestmod->version)) 120191040Sarr bestmod = mod; 120291040Sarr } 120391040Sarr return (bestmod); 120483321Speter} 120583321Speter 120683321Speterstatic modlist_t 120778501Sdesmodlist_newmodule(const char *modname, int version, linker_file_t container) 120874642Sbp{ 120991040Sarr modlist_t mod; 121074642Sbp 121192705Sarr mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT | M_ZERO); 121291040Sarr if (mod == NULL) 121391040Sarr panic("no memory for module list"); 121491040Sarr mod->container = container; 121591040Sarr mod->name = modname; 121691040Sarr mod->version = version; 121791040Sarr TAILQ_INSERT_TAIL(&found_modules, mod, link); 121891040Sarr return (mod); 121974642Sbp} 122074642Sbp 122140159Speterstatic void 122278161Speterlinker_addmodules(linker_file_t lf, struct mod_metadata **start, 122391040Sarr struct mod_metadata **stop, int preload) 122474642Sbp{ 122591040Sarr struct mod_metadata *mp, **mdp; 122691040Sarr const char *modname; 122791040Sarr int ver; 122874642Sbp 122991040Sarr for (mdp = start; mdp < stop; mdp++) { 1230109605Sjake mp = *mdp; 123191040Sarr if (mp->md_type != MDT_VERSION) 123291040Sarr continue; 1233109605Sjake modname = mp->md_cval; 1234109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 123591040Sarr if (modlist_lookup(modname, ver) != NULL) { 123691040Sarr printf("module %s already present!\n", modname); 123791040Sarr /* XXX what can we do? this is a build error. :-( */ 123891040Sarr continue; 123991040Sarr } 124091040Sarr modlist_newmodule(modname, ver, lf); 124174642Sbp } 124274642Sbp} 124374642Sbp 124474642Sbpstatic void 124591040Sarrlinker_preload(void *arg) 124640159Speter{ 124791040Sarr caddr_t modptr; 124891040Sarr const char *modname, *nmodname; 124991040Sarr char *modtype; 125091040Sarr linker_file_t lf; 125191040Sarr linker_class_t lc; 125292032Sdwmalone int error; 125391040Sarr linker_file_list_t loaded_files; 125491040Sarr linker_file_list_t depended_files; 125591040Sarr struct mod_metadata *mp, *nmp; 125691040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 125791040Sarr struct mod_depend *verinfo; 125891040Sarr int nver; 125991040Sarr int resolves; 126091040Sarr modlist_t mod; 126191040Sarr struct sysinit **si_start, **si_stop; 126240159Speter 126391040Sarr TAILQ_INIT(&loaded_files); 126491040Sarr TAILQ_INIT(&depended_files); 126591040Sarr TAILQ_INIT(&found_modules); 126691040Sarr error = 0; 126759751Speter 126891040Sarr modptr = NULL; 126991040Sarr while ((modptr = preload_search_next_name(modptr)) != NULL) { 127091040Sarr modname = (char *)preload_search_info(modptr, MODINFO_NAME); 127191040Sarr modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 127291040Sarr if (modname == NULL) { 127391040Sarr printf("Preloaded module at %p does not have a" 127491040Sarr " name!\n", modptr); 127591040Sarr continue; 127691040Sarr } 127791040Sarr if (modtype == NULL) { 127891040Sarr printf("Preloaded module at %p does not have a type!\n", 127991040Sarr modptr); 128091040Sarr continue; 128191040Sarr } 1282131398Sjhb if (bootverbose) 1283131398Sjhb printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, 1284131398Sjhb modptr); 128540159Speter lf = NULL; 128691040Sarr TAILQ_FOREACH(lc, &classes, link) { 128791040Sarr error = LINKER_LINK_PRELOAD(lc, modname, &lf); 1288134364Siedowse if (!error) 128991040Sarr break; 1290134364Siedowse lf = NULL; 129191040Sarr } 129291040Sarr if (lf) 129391040Sarr TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); 129440159Speter } 129540159Speter 129691040Sarr /* 129791040Sarr * First get a list of stuff in the kernel. 129891040Sarr */ 129991040Sarr if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, 130091040Sarr &stop, NULL) == 0) 130191040Sarr linker_addmodules(linker_kernel_file, start, stop, 1); 130259751Speter 130359751Speter /* 130491040Sarr * this is a once-off kinky bubble sort resolve relocation dependency 130591040Sarr * requirements 130659751Speter */ 130791040Sarrrestart: 130891040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 130991040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 131091040Sarr &stop, NULL); 131191040Sarr /* 131291040Sarr * First, look to see if we would successfully link with this 131391040Sarr * stuff. 131491040Sarr */ 131591040Sarr resolves = 1; /* unless we know otherwise */ 131691040Sarr if (!error) { 131791040Sarr for (mdp = start; mdp < stop; mdp++) { 1318109605Sjake mp = *mdp; 131991040Sarr if (mp->md_type != MDT_DEPEND) 132091040Sarr continue; 1321109605Sjake modname = mp->md_cval; 1322109605Sjake verinfo = mp->md_data; 132391040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1324109605Sjake nmp = *nmdp; 132591040Sarr if (nmp->md_type != MDT_VERSION) 132691040Sarr continue; 1327109605Sjake nmodname = nmp->md_cval; 132892032Sdwmalone if (strcmp(modname, nmodname) == 0) 132991040Sarr break; 133091040Sarr } 133191040Sarr if (nmdp < stop) /* it's a self reference */ 133291040Sarr continue; 133391040Sarr 133491040Sarr /* 133591040Sarr * ok, the module isn't here yet, we 133691040Sarr * are not finished 133791040Sarr */ 133891068Sarr if (modlist_lookup2(modname, verinfo) == NULL) 133991040Sarr resolves = 0; 134091040Sarr } 134164143Speter } 134291040Sarr /* 134391040Sarr * OK, if we found our modules, we can link. So, "provide" 134491040Sarr * the modules inside and add it to the end of the link order 134591040Sarr * list. 134691040Sarr */ 134791040Sarr if (resolves) { 134891040Sarr if (!error) { 134991040Sarr for (mdp = start; mdp < stop; mdp++) { 1350109605Sjake mp = *mdp; 135191040Sarr if (mp->md_type != MDT_VERSION) 135291040Sarr continue; 1353109605Sjake modname = mp->md_cval; 1354109605Sjake nver = ((struct mod_version *) 1355109605Sjake mp->md_data)->mv_version; 135691040Sarr if (modlist_lookup(modname, 135791040Sarr nver) != NULL) { 135891040Sarr printf("module %s already" 135991040Sarr " present!\n", modname); 1360132117Sphk linker_file_unload(lf, 1361132117Sphk LINKER_UNLOAD_FORCE); 136291040Sarr TAILQ_REMOVE(&loaded_files, 136391040Sarr lf, loaded); 136491040Sarr /* we changed tailq next ptr */ 136591068Sarr goto restart; 136691040Sarr } 136791040Sarr modlist_newmodule(modname, nver, lf); 136891040Sarr } 136991040Sarr } 137091040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 137191040Sarr TAILQ_INSERT_TAIL(&depended_files, lf, loaded); 137291040Sarr /* 137391040Sarr * Since we provided modules, we need to restart the 137491040Sarr * sort so that the previous files that depend on us 137591040Sarr * have a chance. Also, we've busted the tailq next 137691040Sarr * pointer with the REMOVE. 137791040Sarr */ 137891040Sarr goto restart; 137959751Speter } 138059751Speter } 138191040Sarr 138259751Speter /* 138391040Sarr * At this point, we check to see what could not be resolved.. 138459751Speter */ 138591040Sarr TAILQ_FOREACH(lf, &loaded_files, loaded) { 138691040Sarr printf("KLD file %s is missing dependencies\n", lf->filename); 1387132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 138891040Sarr TAILQ_REMOVE(&loaded_files, lf, loaded); 138940159Speter } 139059751Speter 139178161Speter /* 139291040Sarr * We made it. Finish off the linking in the order we determined. 139378161Speter */ 139491040Sarr TAILQ_FOREACH(lf, &depended_files, loaded) { 139591040Sarr if (linker_kernel_file) { 139691040Sarr linker_kernel_file->refs++; 139791040Sarr error = linker_file_add_dependency(lf, 139891040Sarr linker_kernel_file); 139991040Sarr if (error) 140091040Sarr panic("cannot add dependency"); 140191040Sarr } 140291040Sarr lf->userrefs++; /* so we can (try to) kldunload it */ 140391040Sarr error = linker_file_lookup_set(lf, MDT_SETNAME, &start, 140491040Sarr &stop, NULL); 140591040Sarr if (!error) { 140691040Sarr for (mdp = start; mdp < stop; mdp++) { 1407109605Sjake mp = *mdp; 140891040Sarr if (mp->md_type != MDT_DEPEND) 140991040Sarr continue; 1410109605Sjake modname = mp->md_cval; 1411109605Sjake verinfo = mp->md_data; 141291040Sarr mod = modlist_lookup2(modname, verinfo); 1413151484Sjdp /* Don't count self-dependencies */ 1414151484Sjdp if (lf == mod->container) 1415151484Sjdp continue; 141691040Sarr mod->container->refs++; 141791040Sarr error = linker_file_add_dependency(lf, 141891040Sarr mod->container); 141991040Sarr if (error) 142091040Sarr panic("cannot add dependency"); 142191040Sarr } 142291040Sarr } 142391040Sarr /* 142491040Sarr * Now do relocation etc using the symbol search paths 142591040Sarr * established by the dependencies 142691040Sarr */ 142791040Sarr error = LINKER_LINK_PRELOAD_FINISH(lf); 142891040Sarr if (error) { 142991040Sarr printf("KLD file %s - could not finalize loading\n", 143091040Sarr lf->filename); 1431132117Sphk linker_file_unload(lf, LINKER_UNLOAD_FORCE); 143291040Sarr continue; 143391040Sarr } 143491040Sarr linker_file_register_modules(lf); 143591040Sarr if (linker_file_lookup_set(lf, "sysinit_set", &si_start, 143691040Sarr &si_stop, NULL) == 0) 143791040Sarr sysinit_add(si_start, si_stop); 143891040Sarr linker_file_register_sysctls(lf); 143991040Sarr lf->flags |= LINKER_FILE_LINKED; 144059751Speter } 144191040Sarr /* woohoo! we made it! */ 144240159Speter} 144340159Speter 144491040SarrSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0) 144540159Speter 144640159Speter/* 144740159Speter * Search for a not-loaded module by name. 144891040Sarr * 144940159Speter * Modules may be found in the following locations: 145091040Sarr * 145191040Sarr * - preloaded (result is just the module name) - on disk (result is full path 145291040Sarr * to module) 145391040Sarr * 145491040Sarr * If the module name is qualified in any way (contains path, etc.) the we 145591040Sarr * simply return a copy of it. 145691040Sarr * 145740159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 145840159Speter * character as a separator to be consistent with the bootloader. 145940159Speter */ 146040159Speter 146183321Speterstatic char linker_hintfile[] = "linker.hints"; 1462111852Srustatic char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; 146340159Speter 146440159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 146591040Sarr sizeof(linker_path), "module load search path"); 146640159Speter 146777843SpeterTUNABLE_STR("module_path", linker_path, sizeof(linker_path)); 146870417Speter 146959751Speterstatic char *linker_ext_list[] = { 147083321Speter "", 147159751Speter ".ko", 147259751Speter NULL 147359751Speter}; 147459751Speter 147583321Speter/* 147691040Sarr * Check if file actually exists either with or without extension listed in 147791040Sarr * the linker_ext_list. (probably should be generic for the rest of the 147891040Sarr * kernel) 147983321Speter */ 148059751Speterstatic char * 148191040Sarrlinker_lookup_file(const char *path, int pathlen, const char *name, 148291040Sarr int namelen, struct vattr *vap) 148340159Speter{ 148491040Sarr struct nameidata nd; 148591040Sarr struct thread *td = curthread; /* XXX */ 148691040Sarr char *result, **cpp, *sep; 1487159808Sjhb int error, len, extlen, reclen, flags, vfslocked; 148891040Sarr enum vtype type; 148940159Speter 149091040Sarr extlen = 0; 149191040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 149291040Sarr len = strlen(*cpp); 149391040Sarr if (len > extlen) 149491040Sarr extlen = len; 149591040Sarr } 149691040Sarr extlen++; /* trailing '\0' */ 149791040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 149883321Speter 149991040Sarr reclen = pathlen + strlen(sep) + namelen + extlen + 1; 1500111119Simp result = malloc(reclen, M_LINKER, M_WAITOK); 150191040Sarr for (cpp = linker_ext_list; *cpp; cpp++) { 150291040Sarr snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, 150391040Sarr namelen, name, *cpp); 150491040Sarr /* 150591040Sarr * Attempt to open the file, and return the path if 150691040Sarr * we succeed and it's a regular file. 150791040Sarr */ 1508159808Sjhb NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); 150991040Sarr flags = FREAD; 1510118094Sphk error = vn_open(&nd, &flags, 0, -1); 151191040Sarr if (error == 0) { 1512159808Sjhb vfslocked = NDHASGIANT(&nd); 151391040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 151491040Sarr type = nd.ni_vp->v_type; 151591040Sarr if (vap) 151691406Sjhb VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 151791040Sarr VOP_UNLOCK(nd.ni_vp, 0, td); 151891406Sjhb vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 1519159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 152091040Sarr if (type == VREG) 152191040Sarr return (result); 152291040Sarr } 152383321Speter } 152491040Sarr free(result, M_LINKER); 152591040Sarr return (NULL); 152683321Speter} 152783321Speter 152891040Sarr#define INT_ALIGN(base, ptr) ptr = \ 152983321Speter (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 153083321Speter 153183321Speter/* 153291040Sarr * Lookup KLD which contains requested module in the "linker.hints" file. If 153391040Sarr * version specification is available, then try to find the best KLD. 153483321Speter * Otherwise just find the latest one. 153583321Speter */ 153683321Speterstatic char * 153791040Sarrlinker_hints_lookup(const char *path, int pathlen, const char *modname, 153891040Sarr int modnamelen, struct mod_depend *verinfo) 153983321Speter{ 154091040Sarr struct thread *td = curthread; /* XXX */ 154191406Sjhb struct ucred *cred = td ? td->td_ucred : NULL; 154291040Sarr struct nameidata nd; 154391040Sarr struct vattr vattr, mattr; 154491040Sarr u_char *hints = NULL; 154591040Sarr u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; 154691040Sarr int error, ival, bestver, *intp, reclen, found, flags, clen, blen; 1547159808Sjhb int vfslocked = 0; 154883321Speter 154991040Sarr result = NULL; 155091040Sarr bestver = found = 0; 155183321Speter 155291040Sarr sep = (path[pathlen - 1] != '/') ? "/" : ""; 155391040Sarr reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + 155491040Sarr strlen(sep) + 1; 1555111119Simp pathbuf = malloc(reclen, M_LINKER, M_WAITOK); 155691040Sarr snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, 155791040Sarr linker_hintfile); 155883321Speter 1559159808Sjhb NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); 156091040Sarr flags = FREAD; 1561118094Sphk error = vn_open(&nd, &flags, 0, -1); 156291040Sarr if (error) 156391040Sarr goto bad; 1564159808Sjhb vfslocked = NDHASGIANT(&nd); 156591040Sarr NDFREE(&nd, NDF_ONLY_PNBUF); 156691040Sarr if (nd.ni_vp->v_type != VREG) 156791040Sarr goto bad; 156891040Sarr best = cp = NULL; 156991040Sarr error = VOP_GETATTR(nd.ni_vp, &vattr, cred, td); 157091040Sarr if (error) 157191040Sarr goto bad; 157291040Sarr /* 157391040Sarr * XXX: we need to limit this number to some reasonable value 157491040Sarr */ 157591040Sarr if (vattr.va_size > 100 * 1024) { 157691040Sarr printf("hints file too large %ld\n", (long)vattr.va_size); 157791040Sarr goto bad; 157891040Sarr } 1579111119Simp hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); 158091040Sarr if (hints == NULL) 158191040Sarr goto bad; 158291068Sarr error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, 1583101941Srwatson UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); 158491040Sarr if (error) 158591040Sarr goto bad; 158699553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 158791040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1588159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 158991040Sarr nd.ni_vp = NULL; 159091040Sarr if (reclen != 0) { 159191040Sarr printf("can't read %d\n", reclen); 159291040Sarr goto bad; 159391040Sarr } 159491040Sarr intp = (int *)hints; 159583321Speter ival = *intp++; 159691040Sarr if (ival != LINKER_HINTS_VERSION) { 159791040Sarr printf("hints file version mismatch %d\n", ival); 159891040Sarr goto bad; 159983321Speter } 160091040Sarr bufend = hints + vattr.va_size; 160191040Sarr recptr = (u_char *)intp; 160291040Sarr clen = blen = 0; 160391040Sarr while (recptr < bufend && !found) { 160491040Sarr intp = (int *)recptr; 160591040Sarr reclen = *intp++; 160691040Sarr ival = *intp++; 160791040Sarr cp = (char *)intp; 160891040Sarr switch (ival) { 160991040Sarr case MDT_VERSION: 161091040Sarr clen = *cp++; 161191040Sarr if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 161291040Sarr break; 161391040Sarr cp += clen; 161491040Sarr INT_ALIGN(hints, cp); 161591040Sarr ival = *(int *)cp; 161691040Sarr cp += sizeof(int); 161791040Sarr clen = *cp++; 161891040Sarr if (verinfo == NULL || 161991040Sarr ival == verinfo->md_ver_preferred) { 162091040Sarr found = 1; 162191040Sarr break; 162291040Sarr } 162391040Sarr if (ival >= verinfo->md_ver_minimum && 162491040Sarr ival <= verinfo->md_ver_maximum && 162591040Sarr ival > bestver) { 162691040Sarr bestver = ival; 162791040Sarr best = cp; 162891040Sarr blen = clen; 162991040Sarr } 163091040Sarr break; 163191040Sarr default: 163291040Sarr break; 163391040Sarr } 163491040Sarr recptr += reclen + sizeof(int); 163591040Sarr } 163683321Speter /* 163791040Sarr * Finally check if KLD is in the place 163883321Speter */ 163991040Sarr if (found) 164091040Sarr result = linker_lookup_file(path, pathlen, cp, clen, &mattr); 164191040Sarr else if (best) 164291040Sarr result = linker_lookup_file(path, pathlen, best, blen, &mattr); 164391040Sarr 164491040Sarr /* 164591040Sarr * KLD is newer than hints file. What we should do now? 164691040Sarr */ 164791040Sarr if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)) 164891040Sarr printf("warning: KLD '%s' is newer than the linker.hints" 164991040Sarr " file\n", result); 165083321Speterbad: 1651105167Sphk free(pathbuf, M_LINKER); 165291040Sarr if (hints) 165391040Sarr free(hints, M_TEMP); 165499553Sjeff if (nd.ni_vp != NULL) { 165599553Sjeff VOP_UNLOCK(nd.ni_vp, 0, td); 165691040Sarr vn_close(nd.ni_vp, FREAD, cred, td); 1657159808Sjhb VFS_UNLOCK_GIANT(vfslocked); 165899553Sjeff } 165991040Sarr /* 166091040Sarr * If nothing found or hints is absent - fallback to the old 166191040Sarr * way by using "kldname[.ko]" as module name. 166291040Sarr */ 166391040Sarr if (!found && !bestver && result == NULL) 166491040Sarr result = linker_lookup_file(path, pathlen, modname, 166591040Sarr modnamelen, NULL); 166691040Sarr return (result); 166783321Speter} 166883321Speter 166983321Speter/* 167083321Speter * Lookup KLD which contains requested module in the all directories. 167183321Speter */ 167283321Speterstatic char * 167383321Speterlinker_search_module(const char *modname, int modnamelen, 167491040Sarr struct mod_depend *verinfo) 167583321Speter{ 167691040Sarr char *cp, *ep, *result; 167783321Speter 167891040Sarr /* 167991040Sarr * traverse the linker path 168091040Sarr */ 168191040Sarr for (cp = linker_path; *cp; cp = ep + 1) { 168291040Sarr /* find the end of this component */ 168391040Sarr for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); 168491068Sarr result = linker_hints_lookup(cp, ep - cp, modname, 168591068Sarr modnamelen, verinfo); 168691040Sarr if (result != NULL) 168791040Sarr return (result); 168891040Sarr if (*ep == 0) 168991040Sarr break; 169091040Sarr } 169191040Sarr return (NULL); 169283321Speter} 169383321Speter 169483321Speter/* 169583321Speter * Search for module in all directories listed in the linker_path. 169683321Speter */ 169783321Speterstatic char * 169883321Speterlinker_search_kld(const char *name) 169983321Speter{ 1700158972Sdelphij char *cp, *ep, *result; 1701158972Sdelphij int len; 170283321Speter 170391040Sarr /* qualified at all? */ 170491040Sarr if (index(name, '/')) 170591040Sarr return (linker_strdup(name)); 170640159Speter 170791040Sarr /* traverse the linker path */ 170891040Sarr len = strlen(name); 170991040Sarr for (ep = linker_path; *ep; ep++) { 171091040Sarr cp = ep; 171191040Sarr /* find the end of this component */ 171291040Sarr for (; *ep != 0 && *ep != ';'; ep++); 171391040Sarr result = linker_lookup_file(cp, ep - cp, name, len, NULL); 171491040Sarr if (result != NULL) 171591040Sarr return (result); 171691040Sarr } 171791040Sarr return (NULL); 171840159Speter} 171959751Speter 172059751Speterstatic const char * 172191040Sarrlinker_basename(const char *path) 172259751Speter{ 172391040Sarr const char *filename; 172459751Speter 172591040Sarr filename = rindex(path, '/'); 172691040Sarr if (filename == NULL) 172791040Sarr return path; 172891040Sarr if (filename[1]) 172991040Sarr filename++; 173091040Sarr return (filename); 173159751Speter} 173259751Speter 1733157144Sjkoshy#ifdef HWPMC_HOOKS 1734157144Sjkoshy 1735159797Sjhbstruct hwpmc_context { 1736159797Sjhb int nobjects; 1737159797Sjhb int nmappings; 1738159797Sjhb struct pmckern_map_in *kobase; 1739159797Sjhb}; 1740159797Sjhb 1741159797Sjhbstatic int 1742159797Sjhblinker_hwpmc_list_object(linker_file_t lf, void *arg) 1743159797Sjhb{ 1744159797Sjhb struct hwpmc_context *hc; 1745159797Sjhb 1746159797Sjhb hc = arg; 1747159797Sjhb 1748159797Sjhb /* If we run out of mappings, fail. */ 1749159797Sjhb if (hc->nobjects >= hc->nmappings) 1750159797Sjhb return (1); 1751159797Sjhb 1752159797Sjhb /* Save the info for this linker file. */ 1753159797Sjhb hc->kobase[hc->nobjects].pm_file = lf->filename; 1754159797Sjhb hc->kobase[hc->nobjects].pm_address = (uintptr_t)lf->address; 1755159797Sjhb hc->nobjects++; 1756159797Sjhb return (0); 1757159797Sjhb} 1758159797Sjhb 175959751Speter/* 1760157144Sjkoshy * Inform hwpmc about the set of kernel modules currently loaded. 1761157144Sjkoshy */ 1762157144Sjkoshyvoid * 1763157144Sjkoshylinker_hwpmc_list_objects(void) 1764157144Sjkoshy{ 1765159797Sjhb struct hwpmc_context hc; 1766157144Sjkoshy 1767159797Sjhb hc.nmappings = 15; /* a reasonable default */ 1768157144Sjkoshy 1769157144Sjkoshy retry: 1770157144Sjkoshy /* allocate nmappings+1 entries */ 1771159797Sjhb MALLOC(hc.kobase, struct pmckern_map_in *, 1772159797Sjhb (hc.nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, 1773157144Sjkoshy M_WAITOK | M_ZERO); 1774157144Sjkoshy 1775159797Sjhb hc.nobjects = 0; 1776159797Sjhb if (linker_file_foreach(linker_hwpmc_list_object, &hc) != 0) { 1777159797Sjhb hc.nmappings = hc.nobjects; 1778159797Sjhb FREE(hc.kobase, M_LINKER); 1779157144Sjkoshy goto retry; 1780157144Sjkoshy } 1781157144Sjkoshy 1782159797Sjhb KASSERT(hc.nobjects > 0, ("linker_hpwmc_list_objects: no kernel " 1783159797Sjhb "objects?")); 1784157144Sjkoshy 1785157144Sjkoshy /* The last entry of the malloced area comprises of all zeros. */ 1786159797Sjhb KASSERT(hc.kobase[hc.nobjects].pm_file == NULL, 1787157144Sjkoshy ("linker_hwpmc_list_objects: last object not NULL")); 1788157144Sjkoshy 1789159797Sjhb return ((void *)hc.kobase); 1790157144Sjkoshy} 1791157144Sjkoshy#endif 1792157144Sjkoshy 1793157144Sjkoshy/* 179491040Sarr * Find a file which contains given module and load it, if "parent" is not 179591040Sarr * NULL, register a reference to it. 179659751Speter */ 1797159796Sjhbstatic int 179883321Speterlinker_load_module(const char *kldname, const char *modname, 179991040Sarr struct linker_file *parent, struct mod_depend *verinfo, 180091040Sarr struct linker_file **lfpp) 180159751Speter{ 180291040Sarr linker_file_t lfdep; 180391040Sarr const char *filename; 180491040Sarr char *pathname; 180591040Sarr int error; 180659751Speter 180791040Sarr if (modname == NULL) { 180891040Sarr /* 180991040Sarr * We have to load KLD 181091040Sarr */ 181191068Sarr KASSERT(verinfo == NULL, ("linker_load_module: verinfo" 181291068Sarr " is not NULL")); 181391040Sarr pathname = linker_search_kld(kldname); 181491040Sarr } else { 181591040Sarr if (modlist_lookup2(modname, verinfo) != NULL) 181691040Sarr return (EEXIST); 181794322Sbrian if (kldname != NULL) 181894322Sbrian pathname = linker_strdup(kldname); 181995488Sbrian else if (rootvnode == NULL) 182094322Sbrian pathname = NULL; 182194322Sbrian else 182291040Sarr /* 182391040Sarr * Need to find a KLD with required module 182491040Sarr */ 182591040Sarr pathname = linker_search_module(modname, 182691040Sarr strlen(modname), verinfo); 182791040Sarr } 182891040Sarr if (pathname == NULL) 182991040Sarr return (ENOENT); 183091040Sarr 183183321Speter /* 183291040Sarr * Can't load more than one file with the same basename XXX: 183391040Sarr * Actually it should be possible to have multiple KLDs with 183491040Sarr * the same basename but different path because they can 183591040Sarr * provide different versions of the same modules. 183683321Speter */ 183791040Sarr filename = linker_basename(pathname); 1838159792Sjhb if (linker_find_file_by_name(filename)) 183991040Sarr error = EEXIST; 1840159792Sjhb else do { 184191040Sarr error = linker_load_file(pathname, &lfdep); 184291040Sarr if (error) 184391040Sarr break; 184491040Sarr if (modname && verinfo && 184591040Sarr modlist_lookup2(modname, verinfo) == NULL) { 1846132117Sphk linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); 184791040Sarr error = ENOENT; 184891040Sarr break; 184991040Sarr } 185091040Sarr if (parent) { 185191040Sarr error = linker_file_add_dependency(parent, lfdep); 185291040Sarr if (error) 185391040Sarr break; 185491040Sarr } 185591040Sarr if (lfpp) 185691040Sarr *lfpp = lfdep; 185791040Sarr } while (0); 1858159791Sjhb free(pathname, M_LINKER); 185991040Sarr return (error); 186059751Speter} 186159751Speter 186259751Speter/* 186391040Sarr * This routine is responsible for finding dependencies of userland initiated 186491040Sarr * kldload(2)'s of files. 186559751Speter */ 186659751Speterint 186786469Siedowselinker_load_dependencies(linker_file_t lf) 186859751Speter{ 186991040Sarr linker_file_t lfdep; 187091040Sarr struct mod_metadata **start, **stop, **mdp, **nmdp; 187191040Sarr struct mod_metadata *mp, *nmp; 187291040Sarr struct mod_depend *verinfo; 187391040Sarr modlist_t mod; 187491040Sarr const char *modname, *nmodname; 187592032Sdwmalone int ver, error = 0, count; 187659751Speter 187791040Sarr /* 187891040Sarr * All files are dependant on /kernel. 187991040Sarr */ 188091040Sarr if (linker_kernel_file) { 188191040Sarr linker_kernel_file->refs++; 188291040Sarr error = linker_file_add_dependency(lf, linker_kernel_file); 188391040Sarr if (error) 188491040Sarr return (error); 188559751Speter } 188691040Sarr if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, 188791040Sarr &count) != 0) 188891040Sarr return (0); 188991040Sarr for (mdp = start; mdp < stop; mdp++) { 1890109605Sjake mp = *mdp; 189191040Sarr if (mp->md_type != MDT_VERSION) 189291040Sarr continue; 1893109605Sjake modname = mp->md_cval; 1894109605Sjake ver = ((struct mod_version *)mp->md_data)->mv_version; 189591040Sarr mod = modlist_lookup(modname, ver); 189691040Sarr if (mod != NULL) { 189791040Sarr printf("interface %s.%d already present in the KLD" 189891040Sarr " '%s'!\n", modname, ver, 189991040Sarr mod->container->filename); 190091040Sarr return (EEXIST); 190191040Sarr } 190291040Sarr } 190374642Sbp 190491040Sarr for (mdp = start; mdp < stop; mdp++) { 1905109605Sjake mp = *mdp; 190691040Sarr if (mp->md_type != MDT_DEPEND) 190791040Sarr continue; 1908109605Sjake modname = mp->md_cval; 1909109605Sjake verinfo = mp->md_data; 191091040Sarr nmodname = NULL; 191191040Sarr for (nmdp = start; nmdp < stop; nmdp++) { 1912109605Sjake nmp = *nmdp; 191391040Sarr if (nmp->md_type != MDT_VERSION) 191491040Sarr continue; 1915109605Sjake nmodname = nmp->md_cval; 191692032Sdwmalone if (strcmp(modname, nmodname) == 0) 191791040Sarr break; 191891040Sarr } 191991040Sarr if (nmdp < stop)/* early exit, it's a self reference */ 192091040Sarr continue; 192191040Sarr mod = modlist_lookup2(modname, verinfo); 192291040Sarr if (mod) { /* woohoo, it's loaded already */ 192391040Sarr lfdep = mod->container; 192491040Sarr lfdep->refs++; 192591040Sarr error = linker_file_add_dependency(lf, lfdep); 192691040Sarr if (error) 192791040Sarr break; 192891040Sarr continue; 192991040Sarr } 193091040Sarr error = linker_load_module(NULL, modname, lf, verinfo, NULL); 193191040Sarr if (error) { 193291040Sarr printf("KLD %s: depends on %s - not available\n", 193391040Sarr lf->filename, modname); 193491040Sarr break; 193591040Sarr } 193659751Speter } 193759751Speter 193891040Sarr if (error) 193991040Sarr return (error); 194091040Sarr linker_addmodules(lf, start, stop, 0); 194191040Sarr return (error); 194259751Speter} 194385736Sgreen 194485736Sgreenstatic int 194585736Sgreensysctl_kern_function_list_iterate(const char *name, void *opaque) 194685736Sgreen{ 194785736Sgreen struct sysctl_req *req; 194885736Sgreen 194985736Sgreen req = opaque; 195085736Sgreen return (SYSCTL_OUT(req, name, strlen(name) + 1)); 195185736Sgreen} 195285736Sgreen 195385736Sgreen/* 195485736Sgreen * Export a nul-separated, double-nul-terminated list of all function names 195585736Sgreen * in the kernel. 195685736Sgreen */ 195785736Sgreenstatic int 195885736Sgreensysctl_kern_function_list(SYSCTL_HANDLER_ARGS) 195985736Sgreen{ 196085736Sgreen linker_file_t lf; 196185736Sgreen int error; 196285736Sgreen 1963107089Srwatson#ifdef MAC 1964107089Srwatson error = mac_check_kld_stat(req->td->td_ucred); 1965107089Srwatson if (error) 1966107089Srwatson return (error); 1967107089Srwatson#endif 1968126253Struckman error = sysctl_wire_old_buffer(req, 0); 1969126253Struckman if (error != 0) 1970126253Struckman return (error); 197198452Sarr mtx_lock(&kld_mtx); 197285736Sgreen TAILQ_FOREACH(lf, &linker_files, link) { 197385736Sgreen error = LINKER_EACH_FUNCTION_NAME(lf, 197485736Sgreen sysctl_kern_function_list_iterate, req); 197598452Sarr if (error) { 197698452Sarr mtx_unlock(&kld_mtx); 197785736Sgreen return (error); 197898452Sarr } 197985736Sgreen } 198098452Sarr mtx_unlock(&kld_mtx); 198185736Sgreen return (SYSCTL_OUT(req, "", 1)); 198285736Sgreen} 198385736Sgreen 198485736SgreenSYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, 198591040Sarr NULL, 0, sysctl_kern_function_list, "", "kernel function list"); 1986