diff options
| author | Sam Ravnborg <sam@ravnborg.org> | 2008-01-24 15:12:37 -0500 |
|---|---|---|
| committer | Sam Ravnborg <sam@ravnborg.org> | 2008-01-28 17:21:18 -0500 |
| commit | 588ccd732ba2d32db8228802ef9283b583d3395f (patch) | |
| tree | 435ad4432c165190d70b82f8392c37b375679b53 /scripts | |
| parent | f5eaa323eb6819d2f737ead42464efccaf2b98b9 (diff) | |
kbuild: add verbose option to Section mismatch reporting in modpost
If the config option CONFIG_SECTION_MISMATCH is not set and
we see a Section mismatch present the following to the user:
modpost: Found 1 section mismatch(es).
To see additional details select "Enable full Section mismatch analysis"
in the Kernel Hacking menu (CONFIG_SECTION_MISMATCH).
If the option CONFIG_SECTION_MISMATCH is selected
then be verbose in the Section mismatch reporting from mdopost.
Sample outputs:
WARNING: o-x86_64/vmlinux.o(.text+0x7396): Section mismatch in reference from the function discover_ebda() to the variable .init.data:ebda_addr
The function discover_ebda() references
the variable __initdata ebda_addr.
This is often because discover_ebda lacks a __initdata
annotation or the annotation of ebda_addr is wrong.
WARNING: o-x86_64/vmlinux.o(.data+0x74d58): Section mismatch in reference from the variable pci_serial_quirks to the function .devexit.text:pci_plx9050_exit()
The variable pci_serial_quirks references
the function __devexit pci_plx9050_exit()
If the reference is valid then annotate the
variable with __exit* (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console,
WARNING: o-x86_64/vmlinux.o(__ksymtab+0x630): Section mismatch in reference from the variable __ksymtab_arch_register_cpu to the function .cpuinit.text:arch_register_cpu()
The symbol arch_register_cpu is exported and annotated __cpuinit
Fix this by removing the __cpuinit annotation of arch_register_cpu or drop the export.
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/Makefile.modpost | 1 | ||||
| -rw-r--r-- | scripts/mod/modpost.c | 255 |
2 files changed, 227 insertions, 29 deletions
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index d988f5d21e3d..65e707e1ffc3 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost | |||
| @@ -62,6 +62,7 @@ modpost = scripts/mod/modpost \ | |||
| 62 | $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ | 62 | $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ |
| 63 | $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ | 63 | $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ |
| 64 | $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ | 64 | $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ |
| 65 | $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ | ||
| 65 | $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) | 66 | $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) |
| 66 | 67 | ||
| 67 | quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules | 68 | quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules |
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index e75739ec9c03..3cf1ba8220d2 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
| @@ -28,6 +28,9 @@ static int vmlinux_section_warnings = 1; | |||
| 28 | /* Only warn about unresolved symbols */ | 28 | /* Only warn about unresolved symbols */ |
| 29 | static int warn_unresolved = 0; | 29 | static int warn_unresolved = 0; |
| 30 | /* How a symbol is exported */ | 30 | /* How a symbol is exported */ |
| 31 | static int sec_mismatch_count = 0; | ||
| 32 | static int sec_mismatch_verbose = 1; | ||
| 33 | |||
| 31 | enum export { | 34 | enum export { |
| 32 | export_plain, export_unused, export_gpl, | 35 | export_plain, export_unused, export_gpl, |
| 33 | export_unused_gpl, export_gpl_future, export_unknown | 36 | export_unused_gpl, export_gpl_future, export_unknown |
| @@ -760,9 +763,23 @@ static const char *head_sections[] = { ".head.text*", NULL }; | |||
| 760 | static const char *linker_symbols[] = | 763 | static const char *linker_symbols[] = |
| 761 | { "__init_begin", "_sinittext", "_einittext", NULL }; | 764 | { "__init_begin", "_sinittext", "_einittext", NULL }; |
| 762 | 765 | ||
| 766 | enum mismatch { | ||
| 767 | NO_MISMATCH, | ||
| 768 | TEXT_TO_INIT, | ||
| 769 | DATA_TO_INIT, | ||
| 770 | TEXT_TO_EXIT, | ||
| 771 | DATA_TO_EXIT, | ||
| 772 | XXXINIT_TO_INIT, | ||
| 773 | XXXEXIT_TO_EXIT, | ||
| 774 | INIT_TO_EXIT, | ||
| 775 | EXIT_TO_INIT, | ||
| 776 | EXPORT_TO_INIT_EXIT, | ||
| 777 | }; | ||
| 778 | |||
| 763 | struct sectioncheck { | 779 | struct sectioncheck { |
| 764 | const char *fromsec[20]; | 780 | const char *fromsec[20]; |
| 765 | const char *tosec[20]; | 781 | const char *tosec[20]; |
| 782 | enum mismatch mismatch; | ||
| 766 | }; | 783 | }; |
| 767 | 784 | ||
| 768 | const struct sectioncheck sectioncheck[] = { | 785 | const struct sectioncheck sectioncheck[] = { |
| @@ -770,33 +787,54 @@ const struct sectioncheck sectioncheck[] = { | |||
| 770 | * normal code and data | 787 | * normal code and data |
| 771 | */ | 788 | */ |
| 772 | { | 789 | { |
| 773 | .fromsec = { TEXT_SECTIONS, DATA_SECTIONS, NULL }, | 790 | .fromsec = { TEXT_SECTIONS, NULL }, |
| 774 | .tosec = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL } | 791 | .tosec = { ALL_INIT_SECTIONS, NULL }, |
| 792 | .mismatch = TEXT_TO_INIT, | ||
| 793 | }, | ||
| 794 | { | ||
| 795 | .fromsec = { DATA_SECTIONS, NULL }, | ||
| 796 | .tosec = { ALL_INIT_SECTIONS, NULL }, | ||
| 797 | .mismatch = DATA_TO_INIT, | ||
| 798 | }, | ||
| 799 | { | ||
| 800 | .fromsec = { TEXT_SECTIONS, NULL }, | ||
| 801 | .tosec = { ALL_EXIT_SECTIONS, NULL }, | ||
| 802 | .mismatch = TEXT_TO_EXIT, | ||
| 803 | }, | ||
| 804 | { | ||
| 805 | .fromsec = { DATA_SECTIONS, NULL }, | ||
| 806 | .tosec = { ALL_EXIT_SECTIONS, NULL }, | ||
| 807 | .mismatch = DATA_TO_EXIT, | ||
| 775 | }, | 808 | }, |
| 776 | /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ | 809 | /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ |
| 777 | { | 810 | { |
| 778 | .fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL }, | 811 | .fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL }, |
| 779 | .tosec = { INIT_SECTIONS, NULL } | 812 | .tosec = { INIT_SECTIONS, NULL }, |
| 813 | .mismatch = XXXINIT_TO_INIT, | ||
| 780 | }, | 814 | }, |
| 781 | /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ | 815 | /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ |
| 782 | { | 816 | { |
| 783 | .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, | 817 | .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, |
| 784 | .tosec = { EXIT_SECTIONS, NULL } | 818 | .tosec = { EXIT_SECTIONS, NULL }, |
| 819 | .mismatch = XXXEXIT_TO_EXIT, | ||
| 785 | }, | 820 | }, |
| 786 | /* Do not use exit code/data from init code */ | 821 | /* Do not use exit code/data from init code */ |
| 787 | { | 822 | { |
| 788 | .fromsec = { ALL_INIT_SECTIONS, NULL }, | 823 | .fromsec = { ALL_INIT_SECTIONS, NULL }, |
| 789 | .tosec = { ALL_EXIT_SECTIONS, NULL }, | 824 | .tosec = { ALL_EXIT_SECTIONS, NULL }, |
| 825 | .mismatch = INIT_TO_EXIT, | ||
| 790 | }, | 826 | }, |
| 791 | /* Do not use init code/data from exit code */ | 827 | /* Do not use init code/data from exit code */ |
| 792 | { | 828 | { |
| 793 | .fromsec = { ALL_EXIT_SECTIONS, NULL }, | 829 | .fromsec = { ALL_EXIT_SECTIONS, NULL }, |
| 794 | .tosec = { ALL_INIT_SECTIONS, NULL } | 830 | .tosec = { ALL_INIT_SECTIONS, NULL }, |
| 831 | .mismatch = EXIT_TO_INIT, | ||
| 795 | }, | 832 | }, |
| 796 | /* Do not export init/exit functions or data */ | 833 | /* Do not export init/exit functions or data */ |
| 797 | { | 834 | { |
| 798 | .fromsec = { "__ksymtab*", NULL }, | 835 | .fromsec = { "__ksymtab*", NULL }, |
| 799 | .tosec = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL } | 836 | .tosec = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }, |
| 837 | .mismatch = EXPORT_TO_INIT_EXIT | ||
| 800 | } | 838 | } |
| 801 | }; | 839 | }; |
| 802 | 840 | ||
| @@ -809,10 +847,10 @@ static int section_mismatch(const char *fromsec, const char *tosec) | |||
| 809 | for (i = 0; i < elems; i++) { | 847 | for (i = 0; i < elems; i++) { |
| 810 | if (match(fromsec, check->fromsec) && | 848 | if (match(fromsec, check->fromsec) && |
| 811 | match(tosec, check->tosec)) | 849 | match(tosec, check->tosec)) |
| 812 | return 1; | 850 | return check->mismatch; |
| 813 | check++; | 851 | check++; |
| 814 | } | 852 | } |
| 815 | return 0; | 853 | return NO_MISMATCH; |
| 816 | } | 854 | } |
| 817 | 855 | ||
| 818 | /** | 856 | /** |
| @@ -989,47 +1027,197 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, | |||
| 989 | } | 1027 | } |
| 990 | 1028 | ||
| 991 | /* | 1029 | /* |
| 1030 | * Convert a section name to the function/data attribute | ||
| 1031 | * .init.text => __init | ||
| 1032 | * .cpuinit.data => __cpudata | ||
| 1033 | * .memexitconst => __memconst | ||
| 1034 | * etc. | ||
| 1035 | */ | ||
| 1036 | static char *sec2annotation(const char *s) | ||
| 1037 | { | ||
| 1038 | if (match(s, init_exit_sections)) { | ||
| 1039 | char *p = malloc(20); | ||
| 1040 | char *r = p; | ||
| 1041 | |||
| 1042 | *p++ = '_'; | ||
| 1043 | *p++ = '_'; | ||
| 1044 | if (*s == '.') | ||
| 1045 | s++; | ||
| 1046 | while (*s && *s != '.') | ||
| 1047 | *p++ = *s++; | ||
| 1048 | *p = '\0'; | ||
| 1049 | if (*s == '.') | ||
| 1050 | s++; | ||
| 1051 | if (strstr(s, "rodata") != NULL) | ||
| 1052 | strcat(p, "const "); | ||
| 1053 | else if (strstr(s, "data") != NULL) | ||
| 1054 | strcat(p, "data "); | ||
| 1055 | else | ||
| 1056 | strcat(p, " "); | ||
| 1057 | return r; /* we leak her but we do not care */ | ||
| 1058 | } else { | ||
| 1059 | return ""; | ||
| 1060 | } | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | static int is_function(Elf_Sym *sym) | ||
| 1064 | { | ||
| 1065 | if (sym) | ||
| 1066 | return ELF_ST_TYPE(sym->st_info) == STT_FUNC; | ||
| 1067 | else | ||
| 1068 | return 0; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | /* | ||
| 992 | * Print a warning about a section mismatch. | 1072 | * Print a warning about a section mismatch. |
| 993 | * Try to find symbols near it so user can find it. | 1073 | * Try to find symbols near it so user can find it. |
| 994 | * Check whitelist before warning - it may be a false positive. | 1074 | * Check whitelist before warning - it may be a false positive. |
| 995 | */ | 1075 | */ |
| 996 | static void report_sec_mismatch(const char *modname, | 1076 | static void report_sec_mismatch(const char *modname, enum mismatch mismatch, |
| 997 | const char *fromsec, | 1077 | const char *fromsec, |
| 998 | unsigned long long fromaddr, | 1078 | unsigned long long fromaddr, |
| 999 | const char *fromsym, | 1079 | const char *fromsym, |
| 1000 | const char *tosec, const char *tosym) | 1080 | int from_is_func, |
| 1001 | { | 1081 | const char *tosec, const char *tosym, |
| 1002 | if (strlen(tosym)) { | 1082 | int to_is_func) |
| 1003 | warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s " | 1083 | { |
| 1004 | "in '%s'\n", | 1084 | const char *from, *from_p; |
| 1005 | modname, fromsec, fromaddr, | 1085 | const char *to, *to_p; |
| 1006 | tosec, tosym, fromsym); | 1086 | from = from_is_func ? "function" : "variable"; |
| 1007 | } else { | 1087 | from_p = from_is_func ? "()" : ""; |
| 1008 | warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s\n", | 1088 | to = to_is_func ? "function" : "variable"; |
| 1009 | modname, fromsec, fromaddr, | 1089 | to_p = to_is_func ? "()" : ""; |
| 1010 | tosec, tosym); | 1090 | |
| 1091 | fprintf(stderr, "WARNING: %s(%s+0x%llx): Section mismatch in" | ||
| 1092 | " reference from the %s %s%s to the %s %s:%s%s\n", | ||
| 1093 | modname, fromsec, fromaddr, from, fromsym, from_p, | ||
| 1094 | to, tosec, tosym, to_p); | ||
| 1095 | |||
| 1096 | sec_mismatch_count++; | ||
| 1097 | if (!sec_mismatch_verbose) | ||
| 1098 | return; | ||
| 1099 | |||
| 1100 | switch (mismatch) { | ||
| 1101 | case TEXT_TO_INIT: | ||
| 1102 | fprintf(stderr, | ||
| 1103 | "The function %s %s() references\n" | ||
| 1104 | "the %s %s%s%s.\n" | ||
| 1105 | "This is often because %s lacks a %s\n" | ||
| 1106 | "annotation or the annotation of %s is wrong.\n", | ||
| 1107 | sec2annotation(fromsec), fromsym, | ||
| 1108 | to, sec2annotation(tosec), tosym, to_p, | ||
| 1109 | fromsym, sec2annotation(tosec), tosym); | ||
| 1110 | break; | ||
| 1111 | case DATA_TO_INIT: { | ||
| 1112 | const char **s = symbol_white_list; | ||
| 1113 | fprintf(stderr, | ||
| 1114 | "The variable %s references\n" | ||
| 1115 | "the %s %s%s%s\n" | ||
| 1116 | "If the reference is valid then annotate the\n" | ||
| 1117 | "variable with __init* (see linux/init.h) " | ||
| 1118 | "or name the variable:\n", | ||
| 1119 | fromsym, to, sec2annotation(tosec), tosym, to_p); | ||
| 1120 | while (*s) | ||
| 1121 | fprintf(stderr, "%s, ", *s++); | ||
| 1122 | fprintf(stderr, "\n"); | ||
| 1123 | break; | ||
| 1011 | } | 1124 | } |
| 1125 | case TEXT_TO_EXIT: | ||
| 1126 | fprintf(stderr, | ||
| 1127 | "The function %s() references a %s in an exit section.\n" | ||
| 1128 | "Often the %s %s%s has valid usage outside the exit section\n" | ||
| 1129 | "and the fix is to remove the %sannotation of %s.\n", | ||
| 1130 | fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym); | ||
| 1131 | break; | ||
| 1132 | case DATA_TO_EXIT: { | ||
| 1133 | const char **s = symbol_white_list; | ||
| 1134 | fprintf(stderr, | ||
| 1135 | "The variable %s references\n" | ||
| 1136 | "the %s %s%s%s\n" | ||
| 1137 | "If the reference is valid then annotate the\n" | ||
| 1138 | "variable with __exit* (see linux/init.h) or " | ||
| 1139 | "name the variable:\n", | ||
| 1140 | fromsym, to, sec2annotation(tosec), tosym, to_p); | ||
| 1141 | while (*s) | ||
| 1142 | fprintf(stderr, "%s, ", *s++); | ||
| 1143 | fprintf(stderr, "\n"); | ||
| 1144 | break; | ||
| 1145 | } | ||
| 1146 | case XXXINIT_TO_INIT: | ||
| 1147 | case XXXEXIT_TO_EXIT: | ||
| 1148 | fprintf(stderr, | ||
| 1149 | "The %s %s%s%s references\n" | ||
| 1150 | "a %s %s%s%s.\n" | ||
| 1151 | "If %s is only used by %s then\n" | ||
| 1152 | "annotate %s with a matching annotation.\n", | ||
| 1153 | from, sec2annotation(fromsec), fromsym, from_p, | ||
| 1154 | to, sec2annotation(tosec), tosym, to_p, | ||
| 1155 | fromsym, tosym, fromsym); | ||
| 1156 | break; | ||
| 1157 | case INIT_TO_EXIT: | ||
| 1158 | fprintf(stderr, | ||
| 1159 | "The %s %s%s%s references\n" | ||
| 1160 | "a %s %s%s%s.\n" | ||
| 1161 | "This is often seen when error handling " | ||
| 1162 | "in the init function\n" | ||
| 1163 | "uses functionality in the exit path.\n" | ||
| 1164 | "The fix is often to remove the %sannotation of\n" | ||
| 1165 | "%s%s so it may be used outside an exit section.\n", | ||
| 1166 | from, sec2annotation(fromsec), fromsym, from_p, | ||
| 1167 | to, sec2annotation(tosec), tosym, to_p, | ||
| 1168 | sec2annotation(tosec), tosym, to_p); | ||
| 1169 | break; | ||
| 1170 | case EXIT_TO_INIT: | ||
| 1171 | fprintf(stderr, | ||
| 1172 | "The %s %s%s%s references\n" | ||
| 1173 | "a %s %s%s%s.\n" | ||
| 1174 | "This is often seen when error handling " | ||
| 1175 | "in the exit function\n" | ||
| 1176 | "uses functionality in the init path.\n" | ||
| 1177 | "The fix is often to remove the %sannotation of\n" | ||
| 1178 | "%s%s so it may be used outside an init section.\n", | ||
| 1179 | from, sec2annotation(fromsec), fromsym, from_p, | ||
| 1180 | to, sec2annotation(tosec), tosym, to_p, | ||
| 1181 | sec2annotation(tosec), tosym, to_p); | ||
| 1182 | break; | ||
| 1183 | case EXPORT_TO_INIT_EXIT: | ||
| 1184 | fprintf(stderr, | ||
| 1185 | "The symbol %s is exported and annotated %s\n" | ||
| 1186 | "Fix this by removing the %sannotation of %s " | ||
| 1187 | "or drop the export.\n", | ||
| 1188 | tosym, sec2annotation(tosec), sec2annotation(tosec), tosym); | ||
| 1189 | case NO_MISMATCH: | ||
| 1190 | /* To get warnings on missing members */ | ||
| 1191 | break; | ||
| 1192 | } | ||
| 1193 | fprintf(stderr, "\n"); | ||
| 1012 | } | 1194 | } |
| 1013 | 1195 | ||
| 1014 | static void check_section_mismatch(const char *modname, struct elf_info *elf, | 1196 | static void check_section_mismatch(const char *modname, struct elf_info *elf, |
| 1015 | Elf_Rela *r, Elf_Sym *sym, const char *fromsec) | 1197 | Elf_Rela *r, Elf_Sym *sym, const char *fromsec) |
| 1016 | { | 1198 | { |
| 1017 | const char *tosec; | 1199 | const char *tosec; |
| 1200 | enum mismatch mismatch; | ||
| 1018 | 1201 | ||
| 1019 | tosec = sec_name(elf, sym->st_shndx); | 1202 | tosec = sec_name(elf, sym->st_shndx); |
| 1020 | if (section_mismatch(fromsec, tosec)) { | 1203 | mismatch = section_mismatch(fromsec, tosec); |
| 1021 | const char *fromsym; | 1204 | if (mismatch != NO_MISMATCH) { |
| 1205 | Elf_Sym *to; | ||
| 1206 | Elf_Sym *from; | ||
| 1022 | const char *tosym; | 1207 | const char *tosym; |
| 1208 | const char *fromsym; | ||
| 1023 | 1209 | ||
| 1024 | fromsym = sym_name(elf, | 1210 | from = find_elf_symbol2(elf, r->r_offset, fromsec); |
| 1025 | find_elf_symbol2(elf, r->r_offset, fromsec)); | 1211 | fromsym = sym_name(elf, from); |
| 1026 | tosym = sym_name(elf, | 1212 | to = find_elf_symbol(elf, r->r_addend, sym); |
| 1027 | find_elf_symbol(elf, r->r_addend, sym)); | 1213 | tosym = sym_name(elf, to); |
| 1028 | 1214 | ||
| 1029 | /* check whitelist - we may ignore it */ | 1215 | /* check whitelist - we may ignore it */ |
| 1030 | if (secref_whitelist(fromsec, fromsym, tosec, tosym)) { | 1216 | if (secref_whitelist(fromsec, fromsym, tosec, tosym)) { |
| 1031 | report_sec_mismatch(modname, fromsec, r->r_offset, | 1217 | report_sec_mismatch(modname, mismatch, |
| 1032 | fromsym, tosec, tosym); | 1218 | fromsec, r->r_offset, fromsym, |
| 1219 | is_function(from), tosec, tosym, | ||
| 1220 | is_function(to)); | ||
| 1033 | } | 1221 | } |
| 1034 | } | 1222 | } |
| 1035 | } | 1223 | } |
| @@ -1643,7 +1831,7 @@ int main(int argc, char **argv) | |||
| 1643 | int opt; | 1831 | int opt; |
| 1644 | int err; | 1832 | int err; |
| 1645 | 1833 | ||
| 1646 | while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) { | 1834 | while ((opt = getopt(argc, argv, "i:I:msSo:aw")) != -1) { |
| 1647 | switch (opt) { | 1835 | switch (opt) { |
| 1648 | case 'i': | 1836 | case 'i': |
| 1649 | kernel_read = optarg; | 1837 | kernel_read = optarg; |
| @@ -1664,6 +1852,9 @@ int main(int argc, char **argv) | |||
| 1664 | case 's': | 1852 | case 's': |
| 1665 | vmlinux_section_warnings = 0; | 1853 | vmlinux_section_warnings = 0; |
| 1666 | break; | 1854 | break; |
| 1855 | case 'S': | ||
| 1856 | sec_mismatch_verbose = 0; | ||
| 1857 | break; | ||
| 1667 | case 'w': | 1858 | case 'w': |
| 1668 | warn_unresolved = 1; | 1859 | warn_unresolved = 1; |
| 1669 | break; | 1860 | break; |
| @@ -1708,6 +1899,12 @@ int main(int argc, char **argv) | |||
| 1708 | 1899 | ||
| 1709 | if (dump_write) | 1900 | if (dump_write) |
| 1710 | write_dump(dump_write); | 1901 | write_dump(dump_write); |
| 1902 | if (sec_mismatch_count && !sec_mismatch_verbose) | ||
| 1903 | fprintf(stderr, "modpost: Found %d section mismatch(es).\n" | ||
| 1904 | "To see additional details select \"Enable full " | ||
| 1905 | "Section mismatch analysis\"\n" | ||
| 1906 | "in the Kernel Hacking menu " | ||
| 1907 | "(CONFIG_SECTION_MISMATCH).\n", sec_mismatch_count); | ||
| 1711 | 1908 | ||
| 1712 | return err; | 1909 | return err; |
| 1713 | } | 1910 | } |
