From 859c81750130844590a83eff847c6c55e2340ab1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 13:56:01 -0500 Subject: modpost,fixdep: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 5c3c50c5ec52..4d4b979d76be 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -166,7 +166,7 @@ struct symbol { * (only for external modules) **/ unsigned int is_static:1; /* 1 if symbol is not global */ enum export export; /* Type of export */ - char name[0]; + char name[]; }; static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; -- cgit v1.2.3-59-g8ed1b From d2e4d05cf1a1f8bfe168ea29b217355be7a4e9ec Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 25 May 2020 14:47:04 +0900 Subject: modpost: fix potential segmentation fault for addend_i386_rel() This may not be a practical problem, but the second pass of ARCH=i386 modpost causes segmentation fault if the -s option is not passed. MODPOST 12 modules Segmentation fault (core dumped) make[2]: *** [scripts/Makefile.modpost:94: __modpost] Error 139 make[1]: *** [Makefile:1339: modules] Error 2 make[1]: *** Waiting for unfinished jobs.... The segmentation fault occurs when section_rel() is called for vmlinux, which is untested in regular builds. The cause of the problem is reloc_location() returning a wrong pointer for ET_EXEC object type. In this case, you need to subtract sechdr->sh_addr, otherwise it would get access beyond the mmap'ed memory. Add sym_get_data_by_offset() helper to avoid code duplication. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 4d4b979d76be..8c5f1bd75481 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -300,19 +300,23 @@ static const char *sec_name(struct elf_info *elf, int secindex) return sech_name(elf, &elf->sechdrs[secindex]); } -static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) +static void *sym_get_data_by_offset(const struct elf_info *info, + unsigned int secindex, unsigned long offset) { - unsigned int secindex = get_secindex(info, sym); Elf_Shdr *sechdr = &info->sechdrs[secindex]; - unsigned long offset; - offset = sym->st_value; if (info->hdr->e_type != ET_REL) offset -= sechdr->sh_addr; return (void *)info->hdr + sechdr->sh_offset + offset; } +static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) +{ + return sym_get_data_by_offset(info, get_secindex(info, sym), + sym->st_value); +} + #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) static enum export export_from_secname(struct elf_info *elf, unsigned int sec) @@ -1752,11 +1756,7 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, static unsigned int *reloc_location(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) { - Elf_Shdr *sechdrs = elf->sechdrs; - int section = sechdr->sh_info; - - return (void *)elf->hdr + sechdrs[section].sh_offset + - r->r_offset; + return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset); } static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) -- cgit v1.2.3-59-g8ed1b From 565587d8d5b518234652063820561587fc269c11 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 25 May 2020 14:47:05 +0900 Subject: modpost: refactor sech_name() Use sym_get_data_by_offset() helper to get access to the .shstrtab section data. No functional change is intended because elf->sechdrs[elf->secindex_strings].sh_addr is 0 for both ET_REL and ET_EXEC object types. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 8c5f1bd75481..160139508821 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -288,18 +288,6 @@ static enum export export_no(const char *s) return export_unknown; } -static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) -{ - return (void *)elf->hdr + - elf->sechdrs[elf->secindex_strings].sh_offset + - sechdr->sh_name; -} - -static const char *sec_name(struct elf_info *elf, int secindex) -{ - return sech_name(elf, &elf->sechdrs[secindex]); -} - static void *sym_get_data_by_offset(const struct elf_info *info, unsigned int secindex, unsigned long offset) { @@ -317,6 +305,17 @@ static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) sym->st_value); } +static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr) +{ + return sym_get_data_by_offset(info, info->secindex_strings, + sechdr->sh_name); +} + +static const char *sec_name(const struct elf_info *info, int secindex) +{ + return sech_name(info, &info->sechdrs[secindex]); +} + #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) static enum export export_from_secname(struct elf_info *elf, unsigned int sec) -- cgit v1.2.3-59-g8ed1b From 2beee868997485a5718a349c7868260d5ee7378f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:04 +0900 Subject: modpost: load KBUILD_EXTRA_SYMBOLS files in order Currently, modpost reads extra symbol dump files in the reverse order. If '-e foo -e bar' is given, modpost reads bar, foo, in this order. This is probably not a big deal, but there is no good reason to reverse the order. Read files in the given order. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 160139508821..5224a02edbf2 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2555,8 +2555,8 @@ int main(int argc, char **argv) int opt; int err; int n; - struct ext_sym_list *extsym_iter; struct ext_sym_list *extsym_start = NULL; + struct ext_sym_list **extsym_iter = &extsym_start; while ((opt = getopt(argc, argv, "i:e:mnsT:o:awENd:")) != -1) { switch (opt) { @@ -2566,11 +2566,9 @@ int main(int argc, char **argv) break; case 'e': external_module = 1; - extsym_iter = - NOFAIL(malloc(sizeof(*extsym_iter))); - extsym_iter->next = extsym_start; - extsym_iter->file = optarg; - extsym_start = extsym_iter; + *extsym_iter = NOFAIL(calloc(1, sizeof(**extsym_iter))); + (*extsym_iter)->file = optarg; + extsym_iter = &(*extsym_iter)->next; break; case 'm': modversions = 1; @@ -2610,10 +2608,12 @@ int main(int argc, char **argv) if (kernel_read) read_dump(kernel_read, 1); while (extsym_start) { + struct ext_sym_list *tmp; + read_dump(extsym_start->file, 0); - extsym_iter = extsym_start->next; + tmp = extsym_start->next; free(extsym_start); - extsym_start = extsym_iter; + extsym_start = tmp; } while (optind < argc) -- cgit v1.2.3-59-g8ed1b From 52c3416db00d970c91a6992ab6e5ff48e077ad29 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:05 +0900 Subject: modpost: track if the symbol origin is a dump file or ELF object The meaning of sym->kernel is obscure; it is set for in-kernel symbols loaded from Modules.symvers. This happens only when we are building external modules, and it is used to determine whether to dump symbols to $(KBUILD_EXTMOD)/Modules.symvers It is clearer to remember whether the symbol or module came from a dump file or ELF object. This changes the KBUILD_EXTRA_SYMBOLS behavior. Previously, symbols loaded from KBUILD_EXTRA_SYMBOLS are accumulated into the current $(KBUILD_EXTMOD)/Modules.symvers Going forward, they will be only used to check symbol references, but not dumped into the current $(KBUILD_EXTMOD)/Modules.symvers. I believe this makes more sense. sym->vmlinux will have no user. Remove it too. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 15 +++++---------- scripts/mod/modpost.h | 1 + 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 5224a02edbf2..60f35b89cea2 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -161,9 +161,6 @@ struct symbol { 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 is_static:1; /* 1 if symbol is not global */ enum export export; /* Type of export */ char name[]; @@ -398,8 +395,6 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod, } s->module = mod; - s->vmlinux = is_vmlinux(mod->name); - s->kernel = 0; s->export = export; return s; } @@ -2427,7 +2422,7 @@ static void write_if_changed(struct buffer *b, const char *fname) /* parse Module.symvers file. line format: * 0x12345678symbolmoduleexportnamespace **/ -static void read_dump(const char *fname, unsigned int kernel) +static void read_dump(const char *fname) { unsigned long size, pos = 0; void *file = grab_file(fname, &size); @@ -2465,9 +2460,9 @@ static void read_dump(const char *fname, unsigned int kernel) have_vmlinux = 1; mod = new_module(modname); mod->skip = 1; + mod->from_dump = 1; } s = sym_add_exported(symname, mod, export_no(export)); - s->kernel = kernel; s->is_static = 0; sym_set_crc(symname, crc); sym_update_namespace(symname, namespace); @@ -2487,7 +2482,7 @@ static int dump_sym(struct symbol *sym) { if (!external_module) return 1; - if (sym->vmlinux || sym->kernel) + if (sym->module->from_dump) return 0; return 1; } @@ -2606,11 +2601,11 @@ int main(int argc, char **argv) } if (kernel_read) - read_dump(kernel_read, 1); + read_dump(kernel_read); while (extsym_start) { struct ext_sym_list *tmp; - read_dump(extsym_start->file, 0); + read_dump(extsym_start->file); tmp = extsym_start->next; free(extsym_start); extsym_start = tmp; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 39f6c29fb568..933a88c733bc 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -119,6 +119,7 @@ struct module { const char *name; int gpl_compatible; struct symbol *unres; + int from_dump; /* 1 if module was loaded from *.symvers */ int seen; int skip; int has_init; -- cgit v1.2.3-59-g8ed1b From ce2ddd6d6ab3b343837d5c8e17538a5f67fa400e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:06 +0900 Subject: modpost: allow to pass -i option multiple times to remove -e option Now that there is no difference between -i and -e, they can be unified. Make modpost accept the -i option multiple times, then remove -e. I will reuse -e for a different purpose. Signed-off-by: Masahiro Yamada --- scripts/Makefile.modpost | 2 +- scripts/mod/modpost.c | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 3334f100a490..7e07adab929c 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -50,7 +50,7 @@ MODPOST = scripts/mod/modpost \ $(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ - $(if $(KBUILD_EXTMOD),$(addprefix -e ,$(KBUILD_EXTRA_SYMBOLS))) \ + $(if $(KBUILD_EXTMOD),$(addprefix -i ,$(KBUILD_EXTRA_SYMBOLS))) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ $(if $(KBUILD_MODPOST_WARN),-w) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 60f35b89cea2..28d8f5377c62 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2544,7 +2544,6 @@ int main(int argc, char **argv) { struct module *mod; struct buffer buf = { }; - char *kernel_read = NULL; char *missing_namespace_deps = NULL; char *dump_write = NULL, *files_source = NULL; int opt; @@ -2553,13 +2552,9 @@ int main(int argc, char **argv) struct ext_sym_list *extsym_start = NULL; struct ext_sym_list **extsym_iter = &extsym_start; - while ((opt = getopt(argc, argv, "i:e:mnsT:o:awENd:")) != -1) { + while ((opt = getopt(argc, argv, "i:mnsT:o:awENd:")) != -1) { switch (opt) { case 'i': - kernel_read = optarg; - external_module = 1; - break; - case 'e': external_module = 1; *extsym_iter = NOFAIL(calloc(1, sizeof(**extsym_iter))); (*extsym_iter)->file = optarg; @@ -2600,8 +2595,6 @@ int main(int argc, char **argv) } } - if (kernel_read) - read_dump(kernel_read); while (extsym_start) { struct ext_sym_list *tmp; -- cgit v1.2.3-59-g8ed1b From 7924799ed2ddaa393c2ef0c4cd13a81d122bffde Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:07 +0900 Subject: modpost: rename ext_sym_list to dump_list The -i option is used to include Modules.symver as well as files from $(KBUILD_EXTRA_SYMBOLS). Make the struct and variable names more generic. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 28d8f5377c62..b8e521f50b2d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2535,8 +2535,8 @@ static void write_namespace_deps_files(const char *fname) free(ns_deps_buf.p); } -struct ext_sym_list { - struct ext_sym_list *next; +struct dump_list { + struct dump_list *next; const char *file; }; @@ -2549,16 +2549,17 @@ int main(int argc, char **argv) int opt; int err; int n; - struct ext_sym_list *extsym_start = NULL; - struct ext_sym_list **extsym_iter = &extsym_start; + struct dump_list *dump_read_start = NULL; + struct dump_list **dump_read_iter = &dump_read_start; while ((opt = getopt(argc, argv, "i:mnsT:o:awENd:")) != -1) { switch (opt) { case 'i': external_module = 1; - *extsym_iter = NOFAIL(calloc(1, sizeof(**extsym_iter))); - (*extsym_iter)->file = optarg; - extsym_iter = &(*extsym_iter)->next; + *dump_read_iter = + NOFAIL(calloc(1, sizeof(**dump_read_iter))); + (*dump_read_iter)->file = optarg; + dump_read_iter = &(*dump_read_iter)->next; break; case 'm': modversions = 1; @@ -2595,13 +2596,13 @@ int main(int argc, char **argv) } } - while (extsym_start) { - struct ext_sym_list *tmp; + while (dump_read_start) { + struct dump_list *tmp; - read_dump(extsym_start->file); - tmp = extsym_start->next; - free(extsym_start); - extsym_start = tmp; + read_dump(dump_read_start->file); + tmp = dump_read_start->next; + free(dump_read_start); + dump_read_start = tmp; } while (optind < argc) -- cgit v1.2.3-59-g8ed1b From e3fb4df7fe4e8636de32a1e4ff5ebc75257f5570 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:08 +0900 Subject: modpost: re-add -e to set external_module flag Previously, the -i option had two functions; load a symbol dump file, and set the external_module flag. I want to assign a dedicate option for each of them. Going forward, the -i is used to load a symbol dump file, and the -e to set the external_module flag. With this, we will be able to use -i for loading in-kernel symbols. Signed-off-by: Masahiro Yamada --- scripts/Makefile.modpost | 4 ++++ scripts/mod/modpost.c | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 7e07adab929c..4d79afe997ad 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -79,6 +79,10 @@ src := $(obj) # Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile) + +# modpost option for external modules +MODPOST += -e + endif # modpost options for modules (both in-kernel and external) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b8e521f50b2d..4a2f27d97bf1 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2552,10 +2552,12 @@ int main(int argc, char **argv) struct dump_list *dump_read_start = NULL; struct dump_list **dump_read_iter = &dump_read_start; - while ((opt = getopt(argc, argv, "i:mnsT:o:awENd:")) != -1) { + while ((opt = getopt(argc, argv, "ei:mnsT:o:awENd:")) != -1) { switch (opt) { - case 'i': + case 'e': external_module = 1; + break; + case 'i': *dump_read_iter = NOFAIL(calloc(1, sizeof(**dump_read_iter))); (*dump_read_iter)->file = optarg; -- cgit v1.2.3-59-g8ed1b From 436b2ac603d58504f38041a0cd8adb5aeace992b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:12 +0900 Subject: modpost: invoke modpost only when input files are updated Currently, the second pass of modpost is always invoked when you run 'make' or 'make modules' even if none of modules is changed. Use if_changed to invoke it only when it is necessary. Signed-off-by: Masahiro Yamada --- scripts/Makefile.modpost | 20 ++++++++++++++++---- scripts/mod/modpost.c | 32 +++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 15 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 896c799911c5..f29a02196b72 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -90,7 +90,7 @@ endif # modpost options for modules (both in-kernel and external) MODPOST += \ - $(addprefix -i ,$(input-symdump)) \ + $(addprefix -i ,$(wildcard $(input-symdump))) \ $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) # 'make -i -k' ignores compile errors, and builds as many modules as possible. @@ -98,13 +98,18 @@ ifneq ($(findstring i,$(filter-out --%,$(MAKEFLAGS))),) MODPOST += -n endif +$(input-symdump): + @: + # Read out modules.order to pass in modpost. # Otherwise, allmodconfig would fail with "Argument list too long". quiet_cmd_modpost = MODPOST $@ - cmd_modpost = sed 's/ko$$/o/' $(MODORDER) | $(MODPOST) -T - + cmd_modpost = sed 's/ko$$/o/' $< | $(MODPOST) -T - -$(output-symdump): FORCE - $(call cmd,modpost) +$(output-symdump): $(MODORDER) $(input-symdump) FORCE + $(call if_changed,modpost) + +targets += $(output-symdump) __modpost: $(output-symdump) ifneq ($(KBUILD_MODPOST_NOFINAL),1) @@ -114,6 +119,13 @@ endif PHONY += FORCE FORCE: +existing-targets := $(wildcard $(sort $(targets))) + +-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) + +PHONY += FORCE +FORCE: + endif .PHONY: $(PHONY) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 4a2f27d97bf1..b839c48689df 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2375,6 +2375,25 @@ static void add_srcversion(struct buffer *b, struct module *mod) } } +static void write_buf(struct buffer *b, const char *fname) +{ + FILE *file; + + file = fopen(fname, "w"); + if (!file) { + perror(fname); + exit(1); + } + if (fwrite(b->p, 1, b->pos, file) != b->pos) { + perror(fname); + exit(1); + } + if (fclose(file) != 0) { + perror(fname); + exit(1); + } +} + static void write_if_changed(struct buffer *b, const char *fname) { char *tmp; @@ -2407,16 +2426,7 @@ static void write_if_changed(struct buffer *b, const char *fname) close_write: fclose(file); write: - file = fopen(fname, "w"); - if (!file) { - perror(fname); - exit(1); - } - if (fwrite(b->p, 1, b->pos, file) != b->pos) { - perror(fname); - exit(1); - } - fclose(file); + write_buf(b, fname); } /* parse Module.symvers file. line format: @@ -2508,7 +2518,7 @@ static void write_dump(const char *fname) symbol = symbol->next; } } - write_if_changed(&buf, fname); + write_buf(&buf, fname); free(buf.p); } -- cgit v1.2.3-59-g8ed1b From 7e8a3235823bcb779acf92de630edd5ddffaf886 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:13 +0900 Subject: modpost: show warning if vmlinux is not found when processing modules check_exports() does not print warnings about unresolved symbols if vmlinux is missing because there would be too many. This situation happens when you do 'make modules' from the clean tree, or compile external modules against a kernel tree that has not been completely built. It is dangerous to not check unresolved symbols because you might be building useless modules. At least it should be warned. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b839c48689df..3df26789c2e6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2001,8 +2001,6 @@ static void read_symbols(const char *modname) mod = new_module(modname); - /* When there's no vmlinux, don't print warnings about - * unresolved symbols (since there'll be too many ;) */ if (is_vmlinux(modname)) { have_vmlinux = 1; mod->skip = 1; @@ -2623,6 +2621,13 @@ int main(int argc, char **argv) if (files_source) read_symbols_from_files(files_source); + /* + * When there's no vmlinux, don't print warnings about + * unresolved symbols (since there'll be too many ;) + */ + if (!have_vmlinux) + warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n"); + err = 0; for (mod = modules; mod; mod = mod->next) { -- cgit v1.2.3-59-g8ed1b From f693153519607449d3e270d9e6af20b032543c05 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:15 +0900 Subject: modpost: drop RCS/CVS $Revision handling in MODULE_VERSION() As far as I understood, this code gets rid of '$Revision$' or '$Revision:' of CVS, RCS or whatever in MODULE_VERSION() tags. Remove the primeval code. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 3 --- scripts/mod/modpost.h | 4 --- scripts/mod/sumversion.c | 66 ------------------------------------------------ 3 files changed, 73 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3df26789c2e6..fbb3d3391e52 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2066,9 +2066,6 @@ static void read_symbols(const char *modname) check_sec_ref(mod, modname, &info); version = get_modinfo(&info, "version"); - if (version) - maybe_frob_rcs_version(modname, version, info.modinfo, - version - (char *)info.hdr); if (version || (all_versions && !is_vmlinux(modname))) get_src_version(modname, mod->srcversion, sizeof(mod->srcversion)-1); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 933a88c733bc..e5eace03a2b3 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -188,10 +188,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, void add_moddevtable(struct buffer *buf, struct module *mod); /* sumversion.c */ -void maybe_frob_rcs_version(const char *modfilename, - char *version, - void *modinfo, - unsigned long modinfo_offset); void get_src_version(const char *modname, char sum[], unsigned sumlen); /* from modpost.c */ diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 63062024ce0e..f27f22420cbc 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -429,69 +429,3 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen) release: release_file(file, len); } - -static void write_version(const char *filename, const char *sum, - unsigned long offset) -{ - int fd; - - fd = open(filename, O_RDWR); - if (fd < 0) { - warn("changing sum in %s failed: %s\n", - filename, strerror(errno)); - return; - } - - if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { - warn("changing sum in %s:%lu failed: %s\n", - filename, offset, strerror(errno)); - goto out; - } - - if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) { - warn("writing sum in %s failed: %s\n", - filename, strerror(errno)); - goto out; - } -out: - close(fd); -} - -static int strip_rcs_crap(char *version) -{ - unsigned int len, full_len; - - if (strncmp(version, "$Revision", strlen("$Revision")) != 0) - return 0; - - /* Space for version string follows. */ - full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2; - - /* Move string to start with version number: prefix will be - * $Revision$ or $Revision: */ - len = strlen("$Revision"); - if (version[len] == ':' || version[len] == '$') - len++; - while (isspace(version[len])) - len++; - memmove(version, version+len, full_len-len); - full_len -= len; - - /* Preserve up to next whitespace. */ - len = 0; - while (version[len] && !isspace(version[len])) - len++; - memmove(version + len, version + strlen(version), - full_len - strlen(version)); - return 1; -} - -/* Clean up RCS-style version numbers. */ -void maybe_frob_rcs_version(const char *modfilename, - char *version, - void *modinfo, - unsigned long version_offset) -{ - if (strip_rcs_crap(version)) - write_version(modfilename, version, version_offset); -} -- cgit v1.2.3-59-g8ed1b From 4ddea2f8e825a86e94011ebc32eb1dce220b2316 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:16 +0900 Subject: modpost: do not call get_modinfo() for vmlinux(.o) The three calls of get_modinfo() ("license", "import_ns", "version") always return NULL for vmlinux(.o) because the built-in module info is prefixed with __MODULE_INFO_PREFIX. It is harmless to call get_modinfo(), but there is no point to search for what apparently does not exist. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index fbb3d3391e52..a5da633af700 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2006,25 +2006,26 @@ static void read_symbols(const char *modname) mod->skip = 1; } - license = get_modinfo(&info, "license"); - if (!license && !is_vmlinux(modname)) - warn("missing MODULE_LICENSE() in %s\n" - "see include/linux/module.h for " - "more information\n", modname); - while (license) { - if (license_is_gpl_compatible(license)) - mod->gpl_compatible = 1; - else { - mod->gpl_compatible = 0; - break; + if (!is_vmlinux(modname)) { + license = get_modinfo(&info, "license"); + if (!license) + warn("missing MODULE_LICENSE() in %s\n", modname); + while (license) { + if (license_is_gpl_compatible(license)) + mod->gpl_compatible = 1; + else { + mod->gpl_compatible = 0; + break; + } + license = get_next_modinfo(&info, "license", license); } - 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); + 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++) { @@ -2065,10 +2066,12 @@ static void read_symbols(const char *modname) if (!is_vmlinux(modname) || vmlinux_section_warnings) check_sec_ref(mod, modname, &info); - version = get_modinfo(&info, "version"); - if (version || (all_versions && !is_vmlinux(modname))) - get_src_version(modname, mod->srcversion, - sizeof(mod->srcversion)-1); + if (!is_vmlinux(modname)) { + version = get_modinfo(&info, "version"); + if (version || all_versions) + get_src_version(modname, mod->srcversion, + sizeof(mod->srcversion) - 1); + } parse_elf_finish(&info); -- cgit v1.2.3-59-g8ed1b From ac5100f54329676469688d1b5415cd8d6428c909 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:17 +0900 Subject: modpost: add read_text_file() and get_line() helpers modpost uses grab_file() to open a file, but it is not suitable for a text file because the mmap'ed file is not terminated by null byte. Actually, I see some issues for the use of grab_file(). The new helper, read_text_file() loads the whole file content into a malloc'ed buffer, and appends a null byte. Then, get_line() reads each line. To handle text files, I intend to replace as follows: grab_file() -> read_text_file() get_new_line() -> get_line() Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ scripts/mod/modpost.h | 2 ++ 2 files changed, 51 insertions(+) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a5da633af700..0a844902998e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -112,6 +112,55 @@ void *do_nofail(void *ptr, const char *expr) return ptr; } +char *read_text_file(const char *filename) +{ + struct stat st; + size_t nbytes; + int fd; + char *buf; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + + if (fstat(fd, &st) < 0) { + perror(filename); + exit(1); + } + + buf = NOFAIL(malloc(st.st_size + 1)); + + nbytes = st.st_size; + + while (nbytes) { + ssize_t bytes_read; + + bytes_read = read(fd, buf, nbytes); + if (bytes_read < 0) { + perror(filename); + exit(1); + } + + nbytes -= bytes_read; + } + buf[st.st_size] = '\0'; + + close(fd); + + return buf; +} + +char *get_line(char **stringp) +{ + /* do not return the unwanted extra line at EOF */ + if (*stringp && **stringp == '\0') + return NULL; + + return strsep(stringp, "\n"); +} + /* A list of all modules we processed */ static struct module *modules; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index e5eace03a2b3..f4412febcd13 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -191,6 +191,8 @@ void add_moddevtable(struct buffer *buf, struct module *mod); void get_src_version(const char *modname, char sum[], unsigned sumlen); /* from modpost.c */ +char *read_text_file(const char *filename); +char *get_line(char **stringp); void *grab_file(const char *filename, unsigned long *size); char* get_next_line(unsigned long *pos, void *file, unsigned long size); void release_file(void *file, unsigned long size); -- cgit v1.2.3-59-g8ed1b From 70f30cfe5b892fcb7f98e7df72ed6ccfe3225628 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:20 +0900 Subject: modpost: use read_text_file() and get_line() for reading text files grab_file() mmaps a file, but it is not so efficient here because get_next_line() copies every line to the temporary buffer anyway. read_text_file() and get_line() are simpler. get_line() exploits the library function strchr(). Going forward, the missing *.symvers or *.cmd is a fatal error. This should not happen because scripts/Makefile.modpost guards the -i option files with $(wildcard $(input-symdump)). Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 15 ++++++++------- scripts/mod/sumversion.c | 16 ++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 0a844902998e..4fdf992e9729 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2481,15 +2481,16 @@ static void write_if_changed(struct buffer *b, const char *fname) **/ static void read_dump(const char *fname) { - unsigned long size, pos = 0; - void *file = grab_file(fname, &size); - char *line; + char *buf, *pos, *line; - if (!file) + buf = read_text_file(fname); + if (!buf) /* No symbol versions, silently ignore */ return; - while ((line = get_next_line(&pos, file, size))) { + pos = buf; + + while ((line = get_line(&pos))) { char *symname, *namespace, *modname, *d, *export; unsigned int crc; struct module *mod; @@ -2524,10 +2525,10 @@ static void read_dump(const char *fname) sym_set_crc(symname, crc); sym_update_namespace(symname, namespace); } - release_file(file, size); + free(buf); return; fail: - release_file(file, size); + free(buf); fatal("parse error in symbol dump file\n"); } diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 9f77c9dfce20..d587f40f1117 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -303,9 +303,8 @@ static int is_static_library(const char *objfile) * to figure out source files. */ static int parse_source_files(const char *objfile, struct md4_ctx *md) { - char *cmd, *file, *line, *dir; + char *cmd, *file, *line, *dir, *pos; const char *base; - unsigned long flen, pos = 0; int dirlen, ret = 0, check_files = 0; cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd"))); @@ -323,14 +322,12 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) strncpy(dir, objfile, dirlen); dir[dirlen] = '\0'; - file = grab_file(cmd, &flen); - if (!file) { - warn("could not find %s for %s\n", cmd, objfile); - goto out; - } + file = read_text_file(cmd); + + pos = file; /* Sum all files in the same dir or subdirs. */ - while ((line = get_next_line(&pos, file, flen)) != NULL) { + while ((line = get_line(&pos))) { char* p = line; if (strncmp(line, "source_", sizeof("source_")-1) == 0) { @@ -381,8 +378,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) /* Everyone parsed OK */ ret = 1; out_file: - release_file(file, flen); -out: + free(file); free(dir); free(cmd); return ret; -- cgit v1.2.3-59-g8ed1b From 75893572d45399cefbb88443d0878adae9cb0b41 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:21 +0900 Subject: modpost: remove get_next_text() and make {grab,release_}file static get_next_line() is no longer used. Remove. grab_file() and release_file() are only used in modpost.c. Make them static. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 38 ++------------------------------------ scripts/mod/modpost.h | 3 --- 2 files changed, 2 insertions(+), 39 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 4fdf992e9729..93019349f022 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -463,7 +463,7 @@ static void sym_set_crc(const char *name, unsigned int crc) s->crc_valid = 1; } -void *grab_file(const char *filename, unsigned long *size) +static void *grab_file(const char *filename, unsigned long *size) { struct stat st; void *map = MAP_FAILED; @@ -485,41 +485,7 @@ failed: return map; } -/** - * Return a copy of the next line in a mmap'ed file. - * spaces in the beginning of the line is trimmed away. - * Return a pointer to a static buffer. - **/ -char *get_next_line(unsigned long *pos, void *file, unsigned long size) -{ - static char line[4096]; - int skip = 1; - size_t len = 0; - signed char *p = (signed char *)file + *pos; - char *s = line; - - for (; *pos < size ; (*pos)++) { - if (skip && isspace(*p)) { - p++; - continue; - } - skip = 0; - if (*p != '\n' && (*pos < size)) { - len++; - *s++ = *p++; - if (len > 4095) - break; /* Too long, stop */ - } else { - /* End of string */ - *s = '\0'; - return line; - } - } - /* End of buffer */ - return NULL; -} - -void release_file(void *file, unsigned long size) +static void release_file(void *file, unsigned long size) { munmap(file, size); } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index f4412febcd13..bc524506d2f9 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -193,9 +193,6 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen); /* from modpost.c */ char *read_text_file(const char *filename); char *get_line(char **stringp); -void *grab_file(const char *filename, unsigned long *size); -char* get_next_line(unsigned long *pos, void *file, unsigned long size); -void release_file(void *file, unsigned long size); enum loglevel { LOG_WARN, -- cgit v1.2.3-59-g8ed1b From 467b82d7cee4373aa7bc47fd3043e2fa0a3440f5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:22 +0900 Subject: modpost: remove -s option The -s option was added by commit 8d8d8289df65 ("kbuild: do not do section mismatch checks on vmlinux in 2nd pass"). Now that the second pass does not parse vmlinux, this option is unneeded. Signed-off-by: Masahiro Yamada --- scripts/Makefile.modpost | 2 +- scripts/mod/modpost.c | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index e47f87557f09..4938a6f368c0 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -62,7 +62,7 @@ __modpost: vmlinux.symvers else -MODPOST += -s \ +MODPOST += \ $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) ifeq ($(KBUILD_EXTMOD),) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 93019349f022..b667f531a645 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -30,8 +30,6 @@ static int have_vmlinux = 0; static int all_versions = 0; /* If we are modposting external module set to 1 */ static int external_module = 0; -/* Warn about section mismatch in vmlinux if set to 1 */ -static int vmlinux_section_warnings = 1; /* Only warn about unresolved symbols */ static int warn_unresolved = 0; /* How a symbol is exported */ @@ -2078,8 +2076,7 @@ static void read_symbols(const char *modname) } } - if (!is_vmlinux(modname) || vmlinux_section_warnings) - check_sec_ref(mod, modname, &info); + check_sec_ref(mod, modname, &info); if (!is_vmlinux(modname)) { version = get_modinfo(&info, "version"); @@ -2576,7 +2573,7 @@ int main(int argc, char **argv) struct dump_list *dump_read_start = NULL; struct dump_list **dump_read_iter = &dump_read_start; - while ((opt = getopt(argc, argv, "ei:mnsT:o:awENd:")) != -1) { + while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { switch (opt) { case 'e': external_module = 1; @@ -2599,9 +2596,6 @@ int main(int argc, char **argv) case 'a': all_versions = 1; break; - case 's': - vmlinux_section_warnings = 0; - break; case 'T': files_source = optarg; break; -- cgit v1.2.3-59-g8ed1b From 3379576dd6e708f66498d49b4cec5f9b198791a0 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:24 +0900 Subject: modpost: remove mod->is_dot_o struct member Previously, there were two cases where mod->is_dot_o is unset: [1] the executable 'vmlinux' in the second pass of modpost [2] modules loaded by read_dump() I think [1] was intended usage to distinguish 'vmlinux.o' and 'vmlinux'. Now that modpost does not parse the executable 'vmlinux', this case does not happen. [2] is obscure, maybe a bug. Module.symver stores module paths without extension. So, none of modules loaded by read_dump() has the .o suffix, and new_module() unsets ->is_dot_o. Anyway, it is not a big deal because handle_symbol() is not called for the case. To sum up, all the parsed ELF files are .o files. mod->is_dot_o is unneeded. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 14 ++------------ scripts/mod/modpost.h | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b667f531a645..bc00bbac50bb 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -182,10 +182,8 @@ static struct module *new_module(const char *modname) p = NOFAIL(strdup(modname)); /* strip trailing .o */ - if (strends(p, ".o")) { + if (strends(p, ".o")) p[strlen(p) - 2] = '\0'; - mod->is_dot_o = 1; - } /* add to list */ mod->name = p; @@ -716,8 +714,7 @@ static void handle_symbol(struct module *mod, struct elf_info *info, enum export export; const char *name; - if ((!is_vmlinux(mod->name) || mod->is_dot_o) && - strstarts(symname, "__ksymtab")) + if (strstarts(symname, "__ksymtab")) export = export_from_secname(info, get_secindex(info, sym)); else export = export_from_sec(info, get_secindex(info, sym)); @@ -2676,13 +2673,6 @@ int main(int argc, char **argv) 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, diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index bc524506d2f9..68d813abf33d 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -126,7 +126,6 @@ struct module { int has_cleanup; struct buffer dev_table_buf; char srcversion[25]; - int is_dot_o; // Missing namespace dependencies struct namespace_list *missing_namespaces; // Actual imported namespaces -- cgit v1.2.3-59-g8ed1b From 1be5fa6c948533bb95ac783010ef686261be5384 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:25 +0900 Subject: modpost: remove is_vmlinux() call in check_for_{gpl_usage,unused}() check_exports() is never called for vmlinux because mod->skip is set for vmlinux. Hence, check_for_gpl_usage() and check_for_unused() are not called for vmlinux, either. is_vmlinux() is always false here. Remove the is_vmlinux() calls, and hard-code the ".ko" suffix. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index bc00bbac50bb..84a642c14775 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2144,20 +2144,18 @@ void buf_write(struct buffer *buf, const char *s, int len) static void check_for_gpl_usage(enum export exp, const char *m, const char *s) { - const char *e = is_vmlinux(m) ?"":".ko"; - switch (exp) { case export_gpl: - fatal("GPL-incompatible module %s%s " - "uses GPL-only symbol '%s'\n", m, e, s); + fatal("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", + m, s); break; case export_unused_gpl: - fatal("GPL-incompatible module %s%s " - "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); + fatal("GPL-incompatible module %s.ko uses GPL-only symbol marked UNUSED '%s'\n", + m, s); break; case export_gpl_future: - warn("GPL-incompatible module %s%s " - "uses future GPL-only symbol '%s'\n", m, e, s); + warn("GPL-incompatible module %s.ko uses future GPL-only symbol '%s'\n", + m, s); break; case export_plain: case export_unused: @@ -2169,13 +2167,11 @@ static void check_for_gpl_usage(enum export exp, const char *m, const char *s) static void check_for_unused(enum export exp, const char *m, const char *s) { - const char *e = is_vmlinux(m) ?"":".ko"; - switch (exp) { case export_unused: case export_unused_gpl: - warn("module %s%s " - "uses symbol '%s' marked UNUSED\n", m, e, s); + warn("module %s.ko uses symbol '%s' marked UNUSED\n", + m, s); break; default: /* ignore */ -- cgit v1.2.3-59-g8ed1b From 5a438af9db2c4a0b80d51d8c1c9c623b0c0de967 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:26 +0900 Subject: modpost: add mod->is_vmlinux struct member is_vmlinux() is called in several places to check whether the current module is vmlinux or not. It is faster and clearer to check mod->is_vmlinux flag. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 19 ++++++++++--------- scripts/mod/modpost.h | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 84a642c14775..167700a7b80f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -187,6 +187,7 @@ static struct module *new_module(const char *modname) /* add to list */ mod->name = p; + mod->is_vmlinux = is_vmlinux(modname); mod->gpl_compatible = -1; mod->next = modules; modules = mod; @@ -431,11 +432,11 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod, if (!s) { s = new_symbol(name, mod, export); - } else if (!external_module || is_vmlinux(s->module->name) || + } else if (!external_module || s->module->is_vmlinux || s->module == mod) { warn("%s: '%s' exported twice. Previous export was in %s%s\n", mod->name, name, s->module->name, - is_vmlinux(s->module->name) ? "" : ".ko"); + s->module->is_vmlinux ? "" : ".ko"); return s; } @@ -692,7 +693,7 @@ static void handle_modversion(const struct module *mod, if (sym->st_shndx == SHN_UNDEF) { warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", - symname, mod->name, is_vmlinux(mod->name) ? "":".ko"); + symname, mod->name, mod->is_vmlinux ? "" : ".ko"); return; } @@ -2011,12 +2012,12 @@ static void read_symbols(const char *modname) mod = new_module(modname); - if (is_vmlinux(modname)) { + if (mod->is_vmlinux) { have_vmlinux = 1; mod->skip = 1; } - if (!is_vmlinux(modname)) { + if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); if (!license) warn("missing MODULE_LICENSE() in %s\n", modname); @@ -2075,7 +2076,7 @@ static void read_symbols(const char *modname) check_sec_ref(mod, modname, &info); - if (!is_vmlinux(modname)) { + if (!mod->is_vmlinux) { version = get_modinfo(&info, "version"); if (version || all_versions) get_src_version(modname, mod->srcversion, @@ -2345,7 +2346,7 @@ static void add_depends(struct buffer *b, struct module *mod) /* Clear ->seen flag of modules that own symbols needed by this. */ for (s = mod->unres; s; s = s->next) if (s->module) - s->module->seen = is_vmlinux(s->module->name); + s->module->seen = s->module->is_vmlinux; buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(depends, \""); @@ -2470,9 +2471,9 @@ static void read_dump(const char *fname) goto fail; mod = find_module(modname); if (!mod) { - if (is_vmlinux(modname)) - have_vmlinux = 1; mod = new_module(modname); + if (mod->is_vmlinux) + have_vmlinux = 1; mod->skip = 1; mod->from_dump = 1; } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 68d813abf33d..87251729539e 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -120,6 +120,7 @@ struct module { int gpl_compatible; struct symbol *unres; int from_dump; /* 1 if module was loaded from *.symvers */ + int is_vmlinux; int seen; int skip; int has_init; -- cgit v1.2.3-59-g8ed1b From 0b19d54cae11bd5b9e208f52e42d88ad33a3b1d9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:27 +0900 Subject: modpost: remove mod->skip struct member The meaning of 'skip' is obscure since it does not explain "what to skip". mod->skip is set when it is vmlinux or the module info came from a dump file. So, mod->skip is equivalent to (mod->is_vmlinux || mod->from_dump). For the check in write_namespace_deps_files(), mod->is_vmlinux is unneeded because the -d option is not passed in the first pass of modpost. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 9 +++------ scripts/mod/modpost.h | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 167700a7b80f..925c1a1856aa 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2012,10 +2012,8 @@ static void read_symbols(const char *modname) mod = new_module(modname); - if (mod->is_vmlinux) { + if (mod->is_vmlinux) have_vmlinux = 1; - mod->skip = 1; - } if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); @@ -2474,7 +2472,6 @@ static void read_dump(const char *fname) mod = new_module(modname); if (mod->is_vmlinux) have_vmlinux = 1; - mod->skip = 1; mod->from_dump = 1; } s = sym_add_exported(symname, mod, export_no(export)); @@ -2535,7 +2532,7 @@ static void write_namespace_deps_files(const char *fname) for (mod = modules; mod; mod = mod->next) { - if (mod->skip || !mod->missing_namespaces) + if (mod->from_dump || !mod->missing_namespaces) continue; buf_printf(&ns_deps_buf, "%s.ko:", mod->name); @@ -2637,7 +2634,7 @@ int main(int argc, char **argv) for (mod = modules; mod; mod = mod->next) { char fname[PATH_MAX]; - if (mod->skip) + if (mod->is_vmlinux || mod->from_dump) continue; buf.pos = 0; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 87251729539e..3dc9e8fa5d1f 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -122,7 +122,6 @@ struct module { int from_dump; /* 1 if module was loaded from *.symvers */ int is_vmlinux; int seen; - int skip; int has_init; int has_cleanup; struct buffer dev_table_buf; -- cgit v1.2.3-59-g8ed1b From 858b937d289bbf7551d496100c1fa9efcad5796e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:28 +0900 Subject: modpost: set have_vmlinux in new_module() Set have_vmlinux flag in a single place. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 925c1a1856aa..b317328ae21b 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -192,6 +192,9 @@ static struct module *new_module(const char *modname) mod->next = modules; modules = mod; + if (mod->is_vmlinux) + have_vmlinux = 1; + return mod; } @@ -2012,9 +2015,6 @@ static void read_symbols(const char *modname) mod = new_module(modname); - if (mod->is_vmlinux) - have_vmlinux = 1; - if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); if (!license) @@ -2470,8 +2470,6 @@ static void read_dump(const char *fname) mod = find_module(modname); if (!mod) { mod = new_module(modname); - if (mod->is_vmlinux) - have_vmlinux = 1; mod->from_dump = 1; } s = sym_add_exported(symname, mod, export_no(export)); -- cgit v1.2.3-59-g8ed1b From a82f794c41ab51f088af325f5d9acba30a6facdb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:29 +0900 Subject: modpost: strip .o from modname before calling new_module() new_module() conditionally strips the .o because the modname has .o suffix when it is called from read_symbols(), but no .o when it is called from read_dump(). It is clearer to strip .o in read_symbols(). I also used flexible-array for mod->name. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 20 +++++++++++--------- scripts/mod/modpost.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b317328ae21b..ebfa9b76ba92 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -175,18 +175,12 @@ static struct module *find_module(const char *modname) static struct module *new_module(const char *modname) { struct module *mod; - char *p; - mod = NOFAIL(malloc(sizeof(*mod))); + mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1)); memset(mod, 0, sizeof(*mod)); - p = NOFAIL(strdup(modname)); - - /* strip trailing .o */ - if (strends(p, ".o")) - p[strlen(p) - 2] = '\0'; /* add to list */ - mod->name = p; + strcpy(mod->name, modname); mod->is_vmlinux = is_vmlinux(modname); mod->gpl_compatible = -1; mod->next = modules; @@ -2013,7 +2007,15 @@ static void read_symbols(const char *modname) if (!parse_elf(&info, modname)) return; - mod = new_module(modname); + { + char *tmp; + + /* strip trailing .o */ + tmp = NOFAIL(strdup(modname)); + tmp[strlen(tmp) - 2] = '\0'; + mod = new_module(tmp); + free(tmp); + } if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 3dc9e8fa5d1f..254c75378583 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -116,7 +116,6 @@ struct namespace_list { struct module { struct module *next; - const char *name; int gpl_compatible; struct symbol *unres; int from_dump; /* 1 if module was loaded from *.symvers */ @@ -130,6 +129,7 @@ struct module { struct namespace_list *missing_namespaces; // Actual imported namespaces struct namespace_list *imported_namespaces; + char name[]; }; struct elf_info { -- cgit v1.2.3-59-g8ed1b From 4de7b62936122570408357417f21072e78292926 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:30 +0900 Subject: modpost: remove is_vmlinux() helper Now that is_vmlinux() is called only in new_module(), we can inline the function call. modname is the basename with '.o' is stripped. No need to compare it with 'vmlinux.o'. vmlinux is always located at the current working directory. No need to strip the directory path. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ebfa9b76ba92..a3ffabf4eca5 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -88,20 +88,6 @@ static inline bool strends(const char *str, const char *postfix) return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; } -static int is_vmlinux(const char *modname) -{ - const char *myname; - - myname = strrchr(modname, '/'); - if (myname) - myname++; - else - myname = modname; - - return (strcmp(myname, "vmlinux") == 0) || - (strcmp(myname, "vmlinux.o") == 0); -} - void *do_nofail(void *ptr, const char *expr) { if (!ptr) @@ -181,7 +167,7 @@ static struct module *new_module(const char *modname) /* add to list */ strcpy(mod->name, modname); - mod->is_vmlinux = is_vmlinux(modname); + mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0); mod->gpl_compatible = -1; mod->next = modules; modules = mod; -- cgit v1.2.3-59-g8ed1b From 3b09efc4f0c94669a928c0453d2dcb54c59543f2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 1 Jun 2020 14:57:31 +0900 Subject: modpost: change elf_info->size to size_t Align with the mmap / munmap APIs. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 9 ++++----- scripts/mod/modpost.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'scripts/mod/modpost.c') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a3ffabf4eca5..e5cee2367d5e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -443,7 +443,7 @@ static void sym_set_crc(const char *name, unsigned int crc) s->crc_valid = 1; } -static void *grab_file(const char *filename, unsigned long *size) +static void *grab_file(const char *filename, size_t *size) { struct stat st; void *map = MAP_FAILED; @@ -465,7 +465,7 @@ failed: return map; } -static void release_file(void *file, unsigned long size) +static void release_file(void *file, size_t size) { munmap(file, size); } @@ -521,9 +521,8 @@ static int parse_elf(struct elf_info *info, const char *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=%lu\n", (unsigned long)hdr->e_shoff, - filename, info->size); + fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", + (unsigned long)hdr->e_shoff, filename, info->size); return 0; } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 254c75378583..3aa052722233 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -133,7 +133,7 @@ struct module { }; struct elf_info { - unsigned long size; + size_t size; Elf_Ehdr *hdr; Elf_Shdr *sechdrs; Elf_Sym *symtab_start; -- cgit v1.2.3-59-g8ed1b