diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/mod/modpost.c | 146 |
1 files changed, 60 insertions, 86 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 6c206b9212b1..986513dcd700 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -625,6 +625,7 @@ static int number_prefix(const char *sym) | |||
625 | 625 | ||
626 | /* The pattern is an array of simple patterns. | 626 | /* The pattern is an array of simple patterns. |
627 | * "foo" will match an exact string equal to "foo" | 627 | * "foo" will match an exact string equal to "foo" |
628 | * "*foo" will match a string that ends with "foo" | ||
628 | * "foo*" will match a string that begins with "foo" | 629 | * "foo*" will match a string that begins with "foo" |
629 | * "foo$" will match a string equal to "foo" or "foo.1" | 630 | * "foo$" will match a string equal to "foo" or "foo.1" |
630 | * where the '1' can be any number including several digits. | 631 | * where the '1' can be any number including several digits. |
@@ -638,8 +639,13 @@ int match(const char *sym, const char * const pat[]) | |||
638 | p = *pat++; | 639 | p = *pat++; |
639 | const char *endp = p + strlen(p) - 1; | 640 | const char *endp = p + strlen(p) - 1; |
640 | 641 | ||
642 | /* "*foo" */ | ||
643 | if (*p == '*') { | ||
644 | if (strrcmp(sym, p + 1) == 0) | ||
645 | return 1; | ||
646 | } | ||
641 | /* "foo*" */ | 647 | /* "foo*" */ |
642 | if (*endp == '*') { | 648 | else if (*endp == '*') { |
643 | if (strncmp(sym, p, strlen(p) - 1) == 0) | 649 | if (strncmp(sym, p, strlen(p) - 1) == 0) |
644 | return 1; | 650 | return 1; |
645 | } | 651 | } |
@@ -660,54 +666,6 @@ int match(const char *sym, const char * const pat[]) | |||
660 | return 0; | 666 | return 0; |
661 | } | 667 | } |
662 | 668 | ||
663 | /* | ||
664 | * Functions used only during module init is marked __init and is stored in | ||
665 | * a .init.text section. Likewise data is marked __initdata and stored in | ||
666 | * a .init.data section. | ||
667 | * If this section is one of these sections return 1 | ||
668 | * See include/linux/init.h for the details | ||
669 | */ | ||
670 | static int init_section(const char *name) | ||
671 | { | ||
672 | if (strcmp(name, ".init") == 0) | ||
673 | return 1; | ||
674 | if (strncmp(name, ".init.", strlen(".init.")) == 0) | ||
675 | return 1; | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /* | ||
680 | * Functions used only during module exit is marked __exit and is stored in | ||
681 | * a .exit.text section. Likewise data is marked __exitdata and stored in | ||
682 | * a .exit.data section. | ||
683 | * If this section is one of these sections return 1 | ||
684 | * See include/linux/init.h for the details | ||
685 | **/ | ||
686 | static int exit_section(const char *name) | ||
687 | { | ||
688 | if (strcmp(name, ".exit.text") == 0) | ||
689 | return 1; | ||
690 | if (strcmp(name, ".exit.data") == 0) | ||
691 | return 1; | ||
692 | return 0; | ||
693 | |||
694 | } | ||
695 | |||
696 | /* | ||
697 | * Data sections are named like this: | ||
698 | * .data | .data.rel | .data.rel.* | ||
699 | * Return 1 if the specified section is a data section | ||
700 | */ | ||
701 | static int data_section(const char *name) | ||
702 | { | ||
703 | if ((strcmp(name, ".data") == 0) || | ||
704 | (strcmp(name, ".data.rel") == 0) || | ||
705 | (strncmp(name, ".data.rel.", strlen(".data.rel.")) == 0)) | ||
706 | return 1; | ||
707 | else | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* sections that we do not want to do full section mismatch check on */ | 669 | /* sections that we do not want to do full section mismatch check on */ |
712 | static const char *section_white_list[] = | 670 | static const char *section_white_list[] = |
713 | { ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL }; | 671 | { ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL }; |
@@ -721,9 +679,50 @@ static const char *section_white_list[] = | |||
721 | #define INIT_SECTIONS INIT_DATA_SECTIONS, INIT_TEXT_SECTIONS | 679 | #define INIT_SECTIONS INIT_DATA_SECTIONS, INIT_TEXT_SECTIONS |
722 | #define EXIT_SECTIONS EXIT_DATA_SECTIONS, EXIT_TEXT_SECTIONS | 680 | #define EXIT_SECTIONS EXIT_DATA_SECTIONS, EXIT_TEXT_SECTIONS |
723 | 681 | ||
724 | #define DATA_SECTIONS ".data$" | 682 | #define DATA_SECTIONS ".data$", ".data.rel$" |
725 | #define TEXT_SECTIONS ".text$" | 683 | #define TEXT_SECTIONS ".text$" |
726 | 684 | ||
685 | /* init data sections */ | ||
686 | static const char *init_data_sections[] = { INIT_DATA_SECTIONS, NULL }; | ||
687 | |||
688 | /* all init sections */ | ||
689 | static const char *init_sections[] = { INIT_SECTIONS, NULL }; | ||
690 | |||
691 | /* All init and exit sections (code + data) */ | ||
692 | static const char *init_exit_sections[] = | ||
693 | {INIT_SECTIONS, EXIT_SECTIONS, NULL }; | ||
694 | |||
695 | /* data section */ | ||
696 | static const char *data_sections[] = { DATA_SECTIONS, NULL }; | ||
697 | |||
698 | /* sections that may refer to an init/exit section with no warning */ | ||
699 | static const char *initref_sections[] = | ||
700 | { | ||
701 | ".text.init.refok*", | ||
702 | ".exit.text.refok*", | ||
703 | ".data.init.refok*", | ||
704 | NULL | ||
705 | }; | ||
706 | |||
707 | |||
708 | /* symbols in .data that may refer to init/exit sections */ | ||
709 | static const char *symbol_white_list[] = | ||
710 | { | ||
711 | "*driver", | ||
712 | "*_template", /* scsi uses *_template a lot */ | ||
713 | "*_timer", /* arm uses ops structures named _timer a lot */ | ||
714 | "*_sht", /* scsi also used *_sht to some extent */ | ||
715 | "*_ops", | ||
716 | "*_probe", | ||
717 | "*_probe_one", | ||
718 | "*_console", | ||
719 | NULL | ||
720 | }; | ||
721 | |||
722 | static const char *head_sections[] = { ".head.text*", NULL }; | ||
723 | static const char *linker_symbols[] = | ||
724 | { "__init_begin", "_sinittext", "_einittext", NULL }; | ||
725 | |||
727 | struct sectioncheck { | 726 | struct sectioncheck { |
728 | const char *fromsec[20]; | 727 | const char *fromsec[20]; |
729 | const char *tosec[20]; | 728 | const char *tosec[20]; |
@@ -817,55 +816,30 @@ static int secref_whitelist(const char *modname, const char *tosec, | |||
817 | const char *fromsec, const char *atsym, | 816 | const char *fromsec, const char *atsym, |
818 | const char *refsymname) | 817 | const char *refsymname) |
819 | { | 818 | { |
820 | const char **s; | ||
821 | const char *pat2sym[] = { | ||
822 | "driver", | ||
823 | "_template", /* scsi uses *_template a lot */ | ||
824 | "_timer", /* arm uses ops structures named _timer a lot */ | ||
825 | "_sht", /* scsi also used *_sht to some extent */ | ||
826 | "_ops", | ||
827 | "_probe", | ||
828 | "_probe_one", | ||
829 | "_console", | ||
830 | NULL | ||
831 | }; | ||
832 | |||
833 | const char *pat3refsym[] = { | ||
834 | "__init_begin", | ||
835 | "_sinittext", | ||
836 | "_einittext", | ||
837 | NULL | ||
838 | }; | ||
839 | |||
840 | /* Check for pattern 0 */ | 819 | /* Check for pattern 0 */ |
841 | if ((strncmp(fromsec, ".text.init.refok", strlen(".text.init.refok")) == 0) || | 820 | if (match(fromsec, initref_sections)) |
842 | (strncmp(fromsec, ".exit.text.refok", strlen(".exit.text.refok")) == 0) || | ||
843 | (strncmp(fromsec, ".data.init.refok", strlen(".data.init.refok")) == 0)) | ||
844 | return 1; | 821 | return 1; |
845 | 822 | ||
846 | /* Check for pattern 1 */ | 823 | /* Check for pattern 1 */ |
847 | if ((strcmp(tosec, ".init.data") == 0) && | 824 | if (match(tosec, init_data_sections) && |
848 | (strncmp(fromsec, ".data", strlen(".data")) == 0) && | 825 | match(fromsec, data_sections) && |
849 | (strncmp(atsym, "__param", strlen("__param")) == 0)) | 826 | (strncmp(atsym, "__param", strlen("__param")) == 0)) |
850 | return 1; | 827 | return 1; |
851 | 828 | ||
852 | /* Check for pattern 2 */ | 829 | /* Check for pattern 2 */ |
853 | if ((init_section(tosec) || exit_section(tosec)) | 830 | if (match(tosec, init_exit_sections) && |
854 | && data_section(fromsec)) | 831 | match(fromsec, data_sections) && |
855 | for (s = pat2sym; *s; s++) | 832 | match(atsym, symbol_white_list)) |
856 | if (strrcmp(atsym, *s) == 0) | 833 | return 1; |
857 | return 1; | ||
858 | 834 | ||
859 | /* Check for pattern 3 */ | 835 | /* Check for pattern 3 */ |
860 | if ((strcmp(fromsec, ".text.head") == 0) && | 836 | if (match(fromsec, head_sections) && |
861 | ((strcmp(tosec, ".init.data") == 0) || | 837 | match(tosec, init_sections)) |
862 | (strcmp(tosec, ".init.text") == 0))) | ||
863 | return 1; | 838 | return 1; |
864 | 839 | ||
865 | /* Check for pattern 4 */ | 840 | /* Check for pattern 4 */ |
866 | for (s = pat3refsym; *s; s++) | 841 | if (match(refsymname, linker_symbols)) |
867 | if (strcmp(refsymname, *s) == 0) | 842 | return 1; |
868 | return 1; | ||
869 | 843 | ||
870 | return 0; | 844 | return 0; |
871 | } | 845 | } |