diff options
Diffstat (limited to 'scripts')
184 files changed, 4617 insertions, 3271 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index e83c620ef52c..b7aec8eb1bd4 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only /asn1_compiler /bin2c -/extract-cert +/generate_rust_target /insert-sys-cert /kallsyms /module.lds diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index cdec22088423..2bc08ace38a3 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -16,6 +16,10 @@ pound := \# dot-target = $(dir $@).$(notdir $@) ### +# Name of target with a '.tmp_' as filename prefix. foo/bar.o => foo/.tmp_bar.o +tmp-target = $(dir $@).tmp_$(notdir $@) + +### # The temporary file to save gcc -MMD generated dependencies must not # contain a comma depfile = $(subst $(comma),_,$(dot-target).d) @@ -96,8 +100,29 @@ echo-cmd = $(if $($(quiet)cmd_$(1)),\ quiet_redirect := silent_redirect := exec >/dev/null; +# Delete the target on interruption +# +# GNU Make automatically deletes the target if it has already been changed by +# the interrupted recipe. So, you can safely stop the build by Ctrl-C (Make +# will delete incomplete targets), and resume it later. +# +# However, this does not work when the stderr is piped to another program, like +# $ make >&2 | tee log +# Make dies with SIGPIPE before cleaning the targets. +# +# To address it, we clean the target in signal traps. +# +# Make deletes the target when it catches SIGHUP, SIGINT, SIGQUIT, SIGTERM. +# So, we cover them, and also SIGPIPE just in case. +# +# Of course, this is unneeded for phony targets. +delete-on-interrupt = \ + $(if $(filter-out $(PHONY), $@), \ + $(foreach sig, HUP INT QUIT TERM PIPE, \ + trap 'rm -f $@; trap - $(sig); kill -s $(sig) $$$$' $(sig);)) + # printing commands -cmd = @set -e; $(echo-cmd) $($(quiet)redirect) $(cmd_$(1)) +cmd = @set -e; $(echo-cmd) $($(quiet)redirect) $(delete-on-interrupt) $(cmd_$(1)) ### # if_changed - execute command if any prerequisite is newer than @@ -138,9 +163,11 @@ check-FORCE = $(if $(filter FORCE, $^),,$(warning FORCE prerequisite is missing) if-changed-cond = $(newer-prereqs)$(cmd-check)$(check-FORCE) # Execute command if command has changed or prerequisite(s) are updated. -if_changed = $(if $(if-changed-cond), \ +if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:) + +cmd_and_savecmd = \ $(cmd); \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) + printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd # Execute the command and also postprocess generated .d dependencies file. if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:) @@ -196,53 +223,6 @@ echo-why = $(call escsq, $(strip $(why))) endif ############################################################################### -# -# When a Kconfig string contains a filename, it is suitable for -# passing to shell commands. It is surrounded by double-quotes, and -# any double-quotes or backslashes within it are escaped by -# backslashes. -# -# This is no use for dependencies or $(wildcard). We need to strip the -# surrounding quotes and the escaping from quotes and backslashes, and -# we *do* need to escape any spaces in the string. So, for example: -# -# Usage: $(eval $(call config_filename,FOO)) -# -# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option, -# transformed as described above to be suitable for use within the -# makefile. -# -# Also, if the filename is a relative filename and exists in the source -# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to -# be prefixed to *both* command invocation and dependencies. -# -# Note: We also print the filenames in the quiet_cmd_foo text, and -# perhaps ought to have a version specially escaped for that purpose. -# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good -# enough. It'll strip the quotes in the common case where there's no -# space and it's a simple filename, and it'll retain the quotes when -# there's a space. There are some esoteric cases in which it'll print -# the wrong thing, but we don't really care. The actual dependencies -# and commands *do* get it right, with various combinations of single -# and double quotes, backslashes and spaces in the filenames. -# -############################################################################### -# -define config_filename -ifneq ($$(CONFIG_$(1)),"") -$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1))))))) -ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME))) -else -ifeq ($$(wildcard $$($(1)_FILENAME)),) -ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),) -$(1)_SRCPREFIX := $(srctree)/ -endif -endif -endif -endif -endef -# -############################################################################### # delete partially updated (i.e. corrupted) files on error .DELETE_ON_ERROR: diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 0496efd6e117..274125307ebd 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,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o) +cc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o) # $(ld-option,<flag>) # Return y if the linker supports <flag>, n otherwise @@ -36,12 +36,12 @@ ld-option = $(success,$(LD) -v $(1)) as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler -o /dev/null -) # check if $(CC) and $(LD) exist -$(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found) +$(error-if,$(failure,command -v $(CC)),C compiler '$(CC)' not found) $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) -# Get the compiler name, version, and error out if it is not supported. +# Get the C compiler name, version, and error out if it is not supported. cc-info := $(shell,$(srctree)/scripts/cc-version.sh $(CC)) -$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this compiler is not supported.) +$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this C compiler is not supported.) cc-name := $(shell,set -- $(cc-info) && echo $1) cc-version := $(shell,set -- $(cc-info) && echo $2) diff --git a/scripts/Makefile b/scripts/Makefile index 9adb6d247818..1575af84d557 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -3,25 +3,22 @@ # scripts contains sources for various helper programs used throughout # the kernel for the build process. -CRYPTO_LIBS = $(shell pkg-config --libs libcrypto 2> /dev/null || echo -lcrypto) -CRYPTO_CFLAGS = $(shell pkg-config --cflags libcrypto 2> /dev/null) - hostprogs-always-$(CONFIG_BUILD_BIN2C) += bin2c hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable hostprogs-always-$(CONFIG_ASN1) += asn1_compiler hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file -hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert -hostprogs-always-$(CONFIG_SYSTEM_REVOCATION_LIST) += extract-cert +hostprogs-always-$(CONFIG_RUST) += generate_rust_target + +generate_rust_target-rust := y HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include +HOSTLDLIBS_sorttable = -lpthread HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include -HOSTCFLAGS_sign-file.o = $(CRYPTO_CFLAGS) -HOSTLDLIBS_sign-file = $(CRYPTO_LIBS) -HOSTCFLAGS_extract-cert.o = $(CRYPTO_CFLAGS) -HOSTLDLIBS_extract-cert = $(CRYPTO_LIBS) +HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null) +HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto) ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) @@ -29,7 +26,10 @@ ARCH := x86 endif HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED -HOSTLDLIBS_sorttable = -lpthread +endif + +ifdef CONFIG_BUILDTIME_MCOUNT_SORT +HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED endif # The following programs are only built on demand diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 78656b527fe5..41f3602fc8de 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -5,8 +5,8 @@ src := $(obj) -PHONY := __build -__build: +PHONY := $(obj)/ +$(obj)/: # Init all relevant variables used in kbuild files so # 1) they have correct type @@ -26,6 +26,7 @@ EXTRA_CPPFLAGS := EXTRA_LDFLAGS := asflags-y := ccflags-y := +rustflags-y := cppflags-y := ldflags-y := @@ -40,8 +41,7 @@ include $(srctree)/scripts/Makefile.compiler # The filename Kbuild has precedence over Makefile kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) -include $(kbuild-file) +include $(or $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Makefile) include $(srctree)/scripts/Makefile.lib @@ -86,11 +86,8 @@ ifdef need-builtin targets-for-builtin += $(obj)/built-in.a endif -targets-for-modules := $(patsubst %.o, %.mod, $(filter %.o, $(obj-m))) - -ifdef CONFIG_LTO_CLANG -targets-for-modules += $(patsubst %.o, %.lto.o, $(filter %.o, $(obj-m))) -endif +targets-for-modules := $(foreach x, o mod $(if $(CONFIG_TRIM_UNUSED_KSYMS), usyms), \ + $(patsubst %.o, %.$x, $(filter %.o, $(obj-m)))) ifdef need-modorder targets-for-modules += $(obj)/modules.order @@ -126,18 +123,16 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(src)/%.c FORCE $(call if_changed_dep,cpp_i_c) +genksyms = scripts/genksyms/genksyms \ + $(if $(1), -T $(2)) \ + $(if $(KBUILD_PRESERVE), -p) \ + -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null) + # These mirror gensymtypes_S and co below, keep them in synch. -cmd_gensymtypes_c = \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ - scripts/genksyms/genksyms $(if $(1), -T $(2)) \ - $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ - $(if $(KBUILD_PRESERVE),-p) \ - -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) +cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms) quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_c = \ - $(call cmd_gensymtypes_c,true,$@) >/dev/null; \ - test -s $@ || rm -f $@ + cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null $(obj)/%.symtypes : $(src)/%.c FORCE $(call cmd,cc_symtypes_c) @@ -145,7 +140,7 @@ $(obj)/%.symtypes : $(src)/%.c FORCE # LLVM assembly # Generate .ll files from .c quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@ - cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -o $@ $< + cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -fno-discard-value-names -o $@ $< $(obj)/%.ll: $(src)/%.c FORCE $(call if_changed_dep,cc_ll_c) @@ -154,8 +149,18 @@ $(obj)/%.ll: $(src)/%.c FORCE # The C file is compiled and updated dependency information is generated. # (See cmd_cc_o_c + relevant part of rule_cc_o_c) +is-single-obj-m = $(and $(part-of-module),$(filter $@, $(obj-m)),y) + +# When a module consists of a single object, there is no reason to keep LLVM IR. +# Make $(LD) covert LLVM IR to ELF here. +ifdef CONFIG_LTO_CLANG +cmd_ld_single_m = $(if $(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@) +endif + quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< $(cmd_objtool) + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \ + $(cmd_ld_single_m) \ + $(cmd_objtool) ifdef CONFIG_MODVERSIONS # When module versioning is enabled the following steps are executed: @@ -163,35 +168,18 @@ ifdef CONFIG_MODVERSIONS # o if <file>.o doesn't contain a __ksymtab version, i.e. does # not export symbols, it's done. # o otherwise, we calculate symbol versions using the good old -# genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate .tmp_<file>.o from <file>.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms -# o remove .tmp_<file>.o to <file>.o +# genksyms on the preprocessed source and dump them into the .cmd file. +# o modpost will extract versions from that file and create *.c files that will +# be compiled and linked to the kernel and/or modules. -ifdef CONFIG_LTO_CLANG -# Generate .o.symversions files for each .o with exported symbols, and link these -# to the kernel and/or modules at the end. -cmd_modversions_c = \ +gen_symversions = \ if $(NM) $@ 2>/dev/null | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $@.symversions; \ - else \ - rm -f $@.symversions; \ - fi; -else -cmd_modversions_c = \ - if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - mv -f $(@D)/.tmp_$(@F) $@; \ - rm -f $(@D)/.tmp_$(@F:.o=.ver); \ + $(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ + >> $(dot-target).cmd; \ fi -endif + +cmd_gen_symversions_c = $(call gen_symversions,c) + endif ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT @@ -223,63 +211,38 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), $(sub_cmd_record_mcount)) endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT -ifdef CONFIG_STACK_VALIDATION - -objtool := $(objtree)/tools/objtool/objtool - -objtool_args = \ - $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ - $(if $(part-of-module), --module) \ - $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ - $(if $(CONFIG_GCOV_KERNEL)$(CONFIG_LTO_CLANG), --no-unreachable)\ - $(if $(CONFIG_RETPOLINE), --retpoline) \ - $(if $(CONFIG_X86_SMAP), --uaccess) \ - $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) - -cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) -cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) - -endif # CONFIG_STACK_VALIDATION - -ifdef CONFIG_LTO_CLANG - -# Skip objtool for LLVM bitcode -$(obj)/%.o: objtool-enabled := - -else - # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file -$(obj)/%.o: objtool-enabled = $(if $(filter-out y%, \ - $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) +is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) -endif +$(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) ifdef CONFIG_TRIM_UNUSED_KSYMS cmd_gen_ksymdeps = \ $(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd - -# List module undefined symbols -undefined_syms = $(NM) $< | $(AWK) '$$1 == "U" { printf("%s%s", x++ ? " " : "", $$2) }'; endif +cmd_check_local_export = $(srctree)/scripts/check-local-export $@ + define rule_cc_o_c $(call cmd_and_fixdep,cc_o_c) $(call cmd,gen_ksymdeps) + $(call cmd,check_local_export) $(call cmd,checksrc) $(call cmd,checkdoc) $(call cmd,gen_objtooldep) - $(call cmd,modversions_c) + $(call cmd,gen_symversions_c) $(call cmd,record_mcount) endef define rule_as_o_S $(call cmd_and_fixdep,as_o_S) $(call cmd,gen_ksymdeps) + $(call cmd,check_local_export) $(call cmd,gen_objtooldep) - $(call cmd,modversions_S) + $(call cmd,gen_symversions_S) endef # Built-in and composite module parts @@ -287,33 +250,19 @@ $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE $(call if_changed_rule,cc_o_c) $(call cmd,force_checksrc) -ifdef CONFIG_LTO_CLANG -# Module .o files may contain LLVM bitcode, compile them into native code -# before ELF processing -quiet_cmd_cc_lto_link_modules = LTO [M] $@ -cmd_cc_lto_link_modules = \ - $(LD) $(ld_flags) -r -o $@ \ - $(shell [ -s $(@:.lto.o=.o.symversions) ] && \ - echo -T $(@:.lto.o=.o.symversions)) \ - --whole-archive $(filter-out FORCE,$^) \ - $(cmd_objtool) - -# objtool was skipped for LLVM bitcode, run it now that we have compiled -# modules into native code -$(obj)/%.lto.o: objtool-enabled = y -$(obj)/%.lto.o: part-of-module := y +# To make this rule robust against "Argument list too long" error, +# ensure to add $(obj)/ prefix by a shell command. +cmd_mod = printf '%s\n' $(call real-search, $*.o, .o, -objs -y -m) | \ + $(AWK) '!x[$$0]++ { print("$(obj)/"$$0) }' > $@ -$(obj)/%.lto.o: $(obj)/%.o FORCE - $(call if_changed,cc_lto_link_modules) -endif +$(obj)/%.mod: FORCE + $(call if_changed,mod) -cmd_mod = { \ - echo $(if $($*-objs)$($*-y)$($*-m), $(addprefix $(obj)/, $($*-objs) $($*-y) $($*-m)), $(@:.mod=.o)); \ - $(undefined_syms) echo; \ - } > $@ +# List module undefined symbols +cmd_undefined_syms = $(NM) $< | sed -n 's/^ *U //p' > $@ -$(obj)/%.mod: $(obj)/%$(mod-prelink-ext).o FORCE - $(call if_changed,mod) +$(obj)/%.usyms: $(obj)/%.o FORCE + $(call if_changed,undefined_syms) quiet_cmd_cc_lst_c = MKLST $@ cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \ @@ -323,6 +272,65 @@ quiet_cmd_cc_lst_c = MKLST $@ $(obj)/%.lst: $(src)/%.c FORCE $(call if_changed_dep,cc_lst_c) +# Compile Rust sources (.rs) +# --------------------------------------------------------------------------- + +rust_allowed_features := core_ffi_c + +rust_common_cmd = \ + RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \ + -Zallow-features=$(rust_allowed_features) \ + -Zcrate-attr=no_std \ + -Zcrate-attr='feature($(rust_allowed_features))' \ + --extern alloc --extern kernel \ + --crate-type rlib --out-dir $(obj) -L $(objtree)/rust/ \ + --crate-name $(basename $(notdir $@)) + +rust_handle_depfile = \ + mv $(obj)/$(basename $(notdir $@)).d $(depfile); \ + sed -i '/^\#/d' $(depfile) + +# `--emit=obj`, `--emit=asm` and `--emit=llvm-ir` imply a single codegen unit +# will be used. We explicitly request `-Ccodegen-units=1` in any case, and +# the compiler shows a warning if it is not 1. However, if we ever stop +# requesting it explicitly and we start using some other `--emit` that does not +# imply it (and for which codegen is performed), then we would be out of sync, +# i.e. the outputs we would get for the different single targets (e.g. `.ll`) +# would not match each other. + +quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_o_rs = \ + $(rust_common_cmd) --emit=dep-info,obj $<; \ + $(rust_handle_depfile) + +$(obj)/%.o: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_o_rs) + +quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_rsi_rs = \ + $(rust_common_cmd) --emit=dep-info -Zunpretty=expanded $< >$@; \ + command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@; \ + $(rust_handle_depfile) + +$(obj)/%.rsi: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_rsi_rs) + +quiet_cmd_rustc_s_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_s_rs = \ + $(rust_common_cmd) --emit=dep-info,asm $<; \ + $(rust_handle_depfile) + +$(obj)/%.s: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_s_rs) + +quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_ll_rs = \ + $(rust_common_cmd) --emit=dep-info,llvm-ir $<; \ + $(rust_handle_depfile) + +$(obj)/%.ll: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_ll_rs) + # Compile assembler sources (.S) # --------------------------------------------------------------------------- @@ -343,16 +351,10 @@ cmd_gensymtypes_S = \ $(CPP) $(a_flags) $< | \ grep "\<___EXPORT_SYMBOL\>" | \ sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ; } | \ - $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \ - scripts/genksyms/genksyms $(if $(1), -T $(2)) \ - $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ - $(if $(KBUILD_PRESERVE),-p) \ - -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) + $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms) quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_S = \ - $(call cmd_gensymtypes_S,true,$@) >/dev/null; \ - test -s $@ || rm -f $@ + cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null $(obj)/%.symtypes : $(src)/%.S FORCE $(call cmd,cc_symtypes_S) @@ -372,16 +374,8 @@ 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. -cmd_modversions_S = \ - if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - mv -f $(@D)/.tmp_$(@F) $@; \ - rm -f $(@D)/.tmp_$(@F:.o=.ver); \ - fi +cmd_gen_symversions_S = $(call gen_symversions,S) + endif $(obj)/%.o: $(src)/%.S FORCE @@ -389,7 +383,7 @@ $(obj)/%.o: $(src)/%.S FORCE targets += $(filter-out $(subdir-builtin), $(real-obj-y)) targets += $(filter-out $(subdir-modorder), $(real-obj-m)) -targets += $(real-dtb-y) $(lib-y) $(always-y) $(MAKECMDGOALS) +targets += $(real-dtb-y) $(lib-y) $(always-y) # Linker scripts preprocessor (.lds.S -> .lds) # --------------------------------------------------------------------------- @@ -416,29 +410,19 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler $(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ; $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ; -# combine symversions for later processing -ifeq ($(CONFIG_LTO_CLANG) $(CONFIG_MODVERSIONS),y y) - cmd_update_lto_symversions = \ - rm -f $@.symversions \ - $(foreach n, $(filter-out FORCE,$^), \ - $(if $(shell test -s $(n).symversions && echo y), \ - ; cat $(n).symversions >> $@.symversions)) -else - cmd_update_lto_symversions = echo >/dev/null -endif - # # Rule to compile a set of .o files into one .a file (without symbol table) # +# To make this rule robust against "Argument list too long" error, +# remove $(obj)/ prefix, and restore it by a shell command. quiet_cmd_ar_builtin = AR $@ - cmd_ar_builtin = rm -f $@; $(AR) cDPrST $@ $(real-prereqs) - -quiet_cmd_ar_and_symver = AR $@ - cmd_ar_and_symver = $(cmd_update_lto_symversions); $(cmd_ar_builtin) + cmd_ar_builtin = rm -f $@; \ + $(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \ + $(AR) cDPrST $@ $(obj)/built-in.a: $(real-obj-y) FORCE - $(call if_changed,ar_and_symver) + $(call if_changed,ar_builtin) # # Rule to create modules.order file @@ -450,7 +434,7 @@ $(obj)/built-in.a: $(real-obj-y) FORCE cmd_modules_order = { $(foreach m, $(real-prereqs), \ $(if $(filter %/modules.order, $m), cat $m, echo $(patsubst %.o,%.ko,$m));) :; } \ - | $(AWK) '!x[$$0]++' - > $@ + > $@ $(obj)/modules.order: $(obj-m) FORCE $(call if_changed,modules_order) @@ -458,33 +442,23 @@ $(obj)/modules.order: $(obj-m) FORCE # # Rule to compile a set of .o files into one .a file (with symbol table) # -quiet_cmd_ar_lib = AR $@ - cmd_ar_lib = $(cmd_update_lto_symversions); $(cmd_ar) $(obj)/lib.a: $(lib-y) FORCE - $(call if_changed,ar_lib) + $(call if_changed,ar) -# NOTE: -# Do not replace $(filter %.o,^) with $(real-prereqs). When a single object -# module is turned into a multi object module, $^ will contain header file -# dependencies recorded in the .*.cmd file. -ifdef CONFIG_LTO_CLANG -quiet_cmd_link_multi-m = AR [M] $@ -cmd_link_multi-m = \ - $(cmd_update_lto_symversions); \ - rm -f $@; \ - $(AR) cDPrsT $@ $(filter %.o,$^) -else -quiet_cmd_link_multi-m = LD [M] $@ - cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^) -endif +quiet_cmd_ld_multi_m = LD [M] $@ + cmd_ld_multi_m = $(LD) $(ld_flags) -r -o $@ @$(patsubst %.o,%.mod,$@) $(cmd_objtool) -$(multi-obj-m): FORCE - $(call if_changed,link_multi-m) -$(call multi_depend, $(multi-obj-m), .o, -objs -y -m) +define rule_ld_multi_m + $(call cmd_and_savecmd,ld_multi_m) + $(call cmd,gen_objtooldep) +endef -targets += $(multi-obj-m) -targets := $(filter-out $(PHONY), $(targets)) +$(multi-obj-m): objtool-enabled := $(delay-objtool) +$(multi-obj-m): part-of-module := y +$(multi-obj-m): %.o: %.mod FORCE + $(call if_changed_rule,ld_multi_m) +$(call multi_depend, $(multi-obj-m), .o, -objs -y -m) # Add intermediate targets: # When building objects with specific suffix patterns, add intermediate @@ -504,52 +478,29 @@ targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \ # Build # --------------------------------------------------------------------------- -ifdef single-build - -KBUILD_SINGLE_TARGETS := $(filter $(obj)/%, $(KBUILD_SINGLE_TARGETS)) - -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-out $(curdir-single), $(KBUILD_SINGLE_TARGETS))) - -single-subdirs := $(foreach d, $(subdir-ym), \ - $(if $(filter $(d)/%, $(KBUILD_SINGLE_TARGETS)), $(d))) - -__build: $(curdir-single) $(single-subdirs) -ifneq ($(unknown-single),) - $(Q)$(MAKE) -f /dev/null $(unknown-single) -endif +$(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \ + $(if $(KBUILD_MODULES), $(targets-for-modules)) \ + $(subdir-ym) $(always-y) @: -ifeq ($(curdir-single),) -# Nothing to do in this directory. Do not include any .*.cmd file for speed-up -targets := -else -targets += $(curdir-single) -endif +# Single targets +# --------------------------------------------------------------------------- -else +single-subdirs := $(foreach d, $(subdir-ym), $(if $(filter $d/%, $(MAKECMDGOALS)), $d)) +single-subdir-goals := $(filter $(addsuffix /%, $(single-subdirs)), $(MAKECMDGOALS)) -__build: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \ - $(if $(KBUILD_MODULES), $(targets-for-modules)) \ - $(subdir-ym) $(always-y) +$(single-subdir-goals): $(single-subdirs) @: -endif - # Descending # --------------------------------------------------------------------------- PHONY += $(subdir-ym) $(subdir-ym): $(Q)$(MAKE) $(build)=$@ \ - $(if $(filter $@/, $(KBUILD_SINGLE_TARGETS)),single-build=) \ need-builtin=$(if $(filter $@/built-in.a, $(subdir-builtin)),1) \ - need-modorder=$(if $(filter $@/modules.order, $(subdir-modorder)),1) + need-modorder=$(if $(filter $@/modules.order, $(subdir-modorder)),1) \ + $(filter $@/%, $(single-subdir-goals)) # Add FORCE to the prequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- @@ -558,6 +509,9 @@ PHONY += FORCE FORCE: +targets += $(filter-out $(single-subdir-goals), $(MAKECMDGOALS)) +targets := $(filter-out $(PHONY), $(targets)) + # 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 diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang index 51fc23e2e9e5..87285b76adb2 100644 --- a/scripts/Makefile.clang +++ b/scripts/Makefile.clang @@ -10,6 +10,7 @@ CLANG_TARGET_FLAGS_powerpc := powerpc64le-linux-gnu CLANG_TARGET_FLAGS_riscv := riscv64-linux-gnu CLANG_TARGET_FLAGS_s390 := s390x-linux-gnu CLANG_TARGET_FLAGS_x86 := x86_64-linux-gnu +CLANG_TARGET_FLAGS_um := $(CLANG_TARGET_FLAGS_$(SUBARCH)) CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(SRCARCH)) ifeq ($(CROSS_COMPILE),) diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index fd6175322470..878cec648959 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -12,7 +12,7 @@ include $(srctree)/scripts/Kbuild.include # The filename Kbuild has precedence over Makefile kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile) +include $(or $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Makefile) # Figure out what we need to build from the various variables # ========================================================================== @@ -36,13 +36,7 @@ __clean-files := \ __clean-files := $(filter-out $(no-clean-files), $(__clean-files)) -# clean-files is given relative to the current directory, unless it -# starts with $(objtree)/ (which means "./", so do not add "./" unless -# you want to delete a file from the toplevel object directory). - -__clean-files := $(wildcard \ - $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \ - $(filter $(objtree)/%, $(__clean-files))) +__clean-files := $(wildcard $(addprefix $(obj)/, $(__clean-files))) # ========================================================================== diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler index 86ecd2ac874c..20d353dcabfb 100644 --- a/scripts/Makefile.compiler +++ b/scripts/Makefile.compiler @@ -21,8 +21,8 @@ TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$ # automatically cleaned up. try-run = $(shell set -e; \ TMP=$(TMPOUT)/tmp; \ - mkdir -p $(TMPOUT); \ trap "rm -rf $(TMPOUT)" EXIT; \ + mkdir -p $(TMPOUT); \ if ($(1)) >/dev/null 2>&1; \ then echo "$(2)"; \ else echo "$(3)"; \ @@ -61,9 +61,13 @@ cc-option-yn = $(call try-run,\ cc-disable-warning = $(call try-run,\ $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) -# cc-ifversion -# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) -cc-ifversion = $(shell [ $(CONFIG_GCC_VERSION)0 $(1) $(2)000 ] && echo $(3) || echo $(4)) +# gcc-min-version +# Usage: cflags-$(call gcc-min-version, 70100) += -foo +gcc-min-version = $(shell [ $(CONFIG_GCC_VERSION)0 -ge $(1)0 ] && echo y) + +# clang-min-version +# Usage: cflags-$(call clang-min-version, 110000) += -foo +clang-min-version = $(shell [ $(CONFIG_CLANG_VERSION)0 -ge $(1)0 ] && echo y) # ld-option # Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y) diff --git a/scripts/Makefile.debug b/scripts/Makefile.debug index 9f39b0130551..332c486f705f 100644 --- a/scripts/Makefile.debug +++ b/scripts/Makefile.debug @@ -1,26 +1,30 @@ DEBUG_CFLAGS := +DEBUG_RUSTFLAGS := + +debug-flags-y := -g ifdef CONFIG_DEBUG_INFO_SPLIT DEBUG_CFLAGS += -gsplit-dwarf -else -DEBUG_CFLAGS += -g -endif - -ifndef CONFIG_AS_IS_LLVM -KBUILD_AFLAGS += -Wa,-gdwarf-2 endif -ifndef CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT -dwarf-version-$(CONFIG_DEBUG_INFO_DWARF4) := 4 -dwarf-version-$(CONFIG_DEBUG_INFO_DWARF5) := 5 -DEBUG_CFLAGS += -gdwarf-$(dwarf-version-y) +debug-flags-$(CONFIG_DEBUG_INFO_DWARF4) += -gdwarf-4 +debug-flags-$(CONFIG_DEBUG_INFO_DWARF5) += -gdwarf-5 +ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_AS_IS_GNU),yy) +# Clang does not pass -g or -gdwarf-* option down to GAS. +# Add -Wa, prefix to explicitly specify the flags. +KBUILD_AFLAGS += $(addprefix -Wa$(comma), $(debug-flags-y)) endif +DEBUG_CFLAGS += $(debug-flags-y) +KBUILD_AFLAGS += $(debug-flags-y) ifdef CONFIG_DEBUG_INFO_REDUCED DEBUG_CFLAGS += -fno-var-tracking +DEBUG_RUSTFLAGS += -Cdebuginfo=1 ifdef CONFIG_CC_IS_GCC DEBUG_CFLAGS += -femit-struct-debug-baseonly endif +else +DEBUG_RUSTFLAGS += -Cdebuginfo=2 endif ifdef CONFIG_DEBUG_INFO_COMPRESSED @@ -29,5 +33,8 @@ KBUILD_AFLAGS += -gz=zlib KBUILD_LDFLAGS += --compress-debug-sections=zlib endif -KBUILD_CFLAGS += $(DEBUG_CFLAGS) +KBUILD_CFLAGS += $(DEBUG_CFLAGS) export DEBUG_CFLAGS + +KBUILD_RUSTFLAGS += $(DEBUG_RUSTFLAGS) +export DEBUG_RUSTFLAGS diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index d53825503874..6bbba36c5969 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -2,8 +2,8 @@ # ========================================================================== # make W=... settings # -# 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. +# There are four warning groups enabled by W=1, W=2, W=3, and W=e +# They are independent, and can be combined like W=12 or W=123e. # ========================================================================== KBUILD_CFLAGS += $(call cc-disable-warning, packed-not-aligned) @@ -36,6 +36,7 @@ KBUILD_CFLAGS += $(call cc-option, -Wstringop-truncation) KBUILD_CFLAGS += -Wno-missing-field-initializers KBUILD_CFLAGS += -Wno-sign-compare KBUILD_CFLAGS += -Wno-type-limits +KBUILD_CFLAGS += -Wno-shift-negative-value KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1 @@ -46,11 +47,24 @@ else ifdef CONFIG_CC_IS_CLANG KBUILD_CFLAGS += -Wno-initializer-overrides +# Clang before clang-16 would warn on default argument promotions. +ifneq ($(call clang-min-version, 160000),y) +# Disable -Wformat KBUILD_CFLAGS += -Wno-format +# Then re-enable flags that were part of the -Wformat group that aren't +# problematic. +KBUILD_CFLAGS += -Wformat-extra-args -Wformat-invalid-specifier +KBUILD_CFLAGS += -Wformat-zero-length -Wnonnull +# Requires clang-12+. +ifeq ($(call clang-min-version, 120000),y) +KBUILD_CFLAGS += -Wformat-insufficient-args +endif +endif KBUILD_CFLAGS += -Wno-sign-compare -KBUILD_CFLAGS += -Wno-format-zero-length KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast) KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare +KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access) +KBUILD_CFLAGS += $(call cc-disable-warning, cast-function-type-strict) endif endif @@ -92,3 +106,12 @@ KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat) KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3 endif + +# +# W=e - error out on warnings +# +ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),) + +KBUILD_CFLAGS += -Werror + +endif diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 1d16ca1b78c9..e4deaf5fa571 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -4,12 +4,10 @@ gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) \ += -DLATENT_ENTROPY_PLUGIN ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY - DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable + DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable -ULATENT_ENTROPY_PLUGIN endif export DISABLE_LATENT_ENTROPY_PLUGIN -gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so - gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \ += -fplugin-arg-structleak_plugin-verbose @@ -24,12 +22,6 @@ export DISABLE_STRUCTLEAK_PLUGIN gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ += -DSTRUCTLEAK_PLUGIN -gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so -gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \ - += -DRANDSTRUCT_PLUGIN -gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \ - += -fplugin-arg-randomize_layout_plugin-performance-mode - gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ += -DSTACKLEAK_PLUGIN @@ -37,6 +29,8 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ += -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE) gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ += -fplugin-arg-stackleak_plugin-arch=$(SRCARCH) +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK_VERBOSE) \ + += -fplugin-arg-stackleak_plugin-verbose ifdef CONFIG_GCC_PLUGIN_STACKLEAK DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable endif @@ -51,13 +45,19 @@ export DISABLE_ARM_SSP_PER_TASK_PLUGIN # All the plugin CFLAGS are collected here in case a build target needs to # filter them out of the KBUILD_CFLAGS. GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) -# The sancov_plugin.so is included via CFLAGS_KCOV, so it is removed here. -GCC_PLUGINS_CFLAGS := $(filter-out %/sancov_plugin.so, $(GCC_PLUGINS_CFLAGS)) export GCC_PLUGINS_CFLAGS # Add the flags to the build! KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -# All enabled GCC plugins are collected here for building below. -GCC_PLUGIN := $(gcc-plugin-y) +# Some plugins are enabled outside of this Makefile, but they still need to +# be included in GCC_PLUGIN so they can get built. +gcc-plugin-external-$(CONFIG_GCC_PLUGIN_SANCOV) \ + += sancov_plugin.so +gcc-plugin-external-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \ + += randomize_layout_plugin.so + +# All enabled GCC plugins are collected here for building in +# scripts/gcc-scripts/Makefile. +GCC_PLUGIN := $(gcc-plugin-y) $(gcc-plugin-external-y) export GCC_PLUGIN diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 278b4d6ac945..da133780b751 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -22,6 +22,8 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE # to preprocess a data file. # # Both C and C++ are supported, but preferred language is C for such utilities. +# Rust is also supported, but it may only be used in scenarios where a Rust +# toolchain is required to be available (e.g. when `CONFIG_RUST` is enabled). # # Sample syntax (see Documentation/kbuild/makefiles.rst for reference) # hostprogs := bin2hex @@ -37,15 +39,20 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE # qconf-objs := menu.o # Will compile qconf as a C++ program, and menu as a C program. # They are linked as C++ code to the executable qconf +# +# hostprogs := target +# target-rust := y +# Will compile `target` as a Rust program, using `target.rs` as the crate root. +# The crate may consist of several source files. # C code # Executables compiled from a single .c file host-csingle := $(foreach m,$(hostprogs), \ - $(if $($(m)-objs)$($(m)-cxxobjs),,$(m))) + $(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-rust),,$(m))) # C executables linked based on several .o files host-cmulti := $(foreach m,$(hostprogs),\ - $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) + $(if $($(m)-cxxobjs)$($(m)-rust),,$(if $($(m)-objs),$(m)))) # Object (.o) files compiled from .c files host-cobjs := $(sort $(foreach m,$(hostprogs),$($(m)-objs))) @@ -58,11 +65,17 @@ host-cxxmulti := $(foreach m,$(hostprogs),$(if $($(m)-cxxobjs),$(m))) # C++ Object (.o) files compiled from .cc files host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs))) +# Rust code +# Executables compiled from a single Rust crate (which may consist of +# one or more .rs files) +host-rust := $(foreach m,$(hostprogs),$(if $($(m)-rust),$(m))) + host-csingle := $(addprefix $(obj)/,$(host-csingle)) host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti)) host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs)) +host-rust := $(addprefix $(obj)/,$(host-rust)) ##### # Handle options to gcc. Support building with separate output directory @@ -71,6 +84,8 @@ _hostc_flags = $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ $(HOSTCFLAGS_$(target-stem).o) _hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ $(HOSTCXXFLAGS_$(target-stem).o) +_hostrust_flags = $(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \ + $(HOSTRUSTFLAGS_$(target-stem)) # $(objtree)/$(obj) for including generated headers from checkin source files ifeq ($(KBUILD_EXTMOD),) @@ -82,6 +97,7 @@ endif hostc_flags = -Wp,-MMD,$(depfile) $(_hostc_flags) hostcxx_flags = -Wp,-MMD,$(depfile) $(_hostcxx_flags) +hostrust_flags = $(_hostrust_flags) ##### # Compile programs on the host @@ -128,5 +144,17 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE $(call if_changed_dep,host-cxxobjs) +# Create executable from a single Rust crate (which may consist of +# one or more `.rs` files) +# host-rust -> Executable +quiet_cmd_host-rust = HOSTRUSTC $@ + cmd_host-rust = \ + $(HOSTRUSTC) $(hostrust_flags) --emit=dep-info,link \ + --out-dir=$(obj)/ $<; \ + mv $(obj)/$(target-stem).d $(depfile); \ + sed -i '/^\#/d' $(depfile) +$(host-rust): $(obj)/%: $(src)/%.rs FORCE + $(call if_changed_dep,host-rust) + targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \ - $(host-cxxmulti) $(host-cxxobjs) + $(host-cxxmulti) $(host-cxxobjs) $(host-rust) diff --git a/scripts/Makefile.kmsan b/scripts/Makefile.kmsan new file mode 100644 index 000000000000..b5b0aa61322e --- /dev/null +++ b/scripts/Makefile.kmsan @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +kmsan-cflags := -fsanitize=kernel-memory + +ifdef CONFIG_KMSAN_CHECK_PARAM_RETVAL +kmsan-cflags += -fsanitize-memory-param-retval +endif + +export CFLAGS_KMSAN := $(kmsan-cflags) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index ab17f7b2e33c..3aa384cec76b 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -8,6 +8,7 @@ ldflags-y += $(EXTRA_LDFLAGS) # flags that take effect in current and sub directories KBUILD_AFLAGS += $(subdir-asflags-y) KBUILD_CFLAGS += $(subdir-ccflags-y) +KBUILD_RUSTFLAGS += $(subdir-rustflags-y) # Figure out what we need to build from the various variables # =========================================================================== @@ -87,13 +88,9 @@ base-dtb-y := $(foreach m, $(multi-dtb-y), $(firstword $(call suffix-search, $m, always-y += $(dtb-y) -ifneq ($(CHECK_DTBS),) -always-y += $(patsubst %.dtb,%.dt.yaml, $(real-dtb-y)) -always-y += $(patsubst %.dtbo,%.dt.yaml, $(real-dtb-y)) -endif - # Add subdir path +ifneq ($(obj),.) extra-y := $(addprefix $(obj)/,$(extra-y)) always-y := $(addprefix $(obj)/,$(always-y)) targets := $(addprefix $(obj)/,$(targets)) @@ -105,13 +102,14 @@ multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m)) multi-dtb-y := $(addprefix $(obj)/, $(multi-dtb-y)) real-dtb-y := $(addprefix $(obj)/, $(real-dtb-y)) subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) +endif # Finds the multi-part object the current object will be linked into. # If the object belongs to two or more multi-part objects, list them all. modname-multi = $(sort $(foreach m,$(multi-obj-ym),\ $(if $(filter $*.o, $(call suffix-search, $m, .o, -objs -y -m)),$(m:.o=)))) -__modname = $(if $(modname-multi),$(modname-multi),$(basetarget)) +__modname = $(or $(modname-multi),$(basetarget)) modname = $(subst $(space),:,$(__modname)) modfile = $(addprefix $(obj)/,$(__modname)) @@ -133,6 +131,10 @@ _c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \ $(filter-out $(ccflags-remove-y), \ $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(ccflags-y)) \ $(CFLAGS_$(target-stem).o)) +_rust_flags = $(filter-out $(RUSTFLAGS_REMOVE_$(target-stem).o), \ + $(filter-out $(rustflags-remove-y), \ + $(KBUILD_RUSTFLAGS) $(rustflags-y)) \ + $(RUSTFLAGS_$(target-stem).o)) _a_flags = $(filter-out $(AFLAGS_REMOVE_$(target-stem).o), \ $(filter-out $(asflags-remove-y), \ $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(asflags-y)) \ @@ -162,6 +164,15 @@ _c_flags += $(if $(patsubst n%,, \ endif endif +ifeq ($(CONFIG_KMSAN),y) +_c_flags += $(if $(patsubst n%,, \ + $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \ + $(CFLAGS_KMSAN)) +_c_flags += $(if $(patsubst n%,, \ + $(KMSAN_ENABLE_CHECKS_$(basetarget).o)$(KMSAN_ENABLE_CHECKS)y), \ + , -mllvm -msan-disable-checks=1) +endif + ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \ $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \ @@ -207,6 +218,11 @@ modkern_cflags = \ $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags)) +modkern_rustflags = \ + $(if $(part-of-module), \ + $(KBUILD_RUSTFLAGS_MODULE) $(RUSTFLAGS_MODULE), \ + $(KBUILD_RUSTFLAGS_KERNEL) $(RUSTFLAGS_KERNEL)) + modkern_aflags = $(if $(part-of-module), \ $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE), \ $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)) @@ -216,6 +232,8 @@ c_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(_c_flags) $(modkern_cflags) \ $(basename_flags) $(modname_flags) +rust_flags = $(_rust_flags) $(modkern_rustflags) @$(objtree)/include/generated/rustc_cfg + a_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(_a_flags) $(modkern_aflags) @@ -230,36 +248,53 @@ dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc \ $(addprefix -I,$(DTC_INCLUDE)) \ -undef -D__DTS__ -ifeq ($(CONFIG_LTO_CLANG),y) -# With CONFIG_LTO_CLANG, .o files in modules might be LLVM bitcode, so we -# need to run LTO to compile them into native code (.lto.o) before further -# processing. -mod-prelink-ext := .lto -endif +ifdef CONFIG_OBJTOOL + +objtool := $(objtree)/tools/objtool/objtool + +objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label +objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr +objtool-args-$(CONFIG_X86_KERNEL_IBT) += --ibt +objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL) += --mcount +objtool-args-$(CONFIG_UNWINDER_ORC) += --orc +objtool-args-$(CONFIG_RETPOLINE) += --retpoline +objtool-args-$(CONFIG_RETHUNK) += --rethunk +objtool-args-$(CONFIG_SLS) += --sls +objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval +objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call +objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess +objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable + +objtool-args = $(objtool-args-y) \ + $(if $(delay-objtool), --link) \ + $(if $(part-of-module), --module) + +delay-objtool := $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT)) + +cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool-args) $@) +cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) + +endif # CONFIG_OBJTOOL # Useful for describing the dependency of composite objects # Usage: # $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add) define multi_depend -$(foreach m, $(notdir $1), \ - $(eval $(obj)/$m: \ - $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s))))))) +$(foreach m, $1, \ + $(eval $m: \ + $(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3)))) endef -quiet_cmd_copy = COPY $@ - cmd_copy = cp $< $@ - -# Shipped files +# Copy a file # =========================================================================== # 'cp' preserves permissions. If you use it to copy a file in read-only srctree, # the copy would be read-only as well, leading to an error when executing the # rule next time. Use 'cat' instead in order to generate a writable file. - -quiet_cmd_shipped = SHIPPED $@ -cmd_shipped = cat $< > $@ +quiet_cmd_copy = COPY $@ + cmd_copy = cat $< > $@ $(obj)/%: $(src)/%_shipped - $(call cmd,shipped) + $(call cmd,copy) # Commands useful for building a boot image # =========================================================================== @@ -347,12 +382,6 @@ cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; -d $(depfile).dtc.tmp $(dtc-tmp) ; \ cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) -$(obj)/%.dtb: $(src)/%.dts $(DTC) FORCE - $(call if_changed_dep,dtc) - -$(obj)/%.dtbo: $(src)/%.dts $(DTC) FORCE - $(call if_changed_dep,dtc) - quiet_cmd_fdtoverlay = DTOVL $@ cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(real-prereqs) @@ -360,22 +389,24 @@ $(multi-dtb-y): FORCE $(call if_changed,fdtoverlay) $(call multi_depend, $(multi-dtb-y), .dtb, -dtbs) +ifneq ($(CHECK_DTBS)$(CHECK_DT_BINDING),) DT_CHECKER ?= dt-validate -DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),,-m) +DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),-l $(DT_SCHEMA_FILES),-m) DT_BINDING_DIR := Documentation/devicetree/bindings -# DT_TMP_SCHEMA may be overridden from Documentation/devicetree/bindings/Makefile -DT_TMP_SCHEMA ?= $(objtree)/$(DT_BINDING_DIR)/processed-schema.json +DT_TMP_SCHEMA := $(objtree)/$(DT_BINDING_DIR)/processed-schema.json -quiet_cmd_dtb_check = CHECK $@ - cmd_dtb_check = $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ +quiet_cmd_dtb = DTC_CHK $@ + cmd_dtb = $(cmd_dtc) ; $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ || true +else +quiet_cmd_dtb = $(quiet_cmd_dtc) + cmd_dtb = $(cmd_dtc) +endif -define rule_dtc - $(call cmd_and_fixdep,dtc) - $(call cmd,dtb_check) -endef +$(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE + $(call if_changed_dep,dtb) -$(obj)/%.dt.yaml: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE - $(call if_changed_rule,dtc) +$(obj)/%.dtbo: $(src)/%.dts $(DTC) FORCE + $(call if_changed_dep,dtc) dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) @@ -399,20 +430,35 @@ printf "%08x\n" $$dec_size | \ } \ ) +quiet_cmd_file_size = GEN $@ + cmd_file_size = $(size_append) > $@ + quiet_cmd_bzip2 = BZIP2 $@ - cmd_bzip2 = { cat $(real-prereqs) | $(KBZIP2) -9; $(size_append); } > $@ + cmd_bzip2 = cat $(real-prereqs) | $(KBZIP2) -9 > $@ + +quiet_cmd_bzip2_with_size = BZIP2 $@ + cmd_bzip2_with_size = { cat $(real-prereqs) | $(KBZIP2) -9; $(size_append); } > $@ # Lzma # --------------------------------------------------------------------------- quiet_cmd_lzma = LZMA $@ - cmd_lzma = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ + cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@ + +quiet_cmd_lzma_with_size = LZMA $@ + cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ quiet_cmd_lzo = LZO $@ - cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ + cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@ + +quiet_cmd_lzo_with_size = LZO $@ + cmd_lzo_with_size = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ quiet_cmd_lz4 = LZ4 $@ - cmd_lz4 = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \ + cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout > $@ + +quiet_cmd_lz4_with_size = LZ4 $@ + cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \ $(size_append); } > $@ # U-Boot mkimage @@ -423,7 +469,7 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh # SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces # the number of overrides in arch makefiles UIMAGE_ARCH ?= $(SRCARCH) -UIMAGE_COMPRESSION ?= $(if $(2),$(2),none) +UIMAGE_COMPRESSION ?= $(or $(2),none) UIMAGE_OPTS-y ?= UIMAGE_TYPE ?= kernel UIMAGE_LOADADDR ?= arch_must_set_this @@ -455,7 +501,10 @@ quiet_cmd_uimage = UIMAGE $@ # big dictionary would increase the memory usage too much in the multi-call # decompression mode. A BCJ filter isn't used either. quiet_cmd_xzkern = XZKERN $@ - cmd_xzkern = { cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh; \ + cmd_xzkern = cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh > $@ + +quiet_cmd_xzkern_with_size = XZKERN $@ + cmd_xzkern_with_size = { cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh; \ $(size_append); } > $@ quiet_cmd_xzmisc = XZMISC $@ @@ -478,10 +527,13 @@ quiet_cmd_xzmisc = XZMISC $@ # be used because it would require zstd to allocate a 128 MB buffer. quiet_cmd_zstd = ZSTD $@ - cmd_zstd = { cat $(real-prereqs) | $(ZSTD) -19; $(size_append); } > $@ + cmd_zstd = cat $(real-prereqs) | $(ZSTD) -19 > $@ quiet_cmd_zstd22 = ZSTD22 $@ - cmd_zstd22 = { cat $(real-prereqs) | $(ZSTD) -22 --ultra; $(size_append); } > $@ + cmd_zstd22 = cat $(real-prereqs) | $(ZSTD) -22 --ultra > $@ + +quiet_cmd_zstd22_with_size = ZSTD22 $@ + cmd_zstd22_with_size = { cat $(real-prereqs) | $(ZSTD) -22 --ultra; $(size_append); } > $@ # ASM offsets # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 7f39599e9fae..25bedd83644b 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -9,7 +9,7 @@ __modfinal: include include/config/auto.conf include $(srctree)/scripts/Kbuild.include -# for c_flags and mod-prelink-ext +# for c_flags include $(srctree)/scripts/Makefile.lib # find all modules listed in modules.order @@ -39,11 +39,13 @@ quiet_cmd_ld_ko_o = LD [M] $@ quiet_cmd_btf_ko = BTF [M] $@ cmd_btf_ko = \ - if [ -f vmlinux ]; then \ + if [ ! -f vmlinux ]; then \ + printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ + elif [ -n "$(CONFIG_RUST)" ] && $(srctree)/scripts/is_rust_module.sh $@; then \ + printf "Skipping BTF generation for %s because it's a Rust module\n" $@ 1>&2; \ + else \ LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \ $(RESOLVE_BTFIDS) -b vmlinux $@; \ - else \ - printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ fi; # Same as newer-prereqs, but allows to exclude specified extra dependencies @@ -54,9 +56,8 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ $(cmd); \ printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) - # Re-generate module BTFs if either module's .ko or vmlinux changed -$(modules): %.ko: %$(mod-prelink-ext).o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE +$(modules): %.ko: %.o %.mod.o scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),vmlinux) FORCE +$(call if_changed_except,ld_ko_o,vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index ff9b09e4cfca..a4c987c23750 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -18,6 +18,9 @@ INSTALL_MOD_DIR ?= extra dst := $(MODLIB)/$(INSTALL_MOD_DIR) endif +$(foreach x, % :, $(if $(findstring $x, $(dst)), \ + $(error module installation path cannot contain '$x'))) + suffix-y := suffix-$(CONFIG_MODULE_COMPRESS_GZIP) := .gz suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz @@ -28,9 +31,6 @@ modules := $(patsubst $(extmod_prefix)%, $(dst)/%$(suffix-y), $(modules)) __modinst: $(modules) @: -quiet_cmd_none = - cmd_none = : - # # Installation # @@ -66,9 +66,9 @@ endif # Don't stop modules_install even if we can't sign external modules. # ifeq ($(CONFIG_MODULE_SIG_ALL),y) +sig-key := $(if $(wildcard $(CONFIG_MODULE_SIG_KEY)),,$(srctree)/)$(CONFIG_MODULE_SIG_KEY) quiet_cmd_sign = SIGN $@ -$(eval $(call config_filename,MODULE_SIG_KEY)) - cmd_sign = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY) certs/signing_key.x509 $@ \ + cmd_sign = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(sig-key) certs/signing_key.x509 $@ \ $(if $(KBUILD_EXTMOD),|| true) else quiet_cmd_sign := diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 48585c4d04ad..e41dee64d429 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -32,52 +32,58 @@ # Step 4 is solely used to allow module versioning in external modules, # where the CRC of each module is retrieved from the Module.symvers file. -# 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: include include/config/auto.conf include $(srctree)/scripts/Kbuild.include -# for mod-prelink-ext -include $(srctree)/scripts/Makefile.lib - -MODPOST = scripts/mod/modpost \ +modpost-args = \ $(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ + $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \ + $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) \ -o $@ -ifdef MODPOST_VMLINUX - -quiet_cmd_modpost = MODPOST $@ - cmd_modpost = $(MODPOST) $< - -vmlinux.symvers: vmlinux.o - $(call cmd,modpost) - -__modpost: vmlinux.symvers - -else +# 'make -i -k' ignores compile errors, and builds as many modules as possible. +ifneq ($(findstring i,$(filter-out --%,$(MAKEFLAGS))),) +modpost-args += -n +endif ifeq ($(KBUILD_EXTMOD),) -input-symdump := vmlinux.symvers -output-symdump := modules-only.symvers - -quiet_cmd_cat = GEN $@ - cmd_cat = cat $(real-prereqs) > $@ +# Generate the list of in-tree objects in vmlinux +# --------------------------------------------------------------------------- -ifneq ($(wildcard vmlinux.symvers),) - -__modpost: Module.symvers -Module.symvers: vmlinux.symvers modules-only.symvers FORCE - $(call if_changed,cat) - -targets += Module.symvers +# This is used to retrieve symbol versions generated by genksyms. +ifdef CONFIG_MODVERSIONS +vmlinux.symvers Module.symvers: .vmlinux.objs +endif +# Ignore libgcc.a +# Some architectures do '$(CC) --print-libgcc-file-name' to borrow libgcc.a +# from the toolchain, but there is no EXPORT_SYMBOL in it. + +quiet_cmd_vmlinux_objs = GEN $@ + cmd_vmlinux_objs = \ + for f in $(real-prereqs); do \ + case $${f} in \ + *libgcc.a) ;; \ + *) $(AR) t $${f} ;; \ + esac \ + done > $@ + +targets += .vmlinux.objs +.vmlinux.objs: vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE + $(call if_changed,vmlinux_objs) + +vmlinux.o-if-present := $(wildcard vmlinux.o) +output-symdump := vmlinux.symvers + +ifdef KBUILD_MODULES +output-symdump := $(if $(vmlinux.o-if-present), Module.symvers, modules-only.symvers) +missing-input := $(filter-out $(vmlinux.o-if-present),vmlinux.o) endif else @@ -87,59 +93,39 @@ obj := $(KBUILD_EXTMOD) src := $(obj) # Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS -include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ - $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile) +include $(or $(wildcard $(src)/Kbuild), $(src)/Makefile) -# modpost option for external modules -MODPOST += -e - -input-symdump := Module.symvers $(KBUILD_EXTRA_SYMBOLS) +module.symvers-if-present := $(wildcard Module.symvers) output-symdump := $(KBUILD_EXTMOD)/Module.symvers +missing-input := $(filter-out $(module.symvers-if-present), Module.symvers) -endif - -existing-input-symdump := $(wildcard $(input-symdump)) +modpost-args += -e $(addprefix -i ,$(module.symvers-if-present) $(KBUILD_EXTRA_SYMBOLS)) -# modpost options for modules (both in-kernel and external) -MODPOST += \ - $(addprefix -i ,$(existing-input-symdump)) \ - $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \ - $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) +endif # ($(KBUILD_EXTMOD),) -# 'make -i -k' ignores compile errors, and builds as many modules as possible. -ifneq ($(findstring i,$(filter-out --%,$(MAKEFLAGS))),) -MODPOST += -n +ifneq ($(KBUILD_MODPOST_WARN)$(missing-input),) +modpost-args += -w endif -# Clear VPATH to not search for *.symvers in $(srctree). Check only $(objtree). -VPATH := -$(input-symdump): - @echo >&2 'WARNING: Symbol version dump "$@" is missing.' - @echo >&2 ' Modules may not have dependencies or modversions.' - @echo >&2 ' You may get many unresolved symbol warnings.' - -modules := $(sort $(shell cat $(MODORDER))) +modorder-if-needed := $(if $(KBUILD_MODULES), $(MODORDER)) -# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined symbols -ifneq ($(KBUILD_MODPOST_WARN)$(filter-out $(existing-input-symdump), $(input-symdump)),) -MODPOST += -w -endif +MODPOST = scripts/mod/modpost # Read out modules.order to pass in modpost. # Otherwise, allmodconfig would fail with "Argument list too long". quiet_cmd_modpost = MODPOST $@ - cmd_modpost = sed 's/\.ko$$/$(mod-prelink-ext)\.o/' $< | $(MODPOST) -T - - -$(output-symdump): $(MODORDER) $(input-symdump) $(modules:.ko=$(mod-prelink-ext).o) FORCE - $(call if_changed,modpost) + cmd_modpost = \ + $(if $(missing-input), \ + echo >&2 "WARNING: $(missing-input) is missing."; \ + echo >&2 " Modules may not have dependencies or modversions."; \ + echo >&2 " You may get many unresolved symbol warnings.";) \ + sed 's/ko$$/o/' $(or $(modorder-if-needed), /dev/null) | $(MODPOST) $(modpost-args) -T - $(vmlinux.o-if-present) targets += $(output-symdump) +$(output-symdump): $(modorder-if-needed) $(vmlinux.o-if-present) $(module.symvers-if-present) $(MODPOST) FORCE + $(call if_changed,modpost) __modpost: $(output-symdump) -ifneq ($(KBUILD_MODPOST_NOFINAL),1) - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal -endif - PHONY += FORCE FORCE: @@ -147,6 +133,4 @@ existing-targets := $(wildcard $(sort $(targets))) -include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) -endif - .PHONY: $(PHONY) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 77b612183c08..8bbcced67c22 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -29,7 +29,10 @@ KDEB_SOURCENAME ?= linux-upstream KBUILD_PKG_ROOTCMD ?="fakeroot -u" export KDEB_SOURCENAME # Include only those top-level files that are needed by make, plus the GPL copy -TAR_CONTENT := $(KBUILD_ALLDIRS) .config .scmversion Makefile \ +TAR_CONTENT := Documentation LICENSES arch block certs crypto drivers fs \ + include init io_uring ipc kernel lib mm net samples scripts \ + security sound tools usr virt \ + .config .scmversion Makefile \ Kbuild Kconfig COPYING $(wildcard localversion*) MKSPEC := $(srctree)/scripts/package/mkspec @@ -56,7 +59,7 @@ rpm-pkg: $(MAKE) clean $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec $(call cmd,src_tar,$(KERNELPATH),kernel.spec) - +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \ + +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -ta $(KERNELPATH).tar.gz \ --define='_smp_mflags %{nil}' # binrpm-pkg @@ -66,7 +69,7 @@ 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 + $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec PHONY += deb-pkg deb-pkg: diff --git a/scripts/Makefile.randstruct b/scripts/Makefile.randstruct new file mode 100644 index 000000000000..24e283e89893 --- /dev/null +++ b/scripts/Makefile.randstruct @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0 + +randstruct-cflags-y += -DRANDSTRUCT + +ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT +randstruct-cflags-y \ + += -fplugin=$(objtree)/scripts/gcc-plugins/randomize_layout_plugin.so +randstruct-cflags-$(CONFIG_RANDSTRUCT_PERFORMANCE) \ + += -fplugin-arg-randomize_layout_plugin-performance-mode +else +randstruct-cflags-y \ + += -frandomize-layout-seed-file=$(objtree)/scripts/basic/randstruct.seed +endif + +export RANDSTRUCT_CFLAGS := $(randstruct-cflags-y) + +KBUILD_CFLAGS += $(RANDSTRUCT_CFLAGS) diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 9e2092fd5206..7099c603ff0a 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -8,7 +8,6 @@ ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS) += -fsanitize=local-bounds ubsan-cflags-$(CONFIG_UBSAN_SHIFT) += -fsanitize=shift ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable -ubsan-cflags-$(CONFIG_UBSAN_OBJECT_SIZE) += -fsanitize=object-size ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux new file mode 100644 index 000000000000..49946cb96844 --- /dev/null +++ b/scripts/Makefile.vmlinux @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only + +PHONY := __default +__default: vmlinux + +include include/config/auto.conf +include $(srctree)/scripts/Kbuild.include + +# for c_flags +include $(srctree)/scripts/Makefile.lib + +targets := + +quiet_cmd_cc_o_c = CC $@ + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + +%.o: %.c FORCE + $(call if_changed_dep,cc_o_c) + +ifdef CONFIG_MODULES +targets += .vmlinux.export.o +vmlinux: .vmlinux.export.o +endif + +ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) + +# Final link of vmlinux with optional arch pass after final link +cmd_link_vmlinux = \ + $< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)"; \ + $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) + +targets += vmlinux +vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE + +$(call if_changed_dep,link_vmlinux) + +# 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.vmlinux_o b/scripts/Makefile.vmlinux_o new file mode 100644 index 000000000000..0edfdb40364b --- /dev/null +++ b/scripts/Makefile.vmlinux_o @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: GPL-2.0-only + +PHONY := __default +__default: vmlinux.o modules.builtin.modinfo modules.builtin + +include include/config/auto.conf +include $(srctree)/scripts/Kbuild.include + +# for objtool +include $(srctree)/scripts/Makefile.lib + +# Generate a linker script to ensure correct ordering of initcalls for Clang LTO +# --------------------------------------------------------------------------- + +quiet_cmd_gen_initcalls_lds = GEN $@ + cmd_gen_initcalls_lds = \ + $(PYTHON3) $(srctree)/scripts/jobserver-exec \ + $(PERL) $(real-prereqs) > $@ + +.tmp_initcalls.lds: $(srctree)/scripts/generate_initcall_order.pl \ + vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE + $(call if_changed,gen_initcalls_lds) + +targets := .tmp_initcalls.lds + +ifdef CONFIG_LTO_CLANG +initcalls-lds := .tmp_initcalls.lds +endif + +# objtool for vmlinux.o +# --------------------------------------------------------------------------- +# +# For LTO and IBT, objtool doesn't run on individual translation units. +# Run everything on vmlinux instead. + +objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION)) + +vmlinux-objtool-args-$(delay-objtool) += $(objtool-args-y) +vmlinux-objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable +vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION) += --noinstr $(if $(CONFIG_CPU_UNRET_ENTRY), --unret) + +objtool-args = $(vmlinux-objtool-args-y) --link + +# Link of vmlinux.o used for section mismatch analysis +# --------------------------------------------------------------------------- + +quiet_cmd_ld_vmlinux.o = LD $@ + cmd_ld_vmlinux.o = \ + $(LD) ${KBUILD_LDFLAGS} -r -o $@ \ + $(addprefix -T , $(initcalls-lds)) \ + --whole-archive vmlinux.a --no-whole-archive \ + --start-group $(KBUILD_VMLINUX_LIBS) --end-group \ + $(cmd_objtool) + +define rule_ld_vmlinux.o + $(call cmd_and_savecmd,ld_vmlinux.o) + $(call cmd,gen_objtooldep) +endef + +vmlinux.o: $(initcalls-lds) vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE + $(call if_changed_rule,ld_vmlinux.o) + +targets += vmlinux.o + +# module.builtin.modinfo +# --------------------------------------------------------------------------- + +OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary + +targets += modules.builtin.modinfo +modules.builtin.modinfo: vmlinux.o FORCE + $(call if_changed,objcopy) + +# module.builtin +# --------------------------------------------------------------------------- + +# The second line aids cases where multiple modules share the same object. + +quiet_cmd_modules_builtin = GEN $@ + cmd_modules_builtin = \ + tr '\0' '\n' < $< | \ + sed -n 's/^[[:alnum:]:_]*\.file=//p' | \ + tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@ + +targets += modules.builtin +modules.builtin: modules.builtin.modinfo FORCE + $(call if_changed,modules_builtin) + +# 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/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh index 59fdb875e818..f1b5ac818411 100755 --- a/scripts/adjust_autoksyms.sh +++ b/scripts/adjust_autoksyms.sh @@ -35,7 +35,7 @@ case "$KBUILD_VERBOSE" in esac # Generate a new symbol list file -$CONFIG_SHELL $srctree/scripts/gen_autoksyms.sh "$new_ksyms_file" +$CONFIG_SHELL $srctree/scripts/gen_autoksyms.sh --modorder "$new_ksyms_file" # Extract changes between old and new list and touch corresponding # dependency files. diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index adabd4145264..71d4a7c87900 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c @@ -832,7 +832,7 @@ static void parse(void) static struct element *element_list; -static struct element *alloc_elem(struct token *type) +static struct element *alloc_elem(void) { struct element *e = calloc(1, sizeof(*e)); if (!e) { @@ -860,7 +860,7 @@ static struct element *parse_type(struct token **_cursor, struct token *end, char *p; int labelled = 0, implicit = 0; - top = element = alloc_elem(cursor); + top = element = alloc_elem(); element->class = ASN1_UNIV; element->method = ASN1_PRIM; element->tag = token_to_tag[cursor->token_type]; @@ -939,7 +939,7 @@ static struct element *parse_type(struct token **_cursor, struct token *end, if (!implicit) element->method |= ASN1_CONS; element->compound = implicit ? TAG_OVERRIDE : SEQUENCE; - element->children = alloc_elem(cursor); + element->children = alloc_elem(); element = element->children; element->class = ASN1_UNIV; element->method = ASN1_PRIM; diff --git a/scripts/atomic/check-atomics.sh b/scripts/atomic/check-atomics.sh deleted file mode 100755 index 0e7bab3eb0d1..000000000000 --- a/scripts/atomic/check-atomics.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# -# Check if atomic headers are up-to-date - -ATOMICDIR=$(dirname $0) -ATOMICTBL=${ATOMICDIR}/atomics.tbl -LINUXDIR=${ATOMICDIR}/../.. - -echo '' | sha1sum - > /dev/null 2>&1 -if [ $? -ne 0 ]; then - printf "sha1sum not available, skipping atomic header checks.\n" - exit 0 -fi - -cat <<EOF | -linux/atomic/atomic-instrumented.h -linux/atomic/atomic-long.h -linux/atomic/atomic-arch-fallback.h -EOF -while read header; do - OLDSUM="$(tail -n 1 ${LINUXDIR}/include/${header})" - OLDSUM="${OLDSUM#// }" - - NEWSUM="$(sed '$d' ${LINUXDIR}/include/${header} | sha1sum)" - NEWSUM="${NEWSUM%% *}" - - if [ "${OLDSUM}" != "${NEWSUM}" ]; then - printf "warning: generated include/${header} has been modified.\n" - fi -done - -exit 0 diff --git a/scripts/atomic/fallbacks/read_acquire b/scripts/atomic/fallbacks/read_acquire index 803ba7561076..a0ea1d26e6b2 100755 --- a/scripts/atomic/fallbacks/read_acquire +++ b/scripts/atomic/fallbacks/read_acquire @@ -2,6 +2,15 @@ cat <<EOF static __always_inline ${ret} arch_${atomic}_read_acquire(const ${atomic}_t *v) { - return smp_load_acquire(&(v)->counter); + ${int} ret; + + if (__native_word(${atomic}_t)) { + ret = smp_load_acquire(&(v)->counter); + } else { + ret = arch_${atomic}_read(v); + __atomic_acquire_fence(); + } + + return ret; } EOF diff --git a/scripts/atomic/fallbacks/set_release b/scripts/atomic/fallbacks/set_release index 86ede759f24e..05cdb7f42477 100755 --- a/scripts/atomic/fallbacks/set_release +++ b/scripts/atomic/fallbacks/set_release @@ -2,6 +2,11 @@ cat <<EOF static __always_inline void arch_${atomic}_set_release(${atomic}_t *v, ${int} i) { - smp_store_release(&(v)->counter, i); + if (__native_word(${atomic}_t)) { + smp_store_release(&(v)->counter, i); + } else { + __atomic_release_fence(); + arch_${atomic}_set(v, i); + } } EOF diff --git a/scripts/atomic/gen-atomic-fallback.sh b/scripts/atomic/gen-atomic-fallback.sh index 8e2da71f1d5f..3a07695e3c89 100755 --- a/scripts/atomic/gen-atomic-fallback.sh +++ b/scripts/atomic/gen-atomic-fallback.sh @@ -164,41 +164,44 @@ gen_xchg_fallbacks() gen_try_cmpxchg_fallback() { + local cmpxchg="$1"; shift; local order="$1"; shift; cat <<EOF -#ifndef arch_try_cmpxchg${order} -#define arch_try_cmpxchg${order}(_ptr, _oldp, _new) \\ +#ifndef arch_try_${cmpxchg}${order} +#define arch_try_${cmpxchg}${order}(_ptr, _oldp, _new) \\ ({ \\ typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \\ - ___r = arch_cmpxchg${order}((_ptr), ___o, (_new)); \\ + ___r = arch_${cmpxchg}${order}((_ptr), ___o, (_new)); \\ if (unlikely(___r != ___o)) \\ *___op = ___r; \\ likely(___r == ___o); \\ }) -#endif /* arch_try_cmpxchg${order} */ +#endif /* arch_try_${cmpxchg}${order} */ EOF } gen_try_cmpxchg_fallbacks() { - printf "#ifndef arch_try_cmpxchg_relaxed\n" - printf "#ifdef arch_try_cmpxchg\n" + local cmpxchg="$1"; shift; - gen_basic_fallbacks "arch_try_cmpxchg" + printf "#ifndef arch_try_${cmpxchg}_relaxed\n" + printf "#ifdef arch_try_${cmpxchg}\n" - printf "#endif /* arch_try_cmpxchg */\n\n" + gen_basic_fallbacks "arch_try_${cmpxchg}" + + printf "#endif /* arch_try_${cmpxchg} */\n\n" for order in "" "_acquire" "_release" "_relaxed"; do - gen_try_cmpxchg_fallback "${order}" + gen_try_cmpxchg_fallback "${cmpxchg}" "${order}" done - printf "#else /* arch_try_cmpxchg_relaxed */\n" + printf "#else /* arch_try_${cmpxchg}_relaxed */\n" - gen_order_fallbacks "arch_try_cmpxchg" + gen_order_fallbacks "arch_try_${cmpxchg}" - printf "#endif /* arch_try_cmpxchg_relaxed */\n\n" + printf "#endif /* arch_try_${cmpxchg}_relaxed */\n\n" } cat << EOF @@ -218,7 +221,9 @@ for xchg in "arch_xchg" "arch_cmpxchg" "arch_cmpxchg64"; do gen_xchg_fallbacks "${xchg}" done -gen_try_cmpxchg_fallbacks +for cmpxchg in "cmpxchg" "cmpxchg64"; do + gen_try_cmpxchg_fallbacks "${cmpxchg}" +done grep '^[a-z]' "$1" | while read name meta args; do gen_proto "${meta}" "${name}" "atomic" "int" ${args} diff --git a/scripts/atomic/gen-atomic-instrumented.sh b/scripts/atomic/gen-atomic-instrumented.sh index 68f902731d01..77c06526a574 100755 --- a/scripts/atomic/gen-atomic-instrumented.sh +++ b/scripts/atomic/gen-atomic-instrumented.sh @@ -166,7 +166,7 @@ grep '^[a-z]' "$1" | while read name meta args; do done -for xchg in "xchg" "cmpxchg" "cmpxchg64" "try_cmpxchg"; do +for xchg in "xchg" "cmpxchg" "cmpxchg64" "try_cmpxchg" "try_cmpxchg64"; do for order in "" "_acquire" "_release" "_relaxed"; do gen_xchg "${xchg}" "${order}" "" printf "\n" diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore index 961c91c8a884..07c195f605a1 100644 --- a/scripts/basic/.gitignore +++ b/scripts/basic/.gitignore @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only /fixdep +/randstruct.seed diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile index eeb6a38c5551..dd289a6725ac 100644 --- a/scripts/basic/Makefile +++ b/scripts/basic/Makefile @@ -3,3 +3,14 @@ # fixdep: used to generate dependency information during build process hostprogs-always-y += fixdep + +# randstruct: the seed is needed before building the gcc-plugin or +# before running a Clang kernel build. +gen-randstruct-seed := $(srctree)/scripts/gen-randstruct-seed.sh +quiet_cmd_create_randstruct_seed = GENSEED $@ +cmd_create_randstruct_seed = \ + $(CONFIG_SHELL) $(gen-randstruct-seed) \ + $@ $(objtree)/include/generated/randstruct_hash.h +$(obj)/randstruct.seed: $(gen-randstruct-seed) FORCE + $(call if_changed,create_randstruct_seed) +always-$(CONFIG_RANDSTRUCT) += randstruct.seed diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 44e887cff49b..2328f9a641da 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -105,25 +105,6 @@ static void usage(void) exit(1); } -/* - * In the intended usage of this program, the stdout is redirected to .*.cmd - * files. The return value of printf() must be checked to catch any error, - * e.g. "No space left on device". - */ -static void xprintf(const char *format, ...) -{ - va_list ap; - int ret; - - va_start(ap, format); - ret = vprintf(format, ap); - if (ret < 0) { - perror("fixdep"); - exit(1); - } - va_end(ap); -} - struct item { struct item *next; unsigned int len; @@ -189,7 +170,7 @@ static void use_config(const char *m, int slen) define_config(m, slen, hash); /* Print out a dependency path from a symbol name. */ - xprintf(" $(wildcard include/config/%.*s) \\\n", slen, m); + printf(" $(wildcard include/config/%.*s) \\\n", slen, m); } /* test if s ends in sub */ @@ -318,13 +299,13 @@ static void parse_dep_file(char *m, const char *target) */ if (!saw_any_target) { saw_any_target = 1; - xprintf("source_%s := %s\n\n", - target, m); - xprintf("deps_%s := \\\n", target); + printf("source_%s := %s\n\n", + target, m); + printf("deps_%s := \\\n", target); } is_first_dep = 0; } else { - xprintf(" %s \\\n", m); + printf(" %s \\\n", m); } buf = read_file(m); @@ -347,8 +328,8 @@ static void parse_dep_file(char *m, const char *target) exit(1); } - xprintf("\n%s: $(deps_%s)\n\n", target, target); - xprintf("$(deps_%s):\n", target); + printf("\n%s: $(deps_%s)\n\n", target, target); + printf("$(deps_%s):\n", target); } int main(int argc, char *argv[]) @@ -363,11 +344,22 @@ int main(int argc, char *argv[]) target = argv[2]; cmdline = argv[3]; - xprintf("cmd_%s := %s\n\n", target, cmdline); + printf("cmd_%s := %s\n\n", target, cmdline); buf = read_file(depfile); parse_dep_file(buf, target); free(buf); + fflush(stdout); + + /* + * In the intended usage, the stdout is redirected to .*.cmd files. + * Call ferror() to catch errors such as "No space left on device". + */ + if (ferror(stdout)) { + fprintf(stderr, "fixdep: not all data was written to the output\n"); + exit(1); + } + return 0; } diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index dcd8d8750b8b..f9553f60a14a 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -7,24 +7,31 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import sys, os, re +import sys, os, re, argparse from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE, SIG_DFL) -if len(sys.argv) < 3: - sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0]) - sys.stderr.write("The options are:\n") - sys.stderr.write("-c categorize output based on symbol type\n") - sys.stderr.write("-d Show delta of Data Section\n") - sys.stderr.write("-t Show delta of text Section\n") - sys.exit(-1) +parser = argparse.ArgumentParser(description="Simple script used to compare the symbol sizes of 2 object files") +group = parser.add_mutually_exclusive_group() +group.add_argument('-c', help='categorize output based on symbol type', action='store_true') +group.add_argument('-d', help='Show delta of Data Section', action='store_true') +group.add_argument('-t', help='Show delta of text Section', action='store_true') +parser.add_argument('-p', dest='prefix', help='Arch prefix for the tool being used. Useful in cross build scenarios') +parser.add_argument('file1', help='First file to compare') +parser.add_argument('file2', help='Second file to compare') + +args = parser.parse_args() re_NUMBER = re.compile(r'\.[0-9]+') def getsizes(file, format): sym = {} - with os.popen("nm --size-sort " + file) as f: + nm = "nm" + if args.prefix: + nm = "{}nm".format(args.prefix) + + with os.popen("{} --size-sort {}".format(nm, file)) as f: for line in f: if line.startswith("\n") or ":" in line: continue @@ -36,6 +43,7 @@ def getsizes(file, format): if name.startswith("__se_compat_sys"): continue if name.startswith("__addressable_"): continue if name == "linux_banner": continue + if name == "vermagic": continue # statics and some other optimizations adds random .NUMBER name = re_NUMBER.sub('', name) sym[name] = sym.get(name, 0) + int(size, 16) @@ -76,9 +84,9 @@ def calc(oldfile, newfile, format): delta.reverse() return grow, shrink, add, remove, up, down, delta, old, new, otot, ntot -def print_result(symboltype, symbolformat, argc): +def print_result(symboltype, symbolformat): grow, shrink, add, remove, up, down, delta, old, new, otot, ntot = \ - calc(sys.argv[argc - 1], sys.argv[argc], symbolformat) + calc(args.file1, args.file2, symbolformat) print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ (add, remove, grow, shrink, up, -down, up-down)) @@ -92,13 +100,13 @@ def print_result(symboltype, symbolformat, argc): percent = 0 print("Total: Before=%d, After=%d, chg %+.2f%%" % (otot, ntot, percent)) -if sys.argv[1] == "-c": - print_result("Function", "tT", 3) - print_result("Data", "dDbB", 3) - print_result("RO Data", "rR", 3) -elif sys.argv[1] == "-d": - print_result("Data", "dDbBrR", 3) -elif sys.argv[1] == "-t": - print_result("Function", "tT", 3) +if args.c: + print_result("Function", "tT") + print_result("Data", "dDbB") + print_result("RO Data", "rR") +elif args.d: + print_result("Data", "dDbBrR") +elif args.t: + print_result("Function", "tT") else: - print_result("Function", "tTdDbBrR", 2) + print_result("Function", "tTdDbBrR") diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index a6403ddf5de7..d5c389df6045 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -10,6 +10,9 @@ from __future__ import print_function import argparse import re import sys, os +import subprocess + +helpersDocStart = 'Start of BPF helper function descriptions:' class NoHelperFound(BaseException): pass @@ -47,6 +50,10 @@ class Helper(APIElement): @desc: textual description of the helper function @ret: description of the return value of the helper function """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.enum_val = None + def proto_break_down(self): """ Break down helper function protocol into smaller chunks: return type, @@ -87,21 +94,26 @@ class HeaderParser(object): self.line = '' self.helpers = [] self.commands = [] + self.desc_unique_helpers = set() + self.define_unique_helpers = [] + self.helper_enum_vals = {} + self.desc_syscalls = [] + self.enum_syscalls = [] def parse_element(self): proto = self.parse_symbol() - desc = self.parse_desc() - ret = self.parse_ret() + desc = self.parse_desc(proto) + ret = self.parse_ret(proto) return APIElement(proto=proto, desc=desc, ret=ret) def parse_helper(self): proto = self.parse_proto() - desc = self.parse_desc() - ret = self.parse_ret() + desc = self.parse_desc(proto) + ret = self.parse_ret(proto) return Helper(proto=proto, desc=desc, ret=ret) def parse_symbol(self): - p = re.compile(' \* ?(.+)$') + p = re.compile(' \* ?(BPF\w+)$') capture = p.match(self.line) if not capture: raise NoSyscallCommandFound @@ -127,16 +139,15 @@ class HeaderParser(object): self.line = self.reader.readline() return capture.group(1) - def parse_desc(self): + def parse_desc(self, proto): p = re.compile(' \* ?(?:\t| {5,8})Description$') capture = p.match(self.line) if not capture: - # Helper can have empty description and we might be parsing another - # attribute: return but do not consume. - return '' + raise Exception("No description section found for " + proto) # Description can be several lines, some of them possibly empty, and it # stops when another subsection title is met. desc = '' + desc_present = False while True: self.line = self.reader.readline() if self.line == ' *\n': @@ -145,21 +156,24 @@ class HeaderParser(object): p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') capture = p.match(self.line) if capture: + desc_present = True desc += capture.group(1) + '\n' else: break + + if not desc_present: + raise Exception("No description found for " + proto) return desc - def parse_ret(self): + def parse_ret(self, proto): p = re.compile(' \* ?(?:\t| {5,8})Return$') capture = p.match(self.line) if not capture: - # Helper can have empty retval and we might be parsing another - # attribute: return but do not consume. - return '' + raise Exception("No return section found for " + proto) # Return value description can be several lines, some of them possibly # empty, and it stops when another subsection title is met. ret = '' + ret_present = False while True: self.line = self.reader.readline() if self.line == ' *\n': @@ -168,44 +182,125 @@ class HeaderParser(object): p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') capture = p.match(self.line) if capture: + ret_present = True ret += capture.group(1) + '\n' else: break + + if not ret_present: + raise Exception("No return found for " + proto) return ret - def seek_to(self, target, help_message): + def seek_to(self, target, help_message, discard_lines = 1): self.reader.seek(0) offset = self.reader.read().find(target) if offset == -1: raise Exception(help_message) self.reader.seek(offset) self.reader.readline() - self.reader.readline() + for _ in range(discard_lines): + self.reader.readline() self.line = self.reader.readline() - def parse_syscall(self): + def parse_desc_syscall(self): self.seek_to('* DOC: eBPF Syscall Commands', 'Could not find start of eBPF syscall descriptions list') while True: try: command = self.parse_element() self.commands.append(command) + self.desc_syscalls.append(command.proto) + except NoSyscallCommandFound: break - def parse_helpers(self): - self.seek_to('* Start of BPF helper function descriptions:', + def parse_enum_syscall(self): + self.seek_to('enum bpf_cmd {', + 'Could not find start of bpf_cmd enum', 0) + # Searches for either one or more BPF\w+ enums + bpf_p = re.compile('\s*(BPF\w+)+') + # Searches for an enum entry assigned to another entry, + # for e.g. BPF_PROG_RUN = BPF_PROG_TEST_RUN, which is + # not documented hence should be skipped in check to + # determine if the right number of syscalls are documented + assign_p = re.compile('\s*(BPF\w+)\s*=\s*(BPF\w+)') + bpf_cmd_str = '' + while True: + capture = assign_p.match(self.line) + if capture: + # Skip line if an enum entry is assigned to another entry + self.line = self.reader.readline() + continue + capture = bpf_p.match(self.line) + if capture: + bpf_cmd_str += self.line + else: + break + self.line = self.reader.readline() + # Find the number of occurences of BPF\w+ + self.enum_syscalls = re.findall('(BPF\w+)+', bpf_cmd_str) + + def parse_desc_helpers(self): + self.seek_to(helpersDocStart, 'Could not find start of eBPF helper descriptions list') while True: try: helper = self.parse_helper() self.helpers.append(helper) + proto = helper.proto_break_down() + self.desc_unique_helpers.add(proto['name']) except NoHelperFound: break + def parse_define_helpers(self): + # Parse FN(...) in #define __BPF_FUNC_MAPPER to compare later with the + # number of unique function names present in description and use the + # correct enumeration value. + # Note: seek_to(..) discards the first line below the target search text, + # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers. + self.seek_to('#define __BPF_FUNC_MAPPER(FN)', + 'Could not find start of eBPF helper definition list') + # Searches for one FN(\w+) define or a backslash for newline + p = re.compile('\s*FN\((\w+)\)|\\\\') + fn_defines_str = '' + i = 1 # 'unspec' is skipped as mentioned above + while True: + capture = p.match(self.line) + if capture: + fn_defines_str += self.line + self.helper_enum_vals[capture.expand(r'bpf_\1')] = i + i += 1 + else: + break + self.line = self.reader.readline() + # Find the number of occurences of FN(\w+) + self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str) + + def assign_helper_values(self): + seen_helpers = set() + for helper in self.helpers: + proto = helper.proto_break_down() + name = proto['name'] + try: + enum_val = self.helper_enum_vals[name] + except KeyError: + raise Exception("Helper %s is missing from enum bpf_func_id" % name) + + # Enforce current practice of having the descriptions ordered + # by enum value. + seen_helpers.add(name) + desc_val = len(seen_helpers) + if desc_val != enum_val: + raise Exception("Helper %s comment order (#%d) must be aligned with its position (#%d) in enum bpf_func_id" % (name, desc_val, enum_val)) + + helper.enum_val = enum_val + def run(self): - self.parse_syscall() - self.parse_helpers() + self.parse_desc_syscall() + self.parse_enum_syscall() + self.parse_desc_helpers() + self.parse_define_helpers() + self.assign_helper_values() self.reader.close() ############################################################################### @@ -235,6 +330,25 @@ class Printer(object): self.print_one(elem) self.print_footer() + def elem_number_check(self, desc_unique_elem, define_unique_elem, type, instance): + """ + Checks the number of helpers/syscalls documented within the header file + description with those defined as part of enum/macro and raise an + Exception if they don't match. + """ + nr_desc_unique_elem = len(desc_unique_elem) + nr_define_unique_elem = len(define_unique_elem) + if nr_desc_unique_elem != nr_define_unique_elem: + exception_msg = ''' +The number of unique %s in description (%d) doesn\'t match the number of unique %s defined in %s (%d) +''' % (type, nr_desc_unique_elem, type, instance, nr_define_unique_elem) + if nr_desc_unique_elem < nr_define_unique_elem: + # Function description is parsed until no helper is found (which can be due to + # misformatting). Hence, only print the first missing/misformatted helper/enum. + exception_msg += ''' +The description for %s is not present or formatted correctly. +''' % (define_unique_elem[nr_desc_unique_elem]) + raise Exception(exception_msg) class PrinterRST(Printer): """ @@ -251,27 +365,7 @@ class PrinterRST(Printer): .. Copyright (C) All BPF authors and contributors from 2014 to present. .. See git log include/uapi/linux/bpf.h in kernel tree for details. .. -.. %%%LICENSE_START(VERBATIM) -.. Permission is granted to make and distribute verbatim copies of this -.. manual provided the copyright notice and this permission notice are -.. preserved on all copies. -.. -.. Permission is granted to copy and distribute modified versions of this -.. manual under the conditions for verbatim copying, provided that the -.. entire resulting derived work is distributed under the terms of a -.. permission notice identical to this one. -.. -.. Since the Linux kernel and libraries are constantly changing, this -.. manual page may be incorrect or out-of-date. The author(s) assume no -.. responsibility for errors or omissions, or for damages resulting from -.. the use of the information contained herein. The author(s) may not -.. have taken the same level of care in the production of this manual, -.. which is licensed free of charge, as they might when working -.. professionally. -.. -.. Formatted or processed versions of this manual, if unaccompanied by -.. the source, must acknowledge the copyright and authors of this work. -.. %%%LICENSE_END +.. SPDX-License-Identifier: Linux-man-pages-copyleft .. .. Please do not edit this file. It was generated from the documentation .. located in file include/uapi/linux/bpf.h of the Linux kernel sources @@ -295,6 +389,30 @@ class PrinterRST(Printer): print('') + def get_kernel_version(self): + try: + version = subprocess.run(['git', 'describe'], cwd=linuxRoot, + capture_output=True, check=True) + version = version.stdout.decode().rstrip() + except: + try: + version = subprocess.run(['make', 'kernelversion'], cwd=linuxRoot, + capture_output=True, check=True) + version = version.stdout.decode().rstrip() + except: + return 'Linux' + return 'Linux {version}'.format(version=version) + + def get_last_doc_update(self, delimiter): + try: + cmd = ['git', 'log', '-1', '--pretty=format:%cs', '--no-patch', + '-L', + '/{}/,/\*\//:include/uapi/linux/bpf.h'.format(delimiter)] + date = subprocess.run(cmd, cwd=linuxRoot, + capture_output=True, check=True) + return date.stdout.decode().rstrip() + except: + return '' class PrinterHelpersRST(PrinterRST): """ @@ -305,6 +423,7 @@ class PrinterHelpersRST(PrinterRST): """ def __init__(self, parser): self.elements = parser.helpers + self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '__BPF_FUNC_MAPPER') def print_header(self): header = '''\ @@ -316,6 +435,8 @@ list of eBPF helper functions ------------------------------------------------------------------------------- :Manual section: 7 +:Version: {version} +{date_field}{date} DESCRIPTION =========== @@ -348,8 +469,13 @@ kernel at the top). HELPERS ======= ''' + kernelVersion = self.get_kernel_version() + lastUpdate = self.get_last_doc_update(helpersDocStart) + PrinterRST.print_license(self) - print(header) + print(header.format(version=kernelVersion, + date_field = ':Date: ' if lastUpdate else '', + date=lastUpdate)) def print_footer(self): footer = ''' @@ -478,6 +604,7 @@ class PrinterSyscallRST(PrinterRST): """ def __init__(self, parser): self.elements = parser.commands + self.elem_number_check(parser.desc_syscalls, parser.enum_syscalls, 'syscall', 'bpf_cmd') def print_header(self): header = '''\ @@ -509,6 +636,7 @@ class PrinterHelpers(Printer): """ def __init__(self, parser): self.elements = parser.helpers + self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '__BPF_FUNC_MAPPER') type_fwds = [ 'struct bpf_fib_lookup', @@ -549,6 +677,10 @@ class PrinterHelpers(Printer): 'struct socket', 'struct file', 'struct bpf_timer', + 'struct mptcp_sock', + 'struct bpf_dynptr', + 'struct iphdr', + 'struct ipv6hdr', ] known_types = { '...', @@ -598,6 +730,10 @@ class PrinterHelpers(Printer): 'struct socket', 'struct file', 'struct bpf_timer', + 'struct mptcp_sock', + 'struct bpf_dynptr', + 'struct iphdr', + 'struct ipv6hdr', } mapped_types = { 'u8': '__u8', @@ -689,7 +825,7 @@ class PrinterHelpers(Printer): comma = ', ' print(one_arg, end='') - print(') = (void *) %d;' % len(self.seen_helpers)) + print(') = (void *) %d;' % helper.enum_val) print('') ############################################################################### diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh index f1952c522466..2401c86fcf53 100755 --- a/scripts/cc-version.sh +++ b/scripts/cc-version.sh @@ -1,13 +1,13 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # -# Print the compiler name and its version in a 5 or 6-digit form. +# Print the C compiler name and its version in a 5 or 6-digit form. # Also, perform the minimum version check. set -e -# Print the compiler name and some version components. -get_compiler_info() +# Print the C compiler name and some version components. +get_c_compiler_info() { cat <<- EOF | "$@" -E -P -x c - 2>/dev/null #if defined(__clang__) @@ -32,7 +32,7 @@ get_canonical_version() # $@ instead of $1 because multiple words might be given, e.g. CC="ccache gcc". orig_args="$@" -set -- $(get_compiler_info "$@") +set -- $(get_c_compiler_info "$@") name=$1 @@ -52,7 +52,7 @@ ICC) min_version=$($min_tool_version icc) ;; *) - echo "$orig_args: unknown compiler" >&2 + echo "$orig_args: unknown C compiler" >&2 exit 1 ;; esac @@ -62,7 +62,7 @@ min_cversion=$(get_canonical_version $min_version) if [ "$cversion" -lt "$min_cversion" ]; then echo >&2 "***" - echo >&2 "*** Compiler is too old." + echo >&2 "*** C compiler is too old." echo >&2 "*** Your $name version: $version" echo >&2 "*** Minimum $name version: $min_version" echo >&2 "***" diff --git a/scripts/check-local-export b/scripts/check-local-export new file mode 100755 index 000000000000..f90b5a9c67b3 --- /dev/null +++ b/scripts/check-local-export @@ -0,0 +1,70 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 Masahiro Yamada <masahiroy@kernel.org> +# Copyright (C) 2022 Owen Rafferty <owen@owenrafferty.com> +# +# Exit with error if a local exported symbol is found. +# EXPORT_SYMBOL should be used for global symbols. + +set -e +pid=$$ + +# If there is no symbol in the object, ${NM} (both GNU nm and llvm-nm) shows +# 'no symbols' diagnostic (but exits with 0). It is harmless and hidden by +# '2>/dev/null'. However, it suppresses real error messages as well. Add a +# hand-crafted error message here. +# +# TODO: +# Use --quiet instead of 2>/dev/null when we upgrade the minimum version of +# binutils to 2.37, llvm to 13.0.0. +# Then, the following line will be simpler: +# { ${NM} --quiet ${1} || kill 0; } | + +{ ${NM} ${1} 2>/dev/null || { echo "${0}: ${NM} failed" >&2; kill $pid; } } | +${AWK} -v "file=${1}" ' +BEGIN { + i = 0 +} + +# Skip the line if the number of fields is less than 3. +# +# case 1) +# For undefined symbols, the first field (value) is empty. +# The outout looks like this: +# " U _printk" +# It is unneeded to record undefined symbols. +# +# case 2) +# For Clang LTO, llvm-nm outputs a line with type t but empty name: +# "---------------- t" +!length($3) { + next +} + +# save (name, type) in the associative array +{ symbol_types[$3]=$2 } + +# append the exported symbol to the array +($3 ~ /^__ksymtab_/) { + export_symbols[i] = $3 + sub(/^__ksymtab_/, "", export_symbols[i]) + i++ +} + +END { + exit_code = 0 + for (j = 0; j < i; ++j) { + name = export_symbols[j] + # nm(3) says "If lowercase, the symbol is usually local" + if (symbol_types[name] ~ /[a-z]/) { + printf "%s: error: local symbol %s was exported\n", + file, name | "cat 1>&2" + exit_code = 1 + } + } + + exit exit_code +}' + +exit $? diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1784921c645d..1e5e66ae5a52 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -334,7 +334,7 @@ if ($user_codespellfile) { } elsif (!(-f $codespellfile)) { # If /usr/share/codespell/dictionary.txt is not present, try to find it # under codespell's install directory: <codespell_root>/data/dictionary.txt - if (($codespell || $help) && which("codespell") ne "" && which("python") ne "") { + if (($codespell || $help) && which("python3") ne "") { my $python_codespell_dict = << "EOF"; import os.path as op @@ -344,7 +344,7 @@ codespell_file = op.join(codespell_dir, 'data', 'dictionary.txt') print(codespell_file, end='') EOF - my $codespell_dict = `python -c "$python_codespell_dict" 2> /dev/null`; + my $codespell_dict = `python3 -c "$python_codespell_dict" 2> /dev/null`; $codespellfile = $codespell_dict if (-f $codespell_dict); } } @@ -576,10 +576,14 @@ our $typeKernelTypedefs = qr{(?x: (?:__)?(?:u|s|be|le)(?:8|16|32|64)| atomic_t )}; +our $typeStdioTypedefs = qr{(?x: + FILE +)}; our $typeTypedefs = qr{(?x: $typeC99Typedefs\b| $typeOtherOSTypedefs\b| - $typeKernelTypedefs\b + $typeKernelTypedefs\b| + $typeStdioTypedefs\b )}; our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b}; @@ -807,6 +811,8 @@ our %deprecated_apis = ( "rcu_barrier_sched" => "rcu_barrier", "get_state_synchronize_sched" => "get_state_synchronize_rcu", "cond_synchronize_sched" => "cond_synchronize_rcu", + "kmap" => "kmap_local_page", + "kmap_atomic" => "kmap_local_page", ); #Create a search pattern for all these strings to speed up a loop below @@ -1042,7 +1048,8 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; our $declaration_macros = qr{(?x: (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(| - (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\( + (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(| + (?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\( )}; our %allow_repeated_words = ( @@ -3139,6 +3146,50 @@ sub process { } } +# Check Fixes: styles is correct + if (!$in_header_lines && + $line =~ /^\s*fixes:?\s*(?:commit\s*)?[0-9a-f]{5,}\b/i) { + my $orig_commit = ""; + my $id = "0123456789ab"; + my $title = "commit title"; + my $tag_case = 1; + my $tag_space = 1; + my $id_length = 1; + my $id_case = 1; + my $title_has_quotes = 0; + + if ($line =~ /(\s*fixes:?)\s+([0-9a-f]{5,})\s+($balanced_parens)/i) { + my $tag = $1; + $orig_commit = $2; + $title = $3; + + $tag_case = 0 if $tag eq "Fixes:"; + $tag_space = 0 if ($line =~ /^fixes:? [0-9a-f]{5,} ($balanced_parens)/i); + + $id_length = 0 if ($orig_commit =~ /^[0-9a-f]{12}$/i); + $id_case = 0 if ($orig_commit !~ /[A-F]/); + + # Always strip leading/trailing parens then double quotes if existing + $title = substr($title, 1, -1); + if ($title =~ /^".*"$/) { + $title = substr($title, 1, -1); + $title_has_quotes = 1; + } + } + + my ($cid, $ctitle) = git_commit_info($orig_commit, $id, + $title); + + if ($ctitle ne $title || $tag_case || $tag_space || + $id_length || $id_case || !$title_has_quotes) { + if (WARN("BAD_FIXES_TAG", + "Please use correct Fixes: style 'Fixes: <12 chars of sha1> (\"<title line>\")' - ie: 'Fixes: $cid (\"$ctitle\")'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = "Fixes: $cid (\"$ctitle\")"; + } + } + } + # Check email subject for common tools that don't need to be mentioned if ($in_header_lines && $line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) { @@ -3172,7 +3223,7 @@ sub process { length($line) > 75 && !($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ || # file delta changes - $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || + $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ || # filename then : $line =~ /^\s*(?:Fixes:|Link:|$signature_tags)/i || # A Fixes: or Link: line or signature tag line @@ -3479,47 +3530,47 @@ sub process { # Kconfig supports named choices), so use a word boundary # (\b) rather than a whitespace character (\s) $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) { - my $length = 0; - my $cnt = $realcnt; - my $ln = $linenr + 1; - my $f; - my $is_start = 0; - my $is_end = 0; - for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { - $f = $lines[$ln - 1]; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $is_end = $lines[$ln - 1] =~ /^\+/; + my $ln = $linenr; + my $needs_help = 0; + my $has_help = 0; + my $help_length = 0; + while (defined $lines[$ln]) { + my $f = $lines[$ln++]; next if ($f =~ /^-/); - last if (!$file && $f =~ /^\@\@/); + last if ($f !~ /^[\+ ]/); # !patch context - if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { - $is_start = 1; - } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { - $length = -1; + if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { + $needs_help = 1; + next; + } + if ($f =~ /^\+\s*help\s*$/) { + $has_help = 1; + next; } - $f =~ s/^.//; - $f =~ s/#.*//; - $f =~ s/^\s+//; - next if ($f =~ /^$/); + $f =~ s/^.//; # strip patch context [+ ] + $f =~ s/#.*//; # strip # directives + $f =~ s/^\s+//; # strip leading blanks + next if ($f =~ /^$/); # skip blank lines + # At the end of this Kconfig block: # This only checks context lines in the patch # and so hopefully shouldn't trigger false # positives, even though some of these are # common words in help texts - if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice| - if|endif|menu|endmenu|source)\b/x) { - $is_end = 1; + if ($f =~ /^(?:config|menuconfig|choice|endchoice| + if|endif|menu|endmenu|source)\b/x) { last; } - $length++; + $help_length++ if ($has_help); } - if ($is_start && $is_end && $length < $min_conf_desc_length) { + if ($needs_help && + $help_length < $min_conf_desc_length) { + my $stat_real = get_stat_real($linenr, $ln - 1); WARN("CONFIG_DESCRIPTION", - "please write a paragraph that describes the config symbol fully\n" . $herecurr); + "please write a help paragraph that fully describes the config symbol\n" . "$here\n$stat_real\n"); } - #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; } # check MAINTAINERS entries @@ -3615,7 +3666,7 @@ sub process { my $comment = ""; if ($realfile =~ /\.(h|s|S)$/) { $comment = '/*'; - } elsif ($realfile =~ /\.(c|dts|dtsi)$/) { + } elsif ($realfile =~ /\.(c|rs|dts|dtsi)$/) { $comment = '//'; } elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc|yaml)$/) { $comment = '#'; @@ -3663,7 +3714,7 @@ sub process { } # check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/); + next if ($realfile !~ /\.(h|c|rs|s|S|sh|dtsi|dts)$/); # check for using SPDX-License-Identifier on the wrong line number if ($realline != $checklicenseline && @@ -3750,7 +3801,7 @@ sub process { if ($realfile =~ /\.S$/ && $line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) { WARN("AVOID_L_PREFIX", - "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/asm-annotations.rst\n" . $herecurr); + "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/core-api/asm-annotations.rst\n" . $herecurr); } # check we are in a valid source file C or perl if not then ignore this hunk @@ -3926,7 +3977,7 @@ sub process { if ($prevline =~ /^[\+ ]};?\s*$/ && $line =~ /^\+/ && !($line =~ /^\+\s*$/ || - $line =~ /^\+\s*EXPORT_SYMBOL/ || + $line =~ /^\+\s*(?:EXPORT_SYMBOL|early_param)/ || $line =~ /^\+\s*MODULE_/i || $line =~ /^\+\s*\#\s*(?:end|elif|else)/ || $line =~ /^\+[a-z_]*init/ || @@ -4694,12 +4745,12 @@ sub process { } } -# avoid BUG() or BUG_ON() - if ($line =~ /\b(?:BUG|BUG_ON)\b/) { +# do not use BUG() or variants + if ($line =~ /\b(?!AA_|BUILD_|DCCP_|IDA_|KVM_|RWLOCK_|snd_|SPIN_)(?:[a-zA-Z_]*_)?BUG(?:_ON)?(?:_[A-Z_]+)?\s*\(/) { my $msg_level = \&WARN; $msg_level = \&CHK if ($file); &{$msg_level}("AVOID_BUG", - "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); + "Do not crash the kernel unless it is absolutely unavoidable--use WARN_ON_ONCE() plus recovery code (if feasible) instead of BUG() or variants\n" . $herecurr); } # avoid LINUX_VERSION_CODE @@ -5551,6 +5602,7 @@ sub process { defined($stat) && defined($cond) && $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { my ($s, $c) = ($stat, $cond); + my $fixed_assign_in_if = 0; if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { if (ERROR("ASSIGN_IN_IF", @@ -5575,6 +5627,7 @@ sub process { $newline .= ')'; $newline .= " {" if (defined($brace)); fix_insert_line($fixlinenr + 1, $newline); + $fixed_assign_in_if = 1; } } } @@ -5598,8 +5651,20 @@ sub process { $stat_real = "[...]\n$stat_real"; } - ERROR("TRAILING_STATEMENTS", - "trailing statements should be on next line\n" . $herecurr . $stat_real); + if (ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr . $stat_real) && + !$fixed_assign_in_if && + $cond_lines == 0 && + $fix && $perl_version_ok && + $fixed[$fixlinenr] =~ /^\+(\s*)((?:if|while|for)\s*$balanced_parens)\s*(.*)$/) { + my $indent = $1; + my $test = $2; + my $rest = rtrim($4); + if ($rest =~ /;$/) { + $fixed[$fixlinenr] = "\+$indent$test"; + fix_insert_line($fixlinenr + 1, "$indent\t$rest"); + } + } } } @@ -5706,7 +5771,7 @@ sub process { $var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ && #Ignore some three character SI units explicitly, like MiB and KHz $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) { - while ($var =~ m{($Ident)}g) { + while ($var =~ m{\b($Ident)}g) { my $word = $1; next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); if ($check) { @@ -6768,15 +6833,19 @@ sub process { } if ($bad_specifier ne "") { my $stat_real = get_stat_real($linenr, $lc); + my $msg_level = \&WARN; my $ext_type = "Invalid"; my $use = ""; if ($bad_specifier =~ /p[Ff]/) { $use = " - use %pS instead"; $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/); + } elsif ($bad_specifier =~ /pA/) { + $use = " - '%pA' is only intended to be used from Rust code"; + $msg_level = \&ERROR; } - WARN("VSPRINTF_POINTER_EXTENSION", - "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n"); + &{$msg_level}("VSPRINTF_POINTER_EXTENSION", + "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n"); } } } @@ -7019,14 +7088,16 @@ sub process { "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); } -# check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc +# check for (kv|k)[mz]alloc with multiplies that could be kmalloc_array/kvmalloc_array/kvcalloc/kcalloc if ($perl_version_ok && defined $stat && - $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { + $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { my $oldfunc = $3; my $a1 = $4; my $a2 = $10; my $newfunc = "kmalloc_array"; + $newfunc = "kvmalloc_array" if ($oldfunc eq "kvmalloc"); + $newfunc = "kvcalloc" if ($oldfunc eq "kvzalloc"); $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); my $r1 = $a1; my $r2 = $a2; @@ -7043,7 +7114,7 @@ sub process { "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && $cnt == 1 && $fix) { - $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; + $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; } } } @@ -7418,6 +7489,13 @@ sub process { WARN("MODULE_LICENSE", "unknown module license " . $extracted_string . "\n" . $herecurr); } + if (!$file && $extracted_string eq '"GPL v2"') { + if (WARN("MODULE_LICENSE", + "Prefer \"GPL\" over \"GPL v2\" - see commit bf7fbeeae6db (\"module: Cure the MODULE_LICENSE \"GPL\" vs. \"GPL v2\" bogosity\")\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bMODULE_LICENSE\s*\(\s*"GPL v2"\s*\)/MODULE_LICENSE("GPL")/; + } + } } # check for sysctl duplicate constants diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index d2c38584ece6..d48dfed6d3db 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -16,6 +16,7 @@ # AArch64, PARISC ports by Kyle McMartin # sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk> # ppc64le port by Breno Leitao <leitao@debian.org> +# riscv port by Wadim Mueller <wafgo01@gmail.com> # # Usage: # objdump -d vmlinux | scripts/checkstack.pl [arch] @@ -108,6 +109,9 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { # f0019d10: 9d e3 bf 90 save %sp, -112, %sp $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; + } elsif ($arch =~ /^riscv(64)?$/) { + #ffffffff8036e868: c2010113 addi sp,sp,-992 + $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; } else { print("wrong or unknown architecture \"$arch\"\n"); exit diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 9dbab13329fa..f33e61aca93d 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -268,4 +268,4 @@ syscall_list() { } (ignore_list && syscall_list $(dirname $0)/../arch/x86/entry/syscalls/syscall_32.tbl) | \ -$* -Wno-error -E -x c - > /dev/null +$* -Wno-error -Wno-unused-macros -E -x c - > /dev/null diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py index 1d1bde1fd45e..d800b2c0af97 100755 --- a/scripts/clang-tools/gen_compile_commands.py +++ b/scripts/clang-tools/gen_compile_commands.py @@ -109,20 +109,6 @@ def to_cmdfile(path): return os.path.join(dir, '.' + base + '.cmd') -def cmdfiles_for_o(obj): - """Generate the iterator of .cmd files associated with the object - - Yield the .cmd file used to build the given object - - Args: - obj: The object path - - Yields: - The path to .cmd file - """ - yield to_cmdfile(obj) - - def cmdfiles_for_a(archive, ar): """Generate the iterator of .cmd files associated with the archive. @@ -157,10 +143,10 @@ def cmdfiles_for_modorder(modorder): if ext != '.ko': sys.exit('{}: module path must end with .ko'.format(ko)) mod = base + '.mod' - # The first line of *.mod lists the objects that compose the module. + # Read from *.mod, to get a list of objects that compose the module. with open(mod) as m: - for obj in m.readline().split(): - yield to_cmdfile(obj) + for mod_line in m: + yield to_cmdfile(mod_line.rstrip()) def process_line(root_directory, command_prefix, file_path): @@ -211,13 +197,10 @@ def main(): for path in paths: # If 'path' is a directory, handle all .cmd files under it. # Otherwise, handle .cmd files associated with the file. - # Most of built-in objects are linked via archives (built-in.a or lib.a) - # but some objects are linked to vmlinux directly. + # built-in objects are linked via vmlinux.a # Modules are listed in modules.order. if os.path.isdir(path): cmdfiles = cmdfiles_in_dir(path) - elif path.endswith('.o'): - cmdfiles = cmdfiles_for_o(path) elif path.endswith('.a'): cmdfiles = cmdfiles_for_a(path, ar) elif path.endswith('modules.order'): diff --git a/scripts/clang-tools/run-clang-tools.py b/scripts/clang-tools/run-clang-tools.py index f754415af398..56f2ec8f0f40 100755 --- a/scripts/clang-tools/run-clang-tools.py +++ b/scripts/clang-tools/run-clang-tools.py @@ -12,7 +12,6 @@ compile_commands.json. import argparse import json import multiprocessing -import os import subprocess import sys @@ -46,12 +45,14 @@ def init(l, a): def run_analysis(entry): # Disable all checks, then re-enable the ones we want - checks = "-checks=-*," + checks = [] + checks.append("-checks=-*") if args.type == "clang-tidy": - checks += "linuxkernel-*" + checks.append("linuxkernel-*") else: - checks += "clang-analyzer-*" - p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]], + checks.append("clang-analyzer-*") + checks.append("-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling") + p = subprocess.run(["clang-tidy", "-p", args.path, ",".join(checks), entry["file"]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=entry["directory"]) diff --git a/scripts/coccinelle/api/alloc/zalloc-simple.cocci b/scripts/coccinelle/api/alloc/zalloc-simple.cocci index b3d0c3c230c1..d66c45356691 100644 --- a/scripts/coccinelle/api/alloc/zalloc-simple.cocci +++ b/scripts/coccinelle/api/alloc/zalloc-simple.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. // Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. // Copyright: (C) 2017 Himanshu Jha -// URL: http://coccinelle.lip6.fr/rules/kzalloc.html +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers // // Keywords: kmalloc, kzalloc diff --git a/scripts/coccinelle/api/atomic_as_refcounter.cocci b/scripts/coccinelle/api/atomic_as_refcounter.cocci index 0f78d94abc35..e63d52408b86 100644 --- a/scripts/coccinelle/api/atomic_as_refcounter.cocci +++ b/scripts/coccinelle/api/atomic_as_refcounter.cocci @@ -5,7 +5,7 @@ // Copyright (c) 2016-2017, Elena Reshetova, Intel Corporation // // Confidence: Moderate -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --include-headers --very-quiet virtual report diff --git a/scripts/coccinelle/api/check_bq27xxx_data.cocci b/scripts/coccinelle/api/check_bq27xxx_data.cocci index fae539ef0ce5..27366c6169ec 100644 --- a/scripts/coccinelle/api/check_bq27xxx_data.cocci +++ b/scripts/coccinelle/api/check_bq27xxx_data.cocci @@ -6,7 +6,7 @@ /// // Confidence: High // Copyright: (C) 2017 Julia Lawall, Inria/LIP6, -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Requires: 1.0.7 // Keywords: BQ27XXX_DATA diff --git a/scripts/coccinelle/api/d_find_alias.cocci b/scripts/coccinelle/api/d_find_alias.cocci index 47e050166f20..3489001378ab 100644 --- a/scripts/coccinelle/api/d_find_alias.cocci +++ b/scripts/coccinelle/api/d_find_alias.cocci @@ -4,7 +4,7 @@ // Keywords: d_find_alias, dput // // Confidence: Moderate -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --include-headers virtual context diff --git a/scripts/coccinelle/api/err_cast.cocci b/scripts/coccinelle/api/err_cast.cocci index 0e661c8d8d6f..7f9dc1212c74 100644 --- a/scripts/coccinelle/api/err_cast.cocci +++ b/scripts/coccinelle/api/err_cast.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. // Copyright: (C) 2009, 2010 Julia Lawall, DIKU. // Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: // // Keywords: ERR_PTR, PTR_ERR, ERR_CAST diff --git a/scripts/coccinelle/api/kstrdup.cocci b/scripts/coccinelle/api/kstrdup.cocci index 3c6dc5469ee4..8a61534676da 100644 --- a/scripts/coccinelle/api/kstrdup.cocci +++ b/scripts/coccinelle/api/kstrdup.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci index 30b15df734e5..d28741c69873 100644 --- a/scripts/coccinelle/api/memdup.cocci +++ b/scripts/coccinelle/api/memdup.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci index e01e95108405..03e7afa09eee 100644 --- a/scripts/coccinelle/api/memdup_user.cocci +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci index 1ccce3fd00b8..4b9778874453 100644 --- a/scripts/coccinelle/api/pm_runtime.cocci +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -4,7 +4,7 @@ // Keywords: pm_runtime // Confidence: Medium // Copyright (C) 2013 Texas Instruments Incorporated - -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --include-headers virtual patch diff --git a/scripts/coccinelle/api/resource_size.cocci b/scripts/coccinelle/api/resource_size.cocci index a9a571ac04ce..16857072d162 100644 --- a/scripts/coccinelle/api/resource_size.cocci +++ b/scripts/coccinelle/api/resource_size.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. // Copyright: (C) 2009, 2010 Julia Lawall, DIKU. // Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: // // Keywords: resource_size diff --git a/scripts/coccinelle/free/clk_put.cocci b/scripts/coccinelle/free/clk_put.cocci index 7237b49496f6..3c732cb7210b 100644 --- a/scripts/coccinelle/free/clk_put.cocci +++ b/scripts/coccinelle/free/clk_put.cocci @@ -8,7 +8,7 @@ // Confidence: Moderate // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci index da80050b91ff..0880729badbc 100644 --- a/scripts/coccinelle/free/devm_free.cocci +++ b/scripts/coccinelle/free/devm_free.cocci @@ -17,7 +17,7 @@ // Confidence: Moderate // Copyright: (C) 2011 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/free/ifnulldev_put.cocci b/scripts/coccinelle/free/ifnulldev_put.cocci new file mode 100644 index 000000000000..2bd2e8fae485 --- /dev/null +++ b/scripts/coccinelle/free/ifnulldev_put.cocci @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Since commit b37a46683739 ("netdevice: add the case if dev is NULL"), +/// NULL check before dev_{put, hold} functions is not needed. +/// +/// Based on ifnullfree.cocci by Fabian Frederick. +/// +// Copyright: (C) 2022 Ziyang Xuan. +// Comments: - +// Options: --no-includes --include-headers +// Version min: 5.15 + +virtual patch +virtual org +virtual report +virtual context + +@r2 depends on patch@ +expression E; +@@ +- if (E != NULL) +( + __dev_put(E); +| + dev_put(E); +| + dev_put_track(E, ...); +| + __dev_hold(E); +| + dev_hold(E); +| + dev_hold_track(E, ...); +) + +@r depends on context || report || org @ +expression E; +position p; +@@ + +* if (E != NULL) +* \(__dev_put@p\|dev_put@p\|dev_put_track@p\|__dev_hold@p\|dev_hold@p\| +* dev_hold_track@p\)(E, ...); + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("NULL check before dev_{put, hold} functions is not needed", p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "WARNING: NULL check before dev_{put, hold} functions is not needed." +coccilib.report.print_report(p[0], msg) diff --git a/scripts/coccinelle/free/iounmap.cocci b/scripts/coccinelle/free/iounmap.cocci index 63b81d0c97b6..90d85fa7bfdf 100644 --- a/scripts/coccinelle/free/iounmap.cocci +++ b/scripts/coccinelle/free/iounmap.cocci @@ -8,7 +8,7 @@ // Confidence: Moderate // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci index 9b6e2037c2a9..6338bbac2f7f 100644 --- a/scripts/coccinelle/free/kfree.cocci +++ b/scripts/coccinelle/free/kfree.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/free/kfreeaddr.cocci b/scripts/coccinelle/free/kfreeaddr.cocci index 142af6337a04..85635a36f0ac 100644 --- a/scripts/coccinelle/free/kfreeaddr.cocci +++ b/scripts/coccinelle/free/kfreeaddr.cocci @@ -3,7 +3,7 @@ /// // Confidence: High // Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/free/pci_free_consistent.cocci b/scripts/coccinelle/free/pci_free_consistent.cocci index d51e92556b42..e062b9ba09ff 100644 --- a/scripts/coccinelle/free/pci_free_consistent.cocci +++ b/scripts/coccinelle/free/pci_free_consistent.cocci @@ -3,7 +3,7 @@ /// // Confidence: Moderate // Copyright: (C) 2013 Petr Strnad. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Keywords: pci_free_consistent, pci_alloc_consistent // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/iterators/device_node_continue.cocci b/scripts/coccinelle/iterators/device_node_continue.cocci index f8cd14dfa604..5713c9cf59ff 100644 --- a/scripts/coccinelle/iterators/device_node_continue.cocci +++ b/scripts/coccinelle/iterators/device_node_continue.cocci @@ -4,7 +4,7 @@ /// // Confidence: High // Copyright: (C) 2015 Julia Lawall, Inria. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers // Requires: 1.0.4 // Keywords: for_each_child_of_node, etc. diff --git a/scripts/coccinelle/iterators/fen.cocci b/scripts/coccinelle/iterators/fen.cocci deleted file mode 100644 index b69f9665f4fb..000000000000 --- a/scripts/coccinelle/iterators/fen.cocci +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/// These iterators only exit normally when the loop cursor is NULL, so there -/// is no point to call of_node_put on the final value. -/// -// Confidence: High -// Copyright: (C) 2010-2012 Nicolas Palix. -// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. -// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ -// Comments: -// Options: --no-includes --include-headers - -virtual patch -virtual context -virtual org -virtual report - -@depends on patch@ -iterator name for_each_node_by_name; -expression np,E; -identifier l; -@@ - -for_each_node_by_name(np,...) { - ... when != break; - when != goto l; -} -... when != np = E -- of_node_put(np); - -@depends on patch@ -iterator name for_each_node_by_type; -expression np,E; -identifier l; -@@ - -for_each_node_by_type(np,...) { - ... when != break; - when != goto l; -} -... when != np = E -- of_node_put(np); - -@depends on patch@ -iterator name for_each_compatible_node; -expression np,E; -identifier l; -@@ - -for_each_compatible_node(np,...) { - ... when != break; - when != goto l; -} -... when != np = E -- of_node_put(np); - -@depends on patch@ -iterator name for_each_matching_node; -expression np,E; -identifier l; -@@ - -for_each_matching_node(np,...) { - ... when != break; - when != goto l; -} -... when != np = E -- of_node_put(np); - -// ---------------------------------------------------------------------- - -@r depends on !patch forall@ -//iterator name for_each_node_by_name; -//iterator name for_each_node_by_type; -//iterator name for_each_compatible_node; -//iterator name for_each_matching_node; -expression np,E; -identifier l; -position p1,p2; -@@ - -( -*for_each_node_by_name@p1(np,...) -{ - ... when != break; - when != goto l; -} -| -*for_each_node_by_type@p1(np,...) -{ - ... when != break; - when != goto l; -} -| -*for_each_compatible_node@p1(np,...) -{ - ... when != break; - when != goto l; -} -| -*for_each_matching_node@p1(np,...) -{ - ... when != break; - when != goto l; -} -) -... when != np = E -* of_node_put@p2(np); - -@script:python depends on org@ -p1 << r.p1; -p2 << r.p2; -@@ - -cocci.print_main("unneeded of_node_put",p2) -cocci.print_secs("iterator",p1) - -@script:python depends on report@ -p1 << r.p1; -p2 << r.p2; -@@ - -msg = "ERROR: of_node_put not needed after iterator on line %s" % (p1[0].line) -coccilib.report.print_report(p2[0], msg) diff --git a/scripts/coccinelle/iterators/for_each_child.cocci b/scripts/coccinelle/iterators/for_each_child.cocci index bc394615948e..2ea98a61a1f2 100644 --- a/scripts/coccinelle/iterators/for_each_child.cocci +++ b/scripts/coccinelle/iterators/for_each_child.cocci @@ -5,7 +5,7 @@ /// // Confidence: High // Copyright: (C) 2020 Sumera Priyadarsini -// URL: http://coccinelle.lip6.fr +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers virtual patch diff --git a/scripts/coccinelle/iterators/itnull.cocci b/scripts/coccinelle/iterators/itnull.cocci index 9b362b98d7a1..7d34802f2724 100644 --- a/scripts/coccinelle/iterators/itnull.cocci +++ b/scripts/coccinelle/iterators/itnull.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/iterators/list_entry_update.cocci b/scripts/coccinelle/iterators/list_entry_update.cocci index d62e8a16085f..9a7593667da6 100644 --- a/scripts/coccinelle/iterators/list_entry_update.cocci +++ b/scripts/coccinelle/iterators/list_entry_update.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci index 676edd562eef..f67110ba7290 100644 --- a/scripts/coccinelle/iterators/use_after_iter.cocci +++ b/scripts/coccinelle/iterators/use_after_iter.cocci @@ -10,7 +10,7 @@ // Confidence: Moderate // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci index 5ca0d81b0015..3720f86d67c5 100644 --- a/scripts/coccinelle/locks/call_kern.cocci +++ b/scripts/coccinelle/locks/call_kern.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2012 Nicolas Palix. // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/double_lock.cocci b/scripts/coccinelle/locks/double_lock.cocci index 9e88a578957c..619cfc714409 100644 --- a/scripts/coccinelle/locks/double_lock.cocci +++ b/scripts/coccinelle/locks/double_lock.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci index 7f990cd55f5a..44acf20a98dd 100644 --- a/scripts/coccinelle/locks/flags.cocci +++ b/scripts/coccinelle/locks/flags.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci index c3ad098f4a5b..71065d8a5d54 100644 --- a/scripts/coccinelle/locks/mini_lock.cocci +++ b/scripts/coccinelle/locks/mini_lock.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/boolreturn.cocci b/scripts/coccinelle/misc/boolreturn.cocci deleted file mode 100644 index 29d2bf41e95d..000000000000 --- a/scripts/coccinelle/misc/boolreturn.cocci +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/// Return statements in functions returning bool should use -/// true/false instead of 1/0. -// -// Confidence: High -// Options: --no-includes --include-headers - -virtual patch -virtual report -virtual context - -@r1 depends on patch@ -identifier fn; -typedef bool; -symbol false; -symbol true; -@@ - -bool fn ( ... ) -{ -<... -return -( -- 0 -+ false -| -- 1 -+ true -) - ; -...> -} - -@r2 depends on report || context@ -identifier fn; -position p; -@@ - -bool fn ( ... ) -{ -<... -return -( -* 0@p -| -* 1@p -) - ; -...> -} - - -@script:python depends on report@ -p << r2.p; -fn << r2.fn; -@@ - -msg = "WARNING: return of 0/1 in function '%s' with return type bool" % fn -coccilib.report.print_report(p[0], msg) diff --git a/scripts/coccinelle/misc/bugon.cocci b/scripts/coccinelle/misc/bugon.cocci deleted file mode 100644 index 8d595c358408..000000000000 --- a/scripts/coccinelle/misc/bugon.cocci +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/// Use BUG_ON instead of a if condition followed by BUG. -/// -//# This makes an effort to find cases where BUG() follows an if -//# condition on an expression and replaces the if condition and BUG() -//# with a BUG_ON having the conditional expression of the if statement -//# as argument. -// -// Confidence: High -// Copyright: (C) 2014 Himangi Saraogi. -// Comments: -// Options: --no-includes --include-headers - -virtual patch -virtual context -virtual org -virtual report - -//---------------------------------------------------------- -// For context mode -//---------------------------------------------------------- - -@depends on context@ -expression e; -@@ - -*if (e) BUG(); - -//---------------------------------------------------------- -// For patch mode -//---------------------------------------------------------- - -@depends on patch@ -expression e; -@@ - --if (e) BUG(); -+BUG_ON(e); - -//---------------------------------------------------------- -// For org and report mode -//---------------------------------------------------------- - -@r depends on (org || report)@ -expression e; -position p; -@@ - - if (e) BUG@p (); - -@script:python depends on org@ -p << r.p; -@@ - -coccilib.org.print_todo(p[0], "WARNING use BUG_ON") - -@script:python depends on report@ -p << r.p; -@@ - -msg="WARNING: Use BUG_ON instead of if condition followed by BUG.\nPlease make sure the condition has no side effects (see conditional BUG_ON definition in include/asm-generic/bug.h)" -coccilib.report.print_report(p[0], msg) - diff --git a/scripts/coccinelle/misc/cstptr.cocci b/scripts/coccinelle/misc/cstptr.cocci index c52e3c8ca9b3..74acf34bee03 100644 --- a/scripts/coccinelle/misc/cstptr.cocci +++ b/scripts/coccinelle/misc/cstptr.cocci @@ -5,7 +5,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci index 2f80d3ab38dd..7dbfde3f44e1 100644 --- a/scripts/coccinelle/misc/doubleinit.cocci +++ b/scripts/coccinelle/misc/doubleinit.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/ifcol.cocci b/scripts/coccinelle/misc/ifcol.cocci index da0351ed5740..442742467c18 100644 --- a/scripts/coccinelle/misc/ifcol.cocci +++ b/scripts/coccinelle/misc/ifcol.cocci @@ -12,7 +12,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/newline_in_nl_msg.cocci b/scripts/coccinelle/misc/newline_in_nl_msg.cocci index c175886e4015..9baffe55d917 100644 --- a/scripts/coccinelle/misc/newline_in_nl_msg.cocci +++ b/scripts/coccinelle/misc/newline_in_nl_msg.cocci @@ -5,7 +5,7 @@ /// // Confidence: Very High // Copyright: (C) 2020 Intel Corporation -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers virtual context diff --git a/scripts/coccinelle/misc/noderef.cocci b/scripts/coccinelle/misc/noderef.cocci index 72de62a77a44..37ee7358d742 100644 --- a/scripts/coccinelle/misc/noderef.cocci +++ b/scripts/coccinelle/misc/noderef.cocci @@ -5,7 +5,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/orplus.cocci b/scripts/coccinelle/misc/orplus.cocci index 52203dc2ca4b..3a1566f1aec9 100644 --- a/scripts/coccinelle/misc/orplus.cocci +++ b/scripts/coccinelle/misc/orplus.cocci @@ -6,7 +6,7 @@ // Confidence: Moderate // Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2013 Gilles Muller, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/returnvar.cocci b/scripts/coccinelle/misc/returnvar.cocci index ce0d9eebc7e1..7ffc55bf51f9 100644 --- a/scripts/coccinelle/misc/returnvar.cocci +++ b/scripts/coccinelle/misc/returnvar.cocci @@ -4,7 +4,7 @@ /// // Confidence: Moderate // Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: Comments on code can be deleted if near code that is removed. // "when strict" can be removed to get more hits, but adds false // positives diff --git a/scripts/coccinelle/misc/semicolon.cocci b/scripts/coccinelle/misc/semicolon.cocci index a53edb026dad..4476bf873deb 100644 --- a/scripts/coccinelle/misc/semicolon.cocci +++ b/scripts/coccinelle/misc/semicolon.cocci @@ -4,7 +4,7 @@ /// // Confidence: Moderate // Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: Some false positives on empty default cases in switch statements. // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/misc/ifaddr.cocci b/scripts/coccinelle/misc/test_addr.cocci index fc92e8fcbfcb..d559b297476c 100644 --- a/scripts/coccinelle/misc/ifaddr.cocci +++ b/scripts/coccinelle/misc/test_addr.cocci @@ -4,7 +4,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers @@ -14,12 +14,10 @@ virtual context @r@ expression x; -statement S1,S2; position p; @@ -*if@p (&x) - S1 else S2 +*\(&x@p == NULL \| &x@p != NULL\) @script:python depends on org@ p << r.p; diff --git a/scripts/coccinelle/misc/warn.cocci b/scripts/coccinelle/misc/warn.cocci index e379661e240d..b5f428035d03 100644 --- a/scripts/coccinelle/misc/warn.cocci +++ b/scripts/coccinelle/misc/warn.cocci @@ -4,7 +4,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/null/badzero.cocci b/scripts/coccinelle/null/badzero.cocci index 882dd65313ab..35d443825c2a 100644 --- a/scripts/coccinelle/null/badzero.cocci +++ b/scripts/coccinelle/null/badzero.cocci @@ -10,7 +10,7 @@ // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Requires: 1.0.0 // Options: diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci index 98f1e7faf503..fdf098d4f522 100644 --- a/scripts/coccinelle/null/deref_null.cocci +++ b/scripts/coccinelle/null/deref_null.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: -I ... -all_includes can give more complete results // Options: diff --git a/scripts/coccinelle/null/eno.cocci b/scripts/coccinelle/null/eno.cocci index 81584ff87956..7107d6c8db9e 100644 --- a/scripts/coccinelle/null/eno.cocci +++ b/scripts/coccinelle/null/eno.cocci @@ -5,7 +5,7 @@ // Copyright: (C) 2010-2012 Nicolas Palix. // Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/null/kmerr.cocci b/scripts/coccinelle/null/kmerr.cocci index d0e004d4e130..68db20de62eb 100644 --- a/scripts/coccinelle/null/kmerr.cocci +++ b/scripts/coccinelle/null/kmerr.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/tests/doublebitand.cocci b/scripts/coccinelle/tests/doublebitand.cocci index 0f0b94e7debd..025436a15040 100644 --- a/scripts/coccinelle/tests/doublebitand.cocci +++ b/scripts/coccinelle/tests/doublebitand.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/tests/doubletest.cocci b/scripts/coccinelle/tests/doubletest.cocci index b35519cddb13..c3d94c31959f 100644 --- a/scripts/coccinelle/tests/doubletest.cocci +++ b/scripts/coccinelle/tests/doubletest.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010 Nicolas Palix, DIKU. // Copyright: (C) 2010 Julia Lawall, DIKU. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Comments: // Options: --no-includes --include-headers diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci index 11d4e2b6deb8..377436abe2d0 100644 --- a/scripts/coccinelle/tests/odd_ptr_err.cocci +++ b/scripts/coccinelle/tests/odd_ptr_err.cocci @@ -6,7 +6,7 @@ // Confidence: High // Copyright: (C) 2012, 2015 Julia Lawall, INRIA. // Copyright: (C) 2012, 2015 Gilles Muller, INRIA. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --no-includes --include-headers virtual patch diff --git a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci index 91e286ace54c..5e188c62d8a9 100644 --- a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci +++ b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci @@ -13,7 +13,7 @@ /// // Confidence: Average // Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd. -// URL: http://coccinelle.lip6.fr/ +// URL: https://coccinelle.gitlabpages.inria.fr/website // Options: --all-includes virtual context diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index 3980985205a0..1eeb7b42c5b9 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -12,19 +12,27 @@ driver_info drm_connector_funcs drm_encoder_funcs drm_encoder_helper_funcs +dvb_frontend_ops +dvb_tuner_ops ethtool_ops extent_io_ops +fb_ops file_lock_operations file_operations hv_ops +hwmon_ops +ib_device_ops ide_dma_ops ide_port_ops +ieee80211_ops +iio_buffer_setup_ops inode_operations intel_dvo_dev_ops irq_domain_ops item_operations iwl_cfg iwl_ops +kernel_param_ops kgdb_arch kgdb_io kset_uevent_ops @@ -32,25 +40,33 @@ lock_manager_operations machine_desc microcode_ops mlxsw_reg_info +mtd_ooblayout_ops mtrr_ops +nand_controller_ops neigh_ops net_device_ops +nft_expr_ops nlmsvc_binding nvkm_device_chip of_device_id pci_raw_ops phy_ops +pinconf_ops pinctrl_ops pinmux_ops pipe_buf_operations platform_hibernation_ops platform_suspend_ops +proc_ops proto_ops +pwm_ops regmap_access_table regulator_ops +reset_control_ops rpc_pipe_ops rtc_class_ops sd_desc +sdhci_ops seq_operations sirfsoc_padmux snd_ac97_build_ops @@ -67,6 +83,13 @@ uart_ops usb_mon_operations v4l2_ctrl_ops v4l2_ioctl_ops +v4l2_subdev_core_ops +v4l2_subdev_internal_ops +v4l2_subdev_ops +v4l2_subdev_pad_ops +v4l2_subdev_video_ops +vb2_ops vm_operations_struct wacom_features +watchdog_ops wd_ops diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 5fbad61fe490..564c5632e1a2 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -8,6 +8,14 @@ usage() { echo " $0 -r <release> | <vmlinux> [<base path>|auto] [<modules path>]" } +# Try to find a Rust demangler +if type llvm-cxxfilt >/dev/null 2>&1 ; then + cppfilt=llvm-cxxfilt +elif type c++filt >/dev/null 2>&1 ; then + cppfilt=c++filt + cppfilt_opts=-i +fi + if [[ $1 == "-r" ]] ; then vmlinux="" basepath="auto" @@ -45,8 +53,13 @@ else fi fi -declare -A cache -declare -A modcache +declare aarray_support=true +declare -A cache 2>/dev/null +if [[ $? != 0 ]]; then + aarray_support=false +else + declare -A modcache +fi find_module() { if [[ -n $debuginfod ]] ; then @@ -97,7 +110,7 @@ parse_symbol() { if [[ $module == "" ]] ; then local objfile=$vmlinux - elif [[ "${modcache[$module]+isset}" == "isset" ]]; then + elif [[ $aarray_support == true && "${modcache[$module]+isset}" == "isset" ]]; then local objfile=${modcache[$module]} else local objfile=$(find_module) @@ -105,7 +118,9 @@ parse_symbol() { echo "WARNING! Modules path isn't set, but is needed to parse this symbol" >&2 return fi - modcache[$module]=$objfile + if [[ $aarray_support == true ]]; then + modcache[$module]=$objfile + fi fi # Remove the englobing parenthesis @@ -125,7 +140,7 @@ parse_symbol() { # Use 'nm vmlinux' to figure out the base address of said symbol. # It's actually faster to call it every time than to load it # all into bash. - if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then + if [[ $aarray_support == true && "${cache[$module,$name]+isset}" == "isset" ]]; then local base_addr=${cache[$module,$name]} else local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') @@ -133,7 +148,9 @@ parse_symbol() { # address not found return fi - cache[$module,$name]="$base_addr" + if [[ $aarray_support == true ]]; then + cache[$module,$name]="$base_addr" + fi fi # Let's start doing the math to get the exact address into the # symbol. First, strip out the symbol total length. @@ -149,11 +166,13 @@ parse_symbol() { # Pass it to addr2line to get filename and line number # Could get more than one result - if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then + if [[ $aarray_support == true && "${cache[$module,$address]+isset}" == "isset" ]]; then local code=${cache[$module,$address]} else local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null) - cache[$module,$address]=$code + if [[ $aarray_support == true ]]; then + cache[$module,$address]=$code + fi fi # addr2line doesn't return a proper error code if it fails, so @@ -169,6 +188,12 @@ parse_symbol() { # In the case of inlines, move everything to same line code=${code//$'\n'/' '} + # Demangle if the name looks like a Rust symbol and if + # we got a Rust demangler + if [[ $name =~ ^_R && $cppfilt != "" ]] ; then + name=$("$cppfilt" "$cppfilt_opts" "$name") + fi + # Replace old address with pretty line numbers symbol="$segment$name ($code)" } diff --git a/scripts/decodecode b/scripts/decodecode index c711a196511c..b28fd2686561 100755 --- a/scripts/decodecode +++ b/scripts/decodecode @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Disassemble the Code: line in Linux oopses # usage: decodecode < oops.file @@ -8,6 +8,8 @@ # AFLAGS=--32 decodecode < 386.oops # PC=hex - the PC (program counter) the oops points to +faultlinenum=1 + cleanup() { rm -f $T $T.s $T.o $T.oo $T.aa $T.dis exit 1 @@ -102,28 +104,125 @@ disas() { grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1 } +# Match the maximum number of opcode bytes from @op_bytes contained within +# @opline +# +# Params: +# @op_bytes: The string of bytes from the Code: line +# @opline: The disassembled line coming from objdump +# +# Returns: +# The max number of opcode bytes from the beginning of @op_bytes which match +# the opcode bytes in the objdump line. +get_substr_opcode_bytes_num() +{ + local op_bytes=$1 + local opline=$2 + + local retval=0 + substr="" + + for opc in $op_bytes; + do + substr+="$opc" + + # return if opcode bytes do not match @opline anymore + if ! echo $opline | grep -q "$substr"; + then + break + fi + + # add trailing space + substr+=" " + retval=$((retval+1)) + done + + return $retval +} + +# Return the line number in objdump output to where the IP marker in the Code: +# line points to +# +# Params: +# @all_code: code in bytes without the marker +# @dis_file: disassembled file +# @ip_byte: The byte to which the IP points to +get_faultlinenum() +{ + local all_code="$1" + local dis_file="$2" + + # num bytes including IP byte + local num_bytes_ip=$(( $3 + 1 * $width )) + + # Add the two header lines (we're counting from 1). + local retval=3 + + # remove marker + all_code=$(echo $all_code | sed -e 's/[<>()]//g') + + while read line + do + get_substr_opcode_bytes_num "$all_code" "$line" + ate_opcodes=$? + + if ! (( $ate_opcodes )); then + continue + fi + + num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) )) + if (( $num_bytes_ip <= 0 )); then + break + fi + + # Delete matched opcode bytes from all_code. For that, compute + # how many chars those opcodes are represented by and include + # trailing space. + # + # a byte is 2 chars, ate_opcodes is also the number of trailing + # spaces + del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes )) + + all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!") + + let "retval+=1" + + done < $dis_file + + return $retval +} + marker=`expr index "$code" "\<"` if [ $marker -eq 0 ]; then marker=`expr index "$code" "\("` fi - touch $T.oo if [ $marker -ne 0 ]; then - # 2 opcode bytes and a single space - pc_sub=$(( $marker / 3 )) + # How many bytes to subtract from the program counter + # in order to get to the beginning virtual address of the + # Code: + pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width )) echo All code >> $T.oo echo ======== >> $T.oo beforemark=`echo "$code"` echo -n " .$type 0x" > $T.s + echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s + disas $T $pc_sub + cat $T.dis >> $T.oo - rm -f $T.o $T.s $T.dis -# and fix code at-and-after marker + get_faultlinenum "$code" "$T.dis" $pc_sub + faultlinenum=$? + + # and fix code at-and-after marker code=`echo "$code" | cut -c$((${marker} + 1))-` + + rm -f $T.o $T.s $T.dis fi + echo Code starting with the faulting instruction > $T.aa echo =========================================== >> $T.aa code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` @@ -132,15 +231,6 @@ echo $code >> $T.s disas $T 0 cat $T.dis >> $T.aa -# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3, -# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is -# special) -faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \ - $(wc -l $T.aa | cut -d" " -f1) + 3)) - -faultline=`cat $T.dis | head -1 | cut -d":" -f2-` -faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'` - cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" echo cat $T.aa diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 95aaf7431bff..4d32b9497da9 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -17,20 +17,7 @@ fdtoverlay-objs := $(libfdt) fdtoverlay.o util.o # Source files need to get at the userspace version of libfdt_env.h to compile HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt - -ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),) -ifneq ($(CHECK_DT_BINDING)$(CHECK_DTBS),) -$(error dtc needs libyaml for DT schema validation support. \ - Install the necessary libyaml development package.) -endif HOST_EXTRACFLAGS += -DNO_YAML -else -dtc-objs += yamltree.o -# To include <yaml.h> installed in a non-default path -HOSTCFLAGS_yamltree.o := $(shell pkg-config --cflags yaml-0.1) -# To link libyaml installed in a non-default path -HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs) -endif # Generated files need one more search path to include headers in source tree HOSTCFLAGS_dtc-lexer.lex.o := -I $(srctree)/$(src) diff --git a/scripts/dtc/dt-extract-compatibles b/scripts/dtc/dt-extract-compatibles new file mode 100755 index 000000000000..a1119762ed08 --- /dev/null +++ b/scripts/dtc/dt-extract-compatibles @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-only + +import os +import glob +import re +import argparse + + +def parse_of_declare_macros(data): + """ Find all compatible strings in OF_DECLARE() style macros """ + compat_list = [] + # CPU_METHOD_OF_DECLARE does not have a compatible string + for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data): + try: + compat = re.search(r'"(.*?)"', m[0])[1] + except: + # Fails on compatible strings in #define, so just skip + continue + compat_list += [compat] + + return compat_list + + +def parse_of_device_id(data): + """ Find all compatible strings in of_device_id structs """ + compat_list = [] + for m in re.finditer(r'of_device_id\s+[a-zA-Z0-9_]+\[\]\s*=\s*({.*?);', data): + compat_list += re.findall(r'\.compatible\s+=\s+"([a-zA-Z0-9_\-,]+)"', m[1]) + + return compat_list + + +def parse_compatibles(file): + with open(file, 'r', encoding='utf-8') as f: + data = f.read().replace('\n', '') + + compat_list = parse_of_declare_macros(data) + compat_list += parse_of_device_id(data) + + return compat_list + +def print_compat(filename, compatibles): + if not compatibles: + return + if show_filename: + compat_str = ' '.join(compatibles) + print(filename + ": compatible(s): " + compat_str) + else: + print(*compatibles, sep='\n') + +show_filename = False + +if __name__ == "__main__": + ap = argparse.ArgumentParser() + ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse") + ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true") + args = ap.parse_args() + + show_filename = args.with_filename + + for f in args.cfile: + if os.path.isdir(f): + for filename in glob.iglob(f + "/**/*.c", recursive=True): + compat_list = parse_compatibles(filename) + print_compat(filename, compat_list) + else: + compat_list = parse_compatibles(f) + print_compat(f, compat_list) diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff index d3422ee15e30..f2bbde4bba86 100755 --- a/scripts/dtc/dtx_diff +++ b/scripts/dtc/dtx_diff @@ -59,12 +59,8 @@ Otherwise DTx is treated as a dts source file (aka .dts). or '/include/' to be processed. If DTx_1 and DTx_2 are in different architectures, then this script - may not work since \${ARCH} is part of the include path. Two possible - workarounds: - - `basename $0` \\ - <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\ - <(ARCH=arch_of_dtx_2 `basename $0` DTx_2) + may not work since \${ARCH} is part of the include path. The following + workaround can be used: `basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts `basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts diff --git a/scripts/dtc/include-prefixes/h8300 b/scripts/dtc/include-prefixes/h8300 deleted file mode 120000 index 3bdaa332c54c..000000000000 --- a/scripts/dtc/include-prefixes/h8300 +++ /dev/null @@ -1 +0,0 @@ -../../../arch/h8300/boot/dts
\ No newline at end of file diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h index f2e68807f277..0c91aa7f67b5 100644 --- a/scripts/dtc/libfdt/fdt.h +++ b/scripts/dtc/libfdt/fdt.h @@ -35,14 +35,14 @@ struct fdt_reserve_entry { struct fdt_node_header { fdt32_t tag; - char name[0]; + char name[]; }; struct fdt_property { fdt32_t tag; fdt32_t len; fdt32_t nameoff; - char data[0]; + char data[]; }; #endif /* !__ASSEMBLY */ diff --git a/scripts/dtc/of_unittest_expect b/scripts/dtc/of_unittest_expect new file mode 100755 index 000000000000..96b12d9ea606 --- /dev/null +++ b/scripts/dtc/of_unittest_expect @@ -0,0 +1,408 @@ +#!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2020, 2022 Sony Corporation +# +# Author: Frank Rowand + +# This program is meant to be an aid to reading the verbose output of +# on the console log that results from executing the Linux kernel +# devicetree unittest (drivers/of/unitest.c). + +$VUFX = "220201a"; + +use strict 'refs'; +use strict subs; + +use Getopt::Long; +use Text::Wrap; + +# strip off everything before final "/" +(undef, $script_name) = split(/^.*\//, $0); + +# following /usr/include/sysexits.h +$EX_OK=0; +$EX_USAGE=64; + + +#______________________________________________________________________________ +sub compare { + my ($expect, $got) = @_; + my $expect_next; + my $expect_next_lit; + my $got_next; + my $type; + + while ($expect) { + + ($expect_next, $type) = split(/<</, $expect); + ($type) = split(/>>/, $type); + $expect =~ s/^.*?>>//; # '?' is non-greedy, minimal match + + # literal, ignore all metacharacters when used in a regex + $expect_next_lit = quotemeta($expect_next); + + $got_next = $got; + $got_next =~ s/^($expect_next_lit).*/\1/; + $got =~ s/^$expect_next_lit//; + + if ($expect_next ne $got_next) { + return 0; + } + + if ($type eq "int") { + if ($got =~ /^[+-]*[0-9]+/) { + $got =~ s/^[+-]*[0-9]+//; + } else { + return 0; + } + } elsif ($type eq "hex") { + if ($got =~ /^(0x)*[0-9a-f]+/) { + $got =~ s/^(0x)*[0-9a-f]+//; + } else { + return 0; + } + } elsif ($type eq "") { + if ($expect_next ne $got_next) { + return 0; + } else { + return 1; + } + } else { + $internal_err++; + print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n"; + return 0; + } + + } + + # should not get here + $internal_err++; + print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n"; + + return 0; +} + + +#______________________________________________________________________________ +sub usage { + +# ***** when editing, be careful to not put tabs in the string printed: + + print STDERR +" +usage: + + $script_name CONSOLE_LOG + + -h print program usage + --help print program usage + --hide-expect suppress output of EXPECTed lines + --line-num report line number of CONSOLE_LOG + --no-expect-stats do not report EXPECT statistics + --no-strip-ts do not strip leading console timestamps + --verbose do not suppress EXPECT begin and end lines + --version print program version and exit + + + Process a console log for EXPECTed test related messages to either + highlight expected devicetree unittest related messages or suppress + the messages. Leading console timestamps will be stripped. + + Various unittests may trigger kernel messages from outside the + unittest code. The unittest annotates that it expects the message + to occur with an 'EXPECT \\ : text' (begin) before triggering the + message, and an 'EXPECT / : text' (end) after triggering the message. + + If an expected message does not occur, that will be reported. + + For each expected message, the 'EXPECT \\ : text' (begin) and + 'EXPECT / : text' (end), 'text' will contain the message text. + + If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain + matching 'text', that will be reported. + + If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the + reverse order of the corresponding 'EXPECT \\' (begin) lines. + + 'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can + contain special patterns in 'text': + + <<int>> matches: [+-]*[0-9]+ + <<hex>> matches: (0x)*[0-9a-f]+ + + 'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed. + + A prefix is added to every line of output: + + 'ok ' Line matches an enclosing EXPECT begin/end pair + + '** ' Line reports $script_name warning or error + + '-> ' Line reports start or end of the unittests + + '>> ' Line reports a unittest test FAIL + + ' ' Lines that are not otherwise prefixed + + Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR. + + Known Issues: + + --line-num causes the CONSOLE_LOG line number to be printed in 4 columns. + If CONSOLE_LOG contains more than 9999 lines then more columns will be + used to report the line number for lines greater than 9999 (eg for + lines 10000 - 99999, 5 columns will be used). +"; + + return {}; +} + +#______________________________________________________________________________ +#______________________________________________________________________________ + +if (!GetOptions( + "h" => \$help, + "help" => \$help, + "hide-expect" => \$hide_expect, + "line-num" => \$print_line_num, + "no-expect-stats" => \$no_expect_stats, + "no-strip-ts" => \$no_strip_ts, + "verbose" => \$verbose, + "version" => \$version, + )) { + print STDERR "\n"; + print STDERR "ERROR processing command line options\n"; + print STDERR "\n"; + print STDERR "For help, type '$script_name --help'\n"; + print STDERR "\n"; + + exit $EX_OK; +} + + +if ($no_strip_ts) { + $strip_ts = 1; + $no_strip_ts = 0; +} else { + $strip_ts = 0; + $no_strip_ts = 1; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if ($help){ + + &usage; + + exit $EX_OK; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +if ($version) { + print STDERR "\n$script_name $VUFX\n\n"; + print STDERR "\n"; + + exit $EX_OK; +} + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if ($#ARGV != 0) { + + # Limit input files to exactly one. + # + # 'while ($line = <ARGV>) {' in the code below supports multiple file + # names on the command line, but the EXPECT statistics are reported + # once for all input - it is not an expected use case to generate one + # set of statistics for multiple input files. + + print STDERR "\n"; + print STDERR "Required arguments: CONSOLE_LOG\n"; + print STDERR "\n"; + + exit $EX_USAGE; +} + + +#______________________________________________________________________________ + +# Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end) +# +# $exp_* are used as regex match patterns, +# so '\\\\' in $exp_begin matches a single '\' +# quotemeta() does not do the right thing in this case +# +# $pr_fmt is the prefix that unittest prints for every message + +$pr_fmt = "### dt-test ### "; +$exp_begin = "${pr_fmt}EXPECT \\\\ : "; +$exp_end = "${pr_fmt}EXPECT / : "; + + +$line_num = ""; +$timestamp = ""; + +LINE: +while ($line = <ARGV>) { + + chomp $line; + + $prefix = " "; ## 2 characters + + + if ($strip_ts) { + + $timestamp = $line; + + if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) { + ($timestamp, $null) = split(/]/, $line); + $timestamp = $timestamp . "] "; + + } else { + $timestamp = ""; + } + } + + $line =~ s/^\[\s*[0-9]+\.[0-9]*\] //; + + + # ----- find EXPECT begin + + if ($line =~ /^\s*$exp_begin/) { + $data = $line; + $data =~ s/^\s*$exp_begin//; + push @begin, $data; + + if ($verbose) { + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; + } + + next LINE; + } + + + # ----- find EXPECT end + + if ($line =~ /^\s*$exp_end/) { + $data = $line; + $data =~ s/^\s*$exp_end//; + + if ($verbose) { + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; + } + + $found = 0; + $no_begin = 0; + if (@found_or_begin > 0) { + $begin = pop @found_or_begin; + if (compare($data, $begin)) { + $found = 1; + } + } elsif (@begin > 0) { + $begin = pop @begin; + } else { + $no_begin = 1; + } + + if ($no_begin) { + + $expect_missing_begin++; + print "** ERROR: EXPECT end without any EXPECT begin:\n"; + print " end ---> $line\n"; + + } elsif (! $found) { + + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + + $expect_not_found++; + printf "** %s%s$script_name WARNING - not found ---> %s\n", + $line_num, $timestamp, $data; + + } elsif (! compare($data, $begin)) { + + $expect_missing_end++; + print "** ERROR: EXPECT end does not match EXPECT begin:\n"; + print " begin -> $begin\n"; + print " end ---> $line\n"; + + } else { + + $expect_found++; + + } + + next LINE; + } + + + # ----- not an EXPECT line + + if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) || + ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ ) ) { + $prefix = "->"; # 2 characters + } elsif ($line =~ /^${pr_fmt}FAIL /) { + $unittest_fail++; + $prefix = ">>"; # 2 characters + } + + $found = 0; + foreach $begin (@begin) { + if (compare($begin, $line)) { + $found = 1; + last; + } + } + + if ($found) { + $begin = shift @begin; + while (! compare($begin, $line)) { + push @found_or_begin, $begin; + $begin = shift @begin; + } + push @found_or_begin, $line; + + if ($hide_expect) { + $suppress_line = 1; + next LINE; + } + $prefix = "ok"; # 2 characters + } + + + if ($print_line_num) { + $line_num = sprintf("%4s ", $.); + } + + printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line; +} + +if (! $no_expect_stats) { + print "\n"; + print "** EXPECT statistics:\n"; + print "**\n"; + printf "** EXPECT found : %4i\n", $expect_found; + printf "** EXPECT not found : %4i\n", $expect_not_found; + printf "** missing EXPECT begin : %4i\n", $expect_missing_begin; + printf "** missing EXPECT end : %4i\n", $expect_missing_end; + printf "** unittest FAIL : %4i\n", $unittest_fail; + printf "** internal error : %4i\n", $internal_err; +} + +if (@begin) { + print "** ERROR: EXPECT begin without any EXPECT end:\n"; + print " This list may be misleading.\n"; + foreach $begin (@begin) { + print " begin ---> $begin\n"; + } +} diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh index 32ff17ffd089..94627541533e 100755 --- a/scripts/dtc/update-dtc-source.sh +++ b/scripts/dtc/update-dtc-source.sh @@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc DTC_LINUX_PATH=`pwd`/scripts/dtc DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ - srcpos.h treesource.c util.c util.h version_gen.h yamltree.c \ + srcpos.h treesource.c util.c util.h version_gen.h \ dtc-lexer.l dtc-parser.y" LIBFDT_SOURCE="fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \ diff --git a/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h b/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc index b2483149bbe5..1db1889f6d81 100755 --- a/scripts/dummy-tools/gcc +++ b/scripts/dummy-tools/gcc @@ -59,7 +59,7 @@ fi if arg_contain -E "$@"; then # For scripts/cc-version.sh; This emulates GCC 20.0.0 if arg_contain - "$@"; then - sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}' + sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}; s/__LONG_DOUBLE_128__/1/ p' exit 0 else echo "no input files" >&2 @@ -96,12 +96,8 @@ fi # To set GCC_PLUGINS if arg_contain -print-file-name=plugin "$@"; then - plugin_dir=$(mktemp -d) - - mkdir -p $plugin_dir/include - touch $plugin_dir/include/plugin-version.h - - echo $plugin_dir + # Use $0 to find the in-tree dummy directory + echo "$(dirname "$(readlink -f "$0")")/dummy-plugin-dir" exit 0 fi diff --git a/scripts/dummy-tools/pahole b/scripts/dummy-tools/pahole new file mode 100755 index 000000000000..53501a36fa71 --- /dev/null +++ b/scripts/dummy-tools/pahole @@ -0,0 +1,4 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +echo v99.99 diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c deleted file mode 100644 index 3bc48c726c41..000000000000 --- a/scripts/extract-cert.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Extract X.509 certificate in DER form from PKCS#11 or PEM. - * - * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved. - * Copyright © 2015 Intel Corporation. - * - * Authors: David Howells <dhowells@redhat.com> - * David Woodhouse <dwmw2@infradead.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the licence, or (at your option) any later version. - */ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <string.h> -#include <err.h> -#include <openssl/bio.h> -#include <openssl/pem.h> -#include <openssl/err.h> -#include <openssl/engine.h> - -#define PKEY_ID_PKCS7 2 - -static __attribute__((noreturn)) -void format(void) -{ - fprintf(stderr, - "Usage: scripts/extract-cert <source> <dest>\n"); - exit(2); -} - -static void display_openssl_errors(int l) -{ - const char *file; - char buf[120]; - int e, line; - - if (ERR_peek_error() == 0) - return; - fprintf(stderr, "At main.c:%d:\n", l); - - while ((e = ERR_get_error_line(&file, &line))) { - ERR_error_string(e, buf); - fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); - } -} - -static void drain_openssl_errors(void) -{ - const char *file; - int line; - - if (ERR_peek_error() == 0) - return; - while (ERR_get_error_line(&file, &line)) {} -} - -#define ERR(cond, fmt, ...) \ - do { \ - bool __cond = (cond); \ - display_openssl_errors(__LINE__); \ - if (__cond) { \ - err(1, fmt, ## __VA_ARGS__); \ - } \ - } while(0) - -static const char *key_pass; -static BIO *wb; -static char *cert_dst; -static int kbuild_verbose; - -static void write_cert(X509 *x509) -{ - char buf[200]; - - if (!wb) { - wb = BIO_new_file(cert_dst, "wb"); - ERR(!wb, "%s", cert_dst); - } - X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); - ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); - if (kbuild_verbose) - fprintf(stderr, "Extracted cert: %s\n", buf); -} - -int main(int argc, char **argv) -{ - char *cert_src; - - OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); - ERR_clear_error(); - - kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0"); - - key_pass = getenv("KBUILD_SIGN_PIN"); - - if (argc != 3) - format(); - - cert_src = argv[1]; - cert_dst = argv[2]; - - if (!cert_src[0]) { - /* Invoked with no input; create empty file */ - FILE *f = fopen(cert_dst, "wb"); - ERR(!f, "%s", cert_dst); - fclose(f); - exit(0); - } else if (!strncmp(cert_src, "pkcs11:", 7)) { - ENGINE *e; - struct { - const char *cert_id; - X509 *cert; - } parms; - - parms.cert_id = cert_src; - parms.cert = NULL; - - ENGINE_load_builtin_engines(); - drain_openssl_errors(); - e = ENGINE_by_id("pkcs11"); - ERR(!e, "Load PKCS#11 ENGINE"); - if (ENGINE_init(e)) - drain_openssl_errors(); - else - ERR(1, "ENGINE_init"); - if (key_pass) - ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); - ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); - ERR(!parms.cert, "Get X.509 from PKCS#11"); - write_cert(parms.cert); - } else { - BIO *b; - X509 *x509; - - b = BIO_new_file(cert_src, "rb"); - ERR(!b, "%s", cert_src); - - while (1) { - x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); - if (wb && !x509) { - unsigned long err = ERR_peek_last_error(); - if (ERR_GET_LIB(err) == ERR_LIB_PEM && - ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { - ERR_clear_error(); - break; - } - } - ERR(!x509, "%s", cert_src); - write_cert(x509); - } - } - - BIO_free(wb); - - return 0; -} diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig index 3b42f255e2ba..8df33e7d6daa 100755 --- a/scripts/extract-ikconfig +++ b/scripts/extract-ikconfig @@ -62,6 +62,7 @@ try_decompress 'BZh' xy bunzip2 try_decompress '\135\0\0\0' xxx unlzma try_decompress '\211\114\132' xy 'lzop -d' try_decompress '\002\041\114\030' xyy 'lz4 -d -l' +try_decompress '\050\265\057\375' xxx unzstd # Bail out: echo "$me: Cannot find kernel config." >&2 diff --git a/scripts/faddr2line b/scripts/faddr2line index 6c6439f69a72..5514c23f45c2 100755 --- a/scripts/faddr2line +++ b/scripts/faddr2line @@ -44,17 +44,6 @@ set -o errexit set -o nounset -READELF="${CROSS_COMPILE:-}readelf" -ADDR2LINE="${CROSS_COMPILE:-}addr2line" -SIZE="${CROSS_COMPILE:-}size" -NM="${CROSS_COMPILE:-}nm" - -command -v awk >/dev/null 2>&1 || die "awk isn't installed" -command -v ${READELF} >/dev/null 2>&1 || die "readelf isn't installed" -command -v ${ADDR2LINE} >/dev/null 2>&1 || die "addr2line isn't installed" -command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed" -command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed" - usage() { echo "usage: faddr2line [--list] <object file> <func+offset> <func+offset>..." >&2 exit 1 @@ -69,6 +58,15 @@ die() { exit 1 } +READELF="${CROSS_COMPILE:-}readelf" +ADDR2LINE="${CROSS_COMPILE:-}addr2line" +AWK="awk" +GREP="grep" + +command -v ${AWK} >/dev/null 2>&1 || die "${AWK} isn't installed" +command -v ${READELF} >/dev/null 2>&1 || die "${READELF} isn't installed" +command -v ${ADDR2LINE} >/dev/null 2>&1 || die "${ADDR2LINE} isn't installed" + # Try to figure out the source directory prefix so we can remove it from the # addr2line output. HACK ALERT: This assumes that start_kernel() is in # init/main.c! This only works for vmlinux. Otherwise it falls back to @@ -76,7 +74,7 @@ die() { find_dir_prefix() { local objfile=$1 - local start_kernel_addr=$(${READELF} -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}') + local start_kernel_addr=$(${READELF} --symbols --wide $objfile | ${AWK} '$8 == "start_kernel" {printf "0x%s", $2}') [[ -z $start_kernel_addr ]] && return local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr) @@ -97,86 +95,158 @@ __faddr2line() { local dir_prefix=$3 local print_warnings=$4 - local func=${func_addr%+*} - local offset=${func_addr#*+} - offset=${offset%/*} - local size= - [[ $func_addr =~ "/" ]] && size=${func_addr#*/} + local sym_name=${func_addr%+*} + local func_offset=${func_addr#*+} + func_offset=${func_offset%/*} + local user_size= + local file_type + local is_vmlinux=0 + [[ $func_addr =~ "/" ]] && user_size=${func_addr#*/} - if [[ -z $func ]] || [[ -z $offset ]] || [[ $func = $func_addr ]]; then + if [[ -z $sym_name ]] || [[ -z $func_offset ]] || [[ $sym_name = $func_addr ]]; then warn "bad func+offset $func_addr" DONE=1 return fi + # vmlinux uses absolute addresses in the section table rather than + # section offsets. + local file_type=$(${READELF} --file-header $objfile | + ${AWK} '$1 == "Type:" { print $2; exit }') + if [[ $file_type = "EXEC" ]] || [[ $file_type == "DYN" ]]; then + is_vmlinux=1 + fi + # Go through each of the object's symbols which match the func name. - # In rare cases there might be duplicates. - file_end=$(${SIZE} -Ax $objfile | awk '$1 == ".text" {print $2}') - while read symbol; do - local fields=($symbol) - local sym_base=0x${fields[0]} - local sym_type=${fields[1]} - local sym_end=${fields[3]} - - # calculate the size - local sym_size=$(($sym_end - $sym_base)) + # In rare cases there might be duplicates, in which case we print all + # matches. + while read line; do + local fields=($line) + local sym_addr=0x${fields[1]} + local sym_elf_size=${fields[2]} + local sym_sec=${fields[6]} + local sec_size + local sec_name + + # Get the section size: + sec_size=$(${READELF} --section-headers --wide $objfile | + sed 's/\[ /\[/' | + ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print "0x" $6; exit }') + + if [[ -z $sec_size ]]; then + warn "bad section size: section: $sym_sec" + DONE=1 + return + fi + + # Get the section name: + sec_name=$(${READELF} --section-headers --wide $objfile | + sed 's/\[ /\[/' | + ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print $2; exit }') + + if [[ -z $sec_name ]]; then + warn "bad section name: section: $sym_sec" + DONE=1 + return + fi + + # Calculate the symbol size. + # + # Unfortunately we can't use the ELF size, because kallsyms + # also includes the padding bytes in its size calculation. For + # kallsyms, the size calculation is the distance between the + # symbol and the next symbol in a sorted list. + local sym_size + local cur_sym_addr + local found=0 + while read line; do + local fields=($line) + cur_sym_addr=0x${fields[1]} + local cur_sym_elf_size=${fields[2]} + local cur_sym_name=${fields[7]:-} + + if [[ $cur_sym_addr = $sym_addr ]] && + [[ $cur_sym_elf_size = $sym_elf_size ]] && + [[ $cur_sym_name = $sym_name ]]; then + found=1 + continue + fi + + if [[ $found = 1 ]]; then + sym_size=$(($cur_sym_addr - $sym_addr)) + [[ $sym_size -lt $sym_elf_size ]] && continue; + found=2 + break + fi + done < <(${READELF} --symbols --wide $objfile | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2) + + if [[ $found = 0 ]]; then + warn "can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size" + DONE=1 + return + fi + + # If nothing was found after the symbol, assume it's the last + # symbol in the section. + [[ $found = 1 ]] && sym_size=$(($sec_size - $sym_addr)) + if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then - warn "bad symbol size: base: $sym_base end: $sym_end" + warn "bad symbol size: sym_addr: $sym_addr cur_sym_addr: $cur_sym_addr" DONE=1 return fi + sym_size=0x$(printf %x $sym_size) - # calculate the address - local addr=$(($sym_base + $offset)) + # Calculate the address from user-supplied offset: + local addr=$(($sym_addr + $func_offset)) if [[ -z $addr ]] || [[ $addr = 0 ]]; then - warn "bad address: $sym_base + $offset" + warn "bad address: $sym_addr + $func_offset" DONE=1 return fi addr=0x$(printf %x $addr) - # weed out non-function symbols - if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then + # If the user provided a size, make sure it matches the symbol's size: + if [[ -n $user_size ]] && [[ $user_size -ne $sym_size ]]; then [[ $print_warnings = 1 ]] && - echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'" - continue - fi - - # if the user provided a size, make sure it matches the symbol's size - if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then - [[ $print_warnings = 1 ]] && - echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)" + echo "skipping $sym_name address at $addr due to size mismatch ($user_size != $sym_size)" continue; fi - # make sure the provided offset is within the symbol's range - if [[ $offset -gt $sym_size ]]; then + # Make sure the provided offset is within the symbol's range: + if [[ $func_offset -gt $sym_size ]]; then [[ $print_warnings = 1 ]] && - echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)" + echo "skipping $sym_name address at $addr due to size mismatch ($func_offset > $sym_size)" continue fi - # separate multiple entries with a blank line + # In case of duplicates or multiple addresses specified on the + # cmdline, separate multiple entries with a blank line: [[ $FIRST = 0 ]] && echo FIRST=0 - # pass real address to addr2line - echo "$func+$offset/$sym_size:" - local file_lines=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;") - [[ -z $file_lines ]] && return + echo "$sym_name+$func_offset/$sym_size:" + # Pass section address to addr2line and strip absolute paths + # from the output: + local args="--functions --pretty-print --inlines --exe=$objfile" + [[ $is_vmlinux = 0 ]] && args="$args --section=$sec_name" + local output=$(${ADDR2LINE} $args $addr | sed "s; $dir_prefix\(\./\)*; ;") + [[ -z $output ]] && continue + + # Default output (non --list): if [[ $LIST = 0 ]]; then - echo "$file_lines" | while read -r line + echo "$output" | while read -r line do echo $line done DONE=1; - return + continue fi - # show each line with context - echo "$file_lines" | while read -r line + # For --list, show each line with its corresponding source code: + echo "$output" | while read -r line do echo echo $line @@ -184,12 +254,12 @@ __faddr2line() { n1=$[$n-5] n2=$[$n+5] f=$(echo $line | sed 's/.*at \(.\+\):.*/\1/g') - awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f + ${AWK} 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f done DONE=1 - done < <(${NM} -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }') + done < <(${READELF} --symbols --wide $objfile | ${AWK} -v fn=$sym_name '$4 == "FUNC" && $8 == fn') } [[ $# -lt 2 ]] && usage @@ -202,6 +272,8 @@ LIST=0 [[ ! -f $objfile ]] && die "can't find objfile $objfile" shift +${READELF} --section-headers --wide $objfile | ${GREP} -q '\.debug_info' || die "CONFIG_DEBUG_INFO not enabled" + DIR_PREFIX=supercalifragilisticexpialidocious find_dir_prefix $objfile diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh deleted file mode 100755 index 8b980fb2270a..000000000000 --- a/scripts/gcc-goto.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# Test for gcc 'asm goto' support -# Copyright (C) 2010, Jason Baron <jbaron@redhat.com> - -cat << "END" | $@ -x c - -fno-PIE -c -o /dev/null -int main(void) -{ -#if defined(__arm__) || defined(__aarch64__) - /* - * Not related to asm goto, but used by jump label - * and broken on some ARM GCC versions (see GCC Bug 48637). - */ - static struct { int dummy; int state; } tp; - asm (".long %c0" :: "i" (&tp.state)); -#endif - -entry: - asm goto ("" :::: entry); - return 0; -} -END diff --git a/scripts/gcc-ld b/scripts/gcc-ld deleted file mode 100755 index 997b818c3962..000000000000 --- a/scripts/gcc-ld +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# run gcc with ld options -# used as a wrapper to execute link time optimizations -# yes virginia, this is not pretty - -ARGS="-nostdlib" - -while [ "$1" != "" ] ; do - case "$1" in - -save-temps|-m32|-m64) N="$1" ;; - -r) N="$1" ;; - -[Wg]*) N="$1" ;; - -[olv]|-[Ofd]*|-nostdlib) N="$1" ;; - --end-group|--start-group) - N="-Wl,$1" ;; - -[RTFGhIezcbyYu]*|\ ---script|--defsym|-init|-Map|--oformat|-rpath|\ --rpath-link|--sort-section|--section-start|-Tbss|-Tdata|-Ttext|\ ---version-script|--dynamic-list|--version-exports-symbol|--wrap|-m) - A="$1" ; shift ; N="-Wl,$A,$1" ;; - -[m]*) N="$1" ;; - -*) N="-Wl,$1" ;; - *) N="$1" ;; - esac - ARGS="$ARGS $N" - shift -done - -exec $CC $ARGS diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig index 51d81c3f03d6..e383cda05367 100644 --- a/scripts/gcc-plugins/Kconfig +++ b/scripts/gcc-plugins/Kconfig @@ -46,44 +46,6 @@ config GCC_PLUGIN_LATENT_ENTROPY * https://grsecurity.net/ * https://pax.grsecurity.net/ -config GCC_PLUGIN_RANDSTRUCT - bool "Randomize layout of sensitive kernel structures" - select MODVERSIONS if MODULES - help - If you say Y here, the layouts of structures that are entirely - function pointers (and have not been manually annotated with - __no_randomize_layout), or structures that have been explicitly - marked with __randomize_layout, will be randomized at compile-time. - This can introduce the requirement of an additional information - exposure vulnerability for exploits targeting these structure - types. - - Enabling this feature will introduce some performance impact, - slightly increase memory usage, and prevent the use of forensic - tools like Volatility against the system (unless the kernel - source tree isn't cleaned after kernel installation). - - The seed used for compilation is located at - scripts/gcc-plugins/randomize_layout_seed.h. It remains after - a make clean to allow for external modules to be compiled with - the existing seed and will be removed by a make mrproper or - make distclean. - - This plugin was ported from grsecurity/PaX. More information at: - * https://grsecurity.net/ - * https://pax.grsecurity.net/ - -config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE - bool "Use cacheline-aware structure randomization" - depends on GCC_PLUGIN_RANDSTRUCT - depends on !COMPILE_TEST # do not reduce test coverage - help - If you say Y here, the RANDSTRUCT randomization will make a - best effort at restricting randomization to cacheline-sized - groups of elements. It will further not randomize bitfields - in structures. This reduces the performance hit of RANDSTRUCT - at the cost of weakened randomization. - config GCC_PLUGIN_ARM_SSP_PER_TASK bool depends on GCC_PLUGINS && ARM diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile index 1952d3bb80c6..b34d11e22636 100644 --- a/scripts/gcc-plugins/Makefile +++ b/scripts/gcc-plugins/Makefile @@ -1,12 +1,17 @@ # SPDX-License-Identifier: GPL-2.0 -$(obj)/randomize_layout_plugin.so: $(objtree)/$(obj)/randomize_layout_seed.h -quiet_cmd_create_randomize_layout_seed = GENSEED $@ +$(obj)/randomize_layout_plugin.so: $(obj)/randomize_layout_seed.h +quiet_cmd_create_randomize_layout_seed = SEEDHDR $@ cmd_create_randomize_layout_seed = \ - $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h -$(objtree)/$(obj)/randomize_layout_seed.h: FORCE + SEED=$$(cat $(filter-out FORCE,$^) </dev/null); \ + echo '/*' > $@; \ + echo ' * This file is automatically generated. Keep it private.' >> $@; \ + echo ' * Exposing this value will expose the layout of randomized structures.' >> $@; \ + echo ' */' >> $@; \ + echo "const char *randstruct_seed = \"$$SEED\";" >> $@ +$(obj)/randomize_layout_seed.h: $(objtree)/scripts/basic/randstruct.seed FORCE $(call if_changed,create_randomize_layout_seed) -targets += randomize_layout_seed.h randomize_layout_hash.h +targets += randomize_layout_seed.h # Build rules for plugins # @@ -23,10 +28,11 @@ GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin) plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \ -include $(srctree)/include/linux/compiler-version.h \ - -I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \ - -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \ - -ggdb -Wno-narrowing -Wno-unused-variable \ - -Wno-format-diag + -DPLUGIN_VERSION=$(call stringify,$(KERNELVERSION)) \ + -I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \ + -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \ + -ggdb -Wno-narrowing -Wno-unused-variable \ + -Wno-format-diag plugin_ldflags = -shared diff --git a/scripts/gcc-plugins/gen-random-seed.sh b/scripts/gcc-plugins/gen-random-seed.sh deleted file mode 100755 index 68af5cc20a64..000000000000 --- a/scripts/gcc-plugins/gen-random-seed.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -if [ ! -f "$1" ]; then - SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'` - echo "const char *randstruct_seed = \"$SEED\";" > "$1" - HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'` - echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2" -fi diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c index 589454bce930..39e86be60dd2 100644 --- a/scripts/gcc-plugins/latent_entropy_plugin.c +++ b/scripts/gcc-plugins/latent_entropy_plugin.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu> * Copyright 2016 by Emese Revfy <re.emese@gmail.com> - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, @@ -82,29 +82,35 @@ __visible int plugin_is_GPL_compatible; static GTY(()) tree latent_entropy_decl; static struct plugin_info latent_entropy_plugin_info = { - .version = "201606141920vanilla", + .version = PLUGIN_VERSION, .help = "disable\tturn off latent entropy instrumentation\n", }; -static unsigned HOST_WIDE_INT seed; -/* - * get_random_seed() (this is a GCC function) generates the seed. - * This is a simple random generator without any cryptographic security because - * the entropy doesn't come from here. - */ +static unsigned HOST_WIDE_INT deterministic_seed; +static unsigned HOST_WIDE_INT rnd_buf[32]; +static size_t rnd_idx = ARRAY_SIZE(rnd_buf); +static int urandom_fd = -1; + static unsigned HOST_WIDE_INT get_random_const(void) { - unsigned int i; - unsigned HOST_WIDE_INT ret = 0; - - for (i = 0; i < 8 * sizeof(ret); i++) { - ret = (ret << 1) | (seed & 1); - seed >>= 1; - if (ret & 1) - seed ^= 0xD800000000000000ULL; + if (deterministic_seed) { + unsigned HOST_WIDE_INT w = deterministic_seed; + w ^= w << 13; + w ^= w >> 7; + w ^= w << 17; + deterministic_seed = w; + return deterministic_seed; } - return ret; + if (urandom_fd < 0) { + urandom_fd = open("/dev/urandom", O_RDONLY); + gcc_assert(urandom_fd >= 0); + } + if (rnd_idx >= ARRAY_SIZE(rnd_buf)) { + gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf)); + rnd_idx = 0; + } + return rnd_buf[rnd_idx++]; } static tree tree_get_random_const(tree type) @@ -537,8 +543,6 @@ static void latent_entropy_start_unit(void *gcc_data __unused, tree type, id; int quals; - seed = get_random_seed(false); - if (in_lto_p) return; @@ -573,6 +577,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, const struct plugin_argument * const argv = plugin_info->argv; int i; + /* + * Call get_random_seed() with noinit=true, so that this returns + * 0 in the case where no seed has been passed via -frandom-seed. + */ + deterministic_seed = get_random_seed(true); + static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = { { .base = &latent_entropy_decl, diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c index 334741a31d0a..951b74ba1b24 100644 --- a/scripts/gcc-plugins/randomize_layout_plugin.c +++ b/scripts/gcc-plugins/randomize_layout_plugin.c @@ -34,29 +34,11 @@ __visible int plugin_is_GPL_compatible; static int performance_mode; static struct plugin_info randomize_layout_plugin_info = { - .version = "201402201816vanilla", + .version = PLUGIN_VERSION, .help = "disable\t\t\tdo not activate plugin\n" "performance-mode\tenable cacheline-aware layout randomization\n" }; -struct whitelist_entry { - const char *pathname; - const char *lhs; - const char *rhs; -}; - -static const struct whitelist_entry whitelist[] = { - /* NIU overloads mapping with page struct */ - { "drivers/net/ethernet/sun/niu.c", "page", "address_space" }, - /* unix_skb_parms via UNIXCB() buffer */ - { "net/unix/af_unix.c", "unix_skb_parms", "char" }, - /* big_key payload.data struct splashing */ - { "security/keys/big_key.c", "path", "void *" }, - /* walk struct security_hook_heads as an array of struct hlist_head */ - { "security/security.c", "hlist_head", "security_hook_heads" }, - { } -}; - /* from old Linux dcache.h */ static inline unsigned long partial_name_hash(unsigned long c, unsigned long prevhash) @@ -742,60 +724,6 @@ static void handle_local_var_initializers(void) } } -static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_name) -{ - const char *type_name; - - if (type_tree == NULL_TREE) - return false; - - switch (TREE_CODE(type_tree)) { - case RECORD_TYPE: - type_name = TYPE_NAME_POINTER(type_tree); - break; - case INTEGER_TYPE: - if (TYPE_PRECISION(type_tree) == CHAR_TYPE_SIZE) - type_name = "char"; - else { - INFORM(gimple_location(stmt), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree); - debug_tree(type_tree); - return false; - } - break; - case POINTER_TYPE: - if (TREE_CODE(TREE_TYPE(type_tree)) == VOID_TYPE) { - type_name = "void *"; - break; - } else { - INFORM(gimple_location(stmt), "found non-void POINTER_TYPE cast comparison %qT\n", type_tree); - debug_tree(type_tree); - return false; - } - default: - INFORM(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree); - debug_tree(type_tree); - return false; - } - - return strcmp(type_name, wanted_name) == 0; -} - -static bool whitelisted_cast(gimple stmt, const_tree lhs_tree, const_tree rhs_tree) -{ - const struct whitelist_entry *entry; - expanded_location xloc = expand_location(gimple_location(stmt)); - - for (entry = whitelist; entry->pathname; entry++) { - if (!strstr(xloc.file, entry->pathname)) - continue; - - if (type_name_eq(stmt, lhs_tree, entry->lhs) && type_name_eq(stmt, rhs_tree, entry->rhs)) - return true; - } - - return false; -} - /* * iterate over all statements to find "bad" casts: * those where the address of the start of a structure is cast @@ -872,10 +800,7 @@ static unsigned int find_bad_casts_execute(void) #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type))) #endif - { - if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type)) - MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type); - } + MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type); continue; } @@ -898,10 +823,7 @@ static unsigned int find_bad_casts_execute(void) #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type))) #endif - { - if (!whitelisted_cast(stmt, ptr_lhs_type, op0_type)) - MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type); - } + MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type); } else { const_tree ssa_name_var = SSA_NAME_VAR(rhs1); /* skip bogus type casts introduced by container_of */ @@ -911,10 +833,7 @@ static unsigned int find_bad_casts_execute(void) #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type))) #endif - { - if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type)) - MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type); - } + MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type); } } diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c index 23bd023a283b..b76cb9c42cec 100644 --- a/scripts/gcc-plugins/sancov_plugin.c +++ b/scripts/gcc-plugins/sancov_plugin.c @@ -26,7 +26,7 @@ __visible int plugin_is_GPL_compatible; tree sancov_fndecl; static struct plugin_info sancov_plugin_info = { - .version = "20160402", + .version = PLUGIN_VERSION, .help = "sancov plugin\n", }; diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c index e9db7dcb3e5f..c5c2ce113c92 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu> * Modified by Alexander Popov <alex.popov@linux.com> - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, @@ -44,7 +44,7 @@ static bool verbose = false; static GTY(()) tree track_function_decl; static struct plugin_info stackleak_plugin_info = { - .version = "201707101337", + .version = PLUGIN_VERSION, .help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n" "arch=target_arch\tspecify target build arch\n" "disable\t\tdo not activate the plugin\n" @@ -429,6 +429,23 @@ static unsigned int stackleak_cleanup_execute(void) return 0; } +/* + * STRING_CST may or may not be NUL terminated: + * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html + */ +static inline bool string_equal(tree node, const char *string, int length) +{ + if (TREE_STRING_LENGTH(node) < length) + return false; + if (TREE_STRING_LENGTH(node) > length + 1) + return false; + if (TREE_STRING_LENGTH(node) == length + 1 && + TREE_STRING_POINTER(node)[length] != '\0') + return false; + return !memcmp(TREE_STRING_POINTER(node), string, length); +} +#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str)) + static bool stackleak_gate(void) { tree section; @@ -438,13 +455,17 @@ static bool stackleak_gate(void) if (section && TREE_VALUE(section)) { section = TREE_VALUE(TREE_VALUE(section)); - if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) + if (STRING_EQUAL(section, ".init.text")) + return false; + if (STRING_EQUAL(section, ".devinit.text")) + return false; + if (STRING_EQUAL(section, ".cpuinit.text")) return false; - if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) + if (STRING_EQUAL(section, ".meminit.text")) return false; - if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) + if (STRING_EQUAL(section, ".noinstr.text")) return false; - if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) + if (STRING_EQUAL(section, ".entry.text")) return false; } diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c index 74e319288389..d8c744233832 100644 --- a/scripts/gcc-plugins/structleak_plugin.c +++ b/scripts/gcc-plugins/structleak_plugin.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013-2017 by PaX Team <pageexec@freemail.hu> - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, @@ -37,7 +37,7 @@ __visible int plugin_is_GPL_compatible; static struct plugin_info structleak_plugin_info = { - .version = "20190125vanilla", + .version = PLUGIN_VERSION, .help = "disable\tdo not activate plugin\n" "byref\tinit structs passed by reference\n" "byref-all\tinit anything passed by reference\n" diff --git a/scripts/gdb/linux/config.py b/scripts/gdb/linux/config.py index 90e1565b1967..8843ab3cbadd 100644 --- a/scripts/gdb/linux/config.py +++ b/scripts/gdb/linux/config.py @@ -24,9 +24,9 @@ class LxConfigDump(gdb.Command): filename = arg try: - py_config_ptr = gdb.parse_and_eval("kernel_config_data + 8") - py_config_size = gdb.parse_and_eval( - "sizeof(kernel_config_data) - 1 - 8 * 2") + py_config_ptr = gdb.parse_and_eval("&kernel_config_data") + py_config_ptr_end = gdb.parse_and_eval("&kernel_config_data_end") + py_config_size = py_config_ptr_end - py_config_ptr except gdb.error as e: raise gdb.GdbError("Can't find config, enable CONFIG_IKCONFIG?") diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py index d5983cf3db7d..c771831eb077 100644 --- a/scripts/gdb/linux/dmesg.py +++ b/scripts/gdb/linux/dmesg.py @@ -22,7 +22,6 @@ prb_desc_type = utils.CachedType("struct prb_desc") prb_desc_ring_type = utils.CachedType("struct prb_desc_ring") prb_data_ring_type = utils.CachedType("struct prb_data_ring") printk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer") -atomic_long_type = utils.CachedType("atomic_long_t") class LxDmesg(gdb.Command): """Print Linux kernel log buffer.""" @@ -68,8 +67,6 @@ class LxDmesg(gdb.Command): off = prb_data_ring_type.get_type()['data'].bitpos // 8 text_data_addr = utils.read_ulong(text_data_ring, off) - counter_off = atomic_long_type.get_type()['counter'].bitpos // 8 - sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8 off = prb_desc_type.get_type()['text_blk_lpos'].bitpos // 8 @@ -89,9 +86,9 @@ class LxDmesg(gdb.Command): # read in tail and head descriptor ids off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8 - tail_id = utils.read_u64(desc_ring, off + counter_off) + tail_id = utils.read_atomic_long(desc_ring, off) off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8 - head_id = utils.read_u64(desc_ring, off + counter_off) + head_id = utils.read_atomic_long(desc_ring, off) did = tail_id while True: @@ -102,7 +99,7 @@ class LxDmesg(gdb.Command): desc = utils.read_memoryview(inf, desc_addr + desc_off, desc_sz).tobytes() # skip non-committed record - state = 3 & (utils.read_u64(desc, sv_off + counter_off) >> desc_flags_shift) + state = 3 & (utils.read_atomic_long(desc, sv_off) >> desc_flags_shift) if state != desc_committed and state != desc_finalized: if did == head_id: break diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index 46f7542db08c..dc07b6d12e30 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -180,7 +180,7 @@ lx-symbols command.""" self.breakpoint.delete() self.breakpoint = None self.breakpoint = LoadModuleBreakpoint( - "kernel/module.c:do_init_module", self) + "kernel/module/main.c:do_init_module", self) else: gdb.write("Note: symbol update on module loading not supported " "with this gdb version\n") diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py index ff7c1799d588..1553f68716cc 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py @@ -35,13 +35,12 @@ class CachedType: long_type = CachedType("long") - +atomic_long_type = CachedType("atomic_long_t") def get_long_type(): global long_type return long_type.get_type() - def offset_of(typeobj, field): element = gdb.Value(0).cast(typeobj) return int(str(element[field].address).split()[0], 16) @@ -129,6 +128,17 @@ def read_ulong(buffer, offset): else: return read_u32(buffer, offset) +atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos +atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof + +def read_atomic_long(buffer, offset): + global atomic_long_counter_offset + global atomic_long_counter_sizeof + + if atomic_long_counter_sizeof == 8: + return read_u64(buffer, offset + atomic_long_counter_offset) + else: + return read_u32(buffer, offset + atomic_long_counter_offset) target_arch = None diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index 4136dc2c59df..3e8d3669f0ce 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -13,7 +13,7 @@ import os -sys.path.insert(0, os.path.dirname(__file__) + "/scripts/gdb") +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + "/scripts/gdb") try: gdb.parse_and_eval("0") diff --git a/scripts/gen-randstruct-seed.sh b/scripts/gen-randstruct-seed.sh new file mode 100755 index 000000000000..61017b36c464 --- /dev/null +++ b/scripts/gen-randstruct-seed.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +SEED=$(od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n') +echo "$SEED" > "$1" +HASH=$(echo -n "$SEED" | sha256sum | cut -d" " -f1) +echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2" diff --git a/scripts/gen_autoksyms.sh b/scripts/gen_autoksyms.sh index 6ed0d225c8b1..653fadbad302 100755 --- a/scripts/gen_autoksyms.sh +++ b/scripts/gen_autoksyms.sh @@ -2,13 +2,10 @@ # SPDX-License-Identifier: GPL-2.0-only # Create an autoksyms.h header file from the list of all module's needed symbols -# as recorded on the second line of *.mod files and the user-provided symbol -# whitelist. +# as recorded in *.usyms files and the user-provided symbol whitelist. set -e -output_file="$1" - # Use "make V=1" to debug this script. case "$KBUILD_VERBOSE" in *1*) @@ -16,20 +13,24 @@ case "$KBUILD_VERBOSE" in ;; esac -# We need access to CONFIG_ symbols -. include/config/auto.conf +read_modorder= + +if [ "$1" = --modorder ]; then + shift + read_modorder=1 +fi + +output_file="$1" needed_symbols= # Special case for modversions (see modpost.c) -if [ -n "$CONFIG_MODVERSIONS" ]; then +if grep -q "^CONFIG_MODVERSIONS=y$" include/config/auto.conf; then needed_symbols="$needed_symbols module_layout" fi -ksym_wl= -if [ -n "$CONFIG_UNUSED_KSYMS_WHITELIST" ]; then - # Use 'eval' to expand the whitelist path and check if it is relative - eval ksym_wl="$CONFIG_UNUSED_KSYMS_WHITELIST" +ksym_wl=$(sed -n 's/^CONFIG_UNUSED_KSYMS_WHITELIST=\(.*\)$/\1/p' include/config/auto.conf) +if [ -n "$ksym_wl" ]; then [ "${ksym_wl}" != "${ksym_wl#/}" ] || ksym_wl="$abs_srctree/$ksym_wl" if [ ! -f "$ksym_wl" ] || [ ! -r "$ksym_wl" ]; then echo "ERROR: '$ksym_wl' whitelist file not found" >&2 @@ -46,10 +47,8 @@ cat > "$output_file" << EOT EOT -[ -f modules.order ] && modlist=modules.order || modlist=/dev/null - { - sed 's/ko$/mod/' $modlist | xargs -n1 sed -n -e '2p' + [ -n "${read_modorder}" ] && sed 's/ko$/usyms/' modules.order | xargs cat echo "$needed_symbols" [ -n "$ksym_wl" ] && cat "$ksym_wl" } | sed -e 's/ /\n/g' | sed -n -e '/^$/!p' | @@ -57,4 +56,7 @@ EOT # point addresses. sed -e 's/^\.//' | sort -u | +# Ignore __this_module. It's not an exported symbol, and will be resolved +# when the final .ko's are linked. +grep -v '^__this_module$' | sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$output_file" diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py new file mode 100755 index 000000000000..75bb611bd751 --- /dev/null +++ b/scripts/generate_rust_analyzer.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +"""generate_rust_analyzer - Generates the `rust-project.json` file for `rust-analyzer`. +""" + +import argparse +import json +import logging +import pathlib +import sys + +def generate_crates(srctree, objtree, sysroot_src): + # Generate the configuration list. + cfg = [] + with open(objtree / "include" / "generated" / "rustc_cfg") as fd: + for line in fd: + line = line.replace("--cfg=", "") + line = line.replace("\n", "") + cfg.append(line) + + # Now fill the crates list -- dependencies need to come first. + # + # Avoid O(n^2) iterations by keeping a map of indexes. + crates = [] + crates_indexes = {} + + def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): + crates_indexes[display_name] = len(crates) + crates.append({ + "display_name": display_name, + "root_module": str(root_module), + "is_workspace_member": is_workspace_member, + "is_proc_macro": is_proc_macro, + "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], + "cfg": cfg, + "edition": "2021", + "env": { + "RUST_MODFILE": "This is only for rust-analyzer" + } + }) + + # First, the ones in `rust/` since they are a bit special. + append_crate( + "core", + sysroot_src / "core" / "src" / "lib.rs", + [], + is_workspace_member=False, + ) + + append_crate( + "compiler_builtins", + srctree / "rust" / "compiler_builtins.rs", + [], + ) + + append_crate( + "alloc", + srctree / "rust" / "alloc" / "lib.rs", + ["core", "compiler_builtins"], + ) + + append_crate( + "macros", + srctree / "rust" / "macros" / "lib.rs", + [], + is_proc_macro=True, + ) + crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so" + + append_crate( + "bindings", + srctree / "rust"/ "bindings" / "lib.rs", + ["core"], + cfg=cfg, + ) + crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True)) + + append_crate( + "kernel", + srctree / "rust" / "kernel" / "lib.rs", + ["core", "alloc", "macros", "bindings"], + cfg=cfg, + ) + crates[-1]["source"] = { + "include_dirs": [ + str(srctree / "rust" / "kernel"), + str(objtree / "rust") + ], + "exclude_dirs": [], + } + + # Then, the rest outside of `rust/`. + # + # We explicitly mention the top-level folders we want to cover. + for folder in ("samples", "drivers"): + for path in (srctree / folder).rglob("*.rs"): + logging.info("Checking %s", path) + name = path.name.replace(".rs", "") + + # Skip those that are not crate roots. + if f"{name}.o" not in open(path.parent / "Makefile").read(): + continue + + logging.info("Adding %s", name) + append_crate( + name, + path, + ["core", "alloc", "kernel"], + cfg=cfg, + ) + + return crates + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--verbose', '-v', action='store_true') + parser.add_argument("srctree", type=pathlib.Path) + parser.add_argument("objtree", type=pathlib.Path) + parser.add_argument("sysroot_src", type=pathlib.Path) + args = parser.parse_args() + + logging.basicConfig( + format="[%(asctime)s] [%(levelname)s] %(message)s", + level=logging.INFO if args.verbose else logging.WARNING + ) + + rust_project = { + "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src), + "sysroot_src": str(args.sysroot_src), + } + + json.dump(rust_project, sys.stdout, sort_keys=True, indent=4) + +if __name__ == "__main__": + main() diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs new file mode 100644 index 000000000000..3c6cbe2b278d --- /dev/null +++ b/scripts/generate_rust_target.rs @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! The custom target specification file generator for `rustc`. +//! +//! To configure a target from scratch, a JSON-encoded file has to be passed +//! to `rustc` (introduced in [RFC 131]). These options and the file itself are +//! unstable. Eventually, `rustc` should provide a way to do this in a stable +//! manner. For instance, via command-line arguments. Therefore, this file +//! should avoid using keys which can be set via `-C` or `-Z` options. +//! +//! [RFC 131]: https://rust-lang.github.io/rfcs/0131-target-specification.html + +use std::{ + collections::HashMap, + fmt::{Display, Formatter, Result}, + io::BufRead, +}; + +enum Value { + Boolean(bool), + Number(i32), + String(String), + Object(Object), +} + +type Object = Vec<(String, Value)>; + +/// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping), +/// enough for this purpose. +impl Display for Value { + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { + match self { + Value::Boolean(boolean) => write!(formatter, "{}", boolean), + Value::Number(number) => write!(formatter, "{}", number), + Value::String(string) => write!(formatter, "\"{}\"", string), + Value::Object(object) => { + formatter.write_str("{")?; + if let [ref rest @ .., ref last] = object[..] { + for (key, value) in rest { + write!(formatter, "\"{}\": {},", key, value)?; + } + write!(formatter, "\"{}\": {}", last.0, last.1)?; + } + formatter.write_str("}") + } + } + } +} + +struct TargetSpec(Object); + +impl TargetSpec { + fn new() -> TargetSpec { + TargetSpec(Vec::new()) + } +} + +trait Push<T> { + fn push(&mut self, key: &str, value: T); +} + +impl Push<bool> for TargetSpec { + fn push(&mut self, key: &str, value: bool) { + self.0.push((key.to_string(), Value::Boolean(value))); + } +} + +impl Push<i32> for TargetSpec { + fn push(&mut self, key: &str, value: i32) { + self.0.push((key.to_string(), Value::Number(value))); + } +} + +impl Push<String> for TargetSpec { + fn push(&mut self, key: &str, value: String) { + self.0.push((key.to_string(), Value::String(value))); + } +} + +impl Push<&str> for TargetSpec { + fn push(&mut self, key: &str, value: &str) { + self.push(key, value.to_string()); + } +} + +impl Push<Object> for TargetSpec { + fn push(&mut self, key: &str, value: Object) { + self.0.push((key.to_string(), Value::Object(value))); + } +} + +impl Display for TargetSpec { + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { + // We add some newlines for clarity. + formatter.write_str("{\n")?; + if let [ref rest @ .., ref last] = self.0[..] { + for (key, value) in rest { + write!(formatter, " \"{}\": {},\n", key, value)?; + } + write!(formatter, " \"{}\": {}\n", last.0, last.1)?; + } + formatter.write_str("}") + } +} + +struct KernelConfig(HashMap<String, String>); + +impl KernelConfig { + /// Parses `include/config/auto.conf` from `stdin`. + fn from_stdin() -> KernelConfig { + let mut result = HashMap::new(); + + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + let mut line = String::new(); + + loop { + line.clear(); + + if handle.read_line(&mut line).unwrap() == 0 { + break; + } + + if line.starts_with('#') { + continue; + } + + let (key, value) = line.split_once('=').expect("Missing `=` in line."); + result.insert(key.to_string(), value.trim_end_matches('\n').to_string()); + } + + KernelConfig(result) + } + + /// Does the option exist in the configuration (any value)? + /// + /// The argument must be passed without the `CONFIG_` prefix. + /// This avoids repetition and it also avoids `fixdep` making us + /// depend on it. + fn has(&self, option: &str) -> bool { + let option = "CONFIG_".to_owned() + option; + self.0.contains_key(&option) + } +} + +fn main() { + let cfg = KernelConfig::from_stdin(); + let mut ts = TargetSpec::new(); + + // `llvm-target`s are taken from `scripts/Makefile.clang`. + if cfg.has("X86_64") { + ts.push("arch", "x86_64"); + ts.push( + "data-layout", + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + ); + let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string(); + if cfg.has("RETPOLINE") { + features += ",+retpoline-external-thunk"; + } + ts.push("features", features); + ts.push("llvm-target", "x86_64-linux-gnu"); + ts.push("target-pointer-width", "64"); + } else { + panic!("Unsupported architecture"); + } + + ts.push("emit-debug-gdb-scripts", false); + ts.push("frame-pointer", "may-omit"); + ts.push( + "stack-probes", + vec![("kind".to_string(), Value::String("none".to_string()))], + ); + + // Everything else is LE, whether `CPU_LITTLE_ENDIAN` is declared or not + // (e.g. x86). It is also `rustc`'s default. + if cfg.has("CPU_BIG_ENDIAN") { + ts.push("target-endian", "big"); + } + + println!("{}", ts); +} diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 4827c5abe5b7..f5dfdb9d80e9 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -33,7 +33,7 @@ char *cur_filename; int in_source_file; static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, - flag_preserve, flag_warnings, flag_rel_crcs; + flag_preserve, flag_warnings; static int errors; static int nsyms; @@ -680,11 +680,7 @@ void export_symbol(const char *name) if (flag_dump_defs) fputs(">\n", debugfile); - /* Used as a linker script. */ - printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" : - "SECTIONS { .rodata : ALIGN(4) { " - "__crc_%s = .; LONG(0x%08lx); } }\n", - name, crc); + printf("#SYMVER %s 0x%08lx\n", name, crc); } } @@ -733,7 +729,6 @@ static void genksyms_usage(void) " -q, --quiet Disable warnings (default)\n" " -h, --help Print this message\n" " -V, --version Print the release version\n" - " -R, --relative-crc Emit section relative symbol CRCs\n" #else /* __GNU_LIBRARY__ */ " -s Select symbol prefix\n" " -d Increment the debug level (repeatable)\n" @@ -745,7 +740,6 @@ static void genksyms_usage(void) " -q Disable warnings (default)\n" " -h Print this message\n" " -V Print the release version\n" - " -R Emit section relative symbol CRCs\n" #endif /* __GNU_LIBRARY__ */ , stderr); } @@ -766,14 +760,13 @@ int main(int argc, char **argv) {"preserve", 0, 0, 'p'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, - {"relative-crc", 0, 0, 'R'}, {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR", + while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF) + while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { case 'd': @@ -813,9 +806,6 @@ int main(int argc, char **argv) case 'h': genksyms_usage(); return 0; - case 'R': - flag_rel_crcs = 1; - break; default: genksyms_usage(); return 1; diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl index 6212f58b69c6..0ffd5531242a 100755 --- a/scripts/get_abi.pl +++ b/scripts/get_abi.pl @@ -92,6 +92,7 @@ sub parse_abi { my $mode = (stat($file))[2]; return if ($mode & S_IFDIR); return if ($file =~ m,/README,); + return if ($file =~ m,/\.,); my $name = $file; $name =~ s,.*/,,; @@ -326,7 +327,7 @@ sub output_rest { my @filepath = split / /, $data{$what}->{filepath}; if ($enable_lineno) { - printf "#define LINENO %s%s#%s\n\n", + printf ".. LINENO %s%s#%s\n\n", $prefix, $file[0], $data{$what}->{line_no}; } @@ -980,14 +981,14 @@ __END__ =head1 NAME -abi_book.pl - parse the Linux ABI files and produce a ReST book. +get_abi.pl - parse the Linux ABI files and produce a ReST book. =head1 SYNOPSIS -B<abi_book.pl> [--debug <level>] [--enable-lineno] [--man] [--help] +B<get_abi.pl> [--debug <level>] [--enable-lineno] [--man] [--help] [--(no-)rst-source] [--dir=<dir>] [--show-hints] [--search-string <regex>] - <COMAND> [<ARGUMENT>] + <COMMAND> [<ARGUMENT>] Where B<COMMAND> can be: @@ -1022,7 +1023,7 @@ logic (B<--no-rst-source>). =item B<--enable-lineno> -Enable output of #define LINENO lines. +Enable output of .. LINENO lines. =item B<--debug> I<debug level> diff --git a/scripts/get_feat.pl b/scripts/get_feat.pl index 457712355676..5c5397eeb237 100755 --- a/scripts/get_feat.pl +++ b/scripts/get_feat.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # SPDX-License-Identifier: GPL-2.0 use strict; @@ -13,6 +13,7 @@ my $man; my $debug; my $arch; my $feat; +my $enable_fname; my $basename = abs_path($0); $basename =~ s,/[^/]+$,/,; @@ -31,6 +32,7 @@ GetOptions( 'arch=s' => \$arch, 'feat=s' => \$feat, 'feature=s' => \$feat, + "enable-fname" => \$enable_fname, man => \$man ) or pod2usage(2); @@ -95,6 +97,10 @@ sub parse_feat { return if ($file =~ m,($prefix)/arch-support.txt,); return if (!($file =~ m,arch-support.txt$,)); + if ($enable_fname) { + printf ".. FILE %s\n", abs_path($file); + } + my $subsys = ""; $subsys = $2 if ( m,.*($prefix)/([^/]+).*,); @@ -580,6 +586,11 @@ Output features for a single specific feature. Changes the location of the Feature files. By default, it uses the Documentation/features directory. +=item B<--enable-fname> + +Prints the file name of the feature files. This can be used in order to +track dependencies during documentation build. + =item B<--debug> Put the script in verbose mode, useful for debugging. Can be called multiple diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 2075db0c08b8..ab123b498fd9 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -983,6 +983,7 @@ sub get_maintainers { } foreach my $email (@file_emails) { + $email = mailmap_email($email); my ($name, $address) = parse_email($email); my $tmp_email = format_email($name, $address, $email_usename); @@ -1718,7 +1719,7 @@ sub vcs_exists { %VCS_cmds = %VCS_cmds_hg; return 2 if eval $VCS_cmds{"available"}; %VCS_cmds = (); - if (!$printed_novcs) { + if (!$printed_novcs && $email_git) { warn("$P: No supported VCS found. Add --nogit to options?\n"); warn("Using a git repository produces better results.\n"); warn("Try Linus Torvalds' latest git repository using:\n"); diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt new file mode 100644 index 000000000000..b16326a92c45 --- /dev/null +++ b/scripts/head-object-list.txt @@ -0,0 +1,53 @@ +# Head objects +# +# The objects listed here are placed at the head of vmlinux. A typical use-case +# is an object that contains the entry point. This is kept for compatibility +# with head-y, which Kbuild used to support. +# +# A counter approach is to control the section placement by the linker script. +# The code marked as __HEAD goes into the ".head.text" section, which is placed +# before the normal ".text" section. +# +# If you can achieve the correct code ordering by linker script, please delete +# the entry from this file. +# +arch/alpha/kernel/head.o +arch/arc/kernel/head.o +arch/arm/kernel/head-nommu.o +arch/arm/kernel/head.o +arch/arm64/kernel/head.o +arch/csky/kernel/head.o +arch/hexagon/kernel/head.o +arch/ia64/kernel/head.o +arch/loongarch/kernel/head.o +arch/m68k/68000/head.o +arch/m68k/coldfire/head.o +arch/m68k/kernel/head.o +arch/m68k/kernel/sun3-head.o +arch/microblaze/kernel/head.o +arch/mips/kernel/head.o +arch/nios2/kernel/head.o +arch/openrisc/kernel/head.o +arch/parisc/kernel/head.o +arch/powerpc/kernel/head_40x.o +arch/powerpc/kernel/head_44x.o +arch/powerpc/kernel/head_64.o +arch/powerpc/kernel/head_8xx.o +arch/powerpc/kernel/head_85xx.o +arch/powerpc/kernel/head_book3s_32.o +arch/powerpc/kernel/entry_64.o +arch/powerpc/kernel/fpu.o +arch/powerpc/kernel/vector.o +arch/powerpc/kernel/prom_init.o +arch/riscv/kernel/head.o +arch/s390/kernel/head64.o +arch/sh/kernel/head_32.o +arch/sparc/kernel/head_32.o +arch/sparc/kernel/head_64.o +arch/x86/kernel/head_32.o +arch/x86/kernel/head_64.o +arch/x86/kernel/head32.o +arch/x86/kernel/head64.o +arch/x86/kernel/ebda.o +arch/x86/kernel/platform-quirks.o +arch/xtensa/kernel/head.o diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl deleted file mode 100755 index b6aec5e4365f..000000000000 --- a/scripts/headers_check.pl +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env perl -# SPDX-License-Identifier: GPL-2.0 -# -# headers_check.pl execute a number of trivial consistency checks -# -# Usage: headers_check.pl dir arch [files...] -# dir: dir to look for included files -# arch: architecture -# files: list of files to check -# -# The script reads the supplied files line by line and: -# -# 1) for each include statement it checks if the -# included file actually exists. -# Only include files located in asm* and linux* are checked. -# The rest are assumed to be system include files. -# -# 2) It is checked that prototypes does not use "extern" -# -# 3) Check for leaked CONFIG_ symbols - -use warnings; -use strict; -use File::Basename; - -my ($dir, $arch, @files) = @ARGV; - -my $ret = 0; -my $line; -my $lineno = 0; -my $filename; - -foreach my $file (@files) { - $filename = $file; - - open(my $fh, '<', $filename) - or die "$filename: $!\n"; - $lineno = 0; - while ($line = <$fh>) { - $lineno++; - &check_include(); - &check_asm_types(); - &check_sizetypes(); - &check_declarations(); - # Dropped for now. Too much noise &check_config(); - } - close $fh; -} -exit $ret; - -sub check_include -{ - if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) { - my $inc = $1; - my $found; - $found = stat($dir . "/" . $inc); - if (!$found) { - $inc =~ s#asm/#asm-$arch/#; - $found = stat($dir . "/" . $inc); - } - if (!$found) { - printf STDERR "$filename:$lineno: included file '$inc' is not exported\n"; - $ret = 1; - } - } -} - -sub check_declarations -{ - # soundcard.h is what it is - if ($line =~ m/^void seqbuf_dump\(void\);/) { - return; - } - # drm headers are being C++ friendly - if ($line =~ m/^extern "C"/) { - return; - } - if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { - printf STDERR "$filename:$lineno: " . - "userspace cannot reference function or " . - "variable defined in the kernel\n"; - } -} - -sub check_config -{ - if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) { - printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n"; - } -} - -my $linux_asm_types; -sub check_asm_types -{ - if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { - return; - } - if ($lineno == 1) { - $linux_asm_types = 0; - } elsif ($linux_asm_types >= 1) { - return; - } - if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) { - $linux_asm_types = 1; - printf STDERR "$filename:$lineno: " . - "include of <linux/types.h> is preferred over <asm/types.h>\n" - # Warn until headers are all fixed - #$ret = 1; - } -} - -my $linux_types; -my %import_stack = (); -sub check_include_typesh -{ - my $path = $_[0]; - my $import_path; - - my $fh; - my @file_paths = ($path, $dir . "/" . $path, dirname($filename) . "/" . $path); - for my $possible ( @file_paths ) { - if (not $import_stack{$possible} and open($fh, '<', $possible)) { - $import_path = $possible; - $import_stack{$import_path} = 1; - last; - } - } - if (eof $fh) { - return; - } - - my $line; - while ($line = <$fh>) { - if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { - $linux_types = 1; - last; - } - if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { - check_include_typesh($included); - } - } - close $fh; - delete $import_stack{$import_path}; -} - -sub check_sizetypes -{ - if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { - return; - } - if ($lineno == 1) { - $linux_types = 0; - } elsif ($linux_types >= 1) { - return; - } - if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { - $linux_types = 1; - return; - } - if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { - check_include_typesh($included); - } - if ($line =~ m/__[us](8|16|32|64)\b/) { - printf STDERR "$filename:$lineno: " . - "found __[us]{8,16,32,64} type " . - "without #include <linux/types.h>\n"; - $linux_types = 2; - # Warn until headers are all fixed - #$ret = 1; - } -} diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index dd554bd436cc..4041881746ad 100755 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -70,7 +70,6 @@ configs=$(sed -e ' # # 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 @@ -84,7 +83,6 @@ arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT 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/eventpoll.h:CONFIG_PM_SLEEP include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 000000000000..9bb0fb44f04a --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Common code factored out by Masahiro Yamada + +set -e + +# Make sure the files actually exist +for file in "${KBUILD_IMAGE}" System.map +do + if [ ! -f "${file}" ]; then + echo >&2 + echo >&2 " *** Missing file: ${file}" + echo >&2 ' *** You need to run "make" before "make install".' + echo >&2 + exit 1 + fi +done + +# User/arch may have a custom install script +for file in "${HOME}/bin/${INSTALLKERNEL}" \ + "/sbin/${INSTALLKERNEL}" \ + "${srctree}/arch/${SRCARCH}/install.sh" \ + "${srctree}/arch/${SRCARCH}/boot/install.sh" +do + if [ ! -x "${file}" ]; then + continue + fi + + # installkernel(8) says the parameters are like follows: + # + # installkernel version zImage System.map [directory] + exec "${file}" "${KERNELRELEASE}" "${KBUILD_IMAGE}" System.map "${INSTALL_PATH}" +done + +echo "No install script found" >&2 +exit 1 diff --git a/scripts/is_rust_module.sh b/scripts/is_rust_module.sh new file mode 100755 index 000000000000..28b3831a7593 --- /dev/null +++ b/scripts/is_rust_module.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# is_rust_module.sh module.ko +# +# Returns `0` if `module.ko` is a Rust module, `1` otherwise. + +set -e + +# Using the `16_` prefix ensures other symbols with the same substring +# are not picked up (even if it would be unlikely). The last part is +# used just in case LLVM decides to use the `.` suffix. +# +# In the future, checking for the `.comment` section may be another +# option, see https://github.com/rust-lang/rust/pull/97550. +${NM} "$*" | grep -qE '^[0-9a-fA-F]+ r _R[^[:space:]]+16___IS_RUST_MODULE[^[:space:]]*$' diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 54ad86d13784..03fa07ad45d9 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -18,6 +18,7 @@ * */ +#include <getopt.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -27,7 +28,23 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) -#define KSYM_NAME_LEN 128 +#define _stringify_1(x) #x +#define _stringify(x) _stringify_1(x) + +#define KSYM_NAME_LEN 512 + +/* + * A substantially bigger size than the current maximum. + * + * It cannot be defined as an expression because it gets stringified + * for the fscanf() format string. Therefore, a _Static_assert() is + * used instead to maintain the relationship with KSYM_NAME_LEN. + */ +#define KSYM_NAME_LEN_BUFFER 2048 +_Static_assert( + KSYM_NAME_LEN_BUFFER == KSYM_NAME_LEN * 4, + "Please keep KSYM_NAME_LEN_BUFFER in sync with KSYM_NAME_LEN" +); struct sym_entry { unsigned long long addr; @@ -70,8 +87,8 @@ static unsigned char best_table_len[256]; static void usage(void) { - fprintf(stderr, "Usage: kallsyms [--all-symbols] " - "[--base-relative] < in.map > out.S\n"); + fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] " + "[--base-relative] in.map > out.S\n"); exit(1); } @@ -107,17 +124,16 @@ static bool is_ignored_symbol(const char *name, char type) /* Symbol names that begin with the following are ignored.*/ static const char * const ignored_prefixes[] = { - "$", /* local symbols for ARM, MIPS, etc. */ - ".LASANPC", /* s390 kasan local symbols */ - "__crc_", /* modversions */ "__efistub_", /* arm64 EFI stub namespace */ - "__kvm_nvhe_", /* arm64 non-VHE KVM namespace */ + "__kvm_nvhe_$", /* arm64 local symbols in non-VHE KVM namespace */ + "__kvm_nvhe_.L", /* arm64 local symbols in non-VHE KVM namespace */ "__AArch64ADRPThunk_", /* arm64 lld */ "__ARMV5PILongThunk_", /* arm lld */ "__ARMV7PILongThunk_", "__ThumbV7PILongThunk_", "__LA25Thunk_", /* mips lld */ "__microLA25Thunk_", + "__kcfi_typeid_", /* CFI type identifiers */ NULL }; @@ -197,15 +213,15 @@ static void check_symbol_range(const char *sym, unsigned long long addr, static struct sym_entry *read_symbol(FILE *in) { - char name[500], type; + char name[KSYM_NAME_LEN_BUFFER+1], type; unsigned long long addr; unsigned int len; struct sym_entry *sym; int rc; - rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name); + rc = fscanf(in, "%llx %c %" _stringify(KSYM_NAME_LEN_BUFFER) "s\n", &addr, &type, name); if (rc != 3) { - if (rc != EOF && fgets(name, 500, in) == NULL) + if (rc != EOF && fgets(name, ARRAY_SIZE(name), in) == NULL) fprintf(stderr, "Read error or end of file.\n"); return NULL; } @@ -312,12 +328,19 @@ static void shrink_table(void) } } -static void read_map(FILE *in) +static void read_map(const char *in) { + FILE *fp; struct sym_entry *sym; - while (!feof(in)) { - sym = read_symbol(in); + fp = fopen(in, "r"); + if (!fp) { + perror(in); + exit(1); + } + + while (!feof(fp)) { + sym = read_symbol(fp); if (!sym) continue; @@ -328,12 +351,15 @@ static void read_map(FILE *in) table = realloc(table, sizeof(*table) * table_size); if (!table) { fprintf(stderr, "out of memory\n"); + fclose(fp); exit (1); } } table[table_cnt++] = sym; } + + fclose(fp); } static void output_label(const char *label) @@ -470,12 +496,35 @@ static void write_src(void) if ((i & 0xFF) == 0) markers[i >> 8] = off; - printf("\t.byte 0x%02x", table[i]->len); + /* There cannot be any symbol of length zero. */ + if (table[i]->len == 0) { + fprintf(stderr, "kallsyms failure: " + "unexpected zero symbol length\n"); + exit(EXIT_FAILURE); + } + + /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */ + if (table[i]->len > 0x3FFF) { + fprintf(stderr, "kallsyms failure: " + "unexpected huge symbol length\n"); + exit(EXIT_FAILURE); + } + + /* Encode length with ULEB128. */ + if (table[i]->len <= 0x7F) { + /* Most symbols use a single byte for the length. */ + printf("\t.byte 0x%02x", table[i]->len); + off += table[i]->len + 1; + } else { + /* "Big" symbols use two bytes. */ + printf("\t.byte 0x%02x, 0x%02x", + (table[i]->len & 0x7F) | 0x80, + (table[i]->len >> 7) & 0x7F); + off += table[i]->len + 2; + } for (k = 0; k < table[i]->len; k++) printf(", 0x%02x", table[i]->sym[k]); printf("\n"); - - off += table[i]->len + 1; } printf("\n"); @@ -764,22 +813,26 @@ static void record_relative_base(void) int main(int argc, char **argv) { - if (argc >= 2) { - int i; - for (i = 1; i < argc; i++) { - if(strcmp(argv[i], "--all-symbols") == 0) - all_symbols = 1; - else if (strcmp(argv[i], "--absolute-percpu") == 0) - absolute_percpu = 1; - else if (strcmp(argv[i], "--base-relative") == 0) - base_relative = 1; - else - usage(); - } - } else if (argc != 1) + while (1) { + static struct option long_options[] = { + {"all-symbols", no_argument, &all_symbols, 1}, + {"absolute-percpu", no_argument, &absolute_percpu, 1}, + {"base-relative", no_argument, &base_relative, 1}, + {}, + }; + + int c = getopt_long(argc, argv, "", long_options, NULL); + + if (c == -1) + break; + if (c != 0) + usage(); + } + + if (optind >= argc) usage(); - read_map(stdin); + read_map(argv[optind]); shrink_table(); if (absolute_percpu) make_percpus_absolute(); diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 5a215880b268..b8ef0fb4bbef 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -69,7 +69,7 @@ localyesconfig localmodconfig: $(obj)/conf # deprecated for external use simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \ alldefconfig randconfig listnewconfig olddefconfig syncconfig \ - helpnewconfig yes2modconfig mod2yesconfig + helpnewconfig yes2modconfig mod2yesconfig mod2noconfig PHONY += $(simple-targets) @@ -134,6 +134,7 @@ help: @echo ' randconfig - New config with random answer to all options' @echo ' yes2modconfig - Change answers from yes to mod if possible' @echo ' mod2yesconfig - Change answers from mod to yes if possible' + @echo ' mod2noconfig - Change answers from mod to no if possible' @echo ' listnewconfig - List new options' @echo ' helpnewconfig - List new options and help text' @echo ' olddefconfig - Same as oldconfig but sets new symbols to their' diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 971da3598fe4..33d19e419908 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -35,6 +35,7 @@ enum input_mode { olddefconfig, yes2modconfig, mod2yesconfig, + mod2noconfig, }; static enum input_mode input_mode = oldaskconfig; static int input_mode_opt; @@ -163,8 +164,6 @@ enum conf_def_mode { def_default, def_yes, def_mod, - def_y2m, - def_m2y, def_no, def_random }; @@ -302,12 +301,10 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) return has_changed; } -static void conf_rewrite_mod_or_yes(enum conf_def_mode mode) +static void conf_rewrite_tristates(tristate old_val, tristate new_val) { struct symbol *sym; int i; - tristate old_val = (mode == def_y2m) ? yes : mod; - tristate new_val = (mode == def_y2m) ? mod : yes; for_all_symbols(i, sym) { if (sym_get_type(sym) == S_TRISTATE && @@ -554,7 +551,7 @@ static int conf_choice(struct menu *menu) print_help(child); continue; } - sym_set_choice_value(sym, child->sym); + sym_set_tristate_value(child->sym, yes); for (child = child->list; child; child = child->next) { indent += 2; conf(child); @@ -685,6 +682,7 @@ static const struct option long_opts[] = { {"olddefconfig", no_argument, &input_mode_opt, olddefconfig}, {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig}, {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig}, + {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig}, {NULL, 0, NULL, 0} }; @@ -713,6 +711,7 @@ static void conf_usage(const char *progname) printf(" --randconfig New config with random answer to all options\n"); printf(" --yes2modconfig Change answers from yes to mod if possible\n"); printf(" --mod2yesconfig Change answers from mod to yes if possible\n"); + printf(" --mod2noconfig Change answers from mod to no if possible\n"); printf(" (If none of the above is given, --oldaskconfig is the default)\n"); } @@ -788,6 +787,7 @@ int main(int ac, char **av) case olddefconfig: case yes2modconfig: case mod2yesconfig: + case mod2noconfig: conf_read(NULL); break; case allnoconfig: @@ -862,10 +862,13 @@ int main(int ac, char **av) case savedefconfig: break; case yes2modconfig: - conf_rewrite_mod_or_yes(def_y2m); + conf_rewrite_tristates(yes, mod); break; case mod2yesconfig: - conf_rewrite_mod_or_yes(def_m2y); + conf_rewrite_tristates(mod, yes); + break; + case mod2noconfig: + conf_rewrite_tristates(mod, no); break; case oldaskconfig: rootEntry = &rootmenu; diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 42bc56ee238c..b7c9f1dd5e42 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -216,6 +216,13 @@ static const char *conf_get_autoheader_name(void) return name ? name : "include/generated/autoconf.h"; } +static const char *conf_get_rustccfg_name(void) +{ + char *name = getenv("KCONFIG_RUSTCCFG"); + + return name ? name : "include/generated/rustc_cfg"; +} + static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) { char *p2; @@ -244,19 +251,21 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) p, sym->name); return 1; case S_STRING: - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; + /* No escaping for S_DEF_AUTO (include/config/auto.conf) */ + if (def != S_DEF_AUTO) { + if (*p++ != '"') break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - if (def != S_DEF_AUTO) + if (!p2) { conf_warning("invalid string found"); - return 1; + return 1; + } } /* fall through */ case S_INT: @@ -603,6 +612,9 @@ static const struct comment_style comment_style_c = { static void conf_write_heading(FILE *fp, const struct comment_style *cs) { + if (!cs) + return; + fprintf(fp, "%s\n", cs->prefix); fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n", @@ -656,13 +668,6 @@ static char *escape_string_value(const char *in) return out; } -/* - * Kconfig configuration printer - * - * This printer is used when generating the resulting configuration after - * kconfig invocation and `defconfig' files. Unset symbol might be omitted by - * passing a non-NULL argument to the printer. - */ enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE }; static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n, @@ -700,7 +705,7 @@ static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym) static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym) { - __print_symbol(fp, sym, OUTPUT_N_NONE, true); + __print_symbol(fp, sym, OUTPUT_N_NONE, false); } void print_symbol_for_listconfig(struct symbol *sym) @@ -750,6 +755,65 @@ static void print_symbol_for_c(FILE *fp, struct symbol *sym) free(escaped); } +static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) +{ + const char *val; + const char *val_prefix = ""; + char *val_prefixed = NULL; + size_t val_prefixed_len; + char *escaped = NULL; + + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + /* + * We do not care about disabled ones, i.e. no need for + * what otherwise are "comments" in other printers. + */ + if (*val == 'n') + return; + + /* + * To have similar functionality to the C macro `IS_ENABLED()` + * we provide an empty `--cfg CONFIG_X` here in both `y` + * and `m` cases. + * + * Then, the common `fprintf()` below will also give us + * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can + * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. + */ + fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name); + break; + case S_HEX: + if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) + val_prefix = "0x"; + break; + default: + break; + } + + if (strlen(val_prefix) > 0) { + val_prefixed_len = strlen(val) + strlen(val_prefix) + 1; + val_prefixed = xmalloc(val_prefixed_len); + snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); + val = val_prefixed; + } + + /* All values get escaped: the `--cfg` option only takes strings */ + escaped = escape_string_value(val); + val = escaped; + + fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val); + + free(escaped); + free(val_prefixed); +} + /* * Write out a minimal config. * All values that has default values are skipped as this is redundant. @@ -901,19 +965,20 @@ next: menu = menu->list; continue; } - if (menu->next) + +end_check: + if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu && + menu->prompt->type == P_MENU) { + fprintf(out, "# end of %s\n", menu_get_prompt(menu)); + need_newline = true; + } + + if (menu->next) { menu = menu->next; - else while ((menu = menu->parent)) { - if (!menu->sym && menu_is_visible(menu) && - menu != &rootmenu) { - str = menu_get_prompt(menu); - fprintf(out, "# end of %s\n", str); - need_newline = true; - } - if (menu->next) { - menu = menu->next; - break; - } + } else { + menu = menu->parent; + if (menu) + goto end_check; } } fclose(out); @@ -977,10 +1042,11 @@ static int conf_write_autoconf_cmd(const char *autoconf_name) fprintf(out, "\n$(deps_config): ;\n"); - if (ferror(out)) /* error check for all fprintf() calls */ - return -1; - + fflush(out); + ret = ferror(out); /* error check for all fprintf() calls */ fclose(out); + if (ret) + return -1; if (rename(tmp, name)) { perror("rename"); @@ -992,14 +1058,19 @@ static int conf_write_autoconf_cmd(const char *autoconf_name) static int conf_touch_deps(void) { - const char *name; + const char *name, *tmp; struct symbol *sym; int res, i; - strcpy(depfile_path, "include/config/"); - depfile_prefix_len = strlen(depfile_path); - name = conf_get_autoconfig_name(); + tmp = strrchr(name, '/'); + depfile_prefix_len = tmp ? tmp - name + 1 : 0; + if (depfile_prefix_len + 1 > sizeof(depfile_path)) + return -1; + + strncpy(depfile_path, name, depfile_prefix_len); + depfile_path[depfile_prefix_len] = 0; + conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); @@ -1090,11 +1161,12 @@ static int __conf_write_autoconf(const char *filename, if ((sym->flags & SYMBOL_WRITE) && sym->name) print_symbol(file, sym); + fflush(file); /* check possible errors in conf_write_heading() and print_symbol() */ - if (ferror(file)) - return -1; - + ret = ferror(file); fclose(file); + if (ret) + return -1; if (rename(tmp, filename)) { perror("rename"); @@ -1129,6 +1201,12 @@ int conf_write_autoconf(int overwrite) if (ret) return ret; + ret = __conf_write_autoconf(conf_get_rustccfg_name(), + print_symbol_for_rustccfg, + NULL); + if (ret) + return ret; + /* * Create include/config/auto.conf. This must be the last step because * Kbuild has a dependency on auto.conf and this marks the successful diff --git a/scripts/kconfig/gconf-cfg.sh b/scripts/kconfig/gconf-cfg.sh index 480ecd8b9f41..cbd90c28c05f 100755 --- a/scripts/kconfig/gconf-cfg.sh +++ b/scripts/kconfig/gconf-cfg.sh @@ -3,14 +3,14 @@ PKG="gtk+-2.0 gmodule-2.0 libglade-2.0" -if [ -z "$(command -v pkg-config)" ]; then +if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then echo >&2 "*" - echo >&2 "* 'make gconfig' requires 'pkg-config'. Please install it." + echo >&2 "* 'make gconfig' requires '${HOSTPKG_CONFIG}'. Please install it." echo >&2 "*" exit 1 fi -if ! pkg-config --exists $PKG; then +if ! ${HOSTPKG_CONFIG} --exists $PKG; then echo >&2 "*" echo >&2 "* Unable to find the GTK+ installation. Please make sure that" echo >&2 "* the GTK+ 2.0 development package is correctly installed." @@ -19,12 +19,12 @@ if ! pkg-config --exists $PKG; then exit 1 fi -if ! pkg-config --atleast-version=2.0.0 gtk+-2.0; then +if ! ${HOSTPKG_CONFIG} --atleast-version=2.0.0 gtk+-2.0; then echo >&2 "*" echo >&2 "* GTK+ is present but version >= 2.0.0 is required." echo >&2 "*" exit 1 fi -echo cflags=\"$(pkg-config --cflags $PKG)\" -echo libs=\"$(pkg-config --libs $PKG)\" +echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG)\" +echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index fa8c010aa683..6ac2eabe109d 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -98,7 +98,6 @@ bool menu_is_empty(struct menu *menu); bool menu_is_visible(struct menu *menu); bool menu_has_prompt(struct menu *menu); const char *menu_get_prompt(struct menu *menu); -struct menu *menu_get_root_menu(struct menu *menu); struct menu *menu_get_parent_menu(struct menu *menu); bool menu_has_help(struct menu *menu); const char *menu_get_help(struct menu *menu); @@ -124,11 +123,6 @@ static inline struct symbol *sym_get_choice_value(struct symbol *sym) return (struct symbol *)sym->curr.val; } -static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) -{ - return sym_set_tristate_value(chval, yes); -} - static inline bool sym_is_choice(struct symbol *sym) { return sym->flags & SYMBOL_CHOICE ? true : false; diff --git a/scripts/kconfig/mconf-cfg.sh b/scripts/kconfig/mconf-cfg.sh index b520e407a8eb..025b565e0b7c 100755 --- a/scripts/kconfig/mconf-cfg.sh +++ b/scripts/kconfig/mconf-cfg.sh @@ -4,16 +4,16 @@ PKG="ncursesw" PKG2="ncurses" -if [ -n "$(command -v pkg-config)" ]; then - if pkg-config --exists $PKG; then - echo cflags=\"$(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" +if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then + if ${HOSTPKG_CONFIG} --exists $PKG; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" exit 0 fi - if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" + if ${HOSTPKG_CONFIG} --exists $PKG2; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG2)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG2)\" exit 0 fi fi @@ -46,7 +46,7 @@ echo >&2 "* Unable to find the ncurses package." echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* depending on your distribution)." echo >&2 "*" -echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" echo >&2 "* ncurses installed in a non-default location." echo >&2 "*" exit 1 diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 3d6f7cba8846..109325f31bef 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -661,11 +661,6 @@ const char *menu_get_prompt(struct menu *menu) return NULL; } -struct menu *menu_get_root_menu(struct menu *menu) -{ - return &rootmenu; -} - struct menu *menu_get_parent_menu(struct menu *menu) { enum prop_type type; @@ -727,8 +722,8 @@ static void get_prompt_str(struct gstr *r, struct property *prop, if (!expr_eq(prop->menu->dep, prop->visible.expr)) get_dep_str(r, prop->visible.expr, " Visible if: "); - menu = prop->menu->parent; - for (i = 0; menu && i < 8; menu = menu->parent) { + menu = prop->menu; + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { bool accessible = menu_is_visible(menu); submenu[i++] = menu; @@ -738,16 +733,7 @@ static void get_prompt_str(struct gstr *r, struct property *prop, if (head && location) { jump = xmalloc(sizeof(struct jump_key)); - if (menu_is_visible(prop->menu)) { - /* - * There is not enough room to put the hint at the - * beginning of the "Prompt" line. Put the hint on the - * last "Location" line even when it would belong on - * the former. - */ - jump->target = prop->menu; - } else - jump->target = location; + jump->target = location; if (list_empty(head)) jump->index = 0; @@ -763,13 +749,7 @@ static void get_prompt_str(struct gstr *r, struct property *prop, menu = submenu[i]; if (jump && menu == location) jump->offset = strlen(r->s); - - if (menu == &rootmenu) - /* The real rootmenu prompt is ugly */ - str_printf(r, "%*cMain menu", j, ' '); - else - str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); - + str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? menu->sym->name : "<choice>", diff --git a/scripts/kconfig/nconf-cfg.sh b/scripts/kconfig/nconf-cfg.sh index c212255070c0..3a10bac2adb3 100755 --- a/scripts/kconfig/nconf-cfg.sh +++ b/scripts/kconfig/nconf-cfg.sh @@ -4,16 +4,16 @@ PKG="ncursesw menuw panelw" PKG2="ncurses menu panel" -if [ -n "$(command -v pkg-config)" ]; then - if pkg-config --exists $PKG; then - echo cflags=\"$(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" +if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then + if ${HOSTPKG_CONFIG} --exists $PKG; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" exit 0 fi - if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" + if ${HOSTPKG_CONFIG} --exists $PKG2; then + echo cflags=\"$(${HOSTPKG_CONFIG} --cflags $PKG2)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG2)\" exit 0 fi fi @@ -44,7 +44,7 @@ echo >&2 "* Unable to find the ncurses package." echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* depending on your distribution)." echo >&2 "*" -echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" echo >&2 "* ncurses installed in a non-default location." echo >&2 "*" exit 1 diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 7b371bd7fb36..3ba8b1af390f 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -52,8 +52,8 @@ static const char nconf_global_help[] = "\n" "Menu navigation keys\n" "----------------------------------------------------------------------\n" -"Linewise up <Up>\n" -"Linewise down <Down>\n" +"Linewise up <Up> <k>\n" +"Linewise down <Down> <j>\n" "Pagewise up <Page Up>\n" "Pagewise down <Page Down>\n" "First entry <Home>\n" @@ -1105,9 +1105,11 @@ static void conf(struct menu *menu) break; switch (res) { case KEY_DOWN: + case 'j': menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: + case 'k': menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: @@ -1287,9 +1289,11 @@ static void conf_choice(struct menu *menu) break; switch (res) { case KEY_DOWN: + case 'j': menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: + case 'k': menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index 0590f86df6e4..748da578b418 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[]) static char *do_shell(int argc, char *argv[]) { FILE *p; - char buf[256]; + char buf[4096]; char *cmd; size_t nread; int i; diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh index fa564cd795b7..ad652cb53947 100755 --- a/scripts/kconfig/qconf-cfg.sh +++ b/scripts/kconfig/qconf-cfg.sh @@ -3,22 +3,23 @@ PKG="Qt5Core Qt5Gui Qt5Widgets" -if [ -z "$(command -v pkg-config)" ]; then +if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then echo >&2 "*" - echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it." + echo >&2 "* 'make xconfig' requires '${HOSTPKG_CONFIG}'. Please install it." echo >&2 "*" exit 1 fi -if pkg-config --exists $PKG; then - echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" - echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\" +if ${HOSTPKG_CONFIG} --exists $PKG; then + echo cflags=\"-std=c++11 -fPIC $(${HOSTPKG_CONFIG} --cflags $PKG)\" + echo libs=\"$(${HOSTPKG_CONFIG} --libs $PKG)\" + echo moc=\"$(${HOSTPKG_CONFIG} --variable=host_bins Qt5Core)/moc\" exit 0 fi echo >&2 "*" -echo >&2 "* Could not find Qt5 via pkg-config." +echo >&2 "* Could not find Qt5 via ${HOSTPKG_CONFIG}." echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH" +echo >&2 "* You need $PKG" echo >&2 "*" exit 1 diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 1a5fea0519eb..3387ad7508f7 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -170,7 +170,7 @@ sub read_kconfig { $source =~ s/\$\($env\)/$ENV{$env}/; } - open(my $kinfile, '<', $source) || die "Can't open $kconfig"; + open(my $kinfile, '<', $source) || die "Can't open $source"; while (<$kinfile>) { chomp; diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 3106b7536b89..aea04365bc69 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -12,202 +12,46 @@ use strict; ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## -## ## -## This software falls under the GNU General Public License. ## -## Please read the COPYING file for more information ## +# +# Copyright (C) 2022 Tomasz WarnieÅ‚Å‚o (POD) -# 18/01/2001 - Cleanups -# Functions prototyped as foo(void) same as foo() -# Stop eval'ing where we don't need to. -# -- huggie@earth.li +use Pod::Usage qw/pod2usage/; -# 27/06/2001 - Allowed whitespace after initial "/**" and -# allowed comments before function declarations. -# -- Christian Kreibich <ck@whoop.org> +=head1 NAME -# Still to do: -# - add perldoc documentation -# - Look more closely at some of the scarier bits :) +kernel-doc - Print formatted kernel documentation to stdout -# 26/05/2001 - Support for separate source and object trees. -# Return error code. -# Keith Owens <kaos@ocs.com.au> +=head1 SYNOPSIS -# 23/09/2001 - Added support for typedefs, structs, enums and unions -# Support for Context section; can be terminated using empty line -# Small fixes (like spaces vs. \s in regex) -# -- Tim Jansen <tim@tjansen.de> + kernel-doc [-h] [-v] [-Werror] + [ -man | + -rst [-sphinx-version VERSION] [-enable-lineno] | + -none + ] + [ + -export | + -internal | + [-function NAME] ... | + [-nosymbol NAME] ... + ] + [-no-doc-sections] + [-export-file FILE] ... + FILE ... -# 25/07/2012 - Added support for HTML5 -# -- Dan Luedtke <mail@danrl.de> +Run `kernel-doc -h` for details. -sub usage { - my $message = <<"EOF"; -Usage: $0 [OPTION ...] FILE ... +=head1 DESCRIPTION Read C language source or header FILEs, extract embedded documentation comments, and print formatted documentation to standard output. -The documentation comments are identified by "/**" opening comment mark. See -Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax. - -Output format selection (mutually exclusive): - -man Output troff manual page format. This is the default. - -rst Output reStructuredText format. - -none Do not output documentation, only warnings. - -Output format selection modifier (affects only ReST output): - - -sphinx-version Use the ReST C domain dialect compatible with an - specific Sphinx Version. - If not specified, kernel-doc will auto-detect using - the sphinx-build version found on PATH. - -Output selection (mutually exclusive): - -export Only output documentation for symbols that have been - exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() - in any input FILE or -export-file FILE. - -internal Only output documentation for symbols that have NOT been - exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() - in any input FILE or -export-file FILE. - -function NAME Only output documentation for the given function(s) - or DOC: section title(s). All other functions and DOC: - sections are ignored. May be specified multiple times. - -nosymbol NAME Exclude the specified symbols from the output - documentation. May be specified multiple times. - -Output selection modifiers: - -no-doc-sections Do not output DOC: sections. - -enable-lineno Enable output of #define LINENO lines. Only works with - reStructuredText format. - -export-file FILE Specify an additional FILE in which to look for - EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used with - -export or -internal. May be specified multiple times. - -Other parameters: - -v Verbose output, more warnings and other information. - -h Print this help. - -Werror Treat warnings as errors. - -EOF - print $message; - exit 1; -} +The documentation comments are identified by the "/**" opening comment mark. -# -# format of comments. -# In the following table, (...)? signifies optional structure. -# (...)* signifies 0 or more structure elements -# /** -# * function_name(:)? (- short description)? -# (* @parameterx: (description of parameter x)?)* -# (* a blank line)? -# * (Description:)? (Description of function)? -# * (section header: (section description)? )* -# (*)?*/ -# -# So .. the trivial example would be: -# -# /** -# * my_function -# */ -# -# If the Description: header tag is omitted, then there must be a blank line -# after the last parameter specification. -# e.g. -# /** -# * my_function - does my stuff -# * @my_arg: its mine damnit -# * -# * Does my stuff explained. -# */ -# -# or, could also use: -# /** -# * my_function - does my stuff -# * @my_arg: its mine damnit -# * Description: Does my stuff explained. -# */ -# etc. -# -# Besides functions you can also write documentation for structs, unions, -# enums and typedefs. Instead of the function name you must write the name -# of the declaration; the struct/union/enum/typedef must always precede -# the name. Nesting of declarations is not supported. -# Use the argument mechanism to document members or constants. -# e.g. -# /** -# * struct my_struct - short description -# * @a: first member -# * @b: second member -# * -# * Longer description -# */ -# struct my_struct { -# int a; -# int b; -# /* private: */ -# int c; -# }; -# -# All descriptions can be multiline, except the short function description. -# -# For really longs structs, you can also describe arguments inside the -# body of the struct. -# eg. -# /** -# * struct my_struct - short description -# * @a: first member -# * @b: second member -# * -# * Longer description -# */ -# struct my_struct { -# int a; -# int b; -# /** -# * @c: This is longer description of C -# * -# * You can use paragraphs to describe arguments -# * using this method. -# */ -# int c; -# }; -# -# This should be use only for struct/enum members. -# -# You can also add additional sections. When documenting kernel functions you -# should document the "Context:" of the function, e.g. whether the functions -# can be called form interrupts. Unlike other sections you can end it with an -# empty line. -# A non-void function should have a "Return:" section describing the return -# value(s). -# Example-sections should contain the string EXAMPLE so that they are marked -# appropriately in DocBook. -# -# Example: -# /** -# * user_function - function that can only be called in user context -# * @a: some argument -# * Context: !in_interrupt() -# * -# * Some description -# * Example: -# * user_function(22); -# */ -# ... -# -# -# All descriptive text is further processed, scanning for the following special -# patterns, which are highlighted appropriately. -# -# 'funcname()' - function -# '$ENVVAR' - environmental variable -# '&struct_name' - name of a structure (up to two words including 'struct') -# '&struct_name.member' - name of a structure member -# '@parameter' - name of a parameter -# '%CONST' - name of a constant. -# '``LITERAL``' - literal string without any spaces on it. +See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax. + +=cut + +# more perldoc at the end of the file ## init lots of data @@ -273,7 +117,13 @@ my $blankline_rst = "\n"; # read arguments if ($#ARGV == -1) { - usage(); + pod2usage( + -message => "No arguments!\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } my $kernelversion; @@ -468,7 +318,7 @@ while ($ARGV[0] =~ m/^--?(.*)/) { } elsif ($cmd eq "Werror") { $Werror = 1; } elsif (($cmd eq "h") || ($cmd eq "help")) { - usage(); + pod2usage(-exitval => 0, -verbose => 2); } elsif ($cmd eq 'no-doc-sections') { $no_doc_sections = 1; } elsif ($cmd eq 'enable-lineno') { @@ -494,7 +344,22 @@ while ($ARGV[0] =~ m/^--?(.*)/) { } } else { # Unknown argument - usage(); + pod2usage( + -message => "Argument unknown!\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); + } + if ($#ARGV < 0){ + pod2usage( + -message => "FILE argument missing\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } } @@ -559,9 +424,16 @@ sub get_kernel_version() { sub print_lineno { my $lineno = shift; if ($enable_lineno && defined($lineno)) { - print "#define LINENO " . $lineno . "\n"; + print ".. LINENO " . $lineno . "\n"; } } + +sub emit_warning { + my $location = shift; + my $msg = shift; + print STDERR "$location: warning: $msg"; + ++$warnings; +} ## # dumps section contents to arrays/hashes intended for that purpose. # @@ -586,8 +458,7 @@ sub dump_section { if (defined($sections{$name}) && ($sections{$name} ne "")) { # Only warn on user specified duplicate section names. if ($name ne $section_default) { - print STDERR "${file}:$.: warning: duplicate section name '$name'\n"; - ++$warnings; + emit_warning("${file}:$.", "duplicate section name '$name'\n"); } $sections{$name} .= $contents; } else { @@ -1229,7 +1100,7 @@ sub dump_struct($$) { if ($members) { if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"); return; } @@ -1433,9 +1304,9 @@ sub dump_enum($$) { if ($members) { if ($identifier ne $declaration_name) { if ($identifier eq "") { - print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n"; + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n"); } else { - print STDERR "${file}:$.: warning: expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"); } return; } @@ -1451,7 +1322,7 @@ sub dump_enum($$) { if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; if (show_warnings("enum", $declaration_name)) { - print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n"; + emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n"); } } $_members{$arg} = 1; @@ -1460,7 +1331,7 @@ sub dump_enum($$) { while (my ($k, $v) = each %parameterdescs) { if (!exists($_members{$k})) { if (show_warnings("enum", $declaration_name)) { - print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$declaration_name'\n"; + emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n"); } } } @@ -1502,7 +1373,7 @@ sub dump_typedef($$) { $return_type =~ s/^\s+//; if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); return; } @@ -1533,7 +1404,7 @@ sub dump_typedef($$) { $declaration_name = $1; if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"; + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); return; } @@ -1689,9 +1560,7 @@ sub push_parameter($$$$$) { $parameterdescs{$param} = $undescribed; if (show_warnings($type, $declaration_name) && $param !~ /\./) { - print STDERR - "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n"; - ++$warnings; + emit_warning("${file}:$.", "Function parameter or member '$param' not described in '$declaration_name'\n"); } } @@ -1739,11 +1608,10 @@ sub check_sections($$$$$) { } if ($err) { if ($decl_type eq "function") { - print STDERR "${file}:$.: warning: " . + emit_warning("${file}:$.", "Excess function parameter " . "'$sects[$sx]' " . - "description in '$decl_name'\n"; - ++$warnings; + "description in '$decl_name'\n"); } } } @@ -1764,10 +1632,9 @@ sub check_return_section { if (!defined($sections{$section_return}) || $sections{$section_return} eq "") { - print STDERR "${file}:$.: warning: " . + emit_warning("${file}:$.", "No description found for return value of " . - "'$declaration_name'\n"; - ++$warnings; + "'$declaration_name'\n"); } } @@ -1849,12 +1716,12 @@ sub dump_function($$) { create_parameterlist($args, ',', $file, $declaration_name); } else { - print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n"; + emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n"); return; } if ($identifier ne $declaration_name) { - print STDERR "${file}:$.: warning: expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"; + emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"); return; } @@ -1936,8 +1803,8 @@ sub tracepoint_munge($) { $tracepointargs = $1; } if (($tracepointname eq 0) || ($tracepointargs eq 0)) { - print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n". - "$prototype\n"; + emit_warning("${file}:$.", "Unrecognized tracepoint format: \n". + "$prototype\n"); } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; $identifier = "trace_$identifier"; @@ -2162,22 +2029,16 @@ sub process_name($$) { } if (!$is_kernel_comment) { - print STDERR "${file}:$.: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n"; - print STDERR $_; - ++$warnings; + emit_warning("${file}:$.", "This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n$_"); $state = STATE_NORMAL; } if (($declaration_purpose eq "") && $verbose) { - print STDERR "${file}:$.: warning: missing initial short description on line:\n"; - print STDERR $_; - ++$warnings; + emit_warning("${file}:$.", "missing initial short description on line:\n$_"); } if ($identifier eq "" && $decl_type ne "enum") { - print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n"; - print STDERR $_; - ++$warnings; + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_"); $state = STATE_NORMAL; } @@ -2185,9 +2046,7 @@ sub process_name($$) { print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n"; } } else { - print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", - " - I thought it was a doc line\n"; - ++$warnings; + emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n"); $state = STATE_NORMAL; } } @@ -2206,8 +2065,7 @@ sub process_body($$) { $section =~ s/\.\.\.$//; if ($verbose) { - print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n"; - ++$warnings; + emit_warning("${file}:$.", "Variable macro arguments should be documented without dots\n"); } } @@ -2236,8 +2094,7 @@ sub process_body($$) { if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { - print STDERR "${file}:$.: warning: contents before sections\n"; - ++$warnings; + emit_warning("${file}:$.", "contents before sections\n"); } dump_section($file, $section, $contents); $section = $section_default; @@ -2263,8 +2120,7 @@ sub process_body($$) { } # look for doc_com + <text> + doc_end: if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { - print STDERR "${file}:$.: warning: suspicious ending line: $_"; - ++$warnings; + emit_warning("${file}:$.", "suspicious ending line: $_"); } $prototype = ""; @@ -2308,8 +2164,7 @@ sub process_body($$) { } } else { # i dont know - bad line? ignore. - print STDERR "${file}:$.: warning: bad line: $_"; - ++$warnings; + emit_warning("${file}:$.", "bad line: $_"); } } @@ -2403,9 +2258,7 @@ sub process_inline($$) { } } elsif ($inline_doc_state == STATE_INLINE_NAME) { $inline_doc_state = STATE_INLINE_ERROR; - print STDERR "${file}:$.: warning: "; - print STDERR "Incorrect use of kernel-doc format: $_"; - ++$warnings; + emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_"); } } } @@ -2454,11 +2307,11 @@ sub process_file($) { if ($initial_section_counter == $section_counter && $ output_mode ne "none") { if ($output_selection == OUTPUT_INCLUDE) { - print STDERR "${file}:1: warning: '$_' not found\n" + emit_warning("${file}:1", "'$_' not found\n") for keys %function_table; } else { - print STDERR "${file}:1: warning: no structured comments found\n"; + emit_warning("${file}:1", "no structured comments found\n"); } } close IN_FILE; @@ -2521,3 +2374,118 @@ if ($Werror && $warnings) { } else { exit($output_mode eq "none" ? 0 : $errors) } + +__END__ + +=head1 OPTIONS + +=head2 Output format selection (mutually exclusive): + +=over 8 + +=item -man + +Output troff manual page format. + +=item -rst + +Output reStructuredText format. This is the default. + +=item -none + +Do not output documentation, only warnings. + +=back + +=head2 Output format modifiers + +=head3 reStructuredText only + +=over 8 + +=item -sphinx-version VERSION + +Use the ReST C domain dialect compatible with a specific Sphinx Version. + +If not specified, kernel-doc will auto-detect using the sphinx-build version +found on PATH. + +=back + +=head2 Output selection (mutually exclusive): + +=over 8 + +=item -export + +Only output documentation for the symbols that have been exported using +EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() in any input FILE or -export-file FILE. + +=item -internal + +Only output documentation for the symbols that have NOT been exported using +EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() in any input FILE or -export-file FILE. + +=item -function NAME + +Only output documentation for the given function or DOC: section title. +All other functions and DOC: sections are ignored. + +May be specified multiple times. + +=item -nosymbol NAME + +Exclude the specified symbol from the output documentation. + +May be specified multiple times. + +=back + +=head2 Output selection modifiers: + +=over 8 + +=item -no-doc-sections + +Do not output DOC: sections. + +=item -export-file FILE + +Specify an additional FILE in which to look for EXPORT_SYMBOL() and +EXPORT_SYMBOL_GPL(). + +To be used with -export or -internal. + +May be specified multiple times. + +=back + +=head3 reStructuredText only + +=over 8 + +=item -enable-lineno + +Enable output of .. LINENO lines. + +=back + +=head2 Other parameters: + +=over 8 + +=item -h, -help + +Print this help. + +=item -v + +Verbose output, more warnings and other information. + +=item -Werror + +Treat warnings as errors. + +=back + +=cut diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 5cdd9bc5c385..918470d768e9 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -3,17 +3,15 @@ # # link vmlinux # -# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_OBJS) and -# $(KBUILD_VMLINUX_LIBS). Most are built-in.a files from top-level directories -# in the kernel tree, others are specified in arch/$(ARCH)/Makefile. +# vmlinux is linked from the objects in vmlinux.a and $(KBUILD_VMLINUX_LIBS). +# vmlinux.a contains objects that are linked unconditionally. # $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally # (not within --whole-archive), and do not require symbol indexes added. # # vmlinux # ^ # | -# +--< $(KBUILD_VMLINUX_OBJS) -# | +--< init/built-in.a drivers/built-in.a mm/built-in.a + more +# +--< vmlinux.a # | # +--< $(KBUILD_VMLINUX_LIBS) # | +--< lib/lib.a + more @@ -34,6 +32,10 @@ LD="$1" KBUILD_LDFLAGS="$2" LDFLAGS_vmlinux="$3" +is_enabled() { + grep -q "^$1=y" include/config/auto.conf +} + # Nice output in kbuild format # Will be supressed by "make -s" info() @@ -41,109 +43,6 @@ info() printf " %-7s %s\n" "${1}" "${2}" } -# Generate a linker script to ensure correct ordering of initcalls. -gen_initcalls() -{ - info GEN .tmp_initcalls.lds - - ${PYTHON} ${srctree}/scripts/jobserver-exec \ - ${PERL} ${srctree}/scripts/generate_initcall_order.pl \ - ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS} \ - > .tmp_initcalls.lds -} - -# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into -# .tmp_symversions.lds -gen_symversions() -{ - info GEN .tmp_symversions.lds - rm -f .tmp_symversions.lds - - for o in ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}; do - if [ -f ${o}.symversions ]; then - cat ${o}.symversions >> .tmp_symversions.lds - fi - done -} - -# Link of vmlinux.o used for section mismatch analysis -# ${1} output file -modpost_link() -{ - local objects - local lds="" - - objects="--whole-archive \ - ${KBUILD_VMLINUX_OBJS} \ - --no-whole-archive \ - --start-group \ - ${KBUILD_VMLINUX_LIBS} \ - --end-group" - - if [ -n "${CONFIG_LTO_CLANG}" ]; then - gen_initcalls - lds="-T .tmp_initcalls.lds" - - if [ -n "${CONFIG_MODVERSIONS}" ]; then - gen_symversions - lds="${lds} -T .tmp_symversions.lds" - fi - - # This might take a while, so indicate that we're doing - # an LTO link - info LTO ${1} - else - info LD ${1} - fi - - ${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${lds} ${objects} -} - -objtool_link() -{ - local objtoolcmd; - local objtoolopt; - - if [ "${CONFIG_LTO_CLANG} ${CONFIG_STACK_VALIDATION}" = "y y" ]; then - # Don't perform vmlinux validation unless explicitly requested, - # but run objtool on vmlinux.o now that we have an object file. - if [ -n "${CONFIG_UNWINDER_ORC}" ]; then - objtoolcmd="orc generate" - fi - - objtoolopt="${objtoolopt} --duplicate" - - if [ -n "${CONFIG_FTRACE_MCOUNT_USE_OBJTOOL}" ]; then - objtoolopt="${objtoolopt} --mcount" - fi - fi - - if [ -n "${CONFIG_VMLINUX_VALIDATION}" ]; then - objtoolopt="${objtoolopt} --noinstr" - fi - - if [ -n "${objtoolopt}" ]; then - if [ -z "${objtoolcmd}" ]; then - objtoolcmd="check" - fi - objtoolopt="${objtoolopt} --vmlinux" - if [ -z "${CONFIG_FRAME_POINTER}" ]; then - objtoolopt="${objtoolopt} --no-fp" - fi - if [ -n "${CONFIG_GCOV_KERNEL}" ] || [ -n "${CONFIG_LTO_CLANG}" ]; then - objtoolopt="${objtoolopt} --no-unreachable" - fi - if [ -n "${CONFIG_RETPOLINE}" ]; then - objtoolopt="${objtoolopt} --retpoline" - fi - if [ -n "${CONFIG_X86_SMAP}" ]; then - objtoolopt="${objtoolopt} --uaccess" - fi - info OBJTOOL ${1} - tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1} - fi -} - # Link of vmlinux # ${1} - output file # ${2}, ${3}, ... - optional extra .o files @@ -161,15 +60,21 @@ vmlinux_link() # skip output file argument shift - if [ -n "${CONFIG_LTO_CLANG}" ]; then + if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then # Use vmlinux.o instead of performing the slow LTO link again. objs=vmlinux.o libs= else - objs="${KBUILD_VMLINUX_OBJS}" + objs=vmlinux.a libs="${KBUILD_VMLINUX_LIBS}" fi + if is_enabled CONFIG_MODULES; then + objs="${objs} .vmlinux.export.o" + fi + + objs="${objs} init/version-timestamp.o" + if [ "${SRCARCH}" = "um" ]; then wl=-Wl, ld="${CC}" @@ -189,7 +94,7 @@ vmlinux_link() ldflags="${ldflags} ${wl}--strip-debug" fi - if [ -n "${CONFIG_VMLINUX_MAP}" ]; then + if is_enabled CONFIG_VMLINUX_MAP; then ldflags="${ldflags} ${wl}-Map=${output}.map" fi @@ -239,20 +144,20 @@ kallsyms() { local kallsymopt; - if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then + if is_enabled CONFIG_KALLSYMS_ALL; then kallsymopt="${kallsymopt} --all-symbols" fi - if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then + if is_enabled CONFIG_KALLSYMS_ABSOLUTE_PERCPU; then kallsymopt="${kallsymopt} --absolute-percpu" fi - if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then + if is_enabled CONFIG_KALLSYMS_BASE_RELATIVE; then kallsymopt="${kallsymopt} --base-relative" fi info KSYMS ${2} - ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2} + scripts/kallsyms ${kallsymopt} ${1} > ${2} } # Perform one step in kallsyms generation, including temporary linking of @@ -265,7 +170,8 @@ kallsyms_step() kallsyms_S=${kallsyms_vmlinux}.S vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} - kallsyms ${kallsyms_vmlinux} ${kallsyms_S} + mksysmap ${kallsyms_vmlinux} ${kallsyms_vmlinux}.syms + kallsyms ${kallsyms_vmlinux}.syms ${kallsyms_S} info AS ${kallsyms_S} ${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \ @@ -277,6 +183,7 @@ kallsyms_step() # See mksymap for additional details mksysmap() { + info NM ${2} ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} } @@ -289,15 +196,9 @@ sorttable() cleanup() { rm -f .btf.* - rm -f .tmp_System.map - rm -f .tmp_initcalls.lds - rm -f .tmp_symversions.lds - rm -f .tmp_vmlinux* rm -f System.map rm -f vmlinux rm -f vmlinux.map - rm -f vmlinux.o - rm -f .vmlinux.d } # Use "make V=1" to debug this script @@ -312,38 +213,10 @@ if [ "$1" = "clean" ]; then exit 0 fi -# We need access to CONFIG_ symbols -. include/config/auto.conf - -# Update version -info GEN .version -if [ -r .version ]; then - VERSION=$(expr 0$(cat .version) + 1) - echo $VERSION > .version -else - rm -f .version - echo 1 > .version -fi; - -# final build of init/ -${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1 - -#link vmlinux.o -modpost_link vmlinux.o -objtool_link vmlinux.o - -# modpost vmlinux.o to check for section mismatches -${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1 - -info MODINFO modules.builtin.modinfo -${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo -info GEN modules.builtin -# The second line aids cases where multiple modules share the same object. -tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' | - tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin +${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o btf_vmlinux_bin_o="" -if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then +if is_enabled CONFIG_DEBUG_INFO_BTF; then btf_vmlinux_bin_o=.btf.vmlinux.bin.o if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then echo >&2 "Failed to generate BTF for vmlinux" @@ -355,7 +228,7 @@ fi kallsymso="" kallsymso_prev="" kallsyms_vmlinux="" -if [ -n "${CONFIG_KALLSYMS}" ]; then +if is_enabled CONFIG_KALLSYMS; then # kallsyms support # Generate section listing all symbols and add it into vmlinux @@ -395,12 +268,14 @@ fi vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} # fill in BTF IDs -if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then +if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then info BTFIDS vmlinux ${RESOLVE_BTFIDS} vmlinux fi -if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then +mksysmap vmlinux System.map + +if is_enabled CONFIG_BUILDTIME_TABLE_SORT; then info SORTTAB vmlinux if ! sorttable vmlinux; then echo >&2 Failed to sort kernel tables @@ -408,14 +283,9 @@ if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then fi fi -info SYSMAP System.map -mksysmap vmlinux System.map - # step a (see comment above) -if [ -n "${CONFIG_KALLSYMS}" ]; then - mksysmap ${kallsyms_vmlinux} .tmp_System.map - - if ! cmp -s System.map .tmp_System.map; then +if is_enabled CONFIG_KALLSYMS; then + if ! cmp -s System.map ${kallsyms_vmlinux}.syms; then echo >&2 Inconsistent kallsyms data echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround exit 1 diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 4edc708baa63..201bccfbc678 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -24,13 +24,18 @@ icc) echo 16.0.3 ;; llvm) - # https://lore.kernel.org/r/YMtib5hKVyNknZt3@osiris/ if [ "$SRCARCH" = s390 ]; then - echo 13.0.0 + echo 15.0.0 else - echo 10.0.1 + echo 11.0.0 fi ;; +rustc) + echo 1.62.0 + ;; +bindgen) + echo 0.56.0 + ;; *) echo "$1: unknown tool" >&2 exit 1 diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index 6a2a04d92f42..2596f78e52ef 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -1,32 +1,10 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -TARGET=$1 -ARCH=$2 -SMP=$3 -PREEMPT=$4 -PREEMPT_RT=$5 -CC_VERSION="$6" -LD=$7 +UTS_MACHINE=$1 +CC_VERSION="$2" +LD=$3 -# Do not expand names -set -f - -# Fix the language to get consistent output -LC_ALL=C -export LC_ALL - -if [ -z "$KBUILD_BUILD_VERSION" ]; then - VERSION=$(cat .version 2>/dev/null || echo 1) -else - VERSION=$KBUILD_BUILD_VERSION -fi - -if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then - TIMESTAMP=`date` -else - TIMESTAMP=$KBUILD_BUILD_TIMESTAMP -fi if test -z "$KBUILD_BUILD_USER"; then LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/') else @@ -38,57 +16,12 @@ else LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST fi -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 - -# Truncate to maximum length -UTS_LEN=64 -UTS_VERSION="$(echo $UTS_VERSION $CONFIG_FLAGS $TIMESTAMP | cut -b -$UTS_LEN)" - -# Generate a temporary compile.h - -{ echo /\* This file is auto generated, version $VERSION \*/ - if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi +LD_VERSION=$(LC_ALL=C $LD -v | head -n1 | + sed -e 's/(compatible with [^)]*)//' -e 's/[[:space:]]*$//') - echo \#define UTS_MACHINE \"$ARCH\" - - echo \#define UTS_VERSION \"$UTS_VERSION\" - - printf '#define LINUX_COMPILE_BY "%s"\n' "$LINUX_COMPILE_BY" - echo \#define LINUX_COMPILE_HOST \"$LINUX_COMPILE_HOST\" - - LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \ - | sed 's/[[:space:]]*$//') - printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION" -} > .tmpcompile - -# Only replace the real compile.h if the new one is different, -# in order to preserve the timestamp and avoid unnecessary -# recompilations. -# We don't consider the file changed if only the date/time changed, -# unless KBUILD_BUILD_TIMESTAMP was explicitly set (e.g. for -# reproducible builds with that value referring to a commit timestamp). -# A kernel config change will increase the generation number, thus -# causing compile.h to be updated (including date/time) due to the -# changed comment in the -# first line. - -if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then - IGNORE_PATTERN="UTS_VERSION" -else - IGNORE_PATTERN="NOT_A_PATTERN_TO_BE_MATCHED" -fi - -if [ -r $TARGET ] && \ - grep -v $IGNORE_PATTERN $TARGET > .tmpver.1 && \ - grep -v $IGNORE_PATTERN .tmpcompile > .tmpver.2 && \ - cmp -s .tmpver.1 .tmpver.2; then - rm -f .tmpcompile -else - echo " UPD $TARGET" - mv -f .tmpcompile $TARGET -fi -rm -f .tmpver.1 .tmpver.2 +cat <<EOF +#define UTS_MACHINE "${UTS_MACHINE}" +#define LINUX_COMPILE_BY "${LINUX_COMPILE_BY}" +#define LINUX_COMPILE_HOST "${LINUX_COMPILE_HOST}" +#define LINUX_COMPILER "${CC_VERSION}, ${LD_VERSION}" +EOF diff --git a/scripts/mksysmap b/scripts/mksysmap index 9aa23d15862a..16a08b8ef2f8 100755 --- a/scripts/mksysmap +++ b/scripts/mksysmap @@ -37,8 +37,24 @@ # readprofile starts reading symbols when _stext is found, and # continue until it finds a symbol which is not either of 'T', 't', -# 'W' or 'w'. __crc_ are 'A' and placed in the middle -# so we just ignore them to let readprofile continue to work. -# (At least sparc64 has __crc_ in the middle). +# 'W' or 'w'. +# +# Ignored prefixes: +# $ - local symbols for ARM, MIPS, etc. +# .L - local labels, .LBB,.Ltmpxxx,.L__unnamed_xx,.LASANPC, etc. +# __crc_ - modversions +# __kstrtab_ - EXPORT_SYMBOL (symbol name) +# __kstrtabns_ - EXPORT_SYMBOL (namespace) +# +# Ignored symbols: +# L0 - for LoongArch? -$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( \.L\)' > $2 +$NM -n $1 | grep -v \ + -e ' [aNUw] ' \ + -e ' \$' \ + -e ' \.L' \ + -e ' __crc_' \ + -e ' __kstrtab_' \ + -e ' __kstrtabns_' \ + -e ' L0$' \ +> $2 diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 5258247d78ac..80d973144fde 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -734,8 +734,6 @@ static int do_vio_entry(const char *filename, void *symval, return 1; } -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static void do_input(char *alias, kernel_ulong_t *arr, unsigned int min, unsigned int max) { @@ -1391,6 +1389,15 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias) return 1; } +/* Looks like: mhi_ep:S */ +static int do_mhi_ep_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD_ADDR(symval, mhi_device_id, chan); + sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan); + + return 1; +} + /* Looks like: ishtp:{guid} */ static int do_ishtp_entry(const char *filename, void *symval, char *alias) { @@ -1519,6 +1526,7 @@ static const struct devtable devtable[] = { {"tee", SIZE_tee_client_device_id, do_tee_entry}, {"wmi", SIZE_wmi_device_id, do_wmi_entry}, {"mhi", SIZE_mhi_device_id, do_mhi_entry}, + {"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry}, {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, {"ssam", SIZE_ssam_device_id, do_ssam_entry}, {"dfl", SIZE_dfl_device_id, do_dfl_entry}, @@ -1563,9 +1571,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, zeros = calloc(1, sym->st_size); symval = zeros; } else { - symval = (void *)info->hdr - + info->sechdrs[get_secindex(info, sym)].sh_offset - + sym->st_value; + symval = sym_get_data(info, sym); } /* First handle the "special" cases */ diff --git a/scripts/mod/list.h b/scripts/mod/list.h new file mode 100644 index 000000000000..a924a6c4aa4d --- /dev/null +++ b/scripts/mod/list.h @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LIST_H +#define LIST_H + +#include <stdbool.h> +#include <stddef.h> + +/* Are two types/vars the same type (ignoring qualifiers)? */ +#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + _Static_assert(__same_type(*(ptr), ((type *)0)->member) || \ + __same_type(*(ptr), void), \ + "pointer type mismatch in container_of()"); \ + ((type *)(__mptr - offsetof(type, member))); }) + +#define LIST_POISON1 ((void *) 0x100) +#define LIST_POISON2 ((void *) 0x122) + +/* + * Circular doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * INIT_LIST_HEAD - Initialize a list_head structure + * @list: list_head structure to be initialized. + * + * Initializes the list_head to point to itself. If it is a list header, + * the result is an empty list. + */ +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del_entry(entry); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_is_head - tests whether @list is the list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * list_entry_is_head - test if the entry points to the head of the list + * @pos: the type * to cursor + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_entry_is_head(pos, head, member) \ + (&pos->member == (head)) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = n, n = list_next_entry(n, member)) + +#endif /* LIST_H */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cb8ab7d91d30..2c80da0220c3 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -13,6 +13,7 @@ #define _GNU_SOURCE #include <elf.h> +#include <fnmatch.h> #include <stdio.h> #include <ctype.h> #include <string.h> @@ -23,20 +24,20 @@ #include "../../include/linux/license.h" /* Are we using CONFIG_MODVERSIONS? */ -static int modversions = 0; +static bool modversions; /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ -static int all_versions = 0; +static bool all_versions; /* If we are modposting external module set to 1 */ -static int external_module = 0; +static bool external_module; /* Only warn about unresolved symbols */ -static int warn_unresolved = 0; -/* How a symbol is exported */ -static int sec_mismatch_count = 0; -static int sec_mismatch_warn_only = true; +static bool warn_unresolved; + +static int sec_mismatch_count; +static bool sec_mismatch_warn_only = true; /* ignore missing files */ -static int ignore_missing_files; +static bool ignore_missing_files; /* If set to 1, only warn (instead of error) about missing ns imports */ -static int allow_missing_ns_imports; +static bool allow_missing_ns_imports; static bool error_occurred; @@ -47,12 +48,6 @@ static bool error_occurred; #define MAX_UNRESOLVED_REPORTS 10 static unsigned int nr_unresolved; -enum export { - export_plain, - export_gpl, - export_unknown -}; - /* In kernel, this size is defined in linux/module.h; * here we use Elf_Addr instead of long for covering cross-compile */ @@ -165,31 +160,43 @@ char *get_line(char **stringp) } /* A list of all modules we processed */ -static struct module *modules; +LIST_HEAD(modules); static struct module *find_module(const char *modname) { struct module *mod; - for (mod = modules; mod; mod = mod->next) + list_for_each_entry(mod, &modules, list) { if (strcmp(mod->name, modname) == 0) - break; - return mod; + return mod; + } + return NULL; } -static struct module *new_module(const char *modname) +static struct module *new_module(const char *name, size_t namelen) { struct module *mod; - mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1)); + mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1)); memset(mod, 0, sizeof(*mod)); - /* add to list */ - strcpy(mod->name, modname); - mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0); - mod->gpl_compatible = -1; - mod->next = modules; - modules = mod; + INIT_LIST_HEAD(&mod->exported_symbols); + INIT_LIST_HEAD(&mod->unresolved_symbols); + INIT_LIST_HEAD(&mod->missing_namespaces); + INIT_LIST_HEAD(&mod->imported_namespaces); + + memcpy(mod->name, name, namelen); + mod->name[namelen] = '\0'; + mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0); + + /* + * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE() + * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue + * modpost will exit wiht error anyway. + */ + mod->is_gpl_compatible = true; + + list_add_tail(&mod->list, &modules); return mod; } @@ -201,13 +208,13 @@ static struct module *new_module(const char *modname) struct symbol { struct symbol *next; + struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */ struct module *module; - unsigned int crc; - int crc_valid; char *namespace; - unsigned int weak:1; - unsigned int is_static:1; /* 1 if symbol is not global */ - enum export export; /* Type of export */ + unsigned int crc; + bool crc_valid; + bool weak; + bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */ char name[]; }; @@ -230,32 +237,37 @@ static inline unsigned int tdb_hash(const char *name) * Allocate a new symbols for use in the hash of exported symbols or * the list of unresolved symbols per module **/ -static struct symbol *alloc_symbol(const char *name, unsigned int weak, - struct symbol *next) +static struct symbol *alloc_symbol(const char *name) { struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); memset(s, 0, sizeof(*s)); strcpy(s->name, name); - s->weak = weak; - s->next = next; - s->is_static = 1; + return s; } /* For the hash of exported symbols */ -static struct symbol *new_symbol(const char *name, struct module *module, - enum export export) +static void hash_add_symbol(struct symbol *sym) { unsigned int hash; - hash = tdb_hash(name) % SYMBOL_HASH_SIZE; - symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); + hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE; + sym->next = symbolhash[hash]; + symbolhash[hash] = sym; +} + +static void sym_add_unresolved(const char *name, struct module *mod, bool weak) +{ + struct symbol *sym; + + sym = alloc_symbol(name); + sym->weak = weak; - return symbolhash[hash]; + list_add_tail(&sym->list, &mod->unresolved_symbols); } -static struct symbol *find_symbol(const char *name) +static struct symbol *sym_find_with_module(const char *name, struct module *mod) { struct symbol *s; @@ -264,67 +276,44 @@ static struct symbol *find_symbol(const char *name) name++; for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { - if (strcmp(s->name, name) == 0) + if (strcmp(s->name, name) == 0 && (!mod || s->module == mod)) return s; } return NULL; } -static bool contains_namespace(struct namespace_list *list, - const char *namespace) +static struct symbol *find_symbol(const char *name) +{ + return sym_find_with_module(name, NULL); +} + +struct namespace_list { + struct list_head list; + char namespace[]; +}; + +static bool contains_namespace(struct list_head *head, const char *namespace) { - for (; list; list = list->next) + struct namespace_list *list; + + list_for_each_entry(list, head, list) { if (!strcmp(list->namespace, namespace)) return true; + } return false; } -static void add_namespace(struct namespace_list **list, const char *namespace) +static void add_namespace(struct list_head *head, const char *namespace) { struct namespace_list *ns_entry; - if (!contains_namespace(*list, namespace)) { - ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) + + if (!contains_namespace(head, namespace)) { + ns_entry = NOFAIL(malloc(sizeof(*ns_entry) + 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; -} export_list[] = { - { .str = "EXPORT_SYMBOL", .export = export_plain }, - { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, - { .str = "(unknown)", .export = export_unknown }, -}; - - -static const char *export_str(enum export ex) -{ - return export_list[ex].str; -} - -static enum export export_no(const char *s) -{ - int i; - - if (!s) - return export_unknown; - for (i = 0; export_list[i].export != export_unknown; i++) { - if (strcmp(export_list[i].str, s) == 0) - return export_list[i].export; + list_add_tail(&ns_entry->list, head); } - return export_unknown; } static void *sym_get_data_by_offset(const struct elf_info *info, @@ -332,13 +321,10 @@ static void *sym_get_data_by_offset(const struct elf_info *info, { Elf_Shdr *sechdr = &info->sechdrs[secindex]; - if (info->hdr->e_type != ET_REL) - offset -= sechdr->sh_addr; - return (void *)info->hdr + sechdr->sh_offset + offset; } -static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) +void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) { return sym_get_data_by_offset(info, get_secindex(info, sym), sym->st_value); @@ -350,42 +336,21 @@ static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr) sechdr->sh_name); } -static const char *sec_name(const struct elf_info *info, int secindex) +static const char *sec_name(const struct elf_info *info, unsigned int secindex) { + /* + * If sym->st_shndx is a special section index, there is no + * corresponding section header. + * Return "" if the index is out of range of info->sechdrs[] array. + */ + if (secindex >= info->num_sections) + return ""; + return sech_name(info, &info->sechdrs[secindex]); } #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) -static enum export export_from_secname(struct elf_info *elf, unsigned int sec) -{ - const char *secname = sec_name(elf, sec); - - if (strstarts(secname, "___ksymtab+")) - return export_plain; - else if (strstarts(secname, "___ksymtab_gpl+")) - return export_gpl; - else - return export_unknown; -} - -static enum export export_from_sec(struct elf_info *elf, unsigned int sec) -{ - if (sec == elf->export_sec) - return export_plain; - else if (sec == elf->export_gpl_sec) - return export_gpl; - else - return export_unknown; -} - -static const char *namespace_from_kstrtabns(const struct elf_info *info, - const Elf_Sym *sym) -{ - const char *value = sym_get_data(info, sym); - return value[0] ? value : NULL; -} - static void sym_update_namespace(const char *symname, const char *namespace) { struct symbol *s = find_symbol(symname); @@ -401,47 +366,33 @@ static void sym_update_namespace(const char *symname, const char *namespace) } free(s->namespace); - s->namespace = - namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL; + s->namespace = namespace[0] ? NOFAIL(strdup(namespace)) : 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) + bool gpl_only) { struct symbol *s = find_symbol(name); - if (!s) { - s = new_symbol(name, mod, export); - } else if (!external_module || s->module->is_vmlinux || - s->module == mod) { - warn("%s: '%s' exported twice. Previous export was in %s%s\n", - mod->name, name, s->module->name, - s->module->is_vmlinux ? "" : ".ko"); - return s; + if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) { + error("%s: '%s' exported twice. Previous export was in %s%s\n", + mod->name, name, s->module->name, + s->module->is_vmlinux ? "" : ".ko"); } + s = alloc_symbol(name); s->module = mod; - s->export = export; + s->is_gpl_only = gpl_only; + list_add_tail(&s->list, &mod->exported_symbols); + hash_add_symbol(s); + return s; } -static void sym_set_crc(const char *name, unsigned int crc) +static void sym_set_crc(struct symbol *sym, unsigned int crc) { - struct symbol *s = find_symbol(name); - - /* - * Ignore stand-alone __crc_*, which might be auto-generated symbols - * such as __*_veneer in ARM ELF. - */ - if (!s) - return; - - s->crc = crc; - s->crc_valid = 1; + sym->crc = crc; + sym->crc_valid = true; } static void *grab_file(const char *filename, size_t *size) @@ -520,6 +471,10 @@ static int parse_elf(struct elf_info *info, const char *filename) sechdrs = (void *)hdr + hdr->e_shoff; info->sechdrs = sechdrs; + /* modpost only works for relocatable objects */ + if (hdr->e_type != ET_REL) + fatal("%s: not relocatable object.", filename); + /* Check if file offset is correct */ if (hdr->e_shoff > info->size) { fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", @@ -576,10 +531,7 @@ static int parse_elf(struct elf_info *info, const char *filename) fatal("%s has NOBITS .modinfo\n", filename); info->modinfo = (void *)hdr + sechdrs[i].sh_offset; info->modinfo_len = sechdrs[i].sh_size; - } else if (strcmp(secname, "__ksymtab") == 0) - info->export_sec = i; - else if (strcmp(secname, "__ksymtab_gpl") == 0) - info->export_gpl_sec = i; + } if (sechdrs[i].sh_type == SHT_SYMTAB) { unsigned int sh_link_idx; @@ -658,48 +610,18 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) strstarts(symname, "_savevr_") || strcmp(symname, ".TOC.") == 0) return 1; + + if (info->hdr->e_machine == EM_S390) + /* Expoline thunks are linked on all kernel modules during final link of .ko */ + if (strstarts(symname, "__s390_indirect_jump_r")) + return 1; /* Do not ignore this symbol */ return 0; } -static void handle_modversion(const struct module *mod, - const struct elf_info *info, - const Elf_Sym *sym, const char *symname) -{ - unsigned int crc; - - if (sym->st_shndx == SHN_UNDEF) { - warn("EXPORT symbol \"%s\" [%s%s] version ...\n" - "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n", - symname, mod->name, mod->is_vmlinux ? "" : ".ko", - symname); - - return; - } - - if (sym->st_shndx == SHN_ABS) { - crc = sym->st_value; - } else { - unsigned int *crcp; - - /* symbol points to the CRC in the ELF object */ - crcp = sym_get_data(info, sym); - crc = TO_NATIVE(*crcp); - } - sym_set_crc(symname, crc); -} - static void handle_symbol(struct module *mod, struct elf_info *info, const Elf_Sym *sym, const char *symname) { - enum export export; - const char *name; - - if (strstarts(symname, "__ksymtab")) - export = export_from_secname(info, get_secindex(info, sym)); - else - export = export_from_sec(info, get_secindex(info, sym)); - switch (sym->st_shndx) { case SHN_COMMON: if (strstarts(symname, "__gnu_lto_")) { @@ -727,20 +649,26 @@ static void handle_symbol(struct module *mod, struct elf_info *info, } } - mod->unres = alloc_symbol(symname, - ELF_ST_BIND(sym->st_info) == STB_WEAK, - mod->unres); + sym_add_unresolved(symname, mod, + ELF_ST_BIND(sym->st_info) == STB_WEAK); break; default: /* All exported symbols */ if (strstarts(symname, "__ksymtab_")) { + const char *name, *secname; + name = symname + strlen("__ksymtab_"); - sym_add_exported(name, mod, export); + secname = sec_name(info, get_secindex(info, sym)); + + if (strstarts(secname, "___ksymtab_gpl+")) + sym_add_exported(name, mod, true); + else if (strstarts(secname, "___ksymtab+")) + sym_add_exported(name, mod, false); } if (strcmp(symname, "init_module") == 0) - mod->has_init = 1; + mod->has_init = true; if (strcmp(symname, "cleanup_module") == 0) - mod->has_cleanup = 1; + mod->has_cleanup = true; break; } } @@ -792,29 +720,6 @@ static char *get_modinfo(struct elf_info *info, const char *tag) return get_next_modinfo(info, tag, NULL); } -/** - * Test if string s ends in string sub - * return 0 if match - **/ -static int strrcmp(const char *s, const char *sub) -{ - int slen, sublen; - - if (!s || !sub) - return 1; - - slen = strlen(s); - sublen = strlen(sub); - - if ((slen == 0) || (sublen == 0)) - return 1; - - if (sublen > slen) - return 1; - - return memcmp(s + slen - sublen, sub, sublen); -} - static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) { if (sym) @@ -823,54 +728,36 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) return "(unknown)"; } -/* The pattern is an array of simple patterns. - * "foo" will match an exact string equal to "foo" - * "*foo" will match a string that ends with "foo" - * "foo*" will match a string that begins with "foo" - * "*foo*" will match a string that contains "foo" +/* + * Check whether the 'string' argument matches one of the 'patterns', + * an array of shell wildcard patterns (glob). + * + * Return true is there is a match. */ -static int match(const char *sym, const char * const pat[]) +static bool match(const char *string, const char *const patterns[]) { - const char *p; - while (*pat) { - p = *pat++; - const char *endp = p + strlen(p) - 1; + const char *pattern; - /* "*foo*" */ - if (*p == '*' && *endp == '*') { - char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2)); - char *here = strstr(sym, bare); - - free(bare); - if (here != NULL) - return 1; - } - /* "*foo" */ - else if (*p == '*') { - if (strrcmp(sym, p + 1) == 0) - return 1; - } - /* "foo*" */ - else if (*endp == '*') { - if (strncmp(sym, p, strlen(p) - 1) == 0) - return 1; - } - /* no wildcards */ - else { - if (strcmp(p, sym) == 0) - return 1; - } + while ((pattern = *patterns++)) { + if (!fnmatch(pattern, string, 0)) + return true; } - /* no match */ - return 0; + + return false; } +/* useful to pass patterns to match() directly */ +#define PATTERNS(...) \ + ({ \ + static const char *const patterns[] = {__VA_ARGS__, NULL}; \ + patterns; \ + }) + /* sections that we do not want to do full section mismatch check on */ static const char *const section_white_list[] = { ".comment*", ".debug*", - ".cranges", /* sh64 */ ".zdebug*", /* Compressed debug sections. */ ".GCC.command.line", /* record-gcc-switches */ ".mdebug*", /* alpha, score, mips etc. */ @@ -958,28 +845,12 @@ static const char *const init_data_sections[] = /* all init sections */ static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; -/* All init and exit sections (code + data) */ -static const char *const init_exit_sections[] = - {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; - /* all text sections */ static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; /* data section */ static const char *const data_sections[] = { DATA_SECTIONS, NULL }; - -/* symbols in .data that may refer to init/exit sections */ -#define DEFAULT_SYMBOL_WHITE_LIST \ - "*driver", \ - "*_template", /* scsi uses *_template a lot */ \ - "*_timer", /* arm uses ops structures named _timer a lot */ \ - "*_sht", /* scsi also used *_sht to some extent */ \ - "*_ops", \ - "*_probe", \ - "*_probe_one", \ - "*_console" - static const char *const head_sections[] = { ".head.text*", NULL }; static const char *const linker_symbols[] = { "__init_begin", "_sinittext", "_einittext", NULL }; @@ -1011,9 +882,6 @@ enum mismatch { * * @mismatch: Type of mismatch. * - * @symbol_white_list: Do not match a relocation to a symbol in this list - * even if it is targeting a section in @bad_to_sec. - * * @handler: Specific handler to call when a match is found. If NULL, * default_mismatch_handler() will be called. * @@ -1023,7 +891,6 @@ struct sectioncheck { const char *bad_tosec[20]; const char *good_tosec[20]; enum mismatch mismatch; - const char *symbol_white_list[20]; void (*handler)(const char *modname, struct elf_info *elf, const struct sectioncheck* const mismatch, Elf_Rela *r, Elf_Sym *sym, const char *fromsec); @@ -1043,75 +910,61 @@ static const struct sectioncheck sectioncheck[] = { .fromsec = { TEXT_SECTIONS, NULL }, .bad_tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = TEXT_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .bad_tosec = { INIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_INIT, - .symbol_white_list = { - "*_template", "*_timer", "*_sht", "*_ops", - "*_probe", "*_probe_one", "*_console", NULL - }, }, { .fromsec = { TEXT_SECTIONS, NULL }, .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = TEXT_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference init code/data from meminit code/data */ { .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .bad_tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_SOME_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference exit code/data from memexit code/data */ { .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .bad_tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_SOME_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = ANY_INIT_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use init code/data from exit code */ { .fromsec = { ALL_EXIT_SECTIONS, NULL }, .bad_tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = ANY_EXIT_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, .bad_tosec = { INIT_SECTIONS, NULL }, .mismatch = ANY_INIT_TO_ANY_EXIT, - .symbol_white_list = { NULL }, }, /* Do not export init/exit functions or data */ { - .fromsec = { "__ksymtab*", NULL }, + .fromsec = { "___ksymtab*", NULL }, .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, .mismatch = EXPORT_TO_INIT_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { "__ex_table", NULL }, @@ -1129,8 +982,6 @@ static const struct sectioncheck *section_mismatch( const char *fromsec, const char *tosec) { int i; - int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); - const struct sectioncheck *check = §ioncheck[0]; /* * The target section could be the SHT_NUL section when we're @@ -1141,14 +992,15 @@ static const struct sectioncheck *section_mismatch( if (*tosec == '\0') return NULL; - for (i = 0; i < elems; i++) { + for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) { + const struct sectioncheck *check = §ioncheck[i]; + if (match(fromsec, check->fromsec)) { if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) return check; if (check->good_tosec[0] && !match(tosec, check->good_tosec)) return check; } - check++; } return NULL; } @@ -1173,15 +1025,6 @@ static const struct sectioncheck *section_mismatch( * fromsec = .data* * atsym = __param_ops_* * - * Pattern 2: - * Many drivers utilise a *driver container with references to - * add, remove, probe functions etc. - * the pattern is identified by: - * tosec = init or exit section - * fromsec = data section - * atsym = *driver, *_template, *_sht, *_ops, *_probe, - * *probe_one, *_console, *_timer - * * Pattern 3: * Whitelist all references from .head.text to any init section * @@ -1230,10 +1073,22 @@ static int secref_whitelist(const struct sectioncheck *mismatch, strstarts(fromsym, "__param_ops_")) return 0; - /* Check for pattern 2 */ - if (match(tosec, init_exit_sections) && - match(fromsec, data_sections) && - match(fromsym, mismatch->symbol_white_list)) + /* symbols in data sections that may refer to any init/exit sections */ + if (match(fromsec, PATTERNS(DATA_SECTIONS)) && + match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) && + match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot + "*_timer", // arm uses ops structures named _timer a lot + "*_sht", // scsi also used *_sht to some extent + "*_ops", + "*_probe", + "*_probe_one", + "*_console"))) + return 0; + + /* symbols in data sections that may refer to meminit/exit sections */ + if (match(fromsec, PATTERNS(DATA_SECTIONS)) && + match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) && + match(fromsym, PATTERNS("*driver"))) return 0; /* Check for pattern 3 */ @@ -1260,7 +1115,8 @@ static int secref_whitelist(const struct sectioncheck *mismatch, static inline int is_arm_mapping_symbol(const char *str) { - return str[0] == '$' && strchr("axtd", str[1]) + return str[0] == '$' && + (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x') && (str[2] == '\0' || str[2] == '.'); } @@ -1350,54 +1206,14 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, continue; if (!is_valid_name(elf, sym)) continue; - if (sym->st_value <= addr) { - if ((addr - sym->st_value) < distance) { - distance = addr - sym->st_value; - near = sym; - } else if ((addr - sym->st_value) == distance) { - near = sym; - } + if (sym->st_value <= addr && addr - sym->st_value <= distance) { + distance = addr - sym->st_value; + near = sym; } } return near; } -/* - * Convert a section name to the function/data attribute - * .init.text => __init - * .memexitconst => __memconst - * etc. - * - * The memory of returned value has been allocated on a heap. The user of this - * method should free it after usage. -*/ -static char *sec2annotation(const char *s) -{ - if (match(s, init_exit_sections)) { - char *p = NOFAIL(malloc(20)); - char *r = p; - - *p++ = '_'; - *p++ = '_'; - if (*s == '.') - s++; - while (*s && *s != '.') - *p++ = *s++; - *p = '\0'; - if (*s == '.') - s++; - if (strstr(s, "rodata") != NULL) - strcat(p, "const "); - else if (strstr(s, "data") != NULL) - strcat(p, "data "); - else - strcat(p, " "); - return r; - } else { - return NOFAIL(strdup("")); - } -} - static int is_function(Elf_Sym *sym) { if (sym) @@ -1406,19 +1222,6 @@ static int is_function(Elf_Sym *sym) return -1; } -static void print_section_list(const char * const list[20]) -{ - const char *const *s = list; - - while (*s) { - fprintf(stderr, "%s", *s); - s++; - if (*s) - fprintf(stderr, ", "); - } - fprintf(stderr, "\n"); -} - static inline void get_pretty_name(int is_func, const char** name, const char** name_p) { switch (is_func) { @@ -1436,141 +1239,31 @@ static inline void get_pretty_name(int is_func, const char** name, const char** static void report_sec_mismatch(const char *modname, const struct sectioncheck *mismatch, const char *fromsec, - unsigned long long fromaddr, const char *fromsym, - int from_is_func, - const char *tosec, const char *tosym, - int to_is_func) + const char *tosec, const char *tosym) { - const char *from, *from_p; - const char *to, *to_p; - char *prl_from; - char *prl_to; - sec_mismatch_count++; - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); - - warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " - "to the %s %s:%s%s\n", - modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, - tosym, to_p); - switch (mismatch->mismatch) { case TEXT_TO_ANY_INIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The function %s%s() references\n" - "the %s %s%s%s.\n" - "This is often because %s lacks a %s\n" - "annotation or the annotation of %s is wrong.\n", - prl_from, fromsym, - to, prl_to, tosym, to_p, - fromsym, prl_to, tosym); - free(prl_from); - free(prl_to); - break; - case DATA_TO_ANY_INIT: { - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The variable %s references\n" - "the %s %s%s%s\n" - "If the reference is valid then annotate the\n" - "variable with __init* or __refdata (see linux/init.h) " - "or name the variable:\n", - fromsym, to, prl_to, tosym, to_p); - print_section_list(mismatch->symbol_white_list); - free(prl_to); - break; - } + case DATA_TO_ANY_INIT: case TEXT_TO_ANY_EXIT: - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The function %s() references a %s in an exit section.\n" - "Often the %s %s%s has valid usage outside the exit section\n" - "and the fix is to remove the %sannotation of %s.\n", - fromsym, to, to, tosym, to_p, prl_to, tosym); - free(prl_to); - break; - case DATA_TO_ANY_EXIT: { - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The variable %s references\n" - "the %s %s%s%s\n" - "If the reference is valid then annotate the\n" - "variable with __exit* (see linux/init.h) or " - "name the variable:\n", - fromsym, to, prl_to, tosym, to_p); - print_section_list(mismatch->symbol_white_list); - free(prl_to); - break; - } + case DATA_TO_ANY_EXIT: case XXXINIT_TO_SOME_INIT: case XXXEXIT_TO_SOME_EXIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "If %s is only used by %s then\n" - "annotate %s with a matching annotation.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - tosym, fromsym, tosym); - free(prl_from); - free(prl_to); - break; case ANY_INIT_TO_ANY_EXIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "This is often seen when error handling " - "in the init function\n" - "uses functionality in the exit path.\n" - "The fix is often to remove the %sannotation of\n" - "%s%s so it may be used outside an exit section.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - prl_to, tosym, to_p); - free(prl_from); - free(prl_to); - break; case ANY_EXIT_TO_ANY_INIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "This is often seen when error handling " - "in the exit function\n" - "uses functionality in the init path.\n" - "The fix is often to remove the %sannotation of\n" - "%s%s so it may be used outside an init section.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - prl_to, tosym, to_p); - free(prl_from); - free(prl_to); + warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n", + modname, fromsym, fromsec, tosym, tosec); break; case EXPORT_TO_INIT_EXIT: - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The symbol %s is exported and annotated %s\n" - "Fix this by removing the %sannotation of %s " - "or drop the export.\n", - tosym, prl_to, prl_to, tosym); - free(prl_to); + warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n", + modname, tosym, tosec); break; case EXTABLE_TO_NON_TEXT: - fatal("There's a special handler for this mismatch type, " - "we should never get here."); + fatal("There's a special handler for this mismatch type, we should never get here.\n"); break; } - fprintf(stderr, "\n"); } static void default_mismatch_handler(const char *modname, struct elf_info *elf, @@ -1586,9 +1279,6 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, from = find_elf_symbol2(elf, r->r_offset, fromsec); fromsym = sym_name(elf, from); - if (strstarts(fromsym, "reference___initcall")) - return; - tosec = sec_name(elf, get_secindex(elf, sym)); to = find_elf_symbol(elf, r->r_addend, sym); tosym = sym_name(elf, to); @@ -1597,9 +1287,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, if (secref_whitelist(mismatch, fromsec, fromsym, tosec, tosym)) { report_sec_mismatch(modname, mismatch, - fromsec, r->r_offset, fromsym, - is_function(from), tosec, tosym, - is_function(to)); + fromsec, fromsym, tosec, tosym); } } @@ -1755,9 +1443,6 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) break; case R_386_PC32: r->r_addend = TO_NATIVE(*location) + 4; - /* For CONFIG_RELOCATABLE=y */ - if (elf->hdr->e_type == ET_EXEC) - r->r_addend += r->r_offset; break; } return 0; @@ -1830,6 +1515,14 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) return 0; } +#ifndef EM_RISCV +#define EM_RISCV 243 +#endif + +#ifndef R_RISCV_SUB32 +#define R_RISCV_SUB32 39 +#endif + static void section_rela(const char *modname, struct elf_info *elf, Elf_Shdr *sechdr) { @@ -1842,8 +1535,7 @@ static void section_rela(const char *modname, struct elf_info *elf, Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; Elf_Rela *stop = (void *)start + sechdr->sh_size; - fromsec = sech_name(elf, sechdr); - fromsec += strlen(".rela"); + fromsec = sec_name(elf, sechdr->sh_info); /* if from section (name) is know good then skip it */ if (match(fromsec, section_white_list)) return; @@ -1866,6 +1558,13 @@ static void section_rela(const char *modname, struct elf_info *elf, r_sym = ELF_R_SYM(r.r_info); #endif r.r_addend = TO_NATIVE(rela->r_addend); + switch (elf->hdr->e_machine) { + case EM_RISCV: + if (!strcmp("__ex_table", fromsec) && + ELF_R_TYPE(r.r_info) == R_RISCV_SUB32) + continue; + break; + } sym = elf->symtab_start + r_sym; /* Skip special sections */ if (is_shndx_special(sym->st_shndx)) @@ -1888,8 +1587,7 @@ static void section_rel(const char *modname, struct elf_info *elf, Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; Elf_Rel *stop = (void *)start + sechdr->sh_size; - fromsec = sech_name(elf, sechdr); - fromsec += strlen(".rel"); + fromsec = sec_name(elf, sechdr->sh_info); /* if from section (name) is know good then skip it */ if (match(fromsec, section_white_list)) return; @@ -1948,8 +1646,7 @@ static void section_rel(const char *modname, struct elf_info *elf, * to find all references to a section that reference a section that will * be discarded and warns about it. **/ -static void check_sec_ref(struct module *mod, const char *modname, - struct elf_info *elf) +static void check_sec_ref(const char *modname, struct elf_info *elf) { int i; Elf_Shdr *sechdrs = elf->sechdrs; @@ -1971,16 +1668,110 @@ static char *remove_dot(char *s) if (n && s[n]) { size_t m = strspn(s + n + 1, "0123456789"); - if (m && (s[n + m] == '.' || s[n + m] == 0)) + if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0)) s[n] = 0; - - /* strip trailing .lto */ - if (strends(s, ".lto")) - s[strlen(s) - 4] = '\0'; } return s; } +/* + * The CRCs are recorded in .*.cmd files in the form of: + * #SYMVER <name> <crc> + */ +static void extract_crcs_for_object(const char *object, struct module *mod) +{ + char cmd_file[PATH_MAX]; + char *buf, *p; + const char *base; + int dirlen, ret; + + base = strrchr(object, '/'); + if (base) { + base++; + dirlen = base - object; + } else { + dirlen = 0; + base = object; + } + + ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd", + dirlen, object, base); + if (ret >= sizeof(cmd_file)) { + error("%s: too long path was truncated\n", cmd_file); + return; + } + + buf = read_text_file(cmd_file); + p = buf; + + while ((p = strstr(p, "\n#SYMVER "))) { + char *name; + size_t namelen; + unsigned int crc; + struct symbol *sym; + + name = p + strlen("\n#SYMVER "); + + p = strchr(name, ' '); + if (!p) + break; + + namelen = p - name; + p++; + + if (!isdigit(*p)) + continue; /* skip this line */ + + crc = strtol(p, &p, 0); + if (*p != '\n') + continue; /* skip this line */ + + name[namelen] = '\0'; + + /* + * sym_find_with_module() may return NULL here. + * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y. + * Since commit e1327a127703, genksyms calculates CRCs of all + * symbols, including trimmed ones. Ignore orphan CRCs. + */ + sym = sym_find_with_module(name, mod); + if (sym) + sym_set_crc(sym, crc); + } + + free(buf); +} + +/* + * The symbol versions (CRC) are recorded in the .*.cmd files. + * Parse them to retrieve CRCs for the current module. + */ +static void mod_set_crcs(struct module *mod) +{ + char objlist[PATH_MAX]; + char *buf, *p, *obj; + int ret; + + if (mod->is_vmlinux) { + strcpy(objlist, ".vmlinux.objs"); + } else { + /* objects for a module are listed in the *.mod file. */ + ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name); + if (ret >= sizeof(objlist)) { + error("%s: too long path was truncated\n", objlist); + return; + } + } + + buf = read_text_file(objlist); + p = buf; + + while ((obj = strsep(&p, "\n")) && obj[0]) + extract_crcs_for_object(obj, mod); + + free(buf); +} + static void read_symbols(const char *modname) { const char *symname; @@ -1994,28 +1785,21 @@ static void read_symbols(const char *modname) if (!parse_elf(&info, modname)) return; - { - char *tmp; - - /* strip trailing .o */ - tmp = NOFAIL(strdup(modname)); - tmp[strlen(tmp) - 2] = '\0'; - /* strip trailing .lto */ - if (strends(tmp, ".lto")) - tmp[strlen(tmp) - 4] = '\0'; - mod = new_module(tmp); - free(tmp); + if (!strends(modname, ".o")) { + error("%s: filename must be suffixed with .o\n", modname); + return; } + /* strip trailing .o */ + mod = new_module(modname, strlen(modname) - strlen(".o")); + if (!mod->is_vmlinux) { license = get_modinfo(&info, "license"); if (!license) error("missing MODULE_LICENSE() in %s\n", modname); while (license) { - if (license_is_gpl_compatible(license)) - mod->gpl_compatible = 1; - else { - mod->gpl_compatible = 0; + if (!license_is_gpl_compatible(license)) { + mod->is_gpl_compatible = false; break; } license = get_next_modinfo(&info, "license", license); @@ -2042,29 +1826,10 @@ static void read_symbols(const char *modname) /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */ if (strstarts(symname, "__kstrtabns_")) sym_update_namespace(symname + strlen("__kstrtabns_"), - namespace_from_kstrtabns(&info, - sym)); - - if (strstarts(symname, "__crc_")) - handle_modversion(mod, &info, sym, - symname + strlen("__crc_")); - } - - // 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; - } + sym_get_data(&info, sym)); } - check_sec_ref(mod, modname, &info); + check_sec_ref(modname, &info); if (!mod->is_vmlinux) { version = get_modinfo(&info, "version"); @@ -2075,12 +1840,17 @@ static void read_symbols(const char *modname) parse_elf_finish(&info); - /* Our trick to get versioning for module struct etc. - it's - * never passed as an argument to an exported function, so - * the automatic versioning doesn't pick it up, but it's really - * important anyhow */ - if (modversions) - mod->unres = alloc_symbol("module_layout", 0, mod->unres); + if (modversions) { + /* + * Our trick to get versioning for module struct etc. - it's + * never passed as an argument to an exported function, so + * the automatic versioning doesn't pick it up, but it's really + * important anyhow. + */ + sym_add_unresolved("module_layout", mod, false); + + mod_set_crcs(mod); + } } static void read_symbols_from_files(const char *filename) @@ -2133,34 +1903,30 @@ void buf_write(struct buffer *buf, const char *s, int len) buf->pos += len; } -static void check_for_gpl_usage(enum export exp, const char *m, const char *s) -{ - switch (exp) { - case export_gpl: - error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", - m, s); - break; - case export_plain: - case export_unknown: - /* ignore */ - break; - } -} - static void check_exports(struct module *mod) { struct symbol *s, *exp; - for (s = mod->unres; s; s = s->next) { + list_for_each_entry(s, &mod->unresolved_symbols, list) { const char *basename; exp = find_symbol(s->name); - if (!exp || exp->module == mod) { + if (!exp) { if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS) modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, "\"%s\" [%s.ko] undefined!\n", s->name, mod->name); continue; } + if (exp->module == mod) { + error("\"%s\" [%s.ko] was exported without definition\n", + s->name, mod->name); + continue; + } + + s->module = exp->module; + s->crc_valid = exp->crc_valid; + s->crc = exp->crc; + basename = strrchr(mod->name, '/'); if (basename) basename++; @@ -2168,15 +1934,16 @@ static void check_exports(struct module *mod) basename = mod->name; if (exp->namespace && - !module_imports_namespace(mod, exp->namespace)) { + !contains_namespace(&mod->imported_namespaces, exp->namespace)) { modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR, "module %s uses symbol %s from namespace %s, but does not import it.\n", basename, exp->name, exp->namespace); add_namespace(&mod->missing_namespaces, exp->namespace); } - if (!mod->gpl_compatible) - check_for_gpl_usage(exp->export, basename, exp->name); + if (!mod->is_gpl_compatible && exp->is_gpl_only) + error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n", + basename, exp->name); } } @@ -2206,6 +1973,7 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "#define INCLUDE_VERMAGIC\n"); buf_printf(b, "#include <linux/build-salt.h>\n"); buf_printf(b, "#include <linux/elfnote-lto.h>\n"); + buf_printf(b, "#include <linux/export-internal.h>\n"); buf_printf(b, "#include <linux/vermagic.h>\n"); buf_printf(b, "#include <linux/compiler.h>\n"); buf_printf(b, "\n"); @@ -2226,26 +1994,42 @@ static void add_header(struct buffer *b, struct module *mod) "#endif\n"); buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); -} -static void add_intree_flag(struct buffer *b, int is_intree) -{ - if (is_intree) + if (!external_module) buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); -} -/* Cannot check for assembler */ -static void add_retpoline(struct buffer *b) -{ - buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n"); - buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n"); - buf_printf(b, "#endif\n"); + buf_printf(b, + "\n" + "#ifdef CONFIG_RETPOLINE\n" + "MODULE_INFO(retpoline, \"Y\");\n" + "#endif\n"); + + if (strstarts(mod->name, "drivers/staging")) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); + + if (strstarts(mod->name, "tools/testing")) + buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); } -static void add_staging_flag(struct buffer *b, const char *name) +static void add_exported_symbols(struct buffer *buf, struct module *mod) { - if (strstarts(name, "drivers/staging")) - buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); + struct symbol *sym; + + if (!modversions) + return; + + /* record CRCs for exported symbols */ + buf_printf(buf, "\n"); + list_for_each_entry(sym, &mod->exported_symbols, list) { + if (!sym->crc_valid) + warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n" + "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n", + sym->name, mod->name, mod->is_vmlinux ? "" : ".ko", + sym->name); + + buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n", + sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : ""); + } } /** @@ -2253,16 +2037,7 @@ static void add_staging_flag(struct buffer *b, const char *name) **/ static void add_versions(struct buffer *b, struct module *mod) { - struct symbol *s, *exp; - - for (s = mod->unres; s; s = s->next) { - exp = find_symbol(s->name); - if (!exp || exp->module == mod) - continue; - s->module = exp->module; - s->crc_valid = exp->crc_valid; - s->crc = exp->crc; - } + struct symbol *s; if (!modversions) return; @@ -2271,7 +2046,7 @@ static void add_versions(struct buffer *b, struct module *mod) buf_printf(b, "static const struct modversion_info ____versions[]\n"); buf_printf(b, "__used __section(\"__versions\") = {\n"); - for (s = mod->unres; s; s = s->next) { + list_for_each_entry(s, &mod->unresolved_symbols, list) { if (!s->module) continue; if (!s->crc_valid) { @@ -2297,13 +2072,14 @@ static void add_depends(struct buffer *b, struct module *mod) int first = 1; /* Clear ->seen flag of modules that own symbols needed by this. */ - for (s = mod->unres; s; s = s->next) + list_for_each_entry(s, &mod->unresolved_symbols, list) { if (s->module) s->module->seen = s->module->is_vmlinux; + } buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(depends, \""); - for (s = mod->unres; s; s = s->next) { + list_for_each_entry(s, &mod->unresolved_symbols, list) { const char *p; if (!s->module) continue; @@ -2311,7 +2087,7 @@ static void add_depends(struct buffer *b, struct module *mod) if (s->module->seen) continue; - s->module->seen = 1; + s->module->seen = true; p = strrchr(s->module->name, '/'); if (p) p++; @@ -2336,6 +2112,9 @@ static void write_buf(struct buffer *b, const char *fname) { FILE *file; + if (error_occurred) + return; + file = fopen(fname, "w"); if (!file) { perror(fname); @@ -2386,6 +2165,47 @@ static void write_if_changed(struct buffer *b, const char *fname) write_buf(b, fname); } +static void write_vmlinux_export_c_file(struct module *mod) +{ + struct buffer buf = { }; + + buf_printf(&buf, + "#include <linux/export-internal.h>\n"); + + add_exported_symbols(&buf, mod); + write_if_changed(&buf, ".vmlinux.export.c"); + free(buf.p); +} + +/* do sanity checks, and generate *.mod.c file */ +static void write_mod_c_file(struct module *mod) +{ + struct buffer buf = { }; + char fname[PATH_MAX]; + int ret; + + check_modname_len(mod); + check_exports(mod); + + add_header(&buf, mod); + add_exported_symbols(&buf, mod); + add_versions(&buf, mod); + add_depends(&buf, mod); + add_moddevtable(&buf, mod); + add_srcversion(&buf, mod); + + ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); + if (ret >= sizeof(fname)) { + error("%s: too long path was truncated\n", fname); + goto free; + } + + write_if_changed(&buf, fname); + +free: + free(buf.p); +} + /* parse Module.symvers file. line format: * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace **/ @@ -2405,6 +2225,7 @@ static void read_dump(const char *fname) unsigned int crc; struct module *mod; struct symbol *s; + bool gpl_only; if (!(symname = strchr(line, '\t'))) goto fail; @@ -2422,14 +2243,23 @@ static void read_dump(const char *fname) crc = strtoul(line, &d, 16); if (*symname == '\0' || *modname == '\0' || *d != '\0') goto fail; + + if (!strcmp(export, "EXPORT_SYMBOL_GPL")) { + gpl_only = true; + } else if (!strcmp(export, "EXPORT_SYMBOL")) { + gpl_only = false; + } else { + error("%s: unknown license %s. skip", symname, export); + continue; + } + mod = find_module(modname); if (!mod) { - mod = new_module(modname); - mod->from_dump = 1; + mod = new_module(modname, strlen(modname)); + mod->from_dump = true; } - s = sym_add_exported(symname, mod, export_no(export)); - s->is_static = 0; - sym_set_crc(symname, crc); + s = sym_add_exported(symname, mod, gpl_only); + sym_set_crc(s, crc); sym_update_namespace(symname, namespace); } free(buf); @@ -2442,22 +2272,17 @@ fail: 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 (!symbol->module->from_dump) { - namespace = symbol->namespace; - buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n", - symbol->crc, symbol->name, - symbol->module->name, - export_str(symbol->export), - namespace ? namespace : ""); - } - symbol = symbol->next; + struct module *mod; + struct symbol *sym; + + list_for_each_entry(mod, &modules, list) { + if (mod->from_dump) + continue; + list_for_each_entry(sym, &mod->exported_symbols, list) { + buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n", + sym->crc, sym->name, mod->name, + sym->is_gpl_only ? "_GPL" : "", + sym->namespace ?: ""); } } write_buf(&buf, fname); @@ -2470,14 +2295,14 @@ static void write_namespace_deps_files(const char *fname) struct namespace_list *ns; struct buffer ns_deps_buf = {}; - for (mod = modules; mod; mod = mod->next) { + list_for_each_entry(mod, &modules, list) { - if (mod->from_dump || !mod->missing_namespaces) + if (mod->from_dump || list_empty(&mod->missing_namespaces)) continue; buf_printf(&ns_deps_buf, "%s.ko:", mod->name); - for (ns = mod->missing_namespaces; ns; ns = ns->next) + list_for_each_entry(ns, &mod->missing_namespaces, list) buf_printf(&ns_deps_buf, " %s", ns->namespace); buf_printf(&ns_deps_buf, "\n"); @@ -2488,55 +2313,52 @@ static void write_namespace_deps_files(const char *fname) } struct dump_list { - struct dump_list *next; + struct list_head list; const char *file; }; int main(int argc, char **argv) { struct module *mod; - struct buffer buf = { }; char *missing_namespace_deps = NULL; char *dump_write = NULL, *files_source = NULL; int opt; - int n; - struct dump_list *dump_read_start = NULL; - struct dump_list **dump_read_iter = &dump_read_start; + LIST_HEAD(dump_lists); + struct dump_list *dl, *dl2; while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { switch (opt) { case 'e': - external_module = 1; + external_module = true; break; case 'i': - *dump_read_iter = - NOFAIL(calloc(1, sizeof(**dump_read_iter))); - (*dump_read_iter)->file = optarg; - dump_read_iter = &(*dump_read_iter)->next; + dl = NOFAIL(malloc(sizeof(*dl))); + dl->file = optarg; + list_add_tail(&dl->list, &dump_lists); break; case 'm': - modversions = 1; + modversions = true; break; case 'n': - ignore_missing_files = 1; + ignore_missing_files = true; break; case 'o': dump_write = optarg; break; case 'a': - all_versions = 1; + all_versions = true; break; case 'T': files_source = optarg; break; case 'w': - warn_unresolved = 1; + warn_unresolved = true; break; case 'E': sec_mismatch_warn_only = false; break; case 'N': - allow_missing_ns_imports = 1; + allow_missing_ns_imports = true; break; case 'd': missing_namespace_deps = optarg; @@ -2546,13 +2368,10 @@ int main(int argc, char **argv) } } - while (dump_read_start) { - struct dump_list *tmp; - - read_dump(dump_read_start->file); - tmp = dump_read_start->next; - free(dump_read_start); - dump_read_start = tmp; + list_for_each_entry_safe(dl, dl2, &dump_lists, list) { + read_dump(dl->file); + list_del(&dl->list); + free(dl); } while (optind < argc) @@ -2561,28 +2380,14 @@ int main(int argc, char **argv) if (files_source) read_symbols_from_files(files_source); - for (mod = modules; mod; mod = mod->next) { - char fname[PATH_MAX]; - - if (mod->is_vmlinux || mod->from_dump) + list_for_each_entry(mod, &modules, list) { + if (mod->from_dump) continue; - buf.pos = 0; - - check_modname_len(mod); - check_exports(mod); - - add_header(&buf, mod); - add_intree_flag(&buf, !external_module); - add_retpoline(&buf); - add_staging_flag(&buf, mod->name); - add_versions(&buf, mod); - add_depends(&buf, mod); - add_moddevtable(&buf, mod); - add_srcversion(&buf, mod); - - sprintf(fname, "%s.mod.c", mod->name); - write_if_changed(&buf, fname); + if (mod->is_vmlinux) + write_vmlinux_export_c_file(mod); + else + write_mod_c_file(mod); } if (missing_namespace_deps) @@ -2593,22 +2398,10 @@ int main(int argc, char **argv) if (sec_mismatch_count && !sec_mismatch_warn_only) error("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; - - for (s = symbolhash[n]; s; s = s->next) { - if (s->is_static) - error("\"%s\" [%s] is a static %s\n", - s->name, s->module->name, - export_str(s->export)); - } - } if (nr_unresolved > MAX_UNRESOLVED_REPORTS) warn("suppressed %u unresolved symbol warnings because there were too many)\n", nr_unresolved - MAX_UNRESOLVED_REPORTS); - free(buf.p); - return error_occurred ? 1 : 0; } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0c47ff95c0e2..1178f40a73f3 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -10,6 +11,7 @@ #include <unistd.h> #include <elf.h> +#include "list.h" #include "elfconfig.h" /* On BSD-alike OSes elf.h defines these according to host's word size */ @@ -24,7 +26,6 @@ #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Addr Elf32_Addr -#define Elf_Sword Elf64_Sword #define Elf_Section Elf32_Half #define ELF_ST_BIND ELF32_ST_BIND #define ELF_ST_TYPE ELF32_ST_TYPE @@ -39,7 +40,6 @@ #define Elf_Shdr Elf64_Shdr #define Elf_Sym Elf64_Sym #define Elf_Addr Elf64_Addr -#define Elf_Sword Elf64_Sxword #define Elf_Section Elf64_Half #define ELF_ST_BIND ELF64_ST_BIND #define ELF_ST_TYPE ELF64_ST_TYPE @@ -95,6 +95,9 @@ static inline void __endian(const void *src, void *dest, unsigned int size) #endif #define NOFAIL(ptr) do_nofail((ptr), #ptr) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + void *do_nofail(void *ptr, const char *expr); struct buffer { @@ -109,26 +112,22 @@ 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[]; -}; - struct module { - struct module *next; - int gpl_compatible; - struct symbol *unres; - int from_dump; /* 1 if module was loaded from *.symvers */ - int is_vmlinux; - int seen; - int has_init; - int has_cleanup; + struct list_head list; + struct list_head exported_symbols; + struct list_head unresolved_symbols; + bool is_gpl_compatible; + bool from_dump; /* true if module was loaded from *.symvers */ + bool is_vmlinux; + bool seen; + bool has_init; + bool has_cleanup; struct buffer dev_table_buf; char srcversion[25]; // Missing namespace dependencies - struct namespace_list *missing_namespaces; + struct list_head missing_namespaces; // Actual imported namespaces - struct namespace_list *imported_namespaces; + struct list_head imported_namespaces; char name[]; }; @@ -138,8 +137,6 @@ struct elf_info { Elf_Shdr *sechdrs; Elf_Sym *symtab_start; Elf_Sym *symtab_stop; - Elf_Section export_sec; - Elf_Section export_gpl_sec; char *strtab; char *modinfo; unsigned int modinfo_len; @@ -159,26 +156,31 @@ static inline int is_shndx_special(unsigned int i) return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; } -/* - * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of - * the way to -256..-1, to avoid conflicting with real section - * indices. - */ -#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) - /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ static inline unsigned int get_secindex(const struct elf_info *info, const Elf_Sym *sym) { - if (is_shndx_special(sym->st_shndx)) - return SPECIAL(sym->st_shndx); - if (sym->st_shndx != SHN_XINDEX) - return sym->st_shndx; - return info->symtab_shndx_start[sym - info->symtab_start]; + unsigned int index = sym->st_shndx; + + /* + * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available + * in the .symtab_shndx section. + */ + if (index == SHN_XINDEX) + return info->symtab_shndx_start[sym - info->symtab_start]; + + /* + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of + * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real + * section indices. + */ + if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE) + return index - SHN_HIRESERVE - 1; + + return index; } /* file2alias.c */ -extern unsigned int cross_build; void handle_moddevtable(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname); void add_moddevtable(struct buffer *buf, struct module *mod); @@ -189,6 +191,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen); /* from modpost.c */ char *read_text_file(const char *filename); char *get_line(char **stringp); +void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); enum loglevel { LOG_WARN, diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 905c0ec291e1..6bf9caca0968 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -290,13 +290,11 @@ static int parse_file(const char *fname, struct md4_ctx *md) return 1; } /* Check whether the file is a static library or not */ -static int is_static_library(const char *objfile) +static bool is_static_library(const char *objfile) { int len = strlen(objfile); - if (objfile[len - 2] == '.' && objfile[len - 1] == 'a') - return 1; - else - return 0; + + return objfile[len - 2] == '.' && objfile[len - 1] == 'a'; } /* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line @@ -387,7 +385,7 @@ out_file: /* Calc and record src checksum. */ void get_src_version(const char *modname, char sum[], unsigned sumlen) { - char *buf, *pos, *firstline; + char *buf; struct md4_ctx md; char *fname; char filelist[PATH_MAX + 1]; @@ -397,15 +395,8 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen) buf = read_text_file(filelist); - pos = buf; - firstline = get_line(&pos); - if (!firstline) { - warn("bad ending versions file for %s\n", modname); - goto free; - } - md4_init(&md); - while ((fname = strsep(&firstline, " "))) { + while ((fname = strsep(&buf, "\n"))) { if (!*fname) continue; if (!(is_static_library(fname)) && diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 1d0e1e4dc3d2..da4bddd26171 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -3,20 +3,10 @@ * Archs are free to supply their own linker scripts. ld will * combine them automatically. */ -#ifdef CONFIG_CFI_CLANG -# include <asm/page.h> -# define ALIGN_CFI ALIGN(PAGE_SIZE) -# define SANITIZER_DISCARDS *(.eh_frame) -#else -# define ALIGN_CFI -# define SANITIZER_DISCARDS -#endif - SECTIONS { /DISCARD/ : { *(.discard) *(.discard.*) - SANITIZER_DISCARDS } __ksymtab 0 : { *(SORT(___ksymtab+*)) } @@ -27,10 +17,16 @@ SECTIONS { .ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) } .init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) } + .altinstructions 0 : ALIGN(8) { KEEP(*(.altinstructions)) } + __bug_table 0 : ALIGN(8) { KEEP(*(__bug_table)) } __jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) } __patchable_function_entries : { *(__patchable_function_entries) } +#ifdef CONFIG_ARCH_USES_CFI_TRAPS + __kcfi_traps : { KEEP(*(.kcfi_traps)) } +#endif + #ifdef CONFIG_LTO_CLANG /* * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and @@ -51,15 +47,6 @@ SECTIONS { *(.rodata .rodata.[0-9a-zA-Z_]*) *(.rodata..L*) } - - /* - * With CONFIG_CFI_CLANG, we assume __cfi_check is at the beginning - * of the .text section, and is aligned to PAGE_SIZE. - */ - .text : ALIGN_CFI { - *(.text.__cfi_check) - *(.text .text.[0-9a-zA-Z_]* .text..L.cfi*) - } #endif } diff --git a/scripts/nsdeps b/scripts/nsdeps index 04c4b96e95ec..f1718cc0d700 100644 --- a/scripts/nsdeps +++ b/scripts/nsdeps @@ -34,9 +34,8 @@ generate_deps() { local mod=${1%.ko:} shift local namespaces="$*" - local mod_source_files="`cat $mod.mod | sed -n 1p \ - | sed -e 's/\.o/\.c/g' \ - | sed "s|[^ ]* *|${src_prefix}&|g"`" + local mod_source_files=$(sed "s|^\(.*\)\.o$|${src_prefix}\1.c|" $mod.mod) + for ns in $namespaces; do echo "Adding namespace $ns to module $mod.ko." generate_deps_for_ns $ns "$mod_source_files" diff --git a/scripts/objdiff b/scripts/objdiff index 72b0b63c3fe1..0685bc3ce3df 100755 --- a/scripts/objdiff +++ b/scripts/objdiff @@ -20,10 +20,10 @@ # $ ./scripts/objdiff diff COMMIT_A COMMIT_B # $ -# And to clean up (everything is in .tmp_objdiff/*) +# And to clean up (everything is in .objdiff/*) # $ ./scripts/objdiff clean all # -# Note: 'make mrproper' will also remove .tmp_objdiff +# Note: 'make mrproper' will also remove .objdiff SRCTREE=$(cd $(git rev-parse --show-toplevel 2>/dev/null); pwd) @@ -32,7 +32,7 @@ if [ -z "$SRCTREE" ]; then exit 1 fi -TMPD=$SRCTREE/.tmp_objdiff +TMPD=$SRCTREE/.objdiff usage() { echo >&2 "Usage: $0 <command> <args>" diff --git a/scripts/objdump-func b/scripts/objdump-func new file mode 100755 index 000000000000..4eb463dd9f52 --- /dev/null +++ b/scripts/objdump-func @@ -0,0 +1,29 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Disassemble a single function. +# +# usage: objdump-func <file> <func> + +set -o errexit +set -o nounset + +OBJDUMP="${CROSS_COMPILE:-}objdump" + +command -v gawk >/dev/null 2>&1 || die "gawk isn't installed" + +usage() { + echo "usage: objdump-func <file> <func>" >&2 + exit 1 +} + +[[ $# -lt 2 ]] && usage + +OBJ=$1; shift +FUNC=$1; shift + +# Secret feature to allow adding extra objdump args at the end +EXTRA_ARGS=$@ + +# Note this also matches compiler-added suffixes like ".cold", etc +${OBJDUMP} -wdr $EXTRA_ARGS $OBJ | gawk -M -v f=$FUNC '/^$/ { P=0; } $0 ~ "<" f "(\\..*)?>:" { P=1; O=strtonum("0x" $1); } { if (P) { o=strtonum("0x" $1); printf("%04x ", o-O); print $0; } }' diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 91a502bb97e8..67cd420dcf89 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -67,7 +67,7 @@ deploy_kernel_headers () { ) > debian/hdrsrcfiles { - if is_enabled CONFIG_STACK_VALIDATION; then + if is_enabled CONFIG_OBJTOOL; then echo tools/objtool/objtool fi diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 7c477ca7dc98..70392fd2fd29 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -49,6 +49,9 @@ sed -e '/^DEL/d' -e 's/^\t*//' <<EOF URL: https://www.kernel.org $S Source: kernel-$__KERNELRELEASE.tar.gz Provides: $PROVIDES + # $UTS_MACHINE as a fallback of _arch in case + # /usr/lib/rpm/platform/*/macros was not included. + %define _arch %{?_arch:$UTS_MACHINE} %define __spec_install_post /usr/lib/rpm/brp-compress || : %define debug_package %{nil} @@ -85,17 +88,15 @@ $S mkdir -p %{buildroot}/boot %ifarch ia64 mkdir -p %{buildroot}/boot/efi - cp \$($MAKE image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE + cp \$($MAKE -s image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE ln -s efi/vmlinuz-$KERNELRELEASE %{buildroot}/boot/ %else - cp \$($MAKE image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE + cp \$($MAKE -s image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE %endif $M $MAKE %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} modules_install $MAKE %{?_smp_mflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install cp System.map %{buildroot}/boot/System.map-$KERNELRELEASE cp .config %{buildroot}/boot/config-$KERNELRELEASE - bzip2 -9 --keep vmlinux - mv vmlinux.bz2 %{buildroot}/boot/vmlinux-$KERNELRELEASE.bz2 $S$M rm -f %{buildroot}/lib/modules/$KERNELRELEASE/build $S$M rm -f %{buildroot}/lib/modules/$KERNELRELEASE/source $S$M mkdir -p %{buildroot}/usr/src/kernels/$KERNELRELEASE diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh index e6093adf4c06..0d99ef17e4a5 100755 --- a/scripts/pahole-flags.sh +++ b/scripts/pahole-flags.sh @@ -7,7 +7,7 @@ if ! [ -x "$(command -v ${PAHOLE})" ]; then exit 0 fi -pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/') +pahole_ver=$($(dirname $0)/pahole-version.sh ${PAHOLE}) if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars @@ -16,5 +16,8 @@ fi if [ "${pahole_ver}" -ge "121" ]; then extra_paholeopt="${extra_paholeopt} --btf_gen_floats" fi +if [ "${pahole_ver}" -ge "122" ]; then + extra_paholeopt="${extra_paholeopt} -j" +fi echo ${extra_paholeopt} diff --git a/scripts/pahole-version.sh b/scripts/pahole-version.sh new file mode 100755 index 000000000000..f8a32ab93ad1 --- /dev/null +++ b/scripts/pahole-version.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Usage: $ ./pahole-version.sh pahole +# +# Prints pahole's version in a 3-digit form, such as 119 for v1.19. + +if [ ! -x "$(command -v "$@")" ]; then + echo 0 + exit 1 +fi + +"$@" --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/' diff --git a/scripts/prune-kernel b/scripts/prune-kernel index e8aa940bc0a9..dadfd0e47f89 100755 --- a/scripts/prune-kernel +++ b/scripts/prune-kernel @@ -16,6 +16,10 @@ do rm -f "/boot/initramfs-$f.img" "/boot/System.map-$f" rm -f "/boot/vmlinuz-$f" "/boot/config-$f" rm -rf "/lib/modules/$f" - new-kernel-pkg --remove $f + if [ -x "$(command -v new-kernel-pkg)" ]; then + new-kernel-pkg --remove $f + elif [ -x "$(command -v kernel-install)" ]; then + kernel-install remove $f + fi fi done diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 3ccb2c70add4..6a4645a57976 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -362,9 +362,6 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_?mcount\$"; $type = ".quad"; $alignment = 2; -} elsif ($arch eq "nds32") { - $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$"; - $alignment = 2; } elsif ($arch eq "csky") { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_CKCORE_PCREL_JSR_IMM26BY2\\s+_mcount\$"; $alignment = 2; diff --git a/scripts/remove-stale-files b/scripts/remove-stale-files index 80430b8fb617..ccadfa3afb2b 100755 --- a/scripts/remove-stale-files +++ b/scripts/remove-stale-files @@ -20,6 +20,8 @@ set -e # yard. Stale files stay in this file for a while (for some release cycles?), # then will be really dead and removed from the code base entirely. +rm -f arch/powerpc/purgatory/kexec-purgatory.c + # These were previously generated source files. When you are building the kernel # with O=, make sure to remove the stale files in the output tree. Otherwise, # the build system wrongly compiles the stale ones. @@ -39,3 +41,9 @@ if [ -n "${building_out_of_srctree}" ]; then rm -f arch/parisc/boot/compressed/${f} done fi + +rm -f arch/riscv/purgatory/kexec-purgatory.c + +rm -f scripts/extract-cert + +rm -f arch/x86/purgatory/kexec-purgatory.c diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh new file mode 100755 index 000000000000..aebbf1913970 --- /dev/null +++ b/scripts/rust_is_available.sh @@ -0,0 +1,160 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Tests whether a suitable Rust toolchain is available. +# +# Pass `-v` for human output and more checks (as warnings). + +set -e + +min_tool_version=$(dirname $0)/min-tool-version.sh + +# Convert the version string x.y.z to a canonical up-to-7-digits form. +# +# Note that this function uses one more digit (compared to other +# instances in other version scripts) to give a bit more space to +# `rustc` since it will reach 1.100.0 in late 2026. +get_canonical_version() +{ + IFS=. + set -- $1 + echo $((100000 * $1 + 100 * $2 + $3)) +} + +# Check that the Rust compiler exists. +if ! command -v "$RUSTC" >/dev/null; then + if [ "$1" = -v ]; then + echo >&2 "***" + echo >&2 "*** Rust compiler '$RUSTC' could not be found." + echo >&2 "***" + fi + exit 1 +fi + +# Check that the Rust bindings generator exists. +if ! command -v "$BINDGEN" >/dev/null; then + if [ "$1" = -v ]; then + echo >&2 "***" + echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found." + echo >&2 "***" + fi + exit 1 +fi + +# Check that the Rust compiler version is suitable. +# +# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`. +rust_compiler_version=$( \ + LC_ALL=C "$RUSTC" --version 2>/dev/null \ + | head -n 1 \ + | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \ +) +rust_compiler_min_version=$($min_tool_version rustc) +rust_compiler_cversion=$(get_canonical_version $rust_compiler_version) +rust_compiler_min_cversion=$(get_canonical_version $rust_compiler_min_version) +if [ "$rust_compiler_cversion" -lt "$rust_compiler_min_cversion" ]; then + if [ "$1" = -v ]; then + echo >&2 "***" + echo >&2 "*** Rust compiler '$RUSTC' is too old." + echo >&2 "*** Your version: $rust_compiler_version" + echo >&2 "*** Minimum version: $rust_compiler_min_version" + echo >&2 "***" + fi + exit 1 +fi +if [ "$1" = -v ] && [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then + echo >&2 "***" + echo >&2 "*** Rust compiler '$RUSTC' is too new. This may or may not work." + echo >&2 "*** Your version: $rust_compiler_version" + echo >&2 "*** Expected version: $rust_compiler_min_version" + echo >&2 "***" +fi + +# Check that the Rust bindings generator is suitable. +# +# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`. +rust_bindings_generator_version=$( \ + LC_ALL=C "$BINDGEN" --version 2>/dev/null \ + | head -n 1 \ + | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \ +) +rust_bindings_generator_min_version=$($min_tool_version bindgen) +rust_bindings_generator_cversion=$(get_canonical_version $rust_bindings_generator_version) +rust_bindings_generator_min_cversion=$(get_canonical_version $rust_bindings_generator_min_version) +if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cversion" ]; then + if [ "$1" = -v ]; then + echo >&2 "***" + echo >&2 "*** Rust bindings generator '$BINDGEN' is too old." + echo >&2 "*** Your version: $rust_bindings_generator_version" + echo >&2 "*** Minimum version: $rust_bindings_generator_min_version" + echo >&2 "***" + fi + exit 1 +fi +if [ "$1" = -v ] && [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then + echo >&2 "***" + echo >&2 "*** Rust bindings generator '$BINDGEN' is too new. This may or may not work." + echo >&2 "*** Your version: $rust_bindings_generator_version" + echo >&2 "*** Expected version: $rust_bindings_generator_min_version" + echo >&2 "***" +fi + +# Check that the `libclang` used by the Rust bindings generator is suitable. +bindgen_libclang_version=$( \ + LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null \ + | grep -F 'clang version ' \ + | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \ + | head -n 1 \ +) +bindgen_libclang_min_version=$($min_tool_version llvm) +bindgen_libclang_cversion=$(get_canonical_version $bindgen_libclang_version) +bindgen_libclang_min_cversion=$(get_canonical_version $bindgen_libclang_min_version) +if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then + if [ "$1" = -v ]; then + echo >&2 "***" + echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') is too old." + echo >&2 "*** Your version: $bindgen_libclang_version" + echo >&2 "*** Minimum version: $bindgen_libclang_min_version" + echo >&2 "***" + fi + exit 1 +fi + +# If the C compiler is Clang, then we can also check whether its version +# matches the `libclang` version used by the Rust bindings generator. +# +# In the future, we might be able to perform a full version check, see +# https://github.com/rust-lang/rust-bindgen/issues/2138. +if [ "$1" = -v ]; then + cc_name=$($(dirname $0)/cc-version.sh "$CC" | cut -f1 -d' ') + if [ "$cc_name" = Clang ]; then + clang_version=$( \ + LC_ALL=C "$CC" --version 2>/dev/null \ + | sed -nE '1s:.*version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p' + ) + if [ "$clang_version" != "$bindgen_libclang_version" ]; then + echo >&2 "***" + echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN')" + echo >&2 "*** version does not match Clang's. This may be a problem." + echo >&2 "*** libclang version: $bindgen_libclang_version" + echo >&2 "*** Clang version: $clang_version" + echo >&2 "***" + fi + fi +fi + +# Check that the source code for the `core` standard library exists. +# +# `$KRUSTFLAGS` is passed in case the user added `--sysroot`. +rustc_sysroot=$("$RUSTC" $KRUSTFLAGS --print sysroot) +rustc_src=${RUST_LIB_SRC:-"$rustc_sysroot/lib/rustlib/src/rust/library"} +rustc_src_core="$rustc_src/core/src/lib.rs" +if [ ! -e "$rustc_src_core" ]; then + if [ "$1" = -v ]; then + echo >&2 "***" + echo >&2 "*** Source code for the 'core' standard library could not be found" + echo >&2 "*** at '$rustc_src_core'." + echo >&2 "***" + fi + exit 1 +fi diff --git a/scripts/rust_is_available_bindgen_libclang.h b/scripts/rust_is_available_bindgen_libclang.h new file mode 100644 index 000000000000..0ef6db10d674 --- /dev/null +++ b/scripts/rust_is_available_bindgen_libclang.h @@ -0,0 +1,2 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#pragma message("clang version " __clang_version__) diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c index f355b3e0e968..15520806889e 100644 --- a/scripts/selinux/genheaders/genheaders.c +++ b/scripts/selinux/genheaders/genheaders.c @@ -59,35 +59,27 @@ int main(int argc, char *argv[]) exit(2); } - for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; - map->name = stoupperx(map->name); - for (j = 0; map->perms[j]; j++) - map->perms[j] = stoupperx(map->perms[j]); - } - - isids_len = sizeof(initial_sid_to_string) / sizeof (char *); - for (i = 1; i < isids_len; i++) { - const char *s = initial_sid_to_string[i]; - - if (s) - initial_sid_to_string[i] = stoupperx(s); - } - fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n"); for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; - fprintf(fout, "#define SECCLASS_%-39s %2d\n", map->name, i+1); + char *name = stoupperx(secclass_map[i].name); + + fprintf(fout, "#define SECCLASS_%-39s %2d\n", name, i+1); + free(name); } fprintf(fout, "\n"); + isids_len = sizeof(initial_sid_to_string) / sizeof(char *); for (i = 1; i < isids_len; i++) { const char *s = initial_sid_to_string[i]; - if (s) - fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i); + if (s) { + char *sidname = stoupperx(s); + + fprintf(fout, "#define SECINITSID_%-39s %2d\n", sidname, i); + free(sidname); + } } fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1); fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n"); @@ -96,10 +88,14 @@ int main(int argc, char *argv[]) fprintf(fout, "\tswitch (kern_tclass) {\n"); for (i = 0; secclass_map[i].name; i++) { static char s[] = "SOCKET"; - struct security_class_mapping *map = &secclass_map[i]; - int len = strlen(map->name), l = sizeof(s) - 1; - if (len >= l && memcmp(map->name + len - l, s, l) == 0) - fprintf(fout, "\tcase SECCLASS_%s:\n", map->name); + int len, l; + char *name = stoupperx(secclass_map[i].name); + + len = strlen(name); + l = sizeof(s) - 1; + if (len >= l && memcmp(name + len - l, s, l) == 0) + fprintf(fout, "\tcase SECCLASS_%s:\n", name); + free(name); } fprintf(fout, "\t\tsock = true;\n"); fprintf(fout, "\t\tbreak;\n"); @@ -110,33 +106,52 @@ int main(int argc, char *argv[]) fprintf(fout, "}\n"); fprintf(fout, "\n#endif\n"); - fclose(fout); + + if (fclose(fout) != 0) { + fprintf(stderr, "Could not successfully close %s: %s\n", + argv[1], strerror(errno)); + exit(4); + } fout = fopen(argv[2], "w"); if (!fout) { fprintf(stderr, "Could not open %s for writing: %s\n", argv[2], strerror(errno)); - exit(4); + exit(5); } fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n"); for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; - int len = strlen(map->name); + const struct security_class_mapping *map = &secclass_map[i]; + int len; + char *name = stoupperx(map->name); + + len = strlen(name); for (j = 0; map->perms[j]; j++) { + char *permname; + if (j >= 32) { fprintf(stderr, "Too many permissions to fit into an access vector at (%s, %s).\n", map->name, map->perms[j]); exit(5); } - fprintf(fout, "#define %s__%-*s 0x%08xU\n", map->name, - 39-len, map->perms[j], 1U<<j); + permname = stoupperx(map->perms[j]); + fprintf(fout, "#define %s__%-*s 0x%08xU\n", name, + 39-len, permname, 1U<<j); + free(permname); } + free(name); } fprintf(fout, "\n#endif\n"); - fclose(fout); + + if (fclose(fout) != 0) { + fprintf(stderr, "Could not successfully close %s: %s\n", + argv[2], strerror(errno)); + exit(6); + } + exit(0); } diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh index 2dccf141241d..24086793b0d8 100755 --- a/scripts/selinux/install_policy.sh +++ b/scripts/selinux/install_policy.sh @@ -31,8 +31,7 @@ fi if selinuxenabled; then echo "SELinux is already enabled" echo "This prevents safely relabeling all files." - echo "Boot with selinux=0 on the kernel command-line or" - echo "SELINUX=disabled in /etc/selinux/config." + echo "Boot with selinux=0 on the kernel command-line." exit 1 fi @@ -78,7 +77,7 @@ cd /etc/selinux/dummy/contexts/files $SF -F file_contexts / mounts=`cat /proc/$$/mounts | \ - egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \ + grep -E "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \ awk '{ print $2 '}` $SF -F file_contexts $mounts diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index 105c1c31a316..1415604c3d24 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) /* print out the class permissions */ for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; + const struct security_class_mapping *map = &secclass_map[i]; fprintf(fout, "class %s\n", map->name); fprintf(fout, "{\n"); for (j = 0; map->perms[j]; j++) @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) #define SYSTEMLOW "s0" #define SYSTEMHIGH "s1:c0.c1" for (i = 0; secclass_map[i].name; i++) { - struct security_class_mapping *map = &secclass_map[i]; + const struct security_class_mapping *map = &secclass_map[i]; fprintf(fout, "mlsconstrain %s {\n", map->name); for (j = 0; map->perms[j]; j++) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 6b54e46a0f12..af4754a35e66 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -111,9 +111,7 @@ if $scm_only; then exit fi -if test -e include/config/auto.conf; then - . include/config/auto.conf -else +if ! test -e include/config/auto.conf; then echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2 exit 1 fi @@ -125,10 +123,11 @@ if test ! "$srctree" -ef .; then fi # CONFIG_LOCALVERSION and LOCALVERSION (if set) -res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}" +config_localversion=$(sed -n 's/^CONFIG_LOCALVERSION=\(.*\)$/\1/p' include/config/auto.conf) +res="${res}${config_localversion}${LOCALVERSION}" # scm version string if not at a tagged commit -if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then +if grep -q "^CONFIG_LOCALVERSION_AUTO=y$" include/config/auto.conf; then # full scm version string res="$res$(scm_version)" elif [ "${LOCALVERSION+set}" != "set" ]; then diff --git a/scripts/sign-file.c b/scripts/sign-file.c index fbd34b8e8f57..598ef5465f82 100644 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -30,6 +30,13 @@ #include <openssl/engine.h> /* + * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API. + * + * Remove this if/when that API is no longer used + */ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +/* * Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to * assume that it's not available and its header file is missing and that we * should use PKCS#7 instead. Switching to the older PKCS#7 format restricts @@ -107,7 +114,7 @@ static void drain_openssl_errors(void) bool __cond = (cond); \ display_openssl_errors(__LINE__); \ if (__cond) { \ - err(1, fmt, ## __VA_ARGS__); \ + errx(1, fmt, ## __VA_ARGS__); \ } \ } while(0) diff --git a/scripts/sorttable.c b/scripts/sorttable.c index b7c2ad71f9cf..fba40e99f354 100644 --- a/scripts/sorttable.c +++ b/scripts/sorttable.c @@ -30,6 +30,8 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <errno.h> +#include <pthread.h> #include <tools/be_byteshift.h> #include <tools/le_byteshift.h> @@ -58,6 +60,10 @@ #define EM_RISCV 243 #endif +#ifndef EM_LOONGARCH +#define EM_LOONGARCH 258 +#endif + static uint32_t (*r)(const uint32_t *); static uint16_t (*r2)(const uint16_t *); static uint64_t (*r8)(const uint64_t *); @@ -231,7 +237,7 @@ static void sort_relative_table(char *extab_image, int image_size) } } -static void arm64_sort_relative_table(char *extab_image, int image_size) +static void sort_relative_table_with_data(char *extab_image, int image_size) { int i = 0; @@ -259,73 +265,6 @@ static void arm64_sort_relative_table(char *extab_image, int image_size) } } -static void x86_sort_relative_table(char *extab_image, int image_size) -{ - int i = 0; - - while (i < image_size) { - uint32_t *loc = (uint32_t *)(extab_image + i); - - w(r(loc) + i, loc); - w(r(loc + 1) + i + 4, loc + 1); - /* Don't touch the fixup type */ - - i += sizeof(uint32_t) * 3; - } - - qsort(extab_image, image_size / 12, 12, compare_relative_table); - - i = 0; - while (i < image_size) { - uint32_t *loc = (uint32_t *)(extab_image + i); - - w(r(loc) - i, loc); - w(r(loc + 1) - (i + 4), loc + 1); - /* Don't touch the fixup type */ - - i += sizeof(uint32_t) * 3; - } -} - -static void s390_sort_relative_table(char *extab_image, int image_size) -{ - int i; - - for (i = 0; i < image_size; i += 16) { - char *loc = extab_image + i; - uint64_t handler; - - w(r((uint32_t *)loc) + i, (uint32_t *)loc); - w(r((uint32_t *)(loc + 4)) + (i + 4), (uint32_t *)(loc + 4)); - /* - * 0 is a special self-relative handler value, which means that - * handler should be ignored. It is safe, because it means that - * handler field points to itself, which should never happen. - * When creating extable-relative values, keep it as 0, since - * this should never occur either: it would mean that handler - * field points to the first extable entry. - */ - handler = r8((uint64_t *)(loc + 8)); - if (handler) - handler += i + 8; - w8(handler, (uint64_t *)(loc + 8)); - } - - qsort(extab_image, image_size / 16, 16, compare_relative_table); - - for (i = 0; i < image_size; i += 16) { - char *loc = extab_image + i; - uint64_t handler; - - w(r((uint32_t *)loc) - i, (uint32_t *)loc); - w(r((uint32_t *)(loc + 4)) - (i + 4), (uint32_t *)(loc + 4)); - handler = r8((uint64_t *)(loc + 8)); - if (handler) - handler -= i + 8; - w8(handler, (uint64_t *)(loc + 8)); - } -} - static int do_file(char const *const fname, void *addr) { int rc = -1; @@ -364,14 +303,11 @@ static int do_file(char const *const fname, void *addr) switch (r2(&ehdr->e_machine)) { case EM_386: - case EM_X86_64: - custom_sort = x86_sort_relative_table; - break; - case EM_S390: - custom_sort = s390_sort_relative_table; - break; case EM_AARCH64: - custom_sort = arm64_sort_relative_table; + case EM_RISCV: + case EM_S390: + case EM_X86_64: + custom_sort = sort_relative_table_with_data; break; case EM_PARISC: case EM_PPC: @@ -381,9 +317,9 @@ static int do_file(char const *const fname, void *addr) case EM_ARCOMPACT: case EM_ARCV2: case EM_ARM: + case EM_LOONGARCH: case EM_MICROBLAZE: case EM_MIPS: - case EM_RISCV: case EM_XTENSA: break; default: diff --git a/scripts/sorttable.h b/scripts/sorttable.h index a2baa2fefb13..deb7c1d3e979 100644 --- a/scripts/sorttable.h +++ b/scripts/sorttable.h @@ -19,6 +19,9 @@ #undef extable_ent_size #undef compare_extable +#undef get_mcount_loc +#undef sort_mcount_loc +#undef elf_mcount_loc #undef do_sort #undef Elf_Addr #undef Elf_Ehdr @@ -41,6 +44,9 @@ #ifdef SORTTABLE_64 # define extable_ent_size 16 # define compare_extable compare_extable_64 +# define get_mcount_loc get_mcount_loc_64 +# define sort_mcount_loc sort_mcount_loc_64 +# define elf_mcount_loc elf_mcount_loc_64 # define do_sort do_sort_64 # define Elf_Addr Elf64_Addr # define Elf_Ehdr Elf64_Ehdr @@ -62,6 +68,9 @@ #else # define extable_ent_size 8 # define compare_extable compare_extable_32 +# define get_mcount_loc get_mcount_loc_32 +# define sort_mcount_loc sort_mcount_loc_32 +# define elf_mcount_loc elf_mcount_loc_32 # define do_sort do_sort_32 # define Elf_Addr Elf32_Addr # define Elf_Ehdr Elf32_Ehdr @@ -84,8 +93,6 @@ #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) /* ORC unwinder only support X86_64 */ -#include <errno.h> -#include <pthread.h> #include <asm/orc_types.h> #define ERRSTR_MAXSZ 256 @@ -191,7 +198,66 @@ static int compare_extable(const void *a, const void *b) return 1; return 0; } +#ifdef MCOUNT_SORT_ENABLED +pthread_t mcount_sort_thread; + +struct elf_mcount_loc { + Elf_Ehdr *ehdr; + Elf_Shdr *init_data_sec; + uint_t start_mcount_loc; + uint_t stop_mcount_loc; +}; + +/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */ +static void *sort_mcount_loc(void *arg) +{ + struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg; + uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr) + + _r(&(emloc->init_data_sec)->sh_offset); + uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc; + unsigned char *start_loc = (void *)emloc->ehdr + offset; + + qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable); + return NULL; +} + +/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */ +static void get_mcount_loc(uint_t *_start, uint_t *_stop) +{ + FILE *file_start, *file_stop; + char start_buff[20]; + char stop_buff[20]; + int len = 0; + + file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r"); + if (!file_start) { + fprintf(stderr, "get start_mcount_loc error!"); + return; + } + + file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r"); + if (!file_stop) { + fprintf(stderr, "get stop_mcount_loc error!"); + pclose(file_start); + return; + } + + while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) { + len = strlen(start_buff); + start_buff[len - 1] = '\0'; + } + *_start = strtoul(start_buff, NULL, 16); + + while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) { + len = strlen(stop_buff); + stop_buff[len - 1] = '\0'; + } + *_stop = strtoul(stop_buff, NULL, 16); + pclose(file_start); + pclose(file_stop); +} +#endif static int do_sort(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) @@ -217,6 +283,11 @@ static int do_sort(Elf_Ehdr *ehdr, int idx; unsigned int shnum; unsigned int shstrndx; +#ifdef MCOUNT_SORT_ENABLED + struct elf_mcount_loc mstruct = {0}; + uint_t _start_mcount_loc = 0; + uint_t _stop_mcount_loc = 0; +#endif #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) unsigned int orc_ip_size = 0; unsigned int orc_size = 0; @@ -253,6 +324,17 @@ static int do_sort(Elf_Ehdr *ehdr, symtab_shndx = (Elf32_Word *)((const char *)ehdr + _r(&s->sh_offset)); +#ifdef MCOUNT_SORT_ENABLED + /* locate the .init.data section in vmlinux */ + if (!strcmp(secstrings + idx, ".init.data")) { + get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc); + mstruct.ehdr = ehdr; + mstruct.init_data_sec = s; + mstruct.start_mcount_loc = _start_mcount_loc; + mstruct.stop_mcount_loc = _stop_mcount_loc; + } +#endif + #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED) /* locate the ORC unwind tables */ if (!strcmp(secstrings + idx, ".orc_unwind_ip")) { @@ -294,6 +376,23 @@ static int do_sort(Elf_Ehdr *ehdr, goto out; } #endif + +#ifdef MCOUNT_SORT_ENABLED + if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) { + fprintf(stderr, + "incomplete mcount's sort in file: %s\n", + fname); + goto out; + } + + /* create thread to sort mcount_loc concurrently */ + if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) { + fprintf(stderr, + "pthread_create mcount_sort_thread failed '%s': %s\n", + strerror(errno), fname); + goto out; + } +#endif if (!extab_sec) { fprintf(stderr, "no __ex_table in file: %s\n", fname); goto out; @@ -364,11 +463,11 @@ out: void *retval = NULL; /* wait for ORC tables sort done */ rc = pthread_join(orc_sort_thread, &retval); - if (rc) + if (rc) { fprintf(stderr, "pthread_join failed '%s': %s\n", strerror(errno), fname); - else if (retval) { + } else if (retval) { rc = -1; fprintf(stderr, "failed to sort ORC tables '%s': %s\n", @@ -376,5 +475,23 @@ out: } } #endif + +#ifdef MCOUNT_SORT_ENABLED + if (mcount_sort_thread) { + void *retval = NULL; + /* wait for mcount sort done */ + rc = pthread_join(mcount_sort_thread, &retval); + if (rc) { + fprintf(stderr, + "pthread_join failed '%s': %s\n", + strerror(errno), fname); + } else if (retval) { + rc = -1; + fprintf(stderr, + "failed to sort mcount '%s': %s\n", + (char *)retval, fname); + } + } +#endif return rc; } diff --git a/scripts/spdxcheck-test.sh b/scripts/spdxcheck-test.sh index cb76324756bd..9f6d1a74da6e 100644 --- a/scripts/spdxcheck-test.sh +++ b/scripts/spdxcheck-test.sh @@ -1,7 +1,7 @@ #!/bin/sh # run check on a text and a binary file -for FILE in Makefile Documentation/logo.gif; do +for FILE in Makefile Documentation/images/logo.gif; do python3 scripts/spdxcheck.py $FILE python3 scripts/spdxcheck.py - < $FILE done diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py index ebd06ae642c9..18cb9f5b3d3d 100755 --- a/scripts/spdxcheck.py +++ b/scripts/spdxcheck.py @@ -6,6 +6,7 @@ from argparse import ArgumentParser from ply import lex, yacc import locale import traceback +import fnmatch import sys import git import re @@ -28,6 +29,21 @@ class SPDXdata(object): self.licenses = [ ] self.exceptions = { } +class dirinfo(object): + def __init__(self): + self.missing = 0 + self.total = 0 + self.files = [] + + def update(self, fname, basedir, miss): + self.total += 1 + self.missing += miss + if miss: + fname = './' + fname + bdir = os.path.dirname(fname) + if bdir == basedir.rstrip('/'): + self.files.append(fname) + # Read the spdx data from the LICENSES directory def read_spdxdata(repo): @@ -91,11 +107,25 @@ class id_parser(object): self.parser = yacc.yacc(module = self, write_tables = False, debug = False) self.lines_checked = 0 self.checked = 0 + self.excluded = 0 self.spdx_valid = 0 self.spdx_errors = 0 + self.spdx_dirs = {} + self.dirdepth = -1 + self.basedir = '.' self.curline = 0 self.deepest = 0 + def set_dirinfo(self, basedir, dirdepth): + if dirdepth >= 0: + self.basedir = basedir + bdir = basedir.lstrip('./').rstrip('/') + if bdir != '': + parts = bdir.split('/') + else: + parts = [] + self.dirdepth = dirdepth + len(parts) + # Validate License and Exception IDs def validate(self, tok): id = tok.value.upper() @@ -167,6 +197,7 @@ class id_parser(object): def parse_lines(self, fd, maxlines, fname): self.checked += 1 self.curline = 0 + fail = 1 try: for line in fd: line = line.decode(locale.getpreferredencoding(False), errors='ignore') @@ -192,6 +223,7 @@ class id_parser(object): # Should we check for more SPDX ids in the same file and # complain if there are any? # + fail = 0 break except ParserException as pe: @@ -200,31 +232,105 @@ class id_parser(object): tok = pe.tok.value sys.stdout.write('%s: %d:%d %s: %s\n' %(fname, self.curline, col, pe.txt, tok)) else: - sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, col, pe.txt)) + sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, pe.txt)) self.spdx_errors += 1 -def scan_git_tree(tree): + if fname == '-': + return + + base = os.path.dirname(fname) + if self.dirdepth > 0: + parts = base.split('/') + i = 0 + base = '.' + while i < self.dirdepth and i < len(parts) and len(parts[i]): + base += '/' + parts[i] + i += 1 + elif self.dirdepth == 0: + base = self.basedir + else: + base = './' + base.rstrip('/') + base += '/' + + di = self.spdx_dirs.get(base, dirinfo()) + di.update(fname, base, fail) + self.spdx_dirs[base] = di + +class pattern(object): + def __init__(self, line): + self.pattern = line + self.match = self.match_file + if line == '.*': + self.match = self.match_dot + elif line.endswith('/'): + self.pattern = line[:-1] + self.match = self.match_dir + elif line.startswith('/'): + self.pattern = line[1:] + self.match = self.match_fn + + def match_dot(self, fpath): + return os.path.basename(fpath).startswith('.') + + def match_file(self, fpath): + return os.path.basename(fpath) == self.pattern + + def match_fn(self, fpath): + return fnmatch.fnmatchcase(fpath, self.pattern) + + def match_dir(self, fpath): + if self.match_fn(os.path.dirname(fpath)): + return True + return fpath.startswith(self.pattern) + +def exclude_file(fpath): + for rule in exclude_rules: + if rule.match(fpath): + return True + return False + +def scan_git_tree(tree, basedir, dirdepth): + parser.set_dirinfo(basedir, dirdepth) for el in tree.traverse(): - # Exclude stuff which would make pointless noise - # FIXME: Put this somewhere more sensible - if el.path.startswith("LICENSES"): - continue - if el.path.find("license-rules.rst") >= 0: - continue if not os.path.isfile(el.path): continue + if exclude_file(el.path): + parser.excluded += 1 + continue with open(el.path, 'rb') as fd: parser.parse_lines(fd, args.maxlines, el.path) -def scan_git_subtree(tree, path): +def scan_git_subtree(tree, path, dirdepth): for p in path.strip('/').split('/'): tree = tree[p] - scan_git_tree(tree) + scan_git_tree(tree, path.strip('/'), dirdepth) + +def read_exclude_file(fname): + rules = [] + if not fname: + return rules + with open(fname) as fd: + for line in fd: + line = line.strip() + if line.startswith('#'): + continue + if not len(line): + continue + rules.append(pattern(line)) + return rules if __name__ == '__main__': ap = ArgumentParser(description='SPDX expression checker') ap.add_argument('path', nargs='*', help='Check path or file. If not given full git tree scan. For stdin use "-"') + ap.add_argument('-d', '--dirs', action='store_true', + help='Show [sub]directory statistics.') + ap.add_argument('-D', '--depth', type=int, default=-1, + help='Directory depth for -d statistics. Default: unlimited') + ap.add_argument('-e', '--exclude', + help='File containing file patterns to exclude. Default: scripts/spdxexclude') + ap.add_argument('-f', '--files', action='store_true', + help='Show files without SPDX.') ap.add_argument('-m', '--maxlines', type=int, default=15, help='Maximum number of lines to scan in a file. Default 15') ap.add_argument('-v', '--verbose', action='store_true', help='Verbose statistics output') @@ -259,6 +365,15 @@ if __name__ == '__main__': sys.exit(1) try: + fname = args.exclude + if not fname: + fname = os.path.join(os.path.dirname(__file__), 'spdxexclude') + exclude_rules = read_exclude_file(fname) + except Exception as ex: + sys.stderr.write('FAIL: Reading exclude file %s: %s\n' %(fname, ex)) + sys.exit(1) + + try: if len(args.path) and args.path[0] == '-': stdin = os.fdopen(sys.stdin.fileno(), 'rb') parser.parse_lines(stdin, args.maxlines, '-') @@ -268,13 +383,21 @@ if __name__ == '__main__': if os.path.isfile(p): parser.parse_lines(open(p, 'rb'), args.maxlines, p) elif os.path.isdir(p): - scan_git_subtree(repo.head.reference.commit.tree, p) + scan_git_subtree(repo.head.reference.commit.tree, p, + args.depth) else: sys.stderr.write('path %s does not exist\n' %p) sys.exit(1) else: # Full git tree scan - scan_git_tree(repo.head.commit.tree) + scan_git_tree(repo.head.commit.tree, '.', args.depth) + + ndirs = len(parser.spdx_dirs) + dirsok = 0 + if ndirs: + for di in parser.spdx_dirs.values(): + if not di.missing: + dirsok += 1 if args.verbose: sys.stderr.write('\n') @@ -283,10 +406,38 @@ if __name__ == '__main__': sys.stderr.write('License IDs %12d\n' %len(spdx.licenses)) sys.stderr.write('Exception IDs %12d\n' %len(spdx.exceptions)) sys.stderr.write('\n') + sys.stderr.write('Files excluded: %12d\n' %parser.excluded) sys.stderr.write('Files checked: %12d\n' %parser.checked) sys.stderr.write('Lines checked: %12d\n' %parser.lines_checked) - sys.stderr.write('Files with SPDX: %12d\n' %parser.spdx_valid) + if parser.checked: + pc = int(100 * parser.spdx_valid / parser.checked) + sys.stderr.write('Files with SPDX: %12d %3d%%\n' %(parser.spdx_valid, pc)) sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors) + if ndirs: + sys.stderr.write('\n') + sys.stderr.write('Directories accounted: %8d\n' %ndirs) + pc = int(100 * dirsok / ndirs) + sys.stderr.write('Directories complete: %8d %3d%%\n' %(dirsok, pc)) + + if ndirs and ndirs != dirsok and args.dirs: + if args.verbose: + sys.stderr.write('\n') + sys.stderr.write('Incomplete directories: SPDX in Files\n') + for f in sorted(parser.spdx_dirs.keys()): + di = parser.spdx_dirs[f] + if di.missing: + valid = di.total - di.missing + pc = int(100 * valid / di.total) + sys.stderr.write(' %-80s: %5d of %5d %3d%%\n' %(f, valid, di.total, pc)) + + if ndirs and ndirs != dirsok and args.files: + if args.verbose or args.dirs: + sys.stderr.write('\n') + sys.stderr.write('Files without SPDX:\n') + for f in sorted(parser.spdx_dirs.keys()): + di = parser.spdx_dirs[f] + for f in sorted(di.files): + sys.stderr.write(' %s\n' %f) sys.exit(0) diff --git a/scripts/spdxexclude b/scripts/spdxexclude new file mode 100644 index 000000000000..81bdb13ed789 --- /dev/null +++ b/scripts/spdxexclude @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Patterns for excluding files and directories + +# Ignore the license directory and the licensing documentation which would +# create lots of noise for no value +LICENSES/ +license-rules.rst + +# Ignore config files and snippets. The majority is generated +# by the Kconfig tools +kernel/configs/ +arch/*/configs/ + +# Other files without copyrightable content +/CREDITS +/MAINTAINERS +/README diff --git a/scripts/spelling.txt b/scripts/spelling.txt index acf6ea711299..8435b99452b6 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -180,6 +180,7 @@ asuming||assuming asycronous||asynchronous asychronous||asynchronous asynchnous||asynchronous +asynchronus||asynchronous asynchromous||asynchronous asymetric||asymmetric asymmeric||asymmetric @@ -231,6 +232,7 @@ baloons||balloons bandwith||bandwidth banlance||balance batery||battery +battey||battery beacuse||because becasue||because becomming||becoming @@ -333,6 +335,7 @@ commoditiy||commodity comsume||consume comsumer||consumer comsuming||consuming +comaptible||compatible compability||compatibility compaibility||compatibility comparsion||comparison @@ -353,7 +356,9 @@ compoment||component comppatible||compatible compres||compress compresion||compression +compresser||compressor comression||compression +comsumed||consumed comunicate||communicate comunication||communication conbination||combination @@ -530,6 +535,7 @@ dissconect||disconnect distiction||distinction divisable||divisible divsiors||divisors +dsiabled||disabled docuentation||documentation documantation||documentation documentaion||documentation @@ -677,6 +683,7 @@ frequence||frequency frequncy||frequency frequancy||frequency frome||from +fronend||frontend fucntion||function fuction||function fuctions||functions @@ -761,6 +768,7 @@ implmentation||implementation implmenting||implementing incative||inactive incomming||incoming +incompaitiblity||incompatibility incompatabilities||incompatibilities incompatable||incompatible incompatble||incompatible @@ -942,6 +950,7 @@ metdata||metadata micropone||microphone microprocesspr||microprocessor migrateable||migratable +millenium||millennium milliseonds||milliseconds minium||minimum minimam||minimum @@ -1007,6 +1016,7 @@ notity||notify nubmer||number numebr||number numner||number +nunber||number obtaion||obtain obusing||abusing occassionally||occasionally @@ -1046,6 +1056,7 @@ oustanding||outstanding overaall||overall overhread||overhead overlaping||overlapping +oveflow||overflow overflw||overflow overlfow||overflow overide||override @@ -1135,6 +1146,7 @@ preprare||prepare pressre||pressure presuambly||presumably previosuly||previously +previsously||previously primative||primitive princliple||principle priorty||priority @@ -1296,6 +1308,7 @@ routins||routines rquest||request runing||running runned||ran +runnnig||running runnning||running runtine||runtime sacrifying||sacrificing @@ -1352,6 +1365,7 @@ similiar||similar simlar||similar simliar||similar simpified||simplified +simultanous||simultaneous singaled||signaled singal||signal singed||signed @@ -1460,6 +1474,7 @@ syste||system sytem||system sythesis||synthesis taht||that +tained||tainted tansmit||transmit targetted||targeted targetting||targeting @@ -1488,6 +1503,7 @@ timout||timeout tmis||this toogle||toggle torerable||tolerable +torlence||tolerance traget||target traking||tracking tramsmitted||transmitted @@ -1502,6 +1518,7 @@ transferd||transferred transfered||transferred transfering||transferring transision||transition +transistioned||transitioned transmittd||transmitted transormed||transformed trasfer||transfer diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index f126ecbb0494..ec84fc62774e 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -25,6 +25,7 @@ my $need_sphinx = 0; my $need_pip = 0; my $need_virtualenv = 0; my $rec_sphinx_upgrade = 0; +my $verbose_warn_install = 1; my $install = ""; my $virtenv_dir = ""; my $python_cmd = ""; @@ -103,10 +104,12 @@ sub check_missing(%) next; } - if ($is_optional) { - print "Warning: better to also install \"$prog\".\n"; - } else { - print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + if ($verbose_warn_install) { + if ($is_optional) { + print "Warning: better to also install \"$prog\".\n"; + } else { + print "ERROR: please install \"$prog\", otherwise, build won't work.\n"; + } } if (defined($map{$prog})) { $install .= " " . $map{$prog}; @@ -386,7 +389,8 @@ sub give_debian_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo apt-get install $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo apt-get install $install\n"); } sub give_redhat_hints() @@ -458,10 +462,12 @@ sub give_redhat_hints() if (!$old) { # dnf, for Fedora 18+ - printf("You should run:\n\n\tsudo dnf install -y $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo dnf install -y $install\n"); } else { # yum, for RHEL (and clones) or Fedora version < 18 - printf("You should run:\n\n\tsudo yum install -y $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo yum install -y $install\n"); } } @@ -509,7 +515,8 @@ sub give_opensuse_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo zypper install --no-recommends $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo zypper install --no-recommends $install\n"); } sub give_mageia_hints() @@ -553,7 +560,8 @@ sub give_mageia_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo $packager_cmd $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo $packager_cmd $install\n"); } sub give_arch_linux_hints() @@ -583,7 +591,8 @@ sub give_arch_linux_hints() check_missing(\%map); return if (!$need && !$optional); - printf("You should run:\n\n\tsudo pacman -S $install\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n\tsudo pacman -S $install\n"); } sub give_gentoo_hints() @@ -610,7 +619,8 @@ sub give_gentoo_hints() return if (!$need && !$optional); - printf("You should run:\n\n"); + printf("You should run:\n") if ($verbose_warn_install); + printf("\n"); my $imagemagick = "media-gfx/imagemagick svg png"; my $cairo = "media-gfx/graphviz cairo pdf"; @@ -700,7 +710,7 @@ sub check_distros() sub deactivate_help() { - printf "\nIf you want to exit the virtualenv, you can use:\n"; + printf "\n If you want to exit the virtualenv, you can use:\n"; printf "\tdeactivate\n"; } @@ -720,6 +730,12 @@ sub get_virtenv() next if (! -f $sphinx_cmd); my $ver = get_sphinx_version($sphinx_cmd); + + if (!$ver) { + $f =~ s#/bin/activate##; + print("Warning: virtual environment $f is not working.\nPython version upgrade? Remove it with:\n\n\trm -rf $f\n\n"); + } + if ($need_sphinx && ($ver ge $min_version)) { return ($f, $ver); } elsif ($ver gt $cur_version) { @@ -741,7 +757,7 @@ sub recommend_sphinx_upgrade() # Get the highest version from sphinx_*/bin/sphinx-build and the # corresponding command to activate the venv/virtenv - $activate_cmd = get_virtenv(); + ($activate_cmd, $venv_ver) = get_virtenv(); # Store the highest version from Sphinx existing virtualenvs if (($activate_cmd ne "") && ($venv_ver gt $cur_version)) { @@ -759,10 +775,14 @@ sub recommend_sphinx_upgrade() # Either there are already a virtual env or a new one should be created $need_pip = 1; + return if (!$latest_avail_ver); + # Return if the reason is due to an upgrade or not if ($latest_avail_ver lt $rec_version) { $rec_sphinx_upgrade = 1; } + + return $latest_avail_ver; } # @@ -775,12 +795,13 @@ sub recommend_sphinx_version($) { my $virtualenv_cmd = shift; - if ($latest_avail_ver lt $min_pdf_version) { - print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n"; - } - # Version is OK. Nothing to do. - return if ($cur_version && ($cur_version ge $rec_version)); + if ($cur_version && ($cur_version ge $rec_version)) { + if ($cur_version lt $min_pdf_version) { + print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n"; + } + return; + }; if (!$need_sphinx) { # sphinx-build is present and its version is >= $min_version @@ -820,13 +841,17 @@ sub recommend_sphinx_version($) } # Suggest newer versions if current ones are too old - if ($latest_avail_ver && $cur_version ge $min_version) { + if ($latest_avail_ver && $latest_avail_ver ge $min_version) { # If there's a good enough version, ask the user to enable it if ($latest_avail_ver ge $rec_version) { printf "\nNeed to activate Sphinx (version $latest_avail_ver) on virtualenv with:\n"; printf "\t. $activate_cmd\n"; deactivate_help(); + if ($latest_avail_ver lt $min_pdf_version) { + print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n"; + } + return; } @@ -848,7 +873,7 @@ sub recommend_sphinx_version($) print "To upgrade Sphinx, use:\n\n"; } } else { - print "Sphinx needs to be installed either as a package or via pip/pypi with:\n"; + print "\nSphinx needs to be installed either:\n1) via pip/pypi with:\n\n"; } $python_cmd = find_python_no_venv(); @@ -858,6 +883,29 @@ sub recommend_sphinx_version($) printf "\t. $virtenv_dir/bin/activate\n"; printf "\tpip install -r $requirement_file\n"; deactivate_help(); + + printf "\n2) As a package with:\n"; + + my $old_need = $need; + my $old_optional = $optional; + %missing = (); + $pdf = 0; + $optional = 0; + $install = ""; + $verbose_warn_install = 0; + + add_package("python-sphinx", 0); + check_python_module("sphinx_rtd_theme", 1); + + check_distros(); + + $need = $old_need; + $optional = $old_optional; + + printf "\n Please note that Sphinx >= 3.0 will currently produce false-positive\n"; + printf " warning when the same name is used for more than one type (functions,\n"; + printf " structs, enums,...). This is known Sphinx bug. For more details, see:\n"; + printf "\thttps://github.com/sphinx-doc/sphinx/pull/8313\n"; } sub check_needs() @@ -897,7 +945,7 @@ sub check_needs() } } - recommend_sphinx_upgrade(); + my $venv_ver = recommend_sphinx_upgrade(); my $virtualenv_cmd; diff --git a/scripts/subarch.include b/scripts/subarch.include index 776849a3c500..4bd327d0ae42 100644 --- a/scripts/subarch.include +++ b/scripts/subarch.include @@ -10,4 +10,4 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e s/s390x/s390/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ - -e s/riscv.*/riscv/) + -e s/riscv.*/riscv/ -e s/loongarch.*/loongarch/) diff --git a/scripts/tags.sh b/scripts/tags.sh index b24bfaec6290..e137cf15aae9 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -25,13 +25,6 @@ else tree=${srctree}/ fi -# ignore userspace tools -if [ -n "$COMPILED_SOURCE" ]; then - ignore="$ignore ( -path ./tools ) -prune -o" -else - ignore="$ignore ( -path ${tree}tools ) -prune -o" -fi - # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH if [ "${ALLSOURCE_ARCHS}" = "" ]; then ALLSOURCE_ARCHS=${SRCARCH} @@ -95,10 +88,13 @@ all_sources() all_compiled_sources() { - realpath -es $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) \ - include/generated/autoconf.h $(find $ignore -name "*.cmd" -exec \ - grep -Poh '(?(?=^source_.* \K).*|(?=^ \K\S).*(?= \\))' {} \+ | - awk '!a[$0]++') | sort -u + { + echo include/generated/autoconf.h + find $ignore -name "*.cmd" -exec \ + grep -Poh '(?(?=^source_.* \K).*|(?=^ \K\S).*(?= \\))' {} \+ | + awk '!a[$0]++' + } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) | + sort -u } all_target_sources() @@ -140,71 +136,71 @@ dogtags() # - etags regular expressions have to match at the start of a line; # a ^[^#] is prepended by setup_regex unless an anchor is already present regex_asm=( - '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/' + '/^\(ENTRY\|_GLOBAL\)([[:space:]]*\([[:alnum:]_\\]*\)).*/\2/' ) regex_c=( - '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/' - '/^BPF_CALL_[0-9](\([[:alnum:]_]*\).*/\1/' - '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/' - '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/' - '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/' - '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/' - '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/' - '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/' - '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/' - '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/' - '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/' - '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/' - '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/' - '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/' - '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/' - '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/' - '/\<TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/' - '/\<__TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/' - '/\<CLEARPAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/' - '/\<__CLEARPAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/' - '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/' - '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/' - '/^PAGEFLAG_FALSE(\([[:alnum:]_]*\).*/Page\1/' - '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/' - '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/' - '/\<SETPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/SetPage\1/' - '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/' - '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/' - '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/' - '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/' - '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/' - '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/' - '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/' - '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/' - '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/' - '/^DEF_MMIO_\(IN\|OUT\)_[XD](\([[:alnum:]_]*\),[^)]*)/\2/' - '/^DEBUGGER_BOILERPLATE(\([[:alnum:]_]*\))/\1/' - '/^DEF_PCI_AC_\(\|NO\)RET(\([[:alnum:]_]*\).*/\2/' - '/^PCI_OP_READ(\(\w*\).*[1-4])/pci_bus_read_config_\1/' - '/^PCI_OP_WRITE(\(\w*\).*[1-4])/pci_bus_write_config_\1/' - '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)(\([[:alnum:]_]*\)/\2/v/' - '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)(\([[:alnum:]_]*\)/\2/v/' - '/\<DECLARE_\(RWSEM\|COMPLETION\)(\([[:alnum:]_]\+\)/\2/v/' - '/\<DECLARE_BITMAP(\([[:alnum:]_]*\)/\1/v/' - '/\(^\|\s\)\(\|L\|H\)LIST_HEAD(\([[:alnum:]_]*\)/\3/v/' - '/\(^\|\s\)RADIX_TREE(\([[:alnum:]_]*\)/\2/v/' - '/\<DEFINE_PER_CPU([^,]*, *\([[:alnum:]_]*\)/\1/v/' - '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*, *\([[:alnum:]_]*\)/\1/v/' - '/\<DECLARE_WAIT_QUEUE_HEAD(\([[:alnum:]_]*\)/\1/v/' - '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/' - '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/' - '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/' - '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/' - '/\<DEFINE_ID\(R\|A\)(\([[:alnum:]_]\+\)/\2/' - '/\<DEFINE_WD_CLASS(\([[:alnum:]_]\+\)/\1/' - '/\<ATOMIC_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/' - '/\<RAW_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/' - '/\<DECLARE_FAULT_ATTR(\([[:alnum:]_]\+\)/\1/' - '/\<BLOCKING_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/' - '/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/' - '/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/' - '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/' + '/^SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/sys_\1/' + '/^BPF_CALL_[0-9]([[:space:]]*\([[:alnum:]_]*\).*/\1/' + '/^COMPAT_SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/compat_sys_\1/' + '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1/' + '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/' + '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1/' + '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/' + '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/get_\1_slot/' + '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/free_\1_slot/' + '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' + '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/' + '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/' + '/^TESTSETFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestSetPage\1/' + '/^TESTPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' + '/^SETPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/' + '/\<__SETPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/' + '/\<TESTCLEARFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' + '/\<__TESTCLEARFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' + '/\<CLEARPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/' + '/\<__CLEARPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^__PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/' + '/^__PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^PAGEFLAG_FALSE([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' + '/\<TESTSCFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestSetPage\1/' + '/\<TESTSCFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' + '/\<SETPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/' + '/\<CLEARPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/' + '/\<__CLEARPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' + '/\<TESTCLEARFLAG_FALSE([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/' + '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' + '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/' + '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^TASK_PFA_TEST([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_\1/' + '/^TASK_PFA_SET([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_set_\1/' + '/^TASK_PFA_CLEAR([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_clear_\1/' + '/^DEF_MMIO_\(IN\|OUT\)_[XD]([[:space:]]*\([[:alnum:]_]*\),[^)]*)/\2/' + '/^DEBUGGER_BOILERPLATE([[:space:]]*\([[:alnum:]_]*\))/\1/' + '/^DEF_PCI_AC_\(\|NO\)RET([[:space:]]*\([[:alnum:]_]*\).*/\2/' + '/^PCI_OP_READ([[:space:]]*\(\w*\).*[1-4])/pci_bus_read_config_\1/' + '/^PCI_OP_WRITE([[:space:]]*\(\w*\).*[1-4])/pci_bus_write_config_\1/' + '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\<DECLARE_\(RWSEM\|COMPLETION\)([[:space:]]*\([[:alnum:]_]\+\)/\2/v/' + '/\<DECLARE_BITMAP([[:space:]]*\([[:alnum:]_]*\)/\1/v/' + '/\(^\|\s\)\(\|L\|H\)LIST_HEAD([[:space:]]*\([[:alnum:]_]*\)/\3/v/' + '/\(^\|\s\)RADIX_TREE([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\<DEFINE_PER_CPU([^,]*,[[:space:]]*\([[:alnum:]_]*\)/\1/v/' + '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*,[[:space:]]*\([[:alnum:]_]*\)/\1/v/' + '/\<DECLARE_WAIT_QUEUE_HEAD([[:space:]]*\([[:alnum:]_]*\)/\1/v/' + '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\(^\s\)OFFSET([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\(^\s\)DEFINE([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\<\(DEFINE\|DECLARE\)_HASHTABLE([[:space:]]*\([[:alnum:]_]*\)/\2/v/' + '/\<DEFINE_ID\(R\|A\)([[:space:]]*\([[:alnum:]_]\+\)/\2/' + '/\<DEFINE_WD_CLASS([[:space:]]*\([[:alnum:]_]\+\)/\1/' + '/\<ATOMIC_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/' + '/\<RAW_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/' + '/\<DECLARE_FAULT_ATTR([[:space:]]*\([[:alnum:]_]\+\)/\1/' + '/\<BLOCKING_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/' + '/\<DEVICE_ATTR_\(RW\|RO\|WO\)([[:space:]]*\([[:alnum:]_]\+\)/dev_attr_\2/' + '/\<DRIVER_ATTR_\(RW\|RO\|WO\)([[:space:]]*\([[:alnum:]_]\+\)/driver_attr_\2/' + '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)([[:space:]]*\([[:alnum:]_]\+\)/\4/' '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_t/' '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/' ) diff --git a/scripts/test_fortify.sh b/scripts/test_fortify.sh index a4da365508f0..c2688ab8281d 100644 --- a/scripts/test_fortify.sh +++ b/scripts/test_fortify.sh @@ -46,8 +46,12 @@ if "$@" -Werror -c "$IN" -o "$OUT".o 2> "$TMP" ; then status="warning: unsafe ${FUNC}() usage lacked '$WANT' symbol in $IN" fi else - # If the build failed, check for the warning in the stderr (gcc). - if ! grep -q -m1 "error: call to .\b${WANT}\b." "$TMP" ; then + # If the build failed, check for the warning in the stderr. + # GCC: + # ./include/linux/fortify-string.h:316:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] + # Clang 14: + # ./include/linux/fortify-string.h:316:4: error: call to __write_overflow_field declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning] + if ! grep -Eq -m1 "error: call to .?\b${WANT}\b.?" "$TMP" ; then status="warning: unsafe ${FUNC}() usage lacked '$WANT' warning in $IN" fi fi diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py index 7011fbe003ff..438516bdfb3c 100755 --- a/scripts/tracing/draw_functrace.py +++ b/scripts/tracing/draw_functrace.py @@ -8,7 +8,7 @@ This script parses a trace provided by the function tracer in kernel/trace/trace_functions.c The resulted trace is processed into a tree to produce a more human view of the call stack by drawing textual but hierarchical tree of -calls. Only the functions's names and the the call time are provided. +calls. Only the functions's names and the call time are provided. Usage: Be sure that you have CONFIG_FUNCTION_TRACER |