kern_linker.c revision 32153
125537Sdfr/*- 225537Sdfr * Copyright (c) 1997 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 * 2632153Sbde * $Id: kern_linker.c,v 1.5 1997/12/12 04:00:59 dyson Exp $ 2725537Sdfr */ 2825537Sdfr 2925537Sdfr#include <sys/param.h> 3025537Sdfr#include <sys/kernel.h> 3125537Sdfr#include <sys/systm.h> 3225537Sdfr#include <sys/malloc.h> 3325537Sdfr#include <sys/sysproto.h> 3425537Sdfr#include <sys/sysent.h> 3525537Sdfr#include <sys/proc.h> 3625537Sdfr#include <sys/lock.h> 3725537Sdfr#include <machine/cpu.h> 3825537Sdfr#include <sys/module.h> 3925537Sdfr#include <sys/linker.h> 4031675Sdyson#include <sys/unistd.h> 4125537Sdfr 4232153SbdeMALLOC_DEFINE(M_LINKER, "kld", "kernel linker"); 4331324Sbdelinker_file_t linker_current_file; 4431324Sbde 4525537Sdfrstatic struct lock lock; /* lock for the file list */ 4625537Sdfrstatic linker_class_list_t classes; 4725537Sdfrstatic linker_file_list_t files; 4825537Sdfrstatic int next_file_id = 1; 4925537Sdfr 5025537Sdfrstatic void 5125537Sdfrlinker_init(void* arg) 5225537Sdfr{ 5325537Sdfr lockinit(&lock, PVM, "klink", 0, 0); 5425537Sdfr TAILQ_INIT(&classes); 5525537Sdfr TAILQ_INIT(&files); 5625537Sdfr} 5725537Sdfr 5825537SdfrSYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0); 5925537Sdfr 6025537Sdfrint 6125537Sdfrlinker_add_class(const char* desc, void* priv, 6225537Sdfr struct linker_class_ops* ops) 6325537Sdfr{ 6425537Sdfr linker_class_t lc; 6525537Sdfr 6625537Sdfr lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); 6725537Sdfr if (!lc) 6825537Sdfr return ENOMEM; 6925537Sdfr 7025537Sdfr lc->desc = desc; 7125537Sdfr lc->priv = priv; 7225537Sdfr lc->ops = ops; 7325537Sdfr TAILQ_INSERT_HEAD(&classes, lc, link); 7425537Sdfr 7525537Sdfr return 0; 7625537Sdfr} 7725537Sdfr 7825537Sdfrstatic void 7925537Sdfrlinker_file_sysinit(linker_file_t lf) 8025537Sdfr{ 8125537Sdfr struct linker_set* sysinits; 8225537Sdfr struct sysinit** sipp; 8325537Sdfr struct sysinit** xipp; 8425537Sdfr struct sysinit* save; 8525537Sdfr 8625537Sdfr linker_current_file = lf; 8725537Sdfr 8825537Sdfr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 8925537Sdfr lf->filename)); 9025537Sdfr 9125537Sdfr sysinits = (struct linker_set*) 9225537Sdfr linker_file_lookup_symbol(lf, "sysinit_set", 0); 9325537Sdfr if (!sysinits) 9425537Sdfr return; 9525537Sdfr 9625537Sdfr /* 9725537Sdfr * Perform a bubble sort of the system initialization objects by 9825537Sdfr * their subsystem (primary key) and order (secondary key). 9925537Sdfr * 10025537Sdfr * Since some things care about execution order, this is the 10125537Sdfr * operation which ensures continued function. 10225537Sdfr */ 10325537Sdfr for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 10425537Sdfr for( xipp = sipp + 1; *xipp; xipp++) { 10525537Sdfr if( (*sipp)->subsystem < (*xipp)->subsystem || 10625537Sdfr ( (*sipp)->subsystem == (*xipp)->subsystem && 10725537Sdfr (*sipp)->order < (*xipp)->order)) 10825537Sdfr continue; /* skip*/ 10925537Sdfr save = *sipp; 11025537Sdfr *sipp = *xipp; 11125537Sdfr *xipp = save; 11225537Sdfr } 11325537Sdfr } 11425537Sdfr 11525537Sdfr 11625537Sdfr /* 11725537Sdfr * Traverse the (now) ordered list of system initialization tasks. 11825537Sdfr * Perform each task, and continue on to the next task. 11925537Sdfr * 12025537Sdfr * The last item on the list is expected to be the scheduler, 12125537Sdfr * which will not return. 12225537Sdfr */ 12325537Sdfr for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 12425537Sdfr if( (*sipp)->subsystem == SI_SUB_DUMMY) 12525537Sdfr continue; /* skip dummy task(s)*/ 12625537Sdfr 12725537Sdfr switch( (*sipp)->type) { 12825537Sdfr case SI_TYPE_DEFAULT: 12925537Sdfr /* no special processing*/ 13025537Sdfr (*((*sipp)->func))( (*sipp)->udata); 13125537Sdfr break; 13225537Sdfr 13325537Sdfr case SI_TYPE_KTHREAD: 13431675Sdyson#if !defined(SMP) 13525537Sdfr /* kernel thread*/ 13631675Sdyson if (fork1(&proc0, RFFDG|RFPROC|RFMEM)) 13731675Sdyson panic("fork kernel thread"); 13831675Sdyson cpu_set_fork_handler(pfind(proc0.p_retval[0]), 13931675Sdyson (*sipp)->func, (*sipp)->udata); 14031675Sdyson break; 14131675Sdyson#endif 14231675Sdyson 14331675Sdyson case SI_TYPE_KPROCESS: 14431675Sdyson /* kernel thread*/ 14531675Sdyson if (fork1(&proc0, RFFDG|RFPROC)) 14625537Sdfr panic("fork kernel process"); 14730994Sphk cpu_set_fork_handler(pfind(proc0.p_retval[0]), 14830994Sphk (*sipp)->func, (*sipp)->udata); 14925537Sdfr break; 15025537Sdfr 15125537Sdfr default: 15225537Sdfr panic( "linker_file_sysinit: unrecognized init type"); 15325537Sdfr } 15425537Sdfr } 15525537Sdfr} 15625537Sdfr 15725537Sdfrint 15825537Sdfrlinker_load_file(const char* filename, linker_file_t* result) 15925537Sdfr{ 16025537Sdfr linker_class_t lc; 16125537Sdfr linker_file_t lf; 16225537Sdfr int error = 0; 16325537Sdfr 16425537Sdfr lf = linker_find_file_by_name(filename); 16525537Sdfr if (lf) { 16625537Sdfr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); 16725537Sdfr *result = lf; 16825537Sdfr lf->refs++; 16925537Sdfr goto out; 17025537Sdfr } 17125537Sdfr 17225537Sdfr lf = NULL; 17325537Sdfr for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { 17425537Sdfr KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", 17525537Sdfr filename, lc->desc)); 17625537Sdfr if (error = lc->ops->load_file(filename, &lf)) 17725537Sdfr goto out; 17825537Sdfr if (lf) { 17925537Sdfr linker_file_sysinit(lf); 18025537Sdfr 18125537Sdfr *result = lf; 18225537Sdfr goto out; 18325537Sdfr } 18425537Sdfr } 18525537Sdfr 18625537Sdfr error = ENOEXEC; /* format not recognised */ 18725537Sdfr 18825537Sdfrout: 18925537Sdfr return error; 19025537Sdfr} 19125537Sdfr 19225537Sdfrlinker_file_t 19325537Sdfrlinker_find_file_by_name(const char* filename) 19425537Sdfr{ 19525537Sdfr linker_file_t lf = 0; 19625537Sdfr 19725537Sdfr lockmgr(&lock, LK_SHARED, 0, curproc); 19825537Sdfr for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 19925537Sdfr if (!strcmp(lf->filename, filename)) 20025537Sdfr break; 20125537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 20225537Sdfr 20325537Sdfr return lf; 20425537Sdfr} 20525537Sdfr 20625537Sdfrlinker_file_t 20725537Sdfrlinker_find_file_by_id(int fileid) 20825537Sdfr{ 20925537Sdfr linker_file_t lf = 0; 21025537Sdfr 21125537Sdfr lockmgr(&lock, LK_SHARED, 0, curproc); 21225537Sdfr for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 21325537Sdfr if (lf->id == fileid) 21425537Sdfr break; 21525537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 21625537Sdfr 21725537Sdfr return lf; 21825537Sdfr} 21925537Sdfr 22025537Sdfrlinker_file_t 22125537Sdfrlinker_make_file(const char* filename, void* priv, struct linker_file_ops* ops) 22225537Sdfr{ 22325537Sdfr linker_file_t lf = 0; 22425537Sdfr int namelen; 22525537Sdfr 22625537Sdfr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 22725537Sdfr lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 22825537Sdfr namelen = strlen(filename) + 1; 22925537Sdfr lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); 23025537Sdfr if (!lf) 23125537Sdfr goto out; 23225537Sdfr 23325537Sdfr lf->refs = 1; 23425537Sdfr lf->userrefs = 0; 23525537Sdfr lf->filename = (char*) (lf + 1); 23625537Sdfr strcpy(lf->filename, filename); 23725537Sdfr lf->id = next_file_id++; 23825537Sdfr lf->ndeps = 0; 23925537Sdfr lf->deps = NULL; 24025537Sdfr STAILQ_INIT(&lf->common); 24125537Sdfr TAILQ_INIT(&lf->modules); 24225537Sdfr 24325537Sdfr lf->priv = priv; 24425537Sdfr lf->ops = ops; 24525537Sdfr TAILQ_INSERT_TAIL(&files, lf, link); 24625537Sdfr 24725537Sdfrout: 24825537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 24925537Sdfr return lf; 25025537Sdfr} 25125537Sdfr 25225537Sdfrint 25325537Sdfrlinker_file_unload(linker_file_t file) 25425537Sdfr{ 25525537Sdfr module_t mod, next; 25625537Sdfr struct common_symbol* cp; 25725537Sdfr int error = 0; 25825537Sdfr int i; 25925537Sdfr 26025537Sdfr KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs)); 26125537Sdfr lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 26225537Sdfr if (file->refs == 1) { 26325537Sdfr KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); 26425537Sdfr /* 26525537Sdfr * Inform any modules associated with this file. 26625537Sdfr */ 26725537Sdfr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 26825537Sdfr next = module_getfnext(mod); 26925537Sdfr 27025537Sdfr /* 27125537Sdfr * Give the module a chance to veto the unload. 27225537Sdfr */ 27325537Sdfr if (error = module_unload(mod)) { 27425537Sdfr KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", 27525537Sdfr mod)); 27625537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 27725537Sdfr goto out; 27825537Sdfr } 27925537Sdfr 28025537Sdfr module_release(mod); 28125537Sdfr } 28225537Sdfr } 28325537Sdfr 28425537Sdfr file->refs--; 28525537Sdfr if (file->refs > 0) { 28625537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 28725537Sdfr goto out; 28825537Sdfr } 28925537Sdfr 29025537Sdfr TAILQ_REMOVE(&files, file, link); 29125537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 29225537Sdfr 29325537Sdfr for (i = 0; i < file->ndeps; i++) 29425537Sdfr linker_file_unload(file->deps[i]); 29525537Sdfr free(file->deps, M_LINKER); 29625537Sdfr 29725537Sdfr for (cp = STAILQ_FIRST(&file->common); cp; 29825537Sdfr cp = STAILQ_FIRST(&file->common)) { 29925537Sdfr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 30025537Sdfr free(cp, M_LINKER); 30125537Sdfr } 30225537Sdfr 30325537Sdfr file->ops->unload(file); 30425537Sdfr free(file, M_LINKER); 30525537Sdfr 30625537Sdfrout: 30725537Sdfr return error; 30825537Sdfr} 30925537Sdfr 31025537Sdfrint 31125537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep) 31225537Sdfr{ 31325537Sdfr linker_file_t* newdeps; 31425537Sdfr 31525537Sdfr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), 31625537Sdfr M_LINKER, M_WAITOK); 31725537Sdfr if (newdeps == NULL) 31825537Sdfr return ENOMEM; 31925537Sdfr 32025537Sdfr if (file->deps) { 32125537Sdfr bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); 32225537Sdfr free(file->deps, M_LINKER); 32325537Sdfr } 32425537Sdfr file->deps = newdeps; 32525537Sdfr file->deps[file->ndeps] = dep; 32625537Sdfr file->ndeps++; 32725537Sdfr 32825537Sdfr return 0; 32925537Sdfr} 33025537Sdfr 33125537Sdfrcaddr_t 33225537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps) 33325537Sdfr{ 33425537Sdfr caddr_t address; 33525537Sdfr size_t size; 33625537Sdfr size_t common_size = 0; 33725537Sdfr int i; 33825537Sdfr 33925537Sdfr KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d", 34025537Sdfr file, name, deps)); 34125537Sdfr 34225537Sdfr if (file->ops->lookup_symbol(file, name, &address, &size) == 0) 34325537Sdfr if (address == 0) 34425537Sdfr /* 34525537Sdfr * For commons, first look them up in the dependancies and 34625537Sdfr * only allocate space if not found there. 34725537Sdfr */ 34825537Sdfr common_size = size; 34925537Sdfr else 35025537Sdfr return address; 35125537Sdfr 35225537Sdfr if (deps) 35325537Sdfr for (i = 0; i < file->ndeps; i++) { 35425537Sdfr address = linker_file_lookup_symbol(file->deps[i], name, 0); 35525537Sdfr if (address) 35625537Sdfr return address; 35725537Sdfr } 35825537Sdfr 35925537Sdfr if (common_size > 0) { 36025537Sdfr /* 36125537Sdfr * This is a common symbol which was not found in the 36225537Sdfr * dependancies. We maintain a simple common symbol table in 36325537Sdfr * the file object. 36425537Sdfr */ 36525537Sdfr struct common_symbol* cp; 36625537Sdfr 36725537Sdfr for (cp = STAILQ_FIRST(&file->common); cp; 36825537Sdfr cp = STAILQ_NEXT(cp, link)) 36925537Sdfr if (!strcmp(cp->name, name)) 37025537Sdfr return cp->address; 37125537Sdfr 37225537Sdfr /* 37325537Sdfr * Round the symbol size up to align. 37425537Sdfr */ 37525537Sdfr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 37625537Sdfr cp = malloc(sizeof(struct common_symbol) 37725537Sdfr + common_size 37825537Sdfr + strlen(name) + 1, 37925537Sdfr M_LINKER, M_WAITOK); 38025537Sdfr if (!cp) 38125537Sdfr return 0; 38225537Sdfr 38325537Sdfr cp->address = (caddr_t) (cp + 1); 38425537Sdfr cp->name = cp->address + common_size; 38525537Sdfr strcpy(cp->name, name); 38625537Sdfr bzero(cp->address, common_size); 38725537Sdfr STAILQ_INSERT_TAIL(&file->common, cp, link); 38825537Sdfr 38925537Sdfr return cp->address; 39025537Sdfr } 39125537Sdfr 39225537Sdfr return 0; 39325537Sdfr} 39425537Sdfr 39525537Sdfr/* 39625537Sdfr * Syscalls. 39725537Sdfr */ 39825537Sdfr 39925537Sdfrint 40030994Sphkkldload(struct proc* p, struct kldload_args* uap) 40125537Sdfr{ 40225537Sdfr char* filename = NULL; 40325537Sdfr linker_file_t lf; 40425537Sdfr int error = 0; 40525537Sdfr 40630994Sphk p->p_retval[0] = -1; 40725537Sdfr 40825537Sdfr if (securelevel > 0) 40925537Sdfr return EPERM; 41025537Sdfr 41125537Sdfr if (error = suser(p->p_ucred, &p->p_acflag)) 41225537Sdfr return error; 41325537Sdfr 41425537Sdfr filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 41525537Sdfr if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 41625537Sdfr goto out; 41725537Sdfr 41825537Sdfr if (error = linker_load_file(uap->file, &lf)) 41925537Sdfr goto out; 42025537Sdfr 42125537Sdfr lf->userrefs++; 42230994Sphk p->p_retval[0] = lf->id; 42325537Sdfr 42425537Sdfrout: 42525537Sdfr if (filename) 42625537Sdfr free(filename, M_TEMP); 42725537Sdfr return error; 42825537Sdfr} 42925537Sdfr 43025537Sdfrint 43130994Sphkkldunload(struct proc* p, struct kldunload_args* uap) 43225537Sdfr{ 43325537Sdfr linker_file_t lf; 43425537Sdfr int error = 0; 43525537Sdfr 43625537Sdfr if (securelevel > 0) 43725537Sdfr return EPERM; 43825537Sdfr 43925537Sdfr if (error = suser(p->p_ucred, &p->p_acflag)) 44025537Sdfr return error; 44125537Sdfr 44225537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 44325537Sdfr if (lf) { 44425537Sdfr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 44525537Sdfr if (lf->userrefs == 0) { 44625537Sdfr printf("linkerunload: attempt to unload file which was not loaded by user\n"); 44725537Sdfr error = EBUSY; 44825537Sdfr goto out; 44925537Sdfr } 45025537Sdfr lf->userrefs--; 45125537Sdfr error = linker_file_unload(lf); 45225537Sdfr } else 45325537Sdfr error = ENOENT; 45425537Sdfr 45525537Sdfrout: 45625537Sdfr return error; 45725537Sdfr} 45825537Sdfr 45925537Sdfrint 46030994Sphkkldfind(struct proc* p, struct kldfind_args* uap) 46125537Sdfr{ 46225537Sdfr char* filename = NULL; 46325537Sdfr linker_file_t lf; 46425537Sdfr int error = 0; 46525537Sdfr 46630994Sphk p->p_retval[0] = -1; 46725537Sdfr 46825537Sdfr filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 46925537Sdfr if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 47025537Sdfr goto out; 47125537Sdfr 47225537Sdfr lf = linker_find_file_by_name(filename); 47325537Sdfr if (lf) 47430994Sphk p->p_retval[0] = lf->id; 47525537Sdfr else 47625537Sdfr error = ENOENT; 47725537Sdfr 47825537Sdfrout: 47925537Sdfr if (filename) 48025537Sdfr free(filename, M_TEMP); 48125537Sdfr return error; 48225537Sdfr} 48325537Sdfr 48425537Sdfrint 48530994Sphkkldnext(struct proc* p, struct kldnext_args* uap) 48625537Sdfr{ 48725537Sdfr linker_file_t lf; 48825537Sdfr int error = 0; 48925537Sdfr 49025537Sdfr if (SCARG(uap, fileid) == 0) { 49125537Sdfr if (TAILQ_FIRST(&files)) 49230994Sphk p->p_retval[0] = TAILQ_FIRST(&files)->id; 49325537Sdfr else 49430994Sphk p->p_retval[0] = 0; 49525537Sdfr return 0; 49625537Sdfr } 49725537Sdfr 49825537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 49925537Sdfr if (lf) { 50025537Sdfr if (TAILQ_NEXT(lf, link)) 50130994Sphk p->p_retval[0] = TAILQ_NEXT(lf, link)->id; 50225537Sdfr else 50330994Sphk p->p_retval[0] = 0; 50425537Sdfr } else 50525537Sdfr error = ENOENT; 50625537Sdfr 50725537Sdfr return error; 50825537Sdfr} 50925537Sdfr 51025537Sdfrint 51130994Sphkkldstat(struct proc* p, struct kldstat_args* uap) 51225537Sdfr{ 51325537Sdfr linker_file_t lf; 51425537Sdfr int error = 0; 51525537Sdfr int version; 51625537Sdfr struct kld_file_stat* stat; 51725537Sdfr int namelen; 51825537Sdfr 51925537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 52025537Sdfr if (!lf) { 52125537Sdfr error = ENOENT; 52225537Sdfr goto out; 52325537Sdfr } 52425537Sdfr 52525537Sdfr stat = SCARG(uap, stat); 52625537Sdfr 52725537Sdfr /* 52825537Sdfr * Check the version of the user's structure. 52925537Sdfr */ 53025537Sdfr if (error = copyin(&stat->version, &version, sizeof(version))) 53125537Sdfr goto out; 53225537Sdfr if (version != sizeof(struct kld_file_stat)) { 53325537Sdfr error = EINVAL; 53425537Sdfr goto out; 53525537Sdfr } 53625537Sdfr 53725537Sdfr namelen = strlen(lf->filename) + 1; 53825537Sdfr if (namelen > MAXPATHLEN) 53925537Sdfr namelen = MAXPATHLEN; 54025537Sdfr if (error = copyout(lf->filename, &stat->name[0], namelen)) 54125537Sdfr goto out; 54225537Sdfr if (error = copyout(&lf->refs, &stat->refs, sizeof(int))) 54325537Sdfr goto out; 54425537Sdfr if (error = copyout(&lf->id, &stat->id, sizeof(int))) 54525537Sdfr goto out; 54625537Sdfr if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) 54725537Sdfr goto out; 54825537Sdfr if (error = copyout(&lf->size, &stat->size, sizeof(size_t))) 54925537Sdfr goto out; 55025537Sdfr 55130994Sphk p->p_retval[0] = 0; 55225537Sdfr 55325537Sdfrout: 55425537Sdfr return error; 55525537Sdfr} 55625537Sdfr 55725537Sdfrint 55830994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap) 55925537Sdfr{ 56025537Sdfr linker_file_t lf; 56125537Sdfr int error = 0; 56225537Sdfr 56325537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 56425537Sdfr if (lf) { 56525537Sdfr if (TAILQ_FIRST(&lf->modules)) 56630994Sphk p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules)); 56725537Sdfr else 56830994Sphk p->p_retval[0] = 0; 56925537Sdfr } else 57025537Sdfr error = ENOENT; 57125537Sdfr 57225537Sdfr return error; 57325537Sdfr} 574