/* Postprocess module symbol versions * * Copyright 2003 Kai Germaschewski * Copyright 2002-2004 Rusty Russell, IBM Corporation * Copyright 2006-2008 Sam Ravnborg * Based in part on module-init-tools/depmod.c,file2alias * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * Usage: modpost vmlinux module1.o module2.o ...
*/
staticbool module_enabled; /* Are we using CONFIG_MODVERSIONS? */ staticbool modversions; /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ staticbool all_versions; /* Is CONFIG_BASIC_MODVERSIONS set? */ staticbool basic_modversions; /* Is CONFIG_EXTENDED_MODVERSIONS set? */ staticbool extended_modversions; /* If we are modposting external module set to 1 */ staticbool external_module; /* Only warn about unresolved symbols */ staticbool warn_unresolved;
staticint sec_mismatch_count; staticbool sec_mismatch_warn_only = true; /* Trim EXPORT_SYMBOLs that are unused by in-tree modules */ staticbool trim_unused_exports;
/* ignore missing files */ staticbool ignore_missing_files; /* If set to 1, only warn (instead of error) about missing ns imports */ staticbool allow_missing_ns_imports;
/* * Cut off the warnings when there are too many. This typically occurs when * vmlinux is missing. ('make modules' without building vmlinux.)
*/ #define MAX_UNRESOLVED_REPORTS 10 staticunsignedint nr_unresolved;
/* In kernel, this size is defined in linux/module.h; * here we use Elf_Addr instead of long for covering cross-compile
*/
/** * get_basename - return the last part of a pathname. * * @path: path to extract the filename from.
*/ constchar *get_basename(constchar *path)
{ constchar *tail = strrchr(path, '/');
return tail ? tail + 1 : path;
}
char *read_text_file(constchar *filename)
{ struct stat st;
size_t nbytes; int fd; char *buf;
/* * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE() * is missing, do not check the use for EXPORT_SYMBOL_GPL() because * modpost will exit with an error anyway.
*/
mod->is_gpl_compatible = true;
list_add_tail(&mod->list, &modules);
return mod;
}
struct symbol { struct hlist_node hnode;/* link to hash table */ struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */ struct module *module; char *namespace; unsignedint crc; bool crc_valid; bool weak; bool is_func; bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */ bool used; /* there exists a user of this symbol */ char name[];
};
/** * Allocate a new symbols for use in the hash of exported symbols or * the list of unresolved symbols per module
**/ staticstruct symbol *alloc_symbol(constchar *name)
{ struct symbol *s = xmalloc(sizeof(*s) + strlen(name) + 1);
memset(s, 0, sizeof(*s));
strcpy(s->name, name);
return s;
}
/* For the hash of exported symbols */ staticvoid hash_add_symbol(struct symbol *sym)
{
hash_add(symbol_hashtable, &sym->hnode, hash_str(sym->name));
}
staticconstchar *sec_name(conststruct elf_info *info, unsignedint secindex)
{ /* * If sym->st_shndx is a special section index, there is no * corresponding section header. * Return "" if the index is out of range of info->sechdrs[] array.
*/ if (secindex >= info->num_sections) return"";
/* modpost only works for relocatable objects */ if (hdr->e_type != ET_REL)
fatal("%s: not relocatable object.", filename);
/* Check if file offset is correct */ if (hdr->e_shoff > info->size)
fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
(unsignedlong)hdr->e_shoff, filename, info->size);
if (hdr->e_shnum == SHN_UNDEF) { /* * There are more than 64k sections, * read count from .sh_size.
*/
info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
} else {
info->num_sections = hdr->e_shnum;
} if (hdr->e_shstrndx == SHN_XINDEX) {
info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
} else {
info->secindex_strings = hdr->e_shstrndx;
}
/* Fix endianness in section headers */ for (i = 0; i < info->num_sections; i++) {
sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign);
sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
} /* Find symbol table. */
secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; for (i = 1; i < info->num_sections; i++) { constchar *secname; int nobits = sechdrs[i].sh_type == SHT_NOBITS;
if (!nobits && sechdrs[i].sh_offset > info->size)
fatal("%s is truncated. sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n",
filename, (unsignedlong)sechdrs[i].sh_offset, sizeof(*hdr));
staticint ignore_undef_symbol(struct elf_info *info, constchar *symname)
{ /* ignore __this_module, it will be resolved shortly */ if (strcmp(symname, "__this_module") == 0) return 1; /* ignore global offset table */ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) return 1; if (info->hdr->e_machine == EM_PPC) /* Special register function linked on all modules during final link of .ko */ if (strstarts(symname, "_restgpr_") ||
strstarts(symname, "_savegpr_") ||
strstarts(symname, "_rest32gpr_") ||
strstarts(symname, "_save32gpr_") ||
strstarts(symname, "_restvr_") ||
strstarts(symname, "_savevr_")) return 1; if (info->hdr->e_machine == EM_PPC64) /* Special register function linked on all modules during final link of .ko */ if (strstarts(symname, "_restgpr0_") ||
strstarts(symname, "_savegpr0_") ||
strstarts(symname, "_restvr_") ||
strstarts(symname, "_savevr_") ||
strcmp(symname, ".TOC.") == 0) return 1; /* Do not ignore this symbol */ return 0;
}
staticvoid handle_symbol(struct module *mod, struct elf_info *info, const Elf_Sym *sym, constchar *symname)
{ switch (sym->st_shndx) { case SHN_COMMON: 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); break; case SHN_UNDEF: /* undefined symbol */ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
ELF_ST_BIND(sym->st_info) != STB_WEAK) break; if (ignore_undef_symbol(info, symname)) break; if (info->hdr->e_machine == EM_SPARC ||
info->hdr->e_machine == EM_SPARCV9) { /* Ignore register directives. */ if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) break; if (symname[0] == '.') { char *munged = xstrdup(symname);
munged[0] = '_';
munged[1] = toupper(munged[1]);
symname = munged;
}
}
/* * Check whether the 'string' argument matches one of the 'patterns', * an array of shell wildcard patterns (glob). * * Return true is there is a match.
*/ staticbool match(constchar *string, constchar *const patterns[])
{ constchar *pattern;
while ((pattern = *patterns++)) { if (!fnmatch(pattern, string, 0)) returntrue;
}
/* sections that we do not want to do full section mismatch check on */ staticconstchar *const section_white_list[] =
{ ".comment*", ".debug*", ".zdebug*", /* Compressed debug sections. */ ".GCC.command.line", /* record-gcc-switches */ ".mdebug*", /* alpha, score, mips etc. */ ".pdr", /* alpha, score, mips etc. */ ".stab*", ".note*", ".got*", ".toc*", ".xt.prop", /* xtensa */ ".xt.lit", /* xtensa */ ".arcextmap*", /* arc */ ".gnu.linkonce.arcext*", /* arc : modules */ ".cmem*", /* EZchip */ ".fmt_slot*", /* EZchip */ ".gnu.lto*", ".discard.*", ".llvm.call-graph-profile", /* call graph */
NULL
};
/* * This is used to find sections missing the SHF_ALLOC flag. * The cause of this is often a section specified in assembler * without "ax" / "aw".
*/ staticvoid check_section(constchar *modname, struct elf_info *elf,
Elf_Shdr *sechdr)
{ constchar *sec = sech_name(elf, sechdr);
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 contains\n" "section definitions for use in .S files.\n\n",
modname, sec);
}
}
/** * Describe how to match sections on different criteria: * * @fromsec: Array of sections to be matched. * * @bad_tosec: Relocations applied to a section in @fromsec to a section in * this array is forbidden (black-list). Can be empty. * * @good_tosec: Relocations applied to a section in @fromsec must be * targeting sections in this array (white-list). Can be empty. * * @mismatch: Type of mismatch.
*/ struct sectioncheck { constchar *fromsec[20]; constchar *bad_tosec[20]; constchar *good_tosec[20]; enum mismatch mismatch;
};
staticconststruct sectioncheck sectioncheck[] = { /* Do not reference init/exit code/data from * normal code and data
*/
{
.fromsec = { TEXT_SECTIONS, DATA_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL },
.mismatch = TEXTDATA_TO_ANY_INIT_EXIT,
}, /* Do not use exit code/data from init code */
{
.fromsec = { ALL_INIT_SECTIONS, NULL },
.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
.mismatch = ANY_INIT_TO_ANY_EXIT,
}, /* Do not use init code/data from exit code */
{
.fromsec = { ALL_EXIT_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = ANY_EXIT_TO_ANY_INIT,
},
{
.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = ANY_INIT_TO_ANY_EXIT,
},
{
.fromsec = { "__ex_table", NULL }, /* If you're adding any new black-listed sections in here, consider * adding a special 'printer' for them in scripts/check_extable.
*/
.bad_tosec = { ".altinstr_replacement", NULL },
.good_tosec = {ALL_TEXT_SECTIONS , NULL},
.mismatch = EXTABLE_TO_NON_TEXT,
}
};
staticconststruct sectioncheck *section_mismatch( constchar *fromsec, constchar *tosec)
{ int i;
/* * The target section could be the SHT_NUL section when we're * handling relocations to un-resolved symbols, trying to match it * doesn't make much sense and causes build failures on parisc * architectures.
*/ if (*tosec == '\0') return NULL;
for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) { conststruct sectioncheck *check = §ioncheck[i];
if (match(fromsec, check->fromsec)) { if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) return check; if (check->good_tosec[0] && !match(tosec, check->good_tosec)) return check;
}
} return NULL;
}
/** * Whitelist to allow certain references to pass with no warning. * * Pattern 1: * If a module parameter is declared __initdata and permissions=0 * then this is legal despite the warning generated. * We cannot see value of permissions here, so just ignore * this pattern. * The pattern is identified by: * tosec = .init.data * fromsec = .data* * atsym =__param* * * Pattern 1a: * module_param_call() ops can refer to __init set function if permissions=0 * The pattern is identified by: * tosec = .init.text * fromsec = .data* * atsym = __param_ops_* * * Pattern 3: * Whitelist all references from .head.text to any init section * * 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 * if init section is freed, its ok to reference those symbols. * For ex. symbols marking the init section boundaries. * This pattern is identified by * refsymname = __init_begin, _sinittext, _einittext * * Pattern 5: * GCC may optimize static inlines when fed constant arg(s) resulting * in functions like cpumask_empty() -- generating an associated symbol * cpumask_empty.constprop.3 that appears in the audit. If the const that * is passed in comes from __init, like say nmi_ipi_mask, we get a * meaningless section warning. May need to add isra symbols too... * This pattern is identified by * tosec = init section * fromsec = text section * refsymname = *.constprop.* *
**/ staticint secref_whitelist(constchar *fromsec, constchar *fromsym, constchar *tosec, constchar *tosym)
{ /* Check for pattern 1 */ if (match(tosec, PATTERNS(ALL_INIT_DATA_SECTIONS)) &&
match(fromsec, PATTERNS(DATA_SECTIONS)) &&
strstarts(fromsym, "__param")) return 0;
/* Check for pattern 1a */ if (strcmp(tosec, ".init.text") == 0 &&
match(fromsec, PATTERNS(DATA_SECTIONS)) &&
strstarts(fromsym, "__param_ops_")) return 0;
/* 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", "*_probe", "*_console"))) return 0;
/* Check for pattern 3 */ if (strstarts(fromsec, ".head.text") &&
match(tosec, PATTERNS(ALL_INIT_SECTIONS))) return 0;
/* Check for pattern 4 */ if (match(tosym, PATTERNS("__init_begin", "_sinittext", "_einittext"))) return 0;
/* Check for pattern 5 */ if (match(fromsec, PATTERNS(ALL_TEXT_SECTIONS)) &&
match(tosec, PATTERNS(ALL_INIT_SECTIONS)) &&
match(fromsym, PATTERNS("*.constprop.*"))) return 0;
/* If the supplied symbol has a valid name, return it */ if (is_valid_name(elf, sym)) return sym;
/* * Strive to find a better symbol name, but the resulting name may not * match the symbol referenced in the original code.
*/
new_sym = symsearch_find_nearest(elf, addr, get_secindex(elf, sym), true, 20); return new_sym ? new_sym : sym;
}
/* check whitelist - we may ignore it */ if (!secref_whitelist(fromsec, fromsym, tosec, tosym)) return;
sec_mismatch_count++;
if (!tosym[0])
snprintf(taddr_str, sizeof(taddr_str), "0x%x", (unsignedint)taddr);
/* * 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] ? "+" : "",
(unsignedint)(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))
fatal("The relocation at %s+0x%lx references\n" "section \"%s\" which is black-listed.\n" "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); elseif (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" "authorized sections. If you're adding a new section\n" "and/or if this reference is valid, add \"%s\" to the\n" "list of authorized sections to jump to on fault.\n" "This can be achieved by adding \"%s\" to\n" "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
fromsec, (long)faddr, tosec, tosec, tosec); else
error("%s+0x%lx references non-executable section '%s'\n",
fromsec, (long)faddr, tosec);
}
}
if (!strstarts(label_name, prefix)) {
error("%s: .export_symbol section contains strange symbol '%s'\n",
mod->name, 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)); 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); return;
}
data = sym_get_data(elf, label); /* license */ if (!strcmp(data, "GPL")) {
is_gpl = true;
} elseif (!strcmp(data, "")) {
is_gpl = false;
} else {
error("%s: unknown license '%s' was specified for '%s'\n",
mod->name, data, name); return;
}
data += strlen(data) + 1; /* namespace */
s = sym_add_exported(name, mod, is_gpl, data);
/* * We need to be aware whether we are exporting a function or * a data on some architectures.
*/
s->is_func = (ELF_ST_TYPE(sym->st_info) == STT_FUNC);
/* * For parisc64, symbols prefixed $$ from the library have the symbol type * STT_LOPROC. They should be handled as functions too.
*/ if (elf->hdr->e_ident[EI_CLASS] == ELFCLASS64 &&
elf->hdr->e_machine == EM_PARISC &&
ELF_ST_TYPE(sym->st_info) == STT_LOPROC)
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); elseif (match(secname, PATTERNS(ALL_EXIT_SECTIONS)))
warn("%s: %s: EXPORT_SYMBOL used for exit symbol. Remove __exit or EXPORT_SYMBOL.\n",
mod->name, name);
}
switch (elf->hdr->e_machine) { case EM_RISCV: if (!strcmp("__ex_table", fromsec) &&
r_type == R_RISCV_SUB32) continue; break; case EM_LOONGARCH: switch (r_type) { case R_LARCH_SUB32: if (!strcmp("__ex_table", fromsec)) continue; break; case R_LARCH_RELAX: case R_LARCH_ALIGN: /* These relocs do not refer to symbols */ continue;
} break;
}
/** * A module includes a number of sections that are discarded * either when loaded or when used as built-in. * For loaded modules all functions marked __init and all data * marked __initdata will be discarded when the module has been initialized. * Likewise for modules used built-in the sections marked __exit * are discarded because __exit marked function are supposed to be called * only when a module is unloaded which never happens for built-in modules. * The check_sec_ref() function traverses all relocation records * to find all references to a section that reference a section that will * be discarded and warns about it.
**/ staticvoid check_sec_ref(struct module *mod, struct elf_info *elf)
{ int i;
/* Walk through all sections */ for (i = 0; i < elf->num_sections; i++) {
Elf_Shdr *sechdr = &elf->sechdrs[i];
check_section(mod->name, 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 */ unsignedint secndx = sechdr->sh_info; constchar *secname = sec_name(elf, secndx); constvoid *start, *stop;
/* If the section is known good, skip it */ if (match(secname, section_white_list)) continue;
start = sym_get_data_by_offset(elf, i, 0);
stop = start + sechdr->sh_size;
staticchar *remove_dot(char *s)
{
size_t n = strcspn(s, ".");
if (n && s[n]) {
size_t m = strspn(s + n + 1, "0123456789"); if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
s[n] = 0;
} return s;
}
/* * The CRCs are recorded in .*.cmd files in the form of: * #SYMVER <name> <crc>
*/ staticvoid extract_crcs_for_object(constchar *object, struct module *mod)
{ char cmd_file[PATH_MAX]; char *buf, *p; constchar *base; int dirlen, ret;
base = get_basename(object);
dirlen = base - object;
ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
dirlen, object, base); if (ret >= sizeof(cmd_file)) {
error("%s: too long path was truncated\n", cmd_file); return;
}
buf = read_text_file(cmd_file);
p = buf;
while ((p = strstr(p, "\n#SYMVER "))) { char *name;
size_t namelen; unsignedint crc; struct symbol *sym;
name = p + strlen("\n#SYMVER ");
p = strchr(name, ' '); if (!p) break;
namelen = p - name;
p++;
if (!isdigit(*p)) continue; /* skip this line */
crc = strtoul(p, &p, 0); if (*p != '\n') continue; /* skip this line */
name[namelen] = '\0';
/* * sym_find_with_module() may return NULL here. * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y. * Since commit e1327a127703, genksyms calculates CRCs of all * symbols, including trimmed ones. Ignore orphan CRCs.
*/
sym = sym_find_with_module(name, mod); if (sym)
sym_set_crc(sym, crc);
}
free(buf);
}
/* * The symbol versions (CRC) are recorded in the .*.cmd files. * Parse them to retrieve CRCs for the current module.
*/ staticvoid mod_set_crcs(struct module *mod)
{ char objlist[PATH_MAX]; char *buf, *p, *obj; int ret;
if (mod->is_vmlinux) {
strcpy(objlist, ".vmlinux.objs");
} else { /* objects for a module are listed in the *.mod file. */
ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name); if (ret >= sizeof(objlist)) {
error("%s: too long path was truncated\n", objlist); return;
}
}
buf = read_text_file(objlist);
p = buf;
while ((obj = strsep(&p, "\n")) && obj[0])
extract_crcs_for_object(obj, mod);
/* save .no_trim_symbol section for later use */ if (info.no_trim_symbol_len) {
mod->no_trim_symbol = xmalloc(info.no_trim_symbol_len);
memcpy(mod->no_trim_symbol, info.no_trim_symbol,
info.no_trim_symbol_len);
mod->no_trim_symbol_len = info.no_trim_symbol_len;
}
if (!mod->is_vmlinux) {
license = get_modinfo(&info, "license"); if (!license)
error("missing MODULE_LICENSE() in %s\n", modname); while (license) { if (!license_is_gpl_compatible(license)) {
mod->is_gpl_compatible = false; break;
}
license = get_next_modinfo(&info, "license", license);
}
for (namespace = get_modinfo(&info, "import_ns"); 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);
if (!mod->is_vmlinux) {
version = get_modinfo(&info, "version"); if (version || all_versions)
get_src_version(mod->name, mod->srcversion, sizeof(mod->srcversion) - 1);
}
parse_elf_finish(&info);
if (modversions) { /* * Our trick to get versioning for module struct etc. - it's * never passed as an argument to an exported function, so * the automatic versioning doesn't pick it up, but it's really * important anyhow.
*/
sym_add_unresolved("module_layout", mod, false);
in = fopen(filename, "r"); if (!in)
fatal("Can't open filenames file %s: %m", filename);
while (fgets(fname, PATH_MAX, in) != NULL) { if (strends(fname, "\n"))
fname[strlen(fname)-1] = '\0';
read_symbols(fname);
}
fclose(in);
}
#define SZ 500
/* We first write the generated file into memory using the * following helper, then compare to the file on disk and
* only update the later if anything changed */
/** * verify_module_namespace() - does @modname have access to this symbol's @namespace * @namespace: export symbol namespace * @modname: module name * * If @namespace is prefixed with "module:" to indicate it is a module namespace * then test if @modname matches any of the comma separated patterns. * * The patterns only support tail-glob.
*/ staticbool verify_module_namespace(constchar *namespace, constchar *modname)
{
size_t len, modlen = strlen(modname); constchar *prefix = "module:"; constchar *sep; bool glob;
if (!strstarts(namespace, prefix)) returnfalse;
for (namespace += strlen(prefix); *namespace; namespace = sep) {
sep = strchrnul(namespace, ',');
len = sep - namespace;
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);
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);
}
}
while ((name = strsep(&p, "\n"))) { struct symbol *sym = find_symbol(name);
if (sym)
sym->used = true;
}
free(buf);
}
/* * Keep symbols recorded in the .no_trim_symbol section. This is necessary to * prevent CONFIG_TRIM_UNUSED_KSYMS from dropping EXPORT_SYMBOL because * symbol_get() relies on the symbol being present in the ksymtab for lookups.
*/ staticvoid keep_no_trim_symbols(struct module *mod)
{ unsignedlong size = mod->no_trim_symbol_len;
for (char *s = mod->no_trim_symbol; s; s = next_string(s , &size)) { struct symbol *sym;
/* * If find_symbol() returns NULL, this symbol is not provided * by any module, and symbol_get() will fail.
*/
sym = find_symbol(s); if (sym)
sym->used = true;
}
}
/* record CRCs for exported symbols */
buf_printf(buf, "\n");
list_for_each_entry(sym, &mod->exported_symbols, list) { if (trim_unused_exports && !sym->used) continue;
if (!sym->crc_valid)
warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n" "Is \"%s\" prototyped in ?\n",
sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
sym->name);
/** * Record CRCs for unresolved symbols, supporting long names
*/ staticvoid add_extended_versions(struct buffer *b, struct module *mod)
{ struct symbol *s;
if (!extended_modversions) return;
buf_printf(b, "\n");
buf_printf(b, "static const u32 ____version_ext_crcs[]\n");
buf_printf(b, "__used __section(\"__version_ext_crcs\") = {\n");
list_for_each_entry(s, &mod->unresolved_symbols, list) { if (!s->module) continue; if (!s->crc_valid) {
warn("\"%s\" [%s.ko] has no CRC!\n",
s->name, mod->name); continue;
}
buf_printf(b, "\t0x%08x,\n", s->crc);
}
buf_printf(b, "};\n");
buf_printf(b, "static const char ____version_ext_names[]\n");
buf_printf(b, "__used __section(\"__version_ext_names\") =\n");
list_for_each_entry(s, &mod->unresolved_symbols, list) { if (!s->module) continue; if (!s->crc_valid) /* * We already warned on this when producing the crc * table. * We need to skip its name too, as the indexes in * both tables need to align.
*/ continue;
buf_printf(b, "\t\"%s\\0\"\n", s->name);
}
buf_printf(b, ";\n");
}
/** * Record CRCs for unresolved symbols
**/ staticvoid add_versions(struct buffer *b, struct module *mod)
{ struct symbol *s;
list_for_each_entry(s, &mod->unresolved_symbols, list) { if (!s->module) continue; if (!s->crc_valid) {
warn("\"%s\" [%s.ko] has no CRC!\n",
s->name, mod->name); continue;
} if (strlen(s->name) >= MODULE_NAME_LEN) { if (extended_modversions) { /* this symbol will only be in the extended info */ continue;
} else {
error("too long symbol \"%s\" [%s.ko]\n",
s->name, mod->name); break;
}
}
buf_printf(b, "\t{ 0x%08x, \"%s\" },\n",
s->crc, s->name);
}
buf_printf(b, "};\n");
}
staticvoid add_depends(struct buffer *b, struct module *mod)
{ struct symbol *s; int first = 1;
/* Clear ->seen flag of modules that own symbols needed by this. */
list_for_each_entry(s, &mod->unresolved_symbols, list) { if (s->module)
s->module->seen = s->module->is_vmlinux;
}
ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); if (ret >= sizeof(fname)) {
error("%s: too long path was truncated\n", fname); goto free;
}
if (unused_exports_white_list)
handle_white_list_exports(unused_exports_white_list);
list_for_each_entry(mod, &modules, list) { if (mod->dump_file) continue;
if (mod->is_vmlinux)
write_vmlinux_export_c_file(mod); else
write_mod_c_file(mod);
}
if (missing_namespace_deps)
write_namespace_deps_files(missing_namespace_deps);
if (dump_write)
write_dump(dump_write); if (sec_mismatch_count && !sec_mismatch_warn_only)
error("Section mismatches detected.\n" "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
if (nr_unresolved > MAX_UNRESOLVED_REPORTS)
warn("suppressed %u unresolved symbol warnings because there were too many)\n",
nr_unresolved - MAX_UNRESOLVED_REPORTS);
return error_occurred ? 1 : 0;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.99Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.