.. | .. |
---|
12 | 12 | */ |
---|
13 | 13 | |
---|
14 | 14 | #define _GNU_SOURCE |
---|
| 15 | +#include <elf.h> |
---|
15 | 16 | #include <stdio.h> |
---|
16 | 17 | #include <ctype.h> |
---|
17 | 18 | #include <string.h> |
---|
18 | 19 | #include <limits.h> |
---|
19 | | -#include <stdbool.h> |
---|
20 | 20 | #include <errno.h> |
---|
21 | 21 | #include "modpost.h" |
---|
22 | 22 | #include "../../include/linux/license.h" |
---|
.. | .. |
---|
29 | 29 | static int all_versions = 0; |
---|
30 | 30 | /* If we are modposting external module set to 1 */ |
---|
31 | 31 | static int external_module = 0; |
---|
32 | | -/* Warn about section mismatch in vmlinux if set to 1 */ |
---|
33 | | -static int vmlinux_section_warnings = 1; |
---|
| 32 | +#define MODULE_SCMVERSION_SIZE 64 |
---|
| 33 | +static char module_scmversion[MODULE_SCMVERSION_SIZE]; |
---|
34 | 34 | /* Only warn about unresolved symbols */ |
---|
35 | 35 | static int warn_unresolved = 0; |
---|
36 | 36 | /* How a symbol is exported */ |
---|
37 | 37 | static int sec_mismatch_count = 0; |
---|
38 | | -static int sec_mismatch_verbose = 1; |
---|
39 | | -static int sec_mismatch_fatal = 0; |
---|
| 38 | +static int sec_mismatch_warn_only = true; |
---|
40 | 39 | /* ignore missing files */ |
---|
41 | 40 | static int ignore_missing_files; |
---|
| 41 | +/* If set to 1, only warn (instead of error) about missing ns imports */ |
---|
| 42 | +static int allow_missing_ns_imports; |
---|
| 43 | + |
---|
| 44 | +static bool error_occurred; |
---|
42 | 45 | |
---|
43 | 46 | enum export { |
---|
44 | 47 | export_plain, export_unused, export_gpl, |
---|
.. | .. |
---|
51 | 54 | |
---|
52 | 55 | #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) |
---|
53 | 56 | |
---|
54 | | -#define PRINTF __attribute__ ((format (printf, 1, 2))) |
---|
55 | | - |
---|
56 | | -PRINTF void fatal(const char *fmt, ...) |
---|
| 57 | +void __attribute__((format(printf, 2, 3))) |
---|
| 58 | +modpost_log(enum loglevel loglevel, const char *fmt, ...) |
---|
57 | 59 | { |
---|
58 | 60 | va_list arglist; |
---|
59 | 61 | |
---|
60 | | - fprintf(stderr, "FATAL: "); |
---|
| 62 | + switch (loglevel) { |
---|
| 63 | + case LOG_WARN: |
---|
| 64 | + fprintf(stderr, "WARNING: "); |
---|
| 65 | + break; |
---|
| 66 | + case LOG_ERROR: |
---|
| 67 | + fprintf(stderr, "ERROR: "); |
---|
| 68 | + break; |
---|
| 69 | + case LOG_FATAL: |
---|
| 70 | + fprintf(stderr, "FATAL: "); |
---|
| 71 | + break; |
---|
| 72 | + default: /* invalid loglevel, ignore */ |
---|
| 73 | + break; |
---|
| 74 | + } |
---|
| 75 | + |
---|
| 76 | + fprintf(stderr, "modpost: "); |
---|
61 | 77 | |
---|
62 | 78 | va_start(arglist, fmt); |
---|
63 | 79 | vfprintf(stderr, fmt, arglist); |
---|
64 | 80 | va_end(arglist); |
---|
65 | 81 | |
---|
66 | | - exit(1); |
---|
67 | | -} |
---|
68 | | - |
---|
69 | | -PRINTF void warn(const char *fmt, ...) |
---|
70 | | -{ |
---|
71 | | - va_list arglist; |
---|
72 | | - |
---|
73 | | - fprintf(stderr, "WARNING: "); |
---|
74 | | - |
---|
75 | | - va_start(arglist, fmt); |
---|
76 | | - vfprintf(stderr, fmt, arglist); |
---|
77 | | - va_end(arglist); |
---|
78 | | -} |
---|
79 | | - |
---|
80 | | -PRINTF void merror(const char *fmt, ...) |
---|
81 | | -{ |
---|
82 | | - va_list arglist; |
---|
83 | | - |
---|
84 | | - fprintf(stderr, "ERROR: "); |
---|
85 | | - |
---|
86 | | - va_start(arglist, fmt); |
---|
87 | | - vfprintf(stderr, fmt, arglist); |
---|
88 | | - va_end(arglist); |
---|
89 | | -} |
---|
90 | | - |
---|
91 | | -static inline bool strends(const char *str, const char *postfix) |
---|
92 | | -{ |
---|
93 | | - if (strlen(str) < strlen(postfix)) |
---|
94 | | - return false; |
---|
95 | | - |
---|
96 | | - return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; |
---|
97 | | -} |
---|
98 | | - |
---|
99 | | -static int is_vmlinux(const char *modname) |
---|
100 | | -{ |
---|
101 | | - const char *myname; |
---|
102 | | - |
---|
103 | | - myname = strrchr(modname, '/'); |
---|
104 | | - if (myname) |
---|
105 | | - myname++; |
---|
106 | | - else |
---|
107 | | - myname = modname; |
---|
108 | | - |
---|
109 | | - return (strcmp(myname, "vmlinux") == 0) || |
---|
110 | | - (strcmp(myname, "vmlinux.o") == 0); |
---|
| 82 | + if (loglevel == LOG_FATAL) |
---|
| 83 | + exit(1); |
---|
| 84 | + if (loglevel == LOG_ERROR) |
---|
| 85 | + error_occurred = true; |
---|
111 | 86 | } |
---|
112 | 87 | |
---|
113 | 88 | void *do_nofail(void *ptr, const char *expr) |
---|
114 | 89 | { |
---|
115 | 90 | if (!ptr) |
---|
116 | | - fatal("modpost: Memory allocation failure: %s.\n", expr); |
---|
| 91 | + fatal("Memory allocation failure: %s.\n", expr); |
---|
117 | 92 | |
---|
118 | 93 | return ptr; |
---|
| 94 | +} |
---|
| 95 | + |
---|
| 96 | +char *read_text_file(const char *filename) |
---|
| 97 | +{ |
---|
| 98 | + struct stat st; |
---|
| 99 | + size_t nbytes; |
---|
| 100 | + int fd; |
---|
| 101 | + char *buf; |
---|
| 102 | + |
---|
| 103 | + fd = open(filename, O_RDONLY); |
---|
| 104 | + if (fd < 0) { |
---|
| 105 | + perror(filename); |
---|
| 106 | + exit(1); |
---|
| 107 | + } |
---|
| 108 | + |
---|
| 109 | + if (fstat(fd, &st) < 0) { |
---|
| 110 | + perror(filename); |
---|
| 111 | + exit(1); |
---|
| 112 | + } |
---|
| 113 | + |
---|
| 114 | + buf = NOFAIL(malloc(st.st_size + 1)); |
---|
| 115 | + |
---|
| 116 | + nbytes = st.st_size; |
---|
| 117 | + |
---|
| 118 | + while (nbytes) { |
---|
| 119 | + ssize_t bytes_read; |
---|
| 120 | + |
---|
| 121 | + bytes_read = read(fd, buf, nbytes); |
---|
| 122 | + if (bytes_read < 0) { |
---|
| 123 | + perror(filename); |
---|
| 124 | + exit(1); |
---|
| 125 | + } |
---|
| 126 | + |
---|
| 127 | + nbytes -= bytes_read; |
---|
| 128 | + } |
---|
| 129 | + buf[st.st_size] = '\0'; |
---|
| 130 | + |
---|
| 131 | + close(fd); |
---|
| 132 | + |
---|
| 133 | + return buf; |
---|
| 134 | +} |
---|
| 135 | + |
---|
| 136 | +char *get_line(char **stringp) |
---|
| 137 | +{ |
---|
| 138 | + char *orig = *stringp, *next; |
---|
| 139 | + |
---|
| 140 | + /* do not return the unwanted extra line at EOF */ |
---|
| 141 | + if (!orig || *orig == '\0') |
---|
| 142 | + return NULL; |
---|
| 143 | + |
---|
| 144 | + /* don't use strsep here, it is not available everywhere */ |
---|
| 145 | + next = strchr(orig, '\n'); |
---|
| 146 | + if (next) |
---|
| 147 | + *next++ = '\0'; |
---|
| 148 | + |
---|
| 149 | + *stringp = next; |
---|
| 150 | + |
---|
| 151 | + return orig; |
---|
119 | 152 | } |
---|
120 | 153 | |
---|
121 | 154 | /* A list of all modules we processed */ |
---|
.. | .. |
---|
134 | 167 | static struct module *new_module(const char *modname) |
---|
135 | 168 | { |
---|
136 | 169 | struct module *mod; |
---|
137 | | - char *p; |
---|
138 | 170 | |
---|
139 | | - mod = NOFAIL(malloc(sizeof(*mod))); |
---|
| 171 | + mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1)); |
---|
140 | 172 | memset(mod, 0, sizeof(*mod)); |
---|
141 | | - p = NOFAIL(strdup(modname)); |
---|
142 | | - |
---|
143 | | - /* strip trailing .o */ |
---|
144 | | - if (strends(p, ".o")) { |
---|
145 | | - p[strlen(p) - 2] = '\0'; |
---|
146 | | - mod->is_dot_o = 1; |
---|
147 | | - } |
---|
148 | | - /* strip trailing .lto */ |
---|
149 | | - if (strends(p, ".lto")) |
---|
150 | | - p[strlen(p) - 4] = '\0'; |
---|
151 | 173 | |
---|
152 | 174 | /* add to list */ |
---|
153 | | - mod->name = p; |
---|
| 175 | + strcpy(mod->name, modname); |
---|
| 176 | + mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0); |
---|
154 | 177 | mod->gpl_compatible = -1; |
---|
155 | 178 | mod->next = modules; |
---|
156 | 179 | modules = mod; |
---|
| 180 | + |
---|
| 181 | + if (mod->is_vmlinux) |
---|
| 182 | + have_vmlinux = 1; |
---|
157 | 183 | |
---|
158 | 184 | return mod; |
---|
159 | 185 | } |
---|
.. | .. |
---|
168 | 194 | struct module *module; |
---|
169 | 195 | unsigned int crc; |
---|
170 | 196 | int crc_valid; |
---|
| 197 | + char *namespace; |
---|
171 | 198 | unsigned int weak:1; |
---|
172 | | - unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ |
---|
173 | | - unsigned int kernel:1; /* 1 if symbol is from kernel |
---|
174 | | - * (only for external modules) **/ |
---|
175 | | - unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ |
---|
| 199 | + unsigned int is_static:1; /* 1 if symbol is not global */ |
---|
176 | 200 | enum export export; /* Type of export */ |
---|
177 | | - char name[0]; |
---|
| 201 | + char name[]; |
---|
178 | 202 | }; |
---|
179 | 203 | |
---|
180 | 204 | static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; |
---|
.. | .. |
---|
205 | 229 | strcpy(s->name, name); |
---|
206 | 230 | s->weak = weak; |
---|
207 | 231 | s->next = next; |
---|
| 232 | + s->is_static = 1; |
---|
208 | 233 | return s; |
---|
209 | 234 | } |
---|
210 | 235 | |
---|
.. | .. |
---|
213 | 238 | enum export export) |
---|
214 | 239 | { |
---|
215 | 240 | unsigned int hash; |
---|
216 | | - struct symbol *new; |
---|
217 | 241 | |
---|
218 | 242 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; |
---|
219 | | - new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
---|
220 | | - new->module = module; |
---|
221 | | - new->export = export; |
---|
222 | | - return new; |
---|
| 243 | + symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
---|
| 244 | + |
---|
| 245 | + return symbolhash[hash]; |
---|
223 | 246 | } |
---|
224 | 247 | |
---|
225 | 248 | static struct symbol *find_symbol(const char *name) |
---|
.. | .. |
---|
235 | 258 | return s; |
---|
236 | 259 | } |
---|
237 | 260 | return NULL; |
---|
| 261 | +} |
---|
| 262 | + |
---|
| 263 | +static bool contains_namespace(struct namespace_list *list, |
---|
| 264 | + const char *namespace) |
---|
| 265 | +{ |
---|
| 266 | + for (; list; list = list->next) |
---|
| 267 | + if (!strcmp(list->namespace, namespace)) |
---|
| 268 | + return true; |
---|
| 269 | + |
---|
| 270 | + return false; |
---|
| 271 | +} |
---|
| 272 | + |
---|
| 273 | +static void add_namespace(struct namespace_list **list, const char *namespace) |
---|
| 274 | +{ |
---|
| 275 | + struct namespace_list *ns_entry; |
---|
| 276 | + |
---|
| 277 | + if (!contains_namespace(*list, namespace)) { |
---|
| 278 | + ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) + |
---|
| 279 | + strlen(namespace) + 1)); |
---|
| 280 | + strcpy(ns_entry->namespace, namespace); |
---|
| 281 | + ns_entry->next = *list; |
---|
| 282 | + *list = ns_entry; |
---|
| 283 | + } |
---|
| 284 | +} |
---|
| 285 | + |
---|
| 286 | +static bool module_imports_namespace(struct module *module, |
---|
| 287 | + const char *namespace) |
---|
| 288 | +{ |
---|
| 289 | + return contains_namespace(module->imported_namespaces, namespace); |
---|
238 | 290 | } |
---|
239 | 291 | |
---|
240 | 292 | static const struct { |
---|
.. | .. |
---|
268 | 320 | return export_unknown; |
---|
269 | 321 | } |
---|
270 | 322 | |
---|
271 | | -static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) |
---|
| 323 | +static void *sym_get_data_by_offset(const struct elf_info *info, |
---|
| 324 | + unsigned int secindex, unsigned long offset) |
---|
272 | 325 | { |
---|
273 | | - return (void *)elf->hdr + |
---|
274 | | - elf->sechdrs[elf->secindex_strings].sh_offset + |
---|
275 | | - sechdr->sh_name; |
---|
| 326 | + Elf_Shdr *sechdr = &info->sechdrs[secindex]; |
---|
| 327 | + |
---|
| 328 | + if (info->hdr->e_type != ET_REL) |
---|
| 329 | + offset -= sechdr->sh_addr; |
---|
| 330 | + |
---|
| 331 | + return (void *)info->hdr + sechdr->sh_offset + offset; |
---|
276 | 332 | } |
---|
277 | 333 | |
---|
278 | | -static const char *sec_name(struct elf_info *elf, int secindex) |
---|
| 334 | +static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) |
---|
279 | 335 | { |
---|
280 | | - return sech_name(elf, &elf->sechdrs[secindex]); |
---|
| 336 | + return sym_get_data_by_offset(info, get_secindex(info, sym), |
---|
| 337 | + sym->st_value); |
---|
| 338 | +} |
---|
| 339 | + |
---|
| 340 | +static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr) |
---|
| 341 | +{ |
---|
| 342 | + return sym_get_data_by_offset(info, info->secindex_strings, |
---|
| 343 | + sechdr->sh_name); |
---|
| 344 | +} |
---|
| 345 | + |
---|
| 346 | +static const char *sec_name(const struct elf_info *info, int secindex) |
---|
| 347 | +{ |
---|
| 348 | + return sech_name(info, &info->sechdrs[secindex]); |
---|
281 | 349 | } |
---|
282 | 350 | |
---|
283 | 351 | #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) |
---|
.. | .. |
---|
316 | 384 | return export_unknown; |
---|
317 | 385 | } |
---|
318 | 386 | |
---|
| 387 | +static const char *namespace_from_kstrtabns(const struct elf_info *info, |
---|
| 388 | + const Elf_Sym *sym) |
---|
| 389 | +{ |
---|
| 390 | + const char *value = sym_get_data(info, sym); |
---|
| 391 | + return value[0] ? value : NULL; |
---|
| 392 | +} |
---|
| 393 | + |
---|
| 394 | +static void sym_update_namespace(const char *symname, const char *namespace) |
---|
| 395 | +{ |
---|
| 396 | + struct symbol *s = find_symbol(symname); |
---|
| 397 | + |
---|
| 398 | + /* |
---|
| 399 | + * That symbol should have been created earlier and thus this is |
---|
| 400 | + * actually an assertion. |
---|
| 401 | + */ |
---|
| 402 | + if (!s) { |
---|
| 403 | + error("Could not update namespace(%s) for symbol %s\n", |
---|
| 404 | + namespace, symname); |
---|
| 405 | + return; |
---|
| 406 | + } |
---|
| 407 | + |
---|
| 408 | + free(s->namespace); |
---|
| 409 | + s->namespace = |
---|
| 410 | + namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL; |
---|
| 411 | +} |
---|
| 412 | + |
---|
319 | 413 | /** |
---|
320 | 414 | * Add an exported symbol - it may have already been added without a |
---|
321 | 415 | * CRC, in this case just update the CRC |
---|
.. | .. |
---|
327 | 421 | |
---|
328 | 422 | if (!s) { |
---|
329 | 423 | s = new_symbol(name, mod, export); |
---|
330 | | - } else { |
---|
331 | | - if (!s->preloaded) { |
---|
332 | | - warn("%s: '%s' exported twice. Previous export " |
---|
333 | | - "was in %s%s\n", mod->name, name, |
---|
334 | | - s->module->name, |
---|
335 | | - is_vmlinux(s->module->name) ?"":".ko"); |
---|
336 | | - } else { |
---|
337 | | - /* In case Module.symvers was out of date */ |
---|
338 | | - s->module = mod; |
---|
339 | | - } |
---|
| 424 | + } else if (!external_module || s->module->is_vmlinux || |
---|
| 425 | + s->module == mod) { |
---|
| 426 | + fatal("%s: '%s' exported twice. Previous export was in %s%s\n", |
---|
| 427 | + mod->name, name, s->module->name, |
---|
| 428 | + s->module->is_vmlinux ? "" : ".ko"); |
---|
340 | 429 | } |
---|
341 | | - s->preloaded = 0; |
---|
342 | | - s->vmlinux = is_vmlinux(mod->name); |
---|
343 | | - s->kernel = 0; |
---|
| 430 | + |
---|
| 431 | + s->module = mod; |
---|
344 | 432 | s->export = export; |
---|
345 | 433 | return s; |
---|
346 | 434 | } |
---|
347 | 435 | |
---|
348 | | -static void sym_update_crc(const char *name, struct module *mod, |
---|
349 | | - unsigned int crc, enum export export) |
---|
| 436 | +static void sym_set_crc(const char *name, unsigned int crc) |
---|
350 | 437 | { |
---|
351 | 438 | struct symbol *s = find_symbol(name); |
---|
352 | 439 | |
---|
353 | | - if (!s) { |
---|
354 | | - s = new_symbol(name, mod, export); |
---|
355 | | - /* Don't complain when we find it later. */ |
---|
356 | | - s->preloaded = 1; |
---|
357 | | - } |
---|
| 440 | + /* |
---|
| 441 | + * Ignore stand-alone __crc_*, which might be auto-generated symbols |
---|
| 442 | + * such as __*_veneer in ARM ELF. |
---|
| 443 | + */ |
---|
| 444 | + if (!s) |
---|
| 445 | + return; |
---|
| 446 | + |
---|
358 | 447 | s->crc = crc; |
---|
359 | 448 | s->crc_valid = 1; |
---|
360 | 449 | } |
---|
361 | 450 | |
---|
362 | | -void *grab_file(const char *filename, unsigned long *size) |
---|
| 451 | +static void *grab_file(const char *filename, size_t *size) |
---|
363 | 452 | { |
---|
364 | 453 | struct stat st; |
---|
365 | 454 | void *map = MAP_FAILED; |
---|
.. | .. |
---|
381 | 470 | return map; |
---|
382 | 471 | } |
---|
383 | 472 | |
---|
384 | | -/** |
---|
385 | | - * Return a copy of the next line in a mmap'ed file. |
---|
386 | | - * spaces in the beginning of the line is trimmed away. |
---|
387 | | - * Return a pointer to a static buffer. |
---|
388 | | - **/ |
---|
389 | | -char *get_next_line(unsigned long *pos, void *file, unsigned long size) |
---|
390 | | -{ |
---|
391 | | - static char line[4096]; |
---|
392 | | - int skip = 1; |
---|
393 | | - size_t len = 0; |
---|
394 | | - signed char *p = (signed char *)file + *pos; |
---|
395 | | - char *s = line; |
---|
396 | | - |
---|
397 | | - for (; *pos < size ; (*pos)++) { |
---|
398 | | - if (skip && isspace(*p)) { |
---|
399 | | - p++; |
---|
400 | | - continue; |
---|
401 | | - } |
---|
402 | | - skip = 0; |
---|
403 | | - if (*p != '\n' && (*pos < size)) { |
---|
404 | | - len++; |
---|
405 | | - *s++ = *p++; |
---|
406 | | - if (len > 4095) |
---|
407 | | - break; /* Too long, stop */ |
---|
408 | | - } else { |
---|
409 | | - /* End of string */ |
---|
410 | | - *s = '\0'; |
---|
411 | | - return line; |
---|
412 | | - } |
---|
413 | | - } |
---|
414 | | - /* End of buffer */ |
---|
415 | | - return NULL; |
---|
416 | | -} |
---|
417 | | - |
---|
418 | | -void release_file(void *file, unsigned long size) |
---|
| 473 | +static void release_file(void *file, size_t size) |
---|
419 | 474 | { |
---|
420 | 475 | munmap(file, size); |
---|
421 | 476 | } |
---|
.. | .. |
---|
471 | 526 | |
---|
472 | 527 | /* Check if file offset is correct */ |
---|
473 | 528 | if (hdr->e_shoff > info->size) { |
---|
474 | | - fatal("section header offset=%lu in file '%s' is bigger than " |
---|
475 | | - "filesize=%lu\n", (unsigned long)hdr->e_shoff, |
---|
476 | | - filename, info->size); |
---|
| 529 | + fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", |
---|
| 530 | + (unsigned long)hdr->e_shoff, filename, info->size); |
---|
477 | 531 | return 0; |
---|
478 | 532 | } |
---|
479 | 533 | |
---|
.. | .. |
---|
618 | 672 | return 0; |
---|
619 | 673 | } |
---|
620 | 674 | |
---|
621 | | -static void handle_modversions(struct module *mod, struct elf_info *info, |
---|
622 | | - Elf_Sym *sym, const char *symname) |
---|
| 675 | +static void handle_modversion(const struct module *mod, |
---|
| 676 | + const struct elf_info *info, |
---|
| 677 | + const Elf_Sym *sym, const char *symname) |
---|
623 | 678 | { |
---|
624 | 679 | unsigned int crc; |
---|
625 | | - enum export export; |
---|
626 | | - bool is_crc = false; |
---|
627 | 680 | |
---|
628 | | - if ((!is_vmlinux(mod->name) || mod->is_dot_o) && |
---|
629 | | - strstarts(symname, "__ksymtab")) |
---|
| 681 | + if (sym->st_shndx == SHN_UNDEF) { |
---|
| 682 | + warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", |
---|
| 683 | + symname, mod->name, mod->is_vmlinux ? "" : ".ko"); |
---|
| 684 | + return; |
---|
| 685 | + } |
---|
| 686 | + |
---|
| 687 | + if (sym->st_shndx == SHN_ABS) { |
---|
| 688 | + crc = sym->st_value; |
---|
| 689 | + } else { |
---|
| 690 | + unsigned int *crcp; |
---|
| 691 | + |
---|
| 692 | + /* symbol points to the CRC in the ELF object */ |
---|
| 693 | + crcp = sym_get_data(info, sym); |
---|
| 694 | + crc = TO_NATIVE(*crcp); |
---|
| 695 | + } |
---|
| 696 | + sym_set_crc(symname, crc); |
---|
| 697 | +} |
---|
| 698 | + |
---|
| 699 | +static void handle_symbol(struct module *mod, struct elf_info *info, |
---|
| 700 | + const Elf_Sym *sym, const char *symname) |
---|
| 701 | +{ |
---|
| 702 | + enum export export; |
---|
| 703 | + const char *name; |
---|
| 704 | + |
---|
| 705 | + if (strstarts(symname, "__ksymtab")) |
---|
630 | 706 | export = export_from_secname(info, get_secindex(info, sym)); |
---|
631 | 707 | else |
---|
632 | 708 | export = export_from_sec(info, get_secindex(info, sym)); |
---|
633 | | - |
---|
634 | | - /* CRC'd symbol */ |
---|
635 | | - if (strstarts(symname, "__crc_")) { |
---|
636 | | - is_crc = true; |
---|
637 | | - crc = (unsigned int) sym->st_value; |
---|
638 | | - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) { |
---|
639 | | - unsigned int *crcp; |
---|
640 | | - |
---|
641 | | - /* symbol points to the CRC in the ELF object */ |
---|
642 | | - crcp = (void *)info->hdr + sym->st_value + |
---|
643 | | - info->sechdrs[sym->st_shndx].sh_offset - |
---|
644 | | - (info->hdr->e_type != ET_REL ? |
---|
645 | | - info->sechdrs[sym->st_shndx].sh_addr : 0); |
---|
646 | | - crc = TO_NATIVE(*crcp); |
---|
647 | | - } |
---|
648 | | - sym_update_crc(symname + strlen("__crc_"), mod, crc, |
---|
649 | | - export); |
---|
650 | | - } |
---|
651 | 709 | |
---|
652 | 710 | switch (sym->st_shndx) { |
---|
653 | 711 | case SHN_COMMON: |
---|
.. | .. |
---|
663 | 721 | break; |
---|
664 | 722 | if (ignore_undef_symbol(info, symname)) |
---|
665 | 723 | break; |
---|
666 | | -/* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ |
---|
667 | | -#if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) |
---|
668 | | -/* add compatibility with older glibc */ |
---|
669 | | -#ifndef STT_SPARC_REGISTER |
---|
670 | | -#define STT_SPARC_REGISTER STT_REGISTER |
---|
671 | | -#endif |
---|
672 | 724 | if (info->hdr->e_machine == EM_SPARC || |
---|
673 | 725 | info->hdr->e_machine == EM_SPARCV9) { |
---|
674 | 726 | /* Ignore register directives. */ |
---|
.. | .. |
---|
681 | 733 | symname = munged; |
---|
682 | 734 | } |
---|
683 | 735 | } |
---|
684 | | -#endif |
---|
685 | 736 | |
---|
686 | | - if (is_crc) { |
---|
687 | | - const char *e = is_vmlinux(mod->name) ?"":".ko"; |
---|
688 | | - warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", |
---|
689 | | - symname + strlen("__crc_"), mod->name, e); |
---|
690 | | - } |
---|
691 | 737 | mod->unres = alloc_symbol(symname, |
---|
692 | 738 | ELF_ST_BIND(sym->st_info) == STB_WEAK, |
---|
693 | 739 | mod->unres); |
---|
.. | .. |
---|
695 | 741 | default: |
---|
696 | 742 | /* All exported symbols */ |
---|
697 | 743 | if (strstarts(symname, "__ksymtab_")) { |
---|
698 | | - sym_add_exported(symname + strlen("__ksymtab_"), mod, |
---|
699 | | - export); |
---|
| 744 | + name = symname + strlen("__ksymtab_"); |
---|
| 745 | + sym_add_exported(name, mod, export); |
---|
700 | 746 | } |
---|
701 | 747 | if (strcmp(symname, "init_module") == 0) |
---|
702 | 748 | mod->has_init = 1; |
---|
.. | .. |
---|
799 | 845 | |
---|
800 | 846 | /* "*foo*" */ |
---|
801 | 847 | if (*p == '*' && *endp == '*') { |
---|
802 | | - char *here, *bare = strndup(p + 1, strlen(p) - 2); |
---|
| 848 | + char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2)); |
---|
| 849 | + char *here = strstr(sym, bare); |
---|
803 | 850 | |
---|
804 | | - here = strstr(sym, bare); |
---|
805 | 851 | free(bare); |
---|
806 | 852 | if (here != NULL) |
---|
807 | 853 | return 1; |
---|
.. | .. |
---|
945 | 991 | static const char *const linker_symbols[] = |
---|
946 | 992 | { "__init_begin", "_sinittext", "_einittext", NULL }; |
---|
947 | 993 | static const char *const optim_symbols[] = { "*.constprop.*", NULL }; |
---|
948 | | -static const char *const cfi_symbols[] = { "*.cfi", NULL }; |
---|
949 | 994 | |
---|
950 | 995 | enum mismatch { |
---|
951 | 996 | TEXT_TO_ANY_INIT, |
---|
.. | .. |
---|
1070 | 1115 | }, |
---|
1071 | 1116 | /* Do not export init/exit functions or data */ |
---|
1072 | 1117 | { |
---|
1073 | | - .fromsec = { "__ksymtab*", NULL }, |
---|
| 1118 | + .fromsec = { "___ksymtab*", NULL }, |
---|
1074 | 1119 | .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, |
---|
1075 | 1120 | .mismatch = EXPORT_TO_INIT_EXIT, |
---|
1076 | 1121 | .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, |
---|
.. | .. |
---|
1175 | 1220 | * whitelisting, which relies on pattern-matching against symbol |
---|
1176 | 1221 | * names to work. (One situation where gcc can autogenerate ELF |
---|
1177 | 1222 | * local symbols is when "-fsection-anchors" is used.) |
---|
1178 | | - * |
---|
1179 | | - * Pattern 7: |
---|
1180 | | - * With CONFIG_CFI_CLANG, clang appends .cfi to all indirectly called |
---|
1181 | | - * functions and creates a function stub with the original name. This |
---|
1182 | | - * stub is always placed in .text, even if the actual function with the |
---|
1183 | | - * .cfi postfix is in .init.text or .exit.text. |
---|
1184 | | - * This pattern is identified by |
---|
1185 | | - * tosec = init or exit section |
---|
1186 | | - * fromsec = text section |
---|
1187 | | - * tosym = *.cfi |
---|
1188 | | - * |
---|
1189 | 1223 | **/ |
---|
1190 | 1224 | static int secref_whitelist(const struct sectioncheck *mismatch, |
---|
1191 | 1225 | const char *fromsec, const char *fromsym, |
---|
.. | .. |
---|
1228 | 1262 | if (strstarts(fromsym, ".L")) |
---|
1229 | 1263 | return 0; |
---|
1230 | 1264 | |
---|
1231 | | - /* Check for pattern 7 */ |
---|
1232 | | - if (match(fromsec, text_sections) && |
---|
1233 | | - match(tosec, init_exit_sections) && |
---|
1234 | | - match(tosym, cfi_symbols)) |
---|
1235 | | - return 0; |
---|
1236 | | - |
---|
1237 | 1265 | return 1; |
---|
1238 | 1266 | } |
---|
1239 | 1267 | |
---|
1240 | 1268 | static inline int is_arm_mapping_symbol(const char *str) |
---|
1241 | 1269 | { |
---|
1242 | | - return str[0] == '$' && strchr("axtd", str[1]) |
---|
| 1270 | + return str[0] == '$' && |
---|
| 1271 | + (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x') |
---|
1243 | 1272 | && (str[2] == '\0' || str[2] == '.'); |
---|
1244 | 1273 | } |
---|
1245 | 1274 | |
---|
.. | .. |
---|
1280 | 1309 | if (relsym->st_name != 0) |
---|
1281 | 1310 | return relsym; |
---|
1282 | 1311 | |
---|
| 1312 | + /* |
---|
| 1313 | + * Strive to find a better symbol name, but the resulting name may not |
---|
| 1314 | + * match the symbol referenced in the original code. |
---|
| 1315 | + */ |
---|
1283 | 1316 | relsym_secindex = get_secindex(elf, relsym); |
---|
1284 | 1317 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { |
---|
1285 | 1318 | if (get_secindex(elf, sym) != relsym_secindex) |
---|
.. | .. |
---|
1427 | 1460 | char *prl_to; |
---|
1428 | 1461 | |
---|
1429 | 1462 | sec_mismatch_count++; |
---|
1430 | | - if (!sec_mismatch_verbose) |
---|
1431 | | - return; |
---|
1432 | 1463 | |
---|
1433 | 1464 | get_pretty_name(from_is_func, &from, &from_p); |
---|
1434 | 1465 | get_pretty_name(to_is_func, &to, &to_p); |
---|
.. | .. |
---|
1586 | 1617 | |
---|
1587 | 1618 | static int is_executable_section(struct elf_info* elf, unsigned int section_index) |
---|
1588 | 1619 | { |
---|
1589 | | - if (section_index > elf->num_sections) |
---|
| 1620 | + if (section_index >= elf->num_sections) |
---|
1590 | 1621 | fatal("section_index is outside elf->num_sections!\n"); |
---|
1591 | 1622 | |
---|
1592 | 1623 | return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); |
---|
.. | .. |
---|
1676 | 1707 | |
---|
1677 | 1708 | sec_mismatch_count++; |
---|
1678 | 1709 | |
---|
1679 | | - if (sec_mismatch_verbose) |
---|
1680 | | - report_extable_warnings(modname, elf, mismatch, r, sym, |
---|
1681 | | - fromsec, tosec); |
---|
| 1710 | + report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec); |
---|
1682 | 1711 | |
---|
1683 | 1712 | if (match(tosec, mismatch->bad_tosec)) |
---|
1684 | 1713 | fatal("The relocation at %s+0x%lx references\n" |
---|
.. | .. |
---|
1724 | 1753 | static unsigned int *reloc_location(struct elf_info *elf, |
---|
1725 | 1754 | Elf_Shdr *sechdr, Elf_Rela *r) |
---|
1726 | 1755 | { |
---|
1727 | | - Elf_Shdr *sechdrs = elf->sechdrs; |
---|
1728 | | - int section = sechdr->sh_info; |
---|
1729 | | - |
---|
1730 | | - return (void *)elf->hdr + sechdrs[section].sh_offset + |
---|
1731 | | - r->r_offset; |
---|
| 1756 | + return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset); |
---|
1732 | 1757 | } |
---|
1733 | 1758 | |
---|
1734 | 1759 | static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
---|
.. | .. |
---|
1767 | 1792 | #define R_ARM_THM_JUMP19 51 |
---|
1768 | 1793 | #endif |
---|
1769 | 1794 | |
---|
| 1795 | +static int32_t sign_extend32(int32_t value, int index) |
---|
| 1796 | +{ |
---|
| 1797 | + uint8_t shift = 31 - index; |
---|
| 1798 | + |
---|
| 1799 | + return (int32_t)(value << shift) >> shift; |
---|
| 1800 | +} |
---|
| 1801 | + |
---|
1770 | 1802 | static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
---|
1771 | 1803 | { |
---|
1772 | 1804 | unsigned int r_typ = ELF_R_TYPE(r->r_info); |
---|
| 1805 | + Elf_Sym *sym = elf->symtab_start + ELF_R_SYM(r->r_info); |
---|
| 1806 | + void *loc = reloc_location(elf, sechdr, r); |
---|
| 1807 | + uint32_t inst; |
---|
| 1808 | + int32_t offset; |
---|
1773 | 1809 | |
---|
1774 | 1810 | switch (r_typ) { |
---|
1775 | 1811 | case R_ARM_ABS32: |
---|
1776 | | - /* From ARM ABI: (S + A) | T */ |
---|
1777 | | - r->r_addend = (int)(long) |
---|
1778 | | - (elf->symtab_start + ELF_R_SYM(r->r_info)); |
---|
| 1812 | + inst = TO_NATIVE(*(uint32_t *)loc); |
---|
| 1813 | + r->r_addend = inst + sym->st_value; |
---|
1779 | 1814 | break; |
---|
1780 | 1815 | case R_ARM_PC24: |
---|
1781 | 1816 | case R_ARM_CALL: |
---|
1782 | 1817 | case R_ARM_JUMP24: |
---|
| 1818 | + inst = TO_NATIVE(*(uint32_t *)loc); |
---|
| 1819 | + offset = sign_extend32((inst & 0x00ffffff) << 2, 25); |
---|
| 1820 | + r->r_addend = offset + sym->st_value + 8; |
---|
| 1821 | + break; |
---|
1783 | 1822 | case R_ARM_THM_CALL: |
---|
1784 | 1823 | case R_ARM_THM_JUMP24: |
---|
1785 | 1824 | case R_ARM_THM_JUMP19: |
---|
.. | .. |
---|
1958 | 1997 | |
---|
1959 | 1998 | if (n && s[n]) { |
---|
1960 | 1999 | size_t m = strspn(s + n + 1, "0123456789"); |
---|
1961 | | - if (m && (s[n + m] == '.' || s[n + m] == 0)) |
---|
| 2000 | + if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0)) |
---|
1962 | 2001 | s[n] = 0; |
---|
1963 | 2002 | |
---|
1964 | 2003 | /* strip trailing .lto */ |
---|
.. | .. |
---|
1973 | 2012 | const char *symname; |
---|
1974 | 2013 | char *version; |
---|
1975 | 2014 | char *license; |
---|
| 2015 | + char *namespace; |
---|
1976 | 2016 | struct module *mod; |
---|
1977 | 2017 | struct elf_info info = { }; |
---|
1978 | 2018 | Elf_Sym *sym; |
---|
.. | .. |
---|
1980 | 2020 | if (!parse_elf(&info, modname)) |
---|
1981 | 2021 | return; |
---|
1982 | 2022 | |
---|
1983 | | - mod = new_module(modname); |
---|
| 2023 | + { |
---|
| 2024 | + char *tmp; |
---|
1984 | 2025 | |
---|
1985 | | - /* When there's no vmlinux, don't print warnings about |
---|
1986 | | - * unresolved symbols (since there'll be too many ;) */ |
---|
1987 | | - if (is_vmlinux(modname)) { |
---|
1988 | | - have_vmlinux = 1; |
---|
1989 | | - mod->skip = 1; |
---|
| 2026 | + /* strip trailing .o */ |
---|
| 2027 | + tmp = NOFAIL(strdup(modname)); |
---|
| 2028 | + tmp[strlen(tmp) - 2] = '\0'; |
---|
| 2029 | + /* strip trailing .lto */ |
---|
| 2030 | + if (strends(tmp, ".lto")) |
---|
| 2031 | + tmp[strlen(tmp) - 4] = '\0'; |
---|
| 2032 | + mod = new_module(tmp); |
---|
| 2033 | + free(tmp); |
---|
1990 | 2034 | } |
---|
1991 | 2035 | |
---|
1992 | | - license = get_modinfo(&info, "license"); |
---|
1993 | | - if (!license && !is_vmlinux(modname)) |
---|
1994 | | - warn("modpost: missing MODULE_LICENSE() in %s\n" |
---|
1995 | | - "see include/linux/module.h for " |
---|
1996 | | - "more information\n", modname); |
---|
1997 | | - while (license) { |
---|
1998 | | - if (license_is_gpl_compatible(license)) |
---|
1999 | | - mod->gpl_compatible = 1; |
---|
2000 | | - else { |
---|
2001 | | - mod->gpl_compatible = 0; |
---|
2002 | | - break; |
---|
| 2036 | + if (!mod->is_vmlinux) { |
---|
| 2037 | + license = get_modinfo(&info, "license"); |
---|
| 2038 | + if (!license) |
---|
| 2039 | + error("missing MODULE_LICENSE() in %s\n", modname); |
---|
| 2040 | + while (license) { |
---|
| 2041 | + if (license_is_gpl_compatible(license)) |
---|
| 2042 | + mod->gpl_compatible = 1; |
---|
| 2043 | + else { |
---|
| 2044 | + mod->gpl_compatible = 0; |
---|
| 2045 | + break; |
---|
| 2046 | + } |
---|
| 2047 | + license = get_next_modinfo(&info, "license", license); |
---|
2003 | 2048 | } |
---|
2004 | | - license = get_next_modinfo(&info, "license", license); |
---|
| 2049 | + |
---|
| 2050 | + namespace = get_modinfo(&info, "import_ns"); |
---|
| 2051 | + while (namespace) { |
---|
| 2052 | + add_namespace(&mod->imported_namespaces, namespace); |
---|
| 2053 | + namespace = get_next_modinfo(&info, "import_ns", |
---|
| 2054 | + namespace); |
---|
| 2055 | + } |
---|
2005 | 2056 | } |
---|
2006 | 2057 | |
---|
2007 | 2058 | for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
---|
2008 | 2059 | symname = remove_dot(info.strtab + sym->st_name); |
---|
2009 | 2060 | |
---|
2010 | | - handle_modversions(mod, &info, sym, symname); |
---|
| 2061 | + handle_symbol(mod, &info, sym, symname); |
---|
2011 | 2062 | handle_moddevtable(mod, &info, sym, symname); |
---|
2012 | 2063 | } |
---|
2013 | | - if (!is_vmlinux(modname) || vmlinux_section_warnings) |
---|
2014 | | - check_sec_ref(mod, modname, &info); |
---|
2015 | 2064 | |
---|
2016 | | - version = get_modinfo(&info, "version"); |
---|
2017 | | - if (version) |
---|
2018 | | - maybe_frob_rcs_version(modname, version, info.modinfo, |
---|
2019 | | - version - (char *)info.hdr); |
---|
2020 | | - if (version || (all_versions && !is_vmlinux(modname))) |
---|
2021 | | - get_src_version(modname, mod->srcversion, |
---|
2022 | | - sizeof(mod->srcversion)-1); |
---|
| 2065 | + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
---|
| 2066 | + symname = remove_dot(info.strtab + sym->st_name); |
---|
| 2067 | + |
---|
| 2068 | + /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */ |
---|
| 2069 | + if (strstarts(symname, "__kstrtabns_")) |
---|
| 2070 | + sym_update_namespace(symname + strlen("__kstrtabns_"), |
---|
| 2071 | + namespace_from_kstrtabns(&info, |
---|
| 2072 | + sym)); |
---|
| 2073 | + |
---|
| 2074 | + if (strstarts(symname, "__crc_")) |
---|
| 2075 | + handle_modversion(mod, &info, sym, |
---|
| 2076 | + symname + strlen("__crc_")); |
---|
| 2077 | + } |
---|
| 2078 | + |
---|
| 2079 | + // check for static EXPORT_SYMBOL_* functions && global vars |
---|
| 2080 | + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
---|
| 2081 | + unsigned char bind = ELF_ST_BIND(sym->st_info); |
---|
| 2082 | + |
---|
| 2083 | + if (bind == STB_GLOBAL || bind == STB_WEAK) { |
---|
| 2084 | + struct symbol *s = |
---|
| 2085 | + find_symbol(remove_dot(info.strtab + |
---|
| 2086 | + sym->st_name)); |
---|
| 2087 | + |
---|
| 2088 | + if (s) |
---|
| 2089 | + s->is_static = 0; |
---|
| 2090 | + } |
---|
| 2091 | + } |
---|
| 2092 | + |
---|
| 2093 | + check_sec_ref(mod, modname, &info); |
---|
| 2094 | + |
---|
| 2095 | + if (!mod->is_vmlinux) { |
---|
| 2096 | + version = get_modinfo(&info, "version"); |
---|
| 2097 | + if (version || all_versions) |
---|
| 2098 | + get_src_version(modname, mod->srcversion, |
---|
| 2099 | + sizeof(mod->srcversion) - 1); |
---|
| 2100 | + } |
---|
2023 | 2101 | |
---|
2024 | 2102 | parse_elf_finish(&info); |
---|
2025 | 2103 | |
---|
.. | .. |
---|
2083 | 2161 | |
---|
2084 | 2162 | static void check_for_gpl_usage(enum export exp, const char *m, const char *s) |
---|
2085 | 2163 | { |
---|
2086 | | - const char *e = is_vmlinux(m) ?"":".ko"; |
---|
2087 | | - |
---|
2088 | 2164 | switch (exp) { |
---|
2089 | 2165 | case export_gpl: |
---|
2090 | | - fatal("modpost: GPL-incompatible module %s%s " |
---|
2091 | | - "uses GPL-only symbol '%s'\n", m, e, s); |
---|
| 2166 | + error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", |
---|
| 2167 | + m, s); |
---|
2092 | 2168 | break; |
---|
2093 | 2169 | case export_unused_gpl: |
---|
2094 | | - fatal("modpost: GPL-incompatible module %s%s " |
---|
2095 | | - "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); |
---|
| 2170 | + error("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n", |
---|
| 2171 | + m, s); |
---|
2096 | 2172 | break; |
---|
2097 | 2173 | case export_gpl_future: |
---|
2098 | | - warn("modpost: GPL-incompatible module %s%s " |
---|
2099 | | - "uses future GPL-only symbol '%s'\n", m, e, s); |
---|
| 2174 | + warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n", |
---|
| 2175 | + m, s); |
---|
2100 | 2176 | break; |
---|
2101 | 2177 | case export_plain: |
---|
2102 | 2178 | case export_unused: |
---|
.. | .. |
---|
2108 | 2184 | |
---|
2109 | 2185 | static void check_for_unused(enum export exp, const char *m, const char *s) |
---|
2110 | 2186 | { |
---|
2111 | | - const char *e = is_vmlinux(m) ?"":".ko"; |
---|
2112 | | - |
---|
2113 | 2187 | switch (exp) { |
---|
2114 | 2188 | case export_unused: |
---|
2115 | 2189 | case export_unused_gpl: |
---|
2116 | | - warn("modpost: module %s%s " |
---|
2117 | | - "uses symbol '%s' marked UNUSED\n", m, e, s); |
---|
| 2190 | + warn("module %s.ko uses symbol '%s' marked UNUSED\n", |
---|
| 2191 | + m, s); |
---|
2118 | 2192 | break; |
---|
2119 | 2193 | default: |
---|
2120 | 2194 | /* ignore */ |
---|
.. | .. |
---|
2129 | 2203 | for (s = mod->unres; s; s = s->next) { |
---|
2130 | 2204 | const char *basename; |
---|
2131 | 2205 | exp = find_symbol(s->name); |
---|
2132 | | - if (!exp || exp->module == mod) |
---|
| 2206 | + if (!exp || exp->module == mod) { |
---|
| 2207 | + if (have_vmlinux && !s->weak) |
---|
| 2208 | + modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, |
---|
| 2209 | + "\"%s\" [%s.ko] undefined!\n", |
---|
| 2210 | + s->name, mod->name); |
---|
2133 | 2211 | continue; |
---|
| 2212 | + } |
---|
2134 | 2213 | basename = strrchr(mod->name, '/'); |
---|
2135 | 2214 | if (basename) |
---|
2136 | 2215 | basename++; |
---|
2137 | 2216 | else |
---|
2138 | 2217 | basename = mod->name; |
---|
| 2218 | + |
---|
| 2219 | + if (exp->namespace && |
---|
| 2220 | + !module_imports_namespace(mod, exp->namespace)) { |
---|
| 2221 | + modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR, |
---|
| 2222 | + "module %s uses symbol %s from namespace %s, but does not import it.\n", |
---|
| 2223 | + basename, exp->name, exp->namespace); |
---|
| 2224 | + add_namespace(&mod->missing_namespaces, exp->namespace); |
---|
| 2225 | + } |
---|
| 2226 | + |
---|
2139 | 2227 | if (!mod->gpl_compatible) |
---|
2140 | 2228 | check_for_gpl_usage(exp->export, basename, exp->name); |
---|
2141 | 2229 | check_for_unused(exp->export, basename, exp->name); |
---|
2142 | 2230 | } |
---|
2143 | 2231 | } |
---|
2144 | 2232 | |
---|
2145 | | -static int check_modname_len(struct module *mod) |
---|
| 2233 | +static void check_modname_len(struct module *mod) |
---|
2146 | 2234 | { |
---|
2147 | 2235 | const char *mod_name; |
---|
2148 | 2236 | |
---|
.. | .. |
---|
2151 | 2239 | mod_name = mod->name; |
---|
2152 | 2240 | else |
---|
2153 | 2241 | mod_name++; |
---|
2154 | | - if (strlen(mod_name) >= MODULE_NAME_LEN) { |
---|
2155 | | - merror("module name is too long [%s.ko]\n", mod->name); |
---|
2156 | | - return 1; |
---|
2157 | | - } |
---|
2158 | | - |
---|
2159 | | - return 0; |
---|
| 2242 | + if (strlen(mod_name) >= MODULE_NAME_LEN) |
---|
| 2243 | + error("module name is too long [%s.ko]\n", mod->name); |
---|
2160 | 2244 | } |
---|
2161 | 2245 | |
---|
2162 | 2246 | /** |
---|
.. | .. |
---|
2169 | 2253 | * Include build-salt.h after module.h in order to |
---|
2170 | 2254 | * inherit the definitions. |
---|
2171 | 2255 | */ |
---|
| 2256 | + buf_printf(b, "#define INCLUDE_VERMAGIC\n"); |
---|
2172 | 2257 | buf_printf(b, "#include <linux/build-salt.h>\n"); |
---|
2173 | 2258 | buf_printf(b, "#include <linux/vermagic.h>\n"); |
---|
2174 | 2259 | buf_printf(b, "#include <linux/compiler.h>\n"); |
---|
.. | .. |
---|
2179 | 2264 | buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); |
---|
2180 | 2265 | buf_printf(b, "\n"); |
---|
2181 | 2266 | buf_printf(b, "__visible struct module __this_module\n"); |
---|
2182 | | - buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); |
---|
| 2267 | + buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); |
---|
2183 | 2268 | buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); |
---|
2184 | 2269 | if (mod->has_init) |
---|
2185 | 2270 | buf_printf(b, "\t.init = init_module,\n"); |
---|
.. | .. |
---|
2195 | 2280 | { |
---|
2196 | 2281 | if (is_intree) |
---|
2197 | 2282 | buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); |
---|
| 2283 | +} |
---|
| 2284 | + |
---|
| 2285 | +/** |
---|
| 2286 | + * add_scmversion() - Adds the MODULE_INFO macro for the scmversion. |
---|
| 2287 | + * @b: Buffer to append to. |
---|
| 2288 | + * |
---|
| 2289 | + * This function fills in the module attribute `scmversion` for the kernel |
---|
| 2290 | + * module. This is useful for determining a given module's SCM version on |
---|
| 2291 | + * device via /sys/modules/<module>/scmversion and/or using the modinfo tool. |
---|
| 2292 | + */ |
---|
| 2293 | +static void add_scmversion(struct buffer *b) |
---|
| 2294 | +{ |
---|
| 2295 | + if (module_scmversion[0] != '\0') |
---|
| 2296 | + buf_printf(b, "\nMODULE_INFO(scmversion, \"%s\");\n", module_scmversion); |
---|
2198 | 2297 | } |
---|
2199 | 2298 | |
---|
2200 | 2299 | /* Cannot check for assembler */ |
---|
.. | .. |
---|
2214 | 2313 | /** |
---|
2215 | 2314 | * Record CRCs for unresolved symbols |
---|
2216 | 2315 | **/ |
---|
2217 | | -static int add_versions(struct buffer *b, struct module *mod) |
---|
| 2316 | +static void add_versions(struct buffer *b, struct module *mod) |
---|
2218 | 2317 | { |
---|
2219 | 2318 | struct symbol *s, *exp; |
---|
2220 | | - int err = 0; |
---|
2221 | 2319 | |
---|
2222 | 2320 | for (s = mod->unres; s; s = s->next) { |
---|
2223 | 2321 | exp = find_symbol(s->name); |
---|
2224 | | - if (!exp || exp->module == mod) { |
---|
2225 | | - if (have_vmlinux && !s->weak) { |
---|
2226 | | - if (warn_unresolved) { |
---|
2227 | | - warn("\"%s\" [%s.ko] undefined!\n", |
---|
2228 | | - s->name, mod->name); |
---|
2229 | | - } else { |
---|
2230 | | - merror("\"%s\" [%s.ko] undefined!\n", |
---|
2231 | | - s->name, mod->name); |
---|
2232 | | - err = 1; |
---|
2233 | | - } |
---|
2234 | | - } |
---|
| 2322 | + if (!exp || exp->module == mod) |
---|
2235 | 2323 | continue; |
---|
2236 | | - } |
---|
2237 | 2324 | s->module = exp->module; |
---|
2238 | 2325 | s->crc_valid = exp->crc_valid; |
---|
2239 | 2326 | s->crc = exp->crc; |
---|
2240 | 2327 | } |
---|
2241 | 2328 | |
---|
2242 | 2329 | if (!modversions) |
---|
2243 | | - return err; |
---|
| 2330 | + return; |
---|
2244 | 2331 | |
---|
2245 | 2332 | buf_printf(b, "\n"); |
---|
2246 | 2333 | buf_printf(b, "static const struct modversion_info ____versions[]\n"); |
---|
2247 | | - buf_printf(b, "__used\n"); |
---|
2248 | | - buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); |
---|
| 2334 | + buf_printf(b, "__used __section(\"__versions\") = {\n"); |
---|
2249 | 2335 | |
---|
2250 | 2336 | for (s = mod->unres; s; s = s->next) { |
---|
2251 | 2337 | if (!s->module) |
---|
.. | .. |
---|
2256 | 2342 | continue; |
---|
2257 | 2343 | } |
---|
2258 | 2344 | if (strlen(s->name) >= MODULE_NAME_LEN) { |
---|
2259 | | - merror("too long symbol \"%s\" [%s.ko]\n", |
---|
2260 | | - s->name, mod->name); |
---|
2261 | | - err = 1; |
---|
| 2345 | + error("too long symbol \"%s\" [%s.ko]\n", |
---|
| 2346 | + s->name, mod->name); |
---|
2262 | 2347 | break; |
---|
2263 | 2348 | } |
---|
2264 | 2349 | buf_printf(b, "\t{ %#8x, \"%s\" },\n", |
---|
.. | .. |
---|
2266 | 2351 | } |
---|
2267 | 2352 | |
---|
2268 | 2353 | buf_printf(b, "};\n"); |
---|
2269 | | - |
---|
2270 | | - return err; |
---|
2271 | 2354 | } |
---|
2272 | 2355 | |
---|
2273 | | -static void add_depends(struct buffer *b, struct module *mod, |
---|
2274 | | - struct module *modules) |
---|
| 2356 | +static void add_depends(struct buffer *b, struct module *mod) |
---|
2275 | 2357 | { |
---|
2276 | 2358 | struct symbol *s; |
---|
2277 | | - struct module *m; |
---|
2278 | 2359 | int first = 1; |
---|
2279 | 2360 | |
---|
2280 | | - for (m = modules; m; m = m->next) |
---|
2281 | | - m->seen = is_vmlinux(m->name); |
---|
| 2361 | + /* Clear ->seen flag of modules that own symbols needed by this. */ |
---|
| 2362 | + for (s = mod->unres; s; s = s->next) |
---|
| 2363 | + if (s->module) |
---|
| 2364 | + s->module->seen = s->module->is_vmlinux; |
---|
2282 | 2365 | |
---|
2283 | 2366 | buf_printf(b, "\n"); |
---|
2284 | | - buf_printf(b, "static const char __module_depends[]\n"); |
---|
2285 | | - buf_printf(b, "__used\n"); |
---|
2286 | | - buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); |
---|
2287 | | - buf_printf(b, "\"depends="); |
---|
| 2367 | + buf_printf(b, "MODULE_INFO(depends, \""); |
---|
2288 | 2368 | for (s = mod->unres; s; s = s->next) { |
---|
2289 | 2369 | const char *p; |
---|
2290 | 2370 | if (!s->module) |
---|
.. | .. |
---|
2302 | 2382 | buf_printf(b, "%s%s", first ? "" : ",", p); |
---|
2303 | 2383 | first = 0; |
---|
2304 | 2384 | } |
---|
2305 | | - buf_printf(b, "\";\n"); |
---|
| 2385 | + buf_printf(b, "\");\n"); |
---|
2306 | 2386 | } |
---|
2307 | 2387 | |
---|
2308 | 2388 | static void add_srcversion(struct buffer *b, struct module *mod) |
---|
.. | .. |
---|
2311 | 2391 | buf_printf(b, "\n"); |
---|
2312 | 2392 | buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", |
---|
2313 | 2393 | mod->srcversion); |
---|
| 2394 | + } |
---|
| 2395 | +} |
---|
| 2396 | + |
---|
| 2397 | +static void write_buf(struct buffer *b, const char *fname) |
---|
| 2398 | +{ |
---|
| 2399 | + FILE *file; |
---|
| 2400 | + |
---|
| 2401 | + file = fopen(fname, "w"); |
---|
| 2402 | + if (!file) { |
---|
| 2403 | + perror(fname); |
---|
| 2404 | + exit(1); |
---|
| 2405 | + } |
---|
| 2406 | + if (fwrite(b->p, 1, b->pos, file) != b->pos) { |
---|
| 2407 | + perror(fname); |
---|
| 2408 | + exit(1); |
---|
| 2409 | + } |
---|
| 2410 | + if (fclose(file) != 0) { |
---|
| 2411 | + perror(fname); |
---|
| 2412 | + exit(1); |
---|
2314 | 2413 | } |
---|
2315 | 2414 | } |
---|
2316 | 2415 | |
---|
.. | .. |
---|
2346 | 2445 | close_write: |
---|
2347 | 2446 | fclose(file); |
---|
2348 | 2447 | write: |
---|
2349 | | - file = fopen(fname, "w"); |
---|
2350 | | - if (!file) { |
---|
2351 | | - perror(fname); |
---|
2352 | | - exit(1); |
---|
2353 | | - } |
---|
2354 | | - if (fwrite(b->p, 1, b->pos, file) != b->pos) { |
---|
2355 | | - perror(fname); |
---|
2356 | | - exit(1); |
---|
2357 | | - } |
---|
2358 | | - fclose(file); |
---|
| 2448 | + write_buf(b, fname); |
---|
2359 | 2449 | } |
---|
2360 | 2450 | |
---|
2361 | 2451 | /* parse Module.symvers file. line format: |
---|
2362 | | - * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something] |
---|
| 2452 | + * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace |
---|
2363 | 2453 | **/ |
---|
2364 | | -static void read_dump(const char *fname, unsigned int kernel) |
---|
| 2454 | +static void read_dump(const char *fname) |
---|
2365 | 2455 | { |
---|
2366 | | - unsigned long size, pos = 0; |
---|
2367 | | - void *file = grab_file(fname, &size); |
---|
2368 | | - char *line; |
---|
| 2456 | + char *buf, *pos, *line; |
---|
2369 | 2457 | |
---|
2370 | | - if (!file) |
---|
| 2458 | + buf = read_text_file(fname); |
---|
| 2459 | + if (!buf) |
---|
2371 | 2460 | /* No symbol versions, silently ignore */ |
---|
2372 | 2461 | return; |
---|
2373 | 2462 | |
---|
2374 | | - while ((line = get_next_line(&pos, file, size))) { |
---|
2375 | | - char *symname, *modname, *d, *export, *end; |
---|
| 2463 | + pos = buf; |
---|
| 2464 | + |
---|
| 2465 | + while ((line = get_line(&pos))) { |
---|
| 2466 | + char *symname, *namespace, *modname, *d, *export; |
---|
2376 | 2467 | unsigned int crc; |
---|
2377 | 2468 | struct module *mod; |
---|
2378 | 2469 | struct symbol *s; |
---|
.. | .. |
---|
2383 | 2474 | if (!(modname = strchr(symname, '\t'))) |
---|
2384 | 2475 | goto fail; |
---|
2385 | 2476 | *modname++ = '\0'; |
---|
2386 | | - if ((export = strchr(modname, '\t')) != NULL) |
---|
2387 | | - *export++ = '\0'; |
---|
2388 | | - if (export && ((end = strchr(export, '\t')) != NULL)) |
---|
2389 | | - *end = '\0'; |
---|
| 2477 | + if (!(export = strchr(modname, '\t'))) |
---|
| 2478 | + goto fail; |
---|
| 2479 | + *export++ = '\0'; |
---|
| 2480 | + if (!(namespace = strchr(export, '\t'))) |
---|
| 2481 | + goto fail; |
---|
| 2482 | + *namespace++ = '\0'; |
---|
| 2483 | + |
---|
2390 | 2484 | crc = strtoul(line, &d, 16); |
---|
2391 | 2485 | if (*symname == '\0' || *modname == '\0' || *d != '\0') |
---|
2392 | 2486 | goto fail; |
---|
2393 | 2487 | mod = find_module(modname); |
---|
2394 | 2488 | if (!mod) { |
---|
2395 | | - if (is_vmlinux(modname)) |
---|
2396 | | - have_vmlinux = 1; |
---|
2397 | 2489 | mod = new_module(modname); |
---|
2398 | | - mod->skip = 1; |
---|
| 2490 | + mod->from_dump = 1; |
---|
2399 | 2491 | } |
---|
2400 | 2492 | s = sym_add_exported(symname, mod, export_no(export)); |
---|
2401 | | - s->kernel = kernel; |
---|
2402 | | - s->preloaded = 1; |
---|
2403 | | - sym_update_crc(symname, mod, crc, export_no(export)); |
---|
| 2493 | + s->is_static = 0; |
---|
| 2494 | + sym_set_crc(symname, crc); |
---|
| 2495 | + sym_update_namespace(symname, namespace); |
---|
2404 | 2496 | } |
---|
2405 | | - release_file(file, size); |
---|
| 2497 | + free(buf); |
---|
2406 | 2498 | return; |
---|
2407 | 2499 | fail: |
---|
2408 | | - release_file(file, size); |
---|
| 2500 | + free(buf); |
---|
2409 | 2501 | fatal("parse error in symbol dump file\n"); |
---|
2410 | | -} |
---|
2411 | | - |
---|
2412 | | -/* For normal builds always dump all symbols. |
---|
2413 | | - * For external modules only dump symbols |
---|
2414 | | - * that are not read from kernel Module.symvers. |
---|
2415 | | - **/ |
---|
2416 | | -static int dump_sym(struct symbol *sym) |
---|
2417 | | -{ |
---|
2418 | | - if (!external_module) |
---|
2419 | | - return 1; |
---|
2420 | | - if (sym->vmlinux || sym->kernel) |
---|
2421 | | - return 0; |
---|
2422 | | - return 1; |
---|
2423 | 2502 | } |
---|
2424 | 2503 | |
---|
2425 | 2504 | static void write_dump(const char *fname) |
---|
2426 | 2505 | { |
---|
2427 | 2506 | struct buffer buf = { }; |
---|
2428 | 2507 | struct symbol *symbol; |
---|
| 2508 | + const char *namespace; |
---|
2429 | 2509 | int n; |
---|
2430 | 2510 | |
---|
2431 | 2511 | for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { |
---|
2432 | 2512 | symbol = symbolhash[n]; |
---|
2433 | 2513 | while (symbol) { |
---|
2434 | | - if (dump_sym(symbol)) |
---|
2435 | | - buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", |
---|
2436 | | - symbol->crc, symbol->name, |
---|
2437 | | - symbol->module->name, |
---|
2438 | | - export_str(symbol->export)); |
---|
| 2514 | + if (!symbol->module->from_dump) { |
---|
| 2515 | + namespace = symbol->namespace; |
---|
| 2516 | + buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n", |
---|
| 2517 | + symbol->crc, symbol->name, |
---|
| 2518 | + symbol->module->name, |
---|
| 2519 | + export_str(symbol->export), |
---|
| 2520 | + namespace ? namespace : ""); |
---|
| 2521 | + } |
---|
2439 | 2522 | symbol = symbol->next; |
---|
2440 | 2523 | } |
---|
2441 | 2524 | } |
---|
2442 | | - write_if_changed(&buf, fname); |
---|
| 2525 | + write_buf(&buf, fname); |
---|
2443 | 2526 | free(buf.p); |
---|
2444 | 2527 | } |
---|
2445 | 2528 | |
---|
2446 | | -struct ext_sym_list { |
---|
2447 | | - struct ext_sym_list *next; |
---|
| 2529 | +static void write_namespace_deps_files(const char *fname) |
---|
| 2530 | +{ |
---|
| 2531 | + struct module *mod; |
---|
| 2532 | + struct namespace_list *ns; |
---|
| 2533 | + struct buffer ns_deps_buf = {}; |
---|
| 2534 | + |
---|
| 2535 | + for (mod = modules; mod; mod = mod->next) { |
---|
| 2536 | + |
---|
| 2537 | + if (mod->from_dump || !mod->missing_namespaces) |
---|
| 2538 | + continue; |
---|
| 2539 | + |
---|
| 2540 | + buf_printf(&ns_deps_buf, "%s.ko:", mod->name); |
---|
| 2541 | + |
---|
| 2542 | + for (ns = mod->missing_namespaces; ns; ns = ns->next) |
---|
| 2543 | + buf_printf(&ns_deps_buf, " %s", ns->namespace); |
---|
| 2544 | + |
---|
| 2545 | + buf_printf(&ns_deps_buf, "\n"); |
---|
| 2546 | + } |
---|
| 2547 | + |
---|
| 2548 | + write_if_changed(&ns_deps_buf, fname); |
---|
| 2549 | + free(ns_deps_buf.p); |
---|
| 2550 | +} |
---|
| 2551 | + |
---|
| 2552 | +struct dump_list { |
---|
| 2553 | + struct dump_list *next; |
---|
2448 | 2554 | const char *file; |
---|
2449 | 2555 | }; |
---|
2450 | 2556 | |
---|
.. | .. |
---|
2452 | 2558 | { |
---|
2453 | 2559 | struct module *mod; |
---|
2454 | 2560 | struct buffer buf = { }; |
---|
2455 | | - char *kernel_read = NULL, *module_read = NULL; |
---|
| 2561 | + char *missing_namespace_deps = NULL; |
---|
2456 | 2562 | char *dump_write = NULL, *files_source = NULL; |
---|
2457 | 2563 | int opt; |
---|
2458 | | - int err; |
---|
2459 | | - struct ext_sym_list *extsym_iter; |
---|
2460 | | - struct ext_sym_list *extsym_start = NULL; |
---|
| 2564 | + int n; |
---|
| 2565 | + struct dump_list *dump_read_start = NULL; |
---|
| 2566 | + struct dump_list **dump_read_iter = &dump_read_start; |
---|
2461 | 2567 | |
---|
2462 | | - while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) { |
---|
| 2568 | + while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:v:")) != -1) { |
---|
2463 | 2569 | switch (opt) { |
---|
2464 | | - case 'i': |
---|
2465 | | - kernel_read = optarg; |
---|
2466 | | - break; |
---|
2467 | | - case 'I': |
---|
2468 | | - module_read = optarg; |
---|
2469 | | - external_module = 1; |
---|
2470 | | - break; |
---|
2471 | 2570 | case 'e': |
---|
2472 | 2571 | external_module = 1; |
---|
2473 | | - extsym_iter = |
---|
2474 | | - NOFAIL(malloc(sizeof(*extsym_iter))); |
---|
2475 | | - extsym_iter->next = extsym_start; |
---|
2476 | | - extsym_iter->file = optarg; |
---|
2477 | | - extsym_start = extsym_iter; |
---|
| 2572 | + break; |
---|
| 2573 | + case 'i': |
---|
| 2574 | + *dump_read_iter = |
---|
| 2575 | + NOFAIL(calloc(1, sizeof(**dump_read_iter))); |
---|
| 2576 | + (*dump_read_iter)->file = optarg; |
---|
| 2577 | + dump_read_iter = &(*dump_read_iter)->next; |
---|
2478 | 2578 | break; |
---|
2479 | 2579 | case 'm': |
---|
2480 | 2580 | modversions = 1; |
---|
.. | .. |
---|
2488 | 2588 | case 'a': |
---|
2489 | 2589 | all_versions = 1; |
---|
2490 | 2590 | break; |
---|
2491 | | - case 's': |
---|
2492 | | - vmlinux_section_warnings = 0; |
---|
2493 | | - break; |
---|
2494 | | - case 'S': |
---|
2495 | | - sec_mismatch_verbose = 0; |
---|
2496 | | - break; |
---|
2497 | 2591 | case 'T': |
---|
2498 | 2592 | files_source = optarg; |
---|
2499 | 2593 | break; |
---|
.. | .. |
---|
2501 | 2595 | warn_unresolved = 1; |
---|
2502 | 2596 | break; |
---|
2503 | 2597 | case 'E': |
---|
2504 | | - sec_mismatch_fatal = 1; |
---|
| 2598 | + sec_mismatch_warn_only = false; |
---|
| 2599 | + break; |
---|
| 2600 | + case 'N': |
---|
| 2601 | + allow_missing_ns_imports = 1; |
---|
| 2602 | + break; |
---|
| 2603 | + case 'd': |
---|
| 2604 | + missing_namespace_deps = optarg; |
---|
| 2605 | + break; |
---|
| 2606 | + case 'v': |
---|
| 2607 | + strncpy(module_scmversion, optarg, sizeof(module_scmversion) - 1); |
---|
2505 | 2608 | break; |
---|
2506 | 2609 | default: |
---|
2507 | 2610 | exit(1); |
---|
2508 | 2611 | } |
---|
2509 | 2612 | } |
---|
2510 | 2613 | |
---|
2511 | | - if (kernel_read) |
---|
2512 | | - read_dump(kernel_read, 1); |
---|
2513 | | - if (module_read) |
---|
2514 | | - read_dump(module_read, 0); |
---|
2515 | | - while (extsym_start) { |
---|
2516 | | - read_dump(extsym_start->file, 0); |
---|
2517 | | - extsym_iter = extsym_start->next; |
---|
2518 | | - free(extsym_start); |
---|
2519 | | - extsym_start = extsym_iter; |
---|
| 2614 | + while (dump_read_start) { |
---|
| 2615 | + struct dump_list *tmp; |
---|
| 2616 | + |
---|
| 2617 | + read_dump(dump_read_start->file); |
---|
| 2618 | + tmp = dump_read_start->next; |
---|
| 2619 | + free(dump_read_start); |
---|
| 2620 | + dump_read_start = tmp; |
---|
2520 | 2621 | } |
---|
2521 | 2622 | |
---|
2522 | 2623 | while (optind < argc) |
---|
.. | .. |
---|
2525 | 2626 | if (files_source) |
---|
2526 | 2627 | read_symbols_from_files(files_source); |
---|
2527 | 2628 | |
---|
2528 | | - for (mod = modules; mod; mod = mod->next) { |
---|
2529 | | - if (mod->skip) |
---|
2530 | | - continue; |
---|
2531 | | - check_exports(mod); |
---|
2532 | | - } |
---|
2533 | | - |
---|
2534 | | - err = 0; |
---|
| 2629 | + /* |
---|
| 2630 | + * When there's no vmlinux, don't print warnings about |
---|
| 2631 | + * unresolved symbols (since there'll be too many ;) |
---|
| 2632 | + */ |
---|
| 2633 | + if (!have_vmlinux) |
---|
| 2634 | + warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n"); |
---|
2535 | 2635 | |
---|
2536 | 2636 | for (mod = modules; mod; mod = mod->next) { |
---|
2537 | 2637 | char fname[PATH_MAX]; |
---|
2538 | 2638 | |
---|
2539 | | - if (mod->skip) |
---|
| 2639 | + if (mod->is_vmlinux || mod->from_dump) |
---|
2540 | 2640 | continue; |
---|
2541 | 2641 | |
---|
2542 | 2642 | buf.pos = 0; |
---|
2543 | 2643 | |
---|
2544 | | - err |= check_modname_len(mod); |
---|
| 2644 | + check_modname_len(mod); |
---|
| 2645 | + check_exports(mod); |
---|
| 2646 | + |
---|
2545 | 2647 | add_header(&buf, mod); |
---|
2546 | 2648 | add_intree_flag(&buf, !external_module); |
---|
2547 | 2649 | add_retpoline(&buf); |
---|
2548 | 2650 | add_staging_flag(&buf, mod->name); |
---|
2549 | | - err |= add_versions(&buf, mod); |
---|
2550 | | - add_depends(&buf, mod, modules); |
---|
| 2651 | + add_versions(&buf, mod); |
---|
| 2652 | + add_depends(&buf, mod); |
---|
2551 | 2653 | add_moddevtable(&buf, mod); |
---|
2552 | 2654 | add_srcversion(&buf, mod); |
---|
| 2655 | + add_scmversion(&buf); |
---|
2553 | 2656 | |
---|
2554 | 2657 | sprintf(fname, "%s.mod.c", mod->name); |
---|
2555 | 2658 | write_if_changed(&buf, fname); |
---|
2556 | 2659 | } |
---|
| 2660 | + |
---|
| 2661 | + if (missing_namespace_deps) |
---|
| 2662 | + write_namespace_deps_files(missing_namespace_deps); |
---|
| 2663 | + |
---|
2557 | 2664 | if (dump_write) |
---|
2558 | 2665 | write_dump(dump_write); |
---|
2559 | | - if (sec_mismatch_count) { |
---|
2560 | | - if (!sec_mismatch_verbose) { |
---|
2561 | | - warn("modpost: Found %d section mismatch(es).\n" |
---|
2562 | | - "To see full details build your kernel with:\n" |
---|
2563 | | - "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", |
---|
2564 | | - sec_mismatch_count); |
---|
2565 | | - } |
---|
2566 | | - if (sec_mismatch_fatal) { |
---|
2567 | | - fatal("modpost: Section mismatches detected.\n" |
---|
2568 | | - "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); |
---|
| 2666 | + if (sec_mismatch_count && !sec_mismatch_warn_only) |
---|
| 2667 | + error("Section mismatches detected.\n" |
---|
| 2668 | + "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); |
---|
| 2669 | + for (n = 0; n < SYMBOL_HASH_SIZE; n++) { |
---|
| 2670 | + struct symbol *s; |
---|
| 2671 | + |
---|
| 2672 | + for (s = symbolhash[n]; s; s = s->next) { |
---|
| 2673 | + if (s->is_static) |
---|
| 2674 | + error("\"%s\" [%s] is a static %s\n", |
---|
| 2675 | + s->name, s->module->name, |
---|
| 2676 | + export_str(s->export)); |
---|
2569 | 2677 | } |
---|
2570 | 2678 | } |
---|
| 2679 | + |
---|
2571 | 2680 | free(buf.p); |
---|
2572 | 2681 | |
---|
2573 | | - return err; |
---|
| 2682 | + return error_occurred ? 1 : 0; |
---|
2574 | 2683 | } |
---|