kern_linker.c revision 54655
1/*-
2 * Copyright (c) 1997 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/kern/kern_linker.c 54655 1999-12-15 23:02:35Z eivind $
27 */
28
29#include "opt_ddb.h"
30
31#include <sys/param.h>
32#include <sys/kernel.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/sysproto.h>
36#include <sys/sysent.h>
37#include <sys/proc.h>
38#include <sys/lock.h>
39#include <sys/module.h>
40#include <sys/linker.h>
41#include <sys/fcntl.h>
42#include <sys/libkern.h>
43#include <sys/namei.h>
44#include <sys/vnode.h>
45#include <sys/sysctl.h>
46
47#include <vm/vm_zone.h>
48
49#ifdef KLD_DEBUG
50int kld_debug = 0;
51#endif
52
53MALLOC_DEFINE(M_LINKER, "kld", "kernel linker");
54linker_file_t linker_current_file;
55linker_file_t linker_kernel_file;
56
57static struct lock lock;	/* lock for the file list */
58static linker_class_list_t classes;
59static linker_file_list_t linker_files;
60static int next_file_id = 1;
61
62static void
63linker_init(void* arg)
64{
65    lockinit(&lock, PVM, "klink", 0, 0);
66    TAILQ_INIT(&classes);
67    TAILQ_INIT(&linker_files);
68}
69
70SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
71
72int
73linker_add_class(const char* desc, void* priv,
74		 struct linker_class_ops* ops)
75{
76    linker_class_t lc;
77
78    lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
79    if (!lc)
80	return ENOMEM;
81    bzero(lc, sizeof(*lc));
82
83    lc->desc = desc;
84    lc->priv = priv;
85    lc->ops = ops;
86    TAILQ_INSERT_HEAD(&classes, lc, link);
87
88    return 0;
89}
90
91static void
92linker_file_sysinit(linker_file_t lf)
93{
94    struct linker_set* sysinits;
95    struct sysinit** sipp;
96    struct sysinit** xipp;
97    struct sysinit* save;
98    const moduledata_t *moddata;
99    int error;
100
101    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
102		   lf->filename));
103
104    sysinits = (struct linker_set*)
105	linker_file_lookup_symbol(lf, "sysinit_set", 0);
106
107    KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits));
108    if (!sysinits)
109	return;
110
111    /* HACK ALERT! */
112    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
113	if ((*sipp)->func == module_register_init) {
114	    moddata = (*sipp)->udata;
115	    error = module_register(moddata, lf);
116	    if (error)
117		printf("linker_file_sysinit \"%s\" failed to register! %d\n",
118		    lf->filename, error);
119	}
120    }
121
122    /*
123     * Perform a bubble sort of the system initialization objects by
124     * their subsystem (primary key) and order (secondary key).
125     *
126     * Since some things care about execution order, this is the
127     * operation which ensures continued function.
128     */
129    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
130	for (xipp = sipp + 1; *xipp; xipp++) {
131	    if ((*sipp)->subsystem <= (*xipp)->subsystem ||
132		 ((*sipp)->subsystem == (*xipp)->subsystem &&
133		  (*sipp)->order <= (*xipp)->order))
134		continue;	/* skip*/
135	    save = *sipp;
136	    *sipp = *xipp;
137	    *xipp = save;
138	}
139    }
140
141
142    /*
143     * Traverse the (now) ordered list of system initialization tasks.
144     * Perform each task, and continue on to the next task.
145     */
146    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
147	if ((*sipp)->subsystem == SI_SUB_DUMMY)
148	    continue;	/* skip dummy task(s)*/
149
150	/* Call function */
151	(*((*sipp)->func))((*sipp)->udata);
152    }
153}
154
155static void
156linker_file_sysuninit(linker_file_t lf)
157{
158    struct linker_set* sysuninits;
159    struct sysinit** sipp;
160    struct sysinit** xipp;
161    struct sysinit* save;
162
163    KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
164		   lf->filename));
165
166    sysuninits = (struct linker_set*)
167	linker_file_lookup_symbol(lf, "sysuninit_set", 0);
168
169    KLD_DPF(FILE, ("linker_file_sysuninit: SYSUNINITs %p\n", sysuninits));
170    if (!sysuninits)
171	return;
172
173    /*
174     * Perform a reverse bubble sort of the system initialization objects
175     * by their subsystem (primary key) and order (secondary key).
176     *
177     * Since some things care about execution order, this is the
178     * operation which ensures continued function.
179     */
180    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
181	for (xipp = sipp + 1; *xipp; xipp++) {
182	    if ((*sipp)->subsystem >= (*xipp)->subsystem ||
183		 ((*sipp)->subsystem == (*xipp)->subsystem &&
184		  (*sipp)->order >= (*xipp)->order))
185		continue;	/* skip*/
186	    save = *sipp;
187	    *sipp = *xipp;
188	    *xipp = save;
189	}
190    }
191
192
193    /*
194     * Traverse the (now) ordered list of system initialization tasks.
195     * Perform each task, and continue on to the next task.
196     */
197    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
198	if ((*sipp)->subsystem == SI_SUB_DUMMY)
199	    continue;	/* skip dummy task(s)*/
200
201	/* Call function */
202	(*((*sipp)->func))((*sipp)->udata);
203    }
204}
205
206static void
207linker_file_register_sysctls(linker_file_t lf)
208{
209    struct linker_set* sysctls;
210
211    KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
212		   lf->filename));
213
214    sysctls = (struct linker_set*)
215	linker_file_lookup_symbol(lf, "sysctl_set", 0);
216
217    KLD_DPF(FILE, ("linker_file_register_sysctls: SYSCTLs %p\n", sysctls));
218    if (!sysctls)
219	return;
220
221    sysctl_register_set(sysctls);
222}
223
224static void
225linker_file_unregister_sysctls(linker_file_t lf)
226{
227    struct linker_set* sysctls;
228
229    KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n",
230		   lf->filename));
231
232    sysctls = (struct linker_set*)
233	linker_file_lookup_symbol(lf, "sysctl_set", 0);
234
235    KLD_DPF(FILE, ("linker_file_unregister_sysctls: SYSCTLs %p\n", sysctls));
236    if (!sysctls)
237	return;
238
239    sysctl_unregister_set(sysctls);
240}
241
242int
243linker_load_file(const char* filename, linker_file_t* result)
244{
245    linker_class_t lc;
246    linker_file_t lf;
247    int foundfile, error = 0;
248    char *koname = NULL;
249
250    lf = linker_find_file_by_name(filename);
251    if (lf) {
252	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
253	*result = lf;
254	lf->refs++;
255	goto out;
256    }
257
258    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
259    if (koname == NULL) {
260	error = ENOMEM;
261	goto out;
262    }
263    sprintf(koname, "%s.ko", filename);
264    lf = NULL;
265    foundfile = 0;
266    for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
267	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
268		       filename, lc->desc));
269
270	error = lc->ops->load_file(koname, &lf);	/* First with .ko */
271	if (lf == NULL && error == ENOENT)
272	    error = lc->ops->load_file(filename, &lf);	/* Then try without */
273	/*
274	 * If we got something other than ENOENT, then it exists but we cannot
275	 * load it for some other reason.
276	 */
277	if (error != ENOENT)
278	    foundfile = 1;
279	if (lf) {
280	    linker_file_register_sysctls(lf);
281	    linker_file_sysinit(lf);
282
283	    *result = lf;
284	    error = 0;
285	    goto out;
286	}
287    }
288    /*
289     * Less than ideal, but tells the user whether it failed to load or
290     * the module was not found.
291     */
292    if (foundfile)
293	error = ENOEXEC;	/* Format not recognised (or unloadable) */
294    else
295	error = ENOENT;		/* Nothing found */
296
297out:
298    if (koname)
299	free(koname, M_LINKER);
300    return error;
301}
302
303linker_file_t
304linker_find_file_by_name(const char* filename)
305{
306    linker_file_t lf = 0;
307    char *koname;
308
309    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
310    if (koname == NULL)
311	goto out;
312    sprintf(koname, "%s.ko", filename);
313
314    lockmgr(&lock, LK_SHARED, 0, curproc);
315    for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
316	if (!strcmp(lf->filename, koname))
317	    break;
318	if (!strcmp(lf->filename, filename))
319	    break;
320    }
321    lockmgr(&lock, LK_RELEASE, 0, curproc);
322
323out:
324    if (koname)
325	free(koname, M_LINKER);
326    return lf;
327}
328
329linker_file_t
330linker_find_file_by_id(int fileid)
331{
332    linker_file_t lf = 0;
333
334    lockmgr(&lock, LK_SHARED, 0, curproc);
335    for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link))
336	if (lf->id == fileid)
337	    break;
338    lockmgr(&lock, LK_RELEASE, 0, curproc);
339
340    return lf;
341}
342
343linker_file_t
344linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops)
345{
346    linker_file_t lf = 0;
347    int namelen;
348    const char *filename;
349
350    filename = rindex(pathname, '/');
351    if (filename && filename[1])
352	filename++;
353    else
354	filename = pathname;
355
356    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
357    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
358    namelen = strlen(filename) + 1;
359    lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
360    if (!lf)
361	goto out;
362    bzero(lf, sizeof(*lf));
363
364    lf->refs = 1;
365    lf->userrefs = 0;
366    lf->flags = 0;
367    lf->filename = (char*) (lf + 1);
368    strcpy(lf->filename, filename);
369    lf->id = next_file_id++;
370    lf->ndeps = 0;
371    lf->deps = NULL;
372    STAILQ_INIT(&lf->common);
373    TAILQ_INIT(&lf->modules);
374
375    lf->priv = priv;
376    lf->ops = ops;
377    TAILQ_INSERT_TAIL(&linker_files, lf, link);
378
379out:
380    lockmgr(&lock, LK_RELEASE, 0, curproc);
381    return lf;
382}
383
384int
385linker_file_unload(linker_file_t file)
386{
387    module_t mod, next;
388    struct common_symbol* cp;
389    int error = 0;
390    int i;
391
392    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
393    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
394    if (file->refs == 1) {
395	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
396	/*
397	 * Inform any modules associated with this file.
398	 */
399	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
400	    next = module_getfnext(mod);
401
402	    /*
403	     * Give the module a chance to veto the unload.
404	     */
405	    if ((error = module_unload(mod)) != 0) {
406		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
407			       mod));
408		lockmgr(&lock, LK_RELEASE, 0, curproc);
409		goto out;
410	    }
411
412	    module_release(mod);
413	}
414    }
415
416    file->refs--;
417    if (file->refs > 0) {
418	lockmgr(&lock, LK_RELEASE, 0, curproc);
419	goto out;
420    }
421
422    /* Don't try to run SYSUNINITs if we are unloaded due to a link error */
423    if (file->flags & LINKER_FILE_LINKED) {
424	linker_file_sysuninit(file);
425	linker_file_unregister_sysctls(file);
426    }
427
428    TAILQ_REMOVE(&linker_files, file, link);
429    lockmgr(&lock, LK_RELEASE, 0, curproc);
430
431    for (i = 0; i < file->ndeps; i++)
432	linker_file_unload(file->deps[i]);
433    free(file->deps, M_LINKER);
434
435    for (cp = STAILQ_FIRST(&file->common); cp;
436	 cp = STAILQ_FIRST(&file->common)) {
437	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
438	free(cp, M_LINKER);
439    }
440
441    file->ops->unload(file);
442    free(file, M_LINKER);
443
444out:
445    return error;
446}
447
448int
449linker_file_add_dependancy(linker_file_t file, linker_file_t dep)
450{
451    linker_file_t* newdeps;
452
453    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
454		     M_LINKER, M_WAITOK);
455    if (newdeps == NULL)
456	return ENOMEM;
457    bzero(newdeps, (file->ndeps + 1) * sizeof(linker_file_t*));
458
459    if (file->deps) {
460	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
461	free(file->deps, M_LINKER);
462    }
463    file->deps = newdeps;
464    file->deps[file->ndeps] = dep;
465    file->ndeps++;
466
467    return 0;
468}
469
470caddr_t
471linker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
472{
473    c_linker_sym_t sym;
474    linker_symval_t symval;
475    linker_file_t lf;
476    caddr_t address;
477    size_t common_size = 0;
478    int i;
479
480    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
481		  file, name, deps));
482
483    if (file->ops->lookup_symbol(file, name, &sym) == 0) {
484	file->ops->symbol_values(file, sym, &symval);
485	if (symval.value == 0)
486	    /*
487	     * For commons, first look them up in the dependancies and
488	     * only allocate space if not found there.
489	     */
490	    common_size = symval.size;
491	else {
492	    KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value));
493	    return symval.value;
494	}
495    }
496
497    if (deps) {
498	for (i = 0; i < file->ndeps; i++) {
499	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
500	    if (address) {
501		KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address));
502		return address;
503	    }
504	}
505
506	/* If we have not found it in the dependencies, search globally */
507	for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
508	    /* But skip the current file if it's on the list */
509	    if (lf == file)
510		continue;
511	    /* And skip the files we searched above */
512	    for (i = 0; i < file->ndeps; i++)
513		if (lf == file->deps[i])
514		    break;
515	    if (i < file->ndeps)
516		continue;
517	    address = linker_file_lookup_symbol(lf, name, 0);
518	    if (address) {
519		KLD_DPF(SYM, ("linker_file_lookup_symbol: global value=%x\n", address));
520		return address;
521	    }
522	}
523    }
524
525    if (common_size > 0) {
526	/*
527	 * This is a common symbol which was not found in the
528	 * dependancies.  We maintain a simple common symbol table in
529	 * the file object.
530	 */
531	struct common_symbol* cp;
532
533	for (cp = STAILQ_FIRST(&file->common); cp;
534	     cp = STAILQ_NEXT(cp, link))
535	    if (!strcmp(cp->name, name)) {
536		KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address));
537		return cp->address;
538	    }
539
540	/*
541	 * Round the symbol size up to align.
542	 */
543	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
544	cp = malloc(sizeof(struct common_symbol)
545		    + common_size
546		    + strlen(name) + 1,
547		    M_LINKER, M_WAITOK);
548	if (!cp) {
549	    KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
550	    return 0;
551	}
552	bzero(cp, sizeof(struct common_symbol) + common_size + strlen(name)+ 1);
553
554	cp->address = (caddr_t) (cp + 1);
555	cp->name = cp->address + common_size;
556	strcpy(cp->name, name);
557	bzero(cp->address, common_size);
558	STAILQ_INSERT_TAIL(&file->common, cp, link);
559
560	KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address));
561	return cp->address;
562    }
563
564    KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
565    return 0;
566}
567
568#ifdef DDB
569/*
570 * DDB Helpers.  DDB has to look across multiple files with their own
571 * symbol tables and string tables.
572 *
573 * Note that we do not obey list locking protocols here.  We really don't
574 * need DDB to hang because somebody's got the lock held.  We'll take the
575 * chance that the files list is inconsistant instead.
576 */
577
578int
579linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
580{
581    linker_file_t lf;
582
583    for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
584	if (lf->ops->lookup_symbol(lf, symstr, sym) == 0)
585	    return 0;
586    }
587    return ENOENT;
588}
589
590int
591linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
592{
593    linker_file_t lf;
594    u_long off = (uintptr_t)value;
595    u_long diff, bestdiff;
596    c_linker_sym_t best;
597    c_linker_sym_t es;
598
599    best = 0;
600    bestdiff = off;
601    for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
602	if (lf->ops->search_symbol(lf, value, &es, &diff) != 0)
603	    continue;
604	if (es != 0 && diff < bestdiff) {
605	    best = es;
606	    bestdiff = diff;
607	}
608	if (bestdiff == 0)
609	    break;
610    }
611    if (best) {
612	*sym = best;
613	*diffp = bestdiff;
614	return 0;
615    } else {
616	*sym = 0;
617	*diffp = off;
618	return ENOENT;
619    }
620}
621
622int
623linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
624{
625    linker_file_t lf;
626
627    for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
628	if (lf->ops->symbol_values(lf, sym, symval) == 0)
629	    return 0;
630    }
631    return ENOENT;
632}
633
634#endif
635
636/*
637 * Syscalls.
638 */
639
640int
641kldload(struct proc* p, struct kldload_args* uap)
642{
643    char* filename = NULL, *modulename;
644    linker_file_t lf;
645    int error = 0;
646
647    p->p_retval[0] = -1;
648
649    if (securelevel > 0)
650	return EPERM;
651
652    if ((error = suser(p)) != 0)
653	return error;
654
655    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
656    if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0)
657	goto out;
658
659    /* Can't load more than one module with the same name */
660    modulename = rindex(filename, '/');
661    if (modulename == NULL)
662	modulename = filename;
663    else
664	modulename++;
665    if (linker_find_file_by_name(modulename)) {
666	error = EEXIST;
667	goto out;
668    }
669
670    if ((error = linker_load_file(filename, &lf)) != 0)
671	goto out;
672
673    lf->userrefs++;
674    p->p_retval[0] = lf->id;
675
676out:
677    if (filename)
678	free(filename, M_TEMP);
679    return error;
680}
681
682int
683kldunload(struct proc* p, struct kldunload_args* uap)
684{
685    linker_file_t lf;
686    int error = 0;
687
688    if (securelevel > 0)
689	return EPERM;
690
691    if ((error = suser(p)) != 0)
692	return error;
693
694    lf = linker_find_file_by_id(SCARG(uap, fileid));
695    if (lf) {
696	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
697	if (lf->userrefs == 0) {
698	    printf("linkerunload: attempt to unload file that was loaded by the kernel\n");
699	    error = EBUSY;
700	    goto out;
701	}
702	lf->userrefs--;
703	error = linker_file_unload(lf);
704	if (error)
705	    lf->userrefs++;
706    } else
707	error = ENOENT;
708
709out:
710    return error;
711}
712
713int
714kldfind(struct proc* p, struct kldfind_args* uap)
715{
716    char* filename = NULL, *modulename;
717    linker_file_t lf;
718    int error = 0;
719
720    p->p_retval[0] = -1;
721
722    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
723    if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0)
724	goto out;
725
726    modulename = rindex(filename, '/');
727    if (modulename == NULL)
728	modulename = filename;
729
730    lf = linker_find_file_by_name(modulename);
731    if (lf)
732	p->p_retval[0] = lf->id;
733    else
734	error = ENOENT;
735
736out:
737    if (filename)
738	free(filename, M_TEMP);
739    return error;
740}
741
742int
743kldnext(struct proc* p, struct kldnext_args* uap)
744{
745    linker_file_t lf;
746    int error = 0;
747
748    if (SCARG(uap, fileid) == 0) {
749	if (TAILQ_FIRST(&linker_files))
750	    p->p_retval[0] = TAILQ_FIRST(&linker_files)->id;
751	else
752	    p->p_retval[0] = 0;
753	return 0;
754    }
755
756    lf = linker_find_file_by_id(SCARG(uap, fileid));
757    if (lf) {
758	if (TAILQ_NEXT(lf, link))
759	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
760	else
761	    p->p_retval[0] = 0;
762    } else
763	error = ENOENT;
764
765    return error;
766}
767
768int
769kldstat(struct proc* p, struct kldstat_args* uap)
770{
771    linker_file_t lf;
772    int error = 0;
773    int version;
774    struct kld_file_stat* stat;
775    int namelen;
776
777    lf = linker_find_file_by_id(SCARG(uap, fileid));
778    if (!lf) {
779	error = ENOENT;
780	goto out;
781    }
782
783    stat = SCARG(uap, stat);
784
785    /*
786     * Check the version of the user's structure.
787     */
788    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
789	goto out;
790    if (version != sizeof(struct kld_file_stat)) {
791	error = EINVAL;
792	goto out;
793    }
794
795    namelen = strlen(lf->filename) + 1;
796    if (namelen > MAXPATHLEN)
797	namelen = MAXPATHLEN;
798    if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
799	goto out;
800    if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
801	goto out;
802    if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
803	goto out;
804    if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0)
805	goto out;
806    if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
807	goto out;
808
809    p->p_retval[0] = 0;
810
811out:
812    return error;
813}
814
815int
816kldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
817{
818    linker_file_t lf;
819    int error = 0;
820
821    lf = linker_find_file_by_id(SCARG(uap, fileid));
822    if (lf) {
823	if (TAILQ_FIRST(&lf->modules))
824	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
825	else
826	    p->p_retval[0] = 0;
827    } else
828	error = ENOENT;
829
830    return error;
831}
832
833int
834kldsym(struct proc *p, struct kldsym_args *uap)
835{
836    char *symstr = NULL;
837    c_linker_sym_t sym;
838    linker_symval_t symval;
839    linker_file_t lf;
840    struct kld_sym_lookup lookup;
841    int error = 0;
842
843    if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
844	goto out;
845    if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) {
846	error = EINVAL;
847	goto out;
848    }
849
850    symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
851    if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
852	goto out;
853
854    if (SCARG(uap, fileid) != 0) {
855	lf = linker_find_file_by_id(SCARG(uap, fileid));
856	if (lf == NULL) {
857	    error = ENOENT;
858	    goto out;
859	}
860	if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
861	    lf->ops->symbol_values(lf, sym, &symval) == 0) {
862	    lookup.symvalue = (uintptr_t)symval.value;
863	    lookup.symsize = symval.size;
864	    error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
865	} else
866	    error = ENOENT;
867    } else {
868	for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
869	    if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
870		lf->ops->symbol_values(lf, sym, &symval) == 0) {
871		lookup.symvalue = (uintptr_t)symval.value;
872		lookup.symsize = symval.size;
873		error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
874		break;
875	    }
876	}
877	if (!lf)
878	    error = ENOENT;
879    }
880out:
881    if (symstr)
882	free(symstr, M_TEMP);
883    return error;
884}
885
886/*
887 * Preloaded module support
888 */
889
890static void
891linker_preload(void* arg)
892{
893    caddr_t		modptr;
894    char		*modname;
895    char		*modtype;
896    linker_file_t	lf;
897    linker_class_t	lc;
898    int			error;
899    struct linker_set	*sysinits;
900    struct sysinit	**sipp;
901    const moduledata_t	*moddata;
902
903    modptr = NULL;
904    while ((modptr = preload_search_next_name(modptr)) != NULL) {
905	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
906	modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
907	if (modname == NULL) {
908	    printf("Preloaded module at %p does not have a name!\n", modptr);
909	    continue;
910	}
911	if (modtype == NULL) {
912	    printf("Preloaded module at %p does not have a type!\n", modptr);
913	    continue;
914	}
915	printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr);
916	lf = linker_find_file_by_name(modname);
917	if (lf) {
918	    lf->userrefs++;
919	    continue;
920	}
921	lf = NULL;
922	for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
923	    error = lc->ops->load_file(modname, &lf);
924	    if (error) {
925		lf = NULL;
926		break;
927	    }
928	}
929	if (lf) {
930	    lf->userrefs++;
931
932	    sysinits = (struct linker_set*)
933		linker_file_lookup_symbol(lf, "sysinit_set", 0);
934	    if (sysinits) {
935		/* HACK ALERT!
936		 * This is to set the sysinit moduledata so that the module
937		 * can attach itself to the correct containing file.
938		 * The sysinit could be run at *any* time.
939		 */
940		for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
941		    if ((*sipp)->func == module_register_init) {
942			moddata = (*sipp)->udata;
943			error = module_register(moddata, lf);
944			if (error)
945			    printf("Preloaded %s \"%s\" failed to register: %d\n",
946				modtype, modname, error);
947		    }
948		}
949		sysinit_add((struct sysinit **)sysinits->ls_items);
950	    }
951	    linker_file_register_sysctls(lf);
952	}
953    }
954}
955
956SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
957
958/*
959 * Search for a not-loaded module by name.
960 *
961 * Modules may be found in the following locations:
962 *
963 * - preloaded (result is just the module name)
964 * - on disk (result is full path to module)
965 *
966 * If the module name is qualified in any way (contains path, etc.)
967 * the we simply return a copy of it.
968 *
969 * The search path can be manipulated via sysctl.  Note that we use the ';'
970 * character as a separator to be consistent with the bootloader.
971 */
972
973static char linker_path[MAXPATHLEN] = "/;/boot/;/modules/";
974
975SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
976	      sizeof(linker_path), "module load search path");
977
978static char *
979linker_strdup(const char *str)
980{
981    char	*result;
982
983    if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
984	strcpy(result, str);
985    return(result);
986}
987
988char *
989linker_search_path(const char *name)
990{
991    struct nameidata	nd;
992    struct proc		*p = curproc;	/* XXX */
993    char		*cp, *ep, *result;
994    int			error;
995    enum vtype		type;
996
997    /* qualified at all? */
998    if (index(name, '/'))
999	return(linker_strdup(name));
1000
1001    /* traverse the linker path */
1002    cp = linker_path;
1003    for (;;) {
1004
1005	/* find the end of this component */
1006	for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
1007	    ;
1008	result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK);
1009	if (result == NULL)	/* actually ENOMEM */
1010	    return(NULL);
1011
1012	strncpy(result, cp, ep - cp);
1013	strcpy(result + (ep - cp), name);
1014
1015	/*
1016	 * Attempt to open the file, and return the path if we succeed and it's
1017	 * a regular file.
1018	 */
1019	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p);
1020	error = vn_open(&nd, FREAD, 0);
1021	if (error == 0) {
1022	    NDFREE(&nd, NDF_ONLY_PNBUF);
1023	    type = nd.ni_vp->v_type;
1024	    VOP_UNLOCK(nd.ni_vp, 0, p);
1025	    vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
1026	    if (type == VREG)
1027		return(result);
1028	}
1029	free(result, M_LINKER);
1030
1031	if (*ep == 0)
1032	    break;
1033	cp = ep + 1;
1034    }
1035    return(NULL);
1036}
1037