This patch adds an option to modpost to generate a <module>.ns_deps file
per module, containing the namespace dependencies for that module.

E.g. if the linked module my-module.ko would depend on the symbol
myfunc.MY_NS in the namespace MY_NS, the my-module.ns_deps file created
by modpost would contain the entry MY_NS to express the namespace
dependency of my-module imposed by using the symbol myfunc.

These files can subsequently be used by static analysis tools (like
coccinelle scripts) to address issues with missing namespace imports. A
later patch of this series will introduce such a script 'nsdeps' and a
corresponding make target to automatically add missing
MODULE_IMPORT_NS() definitions to the module's sources. For that it uses
the information provided in the generated .ns_deps files.

Co-developed-by: Martijn Coenen <m...@android.com>
Signed-off-by: Martijn Coenen <m...@android.com>
Signed-off-by: Matthias Maennich <maenn...@google.com>
---
 scripts/mod/modpost.c | 61 +++++++++++++++++++++++++++++++++++++++----
 scripts/mod/modpost.h |  2 ++
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 538bb24ffee3..833a7e1bcbb5 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,
@@ -2176,10 +2178,15 @@ static int check_exports(struct module *mod)
                else
                        basename = mod->name;
 
-               if (exp->namespace &&
-                   !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 (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)
@@ -2481,6 +2488,38 @@ 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];
+               const char *basename;
+
+               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;
+
+               basename = strrchr(mod->name, '/');
+               if (basename)
+                       basename++;
+               else
+                       basename = mod->name;
+
+               sprintf(fname, ".tmp_versions/%s.ns_deps", basename);
+               write_if_changed(&ns_deps_buf, fname);
+       }
+}
+
 struct ext_sym_list {
        struct ext_sym_list *next;
        const char *file;
@@ -2497,7 +2536,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;
@@ -2538,6 +2577,9 @@ int main(int argc, char **argv)
                case 'E':
                        sec_mismatch_fatal = 1;
                        break;
+               case 'd':
+                       write_namespace_deps = 1;
+                       break;
                default:
                        exit(1);
                }
@@ -2572,6 +2614,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);
@@ -2584,6 +2629,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)
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 9626bf3e7424..92a926d375d2 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -126,6 +126,8 @@ 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;
 };
-- 
2.23.0.rc1.153.gdeed80330f-goog

Reply via email to