diff options
Diffstat (limited to 'scripts/mod/modpost.c')
| -rw-r--r-- | scripts/mod/modpost.c | 167 |
1 files changed, 98 insertions, 69 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 0c25b5ad497b..75374c64b8cc 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -56,7 +56,7 @@ static bool allow_missing_ns_imports; static bool error_occurred; -static bool extra_warn; +static bool extra_warn __attribute__((unused)); bool target_is_big_endian; bool host_is_big_endian; @@ -74,7 +74,7 @@ static unsigned int nr_unresolved; #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) -void modpost_log(bool is_error, const char *fmt, ...) +void modpost_log(bool is_error, struct module *mod, const char *fmt, ...) { va_list arglist; @@ -87,11 +87,17 @@ void modpost_log(bool is_error, const char *fmt, ...) fprintf(stderr, "modpost: "); + if (mod) + fprintf(stderr, "%s%s: ", mod->name, mod->is_vmlinux ? "" : ".ko"); + va_start(arglist, fmt); vfprintf(stderr, fmt, arglist); va_end(arglist); } +#define mod_warn(mod, fmt, args...) modpost_log(false, mod, fmt, ##args) +#define mod_error(mod, fmt, args...) modpost_log(true, mod, fmt, ##args) + static inline bool strends(const char *str, const char *postfix) { if (strlen(str) < strlen(postfix)) @@ -244,6 +250,11 @@ static struct symbol *alloc_symbol(const char *name) return s; } +static uint8_t get_symbol_flags(const struct symbol *sym) +{ + return sym->is_gpl_only ? KSYM_FLAG_GPL_ONLY : 0; +} + /* For the hash of exported symbols */ static void hash_add_symbol(struct symbol *sym) { @@ -354,9 +365,8 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod, struct symbol *s = find_symbol(name); if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) { - error("%s: '%s' exported twice. Previous export was in %s%s\n", - mod->name, name, s->module->name, - s->module->is_vmlinux ? "" : ".ko"); + mod_error(mod, "symbol '%s' exported twice. Previous export was in %s%s\n", + name, s->module->name, s->module->is_vmlinux ? "" : ".ko"); } s = alloc_symbol(name); @@ -627,7 +637,7 @@ static void handle_symbol(struct module *mod, struct elf_info *info, if (strstarts(symname, "__gnu_lto_")) { /* Should warn here, but modpost runs before the linker */ } else - warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); + mod_warn(mod, "'%s' is COMMON symbol\n", symname); break; case SHN_UNDEF: /* undefined symbol */ @@ -760,6 +770,9 @@ static const char *const section_white_list[] = ".gnu.lto*", ".discard.*", ".llvm.call-graph-profile", /* call graph */ + "__llvm_covfun", + "__llvm_covmap", + ".klp.symid", /* objtool --klp-symids */ NULL }; @@ -768,7 +781,7 @@ static const char *const section_white_list[] = * The cause of this is often a section specified in assembler * without "ax" / "aw". */ -static void check_section(const char *modname, struct elf_info *elf, +static void check_section(struct module *mod, struct elf_info *elf, Elf_Shdr *sechdr) { const char *sec = sech_name(elf, sechdr); @@ -776,11 +789,11 @@ static void check_section(const char *modname, struct elf_info *elf, if (sechdr->sh_type == SHT_PROGBITS && !(sechdr->sh_flags & SHF_ALLOC) && !match(sec, section_white_list)) { - warn("%s (%s): unexpected non-allocatable section.\n" - "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" - "Note that for example <linux/init.h> contains\n" - "section definitions for use in .S files.\n\n", - modname, sec); + mod_warn(mod, "unexpected non-allocatable section '%s'.\n" + "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" + "Note that for example <linux/init.h> contains\n" + "section definitions for use in .S files.\n\n", + sec); } } @@ -962,7 +975,7 @@ static int secref_whitelist(const char *fromsec, const char *fromsym, /* symbols in data sections that may refer to any init/exit sections */ if (match(fromsec, PATTERNS(DATA_SECTIONS)) && match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) && - match(fromsym, PATTERNS("*_ops", "*_console"))) + match(fromsym, PATTERNS("*_ops", "*_ops.llvm.*", "*_console"))) return 0; /* Check for pattern 3 */ @@ -1014,7 +1027,7 @@ static bool is_executable_section(struct elf_info *elf, unsigned int secndx) return (elf->sechdrs[secndx].sh_flags & SHF_EXECINSTR) != 0; } -static void default_mismatch_handler(const char *modname, struct elf_info *elf, +static void default_mismatch_handler(struct module *mod, struct elf_info *elf, const struct sectioncheck* const mismatch, Elf_Sym *tsym, unsigned int fsecndx, const char *fromsec, Elf_Addr faddr, @@ -1044,10 +1057,10 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, * The format for the reference source: <symbol_name>+<offset> or <address> * The format for the reference destination: <symbol_name> or <address> */ - warn("%s: section mismatch in reference: %s%s0x%x (section: %s) -> %s (section: %s)\n", - modname, fromsym, fromsym[0] ? "+" : "", - (unsigned int)(faddr - (fromsym[0] ? from->st_value : 0)), - fromsec, tosym[0] ? tosym : taddr_str, tosec); + mod_warn(mod, "section mismatch in reference: %s%s0x%x (section: %s) -> %s (section: %s)\n", + fromsym, fromsym[0] ? "+" : "", + (unsigned int)(faddr - (fromsym[0] ? from->st_value : 0)), + fromsec, tosym[0] ? tosym : taddr_str, tosec); if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) { if (match(tosec, mismatch->bad_tosec)) @@ -1056,7 +1069,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, "Something is seriously wrong and should be fixed.\n" "You might get more information about where this is\n" "coming from by using scripts/check_extable.sh %s\n", - fromsec, (long)faddr, tosec, modname); + fromsec, (long)faddr, tosec, mod->name); else if (is_executable_section(elf, get_secindex(elf, tsym))) warn("The relocation at %s+0x%lx references\n" "section \"%s\" which is not in the list of\n" @@ -1086,22 +1099,22 @@ static void check_export_symbol(struct module *mod, struct elf_info *elf, label_name = sym_name(elf, label); if (!strstarts(label_name, prefix)) { - error("%s: .export_symbol section contains strange symbol '%s'\n", - mod->name, label_name); + mod_error(mod, ".export_symbol section contains strange symbol '%s'\n", + label_name); return; } if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && ELF_ST_BIND(sym->st_info) != STB_WEAK) { - error("%s: local symbol '%s' was exported\n", mod->name, - label_name + strlen(prefix)); + mod_error(mod, "local symbol '%s' was exported\n", + label_name + strlen(prefix)); return; } name = sym_name(elf, sym); if (strcmp(label_name + strlen(prefix), name)) { - error("%s: .export_symbol section references '%s', but it does not seem to be an export symbol\n", - mod->name, name); + mod_error(mod, ".export_symbol section references '%s', but it does not seem to be an export symbol\n", + name); return; } @@ -1111,8 +1124,8 @@ static void check_export_symbol(struct module *mod, struct elf_info *elf, } else if (!strcmp(data, "")) { is_gpl = false; } else { - error("%s: unknown license '%s' was specified for '%s'\n", - mod->name, data, name); + mod_error(mod, "unknown license '%s' was specified for '%s'\n", + data, name); return; } @@ -1135,11 +1148,11 @@ static void check_export_symbol(struct module *mod, struct elf_info *elf, s->is_func = true; if (match(secname, PATTERNS(ALL_INIT_SECTIONS))) - warn("%s: %s: EXPORT_SYMBOL used for init symbol. Remove __init or EXPORT_SYMBOL.\n", - mod->name, name); + mod_warn(mod, "EXPORT_SYMBOL used for init symbol '%s'. Remove __init or EXPORT_SYMBOL.\n", + name); else if (match(secname, PATTERNS(ALL_EXIT_SECTIONS))) - warn("%s: %s: EXPORT_SYMBOL used for exit symbol. Remove __exit or EXPORT_SYMBOL.\n", - mod->name, name); + mod_warn(mod, "EXPORT_SYMBOL used for exit symbol '%s'. Remove __exit or EXPORT_SYMBOL.\n", + name); } static void check_section_mismatch(struct module *mod, struct elf_info *elf, @@ -1159,7 +1172,7 @@ static void check_section_mismatch(struct module *mod, struct elf_info *elf, if (!mismatch) return; - default_mismatch_handler(mod->name, elf, mismatch, sym, + default_mismatch_handler(mod, elf, mismatch, sym, fsecndx, fromsec, faddr, tosec, taddr); } @@ -1436,7 +1449,7 @@ static void check_sec_ref(struct module *mod, struct elf_info *elf) for (i = 0; i < elf->num_sections; i++) { Elf_Shdr *sechdr = &elf->sechdrs[i]; - check_section(mod->name, elf, sechdr); + check_section(mod, elf, sechdr); /* We want to process only relocation sections and not .init */ if (sechdr->sh_type == SHT_REL || sechdr->sh_type == SHT_RELA) { /* section to which the relocation applies */ @@ -1482,13 +1495,22 @@ static void extract_crcs_for_object(const char *object, struct module *mod) char cmd_file[PATH_MAX]; char *buf, *p; const char *base; - int dirlen, ret; + int dirlen, baselen_without_suffix, ret; base = get_basename(object); dirlen = base - object; - ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd", - dirlen, object, base); + baselen_without_suffix = strlen(object) - dirlen - strlen(".o"); + + /* + * When CONFIG_LTO_CLANG_THIN_DIST=y, the ELF is *.thinlto-native.o + * but the symbol CRCs are recorded in *.o.cmd file. + */ + if (strends(object, ".thinlto-native.o")) + baselen_without_suffix -= strlen(".thinlto-native"); + + ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%.*s.o.cmd", + dirlen, object, baselen_without_suffix, base); if (ret >= sizeof(cmd_file)) { error("%s: too long path was truncated\n", cmd_file); return; @@ -1575,14 +1597,14 @@ static void read_symbols(const char *modname) struct elf_info info = { }; Elf_Sym *sym; - if (!parse_elf(&info, modname)) - return; - if (!strends(modname, ".o")) { error("%s: filename must be suffixed with .o\n", modname); return; } + if (!parse_elf(&info, modname)) + return; + /* strip trailing .o */ mod = new_module(modname, strlen(modname) - strlen(".o")); @@ -1597,7 +1619,7 @@ static void read_symbols(const char *modname) if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); if (!license) - error("missing MODULE_LICENSE() in %s\n", modname); + mod_error(mod, "missing MODULE_LICENSE()\n"); while (license) { if (!license_is_gpl_compatible(license)) { mod->is_gpl_compatible = false; @@ -1610,14 +1632,14 @@ static void read_symbols(const char *modname) namespace; namespace = get_next_modinfo(&info, "import_ns", namespace)) { if (strstarts(namespace, MODULE_NS_PREFIX)) - error("%s: explicitly importing namespace \"%s\" is not allowed.\n", - mod->name, namespace); + mod_error(mod, "explicitly importing namespace '%s' is not allowed.\n", + namespace); add_namespace(&mod->imported_namespaces, namespace); } if (!get_modinfo(&info, "description")) - warn("missing MODULE_DESCRIPTION() in %s\n", modname); + mod_warn(mod, "missing MODULE_DESCRIPTION()\n"); } for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { @@ -1684,8 +1706,17 @@ void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, va_start(ap, fmt); len = vsnprintf(tmp, SZ, fmt, ap); - buf_write(buf, tmp, len); va_end(ap); + + if (len < 0) { + perror("vsnprintf failed"); + exit(1); + } + if (len >= SZ) + fatal("buf_printf output truncated for string %s: %d bytes needed, %d available\n", + tmp, len + 1, SZ); + + buf_write(buf, tmp, len); } void buf_write(struct buffer *buf, const char *s, int len) @@ -1747,14 +1778,13 @@ static void check_exports(struct module *mod) exp = find_symbol(s->name); if (!exp) { if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS) - modpost_log(!warn_unresolved, - "\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); + modpost_log(!warn_unresolved, mod, + "symbol '%s' undefined!\n", + s->name); continue; } if (exp->module == mod) { - error("\"%s\" [%s.ko] was exported without definition\n", - s->name, mod->name); + mod_error(mod, "symbol '%s' was exported without definition\n", s->name); continue; } @@ -1767,15 +1797,15 @@ static void check_exports(struct module *mod) if (!verify_module_namespace(exp->namespace, basename) && !contains_namespace(&mod->imported_namespaces, exp->namespace)) { - modpost_log(!allow_missing_ns_imports, - "module %s uses symbol %s from namespace %s, but does not import it.\n", - basename, exp->name, exp->namespace); + modpost_log(!allow_missing_ns_imports, mod, + "module uses symbol '%s' from namespace '%s', but does not import it.\n", + exp->name, exp->namespace); add_namespace(&mod->missing_namespaces, exp->namespace); } if (!mod->is_gpl_compatible && exp->is_gpl_only) - error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", - basename, exp->name); + mod_error(mod, "GPL-incompatible module uses GPL-only symbol '%s'\n", + exp->name); } } @@ -1825,7 +1855,7 @@ static void check_modname_len(struct module *mod) mod_name = get_basename(mod->name); if (strlen(mod_name) >= MODULE_NAME_LEN) - error("module name is too long [%s.ko]\n", mod->name); + mod_error(mod, "module name is too long\n"); } /** @@ -1871,9 +1901,12 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod) if (trim_unused_exports && !sym->used) continue; - buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n", + buf_printf(buf, "KSYMTAB_%s(%s, \"%s\");\n", sym->is_func ? "FUNC" : "DATA", sym->name, - sym->is_gpl_only ? "_gpl" : "", sym->namespace); + sym->namespace); + + buf_printf(buf, "SYMBOL_FLAGS(%s, 0x%02x);\n", + sym->name, get_symbol_flags(sym)); } if (!modversions) @@ -1886,13 +1919,12 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod) continue; if (!sym->crc_valid) - warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n" - "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n", - sym->name, mod->name, mod->is_vmlinux ? "" : ".ko", - sym->name); + mod_warn(mod, "EXPORT symbol '%s' version generation failed, symbol will not be versioned.\n" + "Is '%s' prototyped in <asm/asm-prototypes.h>?\n", + sym->name, sym->name); - buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n", - sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : ""); + buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x);\n", + sym->name, sym->crc); } } @@ -1913,8 +1945,7 @@ static void add_extended_versions(struct buffer *b, struct module *mod) if (!s->module) continue; if (!s->crc_valid) { - warn("\"%s\" [%s.ko] has no CRC!\n", - s->name, mod->name); + mod_warn(mod, "symbol '%s' has no CRC!\n", s->name); continue; } buf_printf(b, "\t0x%08x,\n", s->crc); @@ -1957,8 +1988,7 @@ static void add_versions(struct buffer *b, struct module *mod) if (!s->module) continue; if (!s->crc_valid) { - warn("\"%s\" [%s.ko] has no CRC!\n", - s->name, mod->name); + mod_warn(mod, "symbol '%s' has no CRC!\n", s->name); continue; } if (strlen(s->name) >= MODULE_NAME_LEN) { @@ -1966,8 +1996,7 @@ static void add_versions(struct buffer *b, struct module *mod) /* this symbol will only be in the extended info */ continue; } else { - error("too long symbol \"%s\" [%s.ko]\n", - s->name, mod->name); + mod_error(mod, "too long symbol '%s'\n", s->name); break; } } |
