diff options
Diffstat (limited to 'scripts')
38 files changed, 1204 insertions, 658 deletions
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 8a5c4d645eb1..d4adfbe42690 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -25,7 +25,7 @@ failure = $(if-success,$(1),n,y) # $(cc-option,<flag>) # Return y if the compiler supports <flag>, n otherwise -cc-option = $(success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null) +cc-option = $(success,$(CC) -Werror $(CLANG_FLAGS) $(1) -E -x c /dev/null -o /dev/null) # $(ld-option,<flag>) # Return y if the linker supports <flag>, n otherwise @@ -35,5 +35,8 @@ ld-option = $(success,$(LD) -v $(1)) $(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found) $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) +# Fail if the linker is gold as it's not capable of linking the kernel proper +$(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supported) + # gcc version including patch level gcc-version := $(shell,$(srctree)/scripts/gcc-version.sh $(CC)) diff --git a/scripts/Makefile b/scripts/Makefile index 532f7e0915c3..3e86b300f5a1 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -36,4 +36,4 @@ subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-$(CONFIG_SECURITY_SELINUX) += selinux # Let clean descend into subdirs -subdir- += basic dtc gdb kconfig mod package +subdir- += basic dtc gdb kconfig mod diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 0d434d0afc0b..f72aba64d611 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -52,6 +52,13 @@ ifndef obj $(warning kbuild: Makefile.build is included improperly) endif +ifeq ($(need-modorder),) +ifneq ($(obj-m),) +$(warning $(patsubst %.o,'%.ko',$(obj-m)) will not be built even though obj-m is specified.) +$(warning You cannot use subdir-y/m to visit a module Makefile. Use obj-y/m instead.) +endif +endif + # =========================================================================== ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),) @@ -69,11 +76,6 @@ endif mod-targets := $(patsubst %.o, %.mod, $(obj-m)) -__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ - $(if $(KBUILD_MODULES),$(obj-m) $(mod-targets) $(modorder-target)) \ - $(subdir-ym) $(always) - @: - # Linus' kernel sanity checking tool ifeq ($(KBUILD_CHECKSRC),1) quiet_cmd_checksrc = CHECK $< @@ -83,23 +85,13 @@ else ifeq ($(KBUILD_CHECKSRC),2) cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< endif -ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) +ifneq ($(KBUILD_EXTRA_WARN),) cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $< endif # Compile C sources (.c) # --------------------------------------------------------------------------- -# Default is built-in, unless we know otherwise -$(foreach x, i ll lst o s symtypes, $(patsubst %.o,%.$(x),$(real-obj-m))): \ - part-of-module := y - -modkern_cflags = \ - $(if $(part-of-module), \ - $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ - $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL)) -quiet_modtag = $(if $(part-of-module),[M], ) - quiet_cmd_cc_s_c = CC $(quiet_modtag) $@ cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS), $(c_flags)) $(DISABLE_LTO) -fverbose-asm -S -o $@ $< @@ -303,11 +295,6 @@ $(obj)/%.h.s: $(src)/%.h FORCE # Compile assembler sources (.S) # --------------------------------------------------------------------------- -modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL) - -$(real-obj-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) -$(real-obj-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) - # .S file exports must have their C prototypes defined in asm/asm-prototypes.h # or a file that it includes, in order to get versioned symbols. We build a # dummy C file that includes asm-prototypes and the EXPORT_SYMBOL lines from @@ -349,11 +336,7 @@ $(obj)/%.s: $(src)/%.S FORCE quiet_cmd_as_o_S = AS $(quiet_modtag) $@ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< -ifdef CONFIG_MODVERSIONS - -ASM_PROTOTYPES := $(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/asm-prototypes.h) - -ifneq ($(ASM_PROTOTYPES),) +ifdef CONFIG_ASM_MODVERSIONS # versioning matches the C process described above, with difference that # we parse asm-prototypes.h C header to get function definitions. @@ -369,7 +352,6 @@ cmd_modversions_S = \ rm -f $(@D)/.tmp_$(@F:.o=.ver); \ fi endif -endif $(obj)/%.o: $(src)/%.S $(objtool_dep) FORCE $(call if_changed_rule,as_o_S) @@ -388,9 +370,9 @@ $(obj)/%.lds: $(src)/%.lds.S FORCE # ASN.1 grammar # --------------------------------------------------------------------------- -quiet_cmd_asn1_compiler = ASN.1 $@ +quiet_cmd_asn1_compiler = ASN.1 $(basename $@).[ch] cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ - $(subst .h,.c,$@) $(subst .c,.h,$@) + $(basename $@).c $(basename $@).h $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler $(call cmd,asn1_compiler) @@ -482,12 +464,52 @@ targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \ $(call intermediate_targets, .lex.o, .lex.c) \ $(call intermediate_targets, .tab.o, .tab.c .tab.h) +# Build +# --------------------------------------------------------------------------- + +ifdef single-build + +curdir-single := $(sort $(foreach x, $(KBUILD_SINGLE_TARGETS), \ + $(if $(filter $(x) $(basename $(x)).o, $(targets)), $(x)))) + +# Handle single targets without any rule: show "Nothing to be done for ..." or +# "No rule to make target ..." depending on whether the target exists. +unknown-single := $(filter-out $(addsuffix /%, $(subdir-ym)), \ + $(filter $(obj)/%, \ + $(filter-out $(curdir-single), \ + $(KBUILD_SINGLE_TARGETS)))) + +__build: $(curdir-single) $(subdir-ym) +ifneq ($(unknown-single),) + $(Q)$(MAKE) -f /dev/null $(unknown-single) +endif + @: + +ifeq ($(curdir-single),) +# Nothing to do in this directory. Do not include any .*.cmd file for speed-up +targets := +else +targets += $(curdir-single) +endif + +else + +__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ + $(if $(KBUILD_MODULES),$(obj-m) $(mod-targets) $(modorder-target)) \ + $(subdir-ym) $(always) + @: + +endif + # Descending # --------------------------------------------------------------------------- PHONY += $(subdir-ym) $(subdir-ym): - $(Q)$(MAKE) $(build)=$@ need-builtin=$(if $(findstring $@,$(subdir-obj-y)),1) + $(Q)$(MAKE) $(build)=$@ \ + $(if $(filter $@/, $(KBUILD_SINGLE_TARGETS)),single-build=) \ + need-builtin=$(if $(filter $@/built-in.a, $(subdir-obj-y)),1) \ + need-modorder=$(if $(need-modorder),$(if $(filter $@/modules.order, $(modorder)),1)) # Add FORCE to the prequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index 0b80e3207b20..e367eb95c5c0 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -17,17 +17,8 @@ include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-di # Figure out what we need to build from the various variables # ========================================================================== -__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) -subdir-y += $(__subdir-y) -__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m))) -subdir-m += $(__subdir-m) -__subdir- := $(patsubst %/,%,$(filter %/, $(obj-))) -subdir- += $(__subdir-) - -# Subdirectories we need to descend into - -subdir-ym := $(sort $(subdir-y) $(subdir-m)) -subdir-ymn := $(sort $(subdir-ym) $(subdir-)) +subdir-ymn := $(sort $(subdir-y) $(subdir-m) $(subdir-) \ + $(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m) $(obj-)))) # Add subdir path @@ -52,26 +43,14 @@ __clean-files := $(wildcard \ $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \ $(filter $(objtree)/%, $(__clean-files))) -# same as clean-files - -__clean-dirs := $(wildcard \ - $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(clean-dirs))) \ - $(filter $(objtree)/%, $(clean-dirs))) - # ========================================================================== -quiet_cmd_clean = CLEAN $(obj) - cmd_clean = rm -f $(__clean-files) -quiet_cmd_cleandir = CLEAN $(__clean-dirs) - cmd_cleandir = rm -rf $(__clean-dirs) - +quiet_cmd_clean = CLEAN $(obj) + cmd_clean = rm -rf $(__clean-files) __clean: $(subdir-ymn) ifneq ($(strip $(__clean-files)),) - +$(call cmd,clean) -endif -ifneq ($(strip $(__clean-dirs)),) - +$(call cmd,cleandir) + $(call cmd,clean) endif @: diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index a74ce2e3c33e..ecddf83ac142 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -1,74 +1,91 @@ # SPDX-License-Identifier: GPL-2.0 # ========================================================================== -# # make W=... settings # -# W=1 - warnings that may be relevant and does not occur too often -# W=2 - warnings that occur quite often but may still be relevant -# W=3 - the more obscure warnings, can most likely be ignored -# -# $(call cc-option, -W...) handles gcc -W.. options which -# are not supported by all versions of the compiler +# There are three warning groups enabled by W=1, W=2, W=3. +# They are independent, and can be combined like W=12 or W=123. # ========================================================================== KBUILD_CFLAGS += $(call cc-disable-warning, packed-not-aligned) +# backward compatibility +KBUILD_EXTRA_WARN ?= $(KBUILD_ENABLE_EXTRA_GCC_CHECKS) + ifeq ("$(origin W)", "command line") - export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W) + KBUILD_EXTRA_WARN := $(W) endif -ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS -warning- := $(empty) - -warning-1 := -Wextra -Wunused -Wno-unused-parameter -warning-1 += -Wmissing-declarations -warning-1 += -Wmissing-format-attribute -warning-1 += -Wmissing-prototypes -warning-1 += -Wold-style-definition -warning-1 += -Wmissing-include-dirs -warning-1 += $(call cc-option, -Wunused-but-set-variable) -warning-1 += $(call cc-option, -Wunused-const-variable) -warning-1 += $(call cc-option, -Wpacked-not-aligned) -warning-1 += $(call cc-option, -Wstringop-truncation) +export KBUILD_EXTRA_WARN + +# +# W=1 - warnings which may be relevant and do not occur too often +# +ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),) + +KBUILD_CFLAGS += -Wextra -Wunused -Wno-unused-parameter +KBUILD_CFLAGS += -Wmissing-declarations +KBUILD_CFLAGS += -Wmissing-format-attribute +KBUILD_CFLAGS += -Wmissing-prototypes +KBUILD_CFLAGS += -Wold-style-definition +KBUILD_CFLAGS += -Wmissing-include-dirs +KBUILD_CFLAGS += $(call cc-option, -Wunused-but-set-variable) +KBUILD_CFLAGS += $(call cc-option, -Wunused-const-variable) +KBUILD_CFLAGS += $(call cc-option, -Wpacked-not-aligned) +KBUILD_CFLAGS += $(call cc-option, -Wstringop-truncation) # The following turn off the warnings enabled by -Wextra -warning-1 += -Wno-missing-field-initializers -warning-1 += -Wno-sign-compare - -warning-2 += -Wcast-align -warning-2 += -Wdisabled-optimization -warning-2 += -Wnested-externs -warning-2 += -Wshadow -warning-2 += $(call cc-option, -Wlogical-op) -warning-2 += -Wmissing-field-initializers -warning-2 += -Wsign-compare -warning-2 += $(call cc-option, -Wmaybe-uninitialized) -warning-2 += $(call cc-option, -Wunused-macros) - -warning-3 := -Wbad-function-cast -warning-3 += -Wcast-qual -warning-3 += -Wconversion -warning-3 += -Wpacked -warning-3 += -Wpadded -warning-3 += -Wpointer-arith -warning-3 += -Wredundant-decls -warning-3 += -Wswitch-default -warning-3 += $(call cc-option, -Wpacked-bitfield-compat) - -warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) - -ifeq ("$(strip $(warning))","") - $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown) -endif +KBUILD_CFLAGS += -Wno-missing-field-initializers +KBUILD_CFLAGS += -Wno-sign-compare + +KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1 -KBUILD_CFLAGS += $(warning) else +# Some diagnostics enabled by default are noisy. +# Suppress them by using -Wno... except for W=1. + ifdef CONFIG_CC_IS_CLANG KBUILD_CFLAGS += -Wno-initializer-overrides KBUILD_CFLAGS += -Wno-format KBUILD_CFLAGS += -Wno-sign-compare KBUILD_CFLAGS += -Wno-format-zero-length endif + +endif + +# +# W=2 - warnings which occur quite often but may still be relevant +# +ifneq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) + +KBUILD_CFLAGS += -Wcast-align +KBUILD_CFLAGS += -Wdisabled-optimization +KBUILD_CFLAGS += -Wnested-externs +KBUILD_CFLAGS += -Wshadow +KBUILD_CFLAGS += $(call cc-option, -Wlogical-op) +KBUILD_CFLAGS += -Wmissing-field-initializers +KBUILD_CFLAGS += -Wsign-compare +KBUILD_CFLAGS += $(call cc-option, -Wmaybe-uninitialized) +KBUILD_CFLAGS += $(call cc-option, -Wunused-macros) + +KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN2 + +endif + +# +# W=3 - more obscure warnings, can most likely be ignored +# +ifneq ($(findstring 3, $(KBUILD_EXTRA_WARN)),) + +KBUILD_CFLAGS += -Wbad-function-cast +KBUILD_CFLAGS += -Wcast-qual +KBUILD_CFLAGS += -Wconversion +KBUILD_CFLAGS += -Wpacked +KBUILD_CFLAGS += -Wpadded +KBUILD_CFLAGS += -Wpointer-arith +KBUILD_CFLAGS += -Wredundant-decls +KBUILD_CFLAGS += -Wswitch-default +KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat) + +KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3 + endif diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 2208ebbd8c4c..4c51c95d40f4 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -1,4 +1,21 @@ # SPDX-License-Identifier: GPL-2.0 + +# LEX +# --------------------------------------------------------------------------- +quiet_cmd_flex = LEX $@ + cmd_flex = $(LEX) -o$@ -L $< + +$(obj)/%.lex.c: $(src)/%.l FORCE + $(call if_changed,flex) + +# YACC +# --------------------------------------------------------------------------- +quiet_cmd_bison = YACC $(basename $@).[ch] + cmd_bison = $(YACC) -o $(basename $@).c --defines=$(basename $@).h -t -l $< + +$(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE + $(call if_changed,bison) + # ========================================================================== # Building binaries on the host system # Binaries are used during the compilation of the kernel, for example @@ -63,9 +80,9 @@ host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs)) # Handle options to gcc. Support building with separate output directory _hostc_flags = $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ - $(HOSTCFLAGS_$(basetarget).o) + $(HOSTCFLAGS_$(target-stem).o) _hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ - $(HOSTCXXFLAGS_$(basetarget).o) + $(HOSTCXXFLAGS_$(target-stem).o) # $(objtree)/$(obj) for including generated headers from checkin source files ifeq ($(KBUILD_EXTMOD),) @@ -85,7 +102,7 @@ hostcxx_flags = -Wp,-MD,$(depfile) $(_hostcxx_flags) # host-csingle -> Executable quiet_cmd_host-csingle = HOSTCC $@ cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(KBUILD_HOSTLDFLAGS) -o $@ $< \ - $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) $(host-csingle): $(obj)/%: $(src)/%.c FORCE $(call if_changed_dep,host-csingle) @@ -93,8 +110,8 @@ $(host-csingle): $(obj)/%: $(src)/%.c FORCE # host-cmulti -> executable quiet_cmd_host-cmulti = HOSTLD $@ cmd_host-cmulti = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ \ - $(addprefix $(obj)/,$($(@F)-objs)) \ - $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) + $(addprefix $(obj)/, $($(target-stem)-objs)) \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) $(host-cmulti): FORCE $(call if_changed,host-cmulti) $(call multi_depend, $(host-cmulti), , -objs) @@ -111,8 +128,8 @@ $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE quiet_cmd_host-cxxmulti = HOSTLD $@ cmd_host-cxxmulti = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -o $@ \ $(foreach o,objs cxxobjs,\ - $(addprefix $(obj)/,$($(@F)-$(o)))) \ - $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) + $(addprefix $(obj)/, $($(target-stem)-$(o)))) \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) $(host-cxxmulti): FORCE $(call if_changed,host-cxxmulti) $(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs) @@ -144,8 +161,8 @@ $(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE # *.o -> .so shared library (host-cshlib) quiet_cmd_host-cshlib = HOSTLLD -shared $@ cmd_host-cshlib = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \ - $(addprefix $(obj)/,$($(@F:.so=-objs))) \ - $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) + $(addprefix $(obj)/, $($(target-stem)-objs)) \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem).so) $(host-cshlib): FORCE $(call if_changed,host-cshlib) $(call multi_depend, $(host-cshlib), .so, -objs) @@ -154,8 +171,8 @@ $(call multi_depend, $(host-cshlib), .so, -objs) # *.o -> .so shared library (host-cxxshlib) quiet_cmd_host-cxxshlib = HOSTLLD -shared $@ cmd_host-cxxshlib = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \ - $(addprefix $(obj)/,$($(@F:.so=-objs))) \ - $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) + $(addprefix $(obj)/, $($(target-stem)-objs)) \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem).so) $(host-cxxshlib): FORCE $(call if_changed,host-cxxshlib) $(call multi_depend, $(host-cxxshlib), .so, -objs) diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 6410bd22fe38..03757cc60e06 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -1,4 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 +ifdef CONFIG_KASAN +CFLAGS_KASAN_NOSANITIZE := -fno-builtin +KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET) +endif + ifdef CONFIG_KASAN_GENERIC ifdef CONFIG_KASAN_INLINE @@ -7,8 +12,6 @@ else call_threshold := 0 endif -KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET) - CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1))) @@ -45,7 +48,3 @@ CFLAGS_KASAN := -fsanitize=kernel-hwaddress \ $(instrumentation_flags) endif # CONFIG_KASAN_SW_TAGS - -ifdef CONFIG_KASAN -CFLAGS_KASAN_NOSANITIZE := -fno-builtin -endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 41c50f9461e5..4a0cdd6f5909 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -41,9 +41,9 @@ obj-m := $(filter-out %/, $(obj-m)) # Subdirectories we need to descend into subdir-ym := $(sort $(subdir-y) $(subdir-m)) -# if $(foo-objs), $(foo-y), or $(foo-m) exists, foo.o is a composite object -multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m)))) -multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))), $(m)))) +# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object +multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-))), $(m)))) +multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)) $($(m:.o=-))), $(m)))) multi-used := $(multi-used-y) $(multi-used-m) # $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to @@ -52,8 +52,8 @@ subdir-obj-y := $(filter %/built-in.a, $(obj-y)) # Replace multi-part objects by their individual parts, # including built-in.a from subdirectories -real-obj-y := $(foreach m, $(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) -real-obj-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m))) +real-obj-y := $(foreach m, $(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) +real-obj-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)) $($(m:.o=-))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m))) # DTB # If CONFIG_OF_ALL_DTBS is enabled, all DT blobs are built @@ -101,6 +101,9 @@ modname-multi = $(subst $(space),:,$(sort $(foreach m,$(multi-used),\ modname = $(if $(modname-multi),$(modname-multi),$(basetarget)) +# target with $(obj)/ and its suffix stripped +target-stem = $(basename $(patsubst $(obj)/%,%,$@)) + # These flags are needed for modversions and compiling, so we define them here # $(modname_flags) defines KBUILD_MODNAME as the name of the module it will # end up in (or would, if it gets compiled in) @@ -109,12 +112,12 @@ basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) modname_flags = -DKBUILD_MODNAME=$(call name-fix,$(modname)) orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ - $(ccflags-y) $(CFLAGS_$(basetarget).o) -_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) + $(ccflags-y) $(CFLAGS_$(target-stem).o) +_c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), $(orig_c_flags)) orig_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) \ - $(asflags-y) $(AFLAGS_$(basetarget).o) -_a_flags = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags)) -_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F)) + $(asflags-y) $(AFLAGS_$(target-stem).o) +_a_flags = $(filter-out $(AFLAGS_REMOVE_$(target-stem).o), $(orig_a_flags)) +_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds) # # Enable gcov profiling flags for a file, directory or for all files depending @@ -159,6 +162,18 @@ _cpp_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj) endif endif +part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y) +quiet_modtag = $(if $(part-of-module),[M], ) + +modkern_cflags = \ + $(if $(part-of-module), \ + $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ + $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL)) + +modkern_aflags = $(if $(part-of-module), \ + $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE), \ + $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)) + c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ -include $(srctree)/include/linux/compiler_types.h \ $(_c_flags) $(modkern_cflags) \ @@ -187,28 +202,6 @@ $(foreach m, $(notdir $1), \ $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s))))))) endef -# LEX -# --------------------------------------------------------------------------- -quiet_cmd_flex = LEX $@ - cmd_flex = $(LEX) -o$@ -L $< - -$(obj)/%.lex.c: $(src)/%.l FORCE - $(call if_changed,flex) - -# YACC -# --------------------------------------------------------------------------- -quiet_cmd_bison = YACC $@ - cmd_bison = $(YACC) -o$@ -t -l $< - -$(obj)/%.tab.c: $(src)/%.y FORCE - $(call if_changed,bison) - -quiet_cmd_bison_h = YACC $@ - cmd_bison_h = $(YACC) -o/dev/null --defines=$@ -t -l $< - -$(obj)/%.tab.h: $(src)/%.y FORCE - $(call if_changed,bison_h) - # Shipped files # =========================================================================== @@ -258,7 +251,7 @@ quiet_cmd_gzip = GZIP $@ DTC ?= $(objtree)/scripts/dtc/dtc # Disable noisy checks by default -ifeq ($(findstring 1,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),) +ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) DTC_FLAGS += -Wno-unit_address_vs_reg \ -Wno-unit_address_format \ -Wno-avoid_unnecessary_addr_size \ @@ -269,7 +262,7 @@ DTC_FLAGS += -Wno-unit_address_vs_reg \ -Wno-pci_device_reg endif -ifneq ($(findstring 2,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),) +ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),) DTC_FLAGS += -Wnode_name_chars_strict \ -Wproperty_name_chars_strict endif @@ -374,7 +367,7 @@ UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR) UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)' quiet_cmd_uimage = UIMAGE $@ - cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \ + cmd_uimage = $(BASH) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \ -C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \ -T $(UIMAGE_TYPE) \ -a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \ diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal new file mode 100644 index 000000000000..411c1e600e7d --- /dev/null +++ b/scripts/Makefile.modfinal @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: GPL-2.0-only +# =========================================================================== +# Module final link +# =========================================================================== + +PHONY := __modfinal +__modfinal: + +include $(srctree)/scripts/Kbuild.include + +# for c_flags +include $(srctree)/scripts/Makefile.lib + +# find all modules listed in modules.order +modules := $(sort $(shell cat $(MODORDER))) + +__modfinal: $(modules) + @: + +# modname and part-of-module are set to make c_flags define proper module flags +modname = $(notdir $(@:.mod.o=)) +part-of-module = y + +quiet_cmd_cc_o_c = CC [M] $@ + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + +%.mod.o: %.mod.c FORCE + $(call if_changed_dep,cc_o_c) + +ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) + +quiet_cmd_ld_ko_o = LD [M] $@ + cmd_ld_ko_o = \ + $(LD) -r $(KBUILD_LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + $(addprefix -T , $(KBUILD_LDS_MODULE)) \ + -o $@ $(filter %.o, $^); \ + $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) + +$(modules): %.ko: %.o %.mod.o $(KBUILD_LDS_MODULE) FORCE + +$(call if_changed,ld_ko_o) + +targets += $(modules) $(modules:.ko=.mod.o) + +# Add FORCE to the prequisites of a target to force it to be always rebuilt. +# --------------------------------------------------------------------------- + +PHONY += FORCE +FORCE: + +# Read all saved command lines and dependencies for the $(targets) we +# may be building above, using $(if_changed{,_dep}). As an +# optimization, we don't need to read them if the target does not +# exist, we will rebuild anyway in that case. + +existing-targets := $(wildcard $(sort $(targets))) + +-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) + +.PHONY: $(PHONY) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 6b19c1a4eae5..952fff485546 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -15,15 +15,13 @@ # 2) modpost is then used to # 3) create one <module>.mod.c file pr. module # 4) create one Module.symvers file with CRC for all exported symbols -# 5) compile all <module>.mod.c files -# 6) final link of the module to a <module.ko> file # Step 3 is used to place certain information in the module's ELF # section, including information such as: # Version magic (see include/linux/vermagic.h for full details) # - Kernel release # - SMP is CONFIG_SMP -# - PREEMPT is CONFIG_PREEMPT +# - PREEMPT is CONFIG_PREEMPT[_RT] # - GCC Version # Module info # - Module version (MODULE_VERSION) @@ -38,12 +36,37 @@ # symbols in the final module linking stage # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. # This is solely useful to speed up test compiles -PHONY := _modpost -_modpost: __modpost + +PHONY := __modpost +__modpost: include include/config/auto.conf include scripts/Kbuild.include +kernelsymfile := $(objtree)/Module.symvers +modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers + +MODPOST = scripts/mod/modpost \ + $(if $(CONFIG_MODVERSIONS),-m) \ + $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ + $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ + $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ + $(if $(KBUILD_EXTMOD),$(addprefix -e ,$(KBUILD_EXTRA_SYMBOLS))) \ + $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ + $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ + $(if $(KBUILD_MODPOST_WARN),-w) \ + $(if $(filter nsdeps,$(MAKECMDGOALS)),-d) + +ifdef MODPOST_VMLINUX + +quiet_cmd_modpost = MODPOST vmlinux.o + cmd_modpost = $(MODPOST) vmlinux.o + +__modpost: + $(call cmd,modpost) + +else + # When building external modules load the Kbuild file to retrieve EXTRA_SYMBOLS info ifneq ($(KBUILD_EXTMOD),) @@ -56,99 +79,25 @@ include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile) endif -include scripts/Makefile.lib +MODPOST += $(subst -i,-n,$(filter -i,$(MAKEFLAGS))) -s -T - $(wildcard vmlinux) -kernelsymfile := $(objtree)/Module.symvers -modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers +# find all modules listed in modules.order +modules := $(sort $(shell cat $(MODORDER))) -modorder := $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)modules.order +# Read out modules.order instead of expanding $(modules) to pass in modpost. +# Otherwise, allmodconfig would fail with "Argument list too long". +quiet_cmd_modpost = MODPOST $(words $(modules)) modules + cmd_modpost = sed 's/ko$$/o/' $(MODORDER) | $(MODPOST) -# Step 1), find all modules listed in modules.order -ifdef CONFIG_MODULES -modules := $(sort $(shell cat $(modorder))) +__modpost: + @$(kecho) ' Building modules, stage 2.' + $(call cmd,modpost) +ifneq ($(KBUILD_MODPOST_NOFINAL),1) + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal endif -# Stop after building .o files if NOFINAL is set. Makes compile tests quicker -_modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules)) - -# Step 2), invoke modpost -# Includes step 3,4 -modpost = scripts/mod/modpost \ - $(if $(CONFIG_MODVERSIONS),-m) \ - $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \ - $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ - $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ - $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ - $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ - $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ - $(if $(KBUILD_MODPOST_WARN),-w) - -MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) - -# We can go over command line length here, so be careful. -quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules - cmd_modpost = sed 's/ko$$/o/' $(modorder) | $(modpost) $(MODPOST_OPT) -s -T - - -PHONY += __modpost -__modpost: $(modules:.ko=.o) FORCE - $(call cmd,modpost) $(wildcard vmlinux) - -quiet_cmd_kernel-mod = MODPOST $@ - cmd_kernel-mod = $(modpost) $@ - -vmlinux.o: FORCE - $(call cmd,kernel-mod) - -# Declare generated files as targets for modpost -$(modules:.ko=.mod.c): __modpost ; - - -# Step 5), compile all *.mod.c files - -# modname is set to make c_flags define KBUILD_MODNAME -modname = $(notdir $(@:.mod.o=)) - -quiet_cmd_cc_o_c = CC $@ - cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \ - -c -o $@ $< - -$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) - -targets += $(modules:.ko=.mod.o) - -ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) - -# Step 6), final link of the modules with optional arch pass after final link -quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = \ - $(LD) -r $(KBUILD_LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ - -o $@ $(real-prereqs) ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - -$(modules): %.ko :%.o %.mod.o FORCE - +$(call if_changed,ld_ko_o) - -targets += $(modules) - - -# Add FORCE to the prequisites of a target to force it to be always rebuilt. -# --------------------------------------------------------------------------- - -PHONY += FORCE - -FORCE: - -# Read all saved command lines and dependencies for the $(targets) we -# may be building above, using $(if_changed{,_dep}). As an -# optimization, we don't need to read them if the target does not -# exist, we will rebuild anyway in that case. - -cmd_files := $(wildcard $(foreach f,$(sort $(targets)),$(dir $(f)).$(notdir $(f)).cmd)) +nsdeps: __modpost -ifneq ($(cmd_files),) - include $(cmd_files) endif .PHONY: $(PHONY) diff --git a/scripts/package/Makefile b/scripts/Makefile.package index ca7f46b562a4..56eadcc48d46 100644 --- a/scripts/package/Makefile +++ b/scripts/Makefile.package @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only # Makefile for the different targets used to generate full packages of a kernel -# It uses the generic clean infrastructure of kbuild + +include $(srctree)/scripts/Kbuild.include # RPM target # --------------------------------------------------------------------------- @@ -50,7 +51,8 @@ rm -f $(objtree)/.scmversion # rpm-pkg # --------------------------------------------------------------------------- -rpm-pkg: FORCE +PHONY += rpm-pkg +rpm-pkg: $(MAKE) clean $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec $(call cmd,src_tar,$(KERNELPATH),kernel.spec) @@ -59,15 +61,15 @@ rpm-pkg: FORCE # binrpm-pkg # --------------------------------------------------------------------------- -binrpm-pkg: FORCE +PHONY += binrpm-pkg +binrpm-pkg: $(MAKE) -f $(srctree)/Makefile $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ $(UTS_MACHINE) -bb $(objtree)/binkernel.spec -clean-files += $(objtree)/*.spec - -deb-pkg: FORCE +PHONY += deb-pkg +deb-pkg: $(MAKE) clean $(CONFIG_SHELL) $(srctree)/scripts/package/mkdebian $(call cmd,src_tar,$(KDEB_SOURCENAME)) @@ -75,18 +77,19 @@ deb-pkg: FORCE mv $(KDEB_SOURCENAME).tar.gz ../$(KDEB_SOURCENAME)_$${origversion}.orig.tar.gz +dpkg-buildpackage -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch) $(DPKG_FLAGS) -i.git -us -uc -bindeb-pkg: FORCE +PHONY += bindeb-pkg +bindeb-pkg: $(CONFIG_SHELL) $(srctree)/scripts/package/mkdebian +dpkg-buildpackage -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch) $(DPKG_FLAGS) -b -nc -uc -intdeb-pkg: FORCE +PHONY += intdeb-pkg +intdeb-pkg: +$(CONFIG_SHELL) $(srctree)/scripts/package/builddeb -clean-dirs += $(objtree)/debian/ - # snap-pkg # --------------------------------------------------------------------------- -snap-pkg: FORCE +PHONY += snap-pkg +snap-pkg: rm -rf $(objtree)/snap mkdir $(objtree)/snap $(MAKE) clean @@ -98,17 +101,14 @@ snap-pkg: FORCE cd $(objtree)/snap && \ snapcraft --target-arch=$(UTS_MACHINE) -clean-dirs += $(objtree)/snap/ - # tarball targets # --------------------------------------------------------------------------- -tar%pkg: FORCE +tar-pkgs := tar-pkg targz-pkg tarbz2-pkg tarxz-pkg +PHONY += $(tar-pkgs) +$(tar-pkgs): $(MAKE) -f $(srctree)/Makefile +$(CONFIG_SHELL) $(srctree)/scripts/package/buildtar $@ -clean-dirs += $(objtree)/tar-install/ - - # perf-pkg - generate a source tarball with perf source # --------------------------------------------------------------------------- @@ -133,12 +133,15 @@ $(if $(findstring xz,$@),xz, \ $(error unknown target $@)))) \ -f -9 $(perf-tar).tar) -perf-%pkg: FORCE +perf-tar-pkgs := perf-tar-src-pkg perf-targz-src-pkg perf-tarbz2-src-pkg perf-tarxz-src-pkg +PHONY += $(perf-tar-pkgs) +$(perf-tar-pkgs): $(call cmd,perf_tar) # Help text displayed when executing 'make help' # --------------------------------------------------------------------------- -help: FORCE +PHONY += help +help: @echo ' rpm-pkg - Build both source and binary RPM kernel packages' @echo ' binrpm-pkg - Build only the binary kernel RPM package' @echo ' deb-pkg - Build both source and binary deb kernel packages' @@ -152,3 +155,5 @@ help: FORCE @echo ' perf-targz-src-pkg - Build $(perf-tar).tar.gz source tarball' @echo ' perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball' @echo ' perf-tarxz-src-pkg - Build $(perf-tar).tar.xz source tarball' + +.PHONY: $(PHONY) diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile index 548aeb592806..7c9cb80d097b 100644 --- a/scripts/basic/Makefile +++ b/scripts/basic/Makefile @@ -1,16 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -### -# This Makefile lists the most basic programs used during the build process. -# The programs listed herein are what are needed to do the basic stuff, -# such as fix file dependencies. -# This initial step is needed to avoid files to be recompiled -# when kernel configuration changes (which is what happens when -# .config is included by main Makefile. -# --------------------------------------------------------------------------- -# fixdep: Used to generate dependency information during build process +# +# fixdep: used to generate dependency information during build process hostprogs-y := fixdep always := $(hostprogs-y) - -# fixdep is needed to compile other host programs -$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 93a7edfe0f05..6fcc66afb088 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -62,6 +62,8 @@ my $conststructsfile = "$D/const_structs.checkpatch"; my $typedefsfile = ""; my $color = "auto"; my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE +# git output parsing needs US English output, so first set backtick child process LANGUAGE +my $git_command ='export LANGUAGE=en_US.UTF-8; git'; sub help { my ($exitcode) = @_; @@ -904,7 +906,7 @@ sub seed_camelcase_includes { $camelcase_seeded = 1; if (-e ".git") { - my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`; + my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`; chomp $git_last_include_commit; $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; } else { @@ -932,7 +934,7 @@ sub seed_camelcase_includes { } if (-e ".git") { - $files = `git ls-files "include/*.h"`; + $files = `${git_command} ls-files "include/*.h"`; @include_files = split('\n', $files); } @@ -956,13 +958,13 @@ sub git_commit_info { return ($id, $desc) if ((which("git") eq "") || !(-e ".git")); - my $output = `git log --no-color --format='%H %s' -1 $commit 2>&1`; + my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`; $output =~ s/^\s*//gm; my @lines = split("\n", $output); return ($id, $desc) if ($#lines < 0); - if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) { + if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) { # Maybe one day convert this block of bash into something that returns # all matching commit ids, but it's very slow... # @@ -1006,7 +1008,7 @@ if ($git) { } else { $git_range = "-1 $commit_expr"; } - my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`; + my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`; foreach my $line (split(/\n/, $lines)) { $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; next if (!defined($1) || !defined($2)); @@ -2725,8 +2727,10 @@ sub process { ($line =~ /^\s*(?:WARNING:|BUG:)/ || $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || # timestamp - $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/)) { - # stack dump address + $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/) || + $line =~ /^(?:\s+\w+:\s+[0-9a-fA-F]+){3,3}/ || + $line =~ /^\s*\#\d+\s*\[[0-9a-fA-F]+\]\s*\w+ at [0-9a-fA-F]+/) { + # stack dump address styles $commit_log_possible_stack_dump = 1; } @@ -2898,6 +2902,17 @@ sub process { } } +# check for invalid commit id + if ($in_commit_log && $line =~ /(^fixes:|\bcommit)\s+([0-9a-f]{6,40})\b/i) { + my $id; + my $description; + ($id, $description) = git_commit_info($2, undef, undef); + if (!defined($id)) { + WARN("UNKNOWN_COMMIT_ID", + "Unknown commit id '$2', maybe rebased or not pulled?\n" . $herecurr); + } + } + # ignore non-hunk lines and lines being removed next if (!$hunk_line || $line =~ /^-/); @@ -3069,21 +3084,21 @@ sub process { # check SPDX comment style for .[chsS] files if ($realfile =~ /\.[chsS]$/ && $rawline =~ /SPDX-License-Identifier:/ && - $rawline !~ /^\+\s*\Q$comment\E\s*/) { + $rawline !~ m@^\+\s*\Q$comment\E\s*@) { WARN("SPDX_LICENSE_TAG", "Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $herecurr); } if ($comment !~ /^$/ && - $rawline !~ /^\+\Q$comment\E SPDX-License-Identifier: /) { - WARN("SPDX_LICENSE_TAG", - "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); + $rawline !~ m@^\+\Q$comment\E SPDX-License-Identifier: @) { + WARN("SPDX_LICENSE_TAG", + "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) { - my $spdx_license = $1; - if (!is_SPDX_License_valid($spdx_license)) { - WARN("SPDX_LICENSE_TAG", - "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); - } + my $spdx_license = $1; + if (!is_SPDX_License_valid($spdx_license)) { + WARN("SPDX_LICENSE_TAG", + "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); + } } } } @@ -4660,7 +4675,7 @@ sub process { # closing brace should have a space following it when it has anything # on the line - if ($line =~ /}(?!(?:,|;|\)))\S/) { + if ($line =~ /}(?!(?:,|;|\)|\}))\S/) { if (ERROR("SPACING", "space required after that close brace '}'\n" . $herecurr) && $fix) { @@ -5191,7 +5206,7 @@ sub process { next if ($arg =~ /\.\.\./); next if ($arg =~ /^type$/i); my $tmp_stmt = $define_stmt; - $tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; + $tmp_stmt =~ s/\b(sizeof|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; $tmp_stmt =~ s/\#+\s*$arg\b//g; $tmp_stmt =~ s/\b$arg\s*\#\#//g; my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g; @@ -5873,6 +5888,18 @@ sub process { "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); } +# Check for __attribute__ section, prefer __section + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*_*section_*\s*\(\s*("[^"]*")/) { + my $old = substr($rawline, $-[1], $+[1] - $-[1]); + my $new = substr($old, 1, -1); + if (WARN("PREFER_SECTION", + "__section($new) is preferred over __attribute__((section($old)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*_*section_*\s*\(\s*\Q$old\E\s*\)\s*\)\s*\)/__section($new)/; + } + } + # Check for __attribute__ format(printf, prefer __printf if ($realfile !~ m@\binclude/uapi/@ && $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { @@ -6480,6 +6507,12 @@ sub process { "Using $1 should generally have parentheses around the comparison\n" . $herecurr); } +# nested likely/unlikely calls + if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { + WARN("LIKELY_MISUSE", + "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); + } + # whine mightly about in_atomic if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { diff --git a/scripts/coccinelle/api/atomic_as_refcounter.cocci b/scripts/coccinelle/api/atomic_as_refcounter.cocci index 988120e0fd67..0f78d94abc35 100644 --- a/scripts/coccinelle/api/atomic_as_refcounter.cocci +++ b/scripts/coccinelle/api/atomic_as_refcounter.cocci @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only // Check if refcount_t type and API should be used // instead of atomic_t type when dealing with refcounters // diff --git a/scripts/coccinelle/api/platform_get_irq.cocci b/scripts/coccinelle/api/platform_get_irq.cocci new file mode 100644 index 000000000000..06b6a95e2bfc --- /dev/null +++ b/scripts/coccinelle/api/platform_get_irq.cocci @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/// Remove dev_err() messages after platform_get_irq*() failures +// +// Confidence: Medium +// Options: --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on context@ +expression ret; +struct platform_device *E; +@@ + +ret = +( +platform_get_irq +| +platform_get_irq_byname +)(E, ...); + +if ( \( ret < 0 \| ret <= 0 \) ) +{ +( +if (ret != -EPROBE_DEFER) +{ ... +*dev_err(...); +... } +| +... +*dev_err(...); +) +... +} + +@depends on patch@ +expression ret; +struct platform_device *E; +@@ + +ret = +( +platform_get_irq +| +platform_get_irq_byname +)(E, ...); + +if ( \( ret < 0 \| ret <= 0 \) ) +{ +( +-if (ret != -EPROBE_DEFER) +-{ ... +-dev_err(...); +-... } +| +... +-dev_err(...); +) +... +} + +@r depends on org || report@ +position p1; +expression ret; +struct platform_device *E; +@@ + +ret = +( +platform_get_irq +| +platform_get_irq_byname +)(E, ...); + +if ( \( ret < 0 \| ret <= 0 \) ) +{ +( +if (ret != -EPROBE_DEFER) +{ ... +dev_err@p1(...); +... } +| +... +dev_err@p1(...); +) +... +} + +@script:python depends on org@ +p1 << r.p1; +@@ + +cocci.print_main(p1) + +@script:python depends on report@ +p1 << r.p1; +@@ + +msg = "line %s is redundant because platform_get_irq() already prints an error" % (p1[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/coccinelle/misc/add_namespace.cocci b/scripts/coccinelle/misc/add_namespace.cocci new file mode 100644 index 000000000000..c832bb6445a8 --- /dev/null +++ b/scripts/coccinelle/misc/add_namespace.cocci @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +/// Adds missing MODULE_IMPORT_NS statements to source files +/// +/// This script is usually called from scripts/nsdeps with -D ns=<namespace> to +/// add a missing namespace tag to a module source file. +/// + +@has_ns_import@ +declarer name MODULE_IMPORT_NS; +identifier virtual.ns; +@@ +MODULE_IMPORT_NS(ns); + +// Add missing imports, but only adjacent to a MODULE_LICENSE statement. +// That ensures we are adding it only to the main module source file. +@do_import depends on !has_ns_import@ +declarer name MODULE_LICENSE; +expression license; +identifier virtual.ns; +@@ +MODULE_LICENSE(license); ++ MODULE_IMPORT_NS(ns); diff --git a/scripts/export_report.pl b/scripts/export_report.pl index 7d3030d03a25..548330e8c4e7 100755 --- a/scripts/export_report.pl +++ b/scripts/export_report.pl @@ -94,7 +94,7 @@ if (defined $opt{'o'}) { # while ( <$module_symvers> ) { chomp; - my (undef, $symbol, $module, $gpl) = split; + my (undef, $symbol, $namespace, $module, $gpl) = split('\t'); $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; } close($module_symvers); diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c index 6d5bbd31db7f..bd29e4e7a524 100644 --- a/scripts/gcc-plugins/randomize_layout_plugin.c +++ b/scripts/gcc-plugins/randomize_layout_plugin.c @@ -443,13 +443,13 @@ static int is_pure_ops_struct(const_tree node) if (node == fieldtype) continue; - if (!is_fptr(fieldtype)) - return 0; - - if (code != RECORD_TYPE && code != UNION_TYPE) + if (code == RECORD_TYPE || code == UNION_TYPE) { + if (!is_pure_ops_struct(fieldtype)) + return 0; continue; + } - if (!is_pure_ops_struct(fieldtype)) + if (!is_fptr(fieldtype)) return 0; } diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index 2f5b95f09fa0..34e40e96dee2 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -77,12 +77,12 @@ lx-symbols command.""" gdb.write("scanning for modules in {0}\n".format(path)) for root, dirs, files in os.walk(path): for name in files: - if name.endswith(".ko"): + if name.endswith(".ko") or name.endswith(".ko.debug"): self.module_files.append(root + "/" + name) self.module_files_updated = True def _get_module_file(self, module_name): - module_pattern = ".*/{0}\.ko$".format( + module_pattern = ".*/{0}\.ko(?:.debug)?$".format( module_name.replace("_", r"[_\-]")) for name in self.module_files: if re.match(module_pattern, name) and os.path.exists(name): diff --git a/scripts/genksyms/Makefile b/scripts/genksyms/Makefile index 66c314bc5933..78629f515e78 100644 --- a/scripts/genksyms/Makefile +++ b/scripts/genksyms/Makefile @@ -12,22 +12,15 @@ genksyms-objs := genksyms.o parse.tab.o lex.lex.o # # Just in case, run "$(YACC) --version" without suppressing stderr # so that 'bison: not found' will be displayed if it is missing. -ifeq ($(findstring 1,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),) +ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) quiet_cmd_bison_no_warn = $(quiet_cmd_bison) cmd_bison_no_warn = $(YACC) --version >/dev/null; \ $(cmd_bison) 2>/dev/null -$(obj)/parse.tab.c: $(src)/parse.y FORCE +$(obj)/pars%.tab.c $(obj)/pars%.tab.h: $(src)/pars%.y FORCE $(call if_changed,bison_no_warn) -quiet_cmd_bison_h_no_warn = $(quiet_cmd_bison_h) - cmd_bison_h_no_warn = $(YACC) --version >/dev/null; \ - $(cmd_bison_h) 2>/dev/null - -$(obj)/parse.tab.h: $(src)/parse.y FORCE - $(call if_changed,bison_h_no_warn) - endif # -I needed for generated C source (shipped source) diff --git a/scripts/genksyms/keywords.c b/scripts/genksyms/keywords.c index c586d32dd2c3..7a85c4e21175 100644 --- a/scripts/genksyms/keywords.c +++ b/scripts/genksyms/keywords.c @@ -3,11 +3,7 @@ static struct resword { const char *name; int token; } keywords[] = { - { "EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW }, - { "EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW }, - { "EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW }, - { "EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW }, - { "EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW }, + { "__GENKSYMS_EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW }, { "__asm", ASM_KEYW }, { "__asm__", ASM_KEYW }, { "__attribute", ATTRIBUTE_KEYW }, diff --git a/scripts/genksyms/lex.l b/scripts/genksyms/lex.l index d29c774f51b6..e265c5d96861 100644 --- a/scripts/genksyms/lex.l +++ b/scripts/genksyms/lex.l @@ -1,25 +1,13 @@ -/* Lexical analysis for genksyms. - Copyright 1996, 1997 Linux International. - - New implementation contributed by Richard Henderson <rth@tamu.edu> - Based on original work by Bjorn Ekwall <bj0rn@blox.se> - - Taken from Linux modutils 2.4.22. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Lexical analysis for genksyms. + * Copyright 1996, 1997 Linux International. + * + * New implementation contributed by Richard Henderson <rth@tamu.edu> + * Based on original work by Bjorn Ekwall <bj0rn@blox.se> + * + * Taken from Linux modutils 2.4.22. + */ %{ diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y index 1ebcf52cd0f9..e22b42245bcc 100644 --- a/scripts/genksyms/parse.y +++ b/scripts/genksyms/parse.y @@ -1,25 +1,13 @@ -/* C global declaration parser for genksyms. - Copyright 1996, 1997 Linux International. - - New implementation contributed by Richard Henderson <rth@tamu.edu> - Based on original work by Bjorn Ekwall <bj0rn@blox.se> - - This file is part of the Linux modutils. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * C global declaration parser for genksyms. + * Copyright 1996, 1997 Linux International. + * + * New implementation contributed by Richard Henderson <rth@tamu.edu> + * Based on original work by Bjorn Ekwall <bj0rn@blox.se> + * + * This file is part of the Linux modutils. + */ %{ diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index 47f6f3ea0771..a07668a5c36b 100755 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -23,6 +23,12 @@ TMPFILE=$OUTFILE.tmp trap 'rm -f $OUTFILE $TMPFILE' EXIT +# SPDX-License-Identifier with GPL variants must have "WITH Linux-syscall-note" +if [ -n "$(sed -n -e "/SPDX-License-Identifier:.*GPL-/{/WITH Linux-syscall-note/!p}" $INFILE)" ]; then + echo "error: $INFILE: missing \"WITH Linux-syscall-note\" for SPDX-License-Identifier" >&2 + exit 1 +fi + sed -E -e ' s/([[:space:](])(__user|__force|__iomem)[[:space:]]/\1/g s/__attribute_const__([[:space:]]|$)/\1/g @@ -35,5 +41,77 @@ sed -E -e ' scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ $TMPFILE > $OUTFILE [ $? -gt 1 ] && exit 1 +# Remove /* ... */ style comments, and find CONFIG_ references in code +configs=$(sed -e ' +:comment + s:/\*[^*][^*]*:/*: + s:/\*\*\**\([^/]\):/*\1: + t comment + s:/\*\*/: : + t comment + /\/\*/! b check + N + b comment +:print + P + D +:check + s:^\(CONFIG_[[:alnum:]_]*\):\1\n: + t print + s:^[[:alnum:]_][[:alnum:]_]*:: + s:^[^[:alnum:]_][^[:alnum:]_]*:: + t check + d +' $OUTFILE) + +# The entries in the following list are not warned. +# Please do not add a new entry. This list is only for existing ones. +# The list will be reduced gradually, and deleted eventually. (hopefully) +# +# The format is <file-name>:<CONFIG-option> in each line. +config_leak_ignores=" +arch/alpha/include/uapi/asm/setup.h:CONFIG_ALPHA_LEGACY_START_ADDRESS +arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K +arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K +arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE +arch/arm/include/uapi/asm/ptrace.h:CONFIG_CPU_ENDIAN_BE8 +arch/hexagon/include/uapi/asm/ptrace.h:CONFIG_HEXAGON_ARCH_VERSION +arch/hexagon/include/uapi/asm/user.h:CONFIG_HEXAGON_ARCH_VERSION +arch/ia64/include/uapi/asm/cmpxchg.h:CONFIG_IA64_DEBUG_CMPXCHG +arch/m68k/include/uapi/asm/ptrace.h:CONFIG_COLDFIRE +arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO +arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT +arch/sh/include/uapi/asm/ptrace.h:CONFIG_CPU_SH5 +arch/sh/include/uapi/asm/sigcontext.h:CONFIG_CPU_SH5 +arch/sh/include/uapi/asm/stat.h:CONFIG_CPU_SH5 +arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION +arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64 +arch/x86/include/uapi/asm/mman.h:CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +include/uapi/asm-generic/fcntl.h:CONFIG_64BIT +include/uapi/linux/atmdev.h:CONFIG_COMPAT +include/uapi/linux/elfcore.h:CONFIG_BINFMT_ELF_FDPIC +include/uapi/linux/eventpoll.h:CONFIG_PM_SLEEP +include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS +include/uapi/linux/pktcdvd.h:CONFIG_CDROM_PKTCDVD_WCACHE +include/uapi/linux/raw.h:CONFIG_MAX_RAW_DEVS +" + +for c in $configs +do + warn=1 + + for ignore in $config_leak_ignores + do + if echo "$INFILE:$c" | grep -q "$ignore$"; then + warn= + break + fi + done + + if [ "$warn" = 1 ]; then + echo "warning: $INFILE: leak $c to user-space" >&2 + fi +done + rm -f $TMPFILE trap - EXIT diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 7656e1137b6b..ef2f2336c469 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -114,7 +114,7 @@ testconfig: $(obj)/conf $(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \ -o cache_dir=$(abspath $(obj)/tests/.cache) \ $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no) -clean-dirs += tests/.cache +clean-files += tests/.cache # Help text used by make help help: @@ -166,15 +166,15 @@ $(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/nconf-cfg # mconf: Used for the menuconfig target based on lxdialog hostprogs-y += mconf -lxdialog := checklist.o inputbox.o menubox.o textbox.o util.o yesno.o -mconf-objs := mconf.o $(addprefix lxdialog/, $(lxdialog)) $(common-objs) +lxdialog := $(addprefix lxdialog/, \ + checklist.o inputbox.o menubox.o textbox.o util.o yesno.o) +mconf-objs := mconf.o $(lxdialog) $(common-objs) HOSTLDLIBS_mconf = $(shell . $(obj)/mconf-cfg && echo $$libs) $(foreach f, mconf.o $(lxdialog), \ $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/mconf-cfg && echo $$$$cflags))) -$(obj)/mconf.o: $(obj)/mconf-cfg -$(addprefix $(obj)/lxdialog/, $(lxdialog)): $(obj)/mconf-cfg +$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/mconf-cfg # qconf: Used for the xconfig target based on Qt hostprogs-y += qconf diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 1134892599da..3569d2dec37c 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -848,6 +848,7 @@ int conf_write(const char *name) const char *str; char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; char *env; + int i; bool need_newline = false; if (!name) @@ -930,6 +931,9 @@ next: } fclose(out); + for_all_symbols(i, sym) + sym->flags &= ~SYMBOL_WRITTEN; + if (*tmpname) { if (is_same(name, tmpname)) { conf_message("No change to %s", name); diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh index d924c51d28b7..63c8565206a4 100755 --- a/scripts/kconfig/merge_config.sh +++ b/scripts/kconfig/merge_config.sh @@ -13,12 +13,12 @@ # Copyright (c) 2009-2010 Wind River Systems, Inc. # Copyright 2011 Linaro +set -e + clean_up() { rm -f $TMP_FILE rm -f $MERGE_FILE - exit } -trap clean_up HUP INT TERM usage() { echo "Usage: $0 [OPTIONS] [CONFIG [...]]" @@ -110,6 +110,9 @@ TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX) echo "Using $INITFILE as base" + +trap clean_up EXIT + cat $INITFILE > $TMP_FILE # Merge files, printing warnings on overridden values @@ -155,7 +158,6 @@ if [ "$RUNMAKE" = "false" ]; then echo "#" echo "# merged configuration written to $KCONFIG_CONFIG (needs make)" echo "#" - clean_up exit fi @@ -177,7 +179,7 @@ make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) - ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG") + ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true) if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then echo "Value requested for $CFG not in final .config" echo "Requested value: $REQUESTED_VAL" @@ -185,5 +187,3 @@ for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do echo "" fi done - -clean_up diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 6b03012750da..81dc91760b23 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1245,7 +1245,7 @@ sub dump_enum($$) { # strip #define macros inside enums $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; - if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) { + if ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) { $declaration_name = $1; my $members = $2; my %_members; @@ -1580,6 +1580,7 @@ sub dump_function($$) { $prototype =~ s/__must_check +//; $prototype =~ s/__weak +//; $prototype =~ s/__sched +//; + $prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//; my $define = $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\( (?: diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a7124f895b24..06495379fcd8 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -56,13 +56,19 @@ modpost_link() } # Link of vmlinux -# ${1} - optional extra .o files -# ${2} - output file +# ${1} - output file +# ${2}, ${3}, ... - optional extra .o files vmlinux_link() { local lds="${objtree}/${KBUILD_LDS}" + local output=${1} local objects + info LD ${output} + + # skip output file argument + shift + if [ "${SRCARCH}" != "um" ]; then objects="--whole-archive \ ${KBUILD_VMLINUX_OBJS} \ @@ -70,9 +76,10 @@ vmlinux_link() --start-group \ ${KBUILD_VMLINUX_LIBS} \ --end-group \ - ${1}" + ${@}" - ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \ + -o ${output} \ -T ${lds} ${objects} else objects="-Wl,--whole-archive \ @@ -81,9 +88,10 @@ vmlinux_link() -Wl,--start-group \ ${KBUILD_VMLINUX_LIBS} \ -Wl,--end-group \ - ${1}" + ${@}" - ${CC} ${CFLAGS_vmlinux} -o ${2} \ + ${CC} ${CFLAGS_vmlinux} \ + -o ${output} \ -Wl,-T,${lds} \ ${objects} \ -lutil -lrt -lpthread @@ -92,23 +100,36 @@ vmlinux_link() } # generate .BTF typeinfo from DWARF debuginfo +# ${1} - vmlinux image +# ${2} - file to dump raw BTF data into gen_btf() { - local pahole_ver; + local pahole_ver + local bin_arch if ! [ -x "$(command -v ${PAHOLE})" ]; then info "BTF" "${1}: pahole (${PAHOLE}) is not available" - return 0 + return 1 fi pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/') if [ "${pahole_ver}" -lt "113" ]; then info "BTF" "${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.13" - return 0 + return 1 fi - info "BTF" ${1} + info "BTF" ${2} + vmlinux_link ${1} LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1} + + # dump .BTF section into raw binary file to link with final vmlinux + bin_arch=$(LANG=C ${OBJDUMP} -f ${1} | grep architecture | \ + cut -d, -f1 | cut -d' ' -f2) + bin_format=$(LANG=C ${OBJDUMP} -f ${1} | grep 'file format' | \ + awk '{print $4}') + ${OBJCOPY} --dump-section .BTF=.btf.vmlinux.bin ${1} 2>/dev/null + ${OBJCOPY} -I binary -O ${bin_format} -B ${bin_arch} \ + --rename-section .data=.BTF .btf.vmlinux.bin ${2} } # Create ${2} .o file with all symbols from the ${1} object file @@ -138,6 +159,18 @@ kallsyms() ${CC} ${aflags} -c -o ${2} ${afile} } +# Perform one step in kallsyms generation, including temporary linking of +# vmlinux. +kallsyms_step() +{ + kallsymso_prev=${kallsymso} + kallsymso=.tmp_kallsyms${1}.o + kallsyms_vmlinux=.tmp_vmlinux${1} + + vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} + kallsyms ${kallsyms_vmlinux} ${kallsymso} +} + # Create map file with all symbols from ${1} # See mksymap for additional details mksysmap() @@ -153,6 +186,7 @@ sortextable() # Delete output files in case of error cleanup() { + rm -f .btf.* rm -f .tmp_System.map rm -f .tmp_kallsyms* rm -f .tmp_vmlinux* @@ -210,12 +244,20 @@ info LD vmlinux.o modpost_link vmlinux.o # modpost vmlinux.o to check for section mismatches -${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o +${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1 info MODINFO modules.builtin.modinfo ${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo +btf_vmlinux_bin_o="" +if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then + if gen_btf .tmp_vmlinux.btf .btf.vmlinux.bin.o ; then + btf_vmlinux_bin_o=.btf.vmlinux.bin.o + fi +fi + kallsymso="" +kallsymso_prev="" kallsyms_vmlinux="" if [ -n "${CONFIG_KALLSYMS}" ]; then @@ -242,37 +284,19 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then # a) Verify that the System.map from vmlinux matches the map from # ${kallsymso}. - kallsymso=.tmp_kallsyms2.o - kallsyms_vmlinux=.tmp_vmlinux2 - - # step 1 - vmlinux_link "" .tmp_vmlinux1 - kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o - - # step 2 - vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2 - kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o + kallsyms_step 1 + kallsyms_step 2 # step 3 - size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" .tmp_kallsyms1.o) - size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" .tmp_kallsyms2.o) + size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso_prev}) + size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso}) if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then - kallsymso=.tmp_kallsyms3.o - kallsyms_vmlinux=.tmp_vmlinux3 - - vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3 - - kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o + kallsyms_step 3 fi fi -info LD vmlinux -vmlinux_link "${kallsymso}" vmlinux - -if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then - gen_btf vmlinux -fi +vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then info SORTEX vmlinux diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index 2339f86126cb..d1d757c6edf4 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -5,7 +5,8 @@ TARGET=$1 ARCH=$2 SMP=$3 PREEMPT=$4 -CC=$5 +PREEMPT_RT=$5 +CC=$6 vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; } @@ -53,6 +54,7 @@ UTS_VERSION="#$VERSION" CONFIG_FLAGS="" if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi +if [ -n "$PREEMPT_RT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT_RT"; fi UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" # Truncate to maximum length diff --git a/scripts/mkmakefile b/scripts/mkmakefile index 4d0faebb1719..1cb174751429 100755 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -12,6 +12,6 @@ if [ "${quiet}" != "silent_" ]; then fi cat << EOF > Makefile -# Automatically generated by $(realpath $0): don't edit -include $(realpath $1/Makefile) +# Automatically generated by $0: don't edit +include $1/Makefile EOF 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..3961941e8e7a 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; + 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 * (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,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; @@ -620,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")) @@ -691,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; @@ -795,9 +849,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 +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; @@ -1974,12 +2029,33 @@ 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); } + + // 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 +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); @@ -2159,7 +2247,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 +2301,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 +2337,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 +2355,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 +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; @@ -2349,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) @@ -2366,9 +2453,11 @@ 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; sym_update_crc(symname, mod, crc, export_no(export)); } release_file(file, size); @@ -2395,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; } } @@ -2412,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; @@ -2425,10 +2543,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 +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); } @@ -2503,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); @@ -2515,11 +2640,30 @@ 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 = symbolhash[n]; + + while (s) { + if (s->is_static) + warn("\"%s\" [%s] is a static %s\n", + s->name, s->module->name, + export_str(s->export)); + + s = s->next; + } + } + free(buf.p); return err; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 8453d6ac2f77..92a926d375d2 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 { diff --git a/scripts/nsdeps b/scripts/nsdeps new file mode 100644 index 000000000000..ac2b6031dd13 --- /dev/null +++ b/scripts/nsdeps @@ -0,0 +1,58 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Linux kernel symbol namespace import generator +# +# This script requires a minimum spatch version. +SPATCH_REQ_VERSION="1.0.4" + +DIR="$(dirname $(readlink -f $0))/.." +SPATCH="`which ${SPATCH:=spatch}`" +if [ ! -x "$SPATCH" ]; then + echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/' + exit 1 +fi + +SPATCH_REQ_VERSION_NUM=$(echo $SPATCH_REQ_VERSION | ${DIR}/scripts/ld-version.sh) +SPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}') +SPATCH_VERSION_NUM=$(echo $SPATCH_VERSION | ${DIR}/scripts/ld-version.sh) + +if [ "$SPATCH_VERSION_NUM" -lt "$SPATCH_REQ_VERSION_NUM" ] ; then + echo "spatch needs to be version $SPATCH_REQ_VERSION or higher" + exit 1 +fi + +generate_deps_for_ns() { + $SPATCH --very-quiet --in-place --sp-file \ + $srctree/scripts/coccinelle/misc/add_namespace.cocci -D ns=$1 $2 +} + +generate_deps() { + local mod_name=`basename $@ .ko` + local mod_file=`echo $@ | sed -e 's/\.ko/\.mod/'` + local ns_deps_file=`echo $@ | sed -e 's/\.ko/\.ns_deps/'` + if [ ! -f "$ns_deps_file" ]; then return; fi + local mod_source_files=`cat $mod_file | sed -n 1p \ + | sed -e 's/\.o/\.c/g' \ + | sed "s/[^ ]* */${srctree}\/&/g"` + for ns in `cat $ns_deps_file`; do + echo "Adding namespace $ns to module $mod_name (if needed)." + generate_deps_for_ns $ns $mod_source_files + # sort the imports + for source_file in $mod_source_files; do + sed '/MODULE_IMPORT_NS/Q' $source_file > ${source_file}.tmp + offset=$(wc -l ${source_file}.tmp | awk '{print $1;}') + cat $source_file | grep MODULE_IMPORT_NS | sort -u >> ${source_file}.tmp + tail -n +$((offset +1)) ${source_file} | grep -v MODULE_IMPORT_NS >> ${source_file}.tmp + if ! diff -q ${source_file} ${source_file}.tmp; then + mv ${source_file}.tmp ${source_file} + else + rm ${source_file}.tmp + fi + done + done +} + +for f in `cat $objtree/modules.order`; do + generate_deps $f +done + diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 8387a9bc064a..612268eabef4 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -27,7 +27,6 @@ #include <getopt.h> #include <elf.h> #include <fcntl.h> -#include <setjmp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -43,56 +42,37 @@ static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ static struct stat sb; /* Remember .st_size, etc. */ -static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ static const char *altmcount; /* alternate mcount symbol name */ static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ static void *file_map; /* pointer of the mapped file */ static void *file_end; /* pointer to the end of the mapped file */ static int file_updated; /* flag to state file was changed */ static void *file_ptr; /* current file pointer location */ + static void *file_append; /* added to the end of the file */ static size_t file_append_size; /* how much is added to end of file */ -/* setjmp() return values */ -enum { - SJ_SETJMP = 0, /* hardwired first return */ - SJ_FAIL, - SJ_SUCCEED -}; - /* Per-file resource cleanup when multiple files. */ -static void -cleanup(void) +static void file_append_cleanup(void) { - if (!mmap_failed) - munmap(file_map, sb.st_size); - else - free(file_map); - file_map = NULL; free(file_append); file_append = NULL; file_append_size = 0; file_updated = 0; } -static void __attribute__((noreturn)) -fail_file(void) +static void mmap_cleanup(void) { - cleanup(); - longjmp(jmpenv, SJ_FAIL); -} - -static void __attribute__((noreturn)) -succeed_file(void) -{ - cleanup(); - longjmp(jmpenv, SJ_SUCCEED); + if (!mmap_failed) + munmap(file_map, sb.st_size); + else + free(file_map); + file_map = NULL; } -/* ulseek, uread, ...: Check return value for errors. */ +/* ulseek, uwrite, ...: Check return value for errors. */ -static off_t -ulseek(int const fd, off_t const offset, int const whence) +static off_t ulseek(off_t const offset, int const whence) { switch (whence) { case SEEK_SET: @@ -107,24 +87,12 @@ ulseek(int const fd, off_t const offset, int const whence) } if (file_ptr < file_map) { fprintf(stderr, "lseek: seek before file\n"); - fail_file(); + return -1; } return file_ptr - file_map; } -static size_t -uread(int const fd, void *const buf, size_t const count) -{ - size_t const n = read(fd, buf, count); - if (n != count) { - perror("read"); - fail_file(); - } - return n; -} - -static size_t -uwrite(int const fd, void const *const buf, size_t const count) +static ssize_t uwrite(void const *const buf, size_t const count) { size_t cnt = count; off_t idx = 0; @@ -140,7 +108,9 @@ uwrite(int const fd, void const *const buf, size_t const count) } if (!file_append) { perror("write"); - fail_file(); + file_append_cleanup(); + mmap_cleanup(); + return -1; } if (file_ptr < file_end) { cnt = file_end - file_ptr; @@ -160,17 +130,81 @@ uwrite(int const fd, void const *const buf, size_t const count) return count; } -static void * -umalloc(size_t size) +static void * umalloc(size_t size) { void *const addr = malloc(size); if (addr == 0) { fprintf(stderr, "malloc failed: %zu bytes\n", size); - fail_file(); + file_append_cleanup(); + mmap_cleanup(); + return NULL; } return addr; } +/* + * Get the whole file as a programming convenience in order to avoid + * malloc+lseek+read+free of many pieces. If successful, then mmap + * avoids copying unused pieces; else just read the whole file. + * Open for both read and write; new info will be appended to the file. + * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr + * do not propagate to the file until an explicit overwrite at the last. + * This preserves most aspects of consistency (all except .st_size) + * for simultaneous readers of the file while we are appending to it. + * However, multiple writers still are bad. We choose not to use + * locking because it is expensive and the use case of kernel build + * makes multiple writers unlikely. + */ +static void *mmap_file(char const *fname) +{ + /* Avoid problems if early cleanup() */ + fd_map = -1; + mmap_failed = 1; + file_map = NULL; + file_ptr = NULL; + file_updated = 0; + sb.st_size = 0; + + fd_map = open(fname, O_RDONLY); + if (fd_map < 0) { + perror(fname); + return NULL; + } + if (fstat(fd_map, &sb) < 0) { + perror(fname); + goto out; + } + if (!S_ISREG(sb.st_mode)) { + fprintf(stderr, "not a regular file: %s\n", fname); + goto out; + } + file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, + fd_map, 0); + if (file_map == MAP_FAILED) { + mmap_failed = 1; + file_map = umalloc(sb.st_size); + if (!file_map) { + perror(fname); + goto out; + } + if (read(fd_map, file_map, sb.st_size) != sb.st_size) { + perror(fname); + free(file_map); + file_map = NULL; + goto out; + } + } else + mmap_failed = 0; +out: + close(fd_map); + fd_map = -1; + + file_end = file_map + sb.st_size; + + return file_map; +} + + static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; static unsigned char *ideal_nop; @@ -194,8 +228,10 @@ static int make_nop_x86(void *map, size_t const offset) return -1; /* convert to nop */ - ulseek(fd_map, offset - 1, SEEK_SET); - uwrite(fd_map, ideal_nop, 5); + if (ulseek(offset - 1, SEEK_SET) < 0) + return -1; + if (uwrite(ideal_nop, 5) < 0) + return -1; return 0; } @@ -243,10 +279,12 @@ static int make_nop_arm(void *map, size_t const offset) return -1; /* Convert to nop */ - ulseek(fd_map, off, SEEK_SET); + if (ulseek(off, SEEK_SET) < 0) + return -1; do { - uwrite(fd_map, ideal_nop, nop_size); + if (uwrite(ideal_nop, nop_size) < 0) + return -1; } while (--cnt > 0); return 0; @@ -263,57 +301,20 @@ static int make_nop_arm64(void *map, size_t const offset) return -1; /* Convert to nop */ - ulseek(fd_map, offset, SEEK_SET); - uwrite(fd_map, ideal_nop, 4); + if (ulseek(offset, SEEK_SET) < 0) + return -1; + if (uwrite(ideal_nop, 4) < 0) + return -1; return 0; } -/* - * Get the whole file as a programming convenience in order to avoid - * malloc+lseek+read+free of many pieces. If successful, then mmap - * avoids copying unused pieces; else just read the whole file. - * Open for both read and write; new info will be appended to the file. - * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr - * do not propagate to the file until an explicit overwrite at the last. - * This preserves most aspects of consistency (all except .st_size) - * for simultaneous readers of the file while we are appending to it. - * However, multiple writers still are bad. We choose not to use - * locking because it is expensive and the use case of kernel build - * makes multiple writers unlikely. - */ -static void *mmap_file(char const *fname) -{ - fd_map = open(fname, O_RDONLY); - if (fd_map < 0 || fstat(fd_map, &sb) < 0) { - perror(fname); - fail_file(); - } - if (!S_ISREG(sb.st_mode)) { - fprintf(stderr, "not a regular file: %s\n", fname); - fail_file(); - } - file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, - fd_map, 0); - mmap_failed = 0; - if (file_map == MAP_FAILED) { - mmap_failed = 1; - file_map = umalloc(sb.st_size); - uread(fd_map, file_map, sb.st_size); - } - close(fd_map); - - file_end = file_map + sb.st_size; - - return file_map; -} - -static void write_file(const char *fname) +static int write_file(const char *fname) { char tmp_file[strlen(fname) + 4]; size_t n; if (!file_updated) - return; + return 0; sprintf(tmp_file, "%s.rc", fname); @@ -325,25 +326,28 @@ static void write_file(const char *fname) fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode); if (fd_map < 0) { perror(fname); - fail_file(); + return -1; } n = write(fd_map, file_map, sb.st_size); if (n != sb.st_size) { perror("write"); - fail_file(); + close(fd_map); + return -1; } if (file_append_size) { n = write(fd_map, file_append, file_append_size); if (n != file_append_size) { perror("write"); - fail_file(); + close(fd_map); + return -1; } } close(fd_map); if (rename(tmp_file, fname) < 0) { perror(fname); - fail_file(); + return -1; } + return 0; } /* w8rev, w8nat, ...: Handle endianness. */ @@ -394,8 +398,7 @@ static uint32_t (*w)(uint32_t); static uint32_t (*w2)(uint16_t); /* Names of the sections that could contain calls to mcount. */ -static int -is_mcounted_section_name(char const *const txtname) +static int is_mcounted_section_name(char const *const txtname) { return strncmp(".text", txtname, 5) == 0 || strcmp(".init.text", txtname) == 0 || @@ -405,10 +408,11 @@ is_mcounted_section_name(char const *const txtname) strcmp(".irqentry.text", txtname) == 0 || strcmp(".softirqentry.text", txtname) == 0 || strcmp(".kprobes.text", txtname) == 0 || - strcmp(".cpuidle.text", txtname) == 0 || - strcmp(".text.unlikely", txtname) == 0; + strcmp(".cpuidle.text", txtname) == 0; } +static char const *already_has_rel_mcount = "success"; /* our work here is done! */ + /* 32 bit and 64 bit are very similar */ #include "recordmcount.h" #define RECORD_MCOUNT_64 @@ -447,11 +451,15 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type) }).r_info; } -static void -do_file(char const *const fname) +static int do_file(char const *const fname) { - Elf32_Ehdr *const ehdr = mmap_file(fname); unsigned int reltype = 0; + Elf32_Ehdr *ehdr; + int rc = -1; + + ehdr = mmap_file(fname); + if (!ehdr) + goto out; w = w4nat; w2 = w2nat; @@ -461,8 +469,7 @@ do_file(char const *const fname) default: fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", ehdr->e_ident[EI_DATA], fname); - fail_file(); - break; + goto out; case ELFDATA2LSB: if (*(unsigned char const *)&endian != 1) { /* main() is big endian, file.o is little endian. */ @@ -490,52 +497,54 @@ do_file(char const *const fname) push_bl_mcount_thumb = push_bl_mcount_thumb_be; break; } /* end switch */ - if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 - || w2(ehdr->e_type) != ET_REL - || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 || + w2(ehdr->e_type) != ET_REL || + ehdr->e_ident[EI_VERSION] != EV_CURRENT) { fprintf(stderr, "unrecognized ET_REL file %s\n", fname); - fail_file(); + goto out; } - gpfx = 0; + gpfx = '_'; switch (w2(ehdr->e_machine)) { default: fprintf(stderr, "unrecognized e_machine %u %s\n", w2(ehdr->e_machine), fname); - fail_file(); - break; + goto out; case EM_386: reltype = R_386_32; rel_type_nop = R_386_NONE; make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_32; mcount_adjust_32 = -1; + gpfx = 0; + break; + case EM_ARM: + reltype = R_ARM_ABS32; + altmcount = "__gnu_mcount_nc"; + make_nop = make_nop_arm; + rel_type_nop = R_ARM_NONE; + gpfx = 0; break; - case EM_ARM: reltype = R_ARM_ABS32; - altmcount = "__gnu_mcount_nc"; - make_nop = make_nop_arm; - rel_type_nop = R_ARM_NONE; - break; case EM_AARCH64: - reltype = R_AARCH64_ABS64; - make_nop = make_nop_arm64; - rel_type_nop = R_AARCH64_NONE; - ideal_nop = ideal_nop4_arm64; - gpfx = '_'; - break; - case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break; - case EM_MIPS: /* reltype: e_class */ gpfx = '_'; break; - case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break; - case EM_PPC64: reltype = R_PPC64_ADDR64; gpfx = '_'; break; - case EM_S390: /* reltype: e_class */ gpfx = '_'; break; - case EM_SH: reltype = R_SH_DIR32; break; - case EM_SPARCV9: reltype = R_SPARC_64; gpfx = '_'; break; + reltype = R_AARCH64_ABS64; + make_nop = make_nop_arm64; + rel_type_nop = R_AARCH64_NONE; + ideal_nop = ideal_nop4_arm64; + break; + case EM_IA_64: reltype = R_IA64_IMM64; break; + case EM_MIPS: /* reltype: e_class */ break; + case EM_PPC: reltype = R_PPC_ADDR32; break; + case EM_PPC64: reltype = R_PPC64_ADDR64; break; + case EM_S390: /* reltype: e_class */ break; + case EM_SH: reltype = R_SH_DIR32; gpfx = 0; break; + case EM_SPARCV9: reltype = R_SPARC_64; break; case EM_X86_64: make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_64; reltype = R_X86_64_64; rel_type_nop = R_X86_64_NONE; mcount_adjust_64 = -1; + gpfx = 0; break; } /* end switch */ @@ -543,20 +552,20 @@ do_file(char const *const fname) default: fprintf(stderr, "unrecognized ELF class %d %s\n", ehdr->e_ident[EI_CLASS], fname); - fail_file(); - break; + goto out; case ELFCLASS32: if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { fprintf(stderr, "unrecognized ET_REL file: %s\n", fname); - fail_file(); + goto out; } if (w2(ehdr->e_machine) == EM_MIPS) { reltype = R_MIPS_32; is_fake_mcount32 = MIPS32_is_fake_mcount; } - do32(ehdr, fname, reltype); + if (do32(ehdr, fname, reltype) < 0) + goto out; break; case ELFCLASS64: { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; @@ -564,7 +573,7 @@ do_file(char const *const fname) || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { fprintf(stderr, "unrecognized ET_REL file: %s\n", fname); - fail_file(); + goto out; } if (w2(ghdr->e_machine) == EM_S390) { reltype = R_390_64; @@ -576,17 +585,20 @@ do_file(char const *const fname) Elf64_r_info = MIPS64_r_info; is_fake_mcount64 = MIPS64_is_fake_mcount; } - do64(ghdr, fname, reltype); + if (do64(ghdr, fname, reltype) < 0) + goto out; break; } } /* end switch */ - write_file(fname); - cleanup(); + rc = write_file(fname); +out: + file_append_cleanup(); + mmap_cleanup(); + return rc; } -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { const char ftrace[] = "/ftrace.o"; int ftrace_size = sizeof(ftrace) - 1; @@ -613,7 +625,6 @@ main(int argc, char *argv[]) /* Process each file in turn, allowing deep failure. */ for (i = optind; i < argc; i++) { char *file = argv[i]; - int const sjval = setjmp(jmpenv); int len; /* @@ -626,28 +637,10 @@ main(int argc, char *argv[]) strcmp(file + (len - ftrace_size), ftrace) == 0) continue; - switch (sjval) { - default: - fprintf(stderr, "internal error: %s\n", file); - exit(1); - break; - case SJ_SETJMP: /* normal sequence */ - /* Avoid problems if early cleanup() */ - fd_map = -1; - mmap_failed = 1; - file_map = NULL; - file_ptr = NULL; - file_updated = 0; - do_file(file); - break; - case SJ_FAIL: /* error in do_file or below */ + if (do_file(file)) { fprintf(stderr, "%s: failed\n", file); ++n_error; - break; - case SJ_SUCCEED: /* premature success */ - /* do nothing */ - break; - } /* end switch */ + } } return !!n_error; } diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 47fca2c69a73..8f0a278ce0af 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -174,7 +174,7 @@ static int MIPS_is_fake_mcount(Elf_Rel const *rp) } /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ -static void append_func(Elf_Ehdr *const ehdr, +static int append_func(Elf_Ehdr *const ehdr, Elf_Shdr *const shstr, uint_t const *const mloc0, uint_t const *const mlocp, @@ -202,15 +202,20 @@ static void append_func(Elf_Ehdr *const ehdr, new_e_shoff = t; /* body for new shstrtab */ - ulseek(fd_map, sb.st_size, SEEK_SET); - uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size); - uwrite(fd_map, mc_name, 1 + strlen(mc_name)); + if (ulseek(sb.st_size, SEEK_SET) < 0) + return -1; + if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0) + return -1; + if (uwrite(mc_name, 1 + strlen(mc_name)) < 0) + return -1; /* old(modified) Elf_Shdr table, word-byte aligned */ - ulseek(fd_map, t, SEEK_SET); + if (ulseek(t, SEEK_SET) < 0) + return -1; t += sizeof(Elf_Shdr) * old_shnum; - uwrite(fd_map, old_shoff + (void *)ehdr, - sizeof(Elf_Shdr) * old_shnum); + if (uwrite(old_shoff + (void *)ehdr, + sizeof(Elf_Shdr) * old_shnum) < 0) + return -1; /* new sections __mcount_loc and .rel__mcount_loc */ t += 2*sizeof(mcsec); @@ -225,7 +230,8 @@ static void append_func(Elf_Ehdr *const ehdr, mcsec.sh_info = 0; mcsec.sh_addralign = _w(_size); mcsec.sh_entsize = _w(_size); - uwrite(fd_map, &mcsec, sizeof(mcsec)); + if (uwrite(&mcsec, sizeof(mcsec)) < 0) + return -1; mcsec.sh_name = w(old_shstr_sh_size); mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize) @@ -239,15 +245,22 @@ static void append_func(Elf_Ehdr *const ehdr, mcsec.sh_info = w(old_shnum); mcsec.sh_addralign = _w(_size); mcsec.sh_entsize = _w(rel_entsize); - uwrite(fd_map, &mcsec, sizeof(mcsec)); - uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0); - uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0); + if (uwrite(&mcsec, sizeof(mcsec)) < 0) + return -1; + + if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0) + return -1; + if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0) + return -1; ehdr->e_shoff = _w(new_e_shoff); ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */ - ulseek(fd_map, 0, SEEK_SET); - uwrite(fd_map, ehdr, sizeof(*ehdr)); + if (ulseek(0, SEEK_SET) < 0) + return -1; + if (uwrite(ehdr, sizeof(*ehdr)) < 0) + return -1; + return 0; } static unsigned get_mcountsym(Elf_Sym const *const sym0, @@ -351,9 +364,9 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, * that are not going to be traced. The mcount calls here will be converted * into nops. */ -static void nop_mcount(Elf_Shdr const *const relhdr, - Elf_Ehdr const *const ehdr, - const char *const txtname) +static int nop_mcount(Elf_Shdr const *const relhdr, + Elf_Ehdr const *const ehdr, + const char *const txtname) { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); @@ -376,15 +389,18 @@ static void nop_mcount(Elf_Shdr const *const relhdr, mcountsym = get_mcountsym(sym0, relp, str0); if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { - if (make_nop) + if (make_nop) { ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset)); + if (ret < 0) + return -1; + } if (warn_on_notrace_sect && !once) { printf("Section %s has mcount callers being ignored\n", txtname); once = 1; /* just warn? */ if (!make_nop) - return; + return 0; } } @@ -396,14 +412,16 @@ static void nop_mcount(Elf_Shdr const *const relhdr, Elf_Rel rel; rel = *(Elf_Rel *)relp; Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop); - ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET); - uwrite(fd_map, &rel, sizeof(rel)); + if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0) + return -1; + if (uwrite(&rel, sizeof(rel)) < 0) + return -1; } relp = (Elf_Rel const *)(rel_entsize + (void *)relp); } + return 0; } - /* * Find a symbol in the given section, to be used as the base for relocating * the table of offsets of calls to mcount. A local or global symbol suffices, @@ -414,9 +432,10 @@ static void nop_mcount(Elf_Shdr const *const relhdr, * Num: Value Size Type Bind Vis Ndx Name * 2: 00000000 0 SECTION LOCAL DEFAULT 1 */ -static unsigned find_secsym_ndx(unsigned const txtndx, +static int find_secsym_ndx(unsigned const txtndx, char const *const txtname, uint_t *const recvalp, + unsigned int *sym_index, Elf_Shdr const *const symhdr, Elf_Ehdr const *const ehdr) { @@ -438,21 +457,20 @@ static unsigned find_secsym_ndx(unsigned const txtndx, continue; *recvalp = _w(symp->st_value); - return symp - sym0; + *sym_index = symp - sym0; + return 0; } } fprintf(stderr, "Cannot find symbol for section %u: %s.\n", txtndx, txtname); - fail_file(); + return -1; } - /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */ -static char const * -__has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ - Elf_Shdr const *const shdr0, - char const *const shstrtab, - char const *const fname) +static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */ + Elf_Shdr const *const shdr0, + char const *const shstrtab, + char const *const fname) { /* .sh_info depends on .sh_type == SHT_REL[,A] */ Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; @@ -461,7 +479,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ if (strcmp("__mcount_loc", txtname) == 0) { fprintf(stderr, "warning: __mcount_loc already exists: %s\n", fname); - succeed_file(); + return already_has_rel_mcount; } if (w(txthdr->sh_type) != SHT_PROGBITS || !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) @@ -491,6 +509,10 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0, for (; nhdr; --nhdr, ++shdrp) { txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname); + if (txtname == already_has_rel_mcount) { + totrelsz = 0; + break; + } if (txtname && is_mcounted_section_name(txtname)) totrelsz += _w(shdrp->sh_size); } @@ -499,8 +521,8 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0, /* Overall supervision for Elf32 ET_REL file. */ -static void -do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) +static int do_func(Elf_Ehdr *const ehdr, char const *const fname, + unsigned const reltype) { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); @@ -513,26 +535,54 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) unsigned k; /* Upper bound on space: assume all relevant relocs are for mcount. */ - unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); - Elf_Rel *const mrel0 = umalloc(totrelsz); - Elf_Rel * mrelp = mrel0; + unsigned totrelsz; - /* 2*sizeof(address) <= sizeof(Elf_Rel) */ - uint_t *const mloc0 = umalloc(totrelsz>>1); - uint_t * mlocp = mloc0; + Elf_Rel * mrel0; + Elf_Rel * mrelp; + + uint_t * mloc0; + uint_t * mlocp; unsigned rel_entsize = 0; unsigned symsec_sh_link = 0; + int result = 0; + + totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); + if (totrelsz == 0) + return 0; + mrel0 = umalloc(totrelsz); + mrelp = mrel0; + if (!mrel0) + return -1; + + /* 2*sizeof(address) <= sizeof(Elf_Rel) */ + mloc0 = umalloc(totrelsz>>1); + mlocp = mloc0; + if (!mloc0) { + free(mrel0); + return -1; + } + for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { char const *const txtname = has_rel_mcount(relhdr, shdr0, shstrtab, fname); + if (txtname == already_has_rel_mcount) { + result = 0; + file_updated = 0; + goto out; /* Nothing to be done; don't append! */ + } if (txtname && is_mcounted_section_name(txtname)) { + unsigned int recsym; uint_t recval = 0; - unsigned const recsym = find_secsym_ndx( - w(relhdr->sh_info), txtname, &recval, - &shdr0[symsec_sh_link = w(relhdr->sh_link)], - ehdr); + + symsec_sh_link = w(relhdr->sh_link); + result = find_secsym_ndx(w(relhdr->sh_info), txtname, + &recval, &recsym, + &shdr0[symsec_sh_link], + ehdr); + if (result) + goto out; rel_entsize = _w(relhdr->sh_entsize); mlocp = sift_rel_mcount(mlocp, @@ -543,13 +593,17 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) * This section is ignored by ftrace, but still * has mcount calls. Convert them to nops now. */ - nop_mcount(relhdr, ehdr, txtname); + if (nop_mcount(relhdr, ehdr, txtname) < 0) { + result = -1; + goto out; + } } } - if (mloc0 != mlocp) { - append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp, - rel_entsize, symsec_sh_link); - } + if (!result && mloc0 != mlocp) + result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp, + rel_entsize, symsec_sh_link); +out: free(mrel0); free(mloc0); + return result; } diff --git a/scripts/tools-support-relr.sh b/scripts/tools-support-relr.sh new file mode 100755 index 000000000000..97a2c844a95e --- /dev/null +++ b/scripts/tools-support-relr.sh @@ -0,0 +1,16 @@ +#!/bin/sh -eu +# SPDX-License-Identifier: GPL-2.0 + +tmp_file=$(mktemp) +trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT + +cat << "END" | "$CC" -c -x c - -o $tmp_file.o >/dev/null 2>&1 +void *p = &p; +END +"$LD" $tmp_file.o -shared -Bsymbolic --pack-dyn-relocs=relr -o $tmp_file + +# Despite printing an error message, GNU nm still exits with exit code 0 if it +# sees a relr section. So we need to check that nothing is printed to stderr. +test -z "$("$NM" $tmp_file 2>&1 >/dev/null)" + +"$OBJCOPY" -O binary $tmp_file $tmp_file.bin |