History

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.

Sam Ravnborg committed 18 years ago

Commit 588ccd71 parent f5eaa323 files · +229 −29Browse files

Showing the changes to scripts (2 of 3 files). Show all

Unified · Split

2 files
  1. scripts/Makefile.modpost +1 −0
  2. scripts/mod/modpost.c +226 −29
scripts/Makefile.modpost+1−0
@@ -62,6 +62,7 @@ modpost = scripts/mod/modpost \ · 61 unmodified lines
6262 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
6363 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
6464 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
65+ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \
6566 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
6667
6768 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
scripts/mod/modpost.c+226−29
@@ -28,6 +28,9 @@ static int vmlinux_section_warnings = 1; · 27 unmodified lines
2828 /* Only warn about unresolved symbols */
2929 static int warn_unresolved = 0;
3030 /* How a symbol is exported */
31+static int sec_mismatch_count = 0;
32+static int sec_mismatch_verbose = 1;
33+
3134 enum export {
3235 export_plain, export_unused, export_gpl,
3336 export_unused_gpl, export_gpl_future, export_unknown
@@ -760,9 +763,23 @@ static const char *head_sections[] = { ".head.text*", NULL }; · 726 unmodified lines
760763 static const char *linker_symbols[] =
761764 { "__init_begin", "_sinittext", "_einittext", NULL };
762765
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+
763779 struct sectioncheck {
764780 const char *fromsec[20];
765781 const char *tosec[20];
782+ enum mismatch mismatch;
766783 };
767784
768785 const struct sectioncheck sectioncheck[] = {
@@ -770,33 +787,54 @@ const struct sectioncheck sectioncheck[] = { · 1 unmodified line
770787 * normal code and data
771788 */
772789 {
773− .fromsec = { TEXT_SECTIONS, DATA_SECTIONS, NULL },
774− .tosec = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }
790+ .fromsec = { TEXT_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,
775808 },
776809 /* Do not reference init code/data from devinit/cpuinit/meminit code/data */
777810 {
778811 .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,
780814 },
781815 /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */
782816 {
783817 .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,
785820 },
786821 /* Do not use exit code/data from init code */
787822 {
788823 .fromsec = { ALL_INIT_SECTIONS, NULL },
789824 .tosec = { ALL_EXIT_SECTIONS, NULL },
825+ .mismatch = INIT_TO_EXIT,
790826 },
791827 /* Do not use init code/data from exit code */
792828 {
793829 .fromsec = { ALL_EXIT_SECTIONS, NULL },
794− .tosec = { ALL_INIT_SECTIONS, NULL }
830+ .tosec = { ALL_INIT_SECTIONS, NULL },
831+ .mismatch = EXIT_TO_INIT,
795832 },
796833 /* Do not export init/exit functions or data */
797834 {
798835 .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
800838 }
801839 };
802840
@@ -809,10 +847,10 @@ static int section_mismatch(const char *fromsec, const char *tosec) · 6 unmodified lines
809847 for (i = 0; i < elems; i++) {
810848 if (match(fromsec, check->fromsec) &&
811849 match(tosec, check->tosec))
812− return 1;
850+ return check->mismatch;
813851 check++;
814852 }
815− return 0;
853+ return NO_MISMATCH;
816854 }
817855
818856 /**
@@ -988,48 +1026,198 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, · 169 unmodified lines
9881026 return near;
9891027 }
9901028
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+
9911071 /*
9921072 * Print a warning about a section mismatch.
9931073 * Try to find symbols near it so user can find it.
9941074 * Check whitelist before warning - it may be a false positive.
9951075 */
996−static void report_sec_mismatch(const char *modname,
1076+static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
9971077 const char *fromsec,
9981078 unsigned long long fromaddr,
9991079 const char *fromsym,
1000− const char *tosec, const char *tosym)
1001−{
1002− if (strlen(tosym)) {
1003− warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
1004− "in '%s'\n",
1005− modname, fromsec, fromaddr,
1006− tosec, tosym, fromsym);
1007− } else {
1008− warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s\n",
1009− modname, fromsec, fromaddr,
1010− tosec, tosym);
1080+ int from_is_func,
1081+ const char *tosec, const char *tosym,
1082+ int to_is_func)
1083+{
1084+ const char *from, *from_p;
1085+ const char *to, *to_p;
1086+ from = from_is_func ? "function" : "variable";
1087+ from_p = from_is_func ? "()" : "";
1088+ to = to_is_func ? "function" : "variable";
1089+ to_p = to_is_func ? "()" : "";
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;
10111124 }
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");
10121194 }
10131195
10141196 static void check_section_mismatch(const char *modname, struct elf_info *elf,
10151197 Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
10161198 {
10171199 const char *tosec;
1200+ enum mismatch mismatch;
10181201
10191202 tosec = sec_name(elf, sym->st_shndx);
1020− if (section_mismatch(fromsec, tosec)) {
1021− const char *fromsym;
1203+ mismatch = section_mismatch(fromsec, tosec);
1204+ if (mismatch != NO_MISMATCH) {
1205+ Elf_Sym *to;
1206+ Elf_Sym *from;
10221207 const char *tosym;
1208+ const char *fromsym;
10231209
1024− fromsym = sym_name(elf,
1025− find_elf_symbol2(elf, r->r_offset, fromsec));
1026− tosym = sym_name(elf,
1027− find_elf_symbol(elf, r->r_addend, sym));
1210+ from = find_elf_symbol2(elf, r->r_offset, fromsec);
1211+ fromsym = sym_name(elf, from);
1212+ to = find_elf_symbol(elf, r->r_addend, sym);
1213+ tosym = sym_name(elf, to);
10281214
10291215 /* check whitelist - we may ignore it */
10301216 if (secref_whitelist(fromsec, fromsym, tosec, tosym)) {
1031− report_sec_mismatch(modname, fromsec, r->r_offset,
1032− fromsym, tosec, tosym);
1217+ report_sec_mismatch(modname, mismatch,
1218+ fromsec, r->r_offset, fromsym,
1219+ is_function(from), tosec, tosym,
1220+ is_function(to));
10331221 }
10341222 }
10351223 }
@@ -1643,7 +1831,7 @@ int main(int argc, char **argv) · 607 unmodified lines
16431831 int opt;
16441832 int err;
16451833
1646− while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
1834+ while ((opt = getopt(argc, argv, "i:I:msSo:aw")) != -1) {
16471835 switch (opt) {
16481836 case 'i':
16491837 kernel_read = optarg;
@@ -1664,6 +1852,9 @@ int main(int argc, char **argv) · 14 unmodified lines
16641852 case 's':
16651853 vmlinux_section_warnings = 0;
16661854 break;
1855+ case 'S':
1856+ sec_mismatch_verbose = 0;
1857+ break;
16671858 case 'w':
16681859 warn_unresolved = 1;
16691860 break;
@@ -1708,6 +1899,12 @@ int main(int argc, char **argv) · 38 unmodified lines
17081899
17091900 if (dump_write)
17101901 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);
17111908
17121909 return err;
17131910 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t