diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-06-12 23:11:16 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-06-12 23:11:16 +0000 |
commit | 9f16d614083a96b521cbbca6d5c0b33da91991c4 (patch) | |
tree | 6ec4c6b71fc1728eb66011093f8ea3a2b8de5845 | |
parent | 44760d058cda8cdea96b02f2594797d2b43b01eb (diff) | |
download | busybox-w32-9f16d614083a96b521cbbca6d5c0b33da91991c4.tar.gz busybox-w32-9f16d614083a96b521cbbca6d5c0b33da91991c4.tar.bz2 busybox-w32-9f16d614083a96b521cbbca6d5c0b33da91991c4.zip |
Added a slightly modified version of Ron Alder's insmod patch.
Very cool stuff.
-Erik
-rw-r--r-- | Changelog | 9 | ||||
-rw-r--r-- | busybox.def.h | 18 | ||||
-rw-r--r-- | insmod.c | 2758 | ||||
-rw-r--r-- | modutils/insmod.c | 2758 | ||||
-rw-r--r-- | utility.c | 6 |
5 files changed, 5450 insertions, 99 deletions
@@ -1,12 +1,17 @@ | |||
1 | 0.44 | 1 | 0.44 |
2 | * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the | 2 | * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the |
3 | help messages (i.e --help). Saves 17k over a full compile. | 3 | help messages (i.e --help). Saves 17k over a full compile. |
4 | * Added mktemp, contributed by Daniel Jacobowitz <dan@debian.org> | ||
5 | * Added setkeycodes, for those that have wierd keyboard buttons. | ||
6 | * Added cut and tr from minix, since due to the license change, | 4 | * Added cut and tr from minix, since due to the license change, |
7 | we can now use minix code. Minix tr saves 4k. | 5 | we can now use minix code. Minix tr saves 4k. |
6 | * insmod now works. It costs 29k, but imagine an initrd with a | ||
7 | staticly linked busybox containing only insmod and sh, a few /dev | ||
8 | entries, and a kernel module or two... It doesn't get smaller | ||
9 | then this folks (I pity the fool that writes insmod in asm ;-). | ||
10 | Many kudos go to Ron Alder <alder@lineo.com> for finishing this off!!! | ||
8 | * Added a mini ar archive utility, especially written for BusyBox by | 11 | * Added a mini ar archive utility, especially written for BusyBox by |
9 | Glenn McGrath <bug1@netconnect.com.au> | 12 | Glenn McGrath <bug1@netconnect.com.au> |
13 | * Added mktemp, contributed by Daniel Jacobowitz <dan@debian.org> | ||
14 | * Added setkeycodes, for those that have wierd keyboard buttons. | ||
10 | * Added 'grep -v' option (inverted search) and updated | 15 | * Added 'grep -v' option (inverted search) and updated |
11 | docs accordingly. -beppu | 16 | docs accordingly. -beppu |
12 | * Wrote which | 17 | * Wrote which |
diff --git a/busybox.def.h b/busybox.def.h index 11a791ef4..62ea5096e 100644 --- a/busybox.def.h +++ b/busybox.def.h | |||
@@ -40,8 +40,7 @@ | |||
40 | #define BB_HOSTNAME | 40 | #define BB_HOSTNAME |
41 | #define BB_ID | 41 | #define BB_ID |
42 | #define BB_INIT | 42 | #define BB_INIT |
43 | // Don't bother turning BB_INSMOD on. It doesn't work yet. | 43 | #define BB_INSMOD |
44 | //#define BB_INSMOD | ||
45 | #define BB_KILL | 44 | #define BB_KILL |
46 | #define BB_KILLALL | 45 | #define BB_KILLALL |
47 | #define BB_KLOGD | 46 | #define BB_KLOGD |
@@ -219,6 +218,15 @@ | |||
219 | //Turn on extra fbset options | 218 | //Turn on extra fbset options |
220 | //#define BB_FEATURE_FBSET_FANCY | 219 | //#define BB_FEATURE_FBSET_FANCY |
221 | // | 220 | // |
221 | // You must enable one or both of these features | ||
222 | // Support installing modules from pre 2.1 kernels | ||
223 | //#define BB_FEATURE_INSMOD_OLD_KERNEL | ||
224 | // Support installing modules from kernel versions after 2.1.18 | ||
225 | #define BB_FEATURE_INSMOD_NEW_KERNEL | ||
226 | // | ||
227 | // Support module version checking | ||
228 | //#define BB_FEATURE_INSMOD_VERSION_CHECKING | ||
229 | // | ||
222 | // | 230 | // |
223 | // End of Features List | 231 | // End of Features List |
224 | // | 232 | // |
@@ -271,3 +279,9 @@ | |||
271 | #define BB_FEATURE_USE_TERMIOS | 279 | #define BB_FEATURE_USE_TERMIOS |
272 | #endif | 280 | #endif |
273 | #endif | 281 | #endif |
282 | // | ||
283 | #if defined BB_INSMOD | ||
284 | #ifndef BB_FEATURE_INSMOD_OLD_KERNEL | ||
285 | #define BB_FEATURE_INSMOD_NEW_KERNEL | ||
286 | #endif | ||
287 | #endif | ||
@@ -3,7 +3,15 @@ | |||
3 | * Mini insmod implementation for busybox | 3 | * Mini insmod implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 1999,2000 by Lineo, inc. | 5 | * Copyright (C) 1999,2000 by Lineo, inc. |
6 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> | 6 | * Written by Erik Andersen <andersen@lineo.com> |
7 | * and Ron Alder <alder@lineo.com> | ||
8 | * | ||
9 | * Based almost entirely on the Linux modutils-2.3.11 implementation. | ||
10 | * Copyright 1996, 1997 Linux International. | ||
11 | * New implementation contributed by Richard Henderson <rth@tamu.edu> | ||
12 | * Based on original work by Bjorn Ekwall <bj0rn@blox.se> | ||
13 | * Restructured (and partly rewritten) by: | ||
14 | * Björn Ekwall <bj0rn@blox.se> February 1999 | ||
7 | * | 15 | * |
8 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
@@ -24,25 +32,503 @@ | |||
24 | #include "internal.h" | 32 | #include "internal.h" |
25 | #include <stdlib.h> | 33 | #include <stdlib.h> |
26 | #include <stdio.h> | 34 | #include <stdio.h> |
35 | #include <stddef.h> | ||
27 | #include <errno.h> | 36 | #include <errno.h> |
28 | #include <unistd.h> | 37 | #include <unistd.h> |
29 | #include <dirent.h> | 38 | #include <dirent.h> |
39 | #include <ctype.h> | ||
40 | #include <assert.h> | ||
41 | #include <sys/utsname.h> | ||
30 | #include <sys/syscall.h> | 42 | #include <sys/syscall.h> |
31 | #include <linux/module.h> | 43 | |
44 | //---------------------------------------------------------------------------- | ||
45 | //--------modutils module.h, lines 45-242 | ||
46 | //---------------------------------------------------------------------------- | ||
47 | |||
48 | /* Definitions for the Linux module syscall interface. | ||
49 | Copyright 1996, 1997 Linux International. | ||
50 | |||
51 | Contributed by Richard Henderson <rth@tamu.edu> | ||
52 | |||
53 | This file is part of the Linux modutils. | ||
54 | |||
55 | This program is free software; you can redistribute it and/or modify it | ||
56 | under the terms of the GNU General Public License as published by the | ||
57 | Free Software Foundation; either version 2 of the License, or (at your | ||
58 | option) any later version. | ||
59 | |||
60 | This program is distributed in the hope that it will be useful, but | ||
61 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
62 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
63 | General Public License for more details. | ||
64 | |||
65 | You should have received a copy of the GNU General Public License | ||
66 | along with this program; if not, write to the Free Software Foundation, | ||
67 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
68 | |||
69 | |||
70 | #ifndef MODUTILS_MODULE_H | ||
71 | #define MODUTILS_MODULE_H 1 | ||
72 | |||
73 | #ident "$Id: insmod.c,v 1.8 2000/06/12 23:11:16 andersen Exp $" | ||
74 | |||
75 | /* This file contains the structures used by the 2.0 and 2.1 kernels. | ||
76 | We do not use the kernel headers directly because we do not wish | ||
77 | to be dependant on a particular kernel version to compile insmod. */ | ||
78 | |||
79 | |||
80 | /*======================================================================*/ | ||
81 | /* The structures used by Linux 2.0. */ | ||
82 | |||
83 | /* The symbol format used by get_kernel_syms(2). */ | ||
84 | struct old_kernel_sym | ||
85 | { | ||
86 | unsigned long value; | ||
87 | char name[60]; | ||
88 | }; | ||
89 | |||
90 | struct old_module_ref | ||
91 | { | ||
92 | unsigned long module; /* kernel addresses */ | ||
93 | unsigned long next; | ||
94 | }; | ||
95 | |||
96 | struct old_module_symbol | ||
97 | { | ||
98 | unsigned long addr; | ||
99 | unsigned long name; | ||
100 | }; | ||
101 | |||
102 | struct old_symbol_table | ||
103 | { | ||
104 | int size; /* total, including string table!!! */ | ||
105 | int n_symbols; | ||
106 | int n_refs; | ||
107 | struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */ | ||
108 | struct old_module_ref ref[0]; /* actual size defined by n_refs */ | ||
109 | }; | ||
110 | |||
111 | struct old_mod_routines | ||
112 | { | ||
113 | unsigned long init; | ||
114 | unsigned long cleanup; | ||
115 | }; | ||
116 | |||
117 | struct old_module | ||
118 | { | ||
119 | unsigned long next; | ||
120 | unsigned long ref; /* the list of modules that refer to me */ | ||
121 | unsigned long symtab; | ||
122 | unsigned long name; | ||
123 | int size; /* size of module in pages */ | ||
124 | unsigned long addr; /* address of module */ | ||
125 | int state; | ||
126 | unsigned long cleanup; /* cleanup routine */ | ||
127 | }; | ||
128 | |||
129 | /* Sent to init_module(2) or'ed into the code size parameter. */ | ||
130 | #define OLD_MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */ | ||
131 | |||
132 | int get_kernel_syms(struct old_kernel_sym *); | ||
133 | int old_sys_init_module(const char *name, char *code, unsigned codesize, | ||
134 | struct old_mod_routines *, struct old_symbol_table *); | ||
135 | |||
136 | /*======================================================================*/ | ||
137 | /* For sizeof() which are related to the module platform and not to the | ||
138 | environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ | ||
139 | |||
140 | #define tgt_sizeof_char sizeof(char) | ||
141 | #define tgt_sizeof_short sizeof(short) | ||
142 | #define tgt_sizeof_int sizeof(int) | ||
143 | #define tgt_sizeof_long sizeof(long) | ||
144 | #define tgt_sizeof_char_p sizeof(char *) | ||
145 | #define tgt_sizeof_void_p sizeof(void *) | ||
146 | #define tgt_long long | ||
147 | |||
148 | #if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) | ||
149 | #undef tgt_sizeof_long | ||
150 | #undef tgt_sizeof_char_p | ||
151 | #undef tgt_sizeof_void_p | ||
152 | #undef tgt_long | ||
153 | #define tgt_sizeof_long 8 | ||
154 | #define tgt_sizeof_char_p 8 | ||
155 | #define tgt_sizeof_void_p 8 | ||
156 | #define tgt_long long long | ||
157 | #endif | ||
158 | |||
159 | /*======================================================================*/ | ||
160 | /* The structures used in Linux 2.1. */ | ||
161 | |||
162 | /* Note: new_module_symbol does not use tgt_long intentionally */ | ||
163 | struct new_module_symbol | ||
164 | { | ||
165 | unsigned long value; | ||
166 | unsigned long name; | ||
167 | }; | ||
168 | |||
169 | struct new_module_persist; | ||
170 | |||
171 | struct new_module_ref | ||
172 | { | ||
173 | unsigned tgt_long dep; /* kernel addresses */ | ||
174 | unsigned tgt_long ref; | ||
175 | unsigned tgt_long next_ref; | ||
176 | }; | ||
177 | |||
178 | struct new_module | ||
179 | { | ||
180 | unsigned tgt_long size_of_struct; /* == sizeof(module) */ | ||
181 | unsigned tgt_long next; | ||
182 | unsigned tgt_long name; | ||
183 | unsigned tgt_long size; | ||
184 | |||
185 | tgt_long usecount; | ||
186 | unsigned tgt_long flags; /* AUTOCLEAN et al */ | ||
187 | |||
188 | unsigned nsyms; | ||
189 | unsigned ndeps; | ||
190 | |||
191 | unsigned tgt_long syms; | ||
192 | unsigned tgt_long deps; | ||
193 | unsigned tgt_long refs; | ||
194 | unsigned tgt_long init; | ||
195 | unsigned tgt_long cleanup; | ||
196 | unsigned tgt_long ex_table_start; | ||
197 | unsigned tgt_long ex_table_end; | ||
198 | #ifdef __alpha__ | ||
199 | unsigned tgt_long gp; | ||
200 | #endif | ||
201 | /* Everything after here is extension. */ | ||
202 | unsigned tgt_long persist_start; | ||
203 | unsigned tgt_long persist_end; | ||
204 | unsigned tgt_long can_unload; | ||
205 | unsigned tgt_long runsize; | ||
206 | }; | ||
207 | |||
208 | struct new_module_info | ||
209 | { | ||
210 | unsigned long addr; | ||
211 | unsigned long size; | ||
212 | unsigned long flags; | ||
213 | long usecount; | ||
214 | }; | ||
215 | |||
216 | /* Bits of module.flags. */ | ||
217 | #define NEW_MOD_RUNNING 1 | ||
218 | #define NEW_MOD_DELETED 2 | ||
219 | #define NEW_MOD_AUTOCLEAN 4 | ||
220 | #define NEW_MOD_VISITED 8 | ||
221 | #define NEW_MOD_USED_ONCE 16 | ||
222 | |||
223 | int new_sys_init_module(const char *name, const struct new_module *); | ||
224 | int query_module(const char *name, int which, void *buf, size_t bufsize, | ||
225 | size_t *ret); | ||
226 | |||
227 | /* Values for query_module's which. */ | ||
228 | |||
229 | #define QM_MODULES 1 | ||
230 | #define QM_DEPS 2 | ||
231 | #define QM_REFS 3 | ||
232 | #define QM_SYMBOLS 4 | ||
233 | #define QM_INFO 5 | ||
234 | |||
235 | /*======================================================================*/ | ||
236 | /* The system calls unchanged between 2.0 and 2.1. */ | ||
237 | |||
238 | unsigned long create_module(const char *, size_t); | ||
239 | int delete_module(const char *); | ||
240 | |||
241 | |||
242 | #endif /* module.h */ | ||
243 | |||
244 | //---------------------------------------------------------------------------- | ||
245 | //--------end of modutils module.h | ||
246 | //---------------------------------------------------------------------------- | ||
247 | |||
248 | |||
249 | |||
250 | //---------------------------------------------------------------------------- | ||
251 | //--------modutils obj.h, lines 253-462 | ||
252 | //---------------------------------------------------------------------------- | ||
253 | |||
254 | /* Elf object file loading and relocation routines. | ||
255 | Copyright 1996, 1997 Linux International. | ||
256 | |||
257 | Contributed by Richard Henderson <rth@tamu.edu> | ||
258 | |||
259 | This file is part of the Linux modutils. | ||
260 | |||
261 | This program is free software; you can redistribute it and/or modify it | ||
262 | under the terms of the GNU General Public License as published by the | ||
263 | Free Software Foundation; either version 2 of the License, or (at your | ||
264 | option) any later version. | ||
265 | |||
266 | This program is distributed in the hope that it will be useful, but | ||
267 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
268 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
269 | General Public License for more details. | ||
270 | |||
271 | You should have received a copy of the GNU General Public License | ||
272 | along with this program; if not, write to the Free Software Foundation, | ||
273 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
274 | |||
275 | |||
276 | #ifndef MODUTILS_OBJ_H | ||
277 | #define MODUTILS_OBJ_H 1 | ||
278 | |||
279 | #ident "$Id: insmod.c,v 1.8 2000/06/12 23:11:16 andersen Exp $" | ||
280 | |||
281 | /* The relocatable object is manipulated using elfin types. */ | ||
282 | |||
283 | #include <stdio.h> | ||
284 | #include <elf.h> | ||
285 | |||
286 | |||
287 | /* Machine-specific elf macros for i386 et al. */ | ||
288 | |||
289 | #define ELFCLASSM ELFCLASS32 | ||
290 | #define ELFDATAM ELFDATA2LSB | ||
291 | |||
292 | #define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) | ||
293 | |||
294 | #define SHT_RELM SHT_REL | ||
295 | #define Elf32_RelM Elf32_Rel | ||
296 | |||
297 | |||
298 | #ifndef ElfW | ||
299 | # if ELFCLASSM == ELFCLASS32 | ||
300 | # define ElfW(x) Elf32_ ## x | ||
301 | # define ELFW(x) ELF32_ ## x | ||
302 | # else | ||
303 | # define ElfW(x) Elf64_ ## x | ||
304 | # define ELFW(x) ELF64_ ## x | ||
305 | # endif | ||
306 | #endif | ||
307 | |||
308 | /* For some reason this is missing from libc5. */ | ||
309 | #ifndef ELF32_ST_INFO | ||
310 | # define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) | ||
311 | #endif | ||
312 | |||
313 | #ifndef ELF64_ST_INFO | ||
314 | # define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) | ||
315 | #endif | ||
316 | |||
317 | struct obj_string_patch; | ||
318 | struct obj_symbol_patch; | ||
319 | |||
320 | struct obj_section | ||
321 | { | ||
322 | ElfW(Shdr) header; | ||
323 | const char *name; | ||
324 | char *contents; | ||
325 | struct obj_section *load_next; | ||
326 | int idx; | ||
327 | }; | ||
328 | |||
329 | struct obj_symbol | ||
330 | { | ||
331 | struct obj_symbol *next; /* hash table link */ | ||
332 | const char *name; | ||
333 | unsigned long value; | ||
334 | unsigned long size; | ||
335 | int secidx; /* the defining section index/module */ | ||
336 | int info; | ||
337 | int ksymidx; /* for export to the kernel symtab */ | ||
338 | int referenced; /* actually used in the link */ | ||
339 | }; | ||
340 | |||
341 | /* Hardcode the hash table size. We shouldn't be needing so many | ||
342 | symbols that we begin to degrade performance, and we get a big win | ||
343 | by giving the compiler a constant divisor. */ | ||
344 | |||
345 | #define HASH_BUCKETS 521 | ||
346 | |||
347 | struct obj_file | ||
348 | { | ||
349 | ElfW(Ehdr) header; | ||
350 | ElfW(Addr) baseaddr; | ||
351 | struct obj_section **sections; | ||
352 | struct obj_section *load_order; | ||
353 | struct obj_section **load_order_search_start; | ||
354 | struct obj_string_patch *string_patches; | ||
355 | struct obj_symbol_patch *symbol_patches; | ||
356 | int (*symbol_cmp)(const char *, const char *); | ||
357 | unsigned long (*symbol_hash)(const char *); | ||
358 | unsigned long local_symtab_size; | ||
359 | struct obj_symbol **local_symtab; | ||
360 | struct obj_symbol *symtab[HASH_BUCKETS]; | ||
361 | }; | ||
362 | |||
363 | enum obj_reloc | ||
364 | { | ||
365 | obj_reloc_ok, | ||
366 | obj_reloc_overflow, | ||
367 | obj_reloc_dangerous, | ||
368 | obj_reloc_unhandled | ||
369 | }; | ||
370 | |||
371 | struct obj_string_patch | ||
372 | { | ||
373 | struct obj_string_patch *next; | ||
374 | int reloc_secidx; | ||
375 | ElfW(Addr) reloc_offset; | ||
376 | ElfW(Addr) string_offset; | ||
377 | }; | ||
378 | |||
379 | struct obj_symbol_patch | ||
380 | { | ||
381 | struct obj_symbol_patch *next; | ||
382 | int reloc_secidx; | ||
383 | ElfW(Addr) reloc_offset; | ||
384 | struct obj_symbol *sym; | ||
385 | }; | ||
386 | |||
387 | |||
388 | /* Generic object manipulation routines. */ | ||
389 | |||
390 | unsigned long obj_elf_hash(const char *); | ||
391 | |||
392 | unsigned long obj_elf_hash_n(const char *, unsigned long len); | ||
393 | |||
394 | struct obj_symbol *obj_add_symbol (struct obj_file *f, const char *name, | ||
395 | unsigned long symidx, int info, int secidx, | ||
396 | ElfW(Addr) value, unsigned long size); | ||
397 | |||
398 | struct obj_symbol *obj_find_symbol (struct obj_file *f, | ||
399 | const char *name); | ||
400 | |||
401 | ElfW(Addr) obj_symbol_final_value(struct obj_file *f, | ||
402 | struct obj_symbol *sym); | ||
403 | |||
404 | void obj_set_symbol_compare(struct obj_file *f, | ||
405 | int (*cmp)(const char *, const char *), | ||
406 | unsigned long (*hash)(const char *)); | ||
407 | |||
408 | struct obj_section *obj_find_section (struct obj_file *f, | ||
409 | const char *name); | ||
410 | |||
411 | void obj_insert_section_load_order (struct obj_file *f, | ||
412 | struct obj_section *sec); | ||
413 | |||
414 | struct obj_section *obj_create_alloced_section (struct obj_file *f, | ||
415 | const char *name, | ||
416 | unsigned long align, | ||
417 | unsigned long size); | ||
418 | |||
419 | struct obj_section *obj_create_alloced_section_first (struct obj_file *f, | ||
420 | const char *name, | ||
421 | unsigned long align, | ||
422 | unsigned long size); | ||
423 | |||
424 | void *obj_extend_section (struct obj_section *sec, unsigned long more); | ||
425 | |||
426 | int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
427 | const char *string); | ||
428 | |||
429 | int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
430 | struct obj_symbol *sym); | ||
431 | |||
432 | int obj_check_undefineds(struct obj_file *f); | ||
433 | |||
434 | void obj_allocate_commons(struct obj_file *f); | ||
435 | |||
436 | unsigned long obj_load_size (struct obj_file *f); | ||
437 | |||
438 | int obj_relocate (struct obj_file *f, ElfW(Addr) base); | ||
439 | |||
440 | struct obj_file *obj_load(FILE *f); | ||
441 | |||
442 | int obj_create_image (struct obj_file *f, char *image); | ||
443 | |||
444 | /* Architecture specific manipulation routines. */ | ||
445 | |||
446 | struct obj_file *arch_new_file (void); | ||
447 | |||
448 | struct obj_section *arch_new_section (void); | ||
449 | |||
450 | struct obj_symbol *arch_new_symbol (void); | ||
451 | |||
452 | enum obj_reloc arch_apply_relocation (struct obj_file *f, | ||
453 | struct obj_section *targsec, | ||
454 | struct obj_section *symsec, | ||
455 | struct obj_symbol *sym, | ||
456 | ElfW(RelM) *rel, ElfW(Addr) value); | ||
457 | |||
458 | int arch_create_got (struct obj_file *f); | ||
459 | |||
460 | struct new_module; | ||
461 | int arch_init_module (struct obj_file *f, struct new_module *); | ||
462 | |||
463 | #endif /* obj.h */ | ||
464 | //---------------------------------------------------------------------------- | ||
465 | //--------end of modutils obj.h | ||
466 | //---------------------------------------------------------------------------- | ||
467 | |||
468 | |||
469 | |||
470 | |||
32 | 471 | ||
33 | #define _PATH_MODULES "/lib/modules" | 472 | #define _PATH_MODULES "/lib/modules" |
473 | #define STRVERSIONLEN 32 | ||
474 | |||
475 | #if !defined(BB_FEATURE_INSMOD_NEW_KERNEL) && !defined(BB_FEATURE_INSMOD_OLD_KERNEL) | ||
476 | #error "Must have ether BB_FEATURE_INSMOD_NEW_KERNEL or BB_FEATURE_INSMOD_OLD_KERNEL defined" | ||
477 | #endif | ||
478 | |||
479 | /*======================================================================*/ | ||
480 | |||
481 | int flag_force_load = 0; | ||
482 | int flag_autoclean = 0; | ||
483 | int flag_verbose = 0; | ||
484 | int flag_export = 1; | ||
485 | |||
486 | |||
487 | /*======================================================================*/ | ||
488 | |||
489 | struct i386_got_entry { | ||
490 | int offset; | ||
491 | unsigned offset_done:1; | ||
492 | unsigned reloc_done:1; | ||
493 | }; | ||
494 | |||
495 | struct i386_file { | ||
496 | struct obj_file root; | ||
497 | struct obj_section *got; | ||
498 | }; | ||
499 | |||
500 | struct i386_symbol { | ||
501 | struct obj_symbol root; | ||
502 | struct i386_got_entry gotent; | ||
503 | }; | ||
504 | |||
505 | |||
506 | |||
507 | struct external_module { | ||
508 | const char *name; | ||
509 | ElfW(Addr) addr; | ||
510 | int used; | ||
511 | size_t nsyms; | ||
512 | struct new_module_symbol *syms; | ||
513 | }; | ||
514 | |||
515 | struct new_module_symbol *ksyms; | ||
516 | size_t nksyms; | ||
517 | |||
518 | struct external_module *ext_modules; | ||
519 | int n_ext_modules; | ||
520 | int n_ext_modules_used; | ||
34 | 521 | ||
35 | #warning "Danger Will Robinson, Danger!!!" | ||
36 | #warning " " | ||
37 | #warning "insmod is still under construction. Don't use it." | ||
38 | #warning " " | ||
39 | #warning " You have been warned!" | ||
40 | #warning " " | ||
41 | 522 | ||
42 | 523 | ||
43 | /* Some firendly syscalls to cheer everyone's day... */ | 524 | /* Some firendly syscalls to cheer everyone's day... */ |
44 | _syscall2(int, init_module, const char *, name, | 525 | #define __NR_new_sys_init_module __NR_init_module |
45 | const struct module *, info) | 526 | _syscall2(int, new_sys_init_module, const char *, name, |
527 | const struct new_module *, info) | ||
528 | #define __NR_old_sys_init_module __NR_init_module | ||
529 | _syscall5(int, old_sys_init_module, const char *, name, char *, code, | ||
530 | unsigned, codesize, struct old_mod_routines *, routines, | ||
531 | struct old_symbol_table *, symtab) | ||
46 | #ifndef BB_RMMOD | 532 | #ifndef BB_RMMOD |
47 | _syscall1(int, delete_module, const char *, name) | 533 | _syscall1(int, delete_module, const char *, name) |
48 | #else | 534 | #else |
@@ -74,16 +560,32 @@ static const char insmod_usage[] = | |||
74 | #ifndef BB_FEATURE_TRIVIAL_HELP | 560 | #ifndef BB_FEATURE_TRIVIAL_HELP |
75 | "\nLoads the specified kernel modules into the kernel.\n\n" | 561 | "\nLoads the specified kernel modules into the kernel.\n\n" |
76 | "Options:\n" | 562 | "Options:\n" |
77 | |||
78 | "\t-f\tForce module to load into the wrong kernel version.\n" | 563 | "\t-f\tForce module to load into the wrong kernel version.\n" |
79 | "\t-k\tMake module autoclean-able.\n" | 564 | "\t-k\tMake module autoclean-able.\n" |
565 | "\t-v\tverbose output\n" "\t-x\tdo not export externs\n" | ||
80 | #endif | 566 | #endif |
81 | ; | 567 | ; |
568 | |||
569 | /*======================================================================*/ | ||
570 | |||
571 | void *xrealloc(void *old, size_t size) | ||
572 | { | ||
573 | void *ptr = realloc(old, size); | ||
574 | if (!ptr) { | ||
575 | perror("Out of memory"); | ||
576 | exit(1); | ||
577 | } | ||
578 | return ptr; | ||
579 | } | ||
82 | 580 | ||
83 | 581 | ||
84 | static int findNamedModule(const char *fileName, struct stat *statbuf) | 582 | static int findNamedModule(const char *fileName, struct stat *statbuf, |
583 | void *userDate) | ||
85 | { | 584 | { |
86 | if (m_fullName[0] == '\0') | 585 | char *fullName = (char *) userDate; |
586 | |||
587 | |||
588 | if (fullName[0] == '\0') | ||
87 | return (FALSE); | 589 | return (FALSE); |
88 | else { | 590 | else { |
89 | char *tmp = strrchr(fileName, '/'); | 591 | char *tmp = strrchr(fileName, '/'); |
@@ -92,7 +594,7 @@ static int findNamedModule(const char *fileName, struct stat *statbuf) | |||
92 | tmp = (char *) fileName; | 594 | tmp = (char *) fileName; |
93 | else | 595 | else |
94 | tmp++; | 596 | tmp++; |
95 | if (check_wildcard_match(tmp, m_fullName) == TRUE) { | 597 | if (check_wildcard_match(tmp, fullName) == TRUE) { |
96 | /* Stop searching if we find a match */ | 598 | /* Stop searching if we find a match */ |
97 | memcpy(m_filename, fileName, strlen(fileName)); | 599 | memcpy(m_filename, fileName, strlen(fileName)); |
98 | return (FALSE); | 600 | return (FALSE); |
@@ -102,12 +604,2070 @@ static int findNamedModule(const char *fileName, struct stat *statbuf) | |||
102 | } | 604 | } |
103 | 605 | ||
104 | 606 | ||
105 | extern int insmod_main(int argc, char **argv) | 607 | /*======================================================================*/ |
608 | |||
609 | struct obj_file *arch_new_file(void) | ||
106 | { | 610 | { |
611 | struct i386_file *f; | ||
612 | f = xmalloc(sizeof(*f)); | ||
613 | f->got = NULL; | ||
614 | return &f->root; | ||
615 | } | ||
616 | |||
617 | struct obj_section *arch_new_section(void) | ||
618 | { | ||
619 | return xmalloc(sizeof(struct obj_section)); | ||
620 | } | ||
621 | |||
622 | struct obj_symbol *arch_new_symbol(void) | ||
623 | { | ||
624 | struct i386_symbol *sym; | ||
625 | sym = xmalloc(sizeof(*sym)); | ||
626 | memset(&sym->gotent, 0, sizeof(sym->gotent)); | ||
627 | return &sym->root; | ||
628 | } | ||
629 | enum obj_reloc | ||
630 | arch_apply_relocation(struct obj_file *f, | ||
631 | struct obj_section *targsec, | ||
632 | struct obj_section *symsec, | ||
633 | struct obj_symbol *sym, | ||
634 | Elf32_Rel * rel, Elf32_Addr v) | ||
635 | { | ||
636 | struct i386_file *ifile = (struct i386_file *) f; | ||
637 | struct i386_symbol *isym = (struct i386_symbol *) sym; | ||
638 | |||
639 | Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset); | ||
640 | Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset; | ||
641 | Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0; | ||
642 | |||
643 | enum obj_reloc ret = obj_reloc_ok; | ||
644 | |||
645 | switch (ELF32_R_TYPE(rel->r_info)) { | ||
646 | case R_386_NONE: | ||
647 | break; | ||
648 | |||
649 | case R_386_32: | ||
650 | *loc += v; | ||
651 | break; | ||
652 | |||
653 | case R_386_PLT32: | ||
654 | case R_386_PC32: | ||
655 | *loc += v - dot; | ||
656 | break; | ||
657 | |||
658 | case R_386_GLOB_DAT: | ||
659 | case R_386_JMP_SLOT: | ||
660 | *loc = v; | ||
661 | break; | ||
662 | |||
663 | case R_386_RELATIVE: | ||
664 | *loc += f->baseaddr; | ||
665 | break; | ||
666 | |||
667 | case R_386_GOTPC: | ||
668 | assert(got != 0); | ||
669 | *loc += got - dot; | ||
670 | break; | ||
671 | |||
672 | case R_386_GOT32: | ||
673 | assert(isym != NULL); | ||
674 | if (!isym->gotent.reloc_done) { | ||
675 | isym->gotent.reloc_done = 1; | ||
676 | *(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) = | ||
677 | v; | ||
678 | } | ||
679 | *loc += isym->gotent.offset; | ||
680 | break; | ||
681 | |||
682 | case R_386_GOTOFF: | ||
683 | assert(got != 0); | ||
684 | *loc += v - got; | ||
685 | break; | ||
686 | |||
687 | default: | ||
688 | ret = obj_reloc_unhandled; | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | return ret; | ||
693 | } | ||
694 | |||
695 | int arch_create_got(struct obj_file *f) | ||
696 | { | ||
697 | struct i386_file *ifile = (struct i386_file *) f; | ||
698 | int i, n, offset = 0, gotneeded = 0; | ||
699 | |||
700 | n = ifile->root.header.e_shnum; | ||
701 | for (i = 0; i < n; ++i) { | ||
702 | struct obj_section *relsec, *symsec, *strsec; | ||
703 | Elf32_Rel *rel, *relend; | ||
704 | Elf32_Sym *symtab; | ||
705 | const char *strtab; | ||
706 | |||
707 | relsec = ifile->root.sections[i]; | ||
708 | if (relsec->header.sh_type != SHT_REL) | ||
709 | continue; | ||
710 | |||
711 | symsec = ifile->root.sections[relsec->header.sh_link]; | ||
712 | strsec = ifile->root.sections[symsec->header.sh_link]; | ||
713 | |||
714 | rel = (Elf32_Rel *) relsec->contents; | ||
715 | relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel)); | ||
716 | symtab = (Elf32_Sym *) symsec->contents; | ||
717 | strtab = (const char *) strsec->contents; | ||
718 | |||
719 | for (; rel < relend; ++rel) { | ||
720 | Elf32_Sym *extsym; | ||
721 | struct i386_symbol *intsym; | ||
722 | const char *name; | ||
723 | |||
724 | switch (ELF32_R_TYPE(rel->r_info)) { | ||
725 | case R_386_GOTPC: | ||
726 | case R_386_GOTOFF: | ||
727 | gotneeded = 1; | ||
728 | default: | ||
729 | continue; | ||
730 | |||
731 | case R_386_GOT32: | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | extsym = &symtab[ELF32_R_SYM(rel->r_info)]; | ||
736 | if (extsym->st_name) | ||
737 | name = strtab + extsym->st_name; | ||
738 | else | ||
739 | name = f->sections[extsym->st_shndx]->name; | ||
740 | intsym = | ||
741 | (struct i386_symbol *) obj_find_symbol(&ifile->root, name); | ||
742 | |||
743 | if (!intsym->gotent.offset_done) { | ||
744 | intsym->gotent.offset_done = 1; | ||
745 | intsym->gotent.offset = offset; | ||
746 | offset += 4; | ||
747 | } | ||
748 | } | ||
749 | } | ||
750 | |||
751 | if (offset > 0 || gotneeded) | ||
752 | ifile->got = | ||
753 | obj_create_alloced_section(&ifile->root, ".got", 4, offset); | ||
754 | |||
755 | return 1; | ||
756 | } | ||
757 | |||
758 | int arch_init_module(struct obj_file *f, struct new_module *mod) | ||
759 | { | ||
760 | return 1; | ||
761 | } | ||
762 | |||
763 | |||
764 | /*======================================================================*/ | ||
765 | |||
766 | /* Standard ELF hash function. */ | ||
767 | inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) | ||
768 | { | ||
769 | unsigned long h = 0; | ||
770 | unsigned long g; | ||
771 | unsigned char ch; | ||
772 | |||
773 | while (n > 0) { | ||
774 | ch = *name++; | ||
775 | h = (h << 4) + ch; | ||
776 | if ((g = (h & 0xf0000000)) != 0) { | ||
777 | h ^= g >> 24; | ||
778 | h &= ~g; | ||
779 | } | ||
780 | n--; | ||
781 | } | ||
782 | return h; | ||
783 | } | ||
784 | |||
785 | unsigned long obj_elf_hash(const char *name) | ||
786 | { | ||
787 | return obj_elf_hash_n(name, strlen(name)); | ||
788 | } | ||
789 | |||
790 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
791 | /* Get the kernel version in the canonical integer form. */ | ||
792 | |||
793 | static int get_kernel_version(char str[STRVERSIONLEN]) | ||
794 | { | ||
795 | struct utsname uts_info; | ||
796 | char *p, *q; | ||
797 | int a, b, c; | ||
798 | |||
799 | if (uname(&uts_info) < 0) | ||
800 | return -1; | ||
801 | strncpy(str, uts_info.release, STRVERSIONLEN); | ||
802 | p = uts_info.release; | ||
803 | |||
804 | a = strtoul(p, &p, 10); | ||
805 | if (*p != '.') | ||
806 | return -1; | ||
807 | b = strtoul(p + 1, &p, 10); | ||
808 | if (*p != '.') | ||
809 | return -1; | ||
810 | c = strtoul(p + 1, &q, 10); | ||
811 | if (p + 1 == q) | ||
812 | return -1; | ||
813 | |||
814 | return a << 16 | b << 8 | c; | ||
815 | } | ||
816 | |||
817 | /* String comparison for non-co-versioned kernel and module. */ | ||
818 | |||
819 | static int ncv_strcmp(const char *a, const char *b) | ||
820 | { | ||
821 | size_t alen = strlen(a), blen = strlen(b); | ||
822 | |||
823 | if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') | ||
824 | return strncmp(a, b, alen); | ||
825 | else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') | ||
826 | return strncmp(a, b, blen); | ||
827 | else | ||
828 | return strcmp(a, b); | ||
829 | } | ||
830 | |||
831 | /* String hashing for non-co-versioned kernel and module. Here | ||
832 | we are simply forced to drop the crc from the hash. */ | ||
833 | |||
834 | static unsigned long ncv_symbol_hash(const char *str) | ||
835 | { | ||
836 | size_t len = strlen(str); | ||
837 | if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') | ||
838 | len -= 10; | ||
839 | return obj_elf_hash_n(str, len); | ||
840 | } | ||
841 | |||
842 | void | ||
843 | obj_set_symbol_compare(struct obj_file *f, | ||
844 | int (*cmp) (const char *, const char *), | ||
845 | unsigned long (*hash) (const char *)) | ||
846 | { | ||
847 | if (cmp) | ||
848 | f->symbol_cmp = cmp; | ||
849 | if (hash) { | ||
850 | struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; | ||
851 | int i; | ||
852 | |||
853 | f->symbol_hash = hash; | ||
854 | |||
855 | memcpy(tmptab, f->symtab, sizeof(tmptab)); | ||
856 | memset(f->symtab, 0, sizeof(f->symtab)); | ||
857 | |||
858 | for (i = 0; i < HASH_BUCKETS; ++i) | ||
859 | for (sym = tmptab[i]; sym; sym = next) { | ||
860 | unsigned long h = hash(sym->name) % HASH_BUCKETS; | ||
861 | next = sym->next; | ||
862 | sym->next = f->symtab[h]; | ||
863 | f->symtab[h] = sym; | ||
864 | } | ||
865 | } | ||
866 | } | ||
867 | |||
868 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
869 | |||
870 | |||
871 | struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name, | ||
872 | unsigned long symidx, int info, | ||
873 | int secidx, ElfW(Addr) value, | ||
874 | unsigned long size) | ||
875 | { | ||
876 | struct obj_symbol *sym; | ||
877 | unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; | ||
878 | int n_type = ELFW(ST_TYPE) (info); | ||
879 | int n_binding = ELFW(ST_BIND) (info); | ||
880 | |||
881 | for (sym = f->symtab[hash]; sym; sym = sym->next) | ||
882 | if (f->symbol_cmp(sym->name, name) == 0) { | ||
883 | int o_secidx = sym->secidx; | ||
884 | int o_info = sym->info; | ||
885 | int o_type = ELFW(ST_TYPE) (o_info); | ||
886 | int o_binding = ELFW(ST_BIND) (o_info); | ||
887 | |||
888 | /* A redefinition! Is it legal? */ | ||
889 | |||
890 | if (secidx == SHN_UNDEF) | ||
891 | return sym; | ||
892 | else if (o_secidx == SHN_UNDEF) | ||
893 | goto found; | ||
894 | else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { | ||
895 | /* Cope with local and global symbols of the same name | ||
896 | in the same object file, as might have been created | ||
897 | by ld -r. The only reason locals are now seen at this | ||
898 | level at all is so that we can do semi-sensible things | ||
899 | with parameters. */ | ||
900 | |||
901 | struct obj_symbol *nsym, **p; | ||
902 | |||
903 | nsym = arch_new_symbol(); | ||
904 | nsym->next = sym->next; | ||
905 | nsym->ksymidx = -1; | ||
906 | |||
907 | /* Excise the old (local) symbol from the hash chain. */ | ||
908 | for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) | ||
909 | continue; | ||
910 | *p = sym = nsym; | ||
911 | goto found; | ||
912 | } else if (n_binding == STB_LOCAL) { | ||
913 | /* Another symbol of the same name has already been defined. | ||
914 | Just add this to the local table. */ | ||
915 | sym = arch_new_symbol(); | ||
916 | sym->next = NULL; | ||
917 | sym->ksymidx = -1; | ||
918 | f->local_symtab[symidx] = sym; | ||
919 | goto found; | ||
920 | } else if (n_binding == STB_WEAK) | ||
921 | return sym; | ||
922 | else if (o_binding == STB_WEAK) | ||
923 | goto found; | ||
924 | /* Don't unify COMMON symbols with object types the programmer | ||
925 | doesn't expect. */ | ||
926 | else if (secidx == SHN_COMMON | ||
927 | && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) | ||
928 | return sym; | ||
929 | else if (o_secidx == SHN_COMMON | ||
930 | && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) | ||
931 | goto found; | ||
932 | else { | ||
933 | /* Don't report an error if the symbol is coming from | ||
934 | the kernel or some external module. */ | ||
935 | if (secidx <= SHN_HIRESERVE) | ||
936 | fprintf(stderr, "%s multiply defined\n", name); | ||
937 | return sym; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | /* Completely new symbol. */ | ||
942 | sym = arch_new_symbol(); | ||
943 | sym->next = f->symtab[hash]; | ||
944 | f->symtab[hash] = sym; | ||
945 | sym->ksymidx = -1; | ||
946 | |||
947 | if (ELFW(ST_BIND) (info) == STB_LOCAL) | ||
948 | f->local_symtab[symidx] = sym; | ||
949 | |||
950 | found: | ||
951 | sym->name = name; | ||
952 | sym->value = value; | ||
953 | sym->size = size; | ||
954 | sym->secidx = secidx; | ||
955 | sym->info = info; | ||
956 | |||
957 | return sym; | ||
958 | } | ||
959 | |||
960 | struct obj_symbol *obj_find_symbol(struct obj_file *f, const char *name) | ||
961 | { | ||
962 | struct obj_symbol *sym; | ||
963 | unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; | ||
964 | |||
965 | for (sym = f->symtab[hash]; sym; sym = sym->next) | ||
966 | if (f->symbol_cmp(sym->name, name) == 0) | ||
967 | return sym; | ||
968 | |||
969 | return NULL; | ||
970 | } | ||
971 | |||
972 | ElfW(Addr) | ||
973 | obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) | ||
974 | { | ||
975 | if (sym) { | ||
976 | if (sym->secidx >= SHN_LORESERVE) | ||
977 | return sym->value; | ||
978 | |||
979 | return sym->value + f->sections[sym->secidx]->header.sh_addr; | ||
980 | } else { | ||
981 | /* As a special case, a NULL sym has value zero. */ | ||
982 | return 0; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | struct obj_section *obj_find_section(struct obj_file *f, const char *name) | ||
987 | { | ||
988 | int i, n = f->header.e_shnum; | ||
989 | |||
990 | for (i = 0; i < n; ++i) | ||
991 | if (strcmp(f->sections[i]->name, name) == 0) | ||
992 | return f->sections[i]; | ||
993 | |||
994 | return NULL; | ||
995 | } | ||
996 | |||
997 | static int obj_load_order_prio(struct obj_section *a) | ||
998 | { | ||
999 | unsigned long af, ac; | ||
1000 | |||
1001 | af = a->header.sh_flags; | ||
1002 | |||
1003 | ac = 0; | ||
1004 | if (a->name[0] != '.' || strlen(a->name) != 10 || | ||
1005 | strcmp(a->name + 5, ".init")) | ||
1006 | ac |= 32; | ||
1007 | if (af & SHF_ALLOC) | ||
1008 | ac |= 16; | ||
1009 | if (!(af & SHF_WRITE)) | ||
1010 | ac |= 8; | ||
1011 | if (af & SHF_EXECINSTR) | ||
1012 | ac |= 4; | ||
1013 | if (a->header.sh_type != SHT_NOBITS) | ||
1014 | ac |= 2; | ||
1015 | |||
1016 | return ac; | ||
1017 | } | ||
1018 | |||
1019 | void | ||
1020 | obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) | ||
1021 | { | ||
1022 | struct obj_section **p; | ||
1023 | int prio = obj_load_order_prio(sec); | ||
1024 | for (p = f->load_order_search_start; *p; p = &(*p)->load_next) | ||
1025 | if (obj_load_order_prio(*p) < prio) | ||
1026 | break; | ||
1027 | sec->load_next = *p; | ||
1028 | *p = sec; | ||
1029 | } | ||
1030 | |||
1031 | struct obj_section *obj_create_alloced_section(struct obj_file *f, | ||
1032 | const char *name, | ||
1033 | unsigned long align, | ||
1034 | unsigned long size) | ||
1035 | { | ||
1036 | int newidx = f->header.e_shnum++; | ||
1037 | struct obj_section *sec; | ||
1038 | |||
1039 | f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); | ||
1040 | f->sections[newidx] = sec = arch_new_section(); | ||
1041 | |||
1042 | memset(sec, 0, sizeof(*sec)); | ||
1043 | sec->header.sh_type = SHT_PROGBITS; | ||
1044 | sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; | ||
1045 | sec->header.sh_size = size; | ||
1046 | sec->header.sh_addralign = align; | ||
1047 | sec->name = name; | ||
1048 | sec->idx = newidx; | ||
1049 | if (size) | ||
1050 | sec->contents = xmalloc(size); | ||
1051 | |||
1052 | obj_insert_section_load_order(f, sec); | ||
1053 | |||
1054 | return sec; | ||
1055 | } | ||
1056 | |||
1057 | struct obj_section *obj_create_alloced_section_first(struct obj_file *f, | ||
1058 | const char *name, | ||
1059 | unsigned long align, | ||
1060 | unsigned long size) | ||
1061 | { | ||
1062 | int newidx = f->header.e_shnum++; | ||
1063 | struct obj_section *sec; | ||
1064 | |||
1065 | f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); | ||
1066 | f->sections[newidx] = sec = arch_new_section(); | ||
1067 | |||
1068 | memset(sec, 0, sizeof(*sec)); | ||
1069 | sec->header.sh_type = SHT_PROGBITS; | ||
1070 | sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; | ||
1071 | sec->header.sh_size = size; | ||
1072 | sec->header.sh_addralign = align; | ||
1073 | sec->name = name; | ||
1074 | sec->idx = newidx; | ||
1075 | if (size) | ||
1076 | sec->contents = xmalloc(size); | ||
1077 | |||
1078 | sec->load_next = f->load_order; | ||
1079 | f->load_order = sec; | ||
1080 | if (f->load_order_search_start == &f->load_order) | ||
1081 | f->load_order_search_start = &sec->load_next; | ||
1082 | |||
1083 | return sec; | ||
1084 | } | ||
1085 | |||
1086 | void *obj_extend_section(struct obj_section *sec, unsigned long more) | ||
1087 | { | ||
1088 | unsigned long oldsize = sec->header.sh_size; | ||
1089 | sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); | ||
1090 | return sec->contents + oldsize; | ||
1091 | } | ||
1092 | |||
1093 | |||
1094 | |||
1095 | /* Conditionally add the symbols from the given symbol set to the | ||
1096 | new module. */ | ||
1097 | |||
1098 | static int | ||
1099 | add_symbols_from( | ||
1100 | struct obj_file *f, | ||
1101 | int idx, struct new_module_symbol *syms, size_t nsyms) | ||
1102 | { | ||
1103 | struct new_module_symbol *s; | ||
1104 | size_t i; | ||
1105 | int used = 0; | ||
1106 | |||
1107 | for (i = 0, s = syms; i < nsyms; ++i, ++s) { | ||
1108 | |||
1109 | /* Only add symbols that are already marked external. If we | ||
1110 | override locals we may cause problems for argument initialization. | ||
1111 | We will also create a false dependency on the module. */ | ||
1112 | struct obj_symbol *sym; | ||
1113 | |||
1114 | sym = obj_find_symbol(f, (char *) s->name); | ||
1115 | if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { | ||
1116 | sym = obj_add_symbol(f, (char *) s->name, -1, | ||
1117 | ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), | ||
1118 | idx, s->value, 0); | ||
1119 | /* Did our symbol just get installed? If so, mark the | ||
1120 | module as "used". */ | ||
1121 | if (sym->secidx == idx) | ||
1122 | used = 1; | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | return used; | ||
1127 | } | ||
1128 | |||
1129 | static void add_kernel_symbols(struct obj_file *f) | ||
1130 | { | ||
1131 | struct external_module *m; | ||
1132 | size_t i, nused = 0; | ||
1133 | |||
1134 | /* Add module symbols first. */ | ||
1135 | |||
1136 | for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) | ||
1137 | if (m->nsyms | ||
1138 | && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, | ||
1139 | m->nsyms)) m->used = 1, ++nused; | ||
1140 | |||
1141 | n_ext_modules_used = nused; | ||
1142 | |||
1143 | /* And finally the symbols from the kernel proper. */ | ||
1144 | |||
1145 | if (nksyms) | ||
1146 | add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); | ||
1147 | } | ||
1148 | |||
1149 | static char *get_modinfo_value(struct obj_file *f, const char *key) | ||
1150 | { | ||
1151 | struct obj_section *sec; | ||
1152 | char *p, *v, *n, *ep; | ||
1153 | size_t klen = strlen(key); | ||
1154 | |||
1155 | sec = obj_find_section(f, ".modinfo"); | ||
1156 | if (sec == NULL) | ||
1157 | return NULL; | ||
1158 | p = sec->contents; | ||
1159 | ep = p + sec->header.sh_size; | ||
1160 | while (p < ep) { | ||
1161 | v = strchr(p, '='); | ||
1162 | n = strchr(p, '\0'); | ||
1163 | if (v) { | ||
1164 | if (v - p == klen && strncmp(p, key, klen) == 0) | ||
1165 | return v + 1; | ||
1166 | } else { | ||
1167 | if (n - p == klen && strcmp(p, key) == 0) | ||
1168 | return n; | ||
1169 | } | ||
1170 | p = n + 1; | ||
1171 | } | ||
1172 | |||
1173 | return NULL; | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | /*======================================================================*/ | ||
1178 | /* Functions relating to module loading in pre 2.1 kernels. */ | ||
1179 | |||
1180 | static int | ||
1181 | old_process_module_arguments(struct obj_file *f, int argc, char **argv) | ||
1182 | { | ||
1183 | while (argc > 0) { | ||
1184 | char *p, *q; | ||
1185 | struct obj_symbol *sym; | ||
1186 | int *loc; | ||
1187 | |||
1188 | p = *argv; | ||
1189 | if ((q = strchr(p, '=')) == NULL) | ||
1190 | continue; | ||
1191 | *q++ = '\0'; | ||
1192 | |||
1193 | sym = obj_find_symbol(f, p); | ||
1194 | |||
1195 | /* Also check that the parameter was not resolved from the kernel. */ | ||
1196 | if (sym == NULL || sym->secidx > SHN_HIRESERVE) { | ||
1197 | fprintf(stderr, "symbol for parameter %s not found\n", p); | ||
1198 | return 0; | ||
1199 | } | ||
1200 | |||
1201 | loc = (int *) (f->sections[sym->secidx]->contents + sym->value); | ||
1202 | |||
1203 | /* Do C quoting if we begin with a ". */ | ||
1204 | if (*q == '"') { | ||
1205 | char *r, *str; | ||
1206 | |||
1207 | str = alloca(strlen(q)); | ||
1208 | for (r = str, q++; *q != '"'; ++q, ++r) { | ||
1209 | if (*q == '\0') { | ||
1210 | fprintf(stderr, | ||
1211 | "improperly terminated string argument for %s\n", | ||
1212 | p); | ||
1213 | return 0; | ||
1214 | } else if (*q == '\\') | ||
1215 | switch (*++q) { | ||
1216 | case 'a': | ||
1217 | *r = '\a'; | ||
1218 | break; | ||
1219 | case 'b': | ||
1220 | *r = '\b'; | ||
1221 | break; | ||
1222 | case 'e': | ||
1223 | *r = '\033'; | ||
1224 | break; | ||
1225 | case 'f': | ||
1226 | *r = '\f'; | ||
1227 | break; | ||
1228 | case 'n': | ||
1229 | *r = '\n'; | ||
1230 | break; | ||
1231 | case 'r': | ||
1232 | *r = '\r'; | ||
1233 | break; | ||
1234 | case 't': | ||
1235 | *r = '\t'; | ||
1236 | break; | ||
1237 | |||
1238 | case '0': | ||
1239 | case '1': | ||
1240 | case '2': | ||
1241 | case '3': | ||
1242 | case '4': | ||
1243 | case '5': | ||
1244 | case '6': | ||
1245 | case '7': | ||
1246 | { | ||
1247 | int c = *q - '0'; | ||
1248 | if (q[1] >= '0' && q[1] <= '7') { | ||
1249 | c = (c * 8) + *++q - '0'; | ||
1250 | if (q[1] >= '0' && q[1] <= '7') | ||
1251 | c = (c * 8) + *++q - '0'; | ||
1252 | } | ||
1253 | *r = c; | ||
1254 | } | ||
1255 | break; | ||
1256 | |||
1257 | default: | ||
1258 | *r = *q; | ||
1259 | break; | ||
1260 | } else | ||
1261 | *r = *q; | ||
1262 | } | ||
1263 | *r = '\0'; | ||
1264 | obj_string_patch(f, sym->secidx, sym->value, str); | ||
1265 | } else if (*q >= '0' && *q <= '9') { | ||
1266 | do | ||
1267 | *loc++ = strtoul(q, &q, 0); | ||
1268 | while (*q++ == ','); | ||
1269 | } else { | ||
1270 | char *contents = f->sections[sym->secidx]->contents; | ||
1271 | char *loc = contents + sym->value; | ||
1272 | char *r; /* To search for commas */ | ||
1273 | |||
1274 | /* Break the string with comas */ | ||
1275 | while ((r = strchr(q, ',')) != (char *) NULL) { | ||
1276 | *r++ = '\0'; | ||
1277 | obj_string_patch(f, sym->secidx, loc - contents, q); | ||
1278 | loc += sizeof(char *); | ||
1279 | q = r; | ||
1280 | } | ||
1281 | |||
1282 | /* last part */ | ||
1283 | obj_string_patch(f, sym->secidx, loc - contents, q); | ||
1284 | } | ||
1285 | |||
1286 | argc--, argv++; | ||
1287 | } | ||
1288 | |||
1289 | return 1; | ||
1290 | } | ||
1291 | |||
1292 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
1293 | static int old_is_module_checksummed(struct obj_file *f) | ||
1294 | { | ||
1295 | return obj_find_symbol(f, "Using_Versions") != NULL; | ||
1296 | } | ||
1297 | /* Get the module's kernel version in the canonical integer form. */ | ||
1298 | |||
1299 | static int | ||
1300 | old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) | ||
1301 | { | ||
1302 | struct obj_symbol *sym; | ||
1303 | char *p, *q; | ||
1304 | int a, b, c; | ||
1305 | |||
1306 | sym = obj_find_symbol(f, "kernel_version"); | ||
1307 | if (sym == NULL) | ||
1308 | return -1; | ||
1309 | |||
1310 | p = f->sections[sym->secidx]->contents + sym->value; | ||
1311 | strncpy(str, p, STRVERSIONLEN); | ||
1312 | |||
1313 | a = strtoul(p, &p, 10); | ||
1314 | if (*p != '.') | ||
1315 | return -1; | ||
1316 | b = strtoul(p + 1, &p, 10); | ||
1317 | if (*p != '.') | ||
1318 | return -1; | ||
1319 | c = strtoul(p + 1, &q, 10); | ||
1320 | if (p + 1 == q) | ||
1321 | return -1; | ||
1322 | |||
1323 | return a << 16 | b << 8 | c; | ||
1324 | } | ||
1325 | |||
1326 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
1327 | |||
1328 | #ifdef BB_FEATURE_INSMOD_OLD_KERNEL | ||
1329 | |||
1330 | /* Fetch all the symbols and divvy them up as appropriate for the modules. */ | ||
1331 | |||
1332 | static int old_get_kernel_symbols(void) | ||
1333 | { | ||
1334 | struct old_kernel_sym *ks, *k; | ||
1335 | struct new_module_symbol *s; | ||
1336 | struct external_module *mod; | ||
1337 | int nks, nms, nmod, i; | ||
1338 | |||
1339 | nks = get_kernel_syms(NULL); | ||
1340 | if (nks < 0) { | ||
1341 | perror("get_kernel_syms: %m"); | ||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | ks = k = xmalloc(nks * sizeof(*ks)); | ||
1346 | |||
1347 | if (get_kernel_syms(ks) != nks) { | ||
1348 | perror("inconsistency with get_kernel_syms -- is someone else " | ||
1349 | "playing with modules?"); | ||
1350 | free(ks); | ||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | /* Collect the module information. */ | ||
1355 | |||
1356 | mod = NULL; | ||
1357 | nmod = -1; | ||
1358 | |||
1359 | while (k->name[0] == '#' && k->name[1]) { | ||
1360 | struct old_kernel_sym *k2; | ||
1361 | struct new_module_symbol *s; | ||
1362 | |||
1363 | /* Find out how many symbols this module has. */ | ||
1364 | for (k2 = k + 1; k2->name[0] != '#'; ++k2) | ||
1365 | continue; | ||
1366 | nms = k2 - k - 1; | ||
1367 | |||
1368 | mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod)); | ||
1369 | mod[nmod].name = k->name + 1; | ||
1370 | mod[nmod].addr = k->value; | ||
1371 | mod[nmod].used = 0; | ||
1372 | mod[nmod].nsyms = nms; | ||
1373 | mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); | ||
1374 | |||
1375 | for (i = 0, ++k; i < nms; ++i, ++s, ++k) { | ||
1376 | s->name = (unsigned long) k->name; | ||
1377 | s->value = k->value; | ||
1378 | } | ||
1379 | |||
1380 | k = k2; | ||
1381 | } | ||
1382 | |||
1383 | ext_modules = mod; | ||
1384 | n_ext_modules = nmod + 1; | ||
1385 | |||
1386 | /* Now collect the symbols for the kernel proper. */ | ||
1387 | |||
1388 | if (k->name[0] == '#') | ||
1389 | ++k; | ||
1390 | |||
1391 | nksyms = nms = nks - (k - ks); | ||
1392 | ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); | ||
1393 | |||
1394 | for (i = 0; i < nms; ++i, ++s, ++k) { | ||
1395 | s->name = (unsigned long) k->name; | ||
1396 | s->value = k->value; | ||
1397 | } | ||
1398 | |||
1399 | return 1; | ||
1400 | } | ||
1401 | |||
1402 | /* Return the kernel symbol checksum version, or zero if not used. */ | ||
1403 | |||
1404 | static int old_is_kernel_checksummed(void) | ||
1405 | { | ||
1406 | /* Using_Versions is the first symbol. */ | ||
1407 | if (nksyms > 0 | ||
1408 | && strcmp((char *) ksyms[0].name, | ||
1409 | "Using_Versions") == 0) return ksyms[0].value; | ||
1410 | else | ||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1414 | |||
1415 | static int old_create_mod_use_count(struct obj_file *f) | ||
1416 | { | ||
1417 | struct obj_section *sec; | ||
1418 | |||
1419 | sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long), | ||
1420 | sizeof(long)); | ||
1421 | |||
1422 | obj_add_symbol(f, "mod_use_count_", -1, | ||
1423 | ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, | ||
1424 | sizeof(long)); | ||
1425 | |||
1426 | return 1; | ||
1427 | } | ||
1428 | |||
1429 | static int | ||
1430 | old_init_module(const char *m_name, struct obj_file *f, | ||
1431 | unsigned long m_size) | ||
1432 | { | ||
1433 | char *image; | ||
1434 | struct old_mod_routines routines; | ||
1435 | struct old_symbol_table *symtab; | ||
1436 | int ret; | ||
1437 | |||
1438 | /* Create the symbol table */ | ||
1439 | { | ||
1440 | int nsyms = 0, strsize = 0, total; | ||
1441 | |||
1442 | /* Size things first... */ | ||
1443 | if (flag_export) { | ||
1444 | int i; | ||
1445 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
1446 | struct obj_symbol *sym; | ||
1447 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
1448 | if (ELFW(ST_BIND) (sym->info) != STB_LOCAL | ||
1449 | && sym->secidx <= SHN_HIRESERVE) | ||
1450 | { | ||
1451 | sym->ksymidx = nsyms++; | ||
1452 | strsize += strlen(sym->name) + 1; | ||
1453 | } | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | total = (sizeof(struct old_symbol_table) | ||
1458 | + nsyms * sizeof(struct old_module_symbol) | ||
1459 | + n_ext_modules_used * sizeof(struct old_module_ref) | ||
1460 | + strsize); | ||
1461 | symtab = xmalloc(total); | ||
1462 | symtab->size = total; | ||
1463 | symtab->n_symbols = nsyms; | ||
1464 | symtab->n_refs = n_ext_modules_used; | ||
1465 | |||
1466 | if (flag_export && nsyms) { | ||
1467 | struct old_module_symbol *ksym; | ||
1468 | char *str; | ||
1469 | int i; | ||
1470 | |||
1471 | ksym = symtab->symbol; | ||
1472 | str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol) | ||
1473 | + n_ext_modules_used * sizeof(struct old_module_ref)); | ||
1474 | |||
1475 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
1476 | struct obj_symbol *sym; | ||
1477 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
1478 | if (sym->ksymidx >= 0) { | ||
1479 | ksym->addr = obj_symbol_final_value(f, sym); | ||
1480 | ksym->name = | ||
1481 | (unsigned long) str - (unsigned long) symtab; | ||
1482 | |||
1483 | str = stpcpy(str, sym->name) + 1; | ||
1484 | ksym++; | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | if (n_ext_modules_used) { | ||
1490 | struct old_module_ref *ref; | ||
1491 | int i; | ||
1492 | |||
1493 | ref = (struct old_module_ref *) | ||
1494 | ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol)); | ||
1495 | |||
1496 | for (i = 0; i < n_ext_modules; ++i) | ||
1497 | if (ext_modules[i].used) | ||
1498 | ref++->module = ext_modules[i].addr; | ||
1499 | } | ||
1500 | } | ||
1501 | |||
1502 | /* Fill in routines. */ | ||
1503 | |||
1504 | routines.init = | ||
1505 | obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); | ||
1506 | routines.cleanup = | ||
1507 | obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); | ||
1508 | |||
1509 | /* Whew! All of the initialization is complete. Collect the final | ||
1510 | module image and give it to the kernel. */ | ||
1511 | |||
1512 | image = xmalloc(m_size); | ||
1513 | obj_create_image(f, image); | ||
1514 | |||
1515 | /* image holds the complete relocated module, accounting correctly for | ||
1516 | mod_use_count. However the old module kernel support assume that | ||
1517 | it is receiving something which does not contain mod_use_count. */ | ||
1518 | ret = old_sys_init_module(m_name, image + sizeof(long), | ||
1519 | m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN | ||
1520 | : 0), &routines, symtab); | ||
1521 | if (ret) | ||
1522 | perror("init_module: %m"); | ||
1523 | |||
1524 | free(image); | ||
1525 | free(symtab); | ||
1526 | |||
1527 | return ret == 0; | ||
1528 | } | ||
1529 | |||
1530 | #else | ||
1531 | |||
1532 | #define old_create_mod_use_count(x) TRUE | ||
1533 | #define old_init_module(x, y, z) TRUE | ||
1534 | |||
1535 | #endif /* BB_FEATURE_INSMOD_OLD_KERNEL */ | ||
1536 | |||
1537 | |||
1538 | |||
1539 | /*======================================================================*/ | ||
1540 | /* Functions relating to module loading after 2.1.18. */ | ||
1541 | |||
1542 | static int | ||
1543 | new_process_module_arguments(struct obj_file *f, int argc, char **argv) | ||
1544 | { | ||
1545 | while (argc > 0) { | ||
1546 | char *p, *q, *key; | ||
1547 | struct obj_symbol *sym; | ||
1548 | char *contents, *loc; | ||
1549 | int min, max, n; | ||
1550 | |||
1551 | p = *argv; | ||
1552 | if ((q = strchr(p, '=')) == NULL) | ||
1553 | continue; | ||
1554 | |||
1555 | key = alloca(q - p + 6); | ||
1556 | memcpy(key, "parm_", 5); | ||
1557 | memcpy(key + 5, p, q - p); | ||
1558 | key[q - p + 5] = 0; | ||
1559 | |||
1560 | p = get_modinfo_value(f, key); | ||
1561 | key += 5; | ||
1562 | if (p == NULL) { | ||
1563 | fprintf(stderr, "invalid parameter %s\n", key); | ||
1564 | return 0; | ||
1565 | } | ||
1566 | |||
1567 | sym = obj_find_symbol(f, key); | ||
1568 | |||
1569 | /* Also check that the parameter was not resolved from the kernel. */ | ||
1570 | if (sym == NULL || sym->secidx > SHN_HIRESERVE) { | ||
1571 | fprintf(stderr, "symbol for parameter %s not found\n", key); | ||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1575 | if (isdigit(*p)) { | ||
1576 | min = strtoul(p, &p, 10); | ||
1577 | if (*p == '-') | ||
1578 | max = strtoul(p + 1, &p, 10); | ||
1579 | else | ||
1580 | max = min; | ||
1581 | } else | ||
1582 | min = max = 1; | ||
1583 | |||
1584 | contents = f->sections[sym->secidx]->contents; | ||
1585 | loc = contents + sym->value; | ||
1586 | n = (*++q != '\0'); | ||
1587 | |||
1588 | while (1) { | ||
1589 | if ((*p == 's') || (*p == 'c')) { | ||
1590 | char *str; | ||
1591 | |||
1592 | /* Do C quoting if we begin with a ", else slurp the lot. */ | ||
1593 | if (*q == '"') { | ||
1594 | char *r; | ||
1595 | |||
1596 | str = alloca(strlen(q)); | ||
1597 | for (r = str, q++; *q != '"'; ++q, ++r) { | ||
1598 | if (*q == '\0') { | ||
1599 | fprintf(stderr, | ||
1600 | "improperly terminated string argument for %s\n", | ||
1601 | key); | ||
1602 | return 0; | ||
1603 | } else if (*q == '\\') | ||
1604 | switch (*++q) { | ||
1605 | case 'a': | ||
1606 | *r = '\a'; | ||
1607 | break; | ||
1608 | case 'b': | ||
1609 | *r = '\b'; | ||
1610 | break; | ||
1611 | case 'e': | ||
1612 | *r = '\033'; | ||
1613 | break; | ||
1614 | case 'f': | ||
1615 | *r = '\f'; | ||
1616 | break; | ||
1617 | case 'n': | ||
1618 | *r = '\n'; | ||
1619 | break; | ||
1620 | case 'r': | ||
1621 | *r = '\r'; | ||
1622 | break; | ||
1623 | case 't': | ||
1624 | *r = '\t'; | ||
1625 | break; | ||
1626 | |||
1627 | case '0': | ||
1628 | case '1': | ||
1629 | case '2': | ||
1630 | case '3': | ||
1631 | case '4': | ||
1632 | case '5': | ||
1633 | case '6': | ||
1634 | case '7': | ||
1635 | { | ||
1636 | int c = *q - '0'; | ||
1637 | if (q[1] >= '0' && q[1] <= '7') { | ||
1638 | c = (c * 8) + *++q - '0'; | ||
1639 | if (q[1] >= '0' && q[1] <= '7') | ||
1640 | c = (c * 8) + *++q - '0'; | ||
1641 | } | ||
1642 | *r = c; | ||
1643 | } | ||
1644 | break; | ||
1645 | |||
1646 | default: | ||
1647 | *r = *q; | ||
1648 | break; | ||
1649 | } else | ||
1650 | *r = *q; | ||
1651 | } | ||
1652 | *r = '\0'; | ||
1653 | ++q; | ||
1654 | } else { | ||
1655 | char *r; | ||
1656 | |||
1657 | /* In this case, the string is not quoted. We will break | ||
1658 | it using the coma (like for ints). If the user wants to | ||
1659 | include comas in a string, he just has to quote it */ | ||
1660 | |||
1661 | /* Search the next coma */ | ||
1662 | r = strchr(q, ','); | ||
1663 | |||
1664 | /* Found ? */ | ||
1665 | if (r != (char *) NULL) { | ||
1666 | /* Recopy the current field */ | ||
1667 | str = alloca(r - q + 1); | ||
1668 | memcpy(str, q, r - q); | ||
1669 | |||
1670 | /* I don't know if it is usefull, as the previous case | ||
1671 | doesn't null terminate the string ??? */ | ||
1672 | str[r - q] = '\0'; | ||
1673 | |||
1674 | /* Keep next fields */ | ||
1675 | q = r; | ||
1676 | } else { | ||
1677 | /* last string */ | ||
1678 | str = q; | ||
1679 | q = ""; | ||
1680 | } | ||
1681 | } | ||
1682 | |||
1683 | if (*p == 's') { | ||
1684 | /* Normal string */ | ||
1685 | obj_string_patch(f, sym->secidx, loc - contents, str); | ||
1686 | loc += tgt_sizeof_char_p; | ||
1687 | } else { | ||
1688 | /* Array of chars (in fact, matrix !) */ | ||
1689 | long charssize; /* size of each member */ | ||
1690 | |||
1691 | /* Get the size of each member */ | ||
1692 | /* Probably we should do that outside the loop ? */ | ||
1693 | if (!isdigit(*(p + 1))) { | ||
1694 | fprintf(stderr, | ||
1695 | "parameter type 'c' for %s must be followed by" | ||
1696 | " the maximum size\n", key); | ||
1697 | return 0; | ||
1698 | } | ||
1699 | charssize = strtoul(p + 1, (char **) NULL, 10); | ||
1700 | |||
1701 | /* Check length */ | ||
1702 | if (strlen(str) >= charssize) { | ||
1703 | fprintf(stderr, | ||
1704 | "string too long for %s (max %ld)\n", key, | ||
1705 | charssize - 1); | ||
1706 | return 0; | ||
1707 | } | ||
1708 | |||
1709 | /* Copy to location */ | ||
1710 | strcpy((char *) loc, str); | ||
1711 | loc += charssize; | ||
1712 | } | ||
1713 | } else { | ||
1714 | long v = strtoul(q, &q, 0); | ||
1715 | switch (*p) { | ||
1716 | case 'b': | ||
1717 | *loc++ = v; | ||
1718 | break; | ||
1719 | case 'h': | ||
1720 | *(short *) loc = v; | ||
1721 | loc += tgt_sizeof_short; | ||
1722 | break; | ||
1723 | case 'i': | ||
1724 | *(int *) loc = v; | ||
1725 | loc += tgt_sizeof_int; | ||
1726 | break; | ||
1727 | case 'l': | ||
1728 | *(long *) loc = v; | ||
1729 | loc += tgt_sizeof_long; | ||
1730 | break; | ||
1731 | |||
1732 | default: | ||
1733 | fprintf(stderr, "unknown parameter type '%c' for %s\n", | ||
1734 | *p, key); | ||
1735 | return 0; | ||
1736 | } | ||
1737 | } | ||
1738 | |||
1739 | retry_end_of_value: | ||
1740 | switch (*q) { | ||
1741 | case '\0': | ||
1742 | goto end_of_arg; | ||
1743 | |||
1744 | case ' ': | ||
1745 | case '\t': | ||
1746 | case '\n': | ||
1747 | case '\r': | ||
1748 | ++q; | ||
1749 | goto retry_end_of_value; | ||
1750 | |||
1751 | case ',': | ||
1752 | if (++n > max) { | ||
1753 | fprintf(stderr, "too many values for %s (max %d)\n", | ||
1754 | key, max); | ||
1755 | return 0; | ||
1756 | } | ||
1757 | ++q; | ||
1758 | break; | ||
1759 | |||
1760 | default: | ||
1761 | fprintf(stderr, "invalid argument syntax for %s\n", key); | ||
1762 | return 0; | ||
1763 | } | ||
1764 | } | ||
1765 | |||
1766 | end_of_arg: | ||
1767 | if (n < min) { | ||
1768 | fprintf(stderr, "too few values for %s (min %d)\n", key, min); | ||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | argc--, argv++; | ||
1773 | } | ||
1774 | |||
1775 | return 1; | ||
1776 | } | ||
1777 | |||
1778 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
1779 | static int new_is_module_checksummed(struct obj_file *f) | ||
1780 | { | ||
1781 | const char *p = get_modinfo_value(f, "using_checksums"); | ||
1782 | if (p) | ||
1783 | return atoi(p); | ||
1784 | else | ||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | /* Get the module's kernel version in the canonical integer form. */ | ||
1789 | |||
1790 | static int | ||
1791 | new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) | ||
1792 | { | ||
1793 | char *p, *q; | ||
1794 | int a, b, c; | ||
1795 | |||
1796 | p = get_modinfo_value(f, "kernel_version"); | ||
1797 | if (p == NULL) | ||
1798 | return -1; | ||
1799 | strncpy(str, p, STRVERSIONLEN); | ||
1800 | |||
1801 | a = strtoul(p, &p, 10); | ||
1802 | if (*p != '.') | ||
1803 | return -1; | ||
1804 | b = strtoul(p + 1, &p, 10); | ||
1805 | if (*p != '.') | ||
1806 | return -1; | ||
1807 | c = strtoul(p + 1, &q, 10); | ||
1808 | if (p + 1 == q) | ||
1809 | return -1; | ||
1810 | |||
1811 | return a << 16 | b << 8 | c; | ||
1812 | } | ||
1813 | |||
1814 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
1815 | |||
1816 | |||
1817 | #ifdef BB_FEATURE_INSMOD_NEW_KERNEL | ||
1818 | |||
1819 | /* Fetch the loaded modules, and all currently exported symbols. */ | ||
1820 | |||
1821 | static int new_get_kernel_symbols(void) | ||
1822 | { | ||
1823 | char *module_names, *mn; | ||
1824 | struct external_module *modules, *m; | ||
1825 | struct new_module_symbol *syms, *s; | ||
1826 | size_t ret, bufsize, nmod, nsyms, i, j; | ||
1827 | |||
1828 | /* Collect the loaded modules. */ | ||
1829 | |||
1830 | module_names = xmalloc(bufsize = 256); | ||
1831 | retry_modules_load: | ||
1832 | if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { | ||
1833 | if (errno == ENOSPC) { | ||
1834 | module_names = xrealloc(module_names, bufsize = ret); | ||
1835 | goto retry_modules_load; | ||
1836 | } | ||
1837 | perror("QM_MODULES: %m\n"); | ||
1838 | return 0; | ||
1839 | } | ||
1840 | |||
1841 | n_ext_modules = nmod = ret; | ||
1842 | ext_modules = modules = xmalloc(nmod * sizeof(*modules)); | ||
1843 | memset(modules, 0, nmod * sizeof(*modules)); | ||
1844 | |||
1845 | /* Collect the modules' symbols. */ | ||
1846 | |||
1847 | for (i = 0, mn = module_names, m = modules; | ||
1848 | i < nmod; ++i, ++m, mn += strlen(mn) + 1) { | ||
1849 | struct new_module_info info; | ||
1850 | |||
1851 | if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { | ||
1852 | if (errno == ENOENT) { | ||
1853 | /* The module was removed out from underneath us. */ | ||
1854 | continue; | ||
1855 | } | ||
1856 | perror("query_module: QM_INFO: %m"); | ||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | syms = xmalloc(bufsize = 1024); | ||
1861 | retry_mod_sym_load: | ||
1862 | if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { | ||
1863 | switch (errno) { | ||
1864 | case ENOSPC: | ||
1865 | syms = xrealloc(syms, bufsize = ret); | ||
1866 | goto retry_mod_sym_load; | ||
1867 | case ENOENT: | ||
1868 | /* The module was removed out from underneath us. */ | ||
1869 | continue; | ||
1870 | default: | ||
1871 | perror("query_module: QM_SYMBOLS: %m"); | ||
1872 | return 0; | ||
1873 | } | ||
1874 | } | ||
1875 | nsyms = ret; | ||
1876 | |||
1877 | m->name = mn; | ||
1878 | m->addr = info.addr; | ||
1879 | m->nsyms = nsyms; | ||
1880 | m->syms = syms; | ||
1881 | |||
1882 | for (j = 0, s = syms; j < nsyms; ++j, ++s) { | ||
1883 | s->name += (unsigned long) syms; | ||
1884 | } | ||
1885 | } | ||
1886 | |||
1887 | /* Collect the kernel's symbols. */ | ||
1888 | |||
1889 | syms = xmalloc(bufsize = 16 * 1024); | ||
1890 | retry_kern_sym_load: | ||
1891 | if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { | ||
1892 | if (errno == ENOSPC) { | ||
1893 | syms = xrealloc(syms, bufsize = ret); | ||
1894 | goto retry_kern_sym_load; | ||
1895 | } | ||
1896 | perror("kernel: QM_SYMBOLS: %m"); | ||
1897 | return 0; | ||
1898 | } | ||
1899 | nksyms = nsyms = ret; | ||
1900 | ksyms = syms; | ||
1901 | |||
1902 | for (j = 0, s = syms; j < nsyms; ++j, ++s) { | ||
1903 | s->name += (unsigned long) syms; | ||
1904 | } | ||
1905 | return 1; | ||
1906 | } | ||
1907 | |||
1908 | |||
1909 | /* Return the kernel symbol checksum version, or zero if not used. */ | ||
1910 | |||
1911 | static int new_is_kernel_checksummed(void) | ||
1912 | { | ||
1913 | struct new_module_symbol *s; | ||
1914 | size_t i; | ||
1915 | |||
1916 | /* Using_Versions is not the first symbol, but it should be in there. */ | ||
1917 | |||
1918 | for (i = 0, s = ksyms; i < nksyms; ++i, ++s) | ||
1919 | if (strcmp((char *) s->name, "Using_Versions") == 0) | ||
1920 | return s->value; | ||
1921 | |||
1922 | return 0; | ||
1923 | } | ||
1924 | |||
1925 | |||
1926 | static int new_create_this_module(struct obj_file *f, const char *m_name) | ||
1927 | { | ||
1928 | struct obj_section *sec; | ||
1929 | |||
1930 | sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, | ||
1931 | sizeof(struct new_module)); | ||
1932 | memset(sec->contents, 0, sizeof(struct new_module)); | ||
1933 | |||
1934 | obj_add_symbol(f, "__this_module", -1, | ||
1935 | ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, | ||
1936 | sizeof(struct new_module)); | ||
1937 | |||
1938 | obj_string_patch(f, sec->idx, offsetof(struct new_module, name), | ||
1939 | m_name); | ||
1940 | |||
1941 | return 1; | ||
1942 | } | ||
1943 | |||
1944 | |||
1945 | static int new_create_module_ksymtab(struct obj_file *f) | ||
1946 | { | ||
1947 | struct obj_section *sec; | ||
1948 | int i; | ||
1949 | |||
1950 | /* We must always add the module references. */ | ||
1951 | |||
1952 | if (n_ext_modules_used) { | ||
1953 | struct new_module_ref *dep; | ||
1954 | struct obj_symbol *tm; | ||
1955 | |||
1956 | sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, | ||
1957 | (sizeof(struct new_module_ref) | ||
1958 | * n_ext_modules_used)); | ||
1959 | if (!sec) | ||
1960 | return 0; | ||
1961 | |||
1962 | tm = obj_find_symbol(f, "__this_module"); | ||
1963 | dep = (struct new_module_ref *) sec->contents; | ||
1964 | for (i = 0; i < n_ext_modules; ++i) | ||
1965 | if (ext_modules[i].used) { | ||
1966 | dep->dep = ext_modules[i].addr; | ||
1967 | obj_symbol_patch(f, sec->idx, | ||
1968 | (char *) &dep->ref - sec->contents, tm); | ||
1969 | dep->next_ref = 0; | ||
1970 | ++dep; | ||
1971 | } | ||
1972 | } | ||
1973 | |||
1974 | if (flag_export && !obj_find_section(f, "__ksymtab")) { | ||
1975 | size_t nsyms; | ||
1976 | int *loaded; | ||
1977 | |||
1978 | sec = | ||
1979 | obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, | ||
1980 | 0); | ||
1981 | |||
1982 | /* We don't want to export symbols residing in sections that | ||
1983 | aren't loaded. There are a number of these created so that | ||
1984 | we make sure certain module options don't appear twice. */ | ||
1985 | |||
1986 | loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); | ||
1987 | while (--i >= 0) | ||
1988 | loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; | ||
1989 | |||
1990 | for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { | ||
1991 | struct obj_symbol *sym; | ||
1992 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
1993 | if (ELFW(ST_BIND) (sym->info) != STB_LOCAL | ||
1994 | && sym->secidx <= SHN_HIRESERVE | ||
1995 | && (sym->secidx >= SHN_LORESERVE | ||
1996 | || loaded[sym->secidx])) { | ||
1997 | ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; | ||
1998 | |||
1999 | obj_symbol_patch(f, sec->idx, ofs, sym); | ||
2000 | obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, | ||
2001 | sym->name); | ||
2002 | |||
2003 | nsyms++; | ||
2004 | } | ||
2005 | } | ||
2006 | |||
2007 | obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); | ||
2008 | } | ||
2009 | |||
2010 | return 1; | ||
2011 | } | ||
2012 | |||
2013 | |||
2014 | static int | ||
2015 | new_init_module(const char *m_name, struct obj_file *f, | ||
2016 | unsigned long m_size) | ||
2017 | { | ||
2018 | struct new_module *module; | ||
2019 | struct obj_section *sec; | ||
2020 | void *image; | ||
2021 | int ret; | ||
2022 | tgt_long m_addr; | ||
2023 | |||
2024 | sec = obj_find_section(f, ".this"); | ||
2025 | module = (struct new_module *) sec->contents; | ||
2026 | m_addr = sec->header.sh_addr; | ||
2027 | |||
2028 | module->size_of_struct = sizeof(*module); | ||
2029 | module->size = m_size; | ||
2030 | module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; | ||
2031 | |||
2032 | sec = obj_find_section(f, "__ksymtab"); | ||
2033 | if (sec && sec->header.sh_size) { | ||
2034 | module->syms = sec->header.sh_addr; | ||
2035 | module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); | ||
2036 | } | ||
2037 | |||
2038 | if (n_ext_modules_used) { | ||
2039 | sec = obj_find_section(f, ".kmodtab"); | ||
2040 | module->deps = sec->header.sh_addr; | ||
2041 | module->ndeps = n_ext_modules_used; | ||
2042 | } | ||
2043 | |||
2044 | module->init = | ||
2045 | obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); | ||
2046 | module->cleanup = | ||
2047 | obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); | ||
2048 | |||
2049 | sec = obj_find_section(f, "__ex_table"); | ||
2050 | if (sec) { | ||
2051 | module->ex_table_start = sec->header.sh_addr; | ||
2052 | module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; | ||
2053 | } | ||
2054 | |||
2055 | sec = obj_find_section(f, ".text.init"); | ||
2056 | if (sec) { | ||
2057 | module->runsize = sec->header.sh_addr - m_addr; | ||
2058 | } | ||
2059 | sec = obj_find_section(f, ".data.init"); | ||
2060 | if (sec) { | ||
2061 | if (!module->runsize || | ||
2062 | module->runsize > sec->header.sh_addr - m_addr) | ||
2063 | module->runsize = sec->header.sh_addr - m_addr; | ||
2064 | } | ||
2065 | |||
2066 | if (!arch_init_module(f, module)) | ||
2067 | return 0; | ||
2068 | |||
2069 | /* Whew! All of the initialization is complete. Collect the final | ||
2070 | module image and give it to the kernel. */ | ||
2071 | |||
2072 | image = xmalloc(m_size); | ||
2073 | obj_create_image(f, image); | ||
2074 | |||
2075 | ret = new_sys_init_module(m_name, (struct new_module *) image); | ||
2076 | if (ret) | ||
2077 | perror("init_module: %m"); | ||
2078 | |||
2079 | free(image); | ||
2080 | |||
2081 | return ret == 0; | ||
2082 | } | ||
2083 | |||
2084 | #else | ||
2085 | |||
2086 | #define new_init_module(x, y, z) TRUE | ||
2087 | #define new_create_this_module(x, y) 0 | ||
2088 | #define new_create_module_ksymtab(x) | ||
2089 | |||
2090 | #endif /* BB_FEATURE_INSMOD_OLD_KERNEL */ | ||
2091 | |||
2092 | |||
2093 | /*======================================================================*/ | ||
2094 | |||
2095 | int | ||
2096 | obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
2097 | const char *string) | ||
2098 | { | ||
2099 | struct obj_string_patch *p; | ||
2100 | struct obj_section *strsec; | ||
2101 | size_t len = strlen(string) + 1; | ||
2102 | char *loc; | ||
2103 | |||
2104 | p = xmalloc(sizeof(*p)); | ||
2105 | p->next = f->string_patches; | ||
2106 | p->reloc_secidx = secidx; | ||
2107 | p->reloc_offset = offset; | ||
2108 | f->string_patches = p; | ||
2109 | |||
2110 | strsec = obj_find_section(f, ".kstrtab"); | ||
2111 | if (strsec == NULL) { | ||
2112 | strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); | ||
2113 | p->string_offset = 0; | ||
2114 | loc = strsec->contents; | ||
2115 | } else { | ||
2116 | p->string_offset = strsec->header.sh_size; | ||
2117 | loc = obj_extend_section(strsec, len); | ||
2118 | } | ||
2119 | memcpy(loc, string, len); | ||
2120 | |||
2121 | return 1; | ||
2122 | } | ||
2123 | |||
2124 | int | ||
2125 | obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
2126 | struct obj_symbol *sym) | ||
2127 | { | ||
2128 | struct obj_symbol_patch *p; | ||
2129 | |||
2130 | p = xmalloc(sizeof(*p)); | ||
2131 | p->next = f->symbol_patches; | ||
2132 | p->reloc_secidx = secidx; | ||
2133 | p->reloc_offset = offset; | ||
2134 | p->sym = sym; | ||
2135 | f->symbol_patches = p; | ||
2136 | |||
2137 | return 1; | ||
2138 | } | ||
2139 | |||
2140 | int obj_check_undefineds(struct obj_file *f) | ||
2141 | { | ||
2142 | unsigned long i; | ||
2143 | int ret = 1; | ||
2144 | |||
2145 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
2146 | struct obj_symbol *sym; | ||
2147 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
2148 | if (sym->secidx == SHN_UNDEF) { | ||
2149 | if (ELFW(ST_BIND) (sym->info) == STB_WEAK) { | ||
2150 | sym->secidx = SHN_ABS; | ||
2151 | sym->value = 0; | ||
2152 | } else { | ||
2153 | fprintf(stderr, "unresolved symbol %s\n", sym->name); | ||
2154 | ret = 0; | ||
2155 | } | ||
2156 | } | ||
2157 | } | ||
2158 | |||
2159 | return ret; | ||
2160 | } | ||
2161 | |||
2162 | void obj_allocate_commons(struct obj_file *f) | ||
2163 | { | ||
2164 | struct common_entry { | ||
2165 | struct common_entry *next; | ||
2166 | struct obj_symbol *sym; | ||
2167 | } *common_head = NULL; | ||
2168 | |||
2169 | unsigned long i; | ||
2170 | |||
2171 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
2172 | struct obj_symbol *sym; | ||
2173 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
2174 | if (sym->secidx == SHN_COMMON) { | ||
2175 | /* Collect all COMMON symbols and sort them by size so as to | ||
2176 | minimize space wasted by alignment requirements. */ | ||
2177 | { | ||
2178 | struct common_entry **p, *n; | ||
2179 | for (p = &common_head; *p; p = &(*p)->next) | ||
2180 | if (sym->size <= (*p)->sym->size) | ||
2181 | break; | ||
2182 | |||
2183 | n = alloca(sizeof(*n)); | ||
2184 | n->next = *p; | ||
2185 | n->sym = sym; | ||
2186 | *p = n; | ||
2187 | } | ||
2188 | } | ||
2189 | } | ||
2190 | |||
2191 | for (i = 1; i < f->local_symtab_size; ++i) { | ||
2192 | struct obj_symbol *sym = f->local_symtab[i]; | ||
2193 | if (sym && sym->secidx == SHN_COMMON) { | ||
2194 | struct common_entry **p, *n; | ||
2195 | for (p = &common_head; *p; p = &(*p)->next) | ||
2196 | if (sym == (*p)->sym) | ||
2197 | break; | ||
2198 | else if (sym->size < (*p)->sym->size) { | ||
2199 | n = alloca(sizeof(*n)); | ||
2200 | n->next = *p; | ||
2201 | n->sym = sym; | ||
2202 | *p = n; | ||
2203 | break; | ||
2204 | } | ||
2205 | } | ||
2206 | } | ||
2207 | |||
2208 | if (common_head) { | ||
2209 | /* Find the bss section. */ | ||
2210 | for (i = 0; i < f->header.e_shnum; ++i) | ||
2211 | if (f->sections[i]->header.sh_type == SHT_NOBITS) | ||
2212 | break; | ||
2213 | |||
2214 | /* If for some reason there hadn't been one, create one. */ | ||
2215 | if (i == f->header.e_shnum) { | ||
2216 | struct obj_section *sec; | ||
2217 | |||
2218 | f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec)); | ||
2219 | f->sections[i] = sec = arch_new_section(); | ||
2220 | f->header.e_shnum = i + 1; | ||
2221 | |||
2222 | memset(sec, 0, sizeof(*sec)); | ||
2223 | sec->header.sh_type = SHT_PROGBITS; | ||
2224 | sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; | ||
2225 | sec->name = ".bss"; | ||
2226 | sec->idx = i; | ||
2227 | } | ||
2228 | |||
2229 | /* Allocate the COMMONS. */ | ||
2230 | { | ||
2231 | ElfW(Addr) bss_size = f->sections[i]->header.sh_size; | ||
2232 | ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; | ||
2233 | struct common_entry *c; | ||
2234 | |||
2235 | for (c = common_head; c; c = c->next) { | ||
2236 | ElfW(Addr) align = c->sym->value; | ||
2237 | |||
2238 | if (align > max_align) | ||
2239 | max_align = align; | ||
2240 | if (bss_size & (align - 1)) | ||
2241 | bss_size = (bss_size | (align - 1)) + 1; | ||
2242 | |||
2243 | c->sym->secidx = i; | ||
2244 | c->sym->value = bss_size; | ||
2245 | |||
2246 | bss_size += c->sym->size; | ||
2247 | } | ||
2248 | |||
2249 | f->sections[i]->header.sh_size = bss_size; | ||
2250 | f->sections[i]->header.sh_addralign = max_align; | ||
2251 | } | ||
2252 | } | ||
2253 | |||
2254 | /* For the sake of patch relocation and parameter initialization, | ||
2255 | allocate zeroed data for NOBITS sections now. Note that after | ||
2256 | this we cannot assume NOBITS are really empty. */ | ||
2257 | for (i = 0; i < f->header.e_shnum; ++i) { | ||
2258 | struct obj_section *s = f->sections[i]; | ||
2259 | if (s->header.sh_type == SHT_NOBITS) { | ||
2260 | s->contents = memset(xmalloc(s->header.sh_size), | ||
2261 | 0, s->header.sh_size); | ||
2262 | s->header.sh_type = SHT_PROGBITS; | ||
2263 | } | ||
2264 | } | ||
2265 | } | ||
2266 | |||
2267 | unsigned long obj_load_size(struct obj_file *f) | ||
2268 | { | ||
2269 | unsigned long dot = 0; | ||
2270 | struct obj_section *sec; | ||
2271 | |||
2272 | /* Finalize the positions of the sections relative to one another. */ | ||
2273 | |||
2274 | for (sec = f->load_order; sec; sec = sec->load_next) { | ||
2275 | ElfW(Addr) align; | ||
2276 | |||
2277 | align = sec->header.sh_addralign; | ||
2278 | if (align && (dot & (align - 1))) | ||
2279 | dot = (dot | (align - 1)) + 1; | ||
2280 | |||
2281 | sec->header.sh_addr = dot; | ||
2282 | dot += sec->header.sh_size; | ||
2283 | } | ||
2284 | |||
2285 | return dot; | ||
2286 | } | ||
2287 | |||
2288 | int obj_relocate(struct obj_file *f, ElfW(Addr) base) | ||
2289 | { | ||
2290 | int i, n = f->header.e_shnum; | ||
2291 | int ret = 1; | ||
2292 | |||
2293 | /* Finalize the addresses of the sections. */ | ||
2294 | |||
2295 | f->baseaddr = base; | ||
2296 | for (i = 0; i < n; ++i) | ||
2297 | f->sections[i]->header.sh_addr += base; | ||
2298 | |||
2299 | /* And iterate over all of the relocations. */ | ||
2300 | |||
2301 | for (i = 0; i < n; ++i) { | ||
2302 | struct obj_section *relsec, *symsec, *targsec, *strsec; | ||
2303 | ElfW(RelM) * rel, *relend; | ||
2304 | ElfW(Sym) * symtab; | ||
2305 | const char *strtab; | ||
2306 | |||
2307 | relsec = f->sections[i]; | ||
2308 | if (relsec->header.sh_type != SHT_RELM) | ||
2309 | continue; | ||
2310 | |||
2311 | symsec = f->sections[relsec->header.sh_link]; | ||
2312 | targsec = f->sections[relsec->header.sh_info]; | ||
2313 | strsec = f->sections[symsec->header.sh_link]; | ||
2314 | |||
2315 | rel = (ElfW(RelM) *) relsec->contents; | ||
2316 | relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); | ||
2317 | symtab = (ElfW(Sym) *) symsec->contents; | ||
2318 | strtab = (const char *) strsec->contents; | ||
2319 | |||
2320 | for (; rel < relend; ++rel) { | ||
2321 | ElfW(Addr) value = 0; | ||
2322 | struct obj_symbol *intsym = NULL; | ||
2323 | unsigned long symndx; | ||
2324 | ElfW(Sym) * extsym = 0; | ||
2325 | const char *errmsg; | ||
2326 | |||
2327 | /* Attempt to find a value to use for this relocation. */ | ||
2328 | |||
2329 | symndx = ELFW(R_SYM) (rel->r_info); | ||
2330 | if (symndx) { | ||
2331 | /* Note we've already checked for undefined symbols. */ | ||
2332 | |||
2333 | extsym = &symtab[symndx]; | ||
2334 | if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) { | ||
2335 | /* Local symbols we look up in the local table to be sure | ||
2336 | we get the one that is really intended. */ | ||
2337 | intsym = f->local_symtab[symndx]; | ||
2338 | } else { | ||
2339 | /* Others we look up in the hash table. */ | ||
2340 | const char *name; | ||
2341 | if (extsym->st_name) | ||
2342 | name = strtab + extsym->st_name; | ||
2343 | else | ||
2344 | name = f->sections[extsym->st_shndx]->name; | ||
2345 | intsym = obj_find_symbol(f, name); | ||
2346 | } | ||
2347 | |||
2348 | value = obj_symbol_final_value(f, intsym); | ||
2349 | intsym->referenced = 1; | ||
2350 | } | ||
2351 | #if SHT_RELM == SHT_RELA | ||
2352 | #if defined(__alpha__) && defined(AXP_BROKEN_GAS) | ||
2353 | /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ | ||
2354 | if (!extsym || !extsym->st_name || | ||
2355 | ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL) | ||
2356 | #endif | ||
2357 | value += rel->r_addend; | ||
2358 | #endif | ||
2359 | |||
2360 | /* Do it! */ | ||
2361 | switch (arch_apply_relocation | ||
2362 | (f, targsec, symsec, intsym, rel, value)) { | ||
2363 | case obj_reloc_ok: | ||
2364 | break; | ||
2365 | |||
2366 | case obj_reloc_overflow: | ||
2367 | errmsg = "Relocation overflow"; | ||
2368 | goto bad_reloc; | ||
2369 | case obj_reloc_dangerous: | ||
2370 | errmsg = "Dangerous relocation"; | ||
2371 | goto bad_reloc; | ||
2372 | case obj_reloc_unhandled: | ||
2373 | errmsg = "Unhandled relocation"; | ||
2374 | bad_reloc: | ||
2375 | if (extsym) { | ||
2376 | fprintf(stderr, "%s of type %ld for %s\n", errmsg, | ||
2377 | (long) ELFW(R_TYPE) (rel->r_info), | ||
2378 | strtab + extsym->st_name); | ||
2379 | } else { | ||
2380 | fprintf(stderr, "%s of type %ld\n", errmsg, | ||
2381 | (long) ELFW(R_TYPE) (rel->r_info)); | ||
2382 | } | ||
2383 | ret = 0; | ||
2384 | break; | ||
2385 | } | ||
2386 | } | ||
2387 | } | ||
2388 | |||
2389 | /* Finally, take care of the patches. */ | ||
2390 | |||
2391 | if (f->string_patches) { | ||
2392 | struct obj_string_patch *p; | ||
2393 | struct obj_section *strsec; | ||
2394 | ElfW(Addr) strsec_base; | ||
2395 | strsec = obj_find_section(f, ".kstrtab"); | ||
2396 | strsec_base = strsec->header.sh_addr; | ||
2397 | |||
2398 | for (p = f->string_patches; p; p = p->next) { | ||
2399 | struct obj_section *targsec = f->sections[p->reloc_secidx]; | ||
2400 | *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) | ||
2401 | = strsec_base + p->string_offset; | ||
2402 | } | ||
2403 | } | ||
2404 | |||
2405 | if (f->symbol_patches) { | ||
2406 | struct obj_symbol_patch *p; | ||
2407 | |||
2408 | for (p = f->symbol_patches; p; p = p->next) { | ||
2409 | struct obj_section *targsec = f->sections[p->reloc_secidx]; | ||
2410 | *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) | ||
2411 | = obj_symbol_final_value(f, p->sym); | ||
2412 | } | ||
2413 | } | ||
2414 | |||
2415 | return ret; | ||
2416 | } | ||
2417 | |||
2418 | int obj_create_image(struct obj_file *f, char *image) | ||
2419 | { | ||
2420 | struct obj_section *sec; | ||
2421 | ElfW(Addr) base = f->baseaddr; | ||
2422 | |||
2423 | for (sec = f->load_order; sec; sec = sec->load_next) { | ||
2424 | char *secimg; | ||
2425 | |||
2426 | if (sec->header.sh_size == 0) | ||
2427 | continue; | ||
2428 | |||
2429 | secimg = image + (sec->header.sh_addr - base); | ||
2430 | |||
2431 | /* Note that we allocated data for NOBITS sections earlier. */ | ||
2432 | memcpy(secimg, sec->contents, sec->header.sh_size); | ||
2433 | } | ||
2434 | |||
2435 | return 1; | ||
2436 | } | ||
2437 | |||
2438 | /*======================================================================*/ | ||
2439 | |||
2440 | struct obj_file *obj_load(FILE * fp) | ||
2441 | { | ||
2442 | struct obj_file *f; | ||
2443 | ElfW(Shdr) * section_headers; | ||
2444 | int shnum, i; | ||
2445 | char *shstrtab; | ||
2446 | |||
2447 | /* Read the file header. */ | ||
2448 | |||
2449 | f = arch_new_file(); | ||
2450 | memset(f, 0, sizeof(*f)); | ||
2451 | f->symbol_cmp = strcmp; | ||
2452 | f->symbol_hash = obj_elf_hash; | ||
2453 | f->load_order_search_start = &f->load_order; | ||
2454 | |||
2455 | fseek(fp, 0, SEEK_SET); | ||
2456 | if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { | ||
2457 | perror("error reading ELF header: %m"); | ||
2458 | return NULL; | ||
2459 | } | ||
2460 | |||
2461 | if (f->header.e_ident[EI_MAG0] != ELFMAG0 | ||
2462 | || f->header.e_ident[EI_MAG1] != ELFMAG1 | ||
2463 | || f->header.e_ident[EI_MAG2] != ELFMAG2 | ||
2464 | || f->header.e_ident[EI_MAG3] != ELFMAG3) { | ||
2465 | fprintf(stderr, "not an ELF file\n"); | ||
2466 | return NULL; | ||
2467 | } | ||
2468 | if (f->header.e_ident[EI_CLASS] != ELFCLASSM | ||
2469 | || f->header.e_ident[EI_DATA] != ELFDATAM | ||
2470 | || f->header.e_ident[EI_VERSION] != EV_CURRENT | ||
2471 | || !MATCH_MACHINE(f->header.e_machine)) { | ||
2472 | fprintf(stderr, "ELF file not for this architecture\n"); | ||
2473 | return NULL; | ||
2474 | } | ||
2475 | if (f->header.e_type != ET_REL) { | ||
2476 | fprintf(stderr, "ELF file not a relocatable object\n"); | ||
2477 | return NULL; | ||
2478 | } | ||
2479 | |||
2480 | /* Read the section headers. */ | ||
2481 | |||
2482 | if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { | ||
2483 | fprintf(stderr, "section header size mismatch: %lu != %lu\n", | ||
2484 | (unsigned long) f->header.e_shentsize, | ||
2485 | (unsigned long) sizeof(ElfW(Shdr))); | ||
2486 | return NULL; | ||
2487 | } | ||
2488 | |||
2489 | shnum = f->header.e_shnum; | ||
2490 | f->sections = xmalloc(sizeof(struct obj_section *) * shnum); | ||
2491 | memset(f->sections, 0, sizeof(struct obj_section *) * shnum); | ||
2492 | |||
2493 | section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); | ||
2494 | fseek(fp, f->header.e_shoff, SEEK_SET); | ||
2495 | if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { | ||
2496 | perror("error reading ELF section headers: %m"); | ||
2497 | return NULL; | ||
2498 | } | ||
2499 | |||
2500 | /* Read the section data. */ | ||
2501 | |||
2502 | for (i = 0; i < shnum; ++i) { | ||
2503 | struct obj_section *sec; | ||
2504 | |||
2505 | f->sections[i] = sec = arch_new_section(); | ||
2506 | memset(sec, 0, sizeof(*sec)); | ||
2507 | |||
2508 | sec->header = section_headers[i]; | ||
2509 | sec->idx = i; | ||
2510 | |||
2511 | switch (sec->header.sh_type) { | ||
2512 | case SHT_NULL: | ||
2513 | case SHT_NOTE: | ||
2514 | case SHT_NOBITS: | ||
2515 | /* ignore */ | ||
2516 | break; | ||
2517 | |||
2518 | case SHT_PROGBITS: | ||
2519 | case SHT_SYMTAB: | ||
2520 | case SHT_STRTAB: | ||
2521 | case SHT_RELM: | ||
2522 | if (sec->header.sh_size > 0) { | ||
2523 | sec->contents = xmalloc(sec->header.sh_size); | ||
2524 | fseek(fp, sec->header.sh_offset, SEEK_SET); | ||
2525 | if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { | ||
2526 | fprintf(stderr, | ||
2527 | "error reading ELF section data: %m\n"); | ||
2528 | return NULL; | ||
2529 | } | ||
2530 | } else { | ||
2531 | sec->contents = NULL; | ||
2532 | } | ||
2533 | break; | ||
2534 | |||
2535 | #if SHT_RELM == SHT_REL | ||
2536 | case SHT_RELA: | ||
2537 | fprintf(stderr, | ||
2538 | "RELA relocations not supported on this architecture\n"); | ||
2539 | return NULL; | ||
2540 | #else | ||
2541 | case SHT_REL: | ||
2542 | fprintf(stderr, | ||
2543 | "REL relocations not supported on this architecture\n"); | ||
2544 | return NULL; | ||
2545 | #endif | ||
2546 | |||
2547 | default: | ||
2548 | if (sec->header.sh_type >= SHT_LOPROC) { | ||
2549 | /* Assume processor specific section types are debug | ||
2550 | info and can safely be ignored. If this is ever not | ||
2551 | the case (Hello MIPS?), don't put ifdefs here but | ||
2552 | create an arch_load_proc_section(). */ | ||
2553 | break; | ||
2554 | } | ||
2555 | |||
2556 | fprintf(stderr, "can't handle sections of type %ld\n", | ||
2557 | (long) sec->header.sh_type); | ||
2558 | return NULL; | ||
2559 | } | ||
2560 | } | ||
2561 | |||
2562 | /* Do what sort of interpretation as needed by each section. */ | ||
2563 | |||
2564 | shstrtab = f->sections[f->header.e_shstrndx]->contents; | ||
2565 | |||
2566 | for (i = 0; i < shnum; ++i) { | ||
2567 | struct obj_section *sec = f->sections[i]; | ||
2568 | sec->name = shstrtab + sec->header.sh_name; | ||
2569 | } | ||
2570 | |||
2571 | for (i = 0; i < shnum; ++i) { | ||
2572 | struct obj_section *sec = f->sections[i]; | ||
2573 | |||
2574 | if (sec->header.sh_flags & SHF_ALLOC) | ||
2575 | obj_insert_section_load_order(f, sec); | ||
2576 | |||
2577 | switch (sec->header.sh_type) { | ||
2578 | case SHT_SYMTAB: | ||
2579 | { | ||
2580 | unsigned long nsym, j; | ||
2581 | char *strtab; | ||
2582 | ElfW(Sym) * sym; | ||
2583 | |||
2584 | if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { | ||
2585 | fprintf(stderr, "symbol size mismatch: %lu != %lu\n", | ||
2586 | (unsigned long) sec->header.sh_entsize, | ||
2587 | (unsigned long) sizeof(ElfW(Sym))); | ||
2588 | return NULL; | ||
2589 | } | ||
2590 | |||
2591 | nsym = sec->header.sh_size / sizeof(ElfW(Sym)); | ||
2592 | strtab = f->sections[sec->header.sh_link]->contents; | ||
2593 | sym = (ElfW(Sym) *) sec->contents; | ||
2594 | |||
2595 | /* Allocate space for a table of local symbols. */ | ||
2596 | j = f->local_symtab_size = sec->header.sh_info; | ||
2597 | f->local_symtab = xmalloc(j *= | ||
2598 | sizeof(struct obj_symbol *)); | ||
2599 | memset(f->local_symtab, 0, j); | ||
2600 | |||
2601 | /* Insert all symbols into the hash table. */ | ||
2602 | for (j = 1, ++sym; j < nsym; ++j, ++sym) { | ||
2603 | const char *name; | ||
2604 | if (sym->st_name) | ||
2605 | name = strtab + sym->st_name; | ||
2606 | else | ||
2607 | name = f->sections[sym->st_shndx]->name; | ||
2608 | |||
2609 | obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, | ||
2610 | sym->st_value, sym->st_size); | ||
2611 | } | ||
2612 | } | ||
2613 | break; | ||
2614 | |||
2615 | case SHT_RELM: | ||
2616 | if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { | ||
2617 | fprintf(stderr, | ||
2618 | "relocation entry size mismatch: %lu != %lu\n", | ||
2619 | (unsigned long) sec->header.sh_entsize, | ||
2620 | (unsigned long) sizeof(ElfW(RelM))); | ||
2621 | return NULL; | ||
2622 | } | ||
2623 | break; | ||
2624 | } | ||
2625 | } | ||
2626 | |||
2627 | return f; | ||
2628 | } | ||
2629 | |||
2630 | static void hide_special_symbols(struct obj_file *f) | ||
2631 | { | ||
2632 | static const char *const specials[] = { | ||
2633 | "cleanup_module", | ||
2634 | "init_module", | ||
2635 | "kernel_version", | ||
2636 | NULL | ||
2637 | }; | ||
2638 | |||
2639 | struct obj_symbol *sym; | ||
2640 | const char *const *p; | ||
2641 | |||
2642 | for (p = specials; *p; ++p) | ||
2643 | if ((sym = obj_find_symbol(f, *p)) != NULL) | ||
2644 | sym->info = | ||
2645 | ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); | ||
2646 | } | ||
2647 | |||
2648 | |||
2649 | |||
2650 | extern int insmod_main( int argc, char **argv) | ||
2651 | { | ||
2652 | int k_crcs; | ||
2653 | int k_new_syscalls; | ||
107 | int len; | 2654 | int len; |
108 | char *tmp; | 2655 | char *tmp; |
109 | char m_name[BUFSIZ + 1] = "\0"; | 2656 | unsigned long m_size; |
2657 | ElfW(Addr) m_addr; | ||
110 | FILE *fp; | 2658 | FILE *fp; |
2659 | struct obj_file *f; | ||
2660 | char m_name[BUFSIZ + 1] = "\0"; | ||
2661 | int exit_status = FALSE; | ||
2662 | int m_has_modinfo; | ||
2663 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
2664 | int k_version; | ||
2665 | char k_strversion[STRVERSIONLEN]; | ||
2666 | char m_strversion[STRVERSIONLEN]; | ||
2667 | int m_version; | ||
2668 | int m_crcs; | ||
2669 | #endif | ||
2670 | |||
111 | 2671 | ||
112 | if (argc <= 1) { | 2672 | if (argc <= 1) { |
113 | usage(insmod_usage); | 2673 | usage(insmod_usage); |
@@ -117,9 +2677,17 @@ extern int insmod_main(int argc, char **argv) | |||
117 | while (--argc > 0 && **(++argv) == '-') { | 2677 | while (--argc > 0 && **(++argv) == '-') { |
118 | while (*(++(*argv))) { | 2678 | while (*(++(*argv))) { |
119 | switch (**argv) { | 2679 | switch (**argv) { |
120 | case 'f': | 2680 | case 'f': /* force loading */ |
2681 | flag_force_load = 1; | ||
2682 | break; | ||
2683 | case 'k': /* module loaded by kerneld, auto-cleanable */ | ||
2684 | flag_autoclean = 1; | ||
121 | break; | 2685 | break; |
122 | case 'k': | 2686 | case 'v': /* verbose output */ |
2687 | flag_verbose = 1; | ||
2688 | break; | ||
2689 | case 'x': /* do not export externs */ | ||
2690 | flag_export = 0; | ||
123 | break; | 2691 | break; |
124 | default: | 2692 | default: |
125 | usage(insmod_usage); | 2693 | usage(insmod_usage); |
@@ -127,14 +2695,15 @@ extern int insmod_main(int argc, char **argv) | |||
127 | } | 2695 | } |
128 | } | 2696 | } |
129 | 2697 | ||
130 | if (argc <= 0) | 2698 | if (argc <= 0) { |
131 | usage(insmod_usage); | 2699 | usage(insmod_usage); |
132 | 2700 | } | |
133 | /* Grab the module name */ | 2701 | /* Grab the module name */ |
134 | if ((tmp = strrchr(*argv, '/')) != NULL) | 2702 | if ((tmp = strrchr(*argv, '/')) != NULL) { |
135 | tmp++; | 2703 | tmp++; |
136 | else | 2704 | } else { |
137 | tmp = *argv; | 2705 | tmp = *argv; |
2706 | } | ||
138 | len = strlen(tmp); | 2707 | len = strlen(tmp); |
139 | 2708 | ||
140 | if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') | 2709 | if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') |
@@ -147,9 +2716,11 @@ extern int insmod_main(int argc, char **argv) | |||
147 | if ((fp = fopen(*argv, "r")) == NULL) { | 2716 | if ((fp = fopen(*argv, "r")) == NULL) { |
148 | /* Hmpf. Could not open it. Search through _PATH_MODULES to find a module named m_name */ | 2717 | /* Hmpf. Could not open it. Search through _PATH_MODULES to find a module named m_name */ |
149 | if (recursiveAction(_PATH_MODULES, TRUE, FALSE, FALSE, | 2718 | if (recursiveAction(_PATH_MODULES, TRUE, FALSE, FALSE, |
150 | findNamedModule, findNamedModule) == FALSE) { | 2719 | findNamedModule, 0, m_fullName) == TRUE) |
2720 | { | ||
151 | if (m_filename[0] == '\0' | 2721 | if (m_filename[0] == '\0' |
152 | || ((fp = fopen(m_filename, "r")) == NULL)) { | 2722 | || ((fp = fopen(m_filename, "r")) == NULL)) |
2723 | { | ||
153 | perror("No module by that name found in " _PATH_MODULES | 2724 | perror("No module by that name found in " _PATH_MODULES |
154 | "\n"); | 2725 | "\n"); |
155 | exit(FALSE); | 2726 | exit(FALSE); |
@@ -159,40 +2730,112 @@ extern int insmod_main(int argc, char **argv) | |||
159 | memcpy(m_filename, *argv, strlen(*argv)); | 2730 | memcpy(m_filename, *argv, strlen(*argv)); |
160 | 2731 | ||
161 | 2732 | ||
162 | fprintf(stderr, "m_filename='%s'\n", m_filename); | ||
163 | fprintf(stderr, "m_name='%s'\n", m_name); | ||
164 | |||
165 | |||
166 | /* TODO: do something roughtly like this... */ | ||
167 | #if 0 | ||
168 | |||
169 | if ((f = obj_load(fp)) == NULL) { | 2733 | if ((f = obj_load(fp)) == NULL) { |
170 | perror("Could not load the module\n"); | 2734 | perror("Could not load the module\n"); |
171 | exit(FALSE); | 2735 | exit(FALSE); |
172 | } | 2736 | } |
173 | 2737 | ||
2738 | if (get_modinfo_value(f, "kernel_version") == NULL) | ||
2739 | m_has_modinfo = 0; | ||
2740 | else | ||
2741 | m_has_modinfo = 1; | ||
2742 | |||
2743 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
2744 | /* Version correspondence? */ | ||
2745 | |||
2746 | k_version = get_kernel_version(k_strversion); | ||
2747 | if (m_has_modinfo) { | ||
2748 | m_version = new_get_module_version(f, m_strversion); | ||
2749 | } else { | ||
2750 | m_version = old_get_module_version(f, m_strversion); | ||
2751 | if (m_version == -1) { | ||
2752 | fprintf(stderr, | ||
2753 | "couldn't find the kernel version the module was compiled for\n"); | ||
2754 | goto out; | ||
2755 | } | ||
2756 | } | ||
2757 | |||
2758 | if (strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) { | ||
2759 | if (flag_force_load) { | ||
2760 | fprintf(stderr, "Warning: kernel-module version mismatch\n" | ||
2761 | "\t%s was compiled for kernel version %s\n" | ||
2762 | "\twhile this kernel is version %s\n", | ||
2763 | m_filename, m_strversion, k_strversion); | ||
2764 | } else { | ||
2765 | fprintf(stderr, "kernel-module version mismatch\n" | ||
2766 | "\t%s was compiled for kernel version %s\n" | ||
2767 | "\twhile this kernel is version %s.\n", | ||
2768 | m_filename, m_strversion, k_strversion); | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | ||
2772 | k_crcs = 0; | ||
2773 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
2774 | |||
2775 | k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); | ||
2776 | |||
2777 | if (k_new_syscalls) { | ||
2778 | #ifdef BB_FEATURE_INSMOD_NEW_KERNEL | ||
2779 | if (!new_get_kernel_symbols()) | ||
2780 | goto out; | ||
2781 | k_crcs = new_is_kernel_checksummed(); | ||
2782 | #else | ||
2783 | fprintf(stderr, "Not configured to support new kernels\n"); | ||
2784 | goto out; | ||
2785 | #endif | ||
2786 | } else { | ||
2787 | #ifdef BB_FEATURE_INSMOD_OLD_KERNEL | ||
2788 | if (!old_get_kernel_symbols()) | ||
2789 | goto out; | ||
2790 | k_crcs = old_is_kernel_checksummed(); | ||
2791 | #else | ||
2792 | fprintf(stderr, "Not configured to support old kernels\n"); | ||
2793 | goto out; | ||
2794 | #endif | ||
2795 | } | ||
2796 | |||
2797 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
2798 | if (m_has_modinfo) | ||
2799 | m_crcs = new_is_module_checksummed(f); | ||
2800 | else | ||
2801 | m_crcs = old_is_module_checksummed(f); | ||
2802 | |||
2803 | if (m_crcs != k_crcs) | ||
2804 | obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); | ||
2805 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
2806 | |||
174 | /* Let the module know about the kernel symbols. */ | 2807 | /* Let the module know about the kernel symbols. */ |
175 | add_kernel_symbols(f); | 2808 | add_kernel_symbols(f); |
176 | 2809 | ||
177 | if (!create_this_module(f, m_name)) { | 2810 | /* Allocate common symbols, symbol tables, and string tables. */ |
178 | perror("Could not create the module\n"); | 2811 | |
179 | exit(FALSE); | 2812 | if (k_new_syscalls |
2813 | ? !new_create_this_module(f, m_name) | ||
2814 | : !old_create_mod_use_count(f)) | ||
2815 | { | ||
2816 | goto out; | ||
180 | } | 2817 | } |
181 | 2818 | ||
182 | if (!obj_check_undefineds(f, quiet)) { | 2819 | if (!obj_check_undefineds(f)) { |
183 | perror("Undefined symbols in the module\n"); | 2820 | goto out; |
184 | exit(FALSE); | ||
185 | } | 2821 | } |
186 | obj_allocate_commons(f); | 2822 | obj_allocate_commons(f); |
187 | 2823 | ||
188 | /* Perse the module's arguments */ | 2824 | if (optind < argc) { |
189 | while (argc-- > 0 && *(argv++) != '\0') { | 2825 | if (m_has_modinfo |
190 | if (!process_module_arguments(f, argc - optind, argv + optind)) { | 2826 | ? !new_process_module_arguments(f, argc - optind, argv + optind) |
191 | perror("Undefined symbols in the module\n"); | 2827 | : !old_process_module_arguments(f, argc - optind, argv + optind)) |
192 | exit(FALSE); | 2828 | { |
2829 | goto out; | ||
193 | } | 2830 | } |
194 | } | 2831 | } |
195 | 2832 | ||
2833 | arch_create_got(f); | ||
2834 | hide_special_symbols(f); | ||
2835 | |||
2836 | if (k_new_syscalls) | ||
2837 | new_create_module_ksymtab(f); | ||
2838 | |||
196 | /* Find current size of the module */ | 2839 | /* Find current size of the module */ |
197 | m_size = obj_load_size(f); | 2840 | m_size = obj_load_size(f); |
198 | 2841 | ||
@@ -200,14 +2843,37 @@ extern int insmod_main(int argc, char **argv) | |||
200 | errno = 0; | 2843 | errno = 0; |
201 | m_addr = create_module(m_name, m_size); | 2844 | m_addr = create_module(m_name, m_size); |
202 | switch (errno) { | 2845 | switch (errno) { |
203 | /* yada yada */ | 2846 | case 0: |
2847 | break; | ||
2848 | case EEXIST: | ||
2849 | fprintf(stderr, "A module named %s already exists\n", m_name); | ||
2850 | goto out; | ||
2851 | case ENOMEM: | ||
2852 | fprintf(stderr, | ||
2853 | "Can't allocate kernel memory for module; needed %lu bytes\n", | ||
2854 | m_size); | ||
2855 | goto out; | ||
204 | default: | 2856 | default: |
205 | perror("create_module: %m"); | 2857 | perror("create_module: %m"); |
2858 | goto out; | ||
2859 | } | ||
206 | 2860 | ||
2861 | if (!obj_relocate(f, m_addr)) { | ||
2862 | delete_module(m_name); | ||
2863 | goto out; | ||
207 | } | 2864 | } |
208 | 2865 | ||
209 | #endif | 2866 | if (k_new_syscalls |
2867 | ? !new_init_module(m_name, f, m_size) | ||
2868 | : !old_init_module(m_name, f, m_size)) | ||
2869 | { | ||
2870 | delete_module(m_name); | ||
2871 | goto out; | ||
2872 | } | ||
2873 | |||
2874 | exit_status = TRUE; | ||
210 | 2875 | ||
2876 | out: | ||
211 | fclose(fp); | 2877 | fclose(fp); |
212 | exit(TRUE); | 2878 | exit(exit_status); |
213 | } | 2879 | } |
diff --git a/modutils/insmod.c b/modutils/insmod.c index 9d473ca4a..dfea51832 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c | |||
@@ -3,7 +3,15 @@ | |||
3 | * Mini insmod implementation for busybox | 3 | * Mini insmod implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 1999,2000 by Lineo, inc. | 5 | * Copyright (C) 1999,2000 by Lineo, inc. |
6 | * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> | 6 | * Written by Erik Andersen <andersen@lineo.com> |
7 | * and Ron Alder <alder@lineo.com> | ||
8 | * | ||
9 | * Based almost entirely on the Linux modutils-2.3.11 implementation. | ||
10 | * Copyright 1996, 1997 Linux International. | ||
11 | * New implementation contributed by Richard Henderson <rth@tamu.edu> | ||
12 | * Based on original work by Bjorn Ekwall <bj0rn@blox.se> | ||
13 | * Restructured (and partly rewritten) by: | ||
14 | * Björn Ekwall <bj0rn@blox.se> February 1999 | ||
7 | * | 15 | * |
8 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
@@ -24,25 +32,503 @@ | |||
24 | #include "internal.h" | 32 | #include "internal.h" |
25 | #include <stdlib.h> | 33 | #include <stdlib.h> |
26 | #include <stdio.h> | 34 | #include <stdio.h> |
35 | #include <stddef.h> | ||
27 | #include <errno.h> | 36 | #include <errno.h> |
28 | #include <unistd.h> | 37 | #include <unistd.h> |
29 | #include <dirent.h> | 38 | #include <dirent.h> |
39 | #include <ctype.h> | ||
40 | #include <assert.h> | ||
41 | #include <sys/utsname.h> | ||
30 | #include <sys/syscall.h> | 42 | #include <sys/syscall.h> |
31 | #include <linux/module.h> | 43 | |
44 | //---------------------------------------------------------------------------- | ||
45 | //--------modutils module.h, lines 45-242 | ||
46 | //---------------------------------------------------------------------------- | ||
47 | |||
48 | /* Definitions for the Linux module syscall interface. | ||
49 | Copyright 1996, 1997 Linux International. | ||
50 | |||
51 | Contributed by Richard Henderson <rth@tamu.edu> | ||
52 | |||
53 | This file is part of the Linux modutils. | ||
54 | |||
55 | This program is free software; you can redistribute it and/or modify it | ||
56 | under the terms of the GNU General Public License as published by the | ||
57 | Free Software Foundation; either version 2 of the License, or (at your | ||
58 | option) any later version. | ||
59 | |||
60 | This program is distributed in the hope that it will be useful, but | ||
61 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
62 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
63 | General Public License for more details. | ||
64 | |||
65 | You should have received a copy of the GNU General Public License | ||
66 | along with this program; if not, write to the Free Software Foundation, | ||
67 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
68 | |||
69 | |||
70 | #ifndef MODUTILS_MODULE_H | ||
71 | #define MODUTILS_MODULE_H 1 | ||
72 | |||
73 | #ident "$Id: insmod.c,v 1.8 2000/06/12 23:11:16 andersen Exp $" | ||
74 | |||
75 | /* This file contains the structures used by the 2.0 and 2.1 kernels. | ||
76 | We do not use the kernel headers directly because we do not wish | ||
77 | to be dependant on a particular kernel version to compile insmod. */ | ||
78 | |||
79 | |||
80 | /*======================================================================*/ | ||
81 | /* The structures used by Linux 2.0. */ | ||
82 | |||
83 | /* The symbol format used by get_kernel_syms(2). */ | ||
84 | struct old_kernel_sym | ||
85 | { | ||
86 | unsigned long value; | ||
87 | char name[60]; | ||
88 | }; | ||
89 | |||
90 | struct old_module_ref | ||
91 | { | ||
92 | unsigned long module; /* kernel addresses */ | ||
93 | unsigned long next; | ||
94 | }; | ||
95 | |||
96 | struct old_module_symbol | ||
97 | { | ||
98 | unsigned long addr; | ||
99 | unsigned long name; | ||
100 | }; | ||
101 | |||
102 | struct old_symbol_table | ||
103 | { | ||
104 | int size; /* total, including string table!!! */ | ||
105 | int n_symbols; | ||
106 | int n_refs; | ||
107 | struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */ | ||
108 | struct old_module_ref ref[0]; /* actual size defined by n_refs */ | ||
109 | }; | ||
110 | |||
111 | struct old_mod_routines | ||
112 | { | ||
113 | unsigned long init; | ||
114 | unsigned long cleanup; | ||
115 | }; | ||
116 | |||
117 | struct old_module | ||
118 | { | ||
119 | unsigned long next; | ||
120 | unsigned long ref; /* the list of modules that refer to me */ | ||
121 | unsigned long symtab; | ||
122 | unsigned long name; | ||
123 | int size; /* size of module in pages */ | ||
124 | unsigned long addr; /* address of module */ | ||
125 | int state; | ||
126 | unsigned long cleanup; /* cleanup routine */ | ||
127 | }; | ||
128 | |||
129 | /* Sent to init_module(2) or'ed into the code size parameter. */ | ||
130 | #define OLD_MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */ | ||
131 | |||
132 | int get_kernel_syms(struct old_kernel_sym *); | ||
133 | int old_sys_init_module(const char *name, char *code, unsigned codesize, | ||
134 | struct old_mod_routines *, struct old_symbol_table *); | ||
135 | |||
136 | /*======================================================================*/ | ||
137 | /* For sizeof() which are related to the module platform and not to the | ||
138 | environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ | ||
139 | |||
140 | #define tgt_sizeof_char sizeof(char) | ||
141 | #define tgt_sizeof_short sizeof(short) | ||
142 | #define tgt_sizeof_int sizeof(int) | ||
143 | #define tgt_sizeof_long sizeof(long) | ||
144 | #define tgt_sizeof_char_p sizeof(char *) | ||
145 | #define tgt_sizeof_void_p sizeof(void *) | ||
146 | #define tgt_long long | ||
147 | |||
148 | #if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) | ||
149 | #undef tgt_sizeof_long | ||
150 | #undef tgt_sizeof_char_p | ||
151 | #undef tgt_sizeof_void_p | ||
152 | #undef tgt_long | ||
153 | #define tgt_sizeof_long 8 | ||
154 | #define tgt_sizeof_char_p 8 | ||
155 | #define tgt_sizeof_void_p 8 | ||
156 | #define tgt_long long long | ||
157 | #endif | ||
158 | |||
159 | /*======================================================================*/ | ||
160 | /* The structures used in Linux 2.1. */ | ||
161 | |||
162 | /* Note: new_module_symbol does not use tgt_long intentionally */ | ||
163 | struct new_module_symbol | ||
164 | { | ||
165 | unsigned long value; | ||
166 | unsigned long name; | ||
167 | }; | ||
168 | |||
169 | struct new_module_persist; | ||
170 | |||
171 | struct new_module_ref | ||
172 | { | ||
173 | unsigned tgt_long dep; /* kernel addresses */ | ||
174 | unsigned tgt_long ref; | ||
175 | unsigned tgt_long next_ref; | ||
176 | }; | ||
177 | |||
178 | struct new_module | ||
179 | { | ||
180 | unsigned tgt_long size_of_struct; /* == sizeof(module) */ | ||
181 | unsigned tgt_long next; | ||
182 | unsigned tgt_long name; | ||
183 | unsigned tgt_long size; | ||
184 | |||
185 | tgt_long usecount; | ||
186 | unsigned tgt_long flags; /* AUTOCLEAN et al */ | ||
187 | |||
188 | unsigned nsyms; | ||
189 | unsigned ndeps; | ||
190 | |||
191 | unsigned tgt_long syms; | ||
192 | unsigned tgt_long deps; | ||
193 | unsigned tgt_long refs; | ||
194 | unsigned tgt_long init; | ||
195 | unsigned tgt_long cleanup; | ||
196 | unsigned tgt_long ex_table_start; | ||
197 | unsigned tgt_long ex_table_end; | ||
198 | #ifdef __alpha__ | ||
199 | unsigned tgt_long gp; | ||
200 | #endif | ||
201 | /* Everything after here is extension. */ | ||
202 | unsigned tgt_long persist_start; | ||
203 | unsigned tgt_long persist_end; | ||
204 | unsigned tgt_long can_unload; | ||
205 | unsigned tgt_long runsize; | ||
206 | }; | ||
207 | |||
208 | struct new_module_info | ||
209 | { | ||
210 | unsigned long addr; | ||
211 | unsigned long size; | ||
212 | unsigned long flags; | ||
213 | long usecount; | ||
214 | }; | ||
215 | |||
216 | /* Bits of module.flags. */ | ||
217 | #define NEW_MOD_RUNNING 1 | ||
218 | #define NEW_MOD_DELETED 2 | ||
219 | #define NEW_MOD_AUTOCLEAN 4 | ||
220 | #define NEW_MOD_VISITED 8 | ||
221 | #define NEW_MOD_USED_ONCE 16 | ||
222 | |||
223 | int new_sys_init_module(const char *name, const struct new_module *); | ||
224 | int query_module(const char *name, int which, void *buf, size_t bufsize, | ||
225 | size_t *ret); | ||
226 | |||
227 | /* Values for query_module's which. */ | ||
228 | |||
229 | #define QM_MODULES 1 | ||
230 | #define QM_DEPS 2 | ||
231 | #define QM_REFS 3 | ||
232 | #define QM_SYMBOLS 4 | ||
233 | #define QM_INFO 5 | ||
234 | |||
235 | /*======================================================================*/ | ||
236 | /* The system calls unchanged between 2.0 and 2.1. */ | ||
237 | |||
238 | unsigned long create_module(const char *, size_t); | ||
239 | int delete_module(const char *); | ||
240 | |||
241 | |||
242 | #endif /* module.h */ | ||
243 | |||
244 | //---------------------------------------------------------------------------- | ||
245 | //--------end of modutils module.h | ||
246 | //---------------------------------------------------------------------------- | ||
247 | |||
248 | |||
249 | |||
250 | //---------------------------------------------------------------------------- | ||
251 | //--------modutils obj.h, lines 253-462 | ||
252 | //---------------------------------------------------------------------------- | ||
253 | |||
254 | /* Elf object file loading and relocation routines. | ||
255 | Copyright 1996, 1997 Linux International. | ||
256 | |||
257 | Contributed by Richard Henderson <rth@tamu.edu> | ||
258 | |||
259 | This file is part of the Linux modutils. | ||
260 | |||
261 | This program is free software; you can redistribute it and/or modify it | ||
262 | under the terms of the GNU General Public License as published by the | ||
263 | Free Software Foundation; either version 2 of the License, or (at your | ||
264 | option) any later version. | ||
265 | |||
266 | This program is distributed in the hope that it will be useful, but | ||
267 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
268 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
269 | General Public License for more details. | ||
270 | |||
271 | You should have received a copy of the GNU General Public License | ||
272 | along with this program; if not, write to the Free Software Foundation, | ||
273 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
274 | |||
275 | |||
276 | #ifndef MODUTILS_OBJ_H | ||
277 | #define MODUTILS_OBJ_H 1 | ||
278 | |||
279 | #ident "$Id: insmod.c,v 1.8 2000/06/12 23:11:16 andersen Exp $" | ||
280 | |||
281 | /* The relocatable object is manipulated using elfin types. */ | ||
282 | |||
283 | #include <stdio.h> | ||
284 | #include <elf.h> | ||
285 | |||
286 | |||
287 | /* Machine-specific elf macros for i386 et al. */ | ||
288 | |||
289 | #define ELFCLASSM ELFCLASS32 | ||
290 | #define ELFDATAM ELFDATA2LSB | ||
291 | |||
292 | #define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) | ||
293 | |||
294 | #define SHT_RELM SHT_REL | ||
295 | #define Elf32_RelM Elf32_Rel | ||
296 | |||
297 | |||
298 | #ifndef ElfW | ||
299 | # if ELFCLASSM == ELFCLASS32 | ||
300 | # define ElfW(x) Elf32_ ## x | ||
301 | # define ELFW(x) ELF32_ ## x | ||
302 | # else | ||
303 | # define ElfW(x) Elf64_ ## x | ||
304 | # define ELFW(x) ELF64_ ## x | ||
305 | # endif | ||
306 | #endif | ||
307 | |||
308 | /* For some reason this is missing from libc5. */ | ||
309 | #ifndef ELF32_ST_INFO | ||
310 | # define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) | ||
311 | #endif | ||
312 | |||
313 | #ifndef ELF64_ST_INFO | ||
314 | # define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) | ||
315 | #endif | ||
316 | |||
317 | struct obj_string_patch; | ||
318 | struct obj_symbol_patch; | ||
319 | |||
320 | struct obj_section | ||
321 | { | ||
322 | ElfW(Shdr) header; | ||
323 | const char *name; | ||
324 | char *contents; | ||
325 | struct obj_section *load_next; | ||
326 | int idx; | ||
327 | }; | ||
328 | |||
329 | struct obj_symbol | ||
330 | { | ||
331 | struct obj_symbol *next; /* hash table link */ | ||
332 | const char *name; | ||
333 | unsigned long value; | ||
334 | unsigned long size; | ||
335 | int secidx; /* the defining section index/module */ | ||
336 | int info; | ||
337 | int ksymidx; /* for export to the kernel symtab */ | ||
338 | int referenced; /* actually used in the link */ | ||
339 | }; | ||
340 | |||
341 | /* Hardcode the hash table size. We shouldn't be needing so many | ||
342 | symbols that we begin to degrade performance, and we get a big win | ||
343 | by giving the compiler a constant divisor. */ | ||
344 | |||
345 | #define HASH_BUCKETS 521 | ||
346 | |||
347 | struct obj_file | ||
348 | { | ||
349 | ElfW(Ehdr) header; | ||
350 | ElfW(Addr) baseaddr; | ||
351 | struct obj_section **sections; | ||
352 | struct obj_section *load_order; | ||
353 | struct obj_section **load_order_search_start; | ||
354 | struct obj_string_patch *string_patches; | ||
355 | struct obj_symbol_patch *symbol_patches; | ||
356 | int (*symbol_cmp)(const char *, const char *); | ||
357 | unsigned long (*symbol_hash)(const char *); | ||
358 | unsigned long local_symtab_size; | ||
359 | struct obj_symbol **local_symtab; | ||
360 | struct obj_symbol *symtab[HASH_BUCKETS]; | ||
361 | }; | ||
362 | |||
363 | enum obj_reloc | ||
364 | { | ||
365 | obj_reloc_ok, | ||
366 | obj_reloc_overflow, | ||
367 | obj_reloc_dangerous, | ||
368 | obj_reloc_unhandled | ||
369 | }; | ||
370 | |||
371 | struct obj_string_patch | ||
372 | { | ||
373 | struct obj_string_patch *next; | ||
374 | int reloc_secidx; | ||
375 | ElfW(Addr) reloc_offset; | ||
376 | ElfW(Addr) string_offset; | ||
377 | }; | ||
378 | |||
379 | struct obj_symbol_patch | ||
380 | { | ||
381 | struct obj_symbol_patch *next; | ||
382 | int reloc_secidx; | ||
383 | ElfW(Addr) reloc_offset; | ||
384 | struct obj_symbol *sym; | ||
385 | }; | ||
386 | |||
387 | |||
388 | /* Generic object manipulation routines. */ | ||
389 | |||
390 | unsigned long obj_elf_hash(const char *); | ||
391 | |||
392 | unsigned long obj_elf_hash_n(const char *, unsigned long len); | ||
393 | |||
394 | struct obj_symbol *obj_add_symbol (struct obj_file *f, const char *name, | ||
395 | unsigned long symidx, int info, int secidx, | ||
396 | ElfW(Addr) value, unsigned long size); | ||
397 | |||
398 | struct obj_symbol *obj_find_symbol (struct obj_file *f, | ||
399 | const char *name); | ||
400 | |||
401 | ElfW(Addr) obj_symbol_final_value(struct obj_file *f, | ||
402 | struct obj_symbol *sym); | ||
403 | |||
404 | void obj_set_symbol_compare(struct obj_file *f, | ||
405 | int (*cmp)(const char *, const char *), | ||
406 | unsigned long (*hash)(const char *)); | ||
407 | |||
408 | struct obj_section *obj_find_section (struct obj_file *f, | ||
409 | const char *name); | ||
410 | |||
411 | void obj_insert_section_load_order (struct obj_file *f, | ||
412 | struct obj_section *sec); | ||
413 | |||
414 | struct obj_section *obj_create_alloced_section (struct obj_file *f, | ||
415 | const char *name, | ||
416 | unsigned long align, | ||
417 | unsigned long size); | ||
418 | |||
419 | struct obj_section *obj_create_alloced_section_first (struct obj_file *f, | ||
420 | const char *name, | ||
421 | unsigned long align, | ||
422 | unsigned long size); | ||
423 | |||
424 | void *obj_extend_section (struct obj_section *sec, unsigned long more); | ||
425 | |||
426 | int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
427 | const char *string); | ||
428 | |||
429 | int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
430 | struct obj_symbol *sym); | ||
431 | |||
432 | int obj_check_undefineds(struct obj_file *f); | ||
433 | |||
434 | void obj_allocate_commons(struct obj_file *f); | ||
435 | |||
436 | unsigned long obj_load_size (struct obj_file *f); | ||
437 | |||
438 | int obj_relocate (struct obj_file *f, ElfW(Addr) base); | ||
439 | |||
440 | struct obj_file *obj_load(FILE *f); | ||
441 | |||
442 | int obj_create_image (struct obj_file *f, char *image); | ||
443 | |||
444 | /* Architecture specific manipulation routines. */ | ||
445 | |||
446 | struct obj_file *arch_new_file (void); | ||
447 | |||
448 | struct obj_section *arch_new_section (void); | ||
449 | |||
450 | struct obj_symbol *arch_new_symbol (void); | ||
451 | |||
452 | enum obj_reloc arch_apply_relocation (struct obj_file *f, | ||
453 | struct obj_section *targsec, | ||
454 | struct obj_section *symsec, | ||
455 | struct obj_symbol *sym, | ||
456 | ElfW(RelM) *rel, ElfW(Addr) value); | ||
457 | |||
458 | int arch_create_got (struct obj_file *f); | ||
459 | |||
460 | struct new_module; | ||
461 | int arch_init_module (struct obj_file *f, struct new_module *); | ||
462 | |||
463 | #endif /* obj.h */ | ||
464 | //---------------------------------------------------------------------------- | ||
465 | //--------end of modutils obj.h | ||
466 | //---------------------------------------------------------------------------- | ||
467 | |||
468 | |||
469 | |||
470 | |||
32 | 471 | ||
33 | #define _PATH_MODULES "/lib/modules" | 472 | #define _PATH_MODULES "/lib/modules" |
473 | #define STRVERSIONLEN 32 | ||
474 | |||
475 | #if !defined(BB_FEATURE_INSMOD_NEW_KERNEL) && !defined(BB_FEATURE_INSMOD_OLD_KERNEL) | ||
476 | #error "Must have ether BB_FEATURE_INSMOD_NEW_KERNEL or BB_FEATURE_INSMOD_OLD_KERNEL defined" | ||
477 | #endif | ||
478 | |||
479 | /*======================================================================*/ | ||
480 | |||
481 | int flag_force_load = 0; | ||
482 | int flag_autoclean = 0; | ||
483 | int flag_verbose = 0; | ||
484 | int flag_export = 1; | ||
485 | |||
486 | |||
487 | /*======================================================================*/ | ||
488 | |||
489 | struct i386_got_entry { | ||
490 | int offset; | ||
491 | unsigned offset_done:1; | ||
492 | unsigned reloc_done:1; | ||
493 | }; | ||
494 | |||
495 | struct i386_file { | ||
496 | struct obj_file root; | ||
497 | struct obj_section *got; | ||
498 | }; | ||
499 | |||
500 | struct i386_symbol { | ||
501 | struct obj_symbol root; | ||
502 | struct i386_got_entry gotent; | ||
503 | }; | ||
504 | |||
505 | |||
506 | |||
507 | struct external_module { | ||
508 | const char *name; | ||
509 | ElfW(Addr) addr; | ||
510 | int used; | ||
511 | size_t nsyms; | ||
512 | struct new_module_symbol *syms; | ||
513 | }; | ||
514 | |||
515 | struct new_module_symbol *ksyms; | ||
516 | size_t nksyms; | ||
517 | |||
518 | struct external_module *ext_modules; | ||
519 | int n_ext_modules; | ||
520 | int n_ext_modules_used; | ||
34 | 521 | ||
35 | #warning "Danger Will Robinson, Danger!!!" | ||
36 | #warning " " | ||
37 | #warning "insmod is still under construction. Don't use it." | ||
38 | #warning " " | ||
39 | #warning " You have been warned!" | ||
40 | #warning " " | ||
41 | 522 | ||
42 | 523 | ||
43 | /* Some firendly syscalls to cheer everyone's day... */ | 524 | /* Some firendly syscalls to cheer everyone's day... */ |
44 | _syscall2(int, init_module, const char *, name, | 525 | #define __NR_new_sys_init_module __NR_init_module |
45 | const struct module *, info) | 526 | _syscall2(int, new_sys_init_module, const char *, name, |
527 | const struct new_module *, info) | ||
528 | #define __NR_old_sys_init_module __NR_init_module | ||
529 | _syscall5(int, old_sys_init_module, const char *, name, char *, code, | ||
530 | unsigned, codesize, struct old_mod_routines *, routines, | ||
531 | struct old_symbol_table *, symtab) | ||
46 | #ifndef BB_RMMOD | 532 | #ifndef BB_RMMOD |
47 | _syscall1(int, delete_module, const char *, name) | 533 | _syscall1(int, delete_module, const char *, name) |
48 | #else | 534 | #else |
@@ -74,16 +560,32 @@ static const char insmod_usage[] = | |||
74 | #ifndef BB_FEATURE_TRIVIAL_HELP | 560 | #ifndef BB_FEATURE_TRIVIAL_HELP |
75 | "\nLoads the specified kernel modules into the kernel.\n\n" | 561 | "\nLoads the specified kernel modules into the kernel.\n\n" |
76 | "Options:\n" | 562 | "Options:\n" |
77 | |||
78 | "\t-f\tForce module to load into the wrong kernel version.\n" | 563 | "\t-f\tForce module to load into the wrong kernel version.\n" |
79 | "\t-k\tMake module autoclean-able.\n" | 564 | "\t-k\tMake module autoclean-able.\n" |
565 | "\t-v\tverbose output\n" "\t-x\tdo not export externs\n" | ||
80 | #endif | 566 | #endif |
81 | ; | 567 | ; |
568 | |||
569 | /*======================================================================*/ | ||
570 | |||
571 | void *xrealloc(void *old, size_t size) | ||
572 | { | ||
573 | void *ptr = realloc(old, size); | ||
574 | if (!ptr) { | ||
575 | perror("Out of memory"); | ||
576 | exit(1); | ||
577 | } | ||
578 | return ptr; | ||
579 | } | ||
82 | 580 | ||
83 | 581 | ||
84 | static int findNamedModule(const char *fileName, struct stat *statbuf) | 582 | static int findNamedModule(const char *fileName, struct stat *statbuf, |
583 | void *userDate) | ||
85 | { | 584 | { |
86 | if (m_fullName[0] == '\0') | 585 | char *fullName = (char *) userDate; |
586 | |||
587 | |||
588 | if (fullName[0] == '\0') | ||
87 | return (FALSE); | 589 | return (FALSE); |
88 | else { | 590 | else { |
89 | char *tmp = strrchr(fileName, '/'); | 591 | char *tmp = strrchr(fileName, '/'); |
@@ -92,7 +594,7 @@ static int findNamedModule(const char *fileName, struct stat *statbuf) | |||
92 | tmp = (char *) fileName; | 594 | tmp = (char *) fileName; |
93 | else | 595 | else |
94 | tmp++; | 596 | tmp++; |
95 | if (check_wildcard_match(tmp, m_fullName) == TRUE) { | 597 | if (check_wildcard_match(tmp, fullName) == TRUE) { |
96 | /* Stop searching if we find a match */ | 598 | /* Stop searching if we find a match */ |
97 | memcpy(m_filename, fileName, strlen(fileName)); | 599 | memcpy(m_filename, fileName, strlen(fileName)); |
98 | return (FALSE); | 600 | return (FALSE); |
@@ -102,12 +604,2070 @@ static int findNamedModule(const char *fileName, struct stat *statbuf) | |||
102 | } | 604 | } |
103 | 605 | ||
104 | 606 | ||
105 | extern int insmod_main(int argc, char **argv) | 607 | /*======================================================================*/ |
608 | |||
609 | struct obj_file *arch_new_file(void) | ||
106 | { | 610 | { |
611 | struct i386_file *f; | ||
612 | f = xmalloc(sizeof(*f)); | ||
613 | f->got = NULL; | ||
614 | return &f->root; | ||
615 | } | ||
616 | |||
617 | struct obj_section *arch_new_section(void) | ||
618 | { | ||
619 | return xmalloc(sizeof(struct obj_section)); | ||
620 | } | ||
621 | |||
622 | struct obj_symbol *arch_new_symbol(void) | ||
623 | { | ||
624 | struct i386_symbol *sym; | ||
625 | sym = xmalloc(sizeof(*sym)); | ||
626 | memset(&sym->gotent, 0, sizeof(sym->gotent)); | ||
627 | return &sym->root; | ||
628 | } | ||
629 | enum obj_reloc | ||
630 | arch_apply_relocation(struct obj_file *f, | ||
631 | struct obj_section *targsec, | ||
632 | struct obj_section *symsec, | ||
633 | struct obj_symbol *sym, | ||
634 | Elf32_Rel * rel, Elf32_Addr v) | ||
635 | { | ||
636 | struct i386_file *ifile = (struct i386_file *) f; | ||
637 | struct i386_symbol *isym = (struct i386_symbol *) sym; | ||
638 | |||
639 | Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset); | ||
640 | Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset; | ||
641 | Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0; | ||
642 | |||
643 | enum obj_reloc ret = obj_reloc_ok; | ||
644 | |||
645 | switch (ELF32_R_TYPE(rel->r_info)) { | ||
646 | case R_386_NONE: | ||
647 | break; | ||
648 | |||
649 | case R_386_32: | ||
650 | *loc += v; | ||
651 | break; | ||
652 | |||
653 | case R_386_PLT32: | ||
654 | case R_386_PC32: | ||
655 | *loc += v - dot; | ||
656 | break; | ||
657 | |||
658 | case R_386_GLOB_DAT: | ||
659 | case R_386_JMP_SLOT: | ||
660 | *loc = v; | ||
661 | break; | ||
662 | |||
663 | case R_386_RELATIVE: | ||
664 | *loc += f->baseaddr; | ||
665 | break; | ||
666 | |||
667 | case R_386_GOTPC: | ||
668 | assert(got != 0); | ||
669 | *loc += got - dot; | ||
670 | break; | ||
671 | |||
672 | case R_386_GOT32: | ||
673 | assert(isym != NULL); | ||
674 | if (!isym->gotent.reloc_done) { | ||
675 | isym->gotent.reloc_done = 1; | ||
676 | *(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) = | ||
677 | v; | ||
678 | } | ||
679 | *loc += isym->gotent.offset; | ||
680 | break; | ||
681 | |||
682 | case R_386_GOTOFF: | ||
683 | assert(got != 0); | ||
684 | *loc += v - got; | ||
685 | break; | ||
686 | |||
687 | default: | ||
688 | ret = obj_reloc_unhandled; | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | return ret; | ||
693 | } | ||
694 | |||
695 | int arch_create_got(struct obj_file *f) | ||
696 | { | ||
697 | struct i386_file *ifile = (struct i386_file *) f; | ||
698 | int i, n, offset = 0, gotneeded = 0; | ||
699 | |||
700 | n = ifile->root.header.e_shnum; | ||
701 | for (i = 0; i < n; ++i) { | ||
702 | struct obj_section *relsec, *symsec, *strsec; | ||
703 | Elf32_Rel *rel, *relend; | ||
704 | Elf32_Sym *symtab; | ||
705 | const char *strtab; | ||
706 | |||
707 | relsec = ifile->root.sections[i]; | ||
708 | if (relsec->header.sh_type != SHT_REL) | ||
709 | continue; | ||
710 | |||
711 | symsec = ifile->root.sections[relsec->header.sh_link]; | ||
712 | strsec = ifile->root.sections[symsec->header.sh_link]; | ||
713 | |||
714 | rel = (Elf32_Rel *) relsec->contents; | ||
715 | relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel)); | ||
716 | symtab = (Elf32_Sym *) symsec->contents; | ||
717 | strtab = (const char *) strsec->contents; | ||
718 | |||
719 | for (; rel < relend; ++rel) { | ||
720 | Elf32_Sym *extsym; | ||
721 | struct i386_symbol *intsym; | ||
722 | const char *name; | ||
723 | |||
724 | switch (ELF32_R_TYPE(rel->r_info)) { | ||
725 | case R_386_GOTPC: | ||
726 | case R_386_GOTOFF: | ||
727 | gotneeded = 1; | ||
728 | default: | ||
729 | continue; | ||
730 | |||
731 | case R_386_GOT32: | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | extsym = &symtab[ELF32_R_SYM(rel->r_info)]; | ||
736 | if (extsym->st_name) | ||
737 | name = strtab + extsym->st_name; | ||
738 | else | ||
739 | name = f->sections[extsym->st_shndx]->name; | ||
740 | intsym = | ||
741 | (struct i386_symbol *) obj_find_symbol(&ifile->root, name); | ||
742 | |||
743 | if (!intsym->gotent.offset_done) { | ||
744 | intsym->gotent.offset_done = 1; | ||
745 | intsym->gotent.offset = offset; | ||
746 | offset += 4; | ||
747 | } | ||
748 | } | ||
749 | } | ||
750 | |||
751 | if (offset > 0 || gotneeded) | ||
752 | ifile->got = | ||
753 | obj_create_alloced_section(&ifile->root, ".got", 4, offset); | ||
754 | |||
755 | return 1; | ||
756 | } | ||
757 | |||
758 | int arch_init_module(struct obj_file *f, struct new_module *mod) | ||
759 | { | ||
760 | return 1; | ||
761 | } | ||
762 | |||
763 | |||
764 | /*======================================================================*/ | ||
765 | |||
766 | /* Standard ELF hash function. */ | ||
767 | inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) | ||
768 | { | ||
769 | unsigned long h = 0; | ||
770 | unsigned long g; | ||
771 | unsigned char ch; | ||
772 | |||
773 | while (n > 0) { | ||
774 | ch = *name++; | ||
775 | h = (h << 4) + ch; | ||
776 | if ((g = (h & 0xf0000000)) != 0) { | ||
777 | h ^= g >> 24; | ||
778 | h &= ~g; | ||
779 | } | ||
780 | n--; | ||
781 | } | ||
782 | return h; | ||
783 | } | ||
784 | |||
785 | unsigned long obj_elf_hash(const char *name) | ||
786 | { | ||
787 | return obj_elf_hash_n(name, strlen(name)); | ||
788 | } | ||
789 | |||
790 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
791 | /* Get the kernel version in the canonical integer form. */ | ||
792 | |||
793 | static int get_kernel_version(char str[STRVERSIONLEN]) | ||
794 | { | ||
795 | struct utsname uts_info; | ||
796 | char *p, *q; | ||
797 | int a, b, c; | ||
798 | |||
799 | if (uname(&uts_info) < 0) | ||
800 | return -1; | ||
801 | strncpy(str, uts_info.release, STRVERSIONLEN); | ||
802 | p = uts_info.release; | ||
803 | |||
804 | a = strtoul(p, &p, 10); | ||
805 | if (*p != '.') | ||
806 | return -1; | ||
807 | b = strtoul(p + 1, &p, 10); | ||
808 | if (*p != '.') | ||
809 | return -1; | ||
810 | c = strtoul(p + 1, &q, 10); | ||
811 | if (p + 1 == q) | ||
812 | return -1; | ||
813 | |||
814 | return a << 16 | b << 8 | c; | ||
815 | } | ||
816 | |||
817 | /* String comparison for non-co-versioned kernel and module. */ | ||
818 | |||
819 | static int ncv_strcmp(const char *a, const char *b) | ||
820 | { | ||
821 | size_t alen = strlen(a), blen = strlen(b); | ||
822 | |||
823 | if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') | ||
824 | return strncmp(a, b, alen); | ||
825 | else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') | ||
826 | return strncmp(a, b, blen); | ||
827 | else | ||
828 | return strcmp(a, b); | ||
829 | } | ||
830 | |||
831 | /* String hashing for non-co-versioned kernel and module. Here | ||
832 | we are simply forced to drop the crc from the hash. */ | ||
833 | |||
834 | static unsigned long ncv_symbol_hash(const char *str) | ||
835 | { | ||
836 | size_t len = strlen(str); | ||
837 | if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') | ||
838 | len -= 10; | ||
839 | return obj_elf_hash_n(str, len); | ||
840 | } | ||
841 | |||
842 | void | ||
843 | obj_set_symbol_compare(struct obj_file *f, | ||
844 | int (*cmp) (const char *, const char *), | ||
845 | unsigned long (*hash) (const char *)) | ||
846 | { | ||
847 | if (cmp) | ||
848 | f->symbol_cmp = cmp; | ||
849 | if (hash) { | ||
850 | struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; | ||
851 | int i; | ||
852 | |||
853 | f->symbol_hash = hash; | ||
854 | |||
855 | memcpy(tmptab, f->symtab, sizeof(tmptab)); | ||
856 | memset(f->symtab, 0, sizeof(f->symtab)); | ||
857 | |||
858 | for (i = 0; i < HASH_BUCKETS; ++i) | ||
859 | for (sym = tmptab[i]; sym; sym = next) { | ||
860 | unsigned long h = hash(sym->name) % HASH_BUCKETS; | ||
861 | next = sym->next; | ||
862 | sym->next = f->symtab[h]; | ||
863 | f->symtab[h] = sym; | ||
864 | } | ||
865 | } | ||
866 | } | ||
867 | |||
868 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
869 | |||
870 | |||
871 | struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name, | ||
872 | unsigned long symidx, int info, | ||
873 | int secidx, ElfW(Addr) value, | ||
874 | unsigned long size) | ||
875 | { | ||
876 | struct obj_symbol *sym; | ||
877 | unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; | ||
878 | int n_type = ELFW(ST_TYPE) (info); | ||
879 | int n_binding = ELFW(ST_BIND) (info); | ||
880 | |||
881 | for (sym = f->symtab[hash]; sym; sym = sym->next) | ||
882 | if (f->symbol_cmp(sym->name, name) == 0) { | ||
883 | int o_secidx = sym->secidx; | ||
884 | int o_info = sym->info; | ||
885 | int o_type = ELFW(ST_TYPE) (o_info); | ||
886 | int o_binding = ELFW(ST_BIND) (o_info); | ||
887 | |||
888 | /* A redefinition! Is it legal? */ | ||
889 | |||
890 | if (secidx == SHN_UNDEF) | ||
891 | return sym; | ||
892 | else if (o_secidx == SHN_UNDEF) | ||
893 | goto found; | ||
894 | else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { | ||
895 | /* Cope with local and global symbols of the same name | ||
896 | in the same object file, as might have been created | ||
897 | by ld -r. The only reason locals are now seen at this | ||
898 | level at all is so that we can do semi-sensible things | ||
899 | with parameters. */ | ||
900 | |||
901 | struct obj_symbol *nsym, **p; | ||
902 | |||
903 | nsym = arch_new_symbol(); | ||
904 | nsym->next = sym->next; | ||
905 | nsym->ksymidx = -1; | ||
906 | |||
907 | /* Excise the old (local) symbol from the hash chain. */ | ||
908 | for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) | ||
909 | continue; | ||
910 | *p = sym = nsym; | ||
911 | goto found; | ||
912 | } else if (n_binding == STB_LOCAL) { | ||
913 | /* Another symbol of the same name has already been defined. | ||
914 | Just add this to the local table. */ | ||
915 | sym = arch_new_symbol(); | ||
916 | sym->next = NULL; | ||
917 | sym->ksymidx = -1; | ||
918 | f->local_symtab[symidx] = sym; | ||
919 | goto found; | ||
920 | } else if (n_binding == STB_WEAK) | ||
921 | return sym; | ||
922 | else if (o_binding == STB_WEAK) | ||
923 | goto found; | ||
924 | /* Don't unify COMMON symbols with object types the programmer | ||
925 | doesn't expect. */ | ||
926 | else if (secidx == SHN_COMMON | ||
927 | && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) | ||
928 | return sym; | ||
929 | else if (o_secidx == SHN_COMMON | ||
930 | && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) | ||
931 | goto found; | ||
932 | else { | ||
933 | /* Don't report an error if the symbol is coming from | ||
934 | the kernel or some external module. */ | ||
935 | if (secidx <= SHN_HIRESERVE) | ||
936 | fprintf(stderr, "%s multiply defined\n", name); | ||
937 | return sym; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | /* Completely new symbol. */ | ||
942 | sym = arch_new_symbol(); | ||
943 | sym->next = f->symtab[hash]; | ||
944 | f->symtab[hash] = sym; | ||
945 | sym->ksymidx = -1; | ||
946 | |||
947 | if (ELFW(ST_BIND) (info) == STB_LOCAL) | ||
948 | f->local_symtab[symidx] = sym; | ||
949 | |||
950 | found: | ||
951 | sym->name = name; | ||
952 | sym->value = value; | ||
953 | sym->size = size; | ||
954 | sym->secidx = secidx; | ||
955 | sym->info = info; | ||
956 | |||
957 | return sym; | ||
958 | } | ||
959 | |||
960 | struct obj_symbol *obj_find_symbol(struct obj_file *f, const char *name) | ||
961 | { | ||
962 | struct obj_symbol *sym; | ||
963 | unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; | ||
964 | |||
965 | for (sym = f->symtab[hash]; sym; sym = sym->next) | ||
966 | if (f->symbol_cmp(sym->name, name) == 0) | ||
967 | return sym; | ||
968 | |||
969 | return NULL; | ||
970 | } | ||
971 | |||
972 | ElfW(Addr) | ||
973 | obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) | ||
974 | { | ||
975 | if (sym) { | ||
976 | if (sym->secidx >= SHN_LORESERVE) | ||
977 | return sym->value; | ||
978 | |||
979 | return sym->value + f->sections[sym->secidx]->header.sh_addr; | ||
980 | } else { | ||
981 | /* As a special case, a NULL sym has value zero. */ | ||
982 | return 0; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | struct obj_section *obj_find_section(struct obj_file *f, const char *name) | ||
987 | { | ||
988 | int i, n = f->header.e_shnum; | ||
989 | |||
990 | for (i = 0; i < n; ++i) | ||
991 | if (strcmp(f->sections[i]->name, name) == 0) | ||
992 | return f->sections[i]; | ||
993 | |||
994 | return NULL; | ||
995 | } | ||
996 | |||
997 | static int obj_load_order_prio(struct obj_section *a) | ||
998 | { | ||
999 | unsigned long af, ac; | ||
1000 | |||
1001 | af = a->header.sh_flags; | ||
1002 | |||
1003 | ac = 0; | ||
1004 | if (a->name[0] != '.' || strlen(a->name) != 10 || | ||
1005 | strcmp(a->name + 5, ".init")) | ||
1006 | ac |= 32; | ||
1007 | if (af & SHF_ALLOC) | ||
1008 | ac |= 16; | ||
1009 | if (!(af & SHF_WRITE)) | ||
1010 | ac |= 8; | ||
1011 | if (af & SHF_EXECINSTR) | ||
1012 | ac |= 4; | ||
1013 | if (a->header.sh_type != SHT_NOBITS) | ||
1014 | ac |= 2; | ||
1015 | |||
1016 | return ac; | ||
1017 | } | ||
1018 | |||
1019 | void | ||
1020 | obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) | ||
1021 | { | ||
1022 | struct obj_section **p; | ||
1023 | int prio = obj_load_order_prio(sec); | ||
1024 | for (p = f->load_order_search_start; *p; p = &(*p)->load_next) | ||
1025 | if (obj_load_order_prio(*p) < prio) | ||
1026 | break; | ||
1027 | sec->load_next = *p; | ||
1028 | *p = sec; | ||
1029 | } | ||
1030 | |||
1031 | struct obj_section *obj_create_alloced_section(struct obj_file *f, | ||
1032 | const char *name, | ||
1033 | unsigned long align, | ||
1034 | unsigned long size) | ||
1035 | { | ||
1036 | int newidx = f->header.e_shnum++; | ||
1037 | struct obj_section *sec; | ||
1038 | |||
1039 | f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); | ||
1040 | f->sections[newidx] = sec = arch_new_section(); | ||
1041 | |||
1042 | memset(sec, 0, sizeof(*sec)); | ||
1043 | sec->header.sh_type = SHT_PROGBITS; | ||
1044 | sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; | ||
1045 | sec->header.sh_size = size; | ||
1046 | sec->header.sh_addralign = align; | ||
1047 | sec->name = name; | ||
1048 | sec->idx = newidx; | ||
1049 | if (size) | ||
1050 | sec->contents = xmalloc(size); | ||
1051 | |||
1052 | obj_insert_section_load_order(f, sec); | ||
1053 | |||
1054 | return sec; | ||
1055 | } | ||
1056 | |||
1057 | struct obj_section *obj_create_alloced_section_first(struct obj_file *f, | ||
1058 | const char *name, | ||
1059 | unsigned long align, | ||
1060 | unsigned long size) | ||
1061 | { | ||
1062 | int newidx = f->header.e_shnum++; | ||
1063 | struct obj_section *sec; | ||
1064 | |||
1065 | f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); | ||
1066 | f->sections[newidx] = sec = arch_new_section(); | ||
1067 | |||
1068 | memset(sec, 0, sizeof(*sec)); | ||
1069 | sec->header.sh_type = SHT_PROGBITS; | ||
1070 | sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; | ||
1071 | sec->header.sh_size = size; | ||
1072 | sec->header.sh_addralign = align; | ||
1073 | sec->name = name; | ||
1074 | sec->idx = newidx; | ||
1075 | if (size) | ||
1076 | sec->contents = xmalloc(size); | ||
1077 | |||
1078 | sec->load_next = f->load_order; | ||
1079 | f->load_order = sec; | ||
1080 | if (f->load_order_search_start == &f->load_order) | ||
1081 | f->load_order_search_start = &sec->load_next; | ||
1082 | |||
1083 | return sec; | ||
1084 | } | ||
1085 | |||
1086 | void *obj_extend_section(struct obj_section *sec, unsigned long more) | ||
1087 | { | ||
1088 | unsigned long oldsize = sec->header.sh_size; | ||
1089 | sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); | ||
1090 | return sec->contents + oldsize; | ||
1091 | } | ||
1092 | |||
1093 | |||
1094 | |||
1095 | /* Conditionally add the symbols from the given symbol set to the | ||
1096 | new module. */ | ||
1097 | |||
1098 | static int | ||
1099 | add_symbols_from( | ||
1100 | struct obj_file *f, | ||
1101 | int idx, struct new_module_symbol *syms, size_t nsyms) | ||
1102 | { | ||
1103 | struct new_module_symbol *s; | ||
1104 | size_t i; | ||
1105 | int used = 0; | ||
1106 | |||
1107 | for (i = 0, s = syms; i < nsyms; ++i, ++s) { | ||
1108 | |||
1109 | /* Only add symbols that are already marked external. If we | ||
1110 | override locals we may cause problems for argument initialization. | ||
1111 | We will also create a false dependency on the module. */ | ||
1112 | struct obj_symbol *sym; | ||
1113 | |||
1114 | sym = obj_find_symbol(f, (char *) s->name); | ||
1115 | if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { | ||
1116 | sym = obj_add_symbol(f, (char *) s->name, -1, | ||
1117 | ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), | ||
1118 | idx, s->value, 0); | ||
1119 | /* Did our symbol just get installed? If so, mark the | ||
1120 | module as "used". */ | ||
1121 | if (sym->secidx == idx) | ||
1122 | used = 1; | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | return used; | ||
1127 | } | ||
1128 | |||
1129 | static void add_kernel_symbols(struct obj_file *f) | ||
1130 | { | ||
1131 | struct external_module *m; | ||
1132 | size_t i, nused = 0; | ||
1133 | |||
1134 | /* Add module symbols first. */ | ||
1135 | |||
1136 | for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) | ||
1137 | if (m->nsyms | ||
1138 | && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, | ||
1139 | m->nsyms)) m->used = 1, ++nused; | ||
1140 | |||
1141 | n_ext_modules_used = nused; | ||
1142 | |||
1143 | /* And finally the symbols from the kernel proper. */ | ||
1144 | |||
1145 | if (nksyms) | ||
1146 | add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); | ||
1147 | } | ||
1148 | |||
1149 | static char *get_modinfo_value(struct obj_file *f, const char *key) | ||
1150 | { | ||
1151 | struct obj_section *sec; | ||
1152 | char *p, *v, *n, *ep; | ||
1153 | size_t klen = strlen(key); | ||
1154 | |||
1155 | sec = obj_find_section(f, ".modinfo"); | ||
1156 | if (sec == NULL) | ||
1157 | return NULL; | ||
1158 | p = sec->contents; | ||
1159 | ep = p + sec->header.sh_size; | ||
1160 | while (p < ep) { | ||
1161 | v = strchr(p, '='); | ||
1162 | n = strchr(p, '\0'); | ||
1163 | if (v) { | ||
1164 | if (v - p == klen && strncmp(p, key, klen) == 0) | ||
1165 | return v + 1; | ||
1166 | } else { | ||
1167 | if (n - p == klen && strcmp(p, key) == 0) | ||
1168 | return n; | ||
1169 | } | ||
1170 | p = n + 1; | ||
1171 | } | ||
1172 | |||
1173 | return NULL; | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | /*======================================================================*/ | ||
1178 | /* Functions relating to module loading in pre 2.1 kernels. */ | ||
1179 | |||
1180 | static int | ||
1181 | old_process_module_arguments(struct obj_file *f, int argc, char **argv) | ||
1182 | { | ||
1183 | while (argc > 0) { | ||
1184 | char *p, *q; | ||
1185 | struct obj_symbol *sym; | ||
1186 | int *loc; | ||
1187 | |||
1188 | p = *argv; | ||
1189 | if ((q = strchr(p, '=')) == NULL) | ||
1190 | continue; | ||
1191 | *q++ = '\0'; | ||
1192 | |||
1193 | sym = obj_find_symbol(f, p); | ||
1194 | |||
1195 | /* Also check that the parameter was not resolved from the kernel. */ | ||
1196 | if (sym == NULL || sym->secidx > SHN_HIRESERVE) { | ||
1197 | fprintf(stderr, "symbol for parameter %s not found\n", p); | ||
1198 | return 0; | ||
1199 | } | ||
1200 | |||
1201 | loc = (int *) (f->sections[sym->secidx]->contents + sym->value); | ||
1202 | |||
1203 | /* Do C quoting if we begin with a ". */ | ||
1204 | if (*q == '"') { | ||
1205 | char *r, *str; | ||
1206 | |||
1207 | str = alloca(strlen(q)); | ||
1208 | for (r = str, q++; *q != '"'; ++q, ++r) { | ||
1209 | if (*q == '\0') { | ||
1210 | fprintf(stderr, | ||
1211 | "improperly terminated string argument for %s\n", | ||
1212 | p); | ||
1213 | return 0; | ||
1214 | } else if (*q == '\\') | ||
1215 | switch (*++q) { | ||
1216 | case 'a': | ||
1217 | *r = '\a'; | ||
1218 | break; | ||
1219 | case 'b': | ||
1220 | *r = '\b'; | ||
1221 | break; | ||
1222 | case 'e': | ||
1223 | *r = '\033'; | ||
1224 | break; | ||
1225 | case 'f': | ||
1226 | *r = '\f'; | ||
1227 | break; | ||
1228 | case 'n': | ||
1229 | *r = '\n'; | ||
1230 | break; | ||
1231 | case 'r': | ||
1232 | *r = '\r'; | ||
1233 | break; | ||
1234 | case 't': | ||
1235 | *r = '\t'; | ||
1236 | break; | ||
1237 | |||
1238 | case '0': | ||
1239 | case '1': | ||
1240 | case '2': | ||
1241 | case '3': | ||
1242 | case '4': | ||
1243 | case '5': | ||
1244 | case '6': | ||
1245 | case '7': | ||
1246 | { | ||
1247 | int c = *q - '0'; | ||
1248 | if (q[1] >= '0' && q[1] <= '7') { | ||
1249 | c = (c * 8) + *++q - '0'; | ||
1250 | if (q[1] >= '0' && q[1] <= '7') | ||
1251 | c = (c * 8) + *++q - '0'; | ||
1252 | } | ||
1253 | *r = c; | ||
1254 | } | ||
1255 | break; | ||
1256 | |||
1257 | default: | ||
1258 | *r = *q; | ||
1259 | break; | ||
1260 | } else | ||
1261 | *r = *q; | ||
1262 | } | ||
1263 | *r = '\0'; | ||
1264 | obj_string_patch(f, sym->secidx, sym->value, str); | ||
1265 | } else if (*q >= '0' && *q <= '9') { | ||
1266 | do | ||
1267 | *loc++ = strtoul(q, &q, 0); | ||
1268 | while (*q++ == ','); | ||
1269 | } else { | ||
1270 | char *contents = f->sections[sym->secidx]->contents; | ||
1271 | char *loc = contents + sym->value; | ||
1272 | char *r; /* To search for commas */ | ||
1273 | |||
1274 | /* Break the string with comas */ | ||
1275 | while ((r = strchr(q, ',')) != (char *) NULL) { | ||
1276 | *r++ = '\0'; | ||
1277 | obj_string_patch(f, sym->secidx, loc - contents, q); | ||
1278 | loc += sizeof(char *); | ||
1279 | q = r; | ||
1280 | } | ||
1281 | |||
1282 | /* last part */ | ||
1283 | obj_string_patch(f, sym->secidx, loc - contents, q); | ||
1284 | } | ||
1285 | |||
1286 | argc--, argv++; | ||
1287 | } | ||
1288 | |||
1289 | return 1; | ||
1290 | } | ||
1291 | |||
1292 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
1293 | static int old_is_module_checksummed(struct obj_file *f) | ||
1294 | { | ||
1295 | return obj_find_symbol(f, "Using_Versions") != NULL; | ||
1296 | } | ||
1297 | /* Get the module's kernel version in the canonical integer form. */ | ||
1298 | |||
1299 | static int | ||
1300 | old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) | ||
1301 | { | ||
1302 | struct obj_symbol *sym; | ||
1303 | char *p, *q; | ||
1304 | int a, b, c; | ||
1305 | |||
1306 | sym = obj_find_symbol(f, "kernel_version"); | ||
1307 | if (sym == NULL) | ||
1308 | return -1; | ||
1309 | |||
1310 | p = f->sections[sym->secidx]->contents + sym->value; | ||
1311 | strncpy(str, p, STRVERSIONLEN); | ||
1312 | |||
1313 | a = strtoul(p, &p, 10); | ||
1314 | if (*p != '.') | ||
1315 | return -1; | ||
1316 | b = strtoul(p + 1, &p, 10); | ||
1317 | if (*p != '.') | ||
1318 | return -1; | ||
1319 | c = strtoul(p + 1, &q, 10); | ||
1320 | if (p + 1 == q) | ||
1321 | return -1; | ||
1322 | |||
1323 | return a << 16 | b << 8 | c; | ||
1324 | } | ||
1325 | |||
1326 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
1327 | |||
1328 | #ifdef BB_FEATURE_INSMOD_OLD_KERNEL | ||
1329 | |||
1330 | /* Fetch all the symbols and divvy them up as appropriate for the modules. */ | ||
1331 | |||
1332 | static int old_get_kernel_symbols(void) | ||
1333 | { | ||
1334 | struct old_kernel_sym *ks, *k; | ||
1335 | struct new_module_symbol *s; | ||
1336 | struct external_module *mod; | ||
1337 | int nks, nms, nmod, i; | ||
1338 | |||
1339 | nks = get_kernel_syms(NULL); | ||
1340 | if (nks < 0) { | ||
1341 | perror("get_kernel_syms: %m"); | ||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | ks = k = xmalloc(nks * sizeof(*ks)); | ||
1346 | |||
1347 | if (get_kernel_syms(ks) != nks) { | ||
1348 | perror("inconsistency with get_kernel_syms -- is someone else " | ||
1349 | "playing with modules?"); | ||
1350 | free(ks); | ||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | /* Collect the module information. */ | ||
1355 | |||
1356 | mod = NULL; | ||
1357 | nmod = -1; | ||
1358 | |||
1359 | while (k->name[0] == '#' && k->name[1]) { | ||
1360 | struct old_kernel_sym *k2; | ||
1361 | struct new_module_symbol *s; | ||
1362 | |||
1363 | /* Find out how many symbols this module has. */ | ||
1364 | for (k2 = k + 1; k2->name[0] != '#'; ++k2) | ||
1365 | continue; | ||
1366 | nms = k2 - k - 1; | ||
1367 | |||
1368 | mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod)); | ||
1369 | mod[nmod].name = k->name + 1; | ||
1370 | mod[nmod].addr = k->value; | ||
1371 | mod[nmod].used = 0; | ||
1372 | mod[nmod].nsyms = nms; | ||
1373 | mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); | ||
1374 | |||
1375 | for (i = 0, ++k; i < nms; ++i, ++s, ++k) { | ||
1376 | s->name = (unsigned long) k->name; | ||
1377 | s->value = k->value; | ||
1378 | } | ||
1379 | |||
1380 | k = k2; | ||
1381 | } | ||
1382 | |||
1383 | ext_modules = mod; | ||
1384 | n_ext_modules = nmod + 1; | ||
1385 | |||
1386 | /* Now collect the symbols for the kernel proper. */ | ||
1387 | |||
1388 | if (k->name[0] == '#') | ||
1389 | ++k; | ||
1390 | |||
1391 | nksyms = nms = nks - (k - ks); | ||
1392 | ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); | ||
1393 | |||
1394 | for (i = 0; i < nms; ++i, ++s, ++k) { | ||
1395 | s->name = (unsigned long) k->name; | ||
1396 | s->value = k->value; | ||
1397 | } | ||
1398 | |||
1399 | return 1; | ||
1400 | } | ||
1401 | |||
1402 | /* Return the kernel symbol checksum version, or zero if not used. */ | ||
1403 | |||
1404 | static int old_is_kernel_checksummed(void) | ||
1405 | { | ||
1406 | /* Using_Versions is the first symbol. */ | ||
1407 | if (nksyms > 0 | ||
1408 | && strcmp((char *) ksyms[0].name, | ||
1409 | "Using_Versions") == 0) return ksyms[0].value; | ||
1410 | else | ||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1414 | |||
1415 | static int old_create_mod_use_count(struct obj_file *f) | ||
1416 | { | ||
1417 | struct obj_section *sec; | ||
1418 | |||
1419 | sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long), | ||
1420 | sizeof(long)); | ||
1421 | |||
1422 | obj_add_symbol(f, "mod_use_count_", -1, | ||
1423 | ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, | ||
1424 | sizeof(long)); | ||
1425 | |||
1426 | return 1; | ||
1427 | } | ||
1428 | |||
1429 | static int | ||
1430 | old_init_module(const char *m_name, struct obj_file *f, | ||
1431 | unsigned long m_size) | ||
1432 | { | ||
1433 | char *image; | ||
1434 | struct old_mod_routines routines; | ||
1435 | struct old_symbol_table *symtab; | ||
1436 | int ret; | ||
1437 | |||
1438 | /* Create the symbol table */ | ||
1439 | { | ||
1440 | int nsyms = 0, strsize = 0, total; | ||
1441 | |||
1442 | /* Size things first... */ | ||
1443 | if (flag_export) { | ||
1444 | int i; | ||
1445 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
1446 | struct obj_symbol *sym; | ||
1447 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
1448 | if (ELFW(ST_BIND) (sym->info) != STB_LOCAL | ||
1449 | && sym->secidx <= SHN_HIRESERVE) | ||
1450 | { | ||
1451 | sym->ksymidx = nsyms++; | ||
1452 | strsize += strlen(sym->name) + 1; | ||
1453 | } | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | total = (sizeof(struct old_symbol_table) | ||
1458 | + nsyms * sizeof(struct old_module_symbol) | ||
1459 | + n_ext_modules_used * sizeof(struct old_module_ref) | ||
1460 | + strsize); | ||
1461 | symtab = xmalloc(total); | ||
1462 | symtab->size = total; | ||
1463 | symtab->n_symbols = nsyms; | ||
1464 | symtab->n_refs = n_ext_modules_used; | ||
1465 | |||
1466 | if (flag_export && nsyms) { | ||
1467 | struct old_module_symbol *ksym; | ||
1468 | char *str; | ||
1469 | int i; | ||
1470 | |||
1471 | ksym = symtab->symbol; | ||
1472 | str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol) | ||
1473 | + n_ext_modules_used * sizeof(struct old_module_ref)); | ||
1474 | |||
1475 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
1476 | struct obj_symbol *sym; | ||
1477 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
1478 | if (sym->ksymidx >= 0) { | ||
1479 | ksym->addr = obj_symbol_final_value(f, sym); | ||
1480 | ksym->name = | ||
1481 | (unsigned long) str - (unsigned long) symtab; | ||
1482 | |||
1483 | str = stpcpy(str, sym->name) + 1; | ||
1484 | ksym++; | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | if (n_ext_modules_used) { | ||
1490 | struct old_module_ref *ref; | ||
1491 | int i; | ||
1492 | |||
1493 | ref = (struct old_module_ref *) | ||
1494 | ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol)); | ||
1495 | |||
1496 | for (i = 0; i < n_ext_modules; ++i) | ||
1497 | if (ext_modules[i].used) | ||
1498 | ref++->module = ext_modules[i].addr; | ||
1499 | } | ||
1500 | } | ||
1501 | |||
1502 | /* Fill in routines. */ | ||
1503 | |||
1504 | routines.init = | ||
1505 | obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); | ||
1506 | routines.cleanup = | ||
1507 | obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); | ||
1508 | |||
1509 | /* Whew! All of the initialization is complete. Collect the final | ||
1510 | module image and give it to the kernel. */ | ||
1511 | |||
1512 | image = xmalloc(m_size); | ||
1513 | obj_create_image(f, image); | ||
1514 | |||
1515 | /* image holds the complete relocated module, accounting correctly for | ||
1516 | mod_use_count. However the old module kernel support assume that | ||
1517 | it is receiving something which does not contain mod_use_count. */ | ||
1518 | ret = old_sys_init_module(m_name, image + sizeof(long), | ||
1519 | m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN | ||
1520 | : 0), &routines, symtab); | ||
1521 | if (ret) | ||
1522 | perror("init_module: %m"); | ||
1523 | |||
1524 | free(image); | ||
1525 | free(symtab); | ||
1526 | |||
1527 | return ret == 0; | ||
1528 | } | ||
1529 | |||
1530 | #else | ||
1531 | |||
1532 | #define old_create_mod_use_count(x) TRUE | ||
1533 | #define old_init_module(x, y, z) TRUE | ||
1534 | |||
1535 | #endif /* BB_FEATURE_INSMOD_OLD_KERNEL */ | ||
1536 | |||
1537 | |||
1538 | |||
1539 | /*======================================================================*/ | ||
1540 | /* Functions relating to module loading after 2.1.18. */ | ||
1541 | |||
1542 | static int | ||
1543 | new_process_module_arguments(struct obj_file *f, int argc, char **argv) | ||
1544 | { | ||
1545 | while (argc > 0) { | ||
1546 | char *p, *q, *key; | ||
1547 | struct obj_symbol *sym; | ||
1548 | char *contents, *loc; | ||
1549 | int min, max, n; | ||
1550 | |||
1551 | p = *argv; | ||
1552 | if ((q = strchr(p, '=')) == NULL) | ||
1553 | continue; | ||
1554 | |||
1555 | key = alloca(q - p + 6); | ||
1556 | memcpy(key, "parm_", 5); | ||
1557 | memcpy(key + 5, p, q - p); | ||
1558 | key[q - p + 5] = 0; | ||
1559 | |||
1560 | p = get_modinfo_value(f, key); | ||
1561 | key += 5; | ||
1562 | if (p == NULL) { | ||
1563 | fprintf(stderr, "invalid parameter %s\n", key); | ||
1564 | return 0; | ||
1565 | } | ||
1566 | |||
1567 | sym = obj_find_symbol(f, key); | ||
1568 | |||
1569 | /* Also check that the parameter was not resolved from the kernel. */ | ||
1570 | if (sym == NULL || sym->secidx > SHN_HIRESERVE) { | ||
1571 | fprintf(stderr, "symbol for parameter %s not found\n", key); | ||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1575 | if (isdigit(*p)) { | ||
1576 | min = strtoul(p, &p, 10); | ||
1577 | if (*p == '-') | ||
1578 | max = strtoul(p + 1, &p, 10); | ||
1579 | else | ||
1580 | max = min; | ||
1581 | } else | ||
1582 | min = max = 1; | ||
1583 | |||
1584 | contents = f->sections[sym->secidx]->contents; | ||
1585 | loc = contents + sym->value; | ||
1586 | n = (*++q != '\0'); | ||
1587 | |||
1588 | while (1) { | ||
1589 | if ((*p == 's') || (*p == 'c')) { | ||
1590 | char *str; | ||
1591 | |||
1592 | /* Do C quoting if we begin with a ", else slurp the lot. */ | ||
1593 | if (*q == '"') { | ||
1594 | char *r; | ||
1595 | |||
1596 | str = alloca(strlen(q)); | ||
1597 | for (r = str, q++; *q != '"'; ++q, ++r) { | ||
1598 | if (*q == '\0') { | ||
1599 | fprintf(stderr, | ||
1600 | "improperly terminated string argument for %s\n", | ||
1601 | key); | ||
1602 | return 0; | ||
1603 | } else if (*q == '\\') | ||
1604 | switch (*++q) { | ||
1605 | case 'a': | ||
1606 | *r = '\a'; | ||
1607 | break; | ||
1608 | case 'b': | ||
1609 | *r = '\b'; | ||
1610 | break; | ||
1611 | case 'e': | ||
1612 | *r = '\033'; | ||
1613 | break; | ||
1614 | case 'f': | ||
1615 | *r = '\f'; | ||
1616 | break; | ||
1617 | case 'n': | ||
1618 | *r = '\n'; | ||
1619 | break; | ||
1620 | case 'r': | ||
1621 | *r = '\r'; | ||
1622 | break; | ||
1623 | case 't': | ||
1624 | *r = '\t'; | ||
1625 | break; | ||
1626 | |||
1627 | case '0': | ||
1628 | case '1': | ||
1629 | case '2': | ||
1630 | case '3': | ||
1631 | case '4': | ||
1632 | case '5': | ||
1633 | case '6': | ||
1634 | case '7': | ||
1635 | { | ||
1636 | int c = *q - '0'; | ||
1637 | if (q[1] >= '0' && q[1] <= '7') { | ||
1638 | c = (c * 8) + *++q - '0'; | ||
1639 | if (q[1] >= '0' && q[1] <= '7') | ||
1640 | c = (c * 8) + *++q - '0'; | ||
1641 | } | ||
1642 | *r = c; | ||
1643 | } | ||
1644 | break; | ||
1645 | |||
1646 | default: | ||
1647 | *r = *q; | ||
1648 | break; | ||
1649 | } else | ||
1650 | *r = *q; | ||
1651 | } | ||
1652 | *r = '\0'; | ||
1653 | ++q; | ||
1654 | } else { | ||
1655 | char *r; | ||
1656 | |||
1657 | /* In this case, the string is not quoted. We will break | ||
1658 | it using the coma (like for ints). If the user wants to | ||
1659 | include comas in a string, he just has to quote it */ | ||
1660 | |||
1661 | /* Search the next coma */ | ||
1662 | r = strchr(q, ','); | ||
1663 | |||
1664 | /* Found ? */ | ||
1665 | if (r != (char *) NULL) { | ||
1666 | /* Recopy the current field */ | ||
1667 | str = alloca(r - q + 1); | ||
1668 | memcpy(str, q, r - q); | ||
1669 | |||
1670 | /* I don't know if it is usefull, as the previous case | ||
1671 | doesn't null terminate the string ??? */ | ||
1672 | str[r - q] = '\0'; | ||
1673 | |||
1674 | /* Keep next fields */ | ||
1675 | q = r; | ||
1676 | } else { | ||
1677 | /* last string */ | ||
1678 | str = q; | ||
1679 | q = ""; | ||
1680 | } | ||
1681 | } | ||
1682 | |||
1683 | if (*p == 's') { | ||
1684 | /* Normal string */ | ||
1685 | obj_string_patch(f, sym->secidx, loc - contents, str); | ||
1686 | loc += tgt_sizeof_char_p; | ||
1687 | } else { | ||
1688 | /* Array of chars (in fact, matrix !) */ | ||
1689 | long charssize; /* size of each member */ | ||
1690 | |||
1691 | /* Get the size of each member */ | ||
1692 | /* Probably we should do that outside the loop ? */ | ||
1693 | if (!isdigit(*(p + 1))) { | ||
1694 | fprintf(stderr, | ||
1695 | "parameter type 'c' for %s must be followed by" | ||
1696 | " the maximum size\n", key); | ||
1697 | return 0; | ||
1698 | } | ||
1699 | charssize = strtoul(p + 1, (char **) NULL, 10); | ||
1700 | |||
1701 | /* Check length */ | ||
1702 | if (strlen(str) >= charssize) { | ||
1703 | fprintf(stderr, | ||
1704 | "string too long for %s (max %ld)\n", key, | ||
1705 | charssize - 1); | ||
1706 | return 0; | ||
1707 | } | ||
1708 | |||
1709 | /* Copy to location */ | ||
1710 | strcpy((char *) loc, str); | ||
1711 | loc += charssize; | ||
1712 | } | ||
1713 | } else { | ||
1714 | long v = strtoul(q, &q, 0); | ||
1715 | switch (*p) { | ||
1716 | case 'b': | ||
1717 | *loc++ = v; | ||
1718 | break; | ||
1719 | case 'h': | ||
1720 | *(short *) loc = v; | ||
1721 | loc += tgt_sizeof_short; | ||
1722 | break; | ||
1723 | case 'i': | ||
1724 | *(int *) loc = v; | ||
1725 | loc += tgt_sizeof_int; | ||
1726 | break; | ||
1727 | case 'l': | ||
1728 | *(long *) loc = v; | ||
1729 | loc += tgt_sizeof_long; | ||
1730 | break; | ||
1731 | |||
1732 | default: | ||
1733 | fprintf(stderr, "unknown parameter type '%c' for %s\n", | ||
1734 | *p, key); | ||
1735 | return 0; | ||
1736 | } | ||
1737 | } | ||
1738 | |||
1739 | retry_end_of_value: | ||
1740 | switch (*q) { | ||
1741 | case '\0': | ||
1742 | goto end_of_arg; | ||
1743 | |||
1744 | case ' ': | ||
1745 | case '\t': | ||
1746 | case '\n': | ||
1747 | case '\r': | ||
1748 | ++q; | ||
1749 | goto retry_end_of_value; | ||
1750 | |||
1751 | case ',': | ||
1752 | if (++n > max) { | ||
1753 | fprintf(stderr, "too many values for %s (max %d)\n", | ||
1754 | key, max); | ||
1755 | return 0; | ||
1756 | } | ||
1757 | ++q; | ||
1758 | break; | ||
1759 | |||
1760 | default: | ||
1761 | fprintf(stderr, "invalid argument syntax for %s\n", key); | ||
1762 | return 0; | ||
1763 | } | ||
1764 | } | ||
1765 | |||
1766 | end_of_arg: | ||
1767 | if (n < min) { | ||
1768 | fprintf(stderr, "too few values for %s (min %d)\n", key, min); | ||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | argc--, argv++; | ||
1773 | } | ||
1774 | |||
1775 | return 1; | ||
1776 | } | ||
1777 | |||
1778 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
1779 | static int new_is_module_checksummed(struct obj_file *f) | ||
1780 | { | ||
1781 | const char *p = get_modinfo_value(f, "using_checksums"); | ||
1782 | if (p) | ||
1783 | return atoi(p); | ||
1784 | else | ||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | /* Get the module's kernel version in the canonical integer form. */ | ||
1789 | |||
1790 | static int | ||
1791 | new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) | ||
1792 | { | ||
1793 | char *p, *q; | ||
1794 | int a, b, c; | ||
1795 | |||
1796 | p = get_modinfo_value(f, "kernel_version"); | ||
1797 | if (p == NULL) | ||
1798 | return -1; | ||
1799 | strncpy(str, p, STRVERSIONLEN); | ||
1800 | |||
1801 | a = strtoul(p, &p, 10); | ||
1802 | if (*p != '.') | ||
1803 | return -1; | ||
1804 | b = strtoul(p + 1, &p, 10); | ||
1805 | if (*p != '.') | ||
1806 | return -1; | ||
1807 | c = strtoul(p + 1, &q, 10); | ||
1808 | if (p + 1 == q) | ||
1809 | return -1; | ||
1810 | |||
1811 | return a << 16 | b << 8 | c; | ||
1812 | } | ||
1813 | |||
1814 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
1815 | |||
1816 | |||
1817 | #ifdef BB_FEATURE_INSMOD_NEW_KERNEL | ||
1818 | |||
1819 | /* Fetch the loaded modules, and all currently exported symbols. */ | ||
1820 | |||
1821 | static int new_get_kernel_symbols(void) | ||
1822 | { | ||
1823 | char *module_names, *mn; | ||
1824 | struct external_module *modules, *m; | ||
1825 | struct new_module_symbol *syms, *s; | ||
1826 | size_t ret, bufsize, nmod, nsyms, i, j; | ||
1827 | |||
1828 | /* Collect the loaded modules. */ | ||
1829 | |||
1830 | module_names = xmalloc(bufsize = 256); | ||
1831 | retry_modules_load: | ||
1832 | if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { | ||
1833 | if (errno == ENOSPC) { | ||
1834 | module_names = xrealloc(module_names, bufsize = ret); | ||
1835 | goto retry_modules_load; | ||
1836 | } | ||
1837 | perror("QM_MODULES: %m\n"); | ||
1838 | return 0; | ||
1839 | } | ||
1840 | |||
1841 | n_ext_modules = nmod = ret; | ||
1842 | ext_modules = modules = xmalloc(nmod * sizeof(*modules)); | ||
1843 | memset(modules, 0, nmod * sizeof(*modules)); | ||
1844 | |||
1845 | /* Collect the modules' symbols. */ | ||
1846 | |||
1847 | for (i = 0, mn = module_names, m = modules; | ||
1848 | i < nmod; ++i, ++m, mn += strlen(mn) + 1) { | ||
1849 | struct new_module_info info; | ||
1850 | |||
1851 | if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { | ||
1852 | if (errno == ENOENT) { | ||
1853 | /* The module was removed out from underneath us. */ | ||
1854 | continue; | ||
1855 | } | ||
1856 | perror("query_module: QM_INFO: %m"); | ||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | syms = xmalloc(bufsize = 1024); | ||
1861 | retry_mod_sym_load: | ||
1862 | if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { | ||
1863 | switch (errno) { | ||
1864 | case ENOSPC: | ||
1865 | syms = xrealloc(syms, bufsize = ret); | ||
1866 | goto retry_mod_sym_load; | ||
1867 | case ENOENT: | ||
1868 | /* The module was removed out from underneath us. */ | ||
1869 | continue; | ||
1870 | default: | ||
1871 | perror("query_module: QM_SYMBOLS: %m"); | ||
1872 | return 0; | ||
1873 | } | ||
1874 | } | ||
1875 | nsyms = ret; | ||
1876 | |||
1877 | m->name = mn; | ||
1878 | m->addr = info.addr; | ||
1879 | m->nsyms = nsyms; | ||
1880 | m->syms = syms; | ||
1881 | |||
1882 | for (j = 0, s = syms; j < nsyms; ++j, ++s) { | ||
1883 | s->name += (unsigned long) syms; | ||
1884 | } | ||
1885 | } | ||
1886 | |||
1887 | /* Collect the kernel's symbols. */ | ||
1888 | |||
1889 | syms = xmalloc(bufsize = 16 * 1024); | ||
1890 | retry_kern_sym_load: | ||
1891 | if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { | ||
1892 | if (errno == ENOSPC) { | ||
1893 | syms = xrealloc(syms, bufsize = ret); | ||
1894 | goto retry_kern_sym_load; | ||
1895 | } | ||
1896 | perror("kernel: QM_SYMBOLS: %m"); | ||
1897 | return 0; | ||
1898 | } | ||
1899 | nksyms = nsyms = ret; | ||
1900 | ksyms = syms; | ||
1901 | |||
1902 | for (j = 0, s = syms; j < nsyms; ++j, ++s) { | ||
1903 | s->name += (unsigned long) syms; | ||
1904 | } | ||
1905 | return 1; | ||
1906 | } | ||
1907 | |||
1908 | |||
1909 | /* Return the kernel symbol checksum version, or zero if not used. */ | ||
1910 | |||
1911 | static int new_is_kernel_checksummed(void) | ||
1912 | { | ||
1913 | struct new_module_symbol *s; | ||
1914 | size_t i; | ||
1915 | |||
1916 | /* Using_Versions is not the first symbol, but it should be in there. */ | ||
1917 | |||
1918 | for (i = 0, s = ksyms; i < nksyms; ++i, ++s) | ||
1919 | if (strcmp((char *) s->name, "Using_Versions") == 0) | ||
1920 | return s->value; | ||
1921 | |||
1922 | return 0; | ||
1923 | } | ||
1924 | |||
1925 | |||
1926 | static int new_create_this_module(struct obj_file *f, const char *m_name) | ||
1927 | { | ||
1928 | struct obj_section *sec; | ||
1929 | |||
1930 | sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, | ||
1931 | sizeof(struct new_module)); | ||
1932 | memset(sec->contents, 0, sizeof(struct new_module)); | ||
1933 | |||
1934 | obj_add_symbol(f, "__this_module", -1, | ||
1935 | ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, | ||
1936 | sizeof(struct new_module)); | ||
1937 | |||
1938 | obj_string_patch(f, sec->idx, offsetof(struct new_module, name), | ||
1939 | m_name); | ||
1940 | |||
1941 | return 1; | ||
1942 | } | ||
1943 | |||
1944 | |||
1945 | static int new_create_module_ksymtab(struct obj_file *f) | ||
1946 | { | ||
1947 | struct obj_section *sec; | ||
1948 | int i; | ||
1949 | |||
1950 | /* We must always add the module references. */ | ||
1951 | |||
1952 | if (n_ext_modules_used) { | ||
1953 | struct new_module_ref *dep; | ||
1954 | struct obj_symbol *tm; | ||
1955 | |||
1956 | sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, | ||
1957 | (sizeof(struct new_module_ref) | ||
1958 | * n_ext_modules_used)); | ||
1959 | if (!sec) | ||
1960 | return 0; | ||
1961 | |||
1962 | tm = obj_find_symbol(f, "__this_module"); | ||
1963 | dep = (struct new_module_ref *) sec->contents; | ||
1964 | for (i = 0; i < n_ext_modules; ++i) | ||
1965 | if (ext_modules[i].used) { | ||
1966 | dep->dep = ext_modules[i].addr; | ||
1967 | obj_symbol_patch(f, sec->idx, | ||
1968 | (char *) &dep->ref - sec->contents, tm); | ||
1969 | dep->next_ref = 0; | ||
1970 | ++dep; | ||
1971 | } | ||
1972 | } | ||
1973 | |||
1974 | if (flag_export && !obj_find_section(f, "__ksymtab")) { | ||
1975 | size_t nsyms; | ||
1976 | int *loaded; | ||
1977 | |||
1978 | sec = | ||
1979 | obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, | ||
1980 | 0); | ||
1981 | |||
1982 | /* We don't want to export symbols residing in sections that | ||
1983 | aren't loaded. There are a number of these created so that | ||
1984 | we make sure certain module options don't appear twice. */ | ||
1985 | |||
1986 | loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); | ||
1987 | while (--i >= 0) | ||
1988 | loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; | ||
1989 | |||
1990 | for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { | ||
1991 | struct obj_symbol *sym; | ||
1992 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
1993 | if (ELFW(ST_BIND) (sym->info) != STB_LOCAL | ||
1994 | && sym->secidx <= SHN_HIRESERVE | ||
1995 | && (sym->secidx >= SHN_LORESERVE | ||
1996 | || loaded[sym->secidx])) { | ||
1997 | ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; | ||
1998 | |||
1999 | obj_symbol_patch(f, sec->idx, ofs, sym); | ||
2000 | obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, | ||
2001 | sym->name); | ||
2002 | |||
2003 | nsyms++; | ||
2004 | } | ||
2005 | } | ||
2006 | |||
2007 | obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); | ||
2008 | } | ||
2009 | |||
2010 | return 1; | ||
2011 | } | ||
2012 | |||
2013 | |||
2014 | static int | ||
2015 | new_init_module(const char *m_name, struct obj_file *f, | ||
2016 | unsigned long m_size) | ||
2017 | { | ||
2018 | struct new_module *module; | ||
2019 | struct obj_section *sec; | ||
2020 | void *image; | ||
2021 | int ret; | ||
2022 | tgt_long m_addr; | ||
2023 | |||
2024 | sec = obj_find_section(f, ".this"); | ||
2025 | module = (struct new_module *) sec->contents; | ||
2026 | m_addr = sec->header.sh_addr; | ||
2027 | |||
2028 | module->size_of_struct = sizeof(*module); | ||
2029 | module->size = m_size; | ||
2030 | module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; | ||
2031 | |||
2032 | sec = obj_find_section(f, "__ksymtab"); | ||
2033 | if (sec && sec->header.sh_size) { | ||
2034 | module->syms = sec->header.sh_addr; | ||
2035 | module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); | ||
2036 | } | ||
2037 | |||
2038 | if (n_ext_modules_used) { | ||
2039 | sec = obj_find_section(f, ".kmodtab"); | ||
2040 | module->deps = sec->header.sh_addr; | ||
2041 | module->ndeps = n_ext_modules_used; | ||
2042 | } | ||
2043 | |||
2044 | module->init = | ||
2045 | obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); | ||
2046 | module->cleanup = | ||
2047 | obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); | ||
2048 | |||
2049 | sec = obj_find_section(f, "__ex_table"); | ||
2050 | if (sec) { | ||
2051 | module->ex_table_start = sec->header.sh_addr; | ||
2052 | module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; | ||
2053 | } | ||
2054 | |||
2055 | sec = obj_find_section(f, ".text.init"); | ||
2056 | if (sec) { | ||
2057 | module->runsize = sec->header.sh_addr - m_addr; | ||
2058 | } | ||
2059 | sec = obj_find_section(f, ".data.init"); | ||
2060 | if (sec) { | ||
2061 | if (!module->runsize || | ||
2062 | module->runsize > sec->header.sh_addr - m_addr) | ||
2063 | module->runsize = sec->header.sh_addr - m_addr; | ||
2064 | } | ||
2065 | |||
2066 | if (!arch_init_module(f, module)) | ||
2067 | return 0; | ||
2068 | |||
2069 | /* Whew! All of the initialization is complete. Collect the final | ||
2070 | module image and give it to the kernel. */ | ||
2071 | |||
2072 | image = xmalloc(m_size); | ||
2073 | obj_create_image(f, image); | ||
2074 | |||
2075 | ret = new_sys_init_module(m_name, (struct new_module *) image); | ||
2076 | if (ret) | ||
2077 | perror("init_module: %m"); | ||
2078 | |||
2079 | free(image); | ||
2080 | |||
2081 | return ret == 0; | ||
2082 | } | ||
2083 | |||
2084 | #else | ||
2085 | |||
2086 | #define new_init_module(x, y, z) TRUE | ||
2087 | #define new_create_this_module(x, y) 0 | ||
2088 | #define new_create_module_ksymtab(x) | ||
2089 | |||
2090 | #endif /* BB_FEATURE_INSMOD_OLD_KERNEL */ | ||
2091 | |||
2092 | |||
2093 | /*======================================================================*/ | ||
2094 | |||
2095 | int | ||
2096 | obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
2097 | const char *string) | ||
2098 | { | ||
2099 | struct obj_string_patch *p; | ||
2100 | struct obj_section *strsec; | ||
2101 | size_t len = strlen(string) + 1; | ||
2102 | char *loc; | ||
2103 | |||
2104 | p = xmalloc(sizeof(*p)); | ||
2105 | p->next = f->string_patches; | ||
2106 | p->reloc_secidx = secidx; | ||
2107 | p->reloc_offset = offset; | ||
2108 | f->string_patches = p; | ||
2109 | |||
2110 | strsec = obj_find_section(f, ".kstrtab"); | ||
2111 | if (strsec == NULL) { | ||
2112 | strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); | ||
2113 | p->string_offset = 0; | ||
2114 | loc = strsec->contents; | ||
2115 | } else { | ||
2116 | p->string_offset = strsec->header.sh_size; | ||
2117 | loc = obj_extend_section(strsec, len); | ||
2118 | } | ||
2119 | memcpy(loc, string, len); | ||
2120 | |||
2121 | return 1; | ||
2122 | } | ||
2123 | |||
2124 | int | ||
2125 | obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, | ||
2126 | struct obj_symbol *sym) | ||
2127 | { | ||
2128 | struct obj_symbol_patch *p; | ||
2129 | |||
2130 | p = xmalloc(sizeof(*p)); | ||
2131 | p->next = f->symbol_patches; | ||
2132 | p->reloc_secidx = secidx; | ||
2133 | p->reloc_offset = offset; | ||
2134 | p->sym = sym; | ||
2135 | f->symbol_patches = p; | ||
2136 | |||
2137 | return 1; | ||
2138 | } | ||
2139 | |||
2140 | int obj_check_undefineds(struct obj_file *f) | ||
2141 | { | ||
2142 | unsigned long i; | ||
2143 | int ret = 1; | ||
2144 | |||
2145 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
2146 | struct obj_symbol *sym; | ||
2147 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
2148 | if (sym->secidx == SHN_UNDEF) { | ||
2149 | if (ELFW(ST_BIND) (sym->info) == STB_WEAK) { | ||
2150 | sym->secidx = SHN_ABS; | ||
2151 | sym->value = 0; | ||
2152 | } else { | ||
2153 | fprintf(stderr, "unresolved symbol %s\n", sym->name); | ||
2154 | ret = 0; | ||
2155 | } | ||
2156 | } | ||
2157 | } | ||
2158 | |||
2159 | return ret; | ||
2160 | } | ||
2161 | |||
2162 | void obj_allocate_commons(struct obj_file *f) | ||
2163 | { | ||
2164 | struct common_entry { | ||
2165 | struct common_entry *next; | ||
2166 | struct obj_symbol *sym; | ||
2167 | } *common_head = NULL; | ||
2168 | |||
2169 | unsigned long i; | ||
2170 | |||
2171 | for (i = 0; i < HASH_BUCKETS; ++i) { | ||
2172 | struct obj_symbol *sym; | ||
2173 | for (sym = f->symtab[i]; sym; sym = sym->next) | ||
2174 | if (sym->secidx == SHN_COMMON) { | ||
2175 | /* Collect all COMMON symbols and sort them by size so as to | ||
2176 | minimize space wasted by alignment requirements. */ | ||
2177 | { | ||
2178 | struct common_entry **p, *n; | ||
2179 | for (p = &common_head; *p; p = &(*p)->next) | ||
2180 | if (sym->size <= (*p)->sym->size) | ||
2181 | break; | ||
2182 | |||
2183 | n = alloca(sizeof(*n)); | ||
2184 | n->next = *p; | ||
2185 | n->sym = sym; | ||
2186 | *p = n; | ||
2187 | } | ||
2188 | } | ||
2189 | } | ||
2190 | |||
2191 | for (i = 1; i < f->local_symtab_size; ++i) { | ||
2192 | struct obj_symbol *sym = f->local_symtab[i]; | ||
2193 | if (sym && sym->secidx == SHN_COMMON) { | ||
2194 | struct common_entry **p, *n; | ||
2195 | for (p = &common_head; *p; p = &(*p)->next) | ||
2196 | if (sym == (*p)->sym) | ||
2197 | break; | ||
2198 | else if (sym->size < (*p)->sym->size) { | ||
2199 | n = alloca(sizeof(*n)); | ||
2200 | n->next = *p; | ||
2201 | n->sym = sym; | ||
2202 | *p = n; | ||
2203 | break; | ||
2204 | } | ||
2205 | } | ||
2206 | } | ||
2207 | |||
2208 | if (common_head) { | ||
2209 | /* Find the bss section. */ | ||
2210 | for (i = 0; i < f->header.e_shnum; ++i) | ||
2211 | if (f->sections[i]->header.sh_type == SHT_NOBITS) | ||
2212 | break; | ||
2213 | |||
2214 | /* If for some reason there hadn't been one, create one. */ | ||
2215 | if (i == f->header.e_shnum) { | ||
2216 | struct obj_section *sec; | ||
2217 | |||
2218 | f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec)); | ||
2219 | f->sections[i] = sec = arch_new_section(); | ||
2220 | f->header.e_shnum = i + 1; | ||
2221 | |||
2222 | memset(sec, 0, sizeof(*sec)); | ||
2223 | sec->header.sh_type = SHT_PROGBITS; | ||
2224 | sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; | ||
2225 | sec->name = ".bss"; | ||
2226 | sec->idx = i; | ||
2227 | } | ||
2228 | |||
2229 | /* Allocate the COMMONS. */ | ||
2230 | { | ||
2231 | ElfW(Addr) bss_size = f->sections[i]->header.sh_size; | ||
2232 | ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; | ||
2233 | struct common_entry *c; | ||
2234 | |||
2235 | for (c = common_head; c; c = c->next) { | ||
2236 | ElfW(Addr) align = c->sym->value; | ||
2237 | |||
2238 | if (align > max_align) | ||
2239 | max_align = align; | ||
2240 | if (bss_size & (align - 1)) | ||
2241 | bss_size = (bss_size | (align - 1)) + 1; | ||
2242 | |||
2243 | c->sym->secidx = i; | ||
2244 | c->sym->value = bss_size; | ||
2245 | |||
2246 | bss_size += c->sym->size; | ||
2247 | } | ||
2248 | |||
2249 | f->sections[i]->header.sh_size = bss_size; | ||
2250 | f->sections[i]->header.sh_addralign = max_align; | ||
2251 | } | ||
2252 | } | ||
2253 | |||
2254 | /* For the sake of patch relocation and parameter initialization, | ||
2255 | allocate zeroed data for NOBITS sections now. Note that after | ||
2256 | this we cannot assume NOBITS are really empty. */ | ||
2257 | for (i = 0; i < f->header.e_shnum; ++i) { | ||
2258 | struct obj_section *s = f->sections[i]; | ||
2259 | if (s->header.sh_type == SHT_NOBITS) { | ||
2260 | s->contents = memset(xmalloc(s->header.sh_size), | ||
2261 | 0, s->header.sh_size); | ||
2262 | s->header.sh_type = SHT_PROGBITS; | ||
2263 | } | ||
2264 | } | ||
2265 | } | ||
2266 | |||
2267 | unsigned long obj_load_size(struct obj_file *f) | ||
2268 | { | ||
2269 | unsigned long dot = 0; | ||
2270 | struct obj_section *sec; | ||
2271 | |||
2272 | /* Finalize the positions of the sections relative to one another. */ | ||
2273 | |||
2274 | for (sec = f->load_order; sec; sec = sec->load_next) { | ||
2275 | ElfW(Addr) align; | ||
2276 | |||
2277 | align = sec->header.sh_addralign; | ||
2278 | if (align && (dot & (align - 1))) | ||
2279 | dot = (dot | (align - 1)) + 1; | ||
2280 | |||
2281 | sec->header.sh_addr = dot; | ||
2282 | dot += sec->header.sh_size; | ||
2283 | } | ||
2284 | |||
2285 | return dot; | ||
2286 | } | ||
2287 | |||
2288 | int obj_relocate(struct obj_file *f, ElfW(Addr) base) | ||
2289 | { | ||
2290 | int i, n = f->header.e_shnum; | ||
2291 | int ret = 1; | ||
2292 | |||
2293 | /* Finalize the addresses of the sections. */ | ||
2294 | |||
2295 | f->baseaddr = base; | ||
2296 | for (i = 0; i < n; ++i) | ||
2297 | f->sections[i]->header.sh_addr += base; | ||
2298 | |||
2299 | /* And iterate over all of the relocations. */ | ||
2300 | |||
2301 | for (i = 0; i < n; ++i) { | ||
2302 | struct obj_section *relsec, *symsec, *targsec, *strsec; | ||
2303 | ElfW(RelM) * rel, *relend; | ||
2304 | ElfW(Sym) * symtab; | ||
2305 | const char *strtab; | ||
2306 | |||
2307 | relsec = f->sections[i]; | ||
2308 | if (relsec->header.sh_type != SHT_RELM) | ||
2309 | continue; | ||
2310 | |||
2311 | symsec = f->sections[relsec->header.sh_link]; | ||
2312 | targsec = f->sections[relsec->header.sh_info]; | ||
2313 | strsec = f->sections[symsec->header.sh_link]; | ||
2314 | |||
2315 | rel = (ElfW(RelM) *) relsec->contents; | ||
2316 | relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); | ||
2317 | symtab = (ElfW(Sym) *) symsec->contents; | ||
2318 | strtab = (const char *) strsec->contents; | ||
2319 | |||
2320 | for (; rel < relend; ++rel) { | ||
2321 | ElfW(Addr) value = 0; | ||
2322 | struct obj_symbol *intsym = NULL; | ||
2323 | unsigned long symndx; | ||
2324 | ElfW(Sym) * extsym = 0; | ||
2325 | const char *errmsg; | ||
2326 | |||
2327 | /* Attempt to find a value to use for this relocation. */ | ||
2328 | |||
2329 | symndx = ELFW(R_SYM) (rel->r_info); | ||
2330 | if (symndx) { | ||
2331 | /* Note we've already checked for undefined symbols. */ | ||
2332 | |||
2333 | extsym = &symtab[symndx]; | ||
2334 | if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) { | ||
2335 | /* Local symbols we look up in the local table to be sure | ||
2336 | we get the one that is really intended. */ | ||
2337 | intsym = f->local_symtab[symndx]; | ||
2338 | } else { | ||
2339 | /* Others we look up in the hash table. */ | ||
2340 | const char *name; | ||
2341 | if (extsym->st_name) | ||
2342 | name = strtab + extsym->st_name; | ||
2343 | else | ||
2344 | name = f->sections[extsym->st_shndx]->name; | ||
2345 | intsym = obj_find_symbol(f, name); | ||
2346 | } | ||
2347 | |||
2348 | value = obj_symbol_final_value(f, intsym); | ||
2349 | intsym->referenced = 1; | ||
2350 | } | ||
2351 | #if SHT_RELM == SHT_RELA | ||
2352 | #if defined(__alpha__) && defined(AXP_BROKEN_GAS) | ||
2353 | /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ | ||
2354 | if (!extsym || !extsym->st_name || | ||
2355 | ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL) | ||
2356 | #endif | ||
2357 | value += rel->r_addend; | ||
2358 | #endif | ||
2359 | |||
2360 | /* Do it! */ | ||
2361 | switch (arch_apply_relocation | ||
2362 | (f, targsec, symsec, intsym, rel, value)) { | ||
2363 | case obj_reloc_ok: | ||
2364 | break; | ||
2365 | |||
2366 | case obj_reloc_overflow: | ||
2367 | errmsg = "Relocation overflow"; | ||
2368 | goto bad_reloc; | ||
2369 | case obj_reloc_dangerous: | ||
2370 | errmsg = "Dangerous relocation"; | ||
2371 | goto bad_reloc; | ||
2372 | case obj_reloc_unhandled: | ||
2373 | errmsg = "Unhandled relocation"; | ||
2374 | bad_reloc: | ||
2375 | if (extsym) { | ||
2376 | fprintf(stderr, "%s of type %ld for %s\n", errmsg, | ||
2377 | (long) ELFW(R_TYPE) (rel->r_info), | ||
2378 | strtab + extsym->st_name); | ||
2379 | } else { | ||
2380 | fprintf(stderr, "%s of type %ld\n", errmsg, | ||
2381 | (long) ELFW(R_TYPE) (rel->r_info)); | ||
2382 | } | ||
2383 | ret = 0; | ||
2384 | break; | ||
2385 | } | ||
2386 | } | ||
2387 | } | ||
2388 | |||
2389 | /* Finally, take care of the patches. */ | ||
2390 | |||
2391 | if (f->string_patches) { | ||
2392 | struct obj_string_patch *p; | ||
2393 | struct obj_section *strsec; | ||
2394 | ElfW(Addr) strsec_base; | ||
2395 | strsec = obj_find_section(f, ".kstrtab"); | ||
2396 | strsec_base = strsec->header.sh_addr; | ||
2397 | |||
2398 | for (p = f->string_patches; p; p = p->next) { | ||
2399 | struct obj_section *targsec = f->sections[p->reloc_secidx]; | ||
2400 | *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) | ||
2401 | = strsec_base + p->string_offset; | ||
2402 | } | ||
2403 | } | ||
2404 | |||
2405 | if (f->symbol_patches) { | ||
2406 | struct obj_symbol_patch *p; | ||
2407 | |||
2408 | for (p = f->symbol_patches; p; p = p->next) { | ||
2409 | struct obj_section *targsec = f->sections[p->reloc_secidx]; | ||
2410 | *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) | ||
2411 | = obj_symbol_final_value(f, p->sym); | ||
2412 | } | ||
2413 | } | ||
2414 | |||
2415 | return ret; | ||
2416 | } | ||
2417 | |||
2418 | int obj_create_image(struct obj_file *f, char *image) | ||
2419 | { | ||
2420 | struct obj_section *sec; | ||
2421 | ElfW(Addr) base = f->baseaddr; | ||
2422 | |||
2423 | for (sec = f->load_order; sec; sec = sec->load_next) { | ||
2424 | char *secimg; | ||
2425 | |||
2426 | if (sec->header.sh_size == 0) | ||
2427 | continue; | ||
2428 | |||
2429 | secimg = image + (sec->header.sh_addr - base); | ||
2430 | |||
2431 | /* Note that we allocated data for NOBITS sections earlier. */ | ||
2432 | memcpy(secimg, sec->contents, sec->header.sh_size); | ||
2433 | } | ||
2434 | |||
2435 | return 1; | ||
2436 | } | ||
2437 | |||
2438 | /*======================================================================*/ | ||
2439 | |||
2440 | struct obj_file *obj_load(FILE * fp) | ||
2441 | { | ||
2442 | struct obj_file *f; | ||
2443 | ElfW(Shdr) * section_headers; | ||
2444 | int shnum, i; | ||
2445 | char *shstrtab; | ||
2446 | |||
2447 | /* Read the file header. */ | ||
2448 | |||
2449 | f = arch_new_file(); | ||
2450 | memset(f, 0, sizeof(*f)); | ||
2451 | f->symbol_cmp = strcmp; | ||
2452 | f->symbol_hash = obj_elf_hash; | ||
2453 | f->load_order_search_start = &f->load_order; | ||
2454 | |||
2455 | fseek(fp, 0, SEEK_SET); | ||
2456 | if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { | ||
2457 | perror("error reading ELF header: %m"); | ||
2458 | return NULL; | ||
2459 | } | ||
2460 | |||
2461 | if (f->header.e_ident[EI_MAG0] != ELFMAG0 | ||
2462 | || f->header.e_ident[EI_MAG1] != ELFMAG1 | ||
2463 | || f->header.e_ident[EI_MAG2] != ELFMAG2 | ||
2464 | || f->header.e_ident[EI_MAG3] != ELFMAG3) { | ||
2465 | fprintf(stderr, "not an ELF file\n"); | ||
2466 | return NULL; | ||
2467 | } | ||
2468 | if (f->header.e_ident[EI_CLASS] != ELFCLASSM | ||
2469 | || f->header.e_ident[EI_DATA] != ELFDATAM | ||
2470 | || f->header.e_ident[EI_VERSION] != EV_CURRENT | ||
2471 | || !MATCH_MACHINE(f->header.e_machine)) { | ||
2472 | fprintf(stderr, "ELF file not for this architecture\n"); | ||
2473 | return NULL; | ||
2474 | } | ||
2475 | if (f->header.e_type != ET_REL) { | ||
2476 | fprintf(stderr, "ELF file not a relocatable object\n"); | ||
2477 | return NULL; | ||
2478 | } | ||
2479 | |||
2480 | /* Read the section headers. */ | ||
2481 | |||
2482 | if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { | ||
2483 | fprintf(stderr, "section header size mismatch: %lu != %lu\n", | ||
2484 | (unsigned long) f->header.e_shentsize, | ||
2485 | (unsigned long) sizeof(ElfW(Shdr))); | ||
2486 | return NULL; | ||
2487 | } | ||
2488 | |||
2489 | shnum = f->header.e_shnum; | ||
2490 | f->sections = xmalloc(sizeof(struct obj_section *) * shnum); | ||
2491 | memset(f->sections, 0, sizeof(struct obj_section *) * shnum); | ||
2492 | |||
2493 | section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); | ||
2494 | fseek(fp, f->header.e_shoff, SEEK_SET); | ||
2495 | if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { | ||
2496 | perror("error reading ELF section headers: %m"); | ||
2497 | return NULL; | ||
2498 | } | ||
2499 | |||
2500 | /* Read the section data. */ | ||
2501 | |||
2502 | for (i = 0; i < shnum; ++i) { | ||
2503 | struct obj_section *sec; | ||
2504 | |||
2505 | f->sections[i] = sec = arch_new_section(); | ||
2506 | memset(sec, 0, sizeof(*sec)); | ||
2507 | |||
2508 | sec->header = section_headers[i]; | ||
2509 | sec->idx = i; | ||
2510 | |||
2511 | switch (sec->header.sh_type) { | ||
2512 | case SHT_NULL: | ||
2513 | case SHT_NOTE: | ||
2514 | case SHT_NOBITS: | ||
2515 | /* ignore */ | ||
2516 | break; | ||
2517 | |||
2518 | case SHT_PROGBITS: | ||
2519 | case SHT_SYMTAB: | ||
2520 | case SHT_STRTAB: | ||
2521 | case SHT_RELM: | ||
2522 | if (sec->header.sh_size > 0) { | ||
2523 | sec->contents = xmalloc(sec->header.sh_size); | ||
2524 | fseek(fp, sec->header.sh_offset, SEEK_SET); | ||
2525 | if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { | ||
2526 | fprintf(stderr, | ||
2527 | "error reading ELF section data: %m\n"); | ||
2528 | return NULL; | ||
2529 | } | ||
2530 | } else { | ||
2531 | sec->contents = NULL; | ||
2532 | } | ||
2533 | break; | ||
2534 | |||
2535 | #if SHT_RELM == SHT_REL | ||
2536 | case SHT_RELA: | ||
2537 | fprintf(stderr, | ||
2538 | "RELA relocations not supported on this architecture\n"); | ||
2539 | return NULL; | ||
2540 | #else | ||
2541 | case SHT_REL: | ||
2542 | fprintf(stderr, | ||
2543 | "REL relocations not supported on this architecture\n"); | ||
2544 | return NULL; | ||
2545 | #endif | ||
2546 | |||
2547 | default: | ||
2548 | if (sec->header.sh_type >= SHT_LOPROC) { | ||
2549 | /* Assume processor specific section types are debug | ||
2550 | info and can safely be ignored. If this is ever not | ||
2551 | the case (Hello MIPS?), don't put ifdefs here but | ||
2552 | create an arch_load_proc_section(). */ | ||
2553 | break; | ||
2554 | } | ||
2555 | |||
2556 | fprintf(stderr, "can't handle sections of type %ld\n", | ||
2557 | (long) sec->header.sh_type); | ||
2558 | return NULL; | ||
2559 | } | ||
2560 | } | ||
2561 | |||
2562 | /* Do what sort of interpretation as needed by each section. */ | ||
2563 | |||
2564 | shstrtab = f->sections[f->header.e_shstrndx]->contents; | ||
2565 | |||
2566 | for (i = 0; i < shnum; ++i) { | ||
2567 | struct obj_section *sec = f->sections[i]; | ||
2568 | sec->name = shstrtab + sec->header.sh_name; | ||
2569 | } | ||
2570 | |||
2571 | for (i = 0; i < shnum; ++i) { | ||
2572 | struct obj_section *sec = f->sections[i]; | ||
2573 | |||
2574 | if (sec->header.sh_flags & SHF_ALLOC) | ||
2575 | obj_insert_section_load_order(f, sec); | ||
2576 | |||
2577 | switch (sec->header.sh_type) { | ||
2578 | case SHT_SYMTAB: | ||
2579 | { | ||
2580 | unsigned long nsym, j; | ||
2581 | char *strtab; | ||
2582 | ElfW(Sym) * sym; | ||
2583 | |||
2584 | if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { | ||
2585 | fprintf(stderr, "symbol size mismatch: %lu != %lu\n", | ||
2586 | (unsigned long) sec->header.sh_entsize, | ||
2587 | (unsigned long) sizeof(ElfW(Sym))); | ||
2588 | return NULL; | ||
2589 | } | ||
2590 | |||
2591 | nsym = sec->header.sh_size / sizeof(ElfW(Sym)); | ||
2592 | strtab = f->sections[sec->header.sh_link]->contents; | ||
2593 | sym = (ElfW(Sym) *) sec->contents; | ||
2594 | |||
2595 | /* Allocate space for a table of local symbols. */ | ||
2596 | j = f->local_symtab_size = sec->header.sh_info; | ||
2597 | f->local_symtab = xmalloc(j *= | ||
2598 | sizeof(struct obj_symbol *)); | ||
2599 | memset(f->local_symtab, 0, j); | ||
2600 | |||
2601 | /* Insert all symbols into the hash table. */ | ||
2602 | for (j = 1, ++sym; j < nsym; ++j, ++sym) { | ||
2603 | const char *name; | ||
2604 | if (sym->st_name) | ||
2605 | name = strtab + sym->st_name; | ||
2606 | else | ||
2607 | name = f->sections[sym->st_shndx]->name; | ||
2608 | |||
2609 | obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, | ||
2610 | sym->st_value, sym->st_size); | ||
2611 | } | ||
2612 | } | ||
2613 | break; | ||
2614 | |||
2615 | case SHT_RELM: | ||
2616 | if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { | ||
2617 | fprintf(stderr, | ||
2618 | "relocation entry size mismatch: %lu != %lu\n", | ||
2619 | (unsigned long) sec->header.sh_entsize, | ||
2620 | (unsigned long) sizeof(ElfW(RelM))); | ||
2621 | return NULL; | ||
2622 | } | ||
2623 | break; | ||
2624 | } | ||
2625 | } | ||
2626 | |||
2627 | return f; | ||
2628 | } | ||
2629 | |||
2630 | static void hide_special_symbols(struct obj_file *f) | ||
2631 | { | ||
2632 | static const char *const specials[] = { | ||
2633 | "cleanup_module", | ||
2634 | "init_module", | ||
2635 | "kernel_version", | ||
2636 | NULL | ||
2637 | }; | ||
2638 | |||
2639 | struct obj_symbol *sym; | ||
2640 | const char *const *p; | ||
2641 | |||
2642 | for (p = specials; *p; ++p) | ||
2643 | if ((sym = obj_find_symbol(f, *p)) != NULL) | ||
2644 | sym->info = | ||
2645 | ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); | ||
2646 | } | ||
2647 | |||
2648 | |||
2649 | |||
2650 | extern int insmod_main( int argc, char **argv) | ||
2651 | { | ||
2652 | int k_crcs; | ||
2653 | int k_new_syscalls; | ||
107 | int len; | 2654 | int len; |
108 | char *tmp; | 2655 | char *tmp; |
109 | char m_name[BUFSIZ + 1] = "\0"; | 2656 | unsigned long m_size; |
2657 | ElfW(Addr) m_addr; | ||
110 | FILE *fp; | 2658 | FILE *fp; |
2659 | struct obj_file *f; | ||
2660 | char m_name[BUFSIZ + 1] = "\0"; | ||
2661 | int exit_status = FALSE; | ||
2662 | int m_has_modinfo; | ||
2663 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
2664 | int k_version; | ||
2665 | char k_strversion[STRVERSIONLEN]; | ||
2666 | char m_strversion[STRVERSIONLEN]; | ||
2667 | int m_version; | ||
2668 | int m_crcs; | ||
2669 | #endif | ||
2670 | |||
111 | 2671 | ||
112 | if (argc <= 1) { | 2672 | if (argc <= 1) { |
113 | usage(insmod_usage); | 2673 | usage(insmod_usage); |
@@ -117,9 +2677,17 @@ extern int insmod_main(int argc, char **argv) | |||
117 | while (--argc > 0 && **(++argv) == '-') { | 2677 | while (--argc > 0 && **(++argv) == '-') { |
118 | while (*(++(*argv))) { | 2678 | while (*(++(*argv))) { |
119 | switch (**argv) { | 2679 | switch (**argv) { |
120 | case 'f': | 2680 | case 'f': /* force loading */ |
2681 | flag_force_load = 1; | ||
2682 | break; | ||
2683 | case 'k': /* module loaded by kerneld, auto-cleanable */ | ||
2684 | flag_autoclean = 1; | ||
121 | break; | 2685 | break; |
122 | case 'k': | 2686 | case 'v': /* verbose output */ |
2687 | flag_verbose = 1; | ||
2688 | break; | ||
2689 | case 'x': /* do not export externs */ | ||
2690 | flag_export = 0; | ||
123 | break; | 2691 | break; |
124 | default: | 2692 | default: |
125 | usage(insmod_usage); | 2693 | usage(insmod_usage); |
@@ -127,14 +2695,15 @@ extern int insmod_main(int argc, char **argv) | |||
127 | } | 2695 | } |
128 | } | 2696 | } |
129 | 2697 | ||
130 | if (argc <= 0) | 2698 | if (argc <= 0) { |
131 | usage(insmod_usage); | 2699 | usage(insmod_usage); |
132 | 2700 | } | |
133 | /* Grab the module name */ | 2701 | /* Grab the module name */ |
134 | if ((tmp = strrchr(*argv, '/')) != NULL) | 2702 | if ((tmp = strrchr(*argv, '/')) != NULL) { |
135 | tmp++; | 2703 | tmp++; |
136 | else | 2704 | } else { |
137 | tmp = *argv; | 2705 | tmp = *argv; |
2706 | } | ||
138 | len = strlen(tmp); | 2707 | len = strlen(tmp); |
139 | 2708 | ||
140 | if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') | 2709 | if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') |
@@ -147,9 +2716,11 @@ extern int insmod_main(int argc, char **argv) | |||
147 | if ((fp = fopen(*argv, "r")) == NULL) { | 2716 | if ((fp = fopen(*argv, "r")) == NULL) { |
148 | /* Hmpf. Could not open it. Search through _PATH_MODULES to find a module named m_name */ | 2717 | /* Hmpf. Could not open it. Search through _PATH_MODULES to find a module named m_name */ |
149 | if (recursiveAction(_PATH_MODULES, TRUE, FALSE, FALSE, | 2718 | if (recursiveAction(_PATH_MODULES, TRUE, FALSE, FALSE, |
150 | findNamedModule, findNamedModule) == FALSE) { | 2719 | findNamedModule, 0, m_fullName) == TRUE) |
2720 | { | ||
151 | if (m_filename[0] == '\0' | 2721 | if (m_filename[0] == '\0' |
152 | || ((fp = fopen(m_filename, "r")) == NULL)) { | 2722 | || ((fp = fopen(m_filename, "r")) == NULL)) |
2723 | { | ||
153 | perror("No module by that name found in " _PATH_MODULES | 2724 | perror("No module by that name found in " _PATH_MODULES |
154 | "\n"); | 2725 | "\n"); |
155 | exit(FALSE); | 2726 | exit(FALSE); |
@@ -159,40 +2730,112 @@ extern int insmod_main(int argc, char **argv) | |||
159 | memcpy(m_filename, *argv, strlen(*argv)); | 2730 | memcpy(m_filename, *argv, strlen(*argv)); |
160 | 2731 | ||
161 | 2732 | ||
162 | fprintf(stderr, "m_filename='%s'\n", m_filename); | ||
163 | fprintf(stderr, "m_name='%s'\n", m_name); | ||
164 | |||
165 | |||
166 | /* TODO: do something roughtly like this... */ | ||
167 | #if 0 | ||
168 | |||
169 | if ((f = obj_load(fp)) == NULL) { | 2733 | if ((f = obj_load(fp)) == NULL) { |
170 | perror("Could not load the module\n"); | 2734 | perror("Could not load the module\n"); |
171 | exit(FALSE); | 2735 | exit(FALSE); |
172 | } | 2736 | } |
173 | 2737 | ||
2738 | if (get_modinfo_value(f, "kernel_version") == NULL) | ||
2739 | m_has_modinfo = 0; | ||
2740 | else | ||
2741 | m_has_modinfo = 1; | ||
2742 | |||
2743 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
2744 | /* Version correspondence? */ | ||
2745 | |||
2746 | k_version = get_kernel_version(k_strversion); | ||
2747 | if (m_has_modinfo) { | ||
2748 | m_version = new_get_module_version(f, m_strversion); | ||
2749 | } else { | ||
2750 | m_version = old_get_module_version(f, m_strversion); | ||
2751 | if (m_version == -1) { | ||
2752 | fprintf(stderr, | ||
2753 | "couldn't find the kernel version the module was compiled for\n"); | ||
2754 | goto out; | ||
2755 | } | ||
2756 | } | ||
2757 | |||
2758 | if (strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) { | ||
2759 | if (flag_force_load) { | ||
2760 | fprintf(stderr, "Warning: kernel-module version mismatch\n" | ||
2761 | "\t%s was compiled for kernel version %s\n" | ||
2762 | "\twhile this kernel is version %s\n", | ||
2763 | m_filename, m_strversion, k_strversion); | ||
2764 | } else { | ||
2765 | fprintf(stderr, "kernel-module version mismatch\n" | ||
2766 | "\t%s was compiled for kernel version %s\n" | ||
2767 | "\twhile this kernel is version %s.\n", | ||
2768 | m_filename, m_strversion, k_strversion); | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | ||
2772 | k_crcs = 0; | ||
2773 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
2774 | |||
2775 | k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); | ||
2776 | |||
2777 | if (k_new_syscalls) { | ||
2778 | #ifdef BB_FEATURE_INSMOD_NEW_KERNEL | ||
2779 | if (!new_get_kernel_symbols()) | ||
2780 | goto out; | ||
2781 | k_crcs = new_is_kernel_checksummed(); | ||
2782 | #else | ||
2783 | fprintf(stderr, "Not configured to support new kernels\n"); | ||
2784 | goto out; | ||
2785 | #endif | ||
2786 | } else { | ||
2787 | #ifdef BB_FEATURE_INSMOD_OLD_KERNEL | ||
2788 | if (!old_get_kernel_symbols()) | ||
2789 | goto out; | ||
2790 | k_crcs = old_is_kernel_checksummed(); | ||
2791 | #else | ||
2792 | fprintf(stderr, "Not configured to support old kernels\n"); | ||
2793 | goto out; | ||
2794 | #endif | ||
2795 | } | ||
2796 | |||
2797 | #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING | ||
2798 | if (m_has_modinfo) | ||
2799 | m_crcs = new_is_module_checksummed(f); | ||
2800 | else | ||
2801 | m_crcs = old_is_module_checksummed(f); | ||
2802 | |||
2803 | if (m_crcs != k_crcs) | ||
2804 | obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); | ||
2805 | #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ | ||
2806 | |||
174 | /* Let the module know about the kernel symbols. */ | 2807 | /* Let the module know about the kernel symbols. */ |
175 | add_kernel_symbols(f); | 2808 | add_kernel_symbols(f); |
176 | 2809 | ||
177 | if (!create_this_module(f, m_name)) { | 2810 | /* Allocate common symbols, symbol tables, and string tables. */ |
178 | perror("Could not create the module\n"); | 2811 | |
179 | exit(FALSE); | 2812 | if (k_new_syscalls |
2813 | ? !new_create_this_module(f, m_name) | ||
2814 | : !old_create_mod_use_count(f)) | ||
2815 | { | ||
2816 | goto out; | ||
180 | } | 2817 | } |
181 | 2818 | ||
182 | if (!obj_check_undefineds(f, quiet)) { | 2819 | if (!obj_check_undefineds(f)) { |
183 | perror("Undefined symbols in the module\n"); | 2820 | goto out; |
184 | exit(FALSE); | ||
185 | } | 2821 | } |
186 | obj_allocate_commons(f); | 2822 | obj_allocate_commons(f); |
187 | 2823 | ||
188 | /* Perse the module's arguments */ | 2824 | if (optind < argc) { |
189 | while (argc-- > 0 && *(argv++) != '\0') { | 2825 | if (m_has_modinfo |
190 | if (!process_module_arguments(f, argc - optind, argv + optind)) { | 2826 | ? !new_process_module_arguments(f, argc - optind, argv + optind) |
191 | perror("Undefined symbols in the module\n"); | 2827 | : !old_process_module_arguments(f, argc - optind, argv + optind)) |
192 | exit(FALSE); | 2828 | { |
2829 | goto out; | ||
193 | } | 2830 | } |
194 | } | 2831 | } |
195 | 2832 | ||
2833 | arch_create_got(f); | ||
2834 | hide_special_symbols(f); | ||
2835 | |||
2836 | if (k_new_syscalls) | ||
2837 | new_create_module_ksymtab(f); | ||
2838 | |||
196 | /* Find current size of the module */ | 2839 | /* Find current size of the module */ |
197 | m_size = obj_load_size(f); | 2840 | m_size = obj_load_size(f); |
198 | 2841 | ||
@@ -200,14 +2843,37 @@ extern int insmod_main(int argc, char **argv) | |||
200 | errno = 0; | 2843 | errno = 0; |
201 | m_addr = create_module(m_name, m_size); | 2844 | m_addr = create_module(m_name, m_size); |
202 | switch (errno) { | 2845 | switch (errno) { |
203 | /* yada yada */ | 2846 | case 0: |
2847 | break; | ||
2848 | case EEXIST: | ||
2849 | fprintf(stderr, "A module named %s already exists\n", m_name); | ||
2850 | goto out; | ||
2851 | case ENOMEM: | ||
2852 | fprintf(stderr, | ||
2853 | "Can't allocate kernel memory for module; needed %lu bytes\n", | ||
2854 | m_size); | ||
2855 | goto out; | ||
204 | default: | 2856 | default: |
205 | perror("create_module: %m"); | 2857 | perror("create_module: %m"); |
2858 | goto out; | ||
2859 | } | ||
206 | 2860 | ||
2861 | if (!obj_relocate(f, m_addr)) { | ||
2862 | delete_module(m_name); | ||
2863 | goto out; | ||
207 | } | 2864 | } |
208 | 2865 | ||
209 | #endif | 2866 | if (k_new_syscalls |
2867 | ? !new_init_module(m_name, f, m_size) | ||
2868 | : !old_init_module(m_name, f, m_size)) | ||
2869 | { | ||
2870 | delete_module(m_name); | ||
2871 | goto out; | ||
2872 | } | ||
2873 | |||
2874 | exit_status = TRUE; | ||
210 | 2875 | ||
2876 | out: | ||
211 | fclose(fp); | 2877 | fclose(fp); |
212 | exit(TRUE); | 2878 | exit(exit_status); |
213 | } | 2879 | } |
@@ -33,8 +33,8 @@ | |||
33 | || defined (BB_INSMOD) | 33 | || defined (BB_INSMOD) |
34 | /* same conditions as recursiveAction */ | 34 | /* same conditions as recursiveAction */ |
35 | #define bb_need_name_too_long | 35 | #define bb_need_name_too_long |
36 | #define bb_need_memory_exhausted | ||
37 | #endif | 36 | #endif |
37 | #define bb_need_memory_exhausted | ||
38 | #define BB_DECLARE_EXTERN | 38 | #define BB_DECLARE_EXTERN |
39 | #include "messages.c" | 39 | #include "messages.c" |
40 | 40 | ||
@@ -1056,7 +1056,7 @@ extern int replace_match(char *haystack, char *needle, char *newNeedle, | |||
1056 | #endif /* ! BB_REGEXP && (BB_GREP || BB_SED) */ | 1056 | #endif /* ! BB_REGEXP && (BB_GREP || BB_SED) */ |
1057 | 1057 | ||
1058 | 1058 | ||
1059 | #if defined BB_FIND | 1059 | #if defined BB_FIND || defined BB_INSMOD |
1060 | /* | 1060 | /* |
1061 | * Routine to see if a text string is matched by a wildcard pattern. | 1061 | * Routine to see if a text string is matched by a wildcard pattern. |
1062 | * Returns TRUE if the text is matched, or FALSE if it is not matched | 1062 | * Returns TRUE if the text is matched, or FALSE if it is not matched |
@@ -1156,7 +1156,7 @@ extern int check_wildcard_match(const char *text, const char *pattern) | |||
1156 | 1156 | ||
1157 | return TRUE; | 1157 | return TRUE; |
1158 | } | 1158 | } |
1159 | #endif /* BB_FIND */ | 1159 | #endif /* BB_FIND || BB_INSMOD */ |
1160 | 1160 | ||
1161 | 1161 | ||
1162 | 1162 | ||