modpost: add support for generating namespace dependencies

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 <maco@android.com>
Signed-off-by: Martijn Coenen <maco@android.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Matthias Maennich <maennich@google.com>
Signed-off-by: Jessica Yu <jeyu@kernel.org>
This commit is contained in:
Matthias Maennich 2019-09-06 11:32:31 +01:00 committed by Jessica Yu
parent 8e2adc6a00
commit 1d082773ff
4 changed files with 53 additions and 6 deletions

1
.gitignore vendored
View File

@ -32,6 +32,7 @@
*.lzo *.lzo
*.mod *.mod
*.mod.c *.mod.c
*.ns_deps
*.o *.o
*.o.* *.o.*
*.order *.order

View File

@ -1669,7 +1669,7 @@ clean: $(clean-dirs)
-o -name '*.ko.*' \ -o -name '*.ko.*' \
-o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \ -o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
-o -name '*.dwo' -o -name '*.lst' \ -o -name '*.dwo' -o -name '*.lst' \
-o -name '*.su' -o -name '*.mod' \ -o -name '*.su' -o -name '*.mod' -o -name '*.ns_deps' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.lex.c' -o -name '*.tab.[ch]' \ -o -name '*.lex.c' -o -name '*.tab.[ch]' \
-o -name '*.asn1.[ch]' \ -o -name '*.asn1.[ch]' \

View File

@ -38,6 +38,8 @@ static int sec_mismatch_count = 0;
static int sec_mismatch_fatal = 0; static int sec_mismatch_fatal = 0;
/* ignore missing files */ /* ignore missing files */
static int ignore_missing_files; static int ignore_missing_files;
/* write namespace dependencies */
static int write_namespace_deps;
enum export { enum export {
export_plain, export_unused, export_gpl, export_plain, export_unused, export_gpl,
@ -2176,10 +2178,15 @@ static int check_exports(struct module *mod)
else else
basename = mod->name; basename = mod->name;
if (exp->namespace && if (exp->namespace) {
!module_imports_namespace(mod, exp->namespace)) { add_namespace(&mod->required_namespaces,
warn("module %s uses symbol %s from namespace %s, but does not import it.\n", exp->namespace);
basename, exp->name, 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) if (!mod->gpl_compatible)
@ -2484,6 +2491,31 @@ static void write_dump(const char *fname)
free(buf.p); 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 {
struct ext_sym_list *next; struct ext_sym_list *next;
const char *file; const char *file;
@ -2500,7 +2532,7 @@ int main(int argc, char **argv)
struct ext_sym_list *extsym_iter; struct ext_sym_list *extsym_iter;
struct ext_sym_list *extsym_start = NULL; 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) { switch (opt) {
case 'i': case 'i':
kernel_read = optarg; kernel_read = optarg;
@ -2541,6 +2573,9 @@ int main(int argc, char **argv)
case 'E': case 'E':
sec_mismatch_fatal = 1; sec_mismatch_fatal = 1;
break; break;
case 'd':
write_namespace_deps = 1;
break;
default: default:
exit(1); exit(1);
} }
@ -2575,6 +2610,9 @@ int main(int argc, char **argv)
err |= check_modname_len(mod); err |= check_modname_len(mod);
err |= check_exports(mod); err |= check_exports(mod);
if (write_namespace_deps)
continue;
add_header(&buf, mod); add_header(&buf, mod);
add_intree_flag(&buf, !external_module); add_intree_flag(&buf, !external_module);
add_retpoline(&buf); add_retpoline(&buf);
@ -2587,6 +2625,12 @@ int main(int argc, char **argv)
sprintf(fname, "%s.mod.c", mod->name); sprintf(fname, "%s.mod.c", mod->name);
write_if_changed(&buf, fname); write_if_changed(&buf, fname);
} }
if (write_namespace_deps) {
write_namespace_deps_files();
return 0;
}
if (dump_write) if (dump_write)
write_dump(dump_write); write_dump(dump_write);
if (sec_mismatch_count && sec_mismatch_fatal) if (sec_mismatch_count && sec_mismatch_fatal)

View File

@ -126,6 +126,8 @@ struct module {
struct buffer dev_table_buf; struct buffer dev_table_buf;
char srcversion[25]; char srcversion[25];
int is_dot_o; int is_dot_o;
// Required namespace dependencies
struct namespace_list *required_namespaces;
// Actual imported namespaces // Actual imported namespaces
struct namespace_list *imported_namespaces; struct namespace_list *imported_namespaces;
}; };