aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Ravnborg <sam@mars.ravnborg.org>2006-02-17 16:42:02 -0500
committerSam Ravnborg <sam@mars.ravnborg.org>2006-02-19 03:51:20 -0500
commitb39927cf4cc5a9123d2b157ffd396884cb8156eb (patch)
tree8e372f4b8fa678de7239a125ff4653f136a9dc66
parenta67dc21a38055ec2d8d85b2f64d98091748569b3 (diff)
kbuild: check for section mismatch during modpost stage
Section mismatch is identified as references to .init* sections from non .init sections. And likewise references to .exit.* sections outside .exit sections. .init.* sections are discarded after a module is initialized and references to .init.* sections are oops candidates. .exit.* sections are discarded when a module is built-in and thus references to .exit are also oops candidates. The checks were possible to do using 'make buildcheck' which called the two perl scripts: reference_discarded.pl and reference_init.pl. This patch just moves the same functionality inside modpost and the scripts are then obsoleted. They will though be kept for a while so users can do double checks - but note that some .o files are skipped by the perl scripts so result is not 1:1. All credit for the concept goes to Keith Owens who implemented the original perl scrips - this patch just moves it to modpost. Compared to the perl script the implmentation in modpost will be run for each kernel build - thus catching the error much sooner, but the downside is that the individual .o file are not always identified. Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
-rw-r--r--scripts/mod/modpost.c258
-rw-r--r--scripts/mod/modpost.h10
2 files changed, 268 insertions, 0 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index d901095ea8b7..a7360c379cba 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -451,6 +451,262 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
451 return NULL; 451 return NULL;
452} 452}
453 453
454/*
455 * Find symbols before or equal addr and after addr - in the section sec
456 **/
457static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
458 const char *sec,
459 Elf_Sym **before, Elf_Sym **after)
460{
461 Elf_Sym *sym;
462 Elf_Ehdr *hdr = elf->hdr;
463 Elf_Addr beforediff = ~0;
464 Elf_Addr afterdiff = ~0;
465 const char *secstrings = (void *)hdr +
466 elf->sechdrs[hdr->e_shstrndx].sh_offset;
467
468 *before = NULL;
469 *after = NULL;
470
471 for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
472 const char *symsec;
473
474 if (sym->st_shndx >= SHN_LORESERVE)
475 continue;
476 symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name;
477 if (strcmp(symsec, sec) != 0)
478 continue;
479 if (sym->st_value <= addr) {
480 if ((addr - sym->st_value) < beforediff) {
481 beforediff = addr - sym->st_value;
482 *before = sym;
483 }
484 }
485 else
486 {
487 if ((sym->st_value - addr) < afterdiff) {
488 afterdiff = sym->st_value - addr;
489 *after = sym;
490 }
491 }
492 }
493}
494
495/**
496 * Print a warning about a section mismatch.
497 * Try to find symbols near it so user can find it.
498 **/
499static void warn_sec_mismatch(const char *modname, const char *fromsec,
500 struct elf_info *elf, Elf_Sym *sym, Elf_Rela r)
501{
502 Elf_Sym *before;
503 Elf_Sym *after;
504 Elf_Ehdr *hdr = elf->hdr;
505 Elf_Shdr *sechdrs = elf->sechdrs;
506 const char *secstrings = (void *)hdr +
507 sechdrs[hdr->e_shstrndx].sh_offset;
508 const char *secname = secstrings + sechdrs[sym->st_shndx].sh_name;
509
510 find_symbols_between(elf, r.r_offset, fromsec, &before, &after);
511
512 if (before && after) {
513 warn("%s - Section mismatch: reference to %s from %s "
514 "between '%s' (at offset 0x%lx) and '%s'\n",
515 modname, secname, fromsec,
516 elf->strtab + before->st_name,
517 (long)(r.r_offset - before->st_value),
518 elf->strtab + after->st_name);
519 } else if (before) {
520 warn("%s - Section mismatch: reference to %s from %s "
521 "after '%s' (at offset 0x%lx)\n",
522 modname, secname, fromsec,
523 elf->strtab + before->st_name,
524 (long)(r.r_offset - before->st_value));
525 } else if (after) {
526 warn("%s - Section mismatch: reference to %s from %s "
527 "before '%s' (at offset -0x%lx)\n",
528 modname, secname, fromsec,
529 elf->strtab + before->st_name,
530 (long)(before->st_value - r.r_offset));
531 } else {
532 warn("%s - Section mismatch: reference to %s from %s "
533 "(offset 0x%lx)\n",
534 modname, secname, fromsec, (long)r.r_offset);
535 }
536}
537
538/**
539 * A module includes a number of sections that are discarded
540 * either when loaded or when used as built-in.
541 * For loaded modules all functions marked __init and all data
542 * marked __initdata will be discarded when the module has been intialized.
543 * Likewise for modules used built-in the sections marked __exit
544 * are discarded because __exit marked function are supposed to be called
545 * only when a moduel is unloaded which never happes for built-in modules.
546 * The check_sec_ref() function traverses all relocation records
547 * to find all references to a section that reference a section that will
548 * be discarded and warns about it.
549 **/
550static void check_sec_ref(struct module *mod, const char *modname,
551 struct elf_info *elf,
552 int section(const char*),
553 int section_ref_ok(const char *))
554{
555 int i;
556 Elf_Sym *sym;
557 Elf_Ehdr *hdr = elf->hdr;
558 Elf_Shdr *sechdrs = elf->sechdrs;
559 const char *secstrings = (void *)hdr +
560 sechdrs[hdr->e_shstrndx].sh_offset;
561
562 /* Walk through all sections */
563 for (i = 0; i < hdr->e_shnum; i++) {
564 const char *name = secstrings + sechdrs[i].sh_name +
565 strlen(".rela");
566 /* We want to process only relocation sections and not .init */
567 if (section_ref_ok(name) || (sechdrs[i].sh_type != SHT_RELA))
568 continue;
569 Elf_Rela *rela;
570 Elf_Rela *start = (void *)hdr + sechdrs[i].sh_offset;
571 Elf_Rela *stop = (void*)start + sechdrs[i].sh_size;
572
573 for (rela = start; rela < stop; rela++) {
574 Elf_Rela r;
575 const char *secname;
576 r.r_offset = TO_NATIVE(rela->r_offset);
577 r.r_info = TO_NATIVE(rela->r_info);
578 sym = elf->symtab_start + ELF_R_SYM(r.r_info);
579 secname = secstrings + sechdrs[sym->st_shndx].sh_name;
580 /* Skip special sections */
581 if (sym->st_shndx >= SHN_LORESERVE)
582 continue;
583
584 if (section(secname))
585 warn_sec_mismatch(modname, name, elf, sym, r);
586 }
587 }
588}
589
590/**
591 * Functions used only during module init is marked __init and is stored in
592 * a .init.text section. Likewise data is marked __initdata and stored in
593 * a .init.data section.
594 * If this section is one of these sections return 1
595 * See include/linux/init.h for the details
596 **/
597static int init_section(const char *name)
598{
599 if (strcmp(name, ".init") == 0)
600 return 1;
601 if (strncmp(name, ".init.", strlen(".init.")) == 0)
602 return 1;
603 return 0;
604}
605
606/**
607 * Identify sections from which references to a .init section is OK.
608 *
609 * Unfortunately references to read only data that referenced .init
610 * sections had to be excluded. Almost all of these are false
611 * positives, they are created by gcc. The downside of excluding rodata
612 * is that there really are some user references from rodata to
613 * init code, e.g. drivers/video/vgacon.c:
614 *
615 * const struct consw vga_con = {
616 * con_startup: vgacon_startup,
617 *
618 * where vgacon_startup is __init. If you want to wade through the false
619 * positives, take out the check for rodata.
620 **/
621static int init_section_ref_ok(const char *name)
622{
623 const char **s;
624 /* Absolute section names */
625 const char *namelist1[] = {
626 ".init",
627 ".stab",
628 ".rodata",
629 ".text.lock",
630 ".pci_fixup_header",
631 ".pci_fixup_final",
632 ".pdr",
633 "__param",
634 NULL
635 };
636 /* Start of section names */
637 const char *namelist2[] = {
638 ".init.",
639 ".altinstructions",
640 ".eh_frame",
641 ".debug",
642 NULL
643 };
644
645 for (s = namelist1; *s; s++)
646 if (strcmp(*s, name) == 0)
647 return 1;
648 for (s = namelist2; *s; s++)
649 if (strncmp(*s, name, strlen(*s)) == 0)
650 return 1;
651 return 0;
652}
653
654/*
655 * Functions used only during module exit is marked __exit and is stored in
656 * a .exit.text section. Likewise data is marked __exitdata and stored in
657 * a .exit.data section.
658 * If this section is one of these sections return 1
659 * See include/linux/init.h for the details
660 **/
661static int exit_section(const char *name)
662{
663 if (strcmp(name, ".exit.text") == 0)
664 return 1;
665 if (strcmp(name, ".exit.data") == 0)
666 return 1;
667 return 0;
668
669}
670
671/*
672 * Identify sections from which references to a .exit section is OK.
673 *
674 * [OPD] Keith Ownes <kaos@sgi.com> commented:
675 * For our future {in}sanity, add a comment that this is the ppc .opd
676 * section, not the ia64 .opd section.
677 * ia64 .opd should not point to discarded sections.
678 **/
679static int exit_section_ref_ok(const char *name)
680{
681 const char **s;
682 /* Absolute section names */
683 const char *namelist1[] = {
684 ".exit.text",
685 ".exit.data",
686 ".init.text",
687 ".opd", /* See comment [OPD] */
688 ".altinstructions",
689 ".pdr",
690 ".exitcall.exit",
691 ".eh_frame",
692 ".stab",
693 NULL
694 };
695 /* Start of section names */
696 const char *namelist2[] = {
697 ".debug",
698 NULL
699 };
700
701 for (s = namelist1; *s; s++)
702 if (strcmp(*s, name) == 0)
703 return 1;
704 for (s = namelist2; *s; s++)
705 if (strncmp(*s, name, strlen(*s)) == 0)
706 return 1;
707 return 0;
708}
709
454static void read_symbols(char *modname) 710static void read_symbols(char *modname)
455{ 711{
456 const char *symname; 712 const char *symname;
@@ -476,6 +732,8 @@ static void read_symbols(char *modname)
476 handle_modversions(mod, &info, sym, symname); 732 handle_modversions(mod, &info, sym, symname);
477 handle_moddevtable(mod, &info, sym, symname); 733 handle_moddevtable(mod, &info, sym, symname);
478 } 734 }
735 check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok);
736 check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok);
479 737
480 version = get_modinfo(info.modinfo, info.modinfo_len, "version"); 738 version = get_modinfo(info.modinfo, info.modinfo_len, "version");
481 if (version) 739 if (version)
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index c0de7b98c24c..3b5319dd937f 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -16,17 +16,27 @@
16#define Elf_Ehdr Elf32_Ehdr 16#define Elf_Ehdr Elf32_Ehdr
17#define Elf_Shdr Elf32_Shdr 17#define Elf_Shdr Elf32_Shdr
18#define Elf_Sym Elf32_Sym 18#define Elf_Sym Elf32_Sym
19#define Elf_Addr Elf32_Addr
20#define Elf_Section Elf32_Section
19#define ELF_ST_BIND ELF32_ST_BIND 21#define ELF_ST_BIND ELF32_ST_BIND
20#define ELF_ST_TYPE ELF32_ST_TYPE 22#define ELF_ST_TYPE ELF32_ST_TYPE
21 23
24#define Elf_Rela Elf32_Rela
25#define ELF_R_SYM ELF32_R_SYM
26#define ELF_R_TYPE ELF32_R_TYPE
22#else 27#else
23 28
24#define Elf_Ehdr Elf64_Ehdr 29#define Elf_Ehdr Elf64_Ehdr
25#define Elf_Shdr Elf64_Shdr 30#define Elf_Shdr Elf64_Shdr
26#define Elf_Sym Elf64_Sym 31#define Elf_Sym Elf64_Sym
32#define Elf_Addr Elf64_Addr
33#define Elf_Section Elf64_Section
27#define ELF_ST_BIND ELF64_ST_BIND 34#define ELF_ST_BIND ELF64_ST_BIND
28#define ELF_ST_TYPE ELF64_ST_TYPE 35#define ELF_ST_TYPE ELF64_ST_TYPE
29 36
37#define Elf_Rela Elf64_Rela
38#define ELF_R_SYM ELF64_R_SYM
39#define ELF_R_TYPE ELF64_R_TYPE
30#endif 40#endif
31 41
32#if KERNEL_ELFDATA != HOST_ELFDATA 42#if KERNEL_ELFDATA != HOST_ELFDATA