File: | kern/kern_linker.c |
Warning: | line 1220, column 10 Copies out a struct with a partially unsanitized field |
1 | /*- | |||
2 | * Copyright (c) 1997-2000 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 | ||||
27 | #include <sys/cdefs.h> | |||
28 | __FBSDID("$FreeBSD: releng/11.0/sys/kern/kern_linker.c 301751 2016-06-09 18:27:41Z cem $")__asm__(".ident\t\"" "$FreeBSD: releng/11.0/sys/kern/kern_linker.c 301751 2016-06-09 18:27:41Z cem $" "\""); | |||
29 | ||||
30 | #include "opt_ddb.h" | |||
31 | #include "opt_kld.h" | |||
32 | #include "opt_hwpmc_hooks.h" | |||
33 | ||||
34 | #include <sys/param.h> | |||
35 | #include <sys/kernel.h> | |||
36 | #include <sys/systm.h> | |||
37 | #include <sys/malloc.h> | |||
38 | #include <sys/sysproto.h> | |||
39 | #include <sys/sysent.h> | |||
40 | #include <sys/priv.h> | |||
41 | #include <sys/proc.h> | |||
42 | #include <sys/lock.h> | |||
43 | #include <sys/mutex.h> | |||
44 | #include <sys/sx.h> | |||
45 | #include <sys/module.h> | |||
46 | #include <sys/mount.h> | |||
47 | #include <sys/linker.h> | |||
48 | #include <sys/eventhandler.h> | |||
49 | #include <sys/fcntl.h> | |||
50 | #include <sys/jail.h> | |||
51 | #include <sys/libkern.h> | |||
52 | #include <sys/namei.h> | |||
53 | #include <sys/vnode.h> | |||
54 | #include <sys/syscallsubr.h> | |||
55 | #include <sys/sysctl.h> | |||
56 | ||||
57 | #ifdef DDB | |||
58 | #include <ddb/ddb.h> | |||
59 | #endif | |||
60 | ||||
61 | #include <net/vnet.h> | |||
62 | ||||
63 | #include <security/mac/mac_framework.h> | |||
64 | ||||
65 | #include "linker_if.h" | |||
66 | ||||
67 | #ifdef HWPMC_HOOKS1 | |||
68 | #include <sys/pmckern.h> | |||
69 | #endif | |||
70 | ||||
71 | #ifdef KLD_DEBUG | |||
72 | int kld_debug = 0; | |||
73 | SYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RWTUN,static struct sysctl_oid sysctl___debug_kld_debug = { .oid_parent = ((&(&sysctl___debug)->oid_children)), .oid_children = { ((void *)0) }, .oid_number = ((-1)), .oid_kind = (2 | 0x00040000 | (((0x80000000|0x40000000)|0x00080000))), .oid_arg1 = (& kld_debug), .oid_arg2 = (0), .oid_name = ("kld_debug"), .oid_handler = (sysctl_handle_int), .oid_fmt = ("I"), .oid_descr = "Set various levels of KLD debug" }; __asm__(".globl " "__start_set_sysctl_set"); __asm__(".globl " "__stop_set_sysctl_set"); static void const * const __set_sysctl_set_sym_sysctl___debug_kld_debug __attribute__((__section__("set_" "sysctl_set"))) __attribute__ ((__used__)) = &(sysctl___debug_kld_debug); _Static_assert ((((((0x80000000|0x40000000)|0x00080000)) & 0xf) == 0 || ( (((0x80000000|0x40000000)|0x00080000)) & 0) == 2) && sizeof(int) == sizeof(*(&kld_debug)), "compile-time assertion failed" ) | |||
74 | &kld_debug, 0, "Set various levels of KLD debug")static struct sysctl_oid sysctl___debug_kld_debug = { .oid_parent = ((&(&sysctl___debug)->oid_children)), .oid_children = { ((void *)0) }, .oid_number = ((-1)), .oid_kind = (2 | 0x00040000 | (((0x80000000|0x40000000)|0x00080000))), .oid_arg1 = (& kld_debug), .oid_arg2 = (0), .oid_name = ("kld_debug"), .oid_handler = (sysctl_handle_int), .oid_fmt = ("I"), .oid_descr = "Set various levels of KLD debug" }; __asm__(".globl " "__start_set_sysctl_set"); __asm__(".globl " "__stop_set_sysctl_set"); static void const * const __set_sysctl_set_sym_sysctl___debug_kld_debug __attribute__((__section__("set_" "sysctl_set"))) __attribute__ ((__used__)) = &(sysctl___debug_kld_debug); _Static_assert ((((((0x80000000|0x40000000)|0x00080000)) & 0xf) == 0 || ( (((0x80000000|0x40000000)|0x00080000)) & 0) == 2) && sizeof(int) == sizeof(*(&kld_debug)), "compile-time assertion failed" ); | |||
75 | #endif | |||
76 | ||||
77 | /* These variables are used by kernel debuggers to enumerate loaded files. */ | |||
78 | const int kld_off_address = offsetof(struct linker_file, address)__builtin_offsetof(struct linker_file, address); | |||
79 | const int kld_off_filename = offsetof(struct linker_file, filename)__builtin_offsetof(struct linker_file, filename); | |||
80 | const int kld_off_pathname = offsetof(struct linker_file, pathname)__builtin_offsetof(struct linker_file, pathname); | |||
81 | const int kld_off_next = offsetof(struct linker_file, link.tqe_next)__builtin_offsetof(struct linker_file, link.tqe_next); | |||
82 | ||||
83 | /* | |||
84 | * static char *linker_search_path(const char *name, struct mod_depend | |||
85 | * *verinfo); | |||
86 | */ | |||
87 | static const char *linker_basename(const char *path); | |||
88 | ||||
89 | /* | |||
90 | * Find a currently loaded file given its filename. | |||
91 | */ | |||
92 | static linker_file_t linker_find_file_by_name(const char* _filename); | |||
93 | ||||
94 | /* | |||
95 | * Find a currently loaded file given its file id. | |||
96 | */ | |||
97 | static linker_file_t linker_find_file_by_id(int _fileid); | |||
98 | ||||
99 | /* Metadata from the static kernel */ | |||
100 | SET_DECLARE(modmetadata_set, struct mod_metadata)extern struct mod_metadata __attribute__((__weak__)) *__start_set_modmetadata_set ; extern struct mod_metadata __attribute__((__weak__)) *__stop_set_modmetadata_set; | |||
101 | ||||
102 | MALLOC_DEFINE(M_LINKER, "linker", "kernel linker")struct malloc_type M_LINKER[1] = { { ((void *)0), 877983977, "linker" , ((void *)0) } }; static struct sysinit M_LINKER_init_sys_init = { SI_SUB_KMEM, SI_ORDER_THIRD, (sysinit_cfunc_t)(sysinit_nfunc_t )malloc_init, ((void *)(M_LINKER)) }; __asm__(".globl " "__start_set_sysinit_set" ); __asm__(".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym_M_LINKER_init_sys_init __attribute__ ((__section__("set_" "sysinit_set"))) __attribute__((__used__ )) = &(M_LINKER_init_sys_init); static struct sysinit M_LINKER_uninit_sys_uninit = { SI_SUB_KMEM, SI_ORDER_ANY, (sysinit_cfunc_t)(sysinit_nfunc_t )malloc_uninit, ((void *)(M_LINKER)) }; __asm__(".globl " "__start_set_sysuninit_set" ); __asm__(".globl " "__stop_set_sysuninit_set"); static void const * const __set_sysuninit_set_sym_M_LINKER_uninit_sys_uninit __attribute__((__section__("set_" "sysuninit_set"))) __attribute__ ((__used__)) = &(M_LINKER_uninit_sys_uninit); | |||
103 | ||||
104 | linker_file_t linker_kernel_file; | |||
105 | ||||
106 | static struct sx kld_sx; /* kernel linker lock */ | |||
107 | ||||
108 | /* | |||
109 | * Load counter used by clients to determine if a linker file has been | |||
110 | * re-loaded. This counter is incremented for each file load. | |||
111 | */ | |||
112 | static int loadcnt; | |||
113 | ||||
114 | static linker_class_list_t classes; | |||
115 | static linker_file_list_t linker_files; | |||
116 | static int next_file_id = 1; | |||
117 | static int linker_no_more_classes = 0; | |||
118 | ||||
119 | #define LINKER_GET_NEXT_FILE_ID(a)do { linker_file_t lftmp; if (!cold) (void)0; retry: for ((lftmp ) = (((&linker_files))->tqh_first); (lftmp); (lftmp) = (((lftmp))->link.tqe_next)) { if (next_file_id == lftmp-> id) { next_file_id++; goto retry; } } (a) = next_file_id; } while (0) do { \ | |||
120 | linker_file_t lftmp; \ | |||
121 | \ | |||
122 | if (!cold) \ | |||
123 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; \ | |||
124 | retry: \ | |||
125 | TAILQ_FOREACH(lftmp, &linker_files, link)for ((lftmp) = (((&linker_files))->tqh_first); (lftmp) ; (lftmp) = (((lftmp))->link.tqe_next)) { \ | |||
126 | if (next_file_id == lftmp->id) { \ | |||
127 | next_file_id++; \ | |||
128 | goto retry; \ | |||
129 | } \ | |||
130 | } \ | |||
131 | (a) = next_file_id; \ | |||
132 | } while(0) | |||
133 | ||||
134 | ||||
135 | /* XXX wrong name; we're looking at version provision tags here, not modules */ | |||
136 | typedef TAILQ_HEAD(, modlist)struct { struct modlist *tqh_first; struct modlist **tqh_last ; } modlisthead_t; | |||
137 | struct modlist { | |||
138 | TAILQ_ENTRY(modlist)struct { struct modlist *tqe_next; struct modlist **tqe_prev; } link; /* chain together all modules */ | |||
139 | linker_file_t container; | |||
140 | const char *name; | |||
141 | int version; | |||
142 | }; | |||
143 | typedef struct modlist *modlist_t; | |||
144 | static modlisthead_t found_modules; | |||
145 | ||||
146 | static int linker_file_add_dependency(linker_file_t file, | |||
147 | linker_file_t dep); | |||
148 | static caddr_t linker_file_lookup_symbol_internal(linker_file_t file, | |||
149 | const char* name, int deps); | |||
150 | static int linker_load_module(const char *kldname, | |||
151 | const char *modname, struct linker_file *parent, | |||
152 | const struct mod_depend *verinfo, struct linker_file **lfpp); | |||
153 | static modlist_t modlist_lookup2(const char *name, const struct mod_depend *verinfo); | |||
154 | ||||
155 | static void | |||
156 | linker_init(void *arg) | |||
157 | { | |||
158 | ||||
159 | sx_init(&kld_sx, "kernel linker")sx_init_flags((&kld_sx), ("kernel linker"), 0); | |||
160 | TAILQ_INIT(&classes)do { (((&classes))->tqh_first) = ((void *)0); (&classes )->tqh_last = &(((&classes))->tqh_first); ; } while (0); | |||
161 | TAILQ_INIT(&linker_files)do { (((&linker_files))->tqh_first) = ((void *)0); (& linker_files)->tqh_last = &(((&linker_files))-> tqh_first); ; } while (0); | |||
162 | } | |||
163 | ||||
164 | SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0)static struct sysinit linker_sys_init = { SI_SUB_KLD, SI_ORDER_FIRST , (sysinit_cfunc_t)(sysinit_nfunc_t)linker_init, ((void *)(0) ) }; __asm__(".globl " "__start_set_sysinit_set"); __asm__(".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym_linker_sys_init __attribute__((__section__("set_" "sysinit_set"))) __attribute__ ((__used__)) = &(linker_sys_init); | |||
165 | ||||
166 | static void | |||
167 | linker_stop_class_add(void *arg) | |||
168 | { | |||
169 | ||||
170 | linker_no_more_classes = 1; | |||
171 | } | |||
172 | ||||
173 | SYSINIT(linker_class, SI_SUB_KLD, SI_ORDER_ANY, linker_stop_class_add, NULL)static struct sysinit linker_class_sys_init = { SI_SUB_KLD, SI_ORDER_ANY , (sysinit_cfunc_t)(sysinit_nfunc_t)linker_stop_class_add, (( void *)(((void *)0))) }; __asm__(".globl " "__start_set_sysinit_set" ); __asm__(".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym_linker_class_sys_init __attribute__ ((__section__("set_" "sysinit_set"))) __attribute__((__used__ )) = &(linker_class_sys_init); | |||
174 | ||||
175 | int | |||
176 | linker_add_class(linker_class_t lc) | |||
177 | { | |||
178 | ||||
179 | /* | |||
180 | * We disallow any class registration past SI_ORDER_ANY | |||
181 | * of SI_SUB_KLD. We bump the reference count to keep the | |||
182 | * ops from being freed. | |||
183 | */ | |||
184 | if (linker_no_more_classes == 1) | |||
185 | return (EPERM1); | |||
186 | kobj_class_compile((kobj_class_t) lc); | |||
187 | ((kobj_class_t)lc)->refs++; /* XXX: kobj_mtx */ | |||
188 | TAILQ_INSERT_TAIL(&classes, lc, link)do { ; (((lc))->link.tqe_next) = ((void *)0); (lc)->link .tqe_prev = (&classes)->tqh_last; *(&classes)-> tqh_last = (lc); (&classes)->tqh_last = &(((lc))-> link.tqe_next); ; ; } while (0); | |||
189 | return (0); | |||
190 | } | |||
191 | ||||
192 | static void | |||
193 | linker_file_sysinit(linker_file_t lf) | |||
194 | { | |||
195 | struct sysinit **start, **stop, **sipp, **xipp, *save; | |||
196 | ||||
197 | KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", | |||
198 | lf->filename)); | |||
199 | ||||
200 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
201 | ||||
202 | if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL((void *)0)) != 0) | |||
203 | return; | |||
204 | /* | |||
205 | * Perform a bubble sort of the system initialization objects by | |||
206 | * their subsystem (primary key) and order (secondary key). | |||
207 | * | |||
208 | * Since some things care about execution order, this is the operation | |||
209 | * which ensures continued function. | |||
210 | */ | |||
211 | for (sipp = start; sipp < stop; sipp++) { | |||
212 | for (xipp = sipp + 1; xipp < stop; xipp++) { | |||
213 | if ((*sipp)->subsystem < (*xipp)->subsystem || | |||
214 | ((*sipp)->subsystem == (*xipp)->subsystem && | |||
215 | (*sipp)->order <= (*xipp)->order)) | |||
216 | continue; /* skip */ | |||
217 | save = *sipp; | |||
218 | *sipp = *xipp; | |||
219 | *xipp = save; | |||
220 | } | |||
221 | } | |||
222 | ||||
223 | /* | |||
224 | * Traverse the (now) ordered list of system initialization tasks. | |||
225 | * Perform each task, and continue on to the next task. | |||
226 | */ | |||
227 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
228 | mtx_lock(&Giant)do { uintptr_t _tid = (uintptr_t)((__curthread())); if (((((( &Giant))))->mtx_lock != 0x00000004 || !atomic_cmpset_long (&(((((&Giant)))))->mtx_lock, 0x00000004, (_tid))) ) __mtx_lock_sleep(&(((((&Giant)))))->mtx_lock, _tid , (((0))), ((((void *)0))), ((0))); else do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__acquire->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__acquire->id , (uintptr_t) (((&Giant))), (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0); } while (0); } while (0); | |||
229 | for (sipp = start; sipp < stop; sipp++) { | |||
230 | if ((*sipp)->subsystem == SI_SUB_DUMMY) | |||
231 | continue; /* skip dummy task(s) */ | |||
232 | ||||
233 | /* Call function */ | |||
234 | (*((*sipp)->func)) ((*sipp)->udata); | |||
235 | } | |||
236 | mtx_unlock(&Giant)do { uintptr_t _tid = (uintptr_t)((__curthread())); if (((((& Giant))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release->id , (uintptr_t) (((&Giant))), (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0); } while (0); if ( ((((&Giant))))->mtx_lock != _tid || !atomic_cmpset_long (&(((((&Giant)))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(&(((((&Giant)))))->mtx_lock, ( ((0))), ((((void *)0))), ((0))); } while (0); | |||
237 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
238 | } | |||
239 | ||||
240 | static void | |||
241 | linker_file_sysuninit(linker_file_t lf) | |||
242 | { | |||
243 | struct sysinit **start, **stop, **sipp, **xipp, *save; | |||
244 | ||||
245 | KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", | |||
246 | lf->filename)); | |||
247 | ||||
248 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
249 | ||||
250 | if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, | |||
251 | NULL((void *)0)) != 0) | |||
252 | return; | |||
253 | ||||
254 | /* | |||
255 | * Perform a reverse bubble sort of the system initialization objects | |||
256 | * by their subsystem (primary key) and order (secondary key). | |||
257 | * | |||
258 | * Since some things care about execution order, this is the operation | |||
259 | * which ensures continued function. | |||
260 | */ | |||
261 | for (sipp = start; sipp < stop; sipp++) { | |||
262 | for (xipp = sipp + 1; xipp < stop; xipp++) { | |||
263 | if ((*sipp)->subsystem > (*xipp)->subsystem || | |||
264 | ((*sipp)->subsystem == (*xipp)->subsystem && | |||
265 | (*sipp)->order >= (*xipp)->order)) | |||
266 | continue; /* skip */ | |||
267 | save = *sipp; | |||
268 | *sipp = *xipp; | |||
269 | *xipp = save; | |||
270 | } | |||
271 | } | |||
272 | ||||
273 | /* | |||
274 | * Traverse the (now) ordered list of system initialization tasks. | |||
275 | * Perform each task, and continue on to the next task. | |||
276 | */ | |||
277 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
278 | mtx_lock(&Giant)do { uintptr_t _tid = (uintptr_t)((__curthread())); if (((((( &Giant))))->mtx_lock != 0x00000004 || !atomic_cmpset_long (&(((((&Giant)))))->mtx_lock, 0x00000004, (_tid))) ) __mtx_lock_sleep(&(((((&Giant)))))->mtx_lock, _tid , (((0))), ((((void *)0))), ((0))); else do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__acquire->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__acquire->id , (uintptr_t) (((&Giant))), (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0); } while (0); } while (0); | |||
279 | for (sipp = start; sipp < stop; sipp++) { | |||
280 | if ((*sipp)->subsystem == SI_SUB_DUMMY) | |||
281 | continue; /* skip dummy task(s) */ | |||
282 | ||||
283 | /* Call function */ | |||
284 | (*((*sipp)->func)) ((*sipp)->udata); | |||
285 | } | |||
286 | mtx_unlock(&Giant)do { uintptr_t _tid = (uintptr_t)((__curthread())); if (((((& Giant))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release->id , (uintptr_t) (((&Giant))), (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0); } while (0); if ( ((((&Giant))))->mtx_lock != _tid || !atomic_cmpset_long (&(((((&Giant)))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(&(((((&Giant)))))->mtx_lock, ( ((0))), ((((void *)0))), ((0))); } while (0); | |||
287 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
288 | } | |||
289 | ||||
290 | static void | |||
291 | linker_file_register_sysctls(linker_file_t lf) | |||
292 | { | |||
293 | struct sysctl_oid **start, **stop, **oidp; | |||
294 | ||||
295 | KLD_DPF(FILE, | |||
296 | ("linker_file_register_sysctls: registering SYSCTLs for %s\n", | |||
297 | lf->filename)); | |||
298 | ||||
299 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
300 | ||||
301 | if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL((void *)0)) != 0) | |||
302 | return; | |||
303 | ||||
304 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
305 | sysctl_wlock(); | |||
306 | for (oidp = start; oidp < stop; oidp++) | |||
307 | sysctl_register_oid(*oidp); | |||
308 | sysctl_wunlock(); | |||
309 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
310 | } | |||
311 | ||||
312 | static void | |||
313 | linker_file_unregister_sysctls(linker_file_t lf) | |||
314 | { | |||
315 | struct sysctl_oid **start, **stop, **oidp; | |||
316 | ||||
317 | KLD_DPF(FILE, ("linker_file_unregister_sysctls: unregistering SYSCTLs" | |||
318 | " for %s\n", lf->filename)); | |||
319 | ||||
320 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
321 | ||||
322 | if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL((void *)0)) != 0) | |||
323 | return; | |||
324 | ||||
325 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
326 | sysctl_wlock(); | |||
327 | for (oidp = start; oidp < stop; oidp++) | |||
328 | sysctl_unregister_oid(*oidp); | |||
329 | sysctl_wunlock(); | |||
330 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
331 | } | |||
332 | ||||
333 | static int | |||
334 | linker_file_register_modules(linker_file_t lf) | |||
335 | { | |||
336 | struct mod_metadata **start, **stop, **mdp; | |||
337 | const moduledata_t *moddata; | |||
338 | int first_error, error; | |||
339 | ||||
340 | KLD_DPF(FILE, ("linker_file_register_modules: registering modules" | |||
341 | " in %s\n", lf->filename)); | |||
342 | ||||
343 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
344 | ||||
345 | if (linker_file_lookup_set(lf, "modmetadata_set", &start, | |||
346 | &stop, NULL((void *)0)) != 0) { | |||
347 | /* | |||
348 | * This fallback should be unnecessary, but if we get booted | |||
349 | * from boot2 instead of loader and we are missing our | |||
350 | * metadata then we have to try the best we can. | |||
351 | */ | |||
352 | if (lf == linker_kernel_file) { | |||
353 | start = SET_BEGIN(modmetadata_set)(&__start_set_modmetadata_set); | |||
354 | stop = SET_LIMIT(modmetadata_set)(&__stop_set_modmetadata_set); | |||
355 | } else | |||
356 | return (0); | |||
357 | } | |||
358 | first_error = 0; | |||
359 | for (mdp = start; mdp < stop; mdp++) { | |||
360 | if ((*mdp)->md_type != MDT_MODULE2) | |||
361 | continue; | |||
362 | moddata = (*mdp)->md_data; | |||
363 | KLD_DPF(FILE, ("Registering module %s in %s\n", | |||
364 | moddata->name, lf->filename)); | |||
365 | error = module_register(moddata, lf); | |||
366 | if (error) { | |||
367 | printf("Module %s failed to register: %d\n", | |||
368 | moddata->name, error); | |||
369 | if (first_error == 0) | |||
370 | first_error = error; | |||
371 | } | |||
372 | } | |||
373 | return (first_error); | |||
374 | } | |||
375 | ||||
376 | static void | |||
377 | linker_init_kernel_modules(void) | |||
378 | { | |||
379 | ||||
380 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
381 | linker_file_register_modules(linker_kernel_file); | |||
382 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
383 | } | |||
384 | ||||
385 | SYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules,static struct sysinit linker_kernel_sys_init = { SI_SUB_KLD, SI_ORDER_ANY , (sysinit_cfunc_t)(sysinit_nfunc_t)linker_init_kernel_modules , ((void *)(0)) }; __asm__(".globl " "__start_set_sysinit_set" ); __asm__(".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym_linker_kernel_sys_init __attribute__ ((__section__("set_" "sysinit_set"))) __attribute__((__used__ )) = &(linker_kernel_sys_init) | |||
386 | 0)static struct sysinit linker_kernel_sys_init = { SI_SUB_KLD, SI_ORDER_ANY , (sysinit_cfunc_t)(sysinit_nfunc_t)linker_init_kernel_modules , ((void *)(0)) }; __asm__(".globl " "__start_set_sysinit_set" ); __asm__(".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym_linker_kernel_sys_init __attribute__ ((__section__("set_" "sysinit_set"))) __attribute__((__used__ )) = &(linker_kernel_sys_init); | |||
387 | ||||
388 | static int | |||
389 | linker_load_file(const char *filename, linker_file_t *result) | |||
390 | { | |||
391 | linker_class_t lc; | |||
392 | linker_file_t lf; | |||
393 | int foundfile, error, modules; | |||
394 | ||||
395 | /* Refuse to load modules if securelevel raised */ | |||
396 | if (prison0.pr_securelevel > 0) | |||
397 | return (EPERM1); | |||
398 | ||||
399 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
400 | lf = linker_find_file_by_name(filename); | |||
401 | if (lf) { | |||
402 | KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," | |||
403 | " incrementing refs\n", filename)); | |||
404 | *result = lf; | |||
405 | lf->refs++; | |||
406 | return (0); | |||
407 | } | |||
408 | foundfile = 0; | |||
409 | error = 0; | |||
410 | ||||
411 | /* | |||
412 | * We do not need to protect (lock) classes here because there is | |||
413 | * no class registration past startup (SI_SUB_KLD, SI_ORDER_ANY) | |||
414 | * and there is no class deregistration mechanism at this time. | |||
415 | */ | |||
416 | TAILQ_FOREACH(lc, &classes, link)for ((lc) = (((&classes))->tqh_first); (lc); (lc) = (( (lc))->link.tqe_next)) { | |||
417 | KLD_DPF(FILE, ("linker_load_file: trying to load %s\n", | |||
418 | filename)); | |||
419 | error = LINKER_LOAD_FILE(lc, filename, &lf); | |||
420 | /* | |||
421 | * If we got something other than ENOENT, then it exists but | |||
422 | * we cannot load it for some other reason. | |||
423 | */ | |||
424 | if (error != ENOENT2) | |||
425 | foundfile = 1; | |||
426 | if (lf) { | |||
427 | error = linker_file_register_modules(lf); | |||
428 | if (error == EEXIST17) { | |||
429 | linker_file_unload(lf, LINKER_UNLOAD_FORCE1); | |||
430 | return (error); | |||
431 | } | |||
432 | modules = !TAILQ_EMPTY(&lf->modules)((&lf->modules)->tqh_first == ((void *)0)); | |||
433 | linker_file_register_sysctls(lf); | |||
434 | linker_file_sysinit(lf); | |||
435 | lf->flags |= LINKER_FILE_LINKED0x1; | |||
436 | ||||
437 | /* | |||
438 | * If all of the modules in this file failed | |||
439 | * to load, unload the file and return an | |||
440 | * error of ENOEXEC. | |||
441 | */ | |||
442 | if (modules && TAILQ_EMPTY(&lf->modules)((&lf->modules)->tqh_first == ((void *)0))) { | |||
443 | linker_file_unload(lf, LINKER_UNLOAD_FORCE1); | |||
444 | return (ENOEXEC8); | |||
445 | } | |||
446 | EVENTHANDLER_INVOKE(kld_load, lf)do { struct eventhandler_list *_el; if ((_el = eventhandler_find_list ("kld_load")) != ((void *)0)) do { struct eventhandler_entry * _ep; struct eventhandler_entry_kld_load *_t; do { } while (0) ; (void)0; (_el)->el_runcount++; do { } while (0); (void)0 ; for ((_ep) = (((&((_el)->el_entries)))->tqh_first ); (_ep); (_ep) = (((_ep))->ee_link.tqe_next)) { if (_ep-> ee_priority != (-1)) { do { uintptr_t _tid = (uintptr_t)((__curthread ())); if (((((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); _t = (struct eventhandler_entry_kld_load *)_ep; (void)0; _t->eh_func(_ep->ee_arg , lf); do { uintptr_t _tid = (uintptr_t)((__curthread())); if ((((((&((_el))-> el_lock))))->mtx_lock != 0x00000004 || !atomic_cmpset_long (&(((((&((_el))->el_lock)))))->mtx_lock, 0x00000004 , (_tid)))) __mtx_lock_sleep(&(((((&((_el))->el_lock )))))->mtx_lock, _tid, (((0))), ((((void *)0))), ((0))); else do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__acquire ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__acquire ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); } while (0); } } do { } while (0); (_el)-> el_runcount--; if ((_el)->el_runcount == 0) eventhandler_prune_list (_el); do { uintptr_t _tid = (uintptr_t)((__curthread())); if (((((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); } while (0); } while (0); | |||
447 | *result = lf; | |||
448 | return (0); | |||
449 | } | |||
450 | } | |||
451 | /* | |||
452 | * Less than ideal, but tells the user whether it failed to load or | |||
453 | * the module was not found. | |||
454 | */ | |||
455 | if (foundfile) { | |||
456 | ||||
457 | /* | |||
458 | * If the file type has not been recognized by the last try | |||
459 | * printout a message before to fail. | |||
460 | */ | |||
461 | if (error == ENOSYS78) | |||
462 | printf("linker_load_file: Unsupported file type\n"); | |||
463 | ||||
464 | /* | |||
465 | * Format not recognized or otherwise unloadable. | |||
466 | * When loading a module that is statically built into | |||
467 | * the kernel EEXIST percolates back up as the return | |||
468 | * value. Preserve this so that apps like sysinstall | |||
469 | * can recognize this special case and not post bogus | |||
470 | * dialog boxes. | |||
471 | */ | |||
472 | if (error != EEXIST17) | |||
473 | error = ENOEXEC8; | |||
474 | } else | |||
475 | error = ENOENT2; /* Nothing found */ | |||
476 | return (error); | |||
477 | } | |||
478 | ||||
479 | int | |||
480 | linker_reference_module(const char *modname, struct mod_depend *verinfo, | |||
481 | linker_file_t *result) | |||
482 | { | |||
483 | modlist_t mod; | |||
484 | int error; | |||
485 | ||||
486 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
487 | if ((mod = modlist_lookup2(modname, verinfo)) != NULL((void *)0)) { | |||
488 | *result = mod->container; | |||
489 | (*result)->refs++; | |||
490 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
491 | return (0); | |||
492 | } | |||
493 | ||||
494 | error = linker_load_module(NULL((void *)0), modname, NULL((void *)0), verinfo, result); | |||
495 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
496 | return (error); | |||
497 | } | |||
498 | ||||
499 | int | |||
500 | linker_release_module(const char *modname, struct mod_depend *verinfo, | |||
501 | linker_file_t lf) | |||
502 | { | |||
503 | modlist_t mod; | |||
504 | int error; | |||
505 | ||||
506 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
507 | if (lf == NULL((void *)0)) { | |||
508 | KASSERT(modname != NULL,do { } while (0) | |||
509 | ("linker_release_module: no file or name"))do { } while (0); | |||
510 | mod = modlist_lookup2(modname, verinfo); | |||
511 | if (mod == NULL((void *)0)) { | |||
512 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
513 | return (ESRCH3); | |||
514 | } | |||
515 | lf = mod->container; | |||
516 | } else | |||
517 | KASSERT(modname == NULL && verinfo == NULL,do { } while (0) | |||
518 | ("linker_release_module: both file and name"))do { } while (0); | |||
519 | error = linker_file_unload(lf, LINKER_UNLOAD_NORMAL0); | |||
520 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
521 | return (error); | |||
522 | } | |||
523 | ||||
524 | static linker_file_t | |||
525 | linker_find_file_by_name(const char *filename) | |||
526 | { | |||
527 | linker_file_t lf; | |||
528 | char *koname; | |||
529 | ||||
530 | koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK0x0002); | |||
531 | sprintf(koname, "%s.ko", filename); | |||
532 | ||||
533 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
534 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
535 | if (strcmp(lf->filename, koname) == 0) | |||
536 | break; | |||
537 | if (strcmp(lf->filename, filename) == 0) | |||
538 | break; | |||
539 | } | |||
540 | free(koname, M_LINKER); | |||
541 | return (lf); | |||
542 | } | |||
543 | ||||
544 | static linker_file_t | |||
545 | linker_find_file_by_id(int fileid) | |||
546 | { | |||
547 | linker_file_t lf; | |||
548 | ||||
549 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
550 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) | |||
551 | if (lf->id == fileid && lf->flags & LINKER_FILE_LINKED0x1) | |||
552 | break; | |||
553 | return (lf); | |||
554 | } | |||
555 | ||||
556 | int | |||
557 | linker_file_foreach(linker_predicate_t *predicate, void *context) | |||
558 | { | |||
559 | linker_file_t lf; | |||
560 | int retval = 0; | |||
561 | ||||
562 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
563 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
564 | retval = predicate(lf, context); | |||
565 | if (retval != 0) | |||
566 | break; | |||
567 | } | |||
568 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
569 | return (retval); | |||
570 | } | |||
571 | ||||
572 | linker_file_t | |||
573 | linker_make_file(const char *pathname, linker_class_t lc) | |||
574 | { | |||
575 | linker_file_t lf; | |||
576 | const char *filename; | |||
577 | ||||
578 | if (!cold) | |||
579 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
580 | filename = linker_basename(pathname); | |||
581 | ||||
582 | KLD_DPF(FILE, ("linker_make_file: new file, filename='%s' for pathname='%s'\n", filename, pathname)); | |||
583 | lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK0x0002); | |||
584 | if (lf == NULL((void *)0)) | |||
585 | return (NULL((void *)0)); | |||
586 | lf->ctors_addr = 0; | |||
587 | lf->ctors_size = 0; | |||
588 | lf->refs = 1; | |||
589 | lf->userrefs = 0; | |||
590 | lf->flags = 0; | |||
591 | lf->filename = strdup(filename, M_LINKER); | |||
592 | lf->pathname = strdup(pathname, M_LINKER); | |||
593 | LINKER_GET_NEXT_FILE_ID(lf->id)do { linker_file_t lftmp; if (!cold) (void)0; retry: for ((lftmp ) = (((&linker_files))->tqh_first); (lftmp); (lftmp) = (((lftmp))->link.tqe_next)) { if (next_file_id == lftmp-> id) { next_file_id++; goto retry; } } (lf->id) = next_file_id ; } while(0); | |||
594 | lf->ndeps = 0; | |||
595 | lf->deps = NULL((void *)0); | |||
596 | lf->loadcnt = ++loadcnt; | |||
597 | STAILQ_INIT(&lf->common)do { (((&lf->common))->stqh_first) = ((void *)0); ( &lf->common)->stqh_last = &(((&lf->common ))->stqh_first); } while (0); | |||
598 | TAILQ_INIT(&lf->modules)do { (((&lf->modules))->tqh_first) = ((void *)0); ( &lf->modules)->tqh_last = &(((&lf->modules ))->tqh_first); ; } while (0); | |||
599 | TAILQ_INSERT_TAIL(&linker_files, lf, link)do { ; (((lf))->link.tqe_next) = ((void *)0); (lf)->link .tqe_prev = (&linker_files)->tqh_last; *(&linker_files )->tqh_last = (lf); (&linker_files)->tqh_last = & (((lf))->link.tqe_next); ; ; } while (0); | |||
600 | return (lf); | |||
601 | } | |||
602 | ||||
603 | int | |||
604 | linker_file_unload(linker_file_t file, int flags) | |||
605 | { | |||
606 | module_t mod, next; | |||
607 | modlist_t ml, nextml; | |||
608 | struct common_symbol *cp; | |||
609 | int error, i; | |||
610 | ||||
611 | /* Refuse to unload modules if securelevel raised. */ | |||
612 | if (prison0.pr_securelevel > 0) | |||
613 | return (EPERM1); | |||
614 | ||||
615 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
616 | KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); | |||
617 | ||||
618 | /* Easy case of just dropping a reference. */ | |||
619 | if (file->refs > 1) { | |||
620 | file->refs--; | |||
621 | return (0); | |||
622 | } | |||
623 | ||||
624 | /* Give eventhandlers a chance to prevent the unload. */ | |||
625 | error = 0; | |||
626 | EVENTHANDLER_INVOKE(kld_unload_try, file, &error)do { struct eventhandler_list *_el; if ((_el = eventhandler_find_list ("kld_unload_try")) != ((void *)0)) do { struct eventhandler_entry *_ep; struct eventhandler_entry_kld_unload_try *_t; do { } while (0); (void)0; (_el)->el_runcount++; do { } while (0); (void )0; for ((_ep) = (((&((_el)->el_entries)))->tqh_first ); (_ep); (_ep) = (((_ep))->ee_link.tqe_next)) { if (_ep-> ee_priority != (-1)) { do { uintptr_t _tid = (uintptr_t)((__curthread ())); if (((((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); _t = (struct eventhandler_entry_kld_unload_try *)_ep; (void)0; _t->eh_func(_ep->ee_arg , file, &error ); do { uintptr_t _tid = (uintptr_t)((__curthread())); if ((( (((&((_el))->el_lock))))->mtx_lock != 0x00000004 || !atomic_cmpset_long(&(((((&((_el))->el_lock)))))-> mtx_lock, 0x00000004, (_tid)))) __mtx_lock_sleep(&(((((& ((_el))->el_lock)))))->mtx_lock, _tid, (((0))), ((((void *)0))), ((0))); else do { (void)0; do { if (__builtin_expect ((sdt_lockstat___adaptive__acquire->id), 0)) (*sdt_probe_func )(sdt_lockstat___adaptive__acquire->id, (uintptr_t) (((& ((_el))->el_lock))), (uintptr_t) 0, (uintptr_t) 0, (uintptr_t ) 0, (uintptr_t) 0); } while (0); } while (0); } while (0); } } do { } while (0); (_el)->el_runcount--; if ((_el)->el_runcount == 0) eventhandler_prune_list(_el); do { uintptr_t _tid = (uintptr_t )((__curthread())); if (((((&((_el))->el_lock))))-> lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect ((sdt_lockstat___adaptive__release->id), 0)) (*sdt_probe_func )(sdt_lockstat___adaptive__release->id, (uintptr_t) (((& ((_el))->el_lock))), (uintptr_t) 0, (uintptr_t) 0, (uintptr_t ) 0, (uintptr_t) 0); } while (0); } while (0); if (((((&( (_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long (&(((((&((_el))->el_lock)))))->mtx_lock, (_tid) , 0x00000004)) __mtx_unlock_sleep(&(((((&((_el))-> el_lock)))))->mtx_lock, (((0))), ((((void *)0))), ((0))); } while (0); } while (0); } while (0); | |||
627 | if (error != 0) | |||
628 | return (EBUSY16); | |||
629 | ||||
630 | KLD_DPF(FILE, ("linker_file_unload: file is unloading," | |||
631 | " informing modules\n")); | |||
632 | ||||
633 | /* | |||
634 | * Quiesce all the modules to give them a chance to veto the unload. | |||
635 | */ | |||
636 | MOD_SLOCK(void)__sx_slock(((&modules_sx)), 0, (((void *)0)), (0)); | |||
637 | for (mod = TAILQ_FIRST(&file->modules)((&file->modules)->tqh_first); mod; | |||
638 | mod = module_getfnext(mod)) { | |||
639 | ||||
640 | error = module_quiesce(mod); | |||
641 | if (error != 0 && flags != LINKER_UNLOAD_FORCE1) { | |||
642 | KLD_DPF(FILE, ("linker_file_unload: module %s" | |||
643 | " vetoed unload\n", module_getname(mod))); | |||
644 | /* | |||
645 | * XXX: Do we need to tell all the quiesced modules | |||
646 | * that they can resume work now via a new module | |||
647 | * event? | |||
648 | */ | |||
649 | MOD_SUNLOCK__sx_sunlock(((&modules_sx)), (((void *)0)), (0)); | |||
650 | return (error); | |||
651 | } | |||
652 | } | |||
653 | MOD_SUNLOCK__sx_sunlock(((&modules_sx)), (((void *)0)), (0)); | |||
654 | ||||
655 | /* | |||
656 | * Inform any modules associated with this file that they are | |||
657 | * being unloaded. | |||
658 | */ | |||
659 | MOD_XLOCK(void)__sx_xlock(((&modules_sx)), (__curthread()), 0, ((( void *)0)), (0)); | |||
660 | for (mod = TAILQ_FIRST(&file->modules)((&file->modules)->tqh_first); mod; mod = next) { | |||
661 | next = module_getfnext(mod); | |||
662 | MOD_XUNLOCK__sx_xunlock(((&modules_sx)), (__curthread()), (((void *) 0)), (0)); | |||
663 | ||||
664 | /* | |||
665 | * Give the module a chance to veto the unload. | |||
666 | */ | |||
667 | if ((error = module_unload(mod)) != 0) { | |||
668 | #ifdef KLD_DEBUG | |||
669 | MOD_SLOCK(void)__sx_slock(((&modules_sx)), 0, (((void *)0)), (0)); | |||
670 | KLD_DPF(FILE, ("linker_file_unload: module %s" | |||
671 | " failed unload\n", module_getname(mod))); | |||
672 | MOD_SUNLOCK__sx_sunlock(((&modules_sx)), (((void *)0)), (0)); | |||
673 | #endif | |||
674 | return (error); | |||
675 | } | |||
676 | MOD_XLOCK(void)__sx_xlock(((&modules_sx)), (__curthread()), 0, ((( void *)0)), (0)); | |||
677 | module_release(mod); | |||
678 | } | |||
679 | MOD_XUNLOCK__sx_xunlock(((&modules_sx)), (__curthread()), (((void *) 0)), (0)); | |||
680 | ||||
681 | TAILQ_FOREACH_SAFE(ml, &found_modules, link, nextml)for ((ml) = (((&found_modules))->tqh_first); (ml) && ((nextml) = (((ml))->link.tqe_next), 1); (ml) = (nextml)) { | |||
682 | if (ml->container == file) { | |||
683 | TAILQ_REMOVE(&found_modules, ml, link)do { ; ; ; ; if (((((ml))->link.tqe_next)) != ((void *)0)) (((ml))->link.tqe_next)->link.tqe_prev = (ml)->link .tqe_prev; else { (&found_modules)->tqh_last = (ml)-> link.tqe_prev; ; } *(ml)->link.tqe_prev = (((ml))->link .tqe_next); ; ; ; } while (0); | |||
684 | free(ml, M_LINKER); | |||
685 | } | |||
686 | } | |||
687 | ||||
688 | /* | |||
689 | * Don't try to run SYSUNINITs if we are unloaded due to a | |||
690 | * link error. | |||
691 | */ | |||
692 | if (file->flags & LINKER_FILE_LINKED0x1) { | |||
693 | file->flags &= ~LINKER_FILE_LINKED0x1; | |||
694 | linker_file_sysuninit(file); | |||
695 | linker_file_unregister_sysctls(file); | |||
696 | } | |||
697 | TAILQ_REMOVE(&linker_files, file, link)do { ; ; ; ; if (((((file))->link.tqe_next)) != ((void *)0 )) (((file))->link.tqe_next)->link.tqe_prev = (file)-> link.tqe_prev; else { (&linker_files)->tqh_last = (file )->link.tqe_prev; ; } *(file)->link.tqe_prev = (((file) )->link.tqe_next); ; ; ; } while (0); | |||
698 | ||||
699 | if (file->deps) { | |||
700 | for (i = 0; i < file->ndeps; i++) | |||
701 | linker_file_unload(file->deps[i], flags); | |||
702 | free(file->deps, M_LINKER); | |||
703 | file->deps = NULL((void *)0); | |||
704 | } | |||
705 | while ((cp = STAILQ_FIRST(&file->common)((&file->common)->stqh_first)) != NULL((void *)0)) { | |||
706 | STAILQ_REMOVE_HEAD(&file->common, link)do { if (((((&file->common))->stqh_first) = (((((& file->common))->stqh_first))->link.stqe_next)) == (( void *)0)) (&file->common)->stqh_last = &(((& file->common))->stqh_first); } while (0); | |||
707 | free(cp, M_LINKER); | |||
708 | } | |||
709 | ||||
710 | LINKER_UNLOAD(file); | |||
711 | ||||
712 | EVENTHANDLER_INVOKE(kld_unload, file->filename, file->address,do { struct eventhandler_list *_el; if ((_el = eventhandler_find_list ("kld_unload")) != ((void *)0)) do { struct eventhandler_entry *_ep; struct eventhandler_entry_kld_unload *_t; do { } while (0); (void)0; (_el)->el_runcount++; do { } while (0); (void )0; for ((_ep) = (((&((_el)->el_entries)))->tqh_first ); (_ep); (_ep) = (((_ep))->ee_link.tqe_next)) { if (_ep-> ee_priority != (-1)) { do { uintptr_t _tid = (uintptr_t)((__curthread ())); if (((((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); _t = (struct eventhandler_entry_kld_unload *)_ep; (void)0; _t->eh_func(_ep->ee_arg , file->filename , file->address, file->size); do { uintptr_t _tid = (uintptr_t )((__curthread())); if ((((((&((_el))->el_lock))))-> mtx_lock != 0x00000004 || !atomic_cmpset_long(&(((((& ((_el))->el_lock)))))->mtx_lock, 0x00000004, (_tid)))) __mtx_lock_sleep (&(((((&((_el))->el_lock)))))->mtx_lock, _tid, ( ((0))), ((((void *)0))), ((0))); else do { (void)0; do { if ( __builtin_expect((sdt_lockstat___adaptive__acquire->id), 0 )) (*sdt_probe_func)(sdt_lockstat___adaptive__acquire->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t) 0, ( uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0); } while (0); } while (0); } } do { } while (0); (_el)->el_runcount --; if ((_el)->el_runcount == 0) eventhandler_prune_list(_el ); do { uintptr_t _tid = (uintptr_t)((__curthread())); if ((( ((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); } while (0); } while (0) | |||
713 | file->size)do { struct eventhandler_list *_el; if ((_el = eventhandler_find_list ("kld_unload")) != ((void *)0)) do { struct eventhandler_entry *_ep; struct eventhandler_entry_kld_unload *_t; do { } while (0); (void)0; (_el)->el_runcount++; do { } while (0); (void )0; for ((_ep) = (((&((_el)->el_entries)))->tqh_first ); (_ep); (_ep) = (((_ep))->ee_link.tqe_next)) { if (_ep-> ee_priority != (-1)) { do { uintptr_t _tid = (uintptr_t)((__curthread ())); if (((((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); _t = (struct eventhandler_entry_kld_unload *)_ep; (void)0; _t->eh_func(_ep->ee_arg , file->filename , file->address, file->size); do { uintptr_t _tid = (uintptr_t )((__curthread())); if ((((((&((_el))->el_lock))))-> mtx_lock != 0x00000004 || !atomic_cmpset_long(&(((((& ((_el))->el_lock)))))->mtx_lock, 0x00000004, (_tid)))) __mtx_lock_sleep (&(((((&((_el))->el_lock)))))->mtx_lock, _tid, ( ((0))), ((((void *)0))), ((0))); else do { (void)0; do { if ( __builtin_expect((sdt_lockstat___adaptive__acquire->id), 0 )) (*sdt_probe_func)(sdt_lockstat___adaptive__acquire->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t) 0, ( uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0); } while (0); } while (0); } } do { } while (0); (_el)->el_runcount --; if ((_el)->el_runcount == 0) eventhandler_prune_list(_el ); do { uintptr_t _tid = (uintptr_t)((__curthread())); if ((( ((&((_el))->el_lock))))->lock_object.lo_data == 0) do { (void)0; do { if (__builtin_expect((sdt_lockstat___adaptive__release ->id), 0)) (*sdt_probe_func)(sdt_lockstat___adaptive__release ->id, (uintptr_t) (((&((_el))->el_lock))), (uintptr_t ) 0, (uintptr_t) 0, (uintptr_t) 0, (uintptr_t) 0); } while (0 ); } while (0); if (((((&((_el))->el_lock))))->mtx_lock != _tid || !atomic_cmpset_long(&(((((&((_el))->el_lock )))))->mtx_lock, (_tid), 0x00000004)) __mtx_unlock_sleep(& (((((&((_el))->el_lock)))))->mtx_lock, (((0))), ((( (void *)0))), ((0))); } while (0); } while (0); } while (0); | |||
714 | ||||
715 | if (file->filename) { | |||
716 | free(file->filename, M_LINKER); | |||
717 | file->filename = NULL((void *)0); | |||
718 | } | |||
719 | if (file->pathname) { | |||
720 | free(file->pathname, M_LINKER); | |||
721 | file->pathname = NULL((void *)0); | |||
722 | } | |||
723 | kobj_delete((kobj_t) file, M_LINKER); | |||
724 | return (0); | |||
725 | } | |||
726 | ||||
727 | int | |||
728 | linker_ctf_get(linker_file_t file, linker_ctf_t *lc) | |||
729 | { | |||
730 | return (LINKER_CTF_GET(file, lc)); | |||
731 | } | |||
732 | ||||
733 | static int | |||
734 | linker_file_add_dependency(linker_file_t file, linker_file_t dep) | |||
735 | { | |||
736 | linker_file_t *newdeps; | |||
737 | ||||
738 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
739 | file->deps = realloc(file->deps, (file->ndeps + 1) * sizeof(*newdeps), | |||
740 | M_LINKER, M_WAITOK0x0002 | M_ZERO0x0100); | |||
741 | file->deps[file->ndeps] = dep; | |||
742 | file->ndeps++; | |||
743 | KLD_DPF(FILE, ("linker_file_add_dependency:" | |||
744 | " adding %s as dependency for %s\n", | |||
745 | dep->filename, file->filename)); | |||
746 | return (0); | |||
747 | } | |||
748 | ||||
749 | /* | |||
750 | * Locate a linker set and its contents. This is a helper function to avoid | |||
751 | * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. | |||
752 | * This function is used in this file so we can avoid having lots of (void **) | |||
753 | * casts. | |||
754 | */ | |||
755 | int | |||
756 | linker_file_lookup_set(linker_file_t file, const char *name, | |||
757 | void *firstp, void *lastp, int *countp) | |||
758 | { | |||
759 | ||||
760 | sx_assert(&kld_sx, SA_LOCKED)(void)0; | |||
761 | return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); | |||
762 | } | |||
763 | ||||
764 | /* | |||
765 | * List all functions in a file. | |||
766 | */ | |||
767 | int | |||
768 | linker_file_function_listall(linker_file_t lf, | |||
769 | linker_function_nameval_callback_t callback_func, void *arg) | |||
770 | { | |||
771 | return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); | |||
772 | } | |||
773 | ||||
774 | caddr_t | |||
775 | linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) | |||
776 | { | |||
777 | caddr_t sym; | |||
778 | int locked; | |||
779 | ||||
780 | locked = sx_xlocked(&kld_sx)(((&kld_sx)->sx_lock & ~((0x01 | 0x02 | 0x04 | 0x08 ) & ~0x01)) == (uintptr_t)(__curthread())); | |||
781 | if (!locked) | |||
782 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
783 | sym = linker_file_lookup_symbol_internal(file, name, deps); | |||
784 | if (!locked) | |||
785 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
786 | return (sym); | |||
787 | } | |||
788 | ||||
789 | static caddr_t | |||
790 | linker_file_lookup_symbol_internal(linker_file_t file, const char *name, | |||
791 | int deps) | |||
792 | { | |||
793 | c_linker_sym_t sym; | |||
794 | linker_symval_t symval; | |||
795 | caddr_t address; | |||
796 | size_t common_size = 0; | |||
797 | int i; | |||
798 | ||||
799 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
800 | KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", | |||
801 | file, name, deps)); | |||
802 | ||||
803 | if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { | |||
804 | LINKER_SYMBOL_VALUES(file, sym, &symval); | |||
805 | if (symval.value == 0) | |||
806 | /* | |||
807 | * For commons, first look them up in the | |||
808 | * dependencies and only allocate space if not found | |||
809 | * there. | |||
810 | */ | |||
811 | common_size = symval.size; | |||
812 | else { | |||
813 | KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol" | |||
814 | ".value=%p\n", symval.value)); | |||
815 | return (symval.value); | |||
816 | } | |||
817 | } | |||
818 | if (deps) { | |||
819 | for (i = 0; i < file->ndeps; i++) { | |||
820 | address = linker_file_lookup_symbol_internal( | |||
821 | file->deps[i], name, 0); | |||
822 | if (address) { | |||
823 | KLD_DPF(SYM, ("linker_file_lookup_symbol:" | |||
824 | " deps value=%p\n", address)); | |||
825 | return (address); | |||
826 | } | |||
827 | } | |||
828 | } | |||
829 | if (common_size > 0) { | |||
830 | /* | |||
831 | * This is a common symbol which was not found in the | |||
832 | * dependencies. We maintain a simple common symbol table in | |||
833 | * the file object. | |||
834 | */ | |||
835 | struct common_symbol *cp; | |||
836 | ||||
837 | STAILQ_FOREACH(cp, &file->common, link)for((cp) = (((&file->common))->stqh_first); (cp); ( cp) = (((cp))->link.stqe_next)) { | |||
838 | if (strcmp(cp->name, name) == 0) { | |||
839 | KLD_DPF(SYM, ("linker_file_lookup_symbol:" | |||
840 | " old common value=%p\n", cp->address)); | |||
841 | return (cp->address); | |||
842 | } | |||
843 | } | |||
844 | /* | |||
845 | * Round the symbol size up to align. | |||
846 | */ | |||
847 | common_size = (common_size + sizeof(int) - 1) & -sizeof(int); | |||
848 | cp = malloc(sizeof(struct common_symbol) | |||
849 | + common_size + strlen(name) + 1, M_LINKER, | |||
850 | M_WAITOK0x0002 | M_ZERO0x0100); | |||
851 | cp->address = (caddr_t)(cp + 1); | |||
852 | cp->name = cp->address + common_size; | |||
853 | strcpy(cp->name, name); | |||
854 | bzero(cp->address, common_size); | |||
855 | STAILQ_INSERT_TAIL(&file->common, cp, link)do { (((cp))->link.stqe_next) = ((void *)0); *(&file-> common)->stqh_last = (cp); (&file->common)->stqh_last = &(((cp))->link.stqe_next); } while (0); | |||
856 | ||||
857 | KLD_DPF(SYM, ("linker_file_lookup_symbol: new common" | |||
858 | " value=%p\n", cp->address)); | |||
859 | return (cp->address); | |||
860 | } | |||
861 | KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); | |||
862 | return (0); | |||
863 | } | |||
864 | ||||
865 | /* | |||
866 | * Both DDB and stack(9) rely on the kernel linker to provide forward and | |||
867 | * backward lookup of symbols. However, DDB and sometimes stack(9) need to | |||
868 | * do this in a lockfree manner. We provide a set of internal helper | |||
869 | * routines to perform these operations without locks, and then wrappers that | |||
870 | * optionally lock. | |||
871 | * | |||
872 | * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. | |||
873 | */ | |||
874 | #ifdef DDB | |||
875 | static int | |||
876 | linker_debug_lookup(const char *symstr, c_linker_sym_t *sym) | |||
877 | { | |||
878 | linker_file_t lf; | |||
879 | ||||
880 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
881 | if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) | |||
882 | return (0); | |||
883 | } | |||
884 | return (ENOENT2); | |||
885 | } | |||
886 | #endif | |||
887 | ||||
888 | static int | |||
889 | linker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) | |||
890 | { | |||
891 | linker_file_t lf; | |||
892 | c_linker_sym_t best, es; | |||
893 | u_long diff, bestdiff, off; | |||
894 | ||||
895 | best = 0; | |||
896 | off = (uintptr_t)value; | |||
897 | bestdiff = off; | |||
898 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
899 | if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) | |||
900 | continue; | |||
901 | if (es != 0 && diff < bestdiff) { | |||
902 | best = es; | |||
903 | bestdiff = diff; | |||
904 | } | |||
905 | if (bestdiff == 0) | |||
906 | break; | |||
907 | } | |||
908 | if (best) { | |||
909 | *sym = best; | |||
910 | *diffp = bestdiff; | |||
911 | return (0); | |||
912 | } else { | |||
913 | *sym = 0; | |||
914 | *diffp = off; | |||
915 | return (ENOENT2); | |||
916 | } | |||
917 | } | |||
918 | ||||
919 | static int | |||
920 | linker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) | |||
921 | { | |||
922 | linker_file_t lf; | |||
923 | ||||
924 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
925 | if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) | |||
926 | return (0); | |||
927 | } | |||
928 | return (ENOENT2); | |||
929 | } | |||
930 | ||||
931 | static int | |||
932 | linker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, | |||
933 | long *offset) | |||
934 | { | |||
935 | linker_symval_t symval; | |||
936 | c_linker_sym_t sym; | |||
937 | int error; | |||
938 | ||||
939 | *offset = 0; | |||
940 | error = linker_debug_search_symbol(value, &sym, offset); | |||
941 | if (error) | |||
942 | return (error); | |||
943 | error = linker_debug_symbol_values(sym, &symval); | |||
944 | if (error) | |||
945 | return (error); | |||
946 | strlcpy(buf, symval.name, buflen); | |||
947 | return (0); | |||
948 | } | |||
949 | ||||
950 | /* | |||
951 | * DDB Helpers. DDB has to look across multiple files with their own symbol | |||
952 | * tables and string tables. | |||
953 | * | |||
954 | * Note that we do not obey list locking protocols here. We really don't need | |||
955 | * DDB to hang because somebody's got the lock held. We'll take the chance | |||
956 | * that the files list is inconsistent instead. | |||
957 | */ | |||
958 | #ifdef DDB | |||
959 | int | |||
960 | linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) | |||
961 | { | |||
962 | ||||
963 | return (linker_debug_lookup(symstr, sym)); | |||
964 | } | |||
965 | #endif | |||
966 | ||||
967 | int | |||
968 | linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) | |||
969 | { | |||
970 | ||||
971 | return (linker_debug_search_symbol(value, sym, diffp)); | |||
972 | } | |||
973 | ||||
974 | int | |||
975 | linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) | |||
976 | { | |||
977 | ||||
978 | return (linker_debug_symbol_values(sym, symval)); | |||
979 | } | |||
980 | ||||
981 | int | |||
982 | linker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, | |||
983 | long *offset) | |||
984 | { | |||
985 | ||||
986 | return (linker_debug_search_symbol_name(value, buf, buflen, offset)); | |||
987 | } | |||
988 | ||||
989 | /* | |||
990 | * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do | |||
991 | * obey locking protocols, and offer a significantly less complex interface. | |||
992 | */ | |||
993 | int | |||
994 | linker_search_symbol_name(caddr_t value, char *buf, u_int buflen, | |||
995 | long *offset) | |||
996 | { | |||
997 | int error; | |||
998 | ||||
999 | sx_slock(&kld_sx)(void)__sx_slock(((&kld_sx)), 0, (((void *)0)), (0)); | |||
1000 | error = linker_debug_search_symbol_name(value, buf, buflen, offset); | |||
1001 | sx_sunlock(&kld_sx)__sx_sunlock(((&kld_sx)), (((void *)0)), (0)); | |||
1002 | return (error); | |||
1003 | } | |||
1004 | ||||
1005 | /* | |||
1006 | * Syscalls. | |||
1007 | */ | |||
1008 | int | |||
1009 | kern_kldload(struct thread *td, const char *file, int *fileid) | |||
1010 | { | |||
1011 | const char *kldname, *modname; | |||
1012 | linker_file_t lf; | |||
1013 | int error; | |||
1014 | ||||
1015 | if ((error = securelevel_gt(td->td_ucred, 0)) != 0) | |||
1016 | return (error); | |||
1017 | ||||
1018 | if ((error = priv_check(td, PRIV_KLD_LOAD130)) != 0) | |||
1019 | return (error); | |||
1020 | ||||
1021 | /* | |||
1022 | * It is possible that kldloaded module will attach a new ifnet, | |||
1023 | * so vnet context must be set when this ocurs. | |||
1024 | */ | |||
1025 | CURVNET_SET(TD_TO_VNET(td)); | |||
1026 | ||||
1027 | /* | |||
1028 | * If file does not contain a qualified name or any dot in it | |||
1029 | * (kldname.ko, or kldname.ver.ko) treat it as an interface | |||
1030 | * name. | |||
1031 | */ | |||
1032 | if (strchr(file, '/') || strchr(file, '.')) { | |||
1033 | kldname = file; | |||
1034 | modname = NULL((void *)0); | |||
1035 | } else { | |||
1036 | kldname = NULL((void *)0); | |||
1037 | modname = file; | |||
1038 | } | |||
1039 | ||||
1040 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1041 | error = linker_load_module(kldname, modname, NULL((void *)0), NULL((void *)0), &lf); | |||
1042 | if (error) { | |||
1043 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1044 | goto done; | |||
1045 | } | |||
1046 | lf->userrefs++; | |||
1047 | if (fileid != NULL((void *)0)) | |||
1048 | *fileid = lf->id; | |||
1049 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1050 | ||||
1051 | done: | |||
1052 | CURVNET_RESTORE(); | |||
1053 | return (error); | |||
1054 | } | |||
1055 | ||||
1056 | int | |||
1057 | sys_kldload(struct thread *td, struct kldload_args *uap) | |||
1058 | { | |||
1059 | char *pathname = NULL((void *)0); | |||
1060 | int error, fileid; | |||
1061 | ||||
1062 | td->td_retvaltd_uretoff.tdu_retval[0] = -1; | |||
1063 | ||||
1064 | pathname = malloc(MAXPATHLEN1024, M_TEMP, M_WAITOK0x0002); | |||
1065 | error = copyinstr(uap->file, pathname, MAXPATHLEN1024, NULL((void *)0)); | |||
1066 | if (error == 0) { | |||
1067 | error = kern_kldload(td, pathname, &fileid); | |||
1068 | if (error == 0) | |||
1069 | td->td_retvaltd_uretoff.tdu_retval[0] = fileid; | |||
1070 | } | |||
1071 | free(pathname, M_TEMP); | |||
1072 | return (error); | |||
1073 | } | |||
1074 | ||||
1075 | int | |||
1076 | kern_kldunload(struct thread *td, int fileid, int flags) | |||
1077 | { | |||
1078 | linker_file_t lf; | |||
1079 | int error = 0; | |||
1080 | ||||
1081 | if ((error = securelevel_gt(td->td_ucred, 0)) != 0) | |||
1082 | return (error); | |||
1083 | ||||
1084 | if ((error = priv_check(td, PRIV_KLD_UNLOAD131)) != 0) | |||
1085 | return (error); | |||
1086 | ||||
1087 | CURVNET_SET(TD_TO_VNET(td)); | |||
1088 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1089 | lf = linker_find_file_by_id(fileid); | |||
1090 | if (lf) { | |||
1091 | KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); | |||
1092 | ||||
1093 | if (lf->userrefs == 0) { | |||
1094 | /* | |||
1095 | * XXX: maybe LINKER_UNLOAD_FORCE should override ? | |||
1096 | */ | |||
1097 | printf("kldunload: attempt to unload file that was" | |||
1098 | " loaded by the kernel\n"); | |||
1099 | error = EBUSY16; | |||
1100 | } else { | |||
1101 | lf->userrefs--; | |||
1102 | error = linker_file_unload(lf, flags); | |||
1103 | if (error) | |||
1104 | lf->userrefs++; | |||
1105 | } | |||
1106 | } else | |||
1107 | error = ENOENT2; | |||
1108 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1109 | ||||
1110 | CURVNET_RESTORE(); | |||
1111 | return (error); | |||
1112 | } | |||
1113 | ||||
1114 | int | |||
1115 | sys_kldunload(struct thread *td, struct kldunload_args *uap) | |||
1116 | { | |||
1117 | ||||
1118 | return (kern_kldunload(td, uap->fileid, LINKER_UNLOAD_NORMAL0)); | |||
1119 | } | |||
1120 | ||||
1121 | int | |||
1122 | sys_kldunloadf(struct thread *td, struct kldunloadf_args *uap) | |||
1123 | { | |||
1124 | ||||
1125 | if (uap->flags != LINKER_UNLOAD_NORMAL0 && | |||
1126 | uap->flags != LINKER_UNLOAD_FORCE1) | |||
1127 | return (EINVAL22); | |||
1128 | return (kern_kldunload(td, uap->fileid, uap->flags)); | |||
1129 | } | |||
1130 | ||||
1131 | int | |||
1132 | sys_kldfind(struct thread *td, struct kldfind_args *uap) | |||
1133 | { | |||
1134 | char *pathname; | |||
1135 | const char *filename; | |||
1136 | linker_file_t lf; | |||
1137 | int error; | |||
1138 | ||||
1139 | #ifdef MAC1 | |||
1140 | error = mac_kld_check_stat(td->td_ucred); | |||
1141 | if (error) | |||
1142 | return (error); | |||
1143 | #endif | |||
1144 | ||||
1145 | td->td_retvaltd_uretoff.tdu_retval[0] = -1; | |||
1146 | ||||
1147 | pathname = malloc(MAXPATHLEN1024, M_TEMP, M_WAITOK0x0002); | |||
1148 | if ((error = copyinstr(uap->file, pathname, MAXPATHLEN1024, NULL((void *)0))) != 0) | |||
1149 | goto out; | |||
1150 | ||||
1151 | filename = linker_basename(pathname); | |||
1152 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1153 | lf = linker_find_file_by_name(filename); | |||
1154 | if (lf) | |||
1155 | td->td_retvaltd_uretoff.tdu_retval[0] = lf->id; | |||
1156 | else | |||
1157 | error = ENOENT2; | |||
1158 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1159 | out: | |||
1160 | free(pathname, M_TEMP); | |||
1161 | return (error); | |||
1162 | } | |||
1163 | ||||
1164 | int | |||
1165 | sys_kldnext(struct thread *td, struct kldnext_args *uap) | |||
1166 | { | |||
1167 | linker_file_t lf; | |||
1168 | int error = 0; | |||
1169 | ||||
1170 | #ifdef MAC1 | |||
1171 | error = mac_kld_check_stat(td->td_ucred); | |||
1172 | if (error) | |||
1173 | return (error); | |||
1174 | #endif | |||
1175 | ||||
1176 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1177 | if (uap->fileid == 0) | |||
1178 | lf = TAILQ_FIRST(&linker_files)((&linker_files)->tqh_first); | |||
1179 | else { | |||
1180 | lf = linker_find_file_by_id(uap->fileid); | |||
1181 | if (lf == NULL((void *)0)) { | |||
1182 | error = ENOENT2; | |||
1183 | goto out; | |||
1184 | } | |||
1185 | lf = TAILQ_NEXT(lf, link)((lf)->link.tqe_next); | |||
1186 | } | |||
1187 | ||||
1188 | /* Skip partially loaded files. */ | |||
1189 | while (lf != NULL((void *)0) && !(lf->flags & LINKER_FILE_LINKED0x1)) | |||
1190 | lf = TAILQ_NEXT(lf, link)((lf)->link.tqe_next); | |||
1191 | ||||
1192 | if (lf) | |||
1193 | td->td_retvaltd_uretoff.tdu_retval[0] = lf->id; | |||
1194 | else | |||
1195 | td->td_retvaltd_uretoff.tdu_retval[0] = 0; | |||
1196 | out: | |||
1197 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1198 | return (error); | |||
1199 | } | |||
1200 | ||||
1201 | int | |||
1202 | sys_kldstat(struct thread *td, struct kldstat_args *uap) | |||
1203 | { | |||
1204 | struct kld_file_stat stat; | |||
1205 | int error, version; | |||
1206 | ||||
1207 | /* | |||
1208 | * Check the version of the user's structure. | |||
1209 | */ | |||
1210 | if ((error = copyin(&uap->stat->version, &version, sizeof(version))) | |||
| ||||
1211 | != 0) | |||
1212 | return (error); | |||
1213 | if (version != sizeof(struct kld_file_stat_1) && | |||
1214 | version != sizeof(struct kld_file_stat)) | |||
1215 | return (EINVAL22); | |||
1216 | ||||
1217 | error = kern_kldstat(td, uap->fileid, &stat); | |||
1218 | if (error != 0) | |||
1219 | return (error); | |||
1220 | return (copyout(&stat, uap->stat, version)); | |||
| ||||
1221 | } | |||
1222 | ||||
1223 | int | |||
1224 | kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat) | |||
1225 | { | |||
1226 | linker_file_t lf; | |||
1227 | int namelen; | |||
1228 | #ifdef MAC1 | |||
1229 | int error; | |||
1230 | ||||
1231 | error = mac_kld_check_stat(td->td_ucred); | |||
1232 | if (error) | |||
1233 | return (error); | |||
1234 | #endif | |||
1235 | ||||
1236 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1237 | lf = linker_find_file_by_id(fileid); | |||
1238 | if (lf == NULL((void *)0)) { | |||
1239 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1240 | return (ENOENT2); | |||
1241 | } | |||
1242 | ||||
1243 | /* Version 1 fields: */ | |||
1244 | namelen = strlen(lf->filename) + 1; | |||
1245 | if (namelen > MAXPATHLEN1024) | |||
1246 | namelen = MAXPATHLEN1024; | |||
1247 | bcopy(lf->filename, &stat->name[0], namelen); | |||
1248 | stat->refs = lf->refs; | |||
1249 | stat->id = lf->id; | |||
1250 | stat->address = lf->address; | |||
1251 | stat->size = lf->size; | |||
1252 | /* Version 2 fields: */ | |||
1253 | namelen = strlen(lf->pathname) + 1; | |||
1254 | if (namelen > MAXPATHLEN1024) | |||
1255 | namelen = MAXPATHLEN1024; | |||
1256 | bcopy(lf->pathname, &stat->pathname[0], namelen); | |||
1257 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1258 | ||||
1259 | td->td_retvaltd_uretoff.tdu_retval[0] = 0; | |||
1260 | return (0); | |||
1261 | } | |||
1262 | ||||
1263 | #ifdef DDB | |||
1264 | DB_COMMAND(kldstat, db_kldstat) | |||
1265 | { | |||
1266 | linker_file_t lf; | |||
1267 | ||||
1268 | #define POINTER_WIDTH ((int)(sizeof(void *) * 2 + 2)) | |||
1269 | db_printf("Id Refs Address%*c Size Name\n", POINTER_WIDTH - 7, ' '); | |||
1270 | #undef POINTER_WIDTH | |||
1271 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
1272 | if (db_pager_quit) | |||
1273 | return; | |||
1274 | db_printf("%2d %4d %p %-8zx %s\n", lf->id, lf->refs, | |||
1275 | lf->address, lf->size, lf->filename); | |||
1276 | } | |||
1277 | } | |||
1278 | #endif /* DDB */ | |||
1279 | ||||
1280 | int | |||
1281 | sys_kldfirstmod(struct thread *td, struct kldfirstmod_args *uap) | |||
1282 | { | |||
1283 | linker_file_t lf; | |||
1284 | module_t mp; | |||
1285 | int error = 0; | |||
1286 | ||||
1287 | #ifdef MAC1 | |||
1288 | error = mac_kld_check_stat(td->td_ucred); | |||
1289 | if (error) | |||
1290 | return (error); | |||
1291 | #endif | |||
1292 | ||||
1293 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1294 | lf = linker_find_file_by_id(uap->fileid); | |||
1295 | if (lf) { | |||
1296 | MOD_SLOCK(void)__sx_slock(((&modules_sx)), 0, (((void *)0)), (0)); | |||
1297 | mp = TAILQ_FIRST(&lf->modules)((&lf->modules)->tqh_first); | |||
1298 | if (mp != NULL((void *)0)) | |||
1299 | td->td_retvaltd_uretoff.tdu_retval[0] = module_getid(mp); | |||
1300 | else | |||
1301 | td->td_retvaltd_uretoff.tdu_retval[0] = 0; | |||
1302 | MOD_SUNLOCK__sx_sunlock(((&modules_sx)), (((void *)0)), (0)); | |||
1303 | } else | |||
1304 | error = ENOENT2; | |||
1305 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1306 | return (error); | |||
1307 | } | |||
1308 | ||||
1309 | int | |||
1310 | sys_kldsym(struct thread *td, struct kldsym_args *uap) | |||
1311 | { | |||
1312 | char *symstr = NULL((void *)0); | |||
1313 | c_linker_sym_t sym; | |||
1314 | linker_symval_t symval; | |||
1315 | linker_file_t lf; | |||
1316 | struct kld_sym_lookup lookup; | |||
1317 | int error = 0; | |||
1318 | ||||
1319 | #ifdef MAC1 | |||
1320 | error = mac_kld_check_stat(td->td_ucred); | |||
1321 | if (error) | |||
1322 | return (error); | |||
1323 | #endif | |||
1324 | ||||
1325 | if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) | |||
1326 | return (error); | |||
1327 | if (lookup.version != sizeof(lookup) || | |||
1328 | uap->cmd != KLDSYM_LOOKUP1) | |||
1329 | return (EINVAL22); | |||
1330 | symstr = malloc(MAXPATHLEN1024, M_TEMP, M_WAITOK0x0002); | |||
1331 | if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN1024, NULL((void *)0))) != 0) | |||
1332 | goto out; | |||
1333 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1334 | if (uap->fileid != 0) { | |||
1335 | lf = linker_find_file_by_id(uap->fileid); | |||
1336 | if (lf == NULL((void *)0)) | |||
1337 | error = ENOENT2; | |||
1338 | else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && | |||
1339 | LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { | |||
1340 | lookup.symvalue = (uintptr_t) symval.value; | |||
1341 | lookup.symsize = symval.size; | |||
1342 | error = copyout(&lookup, uap->data, sizeof(lookup)); | |||
1343 | } else | |||
1344 | error = ENOENT2; | |||
1345 | } else { | |||
1346 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
1347 | if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && | |||
1348 | LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { | |||
1349 | lookup.symvalue = (uintptr_t)symval.value; | |||
1350 | lookup.symsize = symval.size; | |||
1351 | error = copyout(&lookup, uap->data, | |||
1352 | sizeof(lookup)); | |||
1353 | break; | |||
1354 | } | |||
1355 | } | |||
1356 | if (lf == NULL((void *)0)) | |||
1357 | error = ENOENT2; | |||
1358 | } | |||
1359 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1360 | out: | |||
1361 | free(symstr, M_TEMP); | |||
1362 | return (error); | |||
1363 | } | |||
1364 | ||||
1365 | /* | |||
1366 | * Preloaded module support | |||
1367 | */ | |||
1368 | ||||
1369 | static modlist_t | |||
1370 | modlist_lookup(const char *name, int ver) | |||
1371 | { | |||
1372 | modlist_t mod; | |||
1373 | ||||
1374 | TAILQ_FOREACH(mod, &found_modules, link)for ((mod) = (((&found_modules))->tqh_first); (mod); ( mod) = (((mod))->link.tqe_next)) { | |||
1375 | if (strcmp(mod->name, name) == 0 && | |||
1376 | (ver == 0 || mod->version == ver)) | |||
1377 | return (mod); | |||
1378 | } | |||
1379 | return (NULL((void *)0)); | |||
1380 | } | |||
1381 | ||||
1382 | static modlist_t | |||
1383 | modlist_lookup2(const char *name, const struct mod_depend *verinfo) | |||
1384 | { | |||
1385 | modlist_t mod, bestmod; | |||
1386 | int ver; | |||
1387 | ||||
1388 | if (verinfo == NULL((void *)0)) | |||
1389 | return (modlist_lookup(name, 0)); | |||
1390 | bestmod = NULL((void *)0); | |||
1391 | TAILQ_FOREACH(mod, &found_modules, link)for ((mod) = (((&found_modules))->tqh_first); (mod); ( mod) = (((mod))->link.tqe_next)) { | |||
1392 | if (strcmp(mod->name, name) != 0) | |||
1393 | continue; | |||
1394 | ver = mod->version; | |||
1395 | if (ver == verinfo->md_ver_preferred) | |||
1396 | return (mod); | |||
1397 | if (ver >= verinfo->md_ver_minimum && | |||
1398 | ver <= verinfo->md_ver_maximum && | |||
1399 | (bestmod == NULL((void *)0) || ver > bestmod->version)) | |||
1400 | bestmod = mod; | |||
1401 | } | |||
1402 | return (bestmod); | |||
1403 | } | |||
1404 | ||||
1405 | static modlist_t | |||
1406 | modlist_newmodule(const char *modname, int version, linker_file_t container) | |||
1407 | { | |||
1408 | modlist_t mod; | |||
1409 | ||||
1410 | mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT0x0001 | M_ZERO0x0100); | |||
1411 | if (mod == NULL((void *)0)) | |||
1412 | panic("no memory for module list"); | |||
1413 | mod->container = container; | |||
1414 | mod->name = modname; | |||
1415 | mod->version = version; | |||
1416 | TAILQ_INSERT_TAIL(&found_modules, mod, link)do { ; (((mod))->link.tqe_next) = ((void *)0); (mod)->link .tqe_prev = (&found_modules)->tqh_last; *(&found_modules )->tqh_last = (mod); (&found_modules)->tqh_last = & (((mod))->link.tqe_next); ; ; } while (0); | |||
1417 | return (mod); | |||
1418 | } | |||
1419 | ||||
1420 | static void | |||
1421 | linker_addmodules(linker_file_t lf, struct mod_metadata **start, | |||
1422 | struct mod_metadata **stop, int preload) | |||
1423 | { | |||
1424 | struct mod_metadata *mp, **mdp; | |||
1425 | const char *modname; | |||
1426 | int ver; | |||
1427 | ||||
1428 | for (mdp = start; mdp < stop; mdp++) { | |||
1429 | mp = *mdp; | |||
1430 | if (mp->md_type != MDT_VERSION3) | |||
1431 | continue; | |||
1432 | modname = mp->md_cval; | |||
1433 | ver = ((const struct mod_version *)mp->md_data)->mv_version; | |||
1434 | if (modlist_lookup(modname, ver) != NULL((void *)0)) { | |||
1435 | printf("module %s already present!\n", modname); | |||
1436 | /* XXX what can we do? this is a build error. :-( */ | |||
1437 | continue; | |||
1438 | } | |||
1439 | modlist_newmodule(modname, ver, lf); | |||
1440 | } | |||
1441 | } | |||
1442 | ||||
1443 | static void | |||
1444 | linker_preload(void *arg) | |||
1445 | { | |||
1446 | caddr_t modptr; | |||
1447 | const char *modname, *nmodname; | |||
1448 | char *modtype; | |||
1449 | linker_file_t lf, nlf; | |||
1450 | linker_class_t lc; | |||
1451 | int error; | |||
1452 | linker_file_list_t loaded_files; | |||
1453 | linker_file_list_t depended_files; | |||
1454 | struct mod_metadata *mp, *nmp; | |||
1455 | struct mod_metadata **start, **stop, **mdp, **nmdp; | |||
1456 | const struct mod_depend *verinfo; | |||
1457 | int nver; | |||
1458 | int resolves; | |||
1459 | modlist_t mod; | |||
1460 | struct sysinit **si_start, **si_stop; | |||
1461 | ||||
1462 | TAILQ_INIT(&loaded_files)do { (((&loaded_files))->tqh_first) = ((void *)0); (& loaded_files)->tqh_last = &(((&loaded_files))-> tqh_first); ; } while (0); | |||
1463 | TAILQ_INIT(&depended_files)do { (((&depended_files))->tqh_first) = ((void *)0); ( &depended_files)->tqh_last = &(((&depended_files ))->tqh_first); ; } while (0); | |||
1464 | TAILQ_INIT(&found_modules)do { (((&found_modules))->tqh_first) = ((void *)0); (& found_modules)->tqh_last = &(((&found_modules))-> tqh_first); ; } while (0); | |||
1465 | error = 0; | |||
1466 | ||||
1467 | modptr = NULL((void *)0); | |||
1468 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
1469 | while ((modptr = preload_search_next_name(modptr)) != NULL((void *)0)) { | |||
1470 | modname = (char *)preload_search_info(modptr, MODINFO_NAME0x0001); | |||
1471 | modtype = (char *)preload_search_info(modptr, MODINFO_TYPE0x0002); | |||
1472 | if (modname == NULL((void *)0)) { | |||
1473 | printf("Preloaded module at %p does not have a" | |||
1474 | " name!\n", modptr); | |||
1475 | continue; | |||
1476 | } | |||
1477 | if (modtype == NULL((void *)0)) { | |||
1478 | printf("Preloaded module at %p does not have a type!\n", | |||
1479 | modptr); | |||
1480 | continue; | |||
1481 | } | |||
1482 | if (bootverbose) | |||
1483 | printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, | |||
1484 | modptr); | |||
1485 | lf = NULL((void *)0); | |||
1486 | TAILQ_FOREACH(lc, &classes, link)for ((lc) = (((&classes))->tqh_first); (lc); (lc) = (( (lc))->link.tqe_next)) { | |||
1487 | error = LINKER_LINK_PRELOAD(lc, modname, &lf); | |||
1488 | if (!error) | |||
1489 | break; | |||
1490 | lf = NULL((void *)0); | |||
1491 | } | |||
1492 | if (lf) | |||
1493 | TAILQ_INSERT_TAIL(&loaded_files, lf, loaded)do { ; (((lf))->loaded.tqe_next) = ((void *)0); (lf)->loaded .tqe_prev = (&loaded_files)->tqh_last; *(&loaded_files )->tqh_last = (lf); (&loaded_files)->tqh_last = & (((lf))->loaded.tqe_next); ; ; } while (0); | |||
1494 | } | |||
1495 | ||||
1496 | /* | |||
1497 | * First get a list of stuff in the kernel. | |||
1498 | */ | |||
1499 | if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME"modmetadata_set", &start, | |||
1500 | &stop, NULL((void *)0)) == 0) | |||
1501 | linker_addmodules(linker_kernel_file, start, stop, 1); | |||
1502 | ||||
1503 | /* | |||
1504 | * This is a once-off kinky bubble sort to resolve relocation | |||
1505 | * dependency requirements. | |||
1506 | */ | |||
1507 | restart: | |||
1508 | TAILQ_FOREACH(lf, &loaded_files, loaded)for ((lf) = (((&loaded_files))->tqh_first); (lf); (lf) = (((lf))->loaded.tqe_next)) { | |||
1509 | error = linker_file_lookup_set(lf, MDT_SETNAME"modmetadata_set", &start, | |||
1510 | &stop, NULL((void *)0)); | |||
1511 | /* | |||
1512 | * First, look to see if we would successfully link with this | |||
1513 | * stuff. | |||
1514 | */ | |||
1515 | resolves = 1; /* unless we know otherwise */ | |||
1516 | if (!error) { | |||
1517 | for (mdp = start; mdp < stop; mdp++) { | |||
1518 | mp = *mdp; | |||
1519 | if (mp->md_type != MDT_DEPEND1) | |||
1520 | continue; | |||
1521 | modname = mp->md_cval; | |||
1522 | verinfo = mp->md_data; | |||
1523 | for (nmdp = start; nmdp < stop; nmdp++) { | |||
1524 | nmp = *nmdp; | |||
1525 | if (nmp->md_type != MDT_VERSION3) | |||
1526 | continue; | |||
1527 | nmodname = nmp->md_cval; | |||
1528 | if (strcmp(modname, nmodname) == 0) | |||
1529 | break; | |||
1530 | } | |||
1531 | if (nmdp < stop) /* it's a self reference */ | |||
1532 | continue; | |||
1533 | ||||
1534 | /* | |||
1535 | * ok, the module isn't here yet, we | |||
1536 | * are not finished | |||
1537 | */ | |||
1538 | if (modlist_lookup2(modname, verinfo) == NULL((void *)0)) | |||
1539 | resolves = 0; | |||
1540 | } | |||
1541 | } | |||
1542 | /* | |||
1543 | * OK, if we found our modules, we can link. So, "provide" | |||
1544 | * the modules inside and add it to the end of the link order | |||
1545 | * list. | |||
1546 | */ | |||
1547 | if (resolves) { | |||
1548 | if (!error) { | |||
1549 | for (mdp = start; mdp < stop; mdp++) { | |||
1550 | mp = *mdp; | |||
1551 | if (mp->md_type != MDT_VERSION3) | |||
1552 | continue; | |||
1553 | modname = mp->md_cval; | |||
1554 | nver = ((const struct mod_version *) | |||
1555 | mp->md_data)->mv_version; | |||
1556 | if (modlist_lookup(modname, | |||
1557 | nver) != NULL((void *)0)) { | |||
1558 | printf("module %s already" | |||
1559 | " present!\n", modname); | |||
1560 | TAILQ_REMOVE(&loaded_files,do { ; ; ; ; if (((((lf))->loaded.tqe_next)) != ((void *)0 )) (((lf))->loaded.tqe_next)->loaded.tqe_prev = (lf)-> loaded.tqe_prev; else { (&loaded_files)->tqh_last = (lf )->loaded.tqe_prev; ; } *(lf)->loaded.tqe_prev = (((lf) )->loaded.tqe_next); ; ; ; } while (0) | |||
1561 | lf, loaded)do { ; ; ; ; if (((((lf))->loaded.tqe_next)) != ((void *)0 )) (((lf))->loaded.tqe_next)->loaded.tqe_prev = (lf)-> loaded.tqe_prev; else { (&loaded_files)->tqh_last = (lf )->loaded.tqe_prev; ; } *(lf)->loaded.tqe_prev = (((lf) )->loaded.tqe_next); ; ; ; } while (0); | |||
1562 | linker_file_unload(lf, | |||
1563 | LINKER_UNLOAD_FORCE1); | |||
1564 | /* we changed tailq next ptr */ | |||
1565 | goto restart; | |||
1566 | } | |||
1567 | modlist_newmodule(modname, nver, lf); | |||
1568 | } | |||
1569 | } | |||
1570 | TAILQ_REMOVE(&loaded_files, lf, loaded)do { ; ; ; ; if (((((lf))->loaded.tqe_next)) != ((void *)0 )) (((lf))->loaded.tqe_next)->loaded.tqe_prev = (lf)-> loaded.tqe_prev; else { (&loaded_files)->tqh_last = (lf )->loaded.tqe_prev; ; } *(lf)->loaded.tqe_prev = (((lf) )->loaded.tqe_next); ; ; ; } while (0); | |||
1571 | TAILQ_INSERT_TAIL(&depended_files, lf, loaded)do { ; (((lf))->loaded.tqe_next) = ((void *)0); (lf)->loaded .tqe_prev = (&depended_files)->tqh_last; *(&depended_files )->tqh_last = (lf); (&depended_files)->tqh_last = & (((lf))->loaded.tqe_next); ; ; } while (0); | |||
1572 | /* | |||
1573 | * Since we provided modules, we need to restart the | |||
1574 | * sort so that the previous files that depend on us | |||
1575 | * have a chance. Also, we've busted the tailq next | |||
1576 | * pointer with the REMOVE. | |||
1577 | */ | |||
1578 | goto restart; | |||
1579 | } | |||
1580 | } | |||
1581 | ||||
1582 | /* | |||
1583 | * At this point, we check to see what could not be resolved.. | |||
1584 | */ | |||
1585 | while ((lf = TAILQ_FIRST(&loaded_files)((&loaded_files)->tqh_first)) != NULL((void *)0)) { | |||
1586 | TAILQ_REMOVE(&loaded_files, lf, loaded)do { ; ; ; ; if (((((lf))->loaded.tqe_next)) != ((void *)0 )) (((lf))->loaded.tqe_next)->loaded.tqe_prev = (lf)-> loaded.tqe_prev; else { (&loaded_files)->tqh_last = (lf )->loaded.tqe_prev; ; } *(lf)->loaded.tqe_prev = (((lf) )->loaded.tqe_next); ; ; ; } while (0); | |||
1587 | printf("KLD file %s is missing dependencies\n", lf->filename); | |||
1588 | linker_file_unload(lf, LINKER_UNLOAD_FORCE1); | |||
1589 | } | |||
1590 | ||||
1591 | /* | |||
1592 | * We made it. Finish off the linking in the order we determined. | |||
1593 | */ | |||
1594 | TAILQ_FOREACH_SAFE(lf, &depended_files, loaded, nlf)for ((lf) = (((&depended_files))->tqh_first); (lf) && ((nlf) = (((lf))->loaded.tqe_next), 1); (lf) = (nlf)) { | |||
1595 | if (linker_kernel_file) { | |||
1596 | linker_kernel_file->refs++; | |||
1597 | error = linker_file_add_dependency(lf, | |||
1598 | linker_kernel_file); | |||
1599 | if (error) | |||
1600 | panic("cannot add dependency"); | |||
1601 | } | |||
1602 | lf->userrefs++; /* so we can (try to) kldunload it */ | |||
1603 | error = linker_file_lookup_set(lf, MDT_SETNAME"modmetadata_set", &start, | |||
1604 | &stop, NULL((void *)0)); | |||
1605 | if (!error) { | |||
1606 | for (mdp = start; mdp < stop; mdp++) { | |||
1607 | mp = *mdp; | |||
1608 | if (mp->md_type != MDT_DEPEND1) | |||
1609 | continue; | |||
1610 | modname = mp->md_cval; | |||
1611 | verinfo = mp->md_data; | |||
1612 | mod = modlist_lookup2(modname, verinfo); | |||
1613 | if (mod == NULL((void *)0)) { | |||
1614 | printf("KLD file %s - cannot find " | |||
1615 | "dependency \"%s\"\n", | |||
1616 | lf->filename, modname); | |||
1617 | goto fail; | |||
1618 | } | |||
1619 | /* Don't count self-dependencies */ | |||
1620 | if (lf == mod->container) | |||
1621 | continue; | |||
1622 | mod->container->refs++; | |||
1623 | error = linker_file_add_dependency(lf, | |||
1624 | mod->container); | |||
1625 | if (error) | |||
1626 | panic("cannot add dependency"); | |||
1627 | } | |||
1628 | } | |||
1629 | /* | |||
1630 | * Now do relocation etc using the symbol search paths | |||
1631 | * established by the dependencies | |||
1632 | */ | |||
1633 | error = LINKER_LINK_PRELOAD_FINISH(lf); | |||
1634 | if (error) { | |||
1635 | printf("KLD file %s - could not finalize loading\n", | |||
1636 | lf->filename); | |||
1637 | goto fail; | |||
1638 | } | |||
1639 | linker_file_register_modules(lf); | |||
1640 | if (linker_file_lookup_set(lf, "sysinit_set", &si_start, | |||
1641 | &si_stop, NULL((void *)0)) == 0) | |||
1642 | sysinit_add(si_start, si_stop); | |||
1643 | linker_file_register_sysctls(lf); | |||
1644 | lf->flags |= LINKER_FILE_LINKED0x1; | |||
1645 | continue; | |||
1646 | fail: | |||
1647 | TAILQ_REMOVE(&depended_files, lf, loaded)do { ; ; ; ; if (((((lf))->loaded.tqe_next)) != ((void *)0 )) (((lf))->loaded.tqe_next)->loaded.tqe_prev = (lf)-> loaded.tqe_prev; else { (&depended_files)->tqh_last = ( lf)->loaded.tqe_prev; ; } *(lf)->loaded.tqe_prev = (((lf ))->loaded.tqe_next); ; ; ; } while (0); | |||
1648 | linker_file_unload(lf, LINKER_UNLOAD_FORCE1); | |||
1649 | } | |||
1650 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
1651 | /* woohoo! we made it! */ | |||
1652 | } | |||
1653 | ||||
1654 | SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0)static struct sysinit preload_sys_init = { SI_SUB_KLD, SI_ORDER_MIDDLE , (sysinit_cfunc_t)(sysinit_nfunc_t)linker_preload, ((void *) (0)) }; __asm__(".globl " "__start_set_sysinit_set"); __asm__ (".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym_preload_sys_init __attribute__((__section__ ("set_" "sysinit_set"))) __attribute__((__used__)) = &(preload_sys_init ); | |||
1655 | ||||
1656 | /* | |||
1657 | * Search for a not-loaded module by name. | |||
1658 | * | |||
1659 | * Modules may be found in the following locations: | |||
1660 | * | |||
1661 | * - preloaded (result is just the module name) - on disk (result is full path | |||
1662 | * to module) | |||
1663 | * | |||
1664 | * If the module name is qualified in any way (contains path, etc.) the we | |||
1665 | * simply return a copy of it. | |||
1666 | * | |||
1667 | * The search path can be manipulated via sysctl. Note that we use the ';' | |||
1668 | * character as a separator to be consistent with the bootloader. | |||
1669 | */ | |||
1670 | ||||
1671 | static char linker_hintfile[] = "linker.hints"; | |||
1672 | static char linker_path[MAXPATHLEN1024] = "/boot/kernel;/boot/modules"; | |||
1673 | ||||
1674 | SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RWTUN, linker_path,static struct sysctl_oid sysctl___kern_module_path = { .oid_parent = ((&(&sysctl___kern)->oid_children)), .oid_children = { ((void *)0) }, .oid_number = ((-1)), .oid_kind = (3|(((0x80000000 |0x40000000)|0x00080000))), .oid_arg1 = (linker_path), .oid_arg2 = (sizeof(linker_path)), .oid_name = ("module_path"), .oid_handler = (sysctl_handle_string), .oid_fmt = ("A"), .oid_descr = "module load search path" }; __asm__(".globl " "__start_set_sysctl_set"); __asm__(".globl " "__stop_set_sysctl_set"); static void const * const __set_sysctl_set_sym_sysctl___kern_module_path __attribute__((__section__("set_" "sysctl_set"))) __attribute__ ((__used__)) = &(sysctl___kern_module_path); _Static_assert (((((0x80000000|0x40000000)|0x00080000)) & 0xf) == 0 || ( (((0x80000000|0x40000000)|0x00080000)) & 0) == 3, "compile-time assertion failed" ) | |||
1675 | sizeof(linker_path), "module load search path")static struct sysctl_oid sysctl___kern_module_path = { .oid_parent = ((&(&sysctl___kern)->oid_children)), .oid_children = { ((void *)0) }, .oid_number = ((-1)), .oid_kind = (3|(((0x80000000 |0x40000000)|0x00080000))), .oid_arg1 = (linker_path), .oid_arg2 = (sizeof(linker_path)), .oid_name = ("module_path"), .oid_handler = (sysctl_handle_string), .oid_fmt = ("A"), .oid_descr = "module load search path" }; __asm__(".globl " "__start_set_sysctl_set"); __asm__(".globl " "__stop_set_sysctl_set"); static void const * const __set_sysctl_set_sym_sysctl___kern_module_path __attribute__((__section__("set_" "sysctl_set"))) __attribute__ ((__used__)) = &(sysctl___kern_module_path); _Static_assert (((((0x80000000|0x40000000)|0x00080000)) & 0xf) == 0 || ( (((0x80000000|0x40000000)|0x00080000)) & 0) == 3, "compile-time assertion failed" ); | |||
1676 | ||||
1677 | TUNABLE_STR("module_path", linker_path, sizeof(linker_path))static struct tunable_str __tunable_str_1677 = { ("module_path" ), (linker_path), (sizeof(linker_path)), }; static struct sysinit __Tunable_init_1677_sys_init = { SI_SUB_TUNABLES, SI_ORDER_MIDDLE , (sysinit_cfunc_t)(sysinit_nfunc_t)tunable_str_init, ((void * )(&__tunable_str_1677)) }; __asm__(".globl " "__start_set_sysinit_set" ); __asm__(".globl " "__stop_set_sysinit_set"); static void const * const __set_sysinit_set_sym___Tunable_init_1677_sys_init __attribute__ ((__section__("set_" "sysinit_set"))) __attribute__((__used__ )) = &(__Tunable_init_1677_sys_init); | |||
1678 | ||||
1679 | static char *linker_ext_list[] = { | |||
1680 | "", | |||
1681 | ".ko", | |||
1682 | NULL((void *)0) | |||
1683 | }; | |||
1684 | ||||
1685 | /* | |||
1686 | * Check if file actually exists either with or without extension listed in | |||
1687 | * the linker_ext_list. (probably should be generic for the rest of the | |||
1688 | * kernel) | |||
1689 | */ | |||
1690 | static char * | |||
1691 | linker_lookup_file(const char *path, int pathlen, const char *name, | |||
1692 | int namelen, struct vattr *vap) | |||
1693 | { | |||
1694 | struct nameidata nd; | |||
1695 | struct thread *td = curthread(__curthread()); /* XXX */ | |||
1696 | char *result, **cpp, *sep; | |||
1697 | int error, len, extlen, reclen, flags; | |||
1698 | enum vtype type; | |||
1699 | ||||
1700 | extlen = 0; | |||
1701 | for (cpp = linker_ext_list; *cpp; cpp++) { | |||
1702 | len = strlen(*cpp); | |||
1703 | if (len > extlen) | |||
1704 | extlen = len; | |||
1705 | } | |||
1706 | extlen++; /* trailing '\0' */ | |||
1707 | sep = (path[pathlen - 1] != '/') ? "/" : ""; | |||
1708 | ||||
1709 | reclen = pathlen + strlen(sep) + namelen + extlen + 1; | |||
1710 | result = malloc(reclen, M_LINKER, M_WAITOK0x0002); | |||
1711 | for (cpp = linker_ext_list; *cpp; cpp++) { | |||
1712 | snprintf(result, reclen, "%.*s%s%.*s%s", pathlen, path, sep, | |||
1713 | namelen, name, *cpp); | |||
1714 | /* | |||
1715 | * Attempt to open the file, and return the path if | |||
1716 | * we succeed and it's a regular file. | |||
1717 | */ | |||
1718 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td)NDINIT_ALL(&nd, 0, 0x0040, UIO_SYSSPACE, result, -100, (( void *)0), 0, td); | |||
1719 | flags = FREAD0x0001; | |||
1720 | error = vn_open(&nd, &flags, 0, NULL((void *)0)); | |||
1721 | if (error == 0) { | |||
1722 | NDFREE(&nd, NDF_ONLY_PNBUF(~0x00000020)); | |||
1723 | type = nd.ni_vp->v_type; | |||
1724 | if (vap) | |||
1725 | VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); | |||
1726 | VOP_UNLOCK(nd.ni_vp, 0); | |||
1727 | vn_close(nd.ni_vp, FREAD0x0001, td->td_ucred, td); | |||
1728 | if (type == VREG) | |||
1729 | return (result); | |||
1730 | } | |||
1731 | } | |||
1732 | free(result, M_LINKER); | |||
1733 | return (NULL((void *)0)); | |||
1734 | } | |||
1735 | ||||
1736 | #define INT_ALIGN(base, ptr)ptr = (base) + ((((ptr) - (base))+((sizeof(int))-1))&(~(( sizeof(int))-1))) ptr = \ | |||
1737 | (base) + roundup2((ptr) - (base), sizeof(int))((((ptr) - (base))+((sizeof(int))-1))&(~((sizeof(int))-1) )) | |||
1738 | ||||
1739 | /* | |||
1740 | * Lookup KLD which contains requested module in the "linker.hints" file. If | |||
1741 | * version specification is available, then try to find the best KLD. | |||
1742 | * Otherwise just find the latest one. | |||
1743 | */ | |||
1744 | static char * | |||
1745 | linker_hints_lookup(const char *path, int pathlen, const char *modname, | |||
1746 | int modnamelen, const struct mod_depend *verinfo) | |||
1747 | { | |||
1748 | struct thread *td = curthread(__curthread()); /* XXX */ | |||
1749 | struct ucred *cred = td ? td->td_ucred : NULL((void *)0); | |||
1750 | struct nameidata nd; | |||
1751 | struct vattr vattr, mattr; | |||
1752 | u_char *hints = NULL((void *)0); | |||
1753 | u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; | |||
1754 | int error, ival, bestver, *intp, found, flags, clen, blen; | |||
1755 | ssize_t reclen; | |||
1756 | ||||
1757 | result = NULL((void *)0); | |||
1758 | bestver = found = 0; | |||
1759 | ||||
1760 | sep = (path[pathlen - 1] != '/') ? "/" : ""; | |||
1761 | reclen = imax(modnamelen, strlen(linker_hintfile)) + pathlen + | |||
1762 | strlen(sep) + 1; | |||
1763 | pathbuf = malloc(reclen, M_LINKER, M_WAITOK0x0002); | |||
1764 | snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, | |||
1765 | linker_hintfile); | |||
1766 | ||||
1767 | NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td)NDINIT_ALL(&nd, 0, 0x0000, UIO_SYSSPACE, pathbuf, -100, ( (void *)0), 0, td); | |||
1768 | flags = FREAD0x0001; | |||
1769 | error = vn_open(&nd, &flags, 0, NULL((void *)0)); | |||
1770 | if (error) | |||
1771 | goto bad; | |||
1772 | NDFREE(&nd, NDF_ONLY_PNBUF(~0x00000020)); | |||
1773 | if (nd.ni_vp->v_type != VREG) | |||
1774 | goto bad; | |||
1775 | best = cp = NULL((void *)0); | |||
1776 | error = VOP_GETATTR(nd.ni_vp, &vattr, cred); | |||
1777 | if (error) | |||
1778 | goto bad; | |||
1779 | /* | |||
1780 | * XXX: we need to limit this number to some reasonable value | |||
1781 | */ | |||
1782 | if (vattr.va_size > LINKER_HINTS_MAX(1 << 20)) { | |||
1783 | printf("hints file too large %ld\n", (long)vattr.va_size); | |||
1784 | goto bad; | |||
1785 | } | |||
1786 | hints = malloc(vattr.va_size, M_TEMP, M_WAITOK0x0002); | |||
1787 | error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, | |||
1788 | UIO_SYSSPACE, IO_NODELOCKED0x0008, cred, NOCRED((struct ucred *)0), &reclen, td); | |||
1789 | if (error) | |||
1790 | goto bad; | |||
1791 | VOP_UNLOCK(nd.ni_vp, 0); | |||
1792 | vn_close(nd.ni_vp, FREAD0x0001, cred, td); | |||
1793 | nd.ni_vp = NULL((void *)0); | |||
1794 | if (reclen != 0) { | |||
1795 | printf("can't read %zd\n", reclen); | |||
1796 | goto bad; | |||
1797 | } | |||
1798 | intp = (int *)hints; | |||
1799 | ival = *intp++; | |||
1800 | if (ival != LINKER_HINTS_VERSION1) { | |||
1801 | printf("hints file version mismatch %d\n", ival); | |||
1802 | goto bad; | |||
1803 | } | |||
1804 | bufend = hints + vattr.va_size; | |||
1805 | recptr = (u_char *)intp; | |||
1806 | clen = blen = 0; | |||
1807 | while (recptr < bufend && !found) { | |||
1808 | intp = (int *)recptr; | |||
1809 | reclen = *intp++; | |||
1810 | ival = *intp++; | |||
1811 | cp = (char *)intp; | |||
1812 | switch (ival) { | |||
1813 | case MDT_VERSION3: | |||
1814 | clen = *cp++; | |||
1815 | if (clen != modnamelen || bcmp(cp, modname, clen) != 0) | |||
1816 | break; | |||
1817 | cp += clen; | |||
1818 | INT_ALIGN(hints, cp)cp = (hints) + ((((cp) - (hints))+((sizeof(int))-1))&(~(( sizeof(int))-1))); | |||
1819 | ival = *(int *)cp; | |||
1820 | cp += sizeof(int); | |||
1821 | clen = *cp++; | |||
1822 | if (verinfo == NULL((void *)0) || | |||
1823 | ival == verinfo->md_ver_preferred) { | |||
1824 | found = 1; | |||
1825 | break; | |||
1826 | } | |||
1827 | if (ival >= verinfo->md_ver_minimum && | |||
1828 | ival <= verinfo->md_ver_maximum && | |||
1829 | ival > bestver) { | |||
1830 | bestver = ival; | |||
1831 | best = cp; | |||
1832 | blen = clen; | |||
1833 | } | |||
1834 | break; | |||
1835 | default: | |||
1836 | break; | |||
1837 | } | |||
1838 | recptr += reclen + sizeof(int); | |||
1839 | } | |||
1840 | /* | |||
1841 | * Finally check if KLD is in the place | |||
1842 | */ | |||
1843 | if (found) | |||
1844 | result = linker_lookup_file(path, pathlen, cp, clen, &mattr); | |||
1845 | else if (best) | |||
1846 | result = linker_lookup_file(path, pathlen, best, blen, &mattr); | |||
1847 | ||||
1848 | /* | |||
1849 | * KLD is newer than hints file. What we should do now? | |||
1850 | */ | |||
1851 | if (result && timespeccmp(&mattr.va_mtime, &vattr.va_mtime, >)(((&mattr.va_mtime)->tv_sec == (&vattr.va_mtime)-> tv_sec) ? ((&mattr.va_mtime)->tv_nsec > (&vattr .va_mtime)->tv_nsec) : ((&mattr.va_mtime)->tv_sec > (&vattr.va_mtime)->tv_sec))) | |||
1852 | printf("warning: KLD '%s' is newer than the linker.hints" | |||
1853 | " file\n", result); | |||
1854 | bad: | |||
1855 | free(pathbuf, M_LINKER); | |||
1856 | if (hints) | |||
1857 | free(hints, M_TEMP); | |||
1858 | if (nd.ni_vp != NULL((void *)0)) { | |||
1859 | VOP_UNLOCK(nd.ni_vp, 0); | |||
1860 | vn_close(nd.ni_vp, FREAD0x0001, cred, td); | |||
1861 | } | |||
1862 | /* | |||
1863 | * If nothing found or hints is absent - fallback to the old | |||
1864 | * way by using "kldname[.ko]" as module name. | |||
1865 | */ | |||
1866 | if (!found && !bestver && result == NULL((void *)0)) | |||
1867 | result = linker_lookup_file(path, pathlen, modname, | |||
1868 | modnamelen, NULL((void *)0)); | |||
1869 | return (result); | |||
1870 | } | |||
1871 | ||||
1872 | /* | |||
1873 | * Lookup KLD which contains requested module in the all directories. | |||
1874 | */ | |||
1875 | static char * | |||
1876 | linker_search_module(const char *modname, int modnamelen, | |||
1877 | const struct mod_depend *verinfo) | |||
1878 | { | |||
1879 | char *cp, *ep, *result; | |||
1880 | ||||
1881 | /* | |||
1882 | * traverse the linker path | |||
1883 | */ | |||
1884 | for (cp = linker_path; *cp; cp = ep + 1) { | |||
1885 | /* find the end of this component */ | |||
1886 | for (ep = cp; (*ep != 0) && (*ep != ';'); ep++); | |||
1887 | result = linker_hints_lookup(cp, ep - cp, modname, | |||
1888 | modnamelen, verinfo); | |||
1889 | if (result != NULL((void *)0)) | |||
1890 | return (result); | |||
1891 | if (*ep == 0) | |||
1892 | break; | |||
1893 | } | |||
1894 | return (NULL((void *)0)); | |||
1895 | } | |||
1896 | ||||
1897 | /* | |||
1898 | * Search for module in all directories listed in the linker_path. | |||
1899 | */ | |||
1900 | static char * | |||
1901 | linker_search_kld(const char *name) | |||
1902 | { | |||
1903 | char *cp, *ep, *result; | |||
1904 | int len; | |||
1905 | ||||
1906 | /* qualified at all? */ | |||
1907 | if (strchr(name, '/')) | |||
1908 | return (strdup(name, M_LINKER)); | |||
1909 | ||||
1910 | /* traverse the linker path */ | |||
1911 | len = strlen(name); | |||
1912 | for (ep = linker_path; *ep; ep++) { | |||
1913 | cp = ep; | |||
1914 | /* find the end of this component */ | |||
1915 | for (; *ep != 0 && *ep != ';'; ep++); | |||
1916 | result = linker_lookup_file(cp, ep - cp, name, len, NULL((void *)0)); | |||
1917 | if (result != NULL((void *)0)) | |||
1918 | return (result); | |||
1919 | } | |||
1920 | return (NULL((void *)0)); | |||
1921 | } | |||
1922 | ||||
1923 | static const char * | |||
1924 | linker_basename(const char *path) | |||
1925 | { | |||
1926 | const char *filename; | |||
1927 | ||||
1928 | filename = strrchr(path, '/'); | |||
1929 | if (filename == NULL((void *)0)) | |||
1930 | return path; | |||
1931 | if (filename[1]) | |||
1932 | filename++; | |||
1933 | return (filename); | |||
1934 | } | |||
1935 | ||||
1936 | #ifdef HWPMC_HOOKS1 | |||
1937 | /* | |||
1938 | * Inform hwpmc about the set of kernel modules currently loaded. | |||
1939 | */ | |||
1940 | void * | |||
1941 | linker_hwpmc_list_objects(void) | |||
1942 | { | |||
1943 | linker_file_t lf; | |||
1944 | struct pmckern_map_in *kobase; | |||
1945 | int i, nmappings; | |||
1946 | ||||
1947 | nmappings = 0; | |||
1948 | sx_slock(&kld_sx)(void)__sx_slock(((&kld_sx)), 0, (((void *)0)), (0)); | |||
1949 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) | |||
1950 | nmappings++; | |||
1951 | ||||
1952 | /* Allocate nmappings + 1 entries. */ | |||
1953 | kobase = malloc((nmappings + 1) * sizeof(struct pmckern_map_in), | |||
1954 | M_LINKER, M_WAITOK0x0002 | M_ZERO0x0100); | |||
1955 | i = 0; | |||
1956 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
1957 | ||||
1958 | /* Save the info for this linker file. */ | |||
1959 | kobase[i].pm_file = lf->filename; | |||
1960 | kobase[i].pm_address = (uintptr_t)lf->address; | |||
1961 | i++; | |||
1962 | } | |||
1963 | sx_sunlock(&kld_sx)__sx_sunlock(((&kld_sx)), (((void *)0)), (0)); | |||
1964 | ||||
1965 | KASSERT(i > 0, ("linker_hpwmc_list_objects: no kernel objects?"))do { } while (0); | |||
1966 | ||||
1967 | /* The last entry of the malloced area comprises of all zeros. */ | |||
1968 | KASSERT(kobase[i].pm_file == NULL,do { } while (0) | |||
1969 | ("linker_hwpmc_list_objects: last object not NULL"))do { } while (0); | |||
1970 | ||||
1971 | return ((void *)kobase); | |||
1972 | } | |||
1973 | #endif | |||
1974 | ||||
1975 | /* | |||
1976 | * Find a file which contains given module and load it, if "parent" is not | |||
1977 | * NULL, register a reference to it. | |||
1978 | */ | |||
1979 | static int | |||
1980 | linker_load_module(const char *kldname, const char *modname, | |||
1981 | struct linker_file *parent, const struct mod_depend *verinfo, | |||
1982 | struct linker_file **lfpp) | |||
1983 | { | |||
1984 | linker_file_t lfdep; | |||
1985 | const char *filename; | |||
1986 | char *pathname; | |||
1987 | int error; | |||
1988 | ||||
1989 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
1990 | if (modname == NULL((void *)0)) { | |||
1991 | /* | |||
1992 | * We have to load KLD | |||
1993 | */ | |||
1994 | KASSERT(verinfo == NULL, ("linker_load_module: verinfo"do { } while (0) | |||
1995 | " is not NULL"))do { } while (0); | |||
1996 | pathname = linker_search_kld(kldname); | |||
1997 | } else { | |||
1998 | if (modlist_lookup2(modname, verinfo) != NULL((void *)0)) | |||
1999 | return (EEXIST17); | |||
2000 | if (kldname != NULL((void *)0)) | |||
2001 | pathname = strdup(kldname, M_LINKER); | |||
2002 | else if (rootvnode == NULL((void *)0)) | |||
2003 | pathname = NULL((void *)0); | |||
2004 | else | |||
2005 | /* | |||
2006 | * Need to find a KLD with required module | |||
2007 | */ | |||
2008 | pathname = linker_search_module(modname, | |||
2009 | strlen(modname), verinfo); | |||
2010 | } | |||
2011 | if (pathname == NULL((void *)0)) | |||
2012 | return (ENOENT2); | |||
2013 | ||||
2014 | /* | |||
2015 | * Can't load more than one file with the same basename XXX: | |||
2016 | * Actually it should be possible to have multiple KLDs with | |||
2017 | * the same basename but different path because they can | |||
2018 | * provide different versions of the same modules. | |||
2019 | */ | |||
2020 | filename = linker_basename(pathname); | |||
2021 | if (linker_find_file_by_name(filename)) | |||
2022 | error = EEXIST17; | |||
2023 | else do { | |||
2024 | error = linker_load_file(pathname, &lfdep); | |||
2025 | if (error) | |||
2026 | break; | |||
2027 | if (modname && verinfo && | |||
2028 | modlist_lookup2(modname, verinfo) == NULL((void *)0)) { | |||
2029 | linker_file_unload(lfdep, LINKER_UNLOAD_FORCE1); | |||
2030 | error = ENOENT2; | |||
2031 | break; | |||
2032 | } | |||
2033 | if (parent) { | |||
2034 | error = linker_file_add_dependency(parent, lfdep); | |||
2035 | if (error) | |||
2036 | break; | |||
2037 | } | |||
2038 | if (lfpp) | |||
2039 | *lfpp = lfdep; | |||
2040 | } while (0); | |||
2041 | free(pathname, M_LINKER); | |||
2042 | return (error); | |||
2043 | } | |||
2044 | ||||
2045 | /* | |||
2046 | * This routine is responsible for finding dependencies of userland initiated | |||
2047 | * kldload(2)'s of files. | |||
2048 | */ | |||
2049 | int | |||
2050 | linker_load_dependencies(linker_file_t lf) | |||
2051 | { | |||
2052 | linker_file_t lfdep; | |||
2053 | struct mod_metadata **start, **stop, **mdp, **nmdp; | |||
2054 | struct mod_metadata *mp, *nmp; | |||
2055 | const struct mod_depend *verinfo; | |||
2056 | modlist_t mod; | |||
2057 | const char *modname, *nmodname; | |||
2058 | int ver, error = 0, count; | |||
2059 | ||||
2060 | /* | |||
2061 | * All files are dependent on /kernel. | |||
2062 | */ | |||
2063 | sx_assert(&kld_sx, SA_XLOCKED)(void)0; | |||
2064 | if (linker_kernel_file) { | |||
2065 | linker_kernel_file->refs++; | |||
2066 | error = linker_file_add_dependency(lf, linker_kernel_file); | |||
2067 | if (error) | |||
2068 | return (error); | |||
2069 | } | |||
2070 | if (linker_file_lookup_set(lf, MDT_SETNAME"modmetadata_set", &start, &stop, | |||
2071 | &count) != 0) | |||
2072 | return (0); | |||
2073 | for (mdp = start; mdp < stop; mdp++) { | |||
2074 | mp = *mdp; | |||
2075 | if (mp->md_type != MDT_VERSION3) | |||
2076 | continue; | |||
2077 | modname = mp->md_cval; | |||
2078 | ver = ((const struct mod_version *)mp->md_data)->mv_version; | |||
2079 | mod = modlist_lookup(modname, ver); | |||
2080 | if (mod != NULL((void *)0)) { | |||
2081 | printf("interface %s.%d already present in the KLD" | |||
2082 | " '%s'!\n", modname, ver, | |||
2083 | mod->container->filename); | |||
2084 | return (EEXIST17); | |||
2085 | } | |||
2086 | } | |||
2087 | ||||
2088 | for (mdp = start; mdp < stop; mdp++) { | |||
2089 | mp = *mdp; | |||
2090 | if (mp->md_type != MDT_DEPEND1) | |||
2091 | continue; | |||
2092 | modname = mp->md_cval; | |||
2093 | verinfo = mp->md_data; | |||
2094 | nmodname = NULL((void *)0); | |||
2095 | for (nmdp = start; nmdp < stop; nmdp++) { | |||
2096 | nmp = *nmdp; | |||
2097 | if (nmp->md_type != MDT_VERSION3) | |||
2098 | continue; | |||
2099 | nmodname = nmp->md_cval; | |||
2100 | if (strcmp(modname, nmodname) == 0) | |||
2101 | break; | |||
2102 | } | |||
2103 | if (nmdp < stop)/* early exit, it's a self reference */ | |||
2104 | continue; | |||
2105 | mod = modlist_lookup2(modname, verinfo); | |||
2106 | if (mod) { /* woohoo, it's loaded already */ | |||
2107 | lfdep = mod->container; | |||
2108 | lfdep->refs++; | |||
2109 | error = linker_file_add_dependency(lf, lfdep); | |||
2110 | if (error) | |||
2111 | break; | |||
2112 | continue; | |||
2113 | } | |||
2114 | error = linker_load_module(NULL((void *)0), modname, lf, verinfo, NULL((void *)0)); | |||
2115 | if (error) { | |||
2116 | printf("KLD %s: depends on %s - not available or" | |||
2117 | " version mismatch\n", lf->filename, modname); | |||
2118 | break; | |||
2119 | } | |||
2120 | } | |||
2121 | ||||
2122 | if (error) | |||
2123 | return (error); | |||
2124 | linker_addmodules(lf, start, stop, 0); | |||
2125 | return (error); | |||
2126 | } | |||
2127 | ||||
2128 | static int | |||
2129 | sysctl_kern_function_list_iterate(const char *name, void *opaque) | |||
2130 | { | |||
2131 | struct sysctl_req *req; | |||
2132 | ||||
2133 | req = opaque; | |||
2134 | return (SYSCTL_OUT(req, name, strlen(name) + 1)(req->oldfunc)(req, name, strlen(name) + 1)); | |||
2135 | } | |||
2136 | ||||
2137 | /* | |||
2138 | * Export a nul-separated, double-nul-terminated list of all function names | |||
2139 | * in the kernel. | |||
2140 | */ | |||
2141 | static int | |||
2142 | sysctl_kern_function_list(SYSCTL_HANDLER_ARGSstruct sysctl_oid *oidp, void *arg1, intmax_t arg2, struct sysctl_req *req) | |||
2143 | { | |||
2144 | linker_file_t lf; | |||
2145 | int error; | |||
2146 | ||||
2147 | #ifdef MAC1 | |||
2148 | error = mac_kld_check_stat(req->td->td_ucred); | |||
2149 | if (error) | |||
2150 | return (error); | |||
2151 | #endif | |||
2152 | error = sysctl_wire_old_buffer(req, 0); | |||
2153 | if (error != 0) | |||
2154 | return (error); | |||
2155 | sx_xlock(&kld_sx)(void)__sx_xlock(((&kld_sx)), (__curthread()), 0, (((void *)0)), (0)); | |||
2156 | TAILQ_FOREACH(lf, &linker_files, link)for ((lf) = (((&linker_files))->tqh_first); (lf); (lf) = (((lf))->link.tqe_next)) { | |||
2157 | error = LINKER_EACH_FUNCTION_NAME(lf, | |||
2158 | sysctl_kern_function_list_iterate, req); | |||
2159 | if (error) { | |||
2160 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
2161 | return (error); | |||
2162 | } | |||
2163 | } | |||
2164 | sx_xunlock(&kld_sx)__sx_xunlock(((&kld_sx)), (__curthread()), (((void *)0)), (0)); | |||
2165 | return (SYSCTL_OUT(req, "", 1)(req->oldfunc)(req, "", 1)); | |||
2166 | } | |||
2167 | ||||
2168 | SYSCTL_PROC(_kern, OID_AUTO, function_list, CTLTYPE_OPAQUE | CTLFLAG_RD,static struct sysctl_oid sysctl___kern_function_list = { .oid_parent = ((&(&sysctl___kern)->oid_children)), .oid_children = { ((void *)0) }, .oid_number = ((-1)), .oid_kind = ((5 | 0x80000000 )), .oid_arg1 = (((void *)0)), .oid_arg2 = (0), .oid_name = ( "function_list"), .oid_handler = (sysctl_kern_function_list), .oid_fmt = (""), .oid_descr = "kernel function list" }; __asm__ (".globl " "__start_set_sysctl_set"); __asm__(".globl " "__stop_set_sysctl_set" ); static void const * const __set_sysctl_set_sym_sysctl___kern_function_list __attribute__((__section__("set_" "sysctl_set"))) __attribute__ ((__used__)) = &(sysctl___kern_function_list); _Static_assert (((5 | 0x80000000) & 0xf) != 0, "compile-time assertion failed" ) | |||
2169 | NULL, 0, sysctl_kern_function_list, "", "kernel function list")static struct sysctl_oid sysctl___kern_function_list = { .oid_parent = ((&(&sysctl___kern)->oid_children)), .oid_children = { ((void *)0) }, .oid_number = ((-1)), .oid_kind = ((5 | 0x80000000 )), .oid_arg1 = (((void *)0)), .oid_arg2 = (0), .oid_name = ( "function_list"), .oid_handler = (sysctl_kern_function_list), .oid_fmt = (""), .oid_descr = "kernel function list" }; __asm__ (".globl " "__start_set_sysctl_set"); __asm__(".globl " "__stop_set_sysctl_set" ); static void const * const __set_sysctl_set_sym_sysctl___kern_function_list __attribute__((__section__("set_" "sysctl_set"))) __attribute__ ((__used__)) = &(sysctl___kern_function_list); _Static_assert (((5 | 0x80000000) & 0xf) != 0, "compile-time assertion failed" ); |