diff options
Diffstat (limited to 'scripts')
116 files changed, 3623 insertions, 2494 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 7778cc97a4e0..2f331879816b 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -114,12 +114,6 @@ endef build := -f $(srctree)/scripts/Makefile.build obj ### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= -# Usage: -# $(Q)$(MAKE) $(dtbinst)=dir -dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj - -### # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= # Usage: # $(Q)$(MAKE) $(clean)=dir diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 5a84b6443875..3ee8ecfb8c04 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -33,7 +33,7 @@ ld-option = $(success,$(LD) -v $(1)) # $(as-instr,<instr>) # Return y if the assembler supports <instr>, n otherwise -as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler-with-cpp -o /dev/null -) +as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -Wa$(comma)--fatal-warnings -c -x assembler-with-cpp -o /dev/null -) # check if $(CC) and $(LD) exist $(error-if,$(failure,command -v $(CC)),C compiler '$(CC)' not found) diff --git a/scripts/Makefile b/scripts/Makefile index 576cf64be667..bc90520a5426 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -11,12 +11,14 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen -always-$(CONFIG_RUST) += target.json +ifneq ($(or $(CONFIG_X86_64),$(CONFIG_LOONGARCH)),) +always-$(CONFIG_RUST) += target.json filechk_rust_target = $< < include/config/auto.conf $(obj)/target.json: scripts/generate_rust_target include/config/auto.conf FORCE $(call filechk,rust_target) +endif hostprogs += generate_rust_target generate_rust_target-rust := y @@ -31,9 +33,12 @@ HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null | ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -ARCH := x86 +SRCARCH := x86 +endif +ifeq ($(ARCH),loongarch) +SRCARCH := loongarch endif -HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include +HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/$(SRCARCH)/include HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED endif diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 9a3063735e71..baf86c0880b6 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -71,6 +71,7 @@ endif # subdir-builtin and subdir-modorder may contain duplications. Use $(sort ...) subdir-builtin := $(sort $(filter %/built-in.a, $(real-obj-y))) subdir-modorder := $(sort $(filter %/modules.order, $(obj-m))) +subdir-dtbslist := $(sort $(filter %/dtbs-list, $(dtb-y))) targets-for-builtin := $(extra-y) @@ -213,7 +214,7 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT # '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 -is-standard-object = $(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_$(target-stem).o)$(OBJECT_FILES_NON_STANDARD)n),y) $(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) @@ -275,6 +276,7 @@ rust_common_cmd = \ --extern alloc --extern kernel \ --crate-type rlib -L $(objtree)/rust/ \ --crate-name $(basename $(notdir $@)) \ + --sysroot=/dev/null \ --out-dir $(dir $@) --emit=dep-info=$(depfile) # `--emit=obj`, `--emit=asm` and `--emit=llvm-ir` imply a single codegen unit @@ -289,7 +291,7 @@ quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(obj)/%.o: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_o_rs) + +$(call if_changed_dep,rustc_o_rs) quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ cmd_rustc_rsi_rs = \ @@ -297,19 +299,19 @@ quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@ $(obj)/%.rsi: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_rsi_rs) + +$(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=asm=$@ $< $(obj)/%.s: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_s_rs) + +$(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=llvm-ir=$@ $< $(obj)/%.ll: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_ll_rs) + +$(call if_changed_dep,rustc_ll_rs) # Compile assembler sources (.S) # --------------------------------------------------------------------------- @@ -387,6 +389,7 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler # To build objects in subdirs, we need to descend into the directories $(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ; $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ; +$(subdir-dtbslist): $(obj)/%/dtbs-list: $(obj)/% ; # # Rule to compile a set of .o files into one .a file (without symbol table) @@ -403,19 +406,21 @@ $(obj)/built-in.a: $(real-obj-y) FORCE $(call if_changed,ar_builtin) # -# Rule to create modules.order file +# Rule to create modules.order and dtbs-list # -# Create commands to either record .ko file or cat modules.order from -# a subdirectory -# Add $(obj-m) as the prerequisite to avoid updating the timestamp of -# modules.order unless contained modules are updated. +# This is a list of build artifacts (module or dtb) from the current Makefile +# and its sub-directories. The timestamp should be updated when any of the +# member files. -cmd_modules_order = { $(foreach m, $(real-prereqs), \ - $(if $(filter %/modules.order, $m), cat $m, echo $m);) :; } \ +cmd_gen_order = { $(foreach m, $(real-prereqs), \ + $(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \ > $@ $(obj)/modules.order: $(obj-m) FORCE - $(call if_changed,modules_order) + $(call if_changed,gen_order) + +$(obj)/dtbs-list: $(dtb-y) FORCE + $(call if_changed,gen_order) # # Rule to compile a set of .o files into one .a file (with symbol table) diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler index 8fcb427405a6..92be0c9a13ee 100644 --- a/scripts/Makefile.compiler +++ b/scripts/Makefile.compiler @@ -38,7 +38,7 @@ as-option = $(call try-run,\ # Usage: aflags-y += $(call as-instr,instr,option1,option2) as-instr = $(call try-run,\ - printf "%b\n" "$(1)" | $(CC) -Werror $(CLANG_FLAGS) $(KBUILD_AFLAGS) -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3)) + printf "%b\n" "$(1)" | $(CC) -Werror $(CLANG_FLAGS) $(KBUILD_AFLAGS) -Wa$(comma)--fatal-warnings -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3)) # __cc-option # Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586) diff --git a/scripts/Makefile.defconf b/scripts/Makefile.defconf index ab271b2051a2..226ea3df3b4b 100644 --- a/scripts/Makefile.defconf +++ b/scripts/Makefile.defconf @@ -9,8 +9,8 @@ # Input config fragments without '.config' suffix define merge_into_defconfig $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ - -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \ - $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config) + -m -O $(objtree) $(srctree)/arch/$(SRCARCH)/configs/$(1) \ + $(foreach config,$(2),$(srctree)/arch/$(SRCARCH)/configs/$(config).config) +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig endef @@ -23,7 +23,7 @@ endef # Input config fragments without '.config' suffix define merge_into_defconfig_override $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ - -Q -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \ - $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config) + -Q -m -O $(objtree) $(srctree)/arch/$(SRCARCH)/configs/$(1) \ + $(foreach config,$(2),$(srctree)/arch/$(SRCARCH)/configs/$(config).config) +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig endef diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst index 4405d5b67578..67956f6496a5 100644 --- a/scripts/Makefile.dtbinst +++ b/scripts/Makefile.dtbinst @@ -8,32 +8,36 @@ # $INSTALL_PATH/dtbs/$KERNELRELEASE # ========================================================================== -src := $(obj) - PHONY := __dtbs_install __dtbs_install: include include/config/auto.conf include $(srctree)/scripts/Kbuild.include -include $(kbuild-file) - -dtbs := $(addprefix $(dst)/, $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-))) -subdirs := $(addprefix $(obj)/, $(subdir-y) $(subdir-m)) -__dtbs_install: $(dtbs) $(subdirs) - @: +dst := $(INSTALL_DTBS_PATH) quiet_cmd_dtb_install = INSTALL $@ cmd_dtb_install = install -D $< $@ -$(dst)/%.dtb: $(obj)/%.dtb +$(dst)/%: $(obj)/% $(call cmd,dtb_install) -$(dst)/%.dtbo: $(obj)/%.dtbo - $(call cmd,dtb_install) +dtbs := $(patsubst $(obj)/%,%,$(call read-file, $(obj)/dtbs-list)) + +ifdef CONFIG_ARCH_WANT_FLAT_DTB_INSTALL -PHONY += $(subdirs) -$(subdirs): - $(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@)) +define gen_install_rules +$(dst)/%: $(obj)/$(1)% + $$(call cmd,dtb_install) +endef + +$(foreach d, $(sort $(dir $(dtbs))), $(eval $(call gen_install_rules,$(d)))) + +dtbs := $(notdir $(dtbs)) + +endif # CONFIG_ARCH_WANT_FLAT_DTB_INSTALL + +__dtbs_install: $(addprefix $(dst)/, $(dtbs)) + @: .PHONY: $(PHONY) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 2fe6f2828d37..c5af566e911a 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -17,6 +17,8 @@ KBUILD_CFLAGS += -Wno-format-security KBUILD_CFLAGS += -Wno-trigraphs KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) +KBUILD_CFLAGS += -Wmissing-declarations +KBUILD_CFLAGS += -Wmissing-prototypes ifneq ($(CONFIG_FRAME_WARN),0) KBUILD_CFLAGS += -Wframe-larger-than=$(CONFIG_FRAME_WARN) @@ -80,25 +82,14 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init) # Warn if there is an enum types mismatch KBUILD_CFLAGS += $(call cc-option,-Wenum-conversion) -# backward compatibility -KBUILD_EXTRA_WARN ?= $(KBUILD_ENABLE_EXTRA_GCC_CHECKS) - -ifeq ("$(origin W)", "command line") - KBUILD_EXTRA_WARN := $(W) -endif - -export KBUILD_EXTRA_WARN - # # W=1 - warnings which may be relevant and do not occur too often # ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),) KBUILD_CFLAGS += -Wextra -Wunused -Wno-unused-parameter -KBUILD_CFLAGS += -Wmissing-declarations KBUILD_CFLAGS += $(call cc-option, -Wrestrict) KBUILD_CFLAGS += -Wmissing-format-attribute -KBUILD_CFLAGS += -Wmissing-prototypes KBUILD_CFLAGS += -Wold-style-definition KBUILD_CFLAGS += -Wmissing-include-dirs KBUILD_CFLAGS += $(call cc-option, -Wunused-but-set-variable) @@ -106,7 +97,6 @@ KBUILD_CFLAGS += $(call cc-option, -Wunused-const-variable) KBUILD_CFLAGS += $(call cc-option, -Wpacked-not-aligned) KBUILD_CFLAGS += $(call cc-option, -Wformat-overflow) KBUILD_CFLAGS += $(call cc-option, -Wformat-truncation) -KBUILD_CFLAGS += $(call cc-option, -Wstringop-overflow) KBUILD_CFLAGS += $(call cc-option, -Wstringop-truncation) KBUILD_CPPFLAGS += -Wundef @@ -122,9 +112,10 @@ KBUILD_CFLAGS += $(call cc-disable-warning, restrict) KBUILD_CFLAGS += $(call cc-disable-warning, packed-not-aligned) KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) -KBUILD_CFLAGS += $(call cc-disable-warning, stringop-overflow) KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) +KBUILD_CFLAGS += -Wno-override-init # alias for -Wno-initializer-overrides in clang + ifdef CONFIG_CC_IS_CLANG # Clang before clang-16 would warn on default argument promotions. ifneq ($(call clang-min-version, 160000),y) @@ -143,6 +134,8 @@ 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) +KBUILD_CFLAGS += -Wno-enum-compare-conditional +KBUILD_CFLAGS += -Wno-enum-enum-conversion endif endif @@ -160,10 +153,6 @@ KBUILD_CFLAGS += -Wtype-limits KBUILD_CFLAGS += $(call cc-option, -Wmaybe-uninitialized) KBUILD_CFLAGS += $(call cc-option, -Wunused-macros) -ifdef CONFIG_CC_IS_CLANG -KBUILD_CFLAGS += -Winitializer-overrides -endif - KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN2 else @@ -173,9 +162,7 @@ KBUILD_CFLAGS += -Wno-missing-field-initializers KBUILD_CFLAGS += -Wno-type-limits KBUILD_CFLAGS += -Wno-shift-negative-value -ifdef CONFIG_CC_IS_CLANG -KBUILD_CFLAGS += -Wno-initializer-overrides -else +ifdef CONFIG_CC_IS_GCC KBUILD_CFLAGS += -Wno-maybe-uninitialized endif @@ -196,7 +183,6 @@ KBUILD_CFLAGS += -Wpointer-arith KBUILD_CFLAGS += -Wredundant-decls KBUILD_CFLAGS += -Wsign-compare KBUILD_CFLAGS += -Wswitch-default -KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat) KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3 diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 08d83d9db31a..3c17e6ba421c 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -156,7 +156,7 @@ quiet_cmd_host-rust = HOSTRUSTC $@ cmd_host-rust = \ $(HOSTRUSTC) $(hostrust_flags) --emit=link=$@ $< $(host-rust): $(obj)/%: $(src)/%.rs FORCE - $(call if_changed_dep,host-rust) + +$(call if_changed_dep,host-rust) targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \ $(host-cxxmulti) $(host-cxxobjs) $(host-rust) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 1a965fe68e01..3179747cbd2c 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -45,6 +45,11 @@ else obj-y := $(filter-out %/, $(obj-y)) endif +ifdef need-dtbslist +dtb-y += $(addsuffix /dtbs-list, $(subdir-ym)) +always-y += dtbs-list +endif + # Expand $(foo-objs) $(foo-y) etc. by replacing their individuals suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s)))) # List composite targets that are constructed by combining other targets @@ -83,8 +88,8 @@ dtb-$(CONFIG_OF_ALL_DTBS) += $(dtb-) multi-dtb-y := $(call multi-search, $(dtb-y), .dtb, -dtbs) # Primitive DTB compiled from *.dts real-dtb-y := $(call real-search, $(dtb-y), .dtb, -dtbs) -# Base DTB that overlay is applied onto (each first word of $(*-dtbs) expansion) -base-dtb-y := $(foreach m, $(multi-dtb-y), $(firstword $(call suffix-search, $m, .dtb, -dtbs))) +# Base DTB that overlay is applied onto +base-dtb-y := $(filter %.dtb, $(call real-search, $(multi-dtb-y), .dtb, -dtbs)) always-y += $(dtb-y) @@ -99,6 +104,7 @@ lib-y := $(addprefix $(obj)/,$(lib-y)) real-obj-y := $(addprefix $(obj)/,$(real-obj-y)) real-obj-m := $(addprefix $(obj)/,$(real-obj-m)) multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m)) +dtb-y := $(addprefix $(obj)/, $(dtb-y)) multi-dtb-y := $(addprefix $(obj)/, $(multi-dtb-y)) real-dtb-y := $(addprefix $(obj)/, $(real-dtb-y)) subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) @@ -148,7 +154,7 @@ _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds) # ifeq ($(CONFIG_GCOV_KERNEL),y) _c_flags += $(if $(patsubst n%,, \ - $(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \ + $(GCOV_PROFILE_$(target-stem).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \ $(CFLAGS_GCOV)) endif @@ -159,29 +165,32 @@ endif ifeq ($(CONFIG_KASAN),y) ifneq ($(CONFIG_KASAN_HW_TAGS),y) _c_flags += $(if $(patsubst n%,, \ - $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ + $(KASAN_SANITIZE_$(target-stem).o)$(KASAN_SANITIZE)y), \ $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE)) endif endif ifeq ($(CONFIG_KMSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \ + $(KMSAN_SANITIZE_$(target-stem).o)$(KMSAN_SANITIZE)y), \ $(CFLAGS_KMSAN)) _c_flags += $(if $(patsubst n%,, \ - $(KMSAN_ENABLE_CHECKS_$(basetarget).o)$(KMSAN_ENABLE_CHECKS)y), \ + $(KMSAN_ENABLE_CHECKS_$(target-stem).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)), \ + $(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SANITIZE)y), \ $(CFLAGS_UBSAN)) +_c_flags += $(if $(patsubst n%,, \ + $(UBSAN_SIGNED_WRAP_$(target-stem).o)$(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)y), \ + $(CFLAGS_UBSAN_SIGNED_WRAP)) endif ifeq ($(CONFIG_KCOV),y) _c_flags += $(if $(patsubst n%,, \ - $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \ + $(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \ $(CFLAGS_KCOV)) endif @@ -191,12 +200,12 @@ endif # ifeq ($(CONFIG_KCSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(KCSAN_SANITIZE_$(basetarget).o)$(KCSAN_SANITIZE)y), \ + $(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)y), \ $(CFLAGS_KCSAN)) # Some uninstrumented files provide implied barriers required to avoid false # positives: set KCSAN_INSTRUMENT_BARRIERS for barrier instrumentation only. _c_flags += $(if $(patsubst n%,, \ - $(KCSAN_INSTRUMENT_BARRIERS_$(basetarget).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \ + $(KCSAN_INSTRUMENT_BARRIERS_$(target-stem).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \ -D__KCSAN_INSTRUMENT_BARRIERS__) endif @@ -254,7 +263,7 @@ 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_CALL_DEPTH_TRACKING) += --hacks=skylake +objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) += --hacks=skylake objtool-args-$(CONFIG_X86_KERNEL_IBT) += --ibt objtool-args-$(CONFIG_FINEIBT) += --cfi objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL) += --mcount @@ -262,9 +271,9 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT) += --mnop endif objtool-args-$(CONFIG_UNWINDER_ORC) += --orc -objtool-args-$(CONFIG_RETPOLINE) += --retpoline -objtool-args-$(CONFIG_RETHUNK) += --rethunk -objtool-args-$(CONFIG_SLS) += --sls +objtool-args-$(CONFIG_MITIGATION_RETPOLINE) += --retpoline +objtool-args-$(CONFIG_MITIGATION_RETHUNK) += --rethunk +objtool-args-$(CONFIG_MITIGATION_SLS) += --sls objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess @@ -340,7 +349,7 @@ quiet_cmd_gzip = GZIP $@ # DTC # --------------------------------------------------------------------------- DTC ?= $(objtree)/scripts/dtc/dtc -DTC_FLAGS += -Wno-interrupt_provider \ +DTC_FLAGS += \ -Wno-unique_unit_address # Disable noisy checks by default @@ -358,11 +367,10 @@ endif ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),) DTC_FLAGS += -Wnode_name_chars_strict \ -Wproperty_name_chars_strict \ - -Winterrupt_provider \ -Wunique_unit_address endif -DTC_FLAGS += $(DTC_FLAGS_$(basetarget)) +DTC_FLAGS += $(DTC_FLAGS_$(target-stem)) # Set -@ if the target is a base DTB that overlay is applied onto DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@) diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 8568d256d6fb..79fcf2731686 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -23,7 +23,7 @@ modname = $(notdir $(@:.mod.o=)) part-of-module = y quiet_cmd_cc_o_c = CC [M] $@ - cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI) $(CFLAGS_GCOV), $(c_flags)) -c -o $@ $< + cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI) $(CFLAGS_GCOV) $(CFLAGS_KCSAN), $(c_flags)) -c -o $@ $< %.mod.o: %.mod.c FORCE $(call if_changed_dep,cc_o_c) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 3addd1c0b989..38653f3e8108 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -4,27 +4,6 @@ include $(srctree)/scripts/Kbuild.include include $(srctree)/scripts/Makefile.lib -KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE)) -# Include only those top-level files that are needed by make, plus the GPL copy -TAR_CONTENT := Documentation LICENSES arch block certs crypto drivers fs \ - include init io_uring ipc kernel lib mm net rust \ - samples scripts security sound tools usr virt \ - .config Makefile \ - Kbuild Kconfig COPYING $(wildcard localversion*) - -quiet_cmd_src_tar = TAR $(2).tar.gz - cmd_src_tar = \ -if test "$(objtree)" != "$(srctree)"; then \ - echo >&2; \ - echo >&2 " ERROR:"; \ - echo >&2 " Building source tarball is not possible outside the"; \ - echo >&2 " kernel source tree. Don't set KBUILD_OUTPUT"; \ - echo >&2; \ - false; \ -fi ; \ -tar -I $(KGZIP) -c $(RCS_TAR_IGNORE) -f $(2).tar.gz \ - --transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3) - # Git # --------------------------------------------------------------------------- @@ -130,8 +109,6 @@ debian-orig: linux.tar$(debian-orig-suffix) debian cp $< ../$(orig-name); \ fi -KBUILD_PKG_ROOTCMD ?= 'fakeroot -u' - PHONY += deb-pkg srcdeb-pkg bindeb-pkg deb-pkg: private build-type := source,binary @@ -146,7 +123,7 @@ deb-pkg srcdeb-pkg bindeb-pkg: $(if $(findstring source, $(build-type)), \ --unsigned-source --compression=$(KDEB_SOURCE_COMPRESS)) \ $(if $(findstring binary, $(build-type)), \ - --rules-file='$(MAKE) -f debian/rules' --jobs=1 -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch), \ + -R'$(MAKE) -f debian/rules' -j1 -a$$(cat debian/arch), \ --no-check-builddeps) \ $(DPKG_FLAGS)) @@ -157,9 +134,8 @@ snap-pkg: rm -rf $(objtree)/snap mkdir $(objtree)/snap $(MAKE) clean - $(call cmd,src_tar,$(KERNELPATH)) sed "s@KERNELRELEASE@$(KERNELRELEASE)@; \ - s@SRCTREE@$(shell realpath $(KERNELPATH).tar.gz)@" \ + s@SRCTREE@$(realpath $(srctree))@" \ $(srctree)/scripts/package/snapcraft.template > \ $(objtree)/snap/snapcraft.yaml cd $(objtree)/snap && \ diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 4749865c1b2c..b2d3b273b802 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -10,6 +10,9 @@ ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum -ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error +ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error) export CFLAGS_UBSAN := $(ubsan-cflags-y) + +ubsan-signed-wrap-cflags-$(CONFIG_UBSAN_SIGNED_WRAP) += -fsanitize=signed-integer-overflow +export CFLAGS_UBSAN_SIGNED_WRAP := $(ubsan-signed-wrap-cflags-y) diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o index 25b3b587d37c..6de297916ce6 100644 --- a/scripts/Makefile.vmlinux_o +++ b/scripts/Makefile.vmlinux_o @@ -38,7 +38,7 @@ 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 $(or $(CONFIG_CPU_UNRET_ENTRY),$(CONFIG_CPU_SRSO)), --unret) + $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret) objtool-args = $(vmlinux-objtool-args-y) --link diff --git a/scripts/atomic/kerneldoc/add_unless b/scripts/atomic/kerneldoc/add_unless index f828e5f6750c..fbc2fadfbdc4 100644 --- a/scripts/atomic/kerneldoc/add_unless +++ b/scripts/atomic/kerneldoc/add_unless @@ -10,6 +10,7 @@ cat <<EOF * @u: ${int} value to compare with * * If (@v != @u), atomically updates @v to (@v + @a) with ${desc_order} ordering. + * Otherwise, @v is not modified and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/atomic/kerneldoc/cmpxchg b/scripts/atomic/kerneldoc/cmpxchg index 3bce328f50cf..02b24ee9d8a4 100644 --- a/scripts/atomic/kerneldoc/cmpxchg +++ b/scripts/atomic/kerneldoc/cmpxchg @@ -6,6 +6,7 @@ cat <<EOF * @new: ${int} value to assign * * If (@v == @old), atomically updates @v to @new with ${desc_order} ordering. + * Otherwise, @v is not modified and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/atomic/kerneldoc/dec_if_positive b/scripts/atomic/kerneldoc/dec_if_positive index 04f1aed3cf83..9468b4a69603 100644 --- a/scripts/atomic/kerneldoc/dec_if_positive +++ b/scripts/atomic/kerneldoc/dec_if_positive @@ -4,6 +4,7 @@ cat <<EOF * @v: pointer to ${atomic}_t * * If (@v > 0), atomically updates @v to (@v - 1) with ${desc_order} ordering. + * Otherwise, @v is not modified and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/atomic/kerneldoc/dec_unless_positive b/scripts/atomic/kerneldoc/dec_unless_positive index ee73612f0354..06a678678f71 100644 --- a/scripts/atomic/kerneldoc/dec_unless_positive +++ b/scripts/atomic/kerneldoc/dec_unless_positive @@ -4,6 +4,7 @@ cat <<EOF * @v: pointer to ${atomic}_t * * If (@v <= 0), atomically updates @v to (@v - 1) with ${desc_order} ordering. + * Otherwise, @v is not modified and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/atomic/kerneldoc/inc_not_zero b/scripts/atomic/kerneldoc/inc_not_zero index 618be08e653e..c1a30fc66ee9 100644 --- a/scripts/atomic/kerneldoc/inc_not_zero +++ b/scripts/atomic/kerneldoc/inc_not_zero @@ -4,6 +4,7 @@ cat <<EOF * @v: pointer to ${atomic}_t * * If (@v != 0), atomically updates @v to (@v + 1) with ${desc_order} ordering. + * Otherwise, @v is not modified and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/atomic/kerneldoc/inc_unless_negative b/scripts/atomic/kerneldoc/inc_unless_negative index 597f23d4dc8d..ece0d2c7b38f 100644 --- a/scripts/atomic/kerneldoc/inc_unless_negative +++ b/scripts/atomic/kerneldoc/inc_unless_negative @@ -4,6 +4,7 @@ cat <<EOF * @v: pointer to ${atomic}_t * * If (@v >= 0), atomically updates @v to (@v + 1) with ${desc_order} ordering. + * Otherwise, @v is not modified and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/atomic/kerneldoc/try_cmpxchg b/scripts/atomic/kerneldoc/try_cmpxchg index 296553206c06..3ccff29538f5 100644 --- a/scripts/atomic/kerneldoc/try_cmpxchg +++ b/scripts/atomic/kerneldoc/try_cmpxchg @@ -6,7 +6,8 @@ cat <<EOF * @new: ${int} value to assign * * If (@v == @old), atomically updates @v to @new with ${desc_order} ordering. - * Otherwise, updates @old to the current value of @v. + * Otherwise, @v is not modified, @old is updated to the current value of @v, + * and relaxed ordering is provided. * * ${desc_noinstr} * diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index 61b7dddedc46..c55878bddfdd 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -414,8 +414,8 @@ class PrinterRST(Printer): version = version.stdout.decode().rstrip() except: try: - version = subprocess.run(['make', 'kernelversion'], cwd=linuxRoot, - capture_output=True, check=True) + version = subprocess.run(['make', '-s', '--no-print-directory', 'kernelversion'], + cwd=linuxRoot, capture_output=True, check=True) version = version.stdout.decode().rstrip() except: return 'Linux' @@ -513,7 +513,7 @@ eBPF programs can have an associated license, passed along with the bytecode instructions to the kernel when the programs are loaded. The format for that string is identical to the one in use for kernel modules (Dual licenses, such as "Dual BSD/GPL", may be used). Some helper functions are only accessible to -programs that are compatible with the GNU Privacy License (GPL). +programs that are compatible with the GNU General Public License (GNU GPL). In order to use such helpers, the eBPF program must be loaded with the correct license string passed (via **attr**) to the **bpf**\\ () system call, and this @@ -827,7 +827,7 @@ class PrinterHelpers(Printer): print(' *{}{}'.format(' \t' if line else '', line)) print(' */') - print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), + print('static %s %s(* const %s)(' % (self.map_type(proto['ret_type']), proto['ret_star'], proto['name']), end='') comma = '' for i, a in enumerate(proto['args']): diff --git a/scripts/check-sysctl-docs b/scripts/check-sysctl-docs index 4f163e0bf6a4..20274c63e745 100755 --- a/scripts/check-sysctl-docs +++ b/scripts/check-sysctl-docs @@ -8,7 +8,7 @@ # Example invocation: # scripts/check-sysctl-docs -vtable="kernel" \ # Documentation/admin-guide/sysctl/kernel.rst \ -# $(git grep -l register_sysctl_) +# $(git grep -l register_sysctl) # # Specify -vdebug=1 to see debugging information @@ -20,14 +20,10 @@ BEGIN { } # The following globals are used: -# children: maps ctl_table names and procnames to child ctl_table names # documented: maps documented entries (each key is an entry) # entries: maps ctl_table names and procnames to counts (so # enumerating the subkeys for a given ctl_table lists its # procnames) -# files: maps procnames to source file names -# paths: maps ctl_path names to paths -# curpath: the name of the current ctl_path struct # curtable: the name of the current ctl_table struct # curentry: the name of the current proc entry (procname when parsing # a ctl_table, constructed path when parsing a ctl_path) @@ -94,42 +90,23 @@ FNR == NR { # Stage 2: process each file and find all sysctl tables BEGINFILE { - delete children delete entries - delete paths - curpath = "" curtable = "" curentry = "" + delete vars if (debug) print "Processing file " FILENAME } -/^static struct ctl_path/ { - match($0, /static struct ctl_path ([^][]+)/, tables) - curpath = tables[1] - if (debug) print "Processing path " curpath -} - -/^static struct ctl_table/ { - match($0, /static struct ctl_table ([^][]+)/, tables) - curtable = tables[1] +/^static( const)? struct ctl_table/ { + match($0, /static( const)? struct ctl_table ([^][]+)/, tables) + curtable = tables[2] if (debug) print "Processing table " curtable } /^};$/ { - curpath = "" curtable = "" curentry = "" -} - -curpath && /\.procname[\t ]*=[\t ]*".+"/ { - match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) - if (curentry) { - curentry = curentry "/" names[1] - } else { - curentry = names[1] - } - if (debug) print "Setting path " curpath " to " curentry - paths[curpath] = curentry + delete vars } curtable && /\.procname[\t ]*=[\t ]*".+"/ { @@ -140,10 +117,32 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ { file[curentry] = FILENAME } -/\.child[\t ]*=/ { - child = trimpunct($NF) - if (debug) print "Linking child " child " to table " curtable " entry " curentry - children[curtable][curentry] = child +/register_sysctl.*/ { + match($0, /register_sysctl(|_init|_sz)\("([^"]+)" *, *([^,)]+)/, tables) + if (debug) print "Registering table " tables[3] " at " tables[2] + if (tables[2] == table) { + for (entry in entries[tables[3]]) { + printentry(entry) + } + } +} + +/kmemdup.*/ { + match($0, /([^ \t]+) *= *kmemdup\(([^,]+) *,/, names) + if (debug) print "Found variable " names[1] " for table " names[2] + if (names[2] in entries) { + vars[names[1]] = names[2] + } +} + +/__register_sysctl_table.*/ { + match($0, /__register_sysctl_table\([^,]+, *"([^"]+)" *, *([^,]+)/, tables) + if (debug) print "Registering variable table " tables[2] " at " tables[1] + if (tables[1] == table && tables[2] in vars) { + for (entry in entries[vars[tables[2]]]) { + printentry(entry) + } + } } END { diff --git a/scripts/check-uapi.sh b/scripts/check-uapi.sh new file mode 100755 index 000000000000..955581735cb3 --- /dev/null +++ b/scripts/check-uapi.sh @@ -0,0 +1,573 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only +# Script to check commits for UAPI backwards compatibility + +set -o errexit +set -o pipefail + +print_usage() { + name=$(basename "$0") + cat << EOF +$name - check for UAPI header stability across Git commits + +By default, the script will check to make sure the latest commit (or current +dirty changes) did not introduce ABI changes when compared to HEAD^1. You can +check against additional commit ranges with the -b and -p options. + +The script will not check UAPI headers for architectures other than the one +defined in ARCH. + +Usage: $name [-b BASE_REF] [-p PAST_REF] [-j N] [-l ERROR_LOG] [-i] [-q] [-v] + +Options: + -b BASE_REF Base git reference to use for comparison. If unspecified or empty, + will use any dirty changes in tree to UAPI files. If there are no + dirty changes, HEAD will be used. + -p PAST_REF Compare BASE_REF to PAST_REF (e.g. -p v6.1). If unspecified or empty, + will use BASE_REF^1. Must be an ancestor of BASE_REF. Only headers + that exist on PAST_REF will be checked for compatibility. + -j JOBS Number of checks to run in parallel (default: number of CPU cores). + -l ERROR_LOG Write error log to file (default: no error log is generated). + -i Ignore ambiguous changes that may or may not break UAPI compatibility. + -q Quiet operation. + -v Verbose operation (print more information about each header being checked). + +Environmental args: + ABIDIFF Custom path to abidiff binary + CC C compiler (default is "gcc") + ARCH Target architecture for the UAPI check (default is host arch) + +Exit codes: + $SUCCESS) Success + $FAIL_ABI) ABI difference detected + $FAIL_PREREQ) Prerequisite not met +EOF +} + +readonly SUCCESS=0 +readonly FAIL_ABI=1 +readonly FAIL_PREREQ=2 + +# Print to stderr +eprintf() { + # shellcheck disable=SC2059 + printf "$@" >&2 +} + +# Expand an array with a specific character (similar to Python string.join()) +join() { + local IFS="$1" + shift + printf "%s" "$*" +} + +# Create abidiff suppressions +gen_suppressions() { + # Common enum variant names which we don't want to worry about + # being shifted when new variants are added. + local -a enum_regex=( + ".*_AFTER_LAST$" + ".*_CNT$" + ".*_COUNT$" + ".*_END$" + ".*_LAST$" + ".*_MASK$" + ".*_MAX$" + ".*_MAX_BIT$" + ".*_MAX_BPF_ATTACH_TYPE$" + ".*_MAX_ID$" + ".*_MAX_SHIFT$" + ".*_NBITS$" + ".*_NETDEV_NUMHOOKS$" + ".*_NFT_META_IIFTYPE$" + ".*_NL80211_ATTR$" + ".*_NLDEV_NUM_OPS$" + ".*_NUM$" + ".*_NUM_ELEMS$" + ".*_NUM_IRQS$" + ".*_SIZE$" + ".*_TLSMAX$" + "^MAX_.*" + "^NUM_.*" + ) + + # Common padding field names which can be expanded into + # without worrying about users. + local -a padding_regex=( + ".*end$" + ".*pad$" + ".*pad[0-9]?$" + ".*pad_[0-9]?$" + ".*padding$" + ".*padding[0-9]?$" + ".*padding_[0-9]?$" + ".*res$" + ".*resv$" + ".*resv[0-9]?$" + ".*resv_[0-9]?$" + ".*reserved$" + ".*reserved[0-9]?$" + ".*reserved_[0-9]?$" + ".*rsvd[0-9]?$" + ".*unused$" + ) + + cat << EOF +[suppress_type] + type_kind = enum + changed_enumerators_regexp = $(join , "${enum_regex[@]}") +EOF + + for p in "${padding_regex[@]}"; do + cat << EOF +[suppress_type] + type_kind = struct + has_data_member_inserted_at = offset_of_first_data_member_regexp(${p}) +EOF + done + +if [ "$IGNORE_AMBIGUOUS_CHANGES" = "true" ]; then + cat << EOF +[suppress_type] + type_kind = struct + has_data_member_inserted_at = end + has_size_change = yes +EOF +fi +} + +# Check if git tree is dirty +tree_is_dirty() { + ! git diff --quiet +} + +# Get list of files installed in $ref +get_file_list() { + local -r ref="$1" + local -r tree="$(get_header_tree "$ref")" + + # Print all installed headers, filtering out ones that can't be compiled + find "$tree" -type f -name '*.h' -printf '%P\n' | grep -v -f "$INCOMPAT_LIST" +} + +# Add to the list of incompatible headers +add_to_incompat_list() { + local -r ref="$1" + + # Start with the usr/include/Makefile to get a list of the headers + # that don't compile using this method. + if [ ! -f usr/include/Makefile ]; then + eprintf "error - no usr/include/Makefile present at %s\n" "$ref" + eprintf "Note: usr/include/Makefile was added in the v5.3 kernel release\n" + exit "$FAIL_PREREQ" + fi + { + # shellcheck disable=SC2016 + printf 'all: ; @echo $(no-header-test)\n' + cat usr/include/Makefile + } | SRCARCH="$ARCH" make --always-make -f - | tr " " "\n" \ + | grep -v "asm-generic" >> "$INCOMPAT_LIST" + + # The makefile also skips all asm-generic files, but prints "asm-generic/%" + # which won't work for our grep match. Instead, print something grep will match. + printf "asm-generic/.*\.h\n" >> "$INCOMPAT_LIST" +} + +# Compile the simple test app +do_compile() { + local -r inc_dir="$1" + local -r header="$2" + local -r out="$3" + printf "int main(void) { return 0; }\n" | \ + "$CC" -c \ + -o "$out" \ + -x c \ + -O0 \ + -std=c90 \ + -fno-eliminate-unused-debug-types \ + -g \ + "-I${inc_dir}" \ + -include "$header" \ + - +} + +# Run make headers_install +run_make_headers_install() { + local -r ref="$1" + local -r install_dir="$(get_header_tree "$ref")" + make -j "$MAX_THREADS" ARCH="$ARCH" INSTALL_HDR_PATH="$install_dir" \ + headers_install > /dev/null +} + +# Install headers for both git refs +install_headers() { + local -r base_ref="$1" + local -r past_ref="$2" + + for ref in "$base_ref" "$past_ref"; do + printf "Installing user-facing UAPI headers from %s... " "${ref:-dirty tree}" + if [ -n "$ref" ]; then + git archive --format=tar --prefix="${ref}-archive/" "$ref" \ + | (cd "$TMP_DIR" && tar xf -) + ( + cd "${TMP_DIR}/${ref}-archive" + run_make_headers_install "$ref" + add_to_incompat_list "$ref" "$INCOMPAT_LIST" + ) + else + run_make_headers_install "$ref" + add_to_incompat_list "$ref" "$INCOMPAT_LIST" + fi + printf "OK\n" + done + sort -u -o "$INCOMPAT_LIST" "$INCOMPAT_LIST" + sed -i -e '/^$/d' "$INCOMPAT_LIST" +} + +# Print the path to the headers_install tree for a given ref +get_header_tree() { + local -r ref="$1" + printf "%s" "${TMP_DIR}/${ref}/usr" +} + +# Check file list for UAPI compatibility +check_uapi_files() { + local -r base_ref="$1" + local -r past_ref="$2" + local -r abi_error_log="$3" + + local passed=0; + local failed=0; + local -a threads=() + set -o errexit + + printf "Checking changes to UAPI headers between %s and %s...\n" "$past_ref" "${base_ref:-dirty tree}" + # Loop over all UAPI headers that were installed by $past_ref (if they only exist on $base_ref, + # there's no way they're broken and no way to compare anyway) + while read -r file; do + if [ "${#threads[@]}" -ge "$MAX_THREADS" ]; then + if wait "${threads[0]}"; then + passed=$((passed + 1)) + else + failed=$((failed + 1)) + fi + threads=("${threads[@]:1}") + fi + + check_individual_file "$base_ref" "$past_ref" "$file" & + threads+=("$!") + done < <(get_file_list "$past_ref") + + for t in "${threads[@]}"; do + if wait "$t"; then + passed=$((passed + 1)) + else + failed=$((failed + 1)) + fi + done + + if [ -n "$abi_error_log" ]; then + printf 'Generated by "%s %s" from git ref %s\n\n' \ + "$0" "$*" "$(git rev-parse HEAD)" > "$abi_error_log" + fi + + while read -r error_file; do + { + cat "$error_file" + printf "\n\n" + } | tee -a "${abi_error_log:-/dev/null}" >&2 + done < <(find "$TMP_DIR" -type f -name '*.error' | sort) + + total="$((passed + failed))" + if [ "$failed" -gt 0 ]; then + eprintf "error - %d/%d UAPI headers compatible with %s appear _not_ to be backwards compatible\n" \ + "$failed" "$total" "$ARCH" + if [ -n "$abi_error_log" ]; then + eprintf "Failure summary saved to %s\n" "$abi_error_log" + fi + else + printf "All %d UAPI headers compatible with %s appear to be backwards compatible\n" \ + "$total" "$ARCH" + fi + + return "$failed" +} + +# Check an individual file for UAPI compatibility +check_individual_file() { + local -r base_ref="$1" + local -r past_ref="$2" + local -r file="$3" + + local -r base_header="$(get_header_tree "$base_ref")/${file}" + local -r past_header="$(get_header_tree "$past_ref")/${file}" + + if [ ! -f "$base_header" ]; then + mkdir -p "$(dirname "$base_header")" + printf "==== UAPI header %s was removed between %s and %s ====" \ + "$file" "$past_ref" "$base_ref" \ + > "${base_header}.error" + return 1 + fi + + compare_abi "$file" "$base_header" "$past_header" "$base_ref" "$past_ref" +} + +# Perform the A/B compilation and compare output ABI +compare_abi() { + local -r file="$1" + local -r base_header="$2" + local -r past_header="$3" + local -r base_ref="$4" + local -r past_ref="$5" + local -r log="${TMP_DIR}/log/${file}.log" + local -r error_log="${TMP_DIR}/log/${file}.error" + + mkdir -p "$(dirname "$log")" + + if ! do_compile "$(get_header_tree "$base_ref")/include" "$base_header" "${base_header}.bin" 2> "$log"; then + { + warn_str=$(printf "==== Could not compile version of UAPI header %s at %s ====\n" \ + "$file" "$base_ref") + printf "%s\n" "$warn_str" + cat "$log" + printf -- "=%.0s" $(seq 0 ${#warn_str}) + } > "$error_log" + return 1 + fi + + if ! do_compile "$(get_header_tree "$past_ref")/include" "$past_header" "${past_header}.bin" 2> "$log"; then + { + warn_str=$(printf "==== Could not compile version of UAPI header %s at %s ====\n" \ + "$file" "$past_ref") + printf "%s\n" "$warn_str" + cat "$log" + printf -- "=%.0s" $(seq 0 ${#warn_str}) + } > "$error_log" + return 1 + fi + + local ret=0 + "$ABIDIFF" --non-reachable-types \ + --suppressions "$SUPPRESSIONS" \ + "${past_header}.bin" "${base_header}.bin" > "$log" || ret="$?" + if [ "$ret" -eq 0 ]; then + if [ "$VERBOSE" = "true" ]; then + printf "No ABI differences detected in %s from %s -> %s\n" \ + "$file" "$past_ref" "$base_ref" + fi + else + # Bits in abidiff's return code can be used to determine the type of error + if [ $((ret & 0x2)) -gt 0 ]; then + eprintf "error - abidiff did not run properly\n" + exit 1 + fi + + if [ "$IGNORE_AMBIGUOUS_CHANGES" = "true" ] && [ "$ret" -eq 4 ]; then + return 0 + fi + + # If the only changes were additions (not modifications to existing APIs), then + # there's no problem. Ignore these diffs. + if grep "Unreachable types summary" "$log" | grep -q "0 removed" && + grep "Unreachable types summary" "$log" | grep -q "0 changed"; then + return 0 + fi + + { + warn_str=$(printf "==== ABI differences detected in %s from %s -> %s ====" \ + "$file" "$past_ref" "$base_ref") + printf "%s\n" "$warn_str" + sed -e '/summary:/d' -e '/changed type/d' -e '/^$/d' -e 's/^/ /g' "$log" + printf -- "=%.0s" $(seq 0 ${#warn_str}) + if cmp "$past_header" "$base_header" > /dev/null 2>&1; then + printf "\n%s did not change between %s and %s...\n" "$file" "$past_ref" "${base_ref:-dirty tree}" + printf "It's possible a change to one of the headers it includes caused this error:\n" + grep '^#include' "$base_header" + printf "\n" + fi + } > "$error_log" + + return 1 + fi +} + +# Check that a minimum software version number is satisfied +min_version_is_satisfied() { + local -r min_version="$1" + local -r version_installed="$2" + + printf "%s\n%s\n" "$min_version" "$version_installed" \ + | sort -Vc > /dev/null 2>&1 +} + +# Make sure we have the tools we need and the arguments make sense +check_deps() { + ABIDIFF="${ABIDIFF:-abidiff}" + CC="${CC:-gcc}" + ARCH="${ARCH:-$(uname -m)}" + if [ "$ARCH" = "x86_64" ]; then + ARCH="x86" + fi + + local -r abidiff_min_version="2.4" + local -r libdw_min_version_if_clang="0.171" + + if ! command -v "$ABIDIFF" > /dev/null 2>&1; then + eprintf "error - abidiff not found!\n" + eprintf "Please install abigail-tools version %s or greater\n" "$abidiff_min_version" + eprintf "See: https://sourceware.org/libabigail/manual/libabigail-overview.html\n" + return 1 + fi + + local -r abidiff_version="$("$ABIDIFF" --version | cut -d ' ' -f 2)" + if ! min_version_is_satisfied "$abidiff_min_version" "$abidiff_version"; then + eprintf "error - abidiff version too old: %s\n" "$abidiff_version" + eprintf "Please install abigail-tools version %s or greater\n" "$abidiff_min_version" + eprintf "See: https://sourceware.org/libabigail/manual/libabigail-overview.html\n" + return 1 + fi + + if ! command -v "$CC" > /dev/null 2>&1; then + eprintf 'error - %s not found\n' "$CC" + return 1 + fi + + if "$CC" --version | grep -q clang; then + local -r libdw_version="$(ldconfig -v 2>/dev/null | grep -v SKIPPED | grep -m 1 -o 'libdw-[0-9]\+.[0-9]\+' | cut -c 7-)" + if ! min_version_is_satisfied "$libdw_min_version_if_clang" "$libdw_version"; then + eprintf "error - libdw version too old for use with clang: %s\n" "$libdw_version" + eprintf "Please install libdw from elfutils version %s or greater\n" "$libdw_min_version_if_clang" + eprintf "See: https://sourceware.org/elfutils/\n" + return 1 + fi + fi + + if [ ! -d "arch/${ARCH}" ]; then + eprintf 'error - ARCH "%s" is not a subdirectory under arch/\n' "$ARCH" + eprintf "Please set ARCH to one of:\n%s\n" "$(find arch -maxdepth 1 -mindepth 1 -type d -printf '%f ' | fmt)" + return 1 + fi + + if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then + eprintf "error - this script requires the kernel tree to be initialized with Git\n" + return 1 + fi + + if ! git rev-parse --verify "$past_ref" > /dev/null 2>&1; then + printf 'error - invalid git reference "%s"\n' "$past_ref" + return 1 + fi + + if [ -n "$base_ref" ]; then + if ! git merge-base --is-ancestor "$past_ref" "$base_ref" > /dev/null 2>&1; then + printf 'error - "%s" is not an ancestor of base ref "%s"\n' "$past_ref" "$base_ref" + return 1 + fi + if [ "$(git rev-parse "$base_ref")" = "$(git rev-parse "$past_ref")" ]; then + printf 'error - "%s" and "%s" are the same reference\n' "$past_ref" "$base_ref" + return 1 + fi + fi +} + +run() { + local base_ref="$1" + local past_ref="$2" + local abi_error_log="$3" + shift 3 + + if [ -z "$KERNEL_SRC" ]; then + KERNEL_SRC="$(realpath "$(dirname "$0")"/..)" + fi + + cd "$KERNEL_SRC" + + if [ -z "$base_ref" ] && ! tree_is_dirty; then + base_ref=HEAD + fi + + if [ -z "$past_ref" ]; then + if [ -n "$base_ref" ]; then + past_ref="${base_ref}^1" + else + past_ref=HEAD + fi + fi + + if ! check_deps; then + exit "$FAIL_PREREQ" + fi + + TMP_DIR=$(mktemp -d) + readonly TMP_DIR + trap 'rm -rf "$TMP_DIR"' EXIT + + readonly INCOMPAT_LIST="${TMP_DIR}/incompat_list.txt" + touch "$INCOMPAT_LIST" + + readonly SUPPRESSIONS="${TMP_DIR}/suppressions.txt" + gen_suppressions > "$SUPPRESSIONS" + + # Run make install_headers for both refs + install_headers "$base_ref" "$past_ref" + + # Check for any differences in the installed header trees + if diff -r -q "$(get_header_tree "$base_ref")" "$(get_header_tree "$past_ref")" > /dev/null 2>&1; then + printf "No changes to UAPI headers were applied between %s and %s\n" "$past_ref" "${base_ref:-dirty tree}" + exit "$SUCCESS" + fi + + if ! check_uapi_files "$base_ref" "$past_ref" "$abi_error_log"; then + exit "$FAIL_ABI" + fi +} + +main() { + MAX_THREADS=$(nproc) + VERBOSE="false" + IGNORE_AMBIGUOUS_CHANGES="false" + quiet="false" + local base_ref="" + while getopts "hb:p:j:l:iqv" opt; do + case $opt in + h) + print_usage + exit "$SUCCESS" + ;; + b) + base_ref="$OPTARG" + ;; + p) + past_ref="$OPTARG" + ;; + j) + MAX_THREADS="$OPTARG" + ;; + l) + abi_error_log="$OPTARG" + ;; + i) + IGNORE_AMBIGUOUS_CHANGES="true" + ;; + q) + quiet="true" + VERBOSE="false" + ;; + v) + VERBOSE="true" + quiet="false" + ;; + *) + exit "$FAIL_PREREQ" + esac + done + + if [ "$quiet" = "true" ]; then + exec > /dev/null 2>&1 + fi + + run "$base_ref" "$past_ref" "$abi_error_log" "$@" +} + +main "$@" diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 25fdb7fda112..9c4c4a61bc83 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -512,6 +512,7 @@ our $Attribute = qr{ __ro_after_init| __kprobes| $InitAttribute| + __aligned\s*\(.*\)| ____cacheline_aligned| ____cacheline_aligned_in_smp| ____cacheline_internodealigned_in_smp| @@ -4054,7 +4055,7 @@ sub process { if ($prevline =~ /^[\+ ]};?\s*$/ && $line =~ /^\+/ && !($line =~ /^\+\s*$/ || - $line =~ /^\+\s*(?:EXPORT_SYMBOL|early_param)/ || + $line =~ /^\+\s*(?:EXPORT_SYMBOL|early_param|ALLOW_ERROR_INJECTION)/ || $line =~ /^\+\s*MODULE_/i || $line =~ /^\+\s*\#\s*(?:end|elif|else)/ || $line =~ /^\+[a-z_]*init/ || @@ -7011,6 +7012,25 @@ sub process { "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr); } +# ethtool_sprintf uses that should likely be ethtool_puts + if ($line =~ /\bethtool_sprintf\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { + if (WARN("PREFER_ETHTOOL_PUTS", + "Prefer ethtool_puts over ethtool_sprintf with only two arguments\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bethtool_sprintf\s*\(\s*($FuncArg)\s*,\s*($FuncArg)/ethtool_puts($1, $7)/; + } + } + + # use $rawline because $line loses %s via sanitization and thus we can't match against it. + if ($rawline =~ /\bethtool_sprintf\s*\(\s*$FuncArg\s*,\s*\"\%s\"\s*,\s*$FuncArg\s*\)/) { + if (WARN("PREFER_ETHTOOL_PUTS", + "Prefer ethtool_puts over ethtool_sprintf with standalone \"%s\" specifier\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bethtool_sprintf\s*\(\s*($FuncArg)\s*,\s*"\%s"\s*,\s*($FuncArg)/ethtool_puts($1, $7)/; + } + } + + # typecasts on min/max could be min_t/max_t if ($perl_version_ok && defined $stat && diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index f27d552aec43..14ce31f732ee 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -8,7 +8,6 @@ # Original idea maybe from Keith Owens # s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de> # Mips port by Juan Quintela <quintela@mandrakesoft.com> -# IA64 port via Andreas Dilger # Arm port by Holger Schurig # Random bits by Matt Mackall <mpm@selenic.com> # M68k port by Geert Uytterhoeven and Andreas Schwab @@ -16,9 +15,10 @@ # 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> +# loongarch port by Youling Tang <tangyouling@kylinos.cn> # # Usage: -# objdump -d vmlinux | scripts/checkstack.pl [arch] +# objdump -d vmlinux | scripts/checkstack.pl [arch] [min_stack] # # TODO : Port to all architectures (one regex per arch) @@ -47,7 +47,7 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); $min_stack = shift; if ($min_stack eq "" || $min_stack !~ /^\d+$/) { - $min_stack = 100; + $min_stack = 512; } $x = "[0-9a-f]"; # hex character @@ -56,7 +56,7 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); if ($arch =~ '^(aarch|arm)64$') { #ffffffc0006325cc: a9bb7bfd stp x29, x30, [sp, #-80]! #a110: d11643ff sub sp, sp, #0x590 - $re = qr/^.*stp.*sp, \#-([0-9]{1,8})\]\!/o; + $re = qr/^.*stp.*sp, ?\#-([0-9]{1,8})\]\!/o; $dre = qr/^.*sub.*sp, sp, #(0x$x{1,8})/o; } elsif ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 @@ -68,25 +68,22 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o; $dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o; - } elsif ($arch eq 'ia64') { - #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 - $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; } elsif ($arch eq 'm68k') { # 2b6c: 4e56 fb70 linkw %fp,#-1168 # 1df770: defc ffe4 addaw #-28,%sp $re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o; } elsif ($arch eq 'mips64') { #8800402c: 67bdfff0 daddiu sp,sp,-16 - $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + $re = qr/.*daddiu.*sp,sp,-([0-9]{1,8})/o; } elsif ($arch eq 'mips') { #88003254: 27bdffe0 addiu sp,sp,-32 - $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + $re = qr/.*addiu.*sp,sp,-([0-9]{1,8})/o; } elsif ($arch eq 'nios2') { #25a8: defffb04 addi sp,sp,-20 - $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + $re = qr/.*addi.*sp,sp,-([0-9]{1,8})/o; } elsif ($arch eq 'openrisc') { # c000043c: 9c 21 fe f0 l.addi r1,r1,-272 - $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o; + $re = qr/.*l\.addi.*r1,r1,-([0-9]{1,8})/o; } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; } elsif ($arch eq 'powerpc' || $arch =~ /^ppc(64)?(le)?$/ ) { @@ -100,10 +97,13 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack); $re = qr/.*(?:lay|ag?hi).*\%r15,-([0-9]+)(?:\(\%r15\))?$/o; } 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; + $re = qr/.*save.*%sp, -([0-9]{1,8}), %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; + $re = qr/.*addi.*sp,sp,-([0-9]{1,8})/o; + } elsif ($arch =~ /^loongarch(32|64)?$/) { + #9000000000224708: 02ff4063 addi.d $sp, $sp, -48(0xfd0) + $re = qr/.*addi\..*sp, .*sp, -([0-9]{1,8}).*/o; } else { print("wrong or unknown architecture \"$arch\"\n"); exit @@ -189,5 +189,20 @@ if ($total_size > $min_stack) { push @stack, "$intro$total_size\n"; } -# Sort output by size (last field) -print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; +# Sort output by size (last field) and function name if size is the same +sub sort_lines { + my ($a, $b) = @_; + + my $num_a = $1 if $a =~ /:\t*(\d+)$/; + my $num_b = $1 if $b =~ /:\t*(\d+)$/; + my $func_a = $1 if $a =~ / (.*):/; + my $func_b = $1 if $b =~ / (.*):/; + + if ($num_a != $num_b) { + return $num_b <=> $num_a; + } else { + return $func_a cmp $func_b; + } +} + +print sort { sort_lines($a, $b) } @stack; diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py index 5dea4479240b..e4fb686dfaa9 100755 --- a/scripts/clang-tools/gen_compile_commands.py +++ b/scripts/clang-tools/gen_compile_commands.py @@ -170,7 +170,7 @@ def process_line(root_directory, command_prefix, file_path): # escape the pound sign '#', either as '\#' or '$(pound)' (depending on the # kernel version). The compile_commands.json file is not interepreted # by Make, so this code replaces the escaped version with '#'. - prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#') + prefix = command_prefix.replace(r'\#', '#').replace('$(pound)', '#') # Return the canonical path, eliminating any symbolic links encountered in the path. abs_path = os.path.realpath(os.path.join(root_directory, file_path)) diff --git a/scripts/coccinelle/api/device_attr_show.cocci b/scripts/coccinelle/api/device_attr_show.cocci index a28dc061653a..dfcf9304195f 100644 --- a/scripts/coccinelle/api/device_attr_show.cocci +++ b/scripts/coccinelle/api/device_attr_show.cocci @@ -1,10 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /// /// From Documentation/filesystems/sysfs.rst: -/// show() must not use snprintf() when formatting the value to be -/// returned to user space. If you can guarantee that an overflow -/// will never happen you can use sprintf() otherwise you must use -/// scnprintf(). +/// show() should only use sysfs_emit() or sysfs_emit_at() when formatting +/// the value to be returned to user space. /// // Confidence: High // Copyright: (C) 2020 Denis Efremov ISPRAS @@ -30,15 +28,16 @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) @rp depends on patch@ identifier show, dev, attr, buf; +expression BUF, SZ, FORMAT; @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) { <... return -- snprintf -+ scnprintf - (...); +- snprintf(BUF, SZ, FORMAT ++ sysfs_emit(BUF, FORMAT + ,...); ...> } @@ -46,10 +45,10 @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) p << r.p; @@ -coccilib.report.print_report(p[0], "WARNING: use scnprintf or sprintf") +coccilib.report.print_report(p[0], "WARNING: please use sysfs_emit or sysfs_emit_at") @script: python depends on org@ p << r.p; @@ -coccilib.org.print_todo(p[0], "WARNING: use scnprintf or sprintf") +coccilib.org.print_todo(p[0], "WARNING: please use sysfs_emit or sysfs_emit_at") diff --git a/scripts/coccinelle/api/string_choices.cocci b/scripts/coccinelle/api/string_choices.cocci new file mode 100644 index 000000000000..a71966c0494e --- /dev/null +++ b/scripts/coccinelle/api/string_choices.cocci @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find places to use string_choices.h's various helpers. +// +// Confidence: Medium +// Options: --no-includes --include-headers +virtual patch +virtual context +virtual report + +@str_plural depends on patch@ +expression E; +@@ +( +- ((E == 1) ? "" : "s") ++ str_plural(E) +| +- ((E != 1) ? "s" : "") ++ str_plural(E) +| +- ((E > 1) ? "s" : "") ++ str_plural(E) +) + +@str_plural_r depends on !patch exists@ +expression E; +position P; +@@ +( +* ((E@P == 1) ? "" : "s") +| +* ((E@P != 1) ? "s" : "") +| +* ((E@P > 1) ? "s" : "") +) + +@script:python depends on report@ +p << str_plural_r.P; +e << str_plural_r.E; +@@ + +coccilib.report.print_report(p[0], "opportunity for str_plural(%s)" % e) diff --git a/scripts/coccinelle/misc/struct_size.cocci b/scripts/coccinelle/misc/struct_size.cocci new file mode 100644 index 000000000000..9b02c37438e4 --- /dev/null +++ b/scripts/coccinelle/misc/struct_size.cocci @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// +/// Check for code that could use struct_size(). +/// +// Confidence: Medium +// Author: Jacob Keller <jacob.e.keller@intel.com> +// Copyright: (C) 2023 Intel Corporation +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +// the overflow Kunit tests have some code which intentionally does not use +// the macros, so we want to ignore this code when reporting potential +// issues. +@overflow_tests@ +identifier f = overflow_size_helpers_test; +@@ + +f + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on !overflow_tests && context@ +expression E1, E2; +identifier m; +@@ +( +* (sizeof(*E1) + (E2 * sizeof(*E1->m))) +) + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on !overflow_tests && patch@ +expression E1, E2; +identifier m; +@@ +( +- (sizeof(*E1) + (E2 * sizeof(*E1->m))) ++ struct_size(E1, m, E2) +) + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on !overflow_tests && (org || report)@ +expression E1, E2; +identifier m; +position p; +@@ +( + (sizeof(*E1)@p + (E2 * sizeof(*E1->m))) +) + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING should use struct_size") + +@script:python depends on report@ +p << r.p; +@@ + +msg="WARNING: Use struct_size" +coccilib.report.print_report(p[0], msg) + diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index 188412aa2757..fa96cfd16e99 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -2,11 +2,13 @@ acpi_dock_ops address_space_operations backlight_ops block_device_operations +bus_type clk_ops comedi_lrange component_ops dentry_operations dev_pm_ops +device_type dma_map_ops driver_info drm_connector_funcs diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 564c5632e1a2..fa5be6f57b00 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -16,6 +16,21 @@ elif type c++filt >/dev/null 2>&1 ; then cppfilt_opts=-i fi +UTIL_SUFFIX= +if [[ -z ${LLVM:-} ]]; then + UTIL_PREFIX=${CROSS_COMPILE:-} +else + UTIL_PREFIX=llvm- + if [[ ${LLVM} == */ ]]; then + UTIL_PREFIX=${LLVM}${UTIL_PREFIX} + elif [[ ${LLVM} == -* ]]; then + UTIL_SUFFIX=${LLVM} + fi +fi + +READELF=${UTIL_PREFIX}readelf${UTIL_SUFFIX} +ADDR2LINE=${UTIL_PREFIX}addr2line${UTIL_SUFFIX} + if [[ $1 == "-r" ]] ; then vmlinux="" basepath="auto" @@ -75,7 +90,7 @@ find_module() { if [[ "$modpath" != "" ]] ; then for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do - if readelf -WS "$fn" | grep -qwF .debug_line ; then + if ${READELF} -WS "$fn" | grep -qwF .debug_line ; then echo $fn return fi @@ -169,7 +184,7 @@ parse_symbol() { 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) + local code=$(${ADDR2LINE} -i -e "$objfile" "$address" 2>/dev/null) if [[ $aarray_support == true ]]; then cache[$module,$address]=$code fi @@ -291,6 +306,9 @@ handle_line() { } while read line; do + # Strip unexpected carriage return at end of line + line=${line%$'\r'} + # Let's see if we have an address in the line if [[ $line =~ \[\<([^]]+)\>\] ]] || [[ $line =~ [^+\ ]+\+0x[0-9a-f]+/0x[0-9a-f]+ ]]; then diff --git a/scripts/decodecode b/scripts/decodecode index 8fe71c292381..6364218b2178 100755 --- a/scripts/decodecode +++ b/scripts/decodecode @@ -67,6 +67,7 @@ if [ -z "$ARCH" ]; then case `uname -m` in aarch64*) ARCH=arm64 ;; arm*) ARCH=arm ;; + loongarch*) ARCH=loongarch ;; esac fi @@ -98,6 +99,10 @@ disas() { ${CROSS_COMPILE}strip $t.o fi + if [ "$ARCH" = "loongarch" ]; then + ${CROSS_COMPILE}strip $t.o + fi + if [ $pc_sub -ne 0 ]; then if [ $PC ]; then adj_vma=$(( $PC - $pc_sub )) diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in index e810e0c27ff1..fd6bd69c5096 100644 --- a/scripts/gdb/linux/constants.py.in +++ b/scripts/gdb/linux/constants.py.in @@ -130,7 +130,11 @@ LX_CONFIG(CONFIG_X86_MCE_THRESHOLD) LX_CONFIG(CONFIG_X86_MCE_AMD) LX_CONFIG(CONFIG_X86_MCE) LX_CONFIG(CONFIG_X86_IO_APIC) -LX_CONFIG(CONFIG_HAVE_KVM) +/* + * CONFIG_KVM can be "m" but it affects common code too. Use CONFIG_KVM_COMMON + * as a proxy for IS_ENABLED(CONFIG_KVM). + */ +LX_CONFIG_KVM = IS_BUILTIN(CONFIG_KVM_COMMON) LX_CONFIG(CONFIG_NUMA) LX_CONFIG(CONFIG_ARM64) LX_CONFIG(CONFIG_ARM64_4K_PAGES) @@ -139,7 +143,7 @@ LX_CONFIG(CONFIG_ARM64_64K_PAGES) if IS_BUILTIN(CONFIG_ARM64): LX_VALUE(CONFIG_ARM64_PA_BITS) LX_VALUE(CONFIG_ARM64_VA_BITS) - LX_VALUE(CONFIG_ARM64_PAGE_SHIFT) + LX_VALUE(CONFIG_PAGE_SHIFT) LX_VALUE(CONFIG_ARCH_FORCE_MAX_ORDER) LX_CONFIG(CONFIG_SPARSEMEM) LX_CONFIG(CONFIG_SPARSEMEM_EXTREME) diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py index ef478e273791..66ae5c7690cf 100644 --- a/scripts/gdb/linux/interrupts.py +++ b/scripts/gdb/linux/interrupts.py @@ -151,7 +151,7 @@ def x86_show_interupts(prec): if cnt is not None: text += "%*s: %10u\n" % (prec, "MIS", cnt['counter']) - if constants.LX_CONFIG_HAVE_KVM: + if constants.LX_CONFIG_KVM: text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event') text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event') text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event') diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py index ad5641dcb068..515730fd4c9d 100644 --- a/scripts/gdb/linux/mm.py +++ b/scripts/gdb/linux/mm.py @@ -41,7 +41,7 @@ class aarch64_page_ops(): self.SECTION_SIZE_BITS = 27 self.MAX_PHYSMEM_BITS = constants.LX_CONFIG_ARM64_VA_BITS - self.PAGE_SHIFT = constants.LX_CONFIG_ARM64_PAGE_SHIFT + self.PAGE_SHIFT = constants.LX_CONFIG_PAGE_SHIFT self.PAGE_SIZE = 1 << self.PAGE_SHIFT self.PAGE_MASK = (~(self.PAGE_SIZE - 1)) & ((1 << 64) - 1) diff --git a/scripts/gdb/linux/page_owner.py b/scripts/gdb/linux/page_owner.py index 844fd5d0c912..8e713a09cfe7 100644 --- a/scripts/gdb/linux/page_owner.py +++ b/scripts/gdb/linux/page_owner.py @@ -122,27 +122,24 @@ class DumpPageOwner(gdb.Command): if not (page_ext['flags'] & (1 << PAGE_EXT_OWNER_ALLOCATED)): gdb.write("page_owner is not allocated\n") - try: - page_owner = self.get_page_owner(page_ext) - gdb.write("Page last allocated via order %d, gfp_mask: 0x%x, pid: %d, tgid: %d (%s), ts %u ns, free_ts %u ns\n" %\ - (page_owner["order"], page_owner["gfp_mask"],\ - page_owner["pid"], page_owner["tgid"], page_owner["comm"],\ - page_owner["ts_nsec"], page_owner["free_ts_nsec"])) - gdb.write("PFN: %d, Flags: 0x%x\n" % (pfn, page['flags'])) - if page_owner["handle"] == 0: - gdb.write('page_owner allocation stack trace missing\n') - else: - stackdepot.stack_depot_print(page_owner["handle"]) + page_owner = self.get_page_owner(page_ext) + gdb.write("Page last allocated via order %d, gfp_mask: 0x%x, pid: %d, tgid: %d (%s), ts %u ns, free_ts %u ns\n" %\ + (page_owner["order"], page_owner["gfp_mask"],\ + page_owner["pid"], page_owner["tgid"], page_owner["comm"].string(),\ + page_owner["ts_nsec"], page_owner["free_ts_nsec"])) + gdb.write("PFN: %d, Flags: 0x%x\n" % (pfn, page['flags'])) + if page_owner["handle"] == 0: + gdb.write('page_owner allocation stack trace missing\n') + else: + stackdepot.stack_depot_print(page_owner["handle"]) - if page_owner["free_handle"] == 0: - gdb.write('page_owner free stack trace missing\n') - else: - gdb.write('page last free stack trace:\n') - stackdepot.stack_depot_print(page_owner["free_handle"]) - if page_owner['last_migrate_reason'] != -1: - gdb.write('page has been migrated, last migrate reason: %s\n' % self.migrate_reason_names[page_owner['last_migrate_reason']]) - except: - gdb.write("\n") + if page_owner["free_handle"] == 0: + gdb.write('page_owner free stack trace missing\n') + else: + gdb.write('page last free stack trace:\n') + stackdepot.stack_depot_print(page_owner["free_handle"]) + if page_owner['last_migrate_reason'] != -1: + gdb.write('page has been migrated, last migrate reason: %s\n' % self.migrate_reason_names[page_owner['last_migrate_reason']]) def read_page_owner(self): pfn = self.min_pfn @@ -173,18 +170,13 @@ class DumpPageOwner(gdb.Command): pfn += 1 continue - try: - page_owner = self.get_page_owner(page_ext) - gdb.write("Page allocated via order %d, gfp_mask: 0x%x, pid: %d, tgid: %d (%s), ts %u ns, free_ts %u ns\n" %\ - (page_owner["order"], page_owner["gfp_mask"],\ - page_owner["pid"], page_owner["tgid"], page_owner["comm"],\ - page_owner["ts_nsec"], page_owner["free_ts_nsec"])) - gdb.write("PFN: %d, Flags: 0x%x\n" % (pfn, page['flags'])) - stackdepot.stack_depot_print(page_owner["handle"]) - pfn += (1 << page_owner["order"]) - continue - except: - gdb.write("\n") - pfn += 1 + page_owner = self.get_page_owner(page_ext) + gdb.write("Page allocated via order %d, gfp_mask: 0x%x, pid: %d, tgid: %d (%s), ts %u ns, free_ts %u ns\n" %\ + (page_owner["order"], page_owner["gfp_mask"],\ + page_owner["pid"], page_owner["tgid"], page_owner["comm"].string(),\ + page_owner["ts_nsec"], page_owner["free_ts_nsec"])) + gdb.write("PFN: %d, Flags: 0x%x\n" % (pfn, page['flags'])) + stackdepot.stack_depot_print(page_owner["handle"]) + pfn += (1 << page_owner["order"]) DumpPageOwner() diff --git a/scripts/gdb/linux/slab.py b/scripts/gdb/linux/slab.py index f012ba38c7d9..0e2d93867fe2 100644 --- a/scripts/gdb/linux/slab.py +++ b/scripts/gdb/linux/slab.py @@ -228,8 +228,7 @@ def slabtrace(alloc, cache_name): nr_cpu = gdb.parse_and_eval('__num_online_cpus')['counter'] if nr_cpu > 1: gdb.write(" cpus=") - for i in loc['cpus']: - gdb.write("%d," % i) + gdb.write(','.join(str(cpu) for cpu in loc['cpus'])) gdb.write("\n") if constants.LX_CONFIG_STACKDEPOT: if loc['handle']: diff --git a/scripts/gdb/linux/stackdepot.py b/scripts/gdb/linux/stackdepot.py index 047d329a6a12..0281d9de4b7c 100644 --- a/scripts/gdb/linux/stackdepot.py +++ b/scripts/gdb/linux/stackdepot.py @@ -25,10 +25,10 @@ def stack_depot_fetch(handle): handle_parts_t = gdb.lookup_type("union handle_parts") parts = handle.cast(handle_parts_t) offset = parts['offset'] << DEPOT_STACK_ALIGN - pool_index_cached = gdb.parse_and_eval('pool_index') + pools_num = gdb.parse_and_eval('pools_num') - if parts['pool_index'] > pool_index_cached: - gdb.write("pool index %d out of bounds (%d) for stack id 0x%08x\n" % (parts['pool_index'], pool_index_cached, handle)) + if parts['pool_index'] > pools_num: + gdb.write("pool index %d out of bounds (%d) for stack id 0x%08x\n" % (parts['pool_index'], pools_num, handle)) return gdb.Value(0), 0 stack_pools = gdb.parse_and_eval('stack_pools') diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index c8047f4441e6..e8316beb17a7 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -82,7 +82,7 @@ lx-symbols command.""" self.module_files_updated = True def _get_module_file(self, module_name): - module_pattern = ".*/{0}\.ko(?:.debug)?$".format( + module_pattern = r".*/{0}\.ko(?:.debug)?$".format( module_name.replace("_", r"[_\-]")) for name in self.module_files: if re.match(module_pattern, name) and os.path.exists(name): diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index aa5ab6251f76..6793d6e86e77 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -82,21 +82,12 @@ LxPs() thread_info_type = utils.CachedType("struct thread_info") -ia64_task_size = None - def get_thread_info(task): thread_info_ptr_type = thread_info_type.get_type().pointer() - if utils.is_target_arch("ia64"): - global ia64_task_size - if ia64_task_size is None: - ia64_task_size = gdb.parse_and_eval("sizeof(struct task_struct)") - thread_info_addr = task.address + ia64_task_size - thread_info = thread_info_addr.cast(thread_info_ptr_type) - else: - if task.type.fields()[0].type == thread_info_type.get_type(): - return task['thread_info'] - thread_info = task['stack'].cast(thread_info_ptr_type) + if task.type.fields()[0].type == thread_info_type.get_type(): + return task['thread_info'] + thread_info = task['stack'].cast(thread_info_ptr_type) return thread_info.dereference() diff --git a/scripts/gdb/linux/vmalloc.py b/scripts/gdb/linux/vmalloc.py index d3c8a0274d1e..803f17371052 100644 --- a/scripts/gdb/linux/vmalloc.py +++ b/scripts/gdb/linux/vmalloc.py @@ -29,32 +29,34 @@ class LxVmallocInfo(gdb.Command): if not constants.LX_CONFIG_MMU: raise gdb.GdbError("Requires MMU support") - vmap_area_list = gdb.parse_and_eval('vmap_area_list') - for vmap_area in lists.list_for_each_entry(vmap_area_list, vmap_area_ptr_type, "list"): - if not vmap_area['vm']: - gdb.write("0x%x-0x%x %10d vm_map_ram\n" % (vmap_area['va_start'], vmap_area['va_end'], - vmap_area['va_end'] - vmap_area['va_start'])) - continue - v = vmap_area['vm'] - gdb.write("0x%x-0x%x %10d" % (v['addr'], v['addr'] + v['size'], v['size'])) - if v['caller']: - gdb.write(" %s" % str(v['caller']).split(' ')[-1]) - if v['nr_pages']: - gdb.write(" pages=%d" % v['nr_pages']) - if v['phys_addr']: - gdb.write(" phys=0x%x" % v['phys_addr']) - if v['flags'] & constants.LX_VM_IOREMAP: - gdb.write(" ioremap") - if v['flags'] & constants.LX_VM_ALLOC: - gdb.write(" vmalloc") - if v['flags'] & constants.LX_VM_MAP: - gdb.write(" vmap") - if v['flags'] & constants.LX_VM_USERMAP: - gdb.write(" user") - if v['flags'] & constants.LX_VM_DMA_COHERENT: - gdb.write(" dma-coherent") - if is_vmalloc_addr(v['pages']): - gdb.write(" vpages") - gdb.write("\n") + nr_vmap_nodes = gdb.parse_and_eval('nr_vmap_nodes') + for i in range(0, nr_vmap_nodes): + vn = gdb.parse_and_eval('&vmap_nodes[%d]' % i) + for vmap_area in lists.list_for_each_entry(vn['busy']['head'], vmap_area_ptr_type, "list"): + if not vmap_area['vm']: + gdb.write("0x%x-0x%x %10d vm_map_ram\n" % (vmap_area['va_start'], vmap_area['va_end'], + vmap_area['va_end'] - vmap_area['va_start'])) + continue + v = vmap_area['vm'] + gdb.write("0x%x-0x%x %10d" % (v['addr'], v['addr'] + v['size'], v['size'])) + if v['caller']: + gdb.write(" %s" % str(v['caller']).split(' ')[-1]) + if v['nr_pages']: + gdb.write(" pages=%d" % v['nr_pages']) + if v['phys_addr']: + gdb.write(" phys=0x%x" % v['phys_addr']) + if v['flags'] & constants.LX_VM_IOREMAP: + gdb.write(" ioremap") + if v['flags'] & constants.LX_VM_ALLOC: + gdb.write(" vmalloc") + if v['flags'] & constants.LX_VM_MAP: + gdb.write(" vmap") + if v['flags'] & constants.LX_VM_USERMAP: + gdb.write(" user") + if v['flags'] & constants.LX_VM_DMA_COHERENT: + gdb.write(" dma-coherent") + if is_vmalloc_addr(v['pages']): + gdb.write(" vpages") + gdb.write("\n") LxVmallocInfo() diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 3c6cbe2b278d..54919cf48621 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -148,19 +148,28 @@ fn main() { let mut ts = TargetSpec::new(); // `llvm-target`s are taken from `scripts/Makefile.clang`. - if cfg.has("X86_64") { + if cfg.has("ARM64") { + panic!("arm64 uses the builtin rustc aarch64-unknown-none target"); + } else 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") { + if cfg.has("MITIGATION_RETPOLINE") { features += ",+retpoline-external-thunk"; } ts.push("features", features); ts.push("llvm-target", "x86_64-linux-gnu"); ts.push("target-pointer-width", "64"); + } else if cfg.has("LOONGARCH") { + ts.push("arch", "loongarch64"); + ts.push("data-layout", "e-m:e-p:64:64-i64:64-i128:128-n64-S128"); + ts.push("features", "-f,-d"); + ts.push("llvm-target", "loongarch64-linux-gnusf"); + ts.push("llvm-abiname", "lp64s"); + ts.push("target-pointer-width", "64"); } else { panic!("Unsupported architecture"); } diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index f5dfdb9d80e9..f3901c55df23 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -16,9 +16,7 @@ #include <unistd.h> #include <assert.h> #include <stdarg.h> -#ifdef __GNU_LIBRARY__ #include <getopt.h> -#endif /* __GNU_LIBRARY__ */ #include "genksyms.h" /*----------------------------------------------------------------------*/ @@ -718,8 +716,6 @@ void error_with_pos(const char *fmt, ...) static void genksyms_usage(void) { fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n" -#ifdef __GNU_LIBRARY__ - " -s, --symbol-prefix Select symbol prefix\n" " -d, --debug Increment the debug level (repeatable)\n" " -D, --dump Dump expanded symbol defs (for debugging only)\n" " -r, --reference file Read reference symbols from a file\n" @@ -729,18 +725,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" -#else /* __GNU_LIBRARY__ */ - " -s Select symbol prefix\n" - " -d Increment the debug level (repeatable)\n" - " -D Dump expanded symbol defs (for debugging only)\n" - " -r file Read reference symbols from a file\n" - " -T file Dump expanded types into file\n" - " -p Preserve reference modversions or fail\n" - " -w Enable warnings\n" - " -q Disable warnings (default)\n" - " -h Print this message\n" - " -V Print the release version\n" -#endif /* __GNU_LIBRARY__ */ , stderr); } @@ -749,7 +733,6 @@ int main(int argc, char **argv) FILE *dumpfile = NULL, *ref_file = NULL; int o; -#ifdef __GNU_LIBRARY__ struct option long_opts[] = { {"debug", 0, 0, 'd'}, {"warnings", 0, 0, 'w'}, @@ -763,11 +746,8 @@ int main(int argc, char **argv) {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", + while ((o = getopt_long(argc, argv, "dwqVDr:T:ph", &long_opts[0], NULL)) != EOF) -#else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) -#endif /* __GNU_LIBRARY__ */ switch (o) { case 'd': flag_debug++; diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl index 0ffd5531242a..de1c0354b50c 100755 --- a/scripts/get_abi.pl +++ b/scripts/get_abi.pl @@ -93,12 +93,13 @@ sub parse_abi { return if ($mode & S_IFDIR); return if ($file =~ m,/README,); return if ($file =~ m,/\.,); + return if ($file =~ m,\.(rej|org|orig|bak)$,); my $name = $file; $name =~ s,.*/,,; my $fn = $file; - $fn =~ s,Documentation/ABI/,,; + $fn =~ s,.*Documentation/ABI/,,; my $nametag = "File $fn"; $data{$nametag}->{what} = "File $name"; diff --git a/scripts/git.orderFile b/scripts/git.orderFile new file mode 100644 index 000000000000..5102ba73357f --- /dev/null +++ b/scripts/git.orderFile @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0 + +# order file for git, to produce patches which are easier to review +# by diffing the important stuff like header changes first. +# +# one-off usage: +# git diff -O scripts/git.orderFile ... +# +# add to git config: +# git config diff.orderFile scripts/git.orderFile +# + +MAINTAINERS + +# Documentation +Documentation/* +*.rst + +# git-specific +.gitignore +scripts/git.orderFile + +# build system +Kconfig* +*/Kconfig* +Kbuild* +*/Kbuild* +Makefile* +*/Makefile* +*.mak +*.mk +scripts/* + +# semantic patches +*.cocci + +# headers +*types.h +*.h + +# code +*.c diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt index 26359968744e..890f69005bab 100644 --- a/scripts/head-object-list.txt +++ b/scripts/head-object-list.txt @@ -17,7 +17,6 @@ arch/arm/kernel/head-nommu.o arch/arm/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 diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index c3064ac31003..f7d9b114de8f 100755 --- a/scripts/headers_install.sh +++ b/scripts/headers_install.sh @@ -74,7 +74,6 @@ arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE arch/arm/include/uapi/asm/ptrace.h:CONFIG_CPU_ENDIAN_BE8 -arch/hexagon/include/uapi/asm/user.h:CONFIG_HEXAGON_ARCH_VERSION arch/m68k/include/uapi/asm/ptrace.h:CONFIG_COLDFIRE arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 4eee155121a8..ea1bf3b3dbde 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -27,6 +27,14 @@ KCONFIG_DEFCONFIG_LIST += \ endif KCONFIG_DEFCONFIG_LIST += arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) +ifneq ($(findstring c, $(KBUILD_EXTRA_WARN)),) +export KCONFIG_WARN_UNKNOWN_SYMBOLS=1 +endif + +ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),) +export KCONFIG_WERROR=1 +endif + # We need this, in case the user has it in its environment unexport CONFIG_ @@ -99,7 +107,7 @@ config-fragments = $(call configfiles,$@) %.config: $(obj)/conf $(if $(config-fragments),, $(error $@ fragment does not exists on this architecture)) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(config-fragments) + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m $(KCONFIG_CONFIG) $(config-fragments) $(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig PHONY += tinyconfig @@ -166,7 +174,7 @@ conf-objs := conf.o $(common-objs) # nconf: Used for the nconfig target based on ncurses hostprogs += nconf -nconf-objs := nconf.o nconf.gui.o $(common-objs) +nconf-objs := nconf.o nconf.gui.o mnconf-common.o $(common-objs) HOSTLDLIBS_nconf = $(call read-file, $(obj)/nconf-libs) HOSTCFLAGS_nconf.o = $(call read-file, $(obj)/nconf-cflags) @@ -179,7 +187,7 @@ $(obj)/nconf.o $(obj)/nconf.gui.o: | $(obj)/nconf-cflags hostprogs += mconf lxdialog := $(addprefix lxdialog/, \ checklist.o inputbox.o menubox.o textbox.o util.o yesno.o) -mconf-objs := mconf.o $(lxdialog) $(common-objs) +mconf-objs := mconf.o $(lxdialog) mnconf-common.o $(common-objs) HOSTLDLIBS_mconf = $(call read-file, $(obj)/mconf-libs) $(foreach f, mconf.o $(lxdialog), \ diff --git a/scripts/kconfig/array_size.h b/scripts/kconfig/array_size.h new file mode 100644 index 000000000000..26ba78d867d1 --- /dev/null +++ b/scripts/kconfig/array_size.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ARRAY_SIZE_H +#define ARRAY_SIZE_H + +/** + * ARRAY_SIZE - get the number of elements in array @arr + * @arr: array to be sized + */ +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#endif /* ARRAY_SIZE_H */ diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 33d19e419908..965bb40c50e5 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -14,6 +14,7 @@ #include <sys/time.h> #include <errno.h> +#include "internal.h" #include "lkc.h" static void conf(struct menu *menu); @@ -171,7 +172,7 @@ enum conf_def_mode { static bool conf_set_all_new_symbols(enum conf_def_mode mode) { struct symbol *sym, *csym; - int i, cnt; + int cnt; /* * can't go as the default in switch-case below, otherwise gcc whines * about -Wmaybe-uninitialized @@ -226,7 +227,7 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) } } - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym_has_value(sym) || sym->flags & SYMBOL_VALID) continue; switch (sym_get_type(sym)) { @@ -278,14 +279,14 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) * and the rest to no. */ if (mode != def_random) { - for_all_symbols(i, csym) { + for_all_symbols(csym) { if ((sym_is_choice(csym) && !sym_has_value(csym)) || sym_is_choice_value(csym)) csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; } } - for_all_symbols(i, csym) { + for_all_symbols(csym) { if (sym_has_value(csym) || !sym_is_choice(csym)) continue; @@ -304,9 +305,8 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) static void conf_rewrite_tristates(tristate old_val, tristate new_val) { struct symbol *sym; - int i; - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym_get_type(sym) == S_TRISTATE && sym->def[S_DEF_USER].tri == old_val) sym->def[S_DEF_USER].tri = new_val; @@ -552,11 +552,6 @@ static int conf_choice(struct menu *menu) continue; } sym_set_tristate_value(child->sym, yes); - for (child = child->list; child; child = child->next) { - indent += 2; - conf(child); - indent -= 2; - } return 1; } } @@ -827,6 +822,9 @@ int main(int ac, char **av) break; } + if (conf_errors()) + exit(1); + if (sync_kconfig) { name = getenv("KCONFIG_NOSILENTUPDATE"); if (name && *name) { @@ -890,6 +888,9 @@ int main(int ac, char **av) break; } + if (sym_dep_errors()) + exit(1); + if (input_mode == savedefconfig) { if (conf_write_defconfig(defconfig_file)) { fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n", diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 4a6811d77d18..0e35c4819cf1 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -18,8 +18,11 @@ #include <time.h> #include <unistd.h> +#include "internal.h" #include "lkc.h" +struct gstr autoconf_cmd; + /* return true if 'path' exists, false otherwise */ static bool is_present(const char *path) { @@ -155,6 +158,13 @@ static void conf_message(const char *fmt, ...) static const char *conf_filename; static int conf_lineno, conf_warnings; +bool conf_errors(void) +{ + if (conf_warnings) + return getenv("KCONFIG_WERROR"); + return false; +} + static void conf_warning(const char *fmt, ...) { va_list ap; @@ -286,59 +296,24 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) return 0; } -#define LINE_GROWTH 16 -static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +/* like getline(), but the newline character is stripped away */ +static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream) { - char *nline; - size_t new_size = slen + 1; - if (new_size > *n) { - new_size += LINE_GROWTH - 1; - new_size *= 2; - nline = xrealloc(*lineptr, new_size); - if (!nline) - return -1; - - *lineptr = nline; - *n = new_size; - } + ssize_t len; - (*lineptr)[slen] = c; + len = getline(lineptr, n, stream); - return 0; -} - -static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) -{ - char *line = *lineptr; - size_t slen = 0; + if (len > 0 && (*lineptr)[len - 1] == '\n') { + len--; + (*lineptr)[len] = '\0'; - for (;;) { - int c = getc(stream); - - switch (c) { - case '\n': - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - /* fall through */ - case EOF: - if (add_byte('\0', &line, slen, n) < 0) - goto e_out; - *lineptr = line; - if (slen == 0) - return -1; - return slen; - default: - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; + if (len > 0 && (*lineptr)[len - 1] == '\r') { + len--; + (*lineptr)[len] = '\0'; } } -e_out: - line[slen-1] = '\0'; - *lineptr = line; - return -1; + return len; } int conf_read_simple(const char *name, int def) @@ -346,14 +321,12 @@ int conf_read_simple(const char *name, int def) FILE *in = NULL; char *line = NULL; size_t line_asize = 0; - char *p, *p2; + char *p, *val; struct symbol *sym; - int i, def_flags; - const char *warn_unknown; - const char *werror; + int def_flags; + const char *warn_unknown, *sym_name; warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS"); - werror = getenv("KCONFIG_WERROR"); if (name) { in = zconf_fopen(name); } else { @@ -408,7 +381,7 @@ load: conf_warnings = 0; def_flags = SYMBOL_DEF << def; - for_all_symbols(i, sym) { + for_all_symbols(sym) { sym->flags |= SYMBOL_CHANGED; sym->flags &= ~(def_flags|SYMBOL_VALID); if (sym_is_choice(sym)) @@ -417,8 +390,7 @@ load: case S_INT: case S_HEX: case S_STRING: - if (sym->def[def].val) - free(sym->def[def].val); + free(sym->def[def].val); /* fall through */ default: sym->def[def].val = NULL; @@ -426,90 +398,68 @@ load: } } - while (compat_getline(&line, &line_asize, in) != -1) { + while (getline_stripped(&line, &line_asize, in) != -1) { conf_lineno++; - sym = NULL; + + if (!line[0]) /* blank line */ + continue; + if (line[0] == '#') { - if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + if (line[1] != ' ') + continue; + p = line + 2; + if (memcmp(p, CONFIG_, strlen(CONFIG_))) continue; - p = strchr(line + 2 + strlen(CONFIG_), ' '); + sym_name = p + strlen(CONFIG_); + p = strchr(sym_name, ' '); if (!p) continue; *p++ = 0; - if (strncmp(p, "is not set", 10)) + if (strcmp(p, "is not set")) continue; - if (def == S_DEF_USER) { - sym = sym_find(line + 2 + strlen(CONFIG_)); - if (!sym) { - if (warn_unknown) - conf_warning("unknown symbol: %s", - line + 2 + strlen(CONFIG_)); - - conf_set_changed(true); - continue; - } - } else { - sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); - if (sym->type == S_UNKNOWN) - sym->type = S_BOOLEAN; - } - if (sym->flags & def_flags) { - conf_warning("override: reassigning to symbol %s", sym->name); - } - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - sym->def[def].tri = no; - sym->flags |= def_flags; - break; - default: - ; - } - } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { - p = strchr(line + strlen(CONFIG_), '='); - if (!p) + + val = "n"; + } else { + if (memcmp(line, CONFIG_, strlen(CONFIG_))) { + conf_warning("unexpected data: %s", line); continue; - *p++ = 0; - p2 = strchr(p, '\n'); - if (p2) { - *p2-- = 0; - if (*p2 == '\r') - *p2 = 0; } - sym = sym_find(line + strlen(CONFIG_)); - if (!sym) { - if (def == S_DEF_AUTO) { - /* - * Reading from include/config/auto.conf - * If CONFIG_FOO previously existed in - * auto.conf but it is missing now, - * include/config/FOO must be touched. - */ - conf_touch_dep(line + strlen(CONFIG_)); - } else { - if (warn_unknown) - conf_warning("unknown symbol: %s", - line + strlen(CONFIG_)); - - conf_set_changed(true); - } + sym_name = line + strlen(CONFIG_); + p = strchr(sym_name, '='); + if (!p) { + conf_warning("unexpected data: %s", line); continue; } + *p = 0; + val = p + 1; + } - if (sym->flags & def_flags) { - conf_warning("override: reassigning to symbol %s", sym->name); - } - if (conf_set_sym_val(sym, def, def_flags, p)) - continue; - } else { - if (line[0] != '\r' && line[0] != '\n') - conf_warning("unexpected data: %.*s", - (int)strcspn(line, "\r\n"), line); + sym = sym_find(sym_name); + if (!sym) { + if (def == S_DEF_AUTO) { + /* + * Reading from include/config/auto.conf. + * If CONFIG_FOO previously existed in auto.conf + * but it is missing now, include/config/FOO + * must be touched. + */ + conf_touch_dep(sym_name); + } else { + if (warn_unknown) + conf_warning("unknown symbol: %s", sym_name); + conf_set_changed(true); + } continue; } + if (sym->flags & def_flags) + conf_warning("override: reassigning to symbol %s", sym->name); + + if (conf_set_sym_val(sym, def, def_flags, val)) + continue; + if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); switch (sym->def[def].tri) { @@ -533,9 +483,6 @@ load: free(line); fclose(in); - if (conf_warnings && werror) - exit(1); - return 0; } @@ -543,7 +490,6 @@ int conf_read(const char *name) { struct symbol *sym; int conf_unsaved = 0; - int i; conf_set_changed(false); @@ -554,7 +500,7 @@ int conf_read(const char *name) sym_calc_value(modules_sym); - for_all_symbols(i, sym) { + for_all_symbols(sym) { sym_calc_value(sym); if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE)) continue; @@ -578,7 +524,7 @@ int conf_read(const char *name) /* maybe print value in verbose mode... */ } - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym_has_value(sym) && !sym_is_choice_value(sym)) { /* Reset values of generates values, so they'll appear * as new, if they should become visible, but that @@ -594,7 +540,7 @@ int conf_read(const char *name) /* Reset a string value if it's out of range */ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) break; - sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + sym->flags &= ~SYMBOL_VALID; conf_unsaved++; break; default: @@ -853,10 +799,7 @@ int conf_write_defconfig(const char *filename) while (menu != NULL) { sym = menu->sym; - if (sym == NULL) { - if (!menu_is_visible(menu)) - goto next_menu; - } else if (!sym_is_choice(sym)) { + if (sym && !sym_is_choice(sym)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) goto next_menu; @@ -916,7 +859,6 @@ int conf_write(const char *name) const char *str; char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; char *env; - int i; bool need_newline = false; if (!name) @@ -1000,7 +942,7 @@ end_check: } fclose(out); - for_all_symbols(i, sym) + for_all_symbols(sym) sym->flags &= ~SYMBOL_WRITTEN; if (*tmpname) { @@ -1028,7 +970,6 @@ end_check: static int conf_write_autoconf_cmd(const char *autoconf_name) { char name[PATH_MAX], tmp[PATH_MAX]; - struct file *file; FILE *out; int ret; @@ -1049,15 +990,9 @@ static int conf_write_autoconf_cmd(const char *autoconf_name) return -1; } - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) - fprintf(out, "\t%s \\\n", file->name); - - fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name); + fprintf(out, "autoconfig := %s\n", autoconf_name); - env_write_dep(out, autoconf_name); - - fprintf(out, "\n$(deps_config): ;\n"); + fputs(str_get(&autoconf_cmd), out); fflush(out); ret = ferror(out); /* error check for all fprintf() calls */ @@ -1077,7 +1012,7 @@ static int conf_touch_deps(void) { const char *name, *tmp; struct symbol *sym; - int res, i; + int res; name = conf_get_autoconfig_name(); tmp = strrchr(name, '/'); @@ -1091,7 +1026,7 @@ static int conf_touch_deps(void) conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); - for_all_symbols(i, sym) { + for_all_symbols(sym) { sym_calc_value(sym); if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name) continue; @@ -1157,7 +1092,7 @@ static int __conf_write_autoconf(const char *filename, char tmp[PATH_MAX]; FILE *file; struct symbol *sym; - int ret, i; + int ret; if (make_parent_dir(filename)) return -1; @@ -1174,7 +1109,7 @@ static int __conf_write_autoconf(const char *filename, conf_write_heading(file, comment_style); - for_all_symbols(i, sym) + for_all_symbols(sym) if ((sym->flags & SYMBOL_WRITE) && sym->name) print_symbol(file, sym); @@ -1197,7 +1132,7 @@ int conf_write_autoconf(int overwrite) { struct symbol *sym; const char *autoconf_name = conf_get_autoconfig_name(); - int ret, i; + int ret; if (!overwrite && is_present(autoconf_name)) return 0; @@ -1209,7 +1144,7 @@ int conf_write_autoconf(int overwrite) if (conf_touch_deps()) return 1; - for_all_symbols(i, sym) + for_all_symbols(sym) sym_calc_value(sym); ret = __conf_write_autoconf(conf_get_autoheader_name(), diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 81ebf8108ca7..a290de36307b 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -1131,7 +1131,6 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2) default: return -1; } - printf("[%dgt%d?]", t1, t2); return 0; } diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 4a9a23b1b7e1..0158f5eac454 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -12,17 +12,12 @@ extern "C" { #include <assert.h> #include <stdio.h> -#include "list.h" +#include "list_types.h" #ifndef __cplusplus #include <stdbool.h> #endif -struct file { - struct file *next; - struct file *parent; - const char *name; - int lineno; -}; +#include "list_types.h" typedef enum tristate { no, mod, yes @@ -81,8 +76,8 @@ enum { * SYMBOL_CHOICE bit set in 'flags'. */ struct symbol { - /* The next symbol in the same bucket in the symbol hash table */ - struct symbol *next; + /* link node for the hash table */ + struct hlist_node node; /* The name of the symbol, e.g. "FOO" for 'config FOO' */ char *name; @@ -113,6 +108,9 @@ struct symbol { */ tristate visible; + /* config entries associated with this symbol */ + struct list_head menus; + /* SYMBOL_* flags */ int flags; @@ -131,8 +129,6 @@ struct symbol { struct expr_value implied; }; -#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) - #define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ #define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ @@ -157,7 +153,6 @@ struct symbol { #define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 #define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 9973 /* A property represent the config options that can be associated * with a config "symbol". @@ -195,7 +190,7 @@ struct property { struct menu *menu; /* the menu the property are associated with * valid for: P_SELECT, P_RANGE, P_CHOICE, * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ - struct file *file; /* what file was this property defined */ + const char *filename; /* what file was this property defined */ int lineno; /* what lineno was this property defined */ }; @@ -230,6 +225,8 @@ struct menu { */ struct symbol *sym; + struct list_head link; /* link to symbol::menus */ + /* * The prompt associated with the node. This holds the prompt for a * symbol as well as the text for a menu or comment, along with the @@ -256,7 +253,7 @@ struct menu { char *help; /* The location where the menu node appears in the Kconfig files */ - struct file *file; + const char *filename; int lineno; /* For use by front ends that need to store auxiliary data */ @@ -277,10 +274,6 @@ struct jump_key { struct menu *target; }; -extern struct file *file_list; -extern struct file *current_file; -struct file *lookup_file(const char *name); - extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; extern int cdebug; diff --git a/scripts/kconfig/hashtable.h b/scripts/kconfig/hashtable.h new file mode 100644 index 000000000000..a0a2c8f5f639 --- /dev/null +++ b/scripts/kconfig/hashtable.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef HASHTABLE_H +#define HASHTABLE_H + +#include "array_size.h" +#include "list.h" + +#define HASH_SIZE(name) (ARRAY_SIZE(name)) + +#define HASHTABLE_DECLARE(name, size) struct hlist_head name[size] + +#define HASHTABLE_DEFINE(name, size) \ + HASHTABLE_DECLARE(name, size) = \ + { [0 ... ((size) - 1)] = HLIST_HEAD_INIT } + +#define hash_head(table, key) (&(table)[(key) % HASH_SIZE(table)]) + +/** + * hash_add - add an object to a hashtable + * @table: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add(table, node, key) \ + hlist_add_head(node, hash_head(table, key)) + +/** + * hash_for_each - iterate over a hashtable + * @table: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each(table, obj, member) \ + for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \ + hlist_for_each_entry(obj, &table[_bkt], member) + +/** + * hash_for_each_possible - iterate over all possible objects hashing to the + * same bucket + * @table: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible(table, obj, member, key) \ + hlist_for_each_entry(obj, hash_head(table, key), member) + +#endif /* HASHTABLE_H */ diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h index 2f7298c21b64..6c721c4cfd72 100644 --- a/scripts/kconfig/internal.h +++ b/scripts/kconfig/internal.h @@ -2,8 +2,20 @@ #ifndef INTERNAL_H #define INTERNAL_H +#include "hashtable.h" + +#define SYMBOL_HASHSIZE (1U << 14) + +extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE); + +#define for_all_symbols(sym) \ + hash_for_each(sym_hashtable, sym, node) + struct menu; extern struct menu *current_menu, *current_entry; +extern const char *cur_filename; +extern int cur_lineno; + #endif /* INTERNAL_H */ diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index cc386e443683..89544c3a1a29 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -14,16 +14,22 @@ #include <string.h> #include "lkc.h" +#include "preprocess.h" + #include "parser.tab.h" #define YY_DECL static int yylex1(void) #define START_STRSIZE 16 -static struct { - struct file *file; - int lineno; -} current_pos; +/* The Kconfig file currently being parsed. */ +const char *cur_filename; + +/* + * The line number of the current statement. This does not match yylineno. + * yylineno is used by the lexer, while cur_lineno is used by the parser. + */ +int cur_lineno; static int prev_prev_token = T_EOL; static int prev_token = T_EOL; @@ -33,6 +39,9 @@ static int text_size, text_asize; struct buffer { struct buffer *parent; YY_BUFFER_STATE state; + int yylineno; + const char *filename; + int source_lineno; }; static struct buffer *current_buf; @@ -77,7 +86,7 @@ static void warn_ignored_character(char chr) { fprintf(stderr, "%s:%d:warning: ignoring unsupported character '%c'\n", - current_file->name, yylineno, chr); + cur_filename, yylineno, chr); } %} @@ -180,7 +189,7 @@ n [A-Za-z0-9_-] \n { fprintf(stderr, "%s:%d:warning: multi-line strings not supported\n", - zconf_curname(), zconf_lineno()); + cur_filename, cur_lineno); unput('\n'); BEGIN(INITIAL); yylval.string = text; @@ -246,9 +255,9 @@ n [A-Za-z0-9_-] if (prev_token != T_EOL && prev_token != T_HELPTEXT) fprintf(stderr, "%s:%d:warning: no new line at end of file\n", - current_file->name, yylineno); + cur_filename, yylineno); - if (current_file) { + if (current_buf) { zconf_endfile(); return T_EOL; } @@ -267,19 +276,17 @@ repeat: token = yylex1(); if (prev_token == T_EOL || prev_token == T_HELPTEXT) { - if (token == T_EOL) { + if (token == T_EOL) /* Do not pass unneeded T_EOL to the parser. */ goto repeat; - } else { + else /* - * For the parser, update file/lineno at the first token + * For the parser, update lineno at the first token * of each statement. Generally, \n is a statement * terminator in Kconfig, but it is not always true * because \n could be escaped by a backslash. */ - current_pos.file = current_file; - current_pos.lineno = yylineno; - } + cur_lineno = yylineno; } if (prev_prev_token == T_EOL && prev_token == T_WORD && @@ -302,8 +309,11 @@ static char *expand_token(const char *in, size_t n) new_string(); append_string(in, n); - /* get the whole line because we do not know the end of token. */ - while ((c = input()) != EOF) { + /* + * get the whole line because we do not know the end of token. + * input() returns 0 (not EOF!) when it reachs the end of file. + */ + while ((c = input()) != 0) { if (c == '\n') { unput(c); break; @@ -391,78 +401,60 @@ void zconf_initscan(const char *name) exit(1); } - current_buf = xmalloc(sizeof(*current_buf)); - memset(current_buf, 0, sizeof(*current_buf)); - - current_file = file_lookup(name); + cur_filename = file_lookup(name); yylineno = 1; } void zconf_nextfile(const char *name) { - struct file *iter; - struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); - memset(buf, 0, sizeof(*buf)); + bool recur_include = false; - current_buf->state = YY_CURRENT_BUFFER; - yyin = zconf_fopen(file->name); + buf->state = YY_CURRENT_BUFFER; + buf->yylineno = yylineno; + buf->filename = cur_filename; + buf->source_lineno = cur_lineno; + buf->parent = current_buf; + current_buf = buf; + yyin = zconf_fopen(name); if (!yyin) { fprintf(stderr, "%s:%d: can't open file \"%s\"\n", - zconf_curname(), zconf_lineno(), file->name); + cur_filename, cur_lineno, name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - buf->parent = current_buf; - current_buf = buf; - current_file->lineno = yylineno; - file->parent = current_file; - - for (iter = current_file; iter; iter = iter->parent) { - if (!strcmp(iter->name, file->name)) { - fprintf(stderr, - "Recursive inclusion detected.\n" - "Inclusion path:\n" - " current file : %s\n", file->name); - iter = file; - do { - iter = iter->parent; - fprintf(stderr, " included from: %s:%d\n", - iter->name, iter->lineno - 1); - } while (strcmp(iter->name, file->name)); - exit(1); - } + for (buf = current_buf; buf; buf = buf->parent) { + if (!strcmp(buf->filename, name)) + recur_include = true; } - yylineno = 1; - current_file = file; -} - -static void zconf_endfile(void) -{ - struct buffer *parent; - - current_file = current_file->parent; - if (current_file) - yylineno = current_file->lineno; + if (recur_include) { + fprintf(stderr, + "Recursive inclusion detected.\n" + "Inclusion path:\n" + " current file : %s\n", name); - parent = current_buf->parent; - if (parent) { - fclose(yyin); - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(parent->state); + for (buf = current_buf; buf; buf = buf->parent) + fprintf(stderr, " included from: %s:%d\n", + buf->filename, buf->source_lineno); + exit(1); } - free(current_buf); - current_buf = parent; -} -int zconf_lineno(void) -{ - return current_pos.lineno; + yylineno = 1; + cur_filename = file_lookup(name); } -const char *zconf_curname(void) +static void zconf_endfile(void) { - return current_pos.file ? current_pos.file->name : "<none>"; + struct buffer *tmp; + + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(current_buf->state); + yylineno = current_buf->yylineno; + cur_filename = current_buf->filename; + tmp = current_buf; + current_buf = current_buf->parent; + free(tmp); } diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h index 45cb237ab7ef..882859ddf9f4 100644 --- a/scripts/kconfig/list.h +++ b/scripts/kconfig/list.h @@ -2,29 +2,39 @@ #ifndef LIST_H #define LIST_H -/* - * Copied from include/linux/... - */ +#include <stddef.h> -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#include "list_types.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. + * @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) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - +#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))); }) -struct list_head { - struct list_head *next, *prev; -}; +#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. + */ #define LIST_HEAD_INIT(name) { &(name), &(name) } @@ -32,45 +42,16 @@ struct list_head { struct list_head name = LIST_HEAD_INIT(name) /** - * 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_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_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*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_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. + * 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 int list_empty(const struct list_head *head) +static inline void INIT_LIST_HEAD(struct list_head *list) { - return head->next == head; + list->next = list; + list->prev = list; } /* @@ -79,14 +60,27 @@ static inline int list_empty(const struct list_head *head) * This is only for internal list manipulation where we know * the prev/next entries already! */ -static inline void __list_add(struct list_head *_new, +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; + 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); } /** @@ -97,9 +91,9 @@ static inline void __list_add(struct list_head *_new, * 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) +static inline void list_add_tail(struct list_head *new, struct list_head *head) { - __list_add(_new, head->prev, head); + __list_add(new, head->prev, head); } /* @@ -115,8 +109,11 @@ static inline void __list_del(struct list_head *prev, struct list_head *next) prev->next = next; } -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) +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. @@ -125,8 +122,135 @@ static inline void __list_del(struct list_head *prev, struct list_head *next) */ static inline void list_del(struct list_head *entry) { - __list_del(entry->prev, entry->next); - entry->next = (struct list_head*)LIST_POISON1; - entry->prev = (struct list_head*)LIST_POISON2; + __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)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#define HLIST_HEAD_INIT { .first = NULL } + +/** + * hlist_add_head - add a new entry at the beginning of the hlist + * @n: new entry to be added + * @h: hlist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; } -#endif + +#define hlist_entry(ptr, type, member) container_of(ptr, type, member) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +/** + * hlist_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 hlist_node within the struct. + */ +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +#endif /* LIST_H */ diff --git a/scripts/kconfig/list_types.h b/scripts/kconfig/list_types.h new file mode 100644 index 000000000000..d935b7c5aa81 --- /dev/null +++ b/scripts/kconfig/list_types.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LIST_TYPES_H +#define LIST_TYPES_H + +struct list_head { + struct list_head *next, *prev; +}; + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#endif /* LIST_TYPES_H */ diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 471a59acecec..e7cc9e985c4f 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -36,10 +36,9 @@ void zconf_starthelp(void); FILE *zconf_fopen(const char *name); void zconf_initscan(const char *name); void zconf_nextfile(const char *name); -int zconf_lineno(void); -const char *zconf_curname(void); /* confdata.c */ +extern struct gstr autoconf_cmd; const char *conf_get_configname(void); void set_all_choice_values(struct symbol *csym); @@ -53,7 +52,8 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) } /* util.c */ -struct file *file_lookup(const char *name); +unsigned int strhash(const char *s); +const char *file_lookup(const char *name); void *xmalloc(size_t size); void *xcalloc(size_t nmemb, size_t size); void *xrealloc(void *p, size_t size); @@ -89,7 +89,7 @@ void menu_add_visibility(struct expr *dep); struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); -void menu_finalize(struct menu *parent); +void menu_finalize(void); void menu_set_type(int type); extern struct menu rootmenu; @@ -99,8 +99,6 @@ 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_parent_menu(struct menu *menu); -bool menu_has_help(struct menu *menu); -const char *menu_get_help(struct menu *menu); int get_jump_key_char(void); struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); void menu_get_ext_help(struct menu *menu, struct gstr *help); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index edd1e617b25c..2807fa584c2b 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -1,4 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LKC_PROTO_H +#define LKC_PROTO_H + #include <stdarg.h> /* confdata.c */ @@ -12,16 +15,16 @@ void conf_set_changed(bool val); bool conf_get_changed(void); void conf_set_changed_callback(void (*fn)(void)); void conf_set_message_callback(void (*fn)(const char *s)); +bool conf_errors(void); /* symbol.c */ -extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; - struct symbol * sym_lookup(const char *name, int flags); struct symbol * sym_find(const char *name); void print_symbol_for_listconfig(struct symbol *sym); struct symbol ** sym_re_search(const char *pattern); const char * sym_type_name(enum symbol_type type); void sym_calc_value(struct symbol *sym); +bool sym_dep_errors(void); enum symbol_type sym_get_type(struct symbol *sym); bool sym_tristate_within_range(struct symbol *sym,tristate tri); bool sym_set_tristate_value(struct symbol *sym,tristate tri); @@ -35,18 +38,7 @@ const char * sym_get_string_value(struct symbol *sym); const char * prop_get_type_name(enum prop_type type); -/* preprocess.c */ -enum variable_flavor { - VAR_SIMPLE, - VAR_RECURSIVE, - VAR_APPEND, -}; -void env_write_dep(FILE *f, const char *auto_conf_name); -void variable_add(const char *name, const char *value, - enum variable_flavor flavor); -void variable_all_del(void); -char *expand_dollar(const char **str); -char *expand_one_token(const char **str); - /* expr.c */ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); + +#endif /* LKC_PROTO_H */ diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c index fd161cfff121..75493302fb85 100644 --- a/scripts/kconfig/lxdialog/checklist.c +++ b/scripts/kconfig/lxdialog/checklist.c @@ -119,7 +119,7 @@ int dialog_checklist(const char *title, const char *prompt, int height, } do_resize: - if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN)) + if (getmaxy(stdscr) < (height + CHECKLIST_HEIGHT_MIN)) return -ERRDISPLAYTOOSMALL; if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN)) return -ERRDISPLAYTOOSMALL; @@ -188,9 +188,8 @@ do_resize: print_buttons(dialog, height, width, 0); - wnoutrefresh(dialog); - wnoutrefresh(list); - doupdate(); + wmove(list, choice, check_x + 1); + wrefresh(list); while (key != KEY_ESC) { key = wgetch(dialog); diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index a501abf9fa31..f6c2ebe6d1f9 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -91,10 +91,6 @@ struct dialog_info { struct dialog_color button_label_active; struct dialog_color button_label_inactive; struct dialog_color inputbox; - struct dialog_color inputbox_border; - struct dialog_color searchbox; - struct dialog_color searchbox_title; - struct dialog_color searchbox_border; struct dialog_color position_indicator; struct dialog_color menubox; struct dialog_color menubox_border; @@ -166,17 +162,17 @@ int on_key_esc(WINDOW *win); int on_key_resize(void); /* minimum (re)size values */ -#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */ +#define CHECKLIST_HEIGHT_MIN 6 /* For dialog_checklist() */ #define CHECKLIST_WIDTH_MIN 6 -#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */ +#define INPUTBOX_HEIGHT_MIN 2 /* For dialog_inputbox() */ #define INPUTBOX_WIDTH_MIN 2 -#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */ +#define MENUBOX_HEIGHT_MIN 15 /* For dialog_menu() */ #define MENUBOX_WIDTH_MIN 65 -#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */ +#define TEXTBOX_HEIGHT_MIN 8 /* For dialog_textbox() */ #define TEXTBOX_WIDTH_MIN 8 -#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */ +#define YESNO_HEIGHT_MIN 4 /* For dialog_yesno() */ #define YESNO_WIDTH_MIN 4 -#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */ +#define WINDOW_HEIGHT_MIN 19 /* For init_dialog() */ #define WINDOW_WIDTH_MIN 80 int init_dialog(const char *backtitle); diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c index 1dcfb288ee63..3c6e24b20f5b 100644 --- a/scripts/kconfig/lxdialog/inputbox.c +++ b/scripts/kconfig/lxdialog/inputbox.c @@ -43,7 +43,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width strcpy(instr, init); do_resize: - if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) + if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGHT_MIN)) return -ERRDISPLAYTOOSMALL; if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) return -ERRDISPLAYTOOSMALL; diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c index 0e333284e947..6e6244df0c56 100644 --- a/scripts/kconfig/lxdialog/menubox.c +++ b/scripts/kconfig/lxdialog/menubox.c @@ -172,7 +172,7 @@ int dialog_menu(const char *title, const char *prompt, do_resize: height = getmaxy(stdscr); width = getmaxx(stdscr); - if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN) + if (height < MENUBOX_HEIGHT_MIN || width < MENUBOX_WIDTH_MIN) return -ERRDISPLAYTOOSMALL; height -= 4; diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 058ed0e5bbd5..0abaf635978f 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -175,7 +175,7 @@ int dialog_textbox(const char *title, const char *tbuf, int initial_height, do_resize: getmaxyx(stdscr, height, width); - if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN) + if (height < TEXTBOX_HEIGHT_MIN || width < TEXTBOX_WIDTH_MIN) return -ERRDISPLAYTOOSMALL; if (initial_height != 0) height = initial_height; diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index 3f78fb265136..f18e2a89f613 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -29,10 +29,6 @@ static void set_mono_theme(void) dlg.button_label_active.atr = A_REVERSE; dlg.button_label_inactive.atr = A_NORMAL; dlg.inputbox.atr = A_NORMAL; - dlg.inputbox_border.atr = A_NORMAL; - dlg.searchbox.atr = A_NORMAL; - dlg.searchbox_title.atr = A_BOLD; - dlg.searchbox_border.atr = A_NORMAL; dlg.position_indicator.atr = A_BOLD; dlg.menubox.atr = A_NORMAL; dlg.menubox_border.atr = A_NORMAL; @@ -69,10 +65,6 @@ static void set_classic_theme(void) DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); @@ -101,14 +93,9 @@ static void set_blackbg_theme(void) DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); - DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); + DLG_COLOR(button_label_inactive, COLOR_WHITE, COLOR_BLACK, false); DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); - - DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); - DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); @@ -136,7 +123,6 @@ static void set_bluetitle_theme(void) DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); @@ -189,10 +175,6 @@ static void init_dialog_colors(void) init_one_color(&dlg.button_label_active); init_one_color(&dlg.button_label_inactive); init_one_color(&dlg.inputbox); - init_one_color(&dlg.inputbox_border); - init_one_color(&dlg.searchbox); - init_one_color(&dlg.searchbox_title); - init_one_color(&dlg.searchbox_border); init_one_color(&dlg.position_indicator); init_one_color(&dlg.menubox); init_one_color(&dlg.menubox_border); @@ -309,7 +291,7 @@ int init_dialog(const char *backtitle) getyx(stdscr, saved_y, saved_x); getmaxyx(stdscr, height, width); - if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { + if (height < WINDOW_HEIGHT_MIN || width < WINDOW_WIDTH_MIN) { endwin(); return -ERRDISPLAYTOOSMALL; } diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c index bcaac9b7bab2..b57d25e1549f 100644 --- a/scripts/kconfig/lxdialog/yesno.c +++ b/scripts/kconfig/lxdialog/yesno.c @@ -32,7 +32,7 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width) WINDOW *dialog; do_resize: - if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) + if (getmaxy(stdscr) < (height + YESNO_HEIGHT_MIN)) return -ERRDISPLAYTOOSMALL; if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) return -ERRDISPLAYTOOSMALL; diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index eccc87a441e7..c0969097447d 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -19,8 +19,10 @@ #include <signal.h> #include <unistd.h> +#include "list.h" #include "lkc.h" #include "lxdialog/dialog.h" +#include "mnconf-common.h" static const char mconf_readme[] = "Overview\n" @@ -247,7 +249,7 @@ search_help[] = " -> PCI support (PCI [=y])\n" "(1) -> PCI access mode (<choice> [=y])\n" " Defined at drivers/pci/Kconfig:47\n" - " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC\n" " Selects: LIBCRC32\n" " Selected by: BAR [=n]\n" "-----------------------------------------------------------------\n" @@ -286,7 +288,6 @@ static int single_menu_mode; static int show_all_options; static int save_and_exit; static int silent; -static int jump_key_char; static void conf(struct menu *menu, struct menu *active_menu); @@ -378,58 +379,6 @@ static void show_help(struct menu *menu) str_free(&help); } -struct search_data { - struct list_head *head; - struct menu *target; -}; - -static int next_jump_key(int key) -{ - if (key < '1' || key > '9') - return '1'; - - key++; - - if (key > '9') - key = '1'; - - return key; -} - -static int handle_search_keys(int key, size_t start, size_t end, void *_data) -{ - struct search_data *data = _data; - struct jump_key *pos; - int index = 0; - - if (key < '1' || key > '9') - return 0; - - list_for_each_entry(pos, data->head, entries) { - index = next_jump_key(index); - - if (pos->offset < start) - continue; - - if (pos->offset >= end) - break; - - if (key == index) { - data->target = pos->target; - return 1; - } - } - - return 0; -} - -int get_jump_key_char(void) -{ - jump_key_char = next_jump_key(jump_key_char); - - return jump_key_char; -} - static void search_conf(void) { struct symbol **sym_arr; @@ -710,9 +659,9 @@ static void conf_choice(struct menu *menu) dialog_clear(); res = dialog_checklist(prompt ? prompt : "Main Menu", radiolist_instructions, - MENUBOX_HEIGTH_MIN, + MENUBOX_HEIGHT_MIN, MENUBOX_WIDTH_MIN, - CHECKLIST_HEIGTH_MIN); + CHECKLIST_HEIGHT_MIN); selected = item_activate_selected(); switch (res) { case 0: diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 61c442d84aef..3b822cd110f4 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -10,20 +10,18 @@ #include "lkc.h" #include "internal.h" +#include "list.h" static const char nohelp_text[] = "There is no help available for this option."; struct menu rootmenu; static struct menu **last_entry_ptr; -struct file *file_list; -struct file *current_file; - void menu_warn(struct menu *menu, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); + fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -33,7 +31,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); + fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -53,14 +51,16 @@ void menu_add_entry(struct symbol *sym) memset(menu, 0, sizeof(*menu)); menu->sym = sym; menu->parent = current_menu; - menu->file = current_file; - menu->lineno = zconf_lineno(); + menu->filename = cur_filename; + menu->lineno = cur_lineno; *last_entry_ptr = menu; last_entry_ptr = &menu->next; current_entry = menu; - if (sym) + if (sym) { menu_add_symbol(P_SYMBOL, sym, NULL); + list_add_tail(&menu->link, &sym->menus); + } } struct menu *menu_add_menu(void) @@ -134,8 +134,8 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr, prop = xmalloc(sizeof(*prop)); memset(prop, 0, sizeof(*prop)); prop->type = type; - prop->file = current_file; - prop->lineno = zconf_lineno(); + prop->filename = cur_filename; + prop->lineno = cur_lineno; prop->menu = current_entry; prop->expr = expr; prop->visible.expr = dep; @@ -282,7 +282,7 @@ static void sym_check_prop(struct symbol *sym) } } -void menu_finalize(struct menu *parent) +static void _menu_finalize(struct menu *parent, bool inside_choice) { struct menu *menu, *last_menu; struct symbol *sym; @@ -296,7 +296,12 @@ void menu_finalize(struct menu *parent) * and propagate parent dependencies before moving on. */ - if (sym && sym_is_choice(sym)) { + bool is_choice = false; + + if (sym && sym_is_choice(sym)) + is_choice = true; + + if (is_choice) { if (sym->type == S_UNKNOWN) { /* find the first choice value to find out choice type */ current_entry = parent; @@ -307,12 +312,6 @@ void menu_finalize(struct menu *parent) } } } - /* set the type of the remaining choice values */ - for (menu = parent->list; menu; menu = menu->next) { - current_entry = menu; - if (menu->sym && menu->sym->type == S_UNKNOWN) - menu_set_type(sym->type); - } /* * Use the choice itself as the parent dependency of @@ -400,7 +399,7 @@ void menu_finalize(struct menu *parent) } } - if (sym && sym_is_choice(sym)) + if (is_choice) expr_free(parentdep); /* @@ -408,8 +407,8 @@ void menu_finalize(struct menu *parent) * moving on */ for (menu = parent->list; menu; menu = menu->next) - menu_finalize(menu); - } else if (sym) { + _menu_finalize(menu, is_choice); + } else if (!inside_choice && sym) { /* * Automatic submenu creation. If sym is a symbol and A, B, C, * ... are consecutive items (symbols, menus, ifs, etc.) that @@ -469,7 +468,7 @@ void menu_finalize(struct menu *parent) /* Superset, put in submenu */ expr_free(dep2); next: - menu_finalize(menu); + _menu_finalize(menu, false); menu->parent = parent; last_menu = menu; } @@ -567,9 +566,6 @@ void menu_finalize(struct menu *parent) if (sym->type == S_UNKNOWN) menu_warn(parent, "config symbol defined without type"); - if (sym_is_choice(sym) && !parent->prompt) - menu_warn(parent, "choice must have a prompt"); - /* Check properties connected to this symbol */ sym_check_prop(sym); sym->flags |= SYMBOL_WARNED; @@ -591,6 +587,11 @@ void menu_finalize(struct menu *parent) } } +void menu_finalize(void) +{ + _menu_finalize(&rootmenu, false); +} + bool menu_has_prompt(struct menu *menu) { if (!menu->prompt) @@ -673,23 +674,10 @@ struct menu *menu_get_parent_menu(struct menu *menu) return menu; } -bool menu_has_help(struct menu *menu) -{ - return menu->help != NULL; -} - -const char *menu_get_help(struct menu *menu) -{ - if (menu->help) - return menu->help; - else - return ""; -} - static void get_def_str(struct gstr *r, struct menu *menu) { str_printf(r, "Defined at %s:%d\n", - menu->file->name, menu->lineno); + menu->filename, menu->lineno); } static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) @@ -790,6 +778,7 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, struct list_head *head) { struct property *prop; + struct menu *menu; if (sym && sym->name) { str_printf(r, "Symbol: %s [=%s]\n", sym->name, @@ -806,17 +795,17 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, } /* Print the definitions with prompts before the ones without */ - for_all_properties(sym, prop, P_SYMBOL) { - if (prop->menu->prompt) { - get_def_str(r, prop->menu); - get_prompt_str(r, prop->menu->prompt, head); + list_for_each_entry(menu, &sym->menus, link) { + if (menu->prompt) { + get_def_str(r, menu); + get_prompt_str(r, menu->prompt, head); } } - for_all_properties(sym, prop, P_SYMBOL) { - if (!prop->menu->prompt) { - get_def_str(r, prop->menu); - get_dep_str(r, prop->menu->dep, " Depends on: "); + list_for_each_entry(menu, &sym->menus, link) { + if (!menu->prompt) { + get_def_str(r, menu); + get_dep_str(r, menu->dep, " Depends on: "); } } @@ -856,10 +845,10 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) struct symbol *sym = menu->sym; const char *help_text = nohelp_text; - if (menu_has_help(menu)) { + if (menu->help) { if (sym->name) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); - help_text = menu_get_help(menu); + help_text = menu->help; } str_printf(help, "%s\n", help_text); if (sym) diff --git a/scripts/kconfig/mnconf-common.c b/scripts/kconfig/mnconf-common.c new file mode 100644 index 000000000000..18cb9a6c5aaa --- /dev/null +++ b/scripts/kconfig/mnconf-common.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "expr.h" +#include "list.h" +#include "mnconf-common.h" + +int jump_key_char; + +int next_jump_key(int key) +{ + if (key < '1' || key > '9') + return '1'; + + key++; + + if (key > '9') + key = '1'; + + return key; +} + +int handle_search_keys(int key, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int index = 0; + + if (key < '1' || key > '9') + return 0; + + list_for_each_entry(pos, data->head, entries) { + index = next_jump_key(index); + + if (pos->offset < start) + continue; + + if (pos->offset >= end) + break; + + if (key == index) { + data->target = pos->target; + return 1; + } + } + + return 0; +} + +int get_jump_key_char(void) +{ + jump_key_char = next_jump_key(jump_key_char); + + return jump_key_char; +} diff --git a/scripts/kconfig/mnconf-common.h b/scripts/kconfig/mnconf-common.h new file mode 100644 index 000000000000..ab6292cc4bf2 --- /dev/null +++ b/scripts/kconfig/mnconf-common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef MNCONF_COMMON_H +#define MNCONF_COMMON_H + +#include <stddef.h> + +struct search_data { + struct list_head *head; + struct menu *target; +}; + +extern int jump_key_char; + +int next_jump_key(int key); +int handle_search_keys(int key, size_t start, size_t end, void *_data); +int get_jump_key_char(void); + +#endif /* MNCONF_COMMON_H */ diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 143a2c351d57..9d22b0f3197b 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -11,7 +11,9 @@ #include <strings.h> #include <stdlib.h> +#include "list.h" #include "lkc.h" +#include "mnconf-common.h" #include "nconf.h" #include <ctype.h> @@ -216,7 +218,7 @@ search_help[] = "Symbol: FOO [ = m]\n" "Prompt: Foo bus is used to drive the bar HW\n" "Defined at drivers/pci/Kconfig:47\n" -"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" +"Depends on: X86_LOCAL_APIC && X86_IO_APIC\n" "Location:\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [ = y])\n" @@ -279,7 +281,6 @@ static const char *current_instructions = menu_instructions; static char *dialog_input_result; static int dialog_input_result_len; -static int jump_key_char; static void selected_conf(struct menu *menu, struct menu *active_menu); static void conf(struct menu *menu); @@ -691,57 +692,6 @@ static int do_exit(void) return 0; } -struct search_data { - struct list_head *head; - struct menu *target; -}; - -static int next_jump_key(int key) -{ - if (key < '1' || key > '9') - return '1'; - - key++; - - if (key > '9') - key = '1'; - - return key; -} - -static int handle_search_keys(int key, size_t start, size_t end, void *_data) -{ - struct search_data *data = _data; - struct jump_key *pos; - int index = 0; - - if (key < '1' || key > '9') - return 0; - - list_for_each_entry(pos, data->head, entries) { - index = next_jump_key(index); - - if (pos->offset < start) - continue; - - if (pos->offset >= end) - break; - - if (key == index) { - data->target = pos->target; - return 1; - } - } - - return 0; -} - -int get_jump_key_char(void) -{ - jump_key_char = next_jump_key(jump_key_char); - - return jump_key_char; -} static void search_conf(void) { diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 2af7ce4e1531..7fb996612c96 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -13,6 +13,7 @@ #include "lkc.h" #include "internal.h" +#include "preprocess.h" #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) @@ -27,8 +28,6 @@ static void zconf_error(const char *err, ...); static bool zconf_endtoken(const char *tokenname, const char *expected_tokenname); -struct symbol *symbol_hash[SYMBOL_HASHSIZE]; - struct menu *current_menu, *current_entry; %} @@ -95,12 +94,12 @@ struct menu *current_menu, *current_entry; %type <expr> if_expr %type <string> end %type <menu> if_entry menu_entry choice_entry -%type <string> word_opt assign_val +%type <string> assign_val %type <flavor> assign_op %destructor { fprintf(stderr, "%s:%d: missing end statement for this entry\n", - $$->file->name, $$->lineno); + $$->filename, $$->lineno); if (current_menu == $$) menu_end_menu(); } if_entry menu_entry choice_entry @@ -143,19 +142,19 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL { $2->flags |= SYMBOL_OPTIONAL; menu_add_entry($2); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name); + printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name); }; config_stmt: config_entry_start config_option_list { - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); }; menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL { $2->flags |= SYMBOL_OPTIONAL; menu_add_entry($2); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name); }; menuconfig_stmt: menuconfig_entry_start config_option_list @@ -164,7 +163,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list current_entry->prompt->type = P_MENU; else zconfprint("warning: menuconfig statement without prompt"); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); }; config_option_list: @@ -177,15 +176,13 @@ config_option_list: config_option: type prompt_stmt_opt T_EOL { menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), - $1); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1); }; config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); }; config_option: default expr if_expr T_EOL @@ -193,27 +190,26 @@ config_option: default expr if_expr T_EOL menu_add_expr(P_DEFAULT, $2, $3); if ($1 != S_UNKNOWN) menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:default(%u)\n", - zconf_curname(), zconf_lineno(), + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno, $1); }; config_option: T_SELECT nonconst_symbol if_expr T_EOL { menu_add_symbol(P_SELECT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno); }; config_option: T_IMPLY nonconst_symbol if_expr T_EOL { menu_add_symbol(P_IMPLY, $2, $3); - printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno); }; config_option: T_RANGE symbol symbol if_expr T_EOL { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); - printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno); }; config_option: T_MODULES T_EOL @@ -226,18 +222,23 @@ config_option: T_MODULES T_EOL /* choice entry */ -choice: T_CHOICE word_opt T_EOL +choice: T_CHOICE T_EOL { - struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + struct symbol *sym = sym_lookup(NULL, SYMBOL_CHOICE); sym->flags |= SYMBOL_NO_WRITE; menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); - free($2); - printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno); }; choice_entry: choice choice_option_list { + if (!current_entry->prompt) { + fprintf(stderr, "%s:%d: error: choice must have a prompt\n", + current_entry->filename, current_entry->lineno); + yynerrs++; + } + $$ = menu_add_menu(); }; @@ -245,7 +246,7 @@ choice_end: end { if (zconf_endtoken($1, "choice")) { menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno); } }; @@ -262,27 +263,25 @@ choice_option_list: choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); }; choice_option: logic_type prompt_stmt_opt T_EOL { menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), $1); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1); }; choice_option: T_OPTIONAL T_EOL { current_entry->sym->flags |= SYMBOL_OPTIONAL; - printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:optional\n", cur_filename, cur_lineno); }; choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL { menu_add_symbol(P_DEFAULT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:default\n", - zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno); }; type: @@ -304,7 +303,7 @@ default: if_entry: T_IF expr T_EOL { - printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno); menu_add_entry(NULL); menu_add_dep($2); $$ = menu_add_menu(); @@ -314,7 +313,7 @@ if_end: end { if (zconf_endtoken($1, "if")) { menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno); } }; @@ -330,7 +329,7 @@ menu: T_MENU T_WORD_QUOTE T_EOL { menu_add_entry(NULL); menu_add_prompt(P_MENU, $2, NULL); - printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno); }; menu_entry: menu menu_option_list @@ -342,7 +341,7 @@ menu_end: end { if (zconf_endtoken($1, "menu")) { menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno); } }; @@ -357,7 +356,7 @@ menu_option_list: source_stmt: T_SOURCE T_WORD_QUOTE T_EOL { - printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2); zconf_nextfile($2); free($2); }; @@ -368,7 +367,7 @@ comment: T_COMMENT T_WORD_QUOTE T_EOL { menu_add_entry(NULL); menu_add_prompt(P_COMMENT, $2, NULL); - printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno); }; comment_stmt: comment comment_option_list @@ -383,7 +382,7 @@ comment_option_list: help_start: T_HELP T_EOL { - printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno); zconf_starthelp(); }; @@ -408,7 +407,7 @@ help: help_start T_HELPTEXT depends: T_DEPENDS T_ON expr T_EOL { menu_add_dep($3); - printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno); }; /* visibility option */ @@ -455,9 +454,6 @@ symbol: nonconst_symbol | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } ; -word_opt: /* empty */ { $$ = NULL; } - | T_WORD - /* assignment statement */ assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); } @@ -477,8 +473,11 @@ assign_val: void conf_parse(const char *name) { - struct symbol *sym; - int i; + struct menu *menu; + + autoconf_cmd = str_new(); + + str_printf(&autoconf_cmd, "\ndeps_config := \\\n"); zconf_initscan(name); @@ -488,24 +487,52 @@ void conf_parse(const char *name) yydebug = 1; yyparse(); + /* + * FIXME: + * cur_filename and cur_lineno are used even after yyparse(); + * menu_finalize() calls menu_add_symbol(). This should be fixed. + */ + cur_filename = "<none>"; + cur_lineno = 0; + + str_printf(&autoconf_cmd, + "\n" + "$(autoconfig): $(deps_config)\n" + "$(deps_config): ;\n"); + + env_write_dep(&autoconf_cmd); + /* Variables are expanded in the parse phase. We can free them here. */ variable_all_del(); if (yynerrs) exit(1); if (!modules_sym) - modules_sym = sym_find( "n" ); + modules_sym = &symbol_no; if (!menu_has_prompt(&rootmenu)) { current_entry = &rootmenu; menu_add_prompt(P_MENU, "Main menu", NULL); } - menu_finalize(&rootmenu); - for_all_symbols(i, sym) { - if (sym_check_deps(sym)) + menu_finalize(); + + menu = &rootmenu; + while (menu) { + if (menu->sym && sym_check_deps(menu->sym)) yynerrs++; + + if (menu->list) { + menu = menu->list; + continue; + } + + while (!menu->next && menu->parent) + menu = menu->parent; + + menu = menu->next; } + if (yynerrs) exit(1); conf_set_changed(true); @@ -520,11 +547,11 @@ static bool zconf_endtoken(const char *tokenname, yynerrs++; return false; } - if (current_menu->file != current_file) { + if (strcmp(current_menu->filename, cur_filename)) { zconf_error("'%s' in different file than '%s'", tokenname, expected_tokenname); fprintf(stderr, "%s:%d: location of the '%s'\n", - current_menu->file->name, current_menu->lineno, + current_menu->filename, current_menu->lineno, expected_tokenname); yynerrs++; return false; @@ -536,7 +563,7 @@ static void zconfprint(const char *err, ...) { va_list ap; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); @@ -548,7 +575,7 @@ static void zconf_error(const char *err, ...) va_list ap; yynerrs++; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); @@ -557,7 +584,7 @@ static void zconf_error(const char *err, ...) static void yyerror(const char *err) { - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); + fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err); } static void print_quoted_string(FILE *out, const char *str) diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index d1f5bcff4b62..f0a4a218c4a5 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -9,10 +9,11 @@ #include <stdlib.h> #include <string.h> +#include "array_size.h" +#include "internal.h" #include "list.h" #include "lkc.h" - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#include "preprocess.h" static char *expand_string_with_args(const char *in, int argc, char *argv[]); static char *expand_string(const char *in); @@ -21,7 +22,7 @@ static void __attribute__((noreturn)) pperror(const char *format, ...) { va_list ap; - fprintf(stderr, "%s:%d: ", current_file->name, yylineno); + fprintf(stderr, "%s:%d: ", cur_filename, yylineno); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); @@ -87,14 +88,17 @@ static char *env_expand(const char *name) return xstrdup(value); } -void env_write_dep(FILE *f, const char *autoconfig_name) +void env_write_dep(struct gstr *s) { struct env *e, *tmp; list_for_each_entry_safe(e, tmp, &env_list, node) { - fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value); - fprintf(f, "%s: FORCE\n", autoconfig_name); - fprintf(f, "endif\n"); + str_printf(s, + "\n" + "ifneq \"$(%s)\" \"%s\"\n" + "$(autoconfig): FORCE\n" + "endif\n", + e->name, e->value); env_del(e); } } @@ -119,7 +123,7 @@ static char *do_error_if(int argc, char *argv[]) static char *do_filename(int argc, char *argv[]) { - return xstrdup(current_file->name); + return xstrdup(cur_filename); } static char *do_info(int argc, char *argv[]) @@ -181,8 +185,7 @@ static char *do_shell(int argc, char *argv[]) static char *do_warning_if(int argc, char *argv[]) { if (!strcmp(argv[0], "y")) - fprintf(stderr, "%s:%d: %s\n", - current_file->name, yylineno, argv[1]); + fprintf(stderr, "%s:%d: %s\n", cur_filename, yylineno, argv[1]); return xstrdup(""); } diff --git a/scripts/kconfig/preprocess.h b/scripts/kconfig/preprocess.h new file mode 100644 index 000000000000..a7e4a550638c --- /dev/null +++ b/scripts/kconfig/preprocess.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef PREPROCESS_H +#define PREPROCESS_H + +enum variable_flavor { + VAR_SIMPLE, + VAR_RECURSIVE, + VAR_APPEND, +}; + +struct gstr; +void env_write_dep(struct gstr *gs); +void variable_add(const char *name, const char *value, + enum variable_flavor flavor); +void variable_all_del(void); +char *expand_dollar(const char **str); +char *expand_one_token(const char **str); + +#endif /* PREPROCESS_H */ diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 620a3527c767..c6c42c0f4e5d 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1058,7 +1058,7 @@ void ConfigInfoView::menuInfo(void) stream << "<br><br>"; } - stream << "defined at " << _menu->file->name << ":" + stream << "defined at " << _menu->filename << ":" << _menu->lineno << "<br><br>"; } } diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index a76925b46ce6..81fe1884ef8a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -9,34 +9,33 @@ #include <string.h> #include <regex.h> +#include "internal.h" #include "lkc.h" struct symbol symbol_yes = { .name = "y", .curr = { "y", yes }, + .menus = LIST_HEAD_INIT(symbol_yes.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; struct symbol symbol_mod = { .name = "m", .curr = { "m", mod }, + .menus = LIST_HEAD_INIT(symbol_mod.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; struct symbol symbol_no = { .name = "n", .curr = { "n", no }, + .menus = LIST_HEAD_INIT(symbol_no.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; -static struct symbol symbol_empty = { - .name = "", - .curr = { "", no }, - .flags = SYMBOL_VALID, -}; - struct symbol *modules_sym; static tristate modules_val; +static int sym_warnings; enum symbol_type sym_get_type(struct symbol *sym) { @@ -165,9 +164,8 @@ static void sym_set_changed(struct symbol *sym) static void sym_set_all_changed(void) { struct symbol *sym; - int i; - for_all_symbols(i, sym) + for_all_symbols(sym) sym_set_changed(sym); } @@ -317,6 +315,14 @@ static void sym_warn_unmet_dep(struct symbol *sym) " Selected by [m]:\n"); fputs(str_get(&gs), stderr); + sym_warnings++; +} + +bool sym_dep_errors(void) +{ + if (sym_warnings) + return getenv("KCONFIG_WERROR"); + return false; } void sym_calc_value(struct symbol *sym) @@ -342,15 +348,21 @@ void sym_calc_value(struct symbol *sym) oldval = sym->curr; + newval.tri = no; + switch (sym->type) { case S_INT: + newval.val = "0"; + break; case S_HEX: + newval.val = "0x0"; + break; case S_STRING: - newval = symbol_empty.curr; + newval.val = ""; break; case S_BOOLEAN: case S_TRISTATE: - newval = symbol_no.curr; + newval.val = "n"; break; default: sym->curr.val = sym->name; @@ -466,9 +478,8 @@ void sym_calc_value(struct symbol *sym) void sym_clear_all_valid(void) { struct symbol *sym; - int i; - for_all_symbols(i, sym) + for_all_symbols(sym) sym->flags &= ~SYMBOL_VALID; conf_set_changed(true); sym_calc_value(modules_sym); @@ -697,13 +708,12 @@ const char *sym_get_string_default(struct symbol *sym) { struct property *prop; struct symbol *ds; - const char *str; + const char *str = ""; tristate val; sym_calc_visibility(sym); sym_calc_value(modules_sym); val = symbol_no.curr.tri; - str = symbol_empty.curr.val; /* If symbol has a default value look it up */ prop = sym_get_default_prop(sym); @@ -753,14 +763,17 @@ const char *sym_get_string_default(struct symbol *sym) case yes: return "y"; } case S_INT: + if (!str[0]) + str = "0"; + break; case S_HEX: - return str; - case S_STRING: - return str; - case S_UNKNOWN: + if (!str[0]) + str = "0x0"; + break; + default: break; } - return ""; + return str; } const char *sym_get_string_value(struct symbol *sym) @@ -792,14 +805,7 @@ bool sym_is_changeable(struct symbol *sym) return sym->visible > sym->rev_dep.tri; } -static unsigned strhash(const char *s) -{ - /* fnv32 hash */ - unsigned hash = 2166136261U; - for (; *s; s++) - hash = (hash ^ *s) * 0x01000193; - return hash; -} +HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE); struct symbol *sym_lookup(const char *name, int flags) { @@ -815,9 +821,9 @@ struct symbol *sym_lookup(const char *name, int flags) case 'n': return &symbol_no; } } - hash = strhash(name) % SYMBOL_HASHSIZE; + hash = strhash(name); - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && !strcmp(symbol->name, name) && (flags ? symbol->flags & flags @@ -835,9 +841,9 @@ struct symbol *sym_lookup(const char *name, int flags) symbol->name = new_name; symbol->type = S_UNKNOWN; symbol->flags = flags; + INIT_LIST_HEAD(&symbol->menus); - symbol->next = symbol_hash[hash]; - symbol_hash[hash] = symbol; + hash_add(sym_hashtable, &symbol->node, hash); return symbol; } @@ -857,9 +863,9 @@ struct symbol *sym_find(const char *name) case 'n': return &symbol_no; } } - hash = strhash(name) % SYMBOL_HASHSIZE; + hash = strhash(name); - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && !strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) @@ -919,7 +925,7 @@ struct symbol **sym_re_search(const char *pattern) if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) return NULL; - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym->flags & SYMBOL_CONST || !sym->name) continue; if (regexec(&re, sym->name, 1, match, 0)) @@ -1030,42 +1036,42 @@ static void sym_check_print_recursive(struct symbol *last_sym) } if (stack->sym == last_sym) fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", - prop->file->name, prop->lineno); + prop->filename, prop->lineno); if (sym_is_choice(sym)) { fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, + menu->filename, menu->lineno, sym->name ? sym->name : "<choice>", next_sym->name ? next_sym->name : "<choice>"); } else if (sym_is_choice_value(sym)) { fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", - menu->file->name, menu->lineno, + menu->filename, menu->lineno, sym->name ? sym->name : "<choice>", next_sym->name ? next_sym->name : "<choice>"); } else if (stack->expr == &sym->dir_dep.expr) { fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "<choice>", next_sym->name ? next_sym->name : "<choice>"); } else if (stack->expr == &sym->rev_dep.expr) { fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "<choice>", next_sym->name ? next_sym->name : "<choice>"); } else if (stack->expr == &sym->implied.expr) { fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "<choice>", next_sym->name ? next_sym->name : "<choice>"); } else if (stack->expr) { fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "<choice>", prop_get_type_name(prop->type), next_sym->name ? next_sym->name : "<choice>"); } else { fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "<choice>", prop_get_type_name(prop->type), next_sym->name ? next_sym->name : "<choice>"); diff --git a/scripts/kconfig/tests/choice_randomize/Kconfig b/scripts/kconfig/tests/choice_randomize/Kconfig new file mode 100644 index 000000000000..93a1699ce3cb --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/Kconfig @@ -0,0 +1,22 @@ +choice + prompt "choose A or B" + +config A + bool "A" + +config B + bool "B" + +endchoice + +choice + prompt "choose X or Y" + depends on B + +config X + bool "X" + +config Y + bool "Y" + +endchoice diff --git a/scripts/kconfig/tests/choice_randomize/__init__.py b/scripts/kconfig/tests/choice_randomize/__init__.py new file mode 100644 index 000000000000..d380045be79c --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/__init__.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only +""" +Randomize all dependent choices + +This is a somewhat tricky case for randconfig; the visibility of one choice is +determined by a member of another choice. Randconfig should be able to generate +all possible patterns. +""" + + +def test(conf): + + expected0 = False + expected1 = False + expected2 = False + + for i in range(100): + assert conf.randconfig(seed=i) == 0 + + if conf.config_matches('expected_config0'): + expected0 = True + elif conf.config_matches('expected_config1'): + expected1 = True + elif conf.config_matches('expected_config2'): + expected2 = True + else: + assert False + + if expected0 and expected1 and expected2: + break + + assert expected0 + assert expected1 + assert expected2 diff --git a/scripts/kconfig/tests/choice_randomize/expected_config0 b/scripts/kconfig/tests/choice_randomize/expected_config0 new file mode 100644 index 000000000000..f69227323759 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/expected_config0 @@ -0,0 +1,6 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +CONFIG_A=y +# CONFIG_B is not set diff --git a/scripts/kconfig/tests/choice_randomize/expected_config1 b/scripts/kconfig/tests/choice_randomize/expected_config1 new file mode 100644 index 000000000000..bf83784c9b2a --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/expected_config1 @@ -0,0 +1,8 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +# CONFIG_A is not set +CONFIG_B=y +CONFIG_X=y +# CONFIG_Y is not set diff --git a/scripts/kconfig/tests/choice_randomize/expected_config2 b/scripts/kconfig/tests/choice_randomize/expected_config2 new file mode 100644 index 000000000000..38f93a8f37bd --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/expected_config2 @@ -0,0 +1,8 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +# CONFIG_A is not set +CONFIG_B=y +# CONFIG_X is not set +CONFIG_Y=y diff --git a/scripts/kconfig/tests/choice_randomize2/Kconfig b/scripts/kconfig/tests/choice_randomize2/Kconfig new file mode 100644 index 000000000000..530cf2ef7f47 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/Kconfig @@ -0,0 +1,32 @@ +choice + prompt "This is always invisible" + depends on n + +config DUMMY + bool "DUMMY" + +endchoice + +choice + prompt "Choose A or B" + +config A + bool "A" + +config B + bool "B" + +endchoice + +config FOO + bool "FOO" + depends on A + +choice + prompt "Choose X" + depends on FOO + +config X + bool "X" + +endchoice diff --git a/scripts/kconfig/tests/choice_randomize2/__init__.py b/scripts/kconfig/tests/choice_randomize2/__init__.py new file mode 100644 index 000000000000..2066757b80b9 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/__init__.py @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +""" +Randomize choices with correct dependencies + +When shuffling a choice may potentially disrupt certain dependencies, symbol +values must be recalculated. + +Related Linux commits: + - c8fb7d7e48d11520ad24808cfce7afb7b9c9f798 +""" + + +def test(conf): + for i in range(20): + assert conf.randconfig(seed=i) == 0 + assert (conf.config_matches('expected_config0') or + conf.config_matches('expected_config1') or + conf.config_matches('expected_config2')) diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config0 b/scripts/kconfig/tests/choice_randomize2/expected_config0 new file mode 100644 index 000000000000..5c9e1c172c15 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/expected_config0 @@ -0,0 +1,8 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +CONFIG_A=y +# CONFIG_B is not set +CONFIG_FOO=y +CONFIG_X=y diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config1 b/scripts/kconfig/tests/choice_randomize2/expected_config1 new file mode 100644 index 000000000000..5b975d91bef1 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/expected_config1 @@ -0,0 +1,7 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +CONFIG_A=y +# CONFIG_B is not set +# CONFIG_FOO is not set diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config2 b/scripts/kconfig/tests/choice_randomize2/expected_config2 new file mode 100644 index 000000000000..5a5ebb90d1d7 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/expected_config2 @@ -0,0 +1,6 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +# CONFIG_A is not set +CONFIG_B=y diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py index af8774a5697c..2a2a7e2da060 100644 --- a/scripts/kconfig/tests/conftest.py +++ b/scripts/kconfig/tests/conftest.py @@ -154,12 +154,10 @@ class Conf: defconfig_path = os.path.join(self._test_dir, defconfig) return self._run_conf('--defconfig={}'.format(defconfig_path)) - def _allconfig(self, mode, all_config): + def _allconfig(self, mode, all_config, extra_env={}): if all_config: all_config_path = os.path.join(self._test_dir, all_config) - extra_env = {'KCONFIG_ALLCONFIG': all_config_path} - else: - extra_env = {} + extra_env['KCONFIG_ALLCONFIG'] = all_config_path return self._run_conf('--{}config'.format(mode), extra_env=extra_env) @@ -195,13 +193,19 @@ class Conf: """ return self._allconfig('alldef', all_config) - def randconfig(self, all_config=None): + def randconfig(self, all_config=None, seed=None): """Run randconfig. all_config: fragment config file for KCONFIG_ALLCONFIG (optional) + seed: the seed for randconfig (optional) returncode: exit status of the Kconfig executable """ - return self._allconfig('rand', all_config) + if seed is not None: + extra_env = {'KCONFIG_SEED': hex(seed)} + else: + extra_env = {} + + return self._allconfig('rand', all_config, extra_env=extra_env) def savedefconfig(self, dot_config): """Run savedefconfig. diff --git a/scripts/kconfig/tests/err_recursive_dep/expected_stderr b/scripts/kconfig/tests/err_recursive_dep/expected_stderr index c9f4abf9a791..05d4ced70320 100644 --- a/scripts/kconfig/tests/err_recursive_dep/expected_stderr +++ b/scripts/kconfig/tests/err_recursive_dep/expected_stderr @@ -1,10 +1,10 @@ -Kconfig:11:error: recursive dependency detected! -Kconfig:11: symbol B is selected by B +Kconfig:5:error: recursive dependency detected! +Kconfig:5: symbol A depends on A For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:5:error: recursive dependency detected! -Kconfig:5: symbol A depends on A +Kconfig:11:error: recursive dependency detected! +Kconfig:11: symbol B is selected by B For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" @@ -14,9 +14,9 @@ Kconfig:21: symbol C2 depends on C1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:32:error: recursive dependency detected! -Kconfig:32: symbol D2 is selected by D1 +Kconfig:27:error: recursive dependency detected! Kconfig:27: symbol D1 depends on D2 +Kconfig:32: symbol D2 is selected by D1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" @@ -26,13 +26,13 @@ Kconfig:42: symbol E2 is implied by E1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:60:error: recursive dependency detected! -Kconfig:60: symbol G depends on G +Kconfig:49:error: recursive dependency detected! +Kconfig:49: symbol F1 default value contains F2 +Kconfig:51: symbol F2 depends on F1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:51:error: recursive dependency detected! -Kconfig:51: symbol F2 depends on F1 -Kconfig:49: symbol F1 default value contains F2 +Kconfig:60:error: recursive dependency detected! +Kconfig:60: symbol G depends on G For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index b78f114ad48c..439c131b424e 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -7,25 +7,50 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> + +#include "hashtable.h" #include "lkc.h" +unsigned int strhash(const char *s) +{ + /* fnv32 hash */ + unsigned int hash = 2166136261U; + + for (; *s; s++) + hash = (hash ^ *s) * 0x01000193; + return hash; +} + +/* hash table of all parsed Kconfig files */ +static HASHTABLE_DEFINE(file_hashtable, 1U << 11); + +struct file { + struct hlist_node node; + char name[]; +}; + /* file already present in list? If not add it */ -struct file *file_lookup(const char *name) +const char *file_lookup(const char *name) { struct file *file; + size_t len; + int hash = strhash(name); - for (file = file_list; file; file = file->next) { - if (!strcmp(name, file->name)) { - return file; - } - } + hash_for_each_possible(file_hashtable, file, node, hash) + if (!strcmp(name, file->name)) + return file->name; - file = xmalloc(sizeof(*file)); + len = strlen(name); + file = xmalloc(sizeof(*file) + len + 1); memset(file, 0, sizeof(*file)); - file->name = xstrdup(name); - file->next = file_list; - file_list = file; - return file; + memcpy(file->name, name, len); + file->name[len] = '\0'; + + hash_add(file_hashtable, &file->node, hash); + + str_printf(&autoconf_cmd, "\t%s \\\n", name); + + return file->name; } /* Allocate initial growable string */ @@ -42,8 +67,7 @@ struct gstr str_new(void) /* Free storage for growable string */ void str_free(struct gstr *gs) { - if (gs->s) - free(gs->s); + free(gs->s); gs->s = NULL; gs->len = 0; } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 08a3e603db19..cb1be22afc65 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1,5 +1,6 @@ #!/usr/bin/env perl # SPDX-License-Identifier: GPL-2.0 +# vim: softtabstop=4 use warnings; use strict; @@ -23,7 +24,7 @@ kernel-doc - Print formatted kernel documentation to stdout =head1 SYNOPSIS - kernel-doc [-h] [-v] [-Werror] [-Wall] [-Wreturn] [-Wshort-description] [-Wcontents-before-sections] + kernel-doc [-h] [-v] [-Werror] [-Wall] [-Wreturn] [-Wshort-desc[ription]] [-Wcontents-before-sections] [ -man | -rst [-sphinx-version VERSION] [-enable-lineno] | -none @@ -64,7 +65,7 @@ my $type_constant = '\b``([^\`]+)``\b'; my $type_constant2 = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; -my $type_param_ref = '([\!~]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; +my $type_param_ref = '([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params my $type_fp_param2 = '\@(\w+->\S+)\(\)'; # Special RST handling for structs with func ptr params my $type_env = '(\$\w+)'; @@ -81,49 +82,51 @@ my $type_member_func = $type_member . '\(\)'; # these are pretty rough my @highlights_man = ( - [$type_constant, "\$1"], - [$type_constant2, "\$1"], - [$type_func, "\\\\fB\$1\\\\fP"], - [$type_enum, "\\\\fI\$1\\\\fP"], - [$type_struct, "\\\\fI\$1\\\\fP"], - [$type_typedef, "\\\\fI\$1\\\\fP"], - [$type_union, "\\\\fI\$1\\\\fP"], - [$type_param, "\\\\fI\$1\\\\fP"], - [$type_param_ref, "\\\\fI\$1\$2\\\\fP"], - [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], - [$type_fallback, "\\\\fI\$1\\\\fP"] - ); + [$type_constant, "\$1"], + [$type_constant2, "\$1"], + [$type_func, "\\\\fB\$1\\\\fP"], + [$type_enum, "\\\\fI\$1\\\\fP"], + [$type_struct, "\\\\fI\$1\\\\fP"], + [$type_typedef, "\\\\fI\$1\\\\fP"], + [$type_union, "\\\\fI\$1\\\\fP"], + [$type_param, "\\\\fI\$1\\\\fP"], + [$type_param_ref, "\\\\fI\$1\$2\\\\fP"], + [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], + [$type_fallback, "\\\\fI\$1\\\\fP"] + ); my $blankline_man = ""; # rst-mode my @highlights_rst = ( - [$type_constant, "``\$1``"], - [$type_constant2, "``\$1``"], - # Note: need to escape () to avoid func matching later - [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], - [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], - [$type_fp_param, "**\$1\\\\(\\\\)**"], - [$type_fp_param2, "**\$1\\\\(\\\\)**"], - [$type_func, "\$1()"], - [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], - [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], - [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], - [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], - # in rst this can refer to any type - [$type_fallback, "\\:c\\:type\\:`\$1`"], - [$type_param_ref, "**\$1\$2**"] - ); + [$type_constant, "``\$1``"], + [$type_constant2, "``\$1``"], + + # Note: need to escape () to avoid func matching later + [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], + [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], + [$type_fp_param, "**\$1\\\\(\\\\)**"], + [$type_fp_param2, "**\$1\\\\(\\\\)**"], + [$type_func, "\$1()"], + [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], + + # in rst this can refer to any type + [$type_fallback, "\\:c\\:type\\:`\$1`"], + [$type_param_ref, "**\$1\$2**"] + ); my $blankline_rst = "\n"; # read arguments if ($#ARGV == -1) { - pod2usage( - -message => "No arguments!\n", - -exitval => 1, - -verbose => 99, - -sections => 'SYNOPSIS', - -output => \*STDERR, - ); + pod2usage( + -message => "No arguments!\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } my $kernelversion; @@ -164,9 +167,9 @@ if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && } my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', - 'November', 'December')[$build_time[4]] . - " " . ($build_time[5]+1900); + 'July', 'August', 'September', 'October', + 'November', 'December')[$build_time[4]] . + " " . ($build_time[5]+1900); # Essentially these are globals. # They probably want to be tidied up, made more localised or something. @@ -179,22 +182,22 @@ my ($type, $declaration_name, $return_type); my ($newsection, $newcontents, $prototype, $brcount, %source_map); if (defined($ENV{'KBUILD_VERBOSE'}) && $ENV{'KBUILD_VERBOSE'} =~ '1') { - $verbose = 1; + $verbose = 1; } if (defined($ENV{'KCFLAGS'})) { - my $kcflags = "$ENV{'KCFLAGS'}"; + my $kcflags = "$ENV{'KCFLAGS'}"; - if ($kcflags =~ /(\s|^)-Werror(\s|$)/) { - $Werror = 1; - } + if ($kcflags =~ /(\s|^)-Werror(\s|$)/) { + $Werror = 1; + } } # reading this variable is for backwards compat just in case # someone was calling it with the variable from outside the # kernel's build system if (defined($ENV{'KDOC_WERROR'})) { - $Werror = "$ENV{'KDOC_WERROR'}"; + $Werror = "$ENV{'KDOC_WERROR'}"; } # other environment variables are converted to command-line # arguments in cmd_checkdoc in the build system @@ -295,90 +298,90 @@ while ($ARGV[0] =~ m/^--?(.*)/) { my $cmd = $1; shift @ARGV; if ($cmd eq "man") { - $output_mode = "man"; - @highlights = @highlights_man; - $blankline = $blankline_man; + $output_mode = "man"; + @highlights = @highlights_man; + $blankline = $blankline_man; } elsif ($cmd eq "rst") { - $output_mode = "rst"; - @highlights = @highlights_rst; - $blankline = $blankline_rst; + $output_mode = "rst"; + @highlights = @highlights_rst; + $blankline = $blankline_rst; } elsif ($cmd eq "none") { - $output_mode = "none"; + $output_mode = "none"; } elsif ($cmd eq "module") { # not needed for XML, inherits from calling document - $modulename = shift @ARGV; + $modulename = shift @ARGV; } elsif ($cmd eq "function") { # to only output specific functions - $output_selection = OUTPUT_INCLUDE; - $function = shift @ARGV; - $function_table{$function} = 1; + $output_selection = OUTPUT_INCLUDE; + $function = shift @ARGV; + $function_table{$function} = 1; } elsif ($cmd eq "nosymbol") { # Exclude specific symbols - my $symbol = shift @ARGV; - $nosymbol_table{$symbol} = 1; + my $symbol = shift @ARGV; + $nosymbol_table{$symbol} = 1; } elsif ($cmd eq "export") { # only exported symbols - $output_selection = OUTPUT_EXPORTED; - %function_table = (); + $output_selection = OUTPUT_EXPORTED; + %function_table = (); } elsif ($cmd eq "internal") { # only non-exported symbols - $output_selection = OUTPUT_INTERNAL; - %function_table = (); + $output_selection = OUTPUT_INTERNAL; + %function_table = (); } elsif ($cmd eq "export-file") { - my $file = shift @ARGV; - push(@export_file_list, $file); + my $file = shift @ARGV; + push(@export_file_list, $file); } elsif ($cmd eq "v") { - $verbose = 1; + $verbose = 1; } elsif ($cmd eq "Werror") { - $Werror = 1; + $Werror = 1; } elsif ($cmd eq "Wreturn") { - $Wreturn = 1; - } elsif ($cmd eq "Wshort-desc") { - $Wshort_desc = 1; + $Wreturn = 1; + } elsif ($cmd eq "Wshort-desc" or $cmd eq "Wshort-description") { + $Wshort_desc = 1; } elsif ($cmd eq "Wcontents-before-sections") { - $Wcontents_before_sections = 1; + $Wcontents_before_sections = 1; } elsif ($cmd eq "Wall") { $Wreturn = 1; $Wshort_desc = 1; $Wcontents_before_sections = 1; } elsif (($cmd eq "h") || ($cmd eq "help")) { - pod2usage(-exitval => 0, -verbose => 2); + pod2usage(-exitval => 0, -verbose => 2); } elsif ($cmd eq 'no-doc-sections') { - $no_doc_sections = 1; + $no_doc_sections = 1; } elsif ($cmd eq 'enable-lineno') { - $enable_lineno = 1; + $enable_lineno = 1; } elsif ($cmd eq 'show-not-found') { - $show_not_found = 1; # A no-op but don't fail + $show_not_found = 1; # A no-op but don't fail } elsif ($cmd eq "sphinx-version") { - my $ver_string = shift @ARGV; - if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) { - $sphinx_major = $1; - if (defined($2)) { - $sphinx_minor = substr($2,1); - } else { - $sphinx_minor = 0; - } - if (defined($3)) { - $sphinx_patch = substr($3,1) - } else { - $sphinx_patch = 0; - } - } else { - die "Sphinx version should either major.minor or major.minor.patch format\n"; - } + my $ver_string = shift @ARGV; + if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) { + $sphinx_major = $1; + if (defined($2)) { + $sphinx_minor = substr($2,1); + } else { + $sphinx_minor = 0; + } + if (defined($3)) { + $sphinx_patch = substr($3,1) + } else { + $sphinx_patch = 0; + } + } else { + die "Sphinx version should either major.minor or major.minor.patch format\n"; + } } else { - # Unknown argument - pod2usage( - -message => "Argument unknown!\n", - -exitval => 1, - -verbose => 99, - -sections => 'SYNOPSIS', - -output => \*STDERR, - ); + # Unknown argument + 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, - ); + pod2usage( + -message => "FILE argument missing\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } } @@ -388,45 +391,45 @@ while ($ARGV[0] =~ m/^--?(.*)/) { # version in order to produce the right tags. sub findprog($) { - foreach(split(/:/, $ENV{PATH})) { - return "$_/$_[0]" if(-x "$_/$_[0]"); - } + foreach(split(/:/, $ENV{PATH})) { + return "$_/$_[0]" if(-x "$_/$_[0]"); + } } sub get_sphinx_version() { - my $ver; - - my $cmd = "sphinx-build"; - if (!findprog($cmd)) { - my $cmd = "sphinx-build3"; - if (!findprog($cmd)) { - $sphinx_major = 1; - $sphinx_minor = 2; - $sphinx_patch = 0; - printf STDERR "Warning: Sphinx version not found. Using default (Sphinx version %d.%d.%d)\n", - $sphinx_major, $sphinx_minor, $sphinx_patch; - return; - } - } - - open IN, "$cmd --version 2>&1 |"; - while (<IN>) { - if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) { - $sphinx_major = $1; - $sphinx_minor = $2; - $sphinx_patch = $3; - last; - } - # Sphinx 1.2.x uses a different format - if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) { - $sphinx_major = $1; - $sphinx_minor = $2; - $sphinx_patch = $3; - last; - } - } - close IN; + my $ver; + + my $cmd = "sphinx-build"; + if (!findprog($cmd)) { + my $cmd = "sphinx-build3"; + if (!findprog($cmd)) { + $sphinx_major = 1; + $sphinx_minor = 2; + $sphinx_patch = 0; + printf STDERR "Warning: Sphinx version not found. Using default (Sphinx version %d.%d.%d)\n", + $sphinx_major, $sphinx_minor, $sphinx_patch; + return; + } + } + + open IN, "$cmd --version 2>&1 |"; + while (<IN>) { + if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) { + $sphinx_major = $1; + $sphinx_minor = $2; + $sphinx_patch = $3; + last; + } + # Sphinx 1.2.x uses a different format + if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) { + $sphinx_major = $1; + $sphinx_minor = $2; + $sphinx_patch = $3; + last; + } + } + close IN; } # get kernel version from env @@ -434,7 +437,7 @@ sub get_kernel_version() { my $version = 'unknown kernel version'; if (defined($ENV{'KERNELVERSION'})) { - $version = $ENV{'KERNELVERSION'}; + $version = $ENV{'KERNELVERSION'}; } return $version; } @@ -462,30 +465,30 @@ sub dump_section { my $contents = join "\n", @_; if ($name =~ m/$type_param/) { - $name = $1; - $parameterdescs{$name} = $contents; - $sectcheck = $sectcheck . $name . " "; + $name = $1; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; $parameterdesc_start_lines{$name} = $new_start_line; $new_start_line = 0; } elsif ($name eq "@\.\.\.") { - $name = "..."; - $parameterdescs{$name} = $contents; - $sectcheck = $sectcheck . $name . " "; + $name = "..."; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; $parameterdesc_start_lines{$name} = $new_start_line; $new_start_line = 0; } else { - if (defined($sections{$name}) && ($sections{$name} ne "")) { - # Only warn on user specified duplicate section names. - if ($name ne $section_default) { - emit_warning("${file}:$.", "duplicate section name '$name'\n"); - } - $sections{$name} .= $contents; - } else { - $sections{$name} = $contents; - push @sectionlist, $name; + if (defined($sections{$name}) && ($sections{$name} ne "")) { + # Only warn on user specified duplicate section names. + if ($name ne $section_default) { + emit_warning("${file}:$.", "duplicate section name '$name'\n"); + } + $sections{$name} .= $contents; + } else { + $sections{$name} = $contents; + push @sectionlist, $name; $section_start_lines{$name} = $new_start_line; $new_start_line = 0; - } + } } } @@ -504,14 +507,14 @@ sub dump_doc_section { return if (defined($nosymbol_table{$name})); if (($output_selection == OUTPUT_ALL) || - (($output_selection == OUTPUT_INCLUDE) && - defined($function_table{$name}))) + (($output_selection == OUTPUT_INCLUDE) && + defined($function_table{$name}))) { - dump_section($file, $name, $contents); - output_blockhead({'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'module' => $modulename, - 'content-only' => ($output_selection != OUTPUT_ALL), }); + dump_section($file, $name, $contents); + output_blockhead({'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'module' => $modulename, + 'content-only' => ($output_selection != OUTPUT_ALL), }); } } @@ -542,21 +545,21 @@ sub output_highlight { # print STDERR "contents af:$contents\n"; foreach $line (split "\n", $contents) { - if (! $output_preformatted) { - $line =~ s/^\s*//; - } - if ($line eq ""){ - if (! $output_preformatted) { - print $lineprefix, $blankline; - } - } else { - if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { - print "\\&$line"; - } else { - print $lineprefix, $line; - } - } - print "\n"; + if (! $output_preformatted) { + $line =~ s/^\s*//; + } + if ($line eq ""){ + if (! $output_preformatted) { + print $lineprefix, $blankline; + } + } else { + if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { + print "\\&$line"; + } else { + print $lineprefix, $line; + } + } + print "\n"; } } @@ -574,40 +577,40 @@ sub output_function_man(%) { print ".SH SYNOPSIS\n"; if ($args{'functiontype'} ne "") { - print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; + print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; } else { - print ".B \"" . $args{'function'} . "\n"; + print ".B \"" . $args{'function'} . "\n"; } $count = 0; my $parenth = "("; my $post = ","; foreach my $parameter (@{$args{'parameterlist'}}) { - if ($count == $#{$args{'parameterlist'}}) { - $post = ");"; - } - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/$function_pointer/) { - # pointer-to-function - print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n"; - } else { - $type =~ s/([^\*])$/$1 /; - print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n"; - } - $count++; - $parenth = ""; + if ($count == $#{$args{'parameterlist'}}) { + $post = ");"; + } + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/$function_pointer/) { + # pointer-to-function + print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n"; + } else { + $type =~ s/([^\*])$/$1 /; + print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n"; + } + $count++; + $parenth = ""; } print ".SH ARGUMENTS\n"; foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - print ".IP \"" . $parameter . "\" 12\n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"", uc $section, "\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"", uc $section, "\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -627,28 +630,27 @@ sub output_enum_man(%) { print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { - print ".br\n.BI \" $parameter\"\n"; - if ($count == $#{$args{'parameterlist'}}) { - print "\n};\n"; - last; - } - else { - print ", \n.br\n"; - } - $count++; + print ".br\n.BI \" $parameter\"\n"; + if ($count == $#{$args{'parameterlist'}}) { + print "\n};\n"; + last; + } else { + print ", \n.br\n"; + } + $count++; } print ".SH Constants\n"; foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - print ".IP \"" . $parameter . "\" 12\n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -672,18 +674,18 @@ sub output_struct_man(%) { print ".SH Members\n"; foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; + ($parameter =~ /^#/) && next; - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print ".IP \"" . $parameter . "\" 12\n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -699,8 +701,8 @@ sub output_typedef_man(%) { print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -712,8 +714,8 @@ sub output_blockhead_man(%) { print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n"; foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -731,15 +733,15 @@ sub output_blockhead_rst(%) { my ($parameter, $section); foreach $section (@{$args{'sectionlist'}}) { - next if (defined($nosymbol_table{$section})); + next if (defined($nosymbol_table{$section})); - if ($output_selection != OUTPUT_INCLUDE) { - print ".. _$section:\n\n"; - print "**$section**\n\n"; - } + if ($output_selection != OUTPUT_INCLUDE) { + print ".. _$section:\n\n"; + print "**$section**\n\n"; + } print_lineno($section_start_lines{$section}); - output_highlight_rst($args{'sections'}{$section}); - print "\n"; + output_highlight_rst($args{'sections'}{$section}); + print "\n"; } } @@ -769,48 +771,48 @@ sub output_highlight_rst { my $block = ""; foreach $line (split "\n",$input) { - # - # If we're in a literal block, see if we should drop out - # of it. Otherwise pass the line straight through unmunged. - # - if ($in_literal) { - if (! ($line =~ /^\s*$/)) { - # - # If this is the first non-blank line in a literal - # block we need to figure out what the proper indent is. - # - if ($litprefix eq "") { - $line =~ /^(\s*)/; - $litprefix = '^' . $1; - $output .= $line . "\n"; - } elsif (! ($line =~ /$litprefix/)) { - $in_literal = 0; - } else { - $output .= $line . "\n"; - } - } else { - $output .= $line . "\n"; - } - } - # - # Not in a literal block (or just dropped out) - # - if (! $in_literal) { - $block .= $line . "\n"; - if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { - $in_literal = 1; - $litprefix = ""; - $output .= highlight_block($block); - $block = "" - } - } + # + # If we're in a literal block, see if we should drop out + # of it. Otherwise pass the line straight through unmunged. + # + if ($in_literal) { + if (! ($line =~ /^\s*$/)) { + # + # If this is the first non-blank line in a literal + # block we need to figure out what the proper indent is. + # + if ($litprefix eq "") { + $line =~ /^(\s*)/; + $litprefix = '^' . $1; + $output .= $line . "\n"; + } elsif (! ($line =~ /$litprefix/)) { + $in_literal = 0; + } else { + $output .= $line . "\n"; + } + } else { + $output .= $line . "\n"; + } + } + # + # Not in a literal block (or just dropped out) + # + if (! $in_literal) { + $block .= $line . "\n"; + if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { + $in_literal = 1; + $litprefix = ""; + $output .= highlight_block($block); + $block = "" + } + } } if ($block) { - $output .= highlight_block($block); + $output .= highlight_block($block); } foreach $line (split "\n", $output) { - print $lineprefix . $line . "\n"; + print $lineprefix . $line . "\n"; } } @@ -818,71 +820,68 @@ sub output_function_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); my $oldprefix = $lineprefix; - my $start = ""; - my $is_macro = 0; - if ($sphinx_major < 3) { - if ($args{'typedef'}) { - print ".. c:type:: ". $args{'function'} . "\n\n"; - print_lineno($declaration_start_line); - print " **Typedef**: "; - $lineprefix = ""; - output_highlight_rst($args{'purpose'}); - $start = "\n\n**Syntax**\n\n ``"; - $is_macro = 1; - } else { - print ".. c:function:: "; - } - } else { - if ($args{'typedef'} || $args{'functiontype'} eq "") { - $is_macro = 1; - print ".. c:macro:: ". $args{'function'} . "\n\n"; - } else { - print ".. c:function:: "; - } - - if ($args{'typedef'}) { - print_lineno($declaration_start_line); - print " **Typedef**: "; - $lineprefix = ""; - output_highlight_rst($args{'purpose'}); - $start = "\n\n**Syntax**\n\n ``"; - } else { - print "``" if ($is_macro); - } - } + my $signature = ""; if ($args{'functiontype'} ne "") { - $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; + $signature = $args{'functiontype'} . " " . $args{'function'} . " ("; } else { - $start .= $args{'function'} . " ("; + $signature = $args{'function'} . " ("; } - print $start; my $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { - if ($count ne 0) { - print ", "; - } - $count++; - $type = $args{'parametertypes'}{$parameter}; - - if ($type =~ m/$function_pointer/) { - # pointer-to-function - print $1 . $parameter . ") (" . $2 . ")"; - } else { - print $type; - } - } - if ($is_macro) { - print ")``\n\n"; + if ($count ne 0) { + $signature .= ", "; + } + $count++; + $type = $args{'parametertypes'}{$parameter}; + + if ($type =~ m/$function_pointer/) { + # pointer-to-function + $signature .= $1 . $parameter . ") (" . $2 . ")"; + } else { + $signature .= $type; + } + } + + $signature .= ")"; + + if ($sphinx_major < 3) { + if ($args{'typedef'}) { + print ".. c:type:: ". $args{'function'} . "\n\n"; + print_lineno($declaration_start_line); + print " **Typedef**: "; + $lineprefix = ""; + output_highlight_rst($args{'purpose'}); + print "\n\n**Syntax**\n\n"; + print " ``$signature``\n\n"; + } else { + print ".. c:function:: $signature\n\n"; + } } else { - print ")\n\n"; + if ($args{'typedef'} || $args{'functiontype'} eq "") { + print ".. c:macro:: ". $args{'function'} . "\n\n"; + + if ($args{'typedef'}) { + print_lineno($declaration_start_line); + print " **Typedef**: "; + $lineprefix = ""; + output_highlight_rst($args{'purpose'}); + print "\n\n**Syntax**\n\n"; + print " ``$signature``\n\n"; + } else { + print "``$signature``\n\n"; + } + } else { + print ".. c:function:: $signature\n\n"; + } } + if (!$args{'typedef'}) { - print_lineno($declaration_start_line); - $lineprefix = " "; - output_highlight_rst($args{'purpose'}); - print "\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; } # @@ -893,27 +892,27 @@ sub output_function_rst(%) { $lineprefix = " "; print $lineprefix . "**Parameters**\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - $type = $args{'parametertypes'}{$parameter}; - - if ($type ne "") { - print $lineprefix . "``$type``\n"; - } else { - print $lineprefix . "``$parameter``\n"; - } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + $type = $args{'parametertypes'}{$parameter}; + + if ($type ne "") { + print $lineprefix . "``$type``\n"; + } else { + print $lineprefix . "``$parameter``\n"; + } print_lineno($parameterdesc_start_lines{$parameter_name}); - $lineprefix = " "; - if (defined($args{'parameterdescs'}{$parameter_name}) && - $args{'parameterdescs'}{$parameter_name} ne $undescribed) { - output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - } else { - print $lineprefix . "*undescribed*\n"; - } - $lineprefix = " "; - print "\n"; + $lineprefix = " "; + if (defined($args{'parameterdescs'}{$parameter_name}) && + $args{'parameterdescs'}{$parameter_name} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + } else { + print $lineprefix . "*undescribed*\n"; + } + $lineprefix = " "; + print "\n"; } output_section_rst(@_); @@ -926,10 +925,10 @@ sub output_section_rst(%) { my $oldprefix = $lineprefix; foreach $section (@{$args{'sectionlist'}}) { - print $lineprefix . "**$section**\n\n"; + print $lineprefix . "**$section**\n\n"; print_lineno($section_start_lines{$section}); - output_highlight_rst($args{'sections'}{$section}); - print "\n"; + output_highlight_rst($args{'sections'}{$section}); + print "\n"; } print "\n"; } @@ -942,11 +941,11 @@ sub output_enum_rst(%) { my $outer; if ($sphinx_major < 3) { - my $name = "enum " . $args{'enum'}; - print "\n\n.. c:type:: " . $name . "\n\n"; + my $name = "enum " . $args{'enum'}; + print "\n\n.. c:type:: " . $name . "\n\n"; } else { - my $name = $args{'enum'}; - print "\n\n.. c:enum:: " . $name . "\n\n"; + my $name = $args{'enum'}; + print "\n\n.. c:enum:: " . $name . "\n\n"; } print_lineno($declaration_start_line); $lineprefix = " "; @@ -958,14 +957,14 @@ sub output_enum_rst(%) { $lineprefix = $outer . " "; print $outer . "**Constants**\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { - print $outer . "``$parameter``\n"; + print $outer . "``$parameter``\n"; - if ($args{'parameterdescs'}{$parameter} ne $undescribed) { - output_highlight_rst($args{'parameterdescs'}{$parameter}); - } else { - print $lineprefix . "*undescribed*\n"; - } - print "\n"; + if ($args{'parameterdescs'}{$parameter} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter}); + } else { + print $lineprefix . "*undescribed*\n"; + } + print "\n"; } print "\n"; $lineprefix = $oldprefix; @@ -979,9 +978,9 @@ sub output_typedef_rst(%) { my $name; if ($sphinx_major < 3) { - $name = "typedef " . $args{'typedef'}; + $name = "typedef " . $args{'typedef'}; } else { - $name = $args{'typedef'}; + $name = $args{'typedef'}; } print "\n\n.. c:type:: " . $name . "\n\n"; print_lineno($declaration_start_line); @@ -999,15 +998,15 @@ sub output_struct_rst(%) { my $oldprefix = $lineprefix; if ($sphinx_major < 3) { - my $name = $args{'type'} . " " . $args{'struct'}; - print "\n\n.. c:type:: " . $name . "\n\n"; + my $name = $args{'type'} . " " . $args{'struct'}; + print "\n\n.. c:type:: " . $name . "\n\n"; } else { - my $name = $args{'struct'}; - if ($args{'type'} eq 'union') { - print "\n\n.. c:union:: " . $name . "\n\n"; - } else { - print "\n\n.. c:struct:: " . $name . "\n\n"; - } + my $name = $args{'struct'}; + if ($args{'type'} eq 'union') { + print "\n\n.. c:union:: " . $name . "\n\n"; + } else { + print "\n\n.. c:struct:: " . $name . "\n\n"; + } } print_lineno($declaration_start_line); $lineprefix = " "; @@ -1024,19 +1023,19 @@ sub output_struct_rst(%) { $lineprefix = " "; print $lineprefix . "**Members**\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; + ($parameter =~ /^#/) && next; - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; print_lineno($parameterdesc_start_lines{$parameter_name}); - print $lineprefix . "``" . $parameter . "``\n"; - $lineprefix = " "; - output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - $lineprefix = " "; - print "\n"; + print $lineprefix . "``" . $parameter . "``\n"; + $lineprefix = " "; + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + $lineprefix = " "; + print "\n"; } print "\n"; @@ -1074,14 +1073,14 @@ sub output_declaration { return if (defined($nosymbol_table{$name})); if (($output_selection == OUTPUT_ALL) || - (($output_selection == OUTPUT_INCLUDE || - $output_selection == OUTPUT_EXPORTED) && - defined($function_table{$name})) || - ($output_selection == OUTPUT_INTERNAL && - !($functype eq "function" && defined($function_table{$name})))) + (($output_selection == OUTPUT_INCLUDE || + $output_selection == OUTPUT_EXPORTED) && + defined($function_table{$name})) || + ($output_selection == OUTPUT_INTERNAL && + !($functype eq "function" && defined($function_table{$name})))) { - &$func(@_); - $section_counter++; + &$func(@_); + $section_counter++; } } @@ -1120,202 +1119,202 @@ sub dump_struct($$) { my $struct_members = qr{($type)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;}; if ($x =~ /($type)\s+(\w+)\s*$definition_body/) { - $decl_type = $1; - $declaration_name = $2; - $members = $3; + $decl_type = $1; + $declaration_name = $2; + $members = $3; } elsif ($x =~ /typedef\s+($type)\s*$definition_body\s*(\w+)\s*;/) { - $decl_type = $1; - $declaration_name = $3; - $members = $2; + $decl_type = $1; + $declaration_name = $3; + $members = $2; } if ($members) { - if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"); - return; - } - - # ignore members marked private: - $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; - $members =~ s/\/\*\s*private:.*//gosi; - # strip comments: - $members =~ s/\/\*.*?\*\///gos; - # strip attributes - $members =~ s/\s*$attribute/ /gi; - $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; - $members =~ s/\s*__packed\s*/ /gos; - $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; - $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; - $members =~ s/\s*____cacheline_aligned/ /gos; - # unwrap struct_group(): - # - first eat non-declaration parameters and rewrite for final match - # - then remove macro, outer parens, and trailing semicolon - $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos; - $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos; - $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos; - $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos; - - my $args = qr{([^,)]+)}; - # replace DECLARE_BITMAP - $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; - $members =~ s/DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, PHY_INTERFACE_MODE_MAX)/gos; - $members =~ s/DECLARE_BITMAP\s*\($args,\s*$args\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; - # replace DECLARE_HASHTABLE - $members =~ s/DECLARE_HASHTABLE\s*\($args,\s*$args\)/unsigned long $1\[1 << (($2) - 1)\]/gos; - # replace DECLARE_KFIFO - $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos; - # replace DECLARE_KFIFO_PTR - $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos; - # replace DECLARE_FLEX_ARRAY - $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos; - #replace DEFINE_DMA_UNMAP_ADDR - $members =~ s/DEFINE_DMA_UNMAP_ADDR\s*\($args\)/dma_addr_t $1/gos; - #replace DEFINE_DMA_UNMAP_LEN - $members =~ s/DEFINE_DMA_UNMAP_LEN\s*\($args\)/__u32 $1/gos; - my $declaration = $members; - - # Split nested struct/union elements as newer ones - while ($members =~ m/$struct_members/) { - my $newmember; - my $maintype = $1; - my $ids = $4; - my $content = $3; - foreach my $id(split /,/, $ids) { - $newmember .= "$maintype $id; "; - - $id =~ s/[:\[].*//; - $id =~ s/^\s*\**(\S+)\s*/$1/; - foreach my $arg (split /;/, $content) { - next if ($arg =~ m/^\s*$/); - if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { - # pointer-to-function - my $type = $1; - my $name = $2; - my $extra = $3; - next if (!$name); - if ($id =~ m/^\s*$/) { - # anonymous struct/union - $newmember .= "$type$name$extra; "; - } else { - $newmember .= "$type$id.$name$extra; "; - } - } else { - my $type; - my $names; - $arg =~ s/^\s+//; - $arg =~ s/\s+$//; - # Handle bitmaps - $arg =~ s/:\s*\d+\s*//g; - # Handle arrays - $arg =~ s/\[.*\]//g; - # The type may have multiple words, - # and multiple IDs can be defined, like: - # const struct foo, *bar, foobar - # So, we remove spaces when parsing the - # names, in order to match just names - # and commas for the names - $arg =~ s/\s*,\s*/,/g; - if ($arg =~ m/(.*)\s+([\S+,]+)/) { - $type = $1; - $names = $2; - } else { - $newmember .= "$arg; "; - next; - } - foreach my $name (split /,/, $names) { - $name =~ s/^\s*\**(\S+)\s*/$1/; - next if (($name =~ m/^\s*$/)); - if ($id =~ m/^\s*$/) { - # anonymous struct/union - $newmember .= "$type $name; "; - } else { - $newmember .= "$type $id.$name; "; - } - } - } - } - } - $members =~ s/$struct_members/$newmember/; - } - - # Ignore other nested elements, like enums - $members =~ s/(\{[^\{\}]*\})//g; - - create_parameterlist($members, ';', $file, $declaration_name); - check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); - - # Adjust declaration for better display - $declaration =~ s/([\{;])/$1\n/g; - $declaration =~ s/\}\s+;/};/g; - # Better handle inlined enums - do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); - - my @def_args = split /\n/, $declaration; - my $level = 1; - $declaration = ""; - foreach my $clause (@def_args) { - $clause =~ s/^\s+//; - $clause =~ s/\s+$//; - $clause =~ s/\s+/ /; - next if (!$clause); - $level-- if ($clause =~ m/(\})/ && $level > 1); - if (!($clause =~ m/^\s*#/)) { - $declaration .= "\t" x $level; - } - $declaration .= "\t" . $clause . "\n"; - $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); - } - output_declaration($declaration_name, - 'struct', - {'struct' => $declaration_name, - 'module' => $modulename, - 'definition' => $declaration, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose, - 'type' => $decl_type - }); - } - else { - print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; - ++$errors; + if ($identifier ne $declaration_name) { + emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"); + return; + } + + # ignore members marked private: + $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; + $members =~ s/\/\*\s*private:.*//gosi; + # strip comments: + $members =~ s/\/\*.*?\*\///gos; + # strip attributes + $members =~ s/\s*$attribute/ /gi; + $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; + $members =~ s/\s*__counted_by\s*\([^;]*\)/ /gos; + $members =~ s/\s*__packed\s*/ /gos; + $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; + $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; + $members =~ s/\s*____cacheline_aligned/ /gos; + # unwrap struct_group(): + # - first eat non-declaration parameters and rewrite for final match + # - then remove macro, outer parens, and trailing semicolon + $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos; + $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos; + $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos; + $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos; + + my $args = qr{([^,)]+)}; + # replace DECLARE_BITMAP + $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; + $members =~ s/DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, PHY_INTERFACE_MODE_MAX)/gos; + $members =~ s/DECLARE_BITMAP\s*\($args,\s*$args\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; + # replace DECLARE_HASHTABLE + $members =~ s/DECLARE_HASHTABLE\s*\($args,\s*$args\)/unsigned long $1\[1 << (($2) - 1)\]/gos; + # replace DECLARE_KFIFO + $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos; + # replace DECLARE_KFIFO_PTR + $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos; + # replace DECLARE_FLEX_ARRAY + $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos; + #replace DEFINE_DMA_UNMAP_ADDR + $members =~ s/DEFINE_DMA_UNMAP_ADDR\s*\($args\)/dma_addr_t $1/gos; + #replace DEFINE_DMA_UNMAP_LEN + $members =~ s/DEFINE_DMA_UNMAP_LEN\s*\($args\)/__u32 $1/gos; + my $declaration = $members; + + # Split nested struct/union elements as newer ones + while ($members =~ m/$struct_members/) { + my $newmember; + my $maintype = $1; + my $ids = $4; + my $content = $3; + foreach my $id(split /,/, $ids) { + $newmember .= "$maintype $id; "; + + $id =~ s/[:\[].*//; + $id =~ s/^\s*\**(\S+)\s*/$1/; + foreach my $arg (split /;/, $content) { + next if ($arg =~ m/^\s*$/); + if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { + # pointer-to-function + my $type = $1; + my $name = $2; + my $extra = $3; + next if (!$name); + if ($id =~ m/^\s*$/) { + # anonymous struct/union + $newmember .= "$type$name$extra; "; + } else { + $newmember .= "$type$id.$name$extra; "; + } + } else { + my $type; + my $names; + $arg =~ s/^\s+//; + $arg =~ s/\s+$//; + # Handle bitmaps + $arg =~ s/:\s*\d+\s*//g; + # Handle arrays + $arg =~ s/\[.*\]//g; + # The type may have multiple words, + # and multiple IDs can be defined, like: + # const struct foo, *bar, foobar + # So, we remove spaces when parsing the + # names, in order to match just names + # and commas for the names + $arg =~ s/\s*,\s*/,/g; + if ($arg =~ m/(.*)\s+([\S+,]+)/) { + $type = $1; + $names = $2; + } else { + $newmember .= "$arg; "; + next; + } + foreach my $name (split /,/, $names) { + $name =~ s/^\s*\**(\S+)\s*/$1/; + next if (($name =~ m/^\s*$/)); + if ($id =~ m/^\s*$/) { + # anonymous struct/union + $newmember .= "$type $name; "; + } else { + $newmember .= "$type $id.$name; "; + } + } + } + } + } + $members =~ s/$struct_members/$newmember/; + } + + # Ignore other nested elements, like enums + $members =~ s/(\{[^\{\}]*\})//g; + + create_parameterlist($members, ';', $file, $declaration_name); + check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); + + # Adjust declaration for better display + $declaration =~ s/([\{;])/$1\n/g; + $declaration =~ s/\}\s+;/};/g; + # Better handle inlined enums + do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); + + my @def_args = split /\n/, $declaration; + my $level = 1; + $declaration = ""; + foreach my $clause (@def_args) { + $clause =~ s/^\s+//; + $clause =~ s/\s+$//; + $clause =~ s/\s+/ /; + next if (!$clause); + $level-- if ($clause =~ m/(\})/ && $level > 1); + if (!($clause =~ m/^\s*#/)) { + $declaration .= "\t" x $level; + } + $declaration .= "\t" . $clause . "\n"; + $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); + } + output_declaration($declaration_name, + 'struct', + {'struct' => $declaration_name, + 'module' => $modulename, + 'definition' => $declaration, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose, + 'type' => $decl_type + }); + } else { + print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; + ++$errors; } } sub show_warnings($$) { - my $functype = shift; - my $name = shift; - - return 0 if (defined($nosymbol_table{$name})); - - return 1 if ($output_selection == OUTPUT_ALL); - - if ($output_selection == OUTPUT_EXPORTED) { - if (defined($function_table{$name})) { - return 1; - } else { - return 0; - } - } - if ($output_selection == OUTPUT_INTERNAL) { - if (!($functype eq "function" && defined($function_table{$name}))) { - return 1; - } else { - return 0; - } - } - if ($output_selection == OUTPUT_INCLUDE) { - if (defined($function_table{$name})) { - return 1; - } else { - return 0; - } - } - die("Please add the new output type at show_warnings()"); + my $functype = shift; + my $name = shift; + + return 0 if (defined($nosymbol_table{$name})); + + return 1 if ($output_selection == OUTPUT_ALL); + + if ($output_selection == OUTPUT_EXPORTED) { + if (defined($function_table{$name})) { + return 1; + } else { + return 0; + } + } + if ($output_selection == OUTPUT_INTERNAL) { + if (!($functype eq "function" && defined($function_table{$name}))) { + return 1; + } else { + return 0; + } + } + if ($output_selection == OUTPUT_INCLUDE) { + if (defined($function_table{$name})) { + return 1; + } else { + return 0; + } + } + die("Please add the new output type at show_warnings()"); } sub dump_enum($$) { @@ -1329,65 +1328,65 @@ sub dump_enum($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. # strip #define macros inside enums - $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; + $x =~ s@#\s*((define|ifdef|if)\s+|endif)[^;]*;@@gos; if ($x =~ /typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;/) { - $declaration_name = $2; - $members = $1; + $declaration_name = $2; + $members = $1; } elsif ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) { - $declaration_name = $1; - $members = $2; + $declaration_name = $1; + $members = $2; } if ($members) { - if ($identifier ne $declaration_name) { - if ($identifier eq "") { - emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n"); - } else { - emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"); - } - return; - } - $declaration_name = "(anonymous)" if ($declaration_name eq ""); - - my %_members; - - $members =~ s/\s+$//; - $members =~ s/\([^;]*?[\)]//g; - - foreach my $arg (split ',', $members) { - $arg =~ s/^\s*(\w+).*/$1/; - push @parameterlist, $arg; - if (!$parameterdescs{$arg}) { - $parameterdescs{$arg} = $undescribed; - if (show_warnings("enum", $declaration_name)) { - emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n"); - } - } - $_members{$arg} = 1; - } - - while (my ($k, $v) = each %parameterdescs) { - if (!exists($_members{$k})) { - if (show_warnings("enum", $declaration_name)) { - emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n"); - } - } - } - - output_declaration($declaration_name, - 'enum', - {'enum' => $declaration_name, - 'module' => $modulename, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); + if ($identifier ne $declaration_name) { + if ($identifier eq "") { + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n"); + } else { + emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"); + } + return; + } + $declaration_name = "(anonymous)" if ($declaration_name eq ""); + + my %_members; + + $members =~ s/\s+$//; + $members =~ s/\([^;]*?[\)]//g; + + foreach my $arg (split ',', $members) { + $arg =~ s/^\s*(\w+).*/$1/; + push @parameterlist, $arg; + if (!$parameterdescs{$arg}) { + $parameterdescs{$arg} = $undescribed; + if (show_warnings("enum", $declaration_name)) { + emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n"); + } + } + $_members{$arg} = 1; + } + + while (my ($k, $v) = each %parameterdescs) { + if (!exists($_members{$k})) { + if (show_warnings("enum", $declaration_name)) { + emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n"); + } + } + } + + output_declaration($declaration_name, + 'enum', + {'enum' => $declaration_name, + 'module' => $modulename, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); } else { - print STDERR "${file}:$.: error: Cannot parse enum!\n"; - ++$errors; + print STDERR "${file}:$.: error: Cannot parse enum!\n"; + ++$errors; } } @@ -1406,59 +1405,58 @@ sub dump_typedef($$) { # Parse function typedef prototypes if ($x =~ $typedef1 || $x =~ $typedef2) { - $return_type = $1; - $declaration_name = $2; - my $args = $3; - $return_type =~ s/^\s+//; - - if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); - return; - } - - create_parameterlist($args, ',', $file, $declaration_name); - - output_declaration($declaration_name, - 'function', - {'function' => $declaration_name, - 'typedef' => 1, - 'module' => $modulename, - 'functiontype' => $return_type, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); - return; + $return_type = $1; + $declaration_name = $2; + my $args = $3; + $return_type =~ s/^\s+//; + + if ($identifier ne $declaration_name) { + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); + return; + } + + create_parameterlist($args, ',', $file, $declaration_name); + + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'typedef' => 1, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); + return; } while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { - $x =~ s/\(*.\)\s*;$/;/; - $x =~ s/\[*.\]\s*;$/;/; + $x =~ s/\(*.\)\s*;$/;/; + $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { - $declaration_name = $1; + $declaration_name = $1; - if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); - return; - } + if ($identifier ne $declaration_name) { + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); + return; + } - output_declaration($declaration_name, - 'typedef', - {'typedef' => $declaration_name, - 'module' => $modulename, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); - } - else { - print STDERR "${file}:$.: error: Cannot parse typedef!\n"; - ++$errors; + output_declaration($declaration_name, + 'typedef', + {'typedef' => $declaration_name, + 'module' => $modulename, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); + } else { + print STDERR "${file}:$.: error: Cannot parse typedef!\n"; + ++$errors; } } @@ -1481,202 +1479,220 @@ sub create_parameterlist($$$$) { # temporarily replace commas inside function pointer definition my $arg_expr = qr{\([^\),]+}; while ($args =~ /$arg_expr,/) { - $args =~ s/($arg_expr),/$1#/g; + $args =~ s/($arg_expr),/$1#/g; } foreach my $arg (split($splitter, $args)) { - # strip comments - $arg =~ s/\/\*.*\*\///; - # ignore argument attributes - $arg =~ s/\sPOS0?\s/ /; - # strip leading/trailing spaces - $arg =~ s/^\s*//; - $arg =~ s/\s*$//; - $arg =~ s/\s+/ /; - - if ($arg =~ /^#/) { - # Treat preprocessor directive as a typeless variable just to fill - # corresponding data structures "correctly". Catch it later in - # output_* subs. - push_parameter($arg, "", "", $file); - } elsif ($arg =~ m/\(.+\)\s*\(/) { - # pointer-to-function - $arg =~ tr/#/,/; - $arg =~ m/[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)/; - $param = $1; - $type = $arg; - $type =~ s/([^\(]+\(\*?)\s*$param/$1/; - save_struct_actual($param); - push_parameter($param, $type, $arg, $file, $declaration_name); - } elsif ($arg) { - $arg =~ s/\s*:\s*/:/g; - $arg =~ s/\s*\[/\[/g; - - my @args = split('\s*,\s*', $arg); - if ($args[0] =~ m/\*/) { - $args[0] =~ s/(\*+)\s*/ $1/; - } - - my @first_arg; - if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { - shift @args; - push(@first_arg, split('\s+', $1)); - push(@first_arg, $2); - } else { - @first_arg = split('\s+', shift @args); - } - - unshift(@args, pop @first_arg); - $type = join " ", @first_arg; - - foreach $param (@args) { - if ($param =~ m/^(\*+)\s*(.*)/) { - save_struct_actual($2); - - push_parameter($2, "$type $1", $arg, $file, $declaration_name); - } - elsif ($param =~ m/(.*?):(\d+)/) { - if ($type ne "") { # skip unnamed bit-fields - save_struct_actual($1); - push_parameter($1, "$type:$2", $arg, $file, $declaration_name) - } - } - else { - save_struct_actual($param); - push_parameter($param, $type, $arg, $file, $declaration_name); - } - } - } + # strip comments + $arg =~ s/\/\*.*\*\///; + # ignore argument attributes + $arg =~ s/\sPOS0?\s/ /; + # strip leading/trailing spaces + $arg =~ s/^\s*//; + $arg =~ s/\s*$//; + $arg =~ s/\s+/ /; + + if ($arg =~ /^#/) { + # Treat preprocessor directive as a typeless variable just to fill + # corresponding data structures "correctly". Catch it later in + # output_* subs. + push_parameter($arg, "", "", $file); + } elsif ($arg =~ m/\(.+\)\s*\(/) { + # pointer-to-function + $arg =~ tr/#/,/; + $arg =~ m/[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)/; + $param = $1; + $type = $arg; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); + } elsif ($arg =~ m/\(.+\)\s*\[/) { + # array-of-pointers + $arg =~ tr/#/,/; + $arg =~ m/[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)/; + $param = $1; + $type = $arg; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); + } elsif ($arg) { + $arg =~ s/\s*:\s*/:/g; + $arg =~ s/\s*\[/\[/g; + + my @args = split('\s*,\s*', $arg); + if ($args[0] =~ m/\*/) { + $args[0] =~ s/(\*+)\s*/ $1/; + } + + my @first_arg; + if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { + shift @args; + push(@first_arg, split('\s+', $1)); + push(@first_arg, $2); + } else { + @first_arg = split('\s+', shift @args); + } + + unshift(@args, pop @first_arg); + $type = join " ", @first_arg; + + foreach $param (@args) { + if ($param =~ m/^(\*+)\s*(.*)/) { + save_struct_actual($2); + + push_parameter($2, "$type $1", $arg, $file, $declaration_name); + } elsif ($param =~ m/(.*?):(\w+)/) { + if ($type ne "") { # skip unnamed bit-fields + save_struct_actual($1); + push_parameter($1, "$type:$2", $arg, $file, $declaration_name) + } + } else { + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); + } + } + } } } sub push_parameter($$$$$) { - my $param = shift; - my $type = shift; - my $org_arg = shift; - my $file = shift; - my $declaration_name = shift; - - if (($anon_struct_union == 1) && ($type eq "") && - ($param eq "}")) { - return; # ignore the ending }; from anon. struct/union - } - - $anon_struct_union = 0; - $param =~ s/[\[\)].*//; - - if ($type eq "" && $param =~ /\.\.\.$/) - { - if (!$param =~ /\w\.\.\.$/) { - # handles unnamed variable parameters - $param = "..."; - } - elsif ($param =~ /\w\.\.\.$/) { - # for named variable parameters of the form `x...`, remove the dots - $param =~ s/\.\.\.$//; - } - if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { - $parameterdescs{$param} = "variable arguments"; - } - } - elsif ($type eq "" && ($param eq "" or $param eq "void")) - { - $param="void"; - $parameterdescs{void} = "no arguments"; - } - elsif ($type eq "" && ($param eq "struct" or $param eq "union")) - # handle unnamed (anonymous) union or struct: - { - $type = $param; - $param = "{unnamed_" . $param . "}"; - $parameterdescs{$param} = "anonymous\n"; - $anon_struct_union = 1; - } - - # warn if parameter has no description - # (but ignore ones starting with # as these are not parameters - # but inline preprocessor statements); - # Note: It will also ignore void params and unnamed structs/unions - if (!defined $parameterdescs{$param} && $param !~ /^#/) { - $parameterdescs{$param} = $undescribed; - - if (show_warnings($type, $declaration_name) && $param !~ /\./) { - emit_warning("${file}:$.", "Function parameter or member '$param' not described in '$declaration_name'\n"); - } - } - - # strip spaces from $param so that it is one continuous string - # on @parameterlist; - # this fixes a problem where check_sections() cannot find - # a parameter like "addr[6 + 2]" because it actually appears - # as "addr[6", "+", "2]" on the parameter list; - # but it's better to maintain the param string unchanged for output, - # so just weaken the string compare in check_sections() to ignore - # "[blah" in a parameter string; - ###$param =~ s/\s*//g; - push @parameterlist, $param; - $org_arg =~ s/\s\s+/ /g; - $parametertypes{$param} = $org_arg; + my $param = shift; + my $type = shift; + my $org_arg = shift; + my $file = shift; + my $declaration_name = shift; + + if (($anon_struct_union == 1) && ($type eq "") && + ($param eq "}")) { + return; # ignore the ending }; from anon. struct/union + } + + $anon_struct_union = 0; + $param =~ s/[\[\)].*//; + + if ($type eq "" && $param =~ /\.\.\.$/) + { + if (!$param =~ /\w\.\.\.$/) { + # handles unnamed variable parameters + $param = "..."; + } elsif ($param =~ /\w\.\.\.$/) { + # for named variable parameters of the form `x...`, remove the dots + $param =~ s/\.\.\.$//; + } + if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { + $parameterdescs{$param} = "variable arguments"; + } + } + elsif ($type eq "" && ($param eq "" or $param eq "void")) + { + $param="void"; + $parameterdescs{void} = "no arguments"; + } + elsif ($type eq "" && ($param eq "struct" or $param eq "union")) + # handle unnamed (anonymous) union or struct: + { + $type = $param; + $param = "{unnamed_" . $param . "}"; + $parameterdescs{$param} = "anonymous\n"; + $anon_struct_union = 1; + } + elsif ($param =~ "__cacheline_group" ) + # handle cache group enforcing variables: they do not need be described in header files + { + return; # ignore __cacheline_group_begin and __cacheline_group_end + } + + # warn if parameter has no description + # (but ignore ones starting with # as these are not parameters + # but inline preprocessor statements); + # Note: It will also ignore void params and unnamed structs/unions + if (!defined $parameterdescs{$param} && $param !~ /^#/) { + $parameterdescs{$param} = $undescribed; + + if (show_warnings($type, $declaration_name) && $param !~ /\./) { + emit_warning("${file}:$.", "Function parameter or struct member '$param' not described in '$declaration_name'\n"); + } + } + + # strip spaces from $param so that it is one continuous string + # on @parameterlist; + # this fixes a problem where check_sections() cannot find + # a parameter like "addr[6 + 2]" because it actually appears + # as "addr[6", "+", "2]" on the parameter list; + # but it's better to maintain the param string unchanged for output, + # so just weaken the string compare in check_sections() to ignore + # "[blah" in a parameter string; + ###$param =~ s/\s*//g; + push @parameterlist, $param; + $org_arg =~ s/\s\s+/ /g; + $parametertypes{$param} = $org_arg; } sub check_sections($$$$$) { - my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_; - my @sects = split ' ', $sectcheck; - my @prms = split ' ', $prmscheck; - my $err; - my ($px, $sx); - my $prm_clean; # strip trailing "[array size]" and/or beginning "*" - - foreach $sx (0 .. $#sects) { - $err = 1; - foreach $px (0 .. $#prms) { - $prm_clean = $prms[$px]; - $prm_clean =~ s/\[.*\]//; - $prm_clean =~ s/$attribute//i; - # ignore array size in a parameter string; - # however, the original param string may contain - # spaces, e.g.: addr[6 + 2] - # and this appears in @prms as "addr[6" since the - # parameter list is split at spaces; - # hence just ignore "[..." for the sections check; - $prm_clean =~ s/\[.*//; - - ##$prm_clean =~ s/^\**//; - if ($prm_clean eq $sects[$sx]) { - $err = 0; - last; - } - } - if ($err) { - if ($decl_type eq "function") { - emit_warning("${file}:$.", - "Excess function parameter " . - "'$sects[$sx]' " . - "description in '$decl_name'\n"); - } - } - } + my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_; + my @sects = split ' ', $sectcheck; + my @prms = split ' ', $prmscheck; + my $err; + my ($px, $sx); + my $prm_clean; # strip trailing "[array size]" and/or beginning "*" + + foreach $sx (0 .. $#sects) { + $err = 1; + foreach $px (0 .. $#prms) { + $prm_clean = $prms[$px]; + $prm_clean =~ s/\[.*\]//; + $prm_clean =~ s/$attribute//i; + # ignore array size in a parameter string; + # however, the original param string may contain + # spaces, e.g.: addr[6 + 2] + # and this appears in @prms as "addr[6" since the + # parameter list is split at spaces; + # hence just ignore "[..." for the sections check; + $prm_clean =~ s/\[.*//; + + ##$prm_clean =~ s/^\**//; + if ($prm_clean eq $sects[$sx]) { + $err = 0; + last; + } + } + if ($err) { + if ($decl_type eq "function") { + emit_warning("${file}:$.", + "Excess function parameter " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"); + } elsif (($decl_type eq "struct") or + ($decl_type eq "union")) { + emit_warning("${file}:$.", + "Excess $decl_type member " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"); + } + } + } } ## # Checks the section describing the return value of a function. sub check_return_section { - my $file = shift; - my $declaration_name = shift; - my $return_type = shift; + my $file = shift; + my $declaration_name = shift; + my $return_type = shift; - # Ignore an empty return type (It's a macro) - # Ignore functions with a "void" return type. (But don't ignore "void *") - if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { - return; - } + # Ignore an empty return type (It's a macro) + # Ignore functions with a "void" return type. (But don't ignore "void *") + if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { + return; + } - if (!defined($sections{$section_return}) || - $sections{$section_return} eq "") { - emit_warning("${file}:$.", - "No description found for return value of " . - "'$declaration_name'\n"); - } + if (!defined($sections{$section_return}) || + $sections{$section_return} eq "") + { + emit_warning("${file}:$.", + "No description found for return value of " . + "'$declaration_name'\n"); + } } ## @@ -1751,21 +1767,21 @@ sub dump_function($$) { $declaration_name = $2; $noret = 1; } elsif ($prototype =~ m/^()($name)\s*$prototype_end/ || - $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ || - $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/) { - $return_type = $1; - $declaration_name = $2; - my $args = $3; + $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ || + $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/) { + $return_type = $1; + $declaration_name = $2; + my $args = $3; - create_parameterlist($args, ',', $file, $declaration_name); + create_parameterlist($args, ',', $file, $declaration_name); } else { - emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n"); - return; + emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n"); + return; } if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"); - return; + emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"); + return; } my $prms = join " ", @parameterlist; @@ -1777,38 +1793,38 @@ sub dump_function($$) { # -Wreturn mode. # TODO: always perform the check. if ($Wreturn && !$noret) { - check_return_section($file, $declaration_name, $return_type); + check_return_section($file, $declaration_name, $return_type); } # The function parser can be called with a typedef parameter. # Handle it. if ($return_type =~ /typedef/) { - output_declaration($declaration_name, - 'function', - {'function' => $declaration_name, - 'typedef' => 1, - 'module' => $modulename, - 'functiontype' => $return_type, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'typedef' => 1, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); } else { - output_declaration($declaration_name, - 'function', - {'function' => $declaration_name, - 'module' => $modulename, - 'functiontype' => $return_type, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); } } @@ -1828,64 +1844,64 @@ sub reset_state { } sub tracepoint_munge($) { - my $file = shift; - my $tracepointname = 0; - my $tracepointargs = 0; - - if ($prototype =~ m/TRACE_EVENT\((.*?),/) { - $tracepointname = $1; - } - if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { - $tracepointname = $1; - } - if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { - $tracepointname = $2; - } - $tracepointname =~ s/^\s+//; #strip leading whitespace - if ($prototype =~ m/TP_PROTO\((.*?)\)/) { - $tracepointargs = $1; - } - if (($tracepointname eq 0) || ($tracepointargs eq 0)) { - emit_warning("${file}:$.", "Unrecognized tracepoint format: \n". - "$prototype\n"); - } else { - $prototype = "static inline void trace_$tracepointname($tracepointargs)"; - $identifier = "trace_$identifier"; - } + my $file = shift; + my $tracepointname = 0; + my $tracepointargs = 0; + + if ($prototype =~ m/TRACE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { + $tracepointname = $2; + } + $tracepointname =~ s/^\s+//; #strip leading whitespace + if ($prototype =~ m/TP_PROTO\((.*?)\)/) { + $tracepointargs = $1; + } + if (($tracepointname eq 0) || ($tracepointargs eq 0)) { + emit_warning("${file}:$.", "Unrecognized tracepoint format: \n". + "$prototype\n"); + } else { + $prototype = "static inline void trace_$tracepointname($tracepointargs)"; + $identifier = "trace_$identifier"; + } } sub syscall_munge() { - my $void = 0; - - $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's -## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { - if ($prototype =~ m/SYSCALL_DEFINE0/) { - $void = 1; -## $prototype = "long sys_$1(void)"; - } - - $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name - if ($prototype =~ m/long (sys_.*?),/) { - $prototype =~ s/,/\(/; - } elsif ($void) { - $prototype =~ s/\)/\(void\)/; - } - - # now delete all of the odd-number commas in $prototype - # so that arg types & arg names don't have a comma between them - my $count = 0; - my $len = length($prototype); - if ($void) { - $len = 0; # skip the for-loop - } - for (my $ix = 0; $ix < $len; $ix++) { - if (substr($prototype, $ix, 1) eq ',') { - $count++; - if ($count % 2 == 1) { - substr($prototype, $ix, 1) = ' '; - } - } - } + my $void = 0; + + $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's +## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { + if ($prototype =~ m/SYSCALL_DEFINE0/) { + $void = 1; +## $prototype = "long sys_$1(void)"; + } + + $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name + if ($prototype =~ m/long (sys_.*?),/) { + $prototype =~ s/,/\(/; + } elsif ($void) { + $prototype =~ s/\)/\(void\)/; + } + + # now delete all of the odd-number commas in $prototype + # so that arg types & arg names don't have a comma between them + my $count = 0; + my $len = length($prototype); + if ($void) { + $len = 0; # skip the for-loop + } + for (my $ix = 0; $ix < $len; $ix++) { + if (substr($prototype, $ix, 1) eq ',') { + $count++; + if ($count % 2 == 1) { + substr($prototype, $ix, 1) = ' '; + } + } + } } sub process_proto_function($$) { @@ -1894,32 +1910,31 @@ sub process_proto_function($$) { $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line - if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) { - # do nothing - } - elsif ($x =~ /([^\{]*)/) { - $prototype .= $1; + if ($x =~ /^#/ && $x !~ /^#\s*define/) { + # do nothing + } elsif ($x =~ /([^\{]*)/) { + $prototype .= $1; } if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { - $prototype =~ s@/\*.*?\*/@@gos; # strip comments. - $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. - $prototype =~ s@^\s+@@gos; # strip leading spaces + $prototype =~ s@/\*.*?\*/@@gos; # strip comments. + $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. + $prototype =~ s@^\s+@@gos; # strip leading spaces - # Handle prototypes for function pointers like: - # int (*pcs_config)(struct foo) - $prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos; + # Handle prototypes for function pointers like: + # int (*pcs_config)(struct foo) + $prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos; - if ($prototype =~ /SYSCALL_DEFINE/) { - syscall_munge(); - } - if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || - $prototype =~ /DEFINE_SINGLE_EVENT/) - { - tracepoint_munge($file); - } - dump_function($prototype, $file); - reset_state(); + if ($prototype =~ /SYSCALL_DEFINE/) { + syscall_munge(); + } + if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || + $prototype =~ /DEFINE_SINGLE_EVENT/) + { + tracepoint_munge($file); + } + dump_function($prototype, $file); + reset_state(); } } @@ -1933,28 +1948,28 @@ sub process_proto_type($$) { $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line if ($x =~ /^#/) { - # To distinguish preprocessor directive from regular declaration later. - $x .= ";"; + # To distinguish preprocessor directive from regular declaration later. + $x .= ";"; } while (1) { - if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { + if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { if( length $prototype ) { $prototype .= " " } - $prototype .= $1 . $2; - ($2 eq '{') && $brcount++; - ($2 eq '}') && $brcount--; - if (($2 eq ';') && ($brcount == 0)) { - dump_declaration($prototype, $file); - reset_state(); - last; - } - $x = $3; - } else { - $prototype .= $x; - last; - } + $prototype .= $1 . $2; + ($2 eq '{') && $brcount++; + ($2 eq '}') && $brcount--; + if (($2 eq ';') && ($brcount == 0)) { + dump_declaration($prototype, $file); + reset_state(); + last; + } + $x = $3; + } else { + $prototype .= $x; + last; + } } } @@ -1964,13 +1979,13 @@ sub map_filename($) { my ($orig_file) = @_; if (defined($ENV{'SRCTREE'})) { - $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; + $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; } else { - $file = $orig_file; + $file = $orig_file; } if (defined($source_map{$file})) { - $file = $source_map{$file}; + $file = $source_map{$file}; } return $file; @@ -1981,20 +1996,20 @@ sub process_export_file($) { my $file = map_filename($orig_file); if (!open(IN,"<$file")) { - print STDERR "Error: Cannot open file $file\n"; - ++$errors; - return; + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; } while (<IN>) { - if (/$export_symbol/) { - next if (defined($nosymbol_table{$2})); - $function_table{$2} = 1; - } - if (/$export_symbol_ns/) { - next if (defined($nosymbol_table{$2})); - $function_table{$2} = 1; - } + if (/$export_symbol/) { + next if (defined($nosymbol_table{$2})); + $function_table{$2} = 1; + } + if (/$export_symbol_ns/) { + next if (defined($nosymbol_table{$2})); + $function_table{$2} = 1; + } } close(IN); @@ -2007,9 +2022,9 @@ sub process_export_file($) { # sub process_normal() { if (/$doc_start/o) { - $state = STATE_NAME; # next line is always the function name - $in_doc_sect = 0; - $declaration_start_line = $. + 1; + $state = STATE_NAME; # next line is always the function name + $in_doc_sect = 0; + $declaration_start_line = $. + 1; } } @@ -2021,80 +2036,80 @@ sub process_name($$) { my $descr; if (/$doc_block/o) { - $state = STATE_DOCBLOCK; - $contents = ""; - $new_start_line = $.; - - if ( $1 eq "" ) { - $section = $section_intro; - } else { - $section = $1; - } + $state = STATE_DOCBLOCK; + $contents = ""; + $new_start_line = $.; + + if ( $1 eq "" ) { + $section = $section_intro; + } else { + $section = $1; + } } elsif (/$doc_decl/o) { - $identifier = $1; - my $is_kernel_comment = 0; - my $decl_start = qr{$doc_com}; - # test for pointer declaration type, foo * bar() - desc - my $fn_type = qr{\w+\s*\*\s*}; - my $parenthesis = qr{\(\w*\)}; - my $decl_end = qr{[-:].*}; - if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) { - $identifier = $1; - } - if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) { - $decl_type = $1; - $identifier = $2; - $is_kernel_comment = 1; - } - # Look for foo() or static void foo() - description; or misspelt - # identifier - elsif (/^$decl_start$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ || - /^$decl_start$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) { - $identifier = $1; - $decl_type = 'function'; - $identifier =~ s/^define\s+//; - $is_kernel_comment = 1; - } - $identifier =~ s/\s+$//; - - $state = STATE_BODY; - # if there's no @param blocks need to set up default section - # here - $contents = ""; - $section = $section_default; - $new_start_line = $. + 1; - if (/[-:](.*)/) { - # strip leading/trailing/multiple spaces - $descr= $1; - $descr =~ s/^\s*//; - $descr =~ s/\s*$//; - $descr =~ s/\s+/ /g; - $declaration_purpose = $descr; - $state = STATE_BODY_MAYBE; - } else { - $declaration_purpose = ""; - } - - if (!$is_kernel_comment) { - 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 "") && $Wshort_desc) { - emit_warning("${file}:$.", "missing initial short description on line:\n$_"); - } - - if ($identifier eq "" && $decl_type ne "enum") { - emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_"); - $state = STATE_NORMAL; - } - - if ($verbose) { - print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n"; - } + $identifier = $1; + my $is_kernel_comment = 0; + my $decl_start = qr{$doc_com}; + # test for pointer declaration type, foo * bar() - desc + my $fn_type = qr{\w+\s*\*\s*}; + my $parenthesis = qr{\(\w*\)}; + my $decl_end = qr{[-:].*}; + if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) { + $identifier = $1; + } + if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) { + $decl_type = $1; + $identifier = $2; + $is_kernel_comment = 1; + } + # Look for foo() or static void foo() - description; or misspelt + # identifier + elsif (/^$decl_start$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ || + /^$decl_start$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) { + $identifier = $1; + $decl_type = 'function'; + $identifier =~ s/^define\s+//; + $is_kernel_comment = 1; + } + $identifier =~ s/\s+$//; + + $state = STATE_BODY; + # if there's no @param blocks need to set up default section + # here + $contents = ""; + $section = $section_default; + $new_start_line = $. + 1; + if (/[-:](.*)/) { + # strip leading/trailing/multiple spaces + $descr= $1; + $descr =~ s/^\s*//; + $descr =~ s/\s*$//; + $descr =~ s/\s+/ /g; + $declaration_purpose = $descr; + $state = STATE_BODY_MAYBE; + } else { + $declaration_purpose = ""; + } + + if (!$is_kernel_comment) { + 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 "") && $Wshort_desc) { + emit_warning("${file}:$.", "missing initial short description on line:\n$_"); + } + + if ($identifier eq "" && $decl_type ne "enum") { + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_"); + $state = STATE_NORMAL; + } + + if ($verbose) { + print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n"; + } } else { - emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n"); - $state = STATE_NORMAL; + emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n"); + $state = STATE_NORMAL; } } @@ -2106,101 +2121,102 @@ sub process_body($$) { my $file = shift; if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) { - dump_section($file, $section, $contents); - $section = $section_default; - $new_start_line = $.; - $contents = ""; + dump_section($file, $section, $contents); + $section = $section_default; + $new_start_line = $.; + $contents = ""; } if (/$doc_sect/i) { # case insensitive for supported section names - $newsection = $1; - $newcontents = $2; - - # map the supported section names to the canonical names - if ($newsection =~ m/^description$/i) { - $newsection = $section_default; - } elsif ($newsection =~ m/^context$/i) { - $newsection = $section_context; - } elsif ($newsection =~ m/^returns?$/i) { - $newsection = $section_return; - } elsif ($newsection =~ m/^\@return$/) { - # special: @return is a section, not a param description - $newsection = $section_return; - } - - if (($contents ne "") && ($contents ne "\n")) { - if (!$in_doc_sect && $Wcontents_before_sections) { - emit_warning("${file}:$.", "contents before sections\n"); - } - dump_section($file, $section, $contents); - $section = $section_default; - } - - $in_doc_sect = 1; - $state = STATE_BODY; - $contents = $newcontents; - $new_start_line = $.; - while (substr($contents, 0, 1) eq " ") { - $contents = substr($contents, 1); - } - if ($contents ne "") { - $contents .= "\n"; - } - $section = $newsection; - $leading_space = undef; + $in_doc_sect = 1; + $newsection = $1; + $newcontents = $2; + + # map the supported section names to the canonical names + if ($newsection =~ m/^description$/i) { + $newsection = $section_default; + } elsif ($newsection =~ m/^context$/i) { + $newsection = $section_context; + } elsif ($newsection =~ m/^returns?$/i) { + $newsection = $section_return; + } elsif ($newsection =~ m/^\@return$/) { + # special: @return is a section, not a param description + $newsection = $section_return; + } + + if (($contents ne "") && ($contents ne "\n")) { + if (!$in_doc_sect && $Wcontents_before_sections) { + emit_warning("${file}:$.", "contents before sections\n"); + } + dump_section($file, $section, $contents); + $section = $section_default; + } + + $in_doc_sect = 1; + $state = STATE_BODY; + $contents = $newcontents; + $new_start_line = $.; + while (substr($contents, 0, 1) eq " ") { + $contents = substr($contents, 1); + } + if ($contents ne "") { + $contents .= "\n"; + } + $section = $newsection; + $leading_space = undef; } elsif (/$doc_end/) { - if (($contents ne "") && ($contents ne "\n")) { - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - } - # look for doc_com + <text> + doc_end: - if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { - emit_warning("${file}:$.", "suspicious ending line: $_"); - } - - $prototype = ""; - $state = STATE_PROTO; - $brcount = 0; + if (($contents ne "") && ($contents ne "\n")) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + # look for doc_com + <text> + doc_end: + if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { + emit_warning("${file}:$.", "suspicious ending line: $_"); + } + + $prototype = ""; + $state = STATE_PROTO; + $brcount = 0; $new_start_line = $. + 1; } elsif (/$doc_content/) { - if ($1 eq "") { - if ($section eq $section_context) { - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - $new_start_line = $.; - $state = STATE_BODY; - } else { - if ($section ne $section_default) { - $state = STATE_BODY_WITH_BLANK_LINE; - } else { - $state = STATE_BODY; - } - $contents .= "\n"; - } - } elsif ($state == STATE_BODY_MAYBE) { - # Continued declaration purpose - chomp($declaration_purpose); - $declaration_purpose .= " " . $1; - $declaration_purpose =~ s/\s+/ /g; - } else { - my $cont = $1; - if ($section =~ m/^@/ || $section eq $section_context) { - if (!defined $leading_space) { - if ($cont =~ m/^(\s+)/) { - $leading_space = $1; - } else { - $leading_space = ""; - } - } - $cont =~ s/^$leading_space//; - } - $contents .= $cont . "\n"; - } + if ($1 eq "") { + if ($section eq $section_context) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + $new_start_line = $.; + $state = STATE_BODY; + } else { + if ($section ne $section_default) { + $state = STATE_BODY_WITH_BLANK_LINE; + } else { + $state = STATE_BODY; + } + $contents .= "\n"; + } + } elsif ($state == STATE_BODY_MAYBE) { + # Continued declaration purpose + chomp($declaration_purpose); + $declaration_purpose .= " " . $1; + $declaration_purpose =~ s/\s+/ /g; + } else { + my $cont = $1; + if ($section =~ m/^@/ || $section eq $section_context) { + if (!defined $leading_space) { + if ($cont =~ m/^(\s+)/) { + $leading_space = $1; + } else { + $leading_space = ""; + } + } + $cont =~ s/^$leading_space//; + } + $contents .= $cont . "\n"; + } } else { - # i dont know - bad line? ignore. - emit_warning("${file}:$.", "bad line: $_"); + # i dont know - bad line? ignore. + emit_warning("${file}:$.", "bad line: $_"); } } @@ -2212,21 +2228,21 @@ sub process_proto($$) { my $file = shift; if (/$doc_inline_oneline/) { - $section = $1; - $contents = $2; - if ($contents ne "") { - $contents .= "\n"; - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - } + $section = $1; + $contents = $2; + if ($contents ne "") { + $contents .= "\n"; + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } } elsif (/$doc_inline_start/) { - $state = STATE_INLINE; - $inline_doc_state = STATE_INLINE_NAME; + $state = STATE_INLINE; + $inline_doc_state = STATE_INLINE_NAME; } elsif ($decl_type eq 'function') { - process_proto_function($_, $file); + process_proto_function($_, $file); } else { - process_proto_type($_, $file); + process_proto_type($_, $file); } } @@ -2237,23 +2253,23 @@ sub process_docblock($$) { my $file = shift; if (/$doc_end/) { - dump_doc_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - $function = ""; - %parameterdescs = (); - %parametertypes = (); - @parameterlist = (); - %sections = (); - @sectionlist = (); - $prototype = ""; - $state = STATE_NORMAL; + dump_doc_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + $function = ""; + %parameterdescs = (); + %parametertypes = (); + @parameterlist = (); + %sections = (); + @sectionlist = (); + $prototype = ""; + $state = STATE_NORMAL; } elsif (/$doc_content/) { - if ( $1 eq "" ) { - $contents .= $blankline; - } else { - $contents .= $1 . "\n"; - } + if ( $1 eq "" ) { + $contents .= $blankline; + } else { + $contents .= $1 . "\n"; + } } } @@ -2265,37 +2281,37 @@ sub process_inline($$) { # First line (state 1) needs to be a @parameter if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { - $section = $1; - $contents = $2; - $new_start_line = $.; - if ($contents ne "") { - while (substr($contents, 0, 1) eq " ") { - $contents = substr($contents, 1); - } - $contents .= "\n"; - } - $inline_doc_state = STATE_INLINE_TEXT; - # Documentation block end */ + $section = $1; + $contents = $2; + $new_start_line = $.; + if ($contents ne "") { + while (substr($contents, 0, 1) eq " ") { + $contents = substr($contents, 1); + } + $contents .= "\n"; + } + $inline_doc_state = STATE_INLINE_TEXT; + # Documentation block end */ } elsif (/$doc_inline_end/) { - if (($contents ne "") && ($contents ne "\n")) { - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - } - $state = STATE_PROTO; - $inline_doc_state = STATE_INLINE_NA; - # Regular text + if (($contents ne "") && ($contents ne "\n")) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + $state = STATE_PROTO; + $inline_doc_state = STATE_INLINE_NA; + # Regular text } elsif (/$doc_content/) { - if ($inline_doc_state == STATE_INLINE_TEXT) { - $contents .= $1 . "\n"; - # nuke leading blank lines - if ($contents =~ /^\s*$/) { - $contents = ""; - } - } elsif ($inline_doc_state == STATE_INLINE_NAME) { - $inline_doc_state = STATE_INLINE_ERROR; - emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_"); - } + if ($inline_doc_state == STATE_INLINE_TEXT) { + $contents .= $1 . "\n"; + # nuke leading blank lines + if ($contents =~ /^\s*$/) { + $contents = ""; + } + } elsif ($inline_doc_state == STATE_INLINE_NAME) { + $inline_doc_state = STATE_INLINE_ERROR; + emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_"); + } } } @@ -2308,54 +2324,53 @@ sub process_file($) { $file = map_filename($orig_file); if (!open(IN_FILE,"<$file")) { - print STDERR "Error: Cannot open file $file\n"; - ++$errors; - return; + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; } $. = 1; $section_counter = 0; while (<IN_FILE>) { - while (s/\\\s*$//) { - $_ .= <IN_FILE>; - } - # Replace tabs by spaces + while (!/^ \*/ && s/\\\s*$//) { + $_ .= <IN_FILE>; + } + # Replace tabs by spaces while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}; - # Hand this line to the appropriate state handler - if ($state == STATE_NORMAL) { - process_normal(); - } elsif ($state == STATE_NAME) { - process_name($file, $_); - } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE || - $state == STATE_BODY_WITH_BLANK_LINE) { - process_body($file, $_); - } elsif ($state == STATE_INLINE) { # scanning for inline parameters - process_inline($file, $_); - } elsif ($state == STATE_PROTO) { - process_proto($file, $_); - } elsif ($state == STATE_DOCBLOCK) { - process_docblock($file, $_); - } + # Hand this line to the appropriate state handler + if ($state == STATE_NORMAL) { + process_normal(); + } elsif ($state == STATE_NAME) { + process_name($file, $_); + } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE || + $state == STATE_BODY_WITH_BLANK_LINE) { + process_body($file, $_); + } elsif ($state == STATE_INLINE) { # scanning for inline parameters + process_inline($file, $_); + } elsif ($state == STATE_PROTO) { + process_proto($file, $_); + } elsif ($state == STATE_DOCBLOCK) { + process_docblock($file, $_); + } } # Make sure we got something interesting. if ($initial_section_counter == $section_counter && $ - output_mode ne "none") { - if ($output_selection == OUTPUT_INCLUDE) { - emit_warning("${file}:1", "'$_' not found\n") - for keys %function_table; - } - else { - emit_warning("${file}:1", "no structured comments found\n"); - } + output_mode ne "none") { + if ($output_selection == OUTPUT_INCLUDE) { + emit_warning("${file}:1", "'$_' not found\n") + for keys %function_table; + } else { + emit_warning("${file}:1", "no structured comments found\n"); + } } close IN_FILE; } if ($output_mode eq "rst") { - get_sphinx_version() if (!$sphinx_major); + get_sphinx_version() if (!$sphinx_major); } $kernelversion = get_kernel_version(); @@ -2372,14 +2387,14 @@ for (my $k = 0; $k < @highlights; $k++) { # Read the file that maps relative names to absolute names for # separate source and object directories and for shadow trees. if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { - my ($relname, $absname); - while(<SOURCE_MAP>) { - chop(); - ($relname, $absname) = (split())[0..1]; - $relname =~ s:^/+::; - $source_map{$relname} = $absname; - } - close(SOURCE_MAP); + my ($relname, $absname); + while(<SOURCE_MAP>) { + chop(); + ($relname, $absname) = (split())[0..1]; + $relname =~ s:^/+::; + $source_map{$relname} = $absname; + } + close(SOURCE_MAP); } if ($output_selection == OUTPUT_EXPORTED || @@ -2388,8 +2403,8 @@ if ($output_selection == OUTPUT_EXPORTED || push(@export_file_list, @ARGV); foreach (@export_file_list) { - chomp; - process_export_file($_); + chomp; + process_export_file($_); } } @@ -2398,10 +2413,10 @@ foreach (@ARGV) { process_file($_); } if ($verbose && $errors) { - print STDERR "$errors errors\n"; + print STDERR "$errors errors\n"; } if ($verbose && $warnings) { - print STDERR "$warnings warnings\n"; + print STDERR "$warnings warnings\n"; } if ($Werror && $warnings) { diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl index e695634d153d..8e992b18bcd9 100755 --- a/scripts/leaking_addresses.pl +++ b/scripts/leaking_addresses.pl @@ -23,6 +23,7 @@ use strict; use POSIX; use File::Basename; use File::Spec; +use File::Temp qw/tempfile/; use Cwd 'abs_path'; use Term::ANSIColor qw(:constants); use Getopt::Long qw(:config no_auto_abbrev); @@ -51,10 +52,13 @@ my $input_raw = ""; # Read raw results from file instead of scanning. my $suppress_dmesg = 0; # Don't show dmesg in output. my $squash_by_path = 0; # Summary report grouped by absolute path. my $squash_by_filename = 0; # Summary report grouped by filename. +my $kallsyms_file = ""; # Kernel symbols file. my $kernel_config_file = ""; # Kernel configuration file. my $opt_32bit = 0; # Scan 32-bit kernel. my $page_offset_32bit = 0; # Page offset for 32-bit kernel. +my @kallsyms = (); + # Skip these absolute paths. my @skip_abs = ( '/proc/kmsg', @@ -95,6 +99,8 @@ Options: --squash-by-path Show one result per unique path. --squash-by-filename Show one result per unique filename. --kernel-config-file=<file> Kernel configuration file (e.g /boot/config) + --kallsyms=<file> Read kernel symbol addresses from file (for + scanning binary files). --32-bit Scan 32-bit kernel. --page-offset-32-bit=o Page offset (for 32-bit kernel 0xABCD1234). -d, --debug Display debugging output. @@ -115,6 +121,7 @@ GetOptions( 'squash-by-path' => \$squash_by_path, 'squash-by-filename' => \$squash_by_filename, 'raw' => \$raw, + 'kallsyms=s' => \$kallsyms_file, 'kernel-config-file=s' => \$kernel_config_file, '32-bit' => \$opt_32bit, 'page-offset-32-bit=o' => \$page_offset_32bit, @@ -155,6 +162,25 @@ if ($output_raw) { select $fh; } +if ($kallsyms_file) { + open my $fh, '<', $kallsyms_file or die "$0: $kallsyms_file: $!\n"; + while (<$fh>) { + chomp; + my @entry = split / /, $_; + my $addr_text = $entry[0]; + if ($addr_text !~ /^0/) { + # TODO: Why is hex() so impossibly slow? + my $addr = hex($addr_text); + my $symbol = $entry[2]; + # Only keep kernel text addresses. + my $long = pack("J", $addr); + my $entry = [$long, $symbol]; + push @kallsyms, $entry; + } + } + close $fh; +} + parse_dmesg(); walk(@DIRS); @@ -221,6 +247,7 @@ sub get_kernel_config_option { my ($option) = @_; my $value = ""; + my $tmp_fh; my $tmp_file = ""; my @config_files; @@ -228,7 +255,8 @@ sub get_kernel_config_option if ($kernel_config_file ne "") { @config_files = ($kernel_config_file); } elsif (-R "/proc/config.gz") { - my $tmp_file = "/tmp/tmpkconf"; + ($tmp_fh, $tmp_file) = tempfile("config.gz-XXXXXX", + UNLINK => 1); if (system("gunzip < /proc/config.gz > $tmp_file")) { dprint("system(gunzip < /proc/config.gz) failed\n"); @@ -250,10 +278,6 @@ sub get_kernel_config_option } } - if ($tmp_file ne "") { - system("rm -f $tmp_file"); - } - return $value; } @@ -285,9 +309,10 @@ sub is_false_positive return is_false_positive_32bit($match); } - # 64 bit false positives. - - if ($match =~ '\b(0x)?(f|F){16}\b' or + # Ignore 64 bit false positives: + # 0xfffffffffffffff[0-f] + # 0x0000000000000000 + if ($match =~ '\b(0x)?(f|F){15}[0-9a-f]\b' or $match =~ '\b(0x)?0{16}\b') { return 1; } @@ -304,7 +329,7 @@ sub is_false_positive_32bit my ($match) = @_; state $page_offset = get_page_offset(); - if ($match =~ '\b(0x)?(f|F){8}\b') { + if ($match =~ '\b(0x)?(f|F){7}[0-9a-f]\b') { return 1; } @@ -347,18 +372,23 @@ sub is_in_vsyscall_memory_region # True if argument potentially contains a kernel address. sub may_leak_address { - my ($line) = @_; + my ($path, $line) = @_; my $address_re; - # Signal masks. + # Ignore Signal masks. if ($line =~ '^SigBlk:' or $line =~ '^SigIgn:' or $line =~ '^SigCgt:') { return 0; } - if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or - $line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') { + # Ignore input device reporting. + # /proc/bus/input/devices: B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe + # /sys/devices/platform/i8042/serio0/input/input1/uevent: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe + # /sys/devices/platform/i8042/serio0/input/input1/capabilities/key: 402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe + if ($line =~ '\bKEY=[[:xdigit:]]{9,14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or + ($path =~ '\bkey$' and + $line =~ '\b[[:xdigit:]]{9,14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b')) { return 0; } @@ -401,7 +431,7 @@ sub parse_dmesg { open my $cmd, '-|', 'dmesg'; while (<$cmd>) { - if (may_leak_address($_)) { + if (may_leak_address("dmesg", $_)) { print 'dmesg: ' . $_; } } @@ -442,6 +472,25 @@ sub timed_parse_file } } +sub parse_binary +{ + my ($file) = @_; + + open my $fh, "<:raw", $file or return; + local $/ = undef; + my $bytes = <$fh>; + close $fh; + + foreach my $entry (@kallsyms) { + my $addr = $entry->[0]; + my $symbol = $entry->[1]; + my $offset = index($bytes, $addr); + if ($offset != -1) { + printf("$file: $symbol @ $offset\n"); + } + } +} + sub parse_file { my ($file) = @_; @@ -451,13 +500,22 @@ sub parse_file } if (! -T $file) { + if ($file =~ m|^/sys/kernel/btf/| or + $file =~ m|^/sys/devices/pci| or + $file =~ m|^/sys/firmware/efi/efivars/| or + $file =~ m|^/proc/bus/pci/|) { + return; + } + if (scalar @kallsyms > 0) { + parse_binary($file); + } return; } open my $fh, "<", $file or return; while ( <$fh> ) { chomp; - if (may_leak_address($_)) { + if (may_leak_address($file, $_)) { printf("$file: $_\n"); } } @@ -469,7 +527,7 @@ sub check_path_for_leaks { my ($path) = @_; - if (may_leak_address($path)) { + if (may_leak_address($path, $path)) { printf("Path name may contain address: $path\n"); } } diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a432b171be82..7862a8101747 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -135,8 +135,13 @@ gen_btf() ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \ --strip-all ${1} ${2} 2>/dev/null # Change e_type to ET_REL so that it can be used to link final vmlinux. - # Unlike GNU ld, lld does not allow an ET_EXEC input. - printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none + # GNU ld 2.35+ and lld do not allow an ET_EXEC input. + if is_enabled CONFIG_CPU_BIG_ENDIAN; then + et_rel='\0\1' + else + et_rel='\1\0' + fi + printf "${et_rel}" | dd of=${2} conv=notrunc bs=1 seek=16 status=none } # Create ${2} .S file with all symbols from the ${1} object file diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index fd5ffdb81bab..5927cc6b7de3 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -26,12 +26,14 @@ gcc) llvm) if [ "$SRCARCH" = s390 ]; then echo 15.0.0 + elif [ "$SRCARCH" = loongarch ]; then + echo 18.0.0 else - echo 11.0.0 + echo 13.0.1 fi ;; rustc) - echo 1.73.0 + echo 1.76.0 ;; bindgen) echo 0.65.1 diff --git a/scripts/mksysmap b/scripts/mksysmap index 9ba1c9da0a40..57ff5656d566 100755 --- a/scripts/mksysmap +++ b/scripts/mksysmap @@ -48,17 +48,8 @@ ${NM} -n ${1} | sed >${2} -e " / __kvm_nvhe_\\$/d / __kvm_nvhe_\.L/d -# arm64 lld -/ __AArch64ADRPThunk_/d - -# arm lld -/ __ARMV5PILongThunk_/d -/ __ARMV7PILongThunk_/d -/ __ThumbV7PILongThunk_/d - -# mips lld -/ __LA25Thunk_/d -/ __microLA25Thunk_/d +# lld arm/aarch64/mips thunks +/ __[[:alnum:]]*Thunk_/d # CFI type identifiers / __kcfi_typeid_/d diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index e91a3c38143b..518200813d4e 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -274,5 +274,8 @@ int main(void) DEVID(vchiq_device_id); DEVID_FIELD(vchiq_device_id, name); + DEVID(coreboot_device_id); + DEVID_FIELD(coreboot_device_id, tag); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 4829680a0a6d..5d1c61fa5a55 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1494,6 +1494,15 @@ static int do_vchiq_entry(const char *filename, void *symval, char *alias) return 1; } +/* Looks like: coreboot:tN */ +static int do_coreboot_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, coreboot_device_id, tag); + sprintf(alias, "coreboot:t%08X", tag); + + return 1; +} + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1575,6 +1584,7 @@ static const struct devtable devtable[] = { {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry}, {"cdx", SIZE_cdx_device_id, do_cdx_entry}, {"vchiq", SIZE_vchiq_device_id, do_vchiq_entry}, + {"coreboot", SIZE_coreboot_device_id, do_coreboot_entry}, }; /* Create MODULE_ALIAS() statements. diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cb6406f485a9..2f5b91da5afa 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -60,8 +60,7 @@ static unsigned int nr_unresolved; #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) -void __attribute__((format(printf, 2, 3))) -modpost_log(enum loglevel loglevel, const char *fmt, ...) +void modpost_log(enum loglevel loglevel, const char *fmt, ...) { va_list arglist; @@ -71,9 +70,7 @@ modpost_log(enum loglevel loglevel, const char *fmt, ...) break; case LOG_ERROR: fprintf(stderr, "ERROR: "); - break; - case LOG_FATAL: - fprintf(stderr, "FATAL: "); + error_occurred = true; break; default: /* invalid loglevel, ignore */ break; @@ -84,11 +81,6 @@ modpost_log(enum loglevel loglevel, const char *fmt, ...) va_start(arglist, fmt); vfprintf(stderr, fmt, arglist); va_end(arglist); - - if (loglevel == LOG_FATAL) - exit(1); - if (loglevel == LOG_ERROR) - error_occurred = true; } static inline bool strends(const char *str, const char *postfix) @@ -474,11 +466,9 @@ static int parse_elf(struct elf_info *info, const char *filename) fatal("%s: not relocatable object.", filename); /* Check if file offset is correct */ - if (hdr->e_shoff > info->size) { + if (hdr->e_shoff > info->size) fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n", (unsigned long)hdr->e_shoff, filename, info->size); - return 0; - } if (hdr->e_shnum == SHN_UNDEF) { /* @@ -516,12 +506,11 @@ static int parse_elf(struct elf_info *info, const char *filename) const char *secname; int nobits = sechdrs[i].sh_type == SHT_NOBITS; - if (!nobits && sechdrs[i].sh_offset > info->size) { + if (!nobits && sechdrs[i].sh_offset > info->size) fatal("%s is truncated. sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n", filename, (unsigned long)sechdrs[i].sh_offset, sizeof(*hdr)); - return 0; - } + secname = secstrings + sechdrs[i].sh_name; if (strcmp(secname, ".modinfo") == 0) { if (nobits) @@ -807,7 +796,8 @@ static void check_section(const char *modname, struct elf_info *elf, #define DATA_SECTIONS ".data", ".data.rel" #define TEXT_SECTIONS ".text", ".text.*", ".sched.text", \ - ".kprobes.text", ".cpuidle.text", ".noinstr.text" + ".kprobes.text", ".cpuidle.text", ".noinstr.text", \ + ".ltext", ".ltext.*" #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ ".fixup", ".entry.text", ".exception.text", \ ".coldtext", ".softirqentry.text" @@ -1017,6 +1007,8 @@ static Elf_Sym *find_fromsym(struct elf_info *elf, Elf_Addr addr, static Elf_Sym *find_tosym(struct elf_info *elf, Elf_Addr addr, Elf_Sym *sym) { + Elf_Sym *new_sym; + /* If the supplied symbol has a valid name, return it */ if (is_valid_name(elf, sym)) return sym; @@ -1025,8 +1017,9 @@ static Elf_Sym *find_tosym(struct elf_info *elf, Elf_Addr addr, Elf_Sym *sym) * Strive to find a better symbol name, but the resulting name may not * match the symbol referenced in the original code. */ - return symsearch_find_nearest(elf, addr, get_secindex(elf, sym), - true, 20); + new_sym = symsearch_find_nearest(elf, addr, get_secindex(elf, sym), + true, 20); + return new_sym ? new_sym : sym; } static bool is_executable_section(struct elf_info *elf, unsigned int secndx) @@ -1060,7 +1053,9 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, sec_mismatch_count++; warn("%s: section mismatch in reference: %s+0x%x (section: %s) -> %s (section: %s)\n", - modname, fromsym, (unsigned int)(faddr - from->st_value), fromsec, tosym, tosec); + modname, fromsym, + (unsigned int)(faddr - (from ? from->st_value : 0)), + fromsec, tosym, tosec); if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) { if (match(tosec, mismatch->bad_tosec)) @@ -1346,6 +1341,14 @@ static Elf_Addr addend_mips_rel(uint32_t *location, unsigned int r_type) #define R_LARCH_SUB32 55 #endif +#ifndef R_LARCH_RELAX +#define R_LARCH_RELAX 100 +#endif + +#ifndef R_LARCH_ALIGN +#define R_LARCH_ALIGN 102 +#endif + static void get_rel_type_and_sym(struct elf_info *elf, uint64_t r_info, unsigned int *r_type, unsigned int *r_sym) { @@ -1400,9 +1403,16 @@ static void section_rela(struct module *mod, struct elf_info *elf, continue; break; case EM_LOONGARCH: - if (!strcmp("__ex_table", fromsec) && - r_type == R_LARCH_SUB32) + switch (r_type) { + case R_LARCH_SUB32: + if (!strcmp("__ex_table", fromsec)) + continue; + break; + case R_LARCH_RELAX: + case R_LARCH_ALIGN: + /* These relocs do not refer to symbols */ continue; + } break; } @@ -1419,7 +1429,7 @@ static void section_rel(struct module *mod, struct elf_info *elf, for (rel = start; rel < stop; rel++) { Elf_Sym *tsym; - Elf_Addr taddr = 0, r_offset; + Elf_Addr taddr, r_offset; unsigned int r_type, r_sym; void *loc; @@ -1843,7 +1853,7 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "\n" - "#ifdef CONFIG_RETPOLINE\n" + "#ifdef CONFIG_MITIGATION_RETPOLINE\n" "MODULE_INFO(retpoline, \"Y\");\n" "#endif\n"); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 69baf014da4f..ee43c7950636 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -194,10 +194,10 @@ void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); enum loglevel { LOG_WARN, LOG_ERROR, - LOG_FATAL }; -void modpost_log(enum loglevel loglevel, const char *fmt, ...); +void __attribute__((format(printf, 2, 3))) +modpost_log(enum loglevel loglevel, const char *fmt, ...); /* * warn - show the given message, then let modpost continue running, still @@ -214,4 +214,4 @@ void modpost_log(enum loglevel loglevel, const char *fmt, ...); */ #define warn(fmt, args...) modpost_log(LOG_WARN, fmt, ##args) #define error(fmt, args...) modpost_log(LOG_ERROR, fmt, ##args) -#define fatal(fmt, args...) modpost_log(LOG_FATAL, fmt, ##args) +#define fatal(fmt, args...) do { error(fmt, ##args); exit(1); } while (1) diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 31066bfdba04..dc4878502276 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -326,7 +326,12 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) /* Sum all files in the same dir or subdirs. */ while ((line = get_line(&pos))) { - char* p = line; + char* p; + + /* trim the leading spaces away */ + while (isspace(*line)) + line++; + p = line; if (strncmp(line, "source_", sizeof("source_")-1) == 0) { p = strrchr(line, ' '); diff --git a/scripts/package/builddeb b/scripts/package/builddeb index d7dd0d04c70c..e797ad360f7a 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -24,45 +24,16 @@ if_enabled_echo() { fi } -create_package() { - local pname="$1" pdir="$2" - local dpkg_deb_opts - - mkdir -m 755 -p "$pdir/DEBIAN" - mkdir -p "$pdir/usr/share/doc/$pname" - cp debian/copyright "$pdir/usr/share/doc/$pname/" - cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian" - gzip -n -9 "$pdir/usr/share/doc/$pname/changelog.Debian" - sh -c "cd '$pdir'; find . -type f ! -path './DEBIAN/*' -printf '%P\0' \ - | xargs -r0 md5sum > DEBIAN/md5sums" - - # Fix ownership and permissions - if [ "$DEB_RULES_REQUIRES_ROOT" = "no" ]; then - dpkg_deb_opts="--root-owner-group" - else - chown -R root:root "$pdir" - fi - # a+rX in case we are in a restrictive umask environment like 0077 - # ug-s in case we build in a setuid/setgid directory - chmod -R go-w,a+rX,ug-s "$pdir" - - # Create the package - dpkg-gencontrol -p$pname -P"$pdir" - dpkg-deb $dpkg_deb_opts ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS} --build "$pdir" .. -} - install_linux_image () { - pdir=$1 - pname=$2 - - rm -rf ${pdir} + pname=$1 + pdir=debian/$1 # Only some architectures with OF support have this target if is_enabled CONFIG_OF_EARLY_FLATTREE && [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then ${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/usr/lib/linux-image-${KERNELRELEASE}" dtbs_install fi - ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${pdir}" modules_install + ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${pdir}" INSTALL_MOD_STRIP=1 modules_install rm -f "${pdir}/lib/modules/${KERNELRELEASE}/build" # Install the kernel @@ -122,26 +93,20 @@ install_linux_image () { } install_linux_image_dbg () { - pdir=$1 - image_pdir=$2 - - rm -rf ${pdir} - - for module in $(find ${image_pdir}/lib/modules/ -name *.ko -printf '%P\n'); do - module=lib/modules/${module} - mkdir -p $(dirname ${pdir}/usr/lib/debug/${module}) - # only keep debug symbols in the debug file - ${OBJCOPY} --only-keep-debug ${image_pdir}/${module} ${pdir}/usr/lib/debug/${module} - # strip original module from debug symbols - ${OBJCOPY} --strip-debug ${image_pdir}/${module} - # then add a link to those - ${OBJCOPY} --add-gnu-debuglink=${pdir}/usr/lib/debug/${module} ${image_pdir}/${module} - done + pdir=debian/$1 - # re-sign stripped modules - if is_enabled CONFIG_MODULE_SIG_ALL; then - ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${image_pdir}" modules_sign - fi + # Parse modules.order directly because 'make modules_install' may sign, + # compress modules, and then run unneeded depmod. + while read -r mod; do + mod="${mod%.o}.ko" + dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}" + buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p') + link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug" + + mkdir -p "${dbg%/*}" "${link%/*}" + "${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}" + ln -sf --relative "${dbg}" "${link}" + done < modules.order # Build debug package # Different tools want the image in different locations @@ -156,10 +121,8 @@ install_linux_image_dbg () { } install_kernel_headers () { - pdir=$1 - version=$2 - - rm -rf $pdir + pdir=debian/$1 + version=${1#linux-headers-} "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" @@ -168,52 +131,25 @@ install_kernel_headers () { } install_libc_headers () { - pdir=$1 - - rm -rf $pdir + pdir=debian/$1 - $MAKE -f $srctree/Makefile headers $MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH=$pdir/usr # move asm headers to /usr/include/<libc-machine>/asm to match the structure # used by Debian-based distros (to support multi-arch) - host_arch=$(dpkg-architecture -a$DEB_HOST_ARCH -qDEB_HOST_MULTIARCH) - mkdir $pdir/usr/include/$host_arch - mv $pdir/usr/include/asm $pdir/usr/include/$host_arch/ + mkdir "$pdir/usr/include/${DEB_HOST_MULTIARCH}" + mv "$pdir/usr/include/asm" "$pdir/usr/include/${DEB_HOST_MULTIARCH}" } -rm -f debian/files - -packages_enabled=$(dh_listpackages) - -for package in ${packages_enabled} -do - case ${package} in - *-dbg) - # This must be done after linux-image, that is, we expect the - # debug package appears after linux-image in debian/control. - install_linux_image_dbg debian/linux-image-dbg debian/linux-image;; - linux-image-*|user-mode-linux-*) - install_linux_image debian/linux-image ${package};; - linux-libc-dev) - install_libc_headers debian/linux-libc-dev;; - linux-headers-*) - install_kernel_headers debian/linux-headers ${package#linux-headers-};; - esac -done - -for package in ${packages_enabled} -do - case ${package} in - *-dbg) - create_package ${package} debian/linux-image-dbg;; - linux-image-*|user-mode-linux-*) - create_package ${package} debian/linux-image;; - linux-libc-dev) - create_package ${package} debian/linux-libc-dev;; - linux-headers-*) - create_package ${package} debian/linux-headers;; - esac -done - -exit 0 +package=$1 + +case "${package}" in +*-dbg) + install_linux_image_dbg "${package}";; +linux-image-*|user-mode-linux-*) + install_linux_image "${package}";; +linux-libc-dev) + install_libc_headers "${package}";; +linux-headers-*) + install_kernel_headers "${package}";; +esac diff --git a/scripts/package/buildtar b/scripts/package/buildtar index 65b4ea502962..72c91a1b832f 100755 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -23,7 +23,6 @@ tmpdir=$1 # rm -rf -- "${tmpdir}" mkdir -p -- "${tmpdir}/boot" -dirs=boot # @@ -38,12 +37,9 @@ fi # -# Try to install modules +# Install modules # -if grep -q '^CONFIG_MODULES=y' include/config/auto.conf; then - make ARCH="${ARCH}" -f ${srctree}/Makefile INSTALL_MOD_PATH="${tmpdir}" modules_install - dirs="$dirs lib" -fi +make ARCH="${ARCH}" -f ${srctree}/Makefile INSTALL_MOD_PATH="${tmpdir}" modules_install # diff --git a/scripts/package/deb-build-option b/scripts/package/deb-build-option deleted file mode 100755 index 7950eff01781..000000000000 --- a/scripts/package/deb-build-option +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-only - -# Set up CROSS_COMPILE if not defined yet -if [ "${CROSS_COMPILE+set}" != "set" -a "${DEB_HOST_ARCH}" != "${DEB_BUILD_ARCH}" ]; then - echo CROSS_COMPILE=${DEB_HOST_GNU_TYPE}- -fi - -version=$(dpkg-parsechangelog -S Version) -debian_revision="${version##*-}" - -if [ "${version}" != "${debian_revision}" ]; then - echo KBUILD_BUILD_VERSION=${debian_revision} -fi diff --git a/scripts/package/debian/copyright b/scripts/package/debian/copyright new file mode 100644 index 000000000000..4f1f06221f09 --- /dev/null +++ b/scripts/package/debian/copyright @@ -0,0 +1,16 @@ +This is a packaged upstream version of the Linux kernel. + +The sources may be found at most Linux archive sites, including: +https://www.kernel.org/pub/linux/kernel + +Copyright: 1991 - 2023 Linus Torvalds and others. + +The git repository for mainline kernel development is at: +git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 dated June, 1991. + +On Debian GNU/Linux systems, the complete text of the GNU General Public +License version 2 can be found in `/usr/share/common-licenses/GPL-2'. diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules index 3dafa9496c63..ca07243bd5cd 100755 --- a/scripts/package/debian/rules +++ b/scripts/package/debian/rules @@ -1,33 +1,91 @@ #!/usr/bin/make -f # SPDX-License-Identifier: GPL-2.0-only -include debian/rules.vars +# in case debian/rules is executed directly +export DEB_RULES_REQUIRES_ROOT := no -srctree ?= . +include debian/rules.vars ifneq (,$(filter-out parallel=1,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))) NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) MAKEFLAGS += -j$(NUMJOBS) endif +# When KBUILD_VERBOSE is undefined (presumably you are directly working with +# the debianized tree), show verbose logs unless DEB_BUILD_OPTION=terse is set. +ifeq ($(origin KBUILD_VERBOSE),undefined) + ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS))) + export KBUILD_VERBOSE := 1 + else + Q := @ + endif +endif + +revision = $(lastword $(subst -, ,$(shell dpkg-parsechangelog -S Version))) +CROSS_COMPILE ?= $(filter-out $(DEB_BUILD_GNU_TYPE)-, $(DEB_HOST_GNU_TYPE)-) +make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(revision) $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE)) + +binary-targets := $(addprefix binary-, image image-dbg headers libc-dev) + +all-packages = $(shell dh_listpackages) +image-package = $(filter linux-image-% user-%, $(filter-out %-dbg, $(all-packages))) +image-dbg-package = $(filter %-dbg, $(all-packages)) +libc-dev-package = $(filter linux-libc-dev, $(all-packages)) +headers-package = $(filter linux-headers-%, $(all-packages)) + +mk-files = $(patsubst binary-%,debian/%.files,$1) +package = $($(@:binary-%=%-package)) + +# DH_OPTION is an environment variable common for all debhelper commands. +# We could 'export' it, but here it is passed from the command line to clarify +# which package is being processed in the build log. +DH_OPTIONS = -p$(package) + +define binary + $(Q)dh_testdir $(DH_OPTIONS) + $(Q)dh_testroot $(DH_OPTIONS) + $(Q)dh_prep $(DH_OPTIONS) + $(Q)+$(MAKE) $(make-opts) run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb $(package)' + $(Q)dh_installdocs $(DH_OPTIONS) + $(Q)dh_installchangelogs $(DH_OPTIONS) + $(Q)dh_compress $(DH_OPTIONS) + $(Q)dh_fixperms $(DH_OPTIONS) + $(Q)dh_gencontrol $(DH_OPTIONS) -- -f$(call mk-files,$@) + $(Q)dh_md5sums $(DH_OPTIONS) + $(Q)dh_builddeb $(DH_OPTIONS) -- $(addprefix -Z,$(KDEB_COMPRESS)) +endef + +.PHONY: $(binary-targets) +$(binary-targets): build-arch + $(Q)truncate -s0 $(call mk-files,$@) + $(if $(package),$(binary)) + .PHONY: binary binary-indep binary-arch binary: binary-arch binary-indep binary-indep: build-indep -binary-arch: build-arch - $(MAKE) -f $(srctree)/Makefile ARCH=$(ARCH) \ - KERNELRELEASE=$(KERNELRELEASE) \ - run-command KBUILD_RUN_COMMAND=+$(srctree)/scripts/package/builddeb +binary-arch: $(binary-targets) + $(Q)cat $(call mk-files,$^) > debian/files .PHONY: build build-indep build-arch build: build-arch build-indep build-indep: build-arch: - $(MAKE) -f $(srctree)/Makefile ARCH=$(ARCH) \ - KERNELRELEASE=$(KERNELRELEASE) \ - $(shell $(srctree)/scripts/package/deb-build-option) \ - olddefconfig all + $(Q)$(MAKE) $(make-opts) olddefconfig + $(Q)$(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all .PHONY: clean clean: - rm -rf debian/files debian/linux-* - $(MAKE) -f $(srctree)/Makefile ARCH=$(ARCH) clean + $(Q)dh_clean + $(Q)rm -rf debian/deb-env.vars* debian/*.files + $(Q)$(MAKE) ARCH=$(ARCH) clean + +# If DEB_HOST_ARCH is empty, it is likely that debian/rules was executed +# directly. Run 'dpkg-architecture --print-set --print-format=make' to +# generate a makefile construct that exports all DEB_* variables. +ifndef DEB_HOST_ARCH +include debian/deb-env.vars + +debian/deb-env.vars: + $(Q)dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp + $(Q)mv $@.tmp $@ +endif diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build index 8a7051fad087..76e0765dfcd6 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -20,7 +20,7 @@ mkdir -p "${destdir}" find "arch/${SRCARCH}" -maxdepth 1 -name 'Makefile*' find include scripts -type f -o -type l find "arch/${SRCARCH}" -name Kbuild.platforms -o -name Platform - find "arch/${SRCARCH}" -name include -o -name scripts -type d + find "arch/${SRCARCH}" -name include -type d ) | tar -c -f - -C "${srctree}" -T - | tar -xf - -C "${destdir}" { diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index 3eee0143e0c5..e095eb1e290e 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -55,52 +55,72 @@ patch -p1 < %{SOURCE2} %{make} %{makeflags} KERNELRELEASE=%{KERNELRELEASE} KBUILD_BUILD_VERSION=%{release} %install -mkdir -p %{buildroot}/boot -%ifarch ia64 -mkdir -p %{buildroot}/boot/efi -cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/efi/vmlinuz-%{KERNELRELEASE} -ln -s efi/vmlinuz-%{KERNELRELEASE} %{buildroot}/boot/ -%else -cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/vmlinuz-%{KERNELRELEASE} -%endif +mkdir -p %{buildroot}/lib/modules/%{KERNELRELEASE} +cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEASE}/vmlinuz %{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install -cp System.map %{buildroot}/boot/System.map-%{KERNELRELEASE} -cp .config %{buildroot}/boot/config-%{KERNELRELEASE} +cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE} +cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config +if %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='test -d ${srctree}/arch/${SRCARCH}/boot/dts' 2>/dev/null; then + %{make} %{makeflags} INSTALL_DTBS_PATH=%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb dtbs_install +fi ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build %if %{with_devel} %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}' %endif +{ + for x in System.map config kernel modules.builtin \ + modules.builtin.modinfo modules.order vmlinuz; do + echo "/lib/modules/%{KERNELRELEASE}/${x}" + done + + for x in alias alias.bin builtin.alias.bin builtin.bin dep dep.bin \ + devname softdep symbols symbols.bin; do + echo "%ghost /lib/modules/%{KERNELRELEASE}/modules.${x}" + done + + for x in System.map config vmlinuz; do + echo "%ghost /boot/${x}-%{KERNELRELEASE}" + done + + if [ -d "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" ];then + echo "/lib/modules/%{KERNELRELEASE}/dtb" + find "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" -printf "%%%ghost /boot/dtb-%{KERNELRELEASE}/%%P\n" + fi + + echo "%exclude /lib/modules/%{KERNELRELEASE}/build" +} > %{buildroot}/kernel.list + %clean rm -rf %{buildroot} %post -if [ -x /sbin/installkernel -a -r /boot/vmlinuz-%{KERNELRELEASE} -a -r /boot/System.map-%{KERNELRELEASE} ]; then -cp /boot/vmlinuz-%{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm -cp /boot/System.map-%{KERNELRELEASE} /boot/.System.map-%{KERNELRELEASE}-rpm -rm -f /boot/vmlinuz-%{KERNELRELEASE} /boot/System.map-%{KERNELRELEASE} -/sbin/installkernel %{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm -rm -f /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm +if [ -x /usr/bin/kernel-install ]; then + /usr/bin/kernel-install add %{KERNELRELEASE} /lib/modules/%{KERNELRELEASE}/vmlinuz +fi +for file in vmlinuz System.map config; do + if ! cmp --silent "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"; then + cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}" + fi +done +if [ -d "/lib/modules/%{KERNELRELEASE}/dtb" ] && \ + ! diff -rq "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}" >/dev/null 2>&1; then + rm -rf "/boot/dtb-%{KERNELRELEASE}" + cp -r "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}" +fi +if [ ! -e "/lib/modules/%{KERNELRELEASE}/modules.dep" ]; then + /usr/sbin/depmod %{KERNELRELEASE} fi %preun -if [ -x /sbin/new-kernel-pkg ]; then -new-kernel-pkg --remove %{KERNELRELEASE} --rminitrd --initrdfile=/boot/initramfs-%{KERNELRELEASE}.img -elif [ -x /usr/bin/kernel-install ]; then +if [ -x /usr/bin/kernel-install ]; then kernel-install remove %{KERNELRELEASE} fi -%postun -if [ -x /sbin/update-bootloader ]; then -/sbin/update-bootloader --remove %{KERNELRELEASE} -fi - -%files +%files -f %{buildroot}/kernel.list %defattr (-, root, root) -/lib/modules/%{KERNELRELEASE} -%exclude /lib/modules/%{KERNELRELEASE}/build -/boot/* +%exclude /kernel.list %files headers %defattr (-, root, root) diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian index 5044224cf671..070149c985fe 100755 --- a/scripts/package/mkdebian +++ b/scripts/package/mkdebian @@ -26,7 +26,7 @@ set_debarch() { # Attempt to find the correct Debian architecture case "$UTS_MACHINE" in - i386|ia64|alpha|m68k|riscv*) + i386|alpha|m68k|riscv*) debarch="$UTS_MACHINE" ;; x86_64) debarch=amd64 ;; @@ -176,8 +176,6 @@ else fi echo $debarch > debian/arch -extra_build_depends=", $(if_enabled_echo CONFIG_UNWINDER_ORC libelf-dev:native)" -extra_build_depends="$extra_build_depends, $(if_enabled_echo CONFIG_SYSTEM_TRUSTED_KEYRING libssl-dev:native)" # Generate a simple changelog template cat <<EOF > debian/changelog @@ -188,26 +186,6 @@ $sourcename ($packageversion) $distribution; urgency=low -- $maintainer $(date -R) EOF -# Generate copyright file -cat <<EOF > debian/copyright -This is a packaged upstream version of the Linux kernel. - -The sources may be found at most Linux archive sites, including: -https://www.kernel.org/pub/linux/kernel - -Copyright: 1991 - 2018 Linus Torvalds and others. - -The git repository for mainline kernel development is at: -git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 dated June, 1991. - -On Debian GNU/Linux systems, the complete text of the GNU General Public -License version 2 can be found in \`/usr/share/common-licenses/GPL-2'. -EOF - # Generate a control file cat <<EOF > debian/control Source: $sourcename @@ -215,7 +193,8 @@ Section: kernel Priority: optional Maintainer: $maintainer Rules-Requires-Root: no -Build-Depends: bc, debhelper, rsync, kmod, cpio, bison, flex $extra_build_depends +Build-Depends: debhelper-compat (= 12) +Build-Depends-Arch: bc, bison, cpio, flex, kmod, libelf-dev:native, libssl-dev:native, rsync Homepage: https://www.kernel.org/ Package: $packagename-$version @@ -268,6 +247,7 @@ ARCH := ${ARCH} KERNELRELEASE := ${KERNELRELEASE} EOF +cp "${srctree}/scripts/package/debian/copyright" debian/ cp "${srctree}/scripts/package/debian/rules" debian/ exit 0 diff --git a/scripts/package/snapcraft.template b/scripts/package/snapcraft.template index 626d278e4a5a..85d5e07d1b40 100644 --- a/scripts/package/snapcraft.template +++ b/scripts/package/snapcraft.template @@ -10,5 +10,5 @@ parts: kernel: plugin: kernel source: SRCTREE - source-type: tar + source-type: local kernel-with-firmware: false diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 40ae6b2c7a6d..3e4f54799cc0 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -590,7 +590,6 @@ static int do_file(char const *const fname) ideal_nop = ideal_nop4_arm64; is_fake_mcount64 = arm64_is_fake_mcount; break; - case EM_IA_64: reltype = R_IA64_IMM64; break; case EM_MIPS: /* reltype: e_class */ break; case EM_LOONGARCH: /* reltype: e_class */ break; case EM_PPC: reltype = R_PPC_ADDR32; break; diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 6a4645a57976..0871b2e92584 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -275,13 +275,6 @@ if ($arch eq "x86_64") { $section_type = '%progbits'; $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+_mcount\$"; $type = ".quad"; -} elsif ($arch eq "ia64") { - $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; - $type = "data8"; - - if ($is_module eq "0") { - $cc .= " -mconstant-gp"; - } } elsif ($arch eq "sparc64") { # In the objdump output there are giblets like: # 0000000000000000 <igmp_net_exit-0x18>: @@ -359,7 +352,7 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; } elsif ($arch eq "riscv") { $function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; - $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_?mcount\$"; + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_mcount\$"; $type = ".quad"; $alignment = 2; } elsif ($arch eq "csky") { diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 855c4863124b..edec60d39bbf 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -26,6 +26,7 @@ accelaration||acceleration accelearion||acceleration acceleratoin||acceleration accelleration||acceleration +accelrometer||accelerometer accesing||accessing accesnt||accent accessable||accessible @@ -137,6 +138,7 @@ anniversery||anniversary annoucement||announcement anomolies||anomalies anomoly||anomaly +anonynous||anonymous anway||anyway aplication||application appearence||appearance @@ -267,6 +269,7 @@ cadidate||candidate cahces||caches calender||calendar calescing||coalescing +calibraiton||calibration calle||called callibration||calibration callled||called @@ -288,6 +291,7 @@ capabitilies||capabilities capablity||capability capatibilities||capabilities capapbilities||capabilities +captuer||capture caputure||capture carefuly||carefully cariage||carriage @@ -340,6 +344,7 @@ comminucation||communication commited||committed commiting||committing committ||commit +commmand||command commnunication||communication commoditiy||commodity comsume||consume @@ -406,6 +411,7 @@ continious||continuous continous||continuous continously||continuously continueing||continuing +contiuous||continuous contraints||constraints contruct||construct contol||control @@ -757,6 +763,7 @@ hardward||hardware havind||having heirarchically||hierarchically heirarchy||hierarchy +heirachy||hierarchy helpfull||helpful hearbeat||heartbeat heterogenous||heterogeneous @@ -1199,6 +1206,7 @@ priting||printing privilaged||privileged privilage||privilege priviledge||privilege +priviledged||privileged priviledges||privileges privleges||privileges probaly||probably @@ -1251,6 +1259,7 @@ purgable||purgeable pwoer||power queing||queuing quering||querying +querrying||querying queus||queues randomally||randomly raoming||roaming @@ -1324,6 +1333,7 @@ reseting||resetting reseved||reserved reseverd||reserved resizeable||resizable +resonable||reasonable resotre||restore resouce||resource resouces||resources @@ -1427,6 +1437,7 @@ sliped||slipped softwade||software softwares||software soley||solely +soluation||solution souce||source speach||speech specfic||specific @@ -1458,6 +1469,7 @@ standart||standard standy||standby stardard||standard staticly||statically +statisitcs||statistics statuss||status stoped||stopped stoping||stopping @@ -1548,6 +1560,7 @@ threds||threads threee||three threshhold||threshold thresold||threshold +throtting||throttling throught||through tansition||transition trackling||tracking @@ -1571,6 +1584,7 @@ tranasction||transaction tranceiver||transceiver tranfer||transfer tranmission||transmission +tranport||transport transcevier||transceiver transciever||transceiver transferd||transferred diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 1fb88fdceec3..4c781617ffe6 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -32,8 +32,7 @@ my $python_cmd = ""; my $activate_cmd; my $min_version; my $cur_version; -my $rec_version = "1.7.9"; # PDF won't build here -my $min_pdf_version = "2.4.4"; # Min version where pdf builds +my $rec_version = "3.4.3"; my $latest_avail_ver; # @@ -281,8 +280,6 @@ sub get_sphinx_version($) sub check_sphinx() { - my $default_version; - open IN, $conf or die "Can't open $conf"; while (<IN>) { if (m/^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]/) { @@ -294,18 +291,7 @@ sub check_sphinx() die "Can't get needs_sphinx version from $conf" if (!$min_version); - open IN, $requirement_file or die "Can't open $requirement_file"; - while (<IN>) { - if (m/^\s*Sphinx\s*==\s*([\d\.]+)$/) { - $default_version=$1; - last; - } - } - close IN; - - die "Can't get default sphinx version from $requirement_file" if (!$default_version); - - $virtenv_dir = $virtenv_prefix . $default_version; + $virtenv_dir = $virtenv_prefix . "latest"; my $sphinx = get_sphinx_fname(); if ($sphinx eq "") { @@ -319,8 +305,8 @@ sub check_sphinx() die "$sphinx didn't return its version" if (!$cur_version); if ($cur_version lt $min_version) { - printf "ERROR: Sphinx version is %s. It should be >= %s (recommended >= %s)\n", - $cur_version, $min_version, $default_version; + printf "ERROR: Sphinx version is %s. It should be >= %s\n", + $cur_version, $min_version; $need_sphinx = 1; return; } @@ -362,6 +348,7 @@ sub give_debian_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-yaml", "ensurepip" => "python3-venv", "virtualenv" => "virtualenv", "dot" => "graphviz", @@ -396,6 +383,7 @@ sub give_redhat_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-pyyaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -422,6 +410,7 @@ sub give_redhat_hints() # my $old = 0; my $rel; + my $noto_sans_redhat = "google-noto-sans-cjk-ttc-fonts"; $rel = $1 if ($system_release =~ /release\s+(\d+)/); if (!($system_release =~ /Fedora/)) { @@ -439,6 +428,9 @@ sub give_redhat_hints() if ($rel && $rel < 26) { $old = 1; } + if ($rel && $rel >= 38) { + $noto_sans_redhat = "google-noto-sans-cjk-fonts"; + } } if (!$rel) { printf("Couldn't identify release number\n"); @@ -447,8 +439,9 @@ sub give_redhat_hints() } if ($pdf) { - check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc"], - "google-noto-sans-cjk-ttc-fonts", 2); + check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc"], + $noto_sans_redhat, 2); } check_rpm_missing(\@fedora26_opt_pkgs, 2) if ($pdf && !$old); @@ -473,6 +466,7 @@ sub give_opensuse_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-pyyaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -791,9 +785,6 @@ sub recommend_sphinx_version($) # Version is OK. Nothing to do. 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; }; @@ -842,10 +833,6 @@ sub recommend_sphinx_version($) 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; } @@ -959,6 +946,7 @@ sub check_needs() # Check for needed programs/tools check_perl_module("Pod::Usage", 0); + check_python_module("yaml", 0); check_program("make", 0); check_program("gcc", 0); check_program("dot", 1); diff --git a/scripts/tags.sh b/scripts/tags.sh index a70d43723146..191e0461d6d5 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -3,7 +3,7 @@ # Generate tags or cscope files # Usage tags.sh <mode> # -# mode may be any of: tags, TAGS, cscope +# mode may be any of: tags, gtags, TAGS, cscope # # Uses the following environment variables: # SUBARCH, SRCARCH, srctree @@ -50,7 +50,7 @@ fi find_arch_sources() { for i in $archincludedir; do - prune="$prune -wholename $i -prune -o" + local prune="$prune ( -path $i ) -prune -o" done find ${tree}arch/$1 $ignore $prune -name "$2" -not -type l -print; } @@ -58,7 +58,7 @@ find_arch_sources() # find sources in arch/$1/include find_arch_include_sources() { - include=$(find ${tree}arch/$1/ -name include -type d -print); + local include=$(find ${tree}arch/$1/ -name include -type d -print); if [ -n "$include" ]; then archincludedir="$archincludedir $include" find $include $ignore -name "$2" -not -type l -print; @@ -81,21 +81,16 @@ find_other_sources() -name "$1" -not -type l -print; } -find_sources() -{ - find_arch_sources $1 "$2" -} - all_sources() { find_arch_include_sources ${SRCARCH} '*.[chS]' - if [ ! -z "$archinclude" ]; then + if [ -n "$archinclude" ]; then find_arch_include_sources $archinclude '*.[chS]' fi find_include_sources '*.[chS]' for arch in $ALLSOURCE_ARCHS do - find_sources $arch '*.[chS]' + find_arch_sources $arch '*.[chS]' done find_other_sources '*.[chS]' } @@ -125,7 +120,7 @@ all_kconfigs() find ${tree}arch/ -maxdepth 1 $ignore \ -name "Kconfig*" -not -type l -print; for arch in $ALLSOURCE_ARCHS; do - find_sources $arch 'Kconfig*' + find_arch_sources $arch 'Kconfig*' done find_other_sources 'Kconfig*' } diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh index 76e9cbcfbeab..d06baf626abe 100755 --- a/scripts/xz_wrap.sh +++ b/scripts/xz_wrap.sh @@ -15,7 +15,6 @@ LZMA2OPTS= case $SRCARCH in x86) BCJ=--x86 ;; powerpc) BCJ=--powerpc ;; - ia64) BCJ=--ia64; LZMA2OPTS=pb=4 ;; arm) BCJ=--arm ;; sparc) BCJ=--sparc ;; esac |