Commit 588ccd732ba2d32db8228802ef9283b583d3395f

Authored by Sam Ravnborg
1 parent f5eaa323eb

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>

Showing 3 changed files with 229 additions and 29 deletions Side-by-side Diff

... ... @@ -108,6 +108,8 @@
108 108 will tell where the mismatch happens much closer to the
109 109 source. The drawback is that we will report the same
110 110 mismatch at least twice.
  111 + - Enable verbose reporting from modpost to help solving
  112 + the section mismatches reported.
111 113  
112 114 config DEBUG_KERNEL
113 115 bool "Kernel debugging"
scripts/Makefile.modpost
... ... @@ -62,6 +62,7 @@
62 62 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
63 63 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
64 64 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
  65 + $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \
65 66 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
66 67  
67 68 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
scripts/mod/modpost.c
... ... @@ -28,6 +28,9 @@
28 28 /* Only warn about unresolved symbols */
29 29 static int warn_unresolved = 0;
30 30 /* How a symbol is exported */
  31 +static int sec_mismatch_count = 0;
  32 +static int sec_mismatch_verbose = 1;
  33 +
31 34 enum export {
32 35 export_plain, export_unused, export_gpl,
33 36 export_unused_gpl, export_gpl_future, export_unknown
34 37  
... ... @@ -760,9 +763,23 @@
760 763 static const char *linker_symbols[] =
761 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 779 struct sectioncheck {
764 780 const char *fromsec[20];
765 781 const char *tosec[20];
  782 + enum mismatch mismatch;
766 783 };
767 784  
768 785 const struct sectioncheck sectioncheck[] = {
769 786  
770 787  
771 788  
772 789  
773 790  
774 791  
... ... @@ -770,33 +787,54 @@
770 787 * normal code and data
771 788 */
772 789 {
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,
775 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,
  808 +},
776 809 /* Do not reference init code/data from devinit/cpuinit/meminit code/data */
777 810 {
778 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 815 /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */
782 816 {
783 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 821 /* Do not use exit code/data from init code */
787 822 {
788 823 .fromsec = { ALL_INIT_SECTIONS, NULL },
789 824 .tosec = { ALL_EXIT_SECTIONS, NULL },
  825 + .mismatch = INIT_TO_EXIT,
790 826 },
791 827 /* Do not use init code/data from exit code */
792 828 {
793 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 833 /* Do not export init/exit functions or data */
797 834 {
798 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  
803 841  
... ... @@ -809,10 +847,10 @@
809 847 for (i = 0; i < elems; i++) {
810 848 if (match(fromsec, check->fromsec) &&
811 849 match(tosec, check->tosec))
812   - return 1;
  850 + return check->mismatch;
813 851 check++;
814 852 }
815   - return 0;
  853 + return NO_MISMATCH;
816 854 }
817 855  
818 856 /**
819 857  
820 858  
821 859  
822 860  
823 861  
824 862  
825 863  
826 864  
827 865  
... ... @@ -989,47 +1027,197 @@
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 1072 * Print a warning about a section mismatch.
993 1073 * Try to find symbols near it so user can find it.
994 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 1077 const char *fromsec,
998 1078 unsigned long long fromaddr,
999 1079 const char *fromsym,
1000   - const char *tosec, const char *tosym)
  1080 + int from_is_func,
  1081 + const char *tosec, const char *tosym,
  1082 + int to_is_func)
1001 1083 {
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);
  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;
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 1196 static void check_section_mismatch(const char *modname, struct elf_info *elf,
1015 1197 Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1016 1198 {
1017 1199 const char *tosec;
  1200 + enum mismatch mismatch;
1018 1201  
1019 1202 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;
1022 1207 const char *tosym;
  1208 + const char *fromsym;
1023 1209  
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);
1028 1214  
1029 1215 /* check whitelist - we may ignore it */
1030 1216 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));
1033 1221 }
1034 1222 }
1035 1223 }
... ... @@ -1643,7 +1831,7 @@
1643 1831 int opt;
1644 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 1835 switch (opt) {
1648 1836 case 'i':
1649 1837 kernel_read = optarg;
... ... @@ -1664,6 +1852,9 @@
1664 1852 case 's':
1665 1853 vmlinux_section_warnings = 0;
1666 1854 break;
  1855 + case 'S':
  1856 + sec_mismatch_verbose = 0;
  1857 + break;
1667 1858 case 'w':
1668 1859 warn_unresolved = 1;
1669 1860 break;
... ... @@ -1708,6 +1899,12 @@
1708 1899  
1709 1900 if (dump_write)
1710 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 1909 return err;
1713 1910 }