diff options
Diffstat (limited to 'scripts')
150 files changed, 5479 insertions, 2704 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 0442c06eefcb..12d302d70128 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,6 +1,7 @@ # # Generated files # +bin2c conmakehash kallsyms pnmtologo diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 50cee534fd64..bb015551c2d9 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -8,8 +8,6 @@ squote := ' empty := space := $(empty) $(empty) space_escape := _-_SPACE_-_ -right_paren := ) -left_paren := ( pound := \# ### @@ -57,9 +55,8 @@ kecho := $($(quiet)kecho) # to specify a valid file as first prerequisite (often the kbuild file) define filechk $(Q)set -e; \ - $(kecho) ' CHK $@'; \ mkdir -p $(dir $@); \ - $(filechk_$(1)) < $< > $@.tmp; \ + $(filechk_$(1)) > $@.tmp; \ if [ -r $@ ] && cmp -s $@ $@.tmp; then \ rm -f $@.tmp; \ else \ @@ -83,71 +80,6 @@ cc-cross-prefix = \ echo $(c); \ fi))) -# Tools for caching Makefile variables that are "expensive" to compute. -# -# Here we want to help deal with variables that take a long time to compute -# by making it easy to store these variables in a cache. -# -# The canonical example here is testing for compiler flags. On a simple system -# each call to the compiler takes 10 ms, but on a system with a compiler that's -# called through various wrappers it can take upwards of 100 ms. If we have -# 100 calls to the compiler this can take 1 second (on a simple system) or 10 -# seconds (on a complicated system). -# -# The "cache" will be in Makefile syntax and can be directly included. -# Any time we try to reference a variable that's not in the cache we'll -# calculate it and store it in the cache for next time. - -# Include values from last time -make-cache := $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/,$(if $(obj),$(obj)/)).cache.mk -$(make-cache): ; --include $(make-cache) - -cached-data := $(filter __cached_%, $(.VARIABLES)) - -# If cache exceeds 1000 lines, shrink it down to 500. -ifneq ($(word 1000,$(cached-data)),) -$(shell tail -n 500 $(make-cache) > $(make-cache).tmp; \ - mv $(make-cache).tmp $(make-cache)) -endif - -create-cache-dir := $(if $(KBUILD_SRC),$(if $(cache-data),,1)) - -# Usage: $(call __sanitize-opt,Hello=Hola$(comma)Goodbye Adios) -# -# Convert all '$', ')', '(', '\', '=', ' ', ',', ':' to '_' -__sanitize-opt = $(subst $$,_,$(subst $(right_paren),_,$(subst $(left_paren),_,$(subst \,_,$(subst =,_,$(subst $(space),_,$(subst $(comma),_,$(subst :,_,$(1))))))))) - -# Usage: $(call shell-cached,shell_command) -# Example: $(call shell-cached,md5sum /usr/bin/gcc) -# -# If we've already seen a call to this exact shell command (even in a -# previous invocation of make!) we'll return the value. If not, we'll -# compute it and store the result for future runs. -# -# This is a bit of voodoo, but basic explanation is that if the variable -# was undefined then we'll evaluate the shell command and store the result -# into the variable. We'll then store that value in the cache and finally -# output the value. -# -# NOTE: The $$(2) here isn't actually a parameter to __run-and-store. We -# happen to know that the caller will have their shell command in $(2) so the -# result of "call"ing this will produce a reference to that $(2). The reason -# for this strangeness is to avoid an extra level of eval (and escaping) of -# $(2). -define __run-and-store -ifeq ($(origin $(1)),undefined) - $$(eval $(1) := $$(shell $$(2))) -ifeq ($(create-cache-dir),1) - $$(shell mkdir -p $(dir $(make-cache))) - $$(eval create-cache-dir :=) -endif - $$(shell echo '$(1) := $$($(1))' >> $(make-cache)) -endif -endef -__shell-cached = $(eval $(call __run-and-store,$(1)))$($(1)) -shell-cached = $(call __shell-cached,__cached_$(call __sanitize-opt,$(1)),$(1)) - # output directory for tests below TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/) @@ -155,41 +87,37 @@ TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/) # Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise) # Exit code chooses option. "$$TMP" serves as a temporary file and is # automatically cleaned up. -__try-run = set -e; \ +try-run = $(shell set -e; \ TMP="$(TMPOUT).$$$$.tmp"; \ TMPO="$(TMPOUT).$$$$.o"; \ if ($(1)) >/dev/null 2>&1; \ then echo "$(2)"; \ else echo "$(3)"; \ fi; \ - rm -f "$$TMP" "$$TMPO" - -try-run = $(shell $(__try-run)) - -# try-run-cached -# This works like try-run, but the result is cached. -try-run-cached = $(call shell-cached,$(__try-run)) + rm -f "$$TMP" "$$TMPO") # as-option # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) -as-option = $(call try-run-cached,\ +as-option = $(call try-run,\ $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2)) # as-instr # Usage: cflags-y += $(call as-instr,instr,option1,option2) -as-instr = $(call try-run-cached,\ +as-instr = $(call try-run,\ printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) # __cc-option # Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586) -__cc-option = $(call try-run-cached,\ +__cc-option = $(call try-run,\ $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4)) # Do not attempt to build with gcc plugins during cc-option tests. # (And this uses delayed resolution so the flags will be up to date.) -CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) +# In addition, do not include the asm macros which are built later. +CC_OPTION_FILTERED = $(GCC_PLUGINS_CFLAGS) $(ASM_MACRO_FLAGS) +CC_OPTION_CFLAGS = $(filter-out $(CC_OPTION_FILTERED),$(KBUILD_CFLAGS)) # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) @@ -200,54 +128,42 @@ cc-option = $(call __cc-option, $(CC),\ # hostcc-option # Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586) hostcc-option = $(call __cc-option, $(HOSTCC),\ - $(HOSTCFLAGS) $(HOST_EXTRACFLAGS),$(1),$(2)) + $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS),$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) -cc-option-yn = $(call try-run-cached,\ +cc-option-yn = $(call try-run,\ $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) -cc-disable-warning = $(call try-run-cached,\ +cc-disable-warning = $(call try-run,\ $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) -# cc-name -# Expands to either gcc or clang -cc-name = $(call shell-cached,$(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) - # cc-version -cc-version = $(call shell-cached,$(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) - -# cc-fullversion -cc-fullversion = $(call shell-cached,$(CONFIG_SHELL) \ - $(srctree)/scripts/gcc-version.sh -p $(CC)) +cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) # cc-ifversion # Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) -# cc-if-fullversion -# Usage: EXTRA_CFLAGS += $(call cc-if-fullversion, -lt, 040502, -O1) -cc-if-fullversion = $(shell [ $(cc-fullversion) $(1) $(2) ] && echo $(3) || echo $(4)) - # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) -cc-ldoption = $(call try-run-cached,\ +cc-ldoption = $(call try-run,\ $(CC) $(1) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) # ld-option -# Usage: LDFLAGS += $(call ld-option, -X) -ld-option = $(call try-run-cached, $(LD) $(LDFLAGS) $(1) -v,$(1),$(2)) +# Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y) +ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3)) # ar-option # Usage: KBUILD_ARFLAGS := $(call ar-option,D) # Important: no spaces around options -ar-option = $(call try-run-cached, $(AR) rc$(1) "$$TMP",$(1),$(2)) +ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2)) # ld-version # Note this is mainly for HJ Lu's 3 number binutil versions -ld-version = $(call shell-cached,$(LD) --version | $(srctree)/scripts/ld-version.sh) +ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) # ld-ifversion # Usage: $(call ld-ifversion, -ge, 22252, y) @@ -271,7 +187,7 @@ modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= # Usage: # $(Q)$(MAKE) $(dtbinst)=dir -dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj +dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj ### # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= @@ -288,7 +204,7 @@ hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj # Prefix -I with $(srctree) if it is not an absolute path. # skip if -I has no parameter addtree = $(if $(patsubst -I%,%,$(1)), \ -$(if $(filter-out -I/% -I./% -I../%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1)),$(1))) +$(if $(filter-out -I/% -I./% -I../%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1)),$(1)),$(1)) # Find all -I options and call addtree flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o))) @@ -474,3 +390,6 @@ endif endef # ############################################################################### + +# delete partially updated (i.e. corrupted) files on error +.DELETE_ON_ERROR: diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include new file mode 100644 index 000000000000..dad5583451af --- /dev/null +++ b/scripts/Kconfig.include @@ -0,0 +1,30 @@ +# Kconfig helper macros + +# Convenient variables +comma := , +quote := " +squote := ' +empty := +space := $(empty) $(empty) +dollar := $ +right_paren := ) +left_paren := ( + +# $(if-success,<command>,<then>,<else>) +# Return <then> if <command> exits with 0, <else> otherwise. +if-success = $(shell,{ $(1); } >/dev/null 2>&1 && echo "$(2)" || echo "$(3)") + +# $(success,<command>) +# Return y if <command> exits with 0, n otherwise +success = $(if-success,$(1),y,n) + +# $(cc-option,<flag>) +# Return y if the compiler supports <flag>, n otherwise +cc-option = $(success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null) + +# $(ld-option,<flag>) +# Return y if the linker supports <flag>, n otherwise +ld-option = $(success,$(LD) -v $(1)) + +# gcc version including patch level +gcc-version := $(shell,$(srctree)/scripts/gcc-version.sh -p $(CC) | sed 's/^0*//') diff --git a/scripts/Makefile b/scripts/Makefile index 25ab143cbe14..ece52ff20171 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -10,6 +10,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include +hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash @@ -22,8 +23,8 @@ hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include -HOSTLOADLIBES_sign-file = -lcrypto -HOSTLOADLIBES_extract-cert = -lcrypto +HOSTLDLIBS_sign-file = -lcrypto +HOSTLDLIBS_extract-cert = -lcrypto always := $(hostprogs-y) $(hostprogs-m) @@ -38,8 +39,7 @@ build_unifdef: $(obj)/unifdef subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-y += mod subdir-$(CONFIG_SECURITY_SELINUX) += selinux -subdir-$(CONFIG_DTC) += dtc subdir-$(CONFIG_GDB_SCRIPTS) += gdb # Let clean descend into subdirs -subdir- += basic kconfig package gcc-plugins +subdir- += basic dtc kconfig package gcc-plugins diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 8bdb1dc4072c..6a6be9f440cf 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -36,30 +36,13 @@ subdir-ccflags-y := include scripts/Kbuild.include -# For backward compatibility check that these variables do not change -save-cflags := $(CFLAGS) - # The filename Kbuild has precedence over Makefile kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) include $(kbuild-file) -# If the save-* variables changed error out -ifeq ($(KBUILD_NOPEDANTIC),) - ifneq ("$(save-cflags)","$(CFLAGS)") - $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y) - endif -endif - include scripts/Makefile.lib -ifdef host-progs -ifneq ($(hostprogs-y),$(host-progs)) -$(warning kbuild: $(obj)/Makefile - Usage of host-progs is deprecated. Please replace with hostprogs-y!) -hostprogs-y += $(host-progs) -endif -endif - # Do not include host rules unless needed ifneq ($(hostprogs-y)$(hostprogs-m)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(hostcxxlibs-m),) include scripts/Makefile.host @@ -90,14 +73,12 @@ __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ @: # Linus' kernel sanity checking tool -ifneq ($(KBUILD_CHECKSRC),0) - ifeq ($(KBUILD_CHECKSRC),2) - quiet_cmd_force_checksrc = CHECK $< - cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; - else - quiet_cmd_checksrc = CHECK $< - cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; - endif +ifeq ($(KBUILD_CHECKSRC),1) + quiet_cmd_checksrc = CHECK $< + cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; +else ifeq ($(KBUILD_CHECKSRC),2) + quiet_cmd_force_checksrc = CHECK $< + cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; endif ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) @@ -147,7 +128,6 @@ $(obj)/%.i: $(src)/%.c FORCE cmd_gensymtypes_c = \ $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ $(GENKSYMS) $(if $(1), -T $(2)) \ - $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ $(if $(KBUILD_PRESERVE),-p) \ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) @@ -198,7 +178,7 @@ cmd_modversions_c = \ $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ > $(@D)/.tmp_$(@F:.o=.ver); \ \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ + $(LD) $(KBUILD_LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ -T $(@D)/.tmp_$(@F:.o=.ver); \ rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ else \ @@ -207,6 +187,8 @@ cmd_modversions_c = \ endif ifdef CONFIG_FTRACE_MCOUNT_RECORD +ifndef CC_USING_RECORD_MCOUNT +# compiler will not generate __mcount_loc use recordmcount or recordmcount.pl ifdef BUILD_C_RECORDMCOUNT ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") RECORDMCOUNT_FLAGS = -w @@ -225,8 +207,8 @@ else sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ "$(if $(CONFIG_64BIT),64,32)" \ - "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \ - "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ + "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \ + "$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \ "$(if $(part-of-module),1,0)" "$(@)"; recordmcount_source := $(srctree)/scripts/recordmcount.pl endif # BUILD_C_RECORDMCOUNT @@ -235,6 +217,7 @@ cmd_record_mcount = \ "$(CC_FLAGS_FTRACE)" ]; then \ $(sub_cmd_record_mcount) \ fi; +endif # CC_USING_RECORD_MCOUNT endif # CONFIG_FTRACE_MCOUNT_RECORD ifdef CONFIG_STACK_VALIDATION @@ -251,14 +234,10 @@ objtool_args += --no-fp endif ifdef CONFIG_GCOV_KERNEL objtool_args += --no-unreachable -else -objtool_args += $(call cc-ifversion, -lt, 0405, --no-unreachable) endif ifdef CONFIG_RETPOLINE -ifneq ($(RETPOLINE_CFLAGS),) objtool_args += --retpoline endif -endif ifdef CONFIG_MODVERSIONS @@ -355,7 +334,6 @@ cmd_gensymtypes_S = \ sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ) | \ $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \ $(GENKSYMS) $(if $(1), -T $(2)) \ - $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ $(if $(KBUILD_PRESERVE),-p) \ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) @@ -400,7 +378,7 @@ cmd_modversions_S = \ $(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ > $(@D)/.tmp_$(@F:.o=.ver); \ \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ + $(LD) $(KBUILD_LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ -T $(@D)/.tmp_$(@F:.o=.ver); \ rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ else \ @@ -487,15 +465,10 @@ targets += $(lib-target) dummy-object = $(obj)/.lib_exports.o ksyms-lds = $(dot-target).lds -ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX -ref_prefix = EXTERN(_ -else -ref_prefix = EXTERN( -endif quiet_cmd_export_list = EXPORTS $@ cmd_export_list = $(OBJDUMP) -h $< | \ - sed -ne '/___ksymtab/s/.*+\([^ ]*\).*/$(ref_prefix)\1)/p' >$(ksyms-lds);\ + sed -ne '/___ksymtab/s/.*+\([^ ]*\).*/EXTERN(\1)/p' >$(ksyms-lds);\ rm -f $(dummy-object);\ echo | $(CC) $(a_flags) -c -o $(dummy-object) -x assembler -;\ $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\ @@ -508,28 +481,12 @@ targets += $(obj)/lib-ksyms.o endif -# -# Rule to link composite objects -# -# Composite objects are specified in kbuild makefile as follows: -# <composite-object>-objs := <list of .o files> -# or -# <composite-object>-y := <list of .o files> -# or -# <composite-object>-m := <list of .o files> -# The -m syntax only works if <composite object> is a module -link_multi_deps = \ -$(filter $(addprefix $(obj)/, \ -$($(subst $(obj)/,,$(@:.o=-objs))) \ -$($(subst $(obj)/,,$(@:.o=-y))) \ -$($(subst $(obj)/,,$(@:.o=-m)))), $^) - quiet_cmd_link_multi-m = LD [M] $@ -cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) +cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^) $(cmd_secanalysis) $(multi-used-m): FORCE $(call if_changed,link_multi-m) - @{ echo $(@:.o=.ko); echo $(link_multi_deps); \ + @{ echo $(@:.o=.ko); echo $(filter %.o,$^); \ $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) $(call multi_depend, $(multi-used-m), .o, -objs -y -m) @@ -591,7 +548,4 @@ endif # We never want them to be removed automatically. .SECONDARY: $(targets) -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - .PHONY: $(PHONY) diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index 808d09f27ad4..0b80e3207b20 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -38,7 +38,6 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn)) __clean-files := $(extra-y) $(extra-m) $(extra-) \ $(always) $(targets) $(clean-files) \ - $(host-progs) \ $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \ $(hostlibs-y) $(hostlibs-m) $(hostlibs-) \ $(hostcxxlibs-y) $(hostcxxlibs-m) @@ -88,7 +87,4 @@ PHONY += $(subdir-ymn) $(subdir-ymn): $(Q)$(MAKE) $(clean)=$@ -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - .PHONY: $(PHONY) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 8d5357053f86..768306add591 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -29,6 +29,7 @@ warning-1 += $(call cc-option, -Wmissing-include-dirs) warning-1 += $(call cc-option, -Wunused-but-set-variable) warning-1 += $(call cc-option, -Wunused-const-variable) warning-1 += $(call cc-option, -Wpacked-not-aligned) +warning-1 += $(call cc-option, -Wstringop-truncation) warning-1 += $(call cc-disable-warning, missing-field-initializers) warning-1 += $(call cc-disable-warning, sign-compare) @@ -52,7 +53,6 @@ warning-3 += -Wpointer-arith warning-3 += -Wredundant-decls warning-3 += -Wswitch-default warning-3 += $(call cc-option, -Wpacked-bitfield-compat) -warning-3 += $(call cc-option, -Wvla) warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) @@ -65,7 +65,7 @@ endif KBUILD_CFLAGS += $(warning) else -ifeq ($(cc-name),clang) +ifdef CONFIG_CC_IS_CLANG KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides) KBUILD_CFLAGS += $(call cc-disable-warning, unused-value) KBUILD_CFLAGS += $(call cc-disable-warning, format) diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 7f5c86246138..46c5c6809806 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -1,84 +1,58 @@ # SPDX-License-Identifier: GPL-2.0 -ifdef CONFIG_GCC_PLUGINS - __PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC)) - PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)") - - SANCOV_PLUGIN := -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so - - gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so - - gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN - ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY - DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable - endif - - ifdef CONFIG_GCC_PLUGIN_SANCOV - ifeq ($(strip $(CFLAGS_KCOV)),) - # It is needed because of the gcc-plugin.sh and gcc version checks. - gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so - - ifneq ($(PLUGINCC),) - CFLAGS_KCOV := $(SANCOV_PLUGIN) - else - $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler) - endif - endif - endif - - gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) += -fplugin-arg-structleak_plugin-byref-all - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN - gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += -DRANDSTRUCT_PLUGIN - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) += -fplugin-arg-randomize_layout_plugin-performance-mode +gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so - GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) - - export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR - export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN +gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) \ + += -DLATENT_ENTROPY_PLUGIN +ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY + DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable +endif +export DISABLE_LATENT_ENTROPY_PLUGIN + +gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so + +gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \ + += -fplugin-arg-structleak_plugin-verbose +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \ + += -fplugin-arg-structleak_plugin-byref-all +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ + += -DSTRUCTLEAK_PLUGIN + +gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \ + += -DRANDSTRUCT_PLUGIN +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \ + += -fplugin-arg-randomize_layout_plugin-performance-mode + +gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ + += -DSTACKLEAK_PLUGIN +gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ + += -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE) +ifdef CONFIG_GCC_PLUGIN_STACKLEAK + DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable +endif +export DISABLE_STACKLEAK_PLUGIN - ifneq ($(PLUGINCC),) - # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. - GCC_PLUGINS_CFLAGS := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGINS_CFLAGS)) - endif +# All the plugin CFLAGS are collected here in case a build target needs to +# filter them out of the KBUILD_CFLAGS. +GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) +# The sancov_plugin.so is included via CFLAGS_KCOV, so it is removed here. +GCC_PLUGINS_CFLAGS := $(filter-out %/sancov_plugin.so, $(GCC_PLUGINS_CFLAGS)) +export GCC_PLUGINS_CFLAGS - KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) - GCC_PLUGIN := $(gcc-plugin-y) - GCC_PLUGIN_SUBDIR := $(gcc-plugin-subdir-y) -endif +# Add the flags to the build! +KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) -# If plugins aren't supported, abort the build before hard-to-read compiler -# errors start getting spewed by the main build. -PHONY += gcc-plugins-check -gcc-plugins-check: FORCE -ifdef CONFIG_GCC_PLUGINS - ifeq ($(PLUGINCC),) - ifneq ($(GCC_PLUGINS_CFLAGS),) - # Various gccs between 4.5 and 5.1 have bugs on powerpc due to missing - # header files. gcc <= 4.6 doesn't work at all, gccs from 4.8 to 5.1 have - # issues with 64-bit targets. - ifeq ($(ARCH),powerpc) - ifeq ($(call cc-ifversion, -le, 0501, y), y) - @echo "Cannot use CONFIG_GCC_PLUGINS: plugin support on gcc <= 5.1 is buggy on powerpc, please upgrade to gcc 5.2 or newer" >&2 && exit 1 - endif - endif - ifeq ($(call cc-ifversion, -ge, 0405, y), y) - $(Q)$(srctree)/scripts/gcc-plugin.sh --show-error "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)" || true - @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc installation does not support plugins, perhaps the necessary headers are missing?" >&2 && exit 1 - else - @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc version does not support plugins, you should upgrade it to at least gcc 4.5" >&2 && exit 1 - endif - endif - endif -endif - @: +# All enabled GCC plugins are collected here for building below. +GCC_PLUGIN := $(gcc-plugin-y) +export GCC_PLUGIN # Actually do the build, if requested. PHONY += gcc-plugins -gcc-plugins: scripts_basic gcc-plugins-check +gcc-plugins: scripts_basic ifdef CONFIG_GCC_PLUGINS $(Q)$(MAKE) $(build)=scripts/gcc-plugins endif diff --git a/scripts/Makefile.host b/scripts/Makefile.host index aa971cc3f339..0393f75db4d4 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -62,9 +62,9 @@ host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs)) ##### # Handle options to gcc. Support building with separate output directory -_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ +_hostc_flags = $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ $(HOSTCFLAGS_$(basetarget).o) -_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ +_hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ $(HOSTCXXFLAGS_$(basetarget).o) ifeq ($(KBUILD_SRC),) @@ -84,17 +84,17 @@ hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags) # Create executable from a single .c file # host-csingle -> Executable quiet_cmd_host-csingle = HOSTCC $@ - cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(HOSTLDFLAGS) -o $@ $< \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) + cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(KBUILD_HOSTLDFLAGS) -o $@ $< \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) $(host-csingle): $(obj)/%: $(src)/%.c FORCE $(call if_changed_dep,host-csingle) # Link an executable based on list of .o files, all plain c # host-cmulti -> executable quiet_cmd_host-cmulti = HOSTLD $@ - cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \ + cmd_host-cmulti = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ \ $(addprefix $(obj)/,$($(@F)-objs)) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) $(host-cmulti): FORCE $(call if_changed,host-cmulti) $(call multi_depend, $(host-cmulti), , -objs) @@ -109,10 +109,10 @@ $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE # Link an executable based on list of .o files, a mixture of .c and .cc # host-cxxmulti -> executable quiet_cmd_host-cxxmulti = HOSTLD $@ - cmd_host-cxxmulti = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \ + cmd_host-cxxmulti = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -o $@ \ $(foreach o,objs cxxobjs,\ $(addprefix $(obj)/,$($(@F)-$(o)))) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) $(host-cxxmulti): FORCE $(call if_changed,host-cxxmulti) $(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs) @@ -143,9 +143,9 @@ $(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE # Link a shared library, based on position independent .o files # *.o -> .so shared library (host-cshlib) quiet_cmd_host-cshlib = HOSTLLD -shared $@ - cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \ + cmd_host-cshlib = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \ $(addprefix $(obj)/,$($(@F:.so=-objs))) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) $(host-cshlib): FORCE $(call if_changed,host-cshlib) $(call multi_depend, $(host-cshlib), .so, -objs) @@ -153,9 +153,9 @@ $(call multi_depend, $(host-cshlib), .so, -objs) # Link a shared library, based on position independent .o files # *.o -> .so shared library (host-cxxshlib) quiet_cmd_host-cxxshlib = HOSTLLD -shared $@ - cmd_host-cxxshlib = $(HOSTCXX) $(HOSTLDFLAGS) -shared -o $@ \ + cmd_host-cxxshlib = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \ $(addprefix $(obj)/,$($(@F:.so=-objs))) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(@F)) $(host-cxxshlib): FORCE $(call if_changed,host-cxxshlib) $(call multi_depend, $(host-cxxshlib), .so, -objs) diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov index 5cc72037e423..3d61c4bfcbee 100644 --- a/scripts/Makefile.kcov +++ b/scripts/Makefile.kcov @@ -1,7 +1,9 @@ ifdef CONFIG_KCOV -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) -ifeq ($(CONFIG_KCOV_ENABLE_COMPARISONS),y) -CFLAGS_KCOV += $(call cc-option,-fsanitize-coverage=trace-cmp,) -endif + +kcov-flags-$(CONFIG_CC_HAS_SANCOV_TRACE_PC) += -fsanitize-coverage=trace-pc +kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp +kcov-flags-$(CONFIG_GCC_PLUGIN_SANCOV) += -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so + +export CFLAGS_KCOV := $(kcov-flags-y) endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 5af34a2b0cd9..8fe4468f9bda 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -162,7 +162,7 @@ a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(__cpp_flags) -ld_flags = $(LDFLAGS) $(ldflags-y) +ld_flags = $(KBUILD_LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) DTC_INCLUDE := $(srctree)/scripts/dtc/include-prefixes @@ -225,8 +225,7 @@ $(obj)/%: $(src)/%_shipped # --------------------------------------------------------------------------- quiet_cmd_ld = LD $@ -cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \ - $(filter-out FORCE,$^) -o $@ +cmd_ld = $(LD) $(ld_flags) $(filter-out FORCE,$^) -o $@ # Objcopy # --------------------------------------------------------------------------- @@ -251,6 +250,9 @@ DTC_FLAGS += -Wno-unit_address_vs_reg \ -Wno-unit_address_format \ -Wno-avoid_unnecessary_addr_size \ -Wno-alias_paths \ + -Wno-graph_child_address \ + -Wno-graph_port \ + -Wno-unique_unit_address \ -Wno-pci_device_reg endif @@ -281,7 +283,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb FORCE quiet_cmd_dtc = DTC $@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ - $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ + $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ $(DTC) -O dtb -o $@ -b 0 \ $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) ; \ @@ -413,7 +415,7 @@ define filechk_offsets echo " * This file was generated by Kbuild"; \ echo " */"; \ echo ""; \ - sed -ne $(sed-offsets); \ + sed -ne $(sed-offsets) < $<; \ echo ""; \ echo "#endif" ) endef diff --git a/scripts/Makefile.modbuiltin b/scripts/Makefile.modbuiltin index a763b4775d06..a072a4267746 100644 --- a/scripts/Makefile.modbuiltin +++ b/scripts/Makefile.modbuiltin @@ -8,10 +8,10 @@ src := $(obj) PHONY := __modbuiltin __modbuiltin: --include include/config/auto.conf +include include/config/auto.conf # tristate.conf sets tristate variables to uppercase 'Y' or 'M' # That way, we get the list of built-in modules in obj-Y --include include/config/tristate.conf +include include/config/tristate.conf include scripts/Kbuild.include @@ -54,8 +54,4 @@ PHONY += $(subdir-ym) $(subdir-ym): $(Q)$(MAKE) $(modbuiltin)=$@ - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - .PHONY: $(PHONY) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index 51ca0244fc8a..ff5ca9817a85 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -35,8 +35,4 @@ modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D)) $(modules): $(call cmd,modules_install,$(MODLIB)/$(modinst_dir)) - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable so we can use it in if_changed and friends. - .PHONY: $(PHONY) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index df4174405feb..7d4af0d0accb 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -120,7 +120,7 @@ ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) # Step 6), final link of the modules with optional arch pass after final link quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ - $(LD) -r $(LDFLAGS) \ + $(LD) -r $(KBUILD_LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -o $@ $(filter-out FORCE,$^) ; \ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) @@ -149,8 +149,4 @@ ifneq ($(cmd_files),) include $(cmd_files) endif - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - .PHONY: $(PHONY) diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign index 171483bc0538..da56aa78d245 100644 --- a/scripts/Makefile.modsign +++ b/scripts/Makefile.modsign @@ -27,7 +27,4 @@ modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D)) $(modules): $(call cmd,sign_ko,$(MODLIB)/$(modinst_dir)) -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - .PHONY: $(PHONY) diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index b593b36ccff8..38b2b4818e8e 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -14,10 +14,6 @@ ifdef CONFIG_UBSAN_ALIGNMENT CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment) endif -ifdef CONFIG_UBSAN_NULL - CFLAGS_UBSAN += $(call cc-option, -fsanitize=null) -endif - # -fsanitize=* options makes GCC less smart than usual and # increase number of 'maybe-uninitialized false-positives CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized) diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh index 016b3c48a4ec..6e6d63957da3 100755 --- a/scripts/adjust_autoksyms.sh +++ b/scripts/adjust_autoksyms.sh @@ -61,9 +61,6 @@ for mod in "$MODVERDIR"/*.mod; do sed -n -e '3{s/ /\n/g;/^$/!p;}' "$mod" done | sort -u | while read sym; do - if [ -n "$CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX" ]; then - sym="${sym#_}" - fi echo "#define __KSYM_${sym} 1" done >> "$new_ksyms_file" diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index c146020fc783..1b28787028d3 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c @@ -413,7 +413,7 @@ static void tokenise(char *buffer, char *end) /* Handle string tokens */ if (isalpha(*p)) { - const char **dir, *start = p; + const char **dir; /* Can be a directive, type name or element * name. Find the end of the name. diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore index 9528ec9e5adc..a776371a3502 100644 --- a/scripts/basic/.gitignore +++ b/scripts/basic/.gitignore @@ -1,2 +1 @@ fixdep -bin2c diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile index 0372b33febe5..af49b446f17d 100644 --- a/scripts/basic/Makefile +++ b/scripts/basic/Makefile @@ -9,7 +9,6 @@ # fixdep: Used to generate dependency information during build process hostprogs-y := fixdep -hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c always := $(hostprogs-y) # fixdep is needed to compile other host programs diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index f387538c58bc..850966f3d602 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -115,7 +115,7 @@ static void usage(void) */ static void print_dep(const char *m, int slen, const char *dir) { - int c, i; + int c, prev_c = '/', i; printf(" $(wildcard %s/", dir); for (i = 0; i < slen; i++) { @@ -124,7 +124,9 @@ static void print_dep(const char *m, int slen, const char *dir) c = '/'; else c = tolower(c); - putchar(c); + if (c != '/' || prev_c != '/') + putchar(c); + prev_c = c; } printf(".h) \\\n"); } diff --git a/scripts/basic/bin2c.c b/scripts/bin2c.c index c3d7eef3ad06..c3d7eef3ad06 100644 --- a/scripts/basic/bin2c.c +++ b/scripts/bin2c.c diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py new file mode 100755 index 000000000000..5010a4d5bfba --- /dev/null +++ b/scripts/bpf_helpers_doc.py @@ -0,0 +1,421 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2018 Netronome Systems, Inc. + +# In case user attempts to run with Python 2. +from __future__ import print_function + +import argparse +import re +import sys, os + +class NoHelperFound(BaseException): + pass + +class ParsingError(BaseException): + def __init__(self, line='<line not provided>', reader=None): + if reader: + BaseException.__init__(self, + 'Error at file offset %d, parsing line: %s' % + (reader.tell(), line)) + else: + BaseException.__init__(self, 'Error parsing line: %s' % line) + +class Helper(object): + """ + An object representing the description of an eBPF helper function. + @proto: function prototype of the helper function + @desc: textual description of the helper function + @ret: description of the return value of the helper function + """ + def __init__(self, proto='', desc='', ret=''): + self.proto = proto + self.desc = desc + self.ret = ret + + def proto_break_down(self): + """ + Break down helper function protocol into smaller chunks: return type, + name, distincts arguments. + """ + arg_re = re.compile('((const )?(struct )?(\w+|...))( (\**)(\w+))?$') + res = {} + proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$') + + capture = proto_re.match(self.proto) + res['ret_type'] = capture.group(1) + res['ret_star'] = capture.group(2) + res['name'] = capture.group(3) + res['args'] = [] + + args = capture.group(4).split(', ') + for a in args: + capture = arg_re.match(a) + res['args'].append({ + 'type' : capture.group(1), + 'star' : capture.group(6), + 'name' : capture.group(7) + }) + + return res + +class HeaderParser(object): + """ + An object used to parse a file in order to extract the documentation of a + list of eBPF helper functions. All the helpers that can be retrieved are + stored as Helper object, in the self.helpers() array. + @filename: name of file to parse, usually include/uapi/linux/bpf.h in the + kernel tree + """ + def __init__(self, filename): + self.reader = open(filename, 'r') + self.line = '' + self.helpers = [] + + def parse_helper(self): + proto = self.parse_proto() + desc = self.parse_desc() + ret = self.parse_ret() + return Helper(proto=proto, desc=desc, ret=ret) + + def parse_proto(self): + # Argument can be of shape: + # - "void" + # - "type name" + # - "type *name" + # - Same as above, with "const" and/or "struct" in front of type + # - "..." (undefined number of arguments, for bpf_trace_printk()) + # There is at least one term ("void"), and at most five arguments. + p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$') + capture = p.match(self.line) + if not capture: + raise NoHelperFound + self.line = self.reader.readline() + return capture.group(1) + + def parse_desc(self): + p = re.compile(' \* ?(?:\t| {5,8})Description$') + capture = p.match(self.line) + if not capture: + # Helper can have empty description and we might be parsing another + # attribute: return but do not consume. + return '' + # Description can be several lines, some of them possibly empty, and it + # stops when another subsection title is met. + desc = '' + while True: + self.line = self.reader.readline() + if self.line == ' *\n': + desc += '\n' + else: + p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') + capture = p.match(self.line) + if capture: + desc += capture.group(1) + '\n' + else: + break + return desc + + def parse_ret(self): + p = re.compile(' \* ?(?:\t| {5,8})Return$') + capture = p.match(self.line) + if not capture: + # Helper can have empty retval and we might be parsing another + # attribute: return but do not consume. + return '' + # Return value description can be several lines, some of them possibly + # empty, and it stops when another subsection title is met. + ret = '' + while True: + self.line = self.reader.readline() + if self.line == ' *\n': + ret += '\n' + else: + p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') + capture = p.match(self.line) + if capture: + ret += capture.group(1) + '\n' + else: + break + return ret + + def run(self): + # Advance to start of helper function descriptions. + offset = self.reader.read().find('* Start of BPF helper function descriptions:') + if offset == -1: + raise Exception('Could not find start of eBPF helper descriptions list') + self.reader.seek(offset) + self.reader.readline() + self.reader.readline() + self.line = self.reader.readline() + + while True: + try: + helper = self.parse_helper() + self.helpers.append(helper) + except NoHelperFound: + break + + self.reader.close() + print('Parsed description of %d helper function(s)' % len(self.helpers), + file=sys.stderr) + +############################################################################### + +class Printer(object): + """ + A generic class for printers. Printers should be created with an array of + Helper objects, and implement a way to print them in the desired fashion. + @helpers: array of Helper objects to print to standard output + """ + def __init__(self, helpers): + self.helpers = helpers + + def print_header(self): + pass + + def print_footer(self): + pass + + def print_one(self, helper): + pass + + def print_all(self): + self.print_header() + for helper in self.helpers: + self.print_one(helper) + self.print_footer() + +class PrinterRST(Printer): + """ + A printer for dumping collected information about helpers as a ReStructured + Text page compatible with the rst2man program, which can be used to + generate a manual page for the helpers. + @helpers: array of Helper objects to print to standard output + """ + def print_header(self): + header = '''\ +.. Copyright (C) All BPF authors and contributors from 2014 to present. +.. See git log include/uapi/linux/bpf.h in kernel tree for details. +.. +.. %%%LICENSE_START(VERBATIM) +.. Permission is granted to make and distribute verbatim copies of this +.. manual provided the copyright notice and this permission notice are +.. preserved on all copies. +.. +.. Permission is granted to copy and distribute modified versions of this +.. manual under the conditions for verbatim copying, provided that the +.. entire resulting derived work is distributed under the terms of a +.. permission notice identical to this one. +.. +.. Since the Linux kernel and libraries are constantly changing, this +.. manual page may be incorrect or out-of-date. The author(s) assume no +.. responsibility for errors or omissions, or for damages resulting from +.. the use of the information contained herein. The author(s) may not +.. have taken the same level of care in the production of this manual, +.. which is licensed free of charge, as they might when working +.. professionally. +.. +.. Formatted or processed versions of this manual, if unaccompanied by +.. the source, must acknowledge the copyright and authors of this work. +.. %%%LICENSE_END +.. +.. Please do not edit this file. It was generated from the documentation +.. located in file include/uapi/linux/bpf.h of the Linux kernel sources +.. (helpers description), and from scripts/bpf_helpers_doc.py in the same +.. repository (header and footer). + +=========== +BPF-HELPERS +=========== +------------------------------------------------------------------------------- +list of eBPF helper functions +------------------------------------------------------------------------------- + +:Manual section: 7 + +DESCRIPTION +=========== + +The extended Berkeley Packet Filter (eBPF) subsystem consists in programs +written in a pseudo-assembly language, then attached to one of the several +kernel hooks and run in reaction of specific events. This framework differs +from the older, "classic" BPF (or "cBPF") in several aspects, one of them being +the ability to call special functions (or "helpers") from within a program. +These functions are restricted to a white-list of helpers defined in the +kernel. + +These helpers are used by eBPF programs to interact with the system, or with +the context in which they work. For instance, they can be used to print +debugging messages, to get the time since the system was booted, to interact +with eBPF maps, or to manipulate network packets. Since there are several eBPF +program types, and that they do not run in the same context, each program type +can only call a subset of those helpers. + +Due to eBPF conventions, a helper can not have more than five arguments. + +Internally, eBPF programs call directly into the compiled helper functions +without requiring any foreign-function interface. As a result, calling helpers +introduces no overhead, thus offering excellent performance. + +This document is an attempt to list and document the helpers available to eBPF +developers. They are sorted by chronological order (the oldest helpers in the +kernel at the top). + +HELPERS +======= +''' + print(header) + + def print_footer(self): + footer = ''' +EXAMPLES +======== + +Example usage for most of the eBPF helpers listed in this manual page are +available within the Linux kernel sources, at the following locations: + +* *samples/bpf/* +* *tools/testing/selftests/bpf/* + +LICENSE +======= + +eBPF programs can have an associated license, passed along with the bytecode +instructions to the kernel when the programs are loaded. The format for that +string is identical to the one in use for kernel modules (Dual licenses, such +as "Dual BSD/GPL", may be used). Some helper functions are only accessible to +programs that are compatible with the GNU Privacy License (GPL). + +In order to use such helpers, the eBPF program must be loaded with the correct +license string passed (via **attr**) to the **bpf**\ () system call, and this +generally translates into the C source code of the program containing a line +similar to the following: + +:: + + char ____license[] __attribute__((section("license"), used)) = "GPL"; + +IMPLEMENTATION +============== + +This manual page is an effort to document the existing eBPF helper functions. +But as of this writing, the BPF sub-system is under heavy development. New eBPF +program or map types are added, along with new helper functions. Some helpers +are occasionally made available for additional program types. So in spite of +the efforts of the community, this page might not be up-to-date. If you want to +check by yourself what helper functions exist in your kernel, or what types of +programs they can support, here are some files among the kernel tree that you +may be interested in: + +* *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list + of all helper functions, as well as many other BPF definitions including most + of the flags, structs or constants used by the helpers. +* *net/core/filter.c* contains the definition of most network-related helper + functions, and the list of program types from which they can be used. +* *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related + helpers. +* *kernel/bpf/verifier.c* contains the functions used to check that valid types + of eBPF maps are used with a given helper function. +* *kernel/bpf/* directory contains other files in which additional helpers are + defined (for cgroups, sockmaps, etc.). + +Compatibility between helper functions and program types can generally be found +in the files where helper functions are defined. Look for the **struct +bpf_func_proto** objects and for functions returning them: these functions +contain a list of helpers that a given program type can call. Note that the +**default:** label of the **switch ... case** used to filter helpers can call +other functions, themselves allowing access to additional helpers. The +requirement for GPL license is also in those **struct bpf_func_proto**. + +Compatibility between helper functions and map types can be found in the +**check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*. + +Helper functions that invalidate the checks on **data** and **data_end** +pointers for network processing are listed in function +**bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*. + +SEE ALSO +======== + +**bpf**\ (2), +**cgroups**\ (7), +**ip**\ (8), +**perf_event_open**\ (2), +**sendmsg**\ (2), +**socket**\ (7), +**tc-bpf**\ (8)''' + print(footer) + + def print_proto(self, helper): + """ + Format function protocol with bold and italics markers. This makes RST + file less readable, but gives nice results in the manual page. + """ + proto = helper.proto_break_down() + + print('**%s %s%s(' % (proto['ret_type'], + proto['ret_star'].replace('*', '\\*'), + proto['name']), + end='') + + comma = '' + for a in proto['args']: + one_arg = '{}{}'.format(comma, a['type']) + if a['name']: + if a['star']: + one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*')) + else: + one_arg += '** ' + one_arg += '*{}*\\ **'.format(a['name']) + comma = ', ' + print(one_arg, end='') + + print(')**') + + def print_one(self, helper): + self.print_proto(helper) + + if (helper.desc): + print('\tDescription') + # Do not strip all newline characters: formatted code at the end of + # a section must be followed by a blank line. + for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): + print('{}{}'.format('\t\t' if line else '', line)) + + if (helper.ret): + print('\tReturn') + for line in helper.ret.rstrip().split('\n'): + print('{}{}'.format('\t\t' if line else '', line)) + + print('') + +############################################################################### + +# If script is launched from scripts/ from kernel tree and can access +# ../include/uapi/linux/bpf.h, use it as a default name for the file to parse, +# otherwise the --filename argument will be required from the command line. +script = os.path.abspath(sys.argv[0]) +linuxRoot = os.path.dirname(os.path.dirname(script)) +bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h') + +argParser = argparse.ArgumentParser(description=""" +Parse eBPF header file and generate documentation for eBPF helper functions. +The RST-formatted output produced can be turned into a manual page with the +rst2man utility. +""") +if (os.path.isfile(bpfh)): + argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h', + default=bpfh) +else: + argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h') +args = argParser.parse_args() + +# Parse file. +headerParser = HeaderParser(args.filename) +headerParser.run() + +# Print formatted output to standard output. +printer = PrinterRST(headerParser.helpers) +printer.print_all() diff --git a/scripts/cc-can-link.sh b/scripts/cc-can-link.sh new file mode 100755 index 000000000000..6efcead31989 --- /dev/null +++ b/scripts/cc-can-link.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +cat << "END" | $@ -x c - -o /dev/null >/dev/null 2>&1 +#include <stdio.h> +int main(void) +{ + printf(""); + return 0; +} +END diff --git a/scripts/check_00index.sh b/scripts/check_00index.sh deleted file mode 100755 index aa47f5926c80..000000000000 --- a/scripts/check_00index.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 - -cd Documentation/ - -# Check entries that should be removed - -obsolete="" -for i in $(tail -n +12 00-INDEX |grep -E '^[a-zA-Z0-9]+'); do - if [ ! -e $i ]; then - obsolete="$obsolete $i" - fi -done - -# Check directory entries that should be added -search="" -dir="" -for i in $(find . -maxdepth 1 -type d); do - if [ "$i" != "." ]; then - new=$(echo $i|perl -ne 's,./(.*),$1/,; print $_') - search="$search $new" - fi -done - -for i in $search; do - if [ "$(grep -P "^$i" 00-INDEX)" == "" ]; then - dir="$dir $i" - fi -done - -# Check file entries that should be added -search="" -file="" -for i in $(find . -maxdepth 1 -type f); do - if [ "$i" != "./.gitignore" ]; then - new=$(echo $i|perl -ne 's,./(.*),$1,; print $_') - search="$search $new" - fi -done - -for i in $search; do - if [ "$(grep -P "^$i\$" 00-INDEX)" == "" ]; then - file="$file $i" - fi -done - -# Output its findings - -echo -e "Documentation/00-INDEX check results:\n" - -if [ "$obsolete" != "" ]; then - echo -e "- Should remove those entries:\n\t$obsolete\n" -else - echo -e "- No obsolete entries\n" -fi - -if [ "$dir" != "" ]; then - echo -e "- Should document those directories:\n\t$dir\n" -else - echo -e "- No new directories to add\n" -fi - -if [ "$file" != "" ]; then - echo -e "- Should document those files:\n\t$file" -else - echo "- No new files to add" -fi diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2d42eb9cd1a5..c883ec55654f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1,9 +1,11 @@ #!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# # (c) 2001, Dave Jones. (the file handling bit) # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) # (c) 2008-2010 Andy Whitcroft <apw@canonical.com> -# Licensed under the terms of the GNU GPL License version 2 +# (c) 2010-2018 Joe Perches <joe@perches.com> use strict; use warnings; @@ -11,6 +13,7 @@ use POSIX; use File::Basename; use Cwd 'abs_path'; use Term::ANSIColor qw(:constants); +use Encode qw(decode encode); my $P = $0; my $D = dirname(abs_path($P)); @@ -238,11 +241,11 @@ $check_orig = $check; my $exit = 0; +my $perl_version_ok = 1; if ($^V && $^V lt $minimum_perl_version) { + $perl_version_ok = 0; printf "$P: requires at least perl version %vd\n", $minimum_perl_version; - if (!$ignore_perl_version) { - exit(1); - } + exit(1) if (!$ignore_perl_version); } #if no filenames are given, push '-' to read patch from stdin @@ -344,9 +347,10 @@ our $Sparse = qr{ __force| __iomem| __must_check| - __init_refok| __kprobes| __ref| + __refconst| + __refdata| __rcu| __private }x; @@ -376,6 +380,7 @@ our $Attribute = qr{ __noclone| __deprecated| __read_mostly| + __ro_after_init| __kprobes| $InitAttribute| ____cacheline_aligned| @@ -845,6 +850,17 @@ sub is_maintained_obsolete { return $status =~ /obsolete/i; } +sub is_SPDX_License_valid { + my ($license) = @_; + + return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git")); + + my $root_path = abs_path($root); + my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`; + return 0 if ($status ne ""); + return 1; +} + my $camelcase_seeded = 0; sub seed_camelcase_includes { return if ($camelcase_seeded); @@ -1024,11 +1040,11 @@ if (!$quiet) { hash_show_words(\%use_type, "Used"); hash_show_words(\%ignore_type, "Ignored"); - if ($^V lt 5.10.0) { + if (!$perl_version_ok) { print << "EOM" NOTE: perl $^V is not modern enough to detect all possible issues. - An upgrade to at least perl v5.10.0 is suggested. + An upgrade to at least perl $minimum_perl_version is suggested. EOM } if ($exit) { @@ -2233,10 +2249,14 @@ sub process { our $clean = 1; my $signoff = 0; + my $author = ''; + my $authorsignoff = 0; my $is_patch = 0; + my $is_binding_patch = -1; my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch my $has_commit_log = 0; #Encountered lines before patch + my $commit_log_lines = 0; #Number of commit log lines my $commit_log_possible_stack_dump = 0; my $commit_log_long_line = 0; my $commit_log_has_diff = 0; @@ -2375,6 +2395,14 @@ sub process { my $rawline = $rawlines[$linenr - 1]; +# check if it's a mode change, rename or start of a patch + if (!$in_commit_log && + ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ || + ($line =~ /^rename (?:from|to) \S+\s*$/ || + $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) { + $is_patch = 1; + } + #extract the line range in the file after the patch is applied if (!$in_commit_log && $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) { @@ -2475,6 +2503,19 @@ sub process { $check = $check_orig; } $checklicenseline = 1; + + if ($realfile !~ /^MAINTAINERS/) { + my $last_binding_patch = $is_binding_patch; + + $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@; + + if (($last_binding_patch != -1) && + ($last_binding_patch ^ $is_binding_patch)) { + WARN("DT_SPLIT_BINDING_PATCH", + "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.txt\n"); + } + } + next; } @@ -2486,6 +2527,18 @@ sub process { $cnt_lines++ if ($realcnt != 0); +# Verify the existence of a commit log if appropriate +# 2 is used because a $signature is counted in $commit_log_lines + if ($in_commit_log) { + if ($line !~ /^\s*$/) { + $commit_log_lines++; #could be a $signature + } + } elsif ($has_commit_log && $commit_log_lines < 2) { + WARN("COMMIT_MESSAGE", + "Missing commit description - Add an appropriate one\n"); + $commit_log_lines = 2; #warn only once + } + # Check if the commit log has what seems like a diff which can confuse patch if ($in_commit_log && !$commit_log_has_diff && (($line =~ m@^\s+diff\b.*a/[\w/]+@ && @@ -2507,10 +2560,24 @@ sub process { } } +# Check the patch for a From: + if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) { + $author = $1; + $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i); + $author =~ s/"//g; + } + # Check the patch for a signoff: if ($line =~ /^\s*signed-off-by:/i) { $signoff++; $in_commit_log = 0; + if ($author ne '') { + my $l = $line; + $l =~ s/"//g; + if ($l =~ /^\s*signed-off-by:\s*\Q$author\E/i) { + $authorsignoff = 1; + } + } } # Check if MAINTAINERS is being updated. If so, there's probably no need to @@ -2596,12 +2663,6 @@ sub process { "A patch subject line should describe the change not the tool that found it\n" . $herecurr); } -# Check for old stable address - if ($line =~ /^\s*cc:\s*.*<?\bstable\@kernel\.org\b>?.*$/i) { - ERROR("STABLE_ADDRESS", - "The 'stable' address should be 'stable\@vger.kernel.org'\n" . $herecurr); - } - # Check for unwanted Gerrit info if ($in_commit_log && $line =~ /^\s*change-id:/i) { ERROR("GERRIT_CHANGE_ID", @@ -2956,8 +3017,14 @@ sub process { if ($comment !~ /^$/ && $rawline !~ /^\+\Q$comment\E SPDX-License-Identifier: /) { - WARN("SPDX_LICENSE_TAG", - "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); + WARN("SPDX_LICENSE_TAG", + "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); + } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) { + my $spdx_license = $1; + if (!is_SPDX_License_valid($spdx_license)) { + WARN("SPDX_LICENSE_TAG", + "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); + } } } } @@ -3075,7 +3142,7 @@ sub process { } # check indentation starts on a tab stop - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) { my $indent = length($1); if ($indent % 8) { @@ -3088,7 +3155,7 @@ sub process { } # check multi-line statement indentation matches previous line - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { $prevline =~ /^\+(\t*)(.*)$/; my $oldindent = $1; @@ -3245,7 +3312,7 @@ sub process { # known declaration macros $sline =~ /^\+\s+$declaration_macros/ || # start of struct or union or enum - $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ || + $sline =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || # start or end of block or continuation of declaration $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || # bitfield continuation @@ -3777,6 +3844,26 @@ sub process { "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr); } +# check for unnecessary <signed> int declarations of short/long/long long + while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) { + my $type = trim($1); + next if ($type !~ /\bint\b/); + next if ($type !~ /\b(?:short|long\s+long|long)\b/); + my $new_type = $type; + $new_type =~ s/\b\s*int\s*\b/ /; + $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /; + $new_type =~ s/^const\s+//; + $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/); + $new_type = "const $new_type" if ($type =~ /^const\b/); + $new_type =~ s/\s+/ /g; + $new_type = trim($new_type); + if (WARN("UNNECESSARY_INT", + "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/; + } + } + # check for static const char * arrays. if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { WARN("STATIC_CONST_CHAR_ARRAY", @@ -3963,7 +4050,7 @@ sub process { # function brace can't be on same line, except for #defines of do while, # or if closed on same line - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ && $sline !~ /\#\s*define\b.*do\s*\{/ && $sline !~ /}/) { @@ -4479,11 +4566,11 @@ sub process { #need space before brace following if, while, etc if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || - $line =~ /do\{/) { + $line =~ /\b(?:else|do)\{/) { if (ERROR("SPACING", "space required before the open brace '{'\n" . $herecurr) && $fix) { - $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\)))\{/$1 {/; + $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/; } } @@ -4574,7 +4661,7 @@ sub process { # check for unnecessary parentheses around comparisons in if uses # when !drivers/staging or command-line uses --strict if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) && - $^V && $^V ge 5.10.0 && defined($stat) && + $perl_version_ok && defined($stat) && $stat =~ /(^.\s*if\s*($balanced_parens))/) { my $if_stat = $1; my $test = substr($2, 1, -1); @@ -4611,7 +4698,7 @@ sub process { # return is not a function if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { my $spacing = $1; - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { my $value = $1; $value = deparenthesize($value); @@ -4638,7 +4725,7 @@ sub process { } # if statements using unnecessary parentheses - ie: if ((foo == bar)) - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /\bif\s*((?:\(\s*){2,})/) { my $openparens = $1; my $count = $openparens =~ tr@\(@\(@; @@ -4655,7 +4742,7 @@ sub process { # avoid cases like "foo + BAR < baz" # only fix matches surrounded by parentheses to avoid incorrect # conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { my $lead = $1; my $const = $2; @@ -4847,17 +4934,6 @@ sub process { while ($line =~ m{($Constant|$Lval)}g) { my $var = $1; -#gcc binary extension - if ($var =~ /^$Binary$/) { - if (WARN("GCC_BINARY_CONSTANT", - "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) && - $fix) { - my $hexval = sprintf("0x%x", oct($var)); - $fixed[$fixlinenr] =~ - s/\b$var\b/$hexval/; - } - } - #CamelCase if ($var !~ /^$Constant$/ && $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && @@ -4945,6 +5021,7 @@ sub process { if (defined $define_args && $define_args ne "") { $define_args = substr($define_args, 1, length($define_args) - 2); $define_args =~ s/\s*//g; + $define_args =~ s/\\\+?//g; @def_args = split(",", $define_args); } @@ -5080,7 +5157,7 @@ sub process { # do {} while (0) macro tests: # single-statement macros do not need to be enclosed in do while (0) loop, # macro should not end with a semicolon - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $realfile !~ m@/vmlinux.lds.h$@ && $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { my $ln = $linenr; @@ -5121,16 +5198,6 @@ sub process { } } -# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... -# all assignments may have only one of the following with an assignment: -# . -# ALIGN(...) -# VMLINUX_SYMBOL(...) - if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { - WARN("MISSING_VMLINUX_SYMBOL", - "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); - } - # check for redundant bracing round if etc if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { my ($level, $endln, @chunks) = @@ -5336,15 +5403,28 @@ sub process { } # concatenated string without spaces between elements - if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) { - CHK("CONCATENATED_STRING", - "Concatenated strings should use spaces between elements\n" . $herecurr); + if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) { + if (CHK("CONCATENATED_STRING", + "Concatenated strings should use spaces between elements\n" . $herecurr) && + $fix) { + while ($line =~ /($String)/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/; + $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/; + } + } } # uncoalesced string fragments if ($line =~ /$String\s*"/) { - WARN("STRING_FRAGMENTS", - "Consecutive strings are generally better as a single string\n" . $herecurr); + if (WARN("STRING_FRAGMENTS", + "Consecutive strings are generally better as a single string\n" . $herecurr) && + $fix) { + while ($line =~ /($String)(?=\s*")/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e; + } + } } # check for non-standard and hex prefixed decimal printf formats @@ -5380,9 +5460,14 @@ sub process { # warn about #if 0 if ($line =~ /^.\s*\#\s*if\s+0\b/) { - CHK("REDUNDANT_CODE", - "if this code is redundant consider removing it\n" . - $herecurr); + WARN("IF_0", + "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr); + } + +# warn about #if 1 + if ($line =~ /^.\s*\#\s*if\s+1\b/) { + WARN("IF_1", + "Consider removing the #if 1 and its #endif\n" . $herecurr); } # check for needless "if (<foo>) fn(<foo>)" uses @@ -5453,7 +5538,7 @@ sub process { } # check for mask then right shift without a parentheses - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so WARN("MASK_THEN_SHIFT", @@ -5461,7 +5546,7 @@ sub process { } # check for pointer comparisons to NULL - if ($^V && $^V ge 5.10.0) { + if ($perl_version_ok) { while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) { my $val = $1; my $equal = "!"; @@ -5733,7 +5818,7 @@ sub process { } # Check for __attribute__ weak, or __weak declarations (may have link issues) - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ && ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ || $line =~ /\b__weak\b/)) { @@ -5815,18 +5900,18 @@ sub process { } # check for vsprintf extension %p<foo> misuses - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && $1 !~ /^_*volatile_*$/) { - my $specifier; - my $extension; - my $bad_specifier = ""; my $stat_real; my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; for (my $count = $linenr; $count <= $lc; $count++) { + my $specifier; + my $extension; + my $bad_specifier = ""; my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); $fmt =~ s/%%//g; @@ -5862,7 +5947,7 @@ sub process { } # Check for misused memsets - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) { @@ -5880,7 +5965,7 @@ sub process { } # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) -# if ($^V && $^V ge 5.10.0 && +# if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # if (WARN("PREFER_ETHER_ADDR_COPY", @@ -5891,7 +5976,7 @@ sub process { # } # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) -# if ($^V && $^V ge 5.10.0 && +# if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # WARN("PREFER_ETHER_ADDR_EQUAL", @@ -5900,7 +5985,7 @@ sub process { # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr -# if ($^V && $^V ge 5.10.0 && +# if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # @@ -5922,7 +6007,7 @@ sub process { # } # typecasts on min/max could be min_t/max_t - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { if (defined $2 || defined $7) { @@ -5946,7 +6031,7 @@ sub process { } # check usleep_range arguments - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { my $min = $1; @@ -5962,7 +6047,7 @@ sub process { } # check for naked sscanf - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $line =~ /\bsscanf\b/ && ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && @@ -5976,7 +6061,7 @@ sub process { } # check for simple sscanf that should be kstrto<foo> - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $line =~ /\bsscanf\b/) { my $lc = $stat =~ tr@\n@@; @@ -6048,7 +6133,7 @@ sub process { } # check for function definitions - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) { $context_function = $1; @@ -6088,14 +6173,14 @@ sub process { # alloc style # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { CHK("ALLOC_SIZEOF_STRUCT", "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); } # check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { my $oldfunc = $3; @@ -6124,8 +6209,9 @@ sub process { } # check for krealloc arg reuse - if ($^V && $^V ge 5.10.0 && - $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) { + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ && + $1 eq $3) { WARN("KREALLOC_ARG_REUSE", "Reusing the krealloc arg is almost always a bug\n" . $herecurr); } @@ -6193,7 +6279,7 @@ sub process { } # check for switch/default statements without a break; - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { my $cnt = statement_rawlines($stat); @@ -6257,6 +6343,13 @@ sub process { "Avoid using bool as bitfield. Prefer bool bitfields as unsigned int or u<8|16|32>\n" . $herecurr); } +# check for bool use in .h files + if ($realfile =~ /\.h$/ && + $sline =~ /^.\s+bool\s*$Ident\s*(?::\s*d+\s*)?;/) { + CHK("BOOL_MEMBER", + "Avoid using bool structure members because of possible alignment issues - see: https://lkml.org/lkml/2017/11/21/384\n" . $herecurr); + } + # check for semaphores initialized locked if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { WARN("CONSIDER_COMPLETION", @@ -6303,7 +6396,7 @@ sub process { } # likely/unlikely comparisons similar to "(likely(foo) > 0)" - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { WARN("LIKELY_MISUSE", "Using $1 should generally have parentheses around the comparison\n" . $herecurr); @@ -6346,7 +6439,7 @@ sub process { # check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO> # and whether or not function naming is typical and if # DEVICE_ATTR permissions uses are unusual too - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) { my $var = $1; @@ -6406,7 +6499,7 @@ sub process { # specific definition of not visible in sysfs. # o Ignore proc_create*(...) uses with a decimal 0 permission as that means # use the default permissions - if ($^V && $^V ge 5.10.0 && + if ($perl_version_ok && defined $stat && $line =~ /$mode_perms_search/) { foreach my $entry (@mode_permission_funcs) { @@ -6492,9 +6585,14 @@ sub process { ERROR("NOT_UNIFIED_DIFF", "Does not appear to be a unified-diff format patch\n"); } - if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) { - ERROR("MISSING_SIGN_OFF", - "Missing Signed-off-by: line(s)\n"); + if ($is_patch && $has_commit_log && $chk_signoff) { + if ($signoff == 0) { + ERROR("MISSING_SIGN_OFF", + "Missing Signed-off-by: line(s)\n"); + } elsif (!$authorsignoff) { + WARN("NO_AUTHOR_SIGN_OFF", + "Missing Signed-off-by: line by nominal patch author '$author'\n"); + } } print report_dump(); diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index cbdf0dfd4c22..8081b6cf67d2 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -15,6 +15,7 @@ # M68k port by Geert Uytterhoeven and Andreas Schwab # AArch64, PARISC ports by Kyle McMartin # sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk> +# ppc64le port by Breno Leitao <leitao@debian.org> # # Usage: # objdump -d vmlinux | scripts/checkstack.pl [arch] @@ -78,13 +79,9 @@ my (@stack, $re, $dre, $x, $xs, $funcre); $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o; } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; - } elsif ($arch eq 'ppc') { - #c00029f4: 94 21 ff 30 stwu r1,-208(r1) - $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch eq 'ppc64') { - #XXX - $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch eq 'powerpc') { + } elsif ($arch eq 'powerpc' || $arch =~ /^ppc(64)?(le)?$/ ) { + # powerpc : 94 21 ff 30 stwu r1,-208(r1) + # ppc64(le) : 81 ff 21 f8 stdu r1,-128(r1) $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; } elsif ($arch =~ /^s390x?$/) { # 11160: a7 fb ff 60 aghi %r15,-160 diff --git a/scripts/clang-version.sh b/scripts/clang-version.sh index 9780efa56980..e65fbc3079d4 100755 --- a/scripts/clang-version.sh +++ b/scripts/clang-version.sh @@ -10,24 +10,14 @@ # clang-5.0.1 etc. # -if [ "$1" = "-p" ] ; then - with_patchlevel=1; - shift; -fi - compiler="$*" -if [ ${#compiler} -eq 0 ]; then - echo "Error: No compiler specified." - printf "Usage:\n\t$0 <clang-command>\n" +if ! ( $compiler --version | grep -q clang) ; then + echo 0 exit 1 fi MAJOR=$(echo __clang_major__ | $compiler -E -x c - | tail -n 1) MINOR=$(echo __clang_minor__ | $compiler -E -x c - | tail -n 1) -if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1) - printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL -else - printf "%02d%02d\\n" $MAJOR $MINOR -fi +PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1) +printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL diff --git a/scripts/coccicheck b/scripts/coccicheck index 9fedca611b7f..e04d328210ac 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -128,9 +128,10 @@ run_cmd_parmap() { fi echo $@ >>$DEBUG_FILE $@ 2>>$DEBUG_FILE - if [[ $? -ne 0 ]]; then + err=$? + if [[ $err -ne 0 ]]; then echo "coccicheck failed" - exit $? + exit $err fi } diff --git a/scripts/coccinelle/api/alloc/zalloc-simple.cocci b/scripts/coccinelle/api/alloc/zalloc-simple.cocci index 92b20913055f..d819275b7fde 100644 --- a/scripts/coccinelle/api/alloc/zalloc-simple.cocci +++ b/scripts/coccinelle/api/alloc/zalloc-simple.cocci @@ -35,8 +35,7 @@ statement S; * x = (T)\(kmalloc(E1, ...)\|vmalloc(E1)\|dma_alloc_coherent(...,E1,...)\| kmalloc_node(E1, ...)\|kmem_cache_alloc(...)\|kmem_alloc(E1, ...)\| - devm_kmalloc(...,E1,...)\|kvmalloc(E1, ...)\|pci_alloc_consistent(...,E1,...)\| - kvmalloc_node(E1,...)\); + devm_kmalloc(...,E1,...)\|kvmalloc(E1, ...)\|kvmalloc_node(E1,...)\); if ((x==NULL) || ...) S * memset((T2)x,0,E1); @@ -124,15 +123,6 @@ statement S; - x = (T)kvmalloc(E1,E2); + x = (T)kvzalloc(E1,E2); | -- x = pci_alloc_consistent(E2,E1,E3); -+ x = pci_zalloc_consistent(E2,E1,E3); -| -- x = (T *)pci_alloc_consistent(E2,E1,E3); -+ x = pci_zalloc_consistent(E2,E1,E3); -| -- x = (T)pci_alloc_consistent(E2,E1,E3); -+ x = (T)pci_zalloc_consistent(E2,E1,E3); -| - x = kvmalloc_node(E1,E2,E3); + x = kvzalloc_node(E1,E2,E3); | @@ -389,35 +379,6 @@ msg="WARNING: kvzalloc should be used for %s, instead of kvmalloc/memset" % (x) coccilib.report.print_report(p[0], msg) //----------------------------------------------------------------- -@r8 depends on org || report@ -type T, T2; -expression x; -expression E1,E2,E3; -statement S; -position p; -@@ - - x = (T)pci_alloc_consistent@p(E2,E1,E3); - if ((x==NULL) || ...) S - memset((T2)x,0,E1); - -@script:python depends on org@ -p << r8.p; -x << r8.x; -@@ - -msg="%s" % (x) -msg_safe=msg.replace("[","@(").replace("]",")") -coccilib.org.print_todo(p[0], msg_safe) - -@script:python depends on report@ -p << r8.p; -x << r8.x; -@@ - -msg="WARNING: pci_zalloc_consistent should be used for %s, instead of pci_alloc_consistent/memset" % (x) -coccilib.report.print_report(p[0], msg) -//----------------------------------------------------------------- @r9 depends on org || report@ type T, T2; expression x; diff --git a/scripts/coccinelle/api/atomic_as_refcounter.cocci b/scripts/coccinelle/api/atomic_as_refcounter.cocci new file mode 100644 index 000000000000..988120e0fd67 --- /dev/null +++ b/scripts/coccinelle/api/atomic_as_refcounter.cocci @@ -0,0 +1,129 @@ +// Check if refcount_t type and API should be used +// instead of atomic_t type when dealing with refcounters +// +// Copyright (c) 2016-2017, Elena Reshetova, Intel Corporation +// +// Confidence: Moderate +// URL: http://coccinelle.lip6.fr/ +// Options: --include-headers --very-quiet + +virtual report + +@r1 exists@ +identifier a, x; +position p1, p2; +identifier fname =~ ".*free.*"; +identifier fname2 =~ ".*destroy.*"; +identifier fname3 =~ ".*del.*"; +identifier fname4 =~ ".*queue_work.*"; +identifier fname5 =~ ".*schedule_work.*"; +identifier fname6 =~ ".*call_rcu.*"; + +@@ + +( + atomic_dec_and_test@p1(&(a)->x) +| + atomic_dec_and_lock@p1(&(a)->x, ...) +| + atomic_long_dec_and_lock@p1(&(a)->x, ...) +| + atomic_long_dec_and_test@p1(&(a)->x) +| + atomic64_dec_and_test@p1(&(a)->x) +| + local_dec_and_test@p1(&(a)->x) +) +... +( + fname@p2(a, ...); +| + fname2@p2(...); +| + fname3@p2(...); +| + fname4@p2(...); +| + fname5@p2(...); +| + fname6@p2(...); +) + + +@script:python depends on report@ +p1 << r1.p1; +p2 << r1.p2; +@@ +msg = "atomic_dec_and_test variation before object free at line %s." +coccilib.report.print_report(p1[0], msg % (p2[0].line)) + +@r4 exists@ +identifier a, x, y; +position p1, p2; +identifier fname =~ ".*free.*"; + +@@ + +( + atomic_dec_and_test@p1(&(a)->x) +| + atomic_dec_and_lock@p1(&(a)->x, ...) +| + atomic_long_dec_and_lock@p1(&(a)->x, ...) +| + atomic_long_dec_and_test@p1(&(a)->x) +| + atomic64_dec_and_test@p1(&(a)->x) +| + local_dec_and_test@p1(&(a)->x) +) +... +y=a +... +fname@p2(y, ...); + + +@script:python depends on report@ +p1 << r4.p1; +p2 << r4.p2; +@@ +msg = "atomic_dec_and_test variation before object free at line %s." +coccilib.report.print_report(p1[0], msg % (p2[0].line)) + +@r2 exists@ +identifier a, x; +position p1; +@@ + +( +atomic_add_unless(&(a)->x,-1,1)@p1 +| +atomic_long_add_unless(&(a)->x,-1,1)@p1 +| +atomic64_add_unless(&(a)->x,-1,1)@p1 +) + +@script:python depends on report@ +p1 << r2.p1; +@@ +msg = "atomic_add_unless" +coccilib.report.print_report(p1[0], msg) + +@r3 exists@ +identifier x; +position p1; +@@ + +( +x = atomic_add_return@p1(-1, ...); +| +x = atomic_long_add_return@p1(-1, ...); +| +x = atomic64_add_return@p1(-1, ...); +) + +@script:python depends on report@ +p1 << r3.p1; +@@ +msg = "x = atomic_add_return(-1, ...)" +coccilib.report.print_report(p1[0], msg) diff --git a/scripts/coccinelle/api/drm-get-put.cocci b/scripts/coccinelle/api/drm-get-put.cocci index ceb71ea7f61c..3a09c97ad87d 100644 --- a/scripts/coccinelle/api/drm-get-put.cocci +++ b/scripts/coccinelle/api/drm-get-put.cocci @@ -40,12 +40,6 @@ expression object; - drm_gem_object_unreference_unlocked(object) + drm_gem_object_put_unlocked(object) | -- drm_property_reference_blob(object) -+ drm_property_blob_get(object) -| -- drm_property_unreference_blob(object) -+ drm_property_blob_put(object) -| - drm_dev_unref(object) + drm_dev_put(object) ) @@ -72,10 +66,6 @@ __drm_gem_object_unreference(object) | drm_gem_object_unreference_unlocked(object) | -drm_property_unreference_blob@p(object) -| -drm_property_reference_blob@p(object) -| drm_dev_unref@p(object) ) diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci index 47f649b0ea87..19c6ee5b986b 100644 --- a/scripts/coccinelle/locks/mini_lock.cocci +++ b/scripts/coccinelle/locks/mini_lock.cocci @@ -67,12 +67,14 @@ identifier lock,unlock; @@ *lock(E1@p,...); -<+... when != E1 +... when != E1 + when any if (...) { ... when != E1 * return@r ...; } -...+> +... when != E1 + when any *unlock@up(E1,...); @script:python depends on org@ diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci index b16ccb7663a7..cbc6184e69ef 100644 --- a/scripts/coccinelle/null/deref_null.cocci +++ b/scripts/coccinelle/null/deref_null.cocci @@ -14,18 +14,10 @@ virtual context virtual org virtual report -@ifm@ -expression *E; -statement S1,S2; -position p1; -@@ - -if@p1 ((E == NULL && ...) || ...) S1 else S2 - // The following two rules are separate, because both can match a single // expression in different ways @pr1 expression@ -expression *ifm.E; +expression E; identifier f; position p1; @@ @@ -33,7 +25,7 @@ position p1; (E != NULL && ...) ? <+...E->f@p1...+> : ... @pr2 expression@ -expression *ifm.E; +expression E; identifier f; position p2; @@ @@ -46,6 +38,14 @@ position p2; sizeof(<+...E->f@p2...+>) ) +@ifm@ +expression *E; +statement S1,S2; +position p1; +@@ + +if@p1 ((E == NULL && ...) || ...) S1 else S2 + // For org and report modes @r depends on !context && (org || report) exists@ @@ -212,16 +212,8 @@ else S3 // The following three rules are duplicates of ifm, pr1 and pr2 respectively. // It is need because the previous rule as already made a "change". -@ifm1 depends on context && !org && !report@ -expression *E; -statement S1,S2; -position p1; -@@ - -if@p1 ((E == NULL && ...) || ...) S1 else S2 - @pr11 depends on context && !org && !report expression@ -expression *ifm1.E; +expression E; identifier f; position p1; @@ @@ -229,7 +221,7 @@ position p1; (E != NULL && ...) ? <+...E->f@p1...+> : ... @pr12 depends on context && !org && !report expression@ -expression *ifm1.E; +expression E; identifier f; position p2; @@ @@ -242,6 +234,14 @@ position p2; sizeof(<+...E->f@p2...+>) ) +@ifm1 depends on context && !org && !report@ +expression *E; +statement S1,S2; +position p1; +@@ + +if@p1 ((E == NULL && ...) || ...) S1 else S2 + @depends on context && !org && !report exists@ expression subE <= ifm1.E; expression *ifm1.E; diff --git a/scripts/coccinelle/tests/doubletest.cocci b/scripts/coccinelle/tests/doubletest.cocci index 78d74c22ca12..7af2ce7eb9bf 100644 --- a/scripts/coccinelle/tests/doubletest.cocci +++ b/scripts/coccinelle/tests/doubletest.cocci @@ -1,6 +1,7 @@ /// Find &&/|| operations that include the same argument more than once -//# A common source of false positives is when the argument performs a side -//# effect. +//# A common source of false positives is when the expression, or +//# another expresssion in the same && or || operation, performs a +//# side effect. /// // Confidence: Moderate // Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. @@ -20,20 +21,37 @@ position p; @@ ( -* E@p - || ... || E + E@p || ... || E | -* E@p - && ... && E + E@p && ... && E ) -@script:python depends on org@ +@bad@ +expression r.E,e1,e2,fn; +position r.p; +assignment operator op; +@@ + +( +E@p +& + <+... \(fn(...)\|e1 op e2\|e1++\|e1--\|++e1\|--e1\) ...+> +) + +@depends on context && !bad@ +expression r.E; +position r.p; +@@ + +*E@p + +@script:python depends on org && !bad@ p << r.p; @@ cocci.print_main("duplicated argument to && or ||",p) -@script:python depends on report@ +@script:python depends on report && !bad@ p << r.p; @@ diff --git a/scripts/depmod.sh b/scripts/depmod.sh index 9831cca31240..e083bcae343f 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -3,34 +3,22 @@ # # A depmod wrapper used by the toplevel Makefile -if test $# -ne 3; then - echo "Usage: $0 /sbin/depmod <kernelrelease> <symbolprefix>" >&2 +if test $# -ne 2; then + echo "Usage: $0 /sbin/depmod <kernelrelease>" >&2 exit 1 fi DEPMOD=$1 KERNELRELEASE=$2 -SYMBOL_PREFIX=$3 -if ! test -r System.map -a -x "$DEPMOD"; then +if ! test -r System.map ; then + echo "Warning: modules_install: missing 'System.map' file. Skipping depmod." >&2 exit 0 fi -# older versions of depmod don't support -P <symbol-prefix> -# support was added in module-init-tools 3.13 -if test -n "$SYMBOL_PREFIX"; then - release=$("$DEPMOD" --version) - package=$(echo "$release" | cut -d' ' -f 1) - if test "$package" = "module-init-tools"; then - version=$(echo "$release" | cut -d' ' -f 2) - later=$(printf '%s\n' "$version" "3.13" | sort -V | tail -n 1) - if test "$later" != "$version"; then - # module-init-tools < 3.13, drop the symbol prefix - SYMBOL_PREFIX="" - fi - fi - if test -n "$SYMBOL_PREFIX"; then - SYMBOL_PREFIX="-P $SYMBOL_PREFIX" - fi +if [ -z $(command -v $DEPMOD) ]; then + echo "Warning: 'make modules_install' requires $DEPMOD. Please install it." >&2 + echo "This is probably in the kmod package." >&2 + exit 0 fi # older versions of depmod require the version string to start with three @@ -55,7 +43,7 @@ set -- -ae -F System.map if test -n "$INSTALL_MOD_PATH"; then set -- "$@" -b "$INSTALL_MOD_PATH" fi -"$DEPMOD" "$@" "$KERNELRELEASE" $SYMBOL_PREFIX +"$DEPMOD" "$@" "$KERNELRELEASE" ret=$? if $depmod_hack_needed; then diff --git a/scripts/documentation-file-ref-check b/scripts/documentation-file-ref-check index bc1659900e89..ad9db6821824 100755 --- a/scripts/documentation-file-ref-check +++ b/scripts/documentation-file-ref-check @@ -1,15 +1,164 @@ -#!/bin/sh +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# # Treewide grep for references to files under Documentation, and report # non-existing files in stderr. -for f in $(git ls-files); do - for ref in $(grep -ho "Documentation/[A-Za-z0-9_.,~/*+-]*" "$f"); do - # presume trailing . and , are not part of the name - ref=${ref%%[.,]} - - # use ls to handle wildcards - if ! ls $ref >/dev/null 2>&1; then - echo "$f: $ref" >&2 - fi - done -done +use warnings; +use strict; +use Getopt::Long qw(:config no_auto_abbrev); + +my $scriptname = $0; +$scriptname =~ s,.*/([^/]+/),$1,; + +# Parse arguments +my $help = 0; +my $fix = 0; + +GetOptions( + 'fix' => \$fix, + 'h|help|usage' => \$help, +); + +if ($help != 0) { + print "$scriptname [--help] [--fix]\n"; + exit -1; +} + +# Step 1: find broken references +print "Finding broken references. This may take a while... " if ($fix); + +my %broken_ref; + +open IN, "git grep 'Documentation/'|" + or die "Failed to run git grep"; +while (<IN>) { + next if (!m/^([^:]+):(.*)/); + + my $f = $1; + my $ln = $2; + + # Makefiles and scripts contain nasty expressions to parse docs + next if ($f =~ m/Makefile/ || $f =~ m/\.sh$/); + + # Skip this script + next if ($f eq $scriptname); + + if ($ln =~ m,\b(\S*)(Documentation/[A-Za-z0-9\_\.\,\~/\*\[\]\?+-]*)(.*),) { + my $prefix = $1; + my $ref = $2; + my $base = $2; + my $extra = $3; + + # some file references are like: + # /usr/src/linux/Documentation/DMA-{API,mapping}.txt + # For now, ignore them + next if ($extra =~ m/^{/); + + # Remove footnotes at the end like: + # Documentation/devicetree/dt-object-internal.txt[1] + $ref =~ s/(txt|rst)\[\d+]$/$1/; + + # Remove ending ']' without any '[' + $ref =~ s/\].*// if (!($ref =~ m/\[/)); + + # Remove puntuation marks at the end + $ref =~ s/[\,\.]+$//; + + my $fulref = "$prefix$ref"; + + $fulref =~ s/^(\<file|ref)://; + $fulref =~ s/^[\'\`]+//; + $fulref =~ s,^\$\(.*\)/,,; + $base =~ s,.*/,,; + + # Remove URL false-positives + next if ($fulref =~ m/^http/); + + # Remove sched-pelt false-positive + next if ($fulref =~ m,^Documentation/scheduler/sched-pelt$,); + + # Discard some build examples from Documentation/target/tcm_mod_builder.txt + next if ($fulref =~ m,mnt/sdb/lio-core-2.6.git/Documentation/target,); + + # Check if exists, evaluating wildcards + next if (grep -e, glob("$ref $fulref")); + + # Accept relative Documentation patches for tools/ + if ($f =~ m/tools/) { + my $path = $f; + $path =~ s,(.*)/.*,$1,; + next if (grep -e, glob("$path/$ref $path/$fulref")); + } + + if ($fix) { + if (!($ref =~ m/(scripts|Kconfig|Kbuild)/)) { + $broken_ref{$ref}++; + } + } else { + print STDERR "$f: $fulref\n"; + } + } +} + +exit 0 if (!$fix); + +# Step 2: Seek for file name alternatives +print "Auto-fixing broken references. Please double-check the results\n"; + +foreach my $ref (keys %broken_ref) { + my $new =$ref; + + # get just the basename + $new =~ s,.*/,,; + + my $f=""; + + # usual reason for breakage: DT file moved around + if ($ref =~ /devicetree/) { + my $search = $new; + $search =~ s,^.*/,,; + $f = qx(find Documentation/devicetree/ -iname "*$search*") if ($search); + if (!$f) { + # Manufacturer name may have changed + $search =~ s/^.*,//; + $f = qx(find Documentation/devicetree/ -iname "*$search*") if ($search); + } + } + + # usual reason for breakage: file renamed to .rst + if (!$f) { + $new =~ s/\.txt$/.rst/; + $f=qx(find . -iname $new) if ($new); + } + + # usual reason for breakage: use dash or underline + if (!$f) { + $new =~ s/[-_]/[-_]/g; + $f=qx(find . -iname $new) if ($new); + } + + # Wild guess: seek for the same name on another place + if (!$f) { + $f = qx(find . -iname $new) if ($new); + } + + my @find = split /\s+/, $f; + + if (!$f) { + print STDERR "ERROR: Didn't find a replacement for $ref\n"; + } elsif (scalar(@find) > 1) { + print STDERR "WARNING: Won't auto-replace, as found multiple files close to $ref:\n"; + foreach my $j (@find) { + $j =~ s,^./,,; + print STDERR " $j\n"; + } + } else { + $f = $find[0]; + $f =~ s,^./,,; + print "INFO: Replacing $ref to $f\n"; + foreach my $j (qx(git grep -l $ref)) { + qx(sed "s\@$ref\@$f\@g" -i $j); + } + } +} diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 9cac65b7419c..056d5da6c477 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # scripts/dtc makefile -hostprogs-y := dtc +hostprogs-$(CONFIG_DTC) := dtc always := $(hostprogs-y) dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ @@ -9,21 +9,18 @@ dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o # Source files need to get at the userspace version of libfdt_env.h to compile +HOST_EXTRACFLAGS := -I$(src)/libfdt -HOSTCFLAGS_DTC := -I$(src) -I$(src)/libfdt +ifeq ($(wildcard /usr/include/yaml.h),) +HOST_EXTRACFLAGS += -DNO_YAML +else +dtc-objs += yamltree.o +HOSTLDLIBS_dtc := -lyaml +endif -HOSTCFLAGS_checks.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_data.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_dtc.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_flattree.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC) - -HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC) -HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC) +# Generated files need one more search path to include headers in source tree +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/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc index bece49b35535..d4375630a7f7 100644 --- a/scripts/dtc/Makefile.dtc +++ b/scripts/dtc/Makefile.dtc @@ -14,5 +14,9 @@ DTC_SRCS = \ treesource.c \ util.c +ifneq ($(NO_YAML),1) +DTC_SRCS += yamltree.c +endif + DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 815eaf140ab5..9c9b0c328af6 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -255,7 +255,7 @@ static void check_duplicate_node_names(struct check *c, struct dt_info *dti, child2; child2 = child2->next_sibling) if (streq(child->name, child2->name)) - FAIL(c, dti, node, "Duplicate node name"); + FAIL(c, dti, child2, "Duplicate node name"); } ERROR(duplicate_node_names, check_duplicate_node_names, NULL); @@ -317,6 +317,11 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, const char *unitname = get_unitname(node); struct property *prop = get_property(node, "reg"); + if (get_subnode(node, "__overlay__")) { + /* HACK: Overlay fragments are a special case */ + return; + } + if (!prop) { prop = get_property(node, "ranges"); if (prop && !prop->val.len) @@ -579,6 +584,8 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti, phandle = get_node_phandle(dt, refnode); *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); + + reference_node(refnode); } } } @@ -609,11 +616,21 @@ static void fixup_path_references(struct check *c, struct dt_info *dti, path = refnode->fullpath; prop->val = data_insert_at_marker(prop->val, m, path, strlen(path) + 1); + + reference_node(refnode); } } } ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names); +static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti, + struct node *node) +{ + if (node->omit_if_unused && !node->is_referenced) + delete_node(node); +} +ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &path_references); + /* * Semantic checks */ @@ -945,6 +962,143 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no } WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); +static const struct bus_type i2c_bus = { + .name = "i2c-bus", +}; + +static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) +{ + if (strprefixeq(node->name, node->basenamelen, "i2c-bus") || + strprefixeq(node->name, node->basenamelen, "i2c-arb")) { + node->bus = &i2c_bus; + } else if (strprefixeq(node->name, node->basenamelen, "i2c")) { + struct node *child; + for_each_child(node, child) { + if (strprefixeq(child->name, node->basenamelen, "i2c-bus")) + return; + } + node->bus = &i2c_bus; + } else + return; + + if (!node->children) + return; + + if (node_addr_cells(node) != 1) + FAIL(c, dti, node, "incorrect #address-cells for I2C bus"); + if (node_size_cells(node) != 0) + FAIL(c, dti, node, "incorrect #size-cells for I2C bus"); + +} +WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells); + +static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + const char *unitname = get_unitname(node); + char unit_addr[17]; + uint32_t reg = 0; + int len; + cell_t *cells = NULL; + + if (!node->parent || (node->parent->bus != &i2c_bus)) + return; + + prop = get_property(node, "reg"); + if (prop) + cells = (cell_t *)prop->val.val; + + if (!cells) { + FAIL(c, dti, node, "missing or empty reg property"); + return; + } + + reg = fdt32_to_cpu(*cells); + snprintf(unit_addr, sizeof(unit_addr), "%x", reg); + if (!streq(unitname, unit_addr)) + FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"", + unit_addr); + + for (len = prop->val.len; len > 0; len -= 4) { + reg = fdt32_to_cpu(*(cells++)); + if (reg > 0x3ff) + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"", + reg); + + } +} +WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge); + +static const struct bus_type spi_bus = { + .name = "spi-bus", +}; + +static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node) +{ + + if (strprefixeq(node->name, node->basenamelen, "spi")) { + node->bus = &spi_bus; + } else { + /* Try to detect SPI buses which don't have proper node name */ + struct node *child; + + if (node_addr_cells(node) != 1 || node_size_cells(node) != 0) + return; + + for_each_child(node, child) { + struct property *prop; + for_each_property(child, prop) { + if (strprefixeq(prop->name, 4, "spi-")) { + node->bus = &spi_bus; + break; + } + } + if (node->bus == &spi_bus) + break; + } + + if (node->bus == &spi_bus && get_property(node, "reg")) + FAIL(c, dti, node, "node name for SPI buses should be 'spi'"); + } + if (node->bus != &spi_bus || !node->children) + return; + + if (node_addr_cells(node) != 1) + FAIL(c, dti, node, "incorrect #address-cells for SPI bus"); + if (node_size_cells(node) != 0) + FAIL(c, dti, node, "incorrect #size-cells for SPI bus"); + +} +WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells); + +static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node) +{ + struct property *prop; + const char *unitname = get_unitname(node); + char unit_addr[9]; + uint32_t reg = 0; + cell_t *cells = NULL; + + if (!node->parent || (node->parent->bus != &spi_bus)) + return; + + prop = get_property(node, "reg"); + if (prop) + cells = (cell_t *)prop->val.val; + + if (!cells) { + FAIL(c, dti, node, "missing or empty reg property"); + return; + } + + reg = fdt32_to_cpu(*cells); + snprintf(unit_addr, sizeof(unit_addr), "%x", reg); + if (!streq(unitname, unit_addr)) + FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"", + unit_addr); +} +WARNING(spi_bus_reg, check_spi_bus_reg, NULL, ®_format, &spi_bus_bridge); + static void check_unit_address_format(struct check *c, struct dt_info *dti, struct node *node) { @@ -1017,6 +1171,36 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d } WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); +static void check_unique_unit_address(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct node *childa; + + if (node->addr_cells < 0 || node->size_cells < 0) + return; + + if (!node->children) + return; + + for_each_child(node, childa) { + struct node *childb; + const char *addr_a = get_unitname(childa); + + if (!strlen(addr_a)) + continue; + + for_each_child(node, childb) { + const char *addr_b = get_unitname(childb); + if (childa == childb) + break; + + if (streq(addr_a, addr_b)) + FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath); + } + } +} +WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size); + static void check_obsolete_chosen_interrupt_controller(struct check *c, struct dt_info *dti, struct node *node) @@ -1357,6 +1541,152 @@ static void check_interrupts_property(struct check *c, } WARNING(interrupts_property, check_interrupts_property, &phandle_references); +static const struct bus_type graph_port_bus = { + .name = "graph-port", +}; + +static const struct bus_type graph_ports_bus = { + .name = "graph-ports", +}; + +static void check_graph_nodes(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct node *child; + + for_each_child(node, child) { + if (!(strprefixeq(child->name, child->basenamelen, "endpoint") || + get_property(child, "remote-endpoint"))) + continue; + + node->bus = &graph_port_bus; + + /* The parent of 'port' nodes can be either 'ports' or a device */ + if (!node->parent->bus && + (streq(node->parent->name, "ports") || get_property(node, "reg"))) + node->parent->bus = &graph_ports_bus; + + break; + } + +} +WARNING(graph_nodes, check_graph_nodes, NULL); + +static void check_graph_child_address(struct check *c, struct dt_info *dti, + struct node *node) +{ + int cnt = 0; + struct node *child; + + if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus) + return; + + for_each_child(node, child) { + struct property *prop = get_property(child, "reg"); + + /* No error if we have any non-zero unit address */ + if (prop && propval_cell(prop) != 0) + return; + + cnt++; + } + + if (cnt == 1 && node->addr_cells != -1) + FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary", + node->children->name); +} +WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes); + +static void check_graph_reg(struct check *c, struct dt_info *dti, + struct node *node) +{ + char unit_addr[9]; + const char *unitname = get_unitname(node); + struct property *prop; + + prop = get_property(node, "reg"); + if (!prop || !unitname) + return; + + if (!(prop->val.val && prop->val.len == sizeof(cell_t))) { + FAIL(c, dti, node, "graph node malformed 'reg' property"); + return; + } + + snprintf(unit_addr, sizeof(unit_addr), "%x", propval_cell(prop)); + if (!streq(unitname, unit_addr)) + FAIL(c, dti, node, "graph node unit address error, expected \"%s\"", + unit_addr); + + if (node->parent->addr_cells != 1) + FAIL_PROP(c, dti, node, get_property(node, "#address-cells"), + "graph node '#address-cells' is %d, must be 1", + node->parent->addr_cells); + if (node->parent->size_cells != 0) + FAIL_PROP(c, dti, node, get_property(node, "#size-cells"), + "graph node '#size-cells' is %d, must be 0", + node->parent->size_cells); +} + +static void check_graph_port(struct check *c, struct dt_info *dti, + struct node *node) +{ + if (node->bus != &graph_port_bus) + return; + + if (!strprefixeq(node->name, node->basenamelen, "port")) + FAIL(c, dti, node, "graph port node name should be 'port'"); + + check_graph_reg(c, dti, node); +} +WARNING(graph_port, check_graph_port, NULL, &graph_nodes); + +static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, + struct node *endpoint) +{ + int phandle; + struct node *node; + struct property *prop; + + prop = get_property(endpoint, "remote-endpoint"); + if (!prop) + return NULL; + + phandle = propval_cell(prop); + /* Give up if this is an overlay with external references */ + if (phandle == 0 || phandle == -1) + return NULL; + + node = get_node_by_phandle(dti->dt, phandle); + if (!node) + FAIL_PROP(c, dti, endpoint, prop, "graph phandle is not valid"); + + return node; +} + +static void check_graph_endpoint(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct node *remote_node; + + if (!node->parent || node->parent->bus != &graph_port_bus) + return; + + if (!strprefixeq(node->name, node->basenamelen, "endpoint")) + FAIL(c, dti, node, "graph endpont node name should be 'endpoint'"); + + check_graph_reg(c, dti, node); + + remote_node = get_remote_endpoint(c, dti, node); + if (!remote_node) + return; + + if (get_remote_endpoint(c, dti, remote_node) != node) + FAIL(c, dti, node, "graph connection to node '%s' is not bidirectional", + remote_node->fullpath); +} +WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes); + static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, @@ -1366,6 +1696,7 @@ static struct check *check_table[] = { &explicit_phandles, &phandle_references, &path_references, + &omit_unused_nodes, &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, &device_type_is_string, &model_is_string, &status_is_string, @@ -1388,8 +1719,15 @@ static struct check *check_table[] = { &simple_bus_bridge, &simple_bus_reg, + &i2c_bus_bridge, + &i2c_bus_reg, + + &spi_bus_bridge, + &spi_bus_reg, + &avoid_default_addr_size, &avoid_unnecessary_addr_size, + &unique_unit_address, &obsolete_chosen_interrupt_controller, &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, @@ -1416,6 +1754,8 @@ static struct check *check_table[] = { &alias_paths, + &graph_nodes, &graph_child_address, &graph_port, &graph_endpoint, + &always_fail, }; diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index aa37a16c8891..4a204145cc7b 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -74,7 +74,8 @@ struct data data_copy_escape_string(const char *s, int len) struct data d; char *q; - d = data_grow_for(empty_data, len + 1); + d = data_add_marker(empty_data, TYPE_STRING, NULL); + d = data_grow_for(d, len + 1); q = d.val; while (i < len) { @@ -94,6 +95,7 @@ struct data data_copy_file(FILE *f, size_t maxlen) { struct data d = empty_data; + d = data_add_marker(d, TYPE_NONE, NULL); while (!feof(f) && (d.len < maxlen)) { size_t chunksize, ret; diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index fd825ebba69c..615b7ec6588f 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -153,6 +153,13 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_DEL_NODE; } +<*>"/omit-if-no-ref/" { + DPRINT("Keyword: /omit-if-no-ref/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_OMIT_NO_REF; + } + <*>{LABEL}: { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 44af170abfea..dd70ebf386f4 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -63,6 +63,7 @@ extern bool treesource_error; %token DT_BITS %token DT_DEL_PROP %token DT_DEL_NODE +%token DT_OMIT_NO_REF %token <propnodename> DT_PROPNODENAME %token <integer> DT_LITERAL %token <integer> DT_CHAR_LITERAL @@ -190,18 +191,18 @@ devicetree: } | devicetree DT_REF nodedef { - struct node *target = get_node_by_ref($1, $2); - - if (target) { - merge_nodes(target, $3); + /* + * We rely on the rule being always: + * versioninfo plugindecl memreserves devicetree + * so $-1 is what we want (plugindecl) + */ + if ($<flags>-1 & DTSF_PLUGIN) { + add_orphan_node($1, $3, $2); } else { - /* - * We rely on the rule being always: - * versioninfo plugindecl memreserves devicetree - * so $-1 is what we want (plugindecl) - */ - if ($<flags>-1 & DTSF_PLUGIN) - add_orphan_node($1, $3, $2); + struct node *target = get_node_by_ref($1, $2); + + if (target) + merge_nodes(target, $3); else ERROR(&@2, "Label or path %s not found", $2); } @@ -219,6 +220,18 @@ devicetree: $$ = $1; } + | devicetree DT_OMIT_NO_REF DT_REF ';' + { + struct node *target = get_node_by_ref($1, $3); + + if (target) + omit_node_if_unused(target); + else + ERROR(&@3, "Label or path %s not found", $3); + + + $$ = $1; + } ; nodedef: @@ -274,6 +287,7 @@ propdata: } | propdataprefix DT_REF { + $1 = data_add_marker($1, TYPE_STRING, $2); $$ = data_add_marker($1, REF_PATH, $2); } | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' @@ -327,22 +341,27 @@ arrayprefix: DT_BITS DT_LITERAL '<' { unsigned long long bits; + enum markertype type = TYPE_UINT32; bits = $2; - if ((bits != 8) && (bits != 16) && - (bits != 32) && (bits != 64)) { + switch (bits) { + case 8: type = TYPE_UINT8; break; + case 16: type = TYPE_UINT16; break; + case 32: type = TYPE_UINT32; break; + case 64: type = TYPE_UINT64; break; + default: ERROR(&@2, "Array elements must be" " 8, 16, 32 or 64-bits"); bits = 32; } - $$.data = empty_data; + $$.data = data_add_marker(empty_data, type, NULL); $$.bits = bits; } | '<' { - $$.data = empty_data; + $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL); $$.bits = 32; } | arrayprefix integer_prim @@ -486,7 +505,7 @@ integer_unary: bytestring: /* empty */ { - $$ = empty_data; + $$ = data_add_marker(empty_data, TYPE_UINT8, NULL); } | bytestring DT_BYTE { @@ -523,6 +542,10 @@ subnode: { $$ = name_node(build_node_delete(), $2); } + | DT_OMIT_NO_REF subnode + { + $$ = omit_node_if_unused($2); + } | DT_LABEL subnode { add_label(&$2->labels, $1); diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index c36994e6eac5..64134aadb997 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -95,6 +95,9 @@ static const char * const usage_opts_help[] = { "\n\tOutput formats are:\n" "\t\tdts - device tree source text\n" "\t\tdtb - device tree blob\n" +#ifndef NO_YAML + "\t\tyaml - device tree encoded as YAML\n" +#endif "\t\tasm - assembler source", "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)", "\n\tOutput dependency file", @@ -128,6 +131,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback) return fallback; if (!strcasecmp(s, ".dts")) return "dts"; + if (!strcasecmp(s, ".yaml")) + return "yaml"; if (!strcasecmp(s, ".dtb")) return "dtb"; return fallback; @@ -350,6 +355,12 @@ int main(int argc, char *argv[]) if (streq(outform, "dts")) { dt_to_source(outf, dti); +#ifndef NO_YAML + } else if (streq(outform, "yaml")) { + if (!streq(inform, "dts")) + die("YAML output format requires dts input format\n"); + dt_to_yaml(outf, dti); +#endif } else if (streq(outform, "dtb")) { dt_to_blob(outf, dti, outversion); } else if (streq(outform, "asm")) { diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 3b18a42b866e..cbe541525c2c 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -74,10 +74,17 @@ typedef uint32_t cell_t; /* Data blobs */ enum markertype { + TYPE_NONE, REF_PHANDLE, REF_PATH, LABEL, + TYPE_UINT8, + TYPE_UINT16, + TYPE_UINT32, + TYPE_UINT64, + TYPE_STRING, }; +extern const char *markername(enum markertype markertype); struct marker { enum markertype type; @@ -101,6 +108,8 @@ struct data { for_each_marker(m) \ if ((m)->type == (t)) +size_t type_marker_length(struct marker *m); + void data_free(struct data d); struct data data_grow_for(struct data d, int xlen); @@ -168,6 +177,8 @@ struct node { struct label *labels; const struct bus_type *bus; + + bool omit_if_unused, is_referenced; }; #define for_each_label_withdel(l0, l) \ @@ -202,6 +213,8 @@ struct property *reverse_properties(struct property *first); struct node *build_node(struct property *proplist, struct node *children); struct node *build_node_delete(void); struct node *name_node(struct node *node, char *name); +struct node *omit_node_if_unused(struct node *node); +struct node *reference_node(struct node *node); struct node *chain_node(struct node *first, struct node *list); struct node *merge_nodes(struct node *old_node, struct node *new_node); struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref); @@ -286,6 +299,10 @@ struct dt_info *dt_from_blob(const char *fname); void dt_to_source(FILE *f, struct dt_info *dti); struct dt_info *dt_from_source(const char *f); +/* YAML source */ + +void dt_to_yaml(FILE *f, struct dt_info *dti); + /* FS trees */ struct dt_info *dt_from_fs(const char *dirname); diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 8d268fb785db..851ea87dbc0f 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -393,7 +393,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version) padlen = 0; if (quiet < 1) fprintf(stderr, - "Warning: blob size %d >= minimum size %d\n", + "Warning: blob size %"PRIu32" >= minimum size %d\n", fdt32_to_cpu(fdt.totalsize), minsize); } } diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 7855a1787763..ae03b1112961 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -55,7 +55,12 @@ #include "libfdt_internal.h" -int fdt_check_header(const void *fdt) +/* + * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks + * that the given buffer contains what appears to be a flattened + * device tree with sane information in its header. + */ +int fdt_ro_probe_(const void *fdt) { if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ @@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt) return 0; } +static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) +{ + return (off >= hdrsize) && (off <= totalsize); +} + +static int check_block_(uint32_t hdrsize, uint32_t totalsize, + uint32_t base, uint32_t size) +{ + if (!check_off_(hdrsize, totalsize, base)) + return 0; /* block start out of bounds */ + if ((base + size) < base) + return 0; /* overflow */ + if (!check_off_(hdrsize, totalsize, base + size)) + return 0; /* block end out of bounds */ + return 1; +} + +size_t fdt_header_size_(uint32_t version) +{ + if (version <= 1) + return FDT_V1_SIZE; + else if (version <= 2) + return FDT_V2_SIZE; + else if (version <= 3) + return FDT_V3_SIZE; + else if (version <= 16) + return FDT_V16_SIZE; + else + return FDT_V17_SIZE; +} + +int fdt_check_header(const void *fdt) +{ + size_t hdrsize; + + if (fdt_magic(fdt) != FDT_MAGIC) + return -FDT_ERR_BADMAGIC; + hdrsize = fdt_header_size(fdt); + if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)) + return -FDT_ERR_BADVERSION; + if (fdt_version(fdt) < fdt_last_comp_version(fdt)) + return -FDT_ERR_BADVERSION; + + if ((fdt_totalsize(fdt) < hdrsize) + || (fdt_totalsize(fdt) > INT_MAX)) + return -FDT_ERR_TRUNCATED; + + /* Bounds check memrsv block */ + if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt))) + return -FDT_ERR_TRUNCATED; + + /* Bounds check structure block */ + if (fdt_version(fdt) < 17) { + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } else { + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } + + /* Bounds check strings block */ + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt))) + return -FDT_ERR_TRUNCATED; + + return 0; +} + const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { unsigned absoffset = offset + fdt_off_dt_struct(fdt); @@ -244,7 +321,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c index eff4dbcc729d..49537b578d03 100644 --- a/scripts/dtc/libfdt/fdt_addresses.c +++ b/scripts/dtc/libfdt/fdt_addresses.c @@ -1,6 +1,7 @@ /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> + * Copyright (C) 2018 embedded brains GmbH * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -55,42 +56,32 @@ #include "libfdt_internal.h" -int fdt_address_cells(const void *fdt, int nodeoffset) +static int fdt_cells(const void *fdt, int nodeoffset, const char *name) { - const fdt32_t *ac; + const fdt32_t *c; int val; int len; - ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); - if (!ac) + c = fdt_getprop(fdt, nodeoffset, name, &len); + if (!c) return 2; - if (len != sizeof(*ac)) + if (len != sizeof(*c)) return -FDT_ERR_BADNCELLS; - val = fdt32_to_cpu(*ac); + val = fdt32_to_cpu(*c); if ((val <= 0) || (val > FDT_MAX_NCELLS)) return -FDT_ERR_BADNCELLS; return val; } -int fdt_size_cells(const void *fdt, int nodeoffset) +int fdt_address_cells(const void *fdt, int nodeoffset) { - const fdt32_t *sc; - int val; - int len; - - sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); - if (!sc) - return 2; - - if (len != sizeof(*sc)) - return -FDT_ERR_BADNCELLS; - - val = fdt32_to_cpu(*sc); - if ((val < 0) || (val > FDT_MAX_NCELLS)) - return -FDT_ERR_BADNCELLS; + return fdt_cells(fdt, nodeoffset, "#address-cells"); +} - return val; +int fdt_size_cells(const void *fdt, int nodeoffset) +{ + return fdt_cells(fdt, nodeoffset, "#size-cells"); } diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c index bf75388ec9a2..5fdab6c6371d 100644 --- a/scripts/dtc/libfdt/fdt_overlay.c +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -697,7 +697,7 @@ static int get_path_len(const void *fdt, int nodeoffset) int len = 0, namelen; const char *name; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); for (;;) { name = fdt_get_name(fdt, nodeoffset, &namelen); @@ -866,8 +866,8 @@ int fdt_overlay_apply(void *fdt, void *fdto) uint32_t delta = fdt_get_max_phandle(fdt); int ret; - FDT_CHECK_HEADER(fdt); - FDT_CHECK_HEADER(fdto); + FDT_RO_PROBE(fdt); + FDT_RO_PROBE(fdto); ret = overlay_adjust_local_phandles(fdto, delta); if (ret) diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index dfb3236da388..eafc14282892 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -76,17 +76,72 @@ static int fdt_nodename_eq_(const void *fdt, int offset, return 0; } +const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) +{ + uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt); + size_t len; + int err; + const char *s, *n; + + err = fdt_ro_probe_(fdt); + if (err != 0) + goto fail; + + err = -FDT_ERR_BADOFFSET; + if (absoffset >= fdt_totalsize(fdt)) + goto fail; + len = fdt_totalsize(fdt) - absoffset; + + if (fdt_magic(fdt) == FDT_MAGIC) { + if (stroffset < 0) + goto fail; + if (fdt_version(fdt) >= 17) { + if (stroffset >= fdt_size_dt_strings(fdt)) + goto fail; + if ((fdt_size_dt_strings(fdt) - stroffset) < len) + len = fdt_size_dt_strings(fdt) - stroffset; + } + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + if ((stroffset >= 0) + || (stroffset < -fdt_size_dt_strings(fdt))) + goto fail; + if ((-stroffset) < len) + len = -stroffset; + } else { + err = -FDT_ERR_INTERNAL; + goto fail; + } + + s = (const char *)fdt + absoffset; + n = memchr(s, '\0', len); + if (!n) { + /* missing terminating NULL */ + err = -FDT_ERR_TRUNCATED; + goto fail; + } + + if (lenp) + *lenp = n - s; + return s; + +fail: + if (lenp) + *lenp = err; + return NULL; +} + const char *fdt_string(const void *fdt, int stroffset) { - return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + return fdt_get_string(fdt, stroffset, NULL); } static int fdt_string_eq_(const void *fdt, int stroffset, const char *s, int len) { - const char *p = fdt_string(fdt, stroffset); + int slen; + const char *p = fdt_get_string(fdt, stroffset, &slen); - return (strlen(p) == len) && (memcmp(p, s, len) == 0); + return p && (slen == len) && (memcmp(p, s, len) == 0); } uint32_t fdt_get_max_phandle(const void *fdt) @@ -115,21 +170,42 @@ uint32_t fdt_get_max_phandle(const void *fdt) return 0; } +static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) +{ + int offset = n * sizeof(struct fdt_reserve_entry); + int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + + if (absoffset < fdt_off_mem_rsvmap(fdt)) + return NULL; + if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry)) + return NULL; + return fdt_mem_rsv_(fdt, n); +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { - FDT_CHECK_HEADER(fdt); - *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); - *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); + const struct fdt_reserve_entry *re; + + FDT_RO_PROBE(fdt); + re = fdt_mem_rsv(fdt, n); + if (!re) + return -FDT_ERR_BADOFFSET; + + *address = fdt64_ld(&re->address); + *size = fdt64_ld(&re->size); return 0; } int fdt_num_mem_rsv(const void *fdt) { - int i = 0; + int i; + const struct fdt_reserve_entry *re; - while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) - i++; - return i; + for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { + if (fdt64_ld(&re->size) == 0) + return i; + } + return -FDT_ERR_TRUNCATED; } static int nextprop_(const void *fdt, int offset) @@ -161,7 +237,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, { int depth; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); for (depth = 0; (offset >= 0) && (depth >= 0); @@ -187,7 +263,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) const char *p = path; int offset = 0; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* see if we have an alias */ if (*path != '/') { @@ -237,7 +313,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) const char *nameptr; int err; - if (((err = fdt_check_header(fdt)) != 0) + if (((err = fdt_ro_probe_(fdt)) != 0) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) goto fail; @@ -303,7 +379,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, prop = fdt_offset_ptr_(fdt, offset); if (lenp) - *lenp = fdt32_to_cpu(prop->len); + *lenp = fdt32_ld(&prop->len); return prop; } @@ -340,7 +416,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, offset = -FDT_ERR_INTERNAL; break; } - if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), + if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; @@ -393,7 +469,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, /* Handle realignment */ if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && - fdt32_to_cpu(prop->len) >= 8) + fdt32_ld(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -406,12 +482,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, prop = fdt_get_property_by_offset_(fdt, offset, lenp); if (!prop) return NULL; - if (namep) - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + if (namep) { + const char *name; + int namelen; + name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), + &namelen); + if (!name) { + if (lenp) + *lenp = namelen; + return NULL; + } + *namep = name; + } /* Handle realignment */ if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && - fdt32_to_cpu(prop->len) >= 8) + fdt32_ld(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -436,7 +522,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return 0; } - return fdt32_to_cpu(*php); + return fdt32_ld(php); } const char *fdt_get_alias_namelen(const void *fdt, @@ -462,7 +548,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) int offset, depth, namelen; const char *name; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; @@ -514,7 +600,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; @@ -573,7 +659,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const void *val; int len; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't @@ -599,7 +685,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we * potentially scan each property of a node in @@ -752,7 +838,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, { int offset, err; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if @@ -771,3 +857,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, return offset; /* error from fdt_next_node() */ } + +int fdt_check_full(const void *fdt, size_t bufsize) +{ + int err; + int num_memrsv; + int offset, nextoffset = 0; + uint32_t tag; + unsigned depth = 0; + const void *prop; + const char *propname; + + if (bufsize < FDT_V1_SIZE) + return -FDT_ERR_TRUNCATED; + err = fdt_check_header(fdt); + if (err != 0) + return err; + if (bufsize < fdt_totalsize(fdt)) + return -FDT_ERR_TRUNCATED; + + num_memrsv = fdt_num_mem_rsv(fdt); + if (num_memrsv < 0) + return num_memrsv; + + while (1) { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + if (nextoffset < 0) + return nextoffset; + + switch (tag) { + case FDT_NOP: + break; + + case FDT_END: + if (depth != 0) + return -FDT_ERR_BADSTRUCTURE; + return 0; + + case FDT_BEGIN_NODE: + depth++; + if (depth > INT_MAX) + return -FDT_ERR_BADSTRUCTURE; + break; + + case FDT_END_NODE: + if (depth == 0) + return -FDT_ERR_BADSTRUCTURE; + depth--; + break; + + case FDT_PROP: + prop = fdt_getprop_by_offset(fdt, offset, &propname, + &err); + if (!prop) + return err; + break; + + default: + return -FDT_ERR_INTERNAL; + } + } +} diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 9b829051e444..2e49855d7cf8 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -67,9 +67,9 @@ static int fdt_blocks_misordered_(const void *fdt, (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } -static int fdt_rw_check_header_(void *fdt) +static int fdt_rw_probe_(void *fdt) { - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; @@ -82,10 +82,10 @@ static int fdt_rw_check_header_(void *fdt) return 0; } -#define FDT_RW_CHECK_HEADER(fdt) \ +#define FDT_RW_PROBE(fdt) \ { \ int err_; \ - if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ + if ((err_ = fdt_rw_probe_(fdt)) != 0) \ return err_; \ } @@ -176,7 +176,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) struct fdt_reserve_entry *re; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); err = fdt_splice_mem_rsv_(fdt, re, 0, 1); @@ -192,7 +192,7 @@ int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; @@ -252,7 +252,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) int oldlen, newlen; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); if (!namep) @@ -275,7 +275,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, struct fdt_property *prop; int err; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) @@ -308,7 +308,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, struct fdt_property *prop; int err, oldlen, newlen; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (prop) { @@ -334,7 +334,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) struct fdt_property *prop; int len, proplen; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (!prop) @@ -354,7 +354,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, uint32_t tag; fdt32_t *endtag; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) @@ -394,7 +394,7 @@ int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); endoffset = fdt_node_end_offset_(fdt, nodeoffset); if (endoffset < 0) @@ -435,7 +435,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; - FDT_CHECK_HEADER(fdt); + FDT_RO_PROBE(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); @@ -494,7 +494,7 @@ int fdt_pack(void *fdt) { int mem_rsv_size; - FDT_RW_CHECK_HEADER(fdt); + FDT_RW_PROBE(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 6d33cc29d022..9fa4a94d83c3 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -55,21 +55,77 @@ #include "libfdt_internal.h" -static int fdt_sw_check_header_(void *fdt) +static int fdt_sw_probe_(void *fdt) { - if (fdt_magic(fdt) != FDT_SW_MAGIC) + if (fdt_magic(fdt) == FDT_MAGIC) + return -FDT_ERR_BADSTATE; + else if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC; - /* FIXME: should check more details about the header state */ return 0; } -#define FDT_SW_CHECK_HEADER(fdt) \ +#define FDT_SW_PROBE(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_(fdt)) != 0) \ + return err; \ + } + +/* 'memrsv' state: Initial state after fdt_create() + * + * Allowed functions: + * fdt_add_reservmap_entry() + * fdt_finish_reservemap() [moves to 'struct' state] + */ +static int fdt_sw_probe_memrsv_(void *fdt) +{ + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (fdt_off_dt_strings(fdt) != 0) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_MEMRSV(fdt) \ + { \ + int err; \ + if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ + return err; \ + } + +/* 'struct' state: Enter this state after fdt_finish_reservemap() + * + * Allowed functions: + * fdt_begin_node() + * fdt_end_node() + * fdt_property*() + * fdt_finish() [moves to 'complete' state] + */ +static int fdt_sw_probe_struct_(void *fdt) +{ + int err = fdt_sw_probe_(fdt); + if (err) + return err; + + if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) + return -FDT_ERR_BADSTATE; + return 0; +} + +#define FDT_SW_PROBE_STRUCT(fdt) \ { \ int err; \ - if ((err = fdt_sw_check_header_(fdt)) != 0) \ + if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ return err; \ } +/* 'complete' state: Enter this state after fdt_finish() + * + * Allowed functions: none + */ + static void *fdt_grab_space_(void *fdt, size_t len) { int offset = fdt_size_dt_struct(fdt); @@ -87,9 +143,11 @@ static void *fdt_grab_space_(void *fdt, size_t len) int fdt_create(void *buf, int bufsize) { + const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); void *fdt = buf; - if (bufsize < sizeof(struct fdt_header)) + if (bufsize < hdrsize) return -FDT_ERR_NOSPACE; memset(buf, 0, bufsize); @@ -99,10 +157,9 @@ int fdt_create(void *buf, int bufsize) fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); - fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry))); + fdt_set_off_mem_rsvmap(fdt, hdrsize); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); - fdt_set_off_dt_strings(fdt, bufsize); + fdt_set_off_dt_strings(fdt, 0); return 0; } @@ -112,11 +169,14 @@ int fdt_resize(void *fdt, void *buf, int bufsize) size_t headsize, tailsize; char *oldtail, *newtail; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE(fdt); - headsize = fdt_off_dt_struct(fdt); + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); + if ((headsize + tailsize) > fdt_totalsize(fdt)) + return -FDT_ERR_INTERNAL; + if ((headsize + tailsize) > bufsize) return -FDT_ERR_NOSPACE; @@ -133,8 +193,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) memmove(buf, fdt, headsize); } - fdt_set_off_dt_strings(buf, bufsize); fdt_set_totalsize(buf, bufsize); + if (fdt_off_dt_strings(buf)) + fdt_set_off_dt_strings(buf, bufsize); return 0; } @@ -144,10 +205,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) struct fdt_reserve_entry *re; int offset; - FDT_SW_CHECK_HEADER(fdt); - - if (fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADSTATE; + FDT_SW_PROBE_MEMRSV(fdt); offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) @@ -164,16 +222,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) int fdt_finish_reservemap(void *fdt) { - return fdt_add_reservemap_entry(fdt, 0, 0); + int err = fdt_add_reservemap_entry(fdt, 0, 0); + + if (err) + return err; + + fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); + return 0; } int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; - int namelen = strlen(name) + 1; + int namelen; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); + namelen = strlen(name) + 1; nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; @@ -187,7 +252,7 @@ int fdt_end_node(void *fdt) { fdt32_t *en; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); en = fdt_grab_space_(fdt, FDT_TAGSIZE); if (! en) @@ -225,7 +290,7 @@ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) struct fdt_property *prop; int nameoff; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); nameoff = fdt_find_add_string_(fdt, name); if (nameoff == 0) @@ -262,7 +327,7 @@ int fdt_finish(void *fdt) uint32_t tag; int offset, nextoffset; - FDT_SW_CHECK_HEADER(fdt); + FDT_SW_PROBE_STRUCT(fdt); /* Add terminator */ end = fdt_grab_space_(fdt, sizeof(*end)); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 1e27780e1185..2bd151dd355f 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -90,8 +90,9 @@ /* Error codes: codes for bad device tree blobs */ #define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ + /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly + * terminated (overflows, goes outside allowed bounds, or + * isn't properly terminated). */ #define FDT_ERR_BADMAGIC 9 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a * device tree at all - it is missing the flattened device @@ -153,6 +154,29 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); +/* + * Alignment helpers: + * These helpers access words from a device tree blob. They're + * built to work even with unaligned pointers on platforms (ike + * ARM) that don't like unaligned loads and stores + */ + +static inline uint32_t fdt32_ld(const fdt32_t *p) +{ + fdt32_t v; + + memcpy(&v, p, sizeof(v)); + return fdt32_to_cpu(v); +} + +static inline uint64_t fdt64_ld(const fdt64_t *p) +{ + fdt64_t v; + + memcpy(&v, p, sizeof(v)); + return fdt64_to_cpu(v); +} + /**********************************************************************/ /* Traversal functions */ /**********************************************************************/ @@ -213,7 +237,7 @@ int fdt_next_subnode(const void *fdt, int offset); /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ - (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) + (fdt32_ld(&((const struct fdt_header *)(fdt))->field)) #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) @@ -244,18 +268,31 @@ fdt_set_hdr_(size_dt_struct); #undef fdt_set_hdr_ /** - * fdt_check_header - sanity check a device tree or possible device tree + * fdt_header_size - return the size of the tree's header + * @fdt: pointer to a flattened device tree + */ +size_t fdt_header_size_(uint32_t version); +static inline size_t fdt_header_size(const void *fdt) +{ + return fdt_header_size_(fdt_version(fdt)); +} + +/** + * fdt_check_header - sanity check a device tree header + * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. + * appears to be a flattened device tree, and that the header contains + * valid information (to the extent that can be determined from the + * header alone). * * returns: * 0, if the buffer appears to contain a valid device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings, as above + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings, as above */ int fdt_check_header(const void *fdt); @@ -284,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); /* Read-only functions */ /**********************************************************************/ +int fdt_check_full(const void *fdt, size_t bufsize); + +/** + * fdt_get_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * @lenp: optional pointer to return the string's length + * + * fdt_get_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt, and optionally also + * returns the string's length in *lenp. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds, or doesn't point to a valid string + */ +const char *fdt_get_string(const void *fdt, int stroffset, int *lenp); + /** * fdt_string - retrieve a string from the strings block of a device tree * @fdt: pointer to the device tree blob @@ -294,7 +349,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize); * * returns: * a pointer to the string, on success - * NULL, if stroffset is out of bounds + * NULL, if stroffset is out of bounds, or doesn't point to a valid string */ const char *fdt_string(const void *fdt, int stroffset); @@ -1090,7 +1145,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * * returns: * 0 <= n < FDT_MAX_NCELLS, on success - * 2, if the node has no #address-cells property + * 2, if the node has no #size-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, @@ -1313,10 +1368,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) fdt64_t tmp = cpu_to_fdt64(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } + +#ifndef SWIG /* Not available in Python */ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { return fdt_property_u32(fdt, name, val); } +#endif /** * fdt_property_placeholder - add a new property and return a ptr to its value diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h index bd2474628775..eb2053845c9c 100644 --- a/scripts/dtc/libfdt/libfdt_env.h +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -56,6 +56,7 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #ifdef __CHECKER__ #define FDT_FORCE __attribute__((force)) diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 7681e192295b..4109f890ae60 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -55,10 +55,11 @@ #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) -#define FDT_CHECK_HEADER(fdt) \ +int fdt_ro_probe_(const void *fdt); +#define FDT_RO_PROBE(fdt) \ { \ int err_; \ - if ((err_ = fdt_check_header(fdt)) != 0) \ + if ((err_ = fdt_ro_probe_(fdt)) != 0) \ return err_; \ } diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 57b7db2ed153..4ff0679e0062 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -134,6 +134,20 @@ struct node *name_node(struct node *node, char *name) return node; } +struct node *omit_node_if_unused(struct node *node) +{ + node->omit_if_unused = 1; + + return node; +} + +struct node *reference_node(struct node *node) +{ + node->is_referenced = 1; + + return node; +} + struct node *merge_nodes(struct node *old_node, struct node *new_node) { struct property *new_prop, *old_prop; @@ -224,10 +238,16 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref) struct data d = empty_data; char *name; - d = data_add_marker(d, REF_PHANDLE, ref); - d = data_append_integer(d, 0xffffffff, 32); + if (ref[0] == '/') { + d = data_append_data(d, ref, strlen(ref) + 1); - p = build_property("target", d); + p = build_property("target-path", d); + } else { + d = data_add_marker(d, REF_PHANDLE, ref); + d = data_append_integer(d, 0xffffffff, 32); + + p = build_property("target", d); + } xasprintf(&name, "fragment@%u", next_orphan_fragment++); @@ -574,6 +594,7 @@ struct node *get_node_by_ref(struct node *tree, const char *ref) cell_t get_node_phandle(struct node *root, struct node *node) { static cell_t phandle = 1; /* FIXME: ick, static local */ + struct data d = empty_data; if ((node->phandle != 0) && (node->phandle != -1)) return node->phandle; @@ -583,17 +604,16 @@ cell_t get_node_phandle(struct node *root, struct node *node) node->phandle = phandle; + d = data_add_marker(d, TYPE_UINT32, NULL); + d = data_append_cell(d, phandle); + if (!get_property(node, "linux,phandle") && (phandle_format & PHANDLE_LEGACY)) - add_property(node, - build_property("linux,phandle", - data_append_cell(empty_data, phandle))); + add_property(node, build_property("linux,phandle", d)); if (!get_property(node, "phandle") && (phandle_format & PHANDLE_EPAPR)) - add_property(node, - build_property("phandle", - data_append_cell(empty_data, phandle))); + add_property(node, build_property("phandle", d)); /* If the node *does* have a phandle property, we must * be dealing with a self-referencing phandle, which will be diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index 2461a3d068a0..f2874f1d1465 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -61,24 +61,14 @@ static bool isstring(char c) || strchr("\a\b\t\n\v\f\r", c)); } -static void write_propval_string(FILE *f, struct data val) +static void write_propval_string(FILE *f, const char *s, size_t len) { - const char *str = val.val; - int i; - struct marker *m = val.markers; - - assert(str[val.len-1] == '\0'); + const char *end = s + len - 1; + assert(*end == '\0'); - while (m && (m->offset == 0)) { - if (m->type == LABEL) - fprintf(f, "%s: ", m->ref); - m = m->next; - } fprintf(f, "\""); - - for (i = 0; i < (val.len-1); i++) { - char c = str[i]; - + while (s < end) { + char c = *s++; switch (c) { case '\a': fprintf(f, "\\a"); @@ -108,91 +98,78 @@ static void write_propval_string(FILE *f, struct data val) fprintf(f, "\\\""); break; case '\0': - fprintf(f, "\", "); - while (m && (m->offset <= (i + 1))) { - if (m->type == LABEL) { - assert(m->offset == (i+1)); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } - fprintf(f, "\""); + fprintf(f, "\\0"); break; default: if (isprint((unsigned char)c)) fprintf(f, "%c", c); else - fprintf(f, "\\x%02hhx", c); + fprintf(f, "\\x%02"PRIx8, c); } } fprintf(f, "\""); - - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } } -static void write_propval_cells(FILE *f, struct data val) +static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) { - void *propend = val.val + val.len; - fdt32_t *cp = (fdt32_t *)val.val; - struct marker *m = val.markers; - - fprintf(f, "<"); - for (;;) { - while (m && (m->offset <= ((char *)cp - val.val))) { - if (m->type == LABEL) { - assert(m->offset == ((char *)cp - val.val)); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } + const char *end = p + len; + assert(len % width == 0); - fprintf(f, "0x%x", fdt32_to_cpu(*cp++)); - if ((void *)cp >= propend) + for (; p < end; p += width) { + switch (width) { + case 1: + fprintf(f, " %02"PRIx8, *(const uint8_t*)p); + break; + case 2: + fprintf(f, " 0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p)); + break; + case 4: + fprintf(f, " 0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p)); + break; + case 8: + fprintf(f, " 0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p)); break; - fprintf(f, " "); + } } +} - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } - fprintf(f, ">"); +static bool has_data_type_information(struct marker *m) +{ + return m->type >= TYPE_UINT8; } -static void write_propval_bytes(FILE *f, struct data val) +static struct marker *next_type_marker(struct marker *m) { - void *propend = val.val + val.len; - const char *bp = val.val; - struct marker *m = val.markers; - - fprintf(f, "["); - for (;;) { - while (m && (m->offset == (bp-val.val))) { - if (m->type == LABEL) - fprintf(f, "%s: ", m->ref); - m = m->next; - } + while (m && !has_data_type_information(m)) + m = m->next; + return m; +} - fprintf(f, "%02hhx", (unsigned char)(*bp++)); - if ((const void *)bp >= propend) - break; - fprintf(f, " "); - } +size_t type_marker_length(struct marker *m) +{ + struct marker *next = next_type_marker(m->next); - /* Wrap up any labels at the end of the value */ - for_each_marker_of_type(m, LABEL) { - assert (m->offset == val.len); - fprintf(f, " %s:", m->ref); - } - fprintf(f, "]"); + if (next) + return next->offset - m->offset; + return 0; } -static void write_propval(FILE *f, struct property *prop) +static const char *delim_start[] = { + [TYPE_UINT8] = "[", + [TYPE_UINT16] = "/bits/ 16 <", + [TYPE_UINT32] = "<", + [TYPE_UINT64] = "/bits/ 64 <", + [TYPE_STRING] = "", +}; +static const char *delim_end[] = { + [TYPE_UINT8] = " ]", + [TYPE_UINT16] = " >", + [TYPE_UINT32] = " >", + [TYPE_UINT64] = " >", + [TYPE_STRING] = "", +}; + +static enum markertype guess_value_type(struct property *prop) { int len = prop->val.len; const char *p = prop->val.val; @@ -201,11 +178,6 @@ static void write_propval(FILE *f, struct property *prop) int nnotstringlbl = 0, nnotcelllbl = 0; int i; - if (len == 0) { - fprintf(f, ";\n"); - return; - } - for (i = 0; i < len; i++) { if (! isstring(p[i])) nnotstring++; @@ -220,17 +192,91 @@ static void write_propval(FILE *f, struct property *prop) nnotcelllbl++; } - fprintf(f, " = "); if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) && (nnotstringlbl == 0)) { - write_propval_string(f, prop->val); + return TYPE_STRING; } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { - write_propval_cells(f, prop->val); - } else { - write_propval_bytes(f, prop->val); + return TYPE_UINT32; } - fprintf(f, ";\n"); + return TYPE_UINT8; +} + +static void write_propval(FILE *f, struct property *prop) +{ + size_t len = prop->val.len; + struct marker *m = prop->val.markers; + struct marker dummy_marker; + enum markertype emit_type = TYPE_NONE; + + if (len == 0) { + fprintf(f, ";\n"); + return; + } + + fprintf(f, " = "); + + if (!next_type_marker(m)) { + /* data type information missing, need to guess */ + dummy_marker.type = guess_value_type(prop); + dummy_marker.next = prop->val.markers; + dummy_marker.offset = 0; + dummy_marker.ref = NULL; + m = &dummy_marker; + } + + struct marker *m_label = prop->val.markers; + for_each_marker(m) { + size_t chunk_len; + const char *p = &prop->val.val[m->offset]; + + if (!has_data_type_information(m)) + continue; + + chunk_len = type_marker_length(m); + if (!chunk_len) + chunk_len = len - m->offset; + + if (emit_type != TYPE_NONE) + fprintf(f, "%s, ", delim_end[emit_type]); + emit_type = m->type; + + for_each_marker_of_type(m_label, LABEL) { + if (m_label->offset > m->offset) + break; + fprintf(f, "%s: ", m_label->ref); + } + + fprintf(f, "%s", delim_start[emit_type]); + + if (chunk_len <= 0) + continue; + + switch(emit_type) { + case TYPE_UINT16: + write_propval_int(f, p, chunk_len, 2); + break; + case TYPE_UINT32: + write_propval_int(f, p, chunk_len, 4); + break; + case TYPE_UINT64: + write_propval_int(f, p, chunk_len, 8); + break; + case TYPE_STRING: + write_propval_string(f, p, chunk_len); + break; + default: + write_propval_int(f, p, chunk_len, 1); + } + } + + /* Wrap up any labels at the end of the value */ + for_each_marker_of_type(m_label, LABEL) { + assert (m_label->offset == len); + fprintf(f, " %s:", m_label->ref); + } + + fprintf(f, "%s;\n", delim_end[emit_type] ? : ""); } static void write_tree_source_node(FILE *f, struct node *tree, int level) @@ -281,4 +327,3 @@ void dt_to_source(FILE *f, struct dt_info *dti) write_tree_source_node(f, dti->dt, 0); } - diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh index 1a009fd195d0..7dd29a0362b8 100755 --- a/scripts/dtc/update-dtc-source.sh +++ b/scripts/dtc/update-dtc-source.sh @@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc DTC_LINUX_PATH=`pwd`/scripts/dtc DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ - srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \ + srcpos.h treesource.c util.c util.h version_gen.h yamltree.c Makefile.dtc \ dtc-lexer.l dtc-parser.y" LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \ diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 9953c32a0244..a69b7a13463d 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -227,11 +227,11 @@ char get_escape_char(const char *s, int *i) return val; } -int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) +int utilfdt_read_err(const char *filename, char **buffp, size_t *len) { int fd = 0; /* assume stdin */ char *buf = NULL; - off_t bufsize = 1024, offset = 0; + size_t bufsize = 1024, offset = 0; int ret = 0; *buffp = NULL; @@ -264,20 +264,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) free(buf); else *buffp = buf; - *len = bufsize; + if (len) + *len = bufsize; return ret; } -int utilfdt_read_err(const char *filename, char **buffp) -{ - off_t len; - return utilfdt_read_err_len(filename, buffp, &len); -} - -char *utilfdt_read_len(const char *filename, off_t *len) +char *utilfdt_read(const char *filename, size_t *len) { char *buff; - int ret = utilfdt_read_err_len(filename, &buff, len); + int ret = utilfdt_read_err(filename, &buff, len); if (ret) { fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, @@ -288,12 +283,6 @@ char *utilfdt_read_len(const char *filename, off_t *len) return buff; } -char *utilfdt_read(const char *filename) -{ - off_t len; - return utilfdt_read_len(filename, &len); -} - int utilfdt_write_err(const char *filename, const void *blob) { int fd = 1; /* assume stdout */ diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index 66fba8ea709b..f6cea8274174 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -98,16 +98,10 @@ char get_escape_char(const char *s, int *i); * stderr. * * @param filename The filename to read, or - for stdin - * @return Pointer to allocated buffer containing fdt, or NULL on error - */ -char *utilfdt_read(const char *filename); - -/** - * Like utilfdt_read(), but also passes back the size of the file read. - * * @param len If non-NULL, the amount of data we managed to read + * @return Pointer to allocated buffer containing fdt, or NULL on error */ -char *utilfdt_read_len(const char *filename, off_t *len); +char *utilfdt_read(const char *filename, size_t *len); /** * Read a device tree file into a buffer. Does not report errors, but only @@ -116,16 +110,10 @@ char *utilfdt_read_len(const char *filename, off_t *len); * * @param filename The filename to read, or - for stdin * @param buffp Returns pointer to buffer containing fdt - * @return 0 if ok, else an errno value representing the error - */ -int utilfdt_read_err(const char *filename, char **buffp); - -/** - * Like utilfdt_read_err(), but also passes back the size of the file read. - * * @param len If non-NULL, the amount of data we managed to read + * @return 0 if ok, else an errno value representing the error */ -int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len); +int utilfdt_read_err(const char *filename, char **buffp, size_t *len); /** * Write a device tree buffer to a file. This will report any errors on diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index ad87849e333b..6d23fd095f16 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.6-gaadd0b65" +#define DTC_VERSION "DTC 1.4.7-gc86da84d" diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c new file mode 100644 index 000000000000..a00285a5a9ec --- /dev/null +++ b/scripts/dtc/yamltree.c @@ -0,0 +1,247 @@ +/* + * (C) Copyright Linaro, Ltd. 2018 + * (C) Copyright Arm Holdings. 2017 + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include <stdlib.h> +#include <yaml.h> +#include "dtc.h" +#include "srcpos.h" + +char *yaml_error_name[] = { + [YAML_NO_ERROR] = "no error", + [YAML_MEMORY_ERROR] = "memory error", + [YAML_READER_ERROR] = "reader error", + [YAML_SCANNER_ERROR] = "scanner error", + [YAML_PARSER_ERROR] = "parser error", + [YAML_COMPOSER_ERROR] = "composer error", + [YAML_WRITER_ERROR] = "writer error", + [YAML_EMITTER_ERROR] = "emitter error", +}; + +#define yaml_emitter_emit_or_die(emitter, event) ( \ +{ \ + if (!yaml_emitter_emit(emitter, event)) \ + die("yaml '%s': %s in %s, line %i\n", \ + yaml_error_name[(emitter)->error], \ + (emitter)->problem, __func__, __LINE__); \ +}) + +static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width) +{ + yaml_event_t event; + void *tag; + int off, start_offset = markers->offset; + + switch(width) { + case 1: tag = "!u8"; break; + case 2: tag = "!u16"; break; + case 4: tag = "!u32"; break; + case 8: tag = "!u64"; break; + default: + die("Invalid width %i", width); + } + assert(len % width == 0); + + yaml_sequence_start_event_initialize(&event, NULL, + (yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + for (off = 0; off < len; off += width) { + char buf[32]; + struct marker *m; + bool is_phandle = false; + + switch(width) { + case 1: + sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off)); + break; + case 2: + sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off))); + break; + case 4: + sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off))); + m = markers; + is_phandle = false; + for_each_marker_of_type(m, REF_PHANDLE) { + if (m->offset == (start_offset + off)) { + is_phandle = true; + break; + } + } + break; + case 8: + sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off))); + break; + } + + if (is_phandle) + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t*)"!phandle", (yaml_char_t *)buf, + strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE); + else + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf, + strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + } + + yaml_sequence_end_event_initialize(&event); + yaml_emitter_emit_or_die(emitter, &event); +} + +static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len) +{ + yaml_event_t event; + int i; + + assert(str[len-1] == '\0'); + + /* Make sure the entire string is in the lower 7-bit ascii range */ + for (i = 0; i < len; i++) + assert(isascii(str[i])); + + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str, + len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); +} + +static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) +{ + yaml_event_t event; + int len = prop->val.len; + struct marker *m = prop->val.markers; + + /* Emit the property name */ + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name, + strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + /* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */ + if (len == 0) { + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_BOOL_TAG, + (yaml_char_t*)"true", + strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + return; + } + + if (!m) + die("No markers present in property '%s' value\n", prop->name); + + yaml_sequence_start_event_initialize(&event, NULL, + (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + for_each_marker(m) { + int chunk_len; + char *data = &prop->val.val[m->offset]; + + if (m->type < TYPE_UINT8) + continue; + + chunk_len = type_marker_length(m) ? : len; + assert(chunk_len > 0); + len -= chunk_len; + + switch(m->type) { + case TYPE_UINT16: + yaml_propval_int(emitter, m, data, chunk_len, 2); + break; + case TYPE_UINT32: + yaml_propval_int(emitter, m, data, chunk_len, 4); + break; + case TYPE_UINT64: + yaml_propval_int(emitter, m, data, chunk_len, 8); + break; + case TYPE_STRING: + yaml_propval_string(emitter, data, chunk_len); + break; + default: + yaml_propval_int(emitter, m, data, chunk_len, 1); + break; + } + } + + yaml_sequence_end_event_initialize(&event); + yaml_emitter_emit_or_die(emitter, &event); +} + + +static void yaml_tree(struct node *tree, yaml_emitter_t *emitter) +{ + struct property *prop; + struct node *child; + yaml_event_t event; + + if (tree->deleted) + return; + + yaml_mapping_start_event_initialize(&event, NULL, + (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + + for_each_property(tree, prop) + yaml_propval(emitter, prop); + + /* Loop over all the children, emitting them into the map */ + for_each_child(tree, child) { + yaml_scalar_event_initialize(&event, NULL, + (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name, + strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE); + yaml_emitter_emit_or_die(emitter, &event); + yaml_tree(child, emitter); + } + + yaml_mapping_end_event_initialize(&event); + yaml_emitter_emit_or_die(emitter, &event); +} + +void dt_to_yaml(FILE *f, struct dt_info *dti) +{ + yaml_emitter_t emitter; + yaml_event_t event; + + yaml_emitter_initialize(&emitter); + yaml_emitter_set_output_file(&emitter, f); + yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_tree(dti->dt, &emitter); + + yaml_sequence_end_event_initialize(&event); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_document_end_event_initialize(&event, 0); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_stream_end_event_initialize(&event); + yaml_emitter_emit_or_die(&emitter, &event); + + yaml_emitter_delete(&emitter); +} diff --git a/scripts/extract-vmlinux b/scripts/extract-vmlinux index 5061abcc2540..85e1f32fb4a0 100755 --- a/scripts/extract-vmlinux +++ b/scripts/extract-vmlinux @@ -48,15 +48,17 @@ fi tmp=$(mktemp /tmp/vmlinux-XXX) trap "rm -f $tmp" 0 -# Initial attempt for uncompressed images or objects: -check_vmlinux $img - # That didn't work, so retry after decompression. try_decompress '\037\213\010' xy gunzip try_decompress '\3757zXZ\000' abcde unxz try_decompress 'BZh' xy bunzip2 try_decompress '\135\0\0\0' xxx unlzma try_decompress '\211\114\132' xy 'lzop -d' +try_decompress '\002!L\030' xxx 'lz4 -d' +try_decompress '(\265/\375' xxx unzstd + +# Finally check for uncompressed images or objects: +check_vmlinux $img # Bail out: echo "$me: Cannot find vmlinux." >&2 diff --git a/scripts/faddr2line b/scripts/faddr2line index 1876a741087c..6c6439f69a72 100755 --- a/scripts/faddr2line +++ b/scripts/faddr2line @@ -56,7 +56,7 @@ command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed" command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed" usage() { - echo "usage: faddr2line <object file> <func+offset> <func+offset>..." >&2 + echo "usage: faddr2line [--list] <object file> <func+offset> <func+offset>..." >&2 exit 1 } @@ -71,7 +71,7 @@ die() { # Try to figure out the source directory prefix so we can remove it from the # addr2line output. HACK ALERT: This assumes that start_kernel() is in -# kernel/init.c! This only works for vmlinux. Otherwise it falls back to +# init/main.c! This only works for vmlinux. Otherwise it falls back to # printing the absolute path. find_dir_prefix() { local objfile=$1 @@ -166,15 +166,25 @@ __faddr2line() { local file_lines=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;") [[ -z $file_lines ]] && return + if [[ $LIST = 0 ]]; then + echo "$file_lines" | while read -r line + do + echo $line + done + DONE=1; + return + fi + # show each line with context echo "$file_lines" | while read -r line do + echo echo $line n=$(echo $line | sed 's/.*:\([0-9]\+\).*/\1/g') n1=$[$n-5] n2=$[$n+5] f=$(echo $line | sed 's/.*at \(.\+\):.*/\1/g') - awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") {printf("%d\t%s\n", NR, $0)}' $f + awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f done DONE=1 @@ -185,6 +195,10 @@ __faddr2line() { [[ $# -lt 2 ]] && usage objfile=$1 + +LIST=0 +[[ "$objfile" == "--list" ]] && LIST=1 && shift && objfile=$1 + [[ ! -f $objfile ]] && die "can't find objfile $objfile" shift diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig new file mode 100644 index 000000000000..0d5c799688f0 --- /dev/null +++ b/scripts/gcc-plugins/Kconfig @@ -0,0 +1,193 @@ +preferred-plugin-hostcc := $(if-success,[ $(gcc-version) -ge 40800 ],$(HOSTCXX),$(HOSTCC)) + +config PLUGIN_HOSTCC + string + default "$(shell,$(srctree)/scripts/gcc-plugin.sh "$(preferred-plugin-hostcc)" "$(HOSTCXX)" "$(CC)")" if CC_IS_GCC + help + Host compiler used to build GCC plugins. This can be $(HOSTCXX), + $(HOSTCC), or a null string if GCC plugin is unsupported. + +config HAVE_GCC_PLUGINS + bool + help + An arch should select this symbol if it supports building with + GCC plugins. + +menuconfig GCC_PLUGINS + bool "GCC plugins" + depends on HAVE_GCC_PLUGINS + depends on PLUGIN_HOSTCC != "" + help + GCC plugins are loadable modules that provide extra features to the + compiler. They are useful for runtime instrumentation and static analysis. + + See Documentation/gcc-plugins.txt for details. + +if GCC_PLUGINS + +config GCC_PLUGIN_CYC_COMPLEXITY + bool "Compute the cyclomatic complexity of a function" if EXPERT + depends on !COMPILE_TEST # too noisy + help + The complexity M of a function's control flow graph is defined as: + M = E - N + 2P + where + + E = the number of edges + N = the number of nodes + P = the number of connected components (exit nodes). + + Enabling this plugin reports the complexity to stderr during the + build. It mainly serves as a simple example of how to create a + gcc plugin for the kernel. + +config GCC_PLUGIN_SANCOV + bool + help + This plugin inserts a __sanitizer_cov_trace_pc() call at the start of + basic blocks. It supports all gcc versions with plugin support (from + gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" + by Dmitry Vyukov <dvyukov@google.com>. + +config GCC_PLUGIN_LATENT_ENTROPY + bool "Generate some entropy during boot and runtime" + help + By saying Y here the kernel will instrument some kernel code to + extract some entropy from both original and artificially created + program state. This will help especially embedded systems where + there is little 'natural' source of entropy normally. The cost + is some slowdown of the boot process (about 0.5%) and fork and + irq processing. + + Note that entropy extracted this way is not cryptographically + secure! + + This plugin was ported from grsecurity/PaX. More information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + +config GCC_PLUGIN_STRUCTLEAK + bool "Force initialization of variables containing userspace addresses" + # Currently STRUCTLEAK inserts initialization out of live scope of + # variables from KASAN point of view. This leads to KASAN false + # positive reports. Prohibit this combination for now. + depends on !KASAN_EXTRA + help + This plugin zero-initializes any structures containing a + __user attribute. This can prevent some classes of information + exposures. + + This plugin was ported from grsecurity/PaX. More information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + +config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL + bool "Force initialize all struct type variables passed by reference" + depends on GCC_PLUGIN_STRUCTLEAK + depends on !COMPILE_TEST + help + Zero initialize any struct type local variable that may be passed by + reference without having been initialized. + +config GCC_PLUGIN_STRUCTLEAK_VERBOSE + bool "Report forcefully initialized variables" + depends on GCC_PLUGIN_STRUCTLEAK + depends on !COMPILE_TEST # too noisy + help + This option will cause a warning to be printed each time the + structleak plugin finds a variable it thinks needs to be + initialized. Since not all existing initializers are detected + by the plugin, this can produce false positive warnings. + +config GCC_PLUGIN_RANDSTRUCT + bool "Randomize layout of sensitive kernel structures" + select MODVERSIONS if MODULES + help + If you say Y here, the layouts of structures that are entirely + function pointers (and have not been manually annotated with + __no_randomize_layout), or structures that have been explicitly + marked with __randomize_layout, will be randomized at compile-time. + This can introduce the requirement of an additional information + exposure vulnerability for exploits targeting these structure + types. + + Enabling this feature will introduce some performance impact, + slightly increase memory usage, and prevent the use of forensic + tools like Volatility against the system (unless the kernel + source tree isn't cleaned after kernel installation). + + The seed used for compilation is located at + scripts/gcc-plgins/randomize_layout_seed.h. It remains after + a make clean to allow for external modules to be compiled with + the existing seed and will be removed by a make mrproper or + make distclean. + + Note that the implementation requires gcc 4.7 or newer. + + This plugin was ported from grsecurity/PaX. More information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + +config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE + bool "Use cacheline-aware structure randomization" + depends on GCC_PLUGIN_RANDSTRUCT + depends on !COMPILE_TEST # do not reduce test coverage + help + If you say Y here, the RANDSTRUCT randomization will make a + best effort at restricting randomization to cacheline-sized + groups of elements. It will further not randomize bitfields + in structures. This reduces the performance hit of RANDSTRUCT + at the cost of weakened randomization. + +config GCC_PLUGIN_STACKLEAK + bool "Erase the kernel stack before returning from syscalls" + depends on GCC_PLUGINS + depends on HAVE_ARCH_STACKLEAK + help + This option makes the kernel erase the kernel stack before + returning from system calls. That reduces the information which + kernel stack leak bugs can reveal and blocks some uninitialized + stack variable attacks. + + The tradeoff is the performance impact: on a single CPU system kernel + compilation sees a 1% slowdown, other systems and workloads may vary + and you are advised to test this feature on your expected workload + before deploying it. + + This plugin was ported from grsecurity/PaX. More information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + +config STACKLEAK_TRACK_MIN_SIZE + int "Minimum stack frame size of functions tracked by STACKLEAK" + default 100 + range 0 4096 + depends on GCC_PLUGIN_STACKLEAK + help + The STACKLEAK gcc plugin instruments the kernel code for tracking + the lowest border of the kernel stack (and for some other purposes). + It inserts the stackleak_track_stack() call for the functions with + a stack frame size greater than or equal to this parameter. + If unsure, leave the default value 100. + +config STACKLEAK_METRICS + bool "Show STACKLEAK metrics in the /proc file system" + depends on GCC_PLUGIN_STACKLEAK + depends on PROC_FS + help + If this is set, STACKLEAK metrics for every task are available in + the /proc file system. In particular, /proc/<pid>/stack_depth + shows the maximum kernel stack consumption for the current and + previous syscalls. Although this information is not precise, it + can be useful for estimating the STACKLEAK performance impact for + your workloads. + +config STACKLEAK_RUNTIME_DISABLE + bool "Allow runtime disabling of kernel stack erasing" + depends on GCC_PLUGIN_STACKLEAK + help + This option provides 'stack_erasing' sysctl, which can be used in + runtime to control kernel stack erasing for kernels built with + CONFIG_GCC_PLUGIN_STACKLEAK. + +endif diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile index e2ff425f4c7e..aa0d0ec6936d 100644 --- a/scripts/gcc-plugins/Makefile +++ b/scripts/gcc-plugins/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +PLUGINCC := $(CONFIG_PLUGIN_HOSTCC:"%"=%) GCC_PLUGINS_DIR := $(shell $(CC) -print-file-name=plugin) ifeq ($(PLUGINCC),$(HOSTCC)) @@ -13,12 +14,6 @@ else export HOST_EXTRACXXFLAGS endif -ifneq ($(CFLAGS_KCOV), $(SANCOV_PLUGIN)) - GCC_PLUGIN := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGIN)) -endif - -export HOSTLIBS - $(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h quiet_cmd_create_randomize_layout_seed = GENSEED $@ cmd_create_randomize_layout_seed = \ @@ -32,7 +27,4 @@ always := $($(HOSTLIBS)-y) $(foreach p,$($(HOSTLIBS)-y:%.so=%),$(eval $(p)-objs := $(p).o)) -subdir-y := $(GCC_PLUGIN_SUBDIR) -subdir- += $(GCC_PLUGIN_SUBDIR) - clean-files += *.so diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h index f46750053377..552d5efd7cb7 100644 --- a/scripts/gcc-plugins/gcc-common.h +++ b/scripts/gcc-plugins/gcc-common.h @@ -392,13 +392,6 @@ static inline struct cgraph_node *cgraph_alias_target(struct cgraph_node *n) } #endif -#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION <= 4009 -#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \ - cgraph_create_edge((caller), (callee), (call_stmt), (count), (freq)) -#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \ - cgraph_create_edge_including_clones((caller), (callee), (old_call_stmt), (call_stmt), (count), (freq), (reason)) -#endif - #if BUILDING_GCC_VERSION <= 4008 #define ENTRY_BLOCK_PTR_FOR_FN(FN) ENTRY_BLOCK_PTR_FOR_FUNCTION(FN) #define EXIT_BLOCK_PTR_FOR_FN(FN) EXIT_BLOCK_PTR_FOR_FUNCTION(FN) @@ -723,10 +716,23 @@ static inline const char *get_decl_section_name(const_tree decl) #define varpool_get_node(decl) varpool_node::get(decl) #define dump_varpool_node(file, node) (node)->dump(file) -#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \ +#if BUILDING_GCC_VERSION >= 8000 +#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \ + (caller)->create_edge((callee), (call_stmt), (count)) + +#define cgraph_create_edge_including_clones(caller, callee, \ + old_call_stmt, call_stmt, count, freq, reason) \ + (caller)->create_edge_including_clones((callee), \ + (old_call_stmt), (call_stmt), (count), (reason)) +#else +#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \ (caller)->create_edge((callee), (call_stmt), (count), (freq)) -#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \ - (caller)->create_edge_including_clones((callee), (old_call_stmt), (call_stmt), (count), (freq), (reason)) + +#define cgraph_create_edge_including_clones(caller, callee, \ + old_call_stmt, call_stmt, count, freq, reason) \ + (caller)->create_edge_including_clones((callee), \ + (old_call_stmt), (call_stmt), (count), (freq), (reason)) +#endif typedef struct cgraph_node *cgraph_node_ptr; typedef struct cgraph_edge *cgraph_edge_p; diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c new file mode 100644 index 000000000000..2f48da98b5d4 --- /dev/null +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -0,0 +1,427 @@ +/* + * Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu> + * Modified by Alexander Popov <alex.popov@linux.com> + * Licensed under the GPL v2 + * + * Note: the choice of the license means that the compilation process is + * NOT 'eligible' as defined by gcc's library exception to the GPL v3, + * but for the kernel it doesn't matter since it doesn't link against + * any of the gcc libraries + * + * This gcc plugin is needed for tracking the lowest border of the kernel stack. + * It instruments the kernel code inserting stackleak_track_stack() calls: + * - after alloca(); + * - for the functions with a stack frame size greater than or equal + * to the "track-min-size" plugin parameter. + * + * This plugin is ported from grsecurity/PaX. For more information see: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + * + * Debugging: + * - use fprintf() to stderr, debug_generic_expr(), debug_gimple_stmt(), + * print_rtl() and print_simple_rtl(); + * - add "-fdump-tree-all -fdump-rtl-all" to the plugin CFLAGS in + * Makefile.gcc-plugins to see the verbose dumps of the gcc passes; + * - use gcc -E to understand the preprocessing shenanigans; + * - use gcc with enabled CFG/GIMPLE/SSA verification (--enable-checking). + */ + +#include "gcc-common.h" + +__visible int plugin_is_GPL_compatible; + +static int track_frame_size = -1; +static const char track_function[] = "stackleak_track_stack"; + +/* + * Mark these global variables (roots) for gcc garbage collector since + * they point to the garbage-collected memory. + */ +static GTY(()) tree track_function_decl; + +static struct plugin_info stackleak_plugin_info = { + .version = "201707101337", + .help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n" + "disable\t\tdo not activate the plugin\n" +}; + +static void stackleak_add_track_stack(gimple_stmt_iterator *gsi, bool after) +{ + gimple stmt; + gcall *stackleak_track_stack; + cgraph_node_ptr node; + int frequency; + basic_block bb; + + /* Insert call to void stackleak_track_stack(void) */ + stmt = gimple_build_call(track_function_decl, 0); + stackleak_track_stack = as_a_gcall(stmt); + if (after) { + gsi_insert_after(gsi, stackleak_track_stack, + GSI_CONTINUE_LINKING); + } else { + gsi_insert_before(gsi, stackleak_track_stack, GSI_SAME_STMT); + } + + /* Update the cgraph */ + bb = gimple_bb(stackleak_track_stack); + node = cgraph_get_create_node(track_function_decl); + gcc_assert(node); + frequency = compute_call_stmt_bb_frequency(current_function_decl, bb); + cgraph_create_edge(cgraph_get_node(current_function_decl), node, + stackleak_track_stack, bb->count, frequency); +} + +static bool is_alloca(gimple stmt) +{ + if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA)) + return true; + +#if BUILDING_GCC_VERSION >= 4007 + if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) + return true; +#endif + + return false; +} + +/* + * Work with the GIMPLE representation of the code. Insert the + * stackleak_track_stack() call after alloca() and into the beginning + * of the function if it is not instrumented. + */ +static unsigned int stackleak_instrument_execute(void) +{ + basic_block bb, entry_bb; + bool prologue_instrumented = false, is_leaf = true; + gimple_stmt_iterator gsi; + + /* + * ENTRY_BLOCK_PTR is a basic block which represents possible entry + * point of a function. This block does not contain any code and + * has a CFG edge to its successor. + */ + gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + entry_bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + + /* + * Loop through the GIMPLE statements in each of cfun basic blocks. + * cfun is a global variable which represents the function that is + * currently processed. + */ + FOR_EACH_BB_FN(bb, cfun) { + for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { + gimple stmt; + + stmt = gsi_stmt(gsi); + + /* Leaf function is a function which makes no calls */ + if (is_gimple_call(stmt)) + is_leaf = false; + + if (!is_alloca(stmt)) + continue; + + /* Insert stackleak_track_stack() call after alloca() */ + stackleak_add_track_stack(&gsi, true); + if (bb == entry_bb) + prologue_instrumented = true; + } + } + + if (prologue_instrumented) + return 0; + + /* + * Special cases to skip the instrumentation. + * + * Taking the address of static inline functions materializes them, + * but we mustn't instrument some of them as the resulting stack + * alignment required by the function call ABI will break other + * assumptions regarding the expected (but not otherwise enforced) + * register clobbering ABI. + * + * Case in point: native_save_fl on amd64 when optimized for size + * clobbers rdx if it were instrumented here. + * + * TODO: any more special cases? + */ + if (is_leaf && + !TREE_PUBLIC(current_function_decl) && + DECL_DECLARED_INLINE_P(current_function_decl)) { + return 0; + } + + if (is_leaf && + !strncmp(IDENTIFIER_POINTER(DECL_NAME(current_function_decl)), + "_paravirt_", 10)) { + return 0; + } + + /* Insert stackleak_track_stack() call at the function beginning */ + bb = entry_bb; + if (!single_pred_p(bb)) { + /* gcc_assert(bb_loop_depth(bb) || + (bb->flags & BB_IRREDUCIBLE_LOOP)); */ + split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + } + gsi = gsi_after_labels(bb); + stackleak_add_track_stack(&gsi, false); + + return 0; +} + +static bool large_stack_frame(void) +{ +#if BUILDING_GCC_VERSION >= 8000 + return maybe_ge(get_frame_size(), track_frame_size); +#else + return (get_frame_size() >= track_frame_size); +#endif +} + +/* + * Work with the RTL representation of the code. + * Remove the unneeded stackleak_track_stack() calls from the functions + * which don't call alloca() and don't have a large enough stack frame size. + */ +static unsigned int stackleak_cleanup_execute(void) +{ + rtx_insn *insn, *next; + + if (cfun->calls_alloca) + return 0; + + if (large_stack_frame()) + return 0; + + /* + * Find stackleak_track_stack() calls. Loop through the chain of insns, + * which is an RTL representation of the code for a function. + * + * The example of a matching insn: + * (call_insn 8 4 10 2 (call (mem (symbol_ref ("stackleak_track_stack") + * [flags 0x41] <function_decl 0x7f7cd3302a80 stackleak_track_stack>) + * [0 stackleak_track_stack S1 A8]) (0)) 675 {*call} (expr_list + * (symbol_ref ("stackleak_track_stack") [flags 0x41] <function_decl + * 0x7f7cd3302a80 stackleak_track_stack>) (expr_list (0) (nil))) (nil)) + */ + for (insn = get_insns(); insn; insn = next) { + rtx body; + + next = NEXT_INSN(insn); + + /* Check the expression code of the insn */ + if (!CALL_P(insn)) + continue; + + /* + * Check the expression code of the insn body, which is an RTL + * Expression (RTX) describing the side effect performed by + * that insn. + */ + body = PATTERN(insn); + + if (GET_CODE(body) == PARALLEL) + body = XVECEXP(body, 0, 0); + + if (GET_CODE(body) != CALL) + continue; + + /* + * Check the first operand of the call expression. It should + * be a mem RTX describing the needed subroutine with a + * symbol_ref RTX. + */ + body = XEXP(body, 0); + if (GET_CODE(body) != MEM) + continue; + + body = XEXP(body, 0); + if (GET_CODE(body) != SYMBOL_REF) + continue; + + if (SYMBOL_REF_DECL(body) != track_function_decl) + continue; + + /* Delete the stackleak_track_stack() call */ + delete_insn_and_edges(insn); +#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION < 8000 + if (GET_CODE(next) == NOTE && + NOTE_KIND(next) == NOTE_INSN_CALL_ARG_LOCATION) { + insn = next; + next = NEXT_INSN(insn); + delete_insn_and_edges(insn); + } +#endif + } + + return 0; +} + +static bool stackleak_gate(void) +{ + tree section; + + section = lookup_attribute("section", + DECL_ATTRIBUTES(current_function_decl)); + if (section && TREE_VALUE(section)) { + section = TREE_VALUE(TREE_VALUE(section)); + + if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) + return false; + if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) + return false; + if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) + return false; + if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) + return false; + } + + return track_frame_size >= 0; +} + +/* Build the function declaration for stackleak_track_stack() */ +static void stackleak_start_unit(void *gcc_data __unused, + void *user_data __unused) +{ + tree fntype; + + /* void stackleak_track_stack(void) */ + fntype = build_function_type_list(void_type_node, NULL_TREE); + track_function_decl = build_fn_decl(track_function, fntype); + DECL_ASSEMBLER_NAME(track_function_decl); /* for LTO */ + TREE_PUBLIC(track_function_decl) = 1; + TREE_USED(track_function_decl) = 1; + DECL_EXTERNAL(track_function_decl) = 1; + DECL_ARTIFICIAL(track_function_decl) = 1; + DECL_PRESERVE_P(track_function_decl) = 1; +} + +/* + * Pass gate function is a predicate function that gets executed before the + * corresponding pass. If the return value is 'true' the pass gets executed, + * otherwise, it is skipped. + */ +static bool stackleak_instrument_gate(void) +{ + return stackleak_gate(); +} + +#define PASS_NAME stackleak_instrument +#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg +#define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts +#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \ + | TODO_update_ssa | TODO_rebuild_cgraph_edges +#include "gcc-generate-gimple-pass.h" + +static bool stackleak_cleanup_gate(void) +{ + return stackleak_gate(); +} + +#define PASS_NAME stackleak_cleanup +#define TODO_FLAGS_FINISH TODO_dump_func +#include "gcc-generate-rtl-pass.h" + +/* + * Every gcc plugin exports a plugin_init() function that is called right + * after the plugin is loaded. This function is responsible for registering + * the plugin callbacks and doing other required initialization. + */ +__visible int plugin_init(struct plugin_name_args *plugin_info, + struct plugin_gcc_version *version) +{ + const char * const plugin_name = plugin_info->base_name; + const int argc = plugin_info->argc; + const struct plugin_argument * const argv = plugin_info->argv; + int i = 0; + + /* Extra GGC root tables describing our GTY-ed data */ + static const struct ggc_root_tab gt_ggc_r_gt_stackleak[] = { + { + .base = &track_function_decl, + .nelt = 1, + .stride = sizeof(track_function_decl), + .cb = >_ggc_mx_tree_node, + .pchw = >_pch_nx_tree_node + }, + LAST_GGC_ROOT_TAB + }; + + /* + * The stackleak_instrument pass should be executed before the + * "optimized" pass, which is the control flow graph cleanup that is + * performed just before expanding gcc trees to the RTL. In former + * versions of the plugin this new pass was inserted before the + * "tree_profile" pass, which is currently called "profile". + */ + PASS_INFO(stackleak_instrument, "optimized", 1, + PASS_POS_INSERT_BEFORE); + + /* + * The stackleak_cleanup pass should be executed after the + * "reload" pass, when the stack frame size is final. + */ + PASS_INFO(stackleak_cleanup, "reload", 1, PASS_POS_INSERT_AFTER); + + if (!plugin_default_version_check(version, &gcc_version)) { + error(G_("incompatible gcc/plugin versions")); + return 1; + } + + /* Parse the plugin arguments */ + for (i = 0; i < argc; i++) { + if (!strcmp(argv[i].key, "disable")) + return 0; + + if (!strcmp(argv[i].key, "track-min-size")) { + if (!argv[i].value) { + error(G_("no value supplied for option '-fplugin-arg-%s-%s'"), + plugin_name, argv[i].key); + return 1; + } + + track_frame_size = atoi(argv[i].value); + if (track_frame_size < 0) { + error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"), + plugin_name, argv[i].key, argv[i].value); + return 1; + } + } else { + error(G_("unknown option '-fplugin-arg-%s-%s'"), + plugin_name, argv[i].key); + return 1; + } + } + + /* Give the information about the plugin */ + register_callback(plugin_name, PLUGIN_INFO, NULL, + &stackleak_plugin_info); + + /* Register to be called before processing a translation unit */ + register_callback(plugin_name, PLUGIN_START_UNIT, + &stackleak_start_unit, NULL); + + /* Register an extra GCC garbage collector (GGC) root table */ + register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, + (void *)>_ggc_r_gt_stackleak); + + /* + * Hook into the Pass Manager to register new gcc passes. + * + * The stack frame size info is available only at the last RTL pass, + * when it's too late to insert complex code like a function call. + * So we register two gcc passes to instrument every function at first + * and remove the unneeded instrumentation later. + */ + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, + &stackleak_instrument_pass_info); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, + &stackleak_cleanup_pass_info); + + return 0; +} diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh index 6b2aeefb9cd3..f5c119495254 100755 --- a/scripts/gcc-x86_32-has-stack-protector.sh +++ b/scripts/gcc-x86_32-has-stack-protector.sh @@ -1,9 +1,4 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" -if [ "$?" -eq "0" ] ; then - echo y -else - echo n -fi +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh index 4a48bdcd4d6b..75e4e22b986a 100755 --- a/scripts/gcc-x86_64-has-stack-protector.sh +++ b/scripts/gcc-x86_64-has-stack-protector.sh @@ -1,9 +1,4 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs" -if [ "$?" -eq "0" ] ; then - echo y -else - echo n -fi +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m64 -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs" diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh deleted file mode 100755 index 10e528b3a08f..000000000000 --- a/scripts/gen_initramfs_list.sh +++ /dev/null @@ -1,328 +0,0 @@ -#!/bin/sh -# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org> -# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org> -# -# Released under the terms of the GNU GPL -# -# Generate a cpio packed initramfs. It uses gen_init_cpio to generate -# the cpio archive, and then compresses it. -# The script may also be used to generate the inputfile used for gen_init_cpio -# This script assumes that gen_init_cpio is located in usr/ directory - -# error out on errors -set -e - -usage() { -cat << EOF -Usage: -$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ... - -o <file> Create compressed initramfs file named <file> using - gen_init_cpio and compressor depending on the extension - -u <uid> User ID to map to user ID 0 (root). - <uid> is only meaningful if <cpio_source> is a - directory. "squash" forces all files to uid 0. - -g <gid> Group ID to map to group ID 0 (root). - <gid> is only meaningful if <cpio_source> is a - directory. "squash" forces all files to gid 0. - <cpio_source> File list or directory for cpio archive. - If <cpio_source> is a .cpio file it will be used - as direct input to initramfs. - -d Output the default cpio list. - -All options except -o and -l may be repeated and are interpreted -sequentially and immediately. -u and -g states are preserved across -<cpio_source> options so an explicit "-u 0 -g 0" is required -to reset the root/group mapping. -EOF -} - -# awk style field access -# $1 - field number; rest is argument string -field() { - shift $1 ; echo $1 -} - -list_default_initramfs() { - # echo usr/kinit/kinit - : -} - -default_initramfs() { - cat <<-EOF >> ${output} - # This is a very simple, default initramfs - - dir /dev 0755 0 0 - nod /dev/console 0600 0 0 c 5 1 - dir /root 0700 0 0 - # file /kinit usr/kinit/kinit 0755 0 0 - # slink /init kinit 0755 0 0 - EOF -} - -filetype() { - local argv1="$1" - - # symlink test must come before file test - if [ -L "${argv1}" ]; then - echo "slink" - elif [ -f "${argv1}" ]; then - echo "file" - elif [ -d "${argv1}" ]; then - echo "dir" - elif [ -b "${argv1}" -o -c "${argv1}" ]; then - echo "nod" - elif [ -p "${argv1}" ]; then - echo "pipe" - elif [ -S "${argv1}" ]; then - echo "sock" - else - echo "invalid" - fi - return 0 -} - -list_print_mtime() { - : -} - -print_mtime() { - local my_mtime="0" - - if [ -e "$1" ]; then - my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1) - fi - - echo "# Last modified: ${my_mtime}" >> ${output} - echo "" >> ${output} -} - -list_parse() { - if [ -L "$1" ]; then - return - fi - echo "$1" | sed 's/:/\\:/g; s/$/ \\/' -} - -# for each file print a line in following format -# <filetype> <name> <path to file> <octal mode> <uid> <gid> -# for links, devices etc the format differs. See gen_init_cpio for details -parse() { - local location="$1" - local name="/${location#${srcdir}}" - # change '//' into '/' - name=$(echo "$name" | sed -e 's://*:/:g') - local mode="$2" - local uid="$3" - local gid="$4" - local ftype=$(filetype "${location}") - # remap uid/gid to 0 if necessary - [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0 - [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0 - local str="${mode} ${uid} ${gid}" - - [ "${ftype}" = "invalid" ] && return 0 - [ "${location}" = "${srcdir}" ] && return 0 - - case "${ftype}" in - "file") - str="${ftype} ${name} ${location} ${str}" - ;; - "nod") - local dev=`LC_ALL=C ls -l "${location}"` - local maj=`field 5 ${dev}` - local min=`field 6 ${dev}` - maj=${maj%,} - - [ -b "${location}" ] && dev="b" || dev="c" - - str="${ftype} ${name} ${str} ${dev} ${maj} ${min}" - ;; - "slink") - local target=`readlink "${location}"` - str="${ftype} ${name} ${target} ${str}" - ;; - *) - str="${ftype} ${name} ${str}" - ;; - esac - - echo "${str}" >> ${output} - - return 0 -} - -unknown_option() { - printf "ERROR: unknown option \"$arg\"\n" >&2 - printf "If the filename validly begins with '-', " >&2 - printf "then it must be prefixed\n" >&2 - printf "by './' so that it won't be interpreted as an option." >&2 - printf "\n" >&2 - usage >&2 - exit 1 -} - -list_header() { - : -} - -header() { - printf "\n#####################\n# $1\n" >> ${output} -} - -# process one directory (incl sub-directories) -dir_filelist() { - ${dep_list}header "$1" - - srcdir=$(echo "$1" | sed -e 's://*:/:g') - dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | sort) - - # If $dirlist is only one line, then the directory is empty - if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then - ${dep_list}print_mtime "$1" - - echo "${dirlist}" | \ - while read x; do - ${dep_list}parse ${x} - done - fi -} - -# if only one file is specified and it is .cpio file then use it direct as fs -# if a directory is specified then add all files in given direcotry to fs -# if a regular file is specified assume it is in gen_initramfs format -input_file() { - source="$1" - if [ -f "$1" ]; then - ${dep_list}header "$1" - is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\{0,1\}/cpio/')" - if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then - cpio_file=$1 - echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed" - [ ! -z ${dep_list} ] && echo "$1" - return 0 - fi - if [ -z ${dep_list} ]; then - print_mtime "$1" >> ${output} - cat "$1" >> ${output} - else - echo "$1 \\" - cat "$1" | while read type dir file perm ; do - if [ "$type" = "file" ]; then - echo "$file \\"; - fi - done - fi - elif [ -d "$1" ]; then - dir_filelist "$1" - else - echo " ${prog}: Cannot open '$1'" >&2 - exit 1 - fi -} - -prog=$0 -root_uid=0 -root_gid=0 -dep_list= -cpio_file= -cpio_list= -output="/dev/stdout" -output_file="" -is_cpio_compressed= -compr="gzip -n -9 -f" - -arg="$1" -case "$arg" in - "-l") # files included in initramfs - used by kbuild - dep_list="list_" - echo "deps_initramfs := $0 \\" - shift - ;; - "-o") # generate compressed cpio image named $1 - shift - output_file="$1" - cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)" - output=${cpio_list} - echo "$output_file" | grep -q "\.gz$" \ - && [ -x "`which gzip 2> /dev/null`" ] \ - && compr="gzip -n -9 -f" - echo "$output_file" | grep -q "\.bz2$" \ - && [ -x "`which bzip2 2> /dev/null`" ] \ - && compr="bzip2 -9 -f" - echo "$output_file" | grep -q "\.lzma$" \ - && [ -x "`which lzma 2> /dev/null`" ] \ - && compr="lzma -9 -f" - echo "$output_file" | grep -q "\.xz$" \ - && [ -x "`which xz 2> /dev/null`" ] \ - && compr="xz --check=crc32 --lzma2=dict=1MiB" - echo "$output_file" | grep -q "\.lzo$" \ - && [ -x "`which lzop 2> /dev/null`" ] \ - && compr="lzop -9 -f" - echo "$output_file" | grep -q "\.lz4$" \ - && [ -x "`which lz4 2> /dev/null`" ] \ - && compr="lz4 -l -9 -f" - echo "$output_file" | grep -q "\.cpio$" && compr="cat" - shift - ;; -esac -while [ $# -gt 0 ]; do - arg="$1" - shift - case "$arg" in - "-u") # map $1 to uid=0 (root) - root_uid="$1" - [ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0) - shift - ;; - "-g") # map $1 to gid=0 (root) - root_gid="$1" - [ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0) - shift - ;; - "-d") # display default initramfs list - default_list="$arg" - ${dep_list}default_initramfs - ;; - "-h") - usage - exit 0 - ;; - *) - case "$arg" in - "-"*) - unknown_option - ;; - *) # input file/dir - process it - input_file "$arg" "$#" - ;; - esac - ;; - esac -done - -# If output_file is set we will generate cpio archive and compress it -# we are careful to delete tmp files -if [ ! -z ${output_file} ]; then - if [ -z ${cpio_file} ]; then - timestamp= - if test -n "$KBUILD_BUILD_TIMESTAMP"; then - timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)" - if test -n "$timestamp"; then - timestamp="-t $timestamp" - fi - fi - cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)" - usr/gen_init_cpio $timestamp ${cpio_list} > ${cpio_tfile} - else - cpio_tfile=${cpio_file} - fi - rm ${cpio_list} - if [ "${is_cpio_compressed}" = "compressed" ]; then - cat ${cpio_tfile} > ${output_file} - else - (cat ${cpio_tfile} | ${compr} - > ${output_file}) \ - || (rm -f ${output_file} ; false) - fi - [ -z ${cpio_file} ] && rm ${cpio_tfile} -fi -exit 0 diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index c9235d8340f1..e007840f45b9 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -45,7 +45,6 @@ int in_source_file; static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, flag_preserve, flag_warnings, flag_rel_crcs; -static const char *mod_prefix = ""; static int errors; static int nsyms; @@ -693,10 +692,10 @@ void export_symbol(const char *name) fputs(">\n", debugfile); /* Used as a linker script. */ - printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" : + printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" : "SECTIONS { .rodata : ALIGN(4) { " - "%s__crc_%s = .; LONG(0x%08lx); } }\n", - mod_prefix, name, crc); + "__crc_%s = .; LONG(0x%08lx); } }\n", + name, crc); } } @@ -769,7 +768,6 @@ int main(int argc, char **argv) #ifdef __GNU_LIBRARY__ struct option long_opts[] = { - {"symbol-prefix", 1, 0, 's'}, {"debug", 0, 0, 'd'}, {"warnings", 0, 0, 'w'}, {"quiet", 0, 0, 'q'}, @@ -789,9 +787,6 @@ int main(int argc, char **argv) while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { - case 's': - mod_prefix = optarg; - break; case 'd': flag_debug++; break; diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 99c96e86eccb..c1c088ef1420 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -1,4 +1,6 @@ #!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# # (c) 2007, Joe Perches <joe@perches.com> # created from checkpatch.pl # @@ -7,8 +9,6 @@ # # usage: perl scripts/get_maintainer.pl [OPTIONS] <patch> # perl scripts/get_maintainer.pl [OPTIONS] -f <file> -# -# Licensed under the terms of the GNU GPL License version 2 use warnings; use strict; @@ -48,6 +48,7 @@ my $output_roles = 0; my $output_rolestats = 1; my $output_section_maxlen = 50; my $scm = 0; +my $tree = 1; my $web = 0; my $subsystem = 0; my $status = 0; @@ -61,7 +62,7 @@ my $self_test = undef; my $version = 0; my $help = 0; my $find_maintainer_files = 0; - +my $maintainer_path; my $vcs_used = 0; my $exit = 0; @@ -255,6 +256,7 @@ if (!GetOptions( 'subsystem!' => \$subsystem, 'status!' => \$status, 'scm!' => \$scm, + 'tree!' => \$tree, 'web!' => \$web, 'letters=s' => \$letters, 'pattern-depth=i' => \$pattern_depth, @@ -263,6 +265,7 @@ if (!GetOptions( 'fe|file-emails!' => \$file_emails, 'f|file' => \$from_filename, 'find-maintainer-files' => \$find_maintainer_files, + 'mpath|maintainer-path=s' => \$maintainer_path, 'self-test:s' => \$self_test, 'v|version' => \$version, 'h|help|usage' => \$help, @@ -319,7 +322,7 @@ if ($email && die "$P: Please select at least 1 email option\n"; } -if (!top_of_kernel_tree($lk_path)) { +if ($tree && !top_of_kernel_tree($lk_path)) { die "$P: The current directory does not appear to be " . "a linux kernel source tree.\n"; } @@ -384,26 +387,36 @@ sub find_ignore_git { read_all_maintainer_files(); sub read_all_maintainer_files { - if (-d "${lk_path}MAINTAINERS") { - opendir(DIR, "${lk_path}MAINTAINERS") or die $!; - my @files = readdir(DIR); - closedir(DIR); - foreach my $file (@files) { - push(@mfiles, "${lk_path}MAINTAINERS/$file") if ($file !~ /^\./); - } - } - - if ($find_maintainer_files) { - find( { wanted => \&find_is_maintainer_file, - preprocess => \&find_ignore_git, - no_chdir => 1, - }, "${lk_path}"); + my $path = "${lk_path}MAINTAINERS"; + if (defined $maintainer_path) { + $path = $maintainer_path; + # Perl Cookbook tilde expansion if necessary + $path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex; + } + + if (-d $path) { + $path .= '/' if ($path !~ m@/$@); + if ($find_maintainer_files) { + find( { wanted => \&find_is_maintainer_file, + preprocess => \&find_ignore_git, + no_chdir => 1, + }, "$path"); + } else { + opendir(DIR, "$path") or die $!; + my @files = readdir(DIR); + closedir(DIR); + foreach my $file (@files) { + push(@mfiles, "$path$file") if ($file !~ /^\./); + } + } + } elsif (-f "$path") { + push(@mfiles, "$path"); } else { - push(@mfiles, "${lk_path}MAINTAINERS") if -f "${lk_path}MAINTAINERS"; + die "$P: MAINTAINER file not found '$path'\n"; } - + die "$P: No MAINTAINER files found in '$path'\n" if (scalar(@mfiles) == 0); foreach my $file (@mfiles) { - read_maintainer_file("$file"); + read_maintainer_file("$file"); } } @@ -542,7 +555,18 @@ foreach my $file (@ARGV) { while (<$patch>) { my $patch_line = $_; - if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) { + if (m/^ mode change [0-7]+ => [0-7]+ (\S+)\s*$/) { + my $filename = $1; + push(@files, $filename); + } elsif (m/^rename (?:from|to) (\S+)\s*$/) { + my $filename = $1; + push(@files, $filename); + } elsif (m/^diff --git a\/(\S+) b\/(\S+)\s*$/) { + my $filename1 = $1; + my $filename2 = $2; + push(@files, $filename1); + push(@files, $filename2); + } elsif (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) { my $filename = $1; $filename =~ s@^[^/]*/@@; $filename =~ s@\n@@; @@ -1020,13 +1044,14 @@ Other options: --sections => print all of the subsystem sections with pattern matches --letters => print all matching 'letter' types from all matching sections --mailmap => use .mailmap file (default: $email_use_mailmap) + --no-tree => run without a kernel tree --self-test => show potential issues with MAINTAINERS file content --version => show version --help => show this help information Default options: - [--email --nogit --git-fallback --m --r --n --l --multiline --pattern-depth=0 - --remove-duplicates --rolestats] + [--email --tree --nogit --git-fallback --m --r --n --l --multiline + --pattern-depth=0 --remove-duplicates --rolestats] Notes: Using "-f directory" may give unexpected results: diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 5abfbf1b8fe2..109a1af7e444 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -48,8 +48,6 @@ static unsigned long long relative_base; static struct addr_range text_ranges[] = { { "_stext", "_etext" }, { "_sinittext", "_einittext" }, - { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */ - { "_stext_l2", "_etext_l2" }, /* Blackfin on-chip L2 SRAM */ }; #define text_range_text (&text_ranges[0]) #define text_range_inittext (&text_ranges[1]) @@ -62,7 +60,6 @@ static struct sym_entry *table; static unsigned int table_size, table_cnt; static int all_symbols = 0; static int absolute_percpu = 0; -static char symbol_prefix_char = '\0'; static int base_relative = 0; int token_profit[0x10000]; @@ -75,7 +72,6 @@ unsigned char best_table_len[256]; static void usage(void) { fprintf(stderr, "Usage: kallsyms [--all-symbols] " - "[--symbol-prefix=<prefix char>] " "[--base-relative] < in.map > out.S\n"); exit(1); } @@ -113,28 +109,22 @@ static int check_symbol_range(const char *sym, unsigned long long addr, static int read_symbol(FILE *in, struct sym_entry *s) { - char str[500]; - char *sym, stype; + char sym[500], stype; int rc; - rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str); + rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, sym); if (rc != 3) { - if (rc != EOF && fgets(str, 500, in) == NULL) + if (rc != EOF && fgets(sym, 500, in) == NULL) fprintf(stderr, "Read error or end of file.\n"); return -1; } - if (strlen(str) > KSYM_NAME_LEN) { + if (strlen(sym) > KSYM_NAME_LEN) { fprintf(stderr, "Symbol %s too long for kallsyms (%zu vs %d).\n" "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n", - str, strlen(str), KSYM_NAME_LEN); + sym, strlen(sym), KSYM_NAME_LEN); return -1; } - sym = str; - /* skip prefix char */ - if (symbol_prefix_char && str[0] == symbol_prefix_char) - sym++; - /* Ignore most absolute/undefined (?) symbols. */ if (strcmp(sym, "_text") == 0) _text = s->addr; @@ -155,7 +145,7 @@ static int read_symbol(FILE *in, struct sym_entry *s) is_arm_mapping_symbol(sym)) return -1; /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */ - else if (str[0] == '$') + else if (sym[0] == '$') return -1; /* exclude debugging symbols */ else if (stype == 'N' || stype == 'n') @@ -163,14 +153,14 @@ static int read_symbol(FILE *in, struct sym_entry *s) /* include the type field in the symbol name, so that it gets * compressed together */ - s->len = strlen(str) + 1; + s->len = strlen(sym) + 1; s->sym = malloc(s->len + 1); if (!s->sym) { fprintf(stderr, "kallsyms failure: " "unable to allocate required amount of memory\n"); exit(EXIT_FAILURE); } - strcpy((char *)s->sym + 1, str); + strcpy((char *)s->sym + 1, sym); s->sym[0] = stype; s->percpu_absolute = 0; @@ -233,11 +223,6 @@ static int symbol_valid(struct sym_entry *s) int i; char *sym_name = (char *)s->sym + 1; - /* skip prefix char */ - if (symbol_prefix_char && *sym_name == symbol_prefix_char) - sym_name++; - - /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { @@ -302,15 +287,9 @@ static void read_map(FILE *in) static void output_label(char *label) { - if (symbol_prefix_char) - printf(".globl %c%s\n", symbol_prefix_char, label); - else - printf(".globl %s\n", label); + printf(".globl %s\n", label); printf("\tALGN\n"); - if (symbol_prefix_char) - printf("%c%s:\n", symbol_prefix_char, label); - else - printf("%s:\n", label); + printf("%s:\n", label); } /* uncompress a compressed symbol. When this function is called, the best table @@ -424,7 +403,7 @@ static void write_src(void) } output_label("kallsyms_num_syms"); - printf("\tPTR\t%d\n", table_cnt); + printf("\t.long\t%u\n", table_cnt); printf("\n"); /* table of offset markers, that give the offset in the compressed stream @@ -453,7 +432,7 @@ static void write_src(void) output_label("kallsyms_markers"); for (i = 0; i < ((table_cnt + 255) >> 8); i++) - printf("\tPTR\t%d\n", markers[i]); + printf("\t.long\t%u\n", markers[i]); printf("\n"); free(markers); @@ -768,13 +747,7 @@ int main(int argc, char **argv) all_symbols = 1; else if (strcmp(argv[i], "--absolute-percpu") == 0) absolute_percpu = 1; - else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { - char *p = &argv[i][16]; - /* skip quote */ - if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\'')) - p++; - symbol_prefix_char = *p; - } else if (strcmp(argv[i], "--base-relative") == 0) + else if (strcmp(argv[i], "--base-relative") == 0) base_relative = 1; else usage(); diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore index 2da579edcbaf..0aabc1d6a182 100644 --- a/scripts/kconfig/.gitignore +++ b/scripts/kconfig/.gitignore @@ -2,9 +2,6 @@ # Generated files # *.moc -gconf.glade.h -*.pot -*.mo # # configuration programs @@ -14,4 +11,3 @@ mconf nconf qconf gconf -kxgettext diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 5def8779d7d8..63b609243d03 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -3,8 +3,8 @@ # Kernel configuration targets # These targets are used from top-level makefile -PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \ - localmodconfig localyesconfig +PHONY += xconfig gconfig menuconfig config localmodconfig localyesconfig \ + build_menuconfig build_nconfig build_gconfig build_xconfig ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) @@ -34,14 +34,15 @@ config: $(obj)/conf nconfig: $(obj)/nconf $< $(silent) $(Kconfig) -# This has become an internal implementation detail and is now deprecated -# for external use. -syncconfig: $(obj)/conf - $(Q)mkdir -p include/config include/generated - $< $(silent) --$@ $(Kconfig) +build_menuconfig: $(obj)/mconf + +build_nconfig: $(obj)/nconf + +build_gconfig: $(obj)/gconf + +build_xconfig: $(obj)/qconf localyesconfig localmodconfig: $(obj)/conf - $(Q)mkdir -p include/config include/generated $(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ @@ -55,52 +56,19 @@ localyesconfig localmodconfig: $(obj)/conf fi $(Q)rm -f .tmp.config -# Create new linux.pot file -# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files -update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h - $(Q)$(kecho) " GEN config.pot" - $(Q)xgettext --default-domain=linux \ - --add-comments --keyword=_ --keyword=N_ \ - --from-code=UTF-8 \ - --files-from=$(srctree)/scripts/kconfig/POTFILES.in \ - --directory=$(srctree) --directory=$(objtree) \ - --output $(obj)/config.pot - $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot - $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ - $(srctree)/arch/*/um/Kconfig`; \ - do \ - $(kecho) " GEN $$i"; \ - $(obj)/kxgettext $$i \ - >> $(obj)/config.pot; \ - done ) - $(Q)$(kecho) " GEN linux.pot" - $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ - --output $(obj)/linux.pot - $(Q)rm -f $(obj)/config.pot - # These targets map 1:1 to the commandline options of 'conf' +# +# Note: +# syncconfig has become an internal implementation detail and is now +# deprecated for external use simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \ - alldefconfig randconfig listnewconfig olddefconfig + alldefconfig randconfig listnewconfig olddefconfig syncconfig PHONY += $(simple-targets) $(simple-targets): $(obj)/conf $< $(silent) --$@ $(Kconfig) -PHONY += oldnoconfig silentoldconfig savedefconfig defconfig - -# oldnoconfig is an alias of olddefconfig, because people already are dependent -# on its behavior (sets new symbols to their default value but not 'n') with the -# counter-intuitive name. -oldnoconfig: olddefconfig - @echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19" - @echo " Please use \"olddefconfig\" instead, which is an alias." - -# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig"). -silentoldconfig: syncconfig - @echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\"" - @echo " and is now an internal implementation detail." - @echo " What you want is probably \"oldconfig\"." - @echo " \"silentoldconfig\" will be removed after Linux 4.19" +PHONY += savedefconfig defconfig savedefconfig: $(obj)/conf $< $(silent) --$@=defconfig $(Kconfig) @@ -151,8 +119,7 @@ clean-dirs += tests/.cache # Help text used by make help help: @echo ' config - Update current config utilising a line-oriented program' - @echo ' nconfig - Update current config utilising a ncurses menu based' - @echo ' program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' @echo ' menuconfig - Update current config utilising a menu based program' @echo ' xconfig - Update current config utilising a Qt based front-end' @echo ' gconfig - Update current config utilising a GTK+ based front-end' @@ -172,141 +139,78 @@ help: @echo ' kvmconfig - Enable additional options for kvm guest kernel support' @echo ' xenconfig - Enable additional options for xen dom0 and guest kernel support' @echo ' tinyconfig - Configure the tiniest possible kernel' - -# lxdialog stuff -check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh - -# Use recursively expanded variables so we do not call gcc unless -# we really need to do so. (Do not call gcc as part of make mrproper) -HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ - -DLOCALE + @echo ' testconfig - Run Kconfig unit tests (requires python3 and pytest)' # =========================================================================== # Shared Makefile for the various kconfig executables: # conf: Used for defconfig, oldconfig and related targets -# nconf: Used for the nconfig target. -# Utilizes ncurses -# mconf: Used for the menuconfig target -# Utilizes the lxdialog package -# qconf: Used for the xconfig target -# Based on Qt which needs to be installed to compile it -# gconf: Used for the gconfig target -# Based on GTK+ which needs to be installed to compile it # object files used by all kconfig flavours -lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o -lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o - conf-objs := conf.o zconf.tab.o -mconf-objs := mconf.o zconf.tab.o $(lxdialog) -nconf-objs := nconf.o zconf.tab.o nconf.gui.o -kxgettext-objs := kxgettext.o zconf.tab.o -qconf-cxxobjs := qconf.o -qconf-objs := zconf.tab.o -gconf-objs := gconf.o zconf.tab.o -hostprogs-y := conf nconf mconf kxgettext qconf gconf +hostprogs-y := conf targets += zconf.lex.c -clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck -clean-files += gconf.glade.h -clean-files += config.pot linux.pot - -# Check that we have the required ncurses stuff installed for lxdialog (menuconfig) -PHONY += $(obj)/dochecklxdialog -$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/dochecklxdialog -$(obj)/dochecklxdialog: - $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) - -always := dochecklxdialog - -# Add environment specific flags -HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) -HOST_EXTRACXXFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCXX) $(HOSTCXXFLAGS)) # generated files seem to need this to find local include files HOSTCFLAGS_zconf.lex.o := -I$(src) HOSTCFLAGS_zconf.tab.o := -I$(src) -HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) - -HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ - -Wno-missing-prototypes - -HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) - -HOSTLOADLIBES_nconf = $(shell \ - pkg-config --libs menuw panelw ncursesw 2>/dev/null \ - || pkg-config --libs menu panel ncurses 2>/dev/null \ - || echo "-lmenu -lpanel -lncurses" ) -$(obj)/qconf.o: $(obj)/.tmp_qtcheck - -ifeq ($(MAKECMDGOALS),xconfig) -$(obj)/.tmp_qtcheck: $(src)/Makefile --include $(obj)/.tmp_qtcheck - -# Qt needs some extra effort... -$(obj)/.tmp_qtcheck: - @set -e; $(kecho) " CHECK qt"; \ - if pkg-config --exists Qt5Core; then \ - cflags="-std=c++11 -fPIC `pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets`"; \ - libs=`pkg-config --libs Qt5Core Qt5Gui Qt5Widgets`; \ - moc=`pkg-config --variable=host_bins Qt5Core`/moc; \ - elif pkg-config --exists QtCore; then \ - cflags=`pkg-config --cflags QtCore QtGui`; \ - libs=`pkg-config --libs QtCore QtGui`; \ - moc=`pkg-config --variable=moc_location QtCore`; \ - else \ - echo >&2 "*"; \ - echo >&2 "* Could not find Qt via pkg-config."; \ - echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH"; \ - echo >&2 "*"; \ - exit 1; \ - fi; \ - echo "KC_QT_CFLAGS=$$cflags" > $@; \ - echo "KC_QT_LIBS=$$libs" >> $@; \ - echo "KC_QT_MOC=$$moc" >> $@ -endif +# nconf: Used for the nconfig target based on ncurses +hostprogs-y += nconf +nconf-objs := nconf.o zconf.tab.o nconf.gui.o -$(obj)/gconf.o: $(obj)/.tmp_gtkcheck - -ifeq ($(MAKECMDGOALS),gconfig) --include $(obj)/.tmp_gtkcheck - -# GTK+ needs some extra effort, too... -$(obj)/.tmp_gtkcheck: - @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ - if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ - touch $@; \ - else \ - echo >&2 "*"; \ - echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ - echo >&2 "*"; \ - false; \ - fi \ - else \ - echo >&2 "*"; \ - echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \ - echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \ - echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ - echo >&2 "*"; \ - false; \ - fi -endif +HOSTLDLIBS_nconf = $(shell . $(obj)/.nconf-cfg && echo $$libs) +HOSTCFLAGS_nconf.o = $(shell . $(obj)/.nconf-cfg && echo $$cflags) +HOSTCFLAGS_nconf.gui.o = $(shell . $(obj)/.nconf-cfg && echo $$cflags) -$(obj)/zconf.tab.o: $(obj)/zconf.lex.c +$(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/.nconf-cfg + +# mconf: Used for the menuconfig target based on lxdialog +hostprogs-y += mconf +lxdialog := checklist.o inputbox.o menubox.o textbox.o util.o yesno.o +mconf-objs := mconf.o zconf.tab.o $(addprefix lxdialog/, $(lxdialog)) + +HOSTLDLIBS_mconf = $(shell . $(obj)/.mconf-cfg && echo $$libs) +$(foreach f, mconf.o $(lxdialog), \ + $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/.mconf-cfg && echo $$$$cflags))) + +$(obj)/mconf.o: $(obj)/.mconf-cfg +$(addprefix $(obj)/lxdialog/, $(lxdialog)): $(obj)/.mconf-cfg + +# qconf: Used for the xconfig target based on Qt +hostprogs-y += qconf +qconf-cxxobjs := qconf.o +qconf-objs := zconf.tab.o + +HOSTLDLIBS_qconf = $(shell . $(obj)/.qconf-cfg && echo $$libs) +HOSTCXXFLAGS_qconf.o = $(shell . $(obj)/.qconf-cfg && echo $$cflags) -$(obj)/qconf.o: $(obj)/qconf.moc +$(obj)/qconf.o: $(obj)/.qconf-cfg $(obj)/qconf.moc quiet_cmd_moc = MOC $@ - cmd_moc = $(KC_QT_MOC) -i $< -o $@ + cmd_moc = $(shell . $(obj)/.qconf-cfg && echo $$moc) -i $< -o $@ -$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck +$(obj)/%.moc: $(src)/%.h $(obj)/.qconf-cfg $(call cmd,moc) -# Extract gconf menu items for i18n support -$(obj)/gconf.glade.h: $(obj)/gconf.glade - $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ - $(obj)/gconf.glade +# gconf: Used for the gconfig target based on GTK+ +hostprogs-y += gconf +gconf-objs := gconf.o zconf.tab.o + +HOSTLDLIBS_gconf = $(shell . $(obj)/.gconf-cfg && echo $$libs) +HOSTCFLAGS_gconf.o = $(shell . $(obj)/.gconf-cfg && echo $$cflags) + +$(obj)/gconf.o: $(obj)/.gconf-cfg + +$(obj)/zconf.tab.o: $(obj)/zconf.lex.c + +# check if necessary packages are available, and configure build flags +define filechk_conf_cfg + $(CONFIG_SHELL) $< +endef + +$(obj)/.%conf-cfg: $(src)/%conf-cfg.sh FORCE + $(call filechk,conf_cfg) + +clean-files += .*conf-cfg diff --git a/scripts/kconfig/POTFILES.in b/scripts/kconfig/POTFILES.in deleted file mode 100644 index 967457396990..000000000000 --- a/scripts/kconfig/POTFILES.in +++ /dev/null @@ -1,12 +0,0 @@ -scripts/kconfig/lxdialog/checklist.c -scripts/kconfig/lxdialog/inputbox.c -scripts/kconfig/lxdialog/menubox.c -scripts/kconfig/lxdialog/textbox.c -scripts/kconfig/lxdialog/util.c -scripts/kconfig/lxdialog/yesno.c -scripts/kconfig/mconf.c -scripts/kconfig/conf.c -scripts/kconfig/confdata.c -scripts/kconfig/gconf.c -scripts/kconfig/gconf.glade.h -scripts/kconfig/qconf.cc diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh deleted file mode 100755 index 97f0fee7d173..000000000000 --- a/scripts/kconfig/check.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# Needed for systems without gettext -$* -x c -o /dev/null - > /dev/null 2>&1 << EOF -#include <libintl.h> -int main() -{ - gettext(""); - return 0; -} -EOF -if [ ! "$?" -eq "0" ]; then - echo -DKBUILD_NO_NLS; -fi diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 283eeedaa4fa..98e0c7a34699 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -3,7 +3,6 @@ * Released under the terms of the GNU GPL v2.0. */ -#include <locale.h> #include <ctype.h> #include <limits.h> #include <stdio.h> @@ -86,7 +85,7 @@ static int conf_askvalue(struct symbol *sym, const char *def) enum symbol_type type = sym_get_type(sym); if (!sym_has_value(sym)) - printf(_("(NEW) ")); + printf("(NEW) "); line[0] = '\n'; line[1] = 0; @@ -133,7 +132,7 @@ static int conf_string(struct menu *menu) const char *def; while (1) { - printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("%*s%s ", indent - 1, "", menu->prompt->text); printf("(%s) ", sym->name); def = sym_get_string_value(sym); if (sym_get_string_value(sym)) @@ -166,7 +165,7 @@ static int conf_sym(struct menu *menu) tristate oldval, newval; while (1) { - printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("%*s%s ", indent - 1, "", menu->prompt->text); if (sym->name) printf("(%s) ", sym->name); putchar('['); @@ -251,7 +250,7 @@ static int conf_choice(struct menu *menu) case no: return 1; case mod: - printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); return 0; case yes: break; @@ -261,7 +260,7 @@ static int conf_choice(struct menu *menu) while (1) { int cnt, def; - printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); def_sym = sym_get_choice_value(sym); cnt = def = 0; line[0] = 0; @@ -269,7 +268,7 @@ static int conf_choice(struct menu *menu) if (!menu_is_visible(child)) continue; if (!child->sym) { - printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + printf("%*c %s\n", indent, '*', menu_get_prompt(child)); continue; } cnt++; @@ -278,14 +277,14 @@ static int conf_choice(struct menu *menu) printf("%*c", indent, '>'); } else printf("%*c", indent, ' '); - printf(" %d. %s", cnt, _(menu_get_prompt(child))); + printf(" %d. %s", cnt, menu_get_prompt(child)); if (child->sym->name) printf(" (%s)", child->sym->name); if (!sym_has_value(child->sym)) - printf(_(" (NEW)")); + printf(" (NEW)"); printf("\n"); } - printf(_("%*schoice"), indent - 1, ""); + printf("%*schoice", indent - 1, ""); if (cnt == 1) { printf("[1]: 1\n"); goto conf_childs; @@ -372,7 +371,7 @@ static void conf(struct menu *menu) if (prompt) printf("%*c\n%*c %s\n%*c\n", indent, '*', - indent, '*', _(prompt), + indent, '*', prompt, indent, '*'); default: ; @@ -437,7 +436,7 @@ static void check_conf(struct menu *menu) } } else { if (!conf_cnt++) - printf(_("*\n* Restart config...\n*\n")); + printf("*\n* Restart config...\n*\n"); rootEntry = menu_get_parent_menu(menu); conf(rootEntry); } @@ -461,12 +460,6 @@ static struct option long_opts[] = { {"randconfig", no_argument, NULL, randconfig}, {"listnewconfig", no_argument, NULL, listnewconfig}, {"olddefconfig", no_argument, NULL, olddefconfig}, - /* - * oldnoconfig is an alias of olddefconfig, because people already - * are dependent on its behavior(sets new symbols to their default - * value but not 'n') with the counter-intuitive name. - */ - {"oldnoconfig", no_argument, NULL, olddefconfig}, {NULL, 0, NULL, 0} }; @@ -481,7 +474,6 @@ static void conf_usage(const char *progname) printf(" --syncconfig Similar to oldconfig but generates configuration in\n" " include/{generated/,config/}\n"); printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n"); - printf(" --oldnoconfig An alias of olddefconfig\n"); printf(" --defconfig <file> New config with default defined in <file>\n"); printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); printf(" --allnoconfig New config where all options are answered with no\n"); @@ -497,10 +489,7 @@ int main(int ac, char **av) int opt; const char *name, *defconfig_file = NULL /* gcc uninit */; struct stat tmpstat; - - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); + int no_conf_write = 0; tty_stdio = isatty(0) && isatty(1); @@ -512,6 +501,11 @@ int main(int ac, char **av) input_mode = (enum input_mode)opt; switch (opt) { case syncconfig: + /* + * syncconfig is invoked during the build stage. + * Suppress distracting "configuration written to ..." + */ + conf_set_message_callback(NULL); sync_kconfig = 1; break; case defconfig: @@ -559,7 +553,7 @@ int main(int ac, char **av) } } if (ac == optind) { - fprintf(stderr, _("%s: Kconfig file missing\n"), av[0]); + fprintf(stderr, "%s: Kconfig file missing\n", av[0]); conf_usage(progname); exit(1); } @@ -569,12 +563,12 @@ int main(int ac, char **av) if (sync_kconfig) { name = conf_get_configname(); if (stat(name, &tmpstat)) { - fprintf(stderr, _("***\n" + fprintf(stderr, "***\n" "*** Configuration file \"%s\" not found!\n" "***\n" "*** Please run some configurator (e.g. \"make oldconfig\" or\n" "*** \"make menuconfig\" or \"make xconfig\").\n" - "***\n"), name); + "***\n", name); exit(1); } } @@ -585,9 +579,9 @@ int main(int ac, char **av) defconfig_file = conf_get_default_confname(); if (conf_read(defconfig_file)) { fprintf(stderr, - _("***\n" + "***\n" "*** Can't find default configuration \"%s\"!\n" - "***\n"), + "***\n", defconfig_file); exit(1); } @@ -611,7 +605,7 @@ int main(int ac, char **av) if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { if (conf_read_simple(name, S_DEF_USER)) { fprintf(stderr, - _("*** Can't read seed configuration \"%s\"!\n"), + "*** Can't read seed configuration \"%s\"!\n", name); exit(1); } @@ -628,7 +622,7 @@ int main(int ac, char **av) if (conf_read_simple(name, S_DEF_USER) && conf_read_simple("all.config", S_DEF_USER)) { fprintf(stderr, - _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n", name); exit(1); } @@ -638,13 +632,14 @@ int main(int ac, char **av) } if (sync_kconfig) { - if (conf_get_changed()) { - name = getenv("KCONFIG_NOSILENTUPDATE"); - if (name && *name) { + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + if (conf_get_changed()) { fprintf(stderr, - _("\n*** The configuration requires explicit update.\n\n")); + "\n*** The configuration requires explicit update.\n\n"); return 1; } + no_conf_write = 1; } } @@ -689,29 +684,32 @@ int main(int ac, char **av) break; } - if (sync_kconfig) { - /* syncconfig is used during the build so we shall update autoconf. - * All other commands are only used to generate a config. - */ - if (conf_get_changed() && conf_write(NULL)) { - fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); - exit(1); - } - if (conf_write_autoconf()) { - fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); - return 1; - } - } else if (input_mode == savedefconfig) { + if (input_mode == savedefconfig) { if (conf_write_defconfig(defconfig_file)) { - fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), + fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n", defconfig_file); return 1; } } else if (input_mode != listnewconfig) { - if (conf_write(NULL)) { - fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + if (!no_conf_write && conf_write(NULL)) { + fprintf(stderr, "\n*** Error during writing of the configuration.\n\n"); exit(1); } + + /* + * Create auto.conf if it does not exist. + * This prevents GNU Make 4.1 or older from emitting + * "include/config/auto.conf: No such file or directory" + * in the top-level Makefile + * + * syncconfig always creates or updates auto.conf because it is + * used during the build. + */ + if (conf_write_autoconf(sync_kconfig) && sync_kconfig) { + fprintf(stderr, + "\n*** Error during sync of the configuration.\n\n"); + return 1; + } } return 0; } diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index df26c7b0fe13..91d0a5c014ac 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -16,6 +16,64 @@ #include "lkc.h" +/* return true if 'path' exists, false otherwise */ +static bool is_present(const char *path) +{ + struct stat st; + + return !stat(path, &st); +} + +/* return true if 'path' exists and it is a directory, false otherwise */ +static bool is_dir(const char *path) +{ + struct stat st; + + if (stat(path, &st)) + return 0; + + return S_ISDIR(st.st_mode); +} + +/* + * Create the parent directory of the given path. + * + * For example, if 'include/config/auto.conf' is given, create 'include/config'. + */ +static int make_parent_dir(const char *path) +{ + char tmp[PATH_MAX + 1]; + char *p; + + strncpy(tmp, path, sizeof(tmp)); + tmp[sizeof(tmp) - 1] = 0; + + /* Remove the base name. Just return if nothing is left */ + p = strrchr(tmp, '/'); + if (!p) + return 0; + *(p + 1) = 0; + + /* Just in case it is an absolute path */ + p = tmp; + while (*p == '/') + p++; + + while ((p = strchr(p, '/'))) { + *p = 0; + + /* skip if the directory exists */ + if (!is_dir(tmp) && mkdir(tmp, 0755)) + return -1; + + *p = '/'; + while (*p == '/') + p++; + } + + return 0; +} + struct conf_printer { void (*print_symbol)(FILE *, struct symbol *, const char *, void *); void (*print_comment)(FILE *, const char *, void *); @@ -30,7 +88,7 @@ static void conf_message(const char *fmt, ...) static const char *conf_filename; static int conf_lineno, conf_warnings; -const char conf_defname[] = "arch/$ARCH/defconfig"; +const char conf_defname[] = "arch/$(ARCH)/defconfig"; static void conf_warning(const char *fmt, ...) { @@ -43,16 +101,16 @@ static void conf_warning(const char *fmt, ...) conf_warnings++; } -static void conf_default_message_callback(const char *fmt, va_list ap) +static void conf_default_message_callback(const char *s) { printf("#\n# "); - vprintf(fmt, ap); + printf("%s", s); printf("\n#\n"); } -static void (*conf_message_callback) (const char *fmt, va_list ap) = +static void (*conf_message_callback)(const char *s) = conf_default_message_callback; -void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +void conf_set_message_callback(void (*fn)(const char *s)) { conf_message_callback = fn; } @@ -60,10 +118,15 @@ void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) static void conf_message(const char *fmt, ...) { va_list ap; + char buf[4096]; + + if (!conf_message_callback) + return; va_start(ap, fmt); - if (conf_message_callback) - conf_message_callback(fmt, ap); + + vsnprintf(buf, sizeof(buf), fmt, ap); + conf_message_callback(buf); va_end(ap); } @@ -81,43 +144,16 @@ const char *conf_get_autoconfig_name(void) return name ? name : "include/config/auto.conf"; } -static char *conf_expand_value(const char *in) -{ - struct symbol *sym; - const char *src; - static char res_value[SYMBOL_MAXLENGTH]; - char *dst, name[SYMBOL_MAXLENGTH]; - - res_value[0] = 0; - dst = name; - while ((src = strchr(in, '$'))) { - strncat(res_value, in, src - in); - src++; - dst = name; - while (isalnum(*src) || *src == '_') - *dst++ = *src++; - *dst = 0; - sym = sym_lookup(name, 0); - sym_calc_value(sym); - strcat(res_value, sym_get_string_value(sym)); - in = src; - } - strcat(res_value, in); - - return res_value; -} - char *conf_get_default_confname(void) { - struct stat buf; static char fullname[PATH_MAX+1]; char *env, *name; - name = conf_expand_value(conf_defname); + name = expand_string(conf_defname); env = getenv(SRCTREE); if (env) { sprintf(fullname, "%s/%s", env, name); - if (!stat(fullname, &buf)) + if (is_present(fullname)) return fullname; } return name; @@ -274,10 +310,11 @@ int conf_read_simple(const char *name, int def) if (expr_calc_value(prop->visible.expr) == no || prop->expr->type != E_SYMBOL) continue; - name = conf_expand_value(prop->expr->left.sym->name); + sym_calc_value(prop->expr->left.sym); + name = sym_get_string_value(prop->expr->left.sym); in = zconf_fopen(name); if (in) { - conf_message(_("using defaults found in %s"), + conf_message("using defaults found in %s", name); goto load; } @@ -422,7 +459,7 @@ int conf_read(const char *name) for_all_symbols(i, sym) { sym_calc_value(sym); - if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE)) continue; if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { /* check that calculated value agrees with saved value */ @@ -745,15 +782,14 @@ int conf_write(const char *name) struct menu *menu; const char *basename; const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; char *env; dirname[0] = 0; if (name && name[0]) { - struct stat st; char *slash; - if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + if (is_dir(name)) { strcpy(dirname, name); strcat(dirname, "/"); basename = conf_get_configname(); @@ -831,33 +867,66 @@ next: return 1; } - conf_message(_("configuration written to %s"), newname); + conf_message("configuration written to %s", newname); sym_set_change_count(0); return 0; } +/* write a dependency file as used by kbuild to track dependencies */ +static int conf_write_dep(const char *name) +{ + struct file *file; + FILE *out; + + if (!name) + name = ".kconfig.d"; + out = fopen("..config.tmp", "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) { + if (file->next) + fprintf(out, "\t%s \\\n", file->name); + else + fprintf(out, "\t%s\n", file->name); + } + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + + env_write_dep(out, conf_get_autoconfig_name()); + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); + + if (make_parent_dir(name)) + return 1; + rename("..config.tmp", name); + return 0; +} + static int conf_split_config(void) { const char *name; char path[PATH_MAX+1]; char *s, *d, c; struct symbol *sym; - struct stat sb; int res, i, fd; name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); + if (make_parent_dir("include/config/foo.h")) + return 1; if (chdir("include/config")) return 1; res = 0; for_all_symbols(i, sym) { sym_calc_value(sym); - if ((sym->flags & SYMBOL_AUTO) || !sym->name) + if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name) continue; if (sym->flags & SYMBOL_WRITE) { if (sym->flags & SYMBOL_DEF_AUTO) { @@ -922,19 +991,12 @@ static int conf_split_config(void) res = 1; break; } - /* - * Create directory components, - * unless they exist already. - */ - d = path; - while ((d = strchr(d, '/'))) { - *d = 0; - if (stat(path, &sb) && mkdir(path, 0755)) { - res = 1; - goto out; - } - *d++ = '/'; + + if (make_parent_dir(path)) { + res = 1; + goto out; } + /* Try it again. */ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { @@ -951,16 +1013,20 @@ out: return res; } -int conf_write_autoconf(void) +int conf_write_autoconf(int overwrite) { struct symbol *sym; const char *name; + const char *autoconf_name = conf_get_autoconfig_name(); FILE *out, *tristate, *out_h; int i; + if (!overwrite && is_present(autoconf_name)) + return 0; + sym_clear_all_valid(); - file_write_dep("include/config/auto.conf.cmd"); + conf_write_dep("include/config/auto.conf.cmd"); if (conf_split_config()) return 1; @@ -1007,19 +1073,26 @@ int conf_write_autoconf(void) name = getenv("KCONFIG_AUTOHEADER"); if (!name) name = "include/generated/autoconf.h"; + if (make_parent_dir(name)) + return 1; if (rename(".tmpconfig.h", name)) return 1; + name = getenv("KCONFIG_TRISTATE"); if (!name) name = "include/config/tristate.conf"; + if (make_parent_dir(name)) + return 1; if (rename(".tmpconfig_tristate", name)) return 1; - name = conf_get_autoconfig_name(); + + if (make_parent_dir(autoconf_name)) + return 1; /* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. */ - if (rename(".tmpconfig", name)) + if (rename(".tmpconfig", autoconf_name)) return 1; return 0; diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 94a383b21df6..7c329e179007 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -141,7 +141,7 @@ struct symbol { #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_AUTO 0x1000 /* value from environment variable */ +#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 */ @@ -171,6 +171,9 @@ struct symbol { * config BAZ * int "BAZ Value" * range 1..255 + * + * Please, also check zconf.y:print_symbol() when modifying the + * list of property types! */ enum prop_type { P_UNKNOWN, @@ -182,7 +185,6 @@ enum prop_type { P_SELECT, /* select BAR */ P_IMPLY, /* imply BAR */ P_RANGE, /* range 7..100 (for a symbol) */ - P_ENV, /* value from environment variable */ P_SYMBOL, /* where a symbol is defined */ }; diff --git a/scripts/kconfig/gconf-cfg.sh b/scripts/kconfig/gconf-cfg.sh new file mode 100755 index 000000000000..480ecd8b9f41 --- /dev/null +++ b/scripts/kconfig/gconf-cfg.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +PKG="gtk+-2.0 gmodule-2.0 libglade-2.0" + +if [ -z "$(command -v pkg-config)" ]; then + echo >&2 "*" + echo >&2 "* 'make gconfig' requires 'pkg-config'. Please install it." + echo >&2 "*" + exit 1 +fi + +if ! pkg-config --exists $PKG; then + echo >&2 "*" + echo >&2 "* Unable to find the GTK+ installation. Please make sure that" + echo >&2 "* the GTK+ 2.0 development package is correctly installed." + echo >&2 "* You need $PKG" + echo >&2 "*" + exit 1 +fi + +if ! pkg-config --atleast-version=2.0.0 gtk+-2.0; then + echo >&2 "*" + echo >&2 "* GTK+ is present but version >= 2.0.0 is required." + echo >&2 "*" + exit 1 +fi + +echo cflags=\"$(pkg-config --cflags $PKG)\" +echo libs=\"$(pkg-config --libs $PKG)\" diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index cfddddb9c9d7..36f578415c4a 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -101,8 +101,8 @@ const char *dbg_sym_flags(int val) strcat(buf, "write/"); if (val & SYMBOL_CHANGED) strcat(buf, "changed/"); - if (val & SYMBOL_AUTO) - strcat(buf, "auto/"); + if (val & SYMBOL_NO_WRITE) + strcat(buf, "no_write/"); buf[strlen(buf) - 1] = '\0'; @@ -137,7 +137,7 @@ void init_main_window(const gchar * glade_file) xml = glade_xml_new(glade_file, "window1", NULL); if (!xml) - g_error(_("GUI loading failed !\n")); + g_error("GUI loading failed !\n"); glade_xml_signal_autoconnect(xml); main_wnd = glade_xml_get_widget(xml, "window1"); @@ -233,7 +233,7 @@ void init_left_tree(void) column = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, column); - gtk_tree_view_column_set_title(column, _("Options")); + gtk_tree_view_column_set_title(column, "Options"); renderer = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), @@ -276,7 +276,7 @@ void init_right_tree(void) column = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, column); - gtk_tree_view_column_set_title(column, _("Options")); + gtk_tree_view_column_set_title(column, "Options"); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), @@ -305,7 +305,7 @@ void init_right_tree(void) renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, - _("Name"), renderer, + "Name", renderer, "text", COL_NAME, "foreground-gdk", COL_COLOR, NULL); @@ -329,7 +329,7 @@ void init_right_tree(void) COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, - _("Value"), renderer, + "Value", renderer, "text", COL_VALUE, "editable", COL_EDIT, @@ -368,7 +368,7 @@ static void text_insert_help(struct menu *menu) { GtkTextBuffer *buffer; GtkTextIter start, end; - const char *prompt = _(menu_get_prompt(menu)); + const char *prompt = menu_get_prompt(menu); struct gstr help = str_new(); menu_get_ext_help(menu, &help); @@ -422,7 +422,7 @@ gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, if (!conf_get_changed()) return FALSE; - dialog = gtk_dialog_new_with_buttons(_("Warning !"), + dialog = gtk_dialog_new_with_buttons("Warning !", GTK_WINDOW(main_wnd), (GtkDialogFlags) (GTK_DIALOG_MODAL | @@ -436,7 +436,7 @@ gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL); - label = gtk_label_new(_("\nSave configuration ?\n")); + label = gtk_label_new("\nSave configuration ?\n"); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); gtk_widget_show(label); @@ -496,7 +496,7 @@ load_filename(GtkFileSelection * file_selector, gpointer user_data) (user_data)); if (conf_read(fn)) - text_insert_msg(_("Error"), _("Unable to load configuration !")); + text_insert_msg("Error", "Unable to load configuration !"); else display_tree(&rootmenu); } @@ -505,7 +505,7 @@ void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *fs; - fs = gtk_file_selection_new(_("Load file...")); + fs = gtk_file_selection_new("Load file..."); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(load_filename), (gpointer) fs); @@ -524,7 +524,8 @@ void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) { if (conf_write(NULL)) - text_insert_msg(_("Error"), _("Unable to save configuration !")); + text_insert_msg("Error", "Unable to save configuration !"); + conf_write_autoconf(0); } @@ -537,7 +538,7 @@ store_filename(GtkFileSelection * file_selector, gpointer user_data) (user_data)); if (conf_write(fn)) - text_insert_msg(_("Error"), _("Unable to save configuration !")); + text_insert_msg("Error", "Unable to save configuration !"); gtk_widget_destroy(GTK_WIDGET(user_data)); } @@ -546,7 +547,7 @@ void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *fs; - fs = gtk_file_selection_new(_("Save file as...")); + fs = gtk_file_selection_new("Save file as..."); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(store_filename), (gpointer) fs); @@ -639,7 +640,7 @@ on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; - const gchar *intro_text = _( + const gchar *intro_text = "Welcome to gkc, the GTK+ graphical configuration tool\n" "For each option, a blank box indicates the feature is disabled, a\n" "check indicates it is enabled, and a dot indicates that it is to\n" @@ -654,7 +655,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) "option.\n" "\n" "Toggling Show Debug Info under the Options menu will show \n" - "the dependencies, which you can then match by examining other options."); + "the dependencies, which you can then match by examining other options."; dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, @@ -671,8 +672,8 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *about_text = - _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n" - "Based on the source code from Roman Zippel.\n"); + "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n" + "Based on the source code from Roman Zippel.\n"; dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, @@ -689,9 +690,9 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *license_text = - _("gkc is released under the terms of the GNU GPL v2.\n" + "gkc is released under the terms of the GNU GPL v2.\n" "For more information, please see the source code or\n" - "visit http://www.fsf.org/licenses/licenses.html\n"); + "visit http://www.fsf.org/licenses/licenses.html\n"; dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, @@ -1049,7 +1050,7 @@ static gchar **fill_row(struct menu *menu) bzero(row, sizeof(row)); row[COL_OPTION] = - g_strdup_printf("%s %s", _(menu_get_prompt(menu)), + g_strdup_printf("%s %s", menu_get_prompt(menu), sym && !sym_has_value(sym) ? "(NEW)" : ""); if (opt_mode == OPT_ALL && !menu_is_visible(menu)) @@ -1102,7 +1103,7 @@ static gchar **fill_row(struct menu *menu) if (def_menu) row[COL_VALUE] = - g_strdup(_(menu_get_prompt(def_menu))); + g_strdup(menu_get_prompt(def_menu)); } if (sym->flags & SYMBOL_CHOICEVAL) row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); @@ -1447,10 +1448,6 @@ int main(int ac, char *av[]) char *env; gchar *glade_file; - bindtextdomain(PACKAGE, LOCALEDIR); - bind_textdomain_codeset(PACKAGE, "UTF-8"); - textdomain(PACKAGE); - /* GTK stuffs */ gtk_set_locale(); gtk_init(&ac, &av); diff --git a/scripts/kconfig/kconf_id.c b/scripts/kconfig/kconf_id.c index 3ea9c5f9f730..b3e0ea0ac732 100644 --- a/scripts/kconfig/kconf_id.c +++ b/scripts/kconfig/kconf_id.c @@ -32,7 +32,6 @@ static struct kconf_id kconf_id_array[] = { { "on", T_ON, TF_PARAM }, { "modules", T_OPT_MODULES, TF_OPTION }, { "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION }, - { "env", T_OPT_ENV, TF_OPTION }, { "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION }, }; diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c deleted file mode 100644 index 240880a89111..000000000000 --- a/scripts/kconfig/kxgettext.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005 - * - * Released under the terms of the GNU GPL v2.0 - */ - -#include <stdlib.h> -#include <string.h> - -#include "lkc.h" - -static char *escape(const char* text, char *bf, int len) -{ - char *bfp = bf; - int multiline = strchr(text, '\n') != NULL; - int eol = 0; - int textlen = strlen(text); - - if ((textlen > 0) && (text[textlen-1] == '\n')) - eol = 1; - - *bfp++ = '"'; - --len; - - if (multiline) { - *bfp++ = '"'; - *bfp++ = '\n'; - *bfp++ = '"'; - len -= 3; - } - - while (*text != '\0' && len > 1) { - if (*text == '"') - *bfp++ = '\\'; - else if (*text == '\n') { - *bfp++ = '\\'; - *bfp++ = 'n'; - *bfp++ = '"'; - *bfp++ = '\n'; - *bfp++ = '"'; - len -= 5; - ++text; - goto next; - } - else if (*text == '\\') { - *bfp++ = '\\'; - len--; - } - *bfp++ = *text++; -next: - --len; - } - - if (multiline && eol) - bfp -= 3; - - *bfp++ = '"'; - *bfp = '\0'; - - return bf; -} - -struct file_line { - struct file_line *next; - const char *file; - int lineno; -}; - -static struct file_line *file_line__new(const char *file, int lineno) -{ - struct file_line *self = malloc(sizeof(*self)); - - if (self == NULL) - goto out; - - self->file = file; - self->lineno = lineno; - self->next = NULL; -out: - return self; -} - -struct message { - const char *msg; - const char *option; - struct message *next; - struct file_line *files; -}; - -static struct message *message__list; - -static struct message *message__new(const char *msg, char *option, - const char *file, int lineno) -{ - struct message *self = malloc(sizeof(*self)); - - if (self == NULL) - goto out; - - self->files = file_line__new(file, lineno); - if (self->files == NULL) - goto out_fail; - - self->msg = xstrdup(msg); - if (self->msg == NULL) - goto out_fail_msg; - - self->option = option; - self->next = NULL; -out: - return self; -out_fail_msg: - free(self->files); -out_fail: - free(self); - self = NULL; - goto out; -} - -static struct message *mesage__find(const char *msg) -{ - struct message *m = message__list; - - while (m != NULL) { - if (strcmp(m->msg, msg) == 0) - break; - m = m->next; - } - - return m; -} - -static int message__add_file_line(struct message *self, const char *file, - int lineno) -{ - int rc = -1; - struct file_line *fl = file_line__new(file, lineno); - - if (fl == NULL) - goto out; - - fl->next = self->files; - self->files = fl; - rc = 0; -out: - return rc; -} - -static int message__add(const char *msg, char *option, const char *file, - int lineno) -{ - int rc = 0; - char bf[16384]; - char *escaped = escape(msg, bf, sizeof(bf)); - struct message *m = mesage__find(escaped); - - if (m != NULL) - rc = message__add_file_line(m, file, lineno); - else { - m = message__new(escaped, option, file, lineno); - - if (m != NULL) { - m->next = message__list; - message__list = m; - } else - rc = -1; - } - return rc; -} - -static void menu_build_message_list(struct menu *menu) -{ - struct menu *child; - - message__add(menu_get_prompt(menu), NULL, - menu->file == NULL ? "Root Menu" : menu->file->name, - menu->lineno); - - if (menu->sym != NULL && menu_has_help(menu)) - message__add(menu_get_help(menu), menu->sym->name, - menu->file == NULL ? "Root Menu" : menu->file->name, - menu->lineno); - - for (child = menu->list; child != NULL; child = child->next) - if (child->prompt != NULL) - menu_build_message_list(child); -} - -static void message__print_file_lineno(struct message *self) -{ - struct file_line *fl = self->files; - - putchar('\n'); - if (self->option != NULL) - printf("# %s:00000\n", self->option); - - printf("#: %s:%d", fl->file, fl->lineno); - fl = fl->next; - - while (fl != NULL) { - printf(", %s:%d", fl->file, fl->lineno); - fl = fl->next; - } - - putchar('\n'); -} - -static void message__print_gettext_msgid_msgstr(struct message *self) -{ - message__print_file_lineno(self); - - printf("msgid %s\n" - "msgstr \"\"\n", self->msg); -} - -static void menu__xgettext(void) -{ - struct message *m = message__list; - - while (m != NULL) { - /* skip empty lines ("") */ - if (strlen(m->msg) > sizeof("\"\"")) - message__print_gettext_msgid_msgstr(m); - m = m->next; - } -} - -int main(int ac, char **av) -{ - conf_parse(av[1]); - - menu_build_message_list(menu_get_root_menu(NULL)); - menu__xgettext(); - return 0; -} diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index f4394af6e4b8..9eb7c837cd8f 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -8,15 +8,6 @@ #include "expr.h" -#ifndef KBUILD_NO_NLS -# include <libintl.h> -#else -static inline const char *gettext(const char *txt) { return txt; } -static inline void textdomain(const char *domainname) {} -static inline void bindtextdomain(const char *name, const char *dir) {} -static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } -#endif - #ifdef __cplusplus extern "C" { #endif @@ -29,11 +20,6 @@ extern "C" { #define PACKAGE "linux" #endif -#define LOCALEDIR "/usr/share/locale" - -#define _(text) gettext(text) -#define N_(text) (text) - #ifndef CONFIG_ #define CONFIG_ "CONFIG_" #endif @@ -58,7 +44,6 @@ enum conf_def_mode { #define T_OPT_MODULES 1 #define T_OPT_DEFCONFIG_LIST 2 -#define T_OPT_ENV 3 #define T_OPT_ALLNOCONFIG_Y 4 struct kconf_id { @@ -112,11 +97,11 @@ void menu_set_type(int type); /* util.c */ struct file *file_lookup(const char *name); -int file_write_dep(const char *name); void *xmalloc(size_t size); void *xcalloc(size_t nmemb, size_t size); void *xrealloc(void *p, size_t size); char *xstrdup(const char *s); +char *xstrndup(const char *s, size_t n); struct gstr { size_t len; @@ -134,16 +119,12 @@ void str_printf(struct gstr *gs, const char *fmt, ...); const char *str_get(struct gstr *gs); /* symbol.c */ -extern struct expr *sym_env_list; - -void sym_init(void); void sym_clear_all_valid(void); struct symbol *sym_choice_default(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym); struct property *prop_alloc(enum prop_type type, struct symbol *sym); struct symbol *prop_get_symbol(struct property *prop); -struct property *sym_get_env_prop(struct symbol *sym); static inline tristate sym_get_tristate_value(struct symbol *sym) { diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 9dc8abfb1dc3..86c267540ccc 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -7,10 +7,10 @@ int conf_read(const char *name); int conf_read_simple(const char *name, int); int conf_write_defconfig(const char *name); int conf_write(const char *name); -int conf_write_autoconf(void); +int conf_write_autoconf(int overwrite); bool conf_get_changed(void); void conf_set_changed_callback(void (*fn)(void)); -void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap)); +void conf_set_message_callback(void (*fn)(const char *s)); /* menu.c */ extern struct menu rootmenu; @@ -31,7 +31,6 @@ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; struct symbol * sym_lookup(const char *name, int flags); struct symbol * sym_find(const char *name); -char *sym_expand_string_value(const char *in); const char * sym_escape_string_value(const char *in); struct symbol ** sym_re_search(const char *pattern); const char * sym_type_name(enum symbol_type type); @@ -49,5 +48,19 @@ 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_string(const char *in); +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/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh deleted file mode 100755 index 6c0bcd9c472d..000000000000 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -# Check ncurses compatibility - -# What library to link -ldflags() -{ - pkg-config --libs ncursesw 2>/dev/null && exit - pkg-config --libs ncurses 2>/dev/null && exit - for ext in so a dll.a dylib ; do - for lib in ncursesw ncurses curses ; do - $cc -print-file-name=lib${lib}.${ext} | grep -q / - if [ $? -eq 0 ]; then - echo "-l${lib}" - exit - fi - done - done - exit 1 -} - -# Where is ncurses.h? -ccflags() -{ - if pkg-config --cflags ncursesw 2>/dev/null; then - echo '-DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1' - elif pkg-config --cflags ncurses 2>/dev/null; then - echo '-DCURSES_LOC="<ncurses.h>"' - elif [ -f /usr/include/ncursesw/curses.h ]; then - echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"' - echo ' -DNCURSES_WIDECHAR=1' - elif [ -f /usr/include/ncurses/ncurses.h ]; then - echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"' - elif [ -f /usr/include/ncurses/curses.h ]; then - echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"' - elif [ -f /usr/include/ncurses.h ]; then - echo '-DCURSES_LOC="<ncurses.h>"' - else - echo '-DCURSES_LOC="<curses.h>"' - fi -} - -# Temp file, try to clean up after us -tmp=.lxdialog.tmp -trap "rm -f $tmp" 0 1 2 3 15 - -# Check if we can link to ncurses -check() { - $cc -x c - -o $tmp 2>/dev/null <<'EOF' -#include CURSES_LOC -main() {} -EOF - if [ $? != 0 ]; then - echo " *** Unable to find the ncurses libraries or the" 1>&2 - echo " *** required header files." 1>&2 - echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 - echo " *** " 1>&2 - echo " *** Install ncurses (ncurses-devel or libncurses-dev " 1>&2 - echo " *** depending on your distribution) and try again." 1>&2 - echo " *** " 1>&2 - exit 1 - fi -} - -usage() { - printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" -} - -if [ $# -eq 0 ]; then - usage - exit 1 -fi - -cc="" -case "$1" in - "-check") - shift - cc="$@" - check - ;; - "-ccflags") - ccflags - ;; - "-ldflags") - shift - cc="$@" - ldflags - ;; - "*") - usage - exit 1 - ;; -esac diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c index 8d016faa28d7..2e96323ad11b 100644 --- a/scripts/kconfig/lxdialog/checklist.c +++ b/scripts/kconfig/lxdialog/checklist.c @@ -103,8 +103,8 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected) int x = width / 2 - 11; int y = height - 2; - print_button(dialog, gettext("Select"), y, x, selected == 0); - print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + print_button(dialog, "Select", y, x, selected == 0); + print_button(dialog, " Help ", y, x + 14, selected == 1); wmove(dialog, y, x + 1 + 14 * selected); wrefresh(dialog); diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index fcffd5b41fb0..0b00be5abaa6 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -26,16 +26,10 @@ #include <string.h> #include <stdbool.h> -#ifndef KBUILD_NO_NLS -# include <libintl.h> -#else -# define gettext(Msgid) ((const char *) (Msgid)) -#endif - #ifdef __sun__ #define CURS_MACROS #endif -#include CURSES_LOC +#include <ncurses.h> /* * Colors in ncurses 1.9.9e do not work properly since foreground and diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c index d58de1dc5360..fe82ff6d744e 100644 --- a/scripts/kconfig/lxdialog/inputbox.c +++ b/scripts/kconfig/lxdialog/inputbox.c @@ -31,8 +31,8 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected) int x = width / 2 - 11; int y = height - 2; - print_button(dialog, gettext(" Ok "), y, x, selected == 0); - print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + print_button(dialog, " Ok ", y, x, selected == 0); + print_button(dialog, " Help ", y, x + 14, selected == 1); wmove(dialog, y, x + 1 + 14 * selected); wrefresh(dialog); diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c index 11ae9ad7ac7b..d70cab36137e 100644 --- a/scripts/kconfig/lxdialog/menubox.c +++ b/scripts/kconfig/lxdialog/menubox.c @@ -157,11 +157,11 @@ static void print_buttons(WINDOW * win, int height, int width, int selected) int x = width / 2 - 28; int y = height - 2; - print_button(win, gettext("Select"), y, x, selected == 0); - print_button(win, gettext(" Exit "), y, x + 12, selected == 1); - print_button(win, gettext(" Help "), y, x + 24, selected == 2); - print_button(win, gettext(" Save "), y, x + 36, selected == 3); - print_button(win, gettext(" Load "), y, x + 48, selected == 4); + print_button(win, "Select", y, x, selected == 0); + print_button(win, " Exit ", y, x + 12, selected == 1); + print_button(win, " Help ", y, x + 24, selected == 2); + print_button(win, " Save ", y, x + 36, selected == 3); + print_button(win, " Load ", y, x + 48, selected == 4); wmove(win, y, x + 1 + 12 * selected); wrefresh(win); diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 1773319b95e7..88d2818ed956 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -129,7 +129,7 @@ do_resize: print_title(dialog, title, width); - print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE); + print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE); wnoutrefresh(dialog); getyx(dialog, cur_y, cur_x); /* Save cursor position */ diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c index 676fb2f824a3..cd1223c903d1 100644 --- a/scripts/kconfig/lxdialog/yesno.c +++ b/scripts/kconfig/lxdialog/yesno.c @@ -29,8 +29,8 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected) int x = width / 2 - 10; int y = height - 2; - print_button(dialog, gettext(" Yes "), y, x, selected == 0); - print_button(dialog, gettext(" No "), y, x + 13, selected == 1); + print_button(dialog, " Yes ", y, x, selected == 0); + print_button(dialog, " No ", y, x + 13, selected == 1); wmove(dialog, y, x + 1 + 13 * selected); wrefresh(dialog); diff --git a/scripts/kconfig/mconf-cfg.sh b/scripts/kconfig/mconf-cfg.sh new file mode 100755 index 000000000000..c812872d7f9d --- /dev/null +++ b/scripts/kconfig/mconf-cfg.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +PKG="ncursesw" +PKG2="ncurses" + +if [ -n "$(command -v pkg-config)" ]; then + if pkg-config --exists $PKG; then + echo cflags=\"$(pkg-config --cflags $PKG)\" + echo libs=\"$(pkg-config --libs $PKG)\" + exit 0 + fi + + if pkg-config --exists $PKG2; then + echo cflags=\"$(pkg-config --cflags $PKG2)\" + echo libs=\"$(pkg-config --libs $PKG2)\" + exit 0 + fi +fi + +# Check the default paths in case pkg-config is not installed. +# (Even if it is installed, some distributions such as openSUSE cannot +# find ncurses by pkg-config.) +if [ -f /usr/include/ncursesw/ncurses.h ]; then + echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\" + echo libs=\"-lncursesw\" + exit 0 +fi + +if [ -f /usr/include/ncurses/ncurses.h ]; then + echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\" + echo libs=\"-lncurses\" + exit 0 +fi + +if [ -f /usr/include/ncurses.h ]; then + echo cflags=\"-D_GNU_SOURCE\" + echo libs=\"-lncurses\" + exit 0 +fi + +echo >&2 "*" +echo >&2 "* Unable to find the ncurses package." +echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" +echo >&2 "* depending on your distribution)." +echo >&2 "*" +exit 1 diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index c829be8bb19f..143c05fec161 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -17,12 +17,11 @@ #include <string.h> #include <signal.h> #include <unistd.h> -#include <locale.h> #include "lkc.h" #include "lxdialog/dialog.h" -static const char mconf_readme[] = N_( +static const char mconf_readme[] = "Overview\n" "--------\n" "This interface lets you select features and parameters for the build.\n" @@ -171,37 +170,37 @@ static const char mconf_readme[] = N_( " blackbg => selects a color scheme with black background\n" " classic => theme with blue background. The classic look\n" " bluetitle => an LCD friendly version of classic. (default)\n" -"\n"), -menu_instructions[] = N_( +"\n", +menu_instructions[] = "Arrow keys navigate the menu. " "<Enter> selects submenus ---> (or empty submenus ----). " "Highlighted letters are hotkeys. " "Pressing <Y> includes, <N> excludes, <M> modularizes features. " "Press <Esc><Esc> to exit, <?> for Help, </> for Search. " - "Legend: [*] built-in [ ] excluded <M> module < > module capable"), -radiolist_instructions[] = N_( + "Legend: [*] built-in [ ] excluded <M> module < > module capable", +radiolist_instructions[] = "Use the arrow keys to navigate this window or " "press the hotkey of the item you wish to select " "followed by the <SPACE BAR>. " - "Press <?> for additional information about this option."), -inputbox_instructions_int[] = N_( + "Press <?> for additional information about this option.", +inputbox_instructions_int[] = "Please enter a decimal value. " "Fractions will not be accepted. " - "Use the <TAB> key to move from the input field to the buttons below it."), -inputbox_instructions_hex[] = N_( + "Use the <TAB> key to move from the input field to the buttons below it.", +inputbox_instructions_hex[] = "Please enter a hexadecimal value. " - "Use the <TAB> key to move from the input field to the buttons below it."), -inputbox_instructions_string[] = N_( + "Use the <TAB> key to move from the input field to the buttons below it.", +inputbox_instructions_string[] = "Please enter a string value. " - "Use the <TAB> key to move from the input field to the buttons below it."), -setmod_text[] = N_( + "Use the <TAB> key to move from the input field to the buttons below it.", +setmod_text[] = "This feature depends on another which has been configured as a module.\n" - "As a result, this feature will be built as a module."), -load_config_text[] = N_( + "As a result, this feature will be built as a module.", +load_config_text[] = "Enter the name of the configuration file you wish to load. " "Accept the name shown to restore the configuration you " - "last retrieved. Leave blank to abort."), -load_config_help[] = N_( + "last retrieved. Leave blank to abort.", +load_config_help[] = "\n" "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" @@ -211,11 +210,11 @@ load_config_help[] = N_( "configuration.\n" "\n" "If you are uncertain, then you have probably never used alternate\n" - "configuration files. You should therefore leave this blank to abort.\n"), -save_config_text[] = N_( + "configuration files. You should therefore leave this blank to abort.\n", +save_config_text[] = "Enter a filename to which this configuration should be saved " - "as an alternate. Leave blank to abort."), -save_config_help[] = N_( + "as an alternate. Leave blank to abort.", +save_config_help[] = "\n" "For various reasons, one may wish to keep different configurations\n" "available on a single machine.\n" @@ -225,8 +224,8 @@ save_config_help[] = N_( "configuration options you have selected at that time.\n" "\n" "If you are uncertain what all this means then you should probably\n" - "leave this blank.\n"), -search_help[] = N_( + "leave this blank.\n", +search_help[] = "\n" "Search for symbols and display their relations.\n" "Regular expressions are allowed.\n" @@ -271,7 +270,7 @@ search_help[] = N_( "Examples: USB => find all symbols containing USB\n" " ^USB => find all symbols starting with USB\n" " USB$ => find all symbols ending with USB\n" - "\n"); + "\n"; static int indent; static struct menu *current_menu; @@ -400,19 +399,19 @@ static void search_conf(void) struct subtitle_part stpart; title = str_new(); - str_printf( &title, _("Enter (sub)string or regexp to search for " - "(with or without \"%s\")"), CONFIG_); + str_printf( &title, "Enter (sub)string or regexp to search for " + "(with or without \"%s\")", CONFIG_); again: dialog_clear(); - dres = dialog_inputbox(_("Search Configuration Parameter"), + dres = dialog_inputbox("Search Configuration Parameter", str_get(&title), 10, 75, ""); switch (dres) { case 0: break; case 1: - show_helptext(_("Search Configuration"), search_help); + show_helptext("Search Configuration", search_help); goto again; default: str_free(&title); @@ -443,7 +442,7 @@ again: res = get_relations_str(sym_arr, &head); set_subtitle(); - dres = show_textbox_ext(_("Search Results"), (char *) + dres = show_textbox_ext("Search Results", (char *) str_get(&res), 0, 0, keys, &vscroll, &hscroll, &update_text, (void *) &data); @@ -491,7 +490,6 @@ static void build_conf(struct menu *menu) switch (prop->type) { case P_MENU: child_count++; - prompt = _(prompt); if (single_menu_mode) { item_make("%s%*c%s", menu->data ? "-->" : "++>", @@ -508,7 +506,7 @@ static void build_conf(struct menu *menu) case P_COMMENT: if (prompt) { child_count++; - item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); + item_make(" %*c*** %s ***", indent + 1, ' ', prompt); item_set_tag(':'); item_set_data(menu); } @@ -516,7 +514,7 @@ static void build_conf(struct menu *menu) default: if (prompt) { child_count++; - item_make("---%*c%s", indent + 1, ' ', _(prompt)); + item_make("---%*c%s", indent + 1, ' ', prompt); item_set_tag(':'); item_set_data(menu); } @@ -560,10 +558,10 @@ static void build_conf(struct menu *menu) item_set_data(menu); } - item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(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(" (%s)", menu_get_prompt(def_menu)); item_add_str(" --->"); if (def_menu->list) { indent += 2; @@ -575,7 +573,7 @@ static void build_conf(struct menu *menu) } } else { if (menu == current_menu) { - item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); item_set_tag(':'); item_set_data(menu); goto conf_childs; @@ -618,17 +616,17 @@ static void build_conf(struct menu *menu) tmp = indent - tmp + 4; if (tmp < 0) tmp = 0; - item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), + item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), (sym_has_value(sym) || !sym_is_changable(sym)) ? - "" : _(" (NEW)")); + "" : " (NEW)"); item_set_tag('s'); item_set_data(menu); goto conf_childs; } } - item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), + item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), (sym_has_value(sym) || !sym_is_changable(sym)) ? - "" : _(" (NEW)")); + "" : " (NEW)"); if (menu->prompt->type == P_MENU) { item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); return; @@ -665,8 +663,8 @@ static void conf(struct menu *menu, struct menu *active_menu) break; set_subtitle(); dialog_clear(); - res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), - _(menu_instructions), + res = dialog_menu(prompt ? prompt : "Main Menu", + menu_instructions, active_menu, &s_scroll); if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) break; @@ -708,7 +706,7 @@ static void conf(struct menu *menu, struct menu *active_menu) show_help(submenu); else { reset_subtitle(); - show_helptext(_("README"), _(mconf_readme)); + show_helptext("README", mconf_readme); } break; case 3: @@ -773,16 +771,13 @@ static void show_helptext(const char *title, const char *text) show_textbox(title, text, 0, 0); } -static void conf_message_callback(const char *fmt, va_list ap) +static void conf_message_callback(const char *s) { - char buf[PATH_MAX+1]; - - vsnprintf(buf, sizeof(buf), fmt, ap); if (save_and_exit) { if (!silent) - printf("%s", buf); + printf("%s", s); } else { - show_textbox(NULL, buf, 6, 60); + show_textbox(NULL, s, 6, 60); } } @@ -793,13 +788,13 @@ static void show_help(struct menu *menu) help.max_width = getmaxx(stdscr) - 10; menu_get_ext_help(menu, &help); - show_helptext(_(menu_get_prompt(menu)), str_get(&help)); + show_helptext(menu_get_prompt(menu), str_get(&help)); str_free(&help); } static void conf_choice(struct menu *menu) { - const char *prompt = _(menu_get_prompt(menu)); + const char *prompt = menu_get_prompt(menu); struct menu *child; struct symbol *active; @@ -814,9 +809,9 @@ static void conf_choice(struct menu *menu) if (!menu_is_visible(child)) continue; if (child->sym) - item_make("%s", _(menu_get_prompt(child))); + item_make("%s", menu_get_prompt(child)); else { - item_make("*** %s ***", _(menu_get_prompt(child))); + item_make("*** %s ***", menu_get_prompt(child)); item_set_tag(':'); } item_set_data(child); @@ -826,8 +821,8 @@ static void conf_choice(struct menu *menu) item_set_tag('X'); } dialog_clear(); - res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), - _(radiolist_instructions), + res = dialog_checklist(prompt ? prompt : "Main Menu", + radiolist_instructions, MENUBOX_HEIGTH_MIN, MENUBOX_WIDTH_MIN, CHECKLIST_HEIGTH_MIN); @@ -868,26 +863,26 @@ static void conf_string(struct menu *menu) switch (sym_get_type(menu->sym)) { case S_INT: - heading = _(inputbox_instructions_int); + heading = inputbox_instructions_int; break; case S_HEX: - heading = _(inputbox_instructions_hex); + heading = inputbox_instructions_hex; break; case S_STRING: - heading = _(inputbox_instructions_string); + heading = inputbox_instructions_string; break; default: - heading = _("Internal mconf error!"); + heading = "Internal mconf error!"; } dialog_clear(); - res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), + res = dialog_inputbox(prompt ? prompt : "Main Menu", heading, 10, 75, sym_get_string_value(menu->sym)); switch (res) { case 0: if (sym_set_string_value(menu->sym, dialog_input_result)) return; - show_textbox(NULL, _("You have made an invalid entry."), 5, 43); + show_textbox(NULL, "You have made an invalid entry.", 5, 43); break; case 1: show_help(menu); @@ -915,10 +910,10 @@ static void conf_load(void) sym_set_change_count(1); return; } - show_textbox(NULL, _("File does not exist!"), 5, 38); + show_textbox(NULL, "File does not exist!", 5, 38); break; case 1: - show_helptext(_("Load Alternate Configuration"), load_config_help); + show_helptext("Load Alternate Configuration", load_config_help); break; case KEY_ESC: return; @@ -941,10 +936,10 @@ static void conf_save(void) set_config_filename(dialog_input_result); return; } - show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); + show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60); break; case 1: - show_helptext(_("Save Alternate Configuration"), save_config_help); + show_helptext("Save Alternate Configuration", save_config_help); break; case KEY_ESC: return; @@ -961,8 +956,8 @@ static int handle_exit(void) dialog_clear(); if (conf_get_changed()) res = dialog_yesno(NULL, - _("Do you wish to save your new configuration?\n" - "(Press <ESC><ESC> to continue kernel configuration.)"), + "Do you wish to save your new configuration?\n" + "(Press <ESC><ESC> to continue kernel configuration.)", 6, 60); else res = -1; @@ -972,26 +967,27 @@ static int handle_exit(void) switch (res) { case 0: if (conf_write(filename)) { - fprintf(stderr, _("\n\n" + fprintf(stderr, "\n\n" "Error while writing of the configuration.\n" "Your configuration changes were NOT saved." - "\n\n")); + "\n\n"); return 1; } + conf_write_autoconf(0); /* fall through */ case -1: if (!silent) - printf(_("\n\n" + printf("\n\n" "*** End of the configuration.\n" "*** Execute 'make' to start the build or try 'make help'." - "\n\n")); + "\n\n"); res = 0; break; default: if (!silent) - fprintf(stderr, _("\n\n" + fprintf(stderr, "\n\n" "Your configuration changes were NOT saved." - "\n\n")); + "\n\n"); if (res != KEY_ESC) res = 0; } @@ -1009,10 +1005,6 @@ int main(int ac, char **av) char *mode; int res; - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - signal(SIGINT, sig_handler); if (ac > 1 && strcmp(av[1], "-s") == 0) { @@ -1031,8 +1023,8 @@ int main(int ac, char **av) } if (init_dialog(NULL)) { - fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); - fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); + fprintf(stderr, "Your display is too small to run Menuconfig!\n"); + fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); return 1; } diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 5c5c1374b151..4cf15d449c05 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -212,10 +212,7 @@ void menu_add_option(int token, char *arg) sym_defconfig_list = current_entry->sym; else if (sym_defconfig_list != current_entry->sym) zconf_error("trying to redefine defconfig symbol"); - sym_defconfig_list->flags |= SYMBOL_AUTO; - break; - case T_OPT_ENV: - prop_add_env(arg); + sym_defconfig_list->flags |= SYMBOL_NO_WRITE; break; case T_OPT_ALLNOCONFIG_Y: current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; @@ -711,7 +708,7 @@ static void get_prompt_str(struct gstr *r, struct property *prop, struct menu *submenu[8], *menu, *location = NULL; struct jump_key *jump = NULL; - str_printf(r, _("Prompt: %s\n"), _(prop->text)); + str_printf(r, "Prompt: %s\n", prop->text); menu = prop->menu->parent; for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { bool accessible = menu_is_visible(menu); @@ -744,16 +741,16 @@ static void get_prompt_str(struct gstr *r, struct property *prop, } if (i > 0) { - str_printf(r, _(" Location:\n")); + str_printf(r, " Location:\n"); for (j = 4; --i >= 0; j += 2) { menu = submenu[i]; if (jump && menu == location) jump->offset = strlen(r->s); str_printf(r, "%*c-> %s", j, ' ', - _(menu_get_prompt(menu))); + menu_get_prompt(menu)); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? - menu->sym->name : _("<choice>"), + menu->sym->name : "<choice>", sym_get_string_value(menu->sym)); } str_append(r, "\n"); @@ -817,23 +814,23 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, prop = get_symbol_prop(sym); if (prop) { - str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, + str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, prop->menu->lineno); if (!expr_is_yes(prop->visible.expr)) { - str_append(r, _(" Depends on: ")); + str_append(r, " Depends on: "); expr_gstr_print(prop->visible.expr, r); str_append(r, "\n"); } } - get_symbol_props_str(r, sym, P_SELECT, _(" Selects: ")); + get_symbol_props_str(r, sym, P_SELECT, " Selects: "); if (sym->rev_dep.expr) { expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n"); expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n"); expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n"); } - get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: ")); + get_symbol_props_str(r, sym, P_IMPLY, " Implies: "); if (sym->implied.expr) { expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n"); expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n"); @@ -852,7 +849,7 @@ struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) for (i = 0; sym_arr && (sym = sym_arr[i]); i++) get_symbol_str(&res, sym, head); if (!i) - str_append(&res, _("No matches found.\n")); + str_append(&res, "No matches found.\n"); return res; } @@ -867,7 +864,7 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); help_text = menu_get_help(menu); } - str_printf(help, "%s\n", _(help_text)); + str_printf(help, "%s\n", help_text); if (sym) get_symbol_str(help, sym, NULL); } diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh index 67d131447631..0ef906499646 100755 --- a/scripts/kconfig/merge_config.sh +++ b/scripts/kconfig/merge_config.sh @@ -33,12 +33,15 @@ usage() { echo " -n use allnoconfig instead of alldefconfig" echo " -r list redundant entries when merging fragments" echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead." + echo + echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable." } RUNMAKE=true ALLTARGET=alldefconfig WARNREDUN=false OUTPUT=. +CONFIG_PREFIX=${CONFIG_-CONFIG_} while true; do case $1 in @@ -99,7 +102,9 @@ if [ ! -r "$INITFILE" ]; then fi MERGE_LIST=$* -SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" +SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p" +SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p" + TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) echo "Using $INITFILE as base" @@ -112,7 +117,7 @@ for MERGE_FILE in $MERGE_LIST ; do echo "The merge file '$MERGE_FILE' does not exist. Exit." >&2 exit 1 fi - CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE) + CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE) for CFG in $CFG_LIST ; do grep -q -w $CFG $TMP_FILE || continue @@ -155,7 +160,7 @@ make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET # Check all specified config values took (might have missed-dependency issues) -for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do +for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG") diff --git a/scripts/kconfig/nconf-cfg.sh b/scripts/kconfig/nconf-cfg.sh new file mode 100644 index 000000000000..001559ef0a60 --- /dev/null +++ b/scripts/kconfig/nconf-cfg.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +PKG="ncursesw menuw panelw" +PKG2="ncurses menu panel" + +if [ -n "$(command -v pkg-config)" ]; then + if pkg-config --exists $PKG; then + echo cflags=\"$(pkg-config --cflags $PKG)\" + echo libs=\"$(pkg-config --libs $PKG)\" + exit 0 + fi + + if pkg-config --exists $PKG2; then + echo cflags=\"$(pkg-config --cflags $PKG2)\" + echo libs=\"$(pkg-config --libs $PKG2)\" + exit 0 + fi +fi + +# Check the default paths in case pkg-config is not installed. +# (Even if it is installed, some distributions such as openSUSE cannot +# find ncurses by pkg-config.) +if [ -f /usr/include/ncursesw/ncurses.h ]; then + echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\" + echo libs=\"-lncursesw -lmenuw -lpanelw\" + exit 0 +fi + +if [ -f /usr/include/ncurses/ncurses.h ]; then + echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\" + echo libs=\"-lncurses -lmenu -lpanel\" + exit 0 +fi + +if [ -f /usr/include/ncurses.h ]; then + echo cflags=\"-D_GNU_SOURCE\" + echo libs=\"-lncurses -lmenu -lpanel\" + exit 0 +fi + +echo >&2 "*" +echo >&2 "* Unable to find the ncurses package." +echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" +echo >&2 "* depending on your distribution)." +echo >&2 "*" +exit 1 diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 003114779815..1ef232ae5ab9 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -15,7 +15,7 @@ #include "nconf.h" #include <ctype.h> -static const char nconf_global_help[] = N_( +static const char nconf_global_help[] = "Help windows\n" "------------\n" "o Global help: Unless in a data entry window, pressing <F1> will give \n" @@ -130,8 +130,8 @@ static const char nconf_global_help[] = N_( "\n" "Note that this mode can eventually be a little more CPU expensive than\n" "the default mode, especially with a larger number of unfolded submenus.\n" -"\n"), -menu_no_f_instructions[] = N_( +"\n", +menu_no_f_instructions[] = "Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" "\n" @@ -147,8 +147,8 @@ menu_no_f_instructions[] = N_( "You do not have function keys support.\n" "Press <1> instead of <F1>, <2> instead of <F2>, etc.\n" "For verbose global help use key <1>.\n" -"For help related to the current menu entry press <?> or <h>.\n"), -menu_instructions[] = N_( +"For help related to the current menu entry press <?> or <h>.\n", +menu_instructions[] = "Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" "\n" @@ -163,30 +163,30 @@ menu_instructions[] = N_( "\n" "Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n" "For verbose global help press <F1>.\n" -"For help related to the current menu entry press <?> or <h>.\n"), -radiolist_instructions[] = N_( +"For help related to the current menu entry press <?> or <h>.\n", +radiolist_instructions[] = "Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n" "with <Space>.\n" "For help related to the current entry press <?> or <h>.\n" -"For global help press <F1>.\n"), -inputbox_instructions_int[] = N_( +"For global help press <F1>.\n", +inputbox_instructions_int[] = "Please enter a decimal value.\n" "Fractions will not be accepted.\n" -"Press <Enter> to apply, <Esc> to cancel."), -inputbox_instructions_hex[] = N_( +"Press <Enter> to apply, <Esc> to cancel.", +inputbox_instructions_hex[] = "Please enter a hexadecimal value.\n" -"Press <Enter> to apply, <Esc> to cancel."), -inputbox_instructions_string[] = N_( +"Press <Enter> to apply, <Esc> to cancel.", +inputbox_instructions_string[] = "Please enter a string value.\n" -"Press <Enter> to apply, <Esc> to cancel."), -setmod_text[] = N_( +"Press <Enter> to apply, <Esc> to cancel.", +setmod_text[] = "This feature depends on another feature which has been configured as a\n" -"module. As a result, the current feature will be built as a module too."), -load_config_text[] = N_( +"module. As a result, the current feature will be built as a module too.", +load_config_text[] = "Enter the name of the configuration file you wish to load.\n" "Accept the name shown to restore the configuration you last\n" -"retrieved. Leave empty to abort."), -load_config_help[] = N_( +"retrieved. Leave empty to abort.", +load_config_help[] = "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" "\n" @@ -194,11 +194,11 @@ load_config_help[] = N_( "default one, entering its name here will allow you to load and modify\n" "that configuration.\n" "\n" -"Leave empty to abort.\n"), -save_config_text[] = N_( +"Leave empty to abort.\n", +save_config_text[] = "Enter a filename to which this configuration should be saved\n" -"as an alternate. Leave empty to abort."), -save_config_help[] = N_( +"as an alternate. Leave empty to abort.", +save_config_help[] = "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" "\n" @@ -206,8 +206,8 @@ save_config_help[] = N_( "and use the current configuration as an alternate to whatever\n" "configuration options you have selected at that time.\n" "\n" -"Leave empty to abort.\n"), -search_help[] = N_( +"Leave empty to abort.\n", +search_help[] = "Search for symbols (configuration variable names CONFIG_*) and display\n" "their relations. Regular expressions are supported.\n" "Example: Search for \"^FOO\".\n" @@ -244,7 +244,7 @@ search_help[] = N_( "USB => find all symbols containing USB\n" "^USB => find all symbols starting with USB\n" "USB$ => find all symbols ending with USB\n" -"\n"); +"\n"; struct mitem { char str[256]; @@ -388,7 +388,7 @@ static void print_function_line(void) static void handle_f1(int *key, struct menu *current_item) { show_scroll_win(main_window, - _("Global help"), _(nconf_global_help)); + "Global help", nconf_global_help); return; } @@ -403,8 +403,8 @@ static void handle_f2(int *key, struct menu *current_item) static void handle_f3(int *key, struct menu *current_item) { show_scroll_win(main_window, - _("Short help"), - _(current_instructions)); + "Short help", + current_instructions); return; } @@ -412,7 +412,7 @@ static void handle_f3(int *key, struct menu *current_item) static void handle_f4(int *key, struct menu *current_item) { int res = btn_dialog(main_window, - _("Show all symbols?"), + "Show all symbols?", 2, " <Show All> ", "<Don't show all>"); @@ -653,8 +653,8 @@ static int do_exit(void) return 0; } res = btn_dialog(main_window, - _("Do you wish to save your new configuration?\n" - "<ESC> to cancel and resume nconfig."), + "Do you wish to save your new configuration?\n" + "<ESC> to cancel and resume nconfig.", 2, " <save> ", "<don't save>"); @@ -670,15 +670,16 @@ static int do_exit(void) if (res) btn_dialog( main_window, - _("Error during writing of configuration.\n" - "Your configuration changes were NOT saved."), + "Error during writing of configuration.\n" + "Your configuration changes were NOT saved.", 1, "<OK>"); + conf_write_autoconf(0); break; default: btn_dialog( main_window, - _("Your configuration changes were NOT saved."), + "Your configuration changes were NOT saved.", 1, "<OK>"); break; @@ -697,12 +698,12 @@ static void search_conf(void) int dres; title = str_new(); - str_printf( &title, _("Enter (sub)string or regexp to search for " - "(with or without \"%s\")"), CONFIG_); + str_printf( &title, "Enter (sub)string or regexp to search for " + "(with or without \"%s\")", CONFIG_); again: dres = dialog_inputbox(main_window, - _("Search Configuration Parameter"), + "Search Configuration Parameter", str_get(&title), "", &dialog_input_result, &dialog_input_result_len); switch (dres) { @@ -710,7 +711,7 @@ again: break; case 1: show_scroll_win(main_window, - _("Search Configuration"), search_help); + "Search Configuration", search_help); goto again; default: str_free(&title); @@ -726,7 +727,7 @@ again: res = get_relations_str(sym_arr, NULL); free(sym_arr); show_scroll_win(main_window, - _("Search Results"), str_get(&res)); + "Search Results", str_get(&res)); str_free(&res); str_free(&title); } @@ -754,7 +755,7 @@ static void build_conf(struct menu *menu) switch (ptype) { case P_MENU: child_count++; - prompt = _(prompt); + prompt = prompt; if (single_menu_mode) { item_make(menu, 'm', "%s%*c%s", @@ -775,7 +776,7 @@ static void build_conf(struct menu *menu) item_make(menu, ':', " %*c*** %s ***", indent + 1, ' ', - _(prompt)); + prompt); } break; default: @@ -783,7 +784,7 @@ static void build_conf(struct menu *menu) child_count++; item_make(menu, ':', "---%*c%s", indent + 1, ' ', - _(prompt)); + prompt); } } } else @@ -829,11 +830,11 @@ static void build_conf(struct menu *menu) } item_add_str("%*c%s", indent + 1, - ' ', _(menu_get_prompt(menu))); + ' ', menu_get_prompt(menu)); if (val == yes) { if (def_menu) { item_add_str(" (%s)", - _(menu_get_prompt(def_menu))); + menu_get_prompt(def_menu)); item_add_str(" --->"); if (def_menu->list) { indent += 2; @@ -847,7 +848,7 @@ static void build_conf(struct menu *menu) if (menu == current_menu) { item_make(menu, ':', "---%*c%s", indent + 1, - ' ', _(menu_get_prompt(menu))); + ' ', menu_get_prompt(menu)); goto conf_childs; } child_count++; @@ -894,17 +895,17 @@ static void build_conf(struct menu *menu) if (tmp < 0) tmp = 0; item_add_str("%*c%s%s", tmp, ' ', - _(menu_get_prompt(menu)), + menu_get_prompt(menu), (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : - _(" (NEW)")); + " (NEW)"); goto conf_childs; } } item_add_str("%*c%s%s", indent + 1, ' ', - _(menu_get_prompt(menu)), + menu_get_prompt(menu), (sym_has_value(sym) || !sym_is_changable(sym)) ? - "" : _(" (NEW)")); + "" : " (NEW)"); if (menu->prompt && menu->prompt->type == P_MENU) { item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); return; @@ -1086,8 +1087,8 @@ static void conf(struct menu *menu) if (!child_count) break; - show_menu(prompt ? _(prompt) : _("Main Menu"), - _(menu_instructions), + show_menu(prompt ? prompt : "Main Menu", + menu_instructions, current_index, &last_top_row); keypad((menu_win(curses_menu)), TRUE); while (!global_exit) { @@ -1210,12 +1211,9 @@ static void conf(struct menu *menu) } } -static void conf_message_callback(const char *fmt, va_list ap) +static void conf_message_callback(const char *s) { - char buf[1024]; - - vsnprintf(buf, sizeof(buf), fmt, ap); - btn_dialog(main_window, buf, 1, "<OK>"); + btn_dialog(main_window, s, 1, "<OK>"); } static void show_help(struct menu *menu) @@ -1227,13 +1225,13 @@ static void show_help(struct menu *menu) help = str_new(); menu_get_ext_help(menu, &help); - show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); + show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help)); str_free(&help); } static void conf_choice(struct menu *menu) { - const char *prompt = _(menu_get_prompt(menu)); + const char *prompt = menu_get_prompt(menu); struct menu *child = NULL; struct symbol *active; int selected_index = 0; @@ -1256,13 +1254,13 @@ static void conf_choice(struct menu *menu) if (child->sym == sym_get_choice_value(menu->sym)) item_make(child, ':', "<X> %s", - _(menu_get_prompt(child))); + menu_get_prompt(child)); else if (child->sym) item_make(child, ':', " %s", - _(menu_get_prompt(child))); + menu_get_prompt(child)); else item_make(child, ':', "*** %s ***", - _(menu_get_prompt(child))); + menu_get_prompt(child)); if (child->sym == active){ last_top_row = top_row(curses_menu); @@ -1270,8 +1268,8 @@ static void conf_choice(struct menu *menu) } i++; } - show_menu(prompt ? _(prompt) : _("Choice Menu"), - _(radiolist_instructions), + show_menu(prompt ? prompt : "Choice Menu", + radiolist_instructions, selected_index, &last_top_row); while (!global_exit) { @@ -1358,19 +1356,19 @@ static void conf_string(struct menu *menu) switch (sym_get_type(menu->sym)) { case S_INT: - heading = _(inputbox_instructions_int); + heading = inputbox_instructions_int; break; case S_HEX: - heading = _(inputbox_instructions_hex); + heading = inputbox_instructions_hex; break; case S_STRING: - heading = _(inputbox_instructions_string); + heading = inputbox_instructions_string; break; default: - heading = _("Internal nconf error!"); + heading = "Internal nconf error!"; } res = dialog_inputbox(main_window, - prompt ? _(prompt) : _("Main Menu"), + prompt ? prompt : "Main Menu", heading, sym_get_string_value(menu->sym), &dialog_input_result, @@ -1381,7 +1379,7 @@ static void conf_string(struct menu *menu) dialog_input_result)) return; btn_dialog(main_window, - _("You have made an invalid entry."), 0); + "You have made an invalid entry.", 0); break; case 1: show_help(menu); @@ -1410,11 +1408,11 @@ static void conf_load(void) sym_set_change_count(1); return; } - btn_dialog(main_window, _("File does not exist!"), 0); + btn_dialog(main_window, "File does not exist!", 0); break; case 1: show_scroll_win(main_window, - _("Load Alternate Configuration"), + "Load Alternate Configuration", load_config_help); break; case KEY_EXIT: @@ -1441,13 +1439,13 @@ static void conf_save(void) set_config_filename(dialog_input_result); return; } - btn_dialog(main_window, _("Can't create file! " - "Probably a nonexistent directory."), + btn_dialog(main_window, "Can't create file! " + "Probably a nonexistent directory.", 1, "<OK>"); break; case 1: show_scroll_win(main_window, - _("Save Alternate Configuration"), + "Save Alternate Configuration", save_config_help); break; case KEY_EXIT: @@ -1480,10 +1478,6 @@ int main(int ac, char **av) int lines, columns; char *mode; - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - if (ac > 1 && strcmp(av[1], "-s") == 0) { /* Silence conf_read() until the real callback is set up */ conf_set_message_callback(NULL); @@ -1541,8 +1535,8 @@ int main(int ac, char **av) /* check for KEY_FUNC(1) */ if (has_key(KEY_F(1)) == FALSE) { show_scroll_win(main_window, - _("Instructions"), - _(menu_no_f_instructions)); + "Instructions", + menu_no_f_instructions); } conf_set_message_callback(conf_message_callback); diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h index 9f6f21d3b0d4..2b9e19f603c4 100644 --- a/scripts/kconfig/nconf.h +++ b/scripts/kconfig/nconf.h @@ -14,7 +14,6 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <locale.h> #include <ncurses.h> #include <menu.h> #include <panel.h> diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c new file mode 100644 index 000000000000..5ca2df790d3c --- /dev/null +++ b/scripts/kconfig/preprocess.c @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com> + +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "list.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +static char *expand_string_with_args(const char *in, int argc, char *argv[]); + +static void __attribute__((noreturn)) pperror(const char *format, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", current_file->name, yylineno); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} + +/* + * Environment variables + */ +static LIST_HEAD(env_list); + +struct env { + char *name; + char *value; + struct list_head node; +}; + +static void env_add(const char *name, const char *value) +{ + struct env *e; + + e = xmalloc(sizeof(*e)); + e->name = xstrdup(name); + e->value = xstrdup(value); + + list_add_tail(&e->node, &env_list); +} + +static void env_del(struct env *e) +{ + list_del(&e->node); + free(e->name); + free(e->value); + free(e); +} + +/* The returned pointer must be freed when done */ +static char *env_expand(const char *name) +{ + struct env *e; + const char *value; + + if (!*name) + return NULL; + + list_for_each_entry(e, &env_list, node) { + if (!strcmp(name, e->name)) + return xstrdup(e->value); + } + + value = getenv(name); + if (!value) + return NULL; + + /* + * We need to remember all referenced environment variables. + * They will be written out to include/config/auto.conf.cmd + */ + env_add(name, value); + + return xstrdup(value); +} + +void env_write_dep(FILE *f, const char *autoconfig_name) +{ + 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"); + env_del(e); + } +} + +/* + * Built-in functions + */ +struct function { + const char *name; + unsigned int min_args; + unsigned int max_args; + char *(*func)(int argc, char *argv[]); +}; + +static char *do_error_if(int argc, char *argv[]) +{ + if (!strcmp(argv[0], "y")) + pperror("%s", argv[1]); + + return NULL; +} + +static char *do_filename(int argc, char *argv[]) +{ + return xstrdup(current_file->name); +} + +static char *do_info(int argc, char *argv[]) +{ + printf("%s\n", argv[0]); + + return xstrdup(""); +} + +static char *do_lineno(int argc, char *argv[]) +{ + char buf[16]; + + sprintf(buf, "%d", yylineno); + + return xstrdup(buf); +} + +static char *do_shell(int argc, char *argv[]) +{ + FILE *p; + char buf[256]; + char *cmd; + size_t nread; + int i; + + cmd = argv[0]; + + p = popen(cmd, "r"); + if (!p) { + perror(cmd); + exit(1); + } + + nread = fread(buf, 1, sizeof(buf), p); + if (nread == sizeof(buf)) + nread--; + + /* remove trailing new lines */ + while (nread > 0 && buf[nread - 1] == '\n') + nread--; + + buf[nread] = 0; + + /* replace a new line with a space */ + for (i = 0; i < nread; i++) { + if (buf[i] == '\n') + buf[i] = ' '; + } + + if (pclose(p) == -1) { + perror(cmd); + exit(1); + } + + return xstrdup(buf); +} + +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]); + + return xstrdup(""); +} + +static const struct function function_table[] = { + /* Name MIN MAX Function */ + { "error-if", 2, 2, do_error_if }, + { "filename", 0, 0, do_filename }, + { "info", 1, 1, do_info }, + { "lineno", 0, 0, do_lineno }, + { "shell", 1, 1, do_shell }, + { "warning-if", 2, 2, do_warning_if }, +}; + +#define FUNCTION_MAX_ARGS 16 + +static char *function_expand(const char *name, int argc, char *argv[]) +{ + const struct function *f; + int i; + + for (i = 0; i < ARRAY_SIZE(function_table); i++) { + f = &function_table[i]; + if (strcmp(f->name, name)) + continue; + + if (argc < f->min_args) + pperror("too few function arguments passed to '%s'", + name); + + if (argc > f->max_args) + pperror("too many function arguments passed to '%s'", + name); + + return f->func(argc, argv); + } + + return NULL; +} + +/* + * Variables (and user-defined functions) + */ +static LIST_HEAD(variable_list); + +struct variable { + char *name; + char *value; + enum variable_flavor flavor; + int exp_count; + struct list_head node; +}; + +static struct variable *variable_lookup(const char *name) +{ + struct variable *v; + + list_for_each_entry(v, &variable_list, node) { + if (!strcmp(name, v->name)) + return v; + } + + return NULL; +} + +static char *variable_expand(const char *name, int argc, char *argv[]) +{ + struct variable *v; + char *res; + + v = variable_lookup(name); + if (!v) + return NULL; + + if (argc == 0 && v->exp_count) + pperror("Recursive variable '%s' references itself (eventually)", + name); + + if (v->exp_count > 1000) + pperror("Too deep recursive expansion"); + + v->exp_count++; + + if (v->flavor == VAR_RECURSIVE) + res = expand_string_with_args(v->value, argc, argv); + else + res = xstrdup(v->value); + + v->exp_count--; + + return res; +} + +void variable_add(const char *name, const char *value, + enum variable_flavor flavor) +{ + struct variable *v; + char *new_value; + bool append = false; + + v = variable_lookup(name); + if (v) { + /* For defined variables, += inherits the existing flavor */ + if (flavor == VAR_APPEND) { + flavor = v->flavor; + append = true; + } else { + free(v->value); + } + } else { + /* For undefined variables, += assumes the recursive flavor */ + if (flavor == VAR_APPEND) + flavor = VAR_RECURSIVE; + + v = xmalloc(sizeof(*v)); + v->name = xstrdup(name); + v->exp_count = 0; + list_add_tail(&v->node, &variable_list); + } + + v->flavor = flavor; + + if (flavor == VAR_SIMPLE) + new_value = expand_string(value); + else + new_value = xstrdup(value); + + if (append) { + v->value = xrealloc(v->value, + strlen(v->value) + strlen(new_value) + 2); + strcat(v->value, " "); + strcat(v->value, new_value); + free(new_value); + } else { + v->value = new_value; + } +} + +static void variable_del(struct variable *v) +{ + list_del(&v->node); + free(v->name); + free(v->value); + free(v); +} + +void variable_all_del(void) +{ + struct variable *v, *tmp; + + list_for_each_entry_safe(v, tmp, &variable_list, node) + variable_del(v); +} + +/* + * Evaluate a clause with arguments. argc/argv are arguments from the upper + * function call. + * + * Returned string must be freed when done + */ +static char *eval_clause(const char *str, size_t len, int argc, char *argv[]) +{ + char *tmp, *name, *res, *endptr, *prev, *p; + int new_argc = 0; + char *new_argv[FUNCTION_MAX_ARGS]; + int nest = 0; + int i; + unsigned long n; + + tmp = xstrndup(str, len); + + /* + * If variable name is '1', '2', etc. It is generally an argument + * from a user-function call (i.e. local-scope variable). If not + * available, then look-up global-scope variables. + */ + n = strtoul(tmp, &endptr, 10); + if (!*endptr && n > 0 && n <= argc) { + res = xstrdup(argv[n - 1]); + goto free_tmp; + } + + prev = p = tmp; + + /* + * Split into tokens + * The function name and arguments are separated by a comma. + * For example, if the function call is like this: + * $(foo,$(x),$(y)) + * + * The input string for this helper should be: + * foo,$(x),$(y) + * + * and split into: + * new_argv[0] = 'foo' + * new_argv[1] = '$(x)' + * new_argv[2] = '$(y)' + */ + while (*p) { + if (nest == 0 && *p == ',') { + *p = 0; + if (new_argc >= FUNCTION_MAX_ARGS) + pperror("too many function arguments"); + new_argv[new_argc++] = prev; + prev = p + 1; + } else if (*p == '(') { + nest++; + } else if (*p == ')') { + nest--; + } + + p++; + } + new_argv[new_argc++] = prev; + + /* + * Shift arguments + * new_argv[0] represents a function name or a variable name. Put it + * into 'name', then shift the rest of the arguments. This simplifies + * 'const' handling. + */ + name = expand_string_with_args(new_argv[0], argc, argv); + new_argc--; + for (i = 0; i < new_argc; i++) + new_argv[i] = expand_string_with_args(new_argv[i + 1], + argc, argv); + + /* Search for variables */ + res = variable_expand(name, new_argc, new_argv); + if (res) + goto free; + + /* Look for built-in functions */ + res = function_expand(name, new_argc, new_argv); + if (res) + goto free; + + /* Last, try environment variable */ + if (new_argc == 0) { + res = env_expand(name); + if (res) + goto free; + } + + res = xstrdup(""); +free: + for (i = 0; i < new_argc; i++) + free(new_argv[i]); + free(name); +free_tmp: + free(tmp); + + return res; +} + +/* + * Expand a string that follows '$' + * + * For example, if the input string is + * ($(FOO)$($(BAR)))$(BAZ) + * this helper evaluates + * $($(FOO)$($(BAR))) + * and returns a new string containing the expansion (note that the string is + * recursively expanded), also advancing 'str' to point to the next character + * after the corresponding closing parenthesis, in this case, *str will be + * $(BAR) + */ +static char *expand_dollar_with_args(const char **str, int argc, char *argv[]) +{ + const char *p = *str; + const char *q; + int nest = 0; + + /* + * In Kconfig, variable/function references always start with "$(". + * Neither single-letter variables as in $A nor curly braces as in ${CC} + * are supported. '$' not followed by '(' loses its special meaning. + */ + if (*p != '(') { + *str = p; + return xstrdup("$"); + } + + p++; + q = p; + while (*q) { + if (*q == '(') { + nest++; + } else if (*q == ')') { + if (nest-- == 0) + break; + } + q++; + } + + if (!*q) + pperror("unterminated reference to '%s': missing ')'", p); + + /* Advance 'str' to after the expanded initial portion of the string */ + *str = q + 1; + + return eval_clause(p, q - p, argc, argv); +} + +char *expand_dollar(const char **str) +{ + return expand_dollar_with_args(str, 0, NULL); +} + +static char *__expand_string(const char **str, bool (*is_end)(char c), + int argc, char *argv[]) +{ + const char *in, *p; + char *expansion, *out; + size_t in_len, out_len; + + out = xmalloc(1); + *out = 0; + out_len = 1; + + p = in = *str; + + while (1) { + if (*p == '$') { + in_len = p - in; + p++; + expansion = expand_dollar_with_args(&p, argc, argv); + out_len += in_len + strlen(expansion); + out = xrealloc(out, out_len); + strncat(out, in, in_len); + strcat(out, expansion); + free(expansion); + in = p; + continue; + } + + if (is_end(*p)) + break; + + p++; + } + + in_len = p - in; + out_len += in_len; + out = xrealloc(out, out_len); + strncat(out, in, in_len); + + /* Advance 'str' to the end character */ + *str = p; + + return out; +} + +static bool is_end_of_str(char c) +{ + return !c; +} + +/* + * Expand variables and functions in the given string. Undefined variables + * expand to an empty string. + * The returned string must be freed when done. + */ +static char *expand_string_with_args(const char *in, int argc, char *argv[]) +{ + return __expand_string(&in, is_end_of_str, argc, argv); +} + +char *expand_string(const char *in) +{ + return expand_string_with_args(in, 0, NULL); +} + +static bool is_end_of_token(char c) +{ + /* Why are '.' and '/' valid characters for symbols? */ + return !(isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/'); +} + +/* + * Expand variables in a token. The parsing stops when a token separater + * (in most cases, it is a whitespace) is encountered. 'str' is updated to + * point to the next character. + * + * The returned string must be freed when done. + */ +char *expand_one_token(const char **str) +{ + return __expand_string(str, is_end_of_token, 0, NULL); +} diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh new file mode 100755 index 000000000000..02ccc0ae1031 --- /dev/null +++ b/scripts/kconfig/qconf-cfg.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +PKG="Qt5Core Qt5Gui Qt5Widgets" +PKG2="QtCore QtGui" + +if [ -z "$(command -v pkg-config)" ]; then + echo >&2 "*" + echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it." + echo >&2 "*" + exit 1 +fi + +if pkg-config --exists $PKG; then + echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets)\" + echo libs=\"$(pkg-config --libs $PKG)\" + echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\" + exit 0 +fi + +if pkg-config --exists $PKG2; then + echo cflags=\"$(pkg-config --cflags $PKG2)\" + echo libs=\"$(pkg-config --libs $PKG2)\" + echo moc=\"$(pkg-config --variable=moc_location QtCore)\" + exit 0 +fi + +echo >&2 "*" +echo >&2 "* Could not find Qt via pkg-config." +echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH" +echo >&2 "*" +exit 1 diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index ae6c72546411..ef4310f2558b 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -34,10 +34,6 @@ #include "qconf.moc" #include "images.c" -#ifdef _ -# undef _ -# define _ qgettext -#endif static QApplication *configApp; static ConfigSettings *configSettings; @@ -46,12 +42,7 @@ QAction *ConfigMainWindow::saveAction; static inline QString qgettext(const char* str) { - return QString::fromLocal8Bit(gettext(str)); -} - -static inline QString qgettext(const QString& str) -{ - return QString::fromLocal8Bit(gettext(str.toLatin1())); + return QString::fromLocal8Bit(str); } ConfigSettings::ConfigSettings() @@ -127,7 +118,7 @@ void ConfigItem::updateMenu(void) sym = menu->sym; prop = menu->prompt; - prompt = _(menu_get_prompt(menu)); + prompt = qgettext(menu_get_prompt(menu)); if (prop) switch (prop->type) { case P_MENU: @@ -216,7 +207,7 @@ void ConfigItem::updateMenu(void) break; } if (!sym_has_value(sym) && visible) - prompt += _(" (NEW)"); + prompt += " (NEW)"; set_prompt: setText(promptColIdx, prompt); } @@ -327,7 +318,7 @@ ConfigList::ConfigList(ConfigView* p, const char *name) setVerticalScrollMode(ScrollPerPixel); setHorizontalScrollMode(ScrollPerPixel); - setHeaderLabels(QStringList() << _("Option") << _("Name") << "N" << "M" << "Y" << _("Value")); + setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value"); connect(this, SIGNAL(itemSelectionChanged(void)), SLOT(updateSelection(void))); @@ -883,7 +874,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e) QAction *action; headerPopup = new QMenu(this); - action = new QAction(_("Show Name"), this); + action = new QAction("Show Name", this); action->setCheckable(true); connect(action, SIGNAL(toggled(bool)), parent(), SLOT(setShowName(bool))); @@ -891,7 +882,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e) action, SLOT(setOn(bool))); action->setChecked(showName); headerPopup->addAction(action); - action = new QAction(_("Show Range"), this); + action = new QAction("Show Range", this); action->setCheckable(true); connect(action, SIGNAL(toggled(bool)), parent(), SLOT(setShowRange(bool))); @@ -899,7 +890,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e) action, SLOT(setOn(bool))); action->setChecked(showRange); headerPopup->addAction(action); - action = new QAction(_("Show Data"), this); + action = new QAction("Show Data", this); action->setCheckable(true); connect(action, SIGNAL(toggled(bool)), parent(), SLOT(setShowData(bool))); @@ -1086,7 +1077,7 @@ void ConfigInfoView::menuInfo(void) if (sym) { if (_menu->prompt) { head += "<big><b>"; - head += print_filter(_(_menu->prompt->text)); + head += print_filter(_menu->prompt->text); head += "</b></big>"; if (sym->name) { head += " ("; @@ -1117,7 +1108,7 @@ void ConfigInfoView::menuInfo(void) str_free(&help_gstr); } else if (_menu->prompt) { head += "<big><b>"; - head += print_filter(_(_menu->prompt->text)); + head += print_filter(_menu->prompt->text); head += "</b></big><br><br>"; if (showDebug()) { if (_menu->prompt->visible.expr) { @@ -1152,13 +1143,12 @@ QString ConfigInfoView::debug_info(struct symbol *sym) case P_PROMPT: case P_MENU: debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu); - debug += print_filter(_(prop->text)); + debug += print_filter(prop->text); debug += "</a><br>"; break; case P_DEFAULT: case P_SELECT: case P_RANGE: - case P_ENV: debug += prop_get_type_name(prop->type); debug += ": "; expr_print(prop->expr, expr_print_help, &debug, E_NONE); @@ -1234,7 +1224,7 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos) { QMenu* popup = Parent::createStandardContextMenu(pos); - QAction* action = new QAction(_("Show Debug Info"), popup); + QAction* action = new QAction("Show Debug Info", popup); action->setCheckable(true); connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); @@ -1261,11 +1251,11 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam QHBoxLayout* layout2 = new QHBoxLayout(0); layout2->setContentsMargins(0, 0, 0, 0); layout2->setSpacing(6); - layout2->addWidget(new QLabel(_("Find:"), this)); + layout2->addWidget(new QLabel("Find:", this)); editField = new QLineEdit(this); connect(editField, SIGNAL(returnPressed()), SLOT(search())); layout2->addWidget(editField); - searchButton = new QPushButton(_("Search"), this); + searchButton = new QPushButton("Search", this); searchButton->setAutoDefault(false); connect(searchButton, SIGNAL(clicked()), SLOT(search())); layout2->addWidget(searchButton); @@ -1387,44 +1377,44 @@ ConfigMainWindow::ConfigMainWindow(void) toolBar = new QToolBar("Tools", this); addToolBar(toolBar); - backAction = new QAction(QPixmap(xpm_back), _("Back"), this); + backAction = new QAction(QPixmap(xpm_back), "Back", this); connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack())); backAction->setEnabled(false); - QAction *quitAction = new QAction(_("&Quit"), this); + QAction *quitAction = new QAction("&Quit", this); quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); connect(quitAction, SIGNAL(triggered(bool)), SLOT(close())); - QAction *loadAction = new QAction(QPixmap(xpm_load), _("&Load"), this); + QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); loadAction->setShortcut(Qt::CTRL + Qt::Key_L); connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig())); - saveAction = new QAction(QPixmap(xpm_save), _("&Save"), this); + saveAction = new QAction(QPixmap(xpm_save), "&Save", this); saveAction->setShortcut(Qt::CTRL + Qt::Key_S); connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig())); conf_set_changed_callback(conf_changed); // Set saveAction's initial state conf_changed(); - QAction *saveAsAction = new QAction(_("Save &As..."), this); + QAction *saveAsAction = new QAction("Save &As...", this); connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs())); - QAction *searchAction = new QAction(_("&Find"), this); + QAction *searchAction = new QAction("&Find", this); searchAction->setShortcut(Qt::CTRL + Qt::Key_F); connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig())); - singleViewAction = new QAction(QPixmap(xpm_single_view), _("Single View"), this); + singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); singleViewAction->setCheckable(true); connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView())); - splitViewAction = new QAction(QPixmap(xpm_split_view), _("Split View"), this); + splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this); splitViewAction->setCheckable(true); connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView())); - fullViewAction = new QAction(QPixmap(xpm_tree_view), _("Full View"), this); + fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this); fullViewAction->setCheckable(true); connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView())); - QAction *showNameAction = new QAction(_("Show Name"), this); + QAction *showNameAction = new QAction("Show Name", this); showNameAction->setCheckable(true); connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); showNameAction->setChecked(configView->showName()); - QAction *showRangeAction = new QAction(_("Show Range"), this); + QAction *showRangeAction = new QAction("Show Range", this); showRangeAction->setCheckable(true); connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); - QAction *showDataAction = new QAction(_("Show Data"), this); + QAction *showDataAction = new QAction("Show Data", this); showDataAction->setCheckable(true); connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); @@ -1435,21 +1425,21 @@ ConfigMainWindow::ConfigMainWindow(void) connect(optGroup, SIGNAL(triggered(QAction *)), menuView, SLOT(setOptionMode(QAction *))); - configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup); - configView->showAllAction = new QAction(_("Show All Options"), optGroup); - configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup); + configView->showNormalAction = new QAction("Show Normal Options", optGroup); + configView->showAllAction = new QAction("Show All Options", optGroup); + configView->showPromptAction = new QAction("Show Prompt Options", optGroup); configView->showNormalAction->setCheckable(true); configView->showAllAction->setCheckable(true); configView->showPromptAction->setCheckable(true); - QAction *showDebugAction = new QAction( _("Show Debug Info"), this); + QAction *showDebugAction = new QAction("Show Debug Info", this); showDebugAction->setCheckable(true); connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); showDebugAction->setChecked(helpText->showDebug()); - QAction *showIntroAction = new QAction( _("Introduction"), this); + QAction *showIntroAction = new QAction("Introduction", this); connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro())); - QAction *showAboutAction = new QAction( _("About"), this); + QAction *showAboutAction = new QAction("About", this); connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout())); // init tool bar @@ -1463,7 +1453,7 @@ ConfigMainWindow::ConfigMainWindow(void) toolBar->addAction(fullViewAction); // create config menu - QMenu* config = menu->addMenu(_("&File")); + QMenu* config = menu->addMenu("&File"); config->addAction(loadAction); config->addAction(saveAction); config->addAction(saveAsAction); @@ -1471,11 +1461,11 @@ ConfigMainWindow::ConfigMainWindow(void) config->addAction(quitAction); // create edit menu - QMenu* editMenu = menu->addMenu(_("&Edit")); + QMenu* editMenu = menu->addMenu("&Edit"); editMenu->addAction(searchAction); // create options menu - QMenu* optionMenu = menu->addMenu(_("&Option")); + QMenu* optionMenu = menu->addMenu("&Option"); optionMenu->addAction(showNameAction); optionMenu->addAction(showRangeAction); optionMenu->addAction(showDataAction); @@ -1486,7 +1476,7 @@ ConfigMainWindow::ConfigMainWindow(void) // create help menu menu->addSeparator(); - QMenu* helpMenu = menu->addMenu(_("&Help")); + QMenu* helpMenu = menu->addMenu("&Help"); helpMenu->addAction(showIntroAction); helpMenu->addAction(showAboutAction); @@ -1534,16 +1524,18 @@ void ConfigMainWindow::loadConfig(void) if (s.isNull()) return; if (conf_read(QFile::encodeName(s))) - QMessageBox::information(this, "qconf", _("Unable to load configuration!")); + QMessageBox::information(this, "qconf", "Unable to load configuration!"); ConfigView::updateListAll(); } bool ConfigMainWindow::saveConfig(void) { if (conf_write(NULL)) { - QMessageBox::information(this, "qconf", _("Unable to save configuration!")); + QMessageBox::information(this, "qconf", "Unable to save configuration!"); return false; } + conf_write_autoconf(0); + return true; } @@ -1723,11 +1715,11 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e) e->accept(); return; } - QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, + QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); - mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); - mb.setButtonText(QMessageBox::No, _("&Discard Changes")); - mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); + mb.setButtonText(QMessageBox::Yes, "&Save Changes"); + mb.setButtonText(QMessageBox::No, "&Discard Changes"); + mb.setButtonText(QMessageBox::Cancel, "Cancel Exit"); switch (mb.exec()) { case QMessageBox::Yes: if (saveConfig()) @@ -1746,7 +1738,7 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e) void ConfigMainWindow::showIntro(void) { - static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n" + static const QString str = "Welcome to the qconf graphical configuration tool.\n\n" "For each option, a blank box indicates the feature is disabled, a check\n" "indicates it is enabled, and a dot indicates that it is to be compiled\n" "as a module. Clicking on the box will cycle through the three states.\n\n" @@ -1756,16 +1748,16 @@ void ConfigMainWindow::showIntro(void) "options must be enabled to support the option you are interested in, you can\n" "still view the help of a grayed-out option.\n\n" "Toggling Show Debug Info under the Options menu will show the dependencies,\n" - "which you can then match by examining other options.\n\n"); + "which you can then match by examining other options.\n\n"; QMessageBox::information(this, "qconf", str); } void ConfigMainWindow::showAbout(void) { - static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n" + static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n" "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n" - "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"; QMessageBox::information(this, "qconf", str); } @@ -1826,7 +1818,7 @@ static const char *progname; static void usage(void) { - printf(_("%s [-s] <config>\n").toLatin1().constData(), progname); + printf("%s [-s] <config>\n", progname); exit(0); } @@ -1835,9 +1827,6 @@ int main(int ac, char** av) ConfigMainWindow* v; const char *name; - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - progname = av[0]; configApp = new QApplication(ac, av); if (ac > 1 && av[1][0] == '-') { diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index a2e83ab17de3..4686531e2f8c 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -165,10 +165,10 @@ sub read_kconfig { my $last_source = ""; # Check for any environment variables used - while ($source =~ /\$(\w+)/ && $last_source ne $source) { + while ($source =~ /\$\((\w+)\)/ && $last_source ne $source) { my $env = $1; $last_source = $source; - $source =~ s/\$$env/$ENV{$env}/; + $source =~ s/\$\($env\)/$ENV{$env}/; } open(my $kinfile, '<', $source) || die "Can't open $kconfig"; diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index f0b2e3b3102d..703b9b899ee9 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -33,33 +33,6 @@ struct symbol *sym_defconfig_list; struct symbol *modules_sym; tristate modules_val; -struct expr *sym_env_list; - -static void sym_add_default(struct symbol *sym, const char *def) -{ - struct property *prop = prop_alloc(P_DEFAULT, sym); - - prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); -} - -void sym_init(void) -{ - struct symbol *sym; - struct utsname uts; - static bool inited = false; - - if (inited) - return; - inited = true; - - uname(&uts); - - sym = sym_lookup("UNAME_RELEASE", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - sym_add_default(sym, uts.release); -} - enum symbol_type sym_get_type(struct symbol *sym) { enum symbol_type type = sym->type; @@ -103,15 +76,6 @@ struct property *sym_get_choice_prop(struct symbol *sym) return NULL; } -struct property *sym_get_env_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_properties(sym, prop, P_ENV) - return prop; - return NULL; -} - static struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; @@ -490,7 +454,7 @@ void sym_calc_value(struct symbol *sym) } } - if (sym->flags & SYMBOL_AUTO) + if (sym->flags & SYMBOL_NO_WRITE) sym->flags &= ~SYMBOL_WRITE; if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) @@ -906,59 +870,6 @@ struct symbol *sym_find(const char *name) return symbol; } -/* - * Expand symbol's names embedded in the string given in argument. Symbols' - * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to - * the empty string. - */ -char *sym_expand_string_value(const char *in) -{ - const char *src; - char *res; - size_t reslen; - - /* - * Note: 'in' might come from a token that's about to be - * freed, so make sure to always allocate a new string - */ - reslen = strlen(in) + 1; - res = xmalloc(reslen); - res[0] = '\0'; - - while ((src = strchr(in, '$'))) { - char *p, name[SYMBOL_MAXLENGTH]; - const char *symval = ""; - struct symbol *sym; - size_t newlen; - - strncat(res, in, src - in); - src++; - - p = name; - while (isalnum(*src) || *src == '_') - *p++ = *src++; - *p = '\0'; - - sym = sym_find(name); - if (sym != NULL) { - sym_calc_value(sym); - symval = sym_get_string_value(sym); - } - - newlen = strlen(res) + strlen(symval) + strlen(src) + 1; - if (newlen > reslen) { - reslen = newlen; - res = xrealloc(res, reslen); - } - - strcat(res, symval); - in = src; - } - strcat(res, in); - - return res; -} - const char *sym_escape_string_value(const char *in) { const char *p; @@ -1100,7 +1011,7 @@ static struct dep_stack { struct dep_stack *prev, *next; struct symbol *sym; struct property *prop; - struct expr *expr; + struct expr **expr; } *check_top; static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) @@ -1165,31 +1076,42 @@ static void sym_check_print_recursive(struct symbol *last_sym) fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", prop->file->name, prop->lineno); - if (stack->expr) { - fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", - prop->file->name, prop->lineno, + if (sym_is_choice(sym)) { + fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", + menu->file->name, menu->lineno, sym->name ? sym->name : "<choice>", - prop_get_type_name(prop->type), next_sym->name ? next_sym->name : "<choice>"); - } else if (stack->prop) { + } else if (sym_is_choice_value(sym)) { + fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", + menu->file->name, 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, sym->name ? sym->name : "<choice>", next_sym->name ? next_sym->name : "<choice>"); - } else if (sym_is_choice(sym)) { - fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, + } else if (stack->expr == &sym->rev_dep.expr) { + fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", + prop->file->name, prop->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, + } else if (stack->expr == &sym->implied.expr) { + fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", + prop->file->name, 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, + 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 is selected by %s\n", + fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", prop->file->name, prop->lineno, sym->name ? sym->name : "<choice>", + prop_get_type_name(prop->type), next_sym->name ? next_sym->name : "<choice>"); } } @@ -1246,12 +1168,26 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) dep_stack_insert(&stack, sym); + stack.expr = &sym->dir_dep.expr; + sym2 = sym_check_expr_deps(sym->dir_dep.expr); + if (sym2) + goto out; + + stack.expr = &sym->rev_dep.expr; sym2 = sym_check_expr_deps(sym->rev_dep.expr); if (sym2) goto out; + stack.expr = &sym->implied.expr; + sym2 = sym_check_expr_deps(sym->implied.expr); + if (sym2) + goto out; + + stack.expr = NULL; + for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT) + if (prop->type == P_CHOICE || prop->type == P_SELECT || + prop->type == P_IMPLY) continue; stack.prop = prop; sym2 = sym_check_expr_deps(prop->visible.expr); @@ -1259,7 +1195,7 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) break; if (prop->type != P_DEFAULT || sym_is_choice(sym)) continue; - stack.expr = prop->expr; + stack.expr = &prop->expr; sym2 = sym_check_expr_deps(prop->expr); if (sym2) break; @@ -1337,9 +1273,6 @@ struct symbol *sym_check_deps(struct symbol *sym) sym->flags &= ~SYMBOL_CHECK; } - if (sym2 && sym2 == sym) - sym2 = NULL; - return sym2; } @@ -1378,8 +1311,6 @@ const char *prop_get_type_name(enum prop_type type) switch (type) { case P_PROMPT: return "prompt"; - case P_ENV: - return "env"; case P_COMMENT: return "comment"; case P_MENU: @@ -1401,32 +1332,3 @@ const char *prop_get_type_name(enum prop_type type) } return "unknown"; } - -static void prop_add_env(const char *env) -{ - struct symbol *sym, *sym2; - struct property *prop; - char *p; - - sym = current_entry->sym; - sym->flags |= SYMBOL_AUTO; - for_all_properties(sym, prop, P_ENV) { - sym2 = prop_get_symbol(prop); - if (strcmp(sym2->name, env)) - menu_warn(current_entry, "redefining environment symbol from %s", - sym2->name); - return; - } - - prop = prop_alloc(P_ENV, sym); - prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); - - sym_env_list = expr_alloc_one(E_LIST, sym_env_list); - sym_env_list->right.sym = sym; - - p = getenv(env); - if (p) - sym_add_default(sym, p); - else - menu_warn(current_entry, "environment variable %s undefined", env); -} diff --git a/scripts/kconfig/tests/warn_recursive_dep/Kconfig b/scripts/kconfig/tests/err_recursive_dep/Kconfig index a65bfcb7137e..ebdb3ffd8717 100644 --- a/scripts/kconfig/tests/warn_recursive_dep/Kconfig +++ b/scripts/kconfig/tests/err_recursive_dep/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + # depends on itself config A @@ -31,7 +33,6 @@ config D2 bool # depends on and imply -# This is not recursive dependency config E1 bool "E1" diff --git a/scripts/kconfig/tests/err_recursive_dep/__init__.py b/scripts/kconfig/tests/err_recursive_dep/__init__.py new file mode 100644 index 000000000000..5f3821b43ce6 --- /dev/null +++ b/scripts/kconfig/tests/err_recursive_dep/__init__.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Detect recursive dependency error. + +Recursive dependency should be treated as an error. +""" + +def test(conf): + assert conf.oldaskconfig() == 1 + assert conf.stderr_contains('expected_stderr') diff --git a/scripts/kconfig/tests/err_recursive_dep/expected_stderr b/scripts/kconfig/tests/err_recursive_dep/expected_stderr new file mode 100644 index 000000000000..84679b104655 --- /dev/null +++ b/scripts/kconfig/tests/err_recursive_dep/expected_stderr @@ -0,0 +1,38 @@ +Kconfig:11:error: recursive dependency detected! +Kconfig:11: symbol B is selected by B +For a resolution refer to Documentation/kbuild/kconfig-language.txt +subsection "Kconfig recursive dependency limitations" + +Kconfig:5:error: recursive dependency detected! +Kconfig:5: symbol A depends on A +For a resolution refer to Documentation/kbuild/kconfig-language.txt +subsection "Kconfig recursive dependency limitations" + +Kconfig:17:error: recursive dependency detected! +Kconfig:17: symbol C1 depends on C2 +Kconfig:21: symbol C2 depends on C1 +For a resolution refer to Documentation/kbuild/kconfig-language.txt +subsection "Kconfig recursive dependency limitations" + +Kconfig:32:error: recursive dependency detected! +Kconfig:32: symbol D2 is selected by D1 +Kconfig:27: symbol D1 depends on D2 +For a resolution refer to Documentation/kbuild/kconfig-language.txt +subsection "Kconfig recursive dependency limitations" + +Kconfig:37:error: recursive dependency detected! +Kconfig:37: symbol E1 depends on E2 +Kconfig:42: symbol E2 is implied by E1 +For a resolution refer to Documentation/kbuild/kconfig-language.txt +subsection "Kconfig recursive dependency limitations" + +Kconfig:60:error: recursive dependency detected! +Kconfig:60: symbol G depends on G +For a resolution refer to Documentation/kbuild/kconfig-language.txt +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 +For a resolution refer to Documentation/kbuild/kconfig-language.txt +subsection "Kconfig recursive dependency limitations" diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config b/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config index 0d15e41da475..473228810c35 100644 --- a/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config +++ b/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config @@ -1,5 +1,5 @@ # # Automatically generated file; DO NOT EDIT. -# Linux Kernel Configuration +# Main menu # # CONFIG_A is not set diff --git a/scripts/kconfig/tests/preprocess/builtin_func/Kconfig b/scripts/kconfig/tests/preprocess/builtin_func/Kconfig new file mode 100644 index 000000000000..baa328827911 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/builtin_func/Kconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0 + +# 'info' prints the argument to stdout. +$(info,hello world 0) + +# 'warning-if', if the first argument is y, sends the second argument to stderr, +# and the message is prefixed with the current file name and line number. +$(warning-if,y,hello world 1) + +# 'error-if' is similar, but it terminates the parsing immediately. +# The following is just no-op since the first argument is not y. +$(error-if,n,this should not be printed) + +# Shorthand +warning = $(warning-if,y,$(1)) + +# 'shell' executes a command, and returns its stdout. +$(warning,$(shell,echo hello world 3)) + +# Every newline in the output is replaced with a space, +# but any trailing newlines are deleted. +$(warning,$(shell,printf 'hello\nworld\n\n4\n\n\n')) + +# 'filename' is expanded to the currently parsed file name, +# 'lineno' to the line number. +$(warning,filename=$(filename)) +$(warning,lineno=$(lineno)) diff --git a/scripts/kconfig/tests/preprocess/builtin_func/__init__.py b/scripts/kconfig/tests/preprocess/builtin_func/__init__.py new file mode 100644 index 000000000000..2e53ba08fca1 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/builtin_func/__init__.py @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Built-in function tests. +""" + +def test(conf): + assert conf.oldaskconfig() == 0 + assert conf.stdout_contains('expected_stdout') + assert conf.stderr_matches('expected_stderr') diff --git a/scripts/kconfig/tests/preprocess/builtin_func/expected_stderr b/scripts/kconfig/tests/preprocess/builtin_func/expected_stderr new file mode 100644 index 000000000000..33ea9ca38400 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/builtin_func/expected_stderr @@ -0,0 +1,5 @@ +Kconfig:8: hello world 1 +Kconfig:18: hello world 3 +Kconfig:22: hello world 4 +Kconfig:26: filename=Kconfig +Kconfig:27: lineno=27 diff --git a/scripts/kconfig/tests/preprocess/builtin_func/expected_stdout b/scripts/kconfig/tests/preprocess/builtin_func/expected_stdout new file mode 100644 index 000000000000..82de3a7e97de --- /dev/null +++ b/scripts/kconfig/tests/preprocess/builtin_func/expected_stdout @@ -0,0 +1 @@ +hello world 0 diff --git a/scripts/kconfig/tests/preprocess/circular_expansion/Kconfig b/scripts/kconfig/tests/preprocess/circular_expansion/Kconfig new file mode 100644 index 000000000000..6838997c23ba --- /dev/null +++ b/scripts/kconfig/tests/preprocess/circular_expansion/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +X = $(Y) +Y = $(X) +$(info $(X)) diff --git a/scripts/kconfig/tests/preprocess/circular_expansion/__init__.py b/scripts/kconfig/tests/preprocess/circular_expansion/__init__.py new file mode 100644 index 000000000000..419bda3e075c --- /dev/null +++ b/scripts/kconfig/tests/preprocess/circular_expansion/__init__.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Detect circular variable expansion. + +If a recursively expanded variable references itself (eventually), +it should fail with an error message. +""" + +def test(conf): + assert conf.oldaskconfig() != 0 + assert conf.stderr_matches('expected_stderr') diff --git a/scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr b/scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr new file mode 100644 index 000000000000..cde68fa989d0 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/circular_expansion/expected_stderr @@ -0,0 +1 @@ +Kconfig:5: Recursive variable 'X' references itself (eventually) diff --git a/scripts/kconfig/tests/preprocess/escape/Kconfig b/scripts/kconfig/tests/preprocess/escape/Kconfig new file mode 100644 index 000000000000..4e3f44445544 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/escape/Kconfig @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Shorthand +warning = $(warning-if,y,$(1)) + +# You can not pass commas directly to a function since they are treated as +# delimiters. You can use the following trick to do so. +comma := , +$(warning,hello$(comma) world) + +# Like Make, single quotes, double quotes, spaces are treated verbatim. +# The following prints the text as-is. +$(warning, ' " '" ' ''' "'") + +# Unlike Make, '$' has special meaning only when it is followed by '('. +# No need to escape '$' itself. +$(warning,$) +$(warning,$$) +$ := 1 +$(warning,$($)) + +# You need a trick to escape '$' followed by '(' +# The following should print "$(X)". It should not be expanded further. +dollar := $ +$(warning,$(dollar)(X)) + +# You need a trick to treat unbalanced parentheses. +# The following should print "(". +left_paren := ( +$(warning,$(left_paren)) + +# A simple expanded should not be expanded multiple times. +# The following should print "$(X)". It should not be expanded further. +Y := $(dollar)(X) +$(warning,$(Y)) + +# The following should print "$(X)" as well. +Y = $(dollar)(X) +$(warning,$(Y)) + +# The following should print "$(". +# It should not be emit "unterminated reference" error. +unterminated := $(dollar)( +$(warning,$(unterminated)) diff --git a/scripts/kconfig/tests/preprocess/escape/__init__.py b/scripts/kconfig/tests/preprocess/escape/__init__.py new file mode 100644 index 000000000000..7ee8e747f546 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/escape/__init__.py @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Escape sequence tests. +""" + +def test(conf): + assert conf.oldaskconfig() == 0 + assert conf.stderr_matches('expected_stderr') diff --git a/scripts/kconfig/tests/preprocess/escape/expected_stderr b/scripts/kconfig/tests/preprocess/escape/expected_stderr new file mode 100644 index 000000000000..1c00957ddaa9 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/escape/expected_stderr @@ -0,0 +1,10 @@ +Kconfig:9: hello, world +Kconfig:13: ' " '" ' ''' "'" +Kconfig:17: $ +Kconfig:18: $$ +Kconfig:20: 1 +Kconfig:25: $(X) +Kconfig:30: ( +Kconfig:35: $(X) +Kconfig:39: $(X) +Kconfig:44: $( diff --git a/scripts/kconfig/tests/preprocess/variable/Kconfig b/scripts/kconfig/tests/preprocess/variable/Kconfig new file mode 100644 index 000000000000..9ce2f95cbd24 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/variable/Kconfig @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Shorthand +warning = $(warning-if,y,$(1)) + +# Simply expanded variable. +X := 1 +SIMPLE := $(X) +X := 2 +$(warning,SIMPLE = $(SIMPLE)) + +# Recursively expanded variable. +X := 1 +RECURSIVE = $(X) +X := 2 +$(warning,RECURSIVE = $(RECURSIVE)) + +# Append something to a simply expanded variable. +Y := 3 +SIMPLE += $(Y) +Y := 4 +$(warning,SIMPLE = $(SIMPLE)) + +# Append something to a recursively expanded variable. +Y := 3 +RECURSIVE += $(Y) +Y := 4 +$(warning,RECURSIVE = $(RECURSIVE)) + +# Use += operator to an undefined variable. +# This works as a recursively expanded variable. +Y := 3 +UNDEFINED_VARIABLE += $(Y) +Y := 4 +$(warning,UNDEFINED_VARIABLE = $(UNDEFINED_VARIABLE)) + +# You can use variable references for the lefthand side of assignment statement. +X := A +Y := B +$(X)$(Y) := 5 +$(warning,AB = $(AB)) + +# User-defined function. +greeting = $(1), my name is $(2). +$(warning,$(greeting,Hello,John)) + +# The number of arguments is not checked for user-defined functions. +# If some arguments are optional, it is useful to pass fewer parameters. +# $(2) will be blank in this case. +$(warning,$(greeting,Hello)) + +# Unreferenced parameters are just ignored. +$(warning,$(greeting,Hello,John,ignored,ignored)) diff --git a/scripts/kconfig/tests/preprocess/variable/__init__.py b/scripts/kconfig/tests/preprocess/variable/__init__.py new file mode 100644 index 000000000000..e88b1708d6d4 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/variable/__init__.py @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Variable and user-defined function tests. +""" + +def test(conf): + assert conf.oldaskconfig() == 0 + assert conf.stderr_matches('expected_stderr') diff --git a/scripts/kconfig/tests/preprocess/variable/expected_stderr b/scripts/kconfig/tests/preprocess/variable/expected_stderr new file mode 100644 index 000000000000..a4841c3fdff5 --- /dev/null +++ b/scripts/kconfig/tests/preprocess/variable/expected_stderr @@ -0,0 +1,9 @@ +Kconfig:10: SIMPLE = 1 +Kconfig:16: RECURSIVE = 2 +Kconfig:22: SIMPLE = 1 3 +Kconfig:28: RECURSIVE = 2 4 +Kconfig:35: UNDEFINED_VARIABLE = 4 +Kconfig:41: AB = 5 +Kconfig:45: Hello, my name is John. +Kconfig:50: Hello, my name is . +Kconfig:53: Hello, my name is John. diff --git a/scripts/kconfig/tests/warn_recursive_dep/__init__.py b/scripts/kconfig/tests/warn_recursive_dep/__init__.py deleted file mode 100644 index adb21951ba41..000000000000 --- a/scripts/kconfig/tests/warn_recursive_dep/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Warn recursive inclusion. - -Recursive dependency should be warned. -""" - -def test(conf): - assert conf.oldaskconfig() == 0 - assert conf.stderr_contains('expected_stderr') diff --git a/scripts/kconfig/tests/warn_recursive_dep/expected_stderr b/scripts/kconfig/tests/warn_recursive_dep/expected_stderr deleted file mode 100644 index 3de807dd9cb2..000000000000 --- a/scripts/kconfig/tests/warn_recursive_dep/expected_stderr +++ /dev/null @@ -1,30 +0,0 @@ -Kconfig:9:error: recursive dependency detected! -Kconfig:9: symbol B is selected by B -For a resolution refer to Documentation/kbuild/kconfig-language.txt -subsection "Kconfig recursive dependency limitations" - -Kconfig:3:error: recursive dependency detected! -Kconfig:3: symbol A depends on A -For a resolution refer to Documentation/kbuild/kconfig-language.txt -subsection "Kconfig recursive dependency limitations" - -Kconfig:15:error: recursive dependency detected! -Kconfig:15: symbol C1 depends on C2 -Kconfig:19: symbol C2 depends on C1 -For a resolution refer to Documentation/kbuild/kconfig-language.txt -subsection "Kconfig recursive dependency limitations" - -Kconfig:30:error: recursive dependency detected! -Kconfig:30: symbol D2 is selected by D1 -Kconfig:25: symbol D1 depends on D2 -For a resolution refer to Documentation/kbuild/kconfig-language.txt -subsection "Kconfig recursive dependency limitations" - -Kconfig:59:error: recursive dependency detected! -Kconfig:59: symbol G depends on G -For a resolution refer to Documentation/kbuild/kconfig-language.txt -subsection "Kconfig recursive dependency limitations" - -Kconfig:50:error: recursive dependency detected! -Kconfig:50: symbol F2 depends on F1 -Kconfig:48: symbol F1 default value contains F2 diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index c6f6e21b809f..d999683bb2a7 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -14,69 +14,21 @@ struct file *file_lookup(const char *name) { struct file *file; - char *file_name = sym_expand_string_value(name); for (file = file_list; file; file = file->next) { if (!strcmp(name, file->name)) { - free(file_name); return file; } } file = xmalloc(sizeof(*file)); memset(file, 0, sizeof(*file)); - file->name = file_name; + file->name = xstrdup(name); file->next = file_list; file_list = file; return file; } -/* write a dependency file as used by kbuild to track dependencies */ -int file_write_dep(const char *name) -{ - struct symbol *sym, *env_sym; - struct expr *e; - struct file *file; - FILE *out; - - if (!name) - name = ".kconfig.d"; - out = fopen("..config.tmp", "w"); - if (!out) - return 1; - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) { - if (file->next) - fprintf(out, "\t%s \\\n", file->name); - else - fprintf(out, "\t%s\n", file->name); - } - fprintf(out, "\n%s: \\\n" - "\t$(deps_config)\n\n", conf_get_autoconfig_name()); - - expr_list_for_each_sym(sym_env_list, e, sym) { - struct property *prop; - const char *value; - - prop = sym_get_env_prop(sym); - env_sym = prop_get_symbol(prop); - if (!env_sym) - continue; - value = getenv(env_sym->name); - if (!value) - value = ""; - fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); - fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); - fprintf(out, "endif\n"); - } - - fprintf(out, "\n$(deps_config): ;\n"); - fclose(out); - rename("..config.tmp", name); - return 0; -} - - /* Allocate initial growable string */ struct gstr str_new(void) { @@ -165,3 +117,14 @@ char *xstrdup(const char *s) fprintf(stderr, "Out of memory.\n"); exit(1); } + +char *xstrndup(const char *s, size_t n) +{ + char *p; + + p = strndup(s, n); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l index 045093d827e1..25bd2b89fe3f 100644 --- a/scripts/kconfig/zconf.l +++ b/scripts/kconfig/zconf.l @@ -1,13 +1,13 @@ %option nostdinit noyywrap never-interactive full ecs %option 8bit nodefault yylineno -%option noinput -%x COMMAND HELP STRING PARAM +%x COMMAND HELP STRING PARAM ASSIGN_VAL %{ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ +#include <assert.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> @@ -35,6 +35,8 @@ struct buffer *current_buf; static int last_ts, first_ts; +static char *expand_token(const char *in, size_t n); +static void append_expanded_string(const char *in); static void zconf_endhelp(void); static void zconf_endfile(void); @@ -101,17 +103,28 @@ n [A-Za-z0-9_-] <COMMAND>{ {n}+ { const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); - BEGIN(PARAM); current_pos.file = current_file; current_pos.lineno = yylineno; if (id && id->flags & TF_COMMAND) { + BEGIN(PARAM); yylval.id = id; return id->token; } alloc_string(yytext, yyleng); yylval.string = text; - return T_WORD; + return T_VARIABLE; } + ({n}|$)+ { + /* this token includes at least one '$' */ + yylval.string = expand_token(yytext, yyleng); + if (strlen(yylval.string)) + return T_VARIABLE; + free(yylval.string); + } + "=" { BEGIN(ASSIGN_VAL); yylval.flavor = VAR_RECURSIVE; return T_ASSIGN; } + ":=" { BEGIN(ASSIGN_VAL); yylval.flavor = VAR_SIMPLE; return T_ASSIGN; } + "+=" { BEGIN(ASSIGN_VAL); yylval.flavor = VAR_APPEND; return T_ASSIGN; } + [[:blank:]]+ . warn_ignored_character(*yytext); \n { BEGIN(INITIAL); @@ -119,6 +132,16 @@ n [A-Za-z0-9_-] } } +<ASSIGN_VAL>{ + [^[:blank:]\n]+.* { + alloc_string(yytext, yyleng); + yylval.string = text; + return T_ASSIGN_VAL; + } + \n { BEGIN(INITIAL); return T_EOL; } + . +} + <PARAM>{ "&&" return T_AND; "||" return T_OR; @@ -147,6 +170,13 @@ n [A-Za-z0-9_-] yylval.string = text; return T_WORD; } + ({n}|[/.$])+ { + /* this token includes at least one '$' */ + yylval.string = expand_token(yytext, yyleng); + if (strlen(yylval.string)) + return T_WORD; + free(yylval.string); + } #.* /* comment */ \\\n ; [[:blank:]]+ @@ -157,12 +187,13 @@ n [A-Za-z0-9_-] } <STRING>{ - [^'"\\\n]+/\n { + "$".* append_expanded_string(yytext); + [^$'"\\\n]+/\n { append_string(yytext, yyleng); yylval.string = text; return T_WORD_QUOTE; } - [^'"\\\n]+ { + [^$'"\\\n]+ { append_string(yytext, yyleng); } \\.?/\n { @@ -249,6 +280,58 @@ n [A-Za-z0-9_-] } %% +static char *expand_token(const char *in, size_t n) +{ + char *out; + int c; + char c2; + const char *rest, *end; + + new_string(); + append_string(in, n); + + /* get the whole line because we do not know the end of token. */ + while ((c = input()) != EOF) { + if (c == '\n') { + unput(c); + break; + } + c2 = c; + append_string(&c2, 1); + } + + rest = text; + out = expand_one_token(&rest); + + /* push back unused characters to the input stream */ + end = rest + strlen(rest); + while (end > rest) + unput(*--end); + + free(text); + + return out; +} + +static void append_expanded_string(const char *str) +{ + const char *end; + char *res; + + str++; + + res = expand_dollar(&str); + + /* push back unused characters to the input stream */ + end = str + strlen(str); + while (end > str) + unput(*--end); + + append_string(res, strlen(res)); + + free(res); +} + void zconf_starthelp(void) { new_string(); diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index ad6305b0f40c..22fceb264cf5 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; %} -%expect 32 +%expect 30 %union { @@ -41,6 +41,7 @@ static struct menu *current_menu, *current_entry; struct expr *expr; struct menu *menu; const struct kconf_id *id; + enum variable_flavor flavor; } %token <id>T_MAINMENU @@ -77,6 +78,9 @@ static struct menu *current_menu, *current_entry; %token T_CLOSE_PAREN %token T_OPEN_PAREN %token T_EOL +%token <string> T_VARIABLE +%token <flavor> T_ASSIGN +%token <string> T_ASSIGN_VAL %left T_OR %left T_AND @@ -92,7 +96,7 @@ static struct menu *current_menu, *current_entry; %type <id> end %type <id> option_name %type <menu> if_entry menu_entry choice_entry -%type <string> symbol_option_arg word_opt +%type <string> symbol_option_arg word_opt assign_val %destructor { fprintf(stderr, "%s:%d: missing end statement for this entry\n", @@ -109,28 +113,15 @@ static struct menu *current_menu, *current_entry; %% input: nl start | start; -start: mainmenu_stmt stmt_list | no_mainmenu_stmt stmt_list; +start: mainmenu_stmt stmt_list | stmt_list; /* mainmenu entry */ -mainmenu_stmt: T_MAINMENU prompt nl +mainmenu_stmt: T_MAINMENU prompt T_EOL { menu_add_prompt(P_MENU, $2, NULL); }; -/* Default main menu, if there's no mainmenu entry */ - -no_mainmenu_stmt: /* empty */ -{ - /* - * Hack: Keep the main menu title on the heap so we can safely free it - * later regardless of whether it comes from the 'prompt' in - * mainmenu_stmt or here - */ - menu_add_prompt(P_MENU, xstrdup("Linux Kernel Configuration"), NULL); -}; - - stmt_list: /* empty */ | stmt_list common_stmt @@ -156,6 +147,7 @@ common_stmt: | config_stmt | menuconfig_stmt | source_stmt + | assignment_stmt ; option_error: @@ -273,7 +265,7 @@ symbol_option_arg: choice: T_CHOICE word_opt T_EOL { struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); - sym->flags |= SYMBOL_AUTO; + sym->flags |= SYMBOL_NO_WRITE; menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); free($2); @@ -345,7 +337,7 @@ choice_block: /* if entry */ -if_entry: T_IF expr nl +if_entry: T_IF expr T_EOL { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); @@ -524,31 +516,42 @@ symbol: nonconst_symbol word_opt: /* empty */ { $$ = NULL; } | T_WORD +/* assignment statement */ + +assignment_stmt: T_VARIABLE T_ASSIGN assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); } + +assign_val: + /* empty */ { $$ = xstrdup(""); }; + | T_ASSIGN_VAL +; + %% void conf_parse(const char *name) { - const char *tmp; struct symbol *sym; int i; zconf_initscan(name); - sym_init(); _menu_init(); if (getenv("ZCONF_DEBUG")) yydebug = 1; yyparse(); + + /* 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" ); - tmp = rootmenu.prompt->text; - rootmenu.prompt->text = _(rootmenu.prompt->text); - rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); - free((char*)tmp); + if (!menu_has_prompt(&rootmenu)) { + current_entry = &rootmenu; + menu_add_prompt(P_MENU, "Main menu", NULL); + } menu_finalize(&rootmenu); for_all_symbols(i, sym) { @@ -714,6 +717,10 @@ static void print_symbol(FILE *out, struct menu *menu) print_quoted_string(out, prop->text); fputc('\n', out); break; + case P_SYMBOL: + fputs( " symbol ", out); + fprintf(out, "%s\n", prop->sym->name); + break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; @@ -780,3 +787,4 @@ void zconfdump(FILE *out) #include "expr.c" #include "symbol.c" #include "menu.c" +#include "preprocess.c" diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 0057d8eafcc1..ffbe901a37b5 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1062,7 +1062,7 @@ sub dump_struct($$) { my $x = shift; my $file = shift; - if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { + if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}/) { my $decl_type = $1; $declaration_name = $2; my $members = $3; @@ -1148,20 +1148,20 @@ sub dump_struct($$) { } } } - $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/; + $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/; } # Ignore other nested elements, like enums - $members =~ s/({[^\{\}]*})//g; + $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; + $declaration =~ s/([\{;])/$1\n/g; + $declaration =~ s/\}\s+;/};/g; # Better handle inlined enums - do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/); + do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); my @def_args = split /\n/, $declaration; my $level = 1; @@ -1171,12 +1171,12 @@ sub dump_struct($$) { $clause =~ s/\s+$//; $clause =~ s/\s+/ /; next if (!$clause); - $level-- if ($clause =~ m/(})/ && $level > 1); + $level-- if ($clause =~ m/(\})/ && $level > 1); if (!($clause =~ m/^\s*#/)) { $declaration .= "\t" x $level; } $declaration .= "\t" . $clause . "\n"; - $level++ if ($clause =~ m/({)/ && !($clause =~m/}/)); + $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); } output_declaration($declaration_name, 'struct', @@ -1244,7 +1244,7 @@ sub dump_enum($$) { # strip #define macros inside enums $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; - if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { + if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) { $declaration_name = $1; my $members = $2; my %_members; @@ -1785,7 +1785,7 @@ sub process_proto_type($$) { } while (1) { - if ( $x =~ /([^{};]*)([{};])(.*)/ ) { + if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { if( length $prototype ) { $prototype .= " " } @@ -1904,13 +1904,13 @@ sub process_name($$) { ++$warnings; } - if ($identifier =~ m/^struct/) { + if ($identifier =~ m/^struct\b/) { $decl_type = 'struct'; - } elsif ($identifier =~ m/^union/) { + } elsif ($identifier =~ m/^union\b/) { $decl_type = 'union'; - } elsif ($identifier =~ m/^enum/) { + } elsif ($identifier =~ m/^enum\b/) { $decl_type = 'enum'; - } elsif ($identifier =~ m/^typedef/) { + } elsif ($identifier =~ m/^typedef\b/) { $decl_type = 'typedef'; } else { $decl_type = 'function'; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 9045823c7be7..c8cf45362bd6 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -75,7 +75,7 @@ modpost_link() ${KBUILD_VMLINUX_LIBS} \ --end-group" - ${LD} ${LDFLAGS} -r -o ${1} ${objects} + ${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${objects} } # Link of vmlinux @@ -95,7 +95,7 @@ vmlinux_link() --end-group \ ${1}" - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ -T ${lds} ${objects} else objects="-Wl,--whole-archive \ @@ -121,10 +121,6 @@ kallsyms() info KSYM ${2} local kallsymopt; - if [ -n "${CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX}" ]; then - kallsymopt="${kallsymopt} --symbol-prefix=_" - fi - if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then kallsymopt="${kallsymopt} --all-symbols" fi diff --git a/scripts/mkmakefile b/scripts/mkmakefile index e19d6565f245..412f13fdff52 100755 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -6,31 +6,20 @@ # Usage # $1 - Kernel src directory -# $2 - Output directory -# $3 - version -# $4 - patchlevel - -test ! -r $2/Makefile -o -O $2/Makefile || exit 0 # Only overwrite automatically generated Makefiles # (so we do not overwrite kernel Makefile) -if test -e $2/Makefile && ! grep -q Automatically $2/Makefile +if test -e Makefile && ! grep -q Automatically Makefile then exit 0 fi if [ "${quiet}" != "silent_" ]; then - echo " GEN $2/Makefile" + echo " GEN Makefile" fi -cat << EOF > $2/Makefile +cat << EOF > Makefile # Automatically generated by $0: don't edit -VERSION = $3 -PATCHLEVEL = $4 - -lastword = \$(word \$(words \$(1)),\$(1)) -makedir := \$(dir \$(call lastword,\$(MAKEFILE_LIST))) - ifeq ("\$(origin V)", "command line") VERBOSE := \$(V) endif @@ -38,15 +27,12 @@ ifneq (\$(VERBOSE),1) Q := @ endif -MAKEARGS := -C $1 -MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$(makedir)) - MAKEFLAGS += --no-print-directory .PHONY: __sub-make \$(MAKECMDGOALS) __sub-make: - \$(Q)\$(MAKE) \$(MAKEARGS) \$(MAKECMDGOALS) + \$(Q)\$(MAKE) -C $1 O=\$(CURDIR) \$(MAKECMDGOALS) \$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make @: diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index 42c5d50f2bcc..a5b4af47987a 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -4,6 +4,8 @@ OBJECT_FILES_NON_STANDARD := y hostprogs-y := modpost mk_elfconfig always := $(hostprogs-y) empty.o +CFLAGS_REMOVE_empty.o := $(ASM_MACRO_FLAGS) + modpost-objs := modpost.o file2alias.o sumversion.o devicetable-offsets-file := devicetable-offsets.h diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 9fad6afe4c41..293004499b4d 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -139,6 +139,9 @@ int main(void) DEVID(hv_vmbus_device_id); DEVID_FIELD(hv_vmbus_device_id, guid); + DEVID(rpmsg_device_id); + DEVID_FIELD(rpmsg_device_id, name); + DEVID(i2c_device_id); DEVID_FIELD(i2c_device_id, name); @@ -218,5 +221,9 @@ int main(void) DEVID_FIELD(tb_service_id, protocol_version); DEVID_FIELD(tb_service_id, protocol_revision); + DEVID(typec_device_id); + DEVID_FIELD(typec_device_id, svid); + DEVID_FIELD(typec_device_id, mode); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index b9beeaa4695b..28a61665bb9c 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -95,12 +95,20 @@ extern struct devtable *__start___devtable[], *__stop___devtable[]; */ #define DEF_FIELD(m, devid, f) \ typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) + +/* Define a variable v that holds the address of field f of struct devid + * based at address m. Due to the way typeof works, for a field of type + * T[N] the variable has type T(*)[N], _not_ T*. + */ +#define DEF_FIELD_ADDR_VAR(m, devid, f, v) \ + typeof(((struct devid *)0)->f) *v = ((m) + OFF_##devid##_##f) + /* Define a variable f that holds the address of field f of struct devid * based at address m. Due to the way typeof works, for a field of type * T[N] the variable has type T(*)[N], _not_ T*. */ #define DEF_FIELD_ADDR(m, devid, f) \ - typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) + DEF_FIELD_ADDR_VAR(m, devid, f, f) /* Add a table entry. We test function type matches while we're here. */ #define ADD_TO_DEVTABLE(device_id, type, function) \ @@ -644,7 +652,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, for (i = 0; i < count; i++) { unsigned int j; - DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs); + DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs); for (j = 0; j < PNP_MAX_DEVICES; j++) { const char *id = (char *)(*devs)[j].id; @@ -656,10 +664,13 @@ static void do_pnp_card_entries(void *symval, unsigned long size, /* find duplicate, already added value */ for (i2 = 0; i2 < i && !dup; i2++) { - DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs); + DEF_FIELD_ADDR_VAR(symval + i2 * id_size, + pnp_card_device_id, + devs, devs_dup); for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { - const char *id2 = (char *)(*devs)[j2].id; + const char *id2 = + (char *)(*devs_dup)[j2].id; if (!id2[0]) break; @@ -944,6 +955,17 @@ static int do_vmbus_entry(const char *filename, void *symval, } ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); +/* Looks like: rpmsg:S */ +static int do_rpmsg_entry(const char *filename, void *symval, + char *alias) +{ + DEF_FIELD_ADDR(symval, rpmsg_device_id, name); + sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name); + + return 1; +} +ADD_TO_DEVTABLE("rpmsg", rpmsg_device_id, do_rpmsg_entry); + /* Looks like: i2c:S */ static int do_i2c_entry(const char *filename, void *symval, char *alias) @@ -1341,6 +1363,19 @@ static int do_tbsvc_entry(const char *filename, void *symval, char *alias) } ADD_TO_DEVTABLE("tbsvc", tb_service_id, do_tbsvc_entry); +/* Looks like: typec:idNmN */ +static int do_typec_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, typec_device_id, svid); + DEF_FIELD(symval, typec_device_id, mode); + + sprintf(alias, "typec:id%04X", svid); + ADD(alias, "m", mode != TYPEC_ANY_MODE, mode); + + return 1; +} +ADD_TO_DEVTABLE("typec", typec_device_id, do_typec_entry); + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1391,11 +1426,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) return; - /* All our symbols are of form <prefix>__mod_<name>__<identifier>_device_table. */ - name = strstr(symname, "__mod_"); - if (!name) + /* All our symbols are of form __mod_<name>__<identifier>_device_table. */ + if (strncmp(symname, "__mod_", strlen("__mod_"))) return; - name += strlen("__mod_"); + name = symname + strlen("__mod_"); namelen = strlen(name); if (namelen < strlen("_device_table")) return; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 4ff08a0ef5d3..0d998c54564d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -19,9 +19,7 @@ #include <stdbool.h> #include <errno.h> #include "modpost.h" -#include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" -#include "../../include/linux/export.h" /* Are we using CONFIG_MODVERSIONS? */ static int modversions = 0; @@ -123,7 +121,7 @@ void *do_nofail(void *ptr, const char *expr) /* A list of all modules we processed */ static struct module *modules; -static struct module *find_module(char *modname) +static struct module *find_module(const char *modname) { struct module *mod; @@ -591,35 +589,32 @@ static void parse_elf_finish(struct elf_info *info) static int ignore_undef_symbol(struct elf_info *info, const char *symname) { /* ignore __this_module, it will be resolved shortly */ - if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0) + if (strcmp(symname, "__this_module") == 0) return 1; /* ignore global offset table */ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) return 1; if (info->hdr->e_machine == EM_PPC) /* Special register function linked on all modules during final link of .ko */ - if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || - strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || - strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || - strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || - strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || - strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) + if (strstarts(symname, "_restgpr_") || + strstarts(symname, "_savegpr_") || + strstarts(symname, "_rest32gpr_") || + strstarts(symname, "_save32gpr_") || + strstarts(symname, "_restvr_") || + strstarts(symname, "_savevr_")) return 1; if (info->hdr->e_machine == EM_PPC64) /* Special register function linked on all modules during final link of .ko */ - if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || - strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || - strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || - strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 || + if (strstarts(symname, "_restgpr0_") || + strstarts(symname, "_savegpr0_") || + strstarts(symname, "_restvr_") || + strstarts(symname, "_savevr_") || strcmp(symname, ".TOC.") == 0) return 1; /* Do not ignore this symbol */ return 0; } -#define CRC_PFX VMLINUX_SYMBOL_STR(__crc_) -#define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_) - static void handle_modversions(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname) { @@ -628,13 +623,13 @@ static void handle_modversions(struct module *mod, struct elf_info *info, bool is_crc = false; if ((!is_vmlinux(mod->name) || mod->is_dot_o) && - strncmp(symname, "__ksymtab", 9) == 0) + strstarts(symname, "__ksymtab")) export = export_from_secname(info, get_secindex(info, sym)); else export = export_from_sec(info, get_secindex(info, sym)); /* CRC'd symbol */ - if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { + if (strstarts(symname, "__crc_")) { is_crc = true; crc = (unsigned int) sym->st_value; if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) { @@ -647,13 +642,13 @@ static void handle_modversions(struct module *mod, struct elf_info *info, info->sechdrs[sym->st_shndx].sh_addr : 0); crc = *crcp; } - sym_update_crc(symname + strlen(CRC_PFX), mod, crc, + sym_update_crc(symname + strlen("__crc_"), mod, crc, export); } switch (sym->st_shndx) { case SHN_COMMON: - if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { + if (strstarts(symname, "__gnu_lto_")) { /* Should warn here, but modpost runs before the linker */ } else warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); @@ -677,7 +672,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) break; if (symname[0] == '.') { - char *munged = strdup(symname); + char *munged = NOFAIL(strdup(symname)); munged[0] = '_'; munged[1] = toupper(munged[1]); symname = munged; @@ -685,15 +680,10 @@ static void handle_modversions(struct module *mod, struct elf_info *info, } #endif -#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX - if (symname[0] != '_') - break; - else - symname++; -#endif if (is_crc) { const char *e = is_vmlinux(mod->name) ?"":".ko"; - warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", symname + strlen(CRC_PFX), mod->name, e); + warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n", + symname + strlen("__crc_"), mod->name, e); } mod->unres = alloc_symbol(symname, ELF_ST_BIND(sym->st_info) == STB_WEAK, @@ -701,13 +691,13 @@ static void handle_modversions(struct module *mod, struct elf_info *info, break; default: /* All exported symbols */ - if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { - sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, + if (strstarts(symname, "__ksymtab_")) { + sym_add_exported(symname + strlen("__ksymtab_"), mod, export); } - if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) + if (strcmp(symname, "init_module") == 0) mod->has_init = 1; - if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) + if (strcmp(symname, "cleanup_module") == 0) mod->has_cleanup = 1; break; } @@ -734,16 +724,17 @@ static char *next_string(char *string, unsigned long *secsize) return string; } -static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, - const char *tag, char *info) +static char *get_next_modinfo(struct elf_info *info, const char *tag, + char *prev) { char *p; unsigned int taglen = strlen(tag); - unsigned long size = modinfo_len; + char *modinfo = info->modinfo; + unsigned long size = info->modinfo_len; - if (info) { - size -= info - (char *)modinfo; - modinfo = next_string(info, &size); + if (prev) { + size -= prev - modinfo; + modinfo = next_string(prev, &size); } for (p = modinfo; p; p = next_string(p, &size)) { @@ -753,11 +744,10 @@ static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, return NULL; } -static char *get_modinfo(void *modinfo, unsigned long modinfo_len, - const char *tag) +static char *get_modinfo(struct elf_info *info, const char *tag) { - return get_next_modinfo(modinfo, modinfo_len, tag, NULL); + return get_next_modinfo(info, tag, NULL); } /** @@ -1181,13 +1171,13 @@ static int secref_whitelist(const struct sectioncheck *mismatch, /* Check for pattern 1 */ if (match(tosec, init_data_sections) && match(fromsec, data_sections) && - (strncmp(fromsym, "__param", strlen("__param")) == 0)) + strstarts(fromsym, "__param")) return 0; /* Check for pattern 1a */ if (strcmp(tosec, ".init.text") == 0 && match(fromsec, data_sections) && - (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) + strstarts(fromsym, "__param_ops_")) return 0; /* Check for pattern 2 */ @@ -1328,7 +1318,7 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, static char *sec2annotation(const char *s) { if (match(s, init_exit_sections)) { - char *p = malloc(20); + char *p = NOFAIL(malloc(20)); char *r = p; *p++ = '_'; @@ -1348,7 +1338,7 @@ static char *sec2annotation(const char *s) strcat(p, " "); return r; } else { - return strdup(""); + return NOFAIL(strdup("")); } } @@ -1542,8 +1532,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, from = find_elf_symbol2(elf, r->r_offset, fromsec); fromsym = sym_name(elf, from); - if (!strncmp(fromsym, "reference___initcall", - sizeof("reference___initcall")-1)) + if (strstarts(fromsym, "reference___initcall")) return; tosec = sec_name(elf, get_secindex(elf, sym)); @@ -1940,7 +1929,7 @@ static char *remove_dot(char *s) return s; } -static void read_symbols(char *modname) +static void read_symbols(const char *modname) { const char *symname; char *version; @@ -1961,7 +1950,7 @@ static void read_symbols(char *modname) mod->skip = 1; } - license = get_modinfo(info.modinfo, info.modinfo_len, "license"); + license = get_modinfo(&info, "license"); if (!license && !is_vmlinux(modname)) warn("modpost: missing MODULE_LICENSE() in %s\n" "see include/linux/module.h for " @@ -1973,8 +1962,7 @@ static void read_symbols(char *modname) mod->gpl_compatible = 0; break; } - license = get_next_modinfo(info.modinfo, info.modinfo_len, - "license", license); + license = get_next_modinfo(&info, "license", license); } for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { @@ -1983,11 +1971,10 @@ static void read_symbols(char *modname) handle_modversions(mod, &info, sym, symname); handle_moddevtable(mod, &info, sym, symname); } - if (!is_vmlinux(modname) || - (is_vmlinux(modname) && vmlinux_section_warnings)) + if (!is_vmlinux(modname) || vmlinux_section_warnings) check_sec_ref(mod, modname, &info); - version = get_modinfo(info.modinfo, info.modinfo_len, "version"); + version = get_modinfo(&info, "version"); if (version) maybe_frob_rcs_version(modname, version, info.modinfo, version - (char *)info.hdr); @@ -2049,7 +2036,7 @@ void buf_write(struct buffer *buf, const char *s, int len) { if (buf->size - buf->pos < len) { buf->size += len + SZ; - buf->p = realloc(buf->p, buf->size); + buf->p = NOFAIL(realloc(buf->p, buf->size)); } strncpy(buf->p + buf->pos, s, len); buf->pos += len; @@ -2138,10 +2125,13 @@ static int check_modname_len(struct module *mod) **/ static void add_header(struct buffer *b, struct module *mod) { + buf_printf(b, "#include <linux/build-salt.h>\n"); buf_printf(b, "#include <linux/module.h>\n"); buf_printf(b, "#include <linux/vermagic.h>\n"); buf_printf(b, "#include <linux/compiler.h>\n"); buf_printf(b, "\n"); + buf_printf(b, "BUILD_SALT;\n"); + buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); buf_printf(b, "\n"); @@ -2174,9 +2164,7 @@ static void add_retpoline(struct buffer *b) static void add_staging_flag(struct buffer *b, const char *name) { - static const char *staging_dir = "drivers/staging"; - - if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) + if (strstarts(name, "drivers/staging")) buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); } @@ -2230,7 +2218,7 @@ static int add_versions(struct buffer *b, struct module *mod) err = 1; break; } - buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", + buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name); } diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 90c9a8ac7adb..f43a274f4f1d 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -81,11 +81,11 @@ else cp System.map "$tmpdir/boot/System.map-$version" cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version" fi -cp "$($MAKE -s image_name)" "$tmpdir/$installed_image_path" +cp "$($MAKE -s -f $srctree/Makefile image_name)" "$tmpdir/$installed_image_path" -if grep -q "^CONFIG_OF=y" $KCONFIG_CONFIG ; then +if grep -q "^CONFIG_OF_EARLY_FLATTREE=y" $KCONFIG_CONFIG ; then # Only some architectures with OF support have this target - if grep -q dtbs_install "${srctree}/arch/$SRCARCH/Makefile"; then + if [ -d "${srctree}/arch/$SRCARCH/boot/dts" ]; then $MAKE KBUILD_SRC= INSTALL_DTBS_PATH="$tmpdir/usr/lib/$packagename" dtbs_install fi fi diff --git a/scripts/package/buildtar b/scripts/package/buildtar index e8cc72a51b32..d624a07a4e77 100755 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -84,10 +84,6 @@ case "${ARCH}" in [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" [ -f "${objtree}/lifimage" ] && cp -v -- "${objtree}/lifimage" "${tmpdir}/boot/lifimage-${KERNELRELEASE}" ;; - vax) - [ -f "${objtree}/vmlinux.SYS" ] && cp -v -- "${objtree}/vmlinux.SYS" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.SYS" - [ -f "${objtree}/vmlinux.dsk" ] && cp -v -- "${objtree}/vmlinux.dsk" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.dsk" - ;; mips) if [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.bin" ]; then cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.bin" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" @@ -109,6 +105,14 @@ case "${ARCH}" in cp -v -- "${objtree}/vmlinux" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" fi ;; + arm64) + for i in Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo ; do + if [ -f "${objtree}/arch/arm64/boot/${i}" ] ; then + cp -v -- "${objtree}/arch/arm64/boot/${i}" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" + break + fi + done + ;; *) [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${KERNELRELEASE}" echo "" >&2 diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian index 6adb3a16ba3b..edcad61fe3cd 100755 --- a/scripts/package/mkdebian +++ b/scripts/package/mkdebian @@ -6,49 +6,81 @@ set -e +is_enabled() { + grep -q "^CONFIG_$1=y" $KCONFIG_CONFIG +} + +if_enabled_echo() { + if is_enabled "$1"; then + echo -n "$2" + elif [ $# -ge 3 ]; then + echo -n "$3" + fi +} + set_debarch() { + if [ -n "$KBUILD_DEBARCH" ] ; then + debarch="$KBUILD_DEBARCH" + return + fi + # Attempt to find the correct Debian architecture case "$UTS_MACHINE" in - i386|ia64|alpha) + i386|ia64|alpha|m68k|riscv*) debarch="$UTS_MACHINE" ;; x86_64) debarch=amd64 ;; sparc*) - debarch=sparc ;; + debarch=sparc$(if_enabled_echo 64BIT 64) ;; s390*) - debarch=s390$(grep -q CONFIG_64BIT=y $KCONFIG_CONFIG && echo x || true) ;; + debarch=s390x ;; ppc*) - debarch=$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo ppc64el || echo powerpc) ;; + if is_enabled 64BIT; then + debarch=ppc64$(if_enabled_echo CPU_LITTLE_ENDIAN el) + else + debarch=powerpc$(if_enabled_echo SPE spe) + fi + ;; parisc*) debarch=hppa ;; mips*) - debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;; + if is_enabled CPU_LITTLE_ENDIAN; then + debarch=mips$(if_enabled_echo 64BIT 64)$(if_enabled_echo CPU_MIPSR6 r6)el + elif is_enabled CPU_MIPSR6; then + debarch=mips$(if_enabled_echo 64BIT 64)r6 + else + debarch=mips + fi + ;; aarch64|arm64) debarch=arm64 ;; arm*) - if grep -q CONFIG_AEABI=y $KCONFIG_CONFIG; then - if grep -q CONFIG_VFP=y $KCONFIG_CONFIG; then - debarch=armhf - else - debarch=armel - fi + if is_enabled AEABI; then + debarch=arm$(if_enabled_echo VFP hf el) else - debarch=arm + debarch=arm + fi + ;; + openrisc) + debarch=or1k ;; + sh) + if is_enabled CPU_SH3; then + debarch=sh3$(if_enabled_echo CPU_BIG_ENDIAN eb) + elif is_enabled CPU_SH4; then + debarch=sh4$(if_enabled_echo CPU_BIG_ENDIAN eb) fi ;; - *) - debarch=$(dpkg --print-architecture) + esac + if [ -z "$debarch" ]; then + debarch=$(dpkg-architecture -qDEB_HOST_ARCH) echo "" >&2 echo "** ** ** WARNING ** ** **" >&2 echo "" >&2 echo "Your architecture doesn't have its equivalent" >&2 echo "Debian userspace architecture defined!" >&2 - echo "Falling back to using your current userspace instead!" >&2 + echo "Falling back to the current host architecture ($debarch)." >&2 echo "Please add support for $UTS_MACHINE to ${0} ..." >&2 echo "" >&2 - esac - if [ -n "$KBUILD_DEBARCH" ] ; then - debarch="$KBUILD_DEBARCH" fi } @@ -56,6 +88,7 @@ set_debarch() { version=$KERNELRELEASE if [ -n "$KDEB_PKGVERSION" ]; then packageversion=$KDEB_PKGVERSION + revision=${packageversion##*-} else revision=$(cat .version 2>/dev/null||echo 1) packageversion=$version-$revision @@ -71,22 +104,21 @@ if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version fi -# Try to determine maintainer and email values -if [ -n "$DEBEMAIL" ]; then - email=$DEBEMAIL -elif [ -n "$EMAIL" ]; then - email=$EMAIL -else - email=$(id -nu)@$(hostname -f 2>/dev/null || hostname) -fi -if [ -n "$DEBFULLNAME" ]; then - name=$DEBFULLNAME -elif [ -n "$NAME" ]; then - name=$NAME +email=${DEBEMAIL-$EMAIL} + +# use email string directly if it contains <email> +if echo $email | grep -q '<.*>'; then + maintainer=$email else - name="Anonymous" + # or construct the maintainer string + user=${KBUILD_BUILD_USER-$(id -nu)} + name=${DEBFULLNAME-$user} + if [ -z "$email" ]; then + buildhost=${KBUILD_BUILD_HOST-$(hostname -f 2>/dev/null || hostname)} + email="$user@$buildhost" + fi + maintainer="$name <$email>" fi -maintainer="$name <$email>" # Try to determine distribution if [ -n "$KDEB_CHANGELOG_DIST" ]; then @@ -174,10 +206,12 @@ cat <<EOF > debian/rules #!$(command -v $MAKE) -f build: - \$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} KBUILD_SRC= + \$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} \ + KBUILD_BUILD_VERSION=${revision} KBUILD_SRC= binary-arch: - \$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} KBUILD_SRC= intdeb-pkg + \$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} \ + KBUILD_BUILD_VERSION=${revision} KBUILD_SRC= intdeb-pkg clean: rm -rf debian/*tmp debian/files diff --git a/scripts/package/mkspec b/scripts/package/mkspec index e05646dc24dc..009147d4718e 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -12,6 +12,7 @@ # how we were called determines which rpms we build and how we build them if [ "$1" = prebuilt ]; then S=DEL + MAKE="$MAKE -f $srctree/Makefile" else S= fi @@ -78,19 +79,19 @@ $S %prep $S %setup -q $S $S %build -$S make %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release} +$S $MAKE %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release} $S %install mkdir -p %{buildroot}/boot %ifarch ia64 mkdir -p %{buildroot}/boot/efi - cp \$(make image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE + cp \$($MAKE image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE ln -s efi/vmlinuz-$KERNELRELEASE %{buildroot}/boot/ %else - cp \$(make image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE + cp \$($MAKE image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE %endif -$M make %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} KBUILD_SRC= modules_install - make %{?_smp_mflags} INSTALL_HDR_PATH=%{buildroot}/usr KBUILD_SRC= headers_install +$M $MAKE %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} modules_install + $MAKE %{?_smp_mflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install cp System.map %{buildroot}/boot/System.map-$KERNELRELEASE cp .config %{buildroot}/boot/config-$KERNELRELEASE bzip2 -9 --keep vmlinux diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 8c9691c3329e..895c40e8679f 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -500,7 +500,7 @@ do_file(char const *const fname) gpfx = 0; switch (w2(ehdr->e_machine)) { default: - fprintf(stderr, "unrecognized e_machine %d %s\n", + fprintf(stderr, "unrecognized e_machine %u %s\n", w2(ehdr->e_machine), fname); fail_file(); break; diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index b9897e2be404..2e7793735e14 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -441,7 +441,7 @@ static unsigned find_secsym_ndx(unsigned const txtndx, return symp - sym0; } } - fprintf(stderr, "Cannot find symbol for section %d: %s.\n", + fprintf(stderr, "Cannot find symbol for section %u: %s.\n", txtndx, txtname); fail_file(); } diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 191eb949d52c..f599031260d5 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -266,13 +266,29 @@ if ($arch eq "x86_64") { $objcopy .= " -O elf32-sh-linux"; } elsif ($arch eq "powerpc") { + my $ldemulation; + $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; # See comment in the sparc64 section for why we use '\w'. $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?\\w*?)>:"; $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; + if ($endian eq "big") { + $cc .= " -mbig-endian "; + $ld .= " -EB "; + $ldemulation = "ppc" + } else { + $cc .= " -mlittle-endian "; + $ld .= " -EL "; + $ldemulation = "lppc" + } if ($bits == 64) { - $type = ".quad"; + $type = ".quad"; + $cc .= " -m64 "; + $ld .= " -m elf64".$ldemulation." "; + } else { + $cc .= " -m32 "; + $ld .= " -m elf32".$ldemulation." "; } } elsif ($arch eq "arm") { @@ -373,6 +389,9 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$"; $type = ".quad"; $alignment = 2; +} elsif ($arch eq "nds32") { + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$"; + $alignment = 2; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index ffe8179f5d41..073fe7537f6c 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c @@ -124,7 +124,6 @@ int main(int argc, char *argv[]) fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n"); - fprintf(fout, "fs_use_xattr lustre user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n"); diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py new file mode 100755 index 000000000000..5056fb3b897d --- /dev/null +++ b/scripts/spdxcheck.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0 +# Copyright Thomas Gleixner <tglx@linutronix.de> + +from argparse import ArgumentParser +from ply import lex, yacc +import locale +import traceback +import sys +import git +import re +import os + +class ParserException(Exception): + def __init__(self, tok, txt): + self.tok = tok + self.txt = txt + +class SPDXException(Exception): + def __init__(self, el, txt): + self.el = el + self.txt = txt + +class SPDXdata(object): + def __init__(self): + self.license_files = 0 + self.exception_files = 0 + self.licenses = [ ] + self.exceptions = { } + +# Read the spdx data from the LICENSES directory +def read_spdxdata(repo): + + # The subdirectories of LICENSES in the kernel source + license_dirs = [ "preferred", "other", "exceptions" ] + lictree = repo.head.commit.tree['LICENSES'] + + spdx = SPDXdata() + + for d in license_dirs: + for el in lictree[d].traverse(): + if not os.path.isfile(el.path): + continue + + exception = None + for l in open(el.path).readlines(): + if l.startswith('Valid-License-Identifier:'): + lid = l.split(':')[1].strip().upper() + if lid in spdx.licenses: + raise SPDXException(el, 'Duplicate License Identifier: %s' %lid) + else: + spdx.licenses.append(lid) + + elif l.startswith('SPDX-Exception-Identifier:'): + exception = l.split(':')[1].strip().upper() + spdx.exceptions[exception] = [] + + elif l.startswith('SPDX-Licenses:'): + for lic in l.split(':')[1].upper().strip().replace(' ', '').replace('\t', '').split(','): + if not lic in spdx.licenses: + raise SPDXException(None, 'Exception %s missing license %s' %(ex, lic)) + spdx.exceptions[exception].append(lic) + + elif l.startswith("License-Text:"): + if exception: + if not len(spdx.exceptions[exception]): + raise SPDXException(el, 'Exception %s is missing SPDX-Licenses' %excid) + spdx.exception_files += 1 + else: + spdx.license_files += 1 + break + return spdx + +class id_parser(object): + + reserved = [ 'AND', 'OR', 'WITH' ] + tokens = [ 'LPAR', 'RPAR', 'ID', 'EXC' ] + reserved + + precedence = ( ('nonassoc', 'AND', 'OR'), ) + + t_ignore = ' \t' + + def __init__(self, spdx): + self.spdx = spdx + self.lasttok = None + self.lastid = None + self.lexer = lex.lex(module = self, reflags = re.UNICODE) + # Initialize the parser. No debug file and no parser rules stored on disk + # The rules are small enough to be generated on the fly + self.parser = yacc.yacc(module = self, write_tables = False, debug = False) + self.lines_checked = 0 + self.checked = 0 + self.spdx_valid = 0 + self.spdx_errors = 0 + self.curline = 0 + self.deepest = 0 + + # Validate License and Exception IDs + def validate(self, tok): + id = tok.value.upper() + if tok.type == 'ID': + if not id in self.spdx.licenses: + raise ParserException(tok, 'Invalid License ID') + self.lastid = id + elif tok.type == 'EXC': + if id not in self.spdx.exceptions: + raise ParserException(tok, 'Invalid Exception ID') + if self.lastid not in self.spdx.exceptions[id]: + raise ParserException(tok, 'Exception not valid for license %s' %self.lastid) + self.lastid = None + elif tok.type != 'WITH': + self.lastid = None + + # Lexer functions + def t_RPAR(self, tok): + r'\)' + self.lasttok = tok.type + return tok + + def t_LPAR(self, tok): + r'\(' + self.lasttok = tok.type + return tok + + def t_ID(self, tok): + r'[A-Za-z.0-9\-+]+' + + if self.lasttok == 'EXC': + print(tok) + raise ParserException(tok, 'Missing parentheses') + + tok.value = tok.value.strip() + val = tok.value.upper() + + if val in self.reserved: + tok.type = val + elif self.lasttok == 'WITH': + tok.type = 'EXC' + + self.lasttok = tok.type + self.validate(tok) + return tok + + def t_error(self, tok): + raise ParserException(tok, 'Invalid token') + + def p_expr(self, p): + '''expr : ID + | ID WITH EXC + | expr AND expr + | expr OR expr + | LPAR expr RPAR''' + pass + + def p_error(self, p): + if not p: + raise ParserException(None, 'Unfinished license expression') + else: + raise ParserException(p, 'Syntax error') + + def parse(self, expr): + self.lasttok = None + self.lastid = None + self.parser.parse(expr, lexer = self.lexer) + + def parse_lines(self, fd, maxlines, fname): + self.checked += 1 + self.curline = 0 + try: + for line in fd: + self.curline += 1 + if self.curline > maxlines: + break + self.lines_checked += 1 + if line.find("SPDX-License-Identifier:") < 0: + continue + expr = line.split(':')[1].replace('*/', '').strip() + self.parse(expr) + self.spdx_valid += 1 + # + # Should we check for more SPDX ids in the same file and + # complain if there are any? + # + break + + except ParserException as pe: + if pe.tok: + col = line.find(expr) + pe.tok.lexpos + tok = pe.tok.value + sys.stdout.write('%s: %d:%d %s: %s\n' %(fname, self.curline, col, pe.txt, tok)) + else: + sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, col, pe.txt)) + self.spdx_errors += 1 + +def scan_git_tree(tree): + for el in tree.traverse(): + # Exclude stuff which would make pointless noise + # FIXME: Put this somewhere more sensible + if el.path.startswith("LICENSES"): + continue + if el.path.find("license-rules.rst") >= 0: + continue + if not os.path.isfile(el.path): + continue + with open(el.path, 'rb') as fd: + parser.parse_lines(fd, args.maxlines, el.path) + +def scan_git_subtree(tree, path): + for p in path.strip('/').split('/'): + tree = tree[p] + scan_git_tree(tree) + +if __name__ == '__main__': + + ap = ArgumentParser(description='SPDX expression checker') + ap.add_argument('path', nargs='*', help='Check path or file. If not given full git tree scan. For stdin use "-"') + ap.add_argument('-m', '--maxlines', type=int, default=15, + help='Maximum number of lines to scan in a file. Default 15') + ap.add_argument('-v', '--verbose', action='store_true', help='Verbose statistics output') + args = ap.parse_args() + + # Sanity check path arguments + if '-' in args.path and len(args.path) > 1: + sys.stderr.write('stdin input "-" must be the only path argument\n') + sys.exit(1) + + try: + # Use git to get the valid license expressions + repo = git.Repo(os.getcwd()) + assert not repo.bare + + # Initialize SPDX data + spdx = read_spdxdata(repo) + + # Initilize the parser + parser = id_parser(spdx) + + except SPDXException as se: + if se.el: + sys.stderr.write('%s: %s\n' %(se.el.path, se.txt)) + else: + sys.stderr.write('%s\n' %se.txt) + sys.exit(1) + + except Exception as ex: + sys.stderr.write('FAIL: %s\n' %ex) + sys.stderr.write('%s\n' %traceback.format_exc()) + sys.exit(1) + + try: + if len(args.path) and args.path[0] == '-': + parser.parse_lines(sys.stdin, args.maxlines, '-') + else: + if args.path: + for p in args.path: + if os.path.isfile(p): + parser.parse_lines(open(p), args.maxlines, p) + elif os.path.isdir(p): + scan_git_subtree(repo.head.reference.commit.tree, p) + else: + sys.stderr.write('path %s does not exist\n' %p) + sys.exit(1) + else: + # Full git tree scan + scan_git_tree(repo.head.commit.tree) + + if args.verbose: + sys.stderr.write('\n') + sys.stderr.write('License files: %12d\n' %spdx.license_files) + sys.stderr.write('Exception files: %12d\n' %spdx.exception_files) + sys.stderr.write('License IDs %12d\n' %len(spdx.licenses)) + sys.stderr.write('Exception IDs %12d\n' %len(spdx.exceptions)) + sys.stderr.write('\n') + sys.stderr.write('Files checked: %12d\n' %parser.checked) + sys.stderr.write('Lines checked: %12d\n' %parser.lines_checked) + sys.stderr.write('Files with SPDX: %12d\n' %parser.spdx_valid) + sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors) + + sys.exit(0) + + except Exception as ex: + sys.stderr.write('FAIL: %s\n' %ex) + sys.stderr.write('%s\n' %traceback.format_exc()) + sys.exit(1) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 9a058cff49d4..517d0c3f83df 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -10,6 +10,8 @@ abandonning||abandoning abigious||ambiguous abitrate||arbitrate +abord||abort +aboslute||absolute abov||above abreviated||abbreviated absense||absence @@ -25,6 +27,7 @@ accessable||accessible accesss||access accidentaly||accidentally accidentually||accidentally +acclerated||accelerated accoding||according accomodate||accommodate accomodates||accommodates @@ -58,12 +61,15 @@ addres||address adddress||address addreses||addresses addresss||address +addrress||address aditional||additional aditionally||additionally aditionaly||additionally adminstrative||administrative adress||address adresses||addresses +adrresses||addresses +advertisment||advertisement adviced||advised afecting||affecting againt||against @@ -100,6 +106,7 @@ alue||value ambigious||ambiguous amoung||among amout||amount +amplifer||amplifier an union||a union an user||a user an userspace||a userspace @@ -145,11 +152,15 @@ assistent||assistant assocation||association associcated||associated assotiated||associated +asssert||assert assum||assume assumtpion||assumption asuming||assuming asycronous||asynchronous asynchnous||asynchronous +asynchromous||asynchronous +asymetric||asymmetric +asymmeric||asymmetric atomatically||automatically atomicly||atomically atempt||attempt @@ -172,6 +183,7 @@ avaible||available availabe||available availabled||available availablity||availability +availaible||available availale||available availavility||availability availble||available @@ -206,8 +218,11 @@ borad||board boundry||boundary brievely||briefly broadcat||broadcast +bufufer||buffer cacluated||calculated +caculate||calculate caculation||calculation +cadidate||candidate calender||calendar calescing||coalescing calle||called @@ -221,12 +236,14 @@ capabilty||capability capabitilies||capabilities capatibilities||capabilities capapbilities||capabilities +caputure||capture carefuly||carefully cariage||carriage catagory||category cehck||check challange||challenge challanges||challenges +chache||cache chanell||channel changable||changeable chanined||chained @@ -240,6 +257,7 @@ charaters||characters charcter||character chcek||check chck||check +checksumed||checksummed checksuming||checksumming childern||children childs||children @@ -292,8 +310,10 @@ comunication||communication conbination||combination conditionaly||conditionally conected||connected +conector||connector connecetd||connected configuartion||configuration +configuation||configuration configuratoin||configuration configuraton||configuration configuretion||configuration @@ -315,6 +335,7 @@ continous||continuous continously||continuously continueing||continuing contraints||constraints +contruct||construct contol||control contoller||controller controled||controlled @@ -343,6 +364,7 @@ dafault||default deafult||default deamon||daemon decompres||decompress +decsribed||described decription||description dectected||detected defailt||default @@ -379,6 +401,7 @@ desctiptor||descriptor desriptor||descriptor desriptors||descriptors destionation||destination +destoried||destroyed destory||destroy destoryed||destroyed destorys||destroys @@ -400,22 +423,30 @@ didnt||didn't diferent||different differrence||difference diffrent||different +differenciate||differentiate diffrentiate||differentiate difinition||definition dimesions||dimensions diplay||display +directon||direction direectly||directly +diregard||disregard disassocation||disassociation disapear||disappear disapeared||disappeared disappared||disappeared +disbale||disable +disbaled||disabled disble||disable disbled||disabled disconnet||disconnect discontinous||discontinuous +disharge||discharge dispertion||dispersion dissapears||disappears distiction||distinction +divisable||divisible +divsiors||divisors docuentation||documentation documantation||documentation documentaion||documentation @@ -427,6 +458,7 @@ downlad||download downlads||downloads druing||during dynmaic||dynamic +eanable||enable easilly||easily ecspecially||especially edditable||editable @@ -484,9 +516,12 @@ exprimental||experimental extened||extended extensability||extensibility extention||extension +extenstion||extension extracter||extractor +faield||failed falied||failed faild||failed +failer||failure faill||fail failied||failed faillure||failure @@ -520,6 +555,7 @@ forseeable||foreseeable forse||force fortan||fortran forwardig||forwarding +frambuffer||framebuffer framming||framing framwork||framework frequncy||frequency @@ -527,6 +563,7 @@ frome||from fucntion||function fuction||function fuctions||functions +funcation||function funcion||function functionallity||functionality functionaly||functionally @@ -540,6 +577,7 @@ futrue||future gaurenteed||guaranteed generiously||generously genereate||generate +genereted||generated genric||generic globel||global grabing||grabbing @@ -553,6 +591,7 @@ guarentee||guarantee halfs||halves hander||handler handfull||handful +hanlde||handle hanled||handled happend||happened harware||hardware @@ -561,6 +600,7 @@ helpfull||helpful hybernate||hibernate hierachy||hierarchy hierarchie||hierarchy +homogenous||homogeneous howver||however hsould||should hypervior||hypervisor @@ -568,6 +608,8 @@ hypter||hyper identidier||identifier iligal||illegal illigal||illegal +illgal||illegal +iomaped||iomapped imblance||imbalance immeadiately||immediately immedaite||immediate @@ -618,12 +660,15 @@ initation||initiation initators||initiators initialiazation||initialization initializiation||initialization +initialze||initialize initialzed||initialized initilization||initialization initilize||initialize inofficial||unofficial +inrerface||interface insititute||institute instal||install +instanciate||instantiate instanciated||instantiated inteface||interface integreated||integrated @@ -657,6 +702,7 @@ intregral||integral intrrupt||interrupt intterrupt||interrupt intuative||intuitive +inavlid||invalid invaid||invalid invald||invalid invalde||invalid @@ -683,6 +729,7 @@ langauge||language langugage||language lauch||launch layed||laid +legnth||length leightweight||lightweight lengh||length lenght||length @@ -696,6 +743,7 @@ licenceing||licencing loggging||logging loggin||login logile||logfile +loobpack||loopback loosing||losing losted||lost machinary||machinery @@ -703,6 +751,7 @@ maintainance||maintenance maintainence||maintenance maintan||maintain makeing||making +mailformed||malformed malplaced||misplaced malplace||misplace managable||manageable @@ -710,6 +759,7 @@ managment||management mangement||management manoeuvering||maneuvering mappping||mapping +matchs||matches mathimatical||mathematical mathimatic||mathematic mathimatics||mathematics @@ -725,6 +775,7 @@ messsage||message messsages||messages micropone||microphone microprocesspr||microprocessor +migrateable||migratable milliseonds||milliseconds minium||minimum minimam||minimum @@ -741,6 +792,7 @@ missmatch||mismatch miximum||maximum mmnemonic||mnemonic mnay||many +modfiy||modify modulues||modules momery||memory memomry||memory @@ -777,6 +829,7 @@ notifed||notified numebr||number numner||number obtaion||obtain +obusing||abusing occassionally||occasionally occationally||occasionally occurance||occurrence @@ -787,6 +840,7 @@ occure||occurred occured||occurred occuring||occurring offet||offset +offloded||offloaded omited||omitted omiting||omitting omitt||omit @@ -829,6 +883,7 @@ parametes||parameters parametised||parametrised paramter||parameter paramters||parameters +parmaters||parameters particuarly||particularly particularily||particularly partiton||partition @@ -837,6 +892,7 @@ passin||passing pathes||paths pecularities||peculiarities peformance||performance +peforming||performing peice||piece pendantic||pedantic peprocessor||preprocessor @@ -846,6 +902,7 @@ peroid||period persistance||persistence persistant||persistent plalform||platform +platfoem||platform platfrom||platform plattform||platform pleaes||please @@ -858,6 +915,7 @@ posible||possible positon||position possibilites||possibilities powerfull||powerful +preamle||preamble preample||preamble preapre||prepare preceeded||preceded @@ -870,6 +928,7 @@ prefered||preferred prefferably||preferably premption||preemption prepaired||prepared +preperation||preparation pressre||pressure primative||primitive princliple||principle @@ -935,6 +994,7 @@ recommanded||recommended recyle||recycle redircet||redirect redirectrion||redirection +redundacy||redundancy reename||rename refcounf||refcount refence||reference @@ -945,6 +1005,7 @@ refernces||references refernnce||reference refrence||reference registerd||registered +registeration||registration registeresd||registered registerred||registered registes||registers @@ -973,7 +1034,9 @@ requirment||requirement requred||required requried||required requst||request +reregisteration||reregistration reseting||resetting +reseverd||reserved resizeable||resizable resouce||resource resouces||resources @@ -982,6 +1045,7 @@ responce||response ressizes||resizes ressource||resource ressources||resources +restesting||retesting retransmited||retransmitted retreived||retrieved retreive||retrieve @@ -1006,6 +1070,7 @@ sacrifying||sacrificing safly||safely safty||safety savable||saveable +scaleing||scaling scaned||scanned scaning||scanning scarch||search @@ -1014,6 +1079,8 @@ searchs||searches secquence||sequence secund||second segement||segment +semaphone||semaphore +senario||scenario senarios||scenarios sentivite||sensitive separatly||separately @@ -1025,9 +1092,13 @@ seperate||separate seperatly||separately seperator||separator sepperate||separate +seqeunce||sequence +seqeuncer||sequencer +seqeuencer||sequencer sequece||sequence sequencial||sequential serveral||several +servive||service setts||sets settting||setting shotdown||shutdown @@ -1073,6 +1144,7 @@ standartization||standardization standart||standard staticly||statically stoped||stopped +stoping||stopping stoppped||stopped straming||streaming struc||struct @@ -1085,6 +1157,7 @@ subdirectoires||subdirectories suble||subtle substract||subtract submition||submission +suceed||succeed succesfully||successfully succesful||successful successed||succeeded @@ -1108,6 +1181,7 @@ surpressed||suppressed surpresses||suppresses susbsystem||subsystem suspeneded||suspended +suspsend||suspend suspicously||suspiciously swaping||swapping switchs||switches @@ -1122,6 +1196,7 @@ swtich||switch symetric||symmetric synax||syntax synchonized||synchronized +synchronuously||synchronously syncronize||synchronize syncronized||synchronized syncronizing||synchronizing @@ -1130,11 +1205,14 @@ syste||system sytem||system sythesis||synthesis taht||that +tansmit||transmit targetted||targeted targetting||targeting +taskelt||tasklet teh||the temorary||temporary temproarily||temporarily +thead||thread therfore||therefore thier||their threds||threads @@ -1143,11 +1221,14 @@ thresold||threshold throught||through troughput||throughput thses||these +tiggers||triggers tiggered||triggered tipically||typically +timeing||timing timout||timeout tmis||this torerable||tolerable +traking||tracking tramsmitted||transmitted tramsmit||transmit tranasction||transaction @@ -1162,6 +1243,7 @@ transormed||transformed trasfer||transfer trasmission||transmission treshold||threshold +trigerred||triggered trigerring||triggering trun||turn tunning||tuning @@ -1169,6 +1251,8 @@ ture||true tyep||type udpate||update uesd||used +uknown||unknown +usupported||unsupported uncommited||uncommitted unconditionaly||unconditionally underun||underrun @@ -1181,11 +1265,14 @@ unexpeted||unexpected unexpexted||unexpected unfortunatelly||unfortunately unifiy||unify +uniterrupted||uninterrupted unintialized||uninitialized unkmown||unknown unknonw||unknown unknow||unknown unkown||unknown +unamed||unnamed +uneeded||unneeded unneded||unneeded unneccecary||unnecessary unneccesary||unnecessary @@ -1210,6 +1297,7 @@ usefull||useful usege||usage usera||users usualy||usually +usupported||unsupported utilites||utilities utillities||utilities utilties||utilities @@ -1233,7 +1321,9 @@ virtaul||virtual virtiual||virtual visiters||visitors vitual||virtual +vunerable||vulnerable wakeus||wakeups +wathdog||watchdog wating||waiting wiat||wait wether||whether diff --git a/scripts/subarch.include b/scripts/subarch.include new file mode 100644 index 000000000000..650682821126 --- /dev/null +++ b/scripts/subarch.include @@ -0,0 +1,13 @@ +# SUBARCH tells the usermode build what the underlying arch is. That is set +# first, and if a usermode build is happening, the "ARCH=um" on the command +# line overrides the setting of ARCH below. If a native build is happening, +# then ARCH is assigned, getting whatever value it gets normally, and +# SUBARCH is subsequently ignored. + +SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ + -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/riscv.*/riscv/) diff --git a/scripts/tags.sh b/scripts/tags.sh index 78e546ff689c..4fa070f9231a 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -28,20 +28,11 @@ fi # ignore userspace tools ignore="$ignore ( -path ${tree}tools ) -prune -o" -# Find all available archs -find_all_archs() -{ - ALLSOURCE_ARCHS="" - for arch in `ls ${tree}arch`; do - ALLSOURCE_ARCHS="${ALLSOURCE_ARCHS} "${arch##\/} - done -} - # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH if [ "${ALLSOURCE_ARCHS}" = "" ]; then ALLSOURCE_ARCHS=${SRCARCH} elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then - find_all_archs + ALLSOURCE_ARCHS=$(find ${tree}arch/ -mindepth 1 -maxdepth 1 -type d -printf '%f ') fi # find sources in arch/$ARCH @@ -161,6 +152,7 @@ regex_asm=( ) regex_c=( '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/' + '/^BPF_CALL_[0-9](\([[:alnum:]_]*\).*/\1/' '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/' '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/' '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/' @@ -188,9 +180,9 @@ regex_c=( '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/' '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/' '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/' - '/^PAGE_MAPCOUNT_OPS(\([[:alnum:]_]*\).*/Page\1/' - '/^PAGE_MAPCOUNT_OPS(\([[:alnum:]_]*\).*/__SetPage\1/' - '/^PAGE_MAPCOUNT_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/' + '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/' + '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/' '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/' '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/' '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/' @@ -211,7 +203,7 @@ regex_c=( '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/' '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/' '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/' - '/\<DEFINE_HASHTABLE(\([[:alnum:]_]*\)/\1/v/' + '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/' ) regex_kconfig=( '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/' @@ -254,7 +246,7 @@ exuberant() { setup_regex exuberant asm c all_target_sources | xargs $1 -a \ - -I __initdata,__exitdata,__initconst, \ + -I __initdata,__exitdata,__initconst,__ro_after_init \ -I __initdata_memblock \ -I __refdata,__attribute,__maybe_unused,__always_unused \ -I __acquires,__releases,__deprecated \ diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py index db40fa04cd51..9b6dd4f36335 100755 --- a/scripts/tracing/draw_functrace.py +++ b/scripts/tracing/draw_functrace.py @@ -123,7 +123,7 @@ def main(): tree = tree.getParent(caller) tree = tree.calls(callee, calltime) - print CallTree.ROOT + print(CallTree.ROOT) if __name__ == "__main__": main() diff --git a/scripts/unifdef.c b/scripts/unifdef.c index 7493c0ee51cc..db00e3e30a59 100644 --- a/scripts/unifdef.c +++ b/scripts/unifdef.c @@ -395,7 +395,7 @@ usage(void) * When we have processed a group that starts off with a known-false * #if/#elif sequence (which has therefore been deleted) followed by a * #elif that we don't understand and therefore must keep, we edit the - * latter into a #if to keep the nesting correct. We use strncpy() to + * latter into a #if to keep the nesting correct. We use memcpy() to * overwrite the 4 byte token "elif" with "if " without a '\0' byte. * * When we find a true #elif in a group, the following block will @@ -450,7 +450,7 @@ static void Idrop (void) { Fdrop(); ignoreon(); } static void Itrue (void) { Ftrue(); ignoreon(); } static void Ifalse(void) { Ffalse(); ignoreon(); } /* modify this line */ -static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); } +static void Mpass (void) { memcpy(keyword, "if ", 4); Pelif(); } static void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); } static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); } static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); } diff --git a/scripts/ver_linux b/scripts/ver_linux index 545ec7388eb7..a6c728db05ce 100755 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -13,28 +13,28 @@ BEGIN { system("uname -a") printf("\n") - printversion("GNU C", version("gcc -dumpversion 2>&1")) - printversion("GNU Make", version("make --version 2>&1")) - printversion("Binutils", version("ld -v 2>&1")) - printversion("Util-linux", version("mount --version 2>&1")) - printversion("Mount", version("mount --version 2>&1")) - printversion("Module-init-tools", version("depmod -V 2>&1")) - printversion("E2fsprogs", version("tune2fs 2>&1")) - printversion("Jfsutils", version("fsck.jfs -V 2>&1")) - printversion("Reiserfsprogs", version("reiserfsck -V 2>&1")) - printversion("Reiser4fsprogs", version("fsck.reiser4 -V 2>&1")) - printversion("Xfsprogs", version("xfs_db -V 2>&1")) - printversion("Pcmciautils", version("pccardctl -V 2>&1")) - printversion("Pcmcia-cs", version("cardmgr -V 2>&1")) - printversion("Quota-tools", version("quota -V 2>&1")) - printversion("PPP", version("pppd --version 2>&1")) - printversion("Isdn4k-utils", version("isdnctrl 2>&1")) - printversion("Nfs-utils", version("showmount --version 2>&1")) + printversion("GNU C", version("gcc -dumpversion")) + printversion("GNU Make", version("make --version")) + printversion("Binutils", version("ld -v")) + printversion("Util-linux", version("mount --version")) + printversion("Mount", version("mount --version")) + printversion("Module-init-tools", version("depmod -V")) + printversion("E2fsprogs", version("tune2fs")) + printversion("Jfsutils", version("fsck.jfs -V")) + printversion("Reiserfsprogs", version("reiserfsck -V")) + printversion("Reiser4fsprogs", version("fsck.reiser4 -V")) + printversion("Xfsprogs", version("xfs_db -V")) + printversion("Pcmciautils", version("pccardctl -V")) + printversion("Pcmcia-cs", version("cardmgr -V")) + printversion("Quota-tools", version("quota -V")) + printversion("PPP", version("pppd --version")) + printversion("Isdn4k-utils", version("isdnctrl")) + printversion("Nfs-utils", version("showmount --version")) - if (system("test -r /proc/self/maps") == 0) { - while (getline <"/proc/self/maps" > 0) { + while (getline <"/proc/self/maps" > 0) { + if (/libc.*\.so$/) { n = split($0, procmaps, "/") - if (/libc.*so$/ && match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) { + if (match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) { ver = substr(procmaps[n], RSTART, RLENGTH) printversion("Linux C Library", ver) break @@ -42,7 +42,7 @@ BEGIN { } } - printversion("Dynamic linker (ldd)", version("ldd --version 2>&1")) + printversion("Dynamic linker (ldd)", version("ldd --version")) while ("ldconfig -p 2>/dev/null" | getline > 0) { if (/(libg|stdc)[+]+\.so/) { @@ -50,30 +50,27 @@ BEGIN { break } } - if (system("test -r " libcpp) == 0) - printversion("Linux C++ Library", version("readlink " libcpp)) + printversion("Linux C++ Library", version("readlink " libcpp)) + printversion("Procps", version("ps --version")) + printversion("Net-tools", version("ifconfig --version")) + printversion("Kbd", version("loadkeys -V")) + printversion("Console-tools", version("loadkeys -V")) + printversion("Oprofile", version("oprofiled --version")) + printversion("Sh-utils", version("expr --v")) + printversion("Udev", version("udevadm --version")) + printversion("Wireless-tools", version("iwconfig --version")) - printversion("Procps", version("ps --version 2>&1")) - printversion("Net-tools", version("ifconfig --version 2>&1")) - printversion("Kbd", version("loadkeys -V 2>&1")) - printversion("Console-tools", version("loadkeys -V 2>&1")) - printversion("Oprofile", version("oprofiled --version 2>&1")) - printversion("Sh-utils", version("expr --v 2>&1")) - printversion("Udev", version("udevadm --version 2>&1")) - printversion("Wireless-tools", version("iwconfig --version 2>&1")) - - if (system("test -r /proc/modules") == 0) { - while ("sort /proc/modules" | getline > 0) { - mods = mods sep $1 - sep = " " - } - printversion("Modules Loaded", mods) + while ("sort /proc/modules" | getline > 0) { + mods = mods sep $1 + sep = " " } + printversion("Modules Loaded", mods) } function version(cmd, ver) { + cmd = cmd " 2>&1" while (cmd | getline > 0) { - if (!/ver_linux/ && match($0, /[0-9]+([.]?[0-9]+)+/)) { + if (match($0, /[0-9]+([.]?[0-9]+)+/)) { ver = substr($0, RSTART, RLENGTH) break } |
