Merge tag 'modules-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu...
[linux-2.6-block.git] / scripts / mod / modpost.c
index 820eed87fb43bf443a7e3ef801b384600c93793d..3961941e8e7a9c95062bde8983c88efd001dba6d 100644 (file)
@@ -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,6 +166,7 @@ struct symbol {
        struct module *module;
        unsigned int crc;
        int crc_valid;
+       const 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
@@ -235,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;
@@ -314,23 +348,39 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
                return export_unknown;
 }
 
+static const char *sym_extract_namespace(const char **symname)
+{
+       size_t n;
+       char *dupsymname;
+
+       n = strcspn(*symname, ".");
+       if (n < strlen(*symname) - 1) {
+               dupsymname = NOFAIL(strdup(*symname));
+               dupsymname[n] = '\0';
+               *symname = dupsymname;
+               return dupsymname + n + 1;
+       }
+
+       return NULL;
+}
+
 /**
  * Add an exported symbol - it may have already been added without a
  * CRC, in this case just update the CRC
  **/
-static struct symbol *sym_add_exported(const char *name, struct module *mod,
-                                      enum export export)
+static struct symbol *sym_add_exported(const char *name, const char *namespace,
+                                      struct module *mod, enum export export)
 {
        struct symbol *s = find_symbol(name);
 
        if (!s) {
                s = new_symbol(name, mod, export);
+               s->namespace = namespace;
        } 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;
@@ -622,6 +672,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, *namespace;
 
        if ((!is_vmlinux(mod->name) || mod->is_dot_o) &&
            strstarts(symname, "__ksymtab"))
@@ -693,8 +744,9 @@ 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_");
+                       namespace = sym_extract_namespace(&name);
+                       sym_add_exported(name, namespace, mod, export);
                }
                if (strcmp(symname, "init_module") == 0)
                        mod->has_init = 1;
@@ -1945,6 +1997,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;
@@ -1976,6 +2029,12 @@ 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);
 
@@ -2135,6 +2194,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);
@@ -2354,7 +2425,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;
@@ -2362,7 +2433,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)
@@ -2379,7 +2453,8 @@ static void read_dump(const char *fname, unsigned int kernel)
                        mod = new_module(modname);
                        mod->skip = 1;
                }
-               s = sym_add_exported(symname, mod, export_no(export));
+               s = sym_add_exported(symname, namespace, mod,
+                                    export_no(export));
                s->kernel    = kernel;
                s->preloaded = 1;
                s->is_static = 0;
@@ -2409,16 +2484,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;
                }
        }
@@ -2426,6 +2505,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;
@@ -2443,7 +2547,7 @@ int main(int argc, char **argv)
        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;
@@ -2484,6 +2588,9 @@ int main(int argc, char **argv)
                case 'E':
                        sec_mismatch_fatal = 1;
                        break;
+               case 'd':
+                       write_namespace_deps = 1;
+                       break;
                default:
                        exit(1);
                }
@@ -2518,6 +2625,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);
@@ -2530,6 +2640,12 @@ 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)