diff options
Diffstat (limited to 'scripts')
115 files changed, 3392 insertions, 2455 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 7778cc97a4e0..faf37bafa3f8 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -62,8 +62,7 @@ stringify = $(squote)$(quote)$1$(quote)$(squote) ### # The path to Kbuild or Makefile. Kbuild has precedence over Makefile. -kbuild-dir = $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -kbuild-file = $(or $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Makefile) +kbuild-file = $(or $(wildcard $(src)/Kbuild),$(src)/Makefile) ### # Read a file, replacing newlines with spaces @@ -114,12 +113,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/Makefile b/scripts/Makefile index 576cf64be667..fe56eeef09dd 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 +ifdef CONFIG_X86_64 +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.asm-generic b/scripts/Makefile.asm-generic index 8d01b37b7677..1486abf34c7c 100644 --- a/scripts/Makefile.asm-generic +++ b/scripts/Makefile.asm-generic @@ -9,7 +9,7 @@ PHONY := all all: -src := $(subst /generated,,$(obj)) +src := $(srctree)/$(subst /generated,,$(obj)) include $(srctree)/scripts/Kbuild.include -include $(kbuild-file) @@ -20,14 +20,14 @@ include $(srctree)/$(generic)/Kbuild endif redundant := $(filter $(mandatory-y) $(generated-y), $(generic-y)) -redundant += $(foreach f, $(generic-y), $(if $(wildcard $(srctree)/$(src)/$(f)),$(f))) +redundant += $(foreach f, $(generic-y), $(if $(wildcard $(src)/$(f)),$(f))) redundant := $(sort $(redundant)) $(if $(redundant),\ $(warning redundant generic-y found in $(src)/Kbuild: $(redundant))) # If arch does not implement mandatory headers, fallback to asm-generic ones. mandatory-y := $(filter-out $(generated-y), $(mandatory-y)) -generic-y += $(foreach f, $(mandatory-y), $(if $(wildcard $(srctree)/$(src)/$(f)),,$(f))) +generic-y += $(foreach f, $(mandatory-y), $(if $(wildcard $(src)/$(f)),,$(f))) generic-y := $(addprefix $(obj)/, $(generic-y)) generated-y := $(addprefix $(obj)/, $(generated-y)) diff --git a/scripts/Makefile.btf b/scripts/Makefile.btf index 82377e470aed..2d6e5ed9081e 100644 --- a/scripts/Makefile.btf +++ b/scripts/Makefile.btf @@ -3,6 +3,8 @@ pahole-ver := $(CONFIG_PAHOLE_VERSION) pahole-flags-y := +ifeq ($(call test-le, $(pahole-ver), 125),y) + # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars ifeq ($(call test-le, $(pahole-ver), 121),y) pahole-flags-$(call test-ge, $(pahole-ver), 118) += --skip_encoding_btf_vars @@ -12,8 +14,17 @@ pahole-flags-$(call test-ge, $(pahole-ver), 121) += --btf_gen_floats pahole-flags-$(call test-ge, $(pahole-ver), 122) += -j -pahole-flags-$(CONFIG_PAHOLE_HAS_LANG_EXCLUDE) += --lang_exclude=rust +ifeq ($(pahole-ver), 125) +pahole-flags-y += --skip_encoding_btf_inconsistent_proto --btf_gen_optimized +endif + +else -pahole-flags-$(call test-ge, $(pahole-ver), 125) += --skip_encoding_btf_inconsistent_proto --btf_gen_optimized +# Switch to using --btf_features for v1.26 and later. +pahole-flags-$(call test-ge, $(pahole-ver), 126) = -j --btf_features=encode_force,var,float,enum64,decl_tag,type_tag,optimized_func,consistent_func + +endif + +pahole-flags-$(CONFIG_PAHOLE_HAS_LANG_EXCLUDE) += --lang_exclude=rust export PAHOLE_FLAGS := $(pahole-flags-y) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index dae447a1ad30..efacca63c897 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -3,7 +3,7 @@ # Building # ========================================================================== -src := $(obj) +src := $(if $(VPATH),$(VPATH)/)$(obj) PHONY := $(obj)/ $(obj)/: @@ -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) @@ -112,13 +113,13 @@ endif quiet_cmd_cc_s_c = CC $(quiet_modtag) $@ cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS) $(CC_FLAGS_LTO), $(c_flags)) -fverbose-asm -S -o $@ $< -$(obj)/%.s: $(src)/%.c FORCE +$(obj)/%.s: $(obj)/%.c FORCE $(call if_changed_dep,cc_s_c) quiet_cmd_cpp_i_c = CPP $(quiet_modtag) $@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< -$(obj)/%.i: $(src)/%.c FORCE +$(obj)/%.i: $(obj)/%.c FORCE $(call if_changed_dep,cpp_i_c) genksyms = scripts/genksyms/genksyms \ @@ -132,7 +133,7 @@ cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms) quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null -$(obj)/%.symtypes : $(src)/%.c FORCE +$(obj)/%.symtypes : $(obj)/%.c FORCE $(call cmd,cc_symtypes_c) # LLVM assembly @@ -140,7 +141,7 @@ $(obj)/%.symtypes : $(src)/%.c FORCE quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@ cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -fno-discard-value-names -o $@ $< -$(obj)/%.ll: $(src)/%.c FORCE +$(obj)/%.ll: $(obj)/%.c FORCE $(call if_changed_dep,cc_ll_c) # C (.c) files @@ -213,9 +214,9 @@ 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),$(is-kernel-object)) -$(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) +$(obj)/%.o: private objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),) cmd_warn_shared_object = $(if $(word 2, $(modname-multi)),$(warning $(kbuild-file): $*.o is added to multiple modules: $(modname-multi))) @@ -239,7 +240,7 @@ define rule_as_o_S endef # Built-in and composite module parts -$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE +$(obj)/%.o: $(obj)/%.c $(recordmcount_source) FORCE $(call if_changed_rule,cc_o_c) $(call cmd,force_checksrc) @@ -256,13 +257,13 @@ quiet_cmd_cc_lst_c = MKLST $@ $(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \ System.map $(OBJDUMP) > $@ -$(obj)/%.lst: $(src)/%.c FORCE +$(obj)/%.lst: $(obj)/%.c FORCE $(call if_changed_dep,cc_lst_c) # Compile Rust sources (.rs) # --------------------------------------------------------------------------- -rust_allowed_features := new_uninit,offset_of +rust_allowed_features := new_uninit # `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree @@ -272,7 +273,7 @@ rust_common_cmd = \ -Zallow-features=$(rust_allowed_features) \ -Zcrate-attr=no_std \ -Zcrate-attr='feature($(rust_allowed_features))' \ - --extern alloc --extern kernel \ + -Zunstable-options --extern force:alloc --extern kernel \ --crate-type rlib -L $(objtree)/rust/ \ --crate-name $(basename $(notdir $@)) \ --sysroot=/dev/null \ @@ -289,28 +290,28 @@ rust_common_cmd = \ 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) +$(obj)/%.o: $(obj)/%.rs FORCE + +$(call if_changed_dep,rustc_o_rs) quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ cmd_rustc_rsi_rs = \ $(rust_common_cmd) -Zunpretty=expanded $< >$@; \ command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@ -$(obj)/%.rsi: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_rsi_rs) +$(obj)/%.rsi: $(obj)/%.rs FORCE + +$(call if_changed_dep,rustc_rsi_rs) quiet_cmd_rustc_s_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ cmd_rustc_s_rs = $(rust_common_cmd) --emit=asm=$@ $< -$(obj)/%.s: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_s_rs) +$(obj)/%.s: $(obj)/%.rs FORCE + +$(call if_changed_dep,rustc_s_rs) quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ cmd_rustc_ll_rs = $(rust_common_cmd) --emit=llvm-ir=$@ $< -$(obj)/%.ll: $(src)/%.rs FORCE - $(call if_changed_dep,rustc_ll_rs) +$(obj)/%.ll: $(obj)/%.rs FORCE + +$(call if_changed_dep,rustc_ll_rs) # Compile assembler sources (.S) # --------------------------------------------------------------------------- @@ -335,14 +336,14 @@ cmd_gensymtypes_S = \ quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@ cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null -$(obj)/%.symtypes : $(src)/%.S FORCE +$(obj)/%.symtypes : $(obj)/%.S FORCE $(call cmd,cc_symtypes_S) quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@ cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $< -$(obj)/%.s: $(src)/%.S FORCE +$(obj)/%.s: $(obj)/%.S FORCE $(call if_changed_dep,cpp_s_S) quiet_cmd_as_o_S = AS $(quiet_modtag) $@ @@ -357,7 +358,7 @@ cmd_gen_symversions_S = $(call gen_symversions,S) endif -$(obj)/%.o: $(src)/%.S FORCE +$(obj)/%.o: $(obj)/%.S FORCE $(call if_changed_rule,as_o_S) targets += $(filter-out $(subdir-builtin), $(real-obj-y)) @@ -388,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) @@ -404,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) @@ -433,8 +437,8 @@ define rule_ld_multi_m $(call cmd,gen_objtooldep) endef -$(multi-obj-m): objtool-enabled := $(delay-objtool) -$(multi-obj-m): part-of-module := y +$(multi-obj-m): private objtool-enabled := $(delay-objtool) +$(multi-obj-m): private part-of-module := y $(multi-obj-m): %.o: %.mod FORCE $(call if_changed_rule,ld_multi_m) $(call multi_depend, $(multi-obj-m), .o, -objs -y -m) diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index f2cb4d7ffd96..4fcfab40ed61 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -3,7 +3,7 @@ # Cleaning up # ========================================================================== -src := $(obj) +src := $(if $(VPATH),$(VPATH)/)$(obj) PHONY := __clean __clean: diff --git a/scripts/Makefile.debug b/scripts/Makefile.debug index 059ff38fe0cb..107db997ce38 100644 --- a/scripts/Makefile.debug +++ b/scripts/Makefile.debug @@ -17,6 +17,12 @@ endif DEBUG_CFLAGS += $(debug-flags-y) KBUILD_AFLAGS += $(debug-flags-y) +ifdef CONFIG_DEBUG_INFO_DWARF4 +DEBUG_RUSTFLAGS += -Zdwarf-version=4 +else ifdef CONFIG_DEBUG_INFO_DWARF5 +DEBUG_RUSTFLAGS += -Zdwarf-version=5 +endif + ifdef CONFIG_DEBUG_INFO_REDUCED DEBUG_CFLAGS += -fno-var-tracking DEBUG_RUSTFLAGS += -Cdebuginfo=1 @@ -29,10 +35,12 @@ endif ifdef CONFIG_DEBUG_INFO_COMPRESSED_ZLIB DEBUG_CFLAGS += -gz=zlib +DEBUG_RUSTFLAGS += -Zdebuginfo-compression=zlib KBUILD_AFLAGS += -gz=zlib KBUILD_LDFLAGS += --compress-debug-sections=zlib else ifdef CONFIG_DEBUG_INFO_COMPRESSED_ZSTD DEBUG_CFLAGS += -gz=zstd +DEBUG_RUSTFLAGS += -Zdebuginfo-compression=zstd KBUILD_AFLAGS += -gz=zstd KBUILD_LDFLAGS += --compress-debug-sections=zstd endif 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 a9e552a1e910..1d13cecc7cc7 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -37,11 +37,6 @@ else KBUILD_CFLAGS += -Wno-main endif -# These warnings generated too much noise in a regular build. -# Use make W=1 to enable them (see scripts/Makefile.extrawarn) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) - # These result in bogus false positives KBUILD_CFLAGS += $(call cc-disable-warning, dangling-pointer) @@ -82,22 +77,17 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init) # Warn if there is an enum types mismatch KBUILD_CFLAGS += $(call cc-option,-Wenum-conversion) +KBUILD_CFLAGS += -Wextra +KBUILD_CFLAGS += -Wunused + # # 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 += $(call cc-option, -Wrestrict) KBUILD_CFLAGS += -Wmissing-format-attribute -KBUILD_CFLAGS += -Wold-style-definition KBUILD_CFLAGS += -Wmissing-include-dirs -KBUILD_CFLAGS += $(call cc-option, -Wunused-but-set-variable) KBUILD_CFLAGS += $(call cc-option, -Wunused-const-variable) -KBUILD_CFLAGS += $(call cc-option, -Wpacked-not-aligned) -KBUILD_CFLAGS += $(call cc-option, -Wformat-overflow) -KBUILD_CFLAGS += $(call cc-option, -Wformat-truncation) -KBUILD_CFLAGS += $(call cc-option, -Wstringop-truncation) KBUILD_CPPFLAGS += -Wundef KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1 @@ -108,12 +98,20 @@ else # Suppress them by using -Wno... except for W=1. KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, restrict) KBUILD_CFLAGS += $(call cc-disable-warning, packed-not-aligned) KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) +ifdef CONFIG_CC_IS_GCC KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) +else +# Clang checks for overflow/truncation with '%p', while GCC does not: +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111219 +KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow-non-kprintf) +KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation-non-kprintf) +endif 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) @@ -131,7 +129,8 @@ endif 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 @@ -144,15 +143,8 @@ ifneq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) KBUILD_CFLAGS += -Wdisabled-optimization KBUILD_CFLAGS += -Wshadow KBUILD_CFLAGS += $(call cc-option, -Wlogical-op) -KBUILD_CFLAGS += -Wmissing-field-initializers -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 @@ -162,9 +154,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 @@ -185,7 +175,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 @@ -193,6 +182,7 @@ else # The following turn off the warnings enabled by -Wextra KBUILD_CFLAGS += -Wno-sign-compare +KBUILD_CFLAGS += -Wno-unused-parameter endif diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 08d83d9db31a..d35f55e0d141 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -112,7 +112,7 @@ endif quiet_cmd_host-csingle = HOSTCC $@ cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(KBUILD_HOSTLDFLAGS) -o $@ $< \ $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) -$(host-csingle): $(obj)/%: $(src)/%.c FORCE +$(host-csingle): $(obj)/%: $(obj)/%.c FORCE $(call if_changed_dep,host-csingle) # Link an executable based on list of .o files, all plain c @@ -129,7 +129,7 @@ $(call multi_depend, $(host-cmulti), , -objs) # host-cobjs -> .o quiet_cmd_host-cobjs = HOSTCC $@ cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $< -$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE +$(host-cobjs): $(obj)/%.o: $(obj)/%.c FORCE $(call if_changed_dep,host-cobjs) # Link an executable based on list of .o files, a mixture of .c and .cc @@ -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 cd5b181060f1..9f06f6aaf7fc 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 @@ -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)$(if $(is-kernel-object),$(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)$(is-kernel-object)), \ $(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)$(is-kernel-object)), \ $(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)$(is-kernel-object)), \ , -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)$(is-kernel-object)), \ $(CFLAGS_UBSAN)) +_c_flags += $(if $(patsubst n%,, \ + $(UBSAN_SIGNED_WRAP_$(target-stem).o)$(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)$(is-kernel-object)), \ + $(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)$(if $(is-kernel-object),$(CONFIG_KCOV_INSTRUMENT_ALL))), \ $(CFLAGS_KCOV)) endif @@ -191,25 +200,29 @@ endif # ifeq ($(CONFIG_KCSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(KCSAN_SANITIZE_$(basetarget).o)$(KCSAN_SANITIZE)y), \ + $(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)$(is-kernel-object)), \ $(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 -# $(srctree)/$(src) for including checkin headers from generated source files -# $(objtree)/$(obj) for including generated headers from checkin source files +# $(src) for including checkin headers from generated source files +# $(obj) for including generated headers from checkin source files ifeq ($(KBUILD_EXTMOD),) ifdef building_out_of_srctree -_c_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj) -_a_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj) -_cpp_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj) +_c_flags += $(addprefix -I, $(src) $(obj)) +_a_flags += $(addprefix -I, $(src) $(obj)) +_cpp_flags += $(addprefix -I, $(src) $(obj)) endif endif +# If $(is-kernel-object) is 'y', this object will be linked to vmlinux or modules +is-kernel-object = $(or $(part-of-builtin),$(part-of-module)) + +part-of-builtin = $(if $(filter $(basename $@).o, $(real-obj-y) $(lib-y)),y) part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y) quiet_modtag = $(if $(part-of-module),[M], ) @@ -254,7 +267,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 +275,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 +353,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 +371,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)), -@) @@ -402,7 +414,7 @@ $(multi-dtb-y): FORCE $(call if_changed,fdtoverlay) $(call multi_depend, $(multi-dtb-y), .dtb, -dtbs) -ifneq ($(CHECK_DTBS)$(CHECK_DT_BINDING),) +ifneq ($(CHECK_DTBS),) DT_CHECKER ?= dt-validate DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),-l $(DT_SCHEMA_FILES),-m) DT_BINDING_DIR := Documentation/devicetree/bindings @@ -415,7 +427,7 @@ quiet_cmd_dtb = $(quiet_cmd_dtc) cmd_dtb = $(cmd_dtc) endif -$(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE +$(obj)/%.dtb: $(obj)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE $(call if_changed_dep,dtb) $(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE @@ -496,6 +508,22 @@ quiet_cmd_uimage = UIMAGE $@ -a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \ -n '$(UIMAGE_NAME)' -d $< $@ +# Flat Image Tree (FIT) +# This allows for packaging of a kernel and all devicetrees files, using +# compression. +# --------------------------------------------------------------------------- + +MAKE_FIT := $(srctree)/scripts/make_fit.py + +# Use this to override the compression algorithm +FIT_COMPRESSION ?= gzip + +quiet_cmd_fit = FIT $@ + cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \ + --name '$(UIMAGE_NAME)' \ + $(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \ + --compress $(FIT_COMPRESSION) -k $< @$(word 2,$^) + # XZ # --------------------------------------------------------------------------- # Use xzkern to compress the kernel image and xzmisc to compress other things. diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 8568d256d6fb..3bec9043e4f3 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -21,9 +21,11 @@ __modfinal: $(modules:%.o=%.ko) # modname and part-of-module are set to make c_flags define proper module flags modname = $(notdir $(@:.mod.o=)) part-of-module = y +GCOV_PROFILE := n +KCSAN_SANITIZE := n 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), $(c_flags)) -c -o $@ $< %.mod.o: %.mod.c FORCE $(call if_changed_dep,cc_o_c) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 739402f45509..44936ebad161 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -94,7 +94,7 @@ targets += .vmlinux.objs ifdef CONFIG_TRIM_UNUSED_KSYMS ksym-wl := $(CONFIG_UNUSED_KSYMS_WHITELIST) -ksym-wl := $(if $(filter-out /%, $(ksym-wl)),$(srctree)/)$(ksym-wl) +ksym-wl := $(if $(filter-out /%, $(ksym-wl)),$(if $(wildcard $(ksym-wl)),,$(srctree)/))$(ksym-wl) modpost-args += -t $(addprefix -u , $(ksym-wl)) modpost-deps += $(ksym-wl) endif @@ -112,7 +112,7 @@ else # set src + obj - they may be used in the modules's Makefile obj := $(KBUILD_EXTMOD) -src := $(obj) +src := $(if $(VPATH),$(VPATH)/)$(obj) # Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS include $(kbuild-file) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index a81dfb1f5181..38653f3e8108 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -135,7 +135,7 @@ snap-pkg: mkdir $(objtree)/snap $(MAKE) clean sed "s@KERNELRELEASE@$(KERNELRELEASE)@; \ - s@SRCTREE@$(abs_srctree)@" \ + 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.vdsoinst b/scripts/Makefile.vdsoinst index c477d17b0aa5..ac85f9a4a569 100644 --- a/scripts/Makefile.vdsoinst +++ b/scripts/Makefile.vdsoinst @@ -13,16 +13,15 @@ install-dir := $(MODLIB)/vdso define gen_install_rules -src := $$(firstword $$(subst :,$(space),$(1))) -dest := $(install-dir)/$$(or $$(word 2,$$(subst :,$(space),$(1))),$$(patsubst %.dbg,%,$$(notdir $(1)))) +dest := $(install-dir)/$$(patsubst %.dbg,%,$$(notdir $(1))) __default: $$(dest) -$$(dest): $$(src) FORCE +$$(dest): $(1) FORCE $$(call cmd,install) # Some architectures create .build-id symlinks -ifneq ($(filter arm sparc x86, $(SRCARCH)),) -link := $(install-dir)/.build-id/$$(shell $(READELF) -n $$(src) | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p').debug +ifneq ($(filter arm s390 sparc x86, $(SRCARCH)),) +link := $(install-dir)/.build-id/$$(shell $(READELF) -n $(1) | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p').debug __default: $$(link) $$(link): $$(dest) FORCE diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index c9f3e03124d7..49946cb96844 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -18,9 +18,6 @@ quiet_cmd_cc_o_c = CC $@ $(call if_changed_dep,cc_o_c) ifdef CONFIG_MODULES -KASAN_SANITIZE_.vmlinux.export.o := n -KCSAN_SANITIZE_.vmlinux.export.o := n -GCOV_PROFILE_.vmlinux.export.o := n targets += .vmlinux.export.o vmlinux: .vmlinux.export.o endif 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 0669bac5e900..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' @@ -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-variable-fonts.sh b/scripts/check-variable-fonts.sh new file mode 100755 index 000000000000..ce63f0acea5f --- /dev/null +++ b/scripts/check-variable-fonts.sh @@ -0,0 +1,115 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) Akira Yokosawa, 2024 +# +# For "make pdfdocs", reports of build errors of translations.pdf started +# arriving early 2024 [1, 2]. It turned out that Fedora and openSUSE +# tumbleweed have started deploying variable-font [3] format of "Noto CJK" +# fonts [4, 5]. For PDF, a LaTeX package named xeCJK is used for CJK +# (Chinese, Japanese, Korean) pages. xeCJK requires XeLaTeX/XeTeX, which +# does not (and likely never will) understand variable fonts for historical +# reasons. +# +# The build error happens even when both of variable- and non-variable-format +# fonts are found on the build system. To make matters worse, Fedora enlists +# variable "Noto CJK" fonts in the requirements of langpacks-ja, -ko, -zh_CN, +# -zh_TW, etc. Hence developers who have interest in CJK pages are more +# likely to encounter the build errors. +# +# This script is invoked from the error path of "make pdfdocs" and emits +# suggestions if variable-font files of "Noto CJK" fonts are in the list of +# fonts accessible from XeTeX. +# +# References: +# [1]: https://lore.kernel.org/r/8734tqsrt7.fsf@meer.lwn.net/ +# [2]: https://lore.kernel.org/r/1708585803.600323099@f111.i.mail.ru/ +# [3]: https://en.wikipedia.org/wiki/Variable_font +# [4]: https://fedoraproject.org/wiki/Changes/Noto_CJK_Variable_Fonts +# [5]: https://build.opensuse.org/request/show/1157217 +# +#=========================================================================== +# Workarounds for building translations.pdf +#=========================================================================== +# +# * Denylist "variable font" Noto CJK fonts. +# - Create $HOME/deny-vf/fontconfig/fonts.conf from template below, with +# tweaks if necessary. Remove leading "# ". +# - Path of fontconfig/fonts.conf can be overridden by setting an env +# variable FONTS_CONF_DENY_VF. +# +# * Template: +# ----------------------------------------------------------------- +# <?xml version="1.0"?> +# <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> +# <fontconfig> +# <!-- +# Ignore variable-font glob (not to break xetex) +# --> +# <selectfont> +# <rejectfont> +# <!-- +# for Fedora +# --> +# <glob>/usr/share/fonts/google-noto-*-cjk-vf-fonts</glob> +# <!-- +# for openSUSE tumbleweed +# --> +# <glob>/usr/share/fonts/truetype/Noto*CJK*-VF.otf</glob> +# </rejectfont> +# </selectfont> +# </fontconfig> +# ----------------------------------------------------------------- +# +# The denylisting is activated for "make pdfdocs". +# +# * For skipping CJK pages in PDF +# - Uninstall texlive-xecjk. +# Denylisting is not needed in this case. +# +# * For printing CJK pages in PDF +# - Need non-variable "Noto CJK" fonts. +# * Fedora +# - google-noto-sans-cjk-fonts +# - google-noto-serif-cjk-fonts +# * openSUSE tumbleweed +# - Non-variable "Noto CJK" fonts are not available as distro packages +# as of April, 2024. Fetch a set of font files from upstream Noto +# CJK Font released at: +# https://github.com/notofonts/noto-cjk/tree/main/Sans#super-otc +# and at: +# https://github.com/notofonts/noto-cjk/tree/main/Serif#super-otc +# , then uncompress and deploy them. +# - Remember to update fontconfig cache by running fc-cache. +# +# !!! Caution !!! +# Uninstalling "variable font" packages can be dangerous. +# They might be depended upon by other packages important for your work. +# Denylisting should be less invasive, as it is effective only while +# XeLaTeX runs in "make pdfdocs". + +# Default per-user fontconfig path (overridden by env variable) +: ${FONTS_CONF_DENY_VF:=$HOME/deny-vf} + +export XDG_CONFIG_HOME=${FONTS_CONF_DENY_VF} + +notocjkvffonts=`fc-list : file family variable | \ + grep 'variable=True' | \ + grep -E -e 'Noto (Sans|Sans Mono|Serif) CJK' | \ + sed -e 's/^/ /' -e 's/: Noto S.*$//' | sort | uniq` + +if [ "x$notocjkvffonts" != "x" ] ; then + echo '=============================================================================' + echo 'XeTeX is confused by "variable font" files listed below:' + echo "$notocjkvffonts" + echo + echo 'For CJK pages in PDF, they need to be hidden from XeTeX by denylisting.' + echo 'Or, CJK pages can be skipped by uninstalling texlive-xecjk.' + echo + echo 'For more info on denylisting, other options, and variable font, see header' + echo 'comments of scripts/check-variable-fonts.sh.' + echo '=============================================================================' +fi + +# As this script is invoked from Makefile's error path, always error exit +# regardless of whether any variable font is discovered or not. +exit 1 diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 9c4c4a61bc83..2b812210b412 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6040,6 +6040,12 @@ sub process { CHK("MACRO_ARG_PRECEDENCE", "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx"); } + +# check if this is an unused argument + if ($define_stmt !~ /\b$arg\b/) { + WARN("MACRO_ARG_UNUSED", + "Argument '$arg' is not used in function-like macro\n" . "$herectx"); + } } # check for macros with flow control, but without ## concatenation diff --git a/scripts/coccinelle/api/device_attr_show.cocci b/scripts/coccinelle/api/device_attr_show.cocci index 550d1d2fc02a..dfcf9304195f 100644 --- a/scripts/coccinelle/api/device_attr_show.cocci +++ b/scripts/coccinelle/api/device_attr_show.cocci @@ -28,7 +28,7 @@ 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, STR; +expression BUF, SZ, FORMAT; @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci index 4b9778874453..2c931e748dda 100644 --- a/scripts/coccinelle/api/pm_runtime.cocci +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/// Make sure pm_runtime_* calls does not use unnecessary IS_ERR_VALUE +/// Make sure pm_runtime_* calls do not unnecessarily use IS_ERR_VALUE /// // Keywords: pm_runtime // Confidence: Medium 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/minmax.cocci b/scripts/coccinelle/misc/minmax.cocci index fcf908b34f27..ca4830ae3042 100644 --- a/scripts/coccinelle/misc/minmax.cocci +++ b/scripts/coccinelle/misc/minmax.cocci @@ -50,11 +50,26 @@ func(...) ...> } +// Ignore errcode returns. +@errcode@ +position p; +identifier func; +expression x; +binary operator cmp = {<, <=}; +@@ + +func(...) +{ + <... + return ((x) cmp@p 0 ? (x) : 0); + ...> +} + @rmin depends on !patch@ identifier func; expression x, y; binary operator cmp = {<, <=}; -position p; +position p != errcode.p; @@ func(...) @@ -116,21 +131,6 @@ func(...) ...> } -// Don't generate patches for errcode returns. -@errcode depends on patch@ -position p; -identifier func; -expression x; -binary operator cmp = {<, <=}; -@@ - -func(...) -{ - <... - return ((x) cmp@p 0 ? (x) : 0); - ...> -} - @pmin depends on patch@ identifier func; expression x, y; 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..52e5bfb61fd0 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 @@ -37,6 +39,7 @@ kgdb_arch kgdb_io kobj_type kset_uevent_ops +lcd_ops lock_manager_operations machine_desc microcode_ops diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 4d32b9497da9..a18657072541 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -16,12 +16,12 @@ libfdt = $(addprefix libfdt/,$(libfdt-objs)) fdtoverlay-objs := $(libfdt) fdtoverlay.o util.o # Source files need to get at the userspace version of libfdt_env.h to compile -HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt +HOST_EXTRACFLAGS += -I $(src)/libfdt HOST_EXTRACFLAGS += -DNO_YAML # Generated files need one more search path to include headers in source tree -HOSTCFLAGS_dtc-lexer.lex.o := -I $(srctree)/$(src) -HOSTCFLAGS_dtc-parser.tab.o := -I $(srctree)/$(src) +HOSTCFLAGS_dtc-lexer.lex.o := -I $(src) +HOSTCFLAGS_dtc-parser.tab.o := -I $(src) # dependencies on generated files need to be listed explicitly $(obj)/dtc-lexer.lex.o: $(obj)/dtc-parser.tab.h diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c index c5c2ce113c92..d20c47d21ad8 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -467,6 +467,8 @@ static bool stackleak_gate(void) return false; if (STRING_EQUAL(section, ".entry.text")) return false; + if (STRING_EQUAL(section, ".head.text")) + return false; } return track_frame_size >= 0; diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index 48941faa6ea6..d77ad9079d0f 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile @@ -2,7 +2,7 @@ ifdef building_out_of_srctree -symlinks := $(patsubst $(srctree)/$(src)/%,%,$(wildcard $(srctree)/$(src)/*.py)) +symlinks := $(patsubst $(src)/%,%,$(wildcard $(src)/*.py)) quiet_cmd_symlink = SYMLINK $@ cmd_symlink = ln -fsn $(patsubst $(obj)/%,$(abspath $(srctree))/$(src)/%,$@) $@ 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/cpus.py b/scripts/gdb/linux/cpus.py index cba589e5b57d..2f11c4f9c345 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -26,11 +26,7 @@ def get_current_cpu(): if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: return gdb.selected_thread().num - 1 elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: - tid = gdb.selected_thread().ptid[2] - if tid > (0x100000000 - MAX_CPUS - 2): - return 0x100000000 - tid - 2 - else: - return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] + return gdb.parse_and_eval("kgdb_active.counter") else: raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " "supported with this gdb server.") @@ -152,9 +148,8 @@ Note that VAR has to be quoted as string.""" def __init__(self): super(PerCpu, self).__init__("lx_per_cpu") - def invoke(self, var_name, cpu=-1): - var_ptr = gdb.parse_and_eval("&" + var_name.string()) - return per_cpu(var_ptr, cpu) + def invoke(self, var, cpu=-1): + return per_cpu(var.address, cpu) PerCpu() diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py index ef478e273791..616a5f26377a 100644 --- a/scripts/gdb/linux/interrupts.py +++ b/scripts/gdb/linux/interrupts.py @@ -37,7 +37,7 @@ def show_irq_desc(prec, irq): any_count = 0 if desc['kstat_irqs']: for cpu in cpus.each_online_cpu(): - any_count += cpus.per_cpu(desc['kstat_irqs'], cpu) + any_count += cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt'] if (desc['action'] == 0 or irq_desc_is_chained(desc)) and any_count == 0: return text; @@ -45,7 +45,7 @@ def show_irq_desc(prec, irq): text += "%*d: " % (prec, irq) for cpu in cpus.each_online_cpu(): if desc['kstat_irqs']: - count = cpus.per_cpu(desc['kstat_irqs'], cpu) + count = cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt'] else: count = 0 text += "%10u" % (count) @@ -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') @@ -177,7 +177,7 @@ def arm_common_show_interrupts(prec): if desc == 0: continue for cpu in cpus.each_online_cpu(): - text += "%10u" % (cpus.per_cpu(desc['kstat_irqs'], cpu)) + text += "%10u" % (cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt']) text += " %s" % (ipi_types[ipi].string()) text += "\n" return text 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/tasks.py b/scripts/gdb/linux/tasks.py index 6793d6e86e77..62348397c1f5 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -85,7 +85,7 @@ thread_info_type = utils.CachedType("struct thread_info") def get_thread_info(task): thread_info_ptr_type = thread_info_type.get_type().pointer() - if task.type.fields()[0].type == thread_info_type.get_type(): + if task_type.get_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/utils.py b/scripts/gdb/linux/utils.py index 7d5278d815fa..245ab297ea84 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py @@ -196,7 +196,7 @@ def get_gdbserver_type(): def probe_kgdb(): try: thread_info = gdb.execute("info thread 2", to_string=True) - return "shadowCPU0" in thread_info + return "shadowCPU" in thread_info except gdb.error: return False 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_analyzer.py b/scripts/generate_rust_analyzer.py index fc52bc41d3e7..f270c7b0cf34 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -66,7 +66,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): append_crate( "alloc", - srctree / "rust" / "alloc" / "lib.rs", + sysroot_src / "alloc" / "src" / "lib.rs", ["core", "compiler_builtins"], cfg=crates_cfgs.get("alloc", []), ) diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 0da52b548ba5..641b713a033a 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -148,26 +148,29 @@ 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("RISCV") { + if cfg.has("64BIT") { + panic!("64-bit RISC-V uses the builtin rustc riscv64-unknown-none-elf target"); + } else { + panic!("32-bit RISC-V is an unsupported architecture"); + } + } 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", + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-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"); + panic!("loongarch uses the builtin rustc loongarch64-unknown-none-softfloat target"); } else { panic!("Unsupported architecture"); } diff --git a/scripts/genksyms/Makefile b/scripts/genksyms/Makefile index d6a422a63b6a..312edccda736 100644 --- a/scripts/genksyms/Makefile +++ b/scripts/genksyms/Makefile @@ -23,8 +23,8 @@ $(obj)/pars%.tab.c $(obj)/pars%.tab.h: $(src)/pars%.y FORCE endif # -I needed for generated C source to include headers in source tree -HOSTCFLAGS_parse.tab.o := -I $(srctree)/$(src) -HOSTCFLAGS_lex.lex.o := -I $(srctree)/$(src) +HOSTCFLAGS_parse.tab.o := -I $(src) +HOSTCFLAGS_lex.lex.o := -I $(src) # dependencies on generated files need to be listed explicitly $(obj)/lex.lex.o: $(obj)/parse.tab.h diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh index f7d9b114de8f..6bbccb43f7e7 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/m68k/include/uapi/asm/ptrace.h:CONFIG_COLDFIRE arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 653b92f6d4c8..47978efe4797 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -204,6 +204,11 @@ static int symbol_in_range(const struct sym_entry *s, return 0; } +static bool string_starts_with(const char *s, const char *prefix) +{ + return strncmp(s, prefix, strlen(prefix)) == 0; +} + static int symbol_valid(const struct sym_entry *s) { const char *name = sym_name(s); @@ -211,6 +216,14 @@ static int symbol_valid(const struct sym_entry *s) /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { + /* + * Symbols starting with __start and __stop are used to denote + * section boundaries, and should always be included: + */ + if (string_starts_with(name, "__start_") || + string_starts_with(name, "__stop_")) + return 1; + if (symbol_in_range(s, text_ranges, ARRAY_SIZE(text_ranges)) == 0) return 0; diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index ea1bf3b3dbde..a0a0be38cbdc 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -57,7 +57,7 @@ $(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rul PHONY += localmodconfig localyesconfig localyesconfig localmodconfig: $(obj)/conf - $(Q)$(PERL) $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)$(PERL) $(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ @@ -118,7 +118,7 @@ tinyconfig: # CHECK: -o cache_dir=<path> working? PHONY += testconfig testconfig: $(obj)/conf - $(Q)$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \ + $(Q)$(PYTHON3) -B -m pytest $(src)/tests \ -o cache_dir=$(abspath $(obj)/tests/.cache) \ $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no) clean-files += tests/.cache @@ -165,8 +165,8 @@ common-objs := confdata.o expr.o lexer.lex.o menu.o parser.tab.o \ preprocess.o symbol.o util.o $(obj)/lexer.lex.o: $(obj)/parser.tab.h -HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src) -HOSTCFLAGS_parser.tab.o := -I $(srctree)/$(src) +HOSTCFLAGS_lexer.lex.o := -I $(src) +HOSTCFLAGS_parser.tab.o := -I $(src) # conf: Used for defconfig, oldconfig and related targets hostprogs += conf 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 662a5e7c37c2..8ad2c52d9b1f 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; @@ -446,7 +446,7 @@ help: } } -static int conf_choice(struct menu *menu) +static void conf_choice(struct menu *menu) { struct symbol *sym, *def_sym; struct menu *child; @@ -459,19 +459,18 @@ static int conf_choice(struct menu *menu) sym_calc_value(sym); switch (sym_get_tristate_value(sym)) { case no: - return 1; case mod: - return 0; + return; case yes: break; } } else { switch (sym_get_tristate_value(sym)) { case no: - return 1; + return; case mod: printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); - return 0; + return; case yes: break; } @@ -497,9 +496,8 @@ static int conf_choice(struct menu *menu) printf("%*c", indent, '>'); } else printf("%*c", indent, ' '); - printf(" %d. %s", cnt, menu_get_prompt(child)); - if (child->sym->name) - printf(" (%s)", child->sym->name); + printf(" %d. %s (%s)", cnt, menu_get_prompt(child), + child->sym->name); if (!sym_has_value(child->sym)) printf(" (NEW)"); printf("\n"); @@ -552,12 +550,7 @@ 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; + return; } } diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index f53dcdd44597..387503daf0f7 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) { @@ -293,63 +296,12 @@ 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) -{ - size_t new_size = slen + 1; - - if (new_size > *n) { - new_size += LINE_GROWTH - 1; - new_size *= 2; - *lineptr = xrealloc(*lineptr, new_size); - *n = new_size; - } - - (*lineptr)[slen] = c; - - return 0; -} - -static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) -{ - char *line = *lineptr; - size_t slen = 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++; - } - } - -e_out: - line[slen-1] = '\0'; - *lineptr = line; - return -1; -} - /* like getline(), but the newline character is stripped away */ static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream) { ssize_t len; - len = compat_getline(lineptr, n, stream); + len = getline(lineptr, n, stream); if (len > 0 && (*lineptr)[len - 1] == '\n') { len--; @@ -371,7 +323,7 @@ int conf_read_simple(const char *name, int def) size_t line_asize = 0; char *p, *val; struct symbol *sym; - int i, def_flags; + int def_flags; const char *warn_unknown, *sym_name; warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS"); @@ -429,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)) @@ -538,7 +490,6 @@ int conf_read(const char *name) { struct symbol *sym; int conf_unsaved = 0; - int i; conf_set_changed(false); @@ -549,9 +500,9 @@ 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)) + if (sym_is_choice(sym)) continue; if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { /* check that calculated value agrees with saved value */ @@ -573,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 @@ -842,62 +793,39 @@ int conf_write_defconfig(const char *filename) sym_clear_all_valid(); - /* Traverse all menus to find all relevant symbols */ - menu = rootmenu.list; + menu_for_each_entry(menu) { + struct menu *choice; - 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; + continue; sym->flags &= ~SYMBOL_WRITE; /* If we cannot change the symbol - skip */ if (!sym_is_changeable(sym)) - goto next_menu; + continue; /* If symbol equals to default value - skip */ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) - goto next_menu; + continue; /* * If symbol is a choice value and equals to the * default for a choice - skip. - * But only if value is bool and equal to "y" and - * choice is not "optional". - * (If choice is "optional" then all values can be "n") */ - if (sym_is_choice_value(sym)) { - struct symbol *cs; + choice = sym_get_choice_menu(sym); + if (choice) { struct symbol *ds; - cs = prop_get_symbol(sym_get_choice_prop(sym)); - ds = sym_choice_default(cs); - if (!sym_is_optional(cs) && sym == ds) { + ds = sym_choice_default(choice->sym); + if (sym == ds) { if ((sym->type == S_BOOLEAN) && sym_get_tristate_value(sym) == yes) - goto next_menu; + continue; } } print_symbol_for_dotconfig(out, sym); } -next_menu: - if (menu->list != NULL) { - menu = menu->list; - } - else if (menu->next != NULL) { - menu = menu->next; - } else { - while ((menu = menu->parent)) { - if (menu->next != NULL) { - menu = menu->next; - break; - } - } - } } fclose(out); return 0; @@ -911,7 +839,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) @@ -959,7 +886,7 @@ int conf_write(const char *name) "# %s\n" "#\n", str); need_newline = false; - } else if (!(sym->flags & SYMBOL_CHOICE) && + } else if (!sym_is_choice(sym) && !(sym->flags & SYMBOL_WRITTEN)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) @@ -995,7 +922,7 @@ end_check: } fclose(out); - for_all_symbols(i, sym) + for_all_symbols(sym) sym->flags &= ~SYMBOL_WRITTEN; if (*tmpname) { @@ -1023,7 +950,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; @@ -1044,15 +970,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 */ @@ -1072,7 +992,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, '/'); @@ -1086,9 +1006,9 @@ 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) + if (sym_is_choice(sym)) continue; if (sym->flags & SYMBOL_WRITE) { if (sym->flags & SYMBOL_DEF_AUTO) { @@ -1152,7 +1072,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; @@ -1169,7 +1089,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); @@ -1192,7 +1112,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; @@ -1204,7 +1124,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.h b/scripts/kconfig/expr.h index 4a9a23b1b7e1..d965e427753e 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 @@ -77,12 +72,11 @@ enum { /* * Represents a configuration symbol. * - * Choices are represented as a special kind of symbol and have the - * SYMBOL_CHOICE bit set in 'flags'. + * Choices are represented as a special kind of symbol with null name. */ 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 +107,9 @@ struct symbol { */ tristate visible; + /* config entries associated with this symbol */ + struct list_head menus; + /* SYMBOL_* flags */ int flags; @@ -131,18 +128,13 @@ 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) */ #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ -#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ #define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ #define SYMBOL_CHANGED 0x0400 /* ? */ #define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */ -#define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */ #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ #define SYMBOL_WARNED 0x8000 /* warning has been issued */ @@ -157,7 +149,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 +186,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 +221,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 +249,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 +270,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/gconf.c b/scripts/kconfig/gconf.c index 9709aca3a30f..cc400ffe6615 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -18,8 +18,6 @@ #include <unistd.h> #include <time.h> -//#define DEBUG - enum { SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW }; @@ -71,39 +69,6 @@ static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); static gchar **fill_row(struct menu *menu); static void conf_changed(void); -/* Helping/Debugging Functions */ -#ifdef DEBUG -static const char *dbg_sym_flags(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val & SYMBOL_CONST) - strcat(buf, "const/"); - if (val & SYMBOL_CHECK) - strcat(buf, "check/"); - if (val & SYMBOL_CHOICE) - strcat(buf, "choice/"); - if (val & SYMBOL_CHOICEVAL) - strcat(buf, "choiceval/"); - if (val & SYMBOL_VALID) - strcat(buf, "valid/"); - if (val & SYMBOL_OPTIONAL) - strcat(buf, "optional/"); - if (val & SYMBOL_WRITE) - strcat(buf, "write/"); - if (val & SYMBOL_CHANGED) - strcat(buf, "changed/"); - if (val & SYMBOL_NO_WRITE) - strcat(buf, "no_write/"); - - buf[strlen(buf) - 1] = '\0'; - - return buf; -} -#endif - static void replace_button_icon(GladeXML *xml, GdkDrawable *window, GtkStyle *style, gchar *btn_name, gchar **xpm) { @@ -493,7 +458,7 @@ load_filename(GtkFileSelection * file_selector, gpointer user_data) if (conf_read(fn)) text_insert_msg("Error", "Unable to load configuration !"); else - display_tree(&rootmenu); + display_tree_part(); } void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) @@ -1082,15 +1047,13 @@ static gchar **fill_row(struct menu *menu) row[COL_NAME] = g_strdup(sym->name); sym_calc_value(sym); - sym->flags &= ~SYMBOL_CHANGED; + menu->flags &= ~MENU_CHANGED; if (sym_is_choice(sym)) { // parse childs for getting final value struct menu *child; struct symbol *def_sym = sym_get_choice_value(sym); struct menu *def_menu = NULL; - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); - for (child = menu->list; child; child = child->next) { if (menu_is_visible(child) && child->sym == def_sym) @@ -1100,6 +1063,11 @@ static gchar **fill_row(struct menu *menu) if (def_menu) row[COL_VALUE] = g_strdup(menu_get_prompt(def_menu)); + + if (sym_get_type(sym) == S_BOOLEAN) { + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + return row; + } } if (sym->flags & SYMBOL_CHOICEVAL) row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); @@ -1107,11 +1075,6 @@ static gchar **fill_row(struct menu *menu) stype = sym_get_type(sym); switch (stype) { case S_BOOLEAN: - if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) - row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); - if (sym_is_choice(sym)) - break; - /* fall through */ case S_TRISTATE: val = sym_get_tristate_value(sym); switch (val) { @@ -1268,12 +1231,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) else menu2 = NULL; // force adding of a first child -#ifdef DEBUG - printf("%*c%s | %s\n", indent, ' ', - menu1 ? menu_get_prompt(menu1) : "nil", - menu2 ? menu_get_prompt(menu2) : "nil"); -#endif - if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { @@ -1314,7 +1271,7 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) else goto reparse; // next child } - } else if (sym && (sym->flags & SYMBOL_CHANGED)) { + } else if (sym && (child1->flags & MENU_CHANGED)) { set_node(child2, menu1, fill_row(menu1)); } @@ -1330,7 +1287,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) /* Display the whole tree (single/split/full view) */ static void display_tree(struct menu *menu) { - struct symbol *sym; struct property *prop; struct menu *child; enum prop_type ptype; @@ -1342,11 +1298,9 @@ static void display_tree(struct menu *menu) for (child = menu->list; child; child = child->next) { prop = child->prompt; - sym = child->sym; ptype = prop ? prop->type : P_UNKNOWN; - if (sym) - sym->flags &= ~SYMBOL_CHANGED; + menu->flags &= ~MENU_CHANGED; if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) && (tree == tree1)) @@ -1360,19 +1314,7 @@ static void display_tree(struct menu *menu) (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || (opt_mode == OPT_ALL && menu_get_prompt(child))) place_node(child, fill_row(child)); -#ifdef DEBUG - printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); - printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); - printf("%s", prop_get_type_name(ptype)); - printf(" | "); - if (sym) { - printf("%s", sym_type_name(sym->type)); - printf(" | "); - printf("%s", dbg_sym_flags(sym->flags)); - printf("\n"); - } else - printf("\n"); -#endif + if ((view_mode != FULL_VIEW) && (ptype == P_MENU) && (tree == tree2)) continue; @@ -1405,6 +1347,8 @@ static void display_tree_part(void) display_tree(current); else if (view_mode == SPLIT_VIEW) display_tree(browsed); + else if (view_mode == FULL_VIEW) + display_tree(&rootmenu); gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); } 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..8dd597c4710d 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); } %} @@ -111,7 +120,6 @@ n [A-Za-z0-9_-] "menuconfig" return T_MENUCONFIG; "modules" return T_MODULES; "on" return T_ON; -"optional" return T_OPTIONAL; "prompt" return T_PROMPT; "range" return T_RANGE; "select" return T_SELECT; @@ -180,7 +188,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 +254,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 +275,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 +308,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 +400,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 5cdc8f5e6446..64dfc354dd5c 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); @@ -79,6 +79,11 @@ void str_printf(struct gstr *gs, const char *fmt, ...); char *str_get(struct gstr *gs); /* menu.c */ +struct menu *menu_next(struct menu *menu, struct menu *root); +#define menu_for_each_sub_entry(menu, root) \ + for (menu = menu_next(root, root); menu; menu = menu_next(menu, root)) +#define menu_for_each_entry(menu) \ + menu_for_each_sub_entry(menu, &rootmenu) void _menu_init(void); void menu_warn(struct menu *menu, const char *fmt, ...); struct menu *menu_add_menu(void); @@ -89,7 +94,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; @@ -124,7 +129,8 @@ static inline struct symbol *sym_get_choice_value(struct symbol *sym) static inline bool sym_is_choice(struct symbol *sym) { - return sym->flags & SYMBOL_CHOICE ? true : false; + /* A choice is a symbol with no name */ + return sym->name == NULL; } static inline bool sym_is_choice_value(struct symbol *sym) @@ -132,11 +138,6 @@ static inline bool sym_is_choice_value(struct symbol *sym) return sym->flags & SYMBOL_CHOICEVAL ? true : false; } -static inline bool sym_is_optional(struct symbol *sym) -{ - return sym->flags & SYMBOL_OPTIONAL ? true : false; -} - static inline bool sym_has_value(struct symbol *sym) { return sym->flags & SYMBOL_DEF_USER ? true : false; diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index a4ae5e9eadad..d76aaf4ea117 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -18,8 +18,6 @@ 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); @@ -36,23 +34,11 @@ bool sym_string_within_range(struct symbol *sym, const char *str); bool sym_set_string_value(struct symbol *sym, const char *newval); bool sym_is_changeable(struct symbol *sym); struct property * sym_get_choice_prop(struct symbol *sym); +struct menu *sym_get_choice_menu(struct symbol *sym); 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); 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..964139c87fcb 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -17,26 +17,13 @@ struct dialog_info dlg; static void set_mono_theme(void) { - dlg.screen.atr = A_NORMAL; - dlg.shadow.atr = A_NORMAL; - dlg.dialog.atr = A_NORMAL; dlg.title.atr = A_BOLD; - dlg.border.atr = A_NORMAL; dlg.button_active.atr = A_REVERSE; dlg.button_inactive.atr = A_DIM; dlg.button_key_active.atr = A_REVERSE; dlg.button_key_inactive.atr = A_BOLD; 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; - dlg.item.atr = A_NORMAL; dlg.item_selected.atr = A_REVERSE; dlg.tag.atr = A_BOLD; dlg.tag_selected.atr = A_REVERSE; @@ -69,10 +56,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 +84,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 +114,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 +166,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 +282,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 5df32148a869..d6a61ca1a984 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -19,6 +19,7 @@ #include <signal.h> #include <unistd.h> +#include "list.h" #include "lkc.h" #include "lxdialog/dialog.h" #include "mnconf-common.h" @@ -524,19 +525,12 @@ static void build_conf(struct menu *menu) val = sym_get_tristate_value(sym); if (sym_is_changeable(sym)) { - switch (type) { - case S_BOOLEAN: - item_make("[%c]", val == no ? ' ' : '*'); - break; - case S_TRISTATE: - switch (val) { - case yes: ch = '*'; break; - case mod: ch = 'M'; break; - default: ch = ' '; break; - } - item_make("<%c>", ch); - break; + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; } + item_make("<%c>", ch); item_set_tag('t'); item_set_data(menu); } else { @@ -547,15 +541,8 @@ static void build_conf(struct menu *menu) item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); if (val == yes) { - if (def_menu) { - item_add_str(" (%s)", menu_get_prompt(def_menu)); - item_add_str(" --->"); - if (def_menu->list) { - indent += 2; - build_conf(def_menu); - indent -= 2; - } - } + if (def_menu) + item_add_str(" (%s) --->", menu_get_prompt(def_menu)); return; } } else { @@ -567,49 +554,43 @@ static void build_conf(struct menu *menu) } child_count++; val = sym_get_tristate_value(sym); - if (sym_is_choice_value(sym) && val == yes) { - item_make(" "); - item_set_tag(':'); + switch (type) { + case S_BOOLEAN: + if (sym_is_changeable(sym)) + item_make("[%c]", val == no ? ' ' : '*'); + else + item_make("-%c-", val == no ? ' ' : '*'); + item_set_tag('t'); item_set_data(menu); - } else { - switch (type) { - case S_BOOLEAN: - if (sym_is_changeable(sym)) - item_make("[%c]", val == no ? ' ' : '*'); - else - item_make("-%c-", val == no ? ' ' : '*'); - item_set_tag('t'); - item_set_data(menu); - break; - case S_TRISTATE: - switch (val) { - case yes: ch = '*'; break; - case mod: ch = 'M'; break; - default: ch = ' '; break; - } - if (sym_is_changeable(sym)) { - if (sym->rev_dep.tri == mod) - item_make("{%c}", ch); - else - item_make("<%c>", ch); - } else - item_make("-%c-", ch); - item_set_tag('t'); - item_set_data(menu); - break; - default: - tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ - item_make("(%s)", sym_get_string_value(sym)); - tmp = indent - tmp + 4; - if (tmp < 0) - tmp = 0; - item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), - (sym_has_value(sym) || !sym_is_changeable(sym)) ? - "" : " (NEW)"); - item_set_tag('s'); - item_set_data(menu); - goto conf_childs; + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; } + if (sym_is_changeable(sym)) { + if (sym->rev_dep.tri == mod) + item_make("{%c}", ch); + else + item_make("<%c>", ch); + } else + item_make("-%c-", ch); + item_set_tag('t'); + item_set_data(menu); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ + item_make("(%s)", sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), + (sym_has_value(sym) || !sym_is_changeable(sym)) ? + "" : " (NEW)"); + item_set_tag('s'); + item_set_data(menu); + goto conf_childs; } item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), (sym_has_value(sym) || !sym_is_changeable(sym)) ? @@ -658,9 +639,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 2cce8b651f61..53151c5a6028 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -10,20 +10,39 @@ #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; +/** + * menu_next - return the next menu entry with depth-first traversal + * @menu: pointer to the current menu + * @root: root of the sub-tree to traverse. If NULL is given, the traveral + * continues until it reaches the end of the entire menu tree. + * return: the menu to visit next, or NULL when it reaches the end. + */ +struct menu *menu_next(struct menu *menu, struct menu *root) +{ + if (menu->list) + return menu->list; + + while (menu != root && !menu->next) + menu = menu->parent; + + if (menu == root) + return NULL; + + return menu->next; +} 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 +52,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 +72,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 +155,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; @@ -242,11 +263,9 @@ static void sym_check_prop(struct symbol *sym) sym->name); } if (sym_is_choice(sym)) { - struct property *choice_prop = - sym_get_choice_prop(sym2); + struct menu *choice = sym_get_choice_menu(sym2); - if (!choice_prop || - prop_get_symbol(choice_prop) != sym) + if (!choice || choice->sym != sym) prop_warn(prop, "choice default symbol '%s' is not contained in the choice", sym2->name); @@ -282,7 +301,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 +315,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 +331,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 +418,7 @@ void menu_finalize(struct menu *parent) } } - if (sym && sym_is_choice(sym)) + if (is_choice) expr_free(parentdep); /* @@ -408,8 +426,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 +487,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; } @@ -487,18 +505,6 @@ void menu_finalize(struct menu *parent) menu->sym && !sym_is_choice_value(menu->sym)) { current_entry = menu; menu->sym->flags |= SYMBOL_CHOICEVAL; - if (!menu->prompt) - menu_warn(menu, "choice value must have a prompt"); - for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->type == P_DEFAULT) - prop_warn(prop, "defaults for choice " - "values not supported"); - if (prop->menu == menu) - continue; - if (prop->type == P_PROMPT && - prop->menu->parent->sym != sym) - prop_warn(prop, "choice value used outside its choice group"); - } /* Non-tristate choice values of tristate choices must * depend on the choice being set to Y. The choice * values' dependencies were propagated to their @@ -567,30 +573,28 @@ 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; } /* - * For non-optional choices, add a reverse dependency (corresponding to - * a select) of '<visibility> && m'. This prevents the user from - * setting the choice mode to 'n' when the choice is visible. - * - * This would also work for non-choice symbols, but only non-optional - * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented - * as a type of symbol. + * For choices, add a reverse dependency (corresponding to a select) of + * '<visibility> && m'. This prevents the user from setting the choice + * mode to 'n' when the choice is visible. */ - if (sym && !sym_is_optional(sym) && parent->prompt) { + if (sym && sym_is_choice(sym) && parent->prompt) { sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, expr_alloc_and(parent->prompt->visible.expr, expr_alloc_symbol(&symbol_mod))); } } +void menu_finalize(void) +{ + _menu_finalize(&rootmenu, false); +} + bool menu_has_prompt(struct menu *menu) { if (!menu->prompt) @@ -676,7 +680,7 @@ struct menu *menu_get_parent_menu(struct menu *menu) 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) @@ -777,6 +781,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, @@ -793,17 +798,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: "); } } diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 1148163cfa7e..e1cb09418cbe 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -11,6 +11,7 @@ #include <strings.h> #include <stdlib.h> +#include "list.h" #include "lkc.h" #include "mnconf-common.h" #include "nconf.h" @@ -825,26 +826,18 @@ static void build_conf(struct menu *menu) val = sym_get_tristate_value(sym); if (sym_is_changeable(sym)) { - switch (type) { - case S_BOOLEAN: - item_make(menu, 't', "[%c]", - val == no ? ' ' : '*'); + switch (val) { + case yes: + ch = '*'; break; - case S_TRISTATE: - switch (val) { - case yes: - ch = '*'; - break; - case mod: - ch = 'M'; - break; - default: - ch = ' '; - break; - } - item_make(menu, 't', "<%c>", ch); + case mod: + ch = 'M'; + break; + default: + ch = ' '; break; } + item_make(menu, 't', "<%c>", ch); } else { item_make(menu, def_menu ? 't' : ':', " "); } @@ -852,16 +845,8 @@ static void build_conf(struct menu *menu) item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); if (val == yes) { - if (def_menu) { - item_add_str(" (%s)", - menu_get_prompt(def_menu)); - item_add_str(" --->"); - if (def_menu->list) { - indent += 2; - build_conf(def_menu); - indent -= 2; - } - } + if (def_menu) + item_add_str(" (%s) --->", menu_get_prompt(def_menu)); return; } } else { @@ -873,54 +858,46 @@ static void build_conf(struct menu *menu) } child_count++; val = sym_get_tristate_value(sym); - if (sym_is_choice_value(sym) && val == yes) { - item_make(menu, ':', " "); - } else { - switch (type) { - case S_BOOLEAN: - if (sym_is_changeable(sym)) - item_make(menu, 't', "[%c]", - val == no ? ' ' : '*'); - else - item_make(menu, 't', "-%c-", - val == no ? ' ' : '*'); + switch (type) { + case S_BOOLEAN: + if (sym_is_changeable(sym)) + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + else + item_make(menu, 't', "-%c-", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; break; - case S_TRISTATE: - switch (val) { - case yes: - ch = '*'; - break; - case mod: - ch = 'M'; - break; - default: - ch = ' '; - break; - } - if (sym_is_changeable(sym)) { - if (sym->rev_dep.tri == mod) - item_make(menu, - 't', "{%c}", ch); - else - item_make(menu, - 't', "<%c>", ch); - } else - item_make(menu, 't', "-%c-", ch); + case mod: + ch = 'M'; break; default: - tmp = 2 + strlen(sym_get_string_value(sym)); - item_make(menu, 's', " (%s)", - sym_get_string_value(sym)); - tmp = indent - tmp + 4; - if (tmp < 0) - tmp = 0; - item_add_str("%*c%s%s", tmp, ' ', - menu_get_prompt(menu), - (sym_has_value(sym) || - !sym_is_changeable(sym)) ? "" : - " (NEW)"); - goto conf_childs; + ch = ' '; + break; } + if (sym_is_changeable(sym)) { + if (sym->rev_dep.tri == mod) + item_make(menu, 't', "{%c}", ch); + else + item_make(menu, 't', "<%c>", ch); + } else + item_make(menu, 't', "-%c-", ch); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); + item_make(menu, 's', " (%s)", + sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), + (sym_has_value(sym) || + !sym_is_changeable(sym)) ? "" : " (NEW)"); + goto conf_childs; } item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 2af7ce4e1531..ff709001b1f0 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,10 +28,10 @@ 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; +static bool inside_choice = false; + %} %union @@ -70,7 +71,6 @@ struct menu *current_menu, *current_entry; %token T_MODULES %token T_ON %token T_OPEN_PAREN -%token T_OPTIONAL %token T_PLUS_EQUAL %token T_PROMPT %token T_RANGE @@ -95,12 +95,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 @@ -141,21 +141,27 @@ stmt_list_in_choice: 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()); + if (inside_choice) { + if (!current_entry->prompt) { + fprintf(stderr, "%s:%d: error: choice member must have a prompt\n", + current_entry->filename, current_entry->lineno); + yynerrs++; + } + } + + 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 +170,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 +183,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 +197,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,26 +229,35 @@ 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); - sym->flags |= SYMBOL_NO_WRITE; + struct symbol *sym = sym_lookup(NULL, 0); + 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(); + + inside_choice = true; }; choice_end: end { + inside_choice = false; + 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 +274,19 @@ 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); -}; - -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:type(%u)\n", cur_filename, cur_lineno, $1); }; 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 +308,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 +318,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 +334,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 +346,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 +361,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 +372,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 +387,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 +412,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 +459,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); } @@ -475,10 +476,45 @@ assign_val: %% +/** + * choice_check_sanity - check sanity of a choice member + * + * @menu: menu of the choice member + * + * Return: -1 if an error is found, 0 otherwise. + */ +static int choice_check_sanity(struct menu *menu) +{ + struct property *prop; + int ret = 0; + + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->type == P_DEFAULT) { + fprintf(stderr, "%s:%d: error: %s", + prop->filename, prop->lineno, + "defaults for choice values not supported\n"); + ret = -1; + } + + if (prop->menu != menu && prop->type == P_PROMPT && + prop->menu->parent != menu->parent) { + fprintf(stderr, "%s:%d: error: %s", + prop->filename, prop->lineno, + "choice value has a prompt outside its choice group\n"); + ret = -1; + } + } + + return ret; +} + 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 +524,49 @@ 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_for_each_entry(menu) { + struct menu *child; + + if (menu->sym && sym_check_deps(menu->sym)) yynerrs++; + + if (menu->sym && sym_is_choice(menu->sym)) { + menu_for_each_sub_entry(child, menu) + if (child->sym && choice_check_sanity(child)) + yynerrs++; + } } + if (yynerrs) exit(1); conf_set_changed(true); @@ -520,11 +581,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 +597,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 +609,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 +618,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 e9e9fb8d8674..aa0e25ee5119 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -9,23 +9,27 @@ #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, }; @@ -74,6 +78,41 @@ struct property *sym_get_choice_prop(struct symbol *sym) return NULL; } +/** + * sym_get_choice_menu - get the parent choice menu if present + * + * @sym: a symbol pointer + * + * Return: a choice menu if this function is called against a choice member. + */ +struct menu *sym_get_choice_menu(struct symbol *sym) +{ + struct menu *menu = NULL; + struct menu *m; + + /* + * Choice members must have a prompt. Find a menu entry with a prompt, + * and assume it resides inside a choice block. + */ + list_for_each_entry(m, &sym->menus, link) + if (m->prompt) { + menu = m; + break; + } + + if (!menu) + return NULL; + + do { + menu = menu->parent; + } while (menu && !menu->sym); + + if (menu && menu->sym && sym_is_choice(menu->sym)) + return menu; + + return NULL; +} + static struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; @@ -148,21 +187,18 @@ static void sym_validate_range(struct symbol *sym) static void sym_set_changed(struct symbol *sym) { - struct property *prop; + struct menu *menu; sym->flags |= SYMBOL_CHANGED; - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu) - prop->menu->flags |= MENU_CHANGED; - } + list_for_each_entry(menu, &sym->menus, link) + menu->flags |= MENU_CHANGED; } 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); } @@ -463,10 +499,9 @@ void sym_calc_value(struct symbol *sym) if (sym->flags & SYMBOL_CHANGED) sym_set_changed(choice_sym); } - } - if (sym->flags & SYMBOL_NO_WRITE) sym->flags &= ~SYMBOL_WRITE; + } if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) set_all_choice_values(sym); @@ -475,9 +510,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); @@ -803,14 +837,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) { @@ -826,13 +853,13 @@ 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 - : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) + : !(symbol->flags & SYMBOL_CONST))) return symbol; } new_name = xstrdup(name); @@ -846,9 +873,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; } @@ -868,9 +895,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)) @@ -930,7 +957,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)) @@ -1041,42 +1068,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>"); @@ -1177,16 +1204,18 @@ out: static struct symbol *sym_check_choice_deps(struct symbol *choice) { - struct symbol *sym, *sym2; - struct property *prop; - struct expr *e; + struct menu *choice_menu, *menu; + struct symbol *sym2; struct dep_stack stack; dep_stack_insert(&stack, choice); - prop = sym_get_choice_prop(choice); - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + choice_menu = list_first_entry(&choice->menus, struct menu, link); + + menu_for_each_sub_entry(menu, choice_menu) { + if (menu->sym) + menu->sym->flags |= SYMBOL_CHECK | SYMBOL_CHECKED; + } choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); sym2 = sym_check_sym_deps(choice); @@ -1194,14 +1223,17 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice) if (sym2) goto out; - expr_list_for_each_sym(prop->expr, e, sym) { - sym2 = sym_check_sym_deps(sym); + menu_for_each_sub_entry(menu, choice_menu) { + if (!menu->sym) + continue; + sym2 = sym_check_sym_deps(menu->sym); if (sym2) break; } out: - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags &= ~SYMBOL_CHECK; + menu_for_each_sub_entry(menu, choice_menu) + if (menu->sym) + menu->sym->flags &= ~SYMBOL_CHECK; if (sym2 && sym_is_choice_value(sym2) && prop_get_symbol(sym_get_choice_prop(sym2)) == choice) diff --git a/scripts/kconfig/tests/choice/Kconfig b/scripts/kconfig/tests/choice/Kconfig index 0930eb65e932..8cdda40868a1 100644 --- a/scripts/kconfig/tests/choice/Kconfig +++ b/scripts/kconfig/tests/choice/Kconfig @@ -18,19 +18,6 @@ config BOOL_CHOICE1 endchoice choice - prompt "optional boolean choice" - optional - default OPT_BOOL_CHOICE1 - -config OPT_BOOL_CHOICE0 - bool "choice 0" - -config OPT_BOOL_CHOICE1 - bool "choice 1" - -endchoice - -choice prompt "tristate choice" default TRI_CHOICE1 @@ -41,16 +28,3 @@ config TRI_CHOICE1 tristate "choice 1" endchoice - -choice - prompt "optional tristate choice" - optional - default OPT_TRI_CHOICE1 - -config OPT_TRI_CHOICE0 - tristate "choice 0" - -config OPT_TRI_CHOICE1 - tristate "choice 1" - -endchoice diff --git a/scripts/kconfig/tests/choice/__init__.py b/scripts/kconfig/tests/choice/__init__.py index 4318fce05912..05e162220085 100644 --- a/scripts/kconfig/tests/choice/__init__.py +++ b/scripts/kconfig/tests/choice/__init__.py @@ -6,8 +6,6 @@ The handling of 'choice' is a bit complicated part in Kconfig. The behavior of 'y' choice is intuitive. If choice values are tristate, the choice can be 'm' where each value can be enabled independently. -Also, if a choice is marked as 'optional', the whole choice can be -invisible. """ diff --git a/scripts/kconfig/tests/choice/allmod_expected_config b/scripts/kconfig/tests/choice/allmod_expected_config index f1f5dcdb7923..d1f51651740c 100644 --- a/scripts/kconfig/tests/choice/allmod_expected_config +++ b/scripts/kconfig/tests/choice/allmod_expected_config @@ -1,9 +1,5 @@ CONFIG_MODULES=y # CONFIG_BOOL_CHOICE0 is not set CONFIG_BOOL_CHOICE1=y -# CONFIG_OPT_BOOL_CHOICE0 is not set -CONFIG_OPT_BOOL_CHOICE1=y CONFIG_TRI_CHOICE0=m CONFIG_TRI_CHOICE1=m -CONFIG_OPT_TRI_CHOICE0=m -CONFIG_OPT_TRI_CHOICE1=m diff --git a/scripts/kconfig/tests/choice/allyes_expected_config b/scripts/kconfig/tests/choice/allyes_expected_config index e5a062a1157c..8a76c1816893 100644 --- a/scripts/kconfig/tests/choice/allyes_expected_config +++ b/scripts/kconfig/tests/choice/allyes_expected_config @@ -1,9 +1,5 @@ CONFIG_MODULES=y # CONFIG_BOOL_CHOICE0 is not set CONFIG_BOOL_CHOICE1=y -# CONFIG_OPT_BOOL_CHOICE0 is not set -CONFIG_OPT_BOOL_CHOICE1=y # CONFIG_TRI_CHOICE0 is not set CONFIG_TRI_CHOICE1=y -# CONFIG_OPT_TRI_CHOICE0 is not set -CONFIG_OPT_TRI_CHOICE1=y diff --git a/scripts/kconfig/tests/choice/oldask0_expected_stdout b/scripts/kconfig/tests/choice/oldask0_expected_stdout index b251bba9698b..d2257db46423 100644 --- a/scripts/kconfig/tests/choice/oldask0_expected_stdout +++ b/scripts/kconfig/tests/choice/oldask0_expected_stdout @@ -3,8 +3,6 @@ boolean choice 1. choice 0 (BOOL_CHOICE0) (NEW) > 2. choice 1 (BOOL_CHOICE1) (NEW) choice[1-2?]: -optional boolean choice [N/y/?] (NEW) tristate choice [M/y/?] (NEW) choice 0 (TRI_CHOICE0) [N/m/?] (NEW) choice 1 (TRI_CHOICE1) [N/m/?] (NEW) -optional tristate choice [N/m/y/?] (NEW) diff --git a/scripts/kconfig/tests/choice/oldask1_config b/scripts/kconfig/tests/choice/oldask1_config index b67bfe3c641f..0f417856c81c 100644 --- a/scripts/kconfig/tests/choice/oldask1_config +++ b/scripts/kconfig/tests/choice/oldask1_config @@ -1,2 +1 @@ # CONFIG_MODULES is not set -CONFIG_OPT_BOOL_CHOICE0=y diff --git a/scripts/kconfig/tests/choice/oldask1_expected_stdout b/scripts/kconfig/tests/choice/oldask1_expected_stdout index c2125e9bf96a..ffa20ad7f38e 100644 --- a/scripts/kconfig/tests/choice/oldask1_expected_stdout +++ b/scripts/kconfig/tests/choice/oldask1_expected_stdout @@ -3,13 +3,7 @@ boolean choice 1. choice 0 (BOOL_CHOICE0) (NEW) > 2. choice 1 (BOOL_CHOICE1) (NEW) choice[1-2?]: -optional boolean choice [Y/n/?] (NEW) -optional boolean choice -> 1. choice 0 (OPT_BOOL_CHOICE0) - 2. choice 1 (OPT_BOOL_CHOICE1) (NEW) -choice[1-2?]: tristate choice 1. choice 0 (TRI_CHOICE0) (NEW) > 2. choice 1 (TRI_CHOICE1) (NEW) choice[1-2?]: -optional tristate choice [N/y/?] 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 92e5b2b9761d..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 */ diff --git a/scripts/kernel-doc b/scripts/kernel-doc index e8aefd258a29..95a59ac78f82 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; @@ -61,10 +62,10 @@ my $anon_struct_union = 0; # match expressions used to find embedded type information my $type_constant = '\b``([^\`]+)``\b'; -my $type_constant2 = '\%([-_\w]+)'; +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; + $Wreturn = 1; } elsif ($cmd eq "Wshort-desc" or $cmd eq "Wshort-description") { - $Wshort_desc = 1; + $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,203 +1119,204 @@ 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*__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; + 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*__counted_by_(le|be)\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\s*\(([^,]*,){2}/STRUCT_GROUP(/gos; + $members =~ s/\bstruct_group_tagged\s*\(([^,]*),([^,]*),/struct $1 $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($$) { @@ -1330,65 +1330,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; } } @@ -1407,59 +1407,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; } } @@ -1482,214 +1481,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; - } - 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; + 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"); - } - elsif (($decl_type eq "struct") or - ($decl_type eq "union")) { - emit_warning("${file}:$.", - "Excess $decl_type member " . - "'$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"); + } } ## @@ -1720,6 +1725,7 @@ sub dump_function($$) { $prototype =~ s/__must_check +//; $prototype =~ s/__weak +//; $prototype =~ s/__sched +//; + $prototype =~ s/_noprof//; $prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//; $prototype =~ s/__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +//; $prototype =~ s/__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +//; @@ -1764,21 +1770,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; @@ -1790,38 +1796,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 + }); } } @@ -1841,64 +1847,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($$) { @@ -1907,32 +1913,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(); } } @@ -1946,28 +1951,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; + } } } @@ -1977,13 +1982,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; @@ -1994,20 +1999,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); @@ -2020,9 +2025,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; } } @@ -2034,80 +2039,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; } } @@ -2119,102 +2124,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 - $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; + $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: $_"); } } @@ -2226,21 +2231,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); } } @@ -2251,23 +2256,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"; + } } } @@ -2279,37 +2284,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: $_"); + } } } @@ -2322,54 +2327,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(); @@ -2386,14 +2390,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 || @@ -2402,8 +2406,8 @@ if ($output_selection == OUTPUT_EXPORTED || push(@export_file_list, @ARGV); foreach (@export_file_list) { - chomp; - process_export_file($_); + chomp; + process_export_file($_); } } @@ -2412,10 +2416,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/make_fit.py b/scripts/make_fit.py new file mode 100755 index 000000000000..3de90c5a094b --- /dev/null +++ b/scripts/make_fit.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2024 Google LLC +# Written by Simon Glass <sjg@chromium.org> +# + +"""Build a FIT containing a lot of devicetree files + +Usage: + make_fit.py -A arm64 -n 'Linux-6.6' -O linux + -o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk + @arch/arm64/boot/dts/dtbs-list -E -c gzip + +Creates a FIT containing the supplied kernel and a set of devicetree files, +either specified individually or listed in a file (with an '@' prefix). + +Use -E to generate an external FIT (where the data is placed after the +FIT data structure). This allows parsing of the data without loading +the entire FIT. + +Use -c to compress the data, using bzip2, gzip, lz4, lzma, lzo and +zstd algorithms. + +The resulting FIT can be booted by bootloaders which support FIT, such +as U-Boot, Linuxboot, Tianocore, etc. + +Note that this tool does not yet support adding a ramdisk / initrd. +""" + +import argparse +import collections +import os +import subprocess +import sys +import tempfile +import time + +import libfdt + + +# Tool extension and the name of the command-line tools +CompTool = collections.namedtuple('CompTool', 'ext,tools') + +COMP_TOOLS = { + 'bzip2': CompTool('.bz2', 'bzip2'), + 'gzip': CompTool('.gz', 'pigz,gzip'), + 'lz4': CompTool('.lz4', 'lz4'), + 'lzma': CompTool('.lzma', 'lzma'), + 'lzo': CompTool('.lzo', 'lzop'), + 'zstd': CompTool('.zstd', 'zstd'), +} + + +def parse_args(): + """Parse the program ArgumentParser + + Returns: + Namespace object containing the arguments + """ + epilog = 'Build a FIT from a directory tree containing .dtb files' + parser = argparse.ArgumentParser(epilog=epilog, fromfile_prefix_chars='@') + parser.add_argument('-A', '--arch', type=str, required=True, + help='Specifies the architecture') + parser.add_argument('-c', '--compress', type=str, default='none', + help='Specifies the compression') + parser.add_argument('-E', '--external', action='store_true', + help='Convert the FIT to use external data') + parser.add_argument('-n', '--name', type=str, required=True, + help='Specifies the name') + parser.add_argument('-o', '--output', type=str, required=True, + help='Specifies the output file (.fit)') + parser.add_argument('-O', '--os', type=str, required=True, + help='Specifies the operating system') + parser.add_argument('-k', '--kernel', type=str, required=True, + help='Specifies the (uncompressed) kernel input file (.itk)') + parser.add_argument('-v', '--verbose', action='store_true', + help='Enable verbose output') + parser.add_argument('dtbs', type=str, nargs='*', + help='Specifies the devicetree files to process') + + return parser.parse_args() + + +def setup_fit(fsw, name): + """Make a start on writing the FIT + + Outputs the root properties and the 'images' node + + Args: + fsw (libfdt.FdtSw): Object to use for writing + name (str): Name of kernel image + """ + fsw.INC_SIZE = 65536 + fsw.finish_reservemap() + fsw.begin_node('') + fsw.property_string('description', f'{name} with devicetree set') + fsw.property_u32('#address-cells', 1) + + fsw.property_u32('timestamp', int(time.time())) + fsw.begin_node('images') + + +def write_kernel(fsw, data, args): + """Write out the kernel image + + Writes a kernel node along with the required properties + + Args: + fsw (libfdt.FdtSw): Object to use for writing + data (bytes): Data to write (possibly compressed) + args (Namespace): Contains necessary strings: + arch: FIT architecture, e.g. 'arm64' + fit_os: Operating Systems, e.g. 'linux' + name: Name of OS, e.g. 'Linux-6.6.0-rc7' + compress: Compression algorithm to use, e.g. 'gzip' + """ + with fsw.add_node('kernel'): + fsw.property_string('description', args.name) + fsw.property_string('type', 'kernel_noload') + fsw.property_string('arch', args.arch) + fsw.property_string('os', args.os) + fsw.property_string('compression', args.compress) + fsw.property('data', data) + fsw.property_u32('load', 0) + fsw.property_u32('entry', 0) + + +def finish_fit(fsw, entries): + """Finish the FIT ready for use + + Writes the /configurations node and subnodes + + Args: + fsw (libfdt.FdtSw): Object to use for writing + entries (list of tuple): List of configurations: + str: Description of model + str: Compatible stringlist + """ + fsw.end_node() + seq = 0 + with fsw.add_node('configurations'): + for model, compat in entries: + seq += 1 + with fsw.add_node(f'conf-{seq}'): + fsw.property('compatible', bytes(compat)) + fsw.property_string('description', model) + fsw.property_string('fdt', f'fdt-{seq}') + fsw.property_string('kernel', 'kernel') + fsw.end_node() + + +def compress_data(inf, compress): + """Compress data using a selected algorithm + + Args: + inf (IOBase): Filename containing the data to compress + compress (str): Compression algorithm, e.g. 'gzip' + + Return: + bytes: Compressed data + """ + if compress == 'none': + return inf.read() + + comp = COMP_TOOLS.get(compress) + if not comp: + raise ValueError(f"Unknown compression algorithm '{compress}'") + + with tempfile.NamedTemporaryFile() as comp_fname: + with open(comp_fname.name, 'wb') as outf: + done = False + for tool in comp.tools.split(','): + try: + subprocess.call([tool, '-c'], stdin=inf, stdout=outf) + done = True + break + except FileNotFoundError: + pass + if not done: + raise ValueError(f'Missing tool(s): {comp.tools}\n') + with open(comp_fname.name, 'rb') as compf: + comp_data = compf.read() + return comp_data + + +def output_dtb(fsw, seq, fname, arch, compress): + """Write out a single devicetree to the FIT + + Args: + fsw (libfdt.FdtSw): Object to use for writing + seq (int): Sequence number (1 for first) + fmame (str): Filename containing the DTB + arch: FIT architecture, e.g. 'arm64' + compress (str): Compressed algorithm, e.g. 'gzip' + + Returns: + tuple: + str: Model name + bytes: Compatible stringlist + """ + with fsw.add_node(f'fdt-{seq}'): + # Get the compatible / model information + with open(fname, 'rb') as inf: + data = inf.read() + fdt = libfdt.FdtRo(data) + model = fdt.getprop(0, 'model').as_str() + compat = fdt.getprop(0, 'compatible') + + fsw.property_string('description', model) + fsw.property_string('type', 'flat_dt') + fsw.property_string('arch', arch) + fsw.property_string('compression', compress) + fsw.property('compatible', bytes(compat)) + + with open(fname, 'rb') as inf: + compressed = compress_data(inf, compress) + fsw.property('data', compressed) + return model, compat + + +def build_fit(args): + """Build the FIT from the provided files and arguments + + Args: + args (Namespace): Program arguments + + Returns: + tuple: + bytes: FIT data + int: Number of configurations generated + size: Total uncompressed size of data + """ + seq = 0 + size = 0 + fsw = libfdt.FdtSw() + setup_fit(fsw, args.name) + entries = [] + + # Handle the kernel + with open(args.kernel, 'rb') as inf: + comp_data = compress_data(inf, args.compress) + size += os.path.getsize(args.kernel) + write_kernel(fsw, comp_data, args) + + for fname in args.dtbs: + # Ignore overlay (.dtbo) files + if os.path.splitext(fname)[1] == '.dtb': + seq += 1 + size += os.path.getsize(fname) + model, compat = output_dtb(fsw, seq, fname, args.arch, args.compress) + entries.append([model, compat]) + + finish_fit(fsw, entries) + + # Include the kernel itself in the returned file count + return fsw.as_fdt().as_bytearray(), seq + 1, size + + +def run_make_fit(): + """Run the tool's main logic""" + args = parse_args() + + out_data, count, size = build_fit(args) + with open(args.output, 'wb') as outf: + outf.write(out_data) + + ext_fit_size = None + if args.external: + mkimage = os.environ.get('MKIMAGE', 'mkimage') + subprocess.check_call([mkimage, '-E', '-F', args.output], + stdout=subprocess.DEVNULL) + + with open(args.output, 'rb') as inf: + data = inf.read() + ext_fit = libfdt.FdtRo(data) + ext_fit_size = ext_fit.totalsize() + + if args.verbose: + comp_size = len(out_data) + print(f'FIT size {comp_size:#x}/{comp_size / 1024 / 1024:.1f} MB', + end='') + if ext_fit_size: + print(f', header {ext_fit_size:#x}/{ext_fit_size / 1024:.1f} KB', + end='') + print(f', {count} files, uncompressed {size / 1024 / 1024:.1f} MB') + + +if __name__ == "__main__": + sys.exit(run_make_fit()) diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 9faa4d3d91e3..91c91201212c 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -29,11 +29,11 @@ llvm) elif [ "$SRCARCH" = loongarch ]; then echo 18.0.0 else - echo 11.0.0 + echo 13.0.1 fi ;; rustc) - echo 1.74.1 + echo 1.78.0 ;; bindgen) echo 0.65.1 diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index 3c54125eb373..c729bc936bae 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -OBJECT_FILES_NON_STANDARD := y CFLAGS_REMOVE_empty.o += $(CC_FLAGS_LTO) hostprogs-always-y += modpost mk_elfconfig 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 267b9a0a3abc..937294ff164f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -601,11 +601,6 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) strstarts(symname, "_savevr_") || strcmp(symname, ".TOC.") == 0) return 1; - - if (info->hdr->e_machine == EM_S390) - /* Expoline thunks are linked on all kernel modules during final link of .ko */ - if (strstarts(symname, "__s390_indirect_jump_r")) - return 1; /* Do not ignore this symbol */ return 0; } @@ -1007,6 +1002,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; @@ -1015,8 +1012,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) @@ -1050,7 +1048,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)) @@ -1848,7 +1848,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/module.lds.S b/scripts/module.lds.S index bf5bcf2836d8..3f43edef813c 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -9,10 +9,13 @@ #define DISCARD_EH_FRAME *(.eh_frame) #endif +#include <asm-generic/codetag.lds.h> + SECTIONS { /DISCARD/ : { *(.discard) *(.discard.*) + *(.export_symbol) } __ksymtab 0 : { *(SORT(___ksymtab+*)) } @@ -47,12 +50,17 @@ SECTIONS { .data : { *(.data .data.[0-9a-zA-Z_]*) *(.data..L*) + CODETAG_SECTIONS() } .rodata : { *(.rodata .rodata.[0-9a-zA-Z_]*) *(.rodata..L*) } +#else + .data : { + CODETAG_SECTIONS() + } #endif } diff --git a/scripts/package/builddeb b/scripts/package/builddeb index bf96a3c24608..e797ad360f7a 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -24,24 +24,10 @@ if_enabled_echo() { fi } -create_package() { - export DH_OPTIONS="-p${1}" - - dh_installdocs - dh_installchangelogs - dh_compress - dh_fixperms - dh_gencontrol - dh_md5sums - dh_builddeb -- ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS} -} - install_linux_image () { pname=$1 pdir=debian/$1 - rm -rf ${pdir} - # 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 @@ -109,8 +95,6 @@ install_linux_image () { install_linux_image_dbg () { pdir=debian/$1 - rm -rf ${pdir} - # Parse modules.order directly because 'make modules_install' may sign, # compress modules, and then run unneeded depmod. while read -r mod; do @@ -140,8 +124,6 @@ install_kernel_headers () { pdir=debian/$1 version=${1#linux-headers-} - rm -rf $pdir - "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" mkdir -p $pdir/lib/modules/$version/ @@ -151,8 +133,6 @@ install_kernel_headers () { install_libc_headers () { pdir=debian/$1 - rm -rf $pdir - $MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH=$pdir/usr # move asm headers to /usr/include/<libc-machine>/asm to match the structure @@ -161,21 +141,15 @@ install_libc_headers () { 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) - 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 - create_package "${package}" -done +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 72c91a1b832f..eb67787f8673 100755 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -53,18 +53,20 @@ cp -v -- "${objtree}/vmlinux" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" # # Install arch-specific kernel image(s) # +# Note: +# mips and arm64 copy the first image found. This may not produce the desired +# outcome because it may pick up a stale file remaining in the build tree. +# case "${ARCH}" in - x86|i386|x86_64) - [ -f "${objtree}/arch/x86/boot/bzImage" ] && cp -v -- "${objtree}/arch/x86/boot/bzImage" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" - ;; alpha) - [ -f "${objtree}/arch/alpha/boot/vmlinux.gz" ] && cp -v -- "${objtree}/arch/alpha/boot/vmlinux.gz" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" + cp -v -- "${objtree}/arch/alpha/boot/vmlinux.gz" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" ;; parisc*) - [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" [ -f "${objtree}/lifimage" ] && cp -v -- "${objtree}/lifimage" "${tmpdir}/boot/lifimage-${KERNELRELEASE}" ;; mips) + # Please note the following code may copy a stale file. if [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.bin" ]; then cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.bin" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" ]; then @@ -86,6 +88,7 @@ case "${ARCH}" in fi ;; arm64) + # Please note the following code may copy a stale file. for i in Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo vmlinuz.efi ; do if [ -f "${objtree}/arch/arm64/boot/${i}" ] ; then cp -v -- "${objtree}/arch/arm64/boot/${i}" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" @@ -94,21 +97,14 @@ case "${ARCH}" in done ;; riscv) - for i in Image.bz2 Image.gz Image; do - if [ -f "${objtree}/arch/riscv/boot/${i}" ] ; then - cp -v -- "${objtree}/arch/riscv/boot/${i}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" - break - fi - done + case "${KBUILD_IMAGE##*/}" in + Image.*|vmlinuz.efi) + cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}";; + *) + cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}";; + esac ;; *) - [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${KERNELRELEASE}" - echo "" >&2 - echo '** ** ** WARNING ** ** **' >&2 - echo "" >&2 - echo "Your architecture did not define any architecture-dependent files" >&2 - echo "to be placed into the tarball. Please add those to ${0} ..." >&2 - echo "" >&2 - sleep 5 + cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" ;; esac diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules index 098307780062..ca07243bd5cd 100755 --- a/scripts/package/debian/rules +++ b/scripts/package/debian/rules @@ -11,28 +11,73 @@ ifneq (,$(filter-out parallel=1,$(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) $(make-opts) \ - 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) $(make-opts) olddefconfig - $(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) 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-* debian/deb-env.vars* - $(MAKE) 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 @@ -41,6 +86,6 @@ ifndef DEB_HOST_ARCH include debian/deb-env.vars debian/deb-env.vars: - dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp - mv $@.tmp $@ + $(Q)dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp + $(Q)mv $@.tmp $@ endif diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index f58726671fb3..e095eb1e290e 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -61,11 +61,37 @@ cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEAS %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install 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} @@ -78,23 +104,23 @@ for file in vmlinuz System.map config; do 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 +%exclude /kernel.list %files headers %defattr (-, root, root) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index f84df9e383fd..0871b2e92584 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -352,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/spdxcheck.py b/scripts/spdxcheck.py index 18cb9f5b3d3d..8b8fb115fc81 100755 --- a/scripts/spdxcheck.py +++ b/scripts/spdxcheck.py @@ -412,6 +412,9 @@ if __name__ == '__main__': if parser.checked: pc = int(100 * parser.spdx_valid / parser.checked) sys.stderr.write('Files with SPDX: %12d %3d%%\n' %(parser.spdx_valid, pc)) + missing = parser.checked - parser.spdx_valid + mpc = int(100 * missing / parser.checked) + sys.stderr.write('Files without SPDX:%12d %3d%%\n' %(missing, mpc)) sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors) if ndirs: sys.stderr.write('\n') diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 25aefbb35377..c1121f098542 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -280,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\.]+)[\'\"]/) { @@ -293,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 "") { @@ -318,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; } @@ -361,6 +348,7 @@ sub give_debian_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-yaml", "ensurepip" => "python3-venv", "virtualenv" => "virtualenv", "dot" => "graphviz", @@ -395,6 +383,7 @@ sub give_redhat_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-pyyaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -421,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/)) { @@ -438,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"); @@ -446,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); @@ -472,6 +466,7 @@ sub give_opensuse_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-pyyaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -519,6 +514,7 @@ sub give_mageia_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-yaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -562,10 +558,11 @@ sub give_mageia_hints() sub give_arch_linux_hints() { my %map = ( + "yaml" => "python-yaml", "virtualenv" => "python-virtualenv", "dot" => "graphviz", "convert" => "imagemagick", - "xelatex" => "texlive-bin", + "xelatex" => "texlive-xetex", "latexmk" => "texlive-core", "rsvg-convert" => "extra/librsvg", ); @@ -592,6 +589,7 @@ sub give_arch_linux_hints() sub give_gentoo_hints() { my %map = ( + "yaml" => "dev-python/pyyaml", "virtualenv" => "dev-python/virtualenv", "dot" => "media-gfx/graphviz", "convert" => "media-gfx/imagemagick", @@ -951,6 +949,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/unifdef.c b/scripts/unifdef.c index db00e3e30a59..ff15efd6e7d7 100644 --- a/scripts/unifdef.c +++ b/scripts/unifdef.c @@ -203,7 +203,7 @@ static int depth; /* current #if nesting */ static int delcount; /* count of deleted lines */ static unsigned blankcount; /* count of blank lines */ static unsigned blankmax; /* maximum recent blankcount */ -static bool constexpr; /* constant #if expression */ +static bool constexpression; /* constant #if expression */ static bool zerosyms = true; /* to format symdepth output */ static bool firstsym; /* ditto */ @@ -819,7 +819,7 @@ static const struct ops { /* * Function for evaluating the innermost parts of expressions, * viz. !expr (expr) number defined(symbol) symbol - * We reset the constexpr flag in the last two cases. + * We reset the constexpression flag in the last two cases. */ static Linetype eval_unary(const struct ops *ops, int *valp, const char **cpp) @@ -877,7 +877,7 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp) cp = skipcomment(cp); if (defparen && *cp++ != ')') return (LT_ERROR); - constexpr = false; + constexpression = false; } else if (!endsym(*cp)) { debug("eval%d symbol", ops - eval_ops); sym = findsym(cp); @@ -895,7 +895,7 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp) lt = *valp ? LT_TRUE : LT_FALSE; cp = skipargs(cp); } - constexpr = false; + constexpression = false; } else { debug("eval%d bad expr", ops - eval_ops); return (LT_ERROR); @@ -955,10 +955,10 @@ ifeval(const char **cpp) int val = 0; debug("eval %s", *cpp); - constexpr = killconsts ? false : true; + constexpression = killconsts ? false : true; ret = eval_table(eval_ops, &val, cpp); debug("eval = %d", val); - return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret); + return (constexpression ? LT_IF : ret == LT_ERROR ? LT_IF : ret); } /* |