diff options
Diffstat (limited to 'scripts/mod')
| -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 | } |
