diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 168 |
1 files changed, 136 insertions, 32 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 65bdfdb5687..113dc77b9f6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -55,6 +55,17 @@ void warn(const char *fmt, ...) va_end(arglist); } +void merror(const char *fmt, ...) +{ + va_list arglist; + + fprintf(stderr, "ERROR: "); + + va_start(arglist, fmt); + vfprintf(stderr, fmt, arglist); + va_end(arglist); +} + static int is_vmlinux(const char *modname) { const char *myname; @@ -333,10 +344,10 @@ void release_file(void *file, unsigned long size) munmap(file, size); } -static void parse_elf(struct elf_info *info, const char *filename) +static int parse_elf(struct elf_info *info, const char *filename) { unsigned int i; - Elf_Ehdr *hdr = info->hdr; + Elf_Ehdr *hdr; Elf_Shdr *sechdrs; Elf_Sym *sym; @@ -346,9 +357,18 @@ static void parse_elf(struct elf_info *info, const char *filename) exit(1); } info->hdr = hdr; - if (info->size < sizeof(*hdr)) - goto truncated; - + if (info->size < sizeof(*hdr)) { + /* file too small, assume this is an empty .o file */ + return 0; + } + /* Is this a valid ELF file? */ + if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || + (hdr->e_ident[EI_MAG1] != ELFMAG1) || + (hdr->e_ident[EI_MAG2] != ELFMAG2) || + (hdr->e_ident[EI_MAG3] != ELFMAG3)) { + /* Not an ELF file - silently ignore it */ + return 0; + } /* Fix endianness in ELF header */ hdr->e_shoff = TO_NATIVE(hdr->e_shoff); hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); @@ -371,8 +391,10 @@ static void parse_elf(struct elf_info *info, const char *filename) = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; const char *secname; - if (sechdrs[i].sh_offset > info->size) - goto truncated; + if (sechdrs[i].sh_offset > info->size) { + fatal("%s is truncated. sechdrs[i].sh_offset=%u > sizeof(*hrd)=%ul\n", filename, (unsigned int)sechdrs[i].sh_offset, sizeof(*hdr)); + return 0; + } secname = secstrings + sechdrs[i].sh_name; if (strcmp(secname, ".modinfo") == 0) { info->modinfo = (void *)hdr + sechdrs[i].sh_offset; @@ -407,10 +429,7 @@ static void parse_elf(struct elf_info *info, const char *filename) sym->st_value = TO_NATIVE(sym->st_value); sym->st_size = TO_NATIVE(sym->st_size); } - return; - - truncated: - fatal("%s is truncated.\n", filename); + return 1; } static void parse_elf_finish(struct elf_info *info) @@ -581,9 +600,17 @@ static int strrcmp(const char *s, const char *sub) * the pattern is identified by: * tosec = .init.text | .exit.text | .init.data * fromsec = .data - * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one + * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console * * Pattern 3: + * Whitelist all references from .pci_fixup* section to .init.text + * This is part of the PCI init when built-in + * + * Pattern 4: + * Whitelist all refereces from .text.head to .init.data + * Whitelist all refereces from .text.head to .init.text + * + * Pattern 5: * Some symbols belong to init section but still it is ok to reference * these from non-init sections as these symbols don't have any memory * allocated for them and symbol address and value are same. So even @@ -591,6 +618,40 @@ static int strrcmp(const char *s, const char *sub) * For ex. symbols marking the init section boundaries. * This pattern is identified by * refsymname = __init_begin, _sinittext, _einittext + * + * Pattern 6: + * During the early init phase we have references from .init.text to + * .text we have an intended section mismatch - do not warn about it. + * See kernel_init() in init/main.c + * tosec = .init.text + * fromsec = .text + * atsym = kernel_init + * + * Pattern 7: + * Logos used in drivers/video/logo reside in __initdata but the + * funtion that references them are EXPORT_SYMBOL() so cannot be + * marker __init. So we whitelist them here. + * The pattern is: + * tosec = .init.data + * fromsec = .text* + * refsymname = logo_ + * + * Pattern 8: + * Symbols contained in .paravirtprobe may safely reference .init.text. + * The pattern is: + * tosec = .init.text + * fromsec = .paravirtprobe + * + * Pattern 9: + * Some of functions are common code between boot time and hotplug + * time. The bootmem allocater is called only boot time in its + * functions. So it's ok to reference. + * tosec = .init.text + * + * Pattern 10: + * ia64 has machvec table for each platform. It is mixture of function + * pointer of .init.text and .text. + * fromsec = .machvec **/ static int secref_whitelist(const char *modname, const char *tosec, const char *fromsec, const char *atsym, @@ -606,6 +667,7 @@ static int secref_whitelist(const char *modname, const char *tosec, "_probe", "_probe_one", "_console", + "apic_es7000", NULL }; @@ -616,6 +678,12 @@ static int secref_whitelist(const char *modname, const char *tosec, NULL }; + const char *pat4sym[] = { + "sparse_index_alloc", + "zone_wait_table_init", + NULL + }; + /* Check for pattern 1 */ if (strcmp(tosec, ".init.data") != 0) f1 = 0; @@ -641,25 +709,50 @@ static int secref_whitelist(const char *modname, const char *tosec, if (f1 && f2) return 1; - /* Whitelist all references from .pci_fixup section if vmlinux - * Whitelist all refereces from .text.head to .init.data if vmlinux - * Whitelist all refereces from .text.head to .init.text if vmlinux - */ - if (is_vmlinux(modname)) { - if ((strcmp(fromsec, ".pci_fixup") == 0) && - (strcmp(tosec, ".init.text") == 0)) + /* Check for pattern 3 */ + if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) && + (strcmp(tosec, ".init.text") == 0)) + return 1; + + /* Check for pattern 4 */ + if ((strcmp(fromsec, ".text.head") == 0) && + ((strcmp(tosec, ".init.data") == 0) || + (strcmp(tosec, ".init.text") == 0))) + return 1; + + /* Check for pattern 5 */ + for (s = pat3refsym; *s; s++) + if (strcmp(refsymname, *s) == 0) + return 1; + + /* Check for pattern 6 */ + if ((strcmp(tosec, ".init.text") == 0) && + (strcmp(fromsec, ".text") == 0) && + (strcmp(refsymname, "kernel_init") == 0)) return 1; - if ((strcmp(fromsec, ".text.head") == 0) && - ((strcmp(tosec, ".init.data") == 0) || - (strcmp(tosec, ".init.text") == 0))) + /* Check for pattern 7 */ + if ((strcmp(tosec, ".init.data") == 0) && + (strncmp(fromsec, ".text", strlen(".text")) == 0) && + (strncmp(refsymname, "logo_", strlen("logo_")) == 0)) return 1; - /* Check for pattern 3 */ - for (s = pat3refsym; *s; s++) - if (strcmp(refsymname, *s) == 0) + /* Check for pattern 8 */ + if ((strcmp(tosec, ".init.text") == 0) && + (strcmp(fromsec, ".paravirtprobe") == 0)) + return 1; + + /* Check for pattern 9 */ + if ((strcmp(tosec, ".init.text") == 0) && + (strcmp(fromsec, ".text") == 0)) + for (s = pat4sym; *s; s++) + if (strcmp(atsym, *s) == 0) return 1; - } + + /* Check for pattern 10 */ + if (strcmp(fromsec, ".machvec") == 0) + return 1; + return 0; } @@ -1089,7 +1182,8 @@ static void read_symbols(char *modname) struct elf_info info = { }; Elf_Sym *sym; - parse_elf(&info, modname); + if (!parse_elf(&info, modname)) + return; mod = new_module(modname); @@ -1249,6 +1343,7 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" " .exit = cleanup_module,\n" "#endif\n"); + buf_printf(b, " .arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); } @@ -1264,9 +1359,14 @@ static int add_versions(struct buffer *b, struct module *mod) exp = find_symbol(s->name); if (!exp || exp->module == mod) { if (have_vmlinux && !s->weak) { - warn("\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); - err = warn_unresolved ? 0 : 1; + if (warn_unresolved) { + warn("\"%s\" [%s.ko] undefined!\n", + s->name, mod->name); + } else { + merror("\"%s\" [%s.ko] undefined!\n", + s->name, mod->name); + err = 1; + } } continue; } @@ -1317,6 +1417,7 @@ static void add_depends(struct buffer *b, struct module *mod, buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); buf_printf(b, "\"depends="); for (s = mod->unres; s; s = s->next) { + const char *p; if (!s->module) continue; @@ -1324,8 +1425,11 @@ static void add_depends(struct buffer *b, struct module *mod, continue; s->module->seen = 1; - buf_printf(b, "%s%s", first ? "" : ",", - strrchr(s->module->name, '/') + 1); + if ((p = strrchr(s->module->name, '/')) != NULL) + p++; + else + p = s->module->name; + buf_printf(b, "%s%s", first ? "" : ",", p); first = 0; } buf_printf(b, "\";\n"); |