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