X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=scripts%2Fmod%2Fmodpost.c;h=87e3ee56e87dd7389c9f2dd601fc9dbf1a9d2f5d;hb=8d8d8289df65cb116d2721becafb37272074f25a;hp=569e68410d7a96a78f2673d4fdaf12bfc65136af;hpb=f8657e1b55901e6c227094258d1fa3642fa242bd;p=safe%2Fjmp%2Flinux-2.6 diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 569e684..87e3ee5 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -23,6 +23,8 @@ int have_vmlinux = 0; static int all_versions = 0; /* If we are modposting external module set to 1 */ static int external_module = 0; +/* Warn about section mismatch in vmlinux if set to 1 */ +static int vmlinux_section_warnings = 1; /* Only warn about unresolved symbols */ static int warn_unresolved = 0; /* How a symbol is exported */ @@ -55,6 +57,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; @@ -64,7 +77,8 @@ static int is_vmlinux(const char *modname) else myname = modname; - return strcmp(myname, "vmlinux") == 0; + return (strcmp(myname, "vmlinux") == 0) || + (strcmp(myname, "vmlinux.o") == 0); } void *do_nofail(void *ptr, const char *expr) @@ -333,10 +347,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,14 +360,24 @@ 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); hdr->e_shnum = TO_NATIVE(hdr->e_shnum); hdr->e_machine = TO_NATIVE(hdr->e_machine); + hdr->e_type = TO_NATIVE(hdr->e_type); sechdrs = (void *)hdr + hdr->e_shoff; info->sechdrs = sechdrs; @@ -364,6 +388,8 @@ static void parse_elf(struct elf_info *info, const char *filename) sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); + sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); + sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); } /* Find symbol table. */ for (i = 1; i < hdr->e_shnum; i++) { @@ -371,8 +397,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 +435,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) @@ -563,6 +588,12 @@ static int strrcmp(const char *s, const char *sub) /** * Whitelist to allow certain references to pass with no warning. + * + * Pattern 0: + * Do not warn if funtion/data are marked with __init_refok/__initdata_refok. + * The pattern is identified by: + * fromsec = .text.init.refok | .data.init.refok + * * Pattern 1: * If a module parameter is declared __initdata and permissions=0 * then this is legal despite the warning generated. @@ -580,10 +611,14 @@ static int strrcmp(const char *s, const char *sub) * warn here. * the pattern is identified by: * tosec = .init.text | .exit.text | .init.data - * fromsec = .data - * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one + * fromsec = .data | .data.rel | .data.rel.* + * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console, *_timer * * Pattern 3: + * Whitelist all refereces from .text.head to .init.data + * Whitelist all refereces from .text.head to .init.text + * + * Pattern 4: * 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 +626,7 @@ 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 + * **/ static int secref_whitelist(const char *modname, const char *tosec, const char *fromsec, const char *atsym, @@ -601,6 +637,7 @@ static int secref_whitelist(const char *modname, const char *tosec, const char *pat2sym[] = { "driver", "_template", /* scsi uses *_template a lot */ + "_timer", /* arm uses ops structures named _timer a lot */ "_sht", /* scsi also used *_sht to some extent */ "_ops", "_probe", @@ -616,6 +653,11 @@ static int secref_whitelist(const char *modname, const char *tosec, NULL }; + /* Check for pattern 0 */ + if ((strcmp(fromsec, ".text.init.refok") == 0) || + (strcmp(fromsec, ".data.init.refok") == 0)) + return 1; + /* Check for pattern 1 */ if (strcmp(tosec, ".init.data") != 0) f1 = 0; @@ -632,7 +674,9 @@ static int secref_whitelist(const char *modname, const char *tosec, (strcmp(tosec, ".exit.text") != 0) && (strcmp(tosec, ".init.data") != 0)) f2 = 0; - if (strcmp(fromsec, ".data") != 0) + if ((strcmp(fromsec, ".data") != 0) && + (strcmp(fromsec, ".data.rel") != 0) && + (strncmp(fromsec, ".data.rel.", strlen(".data.rel.")) != 0)) f2 = 0; for (s = pat2sym; *s; s++) @@ -641,25 +685,17 @@ 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)) - return 1; + /* Check for pattern 3 */ + if ((strcmp(fromsec, ".text.head") == 0) && + ((strcmp(tosec, ".init.data") == 0) || + (strcmp(tosec, ".init.text") == 0))) + return 1; - if ((strcmp(fromsec, ".text.head") == 0) && - ((strcmp(tosec, ".init.data") == 0) || - (strcmp(tosec, ".init.text") == 0))) - return 1; + /* Check for pattern 4 */ + for (s = pat3refsym; *s; s++) + if (strcmp(refsymname, *s) == 0) + return 1; - /* Check for pattern 3 */ - for (s = pat3refsym; *s; s++) - if (strcmp(refsymname, *s) == 0) - return 1; - } return 0; } @@ -680,12 +716,38 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr, for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { if (sym->st_shndx != relsym->st_shndx) continue; + if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) + continue; if (sym->st_value == addr) return sym; } return NULL; } +static inline int is_arm_mapping_symbol(const char *str) +{ + return str[0] == '$' && strchr("atd", str[1]) + && (str[2] == '\0' || str[2] == '.'); +} + +/* + * If there's no name there, ignore it; likewise, ignore it if it's + * one of the magic symbols emitted used by current ARM tools. + * + * Otherwise if find_symbols_between() returns those symbols, they'll + * fail the whitelist tests and cause lots of false alarms ... fixable + * only by merging __exit and __init sections into __text, bloating + * the kernel (which is especially evil on embedded platforms). + */ +static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym) +{ + const char *name = elf->strtab + sym->st_name; + + if (!name || !strlen(name)) + return 0; + return !is_arm_mapping_symbol(name); +} + /* * Find symbols before or equal addr and after addr - in the section sec. * If we find two symbols with equal offset prefer one with a valid name. @@ -714,16 +776,15 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr, symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name; if (strcmp(symsec, sec) != 0) continue; + if (!is_valid_name(elf, sym)) + continue; if (sym->st_value <= addr) { if ((addr - sym->st_value) < beforediff) { beforediff = addr - sym->st_value; *before = sym; } else if ((addr - sym->st_value) == beforediff) { - /* equal offset, valid name? */ - const char *name = elf->strtab + sym->st_name; - if (name && strlen(name)) - *before = sym; + *before = sym; } } else @@ -733,10 +794,7 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr, *after = sym; } else if ((sym->st_value - addr) == afterdiff) { - /* equal offset, valid name? */ - const char *name = elf->strtab + sym->st_name; - if (name && strlen(name)) - *after = sym; + *after = sym; } } } @@ -772,30 +830,101 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec, return; if (before && after) { - warn("%s - Section mismatch: reference to %s:%s from %s " - "between '%s' (at offset 0x%llx) and '%s'\n", - modname, secname, refsymname, fromsec, + warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s " + "(between '%s' and '%s')\n", + modname, fromsec, (unsigned long long)r.r_offset, + secname, refsymname, elf->strtab + before->st_name, - (long long)r.r_offset, elf->strtab + after->st_name); } else if (before) { - warn("%s - Section mismatch: reference to %s:%s from %s " - "after '%s' (at offset 0x%llx)\n", - modname, secname, refsymname, fromsec, - elf->strtab + before->st_name, - (long long)r.r_offset); + warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s " + "(after '%s')\n", + modname, fromsec, (unsigned long long)r.r_offset, + secname, refsymname, + elf->strtab + before->st_name); } else if (after) { - warn("%s - Section mismatch: reference to %s:%s from %s " + warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s " "before '%s' (at offset -0x%llx)\n", - modname, secname, refsymname, fromsec, - elf->strtab + after->st_name, - (long long)r.r_offset); + modname, fromsec, (unsigned long long)r.r_offset, + secname, refsymname, + elf->strtab + after->st_name); } else { - warn("%s - Section mismatch: reference to %s:%s from %s " - "(offset 0x%llx)\n", - modname, secname, fromsec, refsymname, - (long long)r.r_offset); + warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s\n", + modname, fromsec, (unsigned long long)r.r_offset, + secname, refsymname); + } +} + +static unsigned int *reloc_location(struct elf_info *elf, + int rsection, Elf_Rela *r) +{ + Elf_Shdr *sechdrs = elf->sechdrs; + int section = sechdrs[rsection].sh_info; + + return (void *)elf->hdr + sechdrs[section].sh_offset + + (r->r_offset - sechdrs[section].sh_addr); +} + +static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r) +{ + unsigned int r_typ = ELF_R_TYPE(r->r_info); + unsigned int *location = reloc_location(elf, rsection, r); + + switch (r_typ) { + case R_386_32: + r->r_addend = TO_NATIVE(*location); + break; + case R_386_PC32: + r->r_addend = TO_NATIVE(*location) + 4; + /* For CONFIG_RELOCATABLE=y */ + if (elf->hdr->e_type == ET_EXEC) + r->r_addend += r->r_offset; + break; + } + return 0; +} + +static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r) +{ + unsigned int r_typ = ELF_R_TYPE(r->r_info); + + switch (r_typ) { + case R_ARM_ABS32: + /* From ARM ABI: (S + A) | T */ + r->r_addend = (int)(long)(elf->symtab_start + ELF_R_SYM(r->r_info)); + break; + case R_ARM_PC24: + /* From ARM ABI: ((S + A) | T) - P */ + r->r_addend = (int)(long)(elf->hdr + elf->sechdrs[rsection].sh_offset + + (r->r_offset - elf->sechdrs[rsection].sh_addr)); + break; + default: + return 1; } + return 0; +} + +static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r) +{ + unsigned int r_typ = ELF_R_TYPE(r->r_info); + unsigned int *location = reloc_location(elf, rsection, r); + unsigned int inst; + + if (r_typ == R_MIPS_HI16) + return 1; /* skip this */ + inst = TO_NATIVE(*location); + switch (r_typ) { + case R_MIPS_LO16: + r->r_addend = inst & 0xffff; + break; + case R_MIPS_26: + r->r_addend = (inst & 0x03ffffff) << 2; + break; + case R_MIPS_32: + r->r_addend = inst; + break; + } + return 0; } /** @@ -841,8 +970,11 @@ static void check_sec_ref(struct module *mod, const char *modname, r.r_offset = TO_NATIVE(rela->r_offset); #if KERNEL_ELFCLASS == ELFCLASS64 if (hdr->e_machine == EM_MIPS) { + unsigned int r_typ; r_sym = ELF64_MIPS_R_SYM(rela->r_info); r_sym = TO_NATIVE(r_sym); + r_typ = ELF64_MIPS_R_TYPE(rela->r_info); + r.r_info = ELF64_R_INFO(r_sym, r_typ); } else { r.r_info = TO_NATIVE(rela->r_info); r_sym = ELF_R_SYM(r.r_info); @@ -875,8 +1007,11 @@ static void check_sec_ref(struct module *mod, const char *modname, r.r_offset = TO_NATIVE(rel->r_offset); #if KERNEL_ELFCLASS == ELFCLASS64 if (hdr->e_machine == EM_MIPS) { + unsigned int r_typ; r_sym = ELF64_MIPS_R_SYM(rel->r_info); r_sym = TO_NATIVE(r_sym); + r_typ = ELF64_MIPS_R_TYPE(rel->r_info); + r.r_info = ELF64_R_INFO(r_sym, r_typ); } else { r.r_info = TO_NATIVE(rel->r_info); r_sym = ELF_R_SYM(r.r_info); @@ -886,6 +1021,20 @@ static void check_sec_ref(struct module *mod, const char *modname, r_sym = ELF_R_SYM(r.r_info); #endif r.r_addend = 0; + switch (hdr->e_machine) { + case EM_386: + if (addend_386_rel(elf, i, &r)) + continue; + break; + case EM_ARM: + if(addend_arm_rel(elf, i, &r)) + continue; + break; + case EM_MIPS: + if (addend_mips_rel(elf, i, &r)) + continue; + break; + } sym = elf->symtab_start + r_sym; /* Skip special sections */ if (sym->st_shndx >= SHN_LORESERVE) @@ -901,6 +1050,64 @@ static void check_sec_ref(struct module *mod, const char *modname, } } +/* + * Identify sections from which references to either a + * .init or a .exit section is OK. + * + * [OPD] Keith Ownes commented: + * For our future {in}sanity, add a comment that this is the ppc .opd + * section, not the ia64 .opd section. + * ia64 .opd should not point to discarded sections. + * [.rodata] like for .init.text we ignore .rodata references -same reason + */ +static int initexit_section_ref_ok(const char *name) +{ + const char **s; + /* Absolute section names */ + const char *namelist1[] = { + "__bug_table", /* used by powerpc for BUG() */ + "__ex_table", + ".altinstructions", + ".cranges", /* used by sh64 */ + ".fixup", + ".machvec", /* ia64 + powerpc uses these */ + ".machine.desc", + ".opd", /* See comment [OPD] */ + ".parainstructions", + ".pdr", + ".plt", /* seen on ARCH=um build on x86_64. Harmless */ + ".smp_locks", + ".stab", + ".m68k_fixup", + NULL + }; + /* Start of section names */ + const char *namelist2[] = { + ".debug", + ".eh_frame", + ".note", /* ignore ELF notes - may contain anything */ + ".got", /* powerpc - global offset table */ + ".toc", /* powerpc - table of contents */ + NULL + }; + /* part of section name */ + const char *namelist3 [] = { + ".unwind", /* Sample: IA_64.unwind.exit.text */ + NULL + }; + + for (s = namelist1; *s; s++) + if (strcmp(*s, name) == 0) + return 1; + for (s = namelist2; *s; s++) + if (strncmp(*s, name, strlen(*s)) == 0) + return 1; + for (s = namelist3; *s; s++) + if (strstr(name, *s) != NULL) + return 1; + return 0; +} + /** * Functions used only during module init is marked __init and is stored in * a .init.text section. Likewise data is marked __initdata and stored in @@ -917,7 +1124,7 @@ static int init_section(const char *name) return 0; } -/** +/* * Identify sections from which references to a .init section is OK. * * Unfortunately references to read only data that referenced .init @@ -931,56 +1138,42 @@ static int init_section(const char *name) * * where vgacon_startup is __init. If you want to wade through the false * positives, take out the check for rodata. - **/ + */ static int init_section_ref_ok(const char *name) { const char **s; /* Absolute section names */ const char *namelist1[] = { - ".init", - ".opd", /* see comment [OPD] at exit_section_ref_ok() */ - ".toc1", /* used by ppc64 */ - ".stab", - ".rodata", - ".parainstructions", - ".text.lock", - "__bug_table", /* used by powerpc for BUG() */ - ".pci_fixup_header", - ".pci_fixup_final", - ".pdr", - "__param", - "__ex_table", - ".fixup", - ".smp_locks", - ".plt", /* seen on ARCH=um build on x86_64. Harmless */ + "__dbe_table", /* MIPS generate these */ "__ftr_fixup", /* powerpc cpu feature fixup */ "__fw_ftr_fixup", /* powerpc firmware feature fixup */ + "__param", + ".data.rel.ro", /* used by parisc64 */ + ".init", + ".text.lock", NULL }; /* Start of section names */ const char *namelist2[] = { ".init.", - ".altinstructions", - ".eh_frame", - ".debug", - ".parainstructions", - NULL - }; - /* part of section name */ - const char *namelist3 [] = { - ".unwind", /* sample: IA_64.unwind.init.text */ + ".pci_fixup", + ".rodata", NULL }; + if (initexit_section_ref_ok(name)) + return 1; + for (s = namelist1; *s; s++) if (strcmp(*s, name) == 0) return 1; for (s = namelist2; *s; s++) if (strncmp(*s, name, strlen(*s)) == 0) return 1; - for (s = namelist3; *s; s++) - if (strstr(name, *s) != NULL) - return 1; + + /* If section name ends with ".init" we allow references + * as is the case with .initcallN.init, .early_param.init, .taglist.init etc + */ if (strrcmp(name, ".init") == 0) return 1; return 0; @@ -1005,57 +1198,25 @@ static int exit_section(const char *name) /* * Identify sections from which references to a .exit section is OK. - * - * [OPD] Keith Ownes commented: - * For our future {in}sanity, add a comment that this is the ppc .opd - * section, not the ia64 .opd section. - * ia64 .opd should not point to discarded sections. - * [.rodata] like for .init.text we ignore .rodata references -same reason - **/ + */ static int exit_section_ref_ok(const char *name) { const char **s; /* Absolute section names */ const char *namelist1[] = { - ".exit.text", ".exit.data", - ".init.text", - ".rodata", - ".opd", /* See comment [OPD] */ - ".toc1", /* used by ppc64 */ - ".altinstructions", - ".pdr", - "__bug_table", /* used by powerpc for BUG() */ + ".exit.text", ".exitcall.exit", - ".eh_frame", - ".parainstructions", - ".stab", - "__ex_table", - ".fixup", - ".smp_locks", - ".plt", /* seen on ARCH=um build on x86_64. Harmless */ - NULL - }; - /* Start of section names */ - const char *namelist2[] = { - ".debug", - NULL - }; - /* part of section name */ - const char *namelist3 [] = { - ".unwind", /* Sample: IA_64.unwind.exit.text */ + ".rodata", NULL }; + if (initexit_section_ref_ok(name)) + return 1; + for (s = namelist1; *s; s++) if (strcmp(*s, name) == 0) return 1; - for (s = namelist2; *s; s++) - if (strncmp(*s, name, strlen(*s)) == 0) - return 1; - for (s = namelist3; *s; s++) - if (strstr(name, *s) != NULL) - return 1; return 0; } @@ -1068,7 +1229,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); @@ -1097,8 +1259,10 @@ static void read_symbols(char *modname) handle_modversions(mod, &info, sym, symname); handle_moddevtable(mod, &info, sym, symname); } - check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok); - check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok); + if (is_vmlinux(modname) && vmlinux_section_warnings) { + check_sec_ref(mod, modname, &info, init_section, init_section_ref_ok); + check_sec_ref(mod, modname, &info, exit_section, exit_section_ref_ok); + } version = get_modinfo(info.modinfo, info.modinfo_len, "version"); if (version) @@ -1228,6 +1392,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"); } @@ -1243,9 +1408,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; } @@ -1296,6 +1466,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; @@ -1303,8 +1474,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"); @@ -1456,7 +1630,7 @@ int main(int argc, char **argv) int opt; int err; - while ((opt = getopt(argc, argv, "i:I:mo:aw")) != -1) { + while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) { switch(opt) { case 'i': kernel_read = optarg; @@ -1474,6 +1648,9 @@ int main(int argc, char **argv) case 'a': all_versions = 1; break; + case 's': + vmlinux_section_warnings = 0; + break; case 'w': warn_unresolved = 1; break;