aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-01-24 15:12:37 -0500
committerSam Ravnborg <sam@ravnborg.org>2008-01-28 17:21:18 -0500
commit588ccd732ba2d32db8228802ef9283b583d3395f (patch)
tree435ad4432c165190d70b82f8392c37b375679b53
parentf5eaa323eb6819d2f737ead42464efccaf2b98b9 (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>
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--scripts/Makefile.modpost1
-rw-r--r--scripts/mod/modpost.c255
3 files changed, 229 insertions, 29 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 748e72be6e68..c4ecb2994ba3 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -108,6 +108,8 @@ config DEBUG_SECTION_MISMATCH
108 will tell where the mismatch happens much closer to the 108 will tell where the mismatch happens much closer to the
109 source. The drawback is that we will report the same 109 source. The drawback is that we will report the same
110 mismatch at least twice. 110 mismatch at least twice.
111 - Enable verbose reporting from modpost to help solving
112 the section mismatches reported.
111 113
112config DEBUG_KERNEL 114config DEBUG_KERNEL
113 bool "Kernel debugging" 115 bool "Kernel debugging"
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
67quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules 68quiet_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 */
29static int warn_unresolved = 0; 29static int warn_unresolved = 0;
30/* How a symbol is exported */ 30/* How a symbol is exported */
31static int sec_mismatch_count = 0;
32static int sec_mismatch_verbose = 1;
33
31enum export { 34enum 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 };
760static const char *linker_symbols[] = 763static const char *linker_symbols[] =
761 { "__init_begin", "_sinittext", "_einittext", NULL }; 764 { "__init_begin", "_sinittext", "_einittext", NULL };
762 765
766enum 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
763struct sectioncheck { 779struct 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
768const struct sectioncheck sectioncheck[] = { 785const 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*/
1036static 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
1063static 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 */
996static void report_sec_mismatch(const char *modname, 1076static 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
1014static void check_section_mismatch(const char *modname, struct elf_info *elf, 1196static 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}