diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 142 |
1 files changed, 109 insertions, 33 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 65bdfdb56877..4ab36de45aa2 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -55,6 +55,17 @@ void warn(const char *fmt, ...) | |||
55 | va_end(arglist); | 55 | va_end(arglist); |
56 | } | 56 | } |
57 | 57 | ||
58 | void merror(const char *fmt, ...) | ||
59 | { | ||
60 | va_list arglist; | ||
61 | |||
62 | fprintf(stderr, "ERROR: "); | ||
63 | |||
64 | va_start(arglist, fmt); | ||
65 | vfprintf(stderr, fmt, arglist); | ||
66 | va_end(arglist); | ||
67 | } | ||
68 | |||
58 | static int is_vmlinux(const char *modname) | 69 | static int is_vmlinux(const char *modname) |
59 | { | 70 | { |
60 | const char *myname; | 71 | const char *myname; |
@@ -333,10 +344,10 @@ void release_file(void *file, unsigned long size) | |||
333 | munmap(file, size); | 344 | munmap(file, size); |
334 | } | 345 | } |
335 | 346 | ||
336 | static void parse_elf(struct elf_info *info, const char *filename) | 347 | static int parse_elf(struct elf_info *info, const char *filename) |
337 | { | 348 | { |
338 | unsigned int i; | 349 | unsigned int i; |
339 | Elf_Ehdr *hdr = info->hdr; | 350 | Elf_Ehdr *hdr; |
340 | Elf_Shdr *sechdrs; | 351 | Elf_Shdr *sechdrs; |
341 | Elf_Sym *sym; | 352 | Elf_Sym *sym; |
342 | 353 | ||
@@ -346,9 +357,18 @@ static void parse_elf(struct elf_info *info, const char *filename) | |||
346 | exit(1); | 357 | exit(1); |
347 | } | 358 | } |
348 | info->hdr = hdr; | 359 | info->hdr = hdr; |
349 | if (info->size < sizeof(*hdr)) | 360 | if (info->size < sizeof(*hdr)) { |
350 | goto truncated; | 361 | /* file too small, assume this is an empty .o file */ |
351 | 362 | return 0; | |
363 | } | ||
364 | /* Is this a valid ELF file? */ | ||
365 | if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || | ||
366 | (hdr->e_ident[EI_MAG1] != ELFMAG1) || | ||
367 | (hdr->e_ident[EI_MAG2] != ELFMAG2) || | ||
368 | (hdr->e_ident[EI_MAG3] != ELFMAG3)) { | ||
369 | /* Not an ELF file - silently ignore it */ | ||
370 | return 0; | ||
371 | } | ||
352 | /* Fix endianness in ELF header */ | 372 | /* Fix endianness in ELF header */ |
353 | hdr->e_shoff = TO_NATIVE(hdr->e_shoff); | 373 | hdr->e_shoff = TO_NATIVE(hdr->e_shoff); |
354 | hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); | 374 | hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); |
@@ -371,8 +391,10 @@ static void parse_elf(struct elf_info *info, const char *filename) | |||
371 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 391 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
372 | const char *secname; | 392 | const char *secname; |
373 | 393 | ||
374 | if (sechdrs[i].sh_offset > info->size) | 394 | if (sechdrs[i].sh_offset > info->size) { |
375 | goto truncated; | 395 | fatal("%s is truncated. sechdrs[i].sh_offset=%u > sizeof(*hrd)=%ul\n", filename, (unsigned int)sechdrs[i].sh_offset, sizeof(*hdr)); |
396 | return 0; | ||
397 | } | ||
376 | secname = secstrings + sechdrs[i].sh_name; | 398 | secname = secstrings + sechdrs[i].sh_name; |
377 | if (strcmp(secname, ".modinfo") == 0) { | 399 | if (strcmp(secname, ".modinfo") == 0) { |
378 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; | 400 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; |
@@ -407,10 +429,7 @@ static void parse_elf(struct elf_info *info, const char *filename) | |||
407 | sym->st_value = TO_NATIVE(sym->st_value); | 429 | sym->st_value = TO_NATIVE(sym->st_value); |
408 | sym->st_size = TO_NATIVE(sym->st_size); | 430 | sym->st_size = TO_NATIVE(sym->st_size); |
409 | } | 431 | } |
410 | return; | 432 | return 1; |
411 | |||
412 | truncated: | ||
413 | fatal("%s is truncated.\n", filename); | ||
414 | } | 433 | } |
415 | 434 | ||
416 | static void parse_elf_finish(struct elf_info *info) | 435 | static void parse_elf_finish(struct elf_info *info) |
@@ -581,9 +600,17 @@ static int strrcmp(const char *s, const char *sub) | |||
581 | * the pattern is identified by: | 600 | * the pattern is identified by: |
582 | * tosec = .init.text | .exit.text | .init.data | 601 | * tosec = .init.text | .exit.text | .init.data |
583 | * fromsec = .data | 602 | * fromsec = .data |
584 | * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one | 603 | * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console |
585 | * | 604 | * |
586 | * Pattern 3: | 605 | * Pattern 3: |
606 | * Whitelist all references from .pci_fixup* section to .init.text | ||
607 | * This is part of the PCI init when built-in | ||
608 | * | ||
609 | * Pattern 4: | ||
610 | * Whitelist all refereces from .text.head to .init.data | ||
611 | * Whitelist all refereces from .text.head to .init.text | ||
612 | * | ||
613 | * Pattern 5: | ||
587 | * Some symbols belong to init section but still it is ok to reference | 614 | * Some symbols belong to init section but still it is ok to reference |
588 | * these from non-init sections as these symbols don't have any memory | 615 | * these from non-init sections as these symbols don't have any memory |
589 | * allocated for them and symbol address and value are same. So even | 616 | * allocated for them and symbol address and value are same. So even |
@@ -591,6 +618,30 @@ static int strrcmp(const char *s, const char *sub) | |||
591 | * For ex. symbols marking the init section boundaries. | 618 | * For ex. symbols marking the init section boundaries. |
592 | * This pattern is identified by | 619 | * This pattern is identified by |
593 | * refsymname = __init_begin, _sinittext, _einittext | 620 | * refsymname = __init_begin, _sinittext, _einittext |
621 | * | ||
622 | * Pattern 6: | ||
623 | * During the early init phase we have references from .init.text to | ||
624 | * .text we have an intended section mismatch - do not warn about it. | ||
625 | * See kernel_init() in init/main.c | ||
626 | * tosec = .init.text | ||
627 | * fromsec = .text | ||
628 | * atsym = kernel_init | ||
629 | * | ||
630 | * Pattern 7: | ||
631 | * Logos used in drivers/video/logo reside in __initdata but the | ||
632 | * funtion that references them are EXPORT_SYMBOL() so cannot be | ||
633 | * marker __init. So we whitelist them here. | ||
634 | * The pattern is: | ||
635 | * tosec = .init.data | ||
636 | * fromsec = .text* | ||
637 | * refsymname = logo_ | ||
638 | * | ||
639 | * Pattern 8: | ||
640 | * Symbols contained in .paravirtprobe may safely reference .init.text. | ||
641 | * The pattern is: | ||
642 | * tosec = .init.text | ||
643 | * fromsec = .paravirtprobe | ||
644 | * | ||
594 | **/ | 645 | **/ |
595 | static int secref_whitelist(const char *modname, const char *tosec, | 646 | static int secref_whitelist(const char *modname, const char *tosec, |
596 | const char *fromsec, const char *atsym, | 647 | const char *fromsec, const char *atsym, |
@@ -606,6 +657,7 @@ static int secref_whitelist(const char *modname, const char *tosec, | |||
606 | "_probe", | 657 | "_probe", |
607 | "_probe_one", | 658 | "_probe_one", |
608 | "_console", | 659 | "_console", |
660 | "apic_es7000", | ||
609 | NULL | 661 | NULL |
610 | }; | 662 | }; |
611 | 663 | ||
@@ -641,25 +693,39 @@ static int secref_whitelist(const char *modname, const char *tosec, | |||
641 | if (f1 && f2) | 693 | if (f1 && f2) |
642 | return 1; | 694 | return 1; |
643 | 695 | ||
644 | /* Whitelist all references from .pci_fixup section if vmlinux | 696 | /* Check for pattern 3 */ |
645 | * Whitelist all refereces from .text.head to .init.data if vmlinux | 697 | if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) && |
646 | * Whitelist all refereces from .text.head to .init.text if vmlinux | 698 | (strcmp(tosec, ".init.text") == 0)) |
647 | */ | 699 | return 1; |
648 | if (is_vmlinux(modname)) { | 700 | |
649 | if ((strcmp(fromsec, ".pci_fixup") == 0) && | 701 | /* Check for pattern 4 */ |
650 | (strcmp(tosec, ".init.text") == 0)) | 702 | if ((strcmp(fromsec, ".text.head") == 0) && |
703 | ((strcmp(tosec, ".init.data") == 0) || | ||
704 | (strcmp(tosec, ".init.text") == 0))) | ||
705 | return 1; | ||
706 | |||
707 | /* Check for pattern 5 */ | ||
708 | for (s = pat3refsym; *s; s++) | ||
709 | if (strcmp(refsymname, *s) == 0) | ||
710 | return 1; | ||
711 | |||
712 | /* Check for pattern 6 */ | ||
713 | if ((strcmp(tosec, ".init.text") == 0) && | ||
714 | (strcmp(fromsec, ".text") == 0) && | ||
715 | (strcmp(refsymname, "kernel_init") == 0)) | ||
651 | return 1; | 716 | return 1; |
652 | 717 | ||
653 | if ((strcmp(fromsec, ".text.head") == 0) && | 718 | /* Check for pattern 7 */ |
654 | ((strcmp(tosec, ".init.data") == 0) || | 719 | if ((strcmp(tosec, ".init.data") == 0) && |
655 | (strcmp(tosec, ".init.text") == 0))) | 720 | (strncmp(fromsec, ".text", strlen(".text")) == 0) && |
721 | (strncmp(refsymname, "logo_", strlen("logo_")) == 0)) | ||
722 | return 1; | ||
723 | |||
724 | /* Check for pattern 8 */ | ||
725 | if ((strcmp(tosec, ".init.text") == 0) && | ||
726 | (strcmp(fromsec, ".paravirtprobe") == 0)) | ||
656 | return 1; | 727 | return 1; |
657 | 728 | ||
658 | /* Check for pattern 3 */ | ||
659 | for (s = pat3refsym; *s; s++) | ||
660 | if (strcmp(refsymname, *s) == 0) | ||
661 | return 1; | ||
662 | } | ||
663 | return 0; | 729 | return 0; |
664 | } | 730 | } |
665 | 731 | ||
@@ -1089,7 +1155,8 @@ static void read_symbols(char *modname) | |||
1089 | struct elf_info info = { }; | 1155 | struct elf_info info = { }; |
1090 | Elf_Sym *sym; | 1156 | Elf_Sym *sym; |
1091 | 1157 | ||
1092 | parse_elf(&info, modname); | 1158 | if (!parse_elf(&info, modname)) |
1159 | return; | ||
1093 | 1160 | ||
1094 | mod = new_module(modname); | 1161 | mod = new_module(modname); |
1095 | 1162 | ||
@@ -1264,9 +1331,14 @@ static int add_versions(struct buffer *b, struct module *mod) | |||
1264 | exp = find_symbol(s->name); | 1331 | exp = find_symbol(s->name); |
1265 | if (!exp || exp->module == mod) { | 1332 | if (!exp || exp->module == mod) { |
1266 | if (have_vmlinux && !s->weak) { | 1333 | if (have_vmlinux && !s->weak) { |
1267 | warn("\"%s\" [%s.ko] undefined!\n", | 1334 | if (warn_unresolved) { |
1268 | s->name, mod->name); | 1335 | warn("\"%s\" [%s.ko] undefined!\n", |
1269 | err = warn_unresolved ? 0 : 1; | 1336 | s->name, mod->name); |
1337 | } else { | ||
1338 | merror("\"%s\" [%s.ko] undefined!\n", | ||
1339 | s->name, mod->name); | ||
1340 | err = 1; | ||
1341 | } | ||
1270 | } | 1342 | } |
1271 | continue; | 1343 | continue; |
1272 | } | 1344 | } |
@@ -1317,6 +1389,7 @@ static void add_depends(struct buffer *b, struct module *mod, | |||
1317 | buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); | 1389 | buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); |
1318 | buf_printf(b, "\"depends="); | 1390 | buf_printf(b, "\"depends="); |
1319 | for (s = mod->unres; s; s = s->next) { | 1391 | for (s = mod->unres; s; s = s->next) { |
1392 | const char *p; | ||
1320 | if (!s->module) | 1393 | if (!s->module) |
1321 | continue; | 1394 | continue; |
1322 | 1395 | ||
@@ -1324,8 +1397,11 @@ static void add_depends(struct buffer *b, struct module *mod, | |||
1324 | continue; | 1397 | continue; |
1325 | 1398 | ||
1326 | s->module->seen = 1; | 1399 | s->module->seen = 1; |
1327 | buf_printf(b, "%s%s", first ? "" : ",", | 1400 | if ((p = strrchr(s->module->name, '/')) != NULL) |
1328 | strrchr(s->module->name, '/') + 1); | 1401 | p++; |
1402 | else | ||
1403 | p = s->module->name; | ||
1404 | buf_printf(b, "%s%s", first ? "" : ",", p); | ||
1329 | first = 0; | 1405 | first = 0; |
1330 | } | 1406 | } |
1331 | buf_printf(b, "\";\n"); | 1407 | buf_printf(b, "\";\n"); |