aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/mod
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/mod')
-rw-r--r--scripts/mod/file2alias.c5
-rw-r--r--scripts/mod/modpost.c219
-rw-r--r--scripts/mod/modpost.h10
-rw-r--r--scripts/mod/sumversion.c23
4 files changed, 214 insertions, 43 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index e17a29ae2e97..c91eba751804 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -36,6 +36,11 @@ typedef uint16_t __u16;
typedef unsigned char __u8;
typedef struct {
__u8 b[16];
+} guid_t;
+
+/* backwards compatibility, don't use in new code */
+typedef struct {
+ __u8 b[16];
} uuid_le;
typedef struct {
__u8 b[16];
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index f277e116e0eb..d2a30a7b3f07 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -38,6 +38,8 @@ static int sec_mismatch_count = 0;
static int sec_mismatch_fatal = 0;
/* ignore missing files */
static int ignore_missing_files;
+/* write namespace dependencies */
+static int write_namespace_deps;
enum export {
export_plain, export_unused, export_gpl,
@@ -164,11 +166,13 @@ struct symbol {
struct module *module;
unsigned int crc;
int crc_valid;
+ char *namespace;
unsigned int weak:1;
unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/
unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */
+ unsigned int is_static:1; /* 1 if symbol is not global */
enum export export; /* Type of export */
char name[0];
};
@@ -201,6 +205,7 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak,
strcpy(s->name, name);
s->weak = weak;
s->next = next;
+ s->is_static = 1;
return s;
}
@@ -233,6 +238,37 @@ static struct symbol *find_symbol(const char *name)
return NULL;
}
+static bool contains_namespace(struct namespace_list *list,
+ const char *namespace)
+{
+ struct namespace_list *ns_entry;
+
+ for (ns_entry = list; ns_entry != NULL; ns_entry = ns_entry->next)
+ if (strcmp(ns_entry->namespace, namespace) == 0)
+ return true;
+
+ return false;
+}
+
+static void add_namespace(struct namespace_list **list, const char *namespace)
+{
+ struct namespace_list *ns_entry;
+
+ if (!contains_namespace(*list, namespace)) {
+ ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
+ strlen(namespace) + 1));
+ strcpy(ns_entry->namespace, namespace);
+ ns_entry->next = *list;
+ *list = ns_entry;
+ }
+}
+
+static bool module_imports_namespace(struct module *module,
+ const char *namespace)
+{
+ return contains_namespace(module->imported_namespaces, namespace);
+}
+
static const struct {
const char *str;
enum export export;
@@ -312,6 +348,32 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
return export_unknown;
}
+static const char *namespace_from_kstrtabns(struct elf_info *info,
+ Elf_Sym *kstrtabns)
+{
+ char *value = info->ksymtab_strings + kstrtabns->st_value;
+ return value[0] ? value : NULL;
+}
+
+static void sym_update_namespace(const char *symname, const char *namespace)
+{
+ struct symbol *s = find_symbol(symname);
+
+ /*
+ * That symbol should have been created earlier and thus this is
+ * actually an assertion.
+ */
+ if (!s) {
+ merror("Could not update namespace(%s) for symbol %s\n",
+ namespace, symname);
+ return;
+ }
+
+ free(s->namespace);
+ s->namespace =
+ namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
+}
+
/**
* Add an exported symbol - it may have already been added without a
* CRC, in this case just update the CRC
@@ -325,10 +387,9 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
s = new_symbol(name, mod, export);
} else {
if (!s->preloaded) {
- warn("%s: '%s' exported twice. Previous export "
- "was in %s%s\n", mod->name, name,
- s->module->name,
- is_vmlinux(s->module->name) ?"":".ko");
+ warn("%s: '%s' exported twice. Previous export was in %s%s\n",
+ mod->name, name, s->module->name,
+ is_vmlinux(s->module->name) ? "" : ".ko");
} else {
/* In case Module.symvers was out of date */
s->module = mod;
@@ -532,6 +593,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
info->export_unused_gpl_sec = i;
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
info->export_gpl_future_sec = i;
+ else if (strcmp(secname, "__ksymtab_strings") == 0)
+ info->ksymtab_strings = (void *)hdr +
+ sechdrs[i].sh_offset -
+ sechdrs[i].sh_addr;
if (sechdrs[i].sh_type == SHT_SYMTAB) {
unsigned int sh_link_idx;
@@ -620,6 +685,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
unsigned int crc;
enum export export;
bool is_crc = false;
+ const char *name;
if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
strstarts(symname, "__ksymtab"))
@@ -691,8 +757,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
default:
/* All exported symbols */
if (strstarts(symname, "__ksymtab_")) {
- sym_add_exported(symname + strlen("__ksymtab_"), mod,
- export);
+ name = symname + strlen("__ksymtab_");
+ sym_add_exported(name, mod, export);
}
if (strcmp(symname, "init_module") == 0)
mod->has_init = 1;
@@ -795,9 +861,9 @@ static int match(const char *sym, const char * const pat[])
/* "*foo*" */
if (*p == '*' && *endp == '*') {
- char *here, *bare = strndup(p + 1, strlen(p) - 2);
+ char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
+ char *here = strstr(sym, bare);
- here = strstr(sym, bare);
free(bare);
if (here != NULL)
return 1;
@@ -1943,6 +2009,7 @@ static void read_symbols(const char *modname)
const char *symname;
char *version;
char *license;
+ char *namespace;
struct module *mod;
struct elf_info info = { };
Elf_Sym *sym;
@@ -1974,12 +2041,43 @@ static void read_symbols(const char *modname)
license = get_next_modinfo(&info, "license", license);
}
+ namespace = get_modinfo(&info, "import_ns");
+ while (namespace) {
+ add_namespace(&mod->imported_namespaces, namespace);
+ namespace = get_next_modinfo(&info, "import_ns", namespace);
+ }
+
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
symname = remove_dot(info.strtab + sym->st_name);
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
}
+
+ /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ symname = remove_dot(info.strtab + sym->st_name);
+
+ if (strstarts(symname, "__kstrtabns_"))
+ sym_update_namespace(symname + strlen("__kstrtabns_"),
+ namespace_from_kstrtabns(&info,
+ sym));
+ }
+
+ // check for static EXPORT_SYMBOL_* functions && global vars
+ for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
+ unsigned char bind = ELF_ST_BIND(sym->st_info);
+
+ if (bind == STB_GLOBAL || bind == STB_WEAK) {
+ struct symbol *s =
+ find_symbol(remove_dot(info.strtab +
+ sym->st_name));
+
+ if (s)
+ s->is_static = 0;
+ }
+ }
+
if (!is_vmlinux(modname) || vmlinux_section_warnings)
check_sec_ref(mod, modname, &info);
@@ -2118,6 +2216,18 @@ static int check_exports(struct module *mod)
basename++;
else
basename = mod->name;
+
+ if (exp->namespace) {
+ add_namespace(&mod->required_namespaces,
+ exp->namespace);
+
+ if (!write_namespace_deps &&
+ !module_imports_namespace(mod, exp->namespace)) {
+ warn("module %s uses symbol %s from namespace %s, but does not import it.\n",
+ basename, exp->name, exp->namespace);
+ }
+ }
+
if (!mod->gpl_compatible)
check_for_gpl_usage(exp->export, basename, exp->name);
check_for_unused(exp->export, basename, exp->name);
@@ -2159,7 +2269,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n");
- buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
+ buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
if (mod->has_init)
buf_printf(b, "\t.init = init_module,\n");
@@ -2213,8 +2323,7 @@ static int add_versions(struct buffer *b, struct module *mod)
buf_printf(b, "\n");
buf_printf(b, "static const struct modversion_info ____versions[]\n");
- buf_printf(b, "__used\n");
- buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
+ buf_printf(b, "__used __section(__versions) = {\n");
for (s = mod->unres; s; s = s->next) {
if (!s->module)
@@ -2250,10 +2359,7 @@ static void add_depends(struct buffer *b, struct module *mod)
s->module->seen = is_vmlinux(s->module->name);
buf_printf(b, "\n");
- buf_printf(b, "static const char __module_depends[]\n");
- buf_printf(b, "__used\n");
- buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
- buf_printf(b, "\"depends=");
+ buf_printf(b, "MODULE_INFO(depends, \"");
for (s = mod->unres; s; s = s->next) {
const char *p;
if (!s->module)
@@ -2271,7 +2377,7 @@ static void add_depends(struct buffer *b, struct module *mod)
buf_printf(b, "%s%s", first ? "" : ",", p);
first = 0;
}
- buf_printf(b, "\";\n");
+ buf_printf(b, "\");\n");
}
static void add_srcversion(struct buffer *b, struct module *mod)
@@ -2341,7 +2447,7 @@ static void read_dump(const char *fname, unsigned int kernel)
return;
while ((line = get_next_line(&pos, file, size))) {
- char *symname, *modname, *d, *export, *end;
+ char *symname, *namespace, *modname, *d, *export, *end;
unsigned int crc;
struct module *mod;
struct symbol *s;
@@ -2349,7 +2455,10 @@ static void read_dump(const char *fname, unsigned int kernel)
if (!(symname = strchr(line, '\t')))
goto fail;
*symname++ = '\0';
- if (!(modname = strchr(symname, '\t')))
+ if (!(namespace = strchr(symname, '\t')))
+ goto fail;
+ *namespace++ = '\0';
+ if (!(modname = strchr(namespace, '\t')))
goto fail;
*modname++ = '\0';
if ((export = strchr(modname, '\t')) != NULL)
@@ -2369,7 +2478,9 @@ static void read_dump(const char *fname, unsigned int kernel)
s = sym_add_exported(symname, mod, export_no(export));
s->kernel = kernel;
s->preloaded = 1;
+ s->is_static = 0;
sym_update_crc(symname, mod, crc, export_no(export));
+ sym_update_namespace(symname, namespace);
}
release_file(file, size);
return;
@@ -2395,16 +2506,20 @@ static void write_dump(const char *fname)
{
struct buffer buf = { };
struct symbol *symbol;
+ const char *namespace;
int n;
for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
symbol = symbolhash[n];
while (symbol) {
- if (dump_sym(symbol))
- buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
- symbol->crc, symbol->name,
- symbol->module->name,
- export_str(symbol->export));
+ if (dump_sym(symbol)) {
+ namespace = symbol->namespace;
+ buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
+ symbol->crc, symbol->name,
+ namespace ? namespace : "",
+ symbol->module->name,
+ export_str(symbol->export));
+ }
symbol = symbol->next;
}
}
@@ -2412,6 +2527,31 @@ static void write_dump(const char *fname)
free(buf.p);
}
+static void write_namespace_deps_files(void)
+{
+ struct module *mod;
+ struct namespace_list *ns;
+ struct buffer ns_deps_buf = {};
+
+ for (mod = modules; mod; mod = mod->next) {
+ char fname[PATH_MAX];
+
+ if (mod->skip)
+ continue;
+
+ ns_deps_buf.pos = 0;
+
+ for (ns = mod->required_namespaces; ns; ns = ns->next)
+ buf_printf(&ns_deps_buf, "%s\n", ns->namespace);
+
+ if (ns_deps_buf.pos == 0)
+ continue;
+
+ sprintf(fname, "%s.ns_deps", mod->name);
+ write_if_changed(&ns_deps_buf, fname);
+ }
+}
+
struct ext_sym_list {
struct ext_sym_list *next;
const char *file;
@@ -2425,10 +2565,11 @@ int main(int argc, char **argv)
char *dump_write = NULL, *files_source = NULL;
int opt;
int err;
+ int n;
struct ext_sym_list *extsym_iter;
struct ext_sym_list *extsym_start = NULL;
- while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awE")) != -1) {
+ while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awEd")) != -1) {
switch (opt) {
case 'i':
kernel_read = optarg;
@@ -2469,6 +2610,9 @@ int main(int argc, char **argv)
case 'E':
sec_mismatch_fatal = 1;
break;
+ case 'd':
+ write_namespace_deps = 1;
+ break;
default:
exit(1);
}
@@ -2503,6 +2647,9 @@ int main(int argc, char **argv)
err |= check_modname_len(mod);
err |= check_exports(mod);
+ if (write_namespace_deps)
+ continue;
+
add_header(&buf, mod);
add_intree_flag(&buf, !external_module);
add_retpoline(&buf);
@@ -2515,11 +2662,35 @@ int main(int argc, char **argv)
sprintf(fname, "%s.mod.c", mod->name);
write_if_changed(&buf, fname);
}
+
+ if (write_namespace_deps) {
+ write_namespace_deps_files();
+ return 0;
+ }
+
if (dump_write)
write_dump(dump_write);
if (sec_mismatch_count && sec_mismatch_fatal)
fatal("modpost: Section mismatches detected.\n"
"Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
+ for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
+ struct symbol *s;
+
+ for (s = symbolhash[n]; s; s = s->next) {
+ /*
+ * Do not check "vmlinux". This avoids the same warnings
+ * shown twice, and false-positives for ARCH=um.
+ */
+ if (is_vmlinux(s->module->name) && !s->module->is_dot_o)
+ continue;
+
+ if (s->is_static)
+ warn("\"%s\" [%s] is a static %s\n",
+ s->name, s->module->name,
+ export_str(s->export));
+ }
+ }
+
free(buf.p);
return err;
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 8453d6ac2f77..ad271bc6c313 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -109,6 +109,11 @@ buf_printf(struct buffer *buf, const char *fmt, ...);
void
buf_write(struct buffer *buf, const char *s, int len);
+struct namespace_list {
+ struct namespace_list *next;
+ char namespace[0];
+};
+
struct module {
struct module *next;
const char *name;
@@ -121,6 +126,10 @@ struct module {
struct buffer dev_table_buf;
char srcversion[25];
int is_dot_o;
+ // Required namespace dependencies
+ struct namespace_list *required_namespaces;
+ // Actual imported namespaces
+ struct namespace_list *imported_namespaces;
};
struct elf_info {
@@ -134,6 +143,7 @@ struct elf_info {
Elf_Section export_gpl_sec;
Elf_Section export_unused_gpl_sec;
Elf_Section export_gpl_future_sec;
+ char *ksymtab_strings;
char *strtab;
char *modinfo;
unsigned int modinfo_len;
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index 0f6dcb4011a8..63062024ce0e 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -396,34 +396,19 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen)
unsigned long len;
struct md4_ctx md;
char *sources, *end, *fname;
- const char *basename;
char filelist[PATH_MAX + 1];
- char *modverdir = getenv("MODVERDIR");
- if (!modverdir)
- modverdir = ".";
-
- /* Source files for module are in .tmp_versions/modname.mod,
- after the first line. */
- if (strrchr(modname, '/'))
- basename = strrchr(modname, '/') + 1;
- else
- basename = modname;
- snprintf(filelist, sizeof(filelist), "%s/%.*s.mod", modverdir,
- (int) strlen(basename) - 2, basename);
+ /* objects for a module are listed in the first line of *.mod file. */
+ snprintf(filelist, sizeof(filelist), "%.*smod",
+ (int)strlen(modname) - 1, modname);
file = grab_file(filelist, &len);
if (!file)
/* not a module or .mod file missing - ignore */
return;
- sources = strchr(file, '\n');
- if (!sources) {
- warn("malformed versions file for %s\n", modname);
- goto release;
- }
+ sources = file;
- sources++;
end = strchr(sources, '\n');
if (!end) {
warn("bad ending versions file for %s\n", modname);