diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 177 |
1 files changed, 158 insertions, 19 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index d0f86ed43f7a..0dd16177642d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <ctype.h> | 14 | #include <ctype.h> |
15 | #include "modpost.h" | 15 | #include "modpost.h" |
16 | #include "../../include/linux/license.h" | ||
16 | 17 | ||
17 | /* Are we using CONFIG_MODVERSIONS? */ | 18 | /* Are we using CONFIG_MODVERSIONS? */ |
18 | int modversions = 0; | 19 | int modversions = 0; |
@@ -22,6 +23,8 @@ int have_vmlinux = 0; | |||
22 | static int all_versions = 0; | 23 | static int all_versions = 0; |
23 | /* If we are modposting external module set to 1 */ | 24 | /* If we are modposting external module set to 1 */ |
24 | static int external_module = 0; | 25 | static int external_module = 0; |
26 | /* How a symbol is exported */ | ||
27 | enum export {export_plain, export_gpl, export_gpl_future, export_unknown}; | ||
25 | 28 | ||
26 | void fatal(const char *fmt, ...) | 29 | void fatal(const char *fmt, ...) |
27 | { | 30 | { |
@@ -97,6 +100,7 @@ static struct module *new_module(char *modname) | |||
97 | 100 | ||
98 | /* add to list */ | 101 | /* add to list */ |
99 | mod->name = p; | 102 | mod->name = p; |
103 | mod->gpl_compatible = -1; | ||
100 | mod->next = modules; | 104 | mod->next = modules; |
101 | modules = mod; | 105 | modules = mod; |
102 | 106 | ||
@@ -118,6 +122,7 @@ struct symbol { | |||
118 | unsigned int kernel:1; /* 1 if symbol is from kernel | 122 | unsigned int kernel:1; /* 1 if symbol is from kernel |
119 | * (only for external modules) **/ | 123 | * (only for external modules) **/ |
120 | unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ | 124 | unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ |
125 | enum export export; /* Type of export */ | ||
121 | char name[0]; | 126 | char name[0]; |
122 | }; | 127 | }; |
123 | 128 | ||
@@ -153,7 +158,8 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak, | |||
153 | } | 158 | } |
154 | 159 | ||
155 | /* For the hash of exported symbols */ | 160 | /* For the hash of exported symbols */ |
156 | static struct symbol *new_symbol(const char *name, struct module *module) | 161 | static struct symbol *new_symbol(const char *name, struct module *module, |
162 | enum export export) | ||
157 | { | 163 | { |
158 | unsigned int hash; | 164 | unsigned int hash; |
159 | struct symbol *new; | 165 | struct symbol *new; |
@@ -161,6 +167,7 @@ static struct symbol *new_symbol(const char *name, struct module *module) | |||
161 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; | 167 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; |
162 | new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); | 168 | new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
163 | new->module = module; | 169 | new->module = module; |
170 | new->export = export; | ||
164 | return new; | 171 | return new; |
165 | } | 172 | } |
166 | 173 | ||
@@ -179,16 +186,55 @@ static struct symbol *find_symbol(const char *name) | |||
179 | return NULL; | 186 | return NULL; |
180 | } | 187 | } |
181 | 188 | ||
189 | static struct { | ||
190 | const char *str; | ||
191 | enum export export; | ||
192 | } export_list[] = { | ||
193 | { .str = "EXPORT_SYMBOL", .export = export_plain }, | ||
194 | { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, | ||
195 | { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future }, | ||
196 | { .str = "(unknown)", .export = export_unknown }, | ||
197 | }; | ||
198 | |||
199 | |||
200 | static const char *export_str(enum export ex) | ||
201 | { | ||
202 | return export_list[ex].str; | ||
203 | } | ||
204 | |||
205 | static enum export export_no(const char * s) | ||
206 | { | ||
207 | int i; | ||
208 | for (i = 0; export_list[i].export != export_unknown; i++) { | ||
209 | if (strcmp(export_list[i].str, s) == 0) | ||
210 | return export_list[i].export; | ||
211 | } | ||
212 | return export_unknown; | ||
213 | } | ||
214 | |||
215 | static enum export export_from_sec(struct elf_info *elf, Elf_Section sec) | ||
216 | { | ||
217 | if (sec == elf->export_sec) | ||
218 | return export_plain; | ||
219 | else if (sec == elf->export_gpl_sec) | ||
220 | return export_gpl; | ||
221 | else if (sec == elf->export_gpl_future_sec) | ||
222 | return export_gpl_future; | ||
223 | else | ||
224 | return export_unknown; | ||
225 | } | ||
226 | |||
182 | /** | 227 | /** |
183 | * Add an exported symbol - it may have already been added without a | 228 | * Add an exported symbol - it may have already been added without a |
184 | * CRC, in this case just update the CRC | 229 | * CRC, in this case just update the CRC |
185 | **/ | 230 | **/ |
186 | static struct symbol *sym_add_exported(const char *name, struct module *mod) | 231 | static struct symbol *sym_add_exported(const char *name, struct module *mod, |
232 | enum export export) | ||
187 | { | 233 | { |
188 | struct symbol *s = find_symbol(name); | 234 | struct symbol *s = find_symbol(name); |
189 | 235 | ||
190 | if (!s) { | 236 | if (!s) { |
191 | s = new_symbol(name, mod); | 237 | s = new_symbol(name, mod, export); |
192 | } else { | 238 | } else { |
193 | if (!s->preloaded) { | 239 | if (!s->preloaded) { |
194 | warn("%s: '%s' exported twice. Previous export " | 240 | warn("%s: '%s' exported twice. Previous export " |
@@ -200,16 +246,17 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod) | |||
200 | s->preloaded = 0; | 246 | s->preloaded = 0; |
201 | s->vmlinux = is_vmlinux(mod->name); | 247 | s->vmlinux = is_vmlinux(mod->name); |
202 | s->kernel = 0; | 248 | s->kernel = 0; |
249 | s->export = export; | ||
203 | return s; | 250 | return s; |
204 | } | 251 | } |
205 | 252 | ||
206 | static void sym_update_crc(const char *name, struct module *mod, | 253 | static void sym_update_crc(const char *name, struct module *mod, |
207 | unsigned int crc) | 254 | unsigned int crc, enum export export) |
208 | { | 255 | { |
209 | struct symbol *s = find_symbol(name); | 256 | struct symbol *s = find_symbol(name); |
210 | 257 | ||
211 | if (!s) | 258 | if (!s) |
212 | s = new_symbol(name, mod); | 259 | s = new_symbol(name, mod, export); |
213 | s->crc = crc; | 260 | s->crc = crc; |
214 | s->crc_valid = 1; | 261 | s->crc_valid = 1; |
215 | } | 262 | } |
@@ -283,7 +330,7 @@ static void parse_elf(struct elf_info *info, const char *filename) | |||
283 | hdr = grab_file(filename, &info->size); | 330 | hdr = grab_file(filename, &info->size); |
284 | if (!hdr) { | 331 | if (!hdr) { |
285 | perror(filename); | 332 | perror(filename); |
286 | abort(); | 333 | exit(1); |
287 | } | 334 | } |
288 | info->hdr = hdr; | 335 | info->hdr = hdr; |
289 | if (info->size < sizeof(*hdr)) | 336 | if (info->size < sizeof(*hdr)) |
@@ -309,13 +356,21 @@ static void parse_elf(struct elf_info *info, const char *filename) | |||
309 | for (i = 1; i < hdr->e_shnum; i++) { | 356 | for (i = 1; i < hdr->e_shnum; i++) { |
310 | const char *secstrings | 357 | const char *secstrings |
311 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 358 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
359 | const char *secname; | ||
312 | 360 | ||
313 | if (sechdrs[i].sh_offset > info->size) | 361 | if (sechdrs[i].sh_offset > info->size) |
314 | goto truncated; | 362 | goto truncated; |
315 | if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) { | 363 | secname = secstrings + sechdrs[i].sh_name; |
364 | if (strcmp(secname, ".modinfo") == 0) { | ||
316 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; | 365 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; |
317 | info->modinfo_len = sechdrs[i].sh_size; | 366 | info->modinfo_len = sechdrs[i].sh_size; |
318 | } | 367 | } else if (strcmp(secname, "__ksymtab") == 0) |
368 | info->export_sec = i; | ||
369 | else if (strcmp(secname, "__ksymtab_gpl") == 0) | ||
370 | info->export_gpl_sec = i; | ||
371 | else if (strcmp(secname, "__ksymtab_gpl_future") == 0) | ||
372 | info->export_gpl_future_sec = i; | ||
373 | |||
319 | if (sechdrs[i].sh_type != SHT_SYMTAB) | 374 | if (sechdrs[i].sh_type != SHT_SYMTAB) |
320 | continue; | 375 | continue; |
321 | 376 | ||
@@ -353,6 +408,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
353 | Elf_Sym *sym, const char *symname) | 408 | Elf_Sym *sym, const char *symname) |
354 | { | 409 | { |
355 | unsigned int crc; | 410 | unsigned int crc; |
411 | enum export export = export_from_sec(info, sym->st_shndx); | ||
356 | 412 | ||
357 | switch (sym->st_shndx) { | 413 | switch (sym->st_shndx) { |
358 | case SHN_COMMON: | 414 | case SHN_COMMON: |
@@ -362,7 +418,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
362 | /* CRC'd symbol */ | 418 | /* CRC'd symbol */ |
363 | if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { | 419 | if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { |
364 | crc = (unsigned int) sym->st_value; | 420 | crc = (unsigned int) sym->st_value; |
365 | sym_update_crc(symname + strlen(CRC_PFX), mod, crc); | 421 | sym_update_crc(symname + strlen(CRC_PFX), mod, crc, |
422 | export); | ||
366 | } | 423 | } |
367 | break; | 424 | break; |
368 | case SHN_UNDEF: | 425 | case SHN_UNDEF: |
@@ -406,7 +463,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
406 | default: | 463 | default: |
407 | /* All exported symbols */ | 464 | /* All exported symbols */ |
408 | if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { | 465 | if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { |
409 | sym_add_exported(symname + strlen(KSYMTAB_PFX), mod); | 466 | sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, |
467 | export); | ||
410 | } | 468 | } |
411 | if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) | 469 | if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) |
412 | mod->has_init = 1; | 470 | mod->has_init = 1; |
@@ -437,13 +495,18 @@ static char *next_string(char *string, unsigned long *secsize) | |||
437 | return string; | 495 | return string; |
438 | } | 496 | } |
439 | 497 | ||
440 | static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | 498 | static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, |
441 | const char *tag) | 499 | const char *tag, char *info) |
442 | { | 500 | { |
443 | char *p; | 501 | char *p; |
444 | unsigned int taglen = strlen(tag); | 502 | unsigned int taglen = strlen(tag); |
445 | unsigned long size = modinfo_len; | 503 | unsigned long size = modinfo_len; |
446 | 504 | ||
505 | if (info) { | ||
506 | size -= info - (char *)modinfo; | ||
507 | modinfo = next_string(info, &size); | ||
508 | } | ||
509 | |||
447 | for (p = modinfo; p; p = next_string(p, &size)) { | 510 | for (p = modinfo; p; p = next_string(p, &size)) { |
448 | if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') | 511 | if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') |
449 | return p + taglen + 1; | 512 | return p + taglen + 1; |
@@ -451,6 +514,13 @@ static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | |||
451 | return NULL; | 514 | return NULL; |
452 | } | 515 | } |
453 | 516 | ||
517 | static char *get_modinfo(void *modinfo, unsigned long modinfo_len, | ||
518 | const char *tag) | ||
519 | |||
520 | { | ||
521 | return get_next_modinfo(modinfo, modinfo_len, tag, NULL); | ||
522 | } | ||
523 | |||
454 | /** | 524 | /** |
455 | * Test if string s ends in string sub | 525 | * Test if string s ends in string sub |
456 | * return 0 if match | 526 | * return 0 if match |
@@ -821,6 +891,10 @@ static int init_section_ref_ok(const char *name) | |||
821 | ".pci_fixup_final", | 891 | ".pci_fixup_final", |
822 | ".pdr", | 892 | ".pdr", |
823 | "__param", | 893 | "__param", |
894 | "__ex_table", | ||
895 | ".fixup", | ||
896 | ".smp_locks", | ||
897 | ".plt", /* seen on ARCH=um build on x86_64. Harmless */ | ||
824 | NULL | 898 | NULL |
825 | }; | 899 | }; |
826 | /* Start of section names */ | 900 | /* Start of section names */ |
@@ -846,6 +920,8 @@ static int init_section_ref_ok(const char *name) | |||
846 | for (s = namelist3; *s; s++) | 920 | for (s = namelist3; *s; s++) |
847 | if (strstr(name, *s) != NULL) | 921 | if (strstr(name, *s) != NULL) |
848 | return 1; | 922 | return 1; |
923 | if (strrcmp(name, ".init") == 0) | ||
924 | return 1; | ||
849 | return 0; | 925 | return 0; |
850 | } | 926 | } |
851 | 927 | ||
@@ -892,6 +968,10 @@ static int exit_section_ref_ok(const char *name) | |||
892 | ".exitcall.exit", | 968 | ".exitcall.exit", |
893 | ".eh_frame", | 969 | ".eh_frame", |
894 | ".stab", | 970 | ".stab", |
971 | "__ex_table", | ||
972 | ".fixup", | ||
973 | ".smp_locks", | ||
974 | ".plt", /* seen on ARCH=um build on x86_64. Harmless */ | ||
895 | NULL | 975 | NULL |
896 | }; | 976 | }; |
897 | /* Start of section names */ | 977 | /* Start of section names */ |
@@ -921,6 +1001,7 @@ static void read_symbols(char *modname) | |||
921 | { | 1001 | { |
922 | const char *symname; | 1002 | const char *symname; |
923 | char *version; | 1003 | char *version; |
1004 | char *license; | ||
924 | struct module *mod; | 1005 | struct module *mod; |
925 | struct elf_info info = { }; | 1006 | struct elf_info info = { }; |
926 | Elf_Sym *sym; | 1007 | Elf_Sym *sym; |
@@ -936,6 +1017,18 @@ static void read_symbols(char *modname) | |||
936 | mod->skip = 1; | 1017 | mod->skip = 1; |
937 | } | 1018 | } |
938 | 1019 | ||
1020 | license = get_modinfo(info.modinfo, info.modinfo_len, "license"); | ||
1021 | while (license) { | ||
1022 | if (license_is_gpl_compatible(license)) | ||
1023 | mod->gpl_compatible = 1; | ||
1024 | else { | ||
1025 | mod->gpl_compatible = 0; | ||
1026 | break; | ||
1027 | } | ||
1028 | license = get_next_modinfo(info.modinfo, info.modinfo_len, | ||
1029 | "license", license); | ||
1030 | } | ||
1031 | |||
939 | for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { | 1032 | for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { |
940 | symname = info.strtab + sym->st_name; | 1033 | symname = info.strtab + sym->st_name; |
941 | 1034 | ||
@@ -992,6 +1085,41 @@ void buf_write(struct buffer *buf, const char *s, int len) | |||
992 | buf->pos += len; | 1085 | buf->pos += len; |
993 | } | 1086 | } |
994 | 1087 | ||
1088 | void check_license(struct module *mod) | ||
1089 | { | ||
1090 | struct symbol *s, *exp; | ||
1091 | |||
1092 | for (s = mod->unres; s; s = s->next) { | ||
1093 | const char *basename; | ||
1094 | if (mod->gpl_compatible == 1) { | ||
1095 | /* GPL-compatible modules may use all symbols */ | ||
1096 | continue; | ||
1097 | } | ||
1098 | exp = find_symbol(s->name); | ||
1099 | if (!exp || exp->module == mod) | ||
1100 | continue; | ||
1101 | basename = strrchr(mod->name, '/'); | ||
1102 | if (basename) | ||
1103 | basename++; | ||
1104 | switch (exp->export) { | ||
1105 | case export_gpl: | ||
1106 | fatal("modpost: GPL-incompatible module %s " | ||
1107 | "uses GPL-only symbol '%s'\n", | ||
1108 | basename ? basename : mod->name, | ||
1109 | exp->name); | ||
1110 | break; | ||
1111 | case export_gpl_future: | ||
1112 | warn("modpost: GPL-incompatible module %s " | ||
1113 | "uses future GPL-only symbol '%s'\n", | ||
1114 | basename ? basename : mod->name, | ||
1115 | exp->name); | ||
1116 | break; | ||
1117 | case export_plain: /* ignore */ break; | ||
1118 | case export_unknown: /* ignore */ break; | ||
1119 | } | ||
1120 | } | ||
1121 | } | ||
1122 | |||
995 | /** | 1123 | /** |
996 | * Header for the generated file | 1124 | * Header for the generated file |
997 | **/ | 1125 | **/ |
@@ -1142,6 +1270,9 @@ static void write_if_changed(struct buffer *b, const char *fname) | |||
1142 | fclose(file); | 1270 | fclose(file); |
1143 | } | 1271 | } |
1144 | 1272 | ||
1273 | /* parse Module.symvers file. line format: | ||
1274 | * 0x12345678<tab>symbol<tab>module[<tab>export] | ||
1275 | **/ | ||
1145 | static void read_dump(const char *fname, unsigned int kernel) | 1276 | static void read_dump(const char *fname, unsigned int kernel) |
1146 | { | 1277 | { |
1147 | unsigned long size, pos = 0; | 1278 | unsigned long size, pos = 0; |
@@ -1153,7 +1284,7 @@ static void read_dump(const char *fname, unsigned int kernel) | |||
1153 | return; | 1284 | return; |
1154 | 1285 | ||
1155 | while ((line = get_next_line(&pos, file, size))) { | 1286 | while ((line = get_next_line(&pos, file, size))) { |
1156 | char *symname, *modname, *d; | 1287 | char *symname, *modname, *d, *export; |
1157 | unsigned int crc; | 1288 | unsigned int crc; |
1158 | struct module *mod; | 1289 | struct module *mod; |
1159 | struct symbol *s; | 1290 | struct symbol *s; |
@@ -1164,8 +1295,9 @@ static void read_dump(const char *fname, unsigned int kernel) | |||
1164 | if (!(modname = strchr(symname, '\t'))) | 1295 | if (!(modname = strchr(symname, '\t'))) |
1165 | goto fail; | 1296 | goto fail; |
1166 | *modname++ = '\0'; | 1297 | *modname++ = '\0'; |
1167 | if (strchr(modname, '\t')) | 1298 | if ((export = strchr(modname, '\t')) != NULL) |
1168 | goto fail; | 1299 | *export++ = '\0'; |
1300 | |||
1169 | crc = strtoul(line, &d, 16); | 1301 | crc = strtoul(line, &d, 16); |
1170 | if (*symname == '\0' || *modname == '\0' || *d != '\0') | 1302 | if (*symname == '\0' || *modname == '\0' || *d != '\0') |
1171 | goto fail; | 1303 | goto fail; |
@@ -1177,10 +1309,10 @@ static void read_dump(const char *fname, unsigned int kernel) | |||
1177 | mod = new_module(NOFAIL(strdup(modname))); | 1309 | mod = new_module(NOFAIL(strdup(modname))); |
1178 | mod->skip = 1; | 1310 | mod->skip = 1; |
1179 | } | 1311 | } |
1180 | s = sym_add_exported(symname, mod); | 1312 | s = sym_add_exported(symname, mod, export_no(export)); |
1181 | s->kernel = kernel; | 1313 | s->kernel = kernel; |
1182 | s->preloaded = 1; | 1314 | s->preloaded = 1; |
1183 | sym_update_crc(symname, mod, crc); | 1315 | sym_update_crc(symname, mod, crc, export_no(export)); |
1184 | } | 1316 | } |
1185 | return; | 1317 | return; |
1186 | fail: | 1318 | fail: |
@@ -1210,9 +1342,10 @@ static void write_dump(const char *fname) | |||
1210 | symbol = symbolhash[n]; | 1342 | symbol = symbolhash[n]; |
1211 | while (symbol) { | 1343 | while (symbol) { |
1212 | if (dump_sym(symbol)) | 1344 | if (dump_sym(symbol)) |
1213 | buf_printf(&buf, "0x%08x\t%s\t%s\n", | 1345 | buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", |
1214 | symbol->crc, symbol->name, | 1346 | symbol->crc, symbol->name, |
1215 | symbol->module->name); | 1347 | symbol->module->name, |
1348 | export_str(symbol->export)); | ||
1216 | symbol = symbol->next; | 1349 | symbol = symbol->next; |
1217 | } | 1350 | } |
1218 | } | 1351 | } |
@@ -1263,6 +1396,12 @@ int main(int argc, char **argv) | |||
1263 | for (mod = modules; mod; mod = mod->next) { | 1396 | for (mod = modules; mod; mod = mod->next) { |
1264 | if (mod->skip) | 1397 | if (mod->skip) |
1265 | continue; | 1398 | continue; |
1399 | check_license(mod); | ||
1400 | } | ||
1401 | |||
1402 | for (mod = modules; mod; mod = mod->next) { | ||
1403 | if (mod->skip) | ||
1404 | continue; | ||
1266 | 1405 | ||
1267 | buf.pos = 0; | 1406 | buf.pos = 0; |
1268 | 1407 | ||