diff options
Diffstat (limited to 'scripts')
200 files changed, 17777 insertions, 3933 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 105b21f0818..fb070fa1038 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -9,3 +9,5 @@ unifdef ihex2fw recordmcount docproc +sortextable +asn1_compiler diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index d897278b1f9..122f95c9586 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -3,6 +3,7 @@ # Convenient variables comma := , +quote := " squote := ' empty := space := $(empty) $(empty) @@ -98,24 +99,24 @@ try-run = $(shell set -e; \ # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) as-option = $(call try-run,\ - $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) + $(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,\ - /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) + printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) cc-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) cc-option-yn = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) # cc-option-align # Prefix align with either -falign or -malign @@ -125,7 +126,7 @@ cc-option-align = $(subst -functions=0,,\ # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) cc-disable-warning = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) # cc-version # Usage gcc-ver := $(call cc-version) @@ -143,18 +144,27 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) cc-ldoption = $(call try-run,\ - $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) # ld-option # Usage: LDFLAGS += $(call ld-option, -X) ld-option = $(call try-run,\ - $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) + $(CC) -x c /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) # ar-option # Usage: KBUILD_ARFLAGS := $(call ar-option,D) # Important: no spaces around options ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2)) +# ld-version +# Usage: $(call ld-version) +# Note this is mainly for HJ Lu's 3 number binutil versions +ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) + +# ld-ifversion +# Usage: $(call ld-ifversion, -ge, 22252, y) +ld-ifversion = $(shell [ $(call ld-version) $(1) $(2) ] && echo $(3)) + ###### ### @@ -209,7 +219,7 @@ endif # >$< substitution to preserve $ when reloading .cmd file # note: when using inline perl scripts [perl -e '...$$t=1;...'] # in $(cmd_xxx) double $$ your perl vars -make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) +make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. diff --git a/scripts/Makefile b/scripts/Makefile index df7678febf2..890df5c6adf 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -8,11 +8,18 @@ # conmakehash: Create arrays for initializing the kernel console tables # docproc: Used in Documentation/DocBook +HOST_EXTRACFLAGS += -I$(srctree)/tools/include + hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount +hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable +hostprogs-$(CONFIG_ASN1) += asn1_compiler + +HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include +HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include always := $(hostprogs-y) $(hostprogs-m) @@ -20,10 +27,10 @@ always := $(hostprogs-y) $(hostprogs-m) hostprogs-y += unifdef docproc # These targets are used internally to avoid "is up to date" messages -PHONY += build_unifdef -build_unifdef: scripts/unifdef FORCE +PHONY += build_unifdef build_docproc +build_unifdef: $(obj)/unifdef @: -build_docproc: scripts/docproc FORCE +build_docproc: $(obj)/docproc @: subdir-$(CONFIG_MODVERSIONS) += genksyms @@ -32,4 +39,4 @@ subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_DTC) += dtc # Let clean descend into subdirs -subdir- += basic kconfig package selinux +subdir- += basic kconfig package diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic index 40caf3c26cd..045e0098e96 100644 --- a/scripts/Makefile.asm-generic +++ b/scripts/Makefile.asm-generic @@ -5,7 +5,7 @@ # and for each file listed in this file with generic-y creates # a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/asm) -kbuild-file := $(srctree)/arch/$(SRCARCH)/include/asm/Kbuild +kbuild-file := $(srctree)/arch/$(SRCARCH)/include/$(src)/Kbuild -include $(kbuild-file) include scripts/Kbuild.include @@ -21,4 +21,3 @@ all: $(patsubst %, $(obj)/%, $(generic-y)) $(obj)/%.h: $(call cmd,wrap) - diff --git a/scripts/Makefile.build b/scripts/Makefile.build index d2b366c16b6..bf3e6778cd7 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -50,55 +50,6 @@ ifeq ($(KBUILD_NOPEDANTIC),) endif endif -# -# make W=... settings -# -# W=1 - warnings that may be relevant and does not occur too often -# W=2 - warnings that occur quite often but may still be relevant -# W=3 - the more obscure warnings, can most likely be ignored -# -# $(call cc-option, -W...) handles gcc -W.. options which -# are not supported by all versions of the compiler -ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS -warning- := $(empty) - -warning-1 := -Wextra -Wunused -Wno-unused-parameter -warning-1 += -Wmissing-declarations -warning-1 += -Wmissing-format-attribute -warning-1 += -Wmissing-prototypes -warning-1 += -Wold-style-definition -warning-1 += $(call cc-option, -Wmissing-include-dirs) -warning-1 += $(call cc-option, -Wunused-but-set-variable) - -warning-2 := -Waggregate-return -warning-2 += -Wcast-align -warning-2 += -Wdisabled-optimization -warning-2 += -Wnested-externs -warning-2 += -Wshadow -warning-2 += $(call cc-option, -Wlogical-op) - -warning-3 := -Wbad-function-cast -warning-3 += -Wcast-qual -warning-3 += -Wconversion -warning-3 += -Wpacked -warning-3 += -Wpadded -warning-3 += -Wpointer-arith -warning-3 += -Wredundant-decls -warning-3 += -Wswitch-default -warning-3 += $(call cc-option, -Wpacked-bitfield-compat) -warning-3 += $(call cc-option, -Wvla) - -warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) - -ifeq ("$(strip $(warning))","") - $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown) -endif - -KBUILD_CFLAGS += $(warning) -endif - include scripts/Makefile.lib ifdef host-progs @@ -196,7 +147,7 @@ $(multi-objs-y:.o=.s) : modname = $(modname-multi) $(multi-objs-y:.o=.lst) : modname = $(modname-multi) quiet_cmd_cc_s_c = CC $(quiet_modtag) $@ -cmd_cc_s_c = $(CC) $(c_flags) -fverbose-asm -S -o $@ $< +cmd_cc_s_c = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $< $(obj)/%.s: $(src)/%.c FORCE $(call if_changed_dep,cc_s_c) @@ -209,7 +160,8 @@ $(obj)/%.i: $(src)/%.c FORCE cmd_gensymtypes = \ $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ - $(GENKSYMS) $(if $(1), -T $(2)) -a $(ARCH) \ + $(GENKSYMS) $(if $(1), -T $(2)) \ + $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ $(if $(KBUILD_PRESERVE),-p) \ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) @@ -329,7 +281,7 @@ $(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) $(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) quiet_cmd_as_s_S = CPP $(quiet_modtag) $@ -cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< +cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< $(obj)/%.s: $(src)/%.S FORCE $(call if_changed_dep,as_s_S) @@ -352,6 +304,17 @@ quiet_cmd_cpp_lds_S = LDS $@ $(obj)/%.lds: $(src)/%.lds.S FORCE $(call if_changed_dep,cpp_lds_S) +# ASN.1 grammar +# --------------------------------------------------------------------------- +quiet_cmd_asn1_compiler = ASN.1 $@ + cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ + $(subst .h,.c,$@) $(subst .c,.h,$@) + +.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h + +$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler + $(call cmd,asn1_compiler) + # Build the compiled-in targets # --------------------------------------------------------------------------- @@ -412,7 +375,7 @@ link_multi_deps = \ $(filter $(addprefix $(obj)/, \ $($(subst $(obj)/,,$(@:.o=-objs))) \ $($(subst $(obj)/,,$(@:.o=-y)))), $^) - + quiet_cmd_link_multi-y = LD $@ cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn new file mode 100644 index 00000000000..65643506c71 --- /dev/null +++ b/scripts/Makefile.extrawarn @@ -0,0 +1,67 @@ +# ========================================================================== +# +# make W=... settings +# +# W=1 - warnings that may be relevant and does not occur too often +# W=2 - warnings that occur quite often but may still be relevant +# W=3 - the more obscure warnings, can most likely be ignored +# +# $(call cc-option, -W...) handles gcc -W.. options which +# are not supported by all versions of the compiler +# ========================================================================== + +ifeq ("$(origin W)", "command line") + export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W) +endif + +ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS +warning- := $(empty) + +warning-1 := -Wextra -Wunused -Wno-unused-parameter +warning-1 += -Wmissing-declarations +warning-1 += -Wmissing-format-attribute +warning-1 += $(call cc-option, -Wmissing-prototypes) +warning-1 += -Wold-style-definition +warning-1 += $(call cc-option, -Wmissing-include-dirs) +warning-1 += $(call cc-option, -Wunused-but-set-variable) +warning-1 += $(call cc-disable-warning, missing-field-initializers) + +# Clang +warning-1 += $(call cc-disable-warning, initializer-overrides) +warning-1 += $(call cc-disable-warning, unused-value) +warning-1 += $(call cc-disable-warning, format) +warning-1 += $(call cc-disable-warning, unknown-warning-option) +warning-1 += $(call cc-disable-warning, sign-compare) +warning-1 += $(call cc-disable-warning, format-zero-length) +warning-1 += $(call cc-disable-warning, uninitialized) +warning-1 += $(call cc-option, -fcatch-undefined-behavior) + +warning-2 := -Waggregate-return +warning-2 += -Wcast-align +warning-2 += -Wdisabled-optimization +warning-2 += -Wnested-externs +warning-2 += -Wshadow +warning-2 += $(call cc-option, -Wlogical-op) +warning-2 += $(call cc-option, -Wmissing-field-initializers) + +warning-3 := -Wbad-function-cast +warning-3 += -Wcast-qual +warning-3 += -Wconversion +warning-3 += -Wpacked +warning-3 += -Wpadded +warning-3 += -Wpointer-arith +warning-3 += -Wredundant-decls +warning-3 += -Wswitch-default +warning-3 += $(call cc-option, -Wpacked-bitfield-compat) +warning-3 += $(call cc-option, -Wvla) + +warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) +warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) +warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) + +ifeq ("$(strip $(warning))","") + $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown) +endif + +KBUILD_CFLAGS += $(warning) +endif diff --git a/scripts/Makefile.fwinst b/scripts/Makefile.fwinst index 6bf8e87f1dc..d8e335eed22 100644 --- a/scripts/Makefile.fwinst +++ b/scripts/Makefile.fwinst @@ -18,31 +18,29 @@ include $(srctree)/$(obj)/Makefile include scripts/Makefile.host mod-fw := $(fw-shipped-m) -# If CONFIG_FIRMWARE_IN_KERNEL isn't set, then install the +# If CONFIG_FIRMWARE_IN_KERNEL isn't set, then install the # firmware for in-kernel drivers too. ifndef CONFIG_FIRMWARE_IN_KERNEL mod-fw += $(fw-shipped-y) endif +ifneq ($(KBUILD_SRC),) +# Create output directory if not already present +_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) + +firmware-dirs := $(sort $(addprefix $(objtree)/$(obj)/,$(dir $(fw-external-y) $(fw-shipped-all)))) +# Create directories for firmware in subdirectories +_dummy := $(foreach d,$(firmware-dirs), $(shell [ -d $(d) ] || mkdir -p $(d))) +endif + installed-mod-fw := $(addprefix $(INSTALL_FW_PATH)/,$(mod-fw)) installed-fw := $(addprefix $(INSTALL_FW_PATH)/,$(fw-shipped-all)) -installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/. - -# Workaround for make < 3.81, where .SECONDEXPANSION doesn't work. -PHONY += $(INSTALL_FW_PATH)/$$(%) install-all-dirs -$(INSTALL_FW_PATH)/$$(%): install-all-dirs - @true -install-all-dirs: $(installed-fw-dirs) - @true quiet_cmd_install = INSTALL $(subst $(srctree)/,,$@) - cmd_install = $(INSTALL) -m0644 $< $@ - -$(installed-fw-dirs): - $(call cmd,mkdir) + cmd_install = mkdir -p $(@D); $(INSTALL) -m0644 $< $@ -$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $(INSTALL_FW_PATH)/$$(dir %) +$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% $(call cmd,install) PHONY += __fw_install __fw_modinst FORCE diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst index d3bae5e7b60..8ccf83056a7 100644 --- a/scripts/Makefile.headersinst +++ b/scripts/Makefile.headersinst @@ -3,63 +3,86 @@ # # header-y - list files to be installed. They are preprocessed # to remove __KERNEL__ section of the file -# objhdr-y - Same as header-y but for generated files -# genhdr-y - Same as objhdr-y but in a generated/ directory +# genhdr-y - Same as header-y but in a generated/ directory # # ========================================================================== -# called may set destination dir (when installing to asm/) -_dst := $(if $(dst),$(dst),$(obj)) - # generated header directory gen := $(if $(gen),$(gen),$(subst include/,include/generated/,$(obj))) kbuild-file := $(srctree)/$(obj)/Kbuild include $(kbuild-file) -_dst := $(if $(destination-y),$(destination-y),$(_dst)) +# called may set destination dir (when installing to asm/) +_dst := $(if $(destination-y),$(destination-y),$(if $(dst),$(dst),$(obj))) + +old-kbuild-file := $(srctree)/$(subst uapi/,,$(obj))/Kbuild +ifneq ($(wildcard $(old-kbuild-file)),) +include $(old-kbuild-file) +endif include scripts/Kbuild.include -install := $(INSTALL_HDR_PATH)/$(_dst) +installdir := $(INSTALL_HDR_PATH)/$(subst uapi/,,$(_dst)) header-y := $(sort $(header-y)) subdirs := $(patsubst %/,%,$(filter %/, $(header-y))) header-y := $(filter-out %/, $(header-y)) # files used to track state of install/check -install-file := $(install)/.install -check-file := $(install)/.check +install-file := $(installdir)/.install +check-file := $(installdir)/.check # generic-y list all files an architecture uses from asm-generic # Use this to build a list of headers which require a wrapper wrapper-files := $(filter $(header-y), $(generic-y)) +srcdir := $(srctree)/$(obj) +gendir := $(objtree)/$(gen) + +oldsrcdir := $(srctree)/$(subst /uapi,,$(obj)) + # all headers files for this dir header-y := $(filter-out $(generic-y), $(header-y)) -all-files := $(header-y) $(objhdr-y) $(genhdr-y) $(wrapper-files) -input-files := $(addprefix $(srctree)/$(obj)/,$(header-y)) \ - $(addprefix $(objtree)/$(obj)/,$(objhdr-y)) \ - $(addprefix $(objtree)/$(gen)/,$(genhdr-y)) -output-files := $(addprefix $(install)/, $(all-files)) +all-files := $(header-y) $(genhdr-y) $(wrapper-files) +output-files := $(addprefix $(installdir)/, $(all-files)) + +input-files1 := $(foreach hdr, $(header-y), \ + $(if $(wildcard $(srcdir)/$(hdr)), \ + $(wildcard $(srcdir)/$(hdr))) \ + ) +input-files1-name := $(notdir $(input-files1)) +input-files2 := $(foreach hdr, $(header-y), \ + $(if $(wildcard $(srcdir)/$(hdr)),, \ + $(if $(wildcard $(oldsrcdir)/$(hdr)), \ + $(wildcard $(oldsrcdir)/$(hdr)), \ + $(error Missing UAPI file $(srcdir)/$(hdr))) \ + )) +input-files2-name := $(notdir $(input-files2)) +input-files3 := $(foreach hdr, $(genhdr-y), \ + $(if $(wildcard $(gendir)/$(hdr)), \ + $(wildcard $(gendir)/$(hdr)), \ + $(error Missing generated UAPI file $(gendir)/$(hdr)) \ + )) +input-files3-name := $(notdir $(input-files3)) # Work out what needs to be removed -oldheaders := $(patsubst $(install)/%,%,$(wildcard $(install)/*.h)) +oldheaders := $(patsubst $(installdir)/%,%,$(wildcard $(installdir)/*.h)) unwanted := $(filter-out $(all-files),$(oldheaders)) # Prefix unwanted with full paths to $(INSTALL_HDR_PATH) -unwanted-file := $(addprefix $(install)/, $(unwanted)) +unwanted-file := $(addprefix $(installdir)/, $(unwanted)) printdir = $(patsubst $(INSTALL_HDR_PATH)/%/,%,$(dir $@)) quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\ file$(if $(word 2, $(all-files)),s)) cmd_install = \ - $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \ - $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \ - $(PERL) $< $(objtree)/$(gen) $(install) $(SRCARCH) $(genhdr-y); \ + $(CONFIG_SHELL) $< $(installdir) $(srcdir) $(input-files1-name); \ + $(CONFIG_SHELL) $< $(installdir) $(oldsrcdir) $(input-files2-name); \ + $(CONFIG_SHELL) $< $(installdir) $(gendir) $(input-files3-name); \ for F in $(wrapper-files); do \ - echo "\#include <asm-generic/$$F>" > $(install)/$$F; \ + echo "\#include <asm-generic/$$F>" > $(installdir)/$$F; \ done; \ touch $@ @@ -70,7 +93,7 @@ quiet_cmd_check = CHECK $(printdir) ($(words $(all-files)) files) # Headers list can be pretty long, xargs helps to avoid # the "Argument list too long" error. cmd_check = for f in $(all-files); do \ - echo "$(install)/$${f}"; done \ + echo "$(installdir)/$${f}"; done \ | xargs \ $(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH); \ touch $@ @@ -83,7 +106,7 @@ __headersinst: $(subdirs) $(install-file) @: targets += $(install-file) -$(install-file): scripts/headers_install.pl $(input-files) FORCE +$(install-file): scripts/headers_install.sh $(input-files1) $(input-files2) $(input-files3) FORCE $(if $(unwanted),$(call cmd,remove),) $(if $(wildcard $(dir $@)),,$(shell mkdir -p $(dir $@))) $(call if_changed,install) diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 1ac414fd503..66893643fd7 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -166,5 +166,4 @@ $(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE $(call if_changed,host-cshlib) targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ - $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) - + $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 00c368c6e99..260bf8acfce 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -27,7 +27,7 @@ lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) # --------------------------------------------------------------------------- # o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o # and add the directory to the list of dirs to descend into: $(subdir-y) -# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) +# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) # and add the directory to the list of dirs to descend into: $(subdir-m) # Determine modorder. @@ -46,7 +46,7 @@ obj-m := $(filter-out %/, $(obj-m)) subdir-ym := $(sort $(subdir-y) $(subdir-m)) -# if $(foo-objs) exists, foo.o is a composite object +# if $(foo-objs) exists, foo.o is a composite object multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m)))) multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m)))) multi-used := $(multi-used-y) $(multi-used-m) @@ -63,7 +63,7 @@ multi-objs := $(multi-objs-y) $(multi-objs-m) subdir-obj-y := $(filter %/built-in.o, $(obj-y)) # $(obj-dirs) is a list of directories that contain object files -obj-dirs := $(dir $(multi-objs) $(subdir-obj-y)) +obj-dirs := $(dir $(multi-objs) $(obj-y)) # Replace multi-part objects by their individual parts, look at local dir only real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y) @@ -91,7 +91,7 @@ obj-dirs := $(addprefix $(obj)/,$(obj-dirs)) # These flags are needed for modversions and compiling, so we define them here # already -# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will +# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will # end up in (or would, if it gets compiled in) # Note: Files that end up in two or more modules are compiled without the # KBUILD_MODNAME definition. The reason is that any made-up name would @@ -119,13 +119,6 @@ _c_flags += $(if $(patsubst n%,, \ $(CFLAGS_GCOV)) endif -ifdef CONFIG_SYMBOL_PREFIX -_sym_flags = -DSYMBOL_PREFIX=$(patsubst "%",%,$(CONFIG_SYMBOL_PREFIX)) -_cpp_flags += $(_sym_flags) -_a_flags += $(_sym_flags) -endif - - # If building the kernel in a separate objtree expand all occurrences # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). @@ -156,6 +149,12 @@ cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ ld_flags = $(LDFLAGS) $(ldflags-y) +dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \ + -I$(srctree)/arch/$(SRCARCH)/boot/dts \ + -I$(srctree)/arch/$(SRCARCH)/boot/dts/include \ + -I$(srctree)/drivers/of/testcase-data \ + -undef -D__DTS__ + # Finds the multi-part object the current object will be linked into modname-multi = $(sort $(foreach m,$(multi-used),\ $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=)))) @@ -213,7 +212,7 @@ $(obj)/%: $(src)/%_shipped # Commands useful for building a boot image # =========================================================================== -# +# # Use as following: # # target: source(s) FORCE @@ -227,7 +226,7 @@ $(obj)/%: $(src)/%_shipped quiet_cmd_ld = LD $@ cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \ - $(filter-out FORCE,$^) -o $@ + $(filter-out FORCE,$^) -o $@ # Objcopy # --------------------------------------------------------------------------- @@ -246,7 +245,7 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ # --------------------------------------------------------------------------- # Generate an assembly file to wrap the output of the device tree compiler -quiet_cmd_dt_S_dtb= DTB $@ +quiet_cmd_dt_S_dtb= DTB $@ cmd_dt_S_dtb= \ ( \ echo '\#include <asm-generic/vmlinux.lds.h>'; \ @@ -264,7 +263,28 @@ $(obj)/%.dtb.S: $(obj)/%.dtb $(call cmd,dt_S_dtb) quiet_cmd_dtc = DTC $@ -cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) -d $(depfile) $< +cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ + $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \ + -i $(dir $<) $(DTC_FLAGS) \ + -d $(depfile).dtc.tmp $(dtc-tmp) ; \ + cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) + +$(obj)/%.dtb: $(src)/%.dts FORCE + $(call if_changed_dep,dtc) + +dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) + +# Helper targets for Installing DTBs into the boot directory +quiet_cmd_dtb_install = INSTALL $< + cmd_dtb_install = cp $< $(2) + +_dtbinst_pre_: + $(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi + $(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi + $(Q)mkdir -p $(INSTALL_DTBS_PATH) + +%.dtb_dtbinst_: $(obj)/%.dtb _dtbinst_pre_ + $(call cmd,dtb_install,$(INSTALL_DTBS_PATH)) # Bzip2 # --------------------------------------------------------------------------- @@ -304,6 +324,35 @@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) +quiet_cmd_lz4 = LZ4 $@ +cmd_lz4 = (cat $(filter-out FORCE,$^) | \ + lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +# U-Boot mkimage +# --------------------------------------------------------------------------- + +MKIMAGE := $(srctree)/scripts/mkuboot.sh + +# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces +# the number of overrides in arch makefiles +UIMAGE_ARCH ?= $(SRCARCH) +UIMAGE_COMPRESSION ?= $(if $(2),$(2),none) +UIMAGE_OPTS-y ?= +UIMAGE_TYPE ?= kernel +UIMAGE_LOADADDR ?= arch_must_set_this +UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR) +UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)' +UIMAGE_IN ?= $< +UIMAGE_OUT ?= $@ + +quiet_cmd_uimage = UIMAGE $(UIMAGE_OUT) + cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \ + -C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \ + -T $(UIMAGE_TYPE) \ + -a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \ + -n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT) + # XZ # --------------------------------------------------------------------------- # Use xzkern to compress the kernel image and xzmisc to compress other things. @@ -331,7 +380,3 @@ quiet_cmd_xzmisc = XZMISC $@ cmd_xzmisc = (cat $(filter-out FORCE,$^) | \ xz --check=crc32 --lzma2=dict=1MiB) > $@ || \ (rm -f $@ ; false) - -# misc stuff -# --------------------------------------------------------------------------- -quote:=" diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index efa5d940e63..ecbb44797e2 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -9,15 +9,16 @@ include scripts/Kbuild.include # -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +__modules := $(sort $(shell grep -h '\.ko$$' /dev/null $(wildcard $(MODVERDIR)/*.mod))) modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) PHONY += $(modules) __modinst: $(modules) @: +# Don't stop modules_install if we can't sign external modules. quiet_cmd_modules_install = INSTALL $@ - cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) + cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) # Modules built outside the kernel source tree go into extra by default INSTALL_MOD_DIR ?= extra diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 08dce14f2dc..69f0a1417e9 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -60,16 +60,13 @@ kernelsymfile := $(objtree)/Module.symvers modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers # Step 1), find all modules listed in $(MODVERDIR)/ -__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +MODLISTCMD := find $(MODVERDIR) -name '*.mod' | xargs -r grep -h '\.ko$$' | sort -u +__modules := $(shell $(MODLISTCMD)) modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) # Stop after building .o files if NOFINAL is set. Makes compile tests quicker _modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules)) -ifneq ($(KBUILD_BUILDHOST),$(ARCH)) - cross_build := 1 -endif - # Step 2), invoke modpost # Includes step 3,4 modpost = scripts/mod/modpost \ @@ -80,15 +77,17 @@ modpost = scripts/mod/modpost \ $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ - $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ - $(if $(cross_build),-c) + $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) + +MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) +# We can go over command line length here, so be careful. quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules - cmd_modpost = $(modpost) -s + cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) $(MODPOST_OPT) -s -T - PHONY += __modpost __modpost: $(modules:.ko=.o) FORCE - $(call cmd,modpost) $(wildcard vmlinux) $(filter-out FORCE,$^) + $(call cmd,modpost) $(wildcard vmlinux) quiet_cmd_kernel-mod = MODPOST $@ cmd_kernel-mod = $(modpost) $@ diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign new file mode 100644 index 00000000000..abfda626dba --- /dev/null +++ b/scripts/Makefile.modsign @@ -0,0 +1,32 @@ +# ========================================================================== +# Signing modules +# ========================================================================== + +PHONY := __modsign +__modsign: + +include scripts/Kbuild.include + +__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) + +PHONY += $(modules) +__modsign: $(modules) + @: + +quiet_cmd_sign_ko = SIGN [M] $(2)/$(notdir $@) + cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@) + +# Modules built outside the kernel source tree go into extra by default +INSTALL_MOD_DIR ?= extra +ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D)) + +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/analyze_suspend.py b/scripts/analyze_suspend.py new file mode 100755 index 00000000000..4f2cc12dc7c --- /dev/null +++ b/scripts/analyze_suspend.py @@ -0,0 +1,1446 @@ +#!/usr/bin/python +# +# Tool for analyzing suspend/resume timing +# Copyright (c) 2013, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope 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., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# Authors: +# Todd Brandt <todd.e.brandt@linux.intel.com> +# +# Description: +# This tool is designed to assist kernel and OS developers in optimizing +# their linux stack's suspend/resume time. Using a kernel image built +# with a few extra options enabled, the tool will execute a suspend and +# will capture dmesg and ftrace data until resume is complete. This data +# is transformed into a device timeline and a callgraph to give a quick +# and detailed view of which devices and callbacks are taking the most +# time in suspend/resume. The output is a single html file which can be +# viewed in firefox or chrome. +# +# The following kernel build options are required: +# CONFIG_PM_DEBUG=y +# CONFIG_PM_SLEEP_DEBUG=y +# CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER=y +# CONFIG_FUNCTION_GRAPH_TRACER=y +# +# The following additional kernel parameters are required: +# (e.g. in file /etc/default/grub) +# GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." +# + +import sys +import time +import os +import string +import re +import array +import platform +import datetime +import struct + +# -- classes -- + +class SystemValues: + testdir = "." + tpath = "/sys/kernel/debug/tracing/" + mempath = "/dev/mem" + powerfile = "/sys/power/state" + suspendmode = "mem" + prefix = "test" + teststamp = "" + dmesgfile = "" + ftracefile = "" + htmlfile = "" + rtcwake = False + def setOutputFile(self): + if((self.htmlfile == "") and (self.dmesgfile != "")): + m = re.match(r"(?P<name>.*)_dmesg\.txt$", self.dmesgfile) + if(m): + self.htmlfile = m.group("name")+".html" + if((self.htmlfile == "") and (self.ftracefile != "")): + m = re.match(r"(?P<name>.*)_ftrace\.txt$", self.ftracefile) + if(m): + self.htmlfile = m.group("name")+".html" + if(self.htmlfile == ""): + self.htmlfile = "output.html" + def initTestOutput(self): + hostname = platform.node() + if(hostname != ""): + self.prefix = hostname + v = os.popen("cat /proc/version").read().strip() + kver = string.split(v)[2] + self.testdir = os.popen("date \"+suspend-%m%d%y-%H%M%S\"").read().strip() + self.teststamp = "# "+self.testdir+" "+self.prefix+" "+self.suspendmode+" "+kver + self.dmesgfile = self.testdir+"/"+self.prefix+"_"+self.suspendmode+"_dmesg.txt" + self.ftracefile = self.testdir+"/"+self.prefix+"_"+self.suspendmode+"_ftrace.txt" + self.htmlfile = self.testdir+"/"+self.prefix+"_"+self.suspendmode+".html" + os.mkdir(self.testdir) + +class Data: + altdevname = dict() + usedmesg = False + useftrace = False + notestrun = False + verbose = False + phases = [] + dmesg = {} # root data structure + start = 0.0 + end = 0.0 + stamp = {'time': "", 'host': "", 'mode': ""} + id = 0 + tSuspended = 0.0 + fwValid = False + fwSuspend = 0 + fwResume = 0 + def initialize(self): + self.dmesg = { # dmesg log data + 'suspend_general': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "#CCFFCC", 'order': 0}, + 'suspend_early': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "green", 'order': 1}, + 'suspend_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "#00FFFF", 'order': 2}, + 'suspend_cpu': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "blue", 'order': 3}, + 'resume_cpu': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "red", 'order': 4}, + 'resume_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "orange", 'order': 5}, + 'resume_early': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "yellow", 'order': 6}, + 'resume_general': {'list': dict(), 'start': -1.0, 'end': -1.0, + 'row': 0, 'color': "#FFFFCC", 'order': 7} + } + self.phases = self.sortedPhases() + def normalizeTime(self): + tSus = tRes = self.tSuspended + if self.fwValid: + tSus -= -self.fwSuspend / 1000000000.0 + tRes -= self.fwResume / 1000000000.0 + self.tSuspended = 0.0 + self.start -= tSus + self.end -= tRes + for phase in self.phases: + zero = tRes + if "suspend" in phase: + zero = tSus + p = self.dmesg[phase] + p['start'] -= zero + p['end'] -= zero + list = p['list'] + for name in list: + d = list[name] + d['start'] -= zero + d['end'] -= zero + if('ftrace' in d): + cg = d['ftrace'] + cg.start -= zero + cg.end -= zero + for line in cg.list: + line.time -= zero + if self.fwValid: + fws = -self.fwSuspend / 1000000000.0 + fwr = self.fwResume / 1000000000.0 + list = dict() + self.id += 1 + devid = "dc%d" % self.id + list["firmware-suspend"] = \ + {'start': fws, 'end': 0, 'pid': 0, 'par': "", + 'length': -fws, 'row': 0, 'id': devid }; + self.id += 1 + devid = "dc%d" % self.id + list["firmware-resume"] = \ + {'start': 0, 'end': fwr, 'pid': 0, 'par': "", + 'length': fwr, 'row': 0, 'id': devid }; + self.dmesg['BIOS'] = \ + {'list': list, 'start': fws, 'end': fwr, + 'row': 0, 'color': "purple", 'order': 4} + self.dmesg['resume_cpu']['order'] += 1 + self.dmesg['resume_noirq']['order'] += 1 + self.dmesg['resume_early']['order'] += 1 + self.dmesg['resume_general']['order'] += 1 + self.phases = self.sortedPhases() + def vprint(self, msg): + if(self.verbose): + print(msg) + def dmesgSortVal(self, phase): + return self.dmesg[phase]['order'] + def sortedPhases(self): + return sorted(self.dmesg, key=self.dmesgSortVal) + def sortedDevices(self, phase): + list = self.dmesg[phase]['list'] + slist = [] + tmp = dict() + for devname in list: + dev = list[devname] + tmp[dev['start']] = devname + for t in sorted(tmp): + slist.append(tmp[t]) + return slist + def fixupInitcalls(self, phase, end): + # if any calls never returned, clip them at system resume end + phaselist = self.dmesg[phase]['list'] + for devname in phaselist: + dev = phaselist[devname] + if(dev['end'] < 0): + dev['end'] = end + self.vprint("%s (%s): callback didn't return" % (devname, phase)) + def fixupInitcallsThatDidntReturn(self): + # if any calls never returned, clip them at system resume end + for phase in self.phases: + self.fixupInitcalls(phase, self.dmesg['resume_general']['end']) + if(phase == "resume_general"): + break + def newAction(self, phase, name, pid, parent, start, end): + self.id += 1 + devid = "dc%d" % self.id + list = self.dmesg[phase]['list'] + length = -1.0 + if(start >= 0 and end >= 0): + length = end - start + list[name] = {'start': start, 'end': end, 'pid': pid, 'par': parent, + 'length': length, 'row': 0, 'id': devid } + def deviceIDs(self, devlist, phase): + idlist = [] + for p in self.phases: + if(p[0] != phase[0]): + continue + list = data.dmesg[p]['list'] + for devname in list: + if devname in devlist: + idlist.append(list[devname]['id']) + return idlist + def deviceParentID(self, devname, phase): + pdev = "" + pdevid = "" + for p in self.phases: + if(p[0] != phase[0]): + continue + list = data.dmesg[p]['list'] + if devname in list: + pdev = list[devname]['par'] + for p in self.phases: + if(p[0] != phase[0]): + continue + list = data.dmesg[p]['list'] + if pdev in list: + return list[pdev]['id'] + return pdev + def deviceChildrenIDs(self, devname, phase): + devlist = [] + for p in self.phases: + if(p[0] != phase[0]): + continue + list = data.dmesg[p]['list'] + for child in list: + if(list[child]['par'] == devname): + devlist.append(child) + return self.deviceIDs(devlist, phase) + +class FTraceLine: + time = 0.0 + length = 0.0 + fcall = False + freturn = False + fevent = False + depth = 0 + name = "" + def __init__(self, t, m, d): + self.time = float(t) + # check to see if this is a trace event + em = re.match(r"^ *\/\* *(?P<msg>.*) \*\/ *$", m) + if(em): + self.name = em.group("msg") + self.fevent = True + return + # convert the duration to seconds + if(d): + self.length = float(d)/1000000 + # the indentation determines the depth + match = re.match(r"^(?P<d> *)(?P<o>.*)$", m) + if(not match): + return + self.depth = self.getDepth(match.group('d')) + m = match.group('o') + # function return + if(m[0] == '}'): + self.freturn = True + if(len(m) > 1): + # includes comment with function name + match = re.match(r"^} *\/\* *(?P<n>.*) *\*\/$", m) + if(match): + self.name = match.group('n') + # function call + else: + self.fcall = True + # function call with children + if(m[-1] == '{'): + match = re.match(r"^(?P<n>.*) *\(.*", m) + if(match): + self.name = match.group('n') + # function call with no children (leaf) + elif(m[-1] == ';'): + self.freturn = True + match = re.match(r"^(?P<n>.*) *\(.*", m) + if(match): + self.name = match.group('n') + # something else (possibly a trace marker) + else: + self.name = m + def getDepth(self, str): + return len(str)/2 + +class FTraceCallGraph: + start = -1.0 + end = -1.0 + list = [] + invalid = False + depth = 0 + def __init__(self): + self.start = -1.0 + self.end = -1.0 + self.list = [] + self.depth = 0 + def setDepth(self, line): + if(line.fcall and not line.freturn): + line.depth = self.depth + self.depth += 1 + elif(line.freturn and not line.fcall): + self.depth -= 1 + line.depth = self.depth + else: + line.depth = self.depth + def addLine(self, line, match): + if(not self.invalid): + self.setDepth(line) + if(line.depth == 0 and line.freturn): + self.end = line.time + self.list.append(line) + return True + if(self.invalid): + return False + if(len(self.list) >= 1000000 or self.depth < 0): + first = self.list[0] + self.list = [] + self.list.append(first) + self.invalid = True + id = "task %s cpu %s" % (match.group("pid"), match.group("cpu")) + window = "(%f - %f)" % (self.start, line.time) + data.vprint("Too much data for "+id+" "+window+", ignoring this callback") + return False + self.list.append(line) + if(self.start < 0): + self.start = line.time + return False + def sanityCheck(self): + stack = dict() + cnt = 0 + for l in self.list: + if(l.fcall and not l.freturn): + stack[l.depth] = l + cnt += 1 + elif(l.freturn and not l.fcall): + if(not stack[l.depth]): + return False + stack[l.depth].length = l.length + stack[l.depth] = 0 + l.length = 0 + cnt -= 1 + if(cnt == 0): + return True + return False + def debugPrint(self, filename): + if(filename == "stdout"): + print("[%f - %f]") % (self.start, self.end) + for l in self.list: + if(l.freturn and l.fcall): + print("%f (%02d): %s(); (%.3f us)" % (l.time, l.depth, l.name, l.length*1000000)) + elif(l.freturn): + print("%f (%02d): %s} (%.3f us)" % (l.time, l.depth, l.name, l.length*1000000)) + else: + print("%f (%02d): %s() { (%.3f us)" % (l.time, l.depth, l.name, l.length*1000000)) + print(" ") + else: + fp = open(filename, 'w') + print(filename) + for l in self.list: + if(l.freturn and l.fcall): + fp.write("%f (%02d): %s(); (%.3f us)\n" % (l.time, l.depth, l.name, l.length*1000000)) + elif(l.freturn): + fp.write("%f (%02d): %s} (%.3f us)\n" % (l.time, l.depth, l.name, l.length*1000000)) + else: + fp.write("%f (%02d): %s() { (%.3f us)\n" % (l.time, l.depth, l.name, l.length*1000000)) + fp.close() + +class Timeline: + html = {} + scaleH = 0.0 # height of the timescale row as a percent of the timeline height + rowH = 0.0 # height of each row in percent of the timeline height + row_height_pixels = 30 + maxrows = 0 + height = 0 + def __init__(self): + self.html = { + 'timeline': "", + 'legend': "", + 'scale': "" + } + def setRows(self, rows): + self.maxrows = int(rows) + self.scaleH = 100.0/float(self.maxrows) + self.height = self.maxrows*self.row_height_pixels + r = float(self.maxrows - 1) + if(r < 1.0): + r = 1.0 + self.rowH = (100.0 - self.scaleH)/r + +# -- global objects -- + +sysvals = SystemValues() +data = Data() + +# -- functions -- + +# Function: initFtrace +# Description: +# Configure ftrace to capture a function trace during suspend/resume +def initFtrace(): + global sysvals + + print("INITIALIZING FTRACE...") + # turn trace off + os.system("echo 0 > "+sysvals.tpath+"tracing_on") + # set the trace clock to global + os.system("echo global > "+sysvals.tpath+"trace_clock") + # set trace buffer to a huge value + os.system("echo nop > "+sysvals.tpath+"current_tracer") + os.system("echo 100000 > "+sysvals.tpath+"buffer_size_kb") + # clear the trace buffer + os.system("echo \"\" > "+sysvals.tpath+"trace") + # set trace type + os.system("echo function_graph > "+sysvals.tpath+"current_tracer") + os.system("echo \"\" > "+sysvals.tpath+"set_ftrace_filter") + # set trace format options + os.system("echo funcgraph-abstime > "+sysvals.tpath+"trace_options") + os.system("echo funcgraph-proc > "+sysvals.tpath+"trace_options") + # focus only on device suspend and resume + os.system("cat "+sysvals.tpath+"available_filter_functions | grep dpm_run_callback > "+sysvals.tpath+"set_graph_function") + +# Function: verifyFtrace +# Description: +# Check that ftrace is working on the system +def verifyFtrace(): + global sysvals + files = ["available_filter_functions", "buffer_size_kb", + "current_tracer", "set_ftrace_filter", + "trace", "trace_marker"] + for f in files: + if(os.path.exists(sysvals.tpath+f) == False): + return False + return True + +def parseStamp(line): + global data, sysvals + stampfmt = r"# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-"+\ + "(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})"+\ + " (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$" + m = re.match(stampfmt, line) + if(m): + dt = datetime.datetime(int(m.group("y"))+2000, int(m.group("m")), + int(m.group("d")), int(m.group("H")), int(m.group("M")), + int(m.group("S"))) + data.stamp['time'] = dt.strftime("%B %d %Y, %I:%M:%S %p") + data.stamp['host'] = m.group("host") + data.stamp['mode'] = m.group("mode") + data.stamp['kernel'] = m.group("kernel") + sysvals.suspendmode = data.stamp['mode'] + +# Function: analyzeTraceLog +# Description: +# Analyse an ftrace log output file generated from this app during +# the execution phase. Create an "ftrace" structure in memory for +# subsequent formatting in the html output file +def analyzeTraceLog(): + global sysvals, data + + # the ftrace data is tied to the dmesg data + if(not data.usedmesg): + return + + # read through the ftrace and parse the data + data.vprint("Analyzing the ftrace data...") + ftrace_line_fmt = r"^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)"+\ + " *(?P<proc>.*)-(?P<pid>[0-9]*) *\|"+\ + "[ +!]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)" + ftemp = dict() + inthepipe = False + tf = open(sysvals.ftracefile, 'r') + count = 0 + for line in tf: + count = count + 1 + # grab the time stamp if it's valid + if(count == 1): + parseStamp(line) + continue + # parse only valid lines + m = re.match(ftrace_line_fmt, line) + if(not m): + continue + m_time = m.group("time") + m_pid = m.group("pid") + m_msg = m.group("msg") + m_dur = m.group("dur") + if(m_time and m_pid and m_msg): + t = FTraceLine(m_time, m_msg, m_dur) + pid = int(m_pid) + else: + continue + # the line should be a call, return, or event + if(not t.fcall and not t.freturn and not t.fevent): + continue + # only parse the ftrace data during suspend/resume + if(not inthepipe): + # look for the suspend start marker + if(t.fevent): + if(t.name == "SUSPEND START"): + data.vprint("SUSPEND START %f %s:%d" % (t.time, sysvals.ftracefile, count)) + inthepipe = True + continue + else: + # look for the resume end marker + if(t.fevent): + if(t.name == "RESUME COMPLETE"): + data.vprint("RESUME COMPLETE %f %s:%d" % (t.time, sysvals.ftracefile, count)) + inthepipe = False + break + continue + # create a callgraph object for the data + if(pid not in ftemp): + ftemp[pid] = FTraceCallGraph() + # when the call is finished, see which device matches it + if(ftemp[pid].addLine(t, m)): + if(not ftemp[pid].sanityCheck()): + id = "task %s cpu %s" % (pid, m.group("cpu")) + data.vprint("Sanity check failed for "+id+", ignoring this callback") + continue + callstart = ftemp[pid].start + callend = ftemp[pid].end + for p in data.phases: + if(data.dmesg[p]['start'] <= callstart and callstart <= data.dmesg[p]['end']): + list = data.dmesg[p]['list'] + for devname in list: + dev = list[devname] + if(pid == dev['pid'] and callstart <= dev['start'] and callend >= dev['end']): + data.vprint("%15s [%f - %f] %s(%d)" % (p, callstart, callend, devname, pid)) + dev['ftrace'] = ftemp[pid] + break + ftemp[pid] = FTraceCallGraph() + tf.close() + +# Function: sortKernelLog +# Description: +# The dmesg output log sometimes comes with with lines that have +# timestamps out of order. This could cause issues since a call +# could accidentally end up in the wrong phase +def sortKernelLog(): + global sysvals, data + lf = open(sysvals.dmesgfile, 'r') + dmesglist = [] + count = 0 + for line in lf: + line = line.replace("\r\n", "") + if(count == 0): + parseStamp(line) + elif(count == 1): + m = re.match(r"# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$", line) + if(m): + data.fwSuspend = int(m.group("s")) + data.fwResume = int(m.group("r")) + if(data.fwSuspend > 0 or data.fwResume > 0): + data.fwValid = True + if(re.match(r".*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)", line)): + dmesglist.append(line) + count += 1 + lf.close() + last = "" + + # fix lines with the same time stamp and function with the call and return swapped + for line in dmesglist: + mc = re.match(r".*(\[ *)(?P<t>[0-9\.]*)(\]) calling (?P<f>.*)\+ @ .*, parent: .*", line) + mr = re.match(r".*(\[ *)(?P<t>[0-9\.]*)(\]) call (?P<f>.*)\+ returned .* after (?P<dt>.*) usecs", last) + if(mc and mr and (mc.group("t") == mr.group("t")) and (mc.group("f") == mr.group("f"))): + i = dmesglist.index(last) + j = dmesglist.index(line) + dmesglist[i] = line + dmesglist[j] = last + last = line + return dmesglist + +# Function: analyzeKernelLog +# Description: +# Analyse a dmesg log output file generated from this app during +# the execution phase. Create a set of device structures in memory +# for subsequent formatting in the html output file +def analyzeKernelLog(): + global sysvals, data + + print("PROCESSING DATA") + data.vprint("Analyzing the dmesg data...") + if(os.path.exists(sysvals.dmesgfile) == False): + print("ERROR: %s doesn't exist") % sysvals.dmesgfile + return False + + lf = sortKernelLog() + phase = "suspend_runtime" + + dm = { + 'suspend_general': r"PM: Syncing filesystems.*", + 'suspend_early': r"PM: suspend of devices complete after.*", + 'suspend_noirq': r"PM: late suspend of devices complete after.*", + 'suspend_cpu': r"PM: noirq suspend of devices complete after.*", + 'resume_cpu': r"ACPI: Low-level resume complete.*", + 'resume_noirq': r"ACPI: Waking up from system sleep state.*", + 'resume_early': r"PM: noirq resume of devices complete after.*", + 'resume_general': r"PM: early resume of devices complete after.*", + 'resume_complete': r".*Restarting tasks \.\.\..*", + } + if(sysvals.suspendmode == "standby"): + dm['resume_cpu'] = r"PM: Restoring platform NVS memory" + elif(sysvals.suspendmode == "disk"): + dm['suspend_early'] = r"PM: freeze of devices complete after.*" + dm['suspend_noirq'] = r"PM: late freeze of devices complete after.*" + dm['suspend_cpu'] = r"PM: noirq freeze of devices complete after.*" + dm['resume_cpu'] = r"PM: Restoring platform NVS memory" + dm['resume_early'] = r"PM: noirq restore of devices complete after.*" + dm['resume_general'] = r"PM: early restore of devices complete after.*" + + action_start = 0.0 + for line in lf: + # -- preprocessing -- + # parse each dmesg line into the time and message + m = re.match(r".*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)", line) + if(m): + ktime = float(m.group("ktime")) + msg = m.group("msg") + else: + print line + continue + + # -- phase changes -- + # suspend_general start + if(re.match(dm['suspend_general'], msg)): + phase = "suspend_general" + data.dmesg[phase]['start'] = ktime + data.start = ktime + # action start: syncing filesystems + action_start = ktime + # suspend_early start + elif(re.match(dm['suspend_early'], msg)): + data.dmesg["suspend_general"]['end'] = ktime + phase = "suspend_early" + data.dmesg[phase]['start'] = ktime + # suspend_noirq start + elif(re.match(dm['suspend_noirq'], msg)): + data.dmesg["suspend_early"]['end'] = ktime + phase = "suspend_noirq" + data.dmesg[phase]['start'] = ktime + # suspend_cpu start + elif(re.match(dm['suspend_cpu'], msg)): + data.dmesg["suspend_noirq"]['end'] = ktime + phase = "suspend_cpu" + data.dmesg[phase]['start'] = ktime + # resume_cpu start + elif(re.match(dm['resume_cpu'], msg)): + data.tSuspended = ktime + data.dmesg["suspend_cpu"]['end'] = ktime + phase = "resume_cpu" + data.dmesg[phase]['start'] = ktime + # resume_noirq start + elif(re.match(dm['resume_noirq'], msg)): + data.dmesg["resume_cpu"]['end'] = ktime + phase = "resume_noirq" + data.dmesg[phase]['start'] = ktime + # action end: ACPI resume + data.newAction("resume_cpu", "ACPI", -1, "", action_start, ktime) + # resume_early start + elif(re.match(dm['resume_early'], msg)): + data.dmesg["resume_noirq"]['end'] = ktime + phase = "resume_early" + data.dmesg[phase]['start'] = ktime + # resume_general start + elif(re.match(dm['resume_general'], msg)): + data.dmesg["resume_early"]['end'] = ktime + phase = "resume_general" + data.dmesg[phase]['start'] = ktime + # resume complete start + elif(re.match(dm['resume_complete'], msg)): + data.dmesg["resume_general"]['end'] = ktime + data.end = ktime + phase = "resume_runtime" + break + + # -- device callbacks -- + if(phase in data.phases): + # device init call + if(re.match(r"calling (?P<f>.*)\+ @ .*, parent: .*", msg)): + sm = re.match(r"calling (?P<f>.*)\+ @ (?P<n>.*), parent: (?P<p>.*)", msg); + f = sm.group("f") + n = sm.group("n") + p = sm.group("p") + if(f and n and p): + data.newAction(phase, f, int(n), p, ktime, -1) + # device init return + elif(re.match(r"call (?P<f>.*)\+ returned .* after (?P<t>.*) usecs", msg)): + sm = re.match(r"call (?P<f>.*)\+ returned .* after (?P<t>.*) usecs(?P<a>.*)", msg); + f = sm.group("f") + t = sm.group("t") + list = data.dmesg[phase]['list'] + if(f in list): + dev = list[f] + dev['length'] = int(t) + dev['end'] = ktime + data.vprint("%15s [%f - %f] %s(%d) %s" % + (phase, dev['start'], dev['end'], f, dev['pid'], dev['par'])) + + # -- phase specific actions -- + if(phase == "suspend_general"): + if(re.match(r"PM: Preparing system for mem sleep.*", msg)): + data.newAction(phase, "filesystem-sync", -1, "", action_start, ktime) + elif(re.match(r"Freezing user space processes .*", msg)): + action_start = ktime + elif(re.match(r"Freezing remaining freezable tasks.*", msg)): + data.newAction(phase, "freeze-user-processes", -1, "", action_start, ktime) + action_start = ktime + elif(re.match(r"PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*", msg)): + data.newAction(phase, "freeze-tasks", -1, "", action_start, ktime) + elif(phase == "suspend_cpu"): + m = re.match(r"smpboot: CPU (?P<cpu>[0-9]*) is now offline", msg) + if(m): + cpu = "CPU"+m.group("cpu") + data.newAction(phase, cpu, -1, "", action_start, ktime) + action_start = ktime + elif(re.match(r"ACPI: Preparing to enter system sleep state.*", msg)): + action_start = ktime + elif(re.match(r"Disabling non-boot CPUs .*", msg)): + data.newAction(phase, "ACPI", -1, "", action_start, ktime) + action_start = ktime + elif(phase == "resume_cpu"): + m = re.match(r"CPU(?P<cpu>[0-9]*) is up", msg) + if(m): + cpu = "CPU"+m.group("cpu") + data.newAction(phase, cpu, -1, "", action_start, ktime) + action_start = ktime + elif(re.match(r"Enabling non-boot CPUs .*", msg)): + action_start = ktime + + # fill in any missing phases + lp = "suspend_general" + for p in data.phases: + if(p == "suspend_general"): + continue + if(data.dmesg[p]['start'] < 0): + data.dmesg[p]['start'] = data.dmesg[lp]['end'] + if(p == "resume_cpu"): + data.tSuspended = data.dmesg[lp]['end'] + if(data.dmesg[p]['end'] < 0): + data.dmesg[p]['end'] = data.dmesg[p]['start'] + lp = p + + data.fixupInitcallsThatDidntReturn() + return True + +# Function: setTimelineRows +# Description: +# Organize the device or thread lists into the smallest +# number of rows possible, with no entry overlapping +# Arguments: +# list: the list to sort (dmesg or ftrace) +# sortedkeys: sorted key list to use +def setTimelineRows(list, sortedkeys): + global data + + # clear all rows and set them to undefined + remaining = len(list) + rowdata = dict() + row = 0 + for item in list: + list[item]['row'] = -1 + + # try to pack each row with as many ranges as possible + while(remaining > 0): + if(row not in rowdata): + rowdata[row] = [] + for item in sortedkeys: + if(list[item]['row'] < 0): + s = list[item]['start'] + e = list[item]['end'] + valid = True + for ritem in rowdata[row]: + rs = ritem['start'] + re = ritem['end'] + if(not (((s <= rs) and (e <= rs)) or ((s >= re) and (e >= re)))): + valid = False + break + if(valid): + rowdata[row].append(list[item]) + list[item]['row'] = row + remaining -= 1 + row += 1 + return row + +# Function: createTimeScale +# Description: +# Create timescale lines for the dmesg and ftrace timelines +# Arguments: +# t0: start time (suspend begin) +# tMax: end time (resume end) +# tSuspend: time when suspend occurs +def createTimeScale(t0, tMax, tSuspended): + global data + timescale = "<div class=\"t\" style=\"right:{0}%\">{1}</div>\n" + output = '<div id="timescale">\n' + + # set scale for timeline + tTotal = tMax - t0 + tS = 0.1 + if(tTotal <= 0): + return output + if(tTotal > 4): + tS = 1 + if(tSuspended < 0): + for i in range(int(tTotal/tS)+1): + pos = "%0.3f" % (100 - ((float(i)*tS*100)/tTotal)) + if(i > 0): + val = "%0.f" % (float(i)*tS*1000) + else: + val = "" + output += timescale.format(pos, val) + else: + tSuspend = tSuspended - t0 + divTotal = int(tTotal/tS) + 1 + divSuspend = int(tSuspend/tS) + s0 = (tSuspend - tS*divSuspend)*100/tTotal + for i in range(divTotal): + pos = "%0.3f" % (100 - ((float(i)*tS*100)/tTotal) - s0) + if((i == 0) and (s0 < 3)): + val = "" + elif(i == divSuspend): + val = "S/R" + else: + val = "%0.f" % (float(i-divSuspend)*tS*1000) + output += timescale.format(pos, val) + output += '</div>\n' + return output + +# Function: createHTML +# Description: +# Create the output html file. +def createHTML(): + global sysvals, data + + data.normalizeTime() + + # html function templates + headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' + html_zoombox = '<center><button id="zoomin">ZOOM IN</button><button id="zoomout">ZOOM OUT</button><button id="zoomdef">ZOOM 1:1</button></center>\n<div id="dmesgzoombox" class="zoombox">\n' + html_timeline = '<div id="{0}" class="timeline" style="height:{1}px">\n' + html_device = '<div id="{0}" title="{1}" class="thread" style="left:{2}%;top:{3}%;height:{4}%;width:{5}%;">{6}</div>\n' + html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}%;height:{3}%;background-color:{4}">{5}</div>\n' + html_legend = '<div class="square" style="left:{0}%;background-color:{1}"> {2}</div>\n' + html_timetotal = '<table class="time1">\n<tr>'\ + '<td class="gray">{2} Suspend Time: <b>{0} ms</b></td>'\ + '<td class="gray">{2} Resume Time: <b>{1} ms</b></td>'\ + '</tr>\n</table>\n' + html_timegroups = '<table class="time2">\n<tr>'\ + '<td class="green">Kernel Suspend: {0} ms</td>'\ + '<td class="purple">Firmware Suspend: {1} ms</td>'\ + '<td class="purple">Firmware Resume: {2} ms</td>'\ + '<td class="yellow">Kernel Resume: {3} ms</td>'\ + '</tr>\n</table>\n' + + # device timeline (dmesg) + if(data.usedmesg): + data.vprint("Creating Device Timeline...") + devtl = Timeline() + + # Generate the header for this timeline + t0 = data.start + tMax = data.end + tTotal = tMax - t0 + if(tTotal == 0): + print("ERROR: No timeline data") + sys.exit() + suspend_time = "%.0f"%(-data.start*1000) + resume_time = "%.0f"%(data.end*1000) + if data.fwValid: + devtl.html['timeline'] = html_timetotal.format(suspend_time, resume_time, "Total") + sktime = "%.3f"%((data.dmesg['suspend_cpu']['end'] - data.dmesg['suspend_general']['start'])*1000) + sftime = "%.3f"%(data.fwSuspend / 1000000.0) + rftime = "%.3f"%(data.fwResume / 1000000.0) + rktime = "%.3f"%((data.dmesg['resume_general']['end'] - data.dmesg['resume_cpu']['start'])*1000) + devtl.html['timeline'] += html_timegroups.format(sktime, sftime, rftime, rktime) + else: + devtl.html['timeline'] = html_timetotal.format(suspend_time, resume_time, "Kernel") + + # determine the maximum number of rows we need to draw + timelinerows = 0 + for phase in data.dmesg: + list = data.dmesg[phase]['list'] + rows = setTimelineRows(list, list) + data.dmesg[phase]['row'] = rows + if(rows > timelinerows): + timelinerows = rows + + # calculate the timeline height and create its bounding box + devtl.setRows(timelinerows + 1) + devtl.html['timeline'] += html_zoombox; + devtl.html['timeline'] += html_timeline.format("dmesg", devtl.height); + + # draw the colored boxes for each of the phases + for b in data.dmesg: + phase = data.dmesg[b] + left = "%.3f" % (((phase['start']-data.start)*100)/tTotal) + width = "%.3f" % (((phase['end']-phase['start'])*100)/tTotal) + devtl.html['timeline'] += html_phase.format(left, width, "%.3f"%devtl.scaleH, "%.3f"%(100-devtl.scaleH), data.dmesg[b]['color'], "") + + # draw the time scale, try to make the number of labels readable + devtl.html['scale'] = createTimeScale(t0, tMax, data.tSuspended) + devtl.html['timeline'] += devtl.html['scale'] + for b in data.dmesg: + phaselist = data.dmesg[b]['list'] + for d in phaselist: + name = d + if(d in data.altdevname): + name = data.altdevname[d] + dev = phaselist[d] + height = (100.0 - devtl.scaleH)/data.dmesg[b]['row'] + top = "%.3f" % ((dev['row']*height) + devtl.scaleH) + left = "%.3f" % (((dev['start']-data.start)*100)/tTotal) + width = "%.3f" % (((dev['end']-dev['start'])*100)/tTotal) + len = " (%0.3f ms) " % ((dev['end']-dev['start'])*1000) + color = "rgba(204,204,204,0.5)" + devtl.html['timeline'] += html_device.format(dev['id'], name+len+b, left, top, "%.3f"%height, width, name) + + # timeline is finished + devtl.html['timeline'] += "</div>\n</div>\n" + + # draw a legend which describes the phases by color + devtl.html['legend'] = "<div class=\"legend\">\n" + pdelta = 100.0/data.phases.__len__() + pmargin = pdelta / 4.0 + for phase in data.phases: + order = "%.2f" % ((data.dmesg[phase]['order'] * pdelta) + pmargin) + name = string.replace(phase, "_", " ") + devtl.html['legend'] += html_legend.format(order, data.dmesg[phase]['color'], name) + devtl.html['legend'] += "</div>\n" + + hf = open(sysvals.htmlfile, 'w') + thread_height = 0 + + # write the html header first (html head, css code, everything up to the start of body) + html_header = "<!DOCTYPE html>\n<html>\n<head>\n\ + <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n\ + <title>AnalyzeSuspend</title>\n\ + <style type='text/css'>\n\ + body {overflow-y: scroll;}\n\ + .stamp {width: 100%;text-align:center;background-color:gray;line-height:30px;color:white;font: 25px Arial;}\n\ + .callgraph {margin-top: 30px;box-shadow: 5px 5px 20px black;}\n\ + .callgraph article * {padding-left: 28px;}\n\ + h1 {color:black;font: bold 30px Times;}\n\ + table {width:100%;}\n\ + .gray {background-color:rgba(80,80,80,0.1);}\n\ + .green {background-color:rgba(204,255,204,0.4);}\n\ + .purple {background-color:rgba(128,0,128,0.2);}\n\ + .yellow {background-color:rgba(255,255,204,0.4);}\n\ + .time1 {font: 22px Arial;border:1px solid;}\n\ + .time2 {font: 15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ + td {text-align: center;}\n\ + .tdhl {color: red;}\n\ + .hide {display: none;}\n\ + .pf {display: none;}\n\ + .pf:checked + label {background: url(\'data:image/svg+xml;utf,<?xml version=\"1.0\" standalone=\"no\"?><svg xmlns=\"http://www.w3.org/2000/svg\" height=\"18\" width=\"18\" version=\"1.1\"><circle cx=\"9\" cy=\"9\" r=\"8\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/><rect x=\"4\" y=\"8\" width=\"10\" height=\"2\" style=\"fill:black;stroke-width:0\"/><rect x=\"8\" y=\"4\" width=\"2\" height=\"10\" style=\"fill:black;stroke-width:0\"/></svg>\') no-repeat left center;}\n\ + .pf:not(:checked) ~ label {background: url(\'data:image/svg+xml;utf,<?xml version=\"1.0\" standalone=\"no\"?><svg xmlns=\"http://www.w3.org/2000/svg\" height=\"18\" width=\"18\" version=\"1.1\"><circle cx=\"9\" cy=\"9\" r=\"8\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/><rect x=\"4\" y=\"8\" width=\"10\" height=\"2\" style=\"fill:black;stroke-width:0\"/></svg>\') no-repeat left center;}\n\ + .pf:checked ~ *:not(:nth-child(2)) {display: none;}\n\ + .zoombox {position: relative; width: 100%; overflow-x: scroll;}\n\ + .timeline {position: relative; font-size: 14px;cursor: pointer;width: 100%; overflow: hidden; background-color:#dddddd;}\n\ + .thread {position: absolute; height: "+"%.3f"%thread_height+"%; overflow: hidden; line-height: 30px; border:1px solid;text-align:center;white-space:nowrap;background-color:rgba(204,204,204,0.5);}\n\ + .thread:hover {background-color:white;border:1px solid red;z-index:10;}\n\ + .phase {position: absolute;overflow: hidden;border:0px;text-align:center;}\n\ + .t {position: absolute; top: 0%; height: 100%; border-right:1px solid black;}\n\ + .legend {position: relative; width: 100%; height: 40px; text-align: center;margin-bottom:20px}\n\ + .legend .square {position:absolute;top:10px; width: 0px;height: 20px;border:1px solid;padding-left:20px;}\n\ + button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ + </style>\n</head>\n<body>\n" + hf.write(html_header) + + # write the test title and general info header + if(data.stamp['time'] != ""): + hf.write(headline_stamp.format(data.stamp['host'], + data.stamp['kernel'], data.stamp['mode'], data.stamp['time'])) + + # write the dmesg data (device timeline) + if(data.usedmesg): + hf.write(devtl.html['timeline']) + hf.write(devtl.html['legend']) + hf.write('<div id="devicedetail"></div>\n') + hf.write('<div id="devicetree"></div>\n') + + # write the ftrace data (callgraph) + if(data.useftrace): + hf.write('<section id="callgraphs" class="callgraph">\n') + # write out the ftrace data converted to html + html_func_top = '<article id="{0}" class="atop" style="background-color:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' + html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' + html_func_end = '</article>\n' + html_func_leaf = '<article>{0} {1}</article>\n' + num = 0 + for p in data.phases: + list = data.dmesg[p]['list'] + for devname in data.sortedDevices(p): + if('ftrace' not in list[devname]): + continue + name = devname + if(devname in data.altdevname): + name = data.altdevname[devname] + devid = list[devname]['id'] + cg = list[devname]['ftrace'] + flen = "(%.3f ms)" % ((cg.end - cg.start)*1000) + hf.write(html_func_top.format(devid, data.dmesg[p]['color'], num, name+" "+p, flen)) + num += 1 + for line in cg.list: + if(line.length < 0.000000001): + flen = "" + else: + flen = "(%.3f ms)" % (line.length*1000) + if(line.freturn and line.fcall): + hf.write(html_func_leaf.format(line.name, flen)) + elif(line.freturn): + hf.write(html_func_end) + else: + hf.write(html_func_start.format(num, line.name, flen)) + num += 1 + hf.write(html_func_end) + hf.write("\n\n </section>\n") + # write the footer and close + addScriptCode(hf) + hf.write("</body>\n</html>\n") + hf.close() + return True + +def addScriptCode(hf): + global data + + t0 = (data.start - data.tSuspended) * 1000 + tMax = (data.end - data.tSuspended) * 1000 + # create an array in javascript memory with the device details + detail = ' var bounds = [%f,%f];\n' % (t0, tMax) + detail += ' var d = [];\n' + dfmt = ' d["%s"] = { n:"%s", p:"%s", c:[%s] };\n'; + for p in data.dmesg: + list = data.dmesg[p]['list'] + for d in list: + parent = data.deviceParentID(d, p) + idlist = data.deviceChildrenIDs(d, p) + idstr = "" + for i in idlist: + if(idstr == ""): + idstr += '"'+i+'"' + else: + idstr += ', '+'"'+i+'"' + detail += dfmt % (list[d]['id'], d, parent, idstr) + + # add the code which will manipulate the data in the browser + script_code = \ + '<script type="text/javascript">\n'+detail+\ + ' var filter = [];\n'\ + ' var table = [];\n'\ + ' function deviceParent(devid) {\n'\ + ' var devlist = [];\n'\ + ' if(filter.indexOf(devid) < 0) filter[filter.length] = devid;\n'\ + ' if(d[devid].p in d)\n'\ + ' devlist = deviceParent(d[devid].p);\n'\ + ' else if(d[devid].p != "")\n'\ + ' devlist = [d[devid].p];\n'\ + ' devlist[devlist.length] = d[devid].n;\n'\ + ' return devlist;\n'\ + ' }\n'\ + ' function deviceChildren(devid, column, row) {\n'\ + ' if(!(devid in d)) return;\n'\ + ' if(filter.indexOf(devid) < 0) filter[filter.length] = devid;\n'\ + ' var cell = {name: d[devid].n, span: 1};\n'\ + ' var span = 0;\n'\ + ' if(column >= table.length) table[column] = [];\n'\ + ' table[column][row] = cell;\n'\ + ' for(var i = 0; i < d[devid].c.length; i++) {\n'\ + ' var cid = d[devid].c[i];\n'\ + ' span += deviceChildren(cid, column+1, row+span);\n'\ + ' }\n'\ + ' if(span == 0) span = 1;\n'\ + ' table[column][row].span = span;\n'\ + ' return span;\n'\ + ' }\n'\ + ' function deviceTree(devid, resume) {\n'\ + ' var html = "<table border=1>";\n'\ + ' filter = [];\n'\ + ' table = [];\n'\ + ' plist = deviceParent(devid);\n'\ + ' var devidx = plist.length - 1;\n'\ + ' for(var i = 0; i < devidx; i++)\n'\ + ' table[i] = [{name: plist[i], span: 1}];\n'\ + ' deviceChildren(devid, devidx, 0);\n'\ + ' for(var i = 0; i < devidx; i++)\n'\ + ' table[i][0].span = table[devidx][0].span;\n'\ + ' for(var row = 0; row < table[0][0].span; row++) {\n'\ + ' html += "<tr>";\n'\ + ' for(var col = 0; col < table.length; col++)\n'\ + ' if(row in table[col]) {\n'\ + ' var cell = table[col][row];\n'\ + ' var args = "";\n'\ + ' if(cell.span > 1)\n'\ + ' args += " rowspan="+cell.span;\n'\ + ' if((col == devidx) && (row == 0))\n'\ + ' args += " class=tdhl";\n'\ + ' if(resume)\n'\ + ' html += "<td"+args+">"+cell.name+" →</td>";\n'\ + ' else\n'\ + ' html += "<td"+args+">← "+cell.name+"</td>";\n'\ + ' }\n'\ + ' html += "</tr>";\n'\ + ' }\n'\ + ' html += "</table>";\n'\ + ' return html;\n'\ + ' }\n'\ + ' function zoomTimeline() {\n'\ + ' var timescale = document.getElementById("timescale");\n'\ + ' var dmesg = document.getElementById("dmesg");\n'\ + ' var zoombox = document.getElementById("dmesgzoombox");\n'\ + ' var val = parseFloat(dmesg.style.width);\n'\ + ' var newval = 100;\n'\ + ' var sh = window.outerWidth / 2;\n'\ + ' if(this.id == "zoomin") {\n'\ + ' newval = val * 1.2;\n'\ + ' if(newval > 40000) newval = 40000;\n'\ + ' dmesg.style.width = newval+"%";\n'\ + ' zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\ + ' } else if (this.id == "zoomout") {\n'\ + ' newval = val / 1.2;\n'\ + ' if(newval < 100) newval = 100;\n'\ + ' dmesg.style.width = newval+"%";\n'\ + ' zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\ + ' } else {\n'\ + ' zoombox.scrollLeft = 0;\n'\ + ' dmesg.style.width = "100%";\n'\ + ' }\n'\ + ' var html = "";\n'\ + ' var t0 = bounds[0];\n'\ + ' var tMax = bounds[1];\n'\ + ' var tTotal = tMax - t0;\n'\ + ' var wTotal = tTotal * 100.0 / newval;\n'\ + ' for(var tS = 1000; (wTotal / tS) < 3; tS /= 10);\n'\ + ' if(tS < 1) tS = 1;\n'\ + ' for(var s = ((t0 / tS)|0) * tS; s < tMax; s += tS) {\n'\ + ' var pos = (tMax - s) * 100.0 / tTotal;\n'\ + ' var name = (s == 0)?"S/R":(s+"ms");\n'\ + ' html += \"<div class=\\\"t\\\" style=\\\"right:\"+pos+\"%\\\">\"+name+\"</div>\";\n'\ + ' }\n'\ + ' timescale.innerHTML = html;\n'\ + ' }\n'\ + ' function deviceDetail() {\n'\ + ' var devtitle = document.getElementById("devicedetail");\n'\ + ' devtitle.innerHTML = "<h1>"+this.title+"</h1>";\n'\ + ' var devtree = document.getElementById("devicetree");\n'\ + ' devtree.innerHTML = deviceTree(this.id, (this.title.indexOf("resume") >= 0));\n'\ + ' var cglist = document.getElementById("callgraphs");\n'\ + ' if(!cglist) return;\n'\ + ' var cg = cglist.getElementsByClassName("atop");\n'\ + ' for (var i = 0; i < cg.length; i++) {\n'\ + ' if(filter.indexOf(cg[i].id) >= 0) {\n'\ + ' cg[i].style.display = "block";\n'\ + ' } else {\n'\ + ' cg[i].style.display = "none";\n'\ + ' }\n'\ + ' }\n'\ + ' }\n'\ + ' window.addEventListener("load", function () {\n'\ + ' var dmesg = document.getElementById("dmesg");\n'\ + ' dmesg.style.width = "100%"\n'\ + ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ + ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ + ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ + ' var dev = dmesg.getElementsByClassName("thread");\n'\ + ' for (var i = 0; i < dev.length; i++) {\n'\ + ' dev[i].onclick = deviceDetail;\n'\ + ' }\n'\ + ' zoomTimeline();\n'\ + ' });\n'\ + '</script>\n' + hf.write(script_code); + +# Function: executeSuspend +# Description: +# Execute system suspend through the sysfs interface +def executeSuspend(): + global sysvals, data + + detectUSB() + pf = open(sysvals.powerfile, 'w') + # clear the kernel ring buffer just as we start + os.system("dmesg -C") + # start ftrace + if(data.useftrace): + print("START TRACING") + os.system("echo 1 > "+sysvals.tpath+"tracing_on") + os.system("echo SUSPEND START > "+sysvals.tpath+"trace_marker") + # initiate suspend + if(sysvals.rtcwake): + print("SUSPEND START") + os.system("rtcwake -s 10 -m "+sysvals.suspendmode) + else: + print("SUSPEND START (press a key to resume)") + pf.write(sysvals.suspendmode) + # execution will pause here + pf.close() + # return from suspend + print("RESUME COMPLETE") + # stop ftrace + if(data.useftrace): + os.system("echo RESUME COMPLETE > "+sysvals.tpath+"trace_marker") + os.system("echo 0 > "+sysvals.tpath+"tracing_on") + print("CAPTURING FTRACE") + os.system("echo \""+sysvals.teststamp+"\" > "+sysvals.ftracefile) + os.system("cat "+sysvals.tpath+"trace >> "+sysvals.ftracefile) + # grab a copy of the dmesg output + print("CAPTURING DMESG") + os.system("echo \""+sysvals.teststamp+"\" > "+sysvals.dmesgfile) + os.system("dmesg -c >> "+sysvals.dmesgfile) + +# Function: detectUSB +# Description: +# Detect all the USB hosts and devices currently connected +def detectUSB(): + global sysvals, data + + for dirname, dirnames, filenames in os.walk("/sys/devices"): + if(re.match(r".*/usb[0-9]*.*", dirname) and + "idVendor" in filenames and "idProduct" in filenames): + vid = os.popen("cat %s/idVendor 2>/dev/null" % dirname).read().replace('\n', '') + pid = os.popen("cat %s/idProduct 2>/dev/null" % dirname).read().replace('\n', '') + product = os.popen("cat %s/product 2>/dev/null" % dirname).read().replace('\n', '') + name = dirname.split('/')[-1] + if(len(product) > 0): + data.altdevname[name] = "%s [%s]" % (product, name) + else: + data.altdevname[name] = "%s:%s [%s]" % (vid, pid, name) + +def getModes(): + global sysvals + modes = "" + if(os.path.exists(sysvals.powerfile)): + fp = open(sysvals.powerfile, 'r') + modes = string.split(fp.read()) + fp.close() + return modes + +# Function: statusCheck +# Description: +# Verify that the requested command and options will work +def statusCheck(dryrun): + global sysvals, data + res = dict() + + if(data.notestrun): + print("SUCCESS: The command should run!") + return + + # check we have root access + check = "YES" + if(os.environ['USER'] != "root"): + if(not dryrun): + doError("root access is required", False) + check = "NO" + res[" have root access: "] = check + + # check sysfs is mounted + check = "YES" + if(not os.path.exists(sysvals.powerfile)): + if(not dryrun): + doError("sysfs must be mounted", False) + check = "NO" + res[" is sysfs mounted: "] = check + + # check target mode is a valid mode + check = "YES" + modes = getModes() + if(sysvals.suspendmode not in modes): + if(not dryrun): + doError("%s is not a value power mode" % sysvals.suspendmode, False) + check = "NO" + res[" is "+sysvals.suspendmode+" a power mode: "] = check + + # check if ftrace is available + if(data.useftrace): + check = "YES" + if(not verifyFtrace()): + if(not dryrun): + doError("ftrace is not configured", False) + check = "NO" + res[" is ftrace usable: "] = check + + # check if rtcwake + if(sysvals.rtcwake): + check = "YES" + version = os.popen("rtcwake -V 2>/dev/null").read() + if(not version.startswith("rtcwake")): + if(not dryrun): + doError("rtcwake is not installed", False) + check = "NO" + res[" is rtcwake usable: "] = check + + if(dryrun): + status = True + print("Checking if system can run the current command:") + for r in res: + print("%s\t%s" % (r, res[r])) + if(res[r] != "YES"): + status = False + if(status): + print("SUCCESS: The command should run!") + else: + print("FAILURE: The command won't run!") + +def printHelp(): + global sysvals + modes = getModes() + + print("") + print("AnalyzeSuspend") + print("Usage: sudo analyze_suspend.py <options>") + print("") + print("Description:") + print(" Initiates a system suspend/resume while capturing dmesg") + print(" and (optionally) ftrace data to analyze device timing") + print("") + print(" Generates output files in subdirectory: suspend-mmddyy-HHMMSS") + print(" HTML output: <hostname>_<mode>.html") + print(" raw dmesg output: <hostname>_<mode>_dmesg.txt") + print(" raw ftrace output (with -f): <hostname>_<mode>_ftrace.txt") + print("") + print("Options:") + print(" [general]") + print(" -h Print this help text") + print(" -verbose Print extra information during execution and analysis") + print(" -status Test to see if the system is enabled to run this tool") + print(" -modes List available suspend modes") + print(" -m mode Mode to initiate for suspend %s (default: %s)") % (modes, sysvals.suspendmode) + print(" -rtcwake Use rtcwake to autoresume after 10 seconds (default: disabled)") + print(" -f Use ftrace to create device callgraphs (default: disabled)") + print(" [re-analyze data from previous runs]") + print(" -dmesg dmesgfile Create HTML timeline from dmesg file") + print(" -ftrace ftracefile Create HTML callgraph from ftrace file") + print("") + return True + +def doError(msg, help): + print("ERROR: %s") % msg + if(help == True): + printHelp() + sys.exit() + +# -- script main -- +# loop through the command line arguments +cmd = "" +args = iter(sys.argv[1:]) +for arg in args: + if(arg == "-m"): + try: + val = args.next() + except: + doError("No mode supplied", True) + sysvals.suspendmode = val + elif(arg == "-f"): + data.useftrace = True + elif(arg == "-modes"): + cmd = "modes" + elif(arg == "-status"): + cmd = "status" + elif(arg == "-verbose"): + data.verbose = True + elif(arg == "-rtcwake"): + sysvals.rtcwake = True + elif(arg == "-dmesg"): + try: + val = args.next() + except: + doError("No dmesg file supplied", True) + data.notestrun = True + data.usedmesg = True + sysvals.dmesgfile = val + elif(arg == "-ftrace"): + try: + val = args.next() + except: + doError("No ftrace file supplied", True) + data.notestrun = True + data.useftrace = True + sysvals.ftracefile = val + elif(arg == "-h"): + printHelp() + sys.exit() + else: + doError("Invalid argument: "+arg, True) + +# just run a utility command and exit +if(cmd != ""): + if(cmd == "status"): + statusCheck(True) + elif(cmd == "modes"): + modes = getModes() + print modes + sys.exit() + +data.initialize() + +# if instructed, re-analyze existing data files +if(data.notestrun): + sysvals.setOutputFile() + data.vprint("Output file: %s" % sysvals.htmlfile) + if(sysvals.dmesgfile != ""): + analyzeKernelLog() + if(sysvals.ftracefile != ""): + analyzeTraceLog() + createHTML() + sys.exit() + +# verify that we can run a test +data.usedmesg = True +statusCheck(False) + +# prepare for the test +if(data.useftrace): + initFtrace() +sysvals.initTestOutput() + +data.vprint("Output files:\n %s" % sysvals.dmesgfile) +if(data.useftrace): + data.vprint(" %s" % sysvals.ftracefile) +data.vprint(" %s" % sysvals.htmlfile) + +# execute the test +executeSuspend() +analyzeKernelLog() +if(data.useftrace): + analyzeTraceLog() +createHTML() diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c new file mode 100644 index 00000000000..91c4117637a --- /dev/null +++ b/scripts/asn1_compiler.c @@ -0,0 +1,1547 @@ +/* Simplified ASN.1 notation parser + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <linux/asn1_ber_bytecode.h> + +enum token_type { + DIRECTIVE_ABSENT, + DIRECTIVE_ALL, + DIRECTIVE_ANY, + DIRECTIVE_APPLICATION, + DIRECTIVE_AUTOMATIC, + DIRECTIVE_BEGIN, + DIRECTIVE_BIT, + DIRECTIVE_BMPString, + DIRECTIVE_BOOLEAN, + DIRECTIVE_BY, + DIRECTIVE_CHARACTER, + DIRECTIVE_CHOICE, + DIRECTIVE_CLASS, + DIRECTIVE_COMPONENT, + DIRECTIVE_COMPONENTS, + DIRECTIVE_CONSTRAINED, + DIRECTIVE_CONTAINING, + DIRECTIVE_DEFAULT, + DIRECTIVE_DEFINED, + DIRECTIVE_DEFINITIONS, + DIRECTIVE_EMBEDDED, + DIRECTIVE_ENCODED, + DIRECTIVE_ENCODING_CONTROL, + DIRECTIVE_END, + DIRECTIVE_ENUMERATED, + DIRECTIVE_EXCEPT, + DIRECTIVE_EXPLICIT, + DIRECTIVE_EXPORTS, + DIRECTIVE_EXTENSIBILITY, + DIRECTIVE_EXTERNAL, + DIRECTIVE_FALSE, + DIRECTIVE_FROM, + DIRECTIVE_GeneralString, + DIRECTIVE_GeneralizedTime, + DIRECTIVE_GraphicString, + DIRECTIVE_IA5String, + DIRECTIVE_IDENTIFIER, + DIRECTIVE_IMPLICIT, + DIRECTIVE_IMPLIED, + DIRECTIVE_IMPORTS, + DIRECTIVE_INCLUDES, + DIRECTIVE_INSTANCE, + DIRECTIVE_INSTRUCTIONS, + DIRECTIVE_INTEGER, + DIRECTIVE_INTERSECTION, + DIRECTIVE_ISO646String, + DIRECTIVE_MAX, + DIRECTIVE_MIN, + DIRECTIVE_MINUS_INFINITY, + DIRECTIVE_NULL, + DIRECTIVE_NumericString, + DIRECTIVE_OBJECT, + DIRECTIVE_OCTET, + DIRECTIVE_OF, + DIRECTIVE_OPTIONAL, + DIRECTIVE_ObjectDescriptor, + DIRECTIVE_PATTERN, + DIRECTIVE_PDV, + DIRECTIVE_PLUS_INFINITY, + DIRECTIVE_PRESENT, + DIRECTIVE_PRIVATE, + DIRECTIVE_PrintableString, + DIRECTIVE_REAL, + DIRECTIVE_RELATIVE_OID, + DIRECTIVE_SEQUENCE, + DIRECTIVE_SET, + DIRECTIVE_SIZE, + DIRECTIVE_STRING, + DIRECTIVE_SYNTAX, + DIRECTIVE_T61String, + DIRECTIVE_TAGS, + DIRECTIVE_TRUE, + DIRECTIVE_TeletexString, + DIRECTIVE_UNION, + DIRECTIVE_UNIQUE, + DIRECTIVE_UNIVERSAL, + DIRECTIVE_UTCTime, + DIRECTIVE_UTF8String, + DIRECTIVE_UniversalString, + DIRECTIVE_VideotexString, + DIRECTIVE_VisibleString, + DIRECTIVE_WITH, + NR__DIRECTIVES, + TOKEN_ASSIGNMENT = NR__DIRECTIVES, + TOKEN_OPEN_CURLY, + TOKEN_CLOSE_CURLY, + TOKEN_OPEN_SQUARE, + TOKEN_CLOSE_SQUARE, + TOKEN_OPEN_ACTION, + TOKEN_CLOSE_ACTION, + TOKEN_COMMA, + TOKEN_NUMBER, + TOKEN_TYPE_NAME, + TOKEN_ELEMENT_NAME, + NR__TOKENS +}; + +static const unsigned char token_to_tag[NR__TOKENS] = { + /* EOC goes first */ + [DIRECTIVE_BOOLEAN] = ASN1_BOOL, + [DIRECTIVE_INTEGER] = ASN1_INT, + [DIRECTIVE_BIT] = ASN1_BTS, + [DIRECTIVE_OCTET] = ASN1_OTS, + [DIRECTIVE_NULL] = ASN1_NULL, + [DIRECTIVE_OBJECT] = ASN1_OID, + [DIRECTIVE_ObjectDescriptor] = ASN1_ODE, + [DIRECTIVE_EXTERNAL] = ASN1_EXT, + [DIRECTIVE_REAL] = ASN1_REAL, + [DIRECTIVE_ENUMERATED] = ASN1_ENUM, + [DIRECTIVE_EMBEDDED] = 0, + [DIRECTIVE_UTF8String] = ASN1_UTF8STR, + [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID, + /* 14 */ + /* 15 */ + [DIRECTIVE_SEQUENCE] = ASN1_SEQ, + [DIRECTIVE_SET] = ASN1_SET, + [DIRECTIVE_NumericString] = ASN1_NUMSTR, + [DIRECTIVE_PrintableString] = ASN1_PRNSTR, + [DIRECTIVE_T61String] = ASN1_TEXSTR, + [DIRECTIVE_TeletexString] = ASN1_TEXSTR, + [DIRECTIVE_VideotexString] = ASN1_VIDSTR, + [DIRECTIVE_IA5String] = ASN1_IA5STR, + [DIRECTIVE_UTCTime] = ASN1_UNITIM, + [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM, + [DIRECTIVE_GraphicString] = ASN1_GRASTR, + [DIRECTIVE_VisibleString] = ASN1_VISSTR, + [DIRECTIVE_GeneralString] = ASN1_GENSTR, + [DIRECTIVE_UniversalString] = ASN1_UNITIM, + [DIRECTIVE_CHARACTER] = ASN1_CHRSTR, + [DIRECTIVE_BMPString] = ASN1_BMPSTR, +}; + +static const char asn1_classes[4][5] = { + [ASN1_UNIV] = "UNIV", + [ASN1_APPL] = "APPL", + [ASN1_CONT] = "CONT", + [ASN1_PRIV] = "PRIV" +}; + +static const char asn1_methods[2][5] = { + [ASN1_UNIV] = "PRIM", + [ASN1_APPL] = "CONS" +}; + +static const char *const asn1_universal_tags[32] = { + "EOC", + "BOOL", + "INT", + "BTS", + "OTS", + "NULL", + "OID", + "ODE", + "EXT", + "REAL", + "ENUM", + "EPDV", + "UTF8STR", + "RELOID", + NULL, /* 14 */ + NULL, /* 15 */ + "SEQ", + "SET", + "NUMSTR", + "PRNSTR", + "TEXSTR", + "VIDSTR", + "IA5STR", + "UNITIM", + "GENTIM", + "GRASTR", + "VISSTR", + "GENSTR", + "UNISTR", + "CHRSTR", + "BMPSTR", + NULL /* 31 */ +}; + +static const char *filename; +static const char *grammar_name; +static const char *outputname; +static const char *headername; + +static const char *const directives[NR__DIRECTIVES] = { +#define _(X) [DIRECTIVE_##X] = #X + _(ABSENT), + _(ALL), + _(ANY), + _(APPLICATION), + _(AUTOMATIC), + _(BEGIN), + _(BIT), + _(BMPString), + _(BOOLEAN), + _(BY), + _(CHARACTER), + _(CHOICE), + _(CLASS), + _(COMPONENT), + _(COMPONENTS), + _(CONSTRAINED), + _(CONTAINING), + _(DEFAULT), + _(DEFINED), + _(DEFINITIONS), + _(EMBEDDED), + _(ENCODED), + [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL", + _(END), + _(ENUMERATED), + _(EXCEPT), + _(EXPLICIT), + _(EXPORTS), + _(EXTENSIBILITY), + _(EXTERNAL), + _(FALSE), + _(FROM), + _(GeneralString), + _(GeneralizedTime), + _(GraphicString), + _(IA5String), + _(IDENTIFIER), + _(IMPLICIT), + _(IMPLIED), + _(IMPORTS), + _(INCLUDES), + _(INSTANCE), + _(INSTRUCTIONS), + _(INTEGER), + _(INTERSECTION), + _(ISO646String), + _(MAX), + _(MIN), + [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY", + [DIRECTIVE_NULL] = "NULL", + _(NumericString), + _(OBJECT), + _(OCTET), + _(OF), + _(OPTIONAL), + _(ObjectDescriptor), + _(PATTERN), + _(PDV), + [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY", + _(PRESENT), + _(PRIVATE), + _(PrintableString), + _(REAL), + [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID", + _(SEQUENCE), + _(SET), + _(SIZE), + _(STRING), + _(SYNTAX), + _(T61String), + _(TAGS), + _(TRUE), + _(TeletexString), + _(UNION), + _(UNIQUE), + _(UNIVERSAL), + _(UTCTime), + _(UTF8String), + _(UniversalString), + _(VideotexString), + _(VisibleString), + _(WITH) +}; + +struct action { + struct action *next; + unsigned char index; + char name[]; +}; + +static struct action *action_list; +static unsigned nr_actions; + +struct token { + unsigned short line; + enum token_type token_type : 8; + unsigned char size; + struct action *action; + const char *value; + struct type *type; +}; + +static struct token *token_list; +static unsigned nr_tokens; + +static int directive_compare(const void *_key, const void *_pdir) +{ + const struct token *token = _key; + const char *const *pdir = _pdir, *dir = *pdir; + size_t dlen, clen; + int val; + + dlen = strlen(dir); + clen = (dlen < token->size) ? dlen : token->size; + + //printf("cmp(%*.*s,%s) = ", + // (int)token->size, (int)token->size, token->value, + // dir); + + val = memcmp(token->value, dir, clen); + if (val != 0) { + //printf("%d [cmp]\n", val); + return val; + } + + if (dlen == token->size) { + //printf("0\n"); + return 0; + } + //printf("%d\n", (int)dlen - (int)token->size); + return dlen - token->size; /* shorter -> negative */ +} + +/* + * Tokenise an ASN.1 grammar + */ +static void tokenise(char *buffer, char *end) +{ + struct token *tokens; + char *line, *nl, *p, *q; + unsigned tix, lineno; + + /* Assume we're going to have half as many tokens as we have + * characters + */ + token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); + if (!tokens) { + perror(NULL); + exit(1); + } + tix = 0; + + lineno = 0; + while (buffer < end) { + /* First of all, break out a line */ + lineno++; + line = buffer; + nl = memchr(line, '\n', end - buffer); + if (!nl) { + buffer = nl = end; + } else { + buffer = nl + 1; + *nl = '\0'; + } + + /* Remove "--" comments */ + p = line; + next_comment: + while ((p = memchr(p, '-', nl - p))) { + if (p[1] == '-') { + /* Found a comment; see if there's a terminator */ + q = p + 2; + while ((q = memchr(q, '-', nl - q))) { + if (q[1] == '-') { + /* There is - excise the comment */ + q += 2; + memmove(p, q, nl - q); + goto next_comment; + } + q++; + } + *p = '\0'; + nl = p; + break; + } else { + p++; + } + } + + p = line; + while (p < nl) { + /* Skip white space */ + while (p < nl && isspace(*p)) + *(p++) = 0; + if (p >= nl) + break; + + tokens[tix].line = lineno; + tokens[tix].value = p; + + /* Handle string tokens */ + if (isalpha(*p)) { + const char **dir; + + /* Can be a directive, type name or element + * name. Find the end of the name. + */ + q = p + 1; + while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) + q++; + tokens[tix].size = q - p; + p = q; + + /* If it begins with a lowercase letter then + * it's an element name + */ + if (islower(tokens[tix].value[0])) { + tokens[tix++].token_type = TOKEN_ELEMENT_NAME; + continue; + } + + /* Otherwise we need to search the directive + * table + */ + dir = bsearch(&tokens[tix], directives, + sizeof(directives) / sizeof(directives[1]), + sizeof(directives[1]), + directive_compare); + if (dir) { + tokens[tix++].token_type = dir - directives; + continue; + } + + tokens[tix++].token_type = TOKEN_TYPE_NAME; + continue; + } + + /* Handle numbers */ + if (isdigit(*p)) { + /* Find the end of the number */ + q = p + 1; + while (q < nl && (isdigit(*q))) + q++; + tokens[tix].size = q - p; + p = q; + tokens[tix++].token_type = TOKEN_NUMBER; + continue; + } + + if (nl - p >= 3) { + if (memcmp(p, "::=", 3) == 0) { + p += 3; + tokens[tix].size = 3; + tokens[tix++].token_type = TOKEN_ASSIGNMENT; + continue; + } + } + + if (nl - p >= 2) { + if (memcmp(p, "({", 2) == 0) { + p += 2; + tokens[tix].size = 2; + tokens[tix++].token_type = TOKEN_OPEN_ACTION; + continue; + } + if (memcmp(p, "})", 2) == 0) { + p += 2; + tokens[tix].size = 2; + tokens[tix++].token_type = TOKEN_CLOSE_ACTION; + continue; + } + } + + if (nl - p >= 1) { + tokens[tix].size = 1; + switch (*p) { + case '{': + p += 1; + tokens[tix++].token_type = TOKEN_OPEN_CURLY; + continue; + case '}': + p += 1; + tokens[tix++].token_type = TOKEN_CLOSE_CURLY; + continue; + case '[': + p += 1; + tokens[tix++].token_type = TOKEN_OPEN_SQUARE; + continue; + case ']': + p += 1; + tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; + continue; + case ',': + p += 1; + tokens[tix++].token_type = TOKEN_COMMA; + continue; + default: + break; + } + } + + fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", + filename, lineno, *p); + exit(1); + } + } + + nr_tokens = tix; + printf("Extracted %u tokens\n", nr_tokens); + +#if 0 + { + int n; + for (n = 0; n < nr_tokens; n++) + printf("Token %3u: '%*.*s'\n", + n, + (int)token_list[n].size, (int)token_list[n].size, + token_list[n].value); + } +#endif +} + +static void build_type_list(void); +static void parse(void); +static void render(FILE *out, FILE *hdr); + +/* + * + */ +int main(int argc, char **argv) +{ + struct stat st; + ssize_t readlen; + FILE *out, *hdr; + char *buffer, *p; + int fd; + + if (argc != 4) { + fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", + argv[0]); + exit(2); + } + + filename = argv[1]; + outputname = argv[2]; + headername = argv[3]; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + + if (fstat(fd, &st) < 0) { + perror(filename); + exit(1); + } + + if (!(buffer = malloc(st.st_size + 1))) { + perror(NULL); + exit(1); + } + + if ((readlen = read(fd, buffer, st.st_size)) < 0) { + perror(filename); + exit(1); + } + + if (close(fd) < 0) { + perror(filename); + exit(1); + } + + if (readlen != st.st_size) { + fprintf(stderr, "%s: Short read\n", filename); + exit(1); + } + + p = strrchr(argv[1], '/'); + p = p ? p + 1 : argv[1]; + grammar_name = strdup(p); + if (!p) { + perror(NULL); + exit(1); + } + p = strchr(grammar_name, '.'); + if (p) + *p = '\0'; + + buffer[readlen] = 0; + tokenise(buffer, buffer + readlen); + build_type_list(); + parse(); + + out = fopen(outputname, "w"); + if (!out) { + perror(outputname); + exit(1); + } + + hdr = fopen(headername, "w"); + if (!out) { + perror(headername); + exit(1); + } + + render(out, hdr); + + if (fclose(out) < 0) { + perror(outputname); + exit(1); + } + + if (fclose(hdr) < 0) { + perror(headername); + exit(1); + } + + return 0; +} + +enum compound { + NOT_COMPOUND, + SET, + SET_OF, + SEQUENCE, + SEQUENCE_OF, + CHOICE, + ANY, + TYPE_REF, + TAG_OVERRIDE +}; + +struct element { + struct type *type_def; + struct token *name; + struct token *type; + struct action *action; + struct element *children; + struct element *next; + struct element *render_next; + struct element *list_next; + uint8_t n_elements; + enum compound compound : 8; + enum asn1_class class : 8; + enum asn1_method method : 8; + uint8_t tag; + unsigned entry_index; + unsigned flags; +#define ELEMENT_IMPLICIT 0x0001 +#define ELEMENT_EXPLICIT 0x0002 +#define ELEMENT_MARKED 0x0004 +#define ELEMENT_RENDERED 0x0008 +#define ELEMENT_SKIPPABLE 0x0010 +#define ELEMENT_CONDITIONAL 0x0020 +}; + +struct type { + struct token *name; + struct token *def; + struct element *element; + unsigned ref_count; + unsigned flags; +#define TYPE_STOP_MARKER 0x0001 +#define TYPE_BEGIN 0x0002 +}; + +static struct type *type_list; +static struct type **type_index; +static unsigned nr_types; + +static int type_index_compare(const void *_a, const void *_b) +{ + const struct type *const *a = _a, *const *b = _b; + + if ((*a)->name->size != (*b)->name->size) + return (*a)->name->size - (*b)->name->size; + else + return memcmp((*a)->name->value, (*b)->name->value, + (*a)->name->size); +} + +static int type_finder(const void *_key, const void *_ti) +{ + const struct token *token = _key; + const struct type *const *ti = _ti; + const struct type *type = *ti; + + if (token->size != type->name->size) + return token->size - type->name->size; + else + return memcmp(token->value, type->name->value, + token->size); +} + +/* + * Build up a list of types and a sorted index to that list. + */ +static void build_type_list(void) +{ + struct type *types; + unsigned nr, t, n; + + nr = 0; + for (n = 0; n < nr_tokens - 1; n++) + if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && + token_list[n + 1].token_type == TOKEN_ASSIGNMENT) + nr++; + + if (nr == 0) { + fprintf(stderr, "%s: No defined types\n", filename); + exit(1); + } + + nr_types = nr; + types = type_list = calloc(nr + 1, sizeof(type_list[0])); + if (!type_list) { + perror(NULL); + exit(1); + } + type_index = calloc(nr, sizeof(type_index[0])); + if (!type_index) { + perror(NULL); + exit(1); + } + + t = 0; + types[t].flags |= TYPE_BEGIN; + for (n = 0; n < nr_tokens - 1; n++) { + if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && + token_list[n + 1].token_type == TOKEN_ASSIGNMENT) { + types[t].name = &token_list[n]; + type_index[t] = &types[t]; + t++; + } + } + types[t].name = &token_list[n + 1]; + types[t].flags |= TYPE_STOP_MARKER; + + qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); + + printf("Extracted %u types\n", nr_types); +#if 0 + for (n = 0; n < nr_types; n++) { + struct type *type = type_index[n]; + printf("- %*.*s\n", + (int)type->name->size, + (int)type->name->size, + type->name->value); + } +#endif +} + +static struct element *parse_type(struct token **_cursor, struct token *stop, + struct token *name); + +/* + * Parse the token stream + */ +static void parse(void) +{ + struct token *cursor; + struct type *type; + + /* Parse one type definition statement at a time */ + type = type_list; + do { + cursor = type->name; + + if (cursor[0].token_type != TOKEN_TYPE_NAME || + cursor[1].token_type != TOKEN_ASSIGNMENT) + abort(); + cursor += 2; + + type->element = parse_type(&cursor, type[1].name, NULL); + type->element->type_def = type; + + if (cursor != type[1].name) { + fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + } while (type++, !(type->flags & TYPE_STOP_MARKER)); + + printf("Extracted %u actions\n", nr_actions); +} + +static struct element *element_list; + +static struct element *alloc_elem(struct token *type) +{ + struct element *e = calloc(1, sizeof(*e)); + if (!e) { + perror(NULL); + exit(1); + } + e->list_next = element_list; + element_list = e; + return e; +} + +static struct element *parse_compound(struct token **_cursor, struct token *end, + int alternates); + +/* + * Parse one type definition statement + */ +static struct element *parse_type(struct token **_cursor, struct token *end, + struct token *name) +{ + struct element *top, *element; + struct action *action, **ppaction; + struct token *cursor = *_cursor; + struct type **ref; + char *p; + int labelled = 0, implicit = 0; + + top = element = alloc_elem(cursor); + element->class = ASN1_UNIV; + element->method = ASN1_PRIM; + element->tag = token_to_tag[cursor->token_type]; + element->name = name; + + /* Extract the tag value if one given */ + if (cursor->token_type == TOKEN_OPEN_SQUARE) { + cursor++; + if (cursor >= end) + goto overrun_error; + switch (cursor->token_type) { + case DIRECTIVE_UNIVERSAL: + element->class = ASN1_UNIV; + cursor++; + break; + case DIRECTIVE_APPLICATION: + element->class = ASN1_APPL; + cursor++; + break; + case TOKEN_NUMBER: + element->class = ASN1_CONT; + break; + case DIRECTIVE_PRIVATE: + element->class = ASN1_PRIV; + cursor++; + break; + default: + fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_NUMBER) { + fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + element->tag &= ~0x1f; + element->tag |= strtoul(cursor->value, &p, 10); + if (p - cursor->value != cursor->size) + abort(); + cursor++; + + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_CLOSE_SQUARE) { + fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + if (cursor >= end) + goto overrun_error; + labelled = 1; + } + + /* Handle implicit and explicit markers */ + if (cursor->token_type == DIRECTIVE_IMPLICIT) { + element->flags |= ELEMENT_IMPLICIT; + implicit = 1; + cursor++; + if (cursor >= end) + goto overrun_error; + } else if (cursor->token_type == DIRECTIVE_EXPLICIT) { + element->flags |= ELEMENT_EXPLICIT; + cursor++; + if (cursor >= end) + goto overrun_error; + } + + if (labelled) { + if (!implicit) + element->method |= ASN1_CONS; + element->compound = implicit ? TAG_OVERRIDE : SEQUENCE; + element->children = alloc_elem(cursor); + element = element->children; + element->class = ASN1_UNIV; + element->method = ASN1_PRIM; + element->tag = token_to_tag[cursor->token_type]; + element->name = name; + } + + /* Extract the type we're expecting here */ + element->type = cursor; + switch (cursor->token_type) { + case DIRECTIVE_ANY: + element->compound = ANY; + cursor++; + break; + + case DIRECTIVE_NULL: + case DIRECTIVE_BOOLEAN: + case DIRECTIVE_ENUMERATED: + case DIRECTIVE_INTEGER: + element->compound = NOT_COMPOUND; + cursor++; + break; + + case DIRECTIVE_EXTERNAL: + element->method = ASN1_CONS; + + case DIRECTIVE_BMPString: + case DIRECTIVE_GeneralString: + case DIRECTIVE_GraphicString: + case DIRECTIVE_IA5String: + case DIRECTIVE_ISO646String: + case DIRECTIVE_NumericString: + case DIRECTIVE_PrintableString: + case DIRECTIVE_T61String: + case DIRECTIVE_TeletexString: + case DIRECTIVE_UniversalString: + case DIRECTIVE_UTF8String: + case DIRECTIVE_VideotexString: + case DIRECTIVE_VisibleString: + case DIRECTIVE_ObjectDescriptor: + case DIRECTIVE_GeneralizedTime: + case DIRECTIVE_UTCTime: + element->compound = NOT_COMPOUND; + cursor++; + break; + + case DIRECTIVE_BIT: + case DIRECTIVE_OCTET: + element->compound = NOT_COMPOUND; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != DIRECTIVE_STRING) + goto parse_error; + cursor++; + break; + + case DIRECTIVE_OBJECT: + element->compound = NOT_COMPOUND; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != DIRECTIVE_IDENTIFIER) + goto parse_error; + cursor++; + break; + + case TOKEN_TYPE_NAME: + element->compound = TYPE_REF; + ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), + type_finder); + if (!ref) { + fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor->type = *ref; + (*ref)->ref_count++; + cursor++; + break; + + case DIRECTIVE_CHOICE: + element->compound = CHOICE; + cursor++; + element->children = parse_compound(&cursor, end, 1); + break; + + case DIRECTIVE_SEQUENCE: + element->compound = SEQUENCE; + element->method = ASN1_CONS; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type == DIRECTIVE_OF) { + element->compound = SEQUENCE_OF; + cursor++; + if (cursor >= end) + goto overrun_error; + element->children = parse_type(&cursor, end, NULL); + } else { + element->children = parse_compound(&cursor, end, 0); + } + break; + + case DIRECTIVE_SET: + element->compound = SET; + element->method = ASN1_CONS; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type == DIRECTIVE_OF) { + element->compound = SET_OF; + cursor++; + if (cursor >= end) + goto parse_error; + element->children = parse_type(&cursor, end, NULL); + } else { + element->children = parse_compound(&cursor, end, 1); + } + break; + + default: + fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + /* Handle elements that are optional */ + if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL || + cursor->token_type == DIRECTIVE_DEFAULT) + ) { + cursor++; + top->flags |= ELEMENT_SKIPPABLE; + } + + if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) { + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_ELEMENT_NAME) { + fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + + action = malloc(sizeof(struct action) + cursor->size + 1); + if (!action) { + perror(NULL); + exit(1); + } + action->index = 0; + memcpy(action->name, cursor->value, cursor->size); + action->name[cursor->size] = 0; + + for (ppaction = &action_list; + *ppaction; + ppaction = &(*ppaction)->next + ) { + int cmp = strcmp(action->name, (*ppaction)->name); + if (cmp == 0) { + free(action); + action = *ppaction; + goto found; + } + if (cmp < 0) { + action->next = *ppaction; + *ppaction = action; + nr_actions++; + goto found; + } + } + action->next = NULL; + *ppaction = action; + nr_actions++; + found: + + element->action = action; + cursor->action = action; + cursor++; + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_CLOSE_ACTION) { + fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + } + + *_cursor = cursor; + return top; + +parse_error: + fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + +overrun_error: + fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); + exit(1); +} + +/* + * Parse a compound type list + */ +static struct element *parse_compound(struct token **_cursor, struct token *end, + int alternates) +{ + struct element *children, **child_p = &children, *element; + struct token *cursor = *_cursor, *name; + + if (cursor->token_type != TOKEN_OPEN_CURLY) { + fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + if (cursor >= end) + goto overrun_error; + + if (cursor->token_type == TOKEN_OPEN_CURLY) { + fprintf(stderr, "%s:%d: Empty compound\n", + filename, cursor->line); + exit(1); + } + + for (;;) { + name = NULL; + if (cursor->token_type == TOKEN_ELEMENT_NAME) { + name = cursor; + cursor++; + if (cursor >= end) + goto overrun_error; + } + + element = parse_type(&cursor, end, name); + if (alternates) + element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL; + + *child_p = element; + child_p = &element->next; + + if (cursor >= end) + goto overrun_error; + if (cursor->token_type != TOKEN_COMMA) + break; + cursor++; + if (cursor >= end) + goto overrun_error; + } + + children->flags &= ~ELEMENT_CONDITIONAL; + + if (cursor->token_type != TOKEN_CLOSE_CURLY) { + fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", + filename, cursor->line, + (int)cursor->size, (int)cursor->size, cursor->value); + exit(1); + } + cursor++; + + *_cursor = cursor; + return children; + +overrun_error: + fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); + exit(1); +} + +static void render_element(FILE *out, struct element *e, struct element *tag); +static void render_out_of_line_list(FILE *out); + +static int nr_entries; +static int render_depth = 1; +static struct element *render_list, **render_list_p = &render_list; + +__attribute__((format(printf, 2, 3))) +static void render_opcode(FILE *out, const char *fmt, ...) +{ + va_list va; + + if (out) { + fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, ""); + va_start(va, fmt); + vfprintf(out, fmt, va); + va_end(va); + } + nr_entries++; +} + +__attribute__((format(printf, 2, 3))) +static void render_more(FILE *out, const char *fmt, ...) +{ + va_list va; + + if (out) { + va_start(va, fmt); + vfprintf(out, fmt, va); + va_end(va); + } +} + +/* + * Render the grammar into a state machine definition. + */ +static void render(FILE *out, FILE *hdr) +{ + struct element *e; + struct action *action; + struct type *root; + int index; + + fprintf(hdr, "/*\n"); + fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n"); + fprintf(hdr, " *\n"); + fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name); + fprintf(hdr, " */\n"); + fprintf(hdr, "#include <linux/asn1_decoder.h>\n"); + fprintf(hdr, "\n"); + fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name); + if (ferror(hdr)) { + perror(headername); + exit(1); + } + + fprintf(out, "/*\n"); + fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n"); + fprintf(out, " *\n"); + fprintf(out, " * ASN.1 parser for %s\n", grammar_name); + fprintf(out, " */\n"); + fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n"); + fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name); + fprintf(out, "\n"); + if (ferror(out)) { + perror(outputname); + exit(1); + } + + /* Tabulate the action functions we might have to call */ + fprintf(hdr, "\n"); + index = 0; + for (action = action_list; action; action = action->next) { + action->index = index++; + fprintf(hdr, + "extern int %s(void *, size_t, unsigned char," + " const void *, size_t);\n", + action->name); + } + fprintf(hdr, "\n"); + + fprintf(out, "enum %s_actions {\n", grammar_name); + for (action = action_list; action; action = action->next) + fprintf(out, "\tACT_%s = %u,\n", + action->name, action->index); + fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions); + fprintf(out, "};\n"); + + fprintf(out, "\n"); + fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n", + grammar_name, grammar_name); + for (action = action_list; action; action = action->next) + fprintf(out, "\t[%4u] = %s,\n", action->index, action->name); + fprintf(out, "};\n"); + + if (ferror(out)) { + perror(outputname); + exit(1); + } + + /* We do two passes - the first one calculates all the offsets */ + printf("Pass 1\n"); + nr_entries = 0; + root = &type_list[0]; + render_element(NULL, root->element, NULL); + render_opcode(NULL, "ASN1_OP_COMPLETE,\n"); + render_out_of_line_list(NULL); + + for (e = element_list; e; e = e->list_next) + e->flags &= ~ELEMENT_RENDERED; + + /* And then we actually render */ + printf("Pass 2\n"); + fprintf(out, "\n"); + fprintf(out, "static const unsigned char %s_machine[] = {\n", + grammar_name); + + nr_entries = 0; + root = &type_list[0]; + render_element(out, root->element, NULL); + render_opcode(out, "ASN1_OP_COMPLETE,\n"); + render_out_of_line_list(out); + + fprintf(out, "};\n"); + + fprintf(out, "\n"); + fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name); + fprintf(out, "\t.machine = %s_machine,\n", grammar_name); + fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name); + fprintf(out, "\t.actions = %s_action_table,\n", grammar_name); + fprintf(out, "};\n"); +} + +/* + * Render the out-of-line elements + */ +static void render_out_of_line_list(FILE *out) +{ + struct element *e, *ce; + const char *act; + int entry; + + while ((e = render_list)) { + render_list = e->render_next; + if (!render_list) + render_list_p = &render_list; + + render_more(out, "\n"); + e->entry_index = entry = nr_entries; + render_depth++; + for (ce = e->children; ce; ce = ce->next) + render_element(out, ce, NULL); + render_depth--; + + act = e->action ? "_ACT" : ""; + switch (e->compound) { + case SEQUENCE: + render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); + break; + case SEQUENCE_OF: + render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); + render_opcode(out, "_jump_target(%u),\n", entry); + break; + case SET: + render_opcode(out, "ASN1_OP_END_SET%s,\n", act); + break; + case SET_OF: + render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); + render_opcode(out, "_jump_target(%u),\n", entry); + break; + default: + break; + } + if (e->action) + render_opcode(out, "_action(ACT_%s),\n", + e->action->name); + render_opcode(out, "ASN1_OP_RETURN,\n"); + } +} + +/* + * Render an element. + */ +static void render_element(FILE *out, struct element *e, struct element *tag) +{ + struct element *ec; + const char *cond, *act; + int entry, skippable = 0, outofline = 0; + + if (e->flags & ELEMENT_SKIPPABLE || + (tag && tag->flags & ELEMENT_SKIPPABLE)) + skippable = 1; + + if ((e->type_def && e->type_def->ref_count > 1) || + skippable) + outofline = 1; + + if (e->type_def && out) { + render_more(out, "\t// %*.*s\n", + (int)e->type_def->name->size, (int)e->type_def->name->size, + e->type_def->name->value); + } + + /* Render the operation */ + cond = (e->flags & ELEMENT_CONDITIONAL || + (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; + act = e->action ? "_ACT" : ""; + switch (e->compound) { + case ANY: + render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); + if (e->name) + render_more(out, "\t\t// %*.*s", + (int)e->name->size, (int)e->name->size, + e->name->value); + render_more(out, "\n"); + goto dont_render_tag; + + case TAG_OVERRIDE: + render_element(out, e->children, e); + return; + + case SEQUENCE: + case SEQUENCE_OF: + case SET: + case SET_OF: + render_opcode(out, "ASN1_OP_%sMATCH%s%s,", + cond, + outofline ? "_JUMP" : "", + skippable ? "_OR_SKIP" : ""); + break; + + case CHOICE: + goto dont_render_tag; + + case TYPE_REF: + if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) + goto dont_render_tag; + default: + render_opcode(out, "ASN1_OP_%sMATCH%s%s,", + cond, act, + skippable ? "_OR_SKIP" : ""); + break; + } + + if (e->name) + render_more(out, "\t\t// %*.*s", + (int)e->name->size, (int)e->name->size, + e->name->value); + render_more(out, "\n"); + + /* Render the tag */ + if (!tag) + tag = e; + if (tag->class == ASN1_UNIV && + tag->tag != 14 && + tag->tag != 15 && + tag->tag != 31) + render_opcode(out, "_tag(%s, %s, %s),\n", + asn1_classes[tag->class], + asn1_methods[tag->method | e->method], + asn1_universal_tags[tag->tag]); + else + render_opcode(out, "_tagn(%s, %s, %2u),\n", + asn1_classes[tag->class], + asn1_methods[tag->method | e->method], + tag->tag); + tag = NULL; +dont_render_tag: + + /* Deal with compound types */ + switch (e->compound) { + case TYPE_REF: + render_element(out, e->type->type->element, tag); + if (e->action) + render_opcode(out, "ASN1_OP_ACT,\n"); + break; + + case SEQUENCE: + if (outofline) { + /* Render out-of-line for multiple use or + * skipability */ + render_opcode(out, "_jump_target(%u),", e->entry_index); + if (e->type_def && e->type_def->name) + render_more(out, "\t\t// --> %*.*s", + (int)e->type_def->name->size, + (int)e->type_def->name->size, + e->type_def->name->value); + render_more(out, "\n"); + if (!(e->flags & ELEMENT_RENDERED)) { + e->flags |= ELEMENT_RENDERED; + *render_list_p = e; + render_list_p = &e->render_next; + } + return; + } else { + /* Render inline for single use */ + render_depth++; + for (ec = e->children; ec; ec = ec->next) + render_element(out, ec, NULL); + render_depth--; + render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); + } + break; + + case SEQUENCE_OF: + case SET_OF: + if (outofline) { + /* Render out-of-line for multiple use or + * skipability */ + render_opcode(out, "_jump_target(%u),", e->entry_index); + if (e->type_def && e->type_def->name) + render_more(out, "\t\t// --> %*.*s", + (int)e->type_def->name->size, + (int)e->type_def->name->size, + e->type_def->name->value); + render_more(out, "\n"); + if (!(e->flags & ELEMENT_RENDERED)) { + e->flags |= ELEMENT_RENDERED; + *render_list_p = e; + render_list_p = &e->render_next; + } + return; + } else { + /* Render inline for single use */ + entry = nr_entries; + render_depth++; + render_element(out, e->children, NULL); + render_depth--; + if (e->compound == SEQUENCE_OF) + render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); + else + render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); + render_opcode(out, "_jump_target(%u),\n", entry); + } + break; + + case SET: + /* I can't think of a nice way to do SET support without having + * a stack of bitmasks to make sure no element is repeated. + * The bitmask has also to be checked that no non-optional + * elements are left out whilst not preventing optional + * elements from being left out. + */ + fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); + exit(1); + + case CHOICE: + for (ec = e->children; ec; ec = ec->next) + render_element(out, ec, NULL); + if (!skippable) + render_opcode(out, "ASN1_OP_COND_FAIL,\n"); + if (e->action) + render_opcode(out, "ASN1_OP_ACT,\n"); + break; + + default: + break; + } + + if (e->action) + render_opcode(out, "_action(ACT_%s),\n", e->action->name); +} diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index cb1f50cf12e..b30406860b7 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -320,49 +320,78 @@ static void parse_dep_file(void *map, size_t len) char *end = m + len; char *p; char s[PATH_MAX]; - int first; - - p = strchr(m, ':'); - if (!p) { - fprintf(stderr, "fixdep: parse error\n"); - exit(1); - } - memcpy(s, m, p-m); s[p-m] = 0; - m = p+1; + int is_target; + int saw_any_target = 0; + int is_first_dep = 0; clear_config(); - first = 1; while (m < end) { + /* Skip any "white space" */ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) m++; + /* Find next "white space" */ p = m; - while (p < end && *p != ' ') p++; - if (p == end) { - do p--; while (!isalnum(*p)); + while (p < end && *p != ' ' && *p != '\\' && *p != '\n') p++; + /* Is the token we found a target name? */ + is_target = (*(p-1) == ':'); + /* Don't write any target names into the dependency file */ + if (is_target) { + /* The /next/ file is the first dependency */ + is_first_dep = 1; + } else { + /* Save this token/filename */ + memcpy(s, m, p-m); + s[p - m] = 0; + + /* Ignore certain dependencies */ + if (strrcmp(s, "include/generated/autoconf.h") && + strrcmp(s, "arch/um/include/uml-config.h") && + strrcmp(s, "include/linux/kconfig.h") && + strrcmp(s, ".ver")) { + /* + * Do not list the source file as dependency, + * so that kbuild is not confused if a .c file + * is rewritten into .S or vice versa. Storing + * it in source_* is needed for modpost to + * compute srcversions. + */ + if (is_first_dep) { + /* + * If processing the concatenation of + * multiple dependency files, only + * process the first target name, which + * will be the original source name, + * and ignore any other target names, + * which will be intermediate temporary + * files. + */ + if (!saw_any_target) { + saw_any_target = 1; + printf("source_%s := %s\n\n", + target, s); + printf("deps_%s := \\\n", + target); + } + is_first_dep = 0; + } else + printf(" %s \\\n", s); + do_config_file(s); + } } - memcpy(s, m, p-m); s[p-m] = 0; - if (strrcmp(s, "include/generated/autoconf.h") && - strrcmp(s, "arch/um/include/uml-config.h") && - strrcmp(s, "include/linux/kconfig.h") && - strrcmp(s, ".ver")) { - /* - * Do not list the source file as dependency, so that - * kbuild is not confused if a .c file is rewritten - * into .S or vice versa. Storing it in source_* is - * needed for modpost to compute srcversions. - */ - if (first) { - printf("source_%s := %s\n\n", target, s); - printf("deps_%s := \\\n", target); - } else - printf(" %s \\\n", s); - do_config_file(s); - } - first = 0; + /* + * Start searching for next token immediately after the first + * "whitespace" character that follows this token. + */ m = p + 1; } + + if (!saw_any_target) { + fprintf(stderr, "fixdep: parse error; no targets found\n"); + exit(1); + } + printf("\n%s: $(deps_%s)\n\n", target, target); printf("$(deps_%s):\n", target); } @@ -380,10 +409,10 @@ static void print_deps(void) exit(2); } if (fstat(fd, &st) < 0) { - fprintf(stderr, "fixdep: error fstat'ing depfile: "); - perror(depfile); - exit(2); - } + fprintf(stderr, "fixdep: error fstat'ing depfile: "); + perror(depfile); + exit(2); + } if (st.st_size == 0) { fprintf(stderr,"fixdep: %s is empty\n",depfile); close(fd); @@ -409,7 +438,7 @@ static void traps(void) int *p = (int *)test; if (*p != INT_CONF) { - fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n", + fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianness? %#x\n", *p); exit(2); } diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index 6129020c41a..549d0ab8c66 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -19,9 +19,10 @@ def getsizes(file): size, type, name = l[:-1].split() if type in "tTdDbBrR": # strip generated symbols - if name[:6] == "__mod_": continue - # function names begin with '.' on 64-bit powerpc - if "." in name[1:]: name = "static." + name.split(".")[0] + if name.startswith("__mod_"): continue + if name == "linux_banner": continue + # statics and some other optimizations adds random .NUMBER + name = re.sub(r'\.[0-9]+', '', name) sym[name] = sym.get(name, 0) + int(size, 16) return sym diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl index b78fca994a1..9ca667bcaee 100644 --- a/scripts/bootgraph.pl +++ b/scripts/bootgraph.pl @@ -38,6 +38,31 @@ # use strict; +use Getopt::Long; +my $header = 0; + +sub help { + my $text = << "EOM"; +Usage: +1) dmesg | perl scripts/bootgraph.pl [OPTION] > output.svg +2) perl scripts/bootgraph.pl -h + +Options: + -header Insert kernel version and date +EOM + my $std=shift; + if ($std == 1) { + print STDERR $text; + } else { + print $text; + } + exit; +} + +GetOptions( + 'h|help' =>\&help, + 'header' =>\$header +); my %start; my %end; @@ -49,6 +74,11 @@ my $count = 0; my %pids; my %pidctr; +my $headerstep = 20; +my $xheader = 15; +my $yheader = 25; +my $cyheader = 0; + while (<>) { my $line = $_; if ($line =~ /([0-9\.]+)\] calling ([a-zA-Z0-9\_\.]+)\+/) { @@ -112,15 +142,23 @@ if ($count == 0) { print STDERR <<END; No data found in the dmesg. Make sure that 'printk.time=1' and 'initcall_debug' are passed on the kernel command line. -Usage: - dmesg | perl scripts/bootgraph.pl > output.svg END + help(1); exit 1; } print "<?xml version=\"1.0\" standalone=\"no\"?> \n"; print "<svg width=\"2000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n"; + +if ($header) { + my $version = `uname -a`; + my $date = `date`; + print "<text transform=\"translate($xheader,$yheader)\">Kernel version: $version</text>\n"; + $cyheader = $yheader+$headerstep; + print "<text transform=\"translate($xheader,$cyheader)\">Date: $date</text>\n"; +} + my @styles; $styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; diff --git a/scripts/checkkconfigsymbols.sh b/scripts/checkkconfigsymbols.sh index 2ca49bb31ef..ccb3391882d 100755 --- a/scripts/checkkconfigsymbols.sh +++ b/scripts/checkkconfigsymbols.sh @@ -9,7 +9,7 @@ paths="$@" # Doing this once at the beginning saves a lot of time, on a cache-hot tree. Kconfigs="`find . -name 'Kconfig' -o -name 'Kconfig*[^~]'`" -/bin/echo -e "File list \tundefined symbol used" +printf "File list \tundefined symbol used\n" find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while read i do # Output the bare Kconfig variable and the filename; the _MODULE part at @@ -54,6 +54,6 @@ while read symb files; do # beyond the purpose of this script. symb_bare=`echo $symb | sed -e 's/_MODULE//'` if ! grep -q "\<$symb_bare\>" $Kconfigs; then - /bin/echo -e "$files: \t$symb" + printf "$files: \t$symb\n" fi done|sort diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index a3b9782441f..182be0f1240 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6,6 +6,7 @@ # Licensed under the terms of the GNU GPL License version 2 use strict; +use POSIX; my $P = $0; $P =~ s@.*/@@g; @@ -23,16 +24,25 @@ my $emacs = 0; my $terse = 0; my $file = 0; my $check = 0; +my $check_orig = 0; my $summary = 1; my $mailback = 0; my $summary_file = 0; my $show_types = 0; +my $fix = 0; +my $fix_inplace = 0; my $root; my %debug; +my %camelcase = (); +my %use_type = (); +my @use = (); my %ignore_type = (); my @ignore = (); my $help = 0; my $configuration_file = ".checkpatch.conf"; +my $max_line_length = 80; +my $ignore_perl_version = 0; +my $minimum_perl_version = 5.10.0; sub help { my ($exitcode) = @_; @@ -50,7 +60,9 @@ Options: --terse one line per report -f, --file treat FILE as regular source file --subjective, --strict enable more subjective tests + --types TYPE(,TYPE2...) show only these comma separated message types --ignore TYPE(,TYPE2...) ignore various comma separated message types + --max-line-length=n set the maximum line length, if exceeded, warn --show-types show the message "types" in the output --root=PATH PATH to the kernel tree root --no-summary suppress the per-file summary @@ -61,6 +73,16 @@ Options: is all off) --test-only=WORD report only warnings/errors containing WORD literally + --fix EXPERIMENTAL - may create horrible results + If correctable single-line errors exist, create + "<inputfile>.EXPERIMENTAL-checkpatch-fixes" + with potential errors corrected to the preferred + checkpatch style + --fix-inplace EXPERIMENTAL - may create horrible results + Is the same as --fix, but overwrites the input + file. It's your fault if there's no backup or git + --ignore-perl-version override checking of perl version. expect + runtime errors. -h, --help, --version display this help and exit When FILE is - read standard input. @@ -106,12 +128,16 @@ GetOptions( 'subjective!' => \$check, 'strict!' => \$check, 'ignore=s' => \@ignore, + 'types=s' => \@use, 'show-types!' => \$show_types, + 'max-line-length=i' => \$max_line_length, 'root=s' => \$root, 'summary!' => \$summary, 'mailback!' => \$mailback, 'summary-file!' => \$summary_file, - + 'fix!' => \$fix, + 'fix-inplace!' => \$fix_inplace, + 'ignore-perl-version!' => \$ignore_perl_version, 'debug=s' => \%debug, 'test-only=s' => \$tst_only, 'h|help' => \$help, @@ -120,26 +146,55 @@ GetOptions( help(0) if ($help); +$fix = 1 if ($fix_inplace); +$check_orig = $check; + my $exit = 0; +if ($^V && $^V lt $minimum_perl_version) { + printf "$P: requires at least perl version %vd\n", $minimum_perl_version; + if (!$ignore_perl_version) { + exit(1); + } +} + if ($#ARGV < 0) { print "$P: no input files\n"; exit(1); } -@ignore = split(/,/, join(',',@ignore)); -foreach my $word (@ignore) { - $word =~ s/\s*\n?$//g; - $word =~ s/^\s*//g; - $word =~ s/\s+/ /g; - $word =~ tr/[a-z]/[A-Z]/; +sub hash_save_array_words { + my ($hashRef, $arrayRef) = @_; + + my @array = split(/,/, join(',', @$arrayRef)); + foreach my $word (@array) { + $word =~ s/\s*\n?$//g; + $word =~ s/^\s*//g; + $word =~ s/\s+/ /g; + $word =~ tr/[a-z]/[A-Z]/; + + next if ($word =~ m/^\s*#/); + next if ($word =~ m/^\s*$/); - next if ($word =~ m/^\s*#/); - next if ($word =~ m/^\s*$/); + $hashRef->{$word}++; + } +} - $ignore_type{$word}++; +sub hash_show_words { + my ($hashRef, $prefix) = @_; + + if ($quiet == 0 && keys %$hashRef) { + print "NOTE: $prefix message types:"; + foreach my $word (sort keys %$hashRef) { + print " $word"; + } + print "\n\n"; + } } +hash_save_array_words(\%ignore_type, \@ignore); +hash_save_array_words(\%use_type, \@use); + my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; @@ -195,6 +250,11 @@ our $Sparse = qr{ __ref| __rcu }x; +our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)}; +our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)}; +our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)}; +our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)}; +our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit}; # Notes to $Attribute: # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check @@ -216,27 +276,40 @@ our $Attribute = qr{ __deprecated| __read_mostly| __kprobes| - __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)| + $InitAttribute| ____cacheline_aligned| ____cacheline_aligned_in_smp| ____cacheline_internodealigned_in_smp| __weak }x; our $Modifier; -our $Inline = qr{inline|__always_inline|noinline}; +our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__}; our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; our $Lval = qr{$Ident(?:$Member)*}; -our $Constant = qr{(?i:(?:[0-9]+|0x[0-9a-f]+)[ul]*)}; -our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; -our $Compare = qr{<=|>=|==|!=|<|>}; +our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u}; +our $Binary = qr{(?i)0b[01]+$Int_type?}; +our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?}; +our $Int = qr{[0-9]+$Int_type?}; +our $Octal = qr{0[0-7]+$Int_type?}; +our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; +our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; +our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; +our $Float = qr{$Float_hex|$Float_dec|$Float_int}; +our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int}; +our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; +our $Compare = qr{<=|>=|==|!=|<|(?<!-)>}; +our $Arithmetic = qr{\+|-|\*|\/|%}; our $Operators = qr{ <=|>=|==|!=| =>|->|<<|>>|<|>|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% + &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic }x; +our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; + our $NonptrType; +our $NonptrTypeWithAttr; our $Type; our $Declare; @@ -262,10 +335,11 @@ our $typeTypedefs = qr{(?x: our $logFunctions = qr{(?x: printk(?:_ratelimited|_once|)| - [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| + (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| WARN(?:_RATELIMIT|_ONCE|)| panic| - MODULE_[A-Z_]+ + MODULE_[A-Z_]+| + seq_vprintf|seq_printf|seq_puts )}; our $signature_tags = qr{(?xi: @@ -274,6 +348,7 @@ our $signature_tags = qr{(?xi: Tested-by:| Reviewed-by:| Reported-by:| + Suggested-by:| To:| Cc: )}; @@ -298,10 +373,37 @@ our @typeList = ( qr{${Ident}_handler}, qr{${Ident}_handler_fn}, ); +our @typeListWithAttr = ( + @typeList, + qr{struct\s+$InitAttribute\s+$Ident}, + qr{union\s+$InitAttribute\s+$Ident}, +); + our @modifierList = ( qr{fastcall}, ); +our @mode_permission_funcs = ( + ["module_param", 3], + ["module_param_(?:array|named|string)", 4], + ["module_param_array_named", 5], + ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2], + ["proc_create(?:_data|)", 2], + ["(?:CLASS|DEVICE|SENSOR)_ATTR", 2], +); + +#Create a search pattern for all these functions to speed up a loop below +our $mode_perms_search = ""; +foreach my $entry (@mode_permission_funcs) { + $mode_perms_search .= '|' if ($mode_perms_search ne ""); + $mode_perms_search .= $entry->[0]; +} + +our $declaration_macros = qr{(?x: + (?:$Storage\s+)?(?:DECLARE|DEFINE)_[A-Z]+\s*\(| + (?:$Storage\s+)?LIST_HEAD\s*\( +)}; + our $allowed_asm_includes = qr{(?x: irq| memory @@ -311,6 +413,7 @@ our $allowed_asm_includes = qr{(?x: sub build_types { my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; + my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)"; $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; $NonptrType = qr{ (?:$Modifier\s+|const\s+)* @@ -321,55 +424,137 @@ sub build_types { ) (?:\s+$Modifier|\s+const)* }x; + $NonptrTypeWithAttr = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\([^\)]*\)| + (?:$typeTypedefs\b)| + (?:${allWithAttr}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; $Type = qr{ $NonptrType - (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)? (?:\s+$Inline|\s+$Modifier)* }x; - $Declare = qr{(?:$Storage\s+)?$Type}; + $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; } build_types(); -our $match_balanced_parentheses = qr/(\((?:[^\(\)]+|(-1))*\))/; - our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; -our $LvalOrFunc = qr{($Lval)\s*($match_balanced_parentheses{0,1})\s*}; + +# Using $balanced_parens, $LvalOrFunc, or $FuncArg +# requires at least perl version v5.10.0 +# Any use must be runtime checked with $^V + +our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/; +our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*}; our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)}; sub deparenthesize { my ($string) = @_; return "" if (!defined($string)); - $string =~ s@^\s*\(\s*@@g; - $string =~ s@\s*\)\s*$@@g; + + while ($string =~ /^\s*\(.*\)\s*$/) { + $string =~ s@^\s*\(\s*@@; + $string =~ s@\s*\)\s*$@@; + } + $string =~ s@\s+@ @g; + return $string; } -$chk_signoff = 0 if ($file); +sub seed_camelcase_file { + my ($file) = @_; -my @dep_includes = (); -my @dep_functions = (); -my $removal = "Documentation/feature-removal-schedule.txt"; -if ($tree && -f "$root/$removal") { - open(my $REMOVE, '<', "$root/$removal") || - die "$P: $removal: open failed - $!\n"; - while (<$REMOVE>) { - if (/^Check:\s+(.*\S)/) { - for my $entry (split(/[, ]+/, $1)) { - if ($entry =~ m@include/(.*)@) { - push(@dep_includes, $1); - - } elsif ($entry !~ m@/@) { - push(@dep_functions, $entry); - } - } + return if (!(-f $file)); + + local $/; + + open(my $include_file, '<', "$file") + or warn "$P: Can't read '$file' $!\n"; + my $text = <$include_file>; + close($include_file); + + my @lines = split('\n', $text); + + foreach my $line (@lines) { + next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/); + if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) { + $camelcase{$1} = 1; + } + } +} + +my $camelcase_seeded = 0; +sub seed_camelcase_includes { + return if ($camelcase_seeded); + + my $files; + my $camelcase_cache = ""; + my @include_files = (); + + $camelcase_seeded = 1; + + if (-e ".git") { + my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`; + chomp $git_last_include_commit; + $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; + } else { + my $last_mod_date = 0; + $files = `find $root/include -name "*.h"`; + @include_files = split('\n', $files); + foreach my $file (@include_files) { + my $date = POSIX::strftime("%Y%m%d%H%M", + localtime((stat $file)[9])); + $last_mod_date = $date if ($last_mod_date < $date); + } + $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date"; + } + + if ($camelcase_cache ne "" && -f $camelcase_cache) { + open(my $camelcase_file, '<', "$camelcase_cache") + or warn "$P: Can't read '$camelcase_cache' $!\n"; + while (<$camelcase_file>) { + chomp; + $camelcase{$_} = 1; + } + close($camelcase_file); + + return; + } + + if (-e ".git") { + $files = `git ls-files "include/*.h"`; + @include_files = split('\n', $files); + } + + foreach my $file (@include_files) { + seed_camelcase_file($file); + } + + if ($camelcase_cache ne "") { + unlink glob ".checkpatch-camelcase.*"; + open(my $camelcase_file, '>', "$camelcase_cache") + or warn "$P: Can't write '$camelcase_cache' $!\n"; + foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) { + print $camelcase_file ("$_\n"); } + close($camelcase_file); } - close($REMOVE); } +$chk_signoff = 0 if ($file); + my @rawlines = (); my @lines = (); +my @fixed = (); my $vname; for my $filename (@ARGV) { my $FILE; @@ -397,6 +582,7 @@ for my $filename (@ARGV) { } @rawlines = (); @lines = (); + @fixed = (); } exit($exit); @@ -416,7 +602,7 @@ sub top_of_kernel_tree { } } return 1; - } +} sub parse_email { my ($formatted_email) = @_; @@ -437,7 +623,7 @@ sub parse_email { $comment = $2 if defined $2; $formatted_email =~ s/$address.*$//; $name = $formatted_email; - $name =~ s/^\s+|\s+$//g; + $name = trim($name); $name =~ s/^\"|\"$//g; # If there's a name left after stripping spaces and # leading quotes, and the address doesn't have both @@ -452,9 +638,9 @@ sub parse_email { } } - $name =~ s/^\s+|\s+$//g; + $name = trim($name); $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; + $address = trim($address); $address =~ s/^\<|\>$//g; if ($name =~ /[^\w \-]/i) { ##has "must quote" chars @@ -470,9 +656,9 @@ sub format_email { my $formatted_email; - $name =~ s/^\s+|\s+$//g; + $name = trim($name); $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; + $address = trim($address); if ($name =~ /[^\w \-]/i) { ##has "must quote" chars $name =~ s/(?<!\\)"/\\"/g; ##escape quotes @@ -637,6 +823,13 @@ sub sanitise_line { return $res; } +sub get_quoted_string { + my ($line, $rawline) = @_; + + return "" if ($line !~ m/(\"[X]+\")/g); + return substr($rawline, $-[0], $+[0] - $-[0]); +} + sub ctx_statement_block { my ($linenr, $remain, $off) = @_; my $line = $linenr - 1; @@ -1259,19 +1452,25 @@ sub possible { my $prefix = ''; sub show_type { - return !defined $ignore_type{$_[0]}; + my ($type) = @_; + + return defined $use_type{$type} if (scalar keys %use_type > 0); + + return !defined $ignore_type{$type}; } sub report { - if (!show_type($_[1]) || - (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) { + my ($level, $type, $msg) = @_; + + if (!show_type($type) || + (defined $tst_only && $msg !~ /\Q$tst_only\E/)) { return 0; } my $line; if ($show_types) { - $line = "$prefix$_[0]:$_[1]: $_[2]\n"; + $line = "$prefix$level:$type: $msg\n"; } else { - $line = "$prefix$_[0]: $_[2]\n"; + $line = "$prefix$level: $msg\n"; } $line = (split('\n', $line))[0] . "\n" if ($terse); @@ -1279,27 +1478,40 @@ sub report { return 1; } + sub report_dump { our @report; } sub ERROR { - if (report("ERROR", $_[0], $_[1])) { + my ($type, $msg) = @_; + + if (report("ERROR", $type, $msg)) { our $clean = 0; our $cnt_error++; + return 1; } + return 0; } sub WARN { - if (report("WARNING", $_[0], $_[1])) { + my ($type, $msg) = @_; + + if (report("WARNING", $type, $msg)) { our $clean = 0; our $cnt_warn++; + return 1; } + return 0; } sub CHK { - if ($check && report("CHECK", $_[0], $_[1])) { + my ($type, $msg) = @_; + + if ($check && report("CHECK", $type, $msg)) { our $clean = 0; our $cnt_chk++; + return 1; } + return 0; } sub check_absolute_file { @@ -1330,6 +1542,83 @@ sub check_absolute_file { } } +sub trim { + my ($string) = @_; + + $string =~ s/^\s+|\s+$//g; + + return $string; +} + +sub ltrim { + my ($string) = @_; + + $string =~ s/^\s+//; + + return $string; +} + +sub rtrim { + my ($string) = @_; + + $string =~ s/\s+$//; + + return $string; +} + +sub string_find_replace { + my ($string, $find, $replace) = @_; + + $string =~ s/$find/$replace/g; + + return $string; +} + +sub tabify { + my ($leading) = @_; + + my $source_indent = 8; + my $max_spaces_before_tab = $source_indent - 1; + my $spaces_to_tab = " " x $source_indent; + + #convert leading spaces to tabs + 1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g; + #Remove spaces before a tab + 1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g; + + return "$leading"; +} + +sub pos_last_openparen { + my ($line) = @_; + + my $pos = 0; + + my $opens = $line =~ tr/\(/\(/; + my $closes = $line =~ tr/\)/\)/; + + my $last_openparen = 0; + + if (($opens == 0) || ($closes >= $opens)) { + return -1; + } + + my $len = length($line); + + for ($pos = 0; $pos < $len; $pos++) { + my $string = substr($line, $pos); + if ($string =~ /^($FuncArg|$balanced_parens)/) { + $pos += length($1) - 1; + } elsif (substr($line, $pos, 1) eq '(') { + $last_openparen = $pos; + } elsif (index($string, '(') == -1) { + last; + } + } + + return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; +} + sub process { my $filename = shift; @@ -1351,6 +1640,8 @@ sub process { my $in_header_lines = 1; my $in_commit_log = 0; #Scanning lines before patch + my $non_utf8_charset = 0; + our @report = (); our $cnt_lines = 0; our $cnt_error = 0; @@ -1375,18 +1666,24 @@ sub process { my %suppress_export; my $suppress_statement = 0; + my %signatures = (); + # Pre-scan the patch sanitizing the lines. # Pre-scan the patch looking for any __setup documentation. # my @setup_docs = (); my $setup_docs = 0; + my $camelcase_file_seeded = 0; + sanitise_line_reset(); my $line; foreach my $rawline (@rawlines) { $linenr++; $line = $rawline; + push(@fixed, $rawline) if ($fix); + if ($rawline=~/^\+\+\+\s+(\S+)/) { $setup_docs = 0; if ($1 =~ m@Documentation/kernel-parameters.txt$@) { @@ -1464,6 +1761,8 @@ sub process { $linenr = 0; foreach my $line (@lines) { $linenr++; + my $sline = $line; #copy of $line + $sline =~ s/$;/ /g; #with comments as spaces my $rawline = $rawlines[$linenr - 1]; @@ -1516,14 +1815,16 @@ sub process { $here = "#$linenr: " if (!$file); $here = "#$realline: " if ($file); + my $found_file = 0; # extract the filename as it passes if ($line =~ /^diff --git.*?(\S+)$/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@; + $realfile =~ s@^([^/]*)/@@ if (!$file); $in_commit_log = 0; + $found_file = 1; } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@; + $realfile =~ s@^([^/]*)/@@ if (!$file); $in_commit_log = 0; $p1_prefix = $1; @@ -1537,6 +1838,15 @@ sub process { ERROR("MODIFIED_INCLUDE_ASM", "do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n"); } + $found_file = 1; + } + + if ($found_file) { + if ($realfile =~ m@^(drivers/net/|net/)@) { + $check = 1; + } else { + $check = $check_orig; + } next; } @@ -1551,7 +1861,8 @@ sub process { # Check for incorrect file permissions if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { my $permhere = $here . "FILE: $realfile\n"; - if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) { + if ($realfile !~ m@scripts/@ && + $realfile !~ /\.(py|pl|awk|sh)$/) { ERROR("EXECUTE_PERMISSIONS", "do not set execute permissions for source files\n" . $permhere); } @@ -1565,24 +1876,41 @@ sub process { # Check signature styles if (!$in_header_lines && - $line =~ /^(\s*)($signature_tags)(\s*)(.*)/) { + $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { my $space_before = $1; my $sign_off = $2; my $space_after = $3; my $email = $4; my $ucfirst_sign_off = ucfirst(lc($sign_off)); - if (defined $space_before && $space_before ne "") { + if ($sign_off !~ /$signature_tags/) { WARN("BAD_SIGN_OFF", - "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr); + "Non-standard signature: $sign_off\n" . $herecurr); + } + if (defined $space_before && $space_before ne "") { + if (WARN("BAD_SIGN_OFF", + "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] = + "$ucfirst_sign_off $email"; + } } if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { - WARN("BAD_SIGN_OFF", - "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr); + if (WARN("BAD_SIGN_OFF", + "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] = + "$ucfirst_sign_off $email"; + } + } if (!defined $space_after || $space_after ne " ") { - WARN("BAD_SIGN_OFF", - "Use a single space after $ucfirst_sign_off\n" . $herecurr); + if (WARN("BAD_SIGN_OFF", + "Use a single space after $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] = + "$ucfirst_sign_off $email"; + } } my ($email_name, $email_address, $comment) = parse_email($email); @@ -1603,6 +1931,29 @@ sub process { "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); } } + +# Check for duplicate signatures + my $sig_nospace = $line; + $sig_nospace =~ s/\s//g; + $sig_nospace = lc($sig_nospace); + if (defined $signatures{$sig_nospace}) { + WARN("BAD_SIGN_OFF", + "Duplicate signature\n" . $herecurr); + } else { + $signatures{$sig_nospace} = 1; + } + } + +# 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", + "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); } # Check for wrappage within a valid hunk of the file @@ -1647,10 +1998,17 @@ sub process { $in_commit_log = 1; } -# Still not yet in a patch, check for any UTF-8 - if ($in_commit_log && $realfile =~ /^$/ && +# Check if there is UTF-8 in a commit log when a mail header has explicitly +# declined it, i.e defined some charset where it is missing. + if ($in_header_lines && + $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && + $1 !~ /utf-8/i) { + $non_utf8_charset = 1; + } + + if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && $rawline =~ /$NON_ASCII_UTF8/) { - CHK("UTF8_BEFORE_PATCH", + WARN("UTF8_BEFORE_PATCH", "8-bit UTF-8 used in possible commit log\n" . $herecurr); } @@ -1660,16 +2018,33 @@ sub process { #trailing whitespace if ($line =~ /^\+.*\015/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("DOS_LINE_ENDINGS", - "DOS line endings\n" . $herevet); - + if (ERROR("DOS_LINE_ENDINGS", + "DOS line endings\n" . $herevet) && + $fix) { + $fixed[$linenr - 1] =~ s/[\s\015]+$//; + } } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("TRAILING_WHITESPACE", - "trailing whitespace\n" . $herevet); + if (ERROR("TRAILING_WHITESPACE", + "trailing whitespace\n" . $herevet) && + $fix) { + $fixed[$linenr - 1] =~ s/\s+$//; + } + $rpt_cleaners = 1; } +# Check for FSF mailing addresses. + if ($rawline =~ /\bwrite to the Free/i || + $rawline =~ /\b59\s+Temple\s+Pl/i || + $rawline =~ /\b51\s+Franklin\s+St/i) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + my $msg_type = \&ERROR; + $msg_type = \&CHK if ($file); + &{$msg_type}("FSF_MAILING_ADDRESS", + "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet) + } + # check for Kconfig help text having a real description # Only applies when adding the entry originally, after that we do not have # sufficient context to determine whether it is indeed long enough. @@ -1709,6 +2084,13 @@ sub process { #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; } +# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig. + if ($realfile =~ /Kconfig/ && + $line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) { + WARN("CONFIG_EXPERIMENTAL", + "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n"); + } + if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) && ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) { my $flag = $1; @@ -1723,24 +2105,70 @@ sub process { "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag}); } +# check for DT compatible documentation + if (defined $root && + (($realfile =~ /\.dtsi?$/ && $line =~ /^\+\s*compatible\s*=\s*\"/) || + ($realfile =~ /\.[ch]$/ && $line =~ /^\+.*\.compatible\s*=\s*\"/))) { + + my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g; + + my $dt_path = $root . "/Documentation/devicetree/bindings/"; + my $vp_file = $dt_path . "vendor-prefixes.txt"; + + foreach my $compat (@compats) { + my $compat2 = $compat; + $compat2 =~ s/\,[a-zA-Z0-9]*\-/\,<\.\*>\-/; + my $compat3 = $compat; + $compat3 =~ s/\,([a-z]*)[0-9]*\-/\,$1<\.\*>\-/; + `grep -Erq "$compat|$compat2|$compat3" $dt_path`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $herecurr); + } + + next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; + my $vendor = $1; + `grep -Eq "^$vendor\\b" $vp_file`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); + } + } + } + # check we are in a valid source file if not then ignore this hunk next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); -#80 column limit +#line length limit if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && $rawline !~ /^.\s*\*\s*\@$Ident\s/ && !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ || $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && - $length > 80) + $length > $max_line_length) { WARN("LONG_LINE", - "line over 80 characters\n" . $herecurr); + "line over $max_line_length characters\n" . $herecurr); + } + +# Check for user-visible strings broken across lines, which breaks the ability +# to grep for the string. Make exceptions when the previous string ends in a +# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{' +# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value + if ($line =~ /^\+\s*"/ && + $prevline =~ /"\s*$/ && + $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) { + WARN("SPLIT_STRING", + "quoted string split across lines\n" . $hereprev); } # check for spaces before a quoted newline if ($rawline =~ /^.*\".*\s\\n/) { - WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", - "unnecessary whitespace before a quoted newline\n" . $herecurr); + if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", + "unnecessary whitespace before a quoted newline\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/^(\+.*\".*)\s+\\n/$1\\n/; + } + } # check for adding lines without a newline. @@ -1771,16 +2199,130 @@ sub process { if ($rawline =~ /^\+\s* \t\s*\S/ || $rawline =~ /^\+\s* \s*/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("CODE_INDENT", - "code indent should use tabs where possible\n" . $herevet); $rpt_cleaners = 1; + if (ERROR("CODE_INDENT", + "code indent should use tabs where possible\n" . $herevet) && + $fix) { + $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } } # check for space before tabs. if ($rawline =~ /^\+/ && $rawline =~ / \t/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("SPACE_BEFORE_TAB", - "please, no space before tabs\n" . $herevet); + if (WARN("SPACE_BEFORE_TAB", + "please, no space before tabs\n" . $herevet) && + $fix) { + while ($fixed[$linenr - 1] =~ + s/(^\+.*) {8,8}+\t/$1\t\t/) {} + while ($fixed[$linenr - 1] =~ + s/(^\+.*) +\t/$1\t/) {} + } + } + +# check for && or || at the start of a line + if ($rawline =~ /^\+\s*(&&|\|\|)/) { + CHK("LOGICAL_CONTINUATIONS", + "Logical continuations should be on the previous line\n" . $hereprev); + } + +# check multi-line statement indentation matches previous line + if ($^V && $^V ge 5.10.0 && + $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { + $prevline =~ /^\+(\t*)(.*)$/; + my $oldindent = $1; + my $rest = $2; + + my $pos = pos_last_openparen($rest); + if ($pos >= 0) { + $line =~ /^(\+| )([ \t]*)/; + my $newindent = $2; + + my $goodtabindent = $oldindent . + "\t" x ($pos / 8) . + " " x ($pos % 8); + my $goodspaceindent = $oldindent . " " x $pos; + + if ($newindent ne $goodtabindent && + $newindent ne $goodspaceindent) { + + if (CHK("PARENTHESIS_ALIGNMENT", + "Alignment should match open parenthesis\n" . $hereprev) && + $fix && $line =~ /^\+/) { + $fixed[$linenr - 1] =~ + s/^\+[ \t]*/\+$goodtabindent/; + } + } + } + } + + if ($line =~ /^\+.*\*[ \t]*\)[ \t]+(?!$Assignment|$Arithmetic)/) { + if (CHK("SPACING", + "No space is necessary after a cast\n" . $hereprev) && + $fix) { + $fixed[$linenr - 1] =~ + s/^(\+.*\*[ \t]*\))[ \t]+/$1/; + } + } + + if ($realfile =~ m@^(drivers/net/|net/)@ && + $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ && + $rawline =~ /^\+[ \t]*\*/ && + $realline > 2) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); + } + + if ($realfile =~ m@^(drivers/net/|net/)@ && + $prevrawline =~ /^\+[ \t]*\/\*/ && #starting /* + $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ + $rawline =~ /^\+/ && #line is new + $rawline !~ /^\+[ \t]*\*/) { #no leading * + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments start with * on subsequent lines\n" . $hereprev); + } + + if ($realfile =~ m@^(drivers/net/|net/)@ && + $rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ + $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ + $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ + $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments put the trailing */ on a separate line\n" . $herecurr); + } + +# check for missing blank lines after declarations + if ($sline =~ /^\+\s+\S/ && #Not at char 1 + # actual declarations + ($prevline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # foo bar; where foo is some local typedef or #define + $prevline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $prevline =~ /^\+\s+$declaration_macros/) && + # for "else if" which can look like "$Ident $Ident" + !($prevline =~ /^\+\s+$c90_Keywords\b/ || + # other possible extensions of declaration lines + $prevline =~ /(?:$Compare|$Assignment|$Operators)\s*$/ || + # not starting a section or a macro "\" extended line + $prevline =~ /(?:\{\s*|\\)$/) && + # looks like a declaration + !($sline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # foo bar; where foo is some local typedef or #define + $sline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $sline =~ /^\+\s+$declaration_macros/ || + # start of struct or union or enum + $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ || + # start or end of block or continuation of declaration + $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || + # bitfield continuation + $sline =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ || + # other possible extensions of declaration lines + $sline =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/) && + # indentation of previous and current line are the same + (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/)) { + WARN("SPACING", + "Missing a blank line after declarations\n" . $hereprev); } # check for spaces at the beginning of a line. @@ -1788,15 +2330,24 @@ sub process { # 1) within comments # 2) indented preprocessor commands # 3) hanging labels - if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) { + if ($rawline =~ /^\+ / && $line !~ /^\+ *(?:$;|#|$Ident:)/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("LEADING_SPACE", - "please, no spaces at the start of a line\n" . $herevet); + if (WARN("LEADING_SPACE", + "please, no spaces at the start of a line\n" . $herevet) && + $fix) { + $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } } # check we are in a valid C source file if not then ignore this hunk next if ($realfile !~ /\.(h|c)$/); +# discourage the addition of CONFIG_EXPERIMENTAL in #if(def). + if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) { + WARN("CONFIG_EXPERIMENTAL", + "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n"); + } + # check for RCS/CVS revision markers if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { WARN("CVS_KEYWORD", @@ -1815,12 +2366,18 @@ sub process { "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); } +# check for old HOTPLUG __dev<foo> section markings + if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { + WARN("HOTPLUG_SECTION", + "Using $1 is unnecessary\n" . $herecurr); + } + # Check for potential 'bare' types my ($stat, $cond, $line_nr_next, $remain_next, $off_next, $realline_next); #print "LINE<$line>\n"; if ($linenr >= $suppress_statement && - $realcnt && $line =~ /.\s*\S/) { + $realcnt && $sline =~ /.\s*\S/) { ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0); $stat =~ s/\n./\n /g; @@ -2069,7 +2626,7 @@ sub process { $prev_values = substr($curr_values, -1); #ignore lines not being added - if ($line=~/^[^\+]/) {next;} + next if ($line =~ /^[^\+]/); # TEST: allow direct testing of the type matcher. if ($dbg_type) { @@ -2110,15 +2667,25 @@ sub process { my $path = $1; if ($path =~ m{//}) { ERROR("MALFORMED_INCLUDE", - "malformed #include filename\n" . - $herecurr); + "malformed #include filename\n" . $herecurr); + } + if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) { + ERROR("UAPI_INCLUDE", + "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr); } } # no C99 // comments if ($line =~ m{//}) { - ERROR("C99_COMMENTS", - "do not use C99 // comments\n" . $herecurr); + if (ERROR("C99_COMMENTS", + "do not use C99 // comments\n" . $herecurr) && + $fix) { + my $line = $fixed[$linenr - 1]; + if ($line =~ /\/\/(.*)$/) { + my $comment = trim($1); + $fixed[$linenr - 1] =~ s@\/\/(.*)$@/\* $comment \*/@; + } + } } # Remove C99 comments. $line =~ s@//.*@@; @@ -2170,16 +2737,22 @@ sub process { } # check for global initialisers. - if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { - ERROR("GLOBAL_INITIALISERS", - "do not initialise globals to 0 or NULL\n" . - $herecurr); + if ($line =~ /^\+(\s*$Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/) { + if (ERROR("GLOBAL_INITIALISERS", + "do not initialise globals to 0 or NULL\n" . + $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/($Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/$1;/; + } } # check for static initialisers. - if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { - ERROR("INITIALISED_STATIC", - "do not initialise statics to 0 or NULL\n" . - $herecurr); + if ($line =~ /^\+.*\bstatic\s.*=\s*(0|NULL|false)\s*;/) { + if (ERROR("INITIALISED_STATIC", + "do not initialise statics to 0 or NULL\n" . + $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/(\bstatic\s.*?)\s*=\s*(0|NULL|false)\s*;/$1;/; + } } # check for static const char * arrays. @@ -2196,10 +2769,29 @@ sub process { $herecurr); } -# check for declarations of struct pci_device_id - if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { - WARN("DEFINE_PCI_DEVICE_TABLE", - "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); +# check for non-global char *foo[] = {"bar", ...} declarations. + if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "char * array declaration might be better as static const\n" . + $herecurr); + } + +# check for function declarations without arguments like "int foo()" + if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { + if (ERROR("FUNCTION_WITHOUT_ARGS", + "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/; + } + } + +# check for uses of DEFINE_PCI_DEVICE_TABLE + if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) { + if (WARN("DEFINE_PCI_DEVICE_TABLE", + "Prefer struct pci_device_id over deprecated DEFINE_PCI_DEVICE_TABLE\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const struct pci_device_id $1\[\] = /; + } } # check for new typedefs, only function parameters and sparse annotations @@ -2217,7 +2809,7 @@ sub process { # (char*[ const]) while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) { #print "AA<$1>\n"; - my ($from, $to) = ($2, $2); + my ($ident, $from, $to) = ($1, $2, $2); # Should start with a space. $to =~ s/^(\S)/ $1/; @@ -2227,15 +2819,22 @@ sub process { while ($to =~ s/\*\s+\*/\*\*/) { } - #print "from<$from> to<$to>\n"; +## print "1: from<$from> to<$to> ident<$ident>\n"; if ($from ne $to) { - ERROR("POINTER_LOCATION", - "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); + if (ERROR("POINTER_LOCATION", + "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) && + $fix) { + my $sub_from = $ident; + my $sub_to = $ident; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$linenr - 1] =~ + s@\Q$sub_from\E@$sub_to@; + } } } while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) { #print "BB<$1>\n"; - my ($from, $to, $ident) = ($2, $2, $3); + my ($match, $from, $to, $ident) = ($1, $2, $2, $3); # Should start with a space. $to =~ s/^(\S)/ $1/; @@ -2247,10 +2846,18 @@ sub process { # Modifiers should have spaces. $to =~ s/(\b$Modifier$)/$1 /; - #print "from<$from> to<$to> ident<$ident>\n"; +## print "2: from<$from> to<$to> ident<$ident>\n"; if ($from ne $to && $ident !~ /^$Modifier$/) { - ERROR("POINTER_LOCATION", - "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); + if (ERROR("POINTER_LOCATION", + "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) && + $fix) { + + my $sub_from = $match; + my $sub_to = $match; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$linenr - 1] =~ + s@\Q$sub_from\E@$sub_to@; + } } } @@ -2296,6 +2903,34 @@ sub process { } } + if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + my $level2 = $level; + $level2 = "dbg" if ($level eq "debug"); + WARN("PREFER_PR_LEVEL", + "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); + } + + if ($line =~ /\bpr_warning\s*\(/) { + if (WARN("PREFER_PR_LEVEL", + "Prefer pr_warn(... to pr_warning(...\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\bpr_warning\b/pr_warn/; + } + } + + if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + $level = "dbg" if ($level eq "debug"); + WARN("PREFER_DEV_LEVEL", + "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); + } + # function brace can't be on same line, except for #defines of do while, # or if closed on same line if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and @@ -2312,9 +2947,83 @@ sub process { } # missing space after union, struct or enum definition - if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { - WARN("SPACING", - "missing space after $1 definition\n" . $herecurr); + if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) { + if (WARN("SPACING", + "missing space after $1 definition\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/; + } + } + +# Function pointer declarations +# check spacing between type, funcptr, and args +# canonical declaration is "type (*funcptr)(args...)" + if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) { + my $declare = $1; + my $pre_pointer_space = $2; + my $post_pointer_space = $3; + my $funcname = $4; + my $post_funcname_space = $5; + my $pre_args_space = $6; + +# the $Declare variable will capture all spaces after the type +# so check it for a missing trailing missing space but pointer return types +# don't need a space so don't warn for those. + my $post_declare_space = ""; + if ($declare =~ /(\s+)$/) { + $post_declare_space = $1; + $declare = rtrim($declare); + } + if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) { + WARN("SPACING", + "missing space after return type\n" . $herecurr); + $post_declare_space = " "; + } + +# unnecessary space "type (*funcptr)(args...)" +# This test is not currently implemented because these declarations are +# equivalent to +# int foo(int bar, ...) +# and this is form shouldn't/doesn't generate a checkpatch warning. +# +# elsif ($declare =~ /\s{2,}$/) { +# WARN("SPACING", +# "Multiple spaces after return type\n" . $herecurr); +# } + +# unnecessary space "type ( *funcptr)(args...)" + if (defined $pre_pointer_space && + $pre_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer open parenthesis\n" . $herecurr); + } + +# unnecessary space "type (* funcptr)(args...)" + if (defined $post_pointer_space && + $post_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr )(args...)" + if (defined $post_funcname_space && + $post_funcname_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr) (args...)" + if (defined $pre_args_space && + $pre_args_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer arguments\n" . $herecurr); + } + + if (show_type("SPACING") && $fix) { + $fixed[$linenr - 1] =~ + s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex; + } } # check for spacing round square brackets; allowed: @@ -2325,9 +3034,13 @@ sub process { my ($where, $prefix) = ($-[1], $1); if ($prefix !~ /$Type\s+$/ && ($where != 0 || $prefix !~ /^.\s+$/) && - $prefix !~ /{\s+$/) { - ERROR("BRACKET_SPACE", - "space prohibited before open square bracket '['\n" . $herecurr); + $prefix !~ /[{,]\s+$/) { + if (ERROR("BRACKET_SPACE", + "space prohibited before open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/^(\+.*?)\s+\[/$1\[/; + } } } @@ -2344,7 +3057,6 @@ sub process { __attribute__|format|__extension__| asm|__asm__)$/x) { - # cpp #define statements have non-optional spaces, ie # if there is a space between the name and the open # parenthesis it is simply not a parameter group. @@ -2358,25 +3070,53 @@ sub process { } elsif ($ctx =~ /$Type$/) { } else { - WARN("SPACING", - "space prohibited between function name and open parenthesis '('\n" . $herecurr); + if (WARN("SPACING", + "space prohibited between function name and open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\b$name\s+\(/$name\(/; + } } } + # Check operator spacing. if (!($line=~/\#\s*include/)) { + my $fixed_line = ""; + my $line_fixed = 0; + my $ops = qr{ <<=|>>=|<=|>=|==|!=| \+=|-=|\*=|\/=|%=|\^=|\|=|&=| =>|->|<<|>>|<|>|=|!|~| &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|: + \?:|\?|: }x; my @elements = split(/($ops|;)/, $opline); + +## print("element count: <" . $#elements . ">\n"); +## foreach my $el (@elements) { +## print("el: <$el>\n"); +## } + + my @fix_elements = (); my $off = 0; + foreach my $el (@elements) { + push(@fix_elements, substr($rawline, $off, length($el))); + $off += length($el); + } + + $off = 0; + my $blank = copy_spacing($opline); + my $last_after = -1; for (my $n = 0; $n < $#elements; $n += 2) { + + my $good = $fix_elements[$n] . $fix_elements[$n + 1]; + +## print("n: <$n> good: <$good>\n"); + $off += length($elements[$n]); # Pick up the preceding and succeeding characters. @@ -2433,27 +3173,43 @@ sub process { } elsif ($op eq ';') { if ($ctx !~ /.x[WEBC]/ && $cc !~ /^\\/ && $cc !~ /^;/) { - ERROR("SPACING", - "space required after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } } # // is a comment } elsif ($op eq '//') { + # : when part of a bitfield + } elsif ($opv eq ':B') { + # skip the bitfield test for now + # No spaces for: # -> - # : when part of a bitfield - } elsif ($op eq '->' || $opv eq ':B') { + } elsif ($op eq '->') { if ($ctx =~ /Wx.|.xW/) { - ERROR("SPACING", - "spaces prohibited around that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "spaces prohibited around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } # , must have a space on the right. } elsif ($op eq ',') { if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { - ERROR("SPACING", - "space required after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + $last_after = $n; + } } # '*' as part of a type definition -- reported already. @@ -2467,34 +3223,56 @@ sub process { $opv eq '*U' || $opv eq '-U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { - ERROR("SPACING", - "space required before that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required before that '$op' $at\n" . $hereptr)) { + if ($n != $last_after + 2) { + $good = $fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } } if ($op eq '*' && $cc =~/\s*$Modifier\b/) { # A unary '*' may be const } elsif ($ctx =~ /.xW/) { - ERROR("SPACING", - "space prohibited after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . rtrim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } # unary ++ and unary -- are allowed no space on one side. } elsif ($op eq '++' or $op eq '--') { if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { - ERROR("SPACING", - "space required one side of that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required one side of that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } } if ($ctx =~ /Wx[BE]/ || ($ctx =~ /Wx./ && $cc =~ /^;/)) { - ERROR("SPACING", - "space prohibited before that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } } if ($ctx =~ /ExW/) { - ERROR("SPACING", - "space prohibited after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } - # << and >> may either have or not have spaces both sides } elsif ($op eq '<<' or $op eq '>>' or $op eq '&' or $op eq '^' or $op eq '|' or @@ -2503,17 +3281,25 @@ sub process { $op eq '%') { if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { - ERROR("SPACING", - "need consistent spacing around '$op' $at\n" . - $hereptr); + if (ERROR("SPACING", + "need consistent spacing around '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } # A colon needs no spaces before when it is # terminating a case value or a label. } elsif ($opv eq ':C' || $opv eq ':L') { if ($ctx =~ /Wx./) { - ERROR("SPACING", - "space prohibited before that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } } # All the others need spaces both sides. @@ -2529,18 +3315,46 @@ sub process { $ok = 1; } - # Ignore ?: - if (($opv eq ':O' && $ca =~ /\?$/) || - ($op eq '?' && $cc =~ /^:/)) { - $ok = 1; - } - + # messages are ERROR, but ?: are CHK if ($ok == 0) { - ERROR("SPACING", - "spaces required around that '$op' $at\n" . $hereptr); + my $msg_type = \&ERROR; + $msg_type = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/); + + if (&{$msg_type}("SPACING", + "spaces required around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } } $off += length($elements[$n + 1]); + +## print("n: <$n> GOOD: <$good>\n"); + + $fixed_line = $fixed_line . $good; + } + + if (($#elements % 2) == 0) { + $fixed_line = $fixed_line . $fix_elements[$#elements]; + } + + if ($fix && $line_fixed && $fixed_line ne $fixed[$linenr - 1]) { + $fixed[$linenr - 1] = $fixed_line; + } + + + } + +# check for whitespace before a non-naked semicolon + if ($line =~ /^\+.*\S\s+;\s*$/) { + if (WARN("SPACING", + "space prohibited before semicolon\n" . $herecurr) && + $fix) { + 1 while $fixed[$linenr - 1] =~ + s/^(\+.*\S)\s+;/$1;/; } } @@ -2569,71 +3383,125 @@ sub process { #need space before brace following if, while, etc if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) || $line =~ /do{/) { - ERROR("SPACING", - "space required before the open brace '{'\n" . $herecurr); + if (ERROR("SPACING", + "space required before the open brace '{'\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/^(\+.*(?:do|\))){/$1 {/; + } } +## # check for blank lines before declarations +## if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ && +## $prevrawline =~ /^.\s*$/) { +## WARN("SPACING", +## "No blank lines before declarations\n" . $hereprev); +## } +## + # closing brace should have a space following it when it has anything # on the line if ($line =~ /}(?!(?:,|;|\)))\S/) { - ERROR("SPACING", - "space required after that close brace '}'\n" . $herecurr); + if (ERROR("SPACING", + "space required after that close brace '}'\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/}((?!(?:,|;|\)))\S)/} $1/; + } } # check spacing on square brackets if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { - ERROR("SPACING", - "space prohibited after that open square bracket '['\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited after that open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\[\s+/\[/; + } } if ($line =~ /\s\]/) { - ERROR("SPACING", - "space prohibited before that close square bracket ']'\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited before that close square bracket ']'\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\s+\]/\]/; + } } # check spacing on parentheses if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && $line !~ /for\s*\(\s+;/) { - ERROR("SPACING", - "space prohibited after that open parenthesis '('\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited after that open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\(\s+/\(/; + } } if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && $line !~ /for\s*\(.*;\s+\)/ && $line !~ /:\s+\)/) { - ERROR("SPACING", - "space prohibited before that close parenthesis ')'\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited before that close parenthesis ')'\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\s+\)/\)/; + } } #goto labels aren't indented, allow a single space however if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { - WARN("INDENTED_LABEL", - "labels should not be indented\n" . $herecurr); + if (WARN("INDENTED_LABEL", + "labels should not be indented\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/^(.)\s+/$1/; + } } -# Return is not a function. - if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { +# return is not a function + if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { my $spacing = $1; - my $value = $2; - - # Flatten any parentheses - $value =~ s/\(/ \(/g; - $value =~ s/\)/\) /g; - while ($value =~ s/\[[^\[\]]*\]/1/ || - $value !~ /(?:$Ident|-?$Constant)\s* - $Compare\s* - (?:$Ident|-?$Constant)/x && - $value =~ s/\([^\(\)]*\)/1/) { - } -#print "value<$value>\n"; - if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { - ERROR("RETURN_PARENTHESES", - "return is not a function, parentheses are not required\n" . $herecurr); - + if ($^V && $^V ge 5.10.0 && + $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { + my $value = $1; + $value = deparenthesize($value); + if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) { + ERROR("RETURN_PARENTHESES", + "return is not a function, parentheses are not required\n" . $herecurr); + } } elsif ($spacing !~ /\s+/) { ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); } } + +# unnecessary return in a void function +# at end-of-function, with the previous line a single leading tab, then return; +# and the line before that not a goto label target like "out:" + if ($sline =~ /^[ \+]}\s*$/ && + $prevline =~ /^\+\treturn\s*;\s*$/ && + $linenr >= 3 && + $lines[$linenr - 3] =~ /^[ +]/ && + $lines[$linenr - 3] !~ /^[ +]\s*$Ident\s*:/) { + WARN("RETURN_VOID", + "void function return statements are not generally useful\n" . $hereprev); + } + +# if statements using unnecessary parentheses - ie: if ((foo == bar)) + if ($^V && $^V ge 5.10.0 && + $line =~ /\bif\s*((?:\(\s*){2,})/) { + my $openparens = $1; + my $count = $openparens =~ tr@\(@\(@; + my $msg = ""; + if ($line =~ /\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/) { + my $comp = $4; #Not $1 because of $LvalOrFunc + $msg = " - maybe == should be = ?" if ($comp eq "=="); + WARN("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses$msg\n" . $herecurr); + } + } + # Return of what appears to be an errno should normally be -'ve if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { my $name = $1; @@ -2644,8 +3512,13 @@ sub process { } # Need a space before open parenthesis after if, while etc - if ($line=~/\b(if|while|for|switch)\(/) { - ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); + if ($line =~ /\b(if|while|for|switch)\(/) { + if (ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/\b(if|while|for|switch)\(/$1 \(/; + } } # Check for illegal assignment in if conditional -- and check for trailing @@ -2672,6 +3545,7 @@ sub process { } } if (!defined $suppress_whiletrailers{$linenr} && + defined($stat) && defined($cond) && $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { my ($s, $c) = ($stat, $cond); @@ -2769,17 +3643,54 @@ sub process { } } -#studly caps, commented out until figure out how to distinguish between use of existing and adding new -# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) { -# print "No studly caps, use _\n"; -# print "$herecurr"; -# $clean = 0; -# } +#Specific variable tests + 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[$linenr - 1] =~ + s/\b$var\b/$hexval/; + } + } + +#CamelCase + if ($var !~ /^$Constant$/ && + $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && +#Ignore Page<foo> variants + $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && +#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show) + $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/) { + while ($var =~ m{($Ident)}g) { + my $word = $1; + next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); + if ($check) { + seed_camelcase_includes(); + if (!$file && !$camelcase_file_seeded) { + seed_camelcase_file($realfile); + $camelcase_file_seeded = 1; + } + } + if (!defined $camelcase{$word}) { + $camelcase{$word} = 1; + CHK("CAMELCASE", + "Avoid CamelCase: <$word>\n" . $herecurr); + } + } + } + } #no spaces allowed after \ in define - if ($line=~/\#\s*define.*\\\s$/) { - WARN("WHITESPACE_AFTER_LINE_CONTINUATION", - "Whitepspace after \\ makes next lines useless\n" . $herecurr); + if ($line =~ /\#\s*define.*\\\s+$/) { + if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION", + "Whitespace after \\ makes next lines useless\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\s+$//; + } } #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line) @@ -2828,10 +3739,16 @@ sub process { { } + # Flatten any obvious string concatentation. + while ($dstat =~ s/("X*")\s*$Ident/$1/ || + $dstat =~ s/$Ident\s*("X*")/$1/) + { + } + my $exceptions = qr{ $Declare| module_param_named| - MODULE_PARAM_DESC| + MODULE_PARM_DESC| DECLARE_PER_CPU| DEFINE_PER_CPU| __typeof__\(| @@ -2844,14 +3761,17 @@ sub process { if ($dstat ne '' && $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); - $dstat !~ /^(?:$Ident|-?$Constant)$/ && # 10 // foo() + $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz + $dstat !~ /^'X'$/ && # character constants $dstat !~ /$exceptions/ && $dstat !~ /^\.$Ident\s*=/ && # .foo = + $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...) $dstat !~ /^for\s*$Constant$/ && # for (...) $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() $dstat !~ /^do\s*{/ && # do {... - $dstat !~ /^\({/) # ({... + $dstat !~ /^\({/ && # ({... + $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) { $ctx =~ s/\n*$//; my $herectx = $here . "\n"; @@ -2869,6 +3789,68 @@ sub process { "Macros with complex values should be enclosed in parenthesis\n" . "$herectx"); } } + +# check for line continuations outside of #defines, preprocessor #, and asm + + } else { + if ($prevline !~ /^..*\\$/ && + $line !~ /^\+\s*\#.*\\$/ && # preprocessor + $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm + $line =~ /^\+.*\\$/) { + WARN("LINE_CONTINUATIONS", + "Avoid unnecessary line continuations\n" . $herecurr); + } + } + +# 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 && + $realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; + + $dstat =~ s/\\\n.//g; + + if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) { + my $stmts = $2; + my $semis = $3; + + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = $here . "\n"; + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + if (($stmts =~ tr/;/;/) == 1 && + $stmts !~ /^\s*(if|while|for|switch)\b/) { + WARN("SINGLE_STATEMENT_DO_WHILE_MACRO", + "Single statement macros should not use a do {} while (0) loop\n" . "$herectx"); + } + if (defined $semis && $semis ne "") { + WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON", + "do {} while (0) macros should not be semicolon terminated\n" . "$herectx"); + } + } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = $here . "\n"; + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + WARN("TRAILING_SEMICOLON", + "macros should not use a trailing semicolon\n" . "$herectx"); + } } # make sure symbols are always wrapped with VMLINUX_SYMBOL() ... @@ -2888,7 +3870,8 @@ sub process { #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; if ($#chunks > 0 && $level == 0) { - my $allowed = 0; + my @allowed = (); + my $allow = 0; my $seen = 0; my $herectx = $here . "\n"; my $ln = $linenr - 1; @@ -2899,6 +3882,7 @@ sub process { my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); my $offset = statement_rawlines($whitespace) - 1; + $allowed[$allow] = 0; #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; # We have looked at and allowed this specific line. @@ -2911,23 +3895,34 @@ sub process { $seen++ if ($block =~ /^\s*{/); - #print "cond<$cond> block<$block> allowed<$allowed>\n"; + #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n"; if (statement_lines($cond) > 1) { #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; + $allowed[$allow] = 1; } if ($block =~/\b(?:if|for|while)\b/) { #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; + $allowed[$allow] = 1; } if (statement_block_size($block) > 1) { #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; + $allowed[$allow] = 1; } + $allow++; } - if ($seen && !$allowed) { - WARN("BRACES", - "braces {} are not necessary for any arm of this statement\n" . $herectx); + if ($seen) { + my $sum_allowed = 0; + foreach (@allowed) { + $sum_allowed += $_; + } + if ($sum_allowed == 0) { + WARN("BRACES", + "braces {} are not necessary for any arm of this statement\n" . $herectx); + } elsif ($sum_allowed != $allow && + $seen != $allow) { + CHK("BRACES", + "braces {} should be used on all arms of this statement\n" . $herectx); + } } } } @@ -2986,20 +3981,14 @@ sub process { } } -# don't include deprecated include files (uses RAW line) - for my $inc (@dep_includes) { - if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) { - ERROR("DEPRECATED_INCLUDE", - "Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr); - } +# check for unnecessary blank lines around braces + if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) { + CHK("BRACES", + "Blank lines aren't necessary before a close brace '}'\n" . $hereprev); } - -# don't use deprecated functions - for my $func (@dep_functions) { - if ($line =~ /\b$func\b/) { - ERROR("DEPRECATED_FUNCTION", - "Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr); - } + if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) { + CHK("BRACES", + "Blank lines aren't necessary after an open brace '{'\n" . $hereprev); } # no volatiles please @@ -3016,29 +4005,86 @@ sub process { $herecurr); } -# check for needless kfree() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\bkfree\(\Q$expr\E\);/) { - WARN("NEEDLESS_KFREE", - "kfree(NULL) is safe this check is probably not required\n" . $hereprev); +# check for needless "if (<foo>) fn(<foo>)" uses + if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { + my $expr = '\s*\(\s*' . quotemeta($1) . '\s*\)\s*;'; + if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/) { + WARN('NEEDLESS_IF', + "$1(NULL) is safe this check is probably not required\n" . $hereprev); + } + } + +# check for bad placement of section $InitAttribute (e.g.: __initdata) + if ($line =~ /(\b$InitAttribute\b)/) { + my $attr = $1; + if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) { + my $ptr = $1; + my $var = $2; + if ((($ptr =~ /\b(union|struct)\s+$attr\b/ && + ERROR("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr)) || + ($ptr !~ /\b(union|struct)\s+$attr\b/ && + WARN("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr))) && + $fix) { + $fixed[$linenr - 1] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e; + } + } + } + +# check for $InitAttributeData (ie: __initdata) with const + if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) { + my $attr = $1; + $attr =~ /($InitAttributePrefix)(.*)/; + my $attr_prefix = $1; + my $attr_type = $2; + if (ERROR("INIT_ATTRIBUTE", + "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/$InitAttributeData/${attr_prefix}initconst/; + } + } + +# check for $InitAttributeConst (ie: __initconst) without const + if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) { + my $attr = $1; + if (ERROR("INIT_ATTRIBUTE", + "Use of $attr requires a separate use of const\n" . $herecurr) && + $fix) { + my $lead = $fixed[$linenr - 1] =~ + /(^\+\s*(?:static\s+))/; + $lead = rtrim($1); + $lead = "$lead " if ($lead !~ /^\+$/); + $lead = "${lead}const "; + $fixed[$linenr - 1] =~ s/(^\+\s*(?:static\s+))/$lead/; } } -# check for needless usb_free_urb() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) { - WARN("NEEDLESS_USB_FREE_URB", - "usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev); + +# don't use __constant_<foo> functions outside of include/uapi/ + if ($realfile !~ m@^include/uapi/@ && + $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) { + my $constant_func = $1; + my $func = $constant_func; + $func =~ s/^__constant_//; + if (WARN("CONSTANT_CONVERSION", + "$constant_func should be $func\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b$constant_func\b/$func/g; } } # prefer usleep_range over udelay - if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) { + if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { + my $delay = $1; # ignore udelay's < 10, however - if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) { + if (! ($delay < 10) ) { CHK("USLEEP_RANGE", - "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line); + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr); + } + if ($delay > 2000) { + WARN("LONG_UDELAY", + "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr); } } @@ -3046,10 +4092,22 @@ sub process { if ($line =~ /\bmsleep\s*\((\d+)\);/) { if ($1 < 20) { WARN("MSLEEP", - "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line); + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr); } } +# check for comparisons of jiffies + if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) { + WARN("JIFFIES_COMPARISON", + "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr); + } + +# check for comparisons of get_jiffies_64() + if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) { + WARN("JIFFIES_COMPARISON", + "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr); + } + # warn about #ifdefs in C files # if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { # print "#ifdef in C files should be avoided\n"; @@ -3059,8 +4117,13 @@ sub process { # warn about spacing in #ifdefs if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { - ERROR("SPACING", - "exactly one space required after that #$1\n" . $herecurr); + if (ERROR("SPACING", + "exactly one space required after that #$1\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /; + } + } # check for spinlock_t definitions without a comment. @@ -3075,8 +4138,8 @@ sub process { # check for memory barriers without a comment. if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { if (!ctx_has_comment($first_line, $linenr)) { - CHK("MEMORY_BARRIER", - "memory barrier without comment\n" . $herecurr); + WARN("MEMORY_BARRIER", + "memory barrier without comment\n" . $herecurr); } } # check of hardware specific defines @@ -3100,27 +4163,49 @@ sub process { } # Check for __inline__ and __inline, prefer inline - if ($line =~ /\b(__inline__|__inline)\b/) { - WARN("INLINE", - "plain inline is preferred over $1\n" . $herecurr); + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b(__inline__|__inline)\b/) { + if (WARN("INLINE", + "plain inline is preferred over $1\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b(__inline__|__inline)\b/inline/; + + } } # Check for __attribute__ packed, prefer __packed - if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { WARN("PREFER_PACKED", "__packed is preferred over __attribute__((packed))\n" . $herecurr); } # Check for __attribute__ aligned, prefer __aligned - if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { WARN("PREFER_ALIGNED", "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); } # Check for __attribute__ format(printf, prefer __printf - if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { - WARN("PREFER_PRINTF", - "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr); + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { + if (WARN("PREFER_PRINTF", + "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex; + + } + } + +# Check for __attribute__ format(scanf, prefer __scanf + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { + if (WARN("PREFER_SCANF", + "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex; + } } # check for sizeof(&) @@ -3129,19 +4214,47 @@ sub process { "sizeof(& should be avoided\n" . $herecurr); } +# check for sizeof without parenthesis + if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) { + if (WARN("SIZEOF_PARENTHESIS", + "sizeof $1 should be sizeof($1)\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex; + } + } + # check for line continuations in quoted strings with odd counts of " if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) { WARN("LINE_CONTINUATIONS", "Avoid line continuations in quoted strings\n" . $herecurr); } +# check for struct spinlock declarations + if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) { + WARN("USE_SPINLOCK_T", + "struct spinlock should be spinlock_t\n" . $herecurr); + } + +# check for seq_printf uses that could be seq_puts + if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) { + my $fmt = get_quoted_string($line, $rawline); + if ($fmt ne "" && $fmt !~ /[^\\]\%/) { + if (WARN("PREFER_SEQ_PUTS", + "Prefer seq_puts to seq_printf\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\bseq_printf\b/seq_puts/; + } + } + } + # Check for misused memsets - if (defined $stat && + if ($^V && $^V ge 5.10.0 && + defined $stat && $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) { my $ms_addr = $2; - my $ms_val = $8; - my $ms_size = $14; + my $ms_val = $7; + my $ms_size = $12; if ($ms_size =~ /^(0x|)0$/i) { ERROR("MEMSET", @@ -3152,18 +4265,29 @@ sub process { } } +# Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) + if ($^V && $^V ge 5.10.0 && + $line =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/s) { + if (WARN("PREFER_ETHER_ADDR_COPY", + "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; + } + } + # typecasts on min/max could be min_t/max_t - if (defined $stat && + if ($^V && $^V ge 5.10.0 && + defined $stat && $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { - if (defined $2 || defined $8) { + if (defined $2 || defined $7) { my $call = $1; my $cast1 = deparenthesize($2); my $arg1 = $3; - my $cast2 = deparenthesize($8); - my $arg2 = $9; + my $cast2 = deparenthesize($7); + my $arg2 = $8; my $cast; - if ($cast1 ne "" && $cast2 ne "") { + if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) { $cast = "$cast1 or $cast2"; } elsif ($cast1 ne "") { $cast = $cast1; @@ -3175,6 +4299,70 @@ sub process { } } +# check usleep_range arguments + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { + my $min = $1; + my $max = $7; + if ($min eq $max) { + WARN("USLEEP_RANGE", + "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && + $min > $max) { + WARN("USLEEP_RANGE", + "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + } + } + +# check for naked sscanf + if ($^V && $^V ge 5.10.0 && + defined $stat && + $line =~ /\bsscanf\b/ && + ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && + $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ && + $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + WARN("NAKED_SSCANF", + "unchecked sscanf return value\n" . "$here\n$stat_real\n"); + } + +# check for simple sscanf that should be kstrto<foo> + if ($^V && $^V ge 5.10.0 && + defined $stat && + $line =~ /\bsscanf\b/) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { + my $format = $6; + my $count = $format =~ tr@%@%@; + if ($count == 1 && + $format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/) { + WARN("SSCANF_TO_KSTRTO", + "Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n"); + } + } + } + +# check for new externs in .h files. + if ($realfile =~ /\.h$/ && + $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) { + if (CHK("AVOID_EXTERNS", + "extern prototypes should be avoided in .h files\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/(.*)\bextern\b\s*(.*)/$1$2/; + } + } + # check for new externs in .c files. if ($realfile =~ /\.c$/ && defined $stat && $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) @@ -3221,34 +4409,159 @@ sub process { "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); } +# alloc style +# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) + if ($^V && $^V ge 5.10.0 && + $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 && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/) { + my $oldfunc = $3; + my $a1 = $4; + my $a2 = $10; + my $newfunc = "kmalloc_array"; + $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); + if ($a1 =~ /^sizeof\s*\S/ || $a2 =~ /^sizeof\s*\S/) { + if (WARN("ALLOC_WITH_MULTIPLY", + "Prefer $newfunc over $oldfunc with multiply\n" . $herecurr) && + $fix) { + my $r1 = $a1; + my $r2 = $a2; + if ($a1 =~ /^sizeof\s*\S/) { + $r1 = $a2; + $r2 = $a1; + } + $fixed[$linenr - 1] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; + + } + } + } + +# 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*,/) { + WARN("KREALLOC_ARG_REUSE", + "Reusing the krealloc arg is almost always a bug\n" . $herecurr); + } + +# check for alloc argument mismatch + if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) { + WARN("ALLOC_ARRAY_ARGS", + "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); + } + # check for multiple semicolons if ($line =~ /;\s*;\s*$/) { - WARN("ONE_SEMICOLON", - "Statements terminations use 1 semicolon\n" . $herecurr); + if (WARN("ONE_SEMICOLON", + "Statements terminations use 1 semicolon\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/(\s*;\s*){2,}$/;/g; + } + } + +# check for case / default statements not preceeded by break/fallthrough/switch + if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) { + my $has_break = 0; + my $has_statement = 0; + my $count = 0; + my $prevline = $linenr; + while ($prevline > 1 && $count < 3 && !$has_break) { + $prevline--; + my $rline = $rawlines[$prevline - 1]; + my $fline = $lines[$prevline - 1]; + last if ($fline =~ /^\@\@/); + next if ($fline =~ /^\-/); + next if ($fline =~ /^.(?:\s*(?:case\s+(?:$Ident|$Constant)[\s$;]*|default):[\s$;]*)*$/); + $has_break = 1 if ($rline =~ /fall[\s_-]*(through|thru)/i); + next if ($fline =~ /^.[\s$;]*$/); + $has_statement = 1; + $count++; + $has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/); + } + if (!$has_break && $has_statement) { + WARN("MISSING_BREAK", + "Possible switch case/default not preceeded by break or fallthrough comment\n" . $herecurr); + } + } + +# check for switch/default statements without a break; + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { + my $ctx = ''; + my $herectx = $here . "\n"; + my $cnt = statement_rawlines($stat); + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + WARN("DEFAULT_NO_BREAK", + "switch default: should use break\n" . $herectx); } # check for gcc specific __FUNCTION__ - if ($line =~ /__FUNCTION__/) { - WARN("USE_FUNC", - "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); + if ($line =~ /\b__FUNCTION__\b/) { + if (WARN("USE_FUNC", + "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b__FUNCTION__\b/__func__/g; + } + } + +# check for use of yield() + if ($line =~ /\byield\s*\(\s*\)/) { + WARN("YIELD", + "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr); + } + +# check for comparisons against true and false + if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) { + my $lead = $1; + my $arg = $2; + my $test = $3; + my $otype = $4; + my $trail = $5; + my $op = "!"; + + ($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i); + + my $type = lc($otype); + if ($type =~ /^(?:true|false)$/) { + if (("$test" eq "==" && "$type" eq "true") || + ("$test" eq "!=" && "$type" eq "false")) { + $op = ""; + } + + CHK("BOOL_COMPARISON", + "Using comparison to $otype is error prone\n" . $herecurr); + +## maybe suggesting a correct construct would better +## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); + + } } # check for semaphores initialized locked if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { WARN("CONSIDER_COMPLETION", "consider using a completion\n" . $herecurr); - } + # recommend kstrto* over simple_strto* and strict_strto* if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { WARN("CONSIDER_KSTRTO", "$1 is obsolete, use k$3 instead\n" . $herecurr); } -# check for __initcall(), use device_initcall() explicitly please + +# check for __initcall(), use device_initcall() explicitly or more appropriate function please if ($line =~ /^.\s*__initcall\s*\(/) { WARN("USE_DEVICE_INITCALL", - "please use device_initcall() instead of __initcall()\n" . $herecurr); + "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); } + # check for various ops structs, ensure they are const. my $struct_ops = qr{acpi_dock_ops| address_space_operations| @@ -3307,6 +4620,12 @@ sub process { "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); } +# Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. + if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { + ERROR("DEFINE_ARCH_HAS", + "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); + } + # check for %L{u,d,i} in strings my $string; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { @@ -3346,6 +4665,34 @@ sub process { WARN("EXPORTED_WORLD_WRITABLE", "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); } + +# Mode permission misuses where it seems decimal should be octal +# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop + if ($^V && $^V ge 5.10.0 && + $line =~ /$mode_perms_search/) { + foreach my $entry (@mode_permission_funcs) { + my $func = $entry->[0]; + my $arg_pos = $entry->[1]; + + my $skip_args = ""; + if ($arg_pos > 1) { + $arg_pos--; + $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}"; + } + my $test = "\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]"; + if ($line =~ /$test/) { + my $val = $1; + $val = $6 if ($skip_args ne ""); + + if ($val !~ /^0$/ && + (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || + length($val) ne 4)) { + ERROR("NON_OCTAL_PERMISSIONS", + "Use 4 digit octal (0777) not decimal permissions\n" . $herecurr); + } + } + } + } } # If we have no input at all, then there is nothing to report on @@ -3385,6 +4732,12 @@ sub process { } if ($quiet == 0) { + + if ($^V lt 5.10.0) { + print("NOTE: perl $^V is not modern enough to detect all possible issues.\n"); + print("An upgrade to at least perl v5.10.0 is suggested.\n\n"); + } + # If there were whitespace errors which cleanpatch can fix # then suggest that. if ($rpt_cleaners) { @@ -3394,13 +4747,42 @@ sub process { } } - if (keys %ignore_type) { - print "NOTE: Ignored message types:"; - foreach my $ignore (sort keys %ignore_type) { - print " $ignore"; - } - print "\n"; - print "\n" if ($quiet == 0); + hash_show_words(\%use_type, "Used"); + hash_show_words(\%ignore_type, "Ignored"); + + if ($clean == 0 && $fix && "@rawlines" ne "@fixed") { + my $newfile = $filename; + $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); + my $linecount = 0; + my $f; + + open($f, '>', $newfile) + or die "$P: Can't open $newfile for write\n"; + foreach my $fixed_line (@fixed) { + $linecount++; + if ($file) { + if ($linecount > 3) { + $fixed_line =~ s/^\+//; + print $f $fixed_line. "\n"; + } + } else { + print $f $fixed_line . "\n"; + } + } + close($f); + + if (!$quiet) { + print << "EOM"; +Wrote EXPERIMENTAL --fix correction(s) to '$newfile' + +Do _NOT_ trust the results written to this file. +Do _NOT_ submit these changes without inspecting them for correctness. + +This EXPERIMENTAL file is simply a convenience to help rewrite patches. +No warranties, expressed or implied... + +EOM + } } if ($clean == 1 && $quiet == 0) { diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 17e38439670..c05d586b1fe 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -34,7 +34,7 @@ use strict; # $1 (first bracket) matches the dynamic amount of the stack growth # # use anything else and feel the pain ;) -my (@stack, $re, $dre, $x, $xs); +my (@stack, $re, $dre, $x, $xs, $funcre); { my $arch = shift; if ($arch eq "") { @@ -44,6 +44,7 @@ my (@stack, $re, $dre, $x, $xs); $x = "[0-9a-f]"; # hex character $xs = "[0-9a-f ]"; # hex character or space + $funcre = qr/^$x* <(.*)>:$/; if ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; @@ -66,6 +67,10 @@ my (@stack, $re, $dre, $x, $xs); # 2b6c: 4e56 fb70 linkw %fp,#-1168 # 1df770: defc ffe4 addaw #-28,%sp $re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o; + } elsif ($arch eq 'metag') { + #400026fc: 40 00 00 82 ADD A0StP,A0StP,#0x8 + $re = qr/.*ADD.*A0StP,A0StP,\#(0x$x{1,8})/o; + $funcre = qr/^$x* <[^\$](.*)>:$/; } elsif ($arch eq 'mips64') { #8800402c: 67bdfff0 daddiu sp,sp,-16 $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; @@ -109,7 +114,6 @@ my (@stack, $re, $dre, $x, $xs); # # main() # -my $funcre = qr/^$x* <(.*)>:$/; my ($func, $file, $lastslash); while (my $line = <STDIN>) { @@ -169,4 +173,3 @@ while (my $line = <STDIN>) { # Sort output by size (last field) print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; - diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index d24810fc6af..5b3add31f9f 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -25,7 +25,7 @@ cat << EOF #define __IGNORE_rmdir /* unlinkat */ #define __IGNORE_lchown /* fchownat */ #define __IGNORE_access /* faccessat */ -#define __IGNORE_rename /* renameat */ +#define __IGNORE_rename /* renameat2 */ #define __IGNORE_readlink /* readlinkat */ #define __IGNORE_symlink /* symlinkat */ #define __IGNORE_utimes /* futimesat */ @@ -37,6 +37,9 @@ cat << EOF #define __IGNORE_lstat64 /* fstatat64 */ #endif +/* Missing flags argument */ +#define __IGNORE_renameat /* renameat2 */ + /* CLOEXEC flag */ #define __IGNORE_pipe /* pipe2 */ #define __IGNORE_dup2 /* dup3 */ @@ -200,7 +203,7 @@ EOF syscall_list() { grep '^[0-9]' "$1" | sort -n | ( while read nr abi name entry ; do - echo <<EOF + cat <<EOF #if !defined(__NR_${name}) && !defined(__IGNORE_${name}) #warning syscall ${name} not implemented #endif diff --git a/scripts/coccicheck b/scripts/coccicheck index 823e972149e..bbf901afb60 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -1,28 +1,56 @@ -#!/bin/sh +#!/bin/bash + +# +# This script requires at least spatch +# version 1.0.0-rc11. +# SPATCH="`which ${SPATCH:=spatch}`" +trap kill_running SIGTERM SIGINT +declare -a SPATCH_PID + +# The verbosity may be set by the environmental parameter V= +# as for example with 'make V=1 coccicheck' + +if [ -n "$V" -a "$V" != "0" ]; then + VERBOSE="$V" +else + VERBOSE=0 +fi + +if [ -z "$J" ]; then + NPROC=$(getconf _NPROCESSORS_ONLN) +else + NPROC="$J" +fi + +FLAGS="$SPFLAGS --very-quiet" + +# spatch only allows include directories with the syntax "-I include" +# while gcc also allows "-Iinclude" and "-include include" +COCCIINCLUDE=${LINUXINCLUDE//-I/-I } +COCCIINCLUDE=${COCCIINCLUDE//-include/-I} + if [ "$C" = "1" -o "$C" = "2" ]; then ONLINE=1 -# This requires Coccinelle >= 0.2.3 -# FLAGS="-ignore_unknown_options -very_quiet" -# OPTIONS=$* - -# Workaround for Coccinelle < 0.2.3 - FLAGS="-I $srctree/include -very_quiet" - shift $(( $# - 1 )) - OPTIONS=$1 + # Take only the last argument, which is the C file to test + shift $(( $# - 1 )) + OPTIONS="$COCCIINCLUDE $1" else ONLINE=0 - FLAGS="-very_quiet" if [ "$KBUILD_EXTMOD" = "" ] ; then - OPTIONS="-dir $srctree" + OPTIONS="--dir $srctree $COCCIINCLUDE" else - OPTIONS="-dir $KBUILD_EXTMOD -patch $srctree -I $srctree/include -I $KBUILD_EXTMOD/include" + OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE" fi fi +if [ "$KBUILD_EXTMOD" != "" ] ; then + OPTIONS="--patch $srctree $OPTIONS" +fi + if [ ! -x "$SPATCH" ]; then echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/' exit 1 @@ -30,13 +58,21 @@ fi if [ "$MODE" = "" ] ; then if [ "$ONLINE" = "0" ] ; then - echo 'You have not explicitly specified the mode to use. Using default "chain" mode.' - echo 'All available modes will be tried (in that order): patch, report, context, org' + echo 'You have not explicitly specified the mode to use. Using default "report" mode.' + echo 'Available modes are the following: patch, report, context, org' echo 'You can specify the mode with "make coccicheck MODE=<mode>"' + echo 'Note however that some modes are not implemented by some semantic patches.' + fi + MODE="report" +fi + +if [ "$MODE" = "chain" ] ; then + if [ "$ONLINE" = "0" ] ; then + echo 'You have selected the "chain" mode.' + echo 'All available modes will be tried (in that order): patch, report, context, org' fi - MODE="chain" elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then - FLAGS="$FLAGS -no_show_diff" + FLAGS="$FLAGS --no-show-diff" fi if [ "$ONLINE" = "0" ] ; then @@ -46,16 +82,40 @@ if [ "$ONLINE" = "0" ] ; then echo '' fi +run_cmd() { + local i + if [ $VERBOSE -ne 0 ] ; then + echo "Running ($NPROC in parallel): $@" + fi + for i in $(seq 0 $(( NPROC - 1)) ); do + eval "$@ --max $NPROC --index $i &" + SPATCH_PID[$i]=$! + if [ $VERBOSE -eq 2 ] ; then + echo "${SPATCH_PID[$i]} running" + fi + done + wait +} + +kill_running() { + for i in $(seq $(( NPROC - 1 )) ); do + if [ $VERBOSE -eq 2 ] ; then + echo "Killing ${SPATCH_PID[$i]}" + fi + kill ${SPATCH_PID[$i]} 2>/dev/null + done +} + coccinelle () { COCCI="$1" OPT=`grep "Option" $COCCI | cut -d':' -f2` -# The option '-parse_cocci' can be used to syntactically check the SmPL files. +# The option '--parse-cocci' can be used to syntactically check the SmPL files. # # $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null - if [ "$ONLINE" = "0" ] ; then + if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then FILE=`echo $COCCI | sed "s|$srctree/||"` @@ -91,12 +151,21 @@ coccinelle () { fi if [ "$MODE" = "chain" ] ; then - $SPATCH -D patch $FLAGS -sp_file $COCCI $OPT $OPTIONS || \ - $SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \ - $SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \ - $SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1 + run_cmd $SPATCH -D patch \ + $FLAGS --cocci-file $COCCI $OPT $OPTIONS || \ + run_cmd $SPATCH -D report \ + $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || \ + run_cmd $SPATCH -D context \ + $FLAGS --cocci-file $COCCI $OPT $OPTIONS || \ + run_cmd $SPATCH -D org \ + $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || exit 1 + elif [ "$MODE" = "rep+ctxt" ] ; then + run_cmd $SPATCH -D report \ + $FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff && \ + run_cmd $SPATCH -D context \ + $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1 else - $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1 + run_cmd $SPATCH -D $MODE $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1 fi } diff --git a/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci b/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci index 7d4771d449c..bd5d08b882e 100644 --- a/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci +++ b/scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci @@ -5,7 +5,7 @@ // Confidence: High // Copyright: 2009,2010 Nicolas Palix, DIKU. GPLv2. // URL: http://coccinelle.lip6.fr/ -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers // // Keywords: kmalloc, kzalloc, kcalloc // Version min: < 2.6.12 kmalloc diff --git a/scripts/coccinelle/api/alloc/kzalloc-simple.cocci b/scripts/coccinelle/api/alloc/kzalloc-simple.cocci index 046b9b16f8f..52c55e4fa67 100644 --- a/scripts/coccinelle/api/alloc/kzalloc-simple.cocci +++ b/scripts/coccinelle/api/alloc/kzalloc-simple.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. GPLv2. // Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/rules/kzalloc.html -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers // // Keywords: kmalloc, kzalloc // Version min: < 2.6.12 kmalloc diff --git a/scripts/coccinelle/api/d_find_alias.cocci b/scripts/coccinelle/api/d_find_alias.cocci new file mode 100644 index 00000000000..9594c9f7eb8 --- /dev/null +++ b/scripts/coccinelle/api/d_find_alias.cocci @@ -0,0 +1,80 @@ +/// Make sure calls to d_find_alias() have a corresponding call to dput(). +// +// Keywords: d_find_alias, dput +// +// Confidence: Moderate +// URL: http://coccinelle.lip6.fr/ +// Options: --include-headers + +virtual context +virtual org +virtual patch +virtual report + +@r exists@ +local idexpression struct dentry *dent; +expression E, E1; +statement S1, S2; +position p1, p2; +@@ +( + if (!(dent@p1 = d_find_alias(...))) S1 +| + dent@p1 = d_find_alias(...) +) + +<...when != dput(dent) + when != if (...) { <+... dput(dent) ...+> } + when != true !dent || ... + when != dent = E + when != E = dent +if (!dent || ...) S2 +...> +( + return <+...dent...+>; +| + return @p2 ...; +| + dent@p2 = E1; +| + E1 = dent; +) + +@depends on context@ +local idexpression struct dentry *r.dent; +position r.p1,r.p2; +@@ +* dent@p1 = ... + ... +( +* return@p2 ...; +| +* dent@p2 +) + + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ +cocci.print_main("Missing call to dput()",p1) +cocci.print_secs("",p2) + +@depends on patch@ +local idexpression struct dentry *r.dent; +position r.p2; +@@ +( ++ dput(dent); + return @p2 ...; +| ++ dput(dent); + dent@p2 = ...; +) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ +msg = "Missing call to dput() at line %s." +coccilib.report.print_report(p1[0], msg % (p2[0].line)) diff --git a/scripts/coccinelle/api/devm_ioremap_resource.cocci b/scripts/coccinelle/api/devm_ioremap_resource.cocci new file mode 100644 index 00000000000..495daa3dbf7 --- /dev/null +++ b/scripts/coccinelle/api/devm_ioremap_resource.cocci @@ -0,0 +1,90 @@ +virtual patch +virtual report + +@depends on patch@ +expression base, dev, res; +@@ + +-base = devm_request_and_ioremap(dev, res); ++base = devm_ioremap_resource(dev, res); + ... + if ( +-base == NULL ++IS_ERR(base) + || ...) { +<... +- return ...; ++ return PTR_ERR(base); +...> + } + +@depends on patch@ +expression e, E, ret; +identifier l; +@@ + + e = devm_ioremap_resource(...); + ... + if (IS_ERR(e) || ...) { + ... when any +- ret = E; ++ ret = PTR_ERR(e); + ... +( + return ret; +| + goto l; +) + } + +@depends on patch@ +expression e; +@@ + + e = devm_ioremap_resource(...); + ... + if (IS_ERR(e) || ...) { + ... +- \(dev_dbg\|dev_err\|pr_debug\|pr_err\|DRM_ERROR\)(...); + ... + } + +@depends on patch@ +expression e; +identifier l; +@@ + + e = devm_ioremap_resource(...); + ... + if (IS_ERR(e) || ...) +-{ +( + return ...; +| + goto l; +) +-} + +@r depends on report@ +expression e; +identifier l; +position p1; +@@ + +*e = devm_request_and_ioremap@p1(...); + ... + if (e == NULL || ...) { + ... +( + return ...; +| + goto l; +) + } + +@script:python depends on r@ +p1 << r.p1; +@@ + +msg = "ERROR: deprecated devm_request_and_ioremap() API used on line %s" % (p1[0].line) +coccilib.report.print_report(p1[0], msg) diff --git a/scripts/coccinelle/api/devm_request_and_ioremap.cocci b/scripts/coccinelle/api/devm_request_and_ioremap.cocci deleted file mode 100644 index 46beb81406a..00000000000 --- a/scripts/coccinelle/api/devm_request_and_ioremap.cocci +++ /dev/null @@ -1,105 +0,0 @@ -/// Reimplement a call to devm_request_mem_region followed by a call to ioremap -/// or ioremap_nocache by a call to devm_request_and_ioremap. -/// Devm_request_and_ioremap was introduced in -/// 72f8c0bfa0de64c68ee59f40eb9b2683bffffbb0. It makes the code much more -/// concise. -/// -/// -// Confidence: High -// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6. GPLv2. -// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. GPLv2. -// URL: http://coccinelle.lip6.fr/ -// Comments: -// Options: -no_includes -include_headers - -virtual patch -virtual org -virtual report -virtual context - -@nm@ -expression myname; -identifier i; -@@ - -struct platform_driver i = { .driver = { .name = myname } }; - -@depends on patch@ -expression dev,res,size; -@@ - --if (!devm_request_mem_region(dev, res->start, size, -- \(res->name\|dev_name(dev)\))) { -- ... -- return ...; --} -... when != res->start -( --devm_ioremap(dev,res->start,size) -+devm_request_and_ioremap(dev,res) -| --devm_ioremap_nocache(dev,res->start,size) -+devm_request_and_ioremap(dev,res) -) -... when any - when != res->start - -// this rule is separate from the previous one, because a single file can -// have multiple values of myname -@depends on patch@ -expression dev,res,size; -expression nm.myname; -@@ - --if (!devm_request_mem_region(dev, res->start, size,myname)) { -- ... -- return ...; --} -... when != res->start -( --devm_ioremap(dev,res->start,size) -+devm_request_and_ioremap(dev,res) -| --devm_ioremap_nocache(dev,res->start,size) -+devm_request_and_ioremap(dev,res) -) -... when any - when != res->start - - -@pb depends on org || report || context@ -expression dev,res,size; -expression nm.myname; -position p1,p2; -@@ - -*if - (!devm_request_mem_region@p1(dev, res->start, size, - \(res->name\|dev_name(dev)\|myname\))) { - ... - return ...; -} -... when != res->start -( -*devm_ioremap@p2(dev,res->start,size) -| -*devm_ioremap_nocache@p2(dev,res->start,size) -) -... when any - when != res->start - -@script:python depends on org@ -p1 << pb.p1; -p2 << pb.p2; -@@ - -cocci.print_main("INFO: replace by devm_request_and_ioremap",p1) -cocci.print_secs("",p2) - -@script:python depends on report@ -p1 << pb.p1; -p2 << pb.p2; -@@ - -msg = "INFO: devm_request_mem_region followed by ioremap on line %s can be replaced by devm_request_and_ioremap" % (p2[0].line) -coccilib.report.print_report(p1[0],msg) diff --git a/scripts/coccinelle/api/kstrdup.cocci b/scripts/coccinelle/api/kstrdup.cocci index 07a74b2c619..09cba54ed0c 100644 --- a/scripts/coccinelle/api/kstrdup.cocci +++ b/scripts/coccinelle/api/kstrdup.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci index 4dceab6d54d..3d1aa71b757 100644 --- a/scripts/coccinelle/api/memdup.cocci +++ b/scripts/coccinelle/api/memdup.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci index 2efac289fd5..c606231b0e4 100644 --- a/scripts/coccinelle/api/memdup_user.cocci +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context @@ -51,10 +51,10 @@ statement S1,S2; p << r.p; @@ -coccilib.org.print_todo(p[0], "WARNING opportunity for memdep_user") +coccilib.org.print_todo(p[0], "WARNING opportunity for memdup_user") @script:python depends on report@ p << r.p; @@ -coccilib.report.print_report(p[0], "WARNING opportunity for memdep_user") +coccilib.report.print_report(p[0], "WARNING opportunity for memdup_user") diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci new file mode 100644 index 00000000000..f01789e967e --- /dev/null +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -0,0 +1,109 @@ +/// Make sure pm_runtime_* calls does not use unnecessary IS_ERR_VALUE +// +// Keywords: pm_runtime +// Confidence: Medium +// Copyright (C) 2013 Texas Instruments Incorporated - GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Options: --include-headers + +virtual patch +virtual context +virtual org +virtual report + +//---------------------------------------------------------- +// Detection +//---------------------------------------------------------- + +@runtime_bad_err_handle exists@ +expression ret; +@@ +( +ret = \(pm_runtime_idle\| + pm_runtime_suspend\| + pm_runtime_autosuspend\| + pm_runtime_resume\| + pm_request_idle\| + pm_request_resume\| + pm_request_autosuspend\| + pm_runtime_get\| + pm_runtime_get_sync\| + pm_runtime_put\| + pm_runtime_put_autosuspend\| + pm_runtime_put_sync\| + pm_runtime_put_sync_suspend\| + pm_runtime_put_sync_autosuspend\| + pm_runtime_set_active\| + pm_schedule_suspend\| + pm_runtime_barrier\| + pm_generic_runtime_suspend\| + pm_generic_runtime_resume\)(...); +... +IS_ERR_VALUE(ret) +... +) + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on runtime_bad_err_handle && context@ +identifier pm_runtime_api; +expression ret; +@@ +( +ret = pm_runtime_api(...); +... +* IS_ERR_VALUE(ret) +... +) + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on runtime_bad_err_handle && patch@ +identifier pm_runtime_api; +expression ret; +@@ +( +ret = pm_runtime_api(...); +... +- IS_ERR_VALUE(ret) ++ ret < 0 +... +) + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on runtime_bad_err_handle exists@ +position p1, p2; +identifier pm_runtime_api; +expression ret; +@@ +( +ret = pm_runtime_api@p1(...); +... +IS_ERR_VALUE@p2(ret) +... +) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +pm_runtime_api << r.pm_runtime_api; +@@ + +cocci.print_main(pm_runtime_api,p1) +cocci.print_secs("IS_ERR_VALUE",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +pm_runtime_api << r.pm_runtime_api; +@@ + +msg = "%s returns < 0 as error. Unecessary IS_ERR_VALUE at line %s" % (pm_runtime_api, p2[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci new file mode 100644 index 00000000000..dd58dab5d41 --- /dev/null +++ b/scripts/coccinelle/api/ptr_ret.cocci @@ -0,0 +1,96 @@ +/// +/// Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Options: --no-includes --include-headers +// +// Keywords: ERR_PTR, PTR_ERR, PTR_ERR_OR_ZERO +// Version min: 2.6.39 +// + +virtual context +virtual patch +virtual org +virtual report + +@depends on patch@ +expression ptr; +@@ + +- if (IS_ERR(ptr)) return PTR_ERR(ptr); else return 0; ++ return PTR_ERR_OR_ZERO(ptr); + +@depends on patch@ +expression ptr; +@@ + +- if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; ++ return PTR_ERR_OR_ZERO(ptr); + +@depends on patch@ +expression ptr; +@@ + +- (IS_ERR(ptr) ? PTR_ERR(ptr) : 0) ++ PTR_ERR_OR_ZERO(ptr) + +@r1 depends on !patch@ +expression ptr; +position p1; +@@ + +* if@p1 (IS_ERR(ptr)) return PTR_ERR(ptr); else return 0; + +@r2 depends on !patch@ +expression ptr; +position p2; +@@ + +* if@p2 (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; + +@r3 depends on !patch@ +expression ptr; +position p3; +@@ + +* IS_ERR@p3(ptr) ? PTR_ERR(ptr) : 0 + +@script:python depends on org@ +p << r1.p1; +@@ + +coccilib.org.print_todo(p[0], "WARNING: PTR_ERR_OR_ZERO can be used") + + +@script:python depends on org@ +p << r2.p2; +@@ + +coccilib.org.print_todo(p[0], "WARNING: PTR_ERR_OR_ZERO can be used") + +@script:python depends on org@ +p << r3.p3; +@@ + +coccilib.org.print_todo(p[0], "WARNING: PTR_ERR_OR_ZERO can be used") + +@script:python depends on report@ +p << r1.p1; +@@ + +coccilib.report.print_report(p[0], "WARNING: PTR_ERR_OR_ZERO can be used") + +@script:python depends on report@ +p << r2.p2; +@@ + +coccilib.report.print_report(p[0], "WARNING: PTR_ERR_OR_ZERO can be used") + +@script:python depends on report@ +p << r3.p3; +@@ + +coccilib.report.print_report(p[0], "WARNING: PTR_ERR_OR_ZERO can be used") diff --git a/scripts/coccinelle/api/simple_open.cocci b/scripts/coccinelle/api/simple_open.cocci new file mode 100644 index 00000000000..b67e174f3d9 --- /dev/null +++ b/scripts/coccinelle/api/simple_open.cocci @@ -0,0 +1,70 @@ +/// This removes an open coded simple_open() function +/// and replaces file operations references to the function +/// with simple_open() instead. +/// +// Confidence: High +// Comments: +// Options: --no-includes --include-headers + +virtual patch +virtual report + +@ open depends on patch @ +identifier open_f != simple_open; +identifier i, f; +@@ +-int open_f(struct inode *i, struct file *f) +-{ +( +-if (i->i_private) +-f->private_data = i->i_private; +| +-f->private_data = i->i_private; +) +-return 0; +-} + +@ has_open depends on open @ +identifier fops; +identifier open.open_f; +@@ +struct file_operations fops = { +..., +-.open = open_f, ++.open = simple_open, +... +}; + +@ openr depends on report @ +identifier open_f != simple_open; +identifier i, f; +position p; +@@ +int open_f@p(struct inode *i, struct file *f) +{ +( +if (i->i_private) +f->private_data = i->i_private; +| +f->private_data = i->i_private; +) +return 0; +} + +@ has_openr depends on openr @ +identifier fops; +identifier openr.open_f; +position p; +@@ +struct file_operations fops = { +..., +.open = open_f@p, +... +}; + +@script:python@ +pf << openr.p; +ps << has_openr.p; +@@ + +coccilib.report.print_report(pf[0],"WARNING opportunity for simple_open, see also structure on line %s"%(ps[0].line)) diff --git a/scripts/coccinelle/free/clk_put.cocci b/scripts/coccinelle/free/clk_put.cocci new file mode 100644 index 00000000000..46747adfd20 --- /dev/null +++ b/scripts/coccinelle/free/clk_put.cocci @@ -0,0 +1,67 @@ +/// Find missing clk_puts. +/// +//# This only signals a missing clk_put when there is a clk_put later +//# in the same function. +//# False positives can be due to loops. +// +// Confidence: Moderate +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: + +virtual context +virtual org +virtual report + +@clk@ +expression e; +statement S,S1; +int ret; +position p1,p2,p3; +@@ + +e = clk_get@p1(...) +... when != clk_put(e) +if (<+...e...+>) S +... when any + when != clk_put(e) + when != if (...) { ... clk_put(e); ... } +( + if (ret == 0) S1 +| +if (...) + { ... + return 0; } +| +if (...) + { ... + return <+...e...+>; } +| +*if@p2 (...) + { ... when != clk_put(e) + when forall + return@p3 ...; } +) +... when any +clk_put(e); + +@script:python depends on org@ +p1 << clk.p1; +p2 << clk.p2; +p3 << clk.p3; +@@ + +cocci.print_main("clk_get",p1) +cocci.print_secs("if",p2) +cocci.print_secs("needed clk_put",p3) + +@script:python depends on report@ +p1 << clk.p1; +p2 << clk.p2; +p3 << clk.p3; +@@ + +msg = "ERROR: missing clk_put; clk_get on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line) +coccilib.report.print_report(p3[0],msg) diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci index 0a1e36146d7..3d9349012bb 100644 --- a/scripts/coccinelle/free/devm_free.cocci +++ b/scripts/coccinelle/free/devm_free.cocci @@ -18,7 +18,7 @@ // Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual org virtual report diff --git a/scripts/coccinelle/free/iounmap.cocci b/scripts/coccinelle/free/iounmap.cocci new file mode 100644 index 00000000000..5384f4ba119 --- /dev/null +++ b/scripts/coccinelle/free/iounmap.cocci @@ -0,0 +1,67 @@ +/// Find missing iounmaps. +/// +//# This only signals a missing iounmap when there is an iounmap later +//# in the same function. +//# False positives can be due to loops. +// +// Confidence: Moderate +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: + +virtual context +virtual org +virtual report + +@iom@ +expression e; +statement S,S1; +int ret; +position p1,p2,p3; +@@ + +e = \(ioremap@p1\|ioremap_nocache@p1\)(...) +... when != iounmap(e) +if (<+...e...+>) S +... when any + when != iounmap(e) + when != if (...) { ... iounmap(e); ... } +( + if (ret == 0) S1 +| +if (...) + { ... + return 0; } +| +if (...) + { ... + return <+...e...+>; } +| +*if@p2 (...) + { ... when != iounmap(e) + when forall + return@p3 ...; } +) +... when any +iounmap(e); + +@script:python depends on org@ +p1 << iom.p1; +p2 << iom.p2; +p3 << iom.p3; +@@ + +cocci.print_main("ioremap",p1) +cocci.print_secs("if",p2) +cocci.print_secs("needed iounmap",p3) + +@script:python depends on report@ +p1 << iom.p1; +p2 << iom.p2; +p3 << iom.p3; +@@ + +msg = "ERROR: missing iounmap; ioremap on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line) +coccilib.report.print_report(p3[0],msg) diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci index d9ae6d89c2f..577b7805699 100644 --- a/scripts/coccinelle/free/kfree.cocci +++ b/scripts/coccinelle/free/kfree.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual org virtual report diff --git a/scripts/coccinelle/free/kfreeaddr.cocci b/scripts/coccinelle/free/kfreeaddr.cocci new file mode 100644 index 00000000000..ce8aacc314c --- /dev/null +++ b/scripts/coccinelle/free/kfreeaddr.cocci @@ -0,0 +1,32 @@ +/// Free of a structure field +/// +// Confidence: High +// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r depends on context || report || org @ +expression e; +identifier f; +position p; +@@ + +* kfree@p(&e->f) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("kfree",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: kfree of structure field" +coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/free/pci_free_consistent.cocci b/scripts/coccinelle/free/pci_free_consistent.cocci new file mode 100644 index 00000000000..43600ccb62a --- /dev/null +++ b/scripts/coccinelle/free/pci_free_consistent.cocci @@ -0,0 +1,52 @@ +/// Find missing pci_free_consistent for every pci_alloc_consistent. +/// +// Confidence: Moderate +// Copyright: (C) 2013 Petr Strnad. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Keywords: pci_free_consistent, pci_alloc_consistent +// Options: --no-includes --include-headers + +virtual report +virtual org + +@search@ +local idexpression id; +expression x,y,z,e; +position p1,p2; +type T; +@@ + +id = pci_alloc_consistent@p1(x,y,&z) +... when != e = id +if (id == NULL || ...) { ... return ...; } +... when != pci_free_consistent(x,y,id,z) + when != if (id) { ... pci_free_consistent(x,y,id,z) ... } + when != if (y) { ... pci_free_consistent(x,y,id,z) ... } + when != e = (T)id + when exists +( +return 0; +| +return 1; +| +return id; +| +return@p2 ...; +) + +@script:python depends on report@ +p1 << search.p1; +p2 << search.p2; +@@ + +msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line) +coccilib.report.print_report(p2[0],msg) + +@script:python depends on org@ +p1 << search.p1; +p2 << search.p2; +@@ + +msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line) +cocci.print_main(msg,p1) +cocci.print_secs("",p2) diff --git a/scripts/coccinelle/iterators/fen.cocci b/scripts/coccinelle/iterators/fen.cocci index 0a40af828c4..48c152f224e 100644 --- a/scripts/coccinelle/iterators/fen.cocci +++ b/scripts/coccinelle/iterators/fen.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context diff --git a/scripts/coccinelle/iterators/itnull.cocci b/scripts/coccinelle/iterators/itnull.cocci index 259899f6838..f58732b56a4 100644 --- a/scripts/coccinelle/iterators/itnull.cocci +++ b/scripts/coccinelle/iterators/itnull.cocci @@ -11,7 +11,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context diff --git a/scripts/coccinelle/iterators/list_entry_update.cocci b/scripts/coccinelle/iterators/list_entry_update.cocci index b2967475679..873f444e713 100644 --- a/scripts/coccinelle/iterators/list_entry_update.cocci +++ b/scripts/coccinelle/iterators/list_entry_update.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual context virtual org diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci new file mode 100644 index 00000000000..f085f5968c5 --- /dev/null +++ b/scripts/coccinelle/iterators/use_after_iter.cocci @@ -0,0 +1,147 @@ +/// If list_for_each_entry, etc complete a traversal of the list, the iterator +/// variable ends up pointing to an address at an offset from the list head, +/// and not a meaningful structure. Thus this value should not be used after +/// the end of the iterator. +//#False positives arise when there is a goto in the iterator and the +//#reported reference is at the label of this goto. Some flag tests +//#may also cause a report to be a false positive. +/// +// Confidence: Moderate +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual context +virtual org +virtual report + +@r exists@ +identifier c,member; +expression E,x; +iterator name list_for_each_entry; +iterator name list_for_each_entry_reverse; +iterator name list_for_each_entry_continue; +iterator name list_for_each_entry_continue_reverse; +iterator name list_for_each_entry_from; +iterator name list_for_each_entry_safe; +iterator name list_for_each_entry_safe_continue; +iterator name list_for_each_entry_safe_from; +iterator name list_for_each_entry_safe_reverse; +iterator name hlist_for_each_entry; +iterator name hlist_for_each_entry_continue; +iterator name hlist_for_each_entry_from; +iterator name hlist_for_each_entry_safe; +statement S; +position p1,p2; +@@ + +( +list_for_each_entry@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_reverse@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_continue@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_continue_reverse@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_from@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_safe@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_safe_continue@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_safe_from@p1(c,...,member) { ... when != break; + when forall + when strict +} +| +list_for_each_entry_safe_reverse@p1(c,...,member) { ... when != break; + when forall + when strict +} +) +... +( +list_for_each_entry(c,...) S +| +list_for_each_entry_reverse(c,...) S +| +list_for_each_entry_continue(c,...) S +| +list_for_each_entry_continue_reverse(c,...) S +| +list_for_each_entry_from(c,...) S +| +list_for_each_entry_safe(c,...) S +| +list_for_each_entry_safe(x,c,...) S +| +list_for_each_entry_safe_continue(c,...) S +| +list_for_each_entry_safe_continue(x,c,...) S +| +list_for_each_entry_safe_from(c,...) S +| +list_for_each_entry_safe_from(x,c,...) S +| +list_for_each_entry_safe_reverse(c,...) S +| +list_for_each_entry_safe_reverse(x,c,...) S +| +hlist_for_each_entry(c,...) S +| +hlist_for_each_entry_continue(c,...) S +| +hlist_for_each_entry_from(c,...) S +| +hlist_for_each_entry_safe(c,...) S +| +list_remove_head(x,c,...) +| +sizeof(<+...c...+>) +| +&c->member +| +c = E +| +*c@p2 +) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("invalid iterator index reference",p2) +cocci.print_secs("iterator",p1) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "ERROR: invalid reference to the index variable of the iterator on line %s" % (p1[0].line) +coccilib.report.print_report(p2[0], msg) diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci index 8f10b49603c..669b2443624 100644 --- a/scripts/coccinelle/locks/call_kern.cocci +++ b/scripts/coccinelle/locks/call_kern.cocci @@ -9,7 +9,7 @@ // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context diff --git a/scripts/coccinelle/locks/double_lock.cocci b/scripts/coccinelle/locks/double_lock.cocci index 63b24e682fa..002752f97dc 100644 --- a/scripts/coccinelle/locks/double_lock.cocci +++ b/scripts/coccinelle/locks/double_lock.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual org virtual report diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci index 1c4ffe6fd84..debd70e4626 100644 --- a/scripts/coccinelle/locks/flags.cocci +++ b/scripts/coccinelle/locks/flags.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual context virtual org diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci index 3267d7410bd..47f649b0ea8 100644 --- a/scripts/coccinelle/locks/mini_lock.cocci +++ b/scripts/coccinelle/locks/mini_lock.cocci @@ -11,7 +11,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual context virtual org diff --git a/scripts/coccinelle/misc/boolinit.cocci b/scripts/coccinelle/misc/boolinit.cocci new file mode 100644 index 00000000000..b9abed49cd9 --- /dev/null +++ b/scripts/coccinelle/misc/boolinit.cocci @@ -0,0 +1,178 @@ +/// Bool initializations should use true and false. Bool tests don't need +/// comparisons. Based on contributions from Joe Perches, Rusty Russell +/// and Bruce W Allan. +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Options: --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on patch@ +bool t; +symbol true; +symbol false; +@@ + +( +- t == true ++ t +| +- true == t ++ t +| +- t != true ++ !t +| +- true != t ++ !t +| +- t == false ++ !t +| +- false == t ++ !t +| +- t != false ++ t +| +- false != t ++ t +) + +@depends on patch disable is_zero, isnt_zero@ +bool t; +@@ + +( +- t == 1 ++ t +| +- t != 1 ++ !t +| +- t == 0 ++ !t +| +- t != 0 ++ t +) + +@depends on patch@ +bool b; +@@ +( + b = +- 0 ++ false +| + b = +- 1 ++ true +) + +// --------------------------------------------------------------------- + +@r1 depends on !patch@ +bool t; +position p; +@@ + +( +* t@p == true +| +* true == t@p +| +* t@p != true +| +* true != t@p +| +* t@p == false +| +* false == t@p +| +* t@p != false +| +* false != t@p +) + +@r2 depends on !patch disable is_zero, isnt_zero@ +bool t; +position p; +@@ + +( +* t@p == 1 +| +* t@p != 1 +| +* t@p == 0 +| +* t@p != 0 +) + +@r3 depends on !patch@ +bool b; +position p1,p2; +constant c; +@@ +( +*b@p1 = 0 +| +*b@p1 = 1 +| +*b@p2 = c +) + +@script:python depends on org@ +p << r1.p; +@@ + +cocci.print_main("WARNING: Comparison to bool",p) + +@script:python depends on org@ +p << r2.p; +@@ + +cocci.print_main("WARNING: Comparison of bool to 0/1",p) + +@script:python depends on org@ +p1 << r3.p1; +@@ + +cocci.print_main("WARNING: Assignment of bool to 0/1",p1) + +@script:python depends on org@ +p2 << r3.p2; +@@ + +cocci.print_main("ERROR: Assignment of bool to non-0/1 constant",p2) + +@script:python depends on report@ +p << r1.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: Comparison to bool") + +@script:python depends on report@ +p << r2.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: Comparison of bool to 0/1") + +@script:python depends on report@ +p1 << r3.p1; +@@ + +coccilib.report.print_report(p1[0],"WARNING: Assignment of bool to 0/1") + +@script:python depends on report@ +p2 << r3.p2; +@@ + +coccilib.report.print_report(p2[0],"ERROR: Assignment of bool to non-0/1 constant") diff --git a/scripts/coccinelle/misc/boolreturn.cocci b/scripts/coccinelle/misc/boolreturn.cocci new file mode 100644 index 00000000000..a43c7b0c36e --- /dev/null +++ b/scripts/coccinelle/misc/boolreturn.cocci @@ -0,0 +1,58 @@ +/// Return statements in functions returning bool should use +/// true/false instead of 1/0. +// +// Confidence: High +// Options: --no-includes --include-headers + +virtual patch +virtual report +virtual context + +@r1 depends on patch@ +identifier fn; +typedef bool; +symbol false; +symbol true; +@@ + +bool fn ( ... ) +{ +<... +return +( +- 0 ++ false +| +- 1 ++ true +) + ; +...> +} + +@r2 depends on report || context@ +identifier fn; +position p; +@@ + +bool fn ( ... ) +{ +<... +return +( +* 0@p +| +* 1@p +) + ; +...> +} + + +@script:python depends on report@ +p << r2.p; +fn << r2.fn; +@@ + +msg = "WARNING: return of 0/1 in function '%s' with return type bool" % fn +coccilib.report.print_report(p[0], msg) diff --git a/scripts/coccinelle/misc/cstptr.cocci b/scripts/coccinelle/misc/cstptr.cocci new file mode 100644 index 00000000000..f0368b3d456 --- /dev/null +++ b/scripts/coccinelle/misc/cstptr.cocci @@ -0,0 +1,41 @@ +/// PTR_ERR should be applied before its argument is reassigned, typically +/// to NULL +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r exists@ +expression e,e1; +constant c; +position p1,p2; +@@ + +*e@p1 = c +... when != e = e1 + when != &e + when != true IS_ERR(e) +*PTR_ERR@p2(e) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("PTR_ERR",p2) +cocci.print_secs("assignment",p1) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "ERROR: PTR_ERR applied after initialization to constant on line %s" % (p1[0].line) +coccilib.report.print_report(p2[0],msg) diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci index cf74a00cf59..c0c3371d25e 100644 --- a/scripts/coccinelle/misc/doubleinit.cocci +++ b/scripts/coccinelle/misc/doubleinit.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual org virtual report diff --git a/scripts/coccinelle/misc/ifaddr.cocci b/scripts/coccinelle/misc/ifaddr.cocci new file mode 100644 index 00000000000..8aebd1875e7 --- /dev/null +++ b/scripts/coccinelle/misc/ifaddr.cocci @@ -0,0 +1,35 @@ +/// the address of a variable or field is non-zero is likely always to bo +/// non-zero +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r@ +expression x; +statement S1,S2; +position p; +@@ + +*if@p (&x) + S1 else S2 + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("test of a variable/field address",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: test of a variable/field address" +coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/misc/ifcol.cocci b/scripts/coccinelle/misc/ifcol.cocci index b7ed91dbeb9..d0d00ef1f12 100644 --- a/scripts/coccinelle/misc/ifcol.cocci +++ b/scripts/coccinelle/misc/ifcol.cocci @@ -13,7 +13,7 @@ // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual org virtual report diff --git a/scripts/coccinelle/misc/irqf_oneshot.cocci b/scripts/coccinelle/misc/irqf_oneshot.cocci new file mode 100644 index 00000000000..6cfde94be0e --- /dev/null +++ b/scripts/coccinelle/misc/irqf_oneshot.cocci @@ -0,0 +1,65 @@ +/// Make sure threaded IRQs without a primary handler are always request with +/// IRQF_ONESHOT +/// +// +// Confidence: Good +// Comments: +// Options: --no-includes + +virtual patch +virtual context +virtual org +virtual report + +@r1@ +expression irq; +expression thread_fn; +expression flags; +position p; +@@ +request_threaded_irq@p(irq, NULL, thread_fn, +( +flags | IRQF_ONESHOT +| +IRQF_ONESHOT +) +, ...) + +@depends on patch@ +expression irq; +expression thread_fn; +expression flags; +position p != r1.p; +@@ +request_threaded_irq@p(irq, NULL, thread_fn, +( +-0 ++IRQF_ONESHOT +| +-flags ++flags | IRQF_ONESHOT +) +, ...) + +@depends on context@ +position p != r1.p; +@@ +*request_threaded_irq@p(...) + +@match depends on report || org@ +expression irq; +position p != r1.p; +@@ +request_threaded_irq@p(irq, NULL, ...) + +@script:python depends on org@ +p << match.p; +@@ +msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT" +coccilib.org.print_todo(p[0],msg) + +@script:python depends on report@ +p << match.p; +@@ +msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT" +coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/misc/noderef.cocci b/scripts/coccinelle/misc/noderef.cocci new file mode 100644 index 00000000000..80a831c9116 --- /dev/null +++ b/scripts/coccinelle/misc/noderef.cocci @@ -0,0 +1,65 @@ +/// sizeof when applied to a pointer typed expression gives the size of +/// the pointer +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context +virtual patch + +@depends on patch@ +expression *x; +expression f; +type T; +@@ + +( +x = <+... sizeof( +- x ++ *x + ) ...+> +| +f(...,(T)(x),...,sizeof( +- x ++ *x + ),...) +| +f(...,sizeof(x),...,(T)( +- x ++ *x + ),...) +) + +@r depends on !patch@ +expression *x; +expression f; +position p; +type T; +@@ + +( +*x = <+... sizeof@p(x) ...+> +| +*f(...,(T)(x),...,sizeof@p(x),...) +| +*f(...,sizeof@p(x),...,(T)(x),...) +) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("application of sizeof to pointer",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: application of sizeof to pointer" +coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/misc/of_table.cocci b/scripts/coccinelle/misc/of_table.cocci new file mode 100644 index 00000000000..3c934046a06 --- /dev/null +++ b/scripts/coccinelle/misc/of_table.cocci @@ -0,0 +1,62 @@ +/// Make sure of_device_id tables are NULL terminated +// +// Keywords: of_table +// Confidence: Medium +// Options: --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on context@ +identifier var, arr; +expression E; +@@ +struct of_device_id arr[] = { + ..., + { + .var = E, +* } +}; + +@depends on patch@ +identifier var, arr; +expression E; +@@ +struct of_device_id arr[] = { + ..., + { + .var = E, +- } ++ }, ++ { } +}; + +@r depends on org || report@ +position p1; +identifier var, arr; +expression E; +@@ +struct of_device_id arr[] = { + ..., + { + .var = E, + } + @p1 +}; + +@script:python depends on org@ +p1 << r.p1; +arr << r.arr; +@@ + +cocci.print_main(arr,p1) + +@script:python depends on report@ +p1 << r.p1; +arr << r.arr; +@@ + +msg = "%s is not NULL terminated at line %s" % (arr, p1[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/coccinelle/misc/orplus.cocci b/scripts/coccinelle/misc/orplus.cocci new file mode 100644 index 00000000000..81fabf37939 --- /dev/null +++ b/scripts/coccinelle/misc/orplus.cocci @@ -0,0 +1,55 @@ +/// Check for constants that are added but are used elsewhere as bitmasks +/// The results should be checked manually to ensure that the nonzero +/// bits in the two constants are actually disjoint. +/// +// Confidence: Moderate +// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2013 Gilles Muller, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r@ +constant c; +identifier i; +expression e; +@@ + +( +e | c@i +| +e & c@i +| +e |= c@i +| +e &= c@i +) + +@s@ +constant r.c,c1; +identifier i1; +position p; +@@ + +( + c1 + c - 1 +| +*c1@i1 +@p c +) + +@script:python depends on org@ +p << s.p; +@@ + +cocci.print_main("sum of probable bitmasks, consider |",p) + +@script:python depends on report@ +p << s.p; +@@ + +msg = "WARNING: sum of probable bitmasks, consider |" +coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/misc/returnvar.cocci b/scripts/coccinelle/misc/returnvar.cocci new file mode 100644 index 00000000000..605955a91c4 --- /dev/null +++ b/scripts/coccinelle/misc/returnvar.cocci @@ -0,0 +1,66 @@ +/// +/// Removes unneeded variable used to store return value. +/// +// Confidence: Moderate +// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: Comments on code can be deleted if near code that is removed. +// "when strict" can be removed to get more hits, but adds false +// positives +// Options: --no-includes --include-headers + +virtual patch +virtual report +virtual context +virtual org + +@depends on patch@ +type T; +constant C; +identifier ret; +@@ +- T ret = C; +... when != ret + when strict +return +- ret ++ C +; + +@depends on context@ +type T; +constant C; +identifier ret; +@@ +* T ret = C; +... when != ret + when strict +* return ret; + +@r1 depends on report || org@ +type T; +constant C; +identifier ret; +position p1, p2; +@@ +T ret@p1 = C; +... when != ret + when strict +return ret@p2; + +@script:python depends on report@ +p1 << r1.p1; +p2 << r1.p2; +C << r1.C; +ret << r1.ret; +@@ +coccilib.report.print_report(p1[0], "Unneeded variable: \"" + ret + "\". Return \"" + C + "\" on line " + p2[0].line) + +@script:python depends on org@ +p1 << r1.p1; +p2 << r1.p2; +C << r1.C; +ret << r1.ret; +@@ +cocci.print_main("unneeded \"" + ret + "\" variable", p1) +cocci.print_sec("return " + C + " here", p2) diff --git a/scripts/coccinelle/misc/semicolon.cocci b/scripts/coccinelle/misc/semicolon.cocci new file mode 100644 index 00000000000..a47eba2edc9 --- /dev/null +++ b/scripts/coccinelle/misc/semicolon.cocci @@ -0,0 +1,83 @@ +/// +/// Removes unneeded semicolon. +/// +// Confidence: Moderate +// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: Some false positives on empty default cases in switch statements. +// Options: --no-includes --include-headers + +virtual patch +virtual report +virtual context +virtual org + +@r_default@ +position p; +@@ +switch (...) +{ +default: ...;@p +} + +@r_case@ +position p; +@@ +( +switch (...) +{ +case ...:;@p +} +| +switch (...) +{ +case ...:... +case ...:;@p +} +| +switch (...) +{ +case ...:... +case ...: +case ...:;@p +} +) + +@r1@ +statement S; +position p1; +position p != {r_default.p, r_case.p}; +identifier label; +@@ +( +label:; +| +S@p1;@p +) + +@script:python@ +p << r1.p; +p1 << r1.p1; +@@ +if p[0].line != p1[0].line_end: + cocci.include_match(False) + +@depends on patch@ +position r1.p; +@@ +-;@p + +@script:python depends on report@ +p << r1.p; +@@ +coccilib.report.print_report(p[0],"Unneeded semicolon") + +@depends on context@ +position r1.p; +@@ +*;@p + +@script:python depends on org@ +p << r1.p; +@@ +cocci.print_main("Unneeded semicolon",p) diff --git a/scripts/coccinelle/misc/warn.cocci b/scripts/coccinelle/misc/warn.cocci new file mode 100644 index 00000000000..d2e5b6cedb8 --- /dev/null +++ b/scripts/coccinelle/misc/warn.cocci @@ -0,0 +1,109 @@ +/// Use WARN(1,...) rather than printk followed by WARN_ON(1) +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@bad1@ +position p; +@@ + +printk(...); +printk@p(...); +WARN_ON(1); + +@r1 depends on context || report || org@ +position p != bad1.p; +@@ + + printk@p(...); +*WARN_ON(1); + +@script:python depends on org@ +p << r1.p; +@@ + +cocci.print_main("printk + WARN_ON can be just WARN",p) + +@script:python depends on report@ +p << r1.p; +@@ + +msg = "SUGGESTION: printk + WARN_ON can be just WARN" +coccilib.report.print_report(p[0],msg) + +@ok1 depends on patch@ +expression list es; +position p != bad1.p; +@@ + +-printk@p( ++WARN(1, + es); +-WARN_ON(1); + +@depends on patch@ +expression list ok1.es; +@@ + +if (...) +- { + WARN(1,es); +- } + +// -------------------------------------------------------------------- + +@bad2@ +position p; +@@ + +printk(...); +printk@p(...); +WARN_ON_ONCE(1); + +@r2 depends on context || report || org@ +position p != bad1.p; +@@ + + printk@p(...); +*WARN_ON_ONCE(1); + +@script:python depends on org@ +p << r2.p; +@@ + +cocci.print_main("printk + WARN_ON_ONCE can be just WARN_ONCE",p) + +@script:python depends on report@ +p << r2.p; +@@ + +msg = "SUGGESTION: printk + WARN_ON_ONCE can be just WARN_ONCE" +coccilib.report.print_report(p[0],msg) + +@ok2 depends on patch@ +expression list es; +position p != bad2.p; +@@ + +-printk@p( ++WARN_ONCE(1, + es); +-WARN_ON_ONCE(1); + +@depends on patch@ +expression list ok2.es; +@@ + +if (...) +- { + WARN_ONCE(1,es); +- } diff --git a/scripts/coccinelle/null/badzero.cocci b/scripts/coccinelle/null/badzero.cocci new file mode 100644 index 00000000000..d79baf7220e --- /dev/null +++ b/scripts/coccinelle/null/badzero.cocci @@ -0,0 +1,237 @@ +/// Compare pointer-typed values to NULL rather than 0 +/// +//# This makes an effort to choose between !x and x == NULL. !x is used +//# if it has previously been used with the function used to initialize x. +//# This relies on type information. More type information can be obtained +//# using the option -all_includes and the option -I to specify an +//# include path. +// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: + +virtual patch +virtual context +virtual org +virtual report + +@initialize:ocaml@ +let negtable = Hashtbl.create 101 + +@depends on patch@ +expression *E; +identifier f; +@@ + +( + (E = f(...)) == +- 0 ++ NULL +| + (E = f(...)) != +- 0 ++ NULL +| +- 0 ++ NULL + == (E = f(...)) +| +- 0 ++ NULL + != (E = f(...)) +) + + +@t1 depends on !patch@ +expression *E; +identifier f; +position p; +@@ + +( + (E = f(...)) == +* 0@p +| + (E = f(...)) != +* 0@p +| +* 0@p + == (E = f(...)) +| +* 0@p + != (E = f(...)) +) + +@script:python depends on org@ +p << t1.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0") + +@script:python depends on report@ +p << t1.p; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0") + +// Tests of returned values + +@s@ +identifier f; +expression E,E1; +@@ + + E = f(...) + ... when != E = E1 + !E + +@script:ocaml depends on s@ +f << s.f; +@@ + +try let _ = Hashtbl.find negtable f in () +with Not_found -> Hashtbl.add negtable f () + +@ r disable is_zero,isnt_zero exists @ +expression *E; +identifier f; +@@ + +E = f(...) +... +(E == 0 +|E != 0 +|0 == E +|0 != E +) + +@script:ocaml@ +f << r.f; +@@ + +try let _ = Hashtbl.find negtable f in () +with Not_found -> include_match false + +// This rule may lead to inconsistent path problems, if E is defined in two +// places +@ depends on patch disable is_zero,isnt_zero @ +expression *E; +expression E1; +identifier r.f; +@@ + +E = f(...) +<... +( +- E == 0 ++ !E +| +- E != 0 ++ E +| +- 0 == E ++ !E +| +- 0 != E ++ E +) +...> +?E = E1 + +@t2 depends on !patch disable is_zero,isnt_zero @ +expression *E; +expression E1; +identifier r.f; +position p1; +position p2; +@@ + +E = f(...) +<... +( +* E == 0@p1 +| +* E != 0@p2 +| +* 0@p1 == E +| +* 0@p1 != E +) +...> +?E = E1 + +@script:python depends on org@ +p << t2.p1; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0, suggest !E") + +@script:python depends on org@ +p << t2.p2; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0") + +@script:python depends on report@ +p << t2.p1; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0, suggest !E") + +@script:python depends on report@ +p << t2.p2; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0") + +@ depends on patch disable is_zero,isnt_zero @ +expression *E; +@@ + +( + E == +- 0 ++ NULL +| + E != +- 0 ++ NULL +| +- 0 ++ NULL + == E +| +- 0 ++ NULL + != E +) + +@ t3 depends on !patch disable is_zero,isnt_zero @ +expression *E; +position p; +@@ + +( +* E == 0@p +| +* E != 0@p +| +* 0@p == E +| +* 0@p != E +) + +@script:python depends on org@ +p << t3.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0") + +@script:python depends on report@ +p << t3.p; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0") diff --git a/scripts/coccinelle/null/eno.cocci b/scripts/coccinelle/null/eno.cocci index ed961a1f7d1..9bd29aa8339 100644 --- a/scripts/coccinelle/null/eno.cocci +++ b/scripts/coccinelle/null/eno.cocci @@ -6,7 +6,7 @@ // Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual patch virtual context diff --git a/scripts/coccinelle/null/kmerr.cocci b/scripts/coccinelle/null/kmerr.cocci index 949bf656c64..5354a7903cc 100644 --- a/scripts/coccinelle/null/kmerr.cocci +++ b/scripts/coccinelle/null/kmerr.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual context virtual org diff --git a/scripts/coccinelle/tests/doublebitand.cocci b/scripts/coccinelle/tests/doublebitand.cocci index 9ba73d05a77..72f1572aaec 100644 --- a/scripts/coccinelle/tests/doublebitand.cocci +++ b/scripts/coccinelle/tests/doublebitand.cocci @@ -10,7 +10,7 @@ // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual context virtual org diff --git a/scripts/coccinelle/tests/doubletest.cocci b/scripts/coccinelle/tests/doubletest.cocci index 13a2c0e8a4b..78d74c22ca1 100644 --- a/scripts/coccinelle/tests/doubletest.cocci +++ b/scripts/coccinelle/tests/doubletest.cocci @@ -8,7 +8,7 @@ // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: -// Options: -no_includes -include_headers +// Options: --no-includes --include-headers virtual context virtual org diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci new file mode 100644 index 00000000000..cfe0a35cf2d --- /dev/null +++ b/scripts/coccinelle/tests/odd_ptr_err.cocci @@ -0,0 +1,65 @@ +/// PTR_ERR should access the value just tested by IS_ERR +//# There can be false positives in the patch case, where it is the call +//# IS_ERR that is wrong. +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on patch@ +expression e,e1; +@@ + +( +if (IS_ERR(e)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e)) + { ... + PTR_ERR( +- e1 ++ e + ) + ... } +) + +@r depends on !patch@ +expression e,e1; +position p1,p2; +@@ + +( +if (IS_ERR(e)) { ... PTR_ERR(e) ... } +| +if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... } +| +*if (IS_ERR@p1(e)) + { ... +* PTR_ERR@p2(e1) + ... } +) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("inconsistent IS_ERR and PTR_ERR",p1) +cocci.print_secs("PTR_ERR",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "inconsistent IS_ERR and PTR_ERR, PTR_ERR on line %s" % (p2[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/config b/scripts/config index a7c7c4b8e95..026aeb4f32e 100755 --- a/scripts/config +++ b/scripts/config @@ -1,11 +1,16 @@ #!/bin/bash # Manipulate options in a .config file from the command line +myname=${0##*/} + +# If no prefix forced, use the default CONFIG_ +CONFIG_="${CONFIG_-CONFIG_}" + usage() { cat >&2 <<EOL Manipulate options in a .config file from the command line. Usage: -config options command ... +$myname options command ... commands: --enable|-e option Enable option --disable|-d option Disable option @@ -14,6 +19,7 @@ commands: Set option to "string" --set-val option value Set option to value + --undefine|-u option Undefine option --state|-s option Print state of option (n,y,m,undef) --enable-after|-E beforeopt option @@ -26,10 +32,17 @@ commands: commands can be repeated multiple times options: - --file .config file to change (default .config) + --file config-file .config file to change (default .config) + --keep-case|-k Keep next symbols' case (dont' upper-case it) + +$myname doesn't check the validity of the .config file. This is done at next +make time. -config doesn't check the validity of the .config file. This is done at next - make time. +By default, $myname will upper-case the given symbol. Use --keep-case to keep +the case of all following symbols unchanged. + +$myname uses 'CONFIG_' as the default symbol prefix. Set the environment +variable CONFIG_ to the prefix to use. Eg.: CONFIG_="FOO_" $myname ... EOL exit 1 } @@ -40,11 +53,48 @@ checkarg() { usage fi case "$ARG" in - CONFIG_*) - ARG="${ARG/CONFIG_/}" + ${CONFIG_}*) + ARG="${ARG/${CONFIG_}/}" ;; esac - ARG="`echo $ARG | tr a-z A-Z`" + if [ "$MUNGE_CASE" = "yes" ] ; then + ARG="`echo $ARG | tr a-z A-Z`" + fi +} + +txt_append() { + local anchor="$1" + local insert="$2" + local infile="$3" + local tmpfile="$infile.swp" + + # sed append cmd: 'a\' + newline + text + newline + cmd="$(printf "a\\%b$insert" "\n")" + + sed -e "/$anchor/$cmd" "$infile" >"$tmpfile" + # replace original file with the edited one + mv "$tmpfile" "$infile" +} + +txt_subst() { + local before="$1" + local after="$2" + local infile="$3" + local tmpfile="$infile.swp" + + sed -e "s:$before:$after:" "$infile" >"$tmpfile" + # replace original file with the edited one + mv "$tmpfile" "$infile" +} + +txt_delete() { + local text="$1" + local infile="$2" + local tmpfile="$infile.swp" + + sed -e "/$text/d" "$infile" >"$tmpfile" + # replace original file with the edited one + mv "$tmpfile" "$infile" } set_var() { @@ -53,14 +103,23 @@ set_var() { name_re="^($name=|# $name is not set)" before_re="^($before=|# $before is not set)" if test -n "$before" && grep -Eq "$before_re" "$FN"; then - sed -ri "/$before_re/a $new" "$FN" + txt_append "^$before=" "$new" "$FN" + txt_append "^# $before is not set" "$new" "$FN" elif grep -Eq "$name_re" "$FN"; then - sed -ri "s:$name_re.*:$new:" "$FN" + txt_subst "^$name=.*" "$new" "$FN" + txt_subst "^# $name is not set" "$new" "$FN" else echo "$new" >>"$FN" fi } +undef_var() { + local name=$1 + + txt_delete "^$name=" "$FN" + txt_delete "^# $name is not set" "$FN" +} + if [ "$1" = "--file" ]; then FN="$2" if [ "$FN" = "" ] ; then @@ -75,13 +134,18 @@ if [ "$1" = "" ] ; then usage fi +MUNGE_CASE=yes while [ "$1" != "" ] ; do CMD="$1" shift case "$CMD" in + --keep-case|-k) + MUNGE_CASE=no + continue + ;; --refresh) ;; - --*-after) + --*-after|-E|-D|-M) checkarg "$1" A=$ARG checkarg "$2" @@ -95,52 +159,58 @@ while [ "$1" != "" ] ; do esac case "$CMD" in --enable|-e) - set_var "CONFIG_$ARG" "CONFIG_$ARG=y" + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=y" ;; --disable|-d) - set_var "CONFIG_$ARG" "# CONFIG_$ARG is not set" + set_var "${CONFIG_}$ARG" "# ${CONFIG_}$ARG is not set" ;; --module|-m) - set_var "CONFIG_$ARG" "CONFIG_$ARG=m" + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=m" ;; --set-str) - set_var "CONFIG_$ARG" "CONFIG_$ARG=\"$1\"" + # sed swallows one level of escaping, so we need double-escaping + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=\"${1//\"/\\\\\"}\"" shift ;; --set-val) - set_var "CONFIG_$ARG" "CONFIG_$ARG=$1" + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=$1" shift ;; + --undefine|-u) + undef_var "${CONFIG_}$ARG" + ;; --state|-s) - if grep -q "# CONFIG_$ARG is not set" $FN ; then + if grep -q "# ${CONFIG_}$ARG is not set" $FN ; then echo n else - V="$(grep "^CONFIG_$ARG=" $FN)" + V="$(grep "^${CONFIG_}$ARG=" $FN)" if [ $? != 0 ] ; then echo undef else - V="${V/CONFIG_$ARG=/}" - V="${V/\"/}" - echo "$V" + V="${V/#${CONFIG_}$ARG=/}" + V="${V/#\"/}" + V="${V/%\"/}" + V="${V//\\\"/\"}" + echo "${V}" fi fi ;; --enable-after|-E) - set_var "CONFIG_$B" "CONFIG_$B=y" "CONFIG_$A" + set_var "${CONFIG_}$B" "${CONFIG_}$B=y" "${CONFIG_}$A" ;; --disable-after|-D) - set_var "CONFIG_$B" "# CONFIG_$B is not set" "CONFIG_$A" + set_var "${CONFIG_}$B" "# ${CONFIG_}$B is not set" "${CONFIG_}$A" ;; --module-after|-M) - set_var "CONFIG_$B" "CONFIG_$B=m" "CONFIG_$A" + set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A" ;; # undocumented because it ignores --file (fixme) @@ -153,4 +223,3 @@ while [ "$1" != "" ] ; do ;; esac done - diff --git a/scripts/conmakehash.c b/scripts/conmakehash.c index 263a44d57fa..61bbda54cf1 100644 --- a/scripts/conmakehash.c +++ b/scripts/conmakehash.c @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) } } - /* For now we assume the default font is always 256 characters. */ + /* For now we assume the default font is always 256 characters. */ fontlen = 256; /* Initialize table */ @@ -236,15 +236,15 @@ int main(int argc, char *argv[]) } /* Okay, we hit EOF, now output hash table */ - + fclose(ctbl); - + /* Compute total size of Unicode list */ nuni = 0; for ( i = 0 ; i < fontlen ; i++ ) nuni += unicount[i]; - + printf("\ /*\n\ * Do not edit this file; it was automatically generated by\n\ @@ -268,9 +268,9 @@ u8 dfont_unicount[%d] = \n\ else printf(", "); } - + printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni); - + fp0 = 0; nent = 0; for ( i = 0 ; i < nuni ; i++ ) diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh new file mode 100755 index 00000000000..515c4c00e95 --- /dev/null +++ b/scripts/decode_stacktrace.sh @@ -0,0 +1,126 @@ +#!/bin/bash +# (c) 2014, Sasha Levin <sasha.levin@oracle.com> +#set -x + +if [[ $# != 2 ]]; then + echo "Usage:" + echo " $0 [vmlinux] [base path]" + exit 1 +fi + +vmlinux=$1 +basepath=$2 +declare -A cache + +parse_symbol() { + # The structure of symbol at this point is: + # [name]+[offset]/[total length] + # + # For example: + # do_basic_setup+0x9c/0xbf + + + # Strip the symbol name so that we could look it up + local name=${symbol%+*} + + # Use 'nm vmlinux' to figure out the base address of said symbol. + # It's actually faster to call it every time than to load it + # all into bash. + if [[ "${cache[$name]+isset}" == "isset" ]]; then + local base_addr=${cache[$name]} + else + local base_addr=$(nm "$vmlinux" | grep -i ' t ' | awk "/ $name\$/ {print \$1}" | head -n1) + cache["$name"]="$base_addr" + fi + # Let's start doing the math to get the exact address into the + # symbol. First, strip out the symbol total length. + local expr=${symbol%/*} + + # Now, replace the symbol name with the base address we found + # before. + expr=${expr/$name/0x$base_addr} + + # Evaluate it to find the actual address + expr=$((expr)) + local address=$(printf "%x\n" "$expr") + + # Pass it to addr2line to get filename and line number + # Could get more than one result + if [[ "${cache[$address]+isset}" == "isset" ]]; then + local code=${cache[$address]} + else + local code=$(addr2line -i -e "$vmlinux" "$address") + cache[$address]=$code + fi + + # addr2line doesn't return a proper error code if it fails, so + # we detect it using the value it prints so that we could preserve + # the offset/size into the function and bail out + if [[ $code == "??:0" ]]; then + return + fi + + # Strip out the base of the path + code=${code//$basepath/""} + + # In the case of inlines, move everything to same line + code=${code//$'\n'/' '} + + # Replace old address with pretty line numbers + symbol="$name ($code)" +} + +decode_code() { + local scripts=`dirname "${BASH_SOURCE[0]}"` + + echo "$1" | $scripts/decodecode +} + +handle_line() { + local words + + # Tokenize + read -a words <<<"$1" + + # Remove hex numbers. Do it ourselves until it happens in the + # kernel + + # We need to know the index of the last element before we + # remove elements because arrays are sparse + local last=$(( ${#words[@]} - 1 )) + + for i in "${!words[@]}"; do + # Remove the address + if [[ ${words[$i]} =~ \[\<([^]]+)\>\] ]]; then + unset words[$i] + fi + + # Format timestamps with tabs + if [[ ${words[$i]} == \[ && ${words[$i+1]} == *\] ]]; then + unset words[$i] + words[$i+1]=$(printf "[%13s\n" "${words[$i+1]}") + fi + done + + # The symbol is the last element, process it + symbol=${words[$last]} + unset words[$last] + parse_symbol # modifies $symbol + + # Add up the line number to the symbol + echo "${words[@]}" "$symbol" +} + +while read line; do + # Let's see if we have an address in the line + if [[ $line =~ \[\<([^]]+)\>\] ]]; then + # Translate address to line numbers + handle_line "$line" + # Is it a code line? + elif [[ $line == *Code:* ]]; then + decode_code "$line" + else + # Nothing special in this line, show it as is + echo "$line" + fi +done diff --git a/scripts/decodecode b/scripts/decodecode index 18ba881c341..d8824f37acc 100755 --- a/scripts/decodecode +++ b/scripts/decodecode @@ -89,10 +89,16 @@ echo $code >> $T.s disas $T cat $T.dis >> $T.aa -faultline=`cat $T.dis | head -1 | cut -d":" -f2` +# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3, +# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is +# special) +faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \ + $(wc -l $T.aa | cut -d" " -f1) + 3)) + +faultline=`cat $T.dis | head -1 | cut -d":" -f2-` faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'` -cat $T.oo | sed -e "s/\($faultline\)/\*\1 <-- trapping instruction/g" +cat $T.oo | sed -e "${faultlinenum}s/^\(.*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/" echo cat $T.aa cleanup diff --git a/scripts/depmod.sh b/scripts/depmod.sh index 2ae48170314..122599b1c13 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -2,16 +2,36 @@ # # A depmod wrapper used by the toplevel Makefile -if test $# -ne 2; then - echo "Usage: $0 /sbin/depmod <kernelrelease>" >&2 +if test $# -ne 3; then + echo "Usage: $0 /sbin/depmod <kernelrelease> <symbolprefix>" >&2 exit 1 fi DEPMOD=$1 KERNELRELEASE=$2 +SYMBOL_PREFIX=$3 if ! test -r System.map -a -x "$DEPMOD"; then 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 +fi + # older versions of depmod require the version string to start with three # numbers, so we cheat with a symlink here depmod_hack_needed=true @@ -34,7 +54,7 @@ set -- -ae -F System.map if test -n "$INSTALL_MOD_PATH"; then set -- "$@" -b "$INSTALL_MOD_PATH" fi -"$DEPMOD" "$@" "$KERNELRELEASE" +"$DEPMOD" "$@" "$KERNELRELEASE" $SYMBOL_PREFIX ret=$? if $depmod_hack_needed; then diff --git a/scripts/diffconfig b/scripts/diffconfig index b91f3e34d44..6d672836e18 100755 --- a/scripts/diffconfig +++ b/scripts/diffconfig @@ -10,7 +10,7 @@ import sys, os def usage(): - print """Usage: diffconfig [-h] [-m] [<config1> <config2>] + print("""Usage: diffconfig [-h] [-m] [<config1> <config2>] Diffconfig is a simple utility for comparing two .config files. Using standard diff to compare .config files often includes extraneous and @@ -33,7 +33,7 @@ Example usage: EXT2_FS y -> n LOG_BUF_SHIFT 14 -> 16 PRINTK_TIME n -> y -""" +""") sys.exit(0) # returns a dictionary of name/value pairs for config items in the file @@ -54,23 +54,23 @@ def print_config(op, config, value, new_value): if merge_style: if new_value: if new_value=="n": - print "# CONFIG_%s is not set" % config + print("# CONFIG_%s is not set" % config) else: - print "CONFIG_%s=%s" % (config, new_value) + print("CONFIG_%s=%s" % (config, new_value)) else: if op=="-": - print "-%s %s" % (config, value) + print("-%s %s" % (config, value)) elif op=="+": - print "+%s %s" % (config, new_value) + print("+%s %s" % (config, new_value)) else: - print " %s %s -> %s" % (config, value, new_value) + print(" %s %s -> %s" % (config, value, new_value)) def main(): global merge_style # parse command line args if ("-h" in sys.argv or "--help" in sys.argv): - usage() + usage() merge_style = 0 if "-m" in sys.argv: @@ -79,23 +79,27 @@ def main(): argc = len(sys.argv) if not (argc==1 or argc == 3): - print "Error: incorrect number of arguments or unrecognized option" + print("Error: incorrect number of arguments or unrecognized option") usage() if argc == 1: # if no filenames given, assume .config and .config.old build_dir="" - if os.environ.has_key("KBUILD_OUTPUT"): + if "KBUILD_OUTPUT" in os.environ: build_dir = os.environ["KBUILD_OUTPUT"]+"/" - configa_filename = build_dir + ".config.old" configb_filename = build_dir + ".config" else: configa_filename = sys.argv[1] configb_filename = sys.argv[2] - a = readconfig(file(configa_filename)) - b = readconfig(file(configb_filename)) + try: + a = readconfig(open(configa_filename)) + b = readconfig(open(configb_filename)) + except (IOError): + e = sys.exc_info()[1] + print("I/O error[%s]: %s\n" % (e.args[0],e.args[1])) + usage() # print items in a but not b (accumulate, sort and print) old = [] @@ -121,8 +125,7 @@ def main(): # now print items in b but not in a # (items from b that were in a were removed above) - new = b.keys() - new.sort() + new = sorted(b.keys()) for config in new: print_config("+", config, None, b[config]) diff --git a/scripts/docproc.c b/scripts/docproc.c index 4cfdc1797eb..e267e621431 100644 --- a/scripts/docproc.c +++ b/scripts/docproc.c @@ -72,6 +72,7 @@ FILELINE * docsection; #define FUNCTION "-function" #define NOFUNCTION "-nofunction" #define NODOCSECTIONS "-no-doc-sections" +#define SHOWNOTFOUND "-show-not-found" static char *srctree, *kernsrctree; @@ -153,7 +154,7 @@ int symfilecnt = 0; static void add_new_symbol(struct symfile *sym, char * symname) { sym->symbollist = - realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *)); + realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *)); sym->symbollist[sym->symbolcnt++].name = strdup(symname); } @@ -214,7 +215,7 @@ static void find_export_symbols(char * filename) char *p; char *e; if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) || - ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) { + ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) { /* Skip EXPORT_SYMBOL{_GPL} */ while (isalnum(*p) || *p == '_') p++; @@ -290,27 +291,28 @@ static void extfunc(char * filename) { docfunctions(filename, FUNCTION); } static void singfunc(char * filename, char * line) { char *vec[200]; /* Enough for specific functions */ - int i, idx = 0; - int startofsym = 1; + int i, idx = 0; + int startofsym = 1; vec[idx++] = KERNELDOC; vec[idx++] = DOCBOOK; + vec[idx++] = SHOWNOTFOUND; - /* Split line up in individual parameters preceded by FUNCTION */ - for (i=0; line[i]; i++) { - if (isspace(line[i])) { - line[i] = '\0'; - startofsym = 1; - continue; - } - if (startofsym) { - startofsym = 0; - vec[idx++] = FUNCTION; - vec[idx++] = &line[i]; - } - } + /* Split line up in individual parameters preceded by FUNCTION */ + for (i=0; line[i]; i++) { + if (isspace(line[i])) { + line[i] = '\0'; + startofsym = 1; + continue; + } + if (startofsym) { + startofsym = 0; + vec[idx++] = FUNCTION; + vec[idx++] = &line[i]; + } + } for (i = 0; i < idx; i++) { - if (strcmp(vec[i], FUNCTION)) - continue; + if (strcmp(vec[i], FUNCTION)) + continue; consume_symbol(vec[i + 1]); } vec[idx++] = filename; @@ -325,7 +327,8 @@ static void singfunc(char * filename, char * line) */ static void docsect(char *filename, char *line) { - char *vec[6]; /* kerneldoc -docbook -function "section" file NULL */ + /* kerneldoc -docbook -show-not-found -function "section" file NULL */ + char *vec[7]; char *s; for (s = line; *s; s++) @@ -341,10 +344,11 @@ static void docsect(char *filename, char *line) vec[0] = KERNELDOC; vec[1] = DOCBOOK; - vec[2] = FUNCTION; - vec[3] = line; - vec[4] = filename; - vec[5] = NULL; + vec[2] = SHOWNOTFOUND; + vec[3] = FUNCTION; + vec[4] = line; + vec[5] = filename; + vec[6] = NULL; exec_kernel_doc(vec); } @@ -456,14 +460,14 @@ static void parse_file(FILE *infile) break; case 'D': while (*s && !isspace(*s)) s++; - *s = '\0'; - symbolsonly(line+2); - break; + *s = '\0'; + symbolsonly(line+2); + break; case 'F': /* filename */ while (*s && !isspace(*s)) s++; *s++ = '\0'; - /* function names */ + /* function names */ while (isspace(*s)) s++; singlefunctions(line +2, s); @@ -511,11 +515,11 @@ int main(int argc, char *argv[]) } /* Open file, exit on error */ infile = fopen(argv[2], "r"); - if (infile == NULL) { - fprintf(stderr, "docproc: "); - perror(argv[2]); - exit(2); - } + if (infile == NULL) { + fprintf(stderr, "docproc: "); + perror(argv[2]); + exit(2); + } if (strcmp("doc", argv[1]) == 0) { /* Need to do this in two passes. diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore index 095acb49a37..cdabdc95a6e 100644 --- a/scripts/dtc/.gitignore +++ b/scripts/dtc/.gitignore @@ -2,4 +2,3 @@ dtc dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h - diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 6d1c6bb9f22..2a48022c41e 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -27,3 +27,5 @@ HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC) # dependencies on generated files need to be listed explicitly $(obj)/dtc-lexer.lex.o: $(obj)/dtc-parser.tab.h +# generated files need to be cleaned explicitly +clean-files := dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc index 6ddf9ecac66..bece49b3553 100644 --- a/scripts/dtc/Makefile.dtc +++ b/scripts/dtc/Makefile.dtc @@ -3,7 +3,16 @@ # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # -DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \ - checks.c +DTC_SRCS = \ + checks.c \ + data.c \ + dtc.c \ + flattree.c \ + fstree.c \ + livetree.c \ + srcpos.c \ + treesource.c \ + util.c + 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 a662a004479..ee96a2519ef 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -31,12 +31,6 @@ #define TRACE(c, fmt, ...) do { } while (0) #endif -enum checklevel { - IGNORE = 0, - WARN = 1, - ERROR = 2, -}; - enum checkstatus { UNCHECKED = 0, PREREQ, @@ -57,14 +51,14 @@ struct check { node_check_fn node_fn; prop_check_fn prop_fn; void *data; - enum checklevel level; + bool warn, error; enum checkstatus status; int inprogress; int num_prereqs; struct check **prereq; }; -#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \ +#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ static struct check nm = { \ .name = #nm, \ @@ -72,20 +66,37 @@ struct check { .node_fn = (nfn), \ .prop_fn = (pfn), \ .data = (d), \ - .level = (lvl), \ + .warn = (w), \ + .error = (e), \ .status = UNCHECKED, \ .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ .prereq = nm##_prereqs, \ }; - -#define TREE_CHECK(nm, d, lvl, ...) \ - CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__) -#define NODE_CHECK(nm, d, lvl, ...) \ - CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__) -#define PROP_CHECK(nm, d, lvl, ...) \ - CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__) -#define BATCH_CHECK(nm, lvl, ...) \ - CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__) +#define WARNING(nm, tfn, nfn, pfn, d, ...) \ + CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) +#define ERROR(nm, tfn, nfn, pfn, d, ...) \ + CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) +#define CHECK(nm, tfn, nfn, pfn, d, ...) \ + CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) + +#define TREE_WARNING(nm, d, ...) \ + WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) +#define TREE_ERROR(nm, d, ...) \ + ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) +#define TREE_CHECK(nm, d, ...) \ + CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) +#define NODE_WARNING(nm, d, ...) \ + WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) +#define NODE_ERROR(nm, d, ...) \ + ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) +#define NODE_CHECK(nm, d, ...) \ + CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) +#define PROP_WARNING(nm, d, ...) \ + WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +#define PROP_ERROR(nm, d, ...) \ + ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +#define PROP_CHECK(nm, d, ...) \ + CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) #ifdef __GNUC__ static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -95,13 +106,13 @@ static inline void check_msg(struct check *c, const char *fmt, ...) va_list ap; va_start(ap, fmt); - if ((c->level < WARN) || (c->level <= quiet)) - return; /* Suppress message */ - - fprintf(stderr, "%s (%s): ", - (c->level == ERROR) ? "ERROR" : "Warning", c->name); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); + if ((c->warn && (quiet < 1)) + || (c->error && (quiet < 2))) { + fprintf(stderr, "%s (%s): ", + (c->error) ? "ERROR" : "Warning", c->name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } } #define FAIL(c, ...) \ @@ -167,7 +178,7 @@ static int run_check(struct check *c, struct node *dt) out: c->inprogress = 0; - if ((c->status != PASSED) && (c->level == ERROR)) + if ((c->status != PASSED) && (c->error)) error = 1; return error; } @@ -176,6 +187,13 @@ out: * Utility check functions */ +/* A check which always fails, for testing purposes only */ +static inline void check_always_fail(struct check *c, struct node *dt) +{ + FAIL(c, "always_fail check"); +} +TREE_CHECK(always_fail, NULL); + static void check_is_string(struct check *c, struct node *root, struct node *node) { @@ -190,8 +208,10 @@ static void check_is_string(struct check *c, struct node *root, FAIL(c, "\"%s\" property in %s is not a string", propname, node->fullpath); } -#define CHECK_IS_STRING(nm, propname, lvl) \ - CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl)) +#define WARNING_IF_NOT_STRING(nm, propname) \ + WARNING(nm, NULL, check_is_string, NULL, (propname)) +#define ERROR_IF_NOT_STRING(nm, propname) \ + ERROR(nm, NULL, check_is_string, NULL, (propname)) static void check_is_cell(struct check *c, struct node *root, struct node *node) @@ -207,8 +227,10 @@ static void check_is_cell(struct check *c, struct node *root, FAIL(c, "\"%s\" property in %s is not a single cell", propname, node->fullpath); } -#define CHECK_IS_CELL(nm, propname, lvl) \ - CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl)) +#define WARNING_IF_NOT_CELL(nm, propname) \ + WARNING(nm, NULL, check_is_cell, NULL, (propname)) +#define ERROR_IF_NOT_CELL(nm, propname) \ + ERROR(nm, NULL, check_is_cell, NULL, (propname)) /* * Structural check functions @@ -227,20 +249,24 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, FAIL(c, "Duplicate node name %s", child->fullpath); } -NODE_CHECK(duplicate_node_names, NULL, ERROR); +NODE_ERROR(duplicate_node_names, NULL); static void check_duplicate_property_names(struct check *c, struct node *dt, struct node *node) { struct property *prop, *prop2; - for_each_property(node, prop) - for (prop2 = prop->next; prop2; prop2 = prop2->next) + for_each_property(node, prop) { + for (prop2 = prop->next; prop2; prop2 = prop2->next) { + if (prop2->deleted) + continue; if (streq(prop->name, prop2->name)) FAIL(c, "Duplicate property name %s in %s", prop->name, node->fullpath); + } + } } -NODE_CHECK(duplicate_property_names, NULL, ERROR); +NODE_ERROR(duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -256,7 +282,7 @@ static void check_node_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in node %s", node->name[n], node->fullpath); } -NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR); +NODE_ERROR(node_name_chars, PROPNODECHARS "@"); static void check_node_name_format(struct check *c, struct node *dt, struct node *node) @@ -265,7 +291,7 @@ static void check_node_name_format(struct check *c, struct node *dt, FAIL(c, "Node %s has multiple '@' characters in name", node->fullpath); } -NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars); +NODE_ERROR(node_name_format, NULL, &node_name_chars); static void check_property_name_chars(struct check *c, struct node *dt, struct node *node, struct property *prop) @@ -276,7 +302,7 @@ static void check_property_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in property name \"%s\", node %s", prop->name[n], prop->name, node->fullpath); } -PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); +PROP_ERROR(property_name_chars, PROPNODECHARS); #define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_ARGS(node,prop,mark) \ @@ -331,8 +357,8 @@ static void check_duplicate_label_prop(struct check *c, struct node *dt, for_each_marker_of_type(m, LABEL) check_duplicate_label(c, dt, m->ref, node, prop, m); } -CHECK(duplicate_label, NULL, check_duplicate_label_node, - check_duplicate_label_prop, NULL, ERROR); +ERROR(duplicate_label, NULL, check_duplicate_label_node, + check_duplicate_label_prop, NULL); static void check_explicit_phandles(struct check *c, struct node *root, struct node *node, struct property *prop) @@ -391,7 +417,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -PROP_CHECK(explicit_phandles, NULL, ERROR); +PROP_ERROR(explicit_phandles, NULL); static void check_name_properties(struct check *c, struct node *root, struct node *node) @@ -420,8 +446,8 @@ static void check_name_properties(struct check *c, struct node *root, free(prop); } } -CHECK_IS_STRING(name_is_string, "name", ERROR); -NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); +ERROR_IF_NOT_STRING(name_is_string, "name"); +NODE_ERROR(name_properties, NULL, &name_is_string); /* * Reference fixup functions @@ -448,7 +474,7 @@ static void fixup_phandle_references(struct check *c, struct node *dt, *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } -CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, +ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); static void fixup_path_references(struct check *c, struct node *dt, @@ -473,19 +499,19 @@ static void fixup_path_references(struct check *c, struct node *dt, strlen(path) + 1); } } -CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR, +ERROR(path_references, NULL, NULL, fixup_path_references, NULL, &duplicate_node_names); /* * Semantic checks */ -CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN); -CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN); -CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN); +WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); +WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); +WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); -CHECK_IS_STRING(device_type_is_string, "device_type", WARN); -CHECK_IS_STRING(model_is_string, "model", WARN); -CHECK_IS_STRING(status_is_string, "status", WARN); +WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); +WARNING_IF_NOT_STRING(model_is_string, "model"); +WARNING_IF_NOT_STRING(status_is_string, "status"); static void fixup_addr_size_cells(struct check *c, struct node *dt, struct node *node) @@ -503,8 +529,8 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, if (prop) node->size_cells = propval_cell(prop); } -CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN, - &address_cells_is_cell, &size_cells_is_cell); +WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, + &address_cells_is_cell, &size_cells_is_cell); #define node_addr_cells(n) \ (((n)->addr_cells == -1) ? 2 : (n)->addr_cells) @@ -538,7 +564,7 @@ static void check_reg_format(struct check *c, struct node *dt, "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); } -NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells); +NODE_WARNING(reg_format, NULL, &addr_size_cells); static void check_ranges_format(struct check *c, struct node *dt, struct node *node) @@ -579,7 +605,7 @@ static void check_ranges_format(struct check *c, struct node *dt, p_addr_cells, c_addr_cells, c_size_cells); } } -NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells); +NODE_WARNING(ranges_format, NULL, &addr_size_cells); /* * Style checks @@ -606,7 +632,7 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, FAIL(c, "Relying on default #size-cells value for %s", node->fullpath); } -NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells); +NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, struct node *dt) @@ -623,7 +649,7 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, FAIL(c, "/chosen has obsolete \"interrupt-controller\" " "property"); } -TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN); +TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, @@ -642,8 +668,71 @@ static struct check *check_table[] = { &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, + + &always_fail, }; +static void enable_warning_error(struct check *c, bool warn, bool error) +{ + int i; + + /* Raising level, also raise it for prereqs */ + if ((warn && !c->warn) || (error && !c->error)) + for (i = 0; i < c->num_prereqs; i++) + enable_warning_error(c->prereq[i], warn, error); + + c->warn = c->warn || warn; + c->error = c->error || error; +} + +static void disable_warning_error(struct check *c, bool warn, bool error) +{ + int i; + + /* Lowering level, also lower it for things this is the prereq + * for */ + if ((warn && c->warn) || (error && c->error)) { + for (i = 0; i < ARRAY_SIZE(check_table); i++) { + struct check *cc = check_table[i]; + int j; + + for (j = 0; j < cc->num_prereqs; j++) + if (cc->prereq[j] == c) + disable_warning_error(cc, warn, error); + } + } + + c->warn = c->warn && !warn; + c->error = c->error && !error; +} + +void parse_checks_option(bool warn, bool error, const char *optarg) +{ + int i; + const char *name = optarg; + bool enable = true; + + if ((strncmp(optarg, "no-", 3) == 0) + || (strncmp(optarg, "no_", 3) == 0)) { + name = optarg + 3; + enable = false; + } + + for (i = 0; i < ARRAY_SIZE(check_table); i++) { + struct check *c = check_table[i]; + + if (streq(c->name, name)) { + if (enable) + enable_warning_error(c, warn, error); + else + disable_warning_error(c, warn, error); + return; + } + } + + die("Unrecognized check name \"%s\"\n", name); +} + void process_checks(int force, struct boot_info *bi) { struct node *dt = bi->dt; @@ -653,7 +742,7 @@ void process_checks(int force, struct boot_info *bi) for (i = 0; i < ARRAY_SIZE(check_table); i++) { struct check *c = check_table[i]; - if (c->level != IGNORE) + if (c->warn || c->error) error = error || run_check(c, dt); } diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index fe555e819bf..4a40c5b9247 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -68,40 +68,6 @@ struct data data_copy_mem(const char *mem, int len) return d; } -static char get_oct_char(const char *s, int *i) -{ - char x[4]; - char *endx; - long val; - - x[3] = '\0'; - strncpy(x, s + *i, 3); - - val = strtol(x, &endx, 8); - - assert(endx > x); - - (*i) += endx - x; - return val; -} - -static char get_hex_char(const char *s, int *i) -{ - char x[3]; - char *endx; - long val; - - x[2] = '\0'; - strncpy(x, s + *i, 2); - - val = strtol(x, &endx, 16); - if (!(endx > x)) - die("\\x used with no following hex digits\n"); - - (*i) += endx - x; - return val; -} - struct data data_copy_escape_string(const char *s, int len) { int i = 0; @@ -114,53 +80,10 @@ struct data data_copy_escape_string(const char *s, int len) while (i < len) { char c = s[i++]; - if (c != '\\') { - q[d.len++] = c; - continue; - } - - c = s[i++]; - assert(c); - switch (c) { - case 'a': - q[d.len++] = '\a'; - break; - case 'b': - q[d.len++] = '\b'; - break; - case 't': - q[d.len++] = '\t'; - break; - case 'n': - q[d.len++] = '\n'; - break; - case 'v': - q[d.len++] = '\v'; - break; - case 'f': - q[d.len++] = '\f'; - break; - case 'r': - q[d.len++] = '\r'; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - i--; /* need to re-read the first digit as - * part of the octal value */ - q[d.len++] = get_oct_char(s, &i); - break; - case 'x': - q[d.len++] = get_hex_char(s, &i); - break; - default: - q[d.len++] = c; - } + if (c == '\\') + c = get_escape_char(s, &i); + + q[d.len++] = c; } q[d.len++] = '\0'; @@ -245,11 +168,33 @@ struct data data_merge(struct data d1, struct data d2) return d; } -struct data data_append_cell(struct data d, cell_t word) +struct data data_append_integer(struct data d, uint64_t value, int bits) { - cell_t beword = cpu_to_fdt32(word); - - return data_append_data(d, &beword, sizeof(beword)); + uint8_t value_8; + uint16_t value_16; + uint32_t value_32; + uint64_t value_64; + + switch (bits) { + case 8: + value_8 = value; + return data_append_data(d, &value_8, 1); + + case 16: + value_16 = cpu_to_fdt16(value); + return data_append_data(d, &value_16, 2); + + case 32: + value_32 = cpu_to_fdt32(value); + return data_append_data(d, &value_32, 4); + + case 64: + value_64 = cpu_to_fdt64(value); + return data_append_data(d, &value_64, 8); + + default: + die("Invalid literal size (%d)\n", bits); + } } struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) @@ -262,11 +207,14 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) return data_append_data(d, &bere, sizeof(bere)); } -struct data data_append_addr(struct data d, uint64_t addr) +struct data data_append_cell(struct data d, cell_t word) { - uint64_t beaddr = cpu_to_fdt64(addr); + return data_append_integer(d, word, sizeof(word) * 8); +} - return data_append_data(d, &beaddr, sizeof(beaddr)); +struct data data_append_addr(struct data d, uint64_t addr) +{ + return data_append_integer(d, addr, sizeof(addr) * 8); } struct data data_append_byte(struct data d, uint8_t byte) diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index e866ea5166a..3b41bfca636 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -29,6 +29,7 @@ PROPNODECHAR [a-zA-Z0-9,._+*#?@-] PATHCHAR ({PROPNODECHAR}|[/]) LABEL [a-zA-Z_][a-zA-Z0-9_]* STRING \"([^\\"]|\\.)*\" +CHAR_LITERAL '([^']|\\')*' WS [[:space:]] COMMENT "/*"([^*]|\*+[^*/])*\*+"/" LINECOMMENT "//".*\n @@ -70,6 +71,27 @@ static int pop_input_file(void); push_input_file(name); } +<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { + char *line, *tmp, *fn; + /* skip text before line # */ + line = yytext; + while (!isdigit(*line)) + line++; + /* skip digits in line # */ + tmp = line; + while (!isspace(*tmp)) + tmp++; + /* "NULL"-terminate line # */ + *tmp = '\0'; + /* start of filename */ + fn = strchr(tmp + 1, '"') + 1; + /* strip trailing " from filename */ + tmp = strchr(fn, '"'); + *tmp = 0; + /* -1 since #line is the number of the next line */ + srcpos_set_line(xstrdup(fn), atoi(line) - 1); + } + <*><<EOF>> { if (!pop_input_file()) { yyterminate(); @@ -96,6 +118,26 @@ static int pop_input_file(void); return DT_MEMRESERVE; } +<*>"/bits/" { + DPRINT("Keyword: /bits/\n"); + BEGIN_DEFAULT(); + return DT_BITS; + } + +<*>"/delete-property/" { + DPRINT("Keyword: /delete-property/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_PROP; + } + +<*>"/delete-node/" { + DPRINT("Keyword: /delete-node/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_NODE; + } + <*>{LABEL}: { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -103,12 +145,19 @@ static int pop_input_file(void); return DT_LABEL; } -<V1>[0-9]+|0[xX][0-9a-fA-F]+ { +<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? { yylval.literal = xstrdup(yytext); DPRINT("Literal: '%s'\n", yylval.literal); return DT_LITERAL; } +<*>{CHAR_LITERAL} { + yytext[yyleng-1] = '\0'; + yylval.literal = xstrdup(yytext+1); + DPRINT("Character literal: %s\n", yylval.literal); + return DT_CHAR_LITERAL; + } + <*>\&{LABEL} { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); @@ -134,9 +183,10 @@ static int pop_input_file(void); return ']'; } -<PROPNODENAME>{PROPNODECHAR}+ { +<PROPNODENAME>\\?{PROPNODECHAR}+ { DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = xstrdup(yytext); + yylval.propnodename = xstrdup((yytext[0] == '\\') ? + yytext + 1 : yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } @@ -150,6 +200,15 @@ static int pop_input_file(void); <*>{COMMENT}+ /* eat C-style comments */ <*>{LINECOMMENT}+ /* eat C++-style comments */ +<*>"<<" { return DT_LSHIFT; }; +<*>">>" { return DT_RSHIFT; }; +<*>"<=" { return DT_LE; }; +<*>">=" { return DT_GE; }; +<*>"==" { return DT_EQ; }; +<*>"!=" { return DT_NE; }; +<*>"&&" { return DT_AND; }; +<*>"||" { return DT_OR; }; + <*>. { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index 8bbe1281705..2d30f41778b 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -1,5 +1,6 @@ +#line 2 "dtc-lexer.lex.c" -#line 3 "scripts/dtc/dtc-lexer.lex.c_shipped" +#line 4 "dtc-lexer.lex.c" #define YY_INT_ALIGNED short int @@ -53,7 +54,6 @@ typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -84,6 +84,8 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ #ifdef __cplusplus @@ -140,7 +142,15 @@ typedef unsigned int flex_uint32_t; /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -362,8 +372,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 17 -#define YY_END_OF_BUFFER 18 +#define YY_NUM_RULES 30 +#define YY_END_OF_BUFFER 31 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -371,37 +381,43 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[94] = +static yyconst flex_int16_t yy_accept[161] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 18, 16, 13, 13, 16, 16, 16, 16, 16, 16, - 16, 10, 11, 11, 6, 6, 13, 0, 2, 0, - 7, 0, 0, 0, 0, 0, 0, 0, 5, 0, - 9, 9, 11, 11, 6, 0, 7, 0, 0, 0, - 0, 15, 0, 0, 0, 0, 6, 0, 14, 0, - 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 12, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 4, 0 - + 31, 29, 18, 18, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 15, 16, + 16, 29, 16, 10, 10, 18, 26, 0, 3, 0, + 27, 12, 0, 0, 11, 0, 0, 0, 0, 0, + 0, 0, 21, 23, 25, 24, 22, 0, 9, 28, + 0, 0, 0, 14, 14, 16, 16, 16, 10, 10, + 10, 0, 12, 0, 11, 0, 0, 0, 20, 0, + 0, 0, 0, 0, 0, 0, 0, 16, 10, 10, + 10, 0, 19, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 16, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 6, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 17, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 5, 8, 0, 0, 0, 0, 7, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 4, 5, 1, 1, 6, 1, 1, - 1, 7, 5, 5, 8, 5, 9, 10, 11, 12, - 12, 12, 12, 12, 12, 12, 12, 13, 1, 1, - 1, 1, 5, 5, 14, 14, 14, 14, 14, 14, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, - 1, 17, 18, 1, 15, 1, 14, 19, 20, 21, - - 22, 14, 15, 15, 23, 15, 15, 24, 25, 26, - 15, 15, 15, 27, 28, 29, 30, 31, 15, 16, - 15, 15, 32, 1, 33, 1, 1, 1, 1, 1, + 1, 2, 5, 6, 7, 1, 1, 8, 9, 1, + 1, 10, 11, 11, 12, 11, 13, 14, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 17, 1, 18, + 19, 20, 11, 11, 21, 21, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 23, 22, 22, 22, 22, + 22, 22, 22, 22, 24, 22, 22, 25, 22, 22, + 1, 26, 27, 1, 22, 1, 21, 28, 29, 30, + + 31, 21, 22, 22, 32, 22, 22, 33, 34, 35, + 36, 37, 22, 38, 39, 40, 41, 42, 22, 25, + 43, 22, 44, 45, 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -418,112 +434,163 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[34] = +static yyconst flex_int32_t yy_meta[47] = { 0, - 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, - 4, 4, 5, 6, 7, 7, 1, 1, 6, 6, - 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 8, 1 + 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, + 2, 2, 4, 5, 5, 5, 6, 1, 1, 1, + 7, 8, 8, 8, 8, 1, 1, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 3, 1, 1 } ; -static yyconst flex_int16_t yy_base[106] = +static yyconst flex_int16_t yy_base[175] = { 0, - 0, 0, 237, 236, 25, 0, 47, 0, 30, 71, - 244, 247, 82, 84, 84, 211, 95, 229, 218, 0, - 111, 247, 0, 84, 83, 95, 106, 86, 247, 237, - 0, 230, 231, 234, 207, 209, 212, 220, 247, 206, - 247, 218, 0, 106, 116, 0, 0, 0, 223, 89, - 226, 219, 199, 206, 200, 204, 0, 190, 213, 212, - 202, 91, 178, 161, 247, 172, 144, 150, 140, 130, - 140, 124, 128, 120, 138, 137, 123, 122, 247, 247, - 134, 114, 132, 86, 135, 125, 90, 136, 247, 97, - 29, 247, 247, 153, 156, 161, 165, 170, 176, 180, - - 187, 195, 200, 205, 212 + 0, 385, 378, 40, 41, 383, 72, 382, 34, 44, + 388, 393, 61, 117, 368, 116, 115, 115, 115, 48, + 367, 107, 368, 339, 127, 120, 0, 147, 393, 0, + 127, 0, 133, 156, 168, 153, 393, 125, 393, 380, + 393, 0, 369, 127, 393, 160, 371, 377, 347, 21, + 343, 346, 393, 393, 393, 393, 393, 359, 393, 393, + 183, 343, 339, 393, 356, 0, 183, 340, 187, 348, + 347, 0, 0, 0, 178, 359, 195, 365, 354, 326, + 332, 325, 334, 328, 204, 326, 331, 324, 393, 335, + 150, 311, 343, 342, 315, 322, 340, 179, 313, 207, + + 319, 316, 317, 393, 337, 333, 305, 302, 311, 301, + 310, 190, 338, 337, 393, 307, 322, 301, 305, 277, + 208, 311, 307, 278, 271, 270, 248, 246, 213, 130, + 393, 393, 263, 235, 207, 221, 218, 229, 213, 213, + 206, 234, 218, 210, 208, 193, 219, 393, 223, 204, + 176, 157, 393, 393, 120, 106, 97, 119, 393, 393, + 245, 251, 259, 263, 267, 273, 280, 284, 292, 300, + 304, 310, 318, 326 } ; -static yyconst flex_int16_t yy_def[106] = +static yyconst flex_int16_t yy_def[175] = { 0, - 93, 1, 1, 1, 1, 5, 93, 7, 1, 1, - 93, 93, 93, 93, 94, 95, 93, 96, 17, 97, - 96, 93, 98, 99, 93, 93, 93, 94, 93, 94, - 100, 93, 101, 102, 93, 93, 93, 96, 93, 93, - 93, 96, 98, 99, 93, 103, 100, 104, 101, 101, - 102, 93, 93, 93, 93, 93, 103, 104, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 105, 93, 105, 93, 105, - 93, 93, 0, 93, 93, 93, 93, 93, 93, 93, - - 93, 93, 93, 93, 93 + 160, 1, 1, 1, 1, 5, 160, 7, 1, 1, + 160, 160, 160, 160, 160, 161, 162, 163, 160, 160, + 160, 160, 164, 160, 160, 160, 165, 164, 160, 166, + 167, 166, 166, 160, 160, 160, 160, 161, 160, 161, + 160, 168, 160, 163, 160, 163, 169, 170, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 164, 160, 160, + 160, 160, 160, 160, 164, 166, 167, 166, 160, 160, + 160, 171, 168, 172, 163, 169, 169, 170, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 166, 160, 160, + 171, 172, 160, 160, 160, 160, 160, 160, 160, 160, + + 160, 160, 166, 160, 160, 160, 160, 160, 160, 160, + 160, 173, 160, 166, 160, 160, 160, 160, 160, 160, + 173, 160, 173, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 174, 160, 160, 160, 174, 160, 174, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 0, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160 } ; -static yyconst flex_int16_t yy_nxt[281] = +static yyconst flex_int16_t yy_nxt[440] = { 0, - 12, 13, 14, 15, 12, 16, 12, 12, 17, 12, - 12, 12, 12, 18, 18, 18, 12, 12, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 12, 12, 19, 20, 20, 20, 92, 21, 25, - 26, 26, 22, 21, 21, 21, 21, 12, 13, 14, - 15, 23, 16, 23, 23, 19, 23, 23, 23, 12, - 24, 24, 24, 12, 12, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 12, 12, - 25, 26, 26, 27, 27, 27, 27, 29, 43, 29, - 43, 43, 45, 45, 45, 50, 39, 59, 46, 93, - - 30, 33, 30, 34, 45, 45, 45, 27, 27, 68, - 43, 91, 43, 43, 69, 35, 87, 36, 39, 37, - 42, 42, 42, 39, 42, 45, 45, 45, 89, 42, - 42, 42, 42, 85, 85, 86, 85, 85, 86, 89, - 84, 90, 83, 82, 81, 80, 79, 78, 77, 76, - 75, 74, 90, 28, 28, 28, 28, 28, 28, 28, - 28, 31, 31, 31, 38, 38, 38, 38, 41, 73, - 41, 43, 72, 43, 71, 43, 43, 44, 33, 44, - 44, 44, 44, 47, 69, 47, 47, 49, 49, 49, - 49, 49, 49, 49, 49, 51, 51, 51, 51, 51, - - 51, 51, 51, 57, 70, 57, 58, 58, 58, 67, - 58, 58, 88, 88, 88, 88, 88, 88, 88, 88, - 34, 66, 65, 64, 63, 62, 61, 60, 52, 50, - 39, 56, 39, 55, 54, 53, 52, 50, 48, 93, - 40, 39, 32, 93, 19, 19, 11, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93 + 12, 13, 14, 13, 15, 16, 12, 17, 18, 12, + 12, 12, 19, 12, 12, 12, 12, 20, 21, 22, + 23, 23, 23, 23, 23, 12, 12, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 12, 24, 12, 25, 34, 35, 35, + 25, 81, 26, 26, 27, 27, 27, 34, 35, 35, + 82, 28, 36, 36, 36, 53, 54, 29, 28, 28, + 28, 28, 12, 13, 14, 13, 15, 16, 30, 17, + 18, 30, 30, 30, 26, 30, 30, 30, 12, 20, + 21, 22, 31, 31, 31, 31, 31, 32, 12, 31, + + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 12, 24, 12, 36, 36, + 36, 39, 41, 45, 47, 56, 57, 48, 61, 47, + 39, 159, 48, 66, 61, 45, 66, 66, 66, 158, + 46, 40, 49, 59, 50, 157, 51, 49, 52, 50, + 40, 63, 46, 52, 36, 36, 36, 156, 43, 62, + 65, 65, 65, 59, 136, 68, 137, 65, 75, 69, + 69, 69, 70, 71, 65, 65, 65, 65, 70, 71, + 72, 69, 69, 69, 61, 46, 45, 155, 154, 66, + 70, 71, 66, 66, 66, 122, 85, 85, 85, 59, + + 69, 69, 69, 46, 77, 100, 109, 93, 100, 70, + 71, 110, 112, 122, 129, 123, 153, 85, 85, 85, + 135, 135, 135, 148, 148, 160, 135, 135, 135, 152, + 142, 142, 142, 123, 143, 142, 142, 142, 151, 143, + 150, 146, 145, 149, 149, 38, 38, 38, 38, 38, + 38, 38, 38, 42, 144, 141, 140, 42, 42, 44, + 44, 44, 44, 44, 44, 44, 44, 58, 58, 58, + 58, 64, 139, 64, 66, 138, 134, 66, 133, 66, + 66, 67, 132, 131, 67, 67, 67, 67, 73, 130, + 73, 73, 76, 76, 76, 76, 76, 76, 76, 76, + + 78, 78, 78, 78, 78, 78, 78, 78, 91, 160, + 91, 92, 129, 92, 92, 128, 92, 92, 121, 121, + 121, 121, 121, 121, 121, 121, 147, 147, 147, 147, + 147, 147, 147, 147, 127, 126, 125, 124, 61, 61, + 120, 119, 118, 117, 116, 115, 47, 114, 110, 113, + 111, 108, 107, 106, 48, 105, 104, 89, 103, 102, + 101, 99, 98, 97, 96, 95, 94, 79, 77, 90, + 89, 88, 59, 87, 86, 59, 84, 83, 80, 79, + 77, 74, 160, 60, 59, 55, 37, 160, 33, 25, + 26, 25, 11, 160, 160, 160, 160, 160, 160, 160, + + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160 } ; -static yyconst flex_int16_t yy_chk[281] = +static yyconst flex_int16_t yy_chk[440] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 5, 5, 5, 5, 91, 5, 9, - 9, 9, 5, 5, 5, 5, 5, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4, 9, 9, 9, + 10, 50, 4, 5, 5, 5, 5, 10, 10, 10, + 50, 5, 13, 13, 13, 20, 20, 5, 5, 5, + 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 10, 10, 10, 13, 13, 14, 14, 15, 24, 28, - 24, 24, 25, 25, 25, 50, 24, 50, 25, 90, - - 15, 17, 28, 17, 26, 26, 26, 27, 27, 62, - 44, 87, 44, 44, 62, 17, 84, 17, 44, 17, - 21, 21, 21, 21, 21, 45, 45, 45, 86, 21, - 21, 21, 21, 83, 83, 83, 85, 85, 85, 88, - 82, 86, 81, 78, 77, 76, 75, 74, 73, 72, - 71, 70, 88, 94, 94, 94, 94, 94, 94, 94, - 94, 95, 95, 95, 96, 96, 96, 96, 97, 69, - 97, 98, 68, 98, 67, 98, 98, 99, 66, 99, - 99, 99, 99, 100, 64, 100, 100, 101, 101, 101, - 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, - - 102, 102, 102, 103, 63, 103, 104, 104, 104, 61, - 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, - 60, 59, 58, 56, 55, 54, 53, 52, 51, 49, - 42, 40, 38, 37, 36, 35, 34, 33, 32, 30, - 19, 18, 16, 11, 4, 3, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93 + 7, 7, 7, 7, 7, 7, 7, 7, 14, 14, + 14, 16, 17, 18, 19, 22, 22, 19, 25, 26, + 38, 158, 26, 31, 33, 44, 31, 31, 31, 157, + 18, 16, 19, 31, 19, 156, 19, 26, 19, 26, + 38, 26, 44, 26, 36, 36, 36, 155, 17, 25, + 28, 28, 28, 28, 130, 33, 130, 28, 46, 34, + 34, 34, 91, 91, 28, 28, 28, 28, 34, 34, + 34, 35, 35, 35, 61, 46, 75, 152, 151, 67, + 35, 35, 67, 67, 67, 112, 61, 61, 61, 67, + + 69, 69, 69, 75, 77, 85, 98, 77, 100, 69, + 69, 98, 100, 121, 129, 112, 150, 85, 85, 85, + 135, 135, 135, 143, 147, 149, 129, 129, 129, 146, + 138, 138, 138, 121, 138, 142, 142, 142, 145, 142, + 144, 141, 140, 143, 147, 161, 161, 161, 161, 161, + 161, 161, 161, 162, 139, 137, 136, 162, 162, 163, + 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, + 164, 165, 134, 165, 166, 133, 128, 166, 127, 166, + 166, 167, 126, 125, 167, 167, 167, 167, 168, 124, + 168, 168, 169, 169, 169, 169, 169, 169, 169, 169, + + 170, 170, 170, 170, 170, 170, 170, 170, 171, 123, + 171, 172, 122, 172, 172, 120, 172, 172, 173, 173, + 173, 173, 173, 173, 173, 173, 174, 174, 174, 174, + 174, 174, 174, 174, 119, 118, 117, 116, 114, 113, + 111, 110, 109, 108, 107, 106, 105, 103, 102, 101, + 99, 97, 96, 95, 94, 93, 92, 90, 88, 87, + 86, 84, 83, 82, 81, 80, 79, 78, 76, 71, + 70, 68, 65, 63, 62, 58, 52, 51, 49, 48, + 47, 43, 40, 24, 23, 21, 15, 11, 8, 6, + 3, 2, 160, 160, 160, 160, 160, 160, 160, 160, + + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160 } ; static yy_state_type yy_last_accepting_state; @@ -540,6 +607,7 @@ int yy_flex_debug = 0; #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; +#line 1 "dtc-lexer.l" /* * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * @@ -561,6 +629,10 @@ char *yytext; */ #define YY_NO_INPUT 1 + + + +#line 38 "dtc-lexer.l" #include "dtc.h" #include "srcpos.h" #include "dtc-parser.tab.h" @@ -588,6 +660,7 @@ static int dts_version = 1; static void push_input_file(const char *filename); static int pop_input_file(void); +#line 664 "dtc-lexer.lex.c" #define INITIAL 0 #define INCLUDE 1 @@ -670,7 +743,12 @@ static int input (void ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -689,7 +767,7 @@ static int input (void ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - unsigned n; \ + size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -761,6 +839,9 @@ extern int yylex (void); #endif #define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. @@ -771,6 +852,10 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; +#line 67 "dtc-lexer.l" + +#line 858 "dtc-lexer.lex.c" + if ( !(yy_init) ) { (yy_init) = 1; @@ -810,6 +895,7 @@ YY_DECL yy_bp = yy_cp; yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); yy_match: do { @@ -822,13 +908,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 94 ) + if ( yy_current_state >= 161 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 93 ); + while ( yy_current_state != 160 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -851,26 +937,54 @@ do_action: /* This label is used only to access EOF actions. */ case 1: /* rule 1 can match eol */ YY_RULE_SETUP +#line 68 "dtc-lexer.l" { char *name = strchr(yytext, '\"') + 1; yytext[yyleng-1] = '\0'; push_input_file(name); } YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 74 "dtc-lexer.l" +{ + char *line, *tmp, *fn; + /* skip text before line # */ + line = yytext; + while (!isdigit(*line)) + line++; + /* skip digits in line # */ + tmp = line; + while (!isspace(*tmp)) + tmp++; + /* "NULL"-terminate line # */ + *tmp = '\0'; + /* start of filename */ + fn = strchr(tmp + 1, '"') + 1; + /* strip trailing " from filename */ + tmp = strchr(fn, '"'); + *tmp = 0; + /* -1 since #line is the number of the next line */ + srcpos_set_line(xstrdup(fn), atoi(line) - 1); + } + YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(INCLUDE): case YY_STATE_EOF(BYTESTRING): case YY_STATE_EOF(PROPNODENAME): case YY_STATE_EOF(V1): +#line 95 "dtc-lexer.l" { if (!pop_input_file()) { yyterminate(); } } YY_BREAK -case 2: -/* rule 2 can match eol */ +case 3: +/* rule 3 can match eol */ YY_RULE_SETUP +#line 101 "dtc-lexer.l" { DPRINT("String: %s\n", yytext); yylval.data = data_copy_escape_string(yytext+1, @@ -878,8 +992,9 @@ YY_RULE_SETUP return DT_STRING; } YY_BREAK -case 3: +case 4: YY_RULE_SETUP +#line 108 "dtc-lexer.l" { DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; @@ -887,16 +1002,47 @@ YY_RULE_SETUP return DT_V1; } YY_BREAK -case 4: +case 5: YY_RULE_SETUP +#line 115 "dtc-lexer.l" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; } YY_BREAK -case 5: +case 6: +YY_RULE_SETUP +#line 121 "dtc-lexer.l" +{ + DPRINT("Keyword: /bits/\n"); + BEGIN_DEFAULT(); + return DT_BITS; + } + YY_BREAK +case 7: YY_RULE_SETUP +#line 127 "dtc-lexer.l" +{ + DPRINT("Keyword: /delete-property/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_PROP; + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 134 "dtc-lexer.l" +{ + DPRINT("Keyword: /delete-node/\n"); + DPRINT("<PROPNODENAME>\n"); + BEGIN(PROPNODENAME); + return DT_DEL_NODE; + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 141 "dtc-lexer.l" { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -904,24 +1050,38 @@ YY_RULE_SETUP return DT_LABEL; } YY_BREAK -case 6: +case 10: YY_RULE_SETUP +#line 148 "dtc-lexer.l" { yylval.literal = xstrdup(yytext); DPRINT("Literal: '%s'\n", yylval.literal); return DT_LITERAL; } YY_BREAK -case 7: +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 154 "dtc-lexer.l" +{ + yytext[yyleng-1] = '\0'; + yylval.literal = xstrdup(yytext+1); + DPRINT("Character literal: %s\n", yylval.literal); + return DT_CHAR_LITERAL; + } + YY_BREAK +case 12: YY_RULE_SETUP +#line 161 "dtc-lexer.l" { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); return DT_REF; } YY_BREAK -case 8: +case 13: YY_RULE_SETUP +#line 167 "dtc-lexer.l" { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); @@ -929,55 +1089,104 @@ YY_RULE_SETUP return DT_REF; } YY_BREAK -case 9: +case 14: YY_RULE_SETUP +#line 174 "dtc-lexer.l" { yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } YY_BREAK -case 10: +case 15: YY_RULE_SETUP +#line 180 "dtc-lexer.l" { DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } YY_BREAK -case 11: +case 16: YY_RULE_SETUP +#line 186 "dtc-lexer.l" { DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = xstrdup(yytext); + yylval.propnodename = xstrdup((yytext[0] == '\\') ? + yytext + 1 : yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } YY_BREAK -case 12: +case 17: YY_RULE_SETUP +#line 194 "dtc-lexer.l" { DPRINT("Binary Include\n"); return DT_INCBIN; } YY_BREAK -case 13: -/* rule 13 can match eol */ +case 18: +/* rule 18 can match eol */ YY_RULE_SETUP +#line 199 "dtc-lexer.l" /* eat whitespace */ YY_BREAK -case 14: -/* rule 14 can match eol */ +case 19: +/* rule 19 can match eol */ YY_RULE_SETUP +#line 200 "dtc-lexer.l" /* eat C-style comments */ YY_BREAK -case 15: -/* rule 15 can match eol */ +case 20: +/* rule 20 can match eol */ YY_RULE_SETUP +#line 201 "dtc-lexer.l" /* eat C++-style comments */ YY_BREAK -case 16: +case 21: YY_RULE_SETUP +#line 203 "dtc-lexer.l" +{ return DT_LSHIFT; }; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 204 "dtc-lexer.l" +{ return DT_RSHIFT; }; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 205 "dtc-lexer.l" +{ return DT_LE; }; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 206 "dtc-lexer.l" +{ return DT_GE; }; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 207 "dtc-lexer.l" +{ return DT_EQ; }; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 208 "dtc-lexer.l" +{ return DT_NE; }; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 209 "dtc-lexer.l" +{ return DT_AND; }; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 210 "dtc-lexer.l" +{ return DT_OR; }; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 212 "dtc-lexer.l" { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); @@ -993,10 +1202,12 @@ YY_RULE_SETUP return yytext[0]; } YY_BREAK -case 17: +case 30: YY_RULE_SETUP +#line 227 "dtc-lexer.l" ECHO; YY_BREAK +#line 1211 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -1275,6 +1486,7 @@ static int yy_get_next_buffer (void) register char *yy_cp; yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { @@ -1287,7 +1499,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 94 ) + if ( yy_current_state >= 161 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1315,11 +1527,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 94 ) + if ( yy_current_state >= 161 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 93); + yy_is_jam = (yy_current_state == 160); return yy_is_jam ? 0 : yy_current_state; } @@ -1394,6 +1606,8 @@ static int yy_get_next_buffer (void) *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + return c; } #endif /* ifndef YY_NO_INPUT */ @@ -1712,8 +1926,8 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ @@ -1952,6 +2166,10 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" +#line 227 "dtc-lexer.l" + + + static void push_input_file(const char *filename) { assert(filename); @@ -1963,6 +2181,7 @@ static void push_input_file(const char *filename) yypush_buffer_state(yy_create_buffer(yyin,YY_BUF_SIZE)); } + static int pop_input_file(void) { if (srcfile_pop() == 0) diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index b05921e1e84..c8769d550cf 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -1,9 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.4.3. */ +/* A Bison parser, made by GNU Bison 2.7.12-4996. */ -/* Skeleton implementation for Bison's Yacc-like parsers in C +/* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. 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 @@ -45,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.4.3" +#define YYBISON_VERSION "2.7.12-4996" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -59,13 +58,12 @@ /* Pull parsers. */ #define YYPULL 1 -/* Using locations. */ -#define YYLSP_NEEDED 0 /* Copy the first part of user declarations. */ - +/* Line 371 of yacc.c */ +#line 21 "dtc-parser.y" #include <stdio.h> @@ -82,13 +80,18 @@ extern struct boot_info *the_boot_info; extern int treesource_error; static unsigned long long eval_literal(const char *s, int base, int bits); +static unsigned char eval_char_literal(const char *s); +/* Line 371 of yacc.c */ +#line 87 "dtc-parser.tab.c" - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 1 -#endif +# ifndef YY_NULL +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULL nullptr +# else +# define YY_NULL 0 +# endif +# endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE @@ -98,11 +101,17 @@ static unsigned long long eval_literal(const char *s, int base, int bits); # define YYERROR_VERBOSE 0 #endif -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 +/* In a future release of Bison, this section will be replaced + by #include "dtc-parser.tab.h". */ +#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED +# define YY_YY_DTC_PARSER_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; #endif - /* Tokens. */ #ifndef YYTOKENTYPE @@ -112,23 +121,35 @@ static unsigned long long eval_literal(const char *s, int base, int bits); enum yytokentype { DT_V1 = 258, DT_MEMRESERVE = 259, - DT_PROPNODENAME = 260, - DT_LITERAL = 261, - DT_BASE = 262, - DT_BYTE = 263, - DT_STRING = 264, - DT_LABEL = 265, - DT_REF = 266, - DT_INCBIN = 267 + DT_LSHIFT = 260, + DT_RSHIFT = 261, + DT_LE = 262, + DT_GE = 263, + DT_EQ = 264, + DT_NE = 265, + DT_AND = 266, + DT_OR = 267, + DT_BITS = 268, + DT_DEL_PROP = 269, + DT_DEL_NODE = 270, + DT_PROPNODENAME = 271, + DT_LITERAL = 272, + DT_CHAR_LITERAL = 273, + DT_BASE = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { - +/* Line 387 of yacc.c */ +#line 40 "dtc-parser.y" char *propnodename; char *literal; @@ -137,26 +158,49 @@ typedef union YYSTYPE uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; - +/* Line 387 of yacc.c */ +#line 176 "dtc-parser.tab.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif +extern YYSTYPE yylval; -/* Copy the second part of user declarations. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ +#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */ +/* Copy the second part of user declarations. */ + +/* Line 390 of yacc.c */ +#line 204 "dtc-parser.tab.c" #ifdef short # undef short @@ -209,24 +253,33 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include <libintl.h> /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ -# define YY_(msgid) msgid +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if (! defined __GNUC__ || __GNUC__ < 2 \ + || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)) +# define __attribute__(Spec) /* empty */ # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) +# define YYUSE(E) ((void) (E)) #else -# define YYUSE(e) /* empty */ +# define YYUSE(E) /* empty */ #endif + /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint -# define YYID(n) (n) +# define YYID(N) (N) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) @@ -259,11 +312,12 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # endif @@ -286,24 +340,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined _STDLIB_H \ +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -332,23 +386,7 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif +# define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of @@ -368,23 +406,43 @@ union yyalloc #endif +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + /* YYFINAL -- State number of the termination state. */ #define YYFINAL 4 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 56 +#define YYLAST 133 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 25 +#define YYNTOKENS 48 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 16 +#define YYNNTS 28 /* YYNRULES -- Number of rules. */ -#define YYNRULES 39 +#define YYNRULES 79 /* YYNRULES -- Number of states. */ -#define YYNSTATES 67 +#define YYNSTATES 141 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 267 +#define YYMAXUTOK 279 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -395,16 +453,16 @@ static const yytype_uint8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 47, 2, 2, 2, 45, 41, 2, + 33, 35, 44, 42, 34, 43, 2, 26, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 38, 25, + 36, 29, 30, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 22, 24, 2, 2, 23, 2, 2, 14, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, - 18, 17, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 31, 2, 32, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 20, 2, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 15, 2, 16, 2, 2, 2, 2, + 2, 2, 2, 27, 39, 28, 46, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -418,60 +476,89 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12 + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ -static const yytype_uint8 yyprhs[] = +static const yytype_uint16 yyprhs[] = { - 0, 0, 3, 8, 9, 12, 17, 20, 22, 25, - 29, 33, 39, 40, 43, 48, 51, 54, 57, 62, - 67, 70, 80, 86, 89, 90, 93, 96, 97, 100, - 103, 106, 108, 109, 112, 115, 116, 119, 122, 125 + 0, 0, 3, 8, 9, 12, 17, 20, 23, 27, + 31, 36, 42, 43, 46, 51, 54, 58, 61, 64, + 68, 73, 76, 86, 92, 95, 96, 99, 102, 106, + 108, 111, 114, 117, 119, 121, 125, 127, 129, 135, + 137, 141, 143, 147, 149, 153, 155, 159, 161, 165, + 167, 171, 175, 177, 181, 185, 189, 193, 197, 201, + 203, 207, 211, 213, 217, 221, 225, 227, 229, 232, + 235, 238, 239, 242, 245, 246, 249, 252, 255, 259 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 26, 0, -1, 3, 13, 27, 30, -1, -1, 28, - 27, -1, 4, 29, 29, 13, -1, 10, 28, -1, - 6, -1, 14, 31, -1, 30, 14, 31, -1, 30, - 11, 31, -1, 15, 32, 39, 16, 13, -1, -1, - 32, 33, -1, 5, 17, 34, 13, -1, 5, 13, - -1, 10, 33, -1, 35, 9, -1, 35, 18, 36, - 19, -1, 35, 20, 38, 21, -1, 35, 11, -1, - 35, 12, 22, 9, 23, 29, 23, 29, 24, -1, - 35, 12, 22, 9, 24, -1, 34, 10, -1, -1, - 34, 23, -1, 35, 10, -1, -1, 36, 37, -1, - 36, 11, -1, 36, 10, -1, 6, -1, -1, 38, - 8, -1, 38, 10, -1, -1, 40, 39, -1, 40, - 33, -1, 5, 31, -1, 10, 40, -1 + 49, 0, -1, 3, 25, 50, 52, -1, -1, 51, + 50, -1, 4, 59, 59, 25, -1, 22, 51, -1, + 26, 53, -1, 52, 26, 53, -1, 52, 23, 53, + -1, 52, 15, 23, 25, -1, 27, 54, 74, 28, + 25, -1, -1, 54, 55, -1, 16, 29, 56, 25, + -1, 16, 25, -1, 14, 16, 25, -1, 22, 55, + -1, 57, 21, -1, 57, 58, 30, -1, 57, 31, + 73, 32, -1, 57, 23, -1, 57, 24, 33, 21, + 34, 59, 34, 59, 35, -1, 57, 24, 33, 21, + 35, -1, 56, 22, -1, -1, 56, 34, -1, 57, + 22, -1, 13, 17, 36, -1, 36, -1, 58, 59, + -1, 58, 23, -1, 58, 22, -1, 17, -1, 18, + -1, 33, 60, 35, -1, 61, -1, 62, -1, 62, + 37, 60, 38, 61, -1, 63, -1, 62, 12, 63, + -1, 64, -1, 63, 11, 64, -1, 65, -1, 64, + 39, 65, -1, 66, -1, 65, 40, 66, -1, 67, + -1, 66, 41, 67, -1, 68, -1, 67, 9, 68, + -1, 67, 10, 68, -1, 69, -1, 68, 36, 69, + -1, 68, 30, 69, -1, 68, 7, 69, -1, 68, + 8, 69, -1, 69, 5, 70, -1, 69, 6, 70, + -1, 70, -1, 70, 42, 71, -1, 70, 43, 71, + -1, 71, -1, 71, 44, 72, -1, 71, 26, 72, + -1, 71, 45, 72, -1, 72, -1, 59, -1, 43, + 72, -1, 46, 72, -1, 47, 72, -1, -1, 73, + 20, -1, 73, 22, -1, -1, 75, 74, -1, 75, + 55, -1, 16, 53, -1, 15, 16, 25, -1, 22, + 75, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 86, 86, 95, 98, 105, 109, 117, 124, 128, - 132, 145, 153, 156, 163, 167, 171, 179, 183, 187, - 191, 195, 212, 222, 230, 233, 237, 245, 248, 252, - 257, 264, 272, 275, 279, 287, 290, 294, 302, 306 + 0, 109, 109, 118, 121, 128, 132, 140, 144, 148, + 158, 172, 180, 183, 190, 194, 198, 202, 210, 214, + 218, 222, 226, 243, 253, 261, 264, 268, 275, 290, + 295, 315, 329, 336, 340, 344, 351, 355, 356, 360, + 361, 365, 366, 370, 371, 375, 376, 380, 381, 385, + 386, 387, 391, 392, 393, 394, 395, 399, 400, 401, + 405, 406, 407, 411, 412, 413, 414, 418, 419, 420, + 421, 426, 429, 433, 441, 444, 448, 456, 460, 464 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +#if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { - "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", - "DT_PROPNODENAME", "DT_LITERAL", "DT_BASE", "DT_BYTE", "DT_STRING", - "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", - "'<'", "'>'", "'['", "']'", "'('", "','", "')'", "$accept", "sourcefile", - "memreserves", "memreserve", "addr", "devicetree", "nodedef", "proplist", - "propdef", "propdata", "propdataprefix", "celllist", "cellval", - "bytestring", "subnodes", "subnode", 0 + "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT", + "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR", + "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL", + "DT_CHAR_LITERAL", "DT_BASE", "DT_BYTE", "DT_STRING", "DT_LABEL", + "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", + "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", + "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", + "memreserves", "memreserve", "devicetree", "nodedef", "proplist", + "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim", + "integer_expr", "integer_trinary", "integer_or", "integer_and", + "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq", + "integer_rela", "integer_shift", "integer_add", "integer_mul", + "integer_unary", "bytestring", "subnodes", "subnode", YY_NULL }; #endif @@ -481,107 +568,164 @@ static const char *const yytname[] = static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 59, 47, 123, 125, 61, 60, 62, - 91, 93, 40, 44, 41 + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 59, 47, 123, 125, 61, + 62, 91, 93, 40, 44, 41, 60, 63, 58, 124, + 94, 38, 43, 45, 42, 37, 126, 33 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 25, 26, 27, 27, 28, 28, 29, 30, 30, - 30, 31, 32, 32, 33, 33, 33, 34, 34, 34, - 34, 34, 34, 34, 35, 35, 35, 36, 36, 36, - 36, 37, 38, 38, 38, 39, 39, 39, 40, 40 + 0, 48, 49, 50, 50, 51, 51, 52, 52, 52, + 52, 53, 54, 54, 55, 55, 55, 55, 56, 56, + 56, 56, 56, 56, 56, 57, 57, 57, 58, 58, + 58, 58, 58, 59, 59, 59, 60, 61, 61, 62, + 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, + 67, 67, 68, 68, 68, 68, 68, 69, 69, 69, + 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, + 72, 73, 73, 73, 74, 74, 74, 75, 75, 75 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 4, 0, 2, 4, 2, 1, 2, 3, - 3, 5, 0, 2, 4, 2, 2, 2, 4, 4, - 2, 9, 5, 2, 0, 2, 2, 0, 2, 2, - 2, 1, 0, 2, 2, 0, 2, 2, 2, 2 + 0, 2, 4, 0, 2, 4, 2, 2, 3, 3, + 4, 5, 0, 2, 4, 2, 3, 2, 2, 3, + 4, 2, 9, 5, 2, 0, 2, 2, 3, 1, + 2, 2, 2, 1, 1, 3, 1, 1, 5, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, + 3, 3, 1, 3, 3, 3, 1, 1, 2, 2, + 2, 0, 2, 2, 0, 2, 2, 2, 3, 2 }; -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 0, 0, 3, 1, 0, 0, 0, 3, 7, - 0, 6, 0, 2, 4, 0, 12, 8, 0, 0, - 5, 35, 10, 9, 0, 0, 13, 0, 35, 15, - 24, 38, 16, 39, 0, 37, 36, 0, 0, 11, - 23, 14, 25, 17, 26, 20, 0, 27, 32, 0, - 0, 0, 0, 31, 30, 29, 18, 28, 33, 34, - 19, 0, 22, 0, 0, 0, 21 + 0, 0, 0, 3, 1, 0, 0, 0, 3, 33, + 34, 0, 0, 6, 0, 2, 4, 0, 0, 0, + 67, 0, 36, 37, 39, 41, 43, 45, 47, 49, + 52, 59, 62, 66, 0, 12, 7, 0, 0, 0, + 68, 69, 70, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 74, 0, 9, 8, 40, 0, + 42, 44, 46, 48, 50, 51, 55, 56, 54, 53, + 57, 58, 60, 61, 64, 63, 65, 0, 0, 0, + 0, 13, 0, 74, 10, 0, 0, 0, 15, 25, + 77, 17, 79, 0, 76, 75, 38, 16, 78, 0, + 0, 11, 24, 14, 26, 0, 18, 27, 21, 0, + 71, 29, 0, 0, 0, 0, 32, 31, 19, 30, + 28, 0, 72, 73, 20, 0, 23, 0, 0, 0, + 22 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 2, 7, 8, 10, 13, 17, 21, 26, 37, - 38, 50, 57, 51, 27, 28 + -1, 2, 7, 8, 15, 36, 64, 91, 109, 110, + 122, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 125, 92, 93 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -12 +#define YYPACT_NINF -78 static const yytype_int8 yypact[] = { - 10, -11, 18, -1, -12, 22, -1, 15, -1, -12, - 22, -12, 20, 1, -12, 17, -12, -12, 20, 20, - -12, 6, -12, -12, 21, 6, -12, 23, 6, -12, - -12, -12, -12, -12, 28, -12, -12, -6, 13, -12, - -12, -12, -12, -12, -12, -12, 24, -12, -12, 33, - -5, 0, -4, -12, -12, -12, -12, -12, -12, -12, - -12, 22, -12, 25, 22, 19, -12 + 22, 11, 51, 10, -78, 23, 10, 2, 10, -78, + -78, -9, 23, -78, 30, 38, -78, -9, -9, -9, + -78, 35, -78, -6, 52, 29, 48, 49, 33, 3, + 71, 36, 0, -78, 64, -78, -78, 68, 30, 30, + -78, -78, -78, -78, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -78, 44, 67, -78, -78, 52, 55, + 29, 48, 49, 33, 3, 3, 71, 71, 71, 71, + 36, 36, 0, 0, -78, -78, -78, 78, 79, 42, + 44, -78, 69, 44, -78, -9, 73, 74, -78, -78, + -78, -78, -78, 75, -78, -78, -78, -78, -78, -7, + -1, -78, -78, -78, -78, 84, -78, -78, -78, 63, + -78, -78, 32, 66, 82, -3, -78, -78, -78, -78, + -78, 46, -78, -78, -78, 23, -78, 70, 23, 72, + -78 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -12, -12, 36, 39, -10, -12, 8, -12, 12, -12, - -12, -12, -12, -12, 27, 31 + -78, -78, 97, 100, -78, -37, -78, -77, -78, -78, + -78, -5, 65, 13, -78, 76, 77, 62, 80, 83, + 34, 20, 26, 28, -14, -78, 18, 24 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ + number is the opposite. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { - 15, 53, 3, 5, 40, 54, 55, 41, 58, 6, - 59, 24, 18, 1, 56, 19, 25, 42, 4, 61, - 62, 60, 43, 44, 45, 46, 22, 23, 9, 12, - 20, 47, 31, 48, 29, 16, 16, 32, 30, 34, - 35, 39, 52, 66, 14, 11, 49, 0, 64, 0, - 0, 63, 0, 0, 65, 36, 33 + 12, 66, 67, 40, 41, 42, 44, 34, 9, 10, + 52, 53, 115, 101, 5, 112, 104, 132, 113, 133, + 116, 117, 118, 119, 11, 1, 60, 114, 14, 134, + 120, 45, 6, 54, 17, 121, 3, 18, 19, 55, + 9, 10, 50, 51, 61, 62, 84, 85, 86, 9, + 10, 4, 100, 37, 126, 127, 11, 35, 87, 88, + 89, 38, 128, 46, 39, 11, 90, 98, 47, 35, + 43, 99, 76, 77, 78, 79, 56, 57, 58, 59, + 135, 136, 80, 81, 74, 75, 82, 83, 48, 63, + 49, 65, 94, 95, 96, 97, 124, 103, 107, 108, + 111, 123, 130, 131, 138, 16, 13, 140, 106, 71, + 69, 105, 0, 0, 102, 0, 0, 129, 0, 0, + 68, 0, 0, 70, 0, 0, 0, 0, 72, 0, + 137, 0, 73, 139 }; -static const yytype_int8 yycheck[] = +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-78))) + +#define yytable_value_is_error(Yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = { - 10, 6, 13, 4, 10, 10, 11, 13, 8, 10, - 10, 5, 11, 3, 19, 14, 10, 23, 0, 23, - 24, 21, 9, 10, 11, 12, 18, 19, 6, 14, - 13, 18, 24, 20, 13, 15, 15, 25, 17, 16, - 28, 13, 9, 24, 8, 6, 22, -1, 23, -1, - -1, 61, -1, -1, 64, 28, 25 + 5, 38, 39, 17, 18, 19, 12, 12, 17, 18, + 7, 8, 13, 90, 4, 22, 93, 20, 25, 22, + 21, 22, 23, 24, 33, 3, 26, 34, 26, 32, + 31, 37, 22, 30, 43, 36, 25, 46, 47, 36, + 17, 18, 9, 10, 44, 45, 60, 61, 62, 17, + 18, 0, 89, 15, 22, 23, 33, 27, 14, 15, + 16, 23, 30, 11, 26, 33, 22, 25, 39, 27, + 35, 29, 52, 53, 54, 55, 5, 6, 42, 43, + 34, 35, 56, 57, 50, 51, 58, 59, 40, 25, + 41, 23, 25, 38, 16, 16, 33, 28, 25, 25, + 25, 17, 36, 21, 34, 8, 6, 35, 95, 47, + 45, 93, -1, -1, 90, -1, -1, 122, -1, -1, + 44, -1, -1, 46, -1, -1, -1, -1, 48, -1, + 135, -1, 49, 138 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 26, 13, 0, 4, 10, 27, 28, 6, - 29, 28, 14, 30, 27, 29, 15, 31, 11, 14, - 13, 32, 31, 31, 5, 10, 33, 39, 40, 13, - 17, 31, 33, 40, 16, 33, 39, 34, 35, 13, - 10, 13, 23, 9, 10, 11, 12, 18, 20, 22, - 36, 38, 9, 6, 10, 11, 19, 37, 8, 10, - 21, 23, 24, 29, 23, 29, 24 + 0, 3, 49, 25, 0, 4, 22, 50, 51, 17, + 18, 33, 59, 51, 26, 52, 50, 43, 46, 47, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 59, 27, 53, 15, 23, 26, + 72, 72, 72, 35, 12, 37, 11, 39, 40, 41, + 9, 10, 7, 8, 30, 36, 5, 6, 42, 43, + 26, 44, 45, 25, 54, 23, 53, 53, 63, 60, + 64, 65, 66, 67, 68, 68, 69, 69, 69, 69, + 70, 70, 71, 71, 72, 72, 72, 14, 15, 16, + 22, 55, 74, 75, 25, 38, 16, 16, 25, 29, + 53, 55, 75, 28, 55, 74, 61, 25, 25, 56, + 57, 25, 22, 25, 34, 13, 21, 22, 23, 24, + 31, 36, 58, 17, 33, 73, 22, 23, 30, 59, + 36, 21, 20, 22, 32, 34, 35, 59, 34, 59, + 35 }; #define yyerrok (yyerrstatus = 0) @@ -611,72 +755,35 @@ static const yytype_uint8 yystos[] = #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) - +/* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - +/* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ - #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else @@ -726,6 +833,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) YYSTYPE const * const yyvaluep; #endif { + FILE *yyo = yyoutput; + YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT @@ -734,11 +843,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) # else YYUSE (yyoutput); # endif - switch (yytype) - { - default: - break; - } + YYUSE (yytype); } @@ -863,7 +968,6 @@ int yydebug; # define YYMAXDEPTH 10000 #endif - #if YYERROR_VERBOSE @@ -966,115 +1070,145 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULL; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } - if (yysize_overflow) - return YYSIZE_MAXIMUM; + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; } #endif /* YYERROR_VERBOSE */ - /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -1099,44 +1233,34 @@ yydestruct (yymsg, yytype, yyvaluep) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - switch (yytype) - { - - default: - break; - } + YYUSE (yytype); } -/* Prevent warnings from -Wmissing-prototypes. */ -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ + /* The lookahead symbol. */ int yychar; + +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + /* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; +YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); /* Number of syntax errors so far. */ int yynerrs; - -/*-------------------------. -| yyparse or yypush_parse. | -`-------------------------*/ +/*----------. +| yyparse. | +`----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ @@ -1160,8 +1284,6 @@ yyparse () #endif #endif { - - int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -1170,7 +1292,7 @@ yyparse () `yyss': related to states. `yyvs': related to semantic values. - Refer to the stacks thru separate pointers, to allow yyoverflow + Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ @@ -1188,7 +1310,7 @@ yyparse () int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ - int yytoken; + int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; @@ -1206,9 +1328,8 @@ yyparse () Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); @@ -1217,14 +1338,6 @@ yyparse () yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - goto yysetstate; /*------------------------------------------------------------. @@ -1316,7 +1429,7 @@ yybackup: /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) + if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ @@ -1347,8 +1460,8 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; + if (yytable_value_is_error (yyn)) + goto yyerrlab; yyn = -yyn; goto yyreduce; } @@ -1365,7 +1478,9 @@ yybackup: yychar = YYEMPTY; yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -1402,65 +1517,66 @@ yyreduce: switch (yyn) { case 2: - +/* Line 1787 of yacc.c */ +#line 110 "dtc-parser.y" { the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), guess_boot_cpuid((yyvsp[(4) - (4)].node))); - ;} + } break; case 3: - +/* Line 1787 of yacc.c */ +#line 118 "dtc-parser.y" { (yyval.re) = NULL; - ;} + } break; case 4: - +/* Line 1787 of yacc.c */ +#line 122 "dtc-parser.y" { (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); - ;} + } break; case 5: - +/* Line 1787 of yacc.c */ +#line 129 "dtc-parser.y" { - (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].addr), (yyvsp[(3) - (4)].addr)); - ;} + (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer)); + } break; case 6: - +/* Line 1787 of yacc.c */ +#line 133 "dtc-parser.y" { add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref)); (yyval.re) = (yyvsp[(2) - (2)].re); - ;} + } break; case 7: - - { - (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); - ;} - break; - - case 8: - +/* Line 1787 of yacc.c */ +#line 141 "dtc-parser.y" { (yyval.node) = name_node((yyvsp[(2) - (2)].node), ""); - ;} + } break; - case 9: - + case 8: +/* Line 1787 of yacc.c */ +#line 145 "dtc-parser.y" { (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - ;} + } break; - case 10: - + case 9: +/* Line 1787 of yacc.c */ +#line 149 "dtc-parser.y" { struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref)); @@ -1469,102 +1585,137 @@ yyreduce: else print_error("label or path, '%s', not found", (yyvsp[(2) - (3)].labelref)); (yyval.node) = (yyvsp[(1) - (3)].node); - ;} + } break; - case 11: + case 10: +/* Line 1787 of yacc.c */ +#line 159 "dtc-parser.y" + { + struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref)); + + if (!target) + print_error("label or path, '%s', not found", (yyvsp[(3) - (4)].labelref)); + else + delete_node(target); + + (yyval.node) = (yyvsp[(1) - (4)].node); + } + break; + case 11: +/* Line 1787 of yacc.c */ +#line 173 "dtc-parser.y" { (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist)); - ;} + } break; case 12: - +/* Line 1787 of yacc.c */ +#line 180 "dtc-parser.y" { (yyval.proplist) = NULL; - ;} + } break; case 13: - +/* Line 1787 of yacc.c */ +#line 184 "dtc-parser.y" { (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist)); - ;} + } break; case 14: - +/* Line 1787 of yacc.c */ +#line 191 "dtc-parser.y" { (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data)); - ;} + } break; case 15: - +/* Line 1787 of yacc.c */ +#line 195 "dtc-parser.y" { (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data); - ;} + } break; case 16: - +/* Line 1787 of yacc.c */ +#line 199 "dtc-parser.y" { - add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref)); - (yyval.prop) = (yyvsp[(2) - (2)].prop); - ;} + (yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename)); + } break; case 17: - +/* Line 1787 of yacc.c */ +#line 203 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); - ;} + add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref)); + (yyval.prop) = (yyvsp[(2) - (2)].prop); + } break; case 18: - +/* Line 1787 of yacc.c */ +#line 211 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); - ;} + (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); + } break; case 19: - +/* Line 1787 of yacc.c */ +#line 215 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); - ;} + (yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data); + } break; case 20: - +/* Line 1787 of yacc.c */ +#line 219 "dtc-parser.y" { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); - ;} + (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); + } break; case 21: +/* Line 1787 of yacc.c */ +#line 223 "dtc-parser.y" + { + (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); + } + break; + case 22: +/* Line 1787 of yacc.c */ +#line 227 "dtc-parser.y" { FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL); struct data d; - if ((yyvsp[(6) - (9)].addr) != 0) - if (fseek(f, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0) + if ((yyvsp[(6) - (9)].integer) != 0) + if (fseek(f, (yyvsp[(6) - (9)].integer), SEEK_SET) != 0) print_error("Couldn't seek to offset %llu in \"%s\": %s", - (unsigned long long)(yyvsp[(6) - (9)].addr), + (unsigned long long)(yyvsp[(6) - (9)].integer), (yyvsp[(4) - (9)].data).val, strerror(errno)); - d = data_copy_file(f, (yyvsp[(8) - (9)].addr)); + d = data_copy_file(f, (yyvsp[(8) - (9)].integer)); (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d); fclose(f); - ;} + } break; - case 22: - + case 23: +/* Line 1787 of yacc.c */ +#line 244 "dtc-parser.y" { FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL); struct data d = empty_data; @@ -1573,135 +1724,365 @@ yyreduce: (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d); fclose(f); - ;} + } break; - case 23: - + case 24: +/* Line 1787 of yacc.c */ +#line 254 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); - ;} + } break; - case 24: - + case 25: +/* Line 1787 of yacc.c */ +#line 261 "dtc-parser.y" { (yyval.data) = empty_data; - ;} + } break; - case 25: - + case 26: +/* Line 1787 of yacc.c */ +#line 265 "dtc-parser.y" { (yyval.data) = (yyvsp[(1) - (2)].data); - ;} + } break; - case 26: - + case 27: +/* Line 1787 of yacc.c */ +#line 269 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); - ;} + } break; - case 27: + case 28: +/* Line 1787 of yacc.c */ +#line 276 "dtc-parser.y" + { + (yyval.array).data = empty_data; + (yyval.array).bits = eval_literal((yyvsp[(2) - (3)].literal), 0, 7); + + if (((yyval.array).bits != 8) && + ((yyval.array).bits != 16) && + ((yyval.array).bits != 32) && + ((yyval.array).bits != 64)) + { + print_error("Only 8, 16, 32 and 64-bit elements" + " are currently supported"); + (yyval.array).bits = 32; + } + } + break; + case 29: +/* Line 1787 of yacc.c */ +#line 291 "dtc-parser.y" { - (yyval.data) = empty_data; - ;} + (yyval.array).data = empty_data; + (yyval.array).bits = 32; + } break; - case 28: + case 30: +/* Line 1787 of yacc.c */ +#line 296 "dtc-parser.y" + { + if ((yyvsp[(1) - (2)].array).bits < 64) { + uint64_t mask = (1ULL << (yyvsp[(1) - (2)].array).bits) - 1; + /* + * Bits above mask must either be all zero + * (positive within range of mask) or all one + * (negative and sign-extended). The second + * condition is true if when we set all bits + * within the mask to one (i.e. | in the + * mask), all bits are one. + */ + if (((yyvsp[(2) - (2)].integer) > mask) && (((yyvsp[(2) - (2)].integer) | mask) != -1ULL)) + print_error( + "integer value out of range " + "%016lx (%d bits)", (yyvsp[(1) - (2)].array).bits); + } + + (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, (yyvsp[(2) - (2)].integer), (yyvsp[(1) - (2)].array).bits); + } + break; + case 31: +/* Line 1787 of yacc.c */ +#line 316 "dtc-parser.y" { - (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell)); - ;} + uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits); + + if ((yyvsp[(1) - (2)].array).bits == 32) + (yyvsp[(1) - (2)].array).data = data_add_marker((yyvsp[(1) - (2)].array).data, + REF_PHANDLE, + (yyvsp[(2) - (2)].labelref)); + else + print_error("References are only allowed in " + "arrays with 32-bit elements."); + + (yyval.array).data = data_append_integer((yyvsp[(1) - (2)].array).data, val, (yyvsp[(1) - (2)].array).bits); + } break; - case 29: + case 32: +/* Line 1787 of yacc.c */ +#line 330 "dtc-parser.y" + { + (yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref)); + } + break; + case 33: +/* Line 1787 of yacc.c */ +#line 337 "dtc-parser.y" { - (yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE, - (yyvsp[(2) - (2)].labelref)), -1); - ;} + (yyval.integer) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); + } break; - case 30: + case 34: +/* Line 1787 of yacc.c */ +#line 341 "dtc-parser.y" + { + (yyval.integer) = eval_char_literal((yyvsp[(1) - (1)].literal)); + } + break; + case 35: +/* Line 1787 of yacc.c */ +#line 345 "dtc-parser.y" { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); - ;} + (yyval.integer) = (yyvsp[(2) - (3)].integer); + } break; - case 31: + case 38: +/* Line 1787 of yacc.c */ +#line 356 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); } + break; - { - (yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32); - ;} + case 40: +/* Line 1787 of yacc.c */ +#line 361 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); } break; - case 32: + case 42: +/* Line 1787 of yacc.c */ +#line 366 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); } + break; + case 44: +/* Line 1787 of yacc.c */ +#line 371 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); } + break; + + case 46: +/* Line 1787 of yacc.c */ +#line 376 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); } + break; + + case 48: +/* Line 1787 of yacc.c */ +#line 381 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); } + break; + + case 50: +/* Line 1787 of yacc.c */ +#line 386 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); } + break; + + case 51: +/* Line 1787 of yacc.c */ +#line 387 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); } + break; + + case 53: +/* Line 1787 of yacc.c */ +#line 392 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); } + break; + + case 54: +/* Line 1787 of yacc.c */ +#line 393 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); } + break; + + case 55: +/* Line 1787 of yacc.c */ +#line 394 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); } + break; + + case 56: +/* Line 1787 of yacc.c */ +#line 395 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); } + break; + + case 57: +/* Line 1787 of yacc.c */ +#line 399 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); } + break; + + case 58: +/* Line 1787 of yacc.c */ +#line 400 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); } + break; + + case 60: +/* Line 1787 of yacc.c */ +#line 405 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); } + break; + + case 61: +/* Line 1787 of yacc.c */ +#line 406 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); } + break; + + case 63: +/* Line 1787 of yacc.c */ +#line 411 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); } + break; + + case 64: +/* Line 1787 of yacc.c */ +#line 412 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); } + break; + + case 65: +/* Line 1787 of yacc.c */ +#line 413 "dtc-parser.y" + { (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); } + break; + + case 68: +/* Line 1787 of yacc.c */ +#line 419 "dtc-parser.y" + { (yyval.integer) = -(yyvsp[(2) - (2)].integer); } + break; + + case 69: +/* Line 1787 of yacc.c */ +#line 420 "dtc-parser.y" + { (yyval.integer) = ~(yyvsp[(2) - (2)].integer); } + break; + + case 70: +/* Line 1787 of yacc.c */ +#line 421 "dtc-parser.y" + { (yyval.integer) = !(yyvsp[(2) - (2)].integer); } + break; + + case 71: +/* Line 1787 of yacc.c */ +#line 426 "dtc-parser.y" { (yyval.data) = empty_data; - ;} + } break; - case 33: - + case 72: +/* Line 1787 of yacc.c */ +#line 430 "dtc-parser.y" { (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte)); - ;} + } break; - case 34: - + case 73: +/* Line 1787 of yacc.c */ +#line 434 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); - ;} + } break; - case 35: - + case 74: +/* Line 1787 of yacc.c */ +#line 441 "dtc-parser.y" { (yyval.nodelist) = NULL; - ;} + } break; - case 36: - + case 75: +/* Line 1787 of yacc.c */ +#line 445 "dtc-parser.y" { (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist)); - ;} + } break; - case 37: - + case 76: +/* Line 1787 of yacc.c */ +#line 449 "dtc-parser.y" { print_error("syntax error: properties must precede subnodes"); YYERROR; - ;} + } break; - case 38: - + case 77: +/* Line 1787 of yacc.c */ +#line 457 "dtc-parser.y" { (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename)); - ;} + } break; - case 39: + case 78: +/* Line 1787 of yacc.c */ +#line 461 "dtc-parser.y" + { + (yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename)); + } + break; + case 79: +/* Line 1787 of yacc.c */ +#line 465 "dtc-parser.y" { add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref)); (yyval.node) = (yyvsp[(2) - (2)].node); - ;} + } break; - +/* Line 1787 of yacc.c */ +#line 2073 "dtc-parser.tab.c" default: break; } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -1729,6 +2110,10 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -1736,37 +2121,36 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; } +# undef YYSYNTAX_ERROR #endif } @@ -1825,7 +2209,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) + if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -1848,7 +2232,9 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -1872,7 +2258,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -1884,8 +2270,13 @@ yyexhaustedlab: yyreturn: if (yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -1909,7 +2300,8 @@ yyreturn: } - +/* Line 2050 of yacc.c */ +#line 471 "dtc-parser.y" void print_error(char const *fmt, ...) @@ -1934,9 +2326,12 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); - if (*e) - print_error("bad characters in literal"); - else if ((errno == ERANGE) + if (*e) { + size_t uls = strspn(e, "UL"); + if (e[uls]) + print_error("bad characters in literal"); + } + if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) print_error("literal out of range"); else if (errno != 0) @@ -1944,3 +2339,28 @@ static unsigned long long eval_literal(const char *s, int base, int bits) return val; } +static unsigned char eval_char_literal(const char *s) +{ + int i = 1; + char c = s[0]; + + if (c == '\0') + { + print_error("empty character literal"); + return 0; + } + + /* + * If the first character in the character literal is a \ then process + * the remaining characters as an escape encoding. If the first + * character is neither an escape or a terminator it should be the only + * character in the literal and will be returned. + */ + if (c == '\\') + c = get_escape_char(s, &i); + + if (s[i] != '\0') + print_error("malformed character literal"); + + return c; +} diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped index 4ee682bb7d3..b2e7a86cd85 100644 --- a/scripts/dtc/dtc-parser.tab.h_shipped +++ b/scripts/dtc/dtc-parser.tab.h_shipped @@ -1,9 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.4.3. */ +/* A Bison parser, made by GNU Bison 2.7.12-4996. */ -/* Skeleton interface for Bison's Yacc-like parsers in C +/* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. 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 @@ -31,6 +30,15 @@ This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ +#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED +# define YY_YY_DTC_PARSER_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif /* Tokens. */ #ifndef YYTOKENTYPE @@ -40,23 +48,35 @@ enum yytokentype { DT_V1 = 258, DT_MEMRESERVE = 259, - DT_PROPNODENAME = 260, - DT_LITERAL = 261, - DT_BASE = 262, - DT_BYTE = 263, - DT_STRING = 264, - DT_LABEL = 265, - DT_REF = 266, - DT_INCBIN = 267 + DT_LSHIFT = 260, + DT_RSHIFT = 261, + DT_LE = 262, + DT_GE = 263, + DT_EQ = 264, + DT_NE = 265, + DT_AND = 266, + DT_OR = 267, + DT_BITS = 268, + DT_DEL_PROP = 269, + DT_DEL_NODE = 270, + DT_PROPNODENAME = 271, + DT_LITERAL = 272, + DT_CHAR_LITERAL = 273, + DT_BASE = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { - +/* Line 2053 of yacc.c */ +#line 40 "dtc-parser.y" char *propnodename; char *literal; @@ -65,16 +85,21 @@ typedef union YYSTYPE uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; - +/* Line 2053 of yacc.c */ +#line 103 "dtc-parser.tab.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -83,4 +108,18 @@ typedef union YYSTYPE extern YYSTYPE yylval; +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ +#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */ diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 5e84a67fc1d..f412460f94d 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -34,6 +34,7 @@ extern struct boot_info *the_boot_info; extern int treesource_error; static unsigned long long eval_literal(const char *s, int base, int bits); +static unsigned char eval_char_literal(const char *s); %} %union { @@ -44,19 +45,28 @@ static unsigned long long eval_literal(const char *s, int base, int bits); uint8_t byte; struct data data; - uint64_t addr; - cell_t cell; + struct { + struct data data; + int bits; + } array; + struct property *prop; struct property *proplist; struct node *node; struct node *nodelist; struct reserve_info *re; + uint64_t integer; } %token DT_V1 %token DT_MEMRESERVE +%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR +%token DT_BITS +%token DT_DEL_PROP +%token DT_DEL_NODE %token <propnodename> DT_PROPNODENAME %token <literal> DT_LITERAL +%token <literal> DT_CHAR_LITERAL %token <cbase> DT_BASE %token <byte> DT_BYTE %token <data> DT_STRING @@ -68,9 +78,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type <data> propdataprefix %type <re> memreserve %type <re> memreserves -%type <addr> addr -%type <data> celllist -%type <cell> cellval +%type <array> arrayprefix %type <data> bytestring %type <prop> propdef %type <proplist> proplist @@ -80,6 +88,21 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type <node> subnode %type <nodelist> subnodes +%type <integer> integer_prim +%type <integer> integer_unary +%type <integer> integer_mul +%type <integer> integer_add +%type <integer> integer_shift +%type <integer> integer_rela +%type <integer> integer_eq +%type <integer> integer_bitand +%type <integer> integer_bitxor +%type <integer> integer_bitor +%type <integer> integer_and +%type <integer> integer_or +%type <integer> integer_trinary +%type <integer> integer_expr + %% sourcefile: @@ -102,7 +125,7 @@ memreserves: ; memreserve: - DT_MEMRESERVE addr addr ';' + DT_MEMRESERVE integer_prim integer_prim ';' { $$ = build_reserve_entry($2, $3); } @@ -113,13 +136,6 @@ memreserve: } ; -addr: - DT_LITERAL - { - $$ = eval_literal($1, 0, 64); - } - ; - devicetree: '/' nodedef { @@ -139,6 +155,17 @@ devicetree: print_error("label or path, '%s', not found", $2); $$ = $1; } + | devicetree DT_DEL_NODE DT_REF ';' + { + struct node *target = get_node_by_ref($1, $3); + + if (!target) + print_error("label or path, '%s', not found", $3); + else + delete_node(target); + + $$ = $1; + } ; nodedef: @@ -168,6 +195,10 @@ propdef: { $$ = build_property($1, empty_data); } + | DT_DEL_PROP DT_PROPNODENAME ';' + { + $$ = build_property_delete($2); + } | DT_LABEL propdef { add_label(&$2->labels, $1); @@ -180,9 +211,9 @@ propdata: { $$ = data_merge($1, $2); } - | propdataprefix '<' celllist '>' + | propdataprefix arrayprefix '>' { - $$ = data_merge($1, $3); + $$ = data_merge($1, $2.data); } | propdataprefix '[' bytestring ']' { @@ -192,7 +223,7 @@ propdata: { $$ = data_add_marker($1, REF_PATH, $2); } - | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' + | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' { FILE *f = srcfile_relative_open($4.val, NULL); struct data d; @@ -240,31 +271,154 @@ propdataprefix: } ; -celllist: - /* empty */ +arrayprefix: + DT_BITS DT_LITERAL '<' + { + $$.data = empty_data; + $$.bits = eval_literal($2, 0, 7); + + if (($$.bits != 8) && + ($$.bits != 16) && + ($$.bits != 32) && + ($$.bits != 64)) + { + print_error("Only 8, 16, 32 and 64-bit elements" + " are currently supported"); + $$.bits = 32; + } + } + | '<' + { + $$.data = empty_data; + $$.bits = 32; + } + | arrayprefix integer_prim + { + if ($1.bits < 64) { + uint64_t mask = (1ULL << $1.bits) - 1; + /* + * Bits above mask must either be all zero + * (positive within range of mask) or all one + * (negative and sign-extended). The second + * condition is true if when we set all bits + * within the mask to one (i.e. | in the + * mask), all bits are one. + */ + if (($2 > mask) && (($2 | mask) != -1ULL)) + print_error( + "integer value out of range " + "%016lx (%d bits)", $1.bits); + } + + $$.data = data_append_integer($1.data, $2, $1.bits); + } + | arrayprefix DT_REF + { + uint64_t val = ~0ULL >> (64 - $1.bits); + + if ($1.bits == 32) + $1.data = data_add_marker($1.data, + REF_PHANDLE, + $2); + else + print_error("References are only allowed in " + "arrays with 32-bit elements."); + + $$.data = data_append_integer($1.data, val, $1.bits); + } + | arrayprefix DT_LABEL { - $$ = empty_data; + $$.data = data_add_marker($1.data, LABEL, $2); } - | celllist cellval + ; + +integer_prim: + DT_LITERAL { - $$ = data_append_cell($1, $2); + $$ = eval_literal($1, 0, 64); } - | celllist DT_REF + | DT_CHAR_LITERAL { - $$ = data_append_cell(data_add_marker($1, REF_PHANDLE, - $2), -1); + $$ = eval_char_literal($1); } - | celllist DT_LABEL + | '(' integer_expr ')' { - $$ = data_add_marker($1, LABEL, $2); + $$ = $2; } ; -cellval: - DT_LITERAL - { - $$ = eval_literal($1, 0, 32); - } +integer_expr: + integer_trinary + ; + +integer_trinary: + integer_or + | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; } + ; + +integer_or: + integer_and + | integer_or DT_OR integer_and { $$ = $1 || $3; } + ; + +integer_and: + integer_bitor + | integer_and DT_AND integer_bitor { $$ = $1 && $3; } + ; + +integer_bitor: + integer_bitxor + | integer_bitor '|' integer_bitxor { $$ = $1 | $3; } + ; + +integer_bitxor: + integer_bitand + | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; } + ; + +integer_bitand: + integer_eq + | integer_bitand '&' integer_eq { $$ = $1 & $3; } + ; + +integer_eq: + integer_rela + | integer_eq DT_EQ integer_rela { $$ = $1 == $3; } + | integer_eq DT_NE integer_rela { $$ = $1 != $3; } + ; + +integer_rela: + integer_shift + | integer_rela '<' integer_shift { $$ = $1 < $3; } + | integer_rela '>' integer_shift { $$ = $1 > $3; } + | integer_rela DT_LE integer_shift { $$ = $1 <= $3; } + | integer_rela DT_GE integer_shift { $$ = $1 >= $3; } + ; + +integer_shift: + integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } + | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } + | integer_add + ; + +integer_add: + integer_add '+' integer_mul { $$ = $1 + $3; } + | integer_add '-' integer_mul { $$ = $1 - $3; } + | integer_mul + ; + +integer_mul: + integer_mul '*' integer_unary { $$ = $1 * $3; } + | integer_mul '/' integer_unary { $$ = $1 / $3; } + | integer_mul '%' integer_unary { $$ = $1 % $3; } + | integer_unary + ; + +integer_unary: + integer_prim + | '-' integer_unary { $$ = -$2; } + | '~' integer_unary { $$ = ~$2; } + | '!' integer_unary { $$ = !$2; } ; bytestring: @@ -303,6 +457,10 @@ subnode: { $$ = name_node($2, $1); } + | DT_DEL_NODE DT_PROPNODENAME ';' + { + $$ = name_node(build_node_delete(), $2); + } | DT_LABEL subnode { add_label(&$2->labels, $1); @@ -334,12 +492,41 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); - if (*e) - print_error("bad characters in literal"); - else if ((errno == ERANGE) + if (*e) { + size_t uls = strspn(e, "UL"); + if (e[uls]) + print_error("bad characters in literal"); + } + if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) print_error("literal out of range"); else if (errno != 0) print_error("bad literal"); return val; } + +static unsigned char eval_char_literal(const char *s) +{ + int i = 1; + char c = s[0]; + + if (c == '\0') + { + print_error("empty character literal"); + return 0; + } + + /* + * If the first character in the character literal is a \ then process + * the remaining characters as an escape encoding. If the first + * character is neither an escape or a terminator it should be the only + * character in the literal and will be returned. + */ + if (c == '\\') + c = get_escape_char(s, &i); + + if (s[i] != '\0') + print_error("malformed character literal"); + + return c; +} diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 451c92d31b1..e3c96536fd9 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -21,8 +21,6 @@ #include "dtc.h" #include "srcpos.h" -#include "version_gen.h" - /* * Command line options */ @@ -49,50 +47,60 @@ static void fill_fullpaths(struct node *tree, const char *prefix) fill_fullpaths(child, tree->fullpath); } -static void __attribute__ ((noreturn)) usage(void) -{ - fprintf(stderr, "Usage:\n"); - fprintf(stderr, "\tdtc [options] <input file>\n"); - fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, "\t-h\n"); - fprintf(stderr, "\t\tThis help text\n"); - fprintf(stderr, "\t-q\n"); - fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n"); - fprintf(stderr, "\t-I <input format>\n"); - fprintf(stderr, "\t\tInput formats are:\n"); - fprintf(stderr, "\t\t\tdts - device tree source text\n"); - fprintf(stderr, "\t\t\tdtb - device tree blob\n"); - fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n"); - fprintf(stderr, "\t-o <output file>\n"); - fprintf(stderr, "\t-O <output format>\n"); - fprintf(stderr, "\t\tOutput formats are:\n"); - fprintf(stderr, "\t\t\tdts - device tree source text\n"); - fprintf(stderr, "\t\t\tdtb - device tree blob\n"); - fprintf(stderr, "\t\t\tasm - assembler source\n"); - fprintf(stderr, "\t-V <output version>\n"); - fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION); - fprintf(stderr, "\t-d <output dependency file>\n"); - fprintf(stderr, "\t-R <number>\n"); - fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n"); - fprintf(stderr, "\t-S <bytes>\n"); - fprintf(stderr, "\t\tMake the blob at least <bytes> long (extra space)\n"); - fprintf(stderr, "\t-p <bytes>\n"); - fprintf(stderr, "\t\tAdd padding to the blob of <bytes> long (extra space)\n"); - fprintf(stderr, "\t-b <number>\n"); - fprintf(stderr, "\t\tSet the physical boot cpu\n"); - fprintf(stderr, "\t-f\n"); - fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); - fprintf(stderr, "\t-s\n"); - fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n"); - fprintf(stderr, "\t-v\n"); - fprintf(stderr, "\t\tPrint DTC version and exit\n"); - fprintf(stderr, "\t-H <phandle format>\n"); - fprintf(stderr, "\t\tphandle formats are:\n"); - fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n"); - fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n"); - fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n"); - exit(3); -} +/* Usage related data. */ +static const char usage_synopsis[] = "dtc [options] <input file>"; +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; +static struct option const usage_long_opts[] = { + {"quiet", no_argument, NULL, 'q'}, + {"in-format", a_argument, NULL, 'I'}, + {"out", a_argument, NULL, 'o'}, + {"out-format", a_argument, NULL, 'O'}, + {"out-version", a_argument, NULL, 'V'}, + {"out-dependency", a_argument, NULL, 'd'}, + {"reserve", a_argument, NULL, 'R'}, + {"space", a_argument, NULL, 'S'}, + {"pad", a_argument, NULL, 'p'}, + {"boot-cpu", a_argument, NULL, 'b'}, + {"force", no_argument, NULL, 'f'}, + {"include", a_argument, NULL, 'i'}, + {"sort", no_argument, NULL, 's'}, + {"phandle", a_argument, NULL, 'H'}, + {"warning", a_argument, NULL, 'W'}, + {"error", a_argument, NULL, 'E'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, no_argument, NULL, 0x0}, +}; +static const char * const usage_opts_help[] = { + "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all", + "\n\tInput formats are:\n" + "\t\tdts - device tree source text\n" + "\t\tdtb - device tree blob\n" + "\t\tfs - /proc/device-tree style directory", + "\n\tOutput file", + "\n\tOutput formats are:\n" + "\t\tdts - device tree source text\n" + "\t\tdtb - device tree blob\n" + "\t\tasm - assembler source", + "\n\tBlob version to produce, defaults to %d (for dtb and asm output)", //, DEFAULT_FDT_VERSION); + "\n\tOutput dependency file", + "\n\ttMake space for <number> reserve map entries (for dtb and asm output)", + "\n\tMake the blob at least <bytes> long (extra space)", + "\n\tAdd padding to the blob of <bytes> long (extra space)", + "\n\tSet the physical boot cpu", + "\n\tTry to produce output even if the input tree has errors", + "\n\tAdd a path to search for include files", + "\n\tSort nodes and properties before outputting (useful for comparing trees)", + "\n\tValid phandle formats are:\n" + "\t\tlegacy - \"linux,phandle\" properties only\n" + "\t\tepapr - \"phandle\" properties only\n" + "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", + "\n\tEnable/disable warnings (prefix with \"no-\")", + "\n\tEnable/disable errors (prefix with \"no-\")", + "\n\tPrint this help and exit", + "\n\tPrint version and exit", + NULL, +}; int main(int argc, char *argv[]) { @@ -101,7 +109,7 @@ int main(int argc, char *argv[]) const char *outform = "dts"; const char *outname = "-"; const char *depname = NULL; - int force = 0, check = 0, sort = 0; + int force = 0, sort = 0; const char *arg; int opt; FILE *outf = NULL; @@ -113,8 +121,7 @@ int main(int argc, char *argv[]) minsize = 0; padsize = 0; - while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fcqb:vH:s")) - != EOF) { + while ((opt = util_getopt_long()) != EOF) { switch (opt) { case 'I': inform = optarg; @@ -143,18 +150,17 @@ int main(int argc, char *argv[]) case 'f': force = 1; break; - case 'c': - check = 1; - break; case 'q': quiet++; break; case 'b': cmdline_boot_cpuid = strtoll(optarg, NULL, 0); break; + case 'i': + srcfile_add_search_path(optarg); + break; case 'v': - printf("Version: %s\n", DTC_VERSION); - exit(0); + util_version(); case 'H': if (streq(optarg, "legacy")) phandle_format = PHANDLE_LEGACY; @@ -171,14 +177,23 @@ int main(int argc, char *argv[]) sort = 1; break; + case 'W': + parse_checks_option(true, false, optarg); + break; + + case 'E': + parse_checks_option(false, true, optarg); + break; + case 'h': + usage(NULL); default: - usage(); + usage("unknown option"); } } if (argc > (optind+1)) - usage(); + usage("missing files"); else if (argc < (optind+1)) arg = "-"; else @@ -188,12 +203,6 @@ int main(int argc, char *argv[]) if (minsize && padsize) die("Can't set both -p and -S\n"); - if (minsize) - fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n"); - - fprintf(stderr, "DTC: %s->%s on file \"%s\"\n", - inform, outform, arg); - if (depname) { depfile = fopen(depname, "w"); if (!depfile) diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index f37c97eb3df..264a20cf66a 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -25,6 +25,7 @@ #include <string.h> #include <stdlib.h> #include <stdint.h> +#include <stdbool.h> #include <stdarg.h> #include <assert.h> #include <ctype.h> @@ -65,7 +66,6 @@ typedef uint32_t cell_t; #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* Data blobs */ enum markertype { @@ -109,6 +109,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m, const void *p, int len); struct data data_merge(struct data d1, struct data d2); struct data data_append_cell(struct data d, cell_t word); +struct data data_append_integer(struct data d, uint64_t word, int bits); struct data data_append_re(struct data d, const struct fdt_reserve_entry *re); struct data data_append_addr(struct data d, uint64_t addr); struct data data_append_byte(struct data d, uint8_t byte); @@ -126,11 +127,13 @@ int data_is_one_string(struct data d); /* Live trees */ struct label { + int deleted; char *label; struct label *next; }; struct property { + int deleted; char *name; struct data val; @@ -140,6 +143,7 @@ struct property { }; struct node { + int deleted; char *name; struct property *proplist; struct node *children; @@ -156,28 +160,47 @@ struct node { struct label *labels; }; -#define for_each_label(l0, l) \ +#define for_each_label_withdel(l0, l) \ for ((l) = (l0); (l); (l) = (l)->next) -#define for_each_property(n, p) \ +#define for_each_label(l0, l) \ + for_each_label_withdel(l0, l) \ + if (!(l)->deleted) + +#define for_each_property_withdel(n, p) \ for ((p) = (n)->proplist; (p); (p) = (p)->next) -#define for_each_child(n, c) \ +#define for_each_property(n, p) \ + for_each_property_withdel(n, p) \ + if (!(p)->deleted) + +#define for_each_child_withdel(n, c) \ for ((c) = (n)->children; (c); (c) = (c)->next_sibling) +#define for_each_child(n, c) \ + for_each_child_withdel(n, c) \ + if (!(c)->deleted) + void add_label(struct label **labels, char *label); +void delete_labels(struct label **labels); struct property *build_property(char *name, struct data val); +struct property *build_property_delete(char *name); struct property *chain_property(struct property *first, struct property *list); 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 *chain_node(struct node *first, struct node *list); struct node *merge_nodes(struct node *old_node, struct node *new_node); void add_property(struct node *node, struct property *prop); +void delete_property_by_name(struct node *node, char *name); +void delete_property(struct property *prop); void add_child(struct node *parent, struct node *child); +void delete_node_by_name(struct node *parent, char *name); +void delete_node(struct node *node); const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); @@ -224,6 +247,7 @@ void sort_tree(struct boot_info *bi); /* Checks */ +void parse_checks_option(bool warn, bool error, const char *optarg); void process_checks(int force, struct boot_info *bi); /* Flattened trees */ diff --git a/scripts/dtc/fdtdump.c b/scripts/dtc/fdtdump.c new file mode 100644 index 00000000000..207a46d6486 --- /dev/null +++ b/scripts/dtc/fdtdump.c @@ -0,0 +1,162 @@ +/* + * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com> + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <fdt.h> +#include <libfdt_env.h> + +#include "util.h" + +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) +#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4))) + +static void print_data(const char *data, int len) +{ + int i; + const char *p = data; + + /* no data, don't print */ + if (len == 0) + return; + + if (util_is_printable_string(data, len)) { + printf(" = \"%s\"", (const char *)data); + } else if ((len % 4) == 0) { + printf(" = <"); + for (i = 0; i < len; i += 4) + printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)), + i < (len - 4) ? " " : ""); + printf(">"); + } else { + printf(" = ["); + for (i = 0; i < len; i++) + printf("%02x%s", *p++, i < len - 1 ? " " : ""); + printf("]"); + } +} + +static void dump_blob(void *blob) +{ + struct fdt_header *bph = blob; + uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); + uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); + uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); + struct fdt_reserve_entry *p_rsvmap = + (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); + const char *p_struct = (const char *)blob + off_dt; + const char *p_strings = (const char *)blob + off_str; + uint32_t version = fdt32_to_cpu(bph->version); + uint32_t totalsize = fdt32_to_cpu(bph->totalsize); + uint32_t tag; + const char *p, *s, *t; + int depth, sz, shift; + int i; + uint64_t addr, size; + + depth = 0; + shift = 4; + + printf("/dts-v1/;\n"); + printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); + printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); + printf("// off_dt_struct:\t0x%x\n", off_dt); + printf("// off_dt_strings:\t0x%x\n", off_str); + printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); + printf("// version:\t\t%d\n", version); + printf("// last_comp_version:\t%d\n", + fdt32_to_cpu(bph->last_comp_version)); + if (version >= 2) + printf("// boot_cpuid_phys:\t0x%x\n", + fdt32_to_cpu(bph->boot_cpuid_phys)); + + if (version >= 3) + printf("// size_dt_strings:\t0x%x\n", + fdt32_to_cpu(bph->size_dt_strings)); + if (version >= 17) + printf("// size_dt_struct:\t0x%x\n", + fdt32_to_cpu(bph->size_dt_struct)); + printf("\n"); + + for (i = 0; ; i++) { + addr = fdt64_to_cpu(p_rsvmap[i].address); + size = fdt64_to_cpu(p_rsvmap[i].size); + if (addr == 0 && size == 0) + break; + + printf("/memreserve/ %llx %llx;\n", + (unsigned long long)addr, (unsigned long long)size); + } + + p = p_struct; + while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { + + /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ + + if (tag == FDT_BEGIN_NODE) { + s = p; + p = PALIGN(p + strlen(s) + 1, 4); + + if (*s == '\0') + s = "/"; + + printf("%*s%s {\n", depth * shift, "", s); + + depth++; + continue; + } + + if (tag == FDT_END_NODE) { + depth--; + + printf("%*s};\n", depth * shift, ""); + continue; + } + + if (tag == FDT_NOP) { + printf("%*s// [NOP]\n", depth * shift, ""); + continue; + } + + if (tag != FDT_PROP) { + fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); + break; + } + sz = fdt32_to_cpu(GET_CELL(p)); + s = p_strings + fdt32_to_cpu(GET_CELL(p)); + if (version < 16 && sz >= 8) + p = PALIGN(p, 8); + t = p; + + p = PALIGN(p + sz, 4); + + printf("%*s%s", depth * shift, "", s); + print_data(t, sz); + printf(";\n"); + } +} + + +int main(int argc, char *argv[]) +{ + char *buf; + + if (argc < 2) { + fprintf(stderr, "supply input filename\n"); + return 5; + } + + buf = utilfdt_read(argv[1]); + if (buf) + dump_blob(buf); + else + return 10; + + return 0; +} diff --git a/scripts/dtc/fdtget.c b/scripts/dtc/fdtget.c new file mode 100644 index 00000000000..c2fbab2a547 --- /dev/null +++ b/scripts/dtc/fdtget.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * Portions from U-Boot cmd_fdt.c (C) Copyright 2007 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * Based on code written by: + * Pantelis Antoniou <pantelis.antoniou@gmail.com> and + * Matthew McClintock <msm@freescale.com> + * + * 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 <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libfdt.h> + +#include "util.h" + +enum display_mode { + MODE_SHOW_VALUE, /* show values for node properties */ + MODE_LIST_PROPS, /* list the properties for a node */ + MODE_LIST_SUBNODES, /* list the subnodes of a node */ +}; + +/* Holds information which controls our output and options */ +struct display_info { + int type; /* data type (s/i/u/x or 0 for default) */ + int size; /* data size (1/2/4) */ + enum display_mode mode; /* display mode that we are using */ + const char *default_val; /* default value if node/property not found */ +}; + +static void report_error(const char *where, int err) +{ + fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err)); +} + +/** + * Displays data of a given length according to selected options + * + * If a specific data type is provided in disp, then this is used. Otherwise + * we try to guess the data type / size from the contents. + * + * @param disp Display information / options + * @param data Data to display + * @param len Maximum length of buffer + * @return 0 if ok, -1 if data does not match format + */ +static int show_data(struct display_info *disp, const char *data, int len) +{ + int i, size; + const uint8_t *p = (const uint8_t *)data; + const char *s; + int value; + int is_string; + char fmt[3]; + + /* no data, don't print */ + if (len == 0) + return 0; + + is_string = (disp->type) == 's' || + (!disp->type && util_is_printable_string(data, len)); + if (is_string) { + if (data[len - 1] != '\0') { + fprintf(stderr, "Unterminated string\n"); + return -1; + } + for (s = data; s - data < len; s += strlen(s) + 1) { + if (s != data) + printf(" "); + printf("%s", (const char *)s); + } + return 0; + } + size = disp->size; + if (size == -1) { + size = (len % 4) == 0 ? 4 : 1; + } else if (len % size) { + fprintf(stderr, "Property length must be a multiple of " + "selected data size\n"); + return -1; + } + fmt[0] = '%'; + fmt[1] = disp->type ? disp->type : 'd'; + fmt[2] = '\0'; + for (i = 0; i < len; i += size, p += size) { + if (i) + printf(" "); + value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) : + size == 2 ? (*p << 8) | p[1] : *p; + printf(fmt, value); + } + return 0; +} + +/** + * List all properties in a node, one per line. + * + * @param blob FDT blob + * @param node Node to display + * @return 0 if ok, or FDT_ERR... if not. + */ +static int list_properties(const void *blob, int node) +{ + const struct fdt_property *data; + const char *name; + int prop; + + prop = fdt_first_property_offset(blob, node); + do { + /* Stop silently when there are no more properties */ + if (prop < 0) + return prop == -FDT_ERR_NOTFOUND ? 0 : prop; + data = fdt_get_property_by_offset(blob, prop, NULL); + name = fdt_string(blob, fdt32_to_cpu(data->nameoff)); + if (name) + puts(name); + prop = fdt_next_property_offset(blob, prop); + } while (1); +} + +#define MAX_LEVEL 32 /* how deeply nested we will go */ + +/** + * List all subnodes in a node, one per line + * + * @param blob FDT blob + * @param node Node to display + * @return 0 if ok, or FDT_ERR... if not. + */ +static int list_subnodes(const void *blob, int node) +{ + int nextoffset; /* next node offset from libfdt */ + uint32_t tag; /* current tag */ + int level = 0; /* keep track of nesting level */ + const char *pathp; + int depth = 1; /* the assumed depth of this node */ + + while (level >= 0) { + tag = fdt_next_tag(blob, node, &nextoffset); + switch (tag) { + case FDT_BEGIN_NODE: + pathp = fdt_get_name(blob, node, NULL); + if (level <= depth) { + if (pathp == NULL) + pathp = "/* NULL pointer error */"; + if (*pathp == '\0') + pathp = "/"; /* root is nameless */ + if (level == 1) + puts(pathp); + } + level++; + if (level >= MAX_LEVEL) { + printf("Nested too deep, aborting.\n"); + return 1; + } + break; + case FDT_END_NODE: + level--; + if (level == 0) + level = -1; /* exit the loop */ + break; + case FDT_END: + return 1; + case FDT_PROP: + break; + default: + if (level <= depth) + printf("Unknown tag 0x%08X\n", tag); + return 1; + } + node = nextoffset; + } + return 0; +} + +/** + * Show the data for a given node (and perhaps property) according to the + * display option provided. + * + * @param blob FDT blob + * @param disp Display information / options + * @param node Node to display + * @param property Name of property to display, or NULL if none + * @return 0 if ok, -ve on error + */ +static int show_data_for_item(const void *blob, struct display_info *disp, + int node, const char *property) +{ + const void *value = NULL; + int len, err = 0; + + switch (disp->mode) { + case MODE_LIST_PROPS: + err = list_properties(blob, node); + break; + + case MODE_LIST_SUBNODES: + err = list_subnodes(blob, node); + break; + + default: + assert(property); + value = fdt_getprop(blob, node, property, &len); + if (value) { + if (show_data(disp, value, len)) + err = -1; + else + printf("\n"); + } else if (disp->default_val) { + puts(disp->default_val); + } else { + report_error(property, len); + err = -1; + } + break; + } + + return err; +} + +/** + * Run the main fdtget operation, given a filename and valid arguments + * + * @param disp Display information / options + * @param filename Filename of blob file + * @param arg List of arguments to process + * @param arg_count Number of arguments + * @param return 0 if ok, -ve on error + */ +static int do_fdtget(struct display_info *disp, const char *filename, + char **arg, int arg_count, int args_per_step) +{ + char *blob; + const char *prop; + int i, node; + + blob = utilfdt_read(filename); + if (!blob) + return -1; + + for (i = 0; i + args_per_step <= arg_count; i += args_per_step) { + node = fdt_path_offset(blob, arg[i]); + if (node < 0) { + if (disp->default_val) { + puts(disp->default_val); + continue; + } else { + report_error(arg[i], node); + return -1; + } + } + prop = args_per_step == 1 ? NULL : arg[i + 1]; + + if (show_data_for_item(blob, disp, node, prop)) + return -1; + } + return 0; +} + +static const char *usage_msg = + "fdtget - read values from device tree\n" + "\n" + "Each value is printed on a new line.\n\n" + "Usage:\n" + " fdtget <options> <dt file> [<node> <property>]...\n" + " fdtget -p <options> <dt file> [<node> ]...\n" + "Options:\n" + "\t-t <type>\tType of data\n" + "\t-p\t\tList properties for each node\n" + "\t-l\t\tList subnodes for each node\n" + "\t-d\t\tDefault value to display when the property is " + "missing\n" + "\t-h\t\tPrint this help\n\n" + USAGE_TYPE_MSG; + +static void usage(const char *msg) +{ + if (msg) + fprintf(stderr, "Error: %s\n\n", msg); + + fprintf(stderr, "%s", usage_msg); + exit(2); +} + +int main(int argc, char *argv[]) +{ + char *filename = NULL; + struct display_info disp; + int args_per_step = 2; + + /* set defaults */ + memset(&disp, '\0', sizeof(disp)); + disp.size = -1; + disp.mode = MODE_SHOW_VALUE; + for (;;) { + int c = getopt(argc, argv, "d:hlpt:"); + if (c == -1) + break; + + switch (c) { + case 'h': + case '?': + usage(NULL); + + case 't': + if (utilfdt_decode_type(optarg, &disp.type, + &disp.size)) + usage("Invalid type string"); + break; + + case 'p': + disp.mode = MODE_LIST_PROPS; + args_per_step = 1; + break; + + case 'l': + disp.mode = MODE_LIST_SUBNODES; + args_per_step = 1; + break; + + case 'd': + disp.default_val = optarg; + break; + } + } + + if (optind < argc) + filename = argv[optind++]; + if (!filename) + usage("Missing filename"); + + argv += optind; + argc -= optind; + + /* Allow no arguments, and silently succeed */ + if (!argc) + return 0; + + /* Check for node, property arguments */ + if (args_per_step == 2 && (argc % 2)) + usage("Must have an even number of arguments"); + + if (do_fdtget(&disp, filename, argv, argc, args_per_step)) + return 1; + return 0; +} diff --git a/scripts/dtc/fdtput.c b/scripts/dtc/fdtput.c new file mode 100644 index 00000000000..f2197f51930 --- /dev/null +++ b/scripts/dtc/fdtput.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * 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 <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libfdt.h> + +#include "util.h" + +/* These are the operations we support */ +enum oper_type { + OPER_WRITE_PROP, /* Write a property in a node */ + OPER_CREATE_NODE, /* Create a new node */ +}; + +struct display_info { + enum oper_type oper; /* operation to perform */ + int type; /* data type (s/i/u/x or 0 for default) */ + int size; /* data size (1/2/4) */ + int verbose; /* verbose output */ + int auto_path; /* automatically create all path components */ +}; + + +/** + * Report an error with a particular node. + * + * @param name Node name to report error on + * @param namelen Length of node name, or -1 to use entire string + * @param err Error number to report (-FDT_ERR_...) + */ +static void report_error(const char *name, int namelen, int err) +{ + if (namelen == -1) + namelen = strlen(name); + fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name, + fdt_strerror(err)); +} + +/** + * Encode a series of arguments in a property value. + * + * @param disp Display information / options + * @param arg List of arguments from command line + * @param arg_count Number of arguments (may be 0) + * @param valuep Returns buffer containing value + * @param *value_len Returns length of value encoded + */ +static int encode_value(struct display_info *disp, char **arg, int arg_count, + char **valuep, int *value_len) +{ + char *value = NULL; /* holding area for value */ + int value_size = 0; /* size of holding area */ + char *ptr; /* pointer to current value position */ + int len; /* length of this cell/string/byte */ + int ival; + int upto; /* the number of bytes we have written to buf */ + char fmt[3]; + + upto = 0; + + if (disp->verbose) + fprintf(stderr, "Decoding value:\n"); + + fmt[0] = '%'; + fmt[1] = disp->type ? disp->type : 'd'; + fmt[2] = '\0'; + for (; arg_count > 0; arg++, arg_count--, upto += len) { + /* assume integer unless told otherwise */ + if (disp->type == 's') + len = strlen(*arg) + 1; + else + len = disp->size == -1 ? 4 : disp->size; + + /* enlarge our value buffer by a suitable margin if needed */ + if (upto + len > value_size) { + value_size = (upto + len) + 500; + value = realloc(value, value_size); + if (!value) { + fprintf(stderr, "Out of mmory: cannot alloc " + "%d bytes\n", value_size); + return -1; + } + } + + ptr = value + upto; + if (disp->type == 's') { + memcpy(ptr, *arg, len); + if (disp->verbose) + fprintf(stderr, "\tstring: '%s'\n", ptr); + } else { + int *iptr = (int *)ptr; + sscanf(*arg, fmt, &ival); + if (len == 4) + *iptr = cpu_to_fdt32(ival); + else + *ptr = (uint8_t)ival; + if (disp->verbose) { + fprintf(stderr, "\t%s: %d\n", + disp->size == 1 ? "byte" : + disp->size == 2 ? "short" : "int", + ival); + } + } + } + *value_len = upto; + *valuep = value; + if (disp->verbose) + fprintf(stderr, "Value size %d\n", upto); + return 0; +} + +static int store_key_value(void *blob, const char *node_name, + const char *property, const char *buf, int len) +{ + int node; + int err; + + node = fdt_path_offset(blob, node_name); + if (node < 0) { + report_error(node_name, -1, node); + return -1; + } + + err = fdt_setprop(blob, node, property, buf, len); + if (err) { + report_error(property, -1, err); + return -1; + } + return 0; +} + +/** + * Create paths as needed for all components of a path + * + * Any components of the path that do not exist are created. Errors are + * reported. + * + * @param blob FDT blob to write into + * @param in_path Path to process + * @return 0 if ok, -1 on error + */ +static int create_paths(void *blob, const char *in_path) +{ + const char *path = in_path; + const char *sep; + int node, offset = 0; + + /* skip leading '/' */ + while (*path == '/') + path++; + + for (sep = path; *sep; path = sep + 1, offset = node) { + /* equivalent to strchrnul(), but it requires _GNU_SOURCE */ + sep = strchr(path, '/'); + if (!sep) + sep = path + strlen(path); + + node = fdt_subnode_offset_namelen(blob, offset, path, + sep - path); + if (node == -FDT_ERR_NOTFOUND) { + node = fdt_add_subnode_namelen(blob, offset, path, + sep - path); + } + if (node < 0) { + report_error(path, sep - path, node); + return -1; + } + } + + return 0; +} + +/** + * Create a new node in the fdt. + * + * This will overwrite the node_name string. Any error is reported. + * + * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this. + * + * @param blob FDT blob to write into + * @param node_name Name of node to create + * @return new node offset if found, or -1 on failure + */ +static int create_node(void *blob, const char *node_name) +{ + int node = 0; + char *p; + + p = strrchr(node_name, '/'); + if (!p) { + report_error(node_name, -1, -FDT_ERR_BADPATH); + return -1; + } + *p = '\0'; + + if (p > node_name) { + node = fdt_path_offset(blob, node_name); + if (node < 0) { + report_error(node_name, -1, node); + return -1; + } + } + + node = fdt_add_subnode(blob, node, p + 1); + if (node < 0) { + report_error(p + 1, -1, node); + return -1; + } + + return 0; +} + +static int do_fdtput(struct display_info *disp, const char *filename, + char **arg, int arg_count) +{ + char *value; + char *blob; + int len, ret = 0; + + blob = utilfdt_read(filename); + if (!blob) + return -1; + + switch (disp->oper) { + case OPER_WRITE_PROP: + /* + * Convert the arguments into a single binary value, then + * store them into the property. + */ + assert(arg_count >= 2); + if (disp->auto_path && create_paths(blob, *arg)) + return -1; + if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) || + store_key_value(blob, *arg, arg[1], value, len)) + ret = -1; + break; + case OPER_CREATE_NODE: + for (; ret >= 0 && arg_count--; arg++) { + if (disp->auto_path) + ret = create_paths(blob, *arg); + else + ret = create_node(blob, *arg); + } + break; + } + if (ret >= 0) + ret = utilfdt_write(filename, blob); + + free(blob); + return ret; +} + +static const char *usage_msg = + "fdtput - write a property value to a device tree\n" + "\n" + "The command line arguments are joined together into a single value.\n" + "\n" + "Usage:\n" + " fdtput <options> <dt file> <node> <property> [<value>...]\n" + " fdtput -c <options> <dt file> [<node>...]\n" + "Options:\n" + "\t-c\t\tCreate nodes if they don't already exist\n" + "\t-p\t\tAutomatically create nodes as needed for the node path\n" + "\t-t <type>\tType of data\n" + "\t-v\t\tVerbose: display each value decoded from command line\n" + "\t-h\t\tPrint this help\n\n" + USAGE_TYPE_MSG; + +static void usage(const char *msg) +{ + if (msg) + fprintf(stderr, "Error: %s\n\n", msg); + + fprintf(stderr, "%s", usage_msg); + exit(2); +} + +int main(int argc, char *argv[]) +{ + struct display_info disp; + char *filename = NULL; + + memset(&disp, '\0', sizeof(disp)); + disp.size = -1; + disp.oper = OPER_WRITE_PROP; + for (;;) { + int c = getopt(argc, argv, "chpt:v"); + if (c == -1) + break; + + /* + * TODO: add options to: + * - delete property + * - delete node (optionally recursively) + * - rename node + * - pack fdt before writing + * - set amount of free space when writing + * - expand fdt if value doesn't fit + */ + switch (c) { + case 'c': + disp.oper = OPER_CREATE_NODE; + break; + case 'h': + case '?': + usage(NULL); + case 'p': + disp.auto_path = 1; + break; + case 't': + if (utilfdt_decode_type(optarg, &disp.type, + &disp.size)) + usage("Invalid type string"); + break; + + case 'v': + disp.verbose = 1; + break; + } + } + + if (optind < argc) + filename = argv[optind++]; + if (!filename) + usage("Missing filename"); + + argv += optind; + argc -= optind; + + if (disp.oper == OPER_WRITE_PROP) { + if (argc < 1) + usage("Missing node"); + if (argc < 2) + usage("Missing property"); + } + + if (do_fdtput(&disp, filename, argv, argc)) + return 1; + return 0; +} diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index ead0332c87e..665dad7bb46 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -263,6 +263,9 @@ static void flatten_tree(struct node *tree, struct emitter *emit, struct node *child; int seen_name_prop = 0; + if (tree->deleted) + return; + emit->beginnode(etarget, tree->labels); if (vi->flags & FTF_FULLPATH) @@ -697,7 +700,6 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) { struct reserve_info *reservelist = NULL; struct reserve_info *new; - const char *p; struct fdt_reserve_entry re; /* @@ -706,7 +708,6 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) * * First pass, count entries. */ - p = inb->ptr; while (1) { flat_read_chunk(inb, &re, sizeof(re)); re.address = fdt64_to_cpu(re.address); diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c index f3774530170..e464727c880 100644 --- a/scripts/dtc/fstree.c +++ b/scripts/dtc/fstree.c @@ -88,4 +88,3 @@ struct boot_info *dt_from_fs(const char *dirname) return build_boot_info(NULL, tree, guess_boot_cpuid(tree)); } - diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt index 6c42acfa21e..91126c000a1 100644 --- a/scripts/dtc/libfdt/Makefile.libfdt +++ b/scripts/dtc/libfdt/Makefile.libfdt @@ -3,6 +3,8 @@ # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # -LIBFDT_INCLUDES = fdt.h libfdt.h -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index 2acaec5923a..e56833ae9b6 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -74,7 +74,7 @@ int fdt_check_header(const void *fdt) return 0; } -const void *fdt_offset_ptr(const void *fdt, int offset, int len) +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { const char *p; @@ -90,42 +90,53 @@ const void *fdt_offset_ptr(const void *fdt, int offset, int len) return p; } -uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const uint32_t *tagp, *lenp; uint32_t tag; + int offset = startoffset; const char *p; - if (offset % FDT_TAGSIZE) - return -1; - + *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (! tagp) + if (!tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; + *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); - if (! p) - return FDT_END; + if (!p) + return FDT_END; /* premature end */ break; + case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (! lenp) - return FDT_END; - /* skip name offset, length and value */ - offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: break; + + default: + return FDT_END; } - if (nextoffset) - *nextoffset = FDT_TAGALIGN(offset); + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + *nextoffset = FDT_TAGALIGN(offset); return tag; } @@ -138,6 +149,15 @@ int _fdt_check_node_offset(const void *fdt, int offset) return offset; } +int _fdt_check_prop_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; @@ -162,15 +182,16 @@ int fdt_next_node(const void *fdt, int offset, int *depth) break; case FDT_END_NODE: - if (depth) - (*depth)--; + if (depth && ((--(*depth)) < 0)) + return nextoffset; break; case FDT_END: - return -FDT_ERR_NOTFOUND; - - default: - return -FDT_ERR_BADSTRUCTURE; + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; } } while (tag != FDT_BEGIN_NODE); diff --git a/scripts/dtc/libfdt/fdt_empty_tree.c b/scripts/dtc/libfdt/fdt_empty_tree.c new file mode 100644 index 00000000000..f2ae9b77c28 --- /dev/null +++ b/scripts/dtc/libfdt/fdt_empty_tree.c @@ -0,0 +1,83 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 22e692919ff..02b6d687537 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -80,6 +80,14 @@ const char *fdt_string(const void *fdt, int stroffset) return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; } +static int _fdt_string_eq(const void *fdt, int stroffset, + const char *s, int len) +{ + const char *p = fdt_string(fdt, stroffset); + + return (strlen(p) == len) && (memcmp(p, s, len) == 0); +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -97,6 +105,30 @@ int fdt_num_mem_rsv(const void *fdt) return i; } +static int _nextprop(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { @@ -104,20 +136,16 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, FDT_CHECK_HEADER(fdt); - for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); - (offset >= 0) && (depth > 0); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth < 0) - return -FDT_ERR_NOTFOUND; - else if ((depth == 1) - && _fdt_nodename_eq(fdt, offset, name, namelen)) + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && _fdt_nodename_eq(fdt, offset, name, namelen)) return offset; - } - if (offset < 0) - return offset; /* error */ - else + if (depth < 0) return -FDT_ERR_NOTFOUND; + return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, @@ -134,8 +162,20 @@ int fdt_path_offset(const void *fdt, const char *path) FDT_CHECK_HEADER(fdt); - if (*path != '/') - return -FDT_ERR_BADPATH; + /* see if we have an alias */ + if (*path != '/') { + const char *q = strchr(path, '/'); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } while (*p) { const char *q; @@ -178,93 +218,142 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) return NULL; } -const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) { - uint32_t tag; - const struct fdt_property *prop; - int namestroff; - int offset, nextoffset; int err; + const struct fdt_property *prop; - if (((err = fdt_check_header(fdt)) != 0) - || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) - goto fail; + if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } - nextoffset = err; - do { - offset = nextoffset; + prop = _fdt_offset_ptr(fdt, offset); - tag = fdt_next_tag(fdt, offset, &nextoffset); - switch (tag) { - case FDT_END: - err = -FDT_ERR_TRUNCATED; - goto fail; + if (lenp) + *lenp = fdt32_to_cpu(prop->len); - case FDT_BEGIN_NODE: - case FDT_END_NODE: - case FDT_NOP: - break; + return prop; +} - case FDT_PROP: - err = -FDT_ERR_BADSTRUCTURE; - prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); - if (! prop) - goto fail; - namestroff = fdt32_to_cpu(prop->nameoff); - if (strcmp(fdt_string(fdt, namestroff), name) == 0) { - /* Found it! */ - int len = fdt32_to_cpu(prop->len); - prop = fdt_offset_ptr(fdt, offset, - sizeof(*prop)+len); - if (! prop) - goto fail; - - if (lenp) - *lenp = len; - - return prop; - } - break; +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; - default: - err = -FDT_ERR_BADSTRUCTURE; - goto fail; + if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { + offset = -FDT_ERR_INTERNAL; + break; } - } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); + if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), + name, namelen)) + return prop; + } - err = -FDT_ERR_NOTFOUND; - fail: if (lenp) - *lenp = err; + *lenp = offset; return NULL; } -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) { const struct fdt_property *prop; - prop = fdt_get_property(fdt, nodeoffset, name, lenp); + prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); if (! prop) return NULL; return prop->data; } +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { const uint32_t *php; int len; - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } return fdt32_to_cpu(*php); } +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; @@ -279,9 +368,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { - if (pdepth < depth) - continue; /* overflowed buffer */ - while (pdepth > depth) { do { p--; @@ -289,14 +375,16 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) pdepth--; } - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } } if (offset == nodeoffset) { @@ -306,7 +394,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; - return p; + return 0; } } @@ -404,14 +492,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { + int offset; + if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; - phandle = cpu_to_fdt32(phandle); - return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", - &phandle, sizeof(phandle)); + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ } -static int _stringlist_contains(const char *strlist, int listlen, const char *str) +static int _fdt_stringlist_contains(const char *strlist, int listlen, + const char *str) { int len = strlen(str); const char *p; @@ -437,7 +542,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (_stringlist_contains(prop, len, compatible)) + if (_fdt_stringlist_contains(prop, len, compatible)) return 0; else return 1; diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 8e7ec4cb7bc..24437dfc32b 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, return 0; } +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + int fdt_delprop(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; @@ -406,6 +433,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; + if (struct_size < 0) + return struct_size; } if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 698329e0cca..55ebebf1eb2 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -70,7 +70,7 @@ static int _fdt_sw_check_header(void *fdt) return err; \ } -static void *_fdt_grab_space(void *fdt, int len) +static void *_fdt_grab_space(void *fdt, size_t len) { int offset = fdt_size_dt_struct(fdt); int spaceleft; @@ -82,7 +82,7 @@ static void *_fdt_grab_space(void *fdt, int len) return NULL; fdt_set_size_dt_struct(fdt, offset + len); - return fdt_offset_ptr_w(fdt, offset, len); + return _fdt_offset_ptr_w(fdt, offset); } int fdt_create(void *buf, int bufsize) @@ -237,18 +237,17 @@ int fdt_finish(void *fdt) while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = - fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); + _fdt_offset_ptr_w(fdt, offset); int nameoff; - if (! prop) - return -FDT_ERR_BADSTRUCTURE; - nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } + if (nextoffset < 0) + return nextoffset; /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index a4652c6e787..6025fa1fe8f 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -94,41 +94,14 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) return 0; } -int _fdt_node_end_offset(void *fdt, int nodeoffset) +int _fdt_node_end_offset(void *fdt, int offset) { - int level = 0; - uint32_t tag; - int offset, nextoffset; - - tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); - if (tag != FDT_BEGIN_NODE) - return -FDT_ERR_BADOFFSET; - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - return offset; - - case FDT_BEGIN_NODE: - level++; - break; - - case FDT_END_NODE: - level--; - break; - - case FDT_PROP: - case FDT_NOP: - break; - - default: - return -FDT_ERR_BADSTRUCTURE; - } - } while (level >= 0); - - return nextoffset; + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; } int fdt_nop_node(void *fdt, int nodeoffset) diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index ff6246f000c..73f49759a5e 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -61,7 +61,7 @@ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attempted to create a node or property which + /* FDT_ERR_EXISTS: Attemped to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device @@ -122,7 +122,7 @@ /* Low-level functions (you probably don't need these) */ /**********************************************************************/ -const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); @@ -156,7 +156,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth); #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ - struct fdt_header *fdth = fdt; \ + struct fdt_header *fdth = (struct fdt_header*)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); @@ -343,6 +343,91 @@ int fdt_path_offset(const void *fdt, const char *path); const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); /** + * fdt_first_property_offset - find the offset of a node's first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset(const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node's properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset(const void *fdt, int offset); + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp); + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_get_property_namelen(), but only examine the first + * namelen characters of name for matching the property name. + */ +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); + +/** * fdt_get_property - find a given property in a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find @@ -380,6 +465,54 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, } /** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @ffset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset 'offset' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property's namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree's string + * block, not a new copy of the name). + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); + +/** * fdt_getprop - retrieve the value of a given property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find @@ -429,6 +562,32 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset, uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); + +/** + * fdt_get_alias - retreive the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named 'name' in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named 'name', of it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias(const void *fdt, const char *name); + +/** * fdt_get_path - determine the full path of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose path to find @@ -693,17 +852,17 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** - * fdt_setprop_inplace_cell - change the value of a single-cell property + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change - * @val: cell (32-bit integer) value to replace the property with + * @val: 32-bit integer value to replace the property with * - * fdt_setprop_inplace_cell() replaces the value of a given property - * with the 32-bit integer cell value in val, converting val to - * big-endian if necessary. This function cannot change the size of a - * property, and so will only work if the property already exists and - * has length 4. + * fdt_setprop_inplace_u32() replaces the value of a given property + * with the 32-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 4. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part @@ -712,7 +871,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, @@ -720,14 +879,60 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ -static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) +static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); } /** + * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to replace the property with + * + * fdt_setprop_inplace_u64() replaces the value of a given property + * with the 64-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 8. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * + * This is an alternative name for fdt_setprop_inplace_u32() + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); +} + +/** * fdt_nop_property - replace a property with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop @@ -786,11 +991,20 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); -static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_property(fdt, name, &val, sizeof(val)); } +static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_property(fdt, name, &val, sizeof(val)); +} +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ + return fdt_property_u32(fdt, name, val); +} #define fdt_property_string(fdt, name, str) \ fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); @@ -800,6 +1014,7 @@ int fdt_finish(void *fdt); /* Read-write functions */ /**********************************************************************/ +int fdt_create_empty_tree(void *buf, int bufsize); int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); @@ -909,14 +1124,14 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** - * fdt_setprop_cell - set a property to a single cell value + * fdt_setprop_u32 - set a property to a 32-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value for the property (native endian) * - * fdt_setprop_cell() sets the value of the named property in the - * given node to the given cell value (converting to big-endian if + * fdt_setprop_u32() sets the value of the named property in the given + * node to the given 32-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * @@ -936,14 +1151,60 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ -static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, - uint32_t val) +static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, + uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); } /** + * fdt_setprop_u64 - set a property to a 64-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value for the property (native endian) + * + * fdt_setprop_u64() sets the value of the named property in the given + * node to the given 64-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, + uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_setprop_cell - set a property to a single cell value + * + * This is an alternative name for fdt_setprop_u32() + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + return fdt_setprop_u32(fdt, nodeoffset, name, val); +} + +/** * fdt_setprop_string - set a property to a string value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change @@ -975,6 +1236,147 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to append to + * @val: pointer to data to append to the property value + * @len: length of the data to append to the property value + * + * fdt_appendprop() appends the value to the named property in the + * given node, creating the property if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_appendprop_u32 - append a 32-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u32() appends the given 32-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + val = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_appendprop_u64 - append a 64-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u64() appends the given 64-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + val = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_appendprop_cell - append a single cell value to a property + * + * This is an alternative name for fdt_appendprop_u32() + */ +static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_appendprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_appendprop_string - append a string to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value to append to the property + * + * fdt_appendprop_string() appends the given string to the value of + * the named property in the given node, or creates a new property + * with that value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h index 449bf602daf..213d7fb81c4 100644 --- a/scripts/dtc/libfdt/libfdt_env.h +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -5,19 +5,25 @@ #include <stdint.h> #include <string.h> -#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) +#define EXTRACT_BYTE(n) ((unsigned long long)((uint8_t *)&x)[n]) +static inline uint16_t fdt16_to_cpu(uint16_t x) +{ + return (EXTRACT_BYTE(0) << 8) | EXTRACT_BYTE(1); +} +#define cpu_to_fdt16(x) fdt16_to_cpu(x) + static inline uint32_t fdt32_to_cpu(uint32_t x) { - return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3); + return (EXTRACT_BYTE(0) << 24) | (EXTRACT_BYTE(1) << 16) | (EXTRACT_BYTE(2) << 8) | EXTRACT_BYTE(3); } #define cpu_to_fdt32(x) fdt32_to_cpu(x) static inline uint64_t fdt64_to_cpu(uint64_t x) { - return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) - | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); + return (EXTRACT_BYTE(0) << 56) | (EXTRACT_BYTE(1) << 48) | (EXTRACT_BYTE(2) << 40) | (EXTRACT_BYTE(3) << 32) + | (EXTRACT_BYTE(4) << 24) | (EXTRACT_BYTE(5) << 16) | (EXTRACT_BYTE(6) << 8) | EXTRACT_BYTE(7); } #define cpu_to_fdt64(x) fdt64_to_cpu(x) -#undef _B +#undef EXTRACT_BYTE #endif /* _LIBFDT_ENV_H */ diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 46eb93e4af5..381133ba81d 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -62,8 +62,8 @@ return err; \ } -uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); int _fdt_check_node_offset(const void *fdt, int offset); +int _fdt_check_prop_offset(const void *fdt, int offset); const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); int _fdt_node_end_offset(void *fdt, int nodeoffset); diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 26d0e1e60c0..b61465fb2f3 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -29,16 +29,27 @@ void add_label(struct label **labels, char *label) struct label *new; /* Make sure the label isn't already there */ - for_each_label(*labels, new) - if (streq(new->label, label)) + for_each_label_withdel(*labels, new) + if (streq(new->label, label)) { + new->deleted = 0; return; + } new = xmalloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); new->label = label; new->next = *labels; *labels = new; } +void delete_labels(struct label **labels) +{ + struct label *label; + + for_each_label(*labels, label) + label->deleted = 1; +} + struct property *build_property(char *name, struct data val) { struct property *new = xmalloc(sizeof(*new)); @@ -51,6 +62,18 @@ struct property *build_property(char *name, struct data val) return new; } +struct property *build_property_delete(char *name) +{ + struct property *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + + new->name = name; + new->deleted = 1; + + return new; +} + struct property *chain_property(struct property *first, struct property *list) { assert(first->next == NULL); @@ -91,6 +114,17 @@ struct node *build_node(struct property *proplist, struct node *children) return new; } +struct node *build_node_delete(void) +{ + struct node *new = xmalloc(sizeof(*new)); + + memset(new, 0, sizeof(*new)); + + new->deleted = 1; + + return new; +} + struct node *name_node(struct node *node, char *name) { assert(node->name == NULL); @@ -106,8 +140,10 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) struct node *new_child, *old_child; struct label *l; + old_node->deleted = 0; + /* Add new node labels to old node */ - for_each_label(new_node->labels, l) + for_each_label_withdel(new_node->labels, l) add_label(&old_node->labels, l->label); /* Move properties from the new node to the old node. If there @@ -118,14 +154,21 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) new_node->proplist = new_prop->next; new_prop->next = NULL; + if (new_prop->deleted) { + delete_property_by_name(old_node, new_prop->name); + free(new_prop); + continue; + } + /* Look for a collision, set new value if there is */ - for_each_property(old_node, old_prop) { + for_each_property_withdel(old_node, old_prop) { if (streq(old_prop->name, new_prop->name)) { /* Add new labels to old property */ - for_each_label(new_prop->labels, l) + for_each_label_withdel(new_prop->labels, l) add_label(&old_prop->labels, l->label); old_prop->val = new_prop->val; + old_prop->deleted = 0; free(new_prop); new_prop = NULL; break; @@ -146,8 +189,14 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) new_child->parent = NULL; new_child->next_sibling = NULL; + if (new_child->deleted) { + delete_node_by_name(old_node, new_child->name); + free(new_child); + continue; + } + /* Search for a collision. Merge if there is */ - for_each_child(old_node, old_child) { + for_each_child_withdel(old_node, old_child) { if (streq(old_child->name, new_child->name)) { merge_nodes(old_child, new_child); new_child = NULL; @@ -155,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) } } - /* if no collision occurred, add child to the old node. */ + /* if no collision occured, add child to the old node. */ if (new_child) add_child(old_node, new_child); } @@ -188,6 +237,25 @@ void add_property(struct node *node, struct property *prop) *p = prop; } +void delete_property_by_name(struct node *node, char *name) +{ + struct property *prop = node->proplist; + + while (prop) { + if (!strcmp(prop->name, name)) { + delete_property(prop); + return; + } + prop = prop->next; + } +} + +void delete_property(struct property *prop) +{ + prop->deleted = 1; + delete_labels(&prop->labels); +} + void add_child(struct node *parent, struct node *child) { struct node **p; @@ -202,6 +270,32 @@ void add_child(struct node *parent, struct node *child) *p = child; } +void delete_node_by_name(struct node *parent, char *name) +{ + struct node *node = parent->children; + + while (node) { + if (!strcmp(node->name, name)) { + delete_node(node); + return; + } + node = node->next_sibling; + } +} + +void delete_node(struct node *node) +{ + struct property *prop; + struct node *child; + + node->deleted = 1; + for_each_child(node, child) + delete_node(child); + for_each_property(node, prop) + delete_property(prop); + delete_labels(&node->labels); +} + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); @@ -353,8 +447,11 @@ struct node *get_node_by_path(struct node *tree, const char *path) const char *p; struct node *child; - if (!path || ! (*path)) + if (!path || ! (*path)) { + if (tree->deleted) + return NULL; return tree; + } while (path[0] == '/') path++; @@ -397,8 +494,11 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) assert((phandle != 0) && (phandle != -1)); - if (tree->phandle == phandle) + if (tree->phandle == phandle) { + if (tree->deleted) + return NULL; return tree; + } for_each_child(tree, child) { node = get_node_by_phandle(child, phandle); @@ -535,7 +635,7 @@ static void sort_properties(struct node *node) int n = 0, i = 0; struct property *prop, **tbl; - for_each_property(node, prop) + for_each_property_withdel(node, prop) n++; if (n == 0) @@ -543,7 +643,7 @@ static void sort_properties(struct node *node) tbl = xmalloc(n * sizeof(*tbl)); - for_each_property(node, prop) + for_each_property_withdel(node, prop) tbl[i++] = prop; qsort(tbl, n, sizeof(*tbl), cmp_prop); @@ -571,7 +671,7 @@ static void sort_subnodes(struct node *node) int n = 0, i = 0; struct node *subnode, **tbl; - for_each_child(node, subnode) + for_each_child_withdel(node, subnode) n++; if (n == 0) @@ -579,7 +679,7 @@ static void sort_subnodes(struct node *node) tbl = xmalloc(n * sizeof(*tbl)); - for_each_child(node, subnode) + for_each_child_withdel(node, subnode) tbl[i++] = subnode; qsort(tbl, n, sizeof(*tbl), cmp_subnode); @@ -598,7 +698,7 @@ static void sort_node(struct node *node) sort_properties(node); sort_subnodes(node); - for_each_child(node, c) + for_each_child_withdel(node, c) sort_node(c); } diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index 36a38e9f1a2..c20bc5315bc 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -24,6 +24,15 @@ #include "dtc.h" #include "srcpos.h" +/* A node in our list of directories to search for source/include files */ +struct search_path { + struct search_path *next; /* next node in list, NULL for end */ + const char *dirname; /* name of directory to search */ +}; + +/* This is the list of directories that we search for source files */ +static struct search_path *search_path_head, **search_path_tail; + static char *dirname(const char *path) { @@ -47,6 +56,64 @@ struct srcfile_state *current_srcfile; /* = NULL */ #define MAX_SRCFILE_DEPTH (100) static int srcfile_depth; /* = 0 */ + +/** + * Try to open a file in a given directory. + * + * If the filename is an absolute path, then dirname is ignored. If it is a + * relative path, then we look in that directory for the file. + * + * @param dirname Directory to look in, or NULL for none + * @param fname Filename to look for + * @param fp Set to NULL if file did not open + * @return allocated filename on success (caller must free), NULL on failure + */ +static char *try_open(const char *dirname, const char *fname, FILE **fp) +{ + char *fullname; + + if (!dirname || fname[0] == '/') + fullname = xstrdup(fname); + else + fullname = join_path(dirname, fname); + + *fp = fopen(fullname, "r"); + if (!*fp) { + free(fullname); + fullname = NULL; + } + + return fullname; +} + +/** + * Open a file for read access + * + * If it is a relative filename, we search the full search path for it. + * + * @param fname Filename to open + * @param fp Returns pointer to opened FILE, or NULL on failure + * @return pointer to allocated filename, which caller must free + */ +static char *fopen_any_on_path(const char *fname, FILE **fp) +{ + const char *cur_dir = NULL; + struct search_path *node; + char *fullname; + + /* Try current directory first */ + assert(fp); + if (current_srcfile) + cur_dir = current_srcfile->dir; + fullname = try_open(cur_dir, fname, fp); + + /* Failing that, try each search path in turn */ + for (node = search_path_head; !*fp && node; node = node->next) + fullname = try_open(node->dirname, fname, fp); + + return fullname; +} + FILE *srcfile_relative_open(const char *fname, char **fullnamep) { FILE *f; @@ -56,13 +123,7 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep) f = stdin; fullname = xstrdup("<stdin>"); } else { - if (!current_srcfile || !current_srcfile->dir - || (fname[0] == '/')) - fullname = xstrdup(fname); - else - fullname = join_path(current_srcfile->dir, fname); - - f = fopen(fullname, "r"); + fullname = fopen_any_on_path(fname, &f); if (!f) die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); @@ -119,6 +180,23 @@ int srcfile_pop(void) return current_srcfile ? 1 : 0; } +void srcfile_add_search_path(const char *dirname) +{ + struct search_path *node; + + /* Create the node */ + node = xmalloc(sizeof(*node)); + node->next = NULL; + node->dirname = xstrdup(dirname); + + /* Add to the end of our list */ + if (search_path_tail) + *search_path_tail = node; + else + search_path_head = node; + search_path_tail = &node->next; +} + /* * The empty source position. */ @@ -219,9 +297,9 @@ srcpos_verror(struct srcpos *pos, char const *fmt, va_list va) srcstr = srcpos_string(pos); - fprintf(stdout, "Error: %s ", srcstr); - vfprintf(stdout, fmt, va); - fprintf(stdout, "\n"); + fprintf(stderr, "Error: %s ", srcstr); + vfprintf(stderr, fmt, va); + fprintf(stderr, "\n"); } void @@ -250,3 +328,9 @@ srcpos_warn(struct srcpos *pos, char const *fmt, ...) va_end(va); } + +void srcpos_set_line(char *f, int l) +{ + current_srcfile->name = f; + current_srcfile->lineno = l; +} diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index ce980cafe58..93a27123c2e 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -33,10 +33,39 @@ struct srcfile_state { extern FILE *depfile; /* = NULL */ extern struct srcfile_state *current_srcfile; /* = NULL */ +/** + * Open a source file. + * + * If the source file is a relative pathname, then it is searched for in the + * current directory (the directory of the last source file read) and after + * that in the search path. + * + * We work through the search path in order from the first path specified to + * the last. + * + * If the file is not found, then this function does not return, but calls + * die(). + * + * @param fname Filename to search + * @param fullnamep If non-NULL, it is set to the allocated filename of the + * file that was opened. The caller is then responsible + * for freeing the pointer. + * @return pointer to opened FILE + */ FILE *srcfile_relative_open(const char *fname, char **fullnamep); + void srcfile_push(const char *fname); int srcfile_pop(void); +/** + * Add a new directory to the search path for input files + * + * The new path is added at the end of the list. + * + * @param dirname Directory to add + */ +void srcfile_add_search_path(const char *dirname); + struct srcpos { int first_line; int first_column; @@ -84,4 +113,6 @@ extern void srcpos_error(struct srcpos *pos, char const *, ...) extern void srcpos_warn(struct srcpos *pos, char const *, ...) __attribute__((format(printf, 2, 3))); +extern void srcpos_set_line(char *f, int l); + #endif /* _SRCPOS_H_ */ diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index c09aafade31..5740e6992d3 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -23,6 +23,7 @@ extern FILE *yyin; extern int yyparse(void); +extern YYLTYPE yylloc; struct boot_info *the_boot_info; int treesource_error; @@ -34,6 +35,7 @@ struct boot_info *dt_from_source(const char *fname) srcfile_push(fname); yyin = current_srcfile->f; + yylloc.file = current_srcfile; if (yyparse() != 0) die("Unable to parse input tree\n"); @@ -279,4 +281,3 @@ void dt_to_source(FILE *f, struct boot_info *bi) write_tree_source_node(f, bi->dt, 0); } - diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh new file mode 100755 index 00000000000..feb01ef26be --- /dev/null +++ b/scripts/dtc/update-dtc-source.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# Simple script to update the version of DTC carried by the Linux kernel +# +# This script assumes that the dtc and the linux git trees are in the +# same directory. After building dtc in the dtc directory, it copies the +# source files and generated source files into the scripts/dtc directory +# in the kernel and creates a git commit updating them to the new +# version. +# +# Usage: from the top level Linux source tree, run: +# $ ./scripts/dtc/update-dtc-source.sh +# +# The script will change into the dtc tree, build and test dtc, copy the +# relevant files into the kernel tree and create a git commit. The commit +# message will need to be modified to reflect the version of DTC being +# imported +# +# TODO: +# This script is pretty basic, but it is seldom used so a few manual tasks +# aren't a big deal. If anyone is interested in making it more robust, the +# the following would be nice: +# * Actually fail to complete if any testcase fails. +# - The dtc "make check" target needs to return a failure +# * Extract the version number from the dtc repo for the commit message +# * Build dtc in the kernel tree +# * run 'make check" on dtc built from the kernel tree + +set -ev + +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 \ + dtc-lexer.l dtc-parser.y" +DTC_GENERATED="dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h" + +# Build DTC +cd $DTC_UPSTREAM_PATH +make clean +make check + +# Copy the files into the Linux tree +cd $DTC_LINUX_PATH +for f in $DTC_SOURCE; do + cp ${DTC_UPSTREAM_PATH}/${f} ${f} + git add ${f} +done +for f in $DTC_GENERATED; do + cp ${DTC_UPSTREAM_PATH}/$f ${f}_shipped + git add ${f}_shipped +done + +git commit -e -v -m "scripts/dtc: Update to upstream version [CHANGEME]" diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index d7ac27d2ae1..3055c16e980 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -1,6 +1,10 @@ /* + * Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. * + * util_is_printable_string contributed by + * Pantelis Antoniou <pantelis.antoniou AT gmail.com> + * * 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 @@ -17,12 +21,20 @@ * USA */ +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <assert.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include "libfdt.h" #include "util.h" +#include "version_gen.h" char *xstrdup(const char *s) { @@ -57,3 +69,380 @@ char *join_path(const char *path, const char *name) memcpy(str+lenp, name, lenn+1); return str; } + +int util_is_printable_string(const void *data, int len) +{ + const char *s = data; + const char *ss, *se; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + se = s + len; + + while (s < se) { + ss = s; + while (s < se && *s && isprint(*s)) + s++; + + /* not zero, or not done yet */ + if (*s != '\0' || s == ss) + return 0; + + s++; + } + + return 1; +} + +/* + * Parse a octal encoded character starting at index i in string s. The + * resulting character will be returned and the index i will be updated to + * point at the character directly after the end of the encoding, this may be + * the '\0' terminator of the string. + */ +static char get_oct_char(const char *s, int *i) +{ + char x[4]; + char *endx; + long val; + + x[3] = '\0'; + strncpy(x, s + *i, 3); + + val = strtol(x, &endx, 8); + + assert(endx > x); + + (*i) += endx - x; + return val; +} + +/* + * Parse a hexadecimal encoded character starting at index i in string s. The + * resulting character will be returned and the index i will be updated to + * point at the character directly after the end of the encoding, this may be + * the '\0' terminator of the string. + */ +static char get_hex_char(const char *s, int *i) +{ + char x[3]; + char *endx; + long val; + + x[2] = '\0'; + strncpy(x, s + *i, 2); + + val = strtol(x, &endx, 16); + if (!(endx > x)) + die("\\x used with no following hex digits\n"); + + (*i) += endx - x; + return val; +} + +char get_escape_char(const char *s, int *i) +{ + char c = s[*i]; + int j = *i + 1; + char val; + + assert(c); + switch (c) { + case 'a': + val = '\a'; + break; + case 'b': + val = '\b'; + break; + case 't': + val = '\t'; + break; + case 'n': + val = '\n'; + break; + case 'v': + val = '\v'; + break; + case 'f': + val = '\f'; + break; + case 'r': + val = '\r'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + j--; /* need to re-read the first digit as + * part of the octal value */ + val = get_oct_char(s, &j); + break; + case 'x': + val = get_hex_char(s, &j); + break; + default: + val = c; + } + + (*i) = j; + return val; +} + +int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) +{ + int fd = 0; /* assume stdin */ + char *buf = NULL; + off_t bufsize = 1024, offset = 0; + int ret = 0; + + *buffp = NULL; + if (strcmp(filename, "-") != 0) { + fd = open(filename, O_RDONLY); + if (fd < 0) + return errno; + } + + /* Loop until we have read everything */ + buf = xmalloc(bufsize); + do { + /* Expand the buffer to hold the next chunk */ + if (offset == bufsize) { + bufsize *= 2; + buf = xrealloc(buf, bufsize); + if (!buf) { + ret = ENOMEM; + break; + } + } + + ret = read(fd, &buf[offset], bufsize - offset); + if (ret < 0) { + ret = errno; + break; + } + offset += ret; + } while (ret != 0); + + /* Clean up, including closing stdin; return errno on error */ + close(fd); + if (ret) + free(buf); + else + *buffp = buf; + *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 *buff; + int ret = utilfdt_read_err_len(filename, &buff, len); + + if (ret) { + fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, + strerror(ret)); + return NULL; + } + /* Successful read */ + 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 */ + int totalsize; + int offset; + int ret = 0; + const char *ptr = blob; + + if (strcmp(filename, "-") != 0) { + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + return errno; + } + + totalsize = fdt_totalsize(blob); + offset = 0; + + while (offset < totalsize) { + ret = write(fd, ptr + offset, totalsize - offset); + if (ret < 0) { + ret = -errno; + break; + } + offset += ret; + } + /* Close the file/stdin; return errno on error */ + if (fd != 1) + close(fd); + return ret < 0 ? -ret : 0; +} + + +int utilfdt_write(const char *filename, const void *blob) +{ + int ret = utilfdt_write_err(filename, blob); + + if (ret) { + fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename, + strerror(ret)); + } + return ret ? -1 : 0; +} + +int utilfdt_decode_type(const char *fmt, int *type, int *size) +{ + int qualifier = 0; + + if (!*fmt) + return -1; + + /* get the conversion qualifier */ + *size = -1; + if (strchr("hlLb", *fmt)) { + qualifier = *fmt++; + if (qualifier == *fmt) { + switch (*fmt++) { +/* TODO: case 'l': qualifier = 'L'; break;*/ + case 'h': + qualifier = 'b'; + break; + } + } + } + + /* we should now have a type */ + if ((*fmt == '\0') || !strchr("iuxs", *fmt)) + return -1; + + /* convert qualifier (bhL) to byte size */ + if (*fmt != 's') + *size = qualifier == 'b' ? 1 : + qualifier == 'h' ? 2 : + qualifier == 'l' ? 4 : -1; + *type = *fmt++; + + /* that should be it! */ + if (*fmt) + return -1; + return 0; +} + +void utilfdt_print_data(const char *data, int len) +{ + int i; + const char *p = data; + const char *s; + + /* no data, don't print */ + if (len == 0) + return; + + if (util_is_printable_string(data, len)) { + printf(" = "); + + s = data; + do { + printf("\"%s\"", s); + s += strlen(s) + 1; + if (s < data + len) + printf(", "); + } while (s < data + len); + + } else if ((len % 4) == 0) { + const uint32_t *cell = (const uint32_t *)data; + + printf(" = <"); + for (i = 0; i < len; i += 4) + printf("0x%08x%s", fdt32_to_cpu(cell[i]), + i < (len - 4) ? " " : ""); + printf(">"); + } else { + printf(" = ["); + for (i = 0; i < len; i++) + printf("%02x%s", *p++, i < len - 1 ? " " : ""); + printf("]"); + } +} + +void util_version(void) +{ + printf("Version: %s\n", DTC_VERSION); + exit(0); +} + +void util_usage(const char *errmsg, const char *synopsis, + const char *short_opts, struct option const long_opts[], + const char * const opts_help[]) +{ + FILE *fp = errmsg ? stderr : stdout; + const char a_arg[] = "<arg>"; + size_t a_arg_len = strlen(a_arg) + 1; + size_t i; + int optlen; + + fprintf(fp, + "Usage: %s\n" + "\n" + "Options: -[%s]\n", synopsis, short_opts); + + /* prescan the --long opt length to auto-align */ + optlen = 0; + for (i = 0; long_opts[i].name; ++i) { + /* +1 is for space between --opt and help text */ + int l = strlen(long_opts[i].name) + 1; + if (long_opts[i].has_arg == a_argument) + l += a_arg_len; + if (optlen < l) + optlen = l; + } + + for (i = 0; long_opts[i].name; ++i) { + /* helps when adding new applets or options */ + assert(opts_help[i] != NULL); + + /* first output the short flag if it has one */ + if (long_opts[i].val > '~') + fprintf(fp, " "); + else + fprintf(fp, " -%c, ", long_opts[i].val); + + /* then the long flag */ + if (long_opts[i].has_arg == no_argument) + fprintf(fp, "--%-*s", optlen, long_opts[i].name); + else + fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg, + (int)(optlen - strlen(long_opts[i].name) - a_arg_len), ""); + + /* finally the help text */ + fprintf(fp, "%s\n", opts_help[i]); + } + + if (errmsg) { + fprintf(fp, "\nError: %s\n", errmsg); + exit(EXIT_FAILURE); + } else + exit(EXIT_SUCCESS); +} diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index 9cead842c11..8f40b449935 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -1,7 +1,11 @@ #ifndef _UTIL_H #define _UTIL_H +#include <stdarg.h> +#include <getopt.h> + /* + * Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or @@ -20,7 +24,9 @@ * USA */ -static inline void __attribute__((noreturn)) die(char * str, ...) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static inline void __attribute__((noreturn)) die(const char *str, ...) { va_list ap; @@ -53,4 +59,192 @@ static inline void *xrealloc(void *p, size_t len) extern char *xstrdup(const char *s); extern char *join_path(const char *path, const char *name); +/** + * Check a property of a given length to see if it is all printable and + * has a valid terminator. The property can contain either a single string, + * or multiple strings each of non-zero length. + * + * @param data The string to check + * @param len The string length including terminator + * @return 1 if a valid printable string, 0 if not + */ +int util_is_printable_string(const void *data, int len); + +/* + * Parse an escaped character starting at index i in string s. The resulting + * character will be returned and the index i will be updated to point at the + * character directly after the end of the encoding, this may be the '\0' + * terminator of the string. + */ +char get_escape_char(const char *s, int *i); + +/** + * Read a device tree file into a buffer. This will report any errors on + * 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 + */ +char *utilfdt_read_len(const char *filename, off_t *len); + +/** + * Read a device tree file into a buffer. Does not report errors, but only + * returns them. The value returned can be passed to strerror() to obtain + * an error message for the user. + * + * @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 + */ +int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len); + +/** + * Write a device tree buffer to a file. This will report any errors on + * stderr. + * + * @param filename The filename to write, or - for stdout + * @param blob Poiner to buffer containing fdt + * @return 0 if ok, -1 on error + */ +int utilfdt_write(const char *filename, const void *blob); + +/** + * Write a device tree buffer to a file. Does not report errors, but only + * returns them. The value returned can be passed to strerror() to obtain + * an error message for the user. + * + * @param filename The filename to write, or - for stdout + * @param blob Poiner to buffer containing fdt + * @return 0 if ok, else an errno value representing the error + */ +int utilfdt_write_err(const char *filename, const void *blob); + +/** + * Decode a data type string. The purpose of this string + * + * The string consists of an optional character followed by the type: + * Modifier characters: + * hh or b 1 byte + * h 2 byte + * l 4 byte, default + * + * Type character: + * s string + * i signed integer + * u unsigned integer + * x hex + * + * TODO: Implement ll modifier (8 bytes) + * TODO: Implement o type (octal) + * + * @param fmt Format string to process + * @param type Returns type found(s/d/u/x), or 0 if none + * @param size Returns size found(1,2,4,8) or 4 if none + * @return 0 if ok, -1 on error (no type given, or other invalid format) + */ +int utilfdt_decode_type(const char *fmt, int *type, int *size); + +/* + * This is a usage message fragment for the -t option. It is the format + * supported by utilfdt_decode_type. + */ + +#define USAGE_TYPE_MSG \ + "<type>\ts=string, i=int, u=unsigned, x=hex\n" \ + "\tOptional modifier prefix:\n" \ + "\t\thh or b=byte, h=2 byte, l=4 byte (default)"; + +/** + * Print property data in a readable format to stdout + * + * Properties that look like strings will be printed as strings. Otherwise + * the data will be displayed either as cells (if len is a multiple of 4 + * bytes) or bytes. + * + * If len is 0 then this function does nothing. + * + * @param data Pointers to property data + * @param len Length of property data + */ +void utilfdt_print_data(const char *data, int len); + +/** + * Show source version and exit + */ +void util_version(void) __attribute__((noreturn)); + +/** + * Show usage and exit + * + * This helps standardize the output of various utils. You most likely want + * to use the usage() helper below rather than call this. + * + * @param errmsg If non-NULL, an error message to display + * @param synopsis The initial example usage text (and possible examples) + * @param short_opts The string of short options + * @param long_opts The structure of long options + * @param opts_help An array of help strings (should align with long_opts) + */ +void util_usage(const char *errmsg, const char *synopsis, + const char *short_opts, struct option const long_opts[], + const char * const opts_help[]) __attribute__((noreturn)); + +/** + * Show usage and exit + * + * If you name all your usage variables with usage_xxx, then you can call this + * help macro rather than expanding all arguments yourself. + * + * @param errmsg If non-NULL, an error message to display + */ +#define usage(errmsg) \ + util_usage(errmsg, usage_synopsis, usage_short_opts, \ + usage_long_opts, usage_opts_help) + +/** + * Call getopt_long() with standard options + * + * Since all util code runs getopt in the same way, provide a helper. + */ +#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \ + usage_long_opts, NULL) + +/* Helper for aligning long_opts array */ +#define a_argument required_argument + +/* Helper for usage_short_opts string constant */ +#define USAGE_COMMON_SHORT_OPTS "hV" + +/* Helper for usage_long_opts option array */ +#define USAGE_COMMON_LONG_OPTS \ + {"help", no_argument, NULL, 'h'}, \ + {"version", no_argument, NULL, 'V'}, \ + {NULL, no_argument, NULL, 0x0} + +/* Helper for usage_opts_help array */ +#define USAGE_COMMON_OPTS_HELP \ + "Print this help and exit", \ + "Print version and exit", \ + NULL + +/* Helper for getopt case statements */ +#define case_USAGE_COMMON_FLAGS \ + case 'h': usage(NULL); \ + case 'V': util_version(); \ + case '?': usage("unknown option"); + #endif /* _UTIL_H */ diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 6158b867df9..54d4e904433 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.2.0-g37c0b6a0" +#define DTC_VERSION "DTC 1.4.0-dirty" diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh index 98cffcb941e..c9469d34ecc 100644 --- a/scripts/gcc-goto.sh +++ b/scripts/gcc-goto.sh @@ -2,4 +2,20 @@ # Test for gcc 'asm goto' support # Copyright (C) 2010, Jason Baron <jbaron@redhat.com> -echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y" +cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y" +int main(void) +{ +#if defined(__arm__) || defined(__aarch64__) + /* + * Not related to asm goto, but used by jump label + * and broken on some ARM GCC versions (see GCC Bug 48637). + */ + static struct { int dummy; int state; } tp; + asm (".long %c0" :: "i" (&tp.state)); +#endif + +entry: + asm goto ("" :::: entry); + return 0; +} +END diff --git a/scripts/gcc-ld b/scripts/gcc-ld new file mode 100644 index 00000000000..cadab9a13ed --- /dev/null +++ b/scripts/gcc-ld @@ -0,0 +1,29 @@ +#!/bin/sh +# run gcc with ld options +# used as a wrapper to execute link time optimizations +# yes virginia, this is not pretty + +ARGS="-nostdlib" + +while [ "$1" != "" ] ; do + case "$1" in + -save-temps|-m32|-m64) N="$1" ;; + -r) N="$1" ;; + -[Wg]*) N="$1" ;; + -[olv]|-[Ofd]*|-nostdlib) N="$1" ;; + --end-group|--start-group) + N="-Wl,$1" ;; + -[RTFGhIezcbyYu]*|\ +--script|--defsym|-init|-Map|--oformat|-rpath|\ +-rpath-link|--sort-section|--section-start|-Tbss|-Tdata|-Ttext|\ +--version-script|--dynamic-list|--version-exports-symbol|--wrap|-m) + A="$1" ; shift ; N="-Wl,$A,$1" ;; + -[m]*) N="$1" ;; + -*) N="-Wl,$1" ;; + *) N="$1" ;; + esac + ARGS="$ARGS $N" + shift +done + +exec $CC $ARGS diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index debecb5561c..7f2126df91f 100644 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh @@ -22,10 +22,10 @@ if [ ${#compiler} -eq 0 ]; then exit 1 fi -MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) +MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) + PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL else printf "%02d%02d\\n" $MAJOR $MINOR diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh index 29493dc4528..12dbd0b11ea 100644 --- a/scripts/gcc-x86_32-has-stack-protector.sh +++ b/scripts/gcc-x86_32-has-stack-protector.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +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 diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh index afaec618b39..973e8c14156 100644 --- a/scripts/gcc-x86_64-has-stack-protector.sh +++ b/scripts/gcc-x86_64-has-stack-protector.sh @@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index b482f162a18..17fa901418a 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -240,12 +240,24 @@ case "$arg" in output_file="$1" cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)" output=${cpio_list} - echo "$output_file" | grep -q "\.gz$" && compr="gzip -n -9 -f" - echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f" - echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f" - echo "$output_file" | grep -q "\.xz$" && \ - compr="xz --check=crc32 --lzma2=dict=1MiB" - echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f" + 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 ;; diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 8a106499ec4..88632df4381 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; -static const char *arch = ""; static const char *mod_prefix = ""; static int errors; @@ -731,7 +730,7 @@ static void genksyms_usage(void) { fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" #ifdef __GNU_LIBRARY__ - " -a, --arch Select architecture\n" + " -s, --symbol-prefix Select symbol prefix\n" " -d, --debug Increment the debug level (repeatable)\n" " -D, --dump Dump expanded symbol defs (for debugging only)\n" " -r, --reference file Read reference symbols from a file\n" @@ -742,7 +741,7 @@ static void genksyms_usage(void) " -h, --help Print this message\n" " -V, --version Print the release version\n" #else /* __GNU_LIBRARY__ */ - " -a Select architecture\n" + " -s Select symbol prefix\n" " -d Increment the debug level (repeatable)\n" " -D Dump expanded symbol defs (for debugging only)\n" " -r file Read reference symbols from a file\n" @@ -763,7 +762,7 @@ int main(int argc, char **argv) #ifdef __GNU_LIBRARY__ struct option long_opts[] = { - {"arch", 1, 0, 'a'}, + {"symbol-prefix", 1, 0, 's'}, {"debug", 0, 0, 'd'}, {"warnings", 0, 0, 'w'}, {"quiet", 0, 0, 'q'}, @@ -776,14 +775,14 @@ int main(int argc, char **argv) {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph", + while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF) + while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { - case 'a': - arch = optarg; + case 's': + mod_prefix = optarg; break; case 'd': flag_debug++; @@ -826,8 +825,6 @@ int main(int argc, char **argv) genksyms_usage(); return 1; } - if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0)) - mod_prefix = "_"; { extern int yydebug; extern int yy_flex_debug; diff --git a/scripts/genksyms/keywords.gperf b/scripts/genksyms/keywords.gperf index 3e77a943e7b..a9096d99317 100644 --- a/scripts/genksyms/keywords.gperf +++ b/scripts/genksyms/keywords.gperf @@ -23,6 +23,8 @@ __inline, INLINE_KEYW __inline__, INLINE_KEYW __signed, SIGNED_KEYW __signed__, SIGNED_KEYW +__typeof, TYPEOF_KEYW +__typeof__, TYPEOF_KEYW __volatile, VOLATILE_KEYW __volatile__, VOLATILE_KEYW # According to rth, c99 defines _Bool, __restrict, __restrict__, restrict. KAO @@ -51,9 +53,8 @@ signed, SIGNED_KEYW static, STATIC_KEYW struct, STRUCT_KEYW typedef, TYPEDEF_KEYW +typeof, TYPEOF_KEYW union, UNION_KEYW unsigned, UNSIGNED_KEYW void, VOID_KEYW volatile, VOLATILE_KEYW -typeof, TYPEOF_KEYW -__typeof__, TYPEOF_KEYW diff --git a/scripts/genksyms/keywords.hash.c_shipped b/scripts/genksyms/keywords.hash.c_shipped index 82062607e8c..e9452482e19 100644 --- a/scripts/genksyms/keywords.hash.c_shipped +++ b/scripts/genksyms/keywords.hash.c_shipped @@ -34,7 +34,7 @@ struct resword; static const struct resword *is_reserved_word(register const char *str, register unsigned int len); #line 8 "scripts/genksyms/keywords.gperf" struct resword { const char *name; int token; }; -/* maximum key range = 64, duplicates = 0 */ +/* maximum key range = 98, duplicates = 0 */ #ifdef __GNUC__ __inline @@ -48,32 +48,32 @@ is_reserved_hash (register const char *str, register unsigned int len) { static const unsigned char asso_values[] = { - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 0, - 67, 67, 67, 67, 67, 67, 15, 67, 67, 67, - 0, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 0, 67, 0, 67, 5, - 25, 20, 15, 30, 67, 15, 67, 67, 10, 0, - 10, 40, 20, 67, 10, 5, 0, 10, 15, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67 + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, + 101, 101, 101, 101, 101, 101, 15, 101, 101, 101, + 0, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 0, 101, 0, 101, 5, + 25, 20, 55, 30, 101, 15, 101, 101, 10, 0, + 10, 40, 10, 101, 10, 5, 0, 10, 15, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101 }; return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]]; } @@ -89,17 +89,17 @@ is_reserved_word (register const char *str, register unsigned int len) { enum { - TOTAL_KEYWORDS = 45, + TOTAL_KEYWORDS = 46, MIN_WORD_LENGTH = 3, MAX_WORD_LENGTH = 24, MIN_HASH_VALUE = 3, - MAX_HASH_VALUE = 66 + MAX_HASH_VALUE = 100 }; static const struct resword wordlist[] = { {""}, {""}, {""}, -#line 33 "scripts/genksyms/keywords.gperf" +#line 35 "scripts/genksyms/keywords.gperf" {"asm", ASM_KEYW}, {""}, #line 15 "scripts/genksyms/keywords.gperf" @@ -108,7 +108,7 @@ is_reserved_word (register const char *str, register unsigned int len) #line 16 "scripts/genksyms/keywords.gperf" {"__asm__", ASM_KEYW}, {""}, {""}, -#line 59 "scripts/genksyms/keywords.gperf" +#line 27 "scripts/genksyms/keywords.gperf" {"__typeof__", TYPEOF_KEYW}, {""}, #line 19 "scripts/genksyms/keywords.gperf" @@ -119,31 +119,31 @@ is_reserved_word (register const char *str, register unsigned int len) {"__const__", CONST_KEYW}, #line 25 "scripts/genksyms/keywords.gperf" {"__signed__", SIGNED_KEYW}, -#line 51 "scripts/genksyms/keywords.gperf" +#line 53 "scripts/genksyms/keywords.gperf" {"static", STATIC_KEYW}, {""}, -#line 46 "scripts/genksyms/keywords.gperf" +#line 48 "scripts/genksyms/keywords.gperf" {"int", INT_KEYW}, -#line 39 "scripts/genksyms/keywords.gperf" +#line 41 "scripts/genksyms/keywords.gperf" {"char", CHAR_KEYW}, -#line 40 "scripts/genksyms/keywords.gperf" +#line 42 "scripts/genksyms/keywords.gperf" {"const", CONST_KEYW}, -#line 52 "scripts/genksyms/keywords.gperf" +#line 54 "scripts/genksyms/keywords.gperf" {"struct", STRUCT_KEYW}, -#line 31 "scripts/genksyms/keywords.gperf" +#line 33 "scripts/genksyms/keywords.gperf" {"__restrict__", RESTRICT_KEYW}, -#line 32 "scripts/genksyms/keywords.gperf" +#line 34 "scripts/genksyms/keywords.gperf" {"restrict", RESTRICT_KEYW}, #line 12 "scripts/genksyms/keywords.gperf" {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW}, #line 23 "scripts/genksyms/keywords.gperf" {"__inline__", INLINE_KEYW}, {""}, -#line 27 "scripts/genksyms/keywords.gperf" +#line 29 "scripts/genksyms/keywords.gperf" {"__volatile__", VOLATILE_KEYW}, #line 10 "scripts/genksyms/keywords.gperf" {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW}, -#line 30 "scripts/genksyms/keywords.gperf" +#line 32 "scripts/genksyms/keywords.gperf" {"_restrict", RESTRICT_KEYW}, {""}, #line 17 "scripts/genksyms/keywords.gperf" @@ -152,56 +152,65 @@ is_reserved_word (register const char *str, register unsigned int len) {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW}, #line 21 "scripts/genksyms/keywords.gperf" {"__extension__", EXTENSION_KEYW}, -#line 42 "scripts/genksyms/keywords.gperf" +#line 44 "scripts/genksyms/keywords.gperf" {"enum", ENUM_KEYW}, #line 13 "scripts/genksyms/keywords.gperf" {"EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW}, -#line 43 "scripts/genksyms/keywords.gperf" +#line 45 "scripts/genksyms/keywords.gperf" {"extern", EXTERN_KEYW}, {""}, #line 24 "scripts/genksyms/keywords.gperf" {"__signed", SIGNED_KEYW}, #line 14 "scripts/genksyms/keywords.gperf" {"EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW}, -#line 54 "scripts/genksyms/keywords.gperf" +#line 57 "scripts/genksyms/keywords.gperf" {"union", UNION_KEYW}, -#line 58 "scripts/genksyms/keywords.gperf" - {"typeof", TYPEOF_KEYW}, -#line 53 "scripts/genksyms/keywords.gperf" - {"typedef", TYPEDEF_KEYW}, + {""}, {""}, #line 22 "scripts/genksyms/keywords.gperf" {"__inline", INLINE_KEYW}, -#line 38 "scripts/genksyms/keywords.gperf" +#line 40 "scripts/genksyms/keywords.gperf" {"auto", AUTO_KEYW}, -#line 26 "scripts/genksyms/keywords.gperf" +#line 28 "scripts/genksyms/keywords.gperf" {"__volatile", VOLATILE_KEYW}, {""}, {""}, -#line 55 "scripts/genksyms/keywords.gperf" +#line 58 "scripts/genksyms/keywords.gperf" {"unsigned", UNSIGNED_KEYW}, {""}, -#line 49 "scripts/genksyms/keywords.gperf" +#line 51 "scripts/genksyms/keywords.gperf" {"short", SHORT_KEYW}, -#line 45 "scripts/genksyms/keywords.gperf" +#line 47 "scripts/genksyms/keywords.gperf" {"inline", INLINE_KEYW}, {""}, -#line 57 "scripts/genksyms/keywords.gperf" +#line 60 "scripts/genksyms/keywords.gperf" {"volatile", VOLATILE_KEYW}, -#line 47 "scripts/genksyms/keywords.gperf" +#line 49 "scripts/genksyms/keywords.gperf" {"long", LONG_KEYW}, -#line 29 "scripts/genksyms/keywords.gperf" +#line 31 "scripts/genksyms/keywords.gperf" {"_Bool", BOOL_KEYW}, {""}, {""}, -#line 48 "scripts/genksyms/keywords.gperf" +#line 50 "scripts/genksyms/keywords.gperf" {"register", REGISTER_KEYW}, -#line 56 "scripts/genksyms/keywords.gperf" +#line 59 "scripts/genksyms/keywords.gperf" {"void", VOID_KEYW}, -#line 44 "scripts/genksyms/keywords.gperf" - {"float", FLOAT_KEYW}, -#line 41 "scripts/genksyms/keywords.gperf" + {""}, +#line 43 "scripts/genksyms/keywords.gperf" {"double", DOUBLE_KEYW}, + {""}, +#line 26 "scripts/genksyms/keywords.gperf" + {"__typeof", TYPEOF_KEYW}, + {""}, {""}, +#line 52 "scripts/genksyms/keywords.gperf" + {"signed", SIGNED_KEYW}, {""}, {""}, {""}, {""}, -#line 50 "scripts/genksyms/keywords.gperf" - {"signed", SIGNED_KEYW} +#line 56 "scripts/genksyms/keywords.gperf" + {"typeof", TYPEOF_KEYW}, +#line 55 "scripts/genksyms/keywords.gperf" + {"typedef", TYPEDEF_KEYW}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 46 "scripts/genksyms/keywords.gperf" + {"float", FLOAT_KEYW} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) diff --git a/scripts/genksyms/lex.l b/scripts/genksyms/lex.l index f770071719c..e583565f201 100644 --- a/scripts/genksyms/lex.l +++ b/scripts/genksyms/lex.l @@ -129,8 +129,9 @@ int yylex(void) { static enum { - ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_BRACKET, ST_BRACE, - ST_EXPRESSION, ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4, + ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_TYPEOF, ST_TYPEOF_1, + ST_BRACKET, ST_BRACE, ST_EXPRESSION, + ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4, ST_TABLE_5, ST_TABLE_6 } lexstate = ST_NOTSTARTED; @@ -198,6 +199,10 @@ repeat: lexstate = ST_ASM; count = 0; goto repeat; + case TYPEOF_KEYW: + lexstate = ST_TYPEOF; + count = 0; + goto repeat; case STRUCT_KEYW: case UNION_KEYW: @@ -284,6 +289,48 @@ repeat: } break; + case ST_TYPEOF: + switch (token) + { + case '(': + if ( ++count == 1 ) + lexstate = ST_TYPEOF_1; + else + APP; + goto repeat; + case ')': + APP; + if (--count == 0) + { + lexstate = ST_NORMAL; + token = TYPEOF_PHRASE; + break; + } + goto repeat; + default: + APP; + goto repeat; + } + break; + + case ST_TYPEOF_1: + if (token == IDENT) + { + if (is_reserved_word(yytext, yyleng) + || find_symbol(yytext, SYM_TYPEDEF, 1)) + { + yyless(0); + unput('('); + lexstate = ST_NORMAL; + token = TYPEOF_KEYW; + break; + } + _APP("(", 1); + } + APP; + lexstate = ST_TYPEOF; + goto repeat; + case ST_BRACKET: APP; switch (token) diff --git a/scripts/genksyms/lex.lex.c_shipped b/scripts/genksyms/lex.lex.c_shipped index 0bf4157e616..f82740a69b8 100644 --- a/scripts/genksyms/lex.lex.c_shipped +++ b/scripts/genksyms/lex.lex.c_shipped @@ -1938,8 +1938,9 @@ int yylex(void) { static enum { - ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_BRACKET, ST_BRACE, - ST_EXPRESSION, ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4, + ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_TYPEOF, ST_TYPEOF_1, + ST_BRACKET, ST_BRACE, ST_EXPRESSION, + ST_TABLE_1, ST_TABLE_2, ST_TABLE_3, ST_TABLE_4, ST_TABLE_5, ST_TABLE_6 } lexstate = ST_NOTSTARTED; @@ -2007,6 +2008,10 @@ repeat: lexstate = ST_ASM; count = 0; goto repeat; + case TYPEOF_KEYW: + lexstate = ST_TYPEOF; + count = 0; + goto repeat; case STRUCT_KEYW: case UNION_KEYW: @@ -2093,6 +2098,48 @@ repeat: } break; + case ST_TYPEOF: + switch (token) + { + case '(': + if ( ++count == 1 ) + lexstate = ST_TYPEOF_1; + else + APP; + goto repeat; + case ')': + APP; + if (--count == 0) + { + lexstate = ST_NORMAL; + token = TYPEOF_PHRASE; + break; + } + goto repeat; + default: + APP; + goto repeat; + } + break; + + case ST_TYPEOF_1: + if (token == IDENT) + { + if (is_reserved_word(yytext, yyleng) + || find_symbol(yytext, SYM_TYPEDEF, 1)) + { + yyless(0); + unput('('); + lexstate = ST_NORMAL; + token = TYPEOF_KEYW; + break; + } + _APP("(", 1); + } + APP; + lexstate = ST_TYPEOF; + goto repeat; + case ST_BRACKET: APP; switch (token) diff --git a/scripts/genksyms/parse.tab.c_shipped b/scripts/genksyms/parse.tab.c_shipped index ece53c79bb5..c9f0f0ce82f 100644 --- a/scripts/genksyms/parse.tab.c_shipped +++ b/scripts/genksyms/parse.tab.c_shipped @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.5.1. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. 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 @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.5" +#define YYBISON_VERSION "2.5.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -117,6 +117,14 @@ static void record_compound(struct string_list **keyw, +# ifndef YY_NULL +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULL nullptr +# else +# define YY_NULL 0 +# endif +# endif + /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 1 @@ -171,18 +179,19 @@ static void record_compound(struct string_list **keyw, EXPORT_SYMBOL_KEYW = 284, ASM_PHRASE = 285, ATTRIBUTE_PHRASE = 286, - BRACE_PHRASE = 287, - BRACKET_PHRASE = 288, - EXPRESSION_PHRASE = 289, - CHAR = 290, - DOTS = 291, - IDENT = 292, - INT = 293, - REAL = 294, - STRING = 295, - TYPE = 296, - OTHER = 297, - FILENAME = 298 + TYPEOF_PHRASE = 287, + BRACE_PHRASE = 288, + BRACKET_PHRASE = 289, + EXPRESSION_PHRASE = 290, + CHAR = 291, + DOTS = 292, + IDENT = 293, + INT = 294, + REAL = 295, + STRING = 296, + TYPE = 297, + OTHER = 298, + FILENAME = 299 }; #endif @@ -304,6 +313,7 @@ YYID (yyi) # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif @@ -395,20 +405,20 @@ union yyalloc #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from FROM to TO. The source and destination do +/* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ while (YYID (0)) # endif # endif @@ -417,20 +427,20 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 4 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 532 +#define YYLAST 514 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 53 +#define YYNTOKENS 54 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 49 /* YYNRULES -- Number of rules. */ #define YYNRULES 132 /* YYNRULES -- Number of states. */ -#define YYNSTATES 188 +#define YYNSTATES 187 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 298 +#define YYMAXUTOK 299 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -442,15 +452,15 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 47, 49, 48, 2, 46, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 52, 44, - 2, 50, 2, 2, 2, 2, 2, 2, 2, 2, + 48, 49, 50, 2, 47, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 53, 45, + 2, 51, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 51, 2, 45, 2, 2, 2, 2, + 2, 2, 2, 52, 2, 46, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -467,7 +477,7 @@ static const yytype_uint8 yytranslate[] = 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43 + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 }; #if YYDEBUG @@ -478,78 +488,77 @@ static const yytype_uint16 yyprhs[] = 0, 0, 3, 5, 8, 9, 12, 13, 18, 19, 23, 25, 27, 29, 31, 34, 37, 41, 42, 44, 46, 50, 55, 56, 58, 60, 63, 65, 67, 69, - 71, 73, 75, 77, 79, 81, 87, 92, 95, 98, - 101, 105, 109, 113, 116, 119, 122, 124, 126, 128, - 130, 132, 134, 136, 138, 140, 142, 144, 147, 148, - 150, 152, 155, 157, 159, 161, 163, 166, 168, 170, - 175, 180, 183, 187, 191, 194, 196, 198, 200, 205, - 210, 213, 217, 221, 224, 226, 230, 231, 233, 235, - 239, 242, 245, 247, 248, 250, 252, 257, 262, 265, - 269, 273, 277, 278, 280, 283, 287, 291, 292, 294, - 296, 299, 303, 306, 307, 309, 311, 315, 318, 321, - 323, 326, 327, 330, 334, 339, 341, 345, 347, 351, - 354, 355, 357 + 71, 73, 75, 77, 79, 81, 86, 88, 91, 94, + 97, 101, 105, 109, 112, 115, 118, 120, 122, 124, + 126, 128, 130, 132, 134, 136, 138, 140, 143, 144, + 146, 148, 151, 153, 155, 157, 159, 162, 164, 166, + 171, 176, 179, 183, 187, 190, 192, 194, 196, 201, + 206, 209, 213, 217, 220, 222, 226, 227, 229, 231, + 235, 238, 241, 243, 244, 246, 248, 253, 258, 261, + 265, 269, 273, 274, 276, 279, 283, 287, 288, 290, + 292, 295, 299, 302, 303, 305, 307, 311, 314, 317, + 319, 322, 323, 326, 330, 335, 337, 341, 343, 347, + 350, 351, 353 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 54, 0, -1, 55, -1, 54, 55, -1, -1, 56, - 57, -1, -1, 12, 23, 58, 60, -1, -1, 23, - 59, 60, -1, 60, -1, 84, -1, 99, -1, 101, - -1, 1, 44, -1, 1, 45, -1, 64, 61, 44, - -1, -1, 62, -1, 63, -1, 62, 46, 63, -1, - 74, 100, 95, 85, -1, -1, 65, -1, 66, -1, - 65, 66, -1, 67, -1, 68, -1, 5, -1, 17, - -1, 21, -1, 11, -1, 14, -1, 69, -1, 73, - -1, 28, 47, 65, 48, 49, -1, 28, 47, 65, - 49, -1, 22, 37, -1, 24, 37, -1, 10, 37, - -1, 22, 37, 87, -1, 24, 37, 87, -1, 10, - 37, 96, -1, 10, 96, -1, 22, 87, -1, 24, - 87, -1, 7, -1, 19, -1, 15, -1, 16, -1, - 20, -1, 25, -1, 13, -1, 9, -1, 26, -1, - 6, -1, 41, -1, 48, 71, -1, -1, 72, -1, - 73, -1, 72, 73, -1, 8, -1, 27, -1, 31, - -1, 18, -1, 70, 74, -1, 75, -1, 37, -1, - 75, 47, 78, 49, -1, 75, 47, 1, 49, -1, - 75, 33, -1, 47, 74, 49, -1, 47, 1, 49, - -1, 70, 76, -1, 77, -1, 37, -1, 41, -1, - 77, 47, 78, 49, -1, 77, 47, 1, 49, -1, - 77, 33, -1, 47, 76, 49, -1, 47, 1, 49, - -1, 79, 36, -1, 79, -1, 80, 46, 36, -1, - -1, 80, -1, 81, -1, 80, 46, 81, -1, 65, - 82, -1, 70, 82, -1, 83, -1, -1, 37, -1, - 41, -1, 83, 47, 78, 49, -1, 83, 47, 1, - 49, -1, 83, 33, -1, 47, 82, 49, -1, 47, - 1, 49, -1, 64, 74, 32, -1, -1, 86, -1, - 50, 34, -1, 51, 88, 45, -1, 51, 1, 45, - -1, -1, 89, -1, 90, -1, 89, 90, -1, 64, - 91, 44, -1, 1, 44, -1, -1, 92, -1, 93, - -1, 92, 46, 93, -1, 76, 95, -1, 37, 94, - -1, 94, -1, 52, 34, -1, -1, 95, 31, -1, - 51, 97, 45, -1, 51, 97, 46, 45, -1, 98, - -1, 97, 46, 98, -1, 37, -1, 37, 50, 34, - -1, 30, 44, -1, -1, 30, -1, 29, 47, 37, - 49, 44, -1 + 55, 0, -1, 56, -1, 55, 56, -1, -1, 57, + 58, -1, -1, 12, 23, 59, 61, -1, -1, 23, + 60, 61, -1, 61, -1, 85, -1, 100, -1, 102, + -1, 1, 45, -1, 1, 46, -1, 65, 62, 45, + -1, -1, 63, -1, 64, -1, 63, 47, 64, -1, + 75, 101, 96, 86, -1, -1, 66, -1, 67, -1, + 66, 67, -1, 68, -1, 69, -1, 5, -1, 17, + -1, 21, -1, 11, -1, 14, -1, 70, -1, 74, + -1, 28, 48, 82, 49, -1, 32, -1, 22, 38, + -1, 24, 38, -1, 10, 38, -1, 22, 38, 88, + -1, 24, 38, 88, -1, 10, 38, 97, -1, 10, + 97, -1, 22, 88, -1, 24, 88, -1, 7, -1, + 19, -1, 15, -1, 16, -1, 20, -1, 25, -1, + 13, -1, 9, -1, 26, -1, 6, -1, 42, -1, + 50, 72, -1, -1, 73, -1, 74, -1, 73, 74, + -1, 8, -1, 27, -1, 31, -1, 18, -1, 71, + 75, -1, 76, -1, 38, -1, 76, 48, 79, 49, + -1, 76, 48, 1, 49, -1, 76, 34, -1, 48, + 75, 49, -1, 48, 1, 49, -1, 71, 77, -1, + 78, -1, 38, -1, 42, -1, 78, 48, 79, 49, + -1, 78, 48, 1, 49, -1, 78, 34, -1, 48, + 77, 49, -1, 48, 1, 49, -1, 80, 37, -1, + 80, -1, 81, 47, 37, -1, -1, 81, -1, 82, + -1, 81, 47, 82, -1, 66, 83, -1, 71, 83, + -1, 84, -1, -1, 38, -1, 42, -1, 84, 48, + 79, 49, -1, 84, 48, 1, 49, -1, 84, 34, + -1, 48, 83, 49, -1, 48, 1, 49, -1, 65, + 75, 33, -1, -1, 87, -1, 51, 35, -1, 52, + 89, 46, -1, 52, 1, 46, -1, -1, 90, -1, + 91, -1, 90, 91, -1, 65, 92, 45, -1, 1, + 45, -1, -1, 93, -1, 94, -1, 93, 47, 94, + -1, 77, 96, -1, 38, 95, -1, 95, -1, 53, + 35, -1, -1, 96, 31, -1, 52, 98, 46, -1, + 52, 98, 47, 46, -1, 99, -1, 98, 47, 99, + -1, 38, -1, 38, 51, 35, -1, 30, 45, -1, + -1, 30, -1, 29, 48, 38, 49, 45, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 123, 123, 124, 128, 128, 134, 134, 136, 136, - 138, 139, 140, 141, 142, 143, 147, 161, 162, 166, - 174, 187, 193, 194, 198, 199, 203, 209, 213, 214, - 215, 216, 217, 221, 222, 223, 224, 228, 230, 232, - 236, 238, 240, 245, 248, 249, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 267, 272, 273, - 277, 278, 282, 282, 282, 283, 291, 292, 296, 305, - 307, 309, 311, 313, 320, 321, 325, 326, 327, 329, - 331, 333, 335, 340, 341, 342, 346, 347, 351, 352, - 357, 362, 364, 368, 369, 377, 381, 383, 385, 387, - 389, 394, 403, 404, 409, 414, 415, 419, 420, 424, - 425, 429, 431, 436, 437, 441, 442, 446, 447, 448, - 452, 456, 457, 461, 462, 466, 467, 470, 475, 483, - 487, 488, 492 + 0, 124, 124, 125, 129, 129, 135, 135, 137, 137, + 139, 140, 141, 142, 143, 144, 148, 162, 163, 167, + 175, 188, 194, 195, 199, 200, 204, 210, 214, 215, + 216, 217, 218, 222, 223, 224, 225, 229, 231, 233, + 237, 239, 241, 246, 249, 250, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 268, 273, 274, + 278, 279, 283, 283, 283, 284, 292, 293, 297, 306, + 308, 310, 312, 314, 321, 322, 326, 327, 328, 330, + 332, 334, 336, 341, 342, 343, 347, 348, 352, 353, + 358, 363, 365, 369, 370, 378, 382, 384, 386, 388, + 390, 395, 404, 405, 410, 415, 416, 420, 421, 425, + 426, 430, 432, 437, 438, 442, 443, 447, 448, 449, + 453, 457, 458, 462, 463, 467, 468, 471, 476, 484, + 488, 489, 493 }; #endif @@ -565,9 +574,9 @@ static const char *const yytname[] = "SHORT_KEYW", "SIGNED_KEYW", "STATIC_KEYW", "STRUCT_KEYW", "TYPEDEF_KEYW", "UNION_KEYW", "UNSIGNED_KEYW", "VOID_KEYW", "VOLATILE_KEYW", "TYPEOF_KEYW", "EXPORT_SYMBOL_KEYW", "ASM_PHRASE", - "ATTRIBUTE_PHRASE", "BRACE_PHRASE", "BRACKET_PHRASE", + "ATTRIBUTE_PHRASE", "TYPEOF_PHRASE", "BRACE_PHRASE", "BRACKET_PHRASE", "EXPRESSION_PHRASE", "CHAR", "DOTS", "IDENT", "INT", "REAL", "STRING", - "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','", "'('", "'*'", "')'", + "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','", "'('", "')'", "'*'", "'='", "'{'", "':'", "$accept", "declaration_seq", "declaration", "$@1", "declaration1", "$@2", "$@3", "simple_declaration", "init_declarator_list_opt", "init_declarator_list", "init_declarator", @@ -584,7 +593,7 @@ static const char *const yytname[] = "member_declarator_list_opt", "member_declarator_list", "member_declarator", "member_bitfield_declarator", "attribute_opt", "enum_body", "enumerator_list", "enumerator", "asm_definition", - "asm_phrase_opt", "export_definition", 0 + "asm_phrase_opt", "export_definition", YY_NULL }; #endif @@ -597,28 +606,28 @@ static const yytype_uint16 yytoknum[] = 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 59, 125, 44, 40, 42, 41, - 61, 123, 58 + 295, 296, 297, 298, 299, 59, 125, 44, 40, 41, + 42, 61, 123, 58 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 53, 54, 54, 56, 55, 58, 57, 59, 57, - 57, 57, 57, 57, 57, 57, 60, 61, 61, 62, - 62, 63, 64, 64, 65, 65, 66, 66, 67, 67, - 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 70, 71, 71, - 72, 72, 73, 73, 73, 73, 74, 74, 75, 75, - 75, 75, 75, 75, 76, 76, 77, 77, 77, 77, - 77, 77, 77, 78, 78, 78, 79, 79, 80, 80, - 81, 82, 82, 83, 83, 83, 83, 83, 83, 83, - 83, 84, 85, 85, 86, 87, 87, 88, 88, 89, - 89, 90, 90, 91, 91, 92, 92, 93, 93, 93, - 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, - 100, 100, 101 + 0, 54, 55, 55, 57, 56, 59, 58, 60, 58, + 58, 58, 58, 58, 58, 58, 61, 62, 62, 63, + 63, 64, 65, 65, 66, 66, 67, 67, 68, 68, + 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 71, 72, 72, + 73, 73, 74, 74, 74, 74, 75, 75, 76, 76, + 76, 76, 76, 76, 77, 77, 78, 78, 78, 78, + 78, 78, 78, 79, 79, 79, 80, 80, 81, 81, + 82, 83, 83, 84, 84, 84, 84, 84, 84, 84, + 84, 85, 86, 86, 87, 88, 88, 89, 89, 90, + 90, 91, 91, 92, 92, 93, 93, 94, 94, 94, + 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, + 101, 101, 102 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -627,7 +636,7 @@ static const yytype_uint8 yyr2[] = 0, 2, 1, 2, 0, 2, 0, 4, 0, 3, 1, 1, 1, 1, 2, 2, 3, 0, 1, 1, 3, 4, 0, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 5, 4, 2, 2, 2, + 1, 1, 1, 1, 1, 4, 1, 2, 2, 2, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 4, @@ -648,68 +657,68 @@ static const yytype_uint8 yydefact[] = 4, 4, 2, 0, 1, 3, 0, 28, 55, 46, 62, 53, 0, 31, 0, 52, 32, 48, 49, 29, 65, 47, 50, 30, 0, 8, 0, 51, 54, 63, - 0, 0, 0, 64, 56, 5, 10, 17, 23, 24, - 26, 27, 33, 34, 11, 12, 13, 14, 15, 39, - 0, 43, 6, 37, 0, 44, 22, 38, 45, 0, - 0, 129, 68, 0, 58, 0, 18, 19, 0, 130, - 67, 25, 42, 127, 0, 125, 22, 40, 0, 113, - 0, 0, 109, 9, 17, 41, 0, 0, 0, 0, - 57, 59, 60, 16, 0, 66, 131, 101, 121, 71, - 0, 0, 123, 0, 7, 112, 106, 76, 77, 0, - 0, 0, 121, 75, 0, 114, 115, 119, 105, 0, - 110, 130, 0, 36, 0, 73, 72, 61, 20, 102, - 0, 93, 0, 84, 87, 88, 128, 124, 126, 118, - 0, 76, 0, 120, 74, 117, 80, 0, 111, 0, - 35, 132, 122, 0, 21, 103, 70, 94, 56, 0, - 93, 90, 92, 69, 83, 0, 82, 81, 0, 0, - 116, 104, 0, 95, 0, 91, 98, 0, 85, 89, - 79, 78, 100, 99, 0, 0, 97, 96 + 0, 0, 0, 64, 36, 56, 5, 10, 17, 23, + 24, 26, 27, 33, 34, 11, 12, 13, 14, 15, + 39, 0, 43, 6, 37, 0, 44, 22, 38, 45, + 0, 0, 129, 68, 0, 58, 0, 18, 19, 0, + 130, 67, 25, 42, 127, 0, 125, 22, 40, 0, + 113, 0, 0, 109, 9, 17, 41, 93, 0, 0, + 0, 0, 57, 59, 60, 16, 0, 66, 131, 101, + 121, 71, 0, 0, 123, 0, 7, 112, 106, 76, + 77, 0, 0, 0, 121, 75, 0, 114, 115, 119, + 105, 0, 110, 130, 94, 56, 0, 93, 90, 92, + 35, 0, 73, 72, 61, 20, 102, 0, 0, 84, + 87, 88, 128, 124, 126, 118, 0, 76, 0, 120, + 74, 117, 80, 0, 111, 0, 0, 95, 0, 91, + 98, 0, 132, 122, 0, 21, 103, 70, 69, 83, + 0, 82, 81, 0, 0, 116, 100, 99, 0, 0, + 104, 85, 89, 79, 78, 97, 96 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 1, 2, 3, 35, 76, 56, 36, 65, 66, - 67, 79, 38, 39, 40, 41, 42, 68, 90, 91, - 43, 121, 70, 112, 113, 132, 133, 134, 135, 161, - 162, 44, 154, 155, 55, 80, 81, 82, 114, 115, - 116, 117, 129, 51, 74, 75, 45, 98, 46 + -1, 1, 2, 3, 36, 77, 57, 37, 66, 67, + 68, 80, 39, 40, 41, 42, 43, 69, 92, 93, + 44, 123, 71, 114, 115, 138, 139, 140, 141, 128, + 129, 45, 165, 166, 56, 81, 82, 83, 116, 117, + 118, 119, 136, 52, 75, 76, 46, 100, 47 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -135 +#define YYPACT_NINF -140 static const yytype_int16 yypact[] = { - -135, 20, -135, 321, -135, -135, 30, -135, -135, -135, - -135, -135, -28, -135, 2, -135, -135, -135, -135, -135, - -135, -135, -135, -135, -6, -135, 9, -135, -135, -135, - -5, 15, -17, -135, -135, -135, -135, 18, 491, -135, - -135, -135, -135, -135, -135, -135, -135, -135, -135, -22, - 31, -135, -135, 19, 106, -135, 491, 19, -135, 491, - 50, -135, -135, 11, -3, 51, 57, -135, 18, -14, - 14, -135, -135, 48, 46, -135, 491, -135, 33, 32, - 59, 154, -135, -135, 18, -135, 365, 56, 60, 61, - -135, -3, -135, -135, 18, -135, -135, -135, -135, -135, - 202, 74, -135, -23, -135, -135, -135, 77, -135, 16, - 101, 49, -135, 34, 92, 93, -135, -135, -135, 94, - -135, 110, 95, -135, 97, -135, -135, -135, -135, -20, - 96, 410, 99, 113, 100, -135, -135, -135, -135, -135, - 103, -135, 107, -135, -135, 111, -135, 239, -135, 32, - -135, -135, -135, 123, -135, -135, -135, -135, -135, 3, - 52, -135, 38, -135, -135, 454, -135, -135, 117, 128, - -135, -135, 134, -135, 135, -135, -135, 276, -135, -135, - -135, -135, -135, -135, 137, 138, -135, -135 + -140, 29, -140, 207, -140, -140, 40, -140, -140, -140, + -140, -140, -27, -140, 44, -140, -140, -140, -140, -140, + -140, -140, -140, -140, -22, -140, -18, -140, -140, -140, + -9, 22, 28, -140, -140, -140, -140, -140, 42, 472, + -140, -140, -140, -140, -140, -140, -140, -140, -140, -140, + 46, 43, -140, -140, 47, 107, -140, 472, 47, -140, + 472, 62, -140, -140, 16, -3, 57, 56, -140, 42, + 35, -11, -140, -140, 53, 48, -140, 472, -140, 51, + 21, 59, 157, -140, -140, 42, -140, 388, 58, 60, + 70, 81, -140, -3, -140, -140, 42, -140, -140, -140, + -140, -140, 253, 71, -140, -20, -140, -140, -140, 83, + -140, 5, 102, 34, -140, 12, 95, 94, -140, -140, + -140, 97, -140, 113, -140, -140, 2, 41, -140, 27, + -140, 99, -140, -140, -140, -140, -24, 98, 101, 109, + 104, -140, -140, -140, -140, -140, 105, -140, 110, -140, + -140, 117, -140, 298, -140, 21, 112, -140, 120, -140, + -140, 343, -140, -140, 121, -140, -140, -140, -140, -140, + 434, -140, -140, 131, 137, -140, -140, -140, 138, 141, + -140, -140, -140, -140, -140, -140, -140 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -135, -135, 187, -135, -135, -135, -135, -50, -135, -135, - 98, 0, -59, -37, -135, -135, -135, -77, -135, -135, - -54, -30, -135, -90, -135, -134, -135, -135, 24, -58, - -135, -135, -135, -135, -18, -135, -135, 109, -135, -135, - 44, 87, 84, 148, -135, 102, -135, -135, -135 + -140, -140, 190, -140, -140, -140, -140, -45, -140, -140, + 96, 1, -60, -31, -140, -140, -140, -78, -140, -140, + -55, -7, -140, -92, -140, -139, -140, -140, -59, -39, + -140, -140, -140, -140, -13, -140, -140, 111, -140, -140, + 39, 87, 84, 147, -140, 106, -140, -140, -140 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -718,149 +727,145 @@ static const yytype_int16 yypgoto[] = #define YYTABLE_NINF -109 static const yytype_int16 yytable[] = { - 86, 71, 111, 37, 172, 10, 83, 69, 58, 49, - 92, 152, 88, 169, 73, 20, 96, 140, 97, 142, - 4, 144, 137, 50, 29, 52, 104, 61, 33, 50, - 153, 53, 111, 89, 111, 77, -93, 127, 95, 85, - 157, 131, 59, 185, 173, 54, 57, 99, 62, 71, - 159, 64, -93, 141, 160, 62, 84, 108, 63, 64, - 54, 100, 60, 109, 64, 63, 64, 146, 73, 107, - 54, 176, 111, 108, 47, 48, 84, 105, 106, 109, - 64, 147, 160, 160, 110, 177, 141, 87, 131, 157, - 108, 102, 103, 173, 71, 93, 109, 64, 101, 159, - 64, 174, 175, 94, 118, 124, 131, 78, 136, 125, - 126, 7, 8, 9, 10, 11, 12, 13, 131, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 110, - 26, 27, 28, 29, 30, 143, 148, 33, 105, 149, - 96, 151, 152, -22, 150, 156, 165, 34, 163, 164, - -22, -107, 166, -22, -22, 119, 167, 171, -22, 7, - 8, 9, 10, 11, 12, 13, 180, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 181, 26, 27, - 28, 29, 30, 182, 183, 33, 186, 187, 5, 179, - 120, -22, 128, 170, 139, 34, 145, 72, -22, -108, - 0, -22, -22, 130, 0, 138, -22, 7, 8, 9, - 10, 11, 12, 13, 0, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 0, 26, 27, 28, 29, - 30, 0, 0, 33, 0, 0, 0, 0, -86, 0, - 168, 0, 0, 34, 7, 8, 9, 10, 11, 12, - 13, -86, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 0, 26, 27, 28, 29, 30, 0, 0, - 33, 0, 0, 0, 0, -86, 0, 184, 0, 0, - 34, 7, 8, 9, 10, 11, 12, 13, -86, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, - 26, 27, 28, 29, 30, 0, 0, 33, 0, 0, - 0, 0, -86, 0, 0, 0, 0, 34, 0, 0, - 0, 0, 6, 0, 0, -86, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 0, 0, 0, 0, 0, -22, 0, - 0, 0, 34, 0, 0, -22, 0, 0, -22, -22, - 7, 8, 9, 10, 11, 12, 13, 0, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 0, 26, - 27, 28, 29, 30, 0, 0, 33, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, - 0, 0, 0, 122, 123, 7, 8, 9, 10, 11, - 12, 13, 0, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 0, 26, 27, 28, 29, 30, 0, - 0, 33, 0, 0, 0, 0, 0, 157, 0, 0, - 0, 158, 0, 0, 0, 0, 0, 159, 64, 7, + 87, 88, 113, 156, 38, 10, 146, 163, 72, 127, + 94, 50, 84, 59, 174, 20, 54, 90, 74, 148, + 58, 150, 179, 101, 29, 51, 143, 164, 33, 4, + 55, 70, 106, 113, 55, 113, -93, 102, 134, 60, + 124, 78, 87, 147, 157, 86, 152, 110, 127, 127, + 126, -93, 65, 111, 63, 65, 72, 91, 85, 109, + 153, 160, 97, 110, 64, 98, 65, 53, 99, 111, + 61, 65, 147, 62, 112, 161, 110, 113, 85, 124, + 63, 74, 111, 157, 65, 48, 49, 158, 159, 126, + 64, 65, 65, 87, 104, 105, 107, 108, 51, 55, + 89, 87, 95, 96, 103, 120, 142, 130, 79, 131, + 87, 182, 7, 8, 9, 10, 11, 12, 13, 132, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 133, 26, 27, 28, 29, 30, 112, 149, 33, 34, + 154, 155, 107, 98, 162, -22, 169, 167, 163, 35, + 168, 170, -22, -107, 171, -22, 180, -22, 121, 172, + -22, 176, 7, 8, 9, 10, 11, 12, 13, 177, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 183, 26, 27, 28, 29, 30, 184, 185, 33, 34, + 186, 5, 135, 122, 175, -22, 145, 73, 151, 35, + 0, 0, -22, -108, 0, -22, 0, -22, 6, 0, + -22, 144, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 0, 0, 0, 0, 0, -22, 0, 0, 0, 35, + 0, 0, -22, 0, 137, -22, 0, -22, 7, 8, + 9, 10, 11, 12, 13, 0, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 27, 28, + 29, 30, 0, 0, 33, 34, 0, 0, 0, 0, + -86, 0, 0, 0, 0, 35, 0, 0, 0, 173, + 0, 0, -86, 7, 8, 9, 10, 11, 12, 13, + 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 0, 26, 27, 28, 29, 30, 0, 0, 33, + 34, 0, 0, 0, 0, -86, 0, 0, 0, 0, + 35, 0, 0, 0, 178, 0, 0, -86, 7, 8, + 9, 10, 11, 12, 13, 0, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 27, 28, + 29, 30, 0, 0, 33, 34, 0, 0, 0, 0, + -86, 0, 0, 0, 0, 35, 0, 0, 0, 0, + 0, 0, -86, 7, 8, 9, 10, 11, 12, 13, + 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 0, 26, 27, 28, 29, 30, 0, 0, 33, + 34, 0, 0, 0, 0, 0, 124, 0, 0, 0, + 125, 0, 0, 0, 0, 0, 126, 0, 65, 7, 8, 9, 10, 11, 12, 13, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 26, 27, - 28, 29, 30, 0, 0, 33, 0, 0, 0, 0, - 178, 0, 0, 0, 0, 34, 7, 8, 9, 10, - 11, 12, 13, 0, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 0, 26, 27, 28, 29, 30, - 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 34 + 28, 29, 30, 0, 0, 33, 34, 0, 0, 0, + 0, 181, 0, 0, 0, 0, 35, 7, 8, 9, + 10, 11, 12, 13, 0, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 0, 26, 27, 28, 29, + 30, 0, 0, 33, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 35 }; #define yypact_value_is_default(yystate) \ - ((yystate) == (-135)) + ((yystate) == (-140)) #define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int16 yycheck[] = { - 59, 38, 79, 3, 1, 8, 56, 37, 26, 37, - 64, 31, 1, 147, 37, 18, 30, 1, 32, 109, - 0, 111, 45, 51, 27, 23, 76, 44, 31, 51, - 50, 37, 109, 63, 111, 53, 33, 91, 68, 57, - 37, 100, 47, 177, 41, 51, 37, 33, 37, 86, - 47, 48, 49, 37, 131, 37, 56, 41, 47, 48, - 51, 47, 47, 47, 48, 47, 48, 33, 37, 37, - 51, 33, 149, 41, 44, 45, 76, 44, 45, 47, - 48, 47, 159, 160, 52, 47, 37, 37, 147, 37, - 41, 45, 46, 41, 131, 44, 47, 48, 50, 47, - 48, 159, 160, 46, 45, 49, 165, 1, 34, 49, - 49, 5, 6, 7, 8, 9, 10, 11, 177, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 52, - 24, 25, 26, 27, 28, 34, 44, 31, 44, 46, - 30, 44, 31, 37, 49, 49, 46, 41, 49, 36, - 44, 45, 49, 47, 48, 1, 49, 34, 52, 5, - 6, 7, 8, 9, 10, 11, 49, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 49, 24, 25, - 26, 27, 28, 49, 49, 31, 49, 49, 1, 165, - 81, 37, 94, 149, 107, 41, 112, 49, 44, 45, - -1, 47, 48, 1, -1, 103, 52, 5, 6, 7, - 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, -1, 24, 25, 26, 27, - 28, -1, -1, 31, -1, -1, -1, -1, 36, -1, - 1, -1, -1, 41, 5, 6, 7, 8, 9, 10, - 11, 49, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, -1, 24, 25, 26, 27, 28, -1, -1, - 31, -1, -1, -1, -1, 36, -1, 1, -1, -1, - 41, 5, 6, 7, 8, 9, 10, 11, 49, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, -1, - 24, 25, 26, 27, 28, -1, -1, 31, -1, -1, - -1, -1, 36, -1, -1, -1, -1, 41, -1, -1, - -1, -1, 1, -1, -1, 49, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, -1, -1, -1, -1, -1, 37, -1, - -1, -1, 41, -1, -1, 44, -1, -1, 47, 48, - 5, 6, 7, 8, 9, 10, 11, -1, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, -1, 24, - 25, 26, 27, 28, -1, -1, 31, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, - -1, -1, -1, 48, 49, 5, 6, 7, 8, 9, - 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, -1, 24, 25, 26, 27, 28, -1, - -1, 31, -1, -1, -1, -1, -1, 37, -1, -1, - -1, 41, -1, -1, -1, -1, -1, 47, 48, 5, + 60, 60, 80, 1, 3, 8, 1, 31, 39, 87, + 65, 38, 57, 26, 153, 18, 38, 1, 38, 111, + 38, 113, 161, 34, 27, 52, 46, 51, 31, 0, + 52, 38, 77, 111, 52, 113, 34, 48, 93, 48, + 38, 54, 102, 38, 42, 58, 34, 42, 126, 127, + 48, 49, 50, 48, 38, 50, 87, 64, 57, 38, + 48, 34, 69, 42, 48, 30, 50, 23, 33, 48, + 48, 50, 38, 45, 53, 48, 42, 155, 77, 38, + 38, 38, 48, 42, 50, 45, 46, 126, 127, 48, + 48, 50, 50, 153, 46, 47, 45, 46, 52, 52, + 38, 161, 45, 47, 51, 46, 35, 49, 1, 49, + 170, 170, 5, 6, 7, 8, 9, 10, 11, 49, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 49, 24, 25, 26, 27, 28, 53, 35, 31, 32, + 45, 47, 45, 30, 45, 38, 37, 49, 31, 42, + 49, 47, 45, 46, 49, 48, 35, 50, 1, 49, + 53, 49, 5, 6, 7, 8, 9, 10, 11, 49, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 49, 24, 25, 26, 27, 28, 49, 49, 31, 32, + 49, 1, 96, 82, 155, 38, 109, 50, 114, 42, + -1, -1, 45, 46, -1, 48, -1, 50, 1, -1, + 53, 105, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + -1, -1, -1, -1, -1, 38, -1, -1, -1, 42, + -1, -1, 45, -1, 1, 48, -1, 50, 5, 6, + 7, 8, 9, 10, 11, -1, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, -1, 24, 25, 26, + 27, 28, -1, -1, 31, 32, -1, -1, -1, -1, + 37, -1, -1, -1, -1, 42, -1, -1, -1, 1, + -1, -1, 49, 5, 6, 7, 8, 9, 10, 11, + -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, -1, 24, 25, 26, 27, 28, -1, -1, 31, + 32, -1, -1, -1, -1, 37, -1, -1, -1, -1, + 42, -1, -1, -1, 1, -1, -1, 49, 5, 6, + 7, 8, 9, 10, 11, -1, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, -1, 24, 25, 26, + 27, 28, -1, -1, 31, 32, -1, -1, -1, -1, + 37, -1, -1, -1, -1, 42, -1, -1, -1, -1, + -1, -1, 49, 5, 6, 7, 8, 9, 10, 11, + -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, -1, 24, 25, 26, 27, 28, -1, -1, 31, + 32, -1, -1, -1, -1, -1, 38, -1, -1, -1, + 42, -1, -1, -1, -1, -1, 48, -1, 50, 5, 6, 7, 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -1, 24, 25, - 26, 27, 28, -1, -1, 31, -1, -1, -1, -1, - 36, -1, -1, -1, -1, 41, 5, 6, 7, 8, - 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, -1, 24, 25, 26, 27, 28, - -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 41 + 26, 27, 28, -1, -1, 31, 32, -1, -1, -1, + -1, 37, -1, -1, -1, -1, 42, 5, 6, 7, + 8, 9, 10, 11, -1, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, -1, 24, 25, 26, 27, + 28, -1, -1, 31, 32, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 42 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 54, 55, 56, 0, 55, 1, 5, 6, 7, + 0, 55, 56, 57, 0, 56, 1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 41, 57, 60, 64, 65, 66, - 67, 68, 69, 73, 84, 99, 101, 44, 45, 37, - 51, 96, 23, 37, 51, 87, 59, 37, 87, 47, - 47, 44, 37, 47, 48, 61, 62, 63, 70, 74, - 75, 66, 96, 37, 97, 98, 58, 87, 1, 64, - 88, 89, 90, 60, 64, 87, 65, 37, 1, 74, - 71, 72, 73, 44, 46, 74, 30, 32, 100, 33, - 47, 50, 45, 46, 60, 44, 45, 37, 41, 47, - 52, 70, 76, 77, 91, 92, 93, 94, 45, 1, - 90, 74, 48, 49, 49, 49, 49, 73, 63, 95, - 1, 65, 78, 79, 80, 81, 34, 45, 98, 94, - 1, 37, 76, 34, 76, 95, 33, 47, 44, 46, - 49, 44, 31, 50, 85, 86, 49, 37, 41, 47, - 70, 82, 83, 49, 36, 46, 49, 49, 1, 78, - 93, 34, 1, 41, 82, 82, 33, 47, 36, 81, - 49, 49, 49, 49, 1, 78, 49, 49 + 28, 29, 30, 31, 32, 42, 58, 61, 65, 66, + 67, 68, 69, 70, 74, 85, 100, 102, 45, 46, + 38, 52, 97, 23, 38, 52, 88, 60, 38, 88, + 48, 48, 45, 38, 48, 50, 62, 63, 64, 71, + 75, 76, 67, 97, 38, 98, 99, 59, 88, 1, + 65, 89, 90, 91, 61, 65, 88, 66, 82, 38, + 1, 75, 72, 73, 74, 45, 47, 75, 30, 33, + 101, 34, 48, 51, 46, 47, 61, 45, 46, 38, + 42, 48, 53, 71, 77, 78, 92, 93, 94, 95, + 46, 1, 91, 75, 38, 42, 48, 71, 83, 84, + 49, 49, 49, 49, 74, 64, 96, 1, 79, 80, + 81, 82, 35, 46, 99, 95, 1, 38, 77, 35, + 77, 96, 34, 48, 45, 47, 1, 42, 83, 83, + 34, 48, 45, 31, 51, 86, 87, 49, 49, 37, + 47, 49, 49, 1, 79, 94, 49, 49, 1, 79, + 35, 37, 82, 49, 49, 49, 49 }; #define yyerrok (yyerrstatus = 0) @@ -890,17 +895,18 @@ static const yytype_uint8 yystos[] = #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ @@ -995,6 +1001,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) YYSTYPE const * const yyvaluep; #endif { + FILE *yyo = yyoutput; + YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT @@ -1246,12 +1254,12 @@ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ - const char *yyformat = 0; + const char *yyformat = YY_NULL; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per @@ -1311,7 +1319,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, break; } yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; @@ -1463,7 +1471,7 @@ yyparse () `yyss': related to states. `yyvs': related to semantic values. - Refer to the stacks thru separate pointers, to allow yyoverflow + Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ @@ -2346,7 +2354,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ diff --git a/scripts/genksyms/parse.tab.h_shipped b/scripts/genksyms/parse.tab.h_shipped index 93240a3cdec..a4737dec453 100644 --- a/scripts/genksyms/parse.tab.h_shipped +++ b/scripts/genksyms/parse.tab.h_shipped @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.5. */ +/* A Bison parser, made by GNU Bison 2.5.1. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. 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 @@ -66,18 +66,19 @@ EXPORT_SYMBOL_KEYW = 284, ASM_PHRASE = 285, ATTRIBUTE_PHRASE = 286, - BRACE_PHRASE = 287, - BRACKET_PHRASE = 288, - EXPRESSION_PHRASE = 289, - CHAR = 290, - DOTS = 291, - IDENT = 292, - INT = 293, - REAL = 294, - STRING = 295, - TYPE = 296, - OTHER = 297, - FILENAME = 298 + TYPEOF_PHRASE = 287, + BRACE_PHRASE = 288, + BRACKET_PHRASE = 289, + EXPRESSION_PHRASE = 290, + CHAR = 291, + DOTS = 292, + IDENT = 293, + INT = 294, + REAL = 295, + STRING = 296, + TYPE = 297, + OTHER = 298, + FILENAME = 299 }; #endif diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y index 23c39998ad8..b9f4cf20230 100644 --- a/scripts/genksyms/parse.y +++ b/scripts/genksyms/parse.y @@ -103,6 +103,7 @@ static void record_compound(struct string_list **keyw, %token ASM_PHRASE %token ATTRIBUTE_PHRASE +%token TYPEOF_PHRASE %token BRACE_PHRASE %token BRACKET_PHRASE %token EXPRESSION_PHRASE @@ -220,8 +221,8 @@ storage_class_specifier: type_specifier: simple_type_specifier | cvar_qualifier - | TYPEOF_KEYW '(' decl_specifier_seq '*' ')' - | TYPEOF_KEYW '(' decl_specifier_seq ')' + | TYPEOF_KEYW '(' parameter_declaration ')' + | TYPEOF_PHRASE /* References to s/u/e's defined elsewhere. Rearrange things so that it is easier to expand the definition fully later. */ diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index f32a04c4c5b..41987885bd3 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -83,6 +83,8 @@ push(@signature_tags, "Signed-off-by:"); push(@signature_tags, "Reviewed-by:"); push(@signature_tags, "Acked-by:"); +my $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; + # rfc822 email address - preloaded methods go here. my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])"; my $rfc822_char = '[\\000-\\377]'; @@ -93,9 +95,10 @@ my %VCS_cmds; my %VCS_cmds_git = ( "execute_cmd" => \&git_execute_cmd, - "available" => '(which("git") ne "") && (-d ".git")', + "available" => '(which("git") ne "") && (-e ".git")', "find_signers_cmd" => "git log --no-color --follow --since=\$email_git_since " . + '--numstat --no-merges ' . '--format="GitCommit: %H%n' . 'GitAuthor: %an <%ae>%n' . 'GitDate: %aD%n' . @@ -104,6 +107,7 @@ my %VCS_cmds_git = ( " -- \$file", "find_commit_signers_cmd" => "git log --no-color " . + '--numstat ' . '--format="GitCommit: %H%n' . 'GitAuthor: %an <%ae>%n' . 'GitDate: %aD%n' . @@ -112,6 +116,7 @@ my %VCS_cmds_git = ( " -1 \$commit", "find_commit_author_cmd" => "git log --no-color " . + '--numstat ' . '--format="GitCommit: %H%n' . 'GitAuthor: %an <%ae>%n' . 'GitDate: %aD%n' . @@ -123,6 +128,7 @@ my %VCS_cmds_git = ( "blame_commit_pattern" => "^([0-9a-f]+) ", "author_pattern" => "^GitAuthor: (.*)", "subject_pattern" => "^GitSubject: (.*)", + "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$", ); my %VCS_cmds_hg = ( @@ -150,6 +156,7 @@ my %VCS_cmds_hg = ( "blame_commit_pattern" => "^([ 0-9a-f]+):", "author_pattern" => "^HgAuthor: (.*)", "subject_pattern" => "^HgSubject: (.*)", + "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$", ); my $conf = which_conf(".get_maintainer.conf"); @@ -431,7 +438,7 @@ foreach my $file (@ARGV) { while (<$patch>) { my $patch_line = $_; - if (m/^\+\+\+\s+(\S+)/) { + if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) { my $filename = $1; $filename =~ s@^[^/]*/@@; $filename =~ s@\n@@; @@ -473,7 +480,6 @@ my @subsystem = (); my @status = (); my %deduplicate_name_hash = (); my %deduplicate_address_hash = (); -my $signature_pattern; my @maintainers = get_maintainers(); @@ -610,6 +616,10 @@ sub get_maintainers { $hash{$tvi} = $value_pd; } } + } elsif ($type eq 'N') { + if ($file =~ m/$value/x) { + $hash{$tvi} = 0; + } } } } @@ -931,7 +941,7 @@ sub get_maintainer_role { my $start = find_starting_index($index); my $end = find_ending_index($index); - my $role; + my $role = "unknown"; my $subsystem = $typevalue[$start]; if (length($subsystem) > 20) { $subsystem = substr($subsystem, 0, 17); @@ -1027,8 +1037,13 @@ sub add_categories { if ($email_list) { if (!$hash_list_to{lc($list_address)}) { $hash_list_to{lc($list_address)} = 1; - push(@list_to, [$list_address, - "open list${list_role}"]); + if ($list_additional =~ m/moderated/) { + push(@list_to, [$list_address, + "moderated list${list_role}"]); + } else { + push(@list_to, [$list_address, + "open list${list_role}"]); + } } } } @@ -1259,20 +1274,30 @@ sub extract_formatted_signatures { } sub vcs_find_signers { - my ($cmd) = @_; + my ($cmd, $file) = @_; my $commits; my @lines = (); my @signatures = (); + my @authors = (); + my @stats = (); @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); my $pattern = $VCS_cmds{"commit_pattern"}; + my $author_pattern = $VCS_cmds{"author_pattern"}; + my $stat_pattern = $VCS_cmds{"stat_pattern"}; + + $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern $commits = grep(/$pattern/, @lines); # of commits + @authors = grep(/$author_pattern/, @lines); @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines); + @stats = grep(/$stat_pattern/, @lines); + +# print("stats: <@stats>\n"); - return (0, @signatures) if !@signatures; + return (0, \@signatures, \@authors, \@stats) if !@signatures; save_commits_by_author(@lines) if ($interactive); save_commits_by_signer(@lines) if ($interactive); @@ -1281,9 +1306,10 @@ sub vcs_find_signers { @signatures = grep(!/${penguin_chiefs}/i, @signatures); } + my ($author_ref, $authors_ref) = extract_formatted_signatures(@authors); my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); - return ($commits, @$signers_ref); + return ($commits, $signers_ref, $authors_ref, \@stats); } sub vcs_find_author { @@ -1839,7 +1865,12 @@ sub vcs_assign { sub vcs_file_signoffs { my ($file) = @_; + my $authors_ref; + my $signers_ref; + my $stats_ref; + my @authors = (); my @signers = (); + my @stats = (); my $commits; $vcs_used = vcs_exists(); @@ -1848,13 +1879,59 @@ sub vcs_file_signoffs { my $cmd = $VCS_cmds{"find_signers_cmd"}; $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd - ($commits, @signers) = vcs_find_signers($cmd); + ($commits, $signers_ref, $authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); + + @signers = @{$signers_ref} if defined $signers_ref; + @authors = @{$authors_ref} if defined $authors_ref; + @stats = @{$stats_ref} if defined $stats_ref; + +# print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n"); foreach my $signer (@signers) { $signer = deduplicate_email($signer); } vcs_assign("commit_signer", $commits, @signers); + vcs_assign("authored", $commits, @authors); + if ($#authors == $#stats) { + my $stat_pattern = $VCS_cmds{"stat_pattern"}; + $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern + + my $added = 0; + my $deleted = 0; + for (my $i = 0; $i <= $#stats; $i++) { + if ($stats[$i] =~ /$stat_pattern/) { + $added += $1; + $deleted += $2; + } + } + my @tmp_authors = uniq(@authors); + foreach my $author (@tmp_authors) { + $author = deduplicate_email($author); + } + @tmp_authors = uniq(@tmp_authors); + my @list_added = (); + my @list_deleted = (); + foreach my $author (@tmp_authors) { + my $auth_added = 0; + my $auth_deleted = 0; + for (my $i = 0; $i <= $#stats; $i++) { + if ($author eq deduplicate_email($authors[$i]) && + $stats[$i] =~ /$stat_pattern/) { + $auth_added += $1; + $auth_deleted += $2; + } + } + for (my $i = 0; $i < $auth_added; $i++) { + push(@list_added, $author); + } + for (my $i = 0; $i < $auth_deleted; $i++) { + push(@list_deleted, $author); + } + } + vcs_assign("added_lines", $added, @list_added); + vcs_assign("removed_lines", $deleted, @list_deleted); + } } sub vcs_file_blame { @@ -1877,6 +1954,10 @@ sub vcs_file_blame { if ($email_git_blame_signatures) { if (vcs_is_hg()) { my $commit_count; + my $commit_authors_ref; + my $commit_signers_ref; + my $stats_ref; + my @commit_authors = (); my @commit_signers = (); my $commit = join(" -r ", @commits); my $cmd; @@ -1884,19 +1965,27 @@ sub vcs_file_blame { $cmd = $VCS_cmds{"find_commit_signers_cmd"}; $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd - ($commit_count, @commit_signers) = vcs_find_signers($cmd); + ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); + @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; + @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; push(@signers, @commit_signers); } else { foreach my $commit (@commits) { my $commit_count; + my $commit_authors_ref; + my $commit_signers_ref; + my $stats_ref; + my @commit_authors = (); my @commit_signers = (); my $cmd; $cmd = $VCS_cmds{"find_commit_signers_cmd"}; $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd - ($commit_count, @commit_signers) = vcs_find_signers($cmd); + ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); + @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; + @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; push(@signers, @commit_signers); } diff --git a/scripts/gfp-translate b/scripts/gfp-translate index c9230e158a8..c9230e158a8 100644..100755 --- a/scripts/gfp-translate +++ b/scripts/gfp-translate diff --git a/scripts/headers.sh b/scripts/headers.sh index 978b42b3acd..95ece06599a 100755 --- a/scripts/headers.sh +++ b/scripts/headers.sh @@ -28,5 +28,3 @@ for arch in ${archs}; do ;; esac done - - diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index 7957e7a5166..62320f93e90 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -19,6 +19,7 @@ # 3) Check for leaked CONFIG_ symbols use strict; +use File::Basename; my ($dir, $arch, @files) = @ARGV; @@ -64,7 +65,11 @@ sub check_include sub check_declarations { - if ($line =~m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { + # soundcard.h is what it is + if ($line =~ m/^void seqbuf_dump\(void\);/) { + return; + } + if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { printf STDERR "$filename:$lineno: " . "userspace cannot reference function or " . "variable defined in the kernel\n"; @@ -99,6 +104,39 @@ sub check_asm_types } my $linux_types; +my %import_stack = (); +sub check_include_typesh +{ + my $path = $_[0]; + my $import_path; + + my $fh; + my @file_paths = ($path, $dir . "/" . $path, dirname($filename) . "/" . $path); + for my $possible ( @file_paths ) { + if (not $import_stack{$possible} and open($fh, '<', $possible)) { + $import_path = $possible; + $import_stack{$import_path} = 1; + last; + } + } + if (eof $fh) { + return; + } + + my $line; + while ($line = <$fh>) { + if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { + $linux_types = 1; + last; + } + if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { + check_include_typesh($included); + } + } + close $fh; + delete $import_stack{$import_path}; +} + sub check_sizetypes { if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { @@ -113,6 +151,9 @@ sub check_sizetypes $linux_types = 1; return; } + if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { + check_include_typesh($included); + } if ($line =~ m/__[us](8|16|32|64)\b/) { printf STDERR "$filename:$lineno: " . "found __[us]{8,16,32,64} type " . @@ -122,4 +163,3 @@ sub check_sizetypes #$ret = 1; } } - diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl deleted file mode 100644 index 48462be328b..00000000000 --- a/scripts/headers_install.pl +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/perl -w -# -# headers_install prepare the listed header files for use in -# user space and copy the files to their destination. -# -# Usage: headers_install.pl readdir installdir arch [files...] -# readdir: dir to open files -# installdir: dir to install the files -# arch: current architecture -# arch is used to force a reinstallation when the arch -# changes because kbuild then detect a command line change. -# files: list of files to check -# -# Step in preparation for users space: -# 1) Drop all use of compiler.h definitions -# 2) Drop include of compiler.h -# 3) Drop all sections defined out by __KERNEL__ (using unifdef) - -use strict; - -my ($readdir, $installdir, $arch, @files) = @ARGV; - -my $unifdef = "scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__"; - -foreach my $file (@files) { - my $tmpfile = "$installdir/$file.tmp"; - - open(my $in, '<', "$readdir/$file") - or die "$readdir/$file: $!\n"; - open(my $out, '>', $tmpfile) - or die "$tmpfile: $!\n"; - while (my $line = <$in>) { - $line =~ s/([\s(])__user\s/$1/g; - $line =~ s/([\s(])__force\s/$1/g; - $line =~ s/([\s(])__iomem\s/$1/g; - $line =~ s/\s__attribute_const__\s/ /g; - $line =~ s/\s__attribute_const__$//g; - $line =~ s/\b__packed\b/__attribute__((packed))/g; - $line =~ s/^#include <linux\/compiler.h>//; - $line =~ s/(^|\s)(inline)\b/$1__$2__/g; - $line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g; - $line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g; - printf {$out} "%s", $line; - } - close $out; - close $in; - - system $unifdef . " $tmpfile > $installdir/$file"; - # unifdef will exit 0 on success, and will exit 1 when the - # file was processed successfully but no changes were made, - # so abort only when it's higher than that. - my $e = $? >> 8; - if ($e > 1) { - die "$tmpfile: $!\n"; - } - unlink $tmpfile; -} -exit 0; diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh new file mode 100644 index 00000000000..5de5660cb70 --- /dev/null +++ b/scripts/headers_install.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ $# -lt 1 ] +then + echo "Usage: headers_install.sh OUTDIR SRCDIR [FILES...] + echo + echo "Prepares kernel header files for use by user space, by removing" + echo "all compiler.h definitions and #includes, removing any" + echo "#ifdef __KERNEL__ sections, and putting __underscores__ around" + echo "asm/inline/volatile keywords." + echo + echo "OUTDIR: directory to write each userspace header FILE to." + echo "SRCDIR: source directory where files are picked." + echo "FILES: list of header files to operate on." + + exit 1 +fi + +# Grab arguments + +OUTDIR="$1" +shift +SRCDIR="$1" +shift + +# Iterate through files listed on command line + +FILE= +trap 'rm -f "$OUTDIR/$FILE" "$OUTDIR/$FILE.sed"' EXIT +for i in "$@" +do + FILE="$(basename "$i")" + sed -r \ + -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \ + -e 's/__attribute_const__([ \t]|$)/\1/g' \ + -e 's@^#include <linux/compiler.h>@@' \ + -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \ + -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \ + -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \ + "$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1 + scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ "$OUTDIR/$FILE.sed" \ + > "$OUTDIR/$FILE" + [ $? -gt 1 ] && exit 1 + rm -f "$OUTDIR/$FILE.sed" +done +trap - EXIT diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 487ac6f37ca..dc7aa45e80c 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -36,13 +36,13 @@ struct sym_entry { unsigned char *sym; }; -struct text_range { - const char *stext, *etext; +struct addr_range { + const char *start_sym, *end_sym; unsigned long long start, end; }; static unsigned long long _text; -static struct text_range text_ranges[] = { +static struct addr_range text_ranges[] = { { "_stext", "_etext" }, { "_sinittext", "_einittext" }, { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */ @@ -51,10 +51,16 @@ static struct text_range text_ranges[] = { #define text_range_text (&text_ranges[0]) #define text_range_inittext (&text_ranges[1]) +static struct addr_range percpu_range = { + "__per_cpu_start", "__per_cpu_end", -1ULL, 0 +}; + 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 unsigned long long kernel_start_addr = 0; int token_profit[0x10000]; @@ -65,7 +71,10 @@ unsigned char best_table_len[256]; static void usage(void) { - fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n"); + fprintf(stderr, "Usage: kallsyms [--all-symbols] " + "[--symbol-prefix=<prefix char>] " + "[--page-offset=<CONFIG_PAGE_OFFSET>] " + "< in.map > out.S\n"); exit(1); } @@ -79,19 +88,20 @@ static inline int is_arm_mapping_symbol(const char *str) && (str[2] == '\0' || str[2] == '.'); } -static int read_symbol_tr(const char *sym, unsigned long long addr) +static int check_symbol_range(const char *sym, unsigned long long addr, + struct addr_range *ranges, int entries) { size_t i; - struct text_range *tr; + struct addr_range *ar; - for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) { - tr = &text_ranges[i]; + for (i = 0; i < entries; ++i) { + ar = &ranges[i]; - if (strcmp(sym, tr->stext) == 0) { - tr->start = addr; + if (strcmp(sym, ar->start_sym) == 0) { + ar->start = addr; return 0; - } else if (strcmp(sym, tr->etext) == 0) { - tr->end = addr; + } else if (strcmp(sym, ar->end_sym) == 0) { + ar->end = addr; return 0; } } @@ -111,6 +121,12 @@ static int read_symbol(FILE *in, struct sym_entry *s) fprintf(stderr, "Read error or end of file.\n"); return -1; } + if (strlen(str) > 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); + return -1; + } sym = str; /* skip prefix char */ @@ -120,7 +136,8 @@ static int read_symbol(FILE *in, struct sym_entry *s) /* Ignore most absolute/undefined (?) symbols. */ if (strcmp(sym, "_text") == 0) _text = s->addr; - else if (read_symbol_tr(sym, s->addr) == 0) + else if (check_symbol_range(sym, s->addr, text_ranges, + ARRAY_SIZE(text_ranges)) == 0) /* nothing to do */; else if (toupper(stype) == 'A') { @@ -154,18 +171,22 @@ static int read_symbol(FILE *in, struct sym_entry *s) strcpy((char *)s->sym + 1, str); s->sym[0] = stype; + /* Record if we've found __per_cpu_start/end. */ + check_symbol_range(sym, s->addr, &percpu_range, 1); + return 0; } -static int symbol_valid_tr(struct sym_entry *s) +static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges, + int entries) { size_t i; - struct text_range *tr; + struct addr_range *ar; - for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) { - tr = &text_ranges[i]; + for (i = 0; i < entries; ++i) { + ar = &ranges[i]; - if (s->addr >= tr->start && s->addr <= tr->end) + if (s->addr >= ar->start && s->addr <= ar->end) return 1; } @@ -194,6 +215,9 @@ static int symbol_valid(struct sym_entry *s) int i; int offset = 1; + if (s->addr < kernel_start_addr) + return 0; + /* skip prefix char */ if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char) offset++; @@ -201,7 +225,8 @@ static int symbol_valid(struct sym_entry *s) /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { - if (symbol_valid_tr(s) == 0) + if (symbol_in_range(s, text_ranges, + ARRAY_SIZE(text_ranges)) == 0) return 0; /* Corner case. Discard any symbols with the same value as * _etext _einittext; they can move between pass 1 and 2 when @@ -210,9 +235,11 @@ static int symbol_valid(struct sym_entry *s) * rules. */ if ((s->addr == text_range_text->end && - strcmp((char *)s->sym + offset, text_range_text->etext)) || + strcmp((char *)s->sym + offset, + text_range_text->end_sym)) || (s->addr == text_range_inittext->end && - strcmp((char *)s->sym + offset, text_range_inittext->etext))) + strcmp((char *)s->sym + offset, + text_range_inittext->end_sym))) return 0; } @@ -285,6 +312,11 @@ static int expand_symbol(unsigned char *data, int len, char *result) return total; } +static int symbol_absolute(struct sym_entry *s) +{ + return toupper(s->sym[0]) == 'A'; +} + static void write_src(void) { unsigned int i, k, off; @@ -312,7 +344,7 @@ static void write_src(void) */ output_label("kallsyms_addresses"); for (i = 0; i < table_cnt; i++) { - if (toupper(table[i].sym[0]) != 'A') { + if (!symbol_absolute(&table[i])) { if (_text <= table[i].addr) printf("\tPTR\t_text + %#llx\n", table[i].addr - _text); @@ -633,6 +665,15 @@ static void sort_symbols(void) qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); } +static void make_percpus_absolute(void) +{ + unsigned int i; + + for (i = 0; i < table_cnt; i++) + if (symbol_in_range(&table[i], &percpu_range, 1)) + table[i].sym[0] = 'A'; +} + int main(int argc, char **argv) { if (argc >= 2) { @@ -640,12 +681,17 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { if(strcmp(argv[i], "--all-symbols") == 0) all_symbols = 1; + else if (strcmp(argv[i], "--absolute-percpu") == 0) + absolute_percpu = 1; else if (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 (strncmp(argv[i], "--page-offset=", 14) == 0) { + const char *p = &argv[i][14]; + kernel_start_addr = strtoull(p, NULL, 16); } else usage(); } @@ -653,6 +699,8 @@ int main(int argc, char **argv) usage(); read_map(stdin); + if (absolute_percpu) + make_percpus_absolute(); sort_symbols(); optimize_token_table(); write_src(); diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore index ee120d44156..be603c4fef6 100644 --- a/scripts/kconfig/.gitignore +++ b/scripts/kconfig/.gitignore @@ -7,7 +7,6 @@ config* *.tab.h zconf.hash.c *.moc -lkc_defs.h gconf.glade.h *.pot *.mo diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 79662658fb9..9c4d2412fb7 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -11,6 +11,9 @@ else Kconfig := Kconfig endif +# We need this, in case the user has it in its environment +unexport CONFIG_ + xconfig: $(obj)/qconf $< $(Kconfig) @@ -30,11 +33,11 @@ oldconfig: $(obj)/conf $< --$@ $(Kconfig) silentoldconfig: $(obj)/conf - $(Q)mkdir -p include/generated + $(Q)mkdir -p include/config include/generated $< --$@ $(Kconfig) localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf - $(Q)mkdir -p include/generated + $(Q)mkdir -p include/config include/generated $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ @@ -76,11 +79,17 @@ PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf $< --$@ $(Kconfig) -PHONY += listnewconfig oldnoconfig savedefconfig defconfig +PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig -listnewconfig oldnoconfig: $(obj)/conf +listnewconfig olddefconfig: $(obj)/conf $< --$@ $(Kconfig) +# 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: $(obj)/conf + $< --olddefconfig $(Kconfig) + savedefconfig: $(obj)/conf $< --$@=defconfig $(Kconfig) @@ -114,7 +123,7 @@ help: @echo ' alldefconfig - New config with all symbols set to default' @echo ' randconfig - New config with random answer to all options' @echo ' listnewconfig - List new options' - @echo ' oldnoconfig - Same as silentoldconfig but set new symbols to n (unset)' + @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' # lxdialog stuff check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh @@ -210,7 +219,9 @@ HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) -HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses +HOSTLOADLIBES_nconf = $(shell \ + pkg-config --libs menu panel ncurses 2>/dev/null \ + || echo "-lmenu -lpanel -lncurses" ) $(obj)/qconf.o: $(obj)/.tmp_qtcheck ifeq ($(qconf-target),1) @@ -234,12 +245,12 @@ $(obj)/.tmp_qtcheck: if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \ done; \ if [ -z "$$dir" ]; then \ - echo "*"; \ - echo "* Unable to find any QT installation. Please make sure that"; \ - echo "* the QT4 or QT3 development package is correctly installed and"; \ - echo "* either qmake can be found or install pkg-config or set"; \ - echo "* the QTDIR environment variable to the correct location."; \ - echo "*"; \ + echo >&2 "*"; \ + echo >&2 "* Unable to find any QT installation. Please make sure that"; \ + echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \ + echo >&2 "* either qmake can be found or install pkg-config or set"; \ + echo >&2 "* the QTDIR environment variable to the correct location."; \ + echo >&2 "*"; \ false; \ fi; \ libpath=$$dir/lib; lib=qt; osdir=""; \ @@ -260,8 +271,8 @@ $(obj)/.tmp_qtcheck: else \ cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \ libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \ - binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \ - moc="$$binpath/bin/moc"; \ + moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \ + [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \ fi; \ echo "KC_QT_CFLAGS=$$cflags" > $@; \ echo "KC_QT_LIBS=$$libs" >> $@; \ @@ -279,17 +290,17 @@ $(obj)/.tmp_gtkcheck: if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ touch $@; \ else \ - echo "*"; \ - echo "* GTK+ is present but version >= 2.0.0 is required."; \ - echo "*"; \ + echo >&2 "*"; \ + echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ + echo >&2 "*"; \ false; \ fi \ else \ - echo "*"; \ - echo "* Unable to find the GTK+ installation. Please make sure that"; \ - echo "* the GTK+ 2.0 development package is correctly installed..."; \ - echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ - echo "*"; \ + 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 @@ -298,11 +309,13 @@ $(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c $(obj)/qconf.o: $(obj)/qconf.moc -$(obj)/%.moc: $(src)/%.h - $(KC_QT_MOC) -i $< -o $@ +quiet_cmd_moc = MOC $@ + cmd_moc = $(KC_QT_MOC) -i $< -o $@ + +$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck + $(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 - diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh index fa59cbf9d62..55b79ba1ba2 100755 --- a/scripts/kconfig/check.sh +++ b/scripts/kconfig/check.sh @@ -1,6 +1,6 @@ #!/bin/sh # Needed for systems without gettext -$* -xc -o /dev/null - > /dev/null 2>&1 << EOF +$* -x c -o /dev/null - > /dev/null 2>&1 << EOF #include <libintl.h> int main() { @@ -11,4 +11,3 @@ EOF if [ ! "$?" -eq "0" ]; then echo -DKBUILD_NO_NLS; fi - diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index f208f900ed3..fef75fc756f 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -13,6 +13,7 @@ #include <getopt.h> #include <sys/stat.h> #include <sys/time.h> +#include <errno.h> #include "lkc.h" @@ -32,10 +33,11 @@ enum input_mode { defconfig, savedefconfig, listnewconfig, - oldnoconfig, + olddefconfig, } input_mode = oldaskconfig; static int indent = 1; +static int tty_stdio; static int valid_stdin = 1; static int sync_kconfig; static int conf_cnt; @@ -108,6 +110,8 @@ static int conf_askvalue(struct symbol *sym, const char *def) case oldaskconfig: fflush(stdout); xfgets(line, 128, stdin); + if (!tty_stdio) + printf("\n"); return 1; default: break; @@ -365,7 +369,7 @@ static void conf(struct menu *menu) case P_MENU: if ((input_mode == silentoldconfig || input_mode == listnewconfig || - input_mode == oldnoconfig) && + input_mode == olddefconfig) && rootEntry != menu) { check_conf(menu); return; @@ -429,7 +433,7 @@ static void check_conf(struct menu *menu) if (sym->name && !sym_is_choice_value(sym)) { printf("%s%s\n", CONFIG_, sym->name); } - } else if (input_mode != oldnoconfig) { + } else if (input_mode != olddefconfig) { if (!conf_cnt++) printf(_("*\n* Restart config...\n*\n")); rootEntry = menu_get_parent_menu(menu); @@ -454,7 +458,13 @@ static struct option long_opts[] = { {"alldefconfig", no_argument, NULL, alldefconfig}, {"randconfig", no_argument, NULL, randconfig}, {"listnewconfig", no_argument, NULL, listnewconfig}, - {"oldnoconfig", no_argument, NULL, oldnoconfig}, + {"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} }; @@ -467,7 +477,8 @@ static void conf_usage(const char *progname) printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); printf(" --oldconfig Update a configuration using a provided .config as base\n"); printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); - printf(" --oldnoconfig Same as silentoldconfig but set new symbols to no\n"); + printf(" --olddefconfig Same as silentoldconfig 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"); @@ -488,6 +499,8 @@ int main(int ac, char **av) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); + tty_stdio = isatty(0) && isatty(1) && isatty(2); + while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { input_mode = (enum input_mode)opt; switch (opt) { @@ -502,14 +515,24 @@ int main(int ac, char **av) { struct timeval now; unsigned int seed; + char *seed_env; /* * Use microseconds derived seed, * compensate for systems where it may be zero */ gettimeofday(&now, NULL); - seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + + seed_env = getenv("KCONFIG_SEED"); + if( seed_env && *seed_env ) { + char *endp; + int tmp = (int)strtol(seed_env, &endp, 0); + if (*endp == '\0') { + seed = tmp; + } + } + fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); srand(seed); break; } @@ -520,7 +543,7 @@ int main(int ac, char **av) case allmodconfig: case alldefconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: break; case '?': conf_usage(progname); @@ -565,7 +588,7 @@ int main(int ac, char **av) case oldaskconfig: case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: conf_read(NULL); break; case allnoconfig: @@ -574,8 +597,15 @@ int main(int ac, char **av) case alldefconfig: case randconfig: name = getenv("KCONFIG_ALLCONFIG"); - if (name && !stat(name, &tmpstat)) { - conf_read_simple(name, S_DEF_USER); + if (!name) + break; + 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"), + name); + exit(1); + } break; } switch (input_mode) { @@ -586,10 +616,13 @@ int main(int ac, char **av) case randconfig: name = "allrandom.config"; break; default: break; } - if (!stat(name, &tmpstat)) - conf_read_simple(name, S_DEF_USER); - else if (!stat("all.config", &tmpstat)) - conf_read_simple("all.config", S_DEF_USER); + 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"), + name); + exit(1); + } break; default: break; @@ -604,7 +637,7 @@ int main(int ac, char **av) return 1; } } - valid_stdin = isatty(0) && isatty(1) && isatty(2); + valid_stdin = tty_stdio; } switch (input_mode) { @@ -621,7 +654,8 @@ int main(int ac, char **av) conf_set_all_new_symbols(def_default); break; case randconfig: - conf_set_all_new_symbols(def_random); + /* Really nothing to do in this loop */ + while (conf_set_all_new_symbols(def_random)) ; break; case defconfig: conf_set_all_new_symbols(def_default); @@ -635,7 +669,7 @@ int main(int ac, char **av) /* fall through */ case oldconfig: case listnewconfig: - case oldnoconfig: + case olddefconfig: case silentoldconfig: /* Update until a loop caused no more changes */ do { @@ -643,7 +677,7 @@ int main(int ac, char **av) check_conf(&rootmenu); } while (conf_cnt && (input_mode != listnewconfig && - input_mode != oldnoconfig)); + input_mode != olddefconfig)); break; } @@ -662,7 +696,7 @@ int main(int ac, char **av) } else if (input_mode == savedefconfig) { if (conf_write_defconfig(defconfig_file)) { fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), - defconfig_file); + defconfig_file); return 1; } } else if (input_mode != listnewconfig) { diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 7c7a5a6cc3f..f88d90f2022 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -140,7 +140,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) sym->flags |= def_flags; break; } - conf_warning("symbol value '%s' invalid for %s", p, sym->name); + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); return 1; case S_OTHER: if (*p != '"') { @@ -161,7 +163,8 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) memmove(p2, p2 + 1, strlen(p2)); } if (!p2) { - conf_warning("invalid string found"); + if (def != S_DEF_AUTO) + conf_warning("invalid string found"); return 1; } /* fall through */ @@ -172,7 +175,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) sym->def[def].val = strdup(p); sym->flags |= def_flags; } else { - conf_warning("symbol value '%s' invalid for %s", p, sym->name); + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); return 1; } break; @@ -182,10 +187,66 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) return 0; } +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ + char *nline; + size_t new_size = slen + 1; + if (new_size > *n) { + new_size += LINE_GROWTH - 1; + new_size *= 2; + nline = realloc(*lineptr, new_size); + if (!nline) + return -1; + + *lineptr = nline; + *n = new_size; + } + + (*lineptr)[slen] = c; + + return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ + char *line = *lineptr; + size_t slen = 0; + + for (;;) { + int c = getc(stream); + + switch (c) { + case '\n': + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + /* fall through */ + case EOF: + if (add_byte('\0', &line, slen, n) < 0) + goto e_out; + *lineptr = line; + if (slen == 0) + return -1; + return slen; + default: + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + } + } + +e_out: + line[slen-1] = '\0'; + *lineptr = line; + return -1; +} + int conf_read_simple(const char *name, int def) { FILE *in = NULL; - char line[1024]; + char *line = NULL; + size_t line_asize = 0; char *p, *p2; struct symbol *sym; int i, def_flags; @@ -247,7 +308,7 @@ load: } } - while (fgets(line, sizeof(line), in)) { + while (compat_getline(&line, &line_asize, in) != -1) { conf_lineno++; sym = NULL; if (line[0] == '#') { @@ -335,6 +396,7 @@ setsym: cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); } } + free(line); fclose(in); if (modules_sym) @@ -344,10 +406,8 @@ setsym: int conf_read(const char *name) { - struct symbol *sym, *choice_sym; - struct property *prop; - struct expr *e; - int i, flags; + struct symbol *sym; + int i; sym_set_change_count(0); @@ -357,7 +417,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)) - goto sym_ok; + continue; if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { /* check that calculated value agrees with saved value */ switch (sym->type) { @@ -366,30 +426,18 @@ int conf_read(const char *name) if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) break; if (!sym_is_choice(sym)) - goto sym_ok; + continue; /* fall through */ default: if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) - goto sym_ok; + continue; break; } } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) /* no previous value and not saved */ - goto sym_ok; + continue; conf_unsaved++; /* maybe print value in verbose mode... */ - sym_ok: - if (!sym_is_choice(sym)) - continue; - /* The choice symbol only has a set value (and thus is not new) - * if all its visible childs have values. - */ - prop = sym_get_choice_prop(sym); - flags = sym->flags; - expr_list_for_each_sym(prop->expr, e, choice_sym) - if (choice_sym->visible != no) - flags &= choice_sym->flags; - sym->flags &= flags | ~SYMBOL_DEF_USER; } for_all_symbols(i, sym) { @@ -554,35 +602,6 @@ static struct conf_printer header_printer_cb = }; /* - * Generate the __enabled_CONFIG_* and __enabled_CONFIG_*_MODULE macros for - * use by the IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is - * generated even for booleans so that the IS_ENABLED() macro works. - */ -static void -header_print__enabled_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -{ - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: { - fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", - sym->name, (*value == 'y')); - fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", - sym->name, (*value == 'm')); - break; - } - default: - break; - } -} - -static struct conf_printer header__enabled_printer_cb = -{ - .print_symbol = header_print__enabled_symbol, - .print_comment = header_print_comment, -}; - -/* * Tristate printer * * This printer is used when generating the `include/config/tristate.conf' file. @@ -963,16 +982,11 @@ int conf_write_autoconf(void) conf_write_heading(out_h, &header_printer_cb, NULL); for_all_symbols(i, sym) { - if (!sym->name) - continue; - sym_calc_value(sym); - - conf_write_symbol(out_h, sym, &header__enabled_printer_cb, NULL); - - if (!(sym->flags & SYMBOL_WRITE)) + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) continue; + /* write symbol to auto.conf, tristate and header files */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); @@ -1031,7 +1045,7 @@ void conf_set_changed_callback(void (*fn)(void)) conf_changed_callback = fn; } -static void randomize_choice_values(struct symbol *csym) +static bool randomize_choice_values(struct symbol *csym) { struct property *prop; struct symbol *sym; @@ -1044,7 +1058,7 @@ static void randomize_choice_values(struct symbol *csym) * In both cases stop. */ if (csym->curr.tri != yes) - return; + return false; prop = sym_get_choice_prop(csym); @@ -1068,13 +1082,18 @@ static void randomize_choice_values(struct symbol *csym) else { sym->def[S_DEF_USER].tri = no; } + sym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + sym->flags &= ~SYMBOL_VALID; } csym->flags |= SYMBOL_DEF_USER; /* clear VALID to get value calculated */ csym->flags &= ~(SYMBOL_VALID); + + return true; } -static void set_all_choice_values(struct symbol *csym) +void set_all_choice_values(struct symbol *csym) { struct property *prop; struct symbol *sym; @@ -1091,20 +1110,66 @@ static void set_all_choice_values(struct symbol *csym) } csym->flags |= SYMBOL_DEF_USER; /* clear VALID to get value calculated */ - csym->flags &= ~(SYMBOL_VALID); + csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); } -void conf_set_all_new_symbols(enum conf_def_mode mode) +bool conf_set_all_new_symbols(enum conf_def_mode mode) { struct symbol *sym, *csym; - int i, cnt; + int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y + * pty: probability of tristate = y + * ptm: probability of tristate = m + */ + + pby = 50; pty = ptm = 33; /* can't go as the default in switch-case + * below, otherwise gcc whines about + * -Wmaybe-uninitialized */ + if (mode == def_random) { + int n, p[3]; + char *env = getenv("KCONFIG_PROBABILITY"); + n = 0; + while( env && *env ) { + char *endp; + int tmp = strtol( env, &endp, 10 ); + if( tmp >= 0 && tmp <= 100 ) { + p[n++] = tmp; + } else { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + env = (*endp == ':') ? endp+1 : endp; + if( n >=3 ) { + break; + } + } + switch( n ) { + case 1: + pby = p[0]; ptm = pby/2; pty = pby-ptm; + break; + case 2: + pty = p[0]; ptm = p[1]; pby = pty + ptm; + break; + case 3: + pby = p[0]; pty = p[1]; ptm = p[2]; + break; + } + + if( pty+ptm > 100 ) { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + } + bool has_changed = false; for_all_symbols(i, sym) { - if (sym_has_value(sym)) + if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) continue; switch (sym_get_type(sym)) { case S_BOOLEAN: case S_TRISTATE: + has_changed = true; switch (mode) { case def_yes: sym->def[S_DEF_USER].tri = yes; @@ -1113,11 +1178,21 @@ void conf_set_all_new_symbols(enum conf_def_mode mode) sym->def[S_DEF_USER].tri = mod; break; case def_no: - sym->def[S_DEF_USER].tri = no; + if (sym->flags & SYMBOL_ALLNOCONFIG_Y) + sym->def[S_DEF_USER].tri = yes; + else + sym->def[S_DEF_USER].tri = no; break; case def_random: - cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2; - sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt); + sym->def[S_DEF_USER].tri = no; + cnt = rand() % 100; + if (sym->type == S_TRISTATE) { + if (cnt < pty) + sym->def[S_DEF_USER].tri = yes; + else if (cnt < (pty+ptm)) + sym->def[S_DEF_USER].tri = mod; + } else if (cnt < pby) + sym->def[S_DEF_USER].tri = yes; break; default: continue; @@ -1142,14 +1217,26 @@ void conf_set_all_new_symbols(enum conf_def_mode mode) * selected in a choice block and we set it to yes, * and the rest to no. */ + if (mode != def_random) { + for_all_symbols(i, csym) { + if ((sym_is_choice(csym) && !sym_has_value(csym)) || + sym_is_choice_value(csym)) + csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; + } + } + for_all_symbols(i, csym) { if (sym_has_value(csym) || !sym_is_choice(csym)) continue; sym_calc_value(csym); if (mode == def_random) - randomize_choice_values(csym); - else + has_changed = randomize_choice_values(csym); + else { set_all_choice_values(csym); + has_changed = true; + } } + + return has_changed; } diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 290ce41f8ba..d6626521f9b 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -13,7 +13,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym) { - struct expr *e = calloc(1, sizeof(*e)); + struct expr *e = xcalloc(1, sizeof(*e)); e->type = E_SYMBOL; e->left.sym = sym; return e; @@ -21,7 +21,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym) struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) { - struct expr *e = calloc(1, sizeof(*e)); + struct expr *e = xcalloc(1, sizeof(*e)); e->type = type; e->left.expr = ce; return e; @@ -29,7 +29,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) { - struct expr *e = calloc(1, sizeof(*e)); + struct expr *e = xcalloc(1, sizeof(*e)); e->type = type; e->left.expr = e1; e->right.expr = e2; @@ -38,7 +38,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) { - struct expr *e = calloc(1, sizeof(*e)); + struct expr *e = xcalloc(1, sizeof(*e)); e->type = type; e->left.sym = s1; e->right.sym = s2; @@ -66,7 +66,7 @@ struct expr *expr_copy(const struct expr *org) if (!org) return NULL; - e = malloc(sizeof(*org)); + e = xmalloc(sizeof(*org)); memcpy(e, org, sizeof(*org)); switch (org->type) { case E_SYMBOL: diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index d4ecce8bc3a..412ea8a2abb 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -12,6 +12,7 @@ extern "C" { #include <assert.h> #include <stdio.h> +#include "list.h" #ifndef __cplusplus #include <stdbool.h> #endif @@ -92,7 +93,7 @@ struct symbol { #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ -#define SYMBOL_WRITE 0x0200 /* ? */ +#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ #define SYMBOL_CHANGED 0x0400 /* ? */ #define SYMBOL_AUTO 0x1000 /* value from environment variable */ #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ @@ -105,6 +106,12 @@ struct symbol { #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ +/* choice values need to be set before calculating this symbol value */ +#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 + +/* Set symbol to y if allnoconfig; used for symbols that hide others */ +#define SYMBOL_ALLNOCONFIG_Y 0x200000 + #define SYMBOL_MAXLENGTH 256 #define SYMBOL_HASHSIZE 9973 @@ -173,6 +180,15 @@ struct menu { #define MENU_CHANGED 0x0001 #define MENU_ROOT 0x0002 +struct jump_key { + struct list_head entries; + size_t offset; + struct menu *target; + int index; +}; + +#define JUMP_NB 9 + extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index adc230638c5..d0a35b21f30 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -10,6 +10,7 @@ # include <config.h> #endif +#include <stdlib.h> #include "lkc.h" #include "images.c" @@ -22,7 +23,6 @@ #include <string.h> #include <unistd.h> #include <time.h> -#include <stdlib.h> //#define DEBUG @@ -1404,7 +1404,7 @@ static void display_tree(struct menu *menu) && (tree == tree2)) continue; /* - if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) + if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW))*/ diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h new file mode 100644 index 00000000000..685d80e1bb0 --- /dev/null +++ b/scripts/kconfig/list.h @@ -0,0 +1,131 @@ +#ifndef LIST_H +#define LIST_H + +/* + * Copied from include/linux/... + */ + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +struct list_head { + struct list_head *next, *prev; +}; + + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *_new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = (struct list_head*)LIST_POISON1; + entry->prev = (struct list_head*)LIST_POISON2; +} +#endif diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index c18f2bd9c09..d5daa7af8b4 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -39,6 +39,12 @@ extern "C" { #ifndef CONFIG_ #define CONFIG_ "CONFIG_" #endif +static inline const char *CONFIG_prefix(void) +{ + return getenv( "CONFIG_" ) ?: CONFIG_; +} +#undef CONFIG_ +#define CONFIG_ CONFIG_prefix() #define TF_COMMAND 0x0001 #define TF_PARAM 0x0002 @@ -55,6 +61,7 @@ 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 { int name; @@ -80,7 +87,8 @@ const char *conf_get_autoconfig_name(void); char *conf_get_default_confname(void); void sym_set_change_count(int count); void sym_add_change_count(int count); -void conf_set_all_new_symbols(enum conf_def_mode mode); +bool conf_set_all_new_symbols(enum conf_def_mode mode); +void set_all_choice_values(struct symbol *csym); struct conf_printer { void (*print_symbol)(FILE *, struct symbol *, const char *, void *); @@ -116,6 +124,8 @@ 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); struct gstr { size_t len; diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 47fe9c340f9..ecdb9659b67 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -14,6 +14,7 @@ P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap))); /* menu.c */ P(rootmenu,struct menu,); +P(menu_is_empty, bool, (struct menu *menu)); P(menu_is_visible, bool, (struct menu *menu)); P(menu_has_prompt, bool, (struct menu *menu)); P(menu_get_prompt,const char *,(struct menu *menu)); @@ -21,8 +22,10 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu)); -P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); -P(get_relations_str, struct gstr, (struct symbol **sym_arr)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head + *head)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head + *head)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); /* symbol.c */ diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index 82cc3a85e7f..9d2a4c585ee 100644 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh @@ -4,7 +4,9 @@ # What library to link ldflags() { - for ext in so a dylib ; do + 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 @@ -19,12 +21,13 @@ ldflags() # Where is ncurses.h? ccflags() { - if [ -f /usr/include/ncurses/ncurses.h ]; then + if [ -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="<ncurses/curses.h>"' - elif [ -f /usr/include/ncursesw/curses.h ]; then - echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"' + echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"' elif [ -f /usr/include/ncurses.h ]; then echo '-DCURSES_LOC="<ncurses.h>"' else @@ -38,7 +41,7 @@ trap "rm -f $tmp" 0 1 2 3 15 # Check if we can link to ncurses check() { - $cc -xc - -o $tmp 2>/dev/null <<'EOF' + $cc -x c - -o $tmp 2>/dev/null <<'EOF' #include CURSES_LOC main() {} EOF diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c index a2eb80fbc89..8d016faa28d 100644 --- a/scripts/kconfig/lxdialog/checklist.c +++ b/scripts/kconfig/lxdialog/checklist.c @@ -132,16 +132,16 @@ int dialog_checklist(const char *title, const char *prompt, int height, } do_resize: - if (getmaxy(stdscr) < (height + 6)) + if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN)) return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) < (width + 6)) + if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN)) return -ERRDISPLAYTOOSMALL; max_choice = MIN(list_height, item_count()); /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; draw_shadow(stdscr, y, x, height, width); @@ -168,13 +168,13 @@ do_resize: /* create new window for the list */ list = subwin(dialog, list_height, list_width, y + box_y + 1, - x + box_x + 1); + x + box_x + 1); keypad(list, TRUE); /* draw a box around the list items */ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, - dlg.menubox_border.atr, dlg.menubox.atr); + dlg.menubox_border.atr, dlg.menubox.atr); /* Find length of longest item in order to center checklist */ check_x = 0; diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index b5211fce0d9..b4343d38492 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -106,8 +106,14 @@ struct dialog_color { int hl; /* highlight this item */ }; +struct subtitle_list { + struct subtitle_list *next; + const char *text; +}; + struct dialog_info { const char *backtitle; + struct subtitle_list *subtitles; struct dialog_color screen; struct dialog_color shadow; struct dialog_color dialog; @@ -144,6 +150,7 @@ struct dialog_info { */ extern struct dialog_info dlg; extern char dialog_input_result[]; +extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ /* * Function prototypes @@ -193,8 +200,23 @@ int item_is_tag(char tag); int on_key_esc(WINDOW *win); int on_key_resize(void); +/* minimum (re)size values */ +#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */ +#define CHECKLIST_WIDTH_MIN 6 +#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */ +#define INPUTBOX_WIDTH_MIN 2 +#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */ +#define MENUBOX_WIDTH_MIN 65 +#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */ +#define TEXTBOX_WIDTH_MIN 8 +#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */ +#define YESNO_WIDTH_MIN 4 +#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */ +#define WINDOW_WIDTH_MIN 80 + int init_dialog(const char *backtitle); void set_dialog_backtitle(const char *backtitle); +void set_dialog_subtitles(struct subtitle_list *subtitles); void end_dialog(int x, int y); void attr_clear(WINDOW * win, int height, int width, chtype attr); void dialog_clear(void); @@ -209,12 +231,17 @@ int first_alpha(const char *string, const char *exempt); int dialog_yesno(const char *title, const char *prompt, int height, int width); int dialog_msgbox(const char *title, const char *prompt, int height, int width, int pause); -int dialog_textbox(const char *title, const char *file, int height, int width); + + +typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void + *_data); +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data); int dialog_menu(const char *title, const char *prompt, const void *selected, int *s_scroll); int dialog_checklist(const char *title, const char *prompt, int height, int width, int list_height); -extern char dialog_input_result[]; int dialog_inputbox(const char *title, const char *prompt, int height, int width, const char *init); diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c index dd8e587c50e..d58de1dc536 100644 --- a/scripts/kconfig/lxdialog/inputbox.c +++ b/scripts/kconfig/lxdialog/inputbox.c @@ -42,10 +42,11 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected) * Display a dialog box for inputing a string */ int dialog_inputbox(const char *title, const char *prompt, int height, int width, - const char *init) + const char *init) { int i, x, y, box_y, box_x, box_width; - int input_x = 0, scroll = 0, key = 0, button = -1; + int input_x = 0, key = 0, button = -1; + int show_x, len, pos; char *instr = dialog_input_result; WINDOW *dialog; @@ -55,14 +56,14 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width strcpy(instr, init); do_resize: - if (getmaxy(stdscr) <= (height - 2)) + if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) <= (width - 2)) + if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) return -ERRDISPLAYTOOSMALL; /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; draw_shadow(stdscr, y, x, height, width); @@ -97,14 +98,17 @@ do_resize: wmove(dialog, box_y, box_x); wattrset(dialog, dlg.inputbox.atr); - input_x = strlen(instr); + len = strlen(instr); + pos = len; - if (input_x >= box_width) { - scroll = input_x - box_width + 1; + if (len >= box_width) { + show_x = len - box_width + 1; input_x = box_width - 1; for (i = 0; i < box_width - 1; i++) - waddch(dialog, instr[scroll + i]); + waddch(dialog, instr[show_x + i]); } else { + show_x = 0; + input_x = len; waddstr(dialog, instr); } @@ -121,45 +125,104 @@ do_resize: case KEY_UP: case KEY_DOWN: break; - case KEY_LEFT: - continue; - case KEY_RIGHT: - continue; case KEY_BACKSPACE: case 127: - if (input_x || scroll) { + if (pos) { wattrset(dialog, dlg.inputbox.atr); - if (!input_x) { - scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1); - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width; i++) - waddch(dialog, - instr[scroll + input_x + i] ? - instr[scroll + input_x + i] : ' '); - input_x = strlen(instr) - scroll; + if (input_x == 0) { + show_x--; } else input_x--; - instr[scroll + input_x] = '\0'; - mvwaddch(dialog, box_y, input_x + box_x, ' '); + + if (pos < len) { + for (i = pos - 1; i < len; i++) { + instr[i] = instr[i+1]; + } + } + + pos--; + len--; + instr[len] = '\0'; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } wmove(dialog, box_y, input_x + box_x); wrefresh(dialog); } continue; + case KEY_LEFT: + if (pos > 0) { + if (input_x > 0) { + wmove(dialog, box_y, --input_x + box_x); + } else if (input_x == 0) { + show_x--; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } + wmove(dialog, box_y, box_x); + } + pos--; + } + continue; + case KEY_RIGHT: + if (pos < len) { + if (input_x < box_width - 1) { + wmove(dialog, box_y, ++input_x + box_x); + } else if (input_x == box_width - 1) { + show_x++; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } + wmove(dialog, box_y, input_x + box_x); + } + pos++; + } + continue; default: if (key < 0x100 && isprint(key)) { - if (scroll + input_x < MAX_LEN) { + if (len < MAX_LEN) { wattrset(dialog, dlg.inputbox.atr); - instr[scroll + input_x] = key; - instr[scroll + input_x + 1] = '\0'; + if (pos < len) { + for (i = len; i > pos; i--) + instr[i] = instr[i-1]; + instr[pos] = key; + } else { + instr[len] = key; + } + pos++; + len++; + instr[len] = '\0'; + if (input_x == box_width - 1) { - scroll++; - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width - 1; i++) - waddch(dialog, instr [scroll + i]); + show_x++; } else { - wmove(dialog, box_y, input_x++ + box_x); - waddch(dialog, key); + input_x++; + } + + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); } + wmove(dialog, box_y, input_x + box_x); wrefresh(dialog); } else flash(); /* Alarm user about overflow */ diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c index 1d604738fa1..11ae9ad7ac7 100644 --- a/scripts/kconfig/lxdialog/menubox.c +++ b/scripts/kconfig/lxdialog/menubox.c @@ -26,7 +26,7 @@ * * *) A bugfix for the Page-Down problem * - * *) Formerly when I used Page Down and Page Up, the cursor would be set + * *) Formerly when I used Page Down and Page Up, the cursor would be set * to the first position in the menu box. Now lxdialog is a bit * smarter and works more like other menu systems (just have a look at * it). @@ -64,7 +64,7 @@ static int menu_width, item_x; * Print menu item */ static void do_print_item(WINDOW * win, const char *item, int line_y, - int selected, int hotkey) + int selected, int hotkey) { int j; char *menu_item = malloc(menu_width + 1); @@ -154,12 +154,14 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, */ static void print_buttons(WINDOW * win, int height, int width, int selected) { - int x = width / 2 - 16; + 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); wmove(win, y, x + 1 + 12 * selected); wrefresh(win); @@ -180,7 +182,7 @@ static void do_scroll(WINDOW *win, int *scroll, int n) * Display a menu for choosing among a number of options */ int dialog_menu(const char *title, const char *prompt, - const void *selected, int *s_scroll) + const void *selected, int *s_scroll) { int i, j, x, y, box_x, box_y; int height, width, menu_height; @@ -191,7 +193,7 @@ int dialog_menu(const char *title, const char *prompt, do_resize: height = getmaxy(stdscr); width = getmaxx(stdscr); - if (height < 15 || width < 65) + if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN) return -ERRDISPLAYTOOSMALL; height -= 4; @@ -201,8 +203,8 @@ do_resize: max_choice = MIN(menu_height, item_count()); /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; draw_shadow(stdscr, y, x, height, width); @@ -301,10 +303,11 @@ do_resize: } } - if (i < max_choice || - key == KEY_UP || key == KEY_DOWN || - key == '-' || key == '+' || - key == KEY_PPAGE || key == KEY_NPAGE) { + if (item_count() != 0 && + (i < max_choice || + key == KEY_UP || key == KEY_DOWN || + key == '-' || key == '+' || + key == KEY_PPAGE || key == KEY_NPAGE)) { /* Remove highligt of current item */ print_item(scroll + choice, choice, FALSE); @@ -372,7 +375,7 @@ do_resize: case TAB: case KEY_RIGHT: button = ((key == KEY_LEFT ? --button : ++button) < 0) - ? 2 : (button > 2 ? 0 : button); + ? 4 : (button > 4 ? 0 : button); print_buttons(dialog, height, width, button); wrefresh(menu); @@ -399,17 +402,17 @@ do_resize: return 2; case 's': case 'y': - return 3; + return 5; case 'n': - return 4; + return 6; case 'm': - return 5; + return 7; case ' ': - return 6; + return 8; case '/': - return 7; + return 9; case 'z': - return 8; + return 10; case '\n': return button; } diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 154c2dd245b..1773319b95e 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -22,23 +22,25 @@ #include "dialog.h" static void back_lines(int n); -static void print_page(WINDOW * win, int height, int width); -static void print_line(WINDOW * win, int row, int width); +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data); +static void print_line(WINDOW *win, int row, int width); static char *get_line(void); static void print_position(WINDOW * win); static int hscroll; static int begin_reached, end_reached, page_length; -static const char *buf; -static const char *page; +static char *buf; +static char *page; /* * refresh window content */ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, - int cur_y, int cur_x) + int cur_y, int cur_x, update_text_fn update_text, + void *data) { - print_page(box, boxh, boxw); + print_page(box, boxh, boxw, update_text, data); print_position(dialog); wmove(dialog, cur_y, cur_x); /* Restore cursor position */ wrefresh(dialog); @@ -47,14 +49,18 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, /* * Display text from a file in a dialog box. + * + * keys is a null-terminated array + * update_text() may not add or remove any '\n' or '\0' in tbuf */ -int dialog_textbox(const char *title, const char *tbuf, - int initial_height, int initial_width) +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data) { int i, x, y, cur_x, cur_y, key = 0; int height, width, boxh, boxw; - int passed_end; WINDOW *dialog, *box; + bool done = false; begin_reached = 1; end_reached = 0; @@ -63,9 +69,18 @@ int dialog_textbox(const char *title, const char *tbuf, buf = tbuf; page = buf; /* page is pointer to start of page to be displayed */ + if (_vscroll && *_vscroll) { + begin_reached = 0; + + for (i = 0; i < *_vscroll; i++) + get_line(); + } + if (_hscroll) + hscroll = *_hscroll; + do_resize: getmaxyx(stdscr, height, width); - if (height < 8 || width < 8) + if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN) return -ERRDISPLAYTOOSMALL; if (initial_height != 0) height = initial_height; @@ -83,8 +98,8 @@ do_resize: width = 0; /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; draw_shadow(stdscr, y, x, height, width); @@ -120,25 +135,28 @@ do_resize: /* Print first page of text */ attr_clear(box, boxh, boxw, dlg.dialog.atr); - refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, + data); - while ((key != KEY_ESC) && (key != '\n')) { + while (!done) { key = wgetch(dialog); switch (key) { case 'E': /* Exit */ case 'e': case 'X': case 'x': - delwin(box); - delwin(dialog); - return 0; + case 'q': + case '\n': + done = true; + break; case 'g': /* First page */ case KEY_HOME: if (!begin_reached) { begin_reached = 1; page = buf; refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + cur_y, cur_x, update_text, + data); } break; case 'G': /* Last page */ @@ -148,78 +166,48 @@ do_resize: /* point to last char in buf */ page = buf + strlen(buf); back_lines(boxh); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'K': /* Previous line */ case 'k': case KEY_UP: - if (!begin_reached) { - back_lines(page_length + 1); - - /* We don't call print_page() here but use - * scrolling to ensure faster screen update. - * However, 'end_reached' and 'page_length' - * should still be updated, and 'page' should - * point to start of next page. This is done - * by calling get_line() in the following - * 'for' loop. */ - scrollok(box, TRUE); - wscrl(box, -1); /* Scroll box region down one line */ - scrollok(box, FALSE); - page_length = 0; - passed_end = 0; - for (i = 0; i < boxh; i++) { - if (!i) { - /* print first line of page */ - print_line(box, 0, boxw); - wnoutrefresh(box); - } else - /* Called to update 'end_reached' and 'page' */ - get_line(); - if (!passed_end) - page_length++; - if (end_reached && !passed_end) - passed_end = 1; - } + if (begin_reached) + break; - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); - } + back_lines(page_length + 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'B': /* Previous page */ case 'b': + case 'u': case KEY_PPAGE: if (begin_reached) break; back_lines(page_length + boxh); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'J': /* Next line */ case 'j': case KEY_DOWN: - if (!end_reached) { - begin_reached = 0; - scrollok(box, TRUE); - scroll(box); /* Scroll box region up one line */ - scrollok(box, FALSE); - print_line(box, boxh - 1, boxw); - wnoutrefresh(box); - print_position(dialog); - wmove(dialog, cur_y, cur_x); /* Restore cursor position */ - wrefresh(dialog); - } + if (end_reached) + break; + + back_lines(page_length - 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case KEY_NPAGE: /* Next page */ case ' ': + case 'd': if (end_reached) break; begin_reached = 0; - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case '0': /* Beginning of line */ case 'H': /* Scroll left */ @@ -234,8 +222,8 @@ do_resize: hscroll--; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case 'L': /* Scroll right */ case 'l': @@ -245,11 +233,12 @@ do_resize: hscroll++; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); break; case KEY_ESC: - key = on_key_esc(dialog); + if (on_key_esc(dialog) == KEY_ESC) + done = true; break; case KEY_RESIZE: back_lines(height); @@ -257,11 +246,31 @@ do_resize: delwin(dialog); on_key_resize(); goto do_resize; + default: + for (i = 0; keys[i]; i++) { + if (key == keys[i]) { + done = true; + break; + } + } } } delwin(box); delwin(dialog); - return key; /* ESC pressed */ + if (_vscroll) { + const char *s; + + s = buf; + *_vscroll = 0; + back_lines(page_length); + while (s < page && (s = strchr(s, '\n'))) { + (*_vscroll)++; + s++; + } + } + if (_hscroll) + *_hscroll = hscroll; + return key; } /* @@ -298,12 +307,23 @@ static void back_lines(int n) } /* - * Print a new page of text. Called by dialog_textbox(). + * Print a new page of text. */ -static void print_page(WINDOW * win, int height, int width) +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data) { int i, passed_end = 0; + if (update_text) { + char *end; + + for (i = 0; i < height; i++) + get_line(); + end = page; + back_lines(height); + update_text(buf, page - buf, end - buf, data); + } + page_length = 0; for (i = 0; i < height; i++) { print_line(win, i, width); @@ -316,7 +336,7 @@ static void print_page(WINDOW * win, int height, int width) } /* - * Print a new line of text. Called by dialog_textbox() and print_page(). + * Print a new line of text. */ static void print_line(WINDOW * win, int row, int width) { @@ -354,10 +374,8 @@ static char *get_line(void) end_reached = 0; while (*page != '\n') { if (*page == '\0') { - if (!end_reached) { - end_reached = 1; - break; - } + end_reached = 1; + break; } else if (i < MAX_LEN) line[i++] = *(page++); else { @@ -370,7 +388,7 @@ static char *get_line(void) if (i <= MAX_LEN) line[i] = '\0'; if (!end_reached) - page++; /* move pass '\n' */ + page++; /* move past '\n' */ return line; } diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index f2375ad7ebc..f7abdeb92af 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -23,6 +23,9 @@ #include "dialog.h" +/* Needed in signal handler in mconf.c */ +int saved_x, saved_y; + struct dialog_info dlg; static void set_mono_theme(void) @@ -251,15 +254,56 @@ void attr_clear(WINDOW * win, int height, int width, chtype attr) void dialog_clear(void) { - attr_clear(stdscr, LINES, COLS, dlg.screen.atr); + int lines, columns; + + lines = getmaxy(stdscr); + columns = getmaxx(stdscr); + + attr_clear(stdscr, lines, columns, dlg.screen.atr); /* Display background title if it exists ... - SLH */ if (dlg.backtitle != NULL) { - int i; + int i, len = 0, skip = 0; + struct subtitle_list *pos; wattrset(stdscr, dlg.screen.atr); mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); + + for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { + /* 3 is for the arrow and spaces */ + len += strlen(pos->text) + 3; + } + wmove(stdscr, 1, 1); - for (i = 1; i < COLS - 1; i++) + if (len > columns - 2) { + const char *ellipsis = "[...] "; + waddstr(stdscr, ellipsis); + skip = len - (columns - 2 - strlen(ellipsis)); + } + + for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { + if (skip == 0) + waddch(stdscr, ACS_RARROW); + else + skip--; + + if (skip == 0) + waddch(stdscr, ' '); + else + skip--; + + if (skip < strlen(pos->text)) { + waddstr(stdscr, pos->text + skip); + skip = 0; + } else + skip -= strlen(pos->text); + + if (skip == 0) + waddch(stdscr, ' '); + else + skip--; + } + + for (i = len + 1; i < columns - 1; i++) waddch(stdscr, ACS_HLINE); } wnoutrefresh(stdscr); @@ -273,8 +317,12 @@ int init_dialog(const char *backtitle) int height, width; initscr(); /* Init curses */ + + /* Get current cursor position for signal handler in mconf.c */ + getyx(stdscr, saved_y, saved_x); + getmaxyx(stdscr, height, width); - if (height < 19 || width < 80) { + if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { endwin(); return -ERRDISPLAYTOOSMALL; } @@ -295,6 +343,11 @@ void set_dialog_backtitle(const char *backtitle) dlg.backtitle = backtitle; } +void set_dialog_subtitles(struct subtitle_list *subtitles) +{ + dlg.subtitles = subtitles; +} + /* * End using dialog functions. */ @@ -323,27 +376,19 @@ void print_title(WINDOW *dialog, const char *title, int width) /* * Print a string of text in a window, automatically wrap around to the * next line if the string is too long to fit on one line. Newline - * characters '\n' are replaced by spaces. We start on a new line + * characters '\n' are propperly processed. We start on a new line * if there is no room for at least 4 nonblanks following a double-space. */ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) { int newl, cur_x, cur_y; - int i, prompt_len, room, wlen; - char tempstr[MAX_LEN + 1], *word, *sp, *sp2; + int prompt_len, room, wlen; + char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0; strcpy(tempstr, prompt); prompt_len = strlen(tempstr); - /* - * Remove newlines - */ - for (i = 0; i < prompt_len; i++) { - if (tempstr[i] == '\n') - tempstr[i] = ' '; - } - if (prompt_len <= width - x * 2) { /* If prompt is short */ wmove(win, y, (width - prompt_len) / 2); waddstr(win, tempstr); @@ -353,7 +398,10 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) newl = 1; word = tempstr; while (word && *word) { - sp = strchr(word, ' '); + sp = strpbrk(word, "\n "); + if (sp && *sp == '\n') + newline_separator = sp; + if (sp) *sp++ = 0; @@ -365,7 +413,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) if (wlen > room || (newl && wlen < 4 && sp && wlen + 1 + strlen(sp) > room - && (!(sp2 = strchr(sp, ' ')) + && (!(sp2 = strpbrk(sp, "\n ")) || wlen + 1 + (sp2 - sp) > room))) { cur_y++; cur_x = x; @@ -373,7 +421,15 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) wmove(win, cur_y, cur_x); waddstr(win, word); getyx(win, cur_y, cur_x); - cur_x++; + + /* Move to the next line if the word separator was a newline */ + if (newline_separator) { + cur_y++; + cur_x = x; + newline_separator = 0; + } else + cur_x++; + if (sp && *sp == ' ') { cur_x++; /* double space */ while (*++sp == ' ') ; @@ -567,7 +623,7 @@ void item_make(const char *fmt, ...) void item_add_str(const char *fmt, ...) { va_list ap; - size_t avail; + size_t avail; avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c index 4e6e8090c20..676fb2f824a 100644 --- a/scripts/kconfig/lxdialog/yesno.c +++ b/scripts/kconfig/lxdialog/yesno.c @@ -45,14 +45,14 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width) WINDOW *dialog; do_resize: - if (getmaxy(stdscr) < (height + 4)) + if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) < (width + 4)) + if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) return -ERRDISPLAYTOOSMALL; /* center dialog box on screen */ - x = (COLS - width) / 2; - y = (LINES - height) / 2; + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; draw_shadow(stdscr, y, x, height, width); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 2c6286c0bc1..14cea7463a6 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -25,7 +25,7 @@ static const char mconf_readme[] = N_( "Overview\n" "--------\n" -"This interface let you select features and parameters for the build.\n" +"This interface lets you select features and parameters for the build.\n" "Features can either be built-in, modularized, or ignored. Parameters\n" "must be entered in as decimal or hexadecimal numbers or text.\n" "\n" @@ -39,16 +39,16 @@ static const char mconf_readme[] = N_( "\n" "To change any of these features, highlight it with the cursor\n" "keys and press <Y> to build it in, <M> to make it a module or\n" -"<N> to removed it. You may also press the <Space Bar> to cycle\n" -"through the available options (ie. Y->N->M->Y).\n" +"<N> to remove it. You may also press the <Space Bar> to cycle\n" +"through the available options (i.e. Y->N->M->Y).\n" "\n" "Some additional keyboard hints:\n" "\n" "Menus\n" "----------\n" -"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" -" you wish to change or submenu wish to select and press <Enter>.\n" -" Submenus are designated by \"--->\".\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n" +" wish to change or the submenu you wish to select and press <Enter>.\n" +" Submenus are designated by \"--->\", empty ones by \"----\".\n" "\n" " Shortcut: Press the option's highlighted letter (hotkey).\n" " Pressing a hotkey more than once will sequence\n" @@ -65,7 +65,7 @@ static const char mconf_readme[] = N_( " there is a delayed response which you may find annoying.\n" "\n" " Also, the <TAB> and cursor keys will cycle between <Select>,\n" -" <Exit> and <Help>.\n" +" <Exit>, <Help>, <Save>, and <Load>.\n" "\n" "o To get help with an item, use the cursor keys to highlight <Help>\n" " and press <ENTER>.\n" @@ -105,10 +105,10 @@ static const char mconf_readme[] = N_( "Text Box (Help Window)\n" "--------\n" "o Use the cursor keys to scroll up/down/left/right. The VI editor\n" -" keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n" -" who are familiar with less and lynx.\n" +" keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n" +" those who are familiar with less and lynx.\n" "\n" -"o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n" +"o Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n" "\n" "\n" "Alternate Configuration Files\n" @@ -117,23 +117,21 @@ static const char mconf_readme[] = N_( "those who, for various reasons, find it necessary to switch\n" "between different configurations.\n" "\n" -"At the end of the main menu you will find two options. One is\n" -"for saving the current configuration to a file of your choosing.\n" -"The other option is for loading a previously saved alternate\n" -"configuration.\n" +"The <Save> button will let you save the current configuration to\n" +"a file of your choosing. Use the <Load> button to load a previously\n" +"saved alternate configuration.\n" "\n" -"Even if you don't use alternate configuration files, but you\n" -"find during a Menuconfig session that you have completely messed\n" -"up your settings, you may use the \"Load Alternate...\" option to\n" -"restore your previously saved settings from \".config\" without\n" -"restarting Menuconfig.\n" +"Even if you don't use alternate configuration files, but you find\n" +"during a Menuconfig session that you have completely messed up your\n" +"settings, you may use the <Load> button to restore your previously\n" +"saved settings from \".config\" without restarting Menuconfig.\n" "\n" "Other information\n" "-----------------\n" -"If you use Menuconfig in an XTERM window make sure you have your\n" -"$TERM variable set to point to a xterm definition which supports color.\n" -"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n" -"display correctly in a RXVT window because rxvt displays only one\n" +"If you use Menuconfig in an XTERM window, make sure you have your\n" +"$TERM variable set to point to an xterm definition which supports\n" +"color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n" +"not display correctly in an RXVT window because rxvt displays only one\n" "intensity of color, bright.\n" "\n" "Menuconfig will display larger menus on screens or xterms which are\n" @@ -148,8 +146,8 @@ static const char mconf_readme[] = N_( "\n" "Optional personality available\n" "------------------------------\n" -"If you prefer to have all of the options listed in a single menu, rather\n" -"than the default multimenu hierarchy, run the menuconfig with\n" +"If you prefer to have all of the options listed in a single menu,\n" +"rather than the default multimenu hierarchy, run the menuconfig with\n" "MENUCONFIG_MODE environment variable set to single_menu. Example:\n" "\n" "make MENUCONFIG_MODE=single_menu menuconfig\n" @@ -172,11 +170,11 @@ static const char mconf_readme[] = N_( " mono => selects colors suitable for monochrome displays\n" " blackbg => selects a color scheme with black background\n" " classic => theme with blue background. The classic look\n" -" bluetitle => a LCD friendly version of classic. (default)\n" +" bluetitle => an LCD friendly version of classic. (default)\n" "\n"), menu_instructions[] = N_( "Arrow keys navigate the menu. " - "<Enter> selects submenus --->. " + "<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. " @@ -236,29 +234,36 @@ search_help[] = N_( "Result:\n" "-----------------------------------------------------------------\n" "Symbol: FOO [=m]\n" + "Type : tristate\n" "Prompt: Foo bus is used to drive the bar HW\n" - "Defined at drivers/pci/Kconfig:47\n" - "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" - "Location:\n" - " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" - " -> PCI support (PCI [=y])\n" - " -> PCI access mode (<choice> [=y])\n" - "Selects: LIBCRC32\n" - "Selected by: BAR\n" + " Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" + " -> PCI support (PCI [=y])\n" + "(1) -> PCI access mode (<choice> [=y])\n" + " Defined at drivers/pci/Kconfig:47\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Selects: LIBCRC32\n" + " Selected by: BAR [=n]\n" "-----------------------------------------------------------------\n" + "o The line 'Type:' shows the type of the configuration option for\n" + " this symbol (boolean, tristate, string, ...)\n" "o The line 'Prompt:' shows the text used in the menu structure for\n" " this symbol\n" - "o The 'Defined at' line tell at what file / line number the symbol\n" + "o The 'Defined at' line tells at what file / line number the symbol\n" " is defined\n" - "o The 'Depends on:' line tell what symbols needs to be defined for\n" + "o The 'Depends on:' line tells what symbols need to be defined for\n" " this symbol to be visible in the menu (selectable)\n" - "o The 'Location:' lines tell where in the menu structure this symbol\n" + "o The 'Location:' lines tells where in the menu structure this symbol\n" " is located\n" - " A location followed by a [=y] indicate that this is a selectable\n" - " menu item - and current value is displayed inside brackets.\n" - "o The 'Selects:' line tell what symbol will be automatically\n" + " A location followed by a [=y] indicates that this is a\n" + " selectable menu item - and the current value is displayed inside\n" + " brackets.\n" + " Press the key in the (#) prefix to jump directly to that\n" + " location. You will be returned to the current search results\n" + " after exiting this new menu.\n" + "o The 'Selects:' line tells what symbols will be automatically\n" " selected if this symbol is selected (y or m)\n" - "o The 'Selected by' line tell what symbol has selected this symbol\n" + "o The 'Selected by' line tells what symbol has selected this symbol\n" "\n" "Only relevant lines are shown.\n" "\n\n" @@ -273,13 +278,16 @@ static struct menu *current_menu; static int child_count; static int single_menu_mode; static int show_all_options; -static int saved_x, saved_y; +static int save_and_exit; -static void conf(struct menu *menu); +static void conf(struct menu *menu, struct menu *active_menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); static void conf_load(void); static void conf_save(void); +static int show_textbox_ext(const char *title, char *text, int r, int c, + int *keys, int *vscroll, int *hscroll, + update_text_fn update_text, void *data); static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); @@ -291,7 +299,7 @@ static void set_config_filename(const char *config_filename) int size; size = snprintf(menu_backtitle, sizeof(menu_backtitle), - "%s - %s", config_filename, rootmenu.prompt->text); + "%s - %s", config_filename, rootmenu.prompt->text); if (size >= sizeof(menu_backtitle)) menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; set_dialog_backtitle(menu_backtitle); @@ -301,18 +309,103 @@ static void set_config_filename(const char *config_filename) filename[sizeof(filename)-1] = '\0'; } +struct subtitle_part { + struct list_head entries; + const char *text; +}; +static LIST_HEAD(trail); + +static struct subtitle_list *subtitles; +static void set_subtitle(void) +{ + struct subtitle_part *sp; + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + + subtitles = NULL; + list_for_each_entry(sp, &trail, entries) { + if (sp->text) { + if (pos) { + pos->next = xcalloc(sizeof(*pos), 1); + pos = pos->next; + } else { + subtitles = pos = xcalloc(sizeof(*pos), 1); + } + pos->text = sp->text; + } + } + + set_dialog_subtitles(subtitles); +} + +static void reset_subtitle(void) +{ + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + subtitles = NULL; + set_dialog_subtitles(subtitles); +} + +struct search_data { + struct list_head *head; + struct menu **targets; + int *keys; +}; + +static void update_text(char *buf, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int k = 0; + + list_for_each_entry(pos, data->head, entries) { + if (pos->offset >= start && pos->offset < end) { + char header[4]; + + if (k < JUMP_NB) { + int key = '0' + (pos->index % JUMP_NB) + 1; + + sprintf(header, "(%c)", key); + data->keys[k] = key; + data->targets[k] = pos->target; + k++; + } else { + sprintf(header, " "); + } + + memcpy(buf + pos->offset, header, sizeof(header) - 1); + } + } + data->keys[k] = 0; +} static void search_conf(void) { struct symbol **sym_arr; struct gstr res; + struct gstr title; char *dialog_input; - int dres; + int dres, vscroll = 0, hscroll = 0; + bool again; + struct gstr sttext; + struct subtitle_part stpart; + + title = str_new(); + 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"), - _("Enter " CONFIG_ " (sub)string to search for " - "(with or without \"" CONFIG_ "\")"), + str_get(&title), 10, 75, ""); switch (dres) { case 0: @@ -321,6 +414,7 @@ again: show_helptext(_("Search Configuration"), search_help); goto again; default: + str_free(&title); return; } @@ -329,11 +423,43 @@ again: if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) dialog_input += strlen(CONFIG_); + sttext = str_new(); + str_printf(&sttext, "Search (%s)", dialog_input_result); + stpart.text = str_get(&sttext); + list_add_tail(&stpart.entries, &trail); + sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr); + do { + LIST_HEAD(head); + struct menu *targets[JUMP_NB]; + int keys[JUMP_NB + 1], i; + struct search_data data = { + .head = &head, + .targets = targets, + .keys = keys, + }; + struct jump_key *pos, *tmp; + + res = get_relations_str(sym_arr, &head); + set_subtitle(); + dres = show_textbox_ext(_("Search Results"), (char *) + str_get(&res), 0, 0, keys, &vscroll, + &hscroll, &update_text, (void *) + &data); + again = false; + for (i = 0; i < JUMP_NB && keys[i]; i++) + if (dres == keys[i]) { + conf(targets[i]->parent, targets[i]); + again = true; + } + str_free(&res); + list_for_each_entry_safe(pos, tmp, &head, entries) + free(pos); + } while (again); free(sym_arr); - show_textbox(_("Search Results"), str_get(&res), 0, 0); - str_free(&res); + str_free(&title); + list_del(trail.prev); + str_free(&sttext); } static void build_conf(struct menu *menu) @@ -370,8 +496,9 @@ static void build_conf(struct menu *menu) menu->data ? "-->" : "++>", indent + 1, ' ', prompt); } else - item_make(" %*c%s --->", indent + 1, ' ', prompt); - + item_make(" %*c%s %s", + indent + 1, ' ', prompt, + menu_is_empty(menu) ? "----" : "--->"); item_set_tag('m'); item_set_data(menu); if (single_menu_mode && menu->data) @@ -502,7 +629,7 @@ static void build_conf(struct menu *menu) (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : _(" (NEW)")); if (menu->prompt->type == P_MENU) { - item_add_str(" --->"); + item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); return; } } @@ -514,40 +641,40 @@ conf_childs: indent -= doint; } -static void conf(struct menu *menu) +static void conf(struct menu *menu, struct menu *active_menu) { struct menu *submenu; const char *prompt = menu_get_prompt(menu); + struct subtitle_part stpart; struct symbol *sym; - struct menu *active_menu = NULL; int res; int s_scroll = 0; + if (menu != &rootmenu) + stpart.text = menu_get_prompt(menu); + else + stpart.text = NULL; + list_add_tail(&stpart.entries, &trail); + while (1) { item_reset(); current_menu = menu; build_conf(menu); if (!child_count) break; - if (menu == &rootmenu) { - item_make("--- "); - item_set_tag(':'); - item_make(_(" Load an Alternate Configuration File")); - item_set_tag('L'); - item_make(_(" Save an Alternate Configuration File")); - item_set_tag('S'); - } + set_subtitle(); dialog_clear(); res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), _(menu_instructions), active_menu, &s_scroll); if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) break; - if (!item_activate_selected()) - continue; - if (!item_tag()) - continue; - + if (item_count() != 0) { + if (!item_activate_selected()) + continue; + if (!item_tag()) + continue; + } submenu = item_data(); active_menu = item_data(); if (submenu) @@ -562,32 +689,36 @@ static void conf(struct menu *menu) if (single_menu_mode) submenu->data = (void *) (long) !submenu->data; else - conf(submenu); + conf(submenu, NULL); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); else if (submenu->prompt->type == P_MENU) - conf(submenu); + conf(submenu, NULL); break; case 's': conf_string(submenu); break; - case 'L': - conf_load(); - break; - case 'S': - conf_save(); - break; } break; case 2: if (sym) show_help(submenu); - else + else { + reset_subtitle(); show_helptext(_("README"), _(mconf_readme)); + } break; case 3: + reset_subtitle(); + conf_save(); + break; + case 4: + reset_subtitle(); + conf_load(); + break; + case 5: if (item_is_tag('t')) { if (sym_set_tristate_value(sym, yes)) break; @@ -595,34 +726,45 @@ static void conf(struct menu *menu) show_textbox(NULL, setmod_text, 6, 74); } break; - case 4: + case 6: if (item_is_tag('t')) sym_set_tristate_value(sym, no); break; - case 5: + case 7: if (item_is_tag('t')) sym_set_tristate_value(sym, mod); break; - case 6: + case 8: if (item_is_tag('t')) sym_toggle_tristate_value(sym); else if (item_is_tag('m')) - conf(submenu); + conf(submenu, NULL); break; - case 7: + case 9: search_conf(); break; - case 8: + case 10: show_all_options = !show_all_options; break; } } + + list_del(trail.prev); } -static void show_textbox(const char *title, const char *text, int r, int c) +static int show_textbox_ext(const char *title, char *text, int r, int c, int + *keys, int *vscroll, int *hscroll, update_text_fn + update_text, void *data) { dialog_clear(); - dialog_textbox(title, text, r, c); + return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, + update_text, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, + NULL, NULL); } static void show_helptext(const char *title, const char *text) @@ -630,6 +772,17 @@ 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) +{ + char buf[PATH_MAX+1]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + if (save_and_exit) + printf("%s", buf); + else + show_textbox(NULL, buf, 6, 60); +} + static void show_help(struct menu *menu) { struct gstr help = str_new(); @@ -672,7 +825,9 @@ static void conf_choice(struct menu *menu) dialog_clear(); res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), _(radiolist_instructions), - 15, 70, 6); + MENUBOX_HEIGTH_MIN, + MENUBOX_WIDTH_MIN, + CHECKLIST_HEIGTH_MIN); selected = item_activate_selected(); switch (res) { case 0: @@ -798,11 +953,13 @@ static int handle_exit(void) { int res; + save_and_exit = 1; + reset_subtitle(); dialog_clear(); if (conf_get_changed()) res = dialog_yesno(NULL, - _("Do you wish to save your new configuration ?\n" - "<ESC><ESC> to continue."), + _("Do you wish to save your new configuration?\n" + "(Press <ESC><ESC> to continue kernel configuration.)"), 6, 60); else res = -1; @@ -862,9 +1019,6 @@ int main(int ac, char **av) single_menu_mode = 1; } - initscr(); - - getyx(stdscr, saved_y, saved_x); 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")); @@ -872,11 +1026,11 @@ int main(int ac, char **av) } set_config_filename(conf_get_configname()); + conf_set_message_callback(conf_message_callback); do { - conf(&rootmenu); + conf(&rootmenu, NULL); res = handle_exit(); } while (res == KEY_ESC); return res; } - diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 8c2a97e60fa..a26cc5d2a9b 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -48,7 +48,7 @@ void menu_add_entry(struct symbol *sym) { struct menu *menu; - menu = malloc(sizeof(*menu)); + menu = xmalloc(sizeof(*menu)); memset(menu, 0, sizeof(*menu)); menu->sym = sym; menu->parent = current_menu; @@ -119,9 +119,10 @@ void menu_set_type(int type) sym->type = type; return; } - menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'", - sym->name ? sym->name : "<choice>", - sym_type_name(sym->type), sym_type_name(type)); + menu_warn(current_entry, + "ignoring type redefinition of '%s' from '%s' to '%s'", + sym->name ? sym->name : "<choice>", + sym_type_name(sym->type), sym_type_name(type)); } struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) @@ -146,11 +147,24 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e struct menu *menu = current_entry; while ((menu = menu->parent) != NULL) { + struct expr *dup_expr; + if (!menu->visibility) continue; + /* + * Do not add a reference to the + * menu's visibility expression but + * use a copy of it. Otherwise the + * expression reduction functions + * will modify expressions that have + * multiple references which can + * cause unwanted side effects. + */ + dup_expr = expr_copy(menu->visibility); + prop->visible.expr = expr_alloc_and(prop->visible.expr, - menu->visibility); + dup_expr); } } @@ -184,12 +198,15 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) void menu_add_option(int token, char *arg) { - struct property *prop; - switch (token) { case T_OPT_MODULES: - prop = prop_alloc(P_DEFAULT, modules_sym); - prop->expr = expr_alloc_symbol(current_entry->sym); + if (modules_sym) + zconf_error("symbol '%s' redefines option 'modules'" + " already defined by symbol '%s'", + current_entry->sym->name, + modules_sym->name + ); + modules_sym = current_entry->sym; break; case T_OPT_DEFCONFIG_LIST: if (!sym_defconfig_list) @@ -200,6 +217,9 @@ void menu_add_option(int token, char *arg) case T_OPT_ENV: prop_add_env(arg); break; + case T_OPT_ALLNOCONFIG_Y: + current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; + break; } } @@ -238,8 +258,8 @@ static void sym_check_prop(struct symbol *sym) "config symbol '%s' uses select, but is " "not boolean or tristate", sym->name); else if (sym2->type != S_UNKNOWN && - sym2->type != S_BOOLEAN && - sym2->type != S_TRISTATE) + sym2->type != S_BOOLEAN && + sym2->type != S_TRISTATE) prop_warn(prop, "'%s' has wrong type. 'select' only " "accept arguments of boolean and " @@ -248,7 +268,7 @@ static void sym_check_prop(struct symbol *sym) case P_RANGE: if (sym->type != S_INT && sym->type != S_HEX) prop_warn(prop, "range is only allowed " - "for int or hex symbols"); + "for int or hex symbols"); if (!menu_validate_number(sym, prop->expr->left.sym) || !menu_validate_number(sym, prop->expr->right.sym)) prop_warn(prop, "range is invalid"); @@ -430,6 +450,22 @@ bool menu_has_prompt(struct menu *menu) return true; } +/* + * Determine if a menu is empty. + * A menu is considered empty if it contains no or only + * invisible entries. + */ +bool menu_is_empty(struct menu *menu) +{ + struct menu *child; + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child)) + return(false); + } + return(true); +} + bool menu_is_visible(struct menu *menu) { struct menu *child; @@ -507,27 +543,53 @@ const char *menu_get_help(struct menu *menu) return ""; } -static void get_prompt_str(struct gstr *r, struct property *prop) +static void get_prompt_str(struct gstr *r, struct property *prop, + struct list_head *head) { int i, j; - struct menu *submenu[8], *menu; + struct menu *submenu[8], *menu, *location = NULL; + struct jump_key *jump; str_printf(r, _("Prompt: %s\n"), _(prop->text)); - 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: ")); - expr_gstr_print(prop->visible.expr, r); - str_append(r, "\n"); - } menu = prop->menu->parent; - for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { + bool accessible = menu_is_visible(menu); + submenu[i++] = menu; + if (location == NULL && accessible) + location = menu; + } + if (head && location) { + jump = xmalloc(sizeof(struct jump_key)); + + if (menu_is_visible(prop->menu)) { + /* + * There is not enough room to put the hint at the + * beginning of the "Prompt" line. Put the hint on the + * last "Location" line even when it would belong on + * the former. + */ + jump->target = prop->menu; + } else + jump->target = location; + + if (list_empty(head)) + jump->index = 0; + else + jump->index = list_entry(head->prev, struct jump_key, + entries)->index + 1; + + list_add_tail(&jump->entries, head); + } + if (i > 0) { str_printf(r, _(" Location:\n")); for (j = 4; --i >= 0; j += 2) { menu = submenu[i]; - str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); + if (head && location && menu == location) + jump->offset = strlen(r->s); + str_printf(r, "%*c-> %s", j, ' ', + _(menu_get_prompt(menu))); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? menu->sym->name : _("<choice>"), @@ -538,7 +600,23 @@ static void get_prompt_str(struct gstr *r, struct property *prop) } } -void get_symbol_str(struct gstr *r, struct symbol *sym) +/* + * get property of type P_SYMBOL + */ +static struct property *get_symbol_prop(struct symbol *sym) +{ + struct property *prop = NULL; + + for_all_properties(sym, prop, P_SYMBOL) + break; + return prop; +} + +/* + * head is optional and may be NULL + */ +void get_symbol_str(struct gstr *r, struct symbol *sym, + struct list_head *head) { bool hit; struct property *prop; @@ -557,7 +635,19 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) } } for_all_prompts(sym, prop) - get_prompt_str(r, prop); + get_prompt_str(r, prop, head); + + prop = get_symbol_prop(sym); + if (prop) { + 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: ")); + expr_gstr_print(prop->visible.expr, r); + str_append(r, "\n"); + } + } + hit = false; for_all_properties(sym, prop, P_SELECT) { if (!hit) { @@ -577,14 +667,14 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) str_append(r, "\n\n"); } -struct gstr get_relations_str(struct symbol **sym_arr) +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) { struct symbol *sym; struct gstr res = str_new(); int i; for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym); + get_symbol_str(&res, sym, head); if (!i) str_append(&res, _("No matches found.\n")); return res; @@ -603,5 +693,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) } str_printf(help, "%s\n", _(help_text)); if (sym) - get_symbol_str(help, sym); + get_symbol_str(help, sym, NULL); } diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh index ceadf0e150c..81b0c61bb9e 100644..100755 --- a/scripts/kconfig/merge_config.sh +++ b/scripts/kconfig/merge_config.sh @@ -31,10 +31,14 @@ usage() { echo " -h display this help text" echo " -m only merge the fragments, do not execute the make command" echo " -n use allnoconfig instead of alldefconfig" + echo " -r list redundant entries when merging fragments" + echo " -O dir to put generated output files" } MAKE=true ALLTARGET=alldefconfig +WARNREDUN=false +OUTPUT=. while true; do case $1 in @@ -52,18 +56,37 @@ while true; do usage exit ;; + "-r") + WARNREDUN=true + shift + continue + ;; + "-O") + if [ -d $2 ];then + OUTPUT=$(echo $2 | sed 's/\/*$//') + else + echo "output directory $2 does not exist" 1>&2 + exit 1 + fi + shift 2 + continue + ;; *) break ;; esac done - +INITFILE=$1 +shift; MERGE_LIST=$* SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) +echo "Using $INITFILE as base" +cat $INITFILE > $TMP_FILE + # Merge files, printing warnings on overrided values for MERGE_FILE in $MERGE_LIST ; do echo "Merging $MERGE_FILE" @@ -79,6 +102,8 @@ for MERGE_FILE in $MERGE_LIST ; do echo Previous value: $PREV_VAL echo New value: $NEW_VAL echo + elif [ "$WARNREDUN" = "true" ]; then + echo Value of $CFG is redundant by fragment $MERGE_FILE: fi sed -i "/$CFG[ =]/d" $TMP_FILE fi @@ -87,25 +112,33 @@ for MERGE_FILE in $MERGE_LIST ; do done if [ "$MAKE" = "false" ]; then - cp $TMP_FILE .config + cp $TMP_FILE $OUTPUT/.config echo "#" - echo "# merged configuration written to .config (needs make)" + echo "# merged configuration written to $OUTPUT/.config (needs make)" echo "#" clean_up exit fi +# If we have an output dir, setup the O= argument, otherwise leave +# it blank, since O=. will create an unnecessary ./source softlink +OUTPUT_ARG="" +if [ "$OUTPUT" != "." ] ; then + OUTPUT_ARG="O=$OUTPUT" +fi + + # Use the merged file as the starting point for: # alldefconfig: Fills in any missing symbols with Kconfig default # allnoconfig: Fills in any missing symbols with # CONFIG_* is not set -make KCONFIG_ALLCONFIG=$TMP_FILE $ALLTARGET +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 REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) - ACTUAL_VAL=$(grep -w -e "$CFG" .config) + ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config) if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then echo "Value requested for $CFG not in final .config" echo "Requested value: $REQUESTED_VAL" diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 73070cb0b6d..984489ef2b4 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -7,215 +7,208 @@ */ #define _GNU_SOURCE #include <string.h> +#include <stdlib.h> #include "lkc.h" #include "nconf.h" #include <ctype.h> -static const char nconf_readme[] = N_( -"Overview\n" -"--------\n" -"This interface let you select features and parameters for the build.\n" -"Features can either be built-in, modularized, or ignored. Parameters\n" -"must be entered in as decimal or hexadecimal numbers or text.\n" +static const char nconf_global_help[] = N_( +"Help windows\n" +"------------\n" +"o Global help: Unless in a data entry window, pressing <F1> will give \n" +" you the global help window, which you are just reading.\n" "\n" -"Menu items beginning with following braces represent features that\n" -" [ ] can be built in or removed\n" -" < > can be built in, modularized or removed\n" -" { } can be built in or modularized (selected by other feature)\n" -" - - are selected by other feature,\n" -" XXX cannot be selected. Use Symbol Info to find out why,\n" -"while *, M or whitespace inside braces means to build in, build as\n" -"a module or to exclude the feature respectively.\n" +"o A short version of the global help is available by pressing <F3>.\n" "\n" -"To change any of these features, highlight it with the cursor\n" -"keys and press <Y> to build it in, <M> to make it a module or\n" -"<N> to removed it. You may also press the <Space Bar> to cycle\n" -"through the available options (ie. Y->N->M->Y).\n" +"o Local help: To get help related to the current menu entry, use any\n" +" of <?> <h>, or if in a data entry window then press <F1>.\n" "\n" -"Some additional keyboard hints:\n" "\n" -"Menus\n" -"----------\n" -"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" -" you wish to change use <Enter> or <Space>. Goto submenu by \n" -" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n" -" Submenus are designated by \"--->\".\n" -"\n" -" Searching: pressing '/' triggers interactive search mode.\n" -" nconfig performs a case insensitive search for the string\n" -" in the menu prompts (no regex support).\n" -" Pressing the up/down keys highlights the previous/next\n" -" matching item. Backspace removes one character from the\n" -" match string. Pressing either '/' again or ESC exits\n" -" search mode. All other keys behave normally.\n" -"\n" -" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n" -" unseen options into view.\n" +"Menu entries\n" +"------------\n" +"This interface lets you select features and parameters for the kernel\n" +"build. Kernel features can either be built-in, modularized, or removed.\n" +"Parameters must be entered as text or decimal or hexadecimal numbers.\n" "\n" -"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n" +"Menu entries beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized, are selected by another feature\n" +" - - are selected by another feature\n" +" XXX cannot be selected. Symbol Info <F2> tells you why.\n" +"*, M or whitespace inside braces means to build in, build as a module\n" +"or to exclude the feature respectively.\n" "\n" -"o To get help with an item, press <F1>\n" -" Shortcut: Press <h> or <?>.\n" +"To change any of these features, highlight it with the movement keys\n" +"listed below and press <y> to build it in, <m> to make it a module or\n" +"<n> to remove it. You may press the <Space> key to cycle through the\n" +"available options.\n" "\n" +"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n" +"empty submenu.\n" "\n" -"Radiolists (Choice lists)\n" -"-----------\n" -"o Use the cursor keys to select the option you wish to set and press\n" -" <S> or the <SPACE BAR>.\n" +"Menu navigation keys\n" +"----------------------------------------------------------------------\n" +"Linewise up <Up>\n" +"Linewise down <Down>\n" +"Pagewise up <Page Up>\n" +"Pagewise down <Page Down>\n" +"First entry <Home>\n" +"Last entry <End>\n" +"Enter a submenu <Right> <Enter>\n" +"Go back to parent menu <Left> <Esc> <F5>\n" +"Close a help window <Enter> <Esc> <F5>\n" +"Close entry window, apply <Enter>\n" +"Close entry window, forget <Esc> <F5>\n" +"Start incremental, case-insensitive search for STRING in menu entries,\n" +" no regex support, STRING is displayed in upper left corner\n" +" </>STRING\n" +" Remove last character <Backspace>\n" +" Jump to next hit <Down>\n" +" Jump to previous hit <Up>\n" +"Exit menu search mode </> <Esc>\n" +"Search for configuration variables with or without leading CONFIG_\n" +" <F8>RegExpr<Enter>\n" +"Verbose search help <F8><F1>\n" +"----------------------------------------------------------------------\n" "\n" -" Shortcut: Press the first letter of the option you wish to set then\n" -" press <S> or <SPACE BAR>.\n" +"Unless in a data entry window, key <1> may be used instead of <F1>,\n" +"<2> instead of <F2>, etc.\n" "\n" -"o To see available help for the item, press <F1>\n" -" Shortcut: Press <H> or <?>.\n" "\n" +"Radiolist (Choice list)\n" +"-----------------------\n" +"Use the movement keys listed above to select the option you wish to set\n" +"and press <Space>.\n" "\n" -"Data Entry\n" -"-----------\n" -"o Enter the requested information and press <ENTER>\n" -" If you are entering hexadecimal values, it is not necessary to\n" -" add the '0x' prefix to the entry.\n" "\n" -"o For help, press <F1>.\n" +"Data entry\n" +"----------\n" +"Enter the requested information and press <Enter>. Hexadecimal values\n" +"may be entered without the \"0x\" prefix.\n" "\n" "\n" -"Text Box (Help Window)\n" -"--------\n" -"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" -" keys h,j,k,l function here as do <SPACE BAR> for those\n" -" who are familiar with less and lynx.\n" +"Text Box (Help Window)\n" +"----------------------\n" +"Use movement keys as listed in table above.\n" "\n" -"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n" +"Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n" "\n" "\n" -"Alternate Configuration Files\n" +"Alternate configuration files\n" "-----------------------------\n" -"nconfig supports the use of alternate configuration files for\n" -"those who, for various reasons, find it necessary to switch\n" -"between different configurations.\n" +"nconfig supports switching between different configurations.\n" +"Press <F6> to save your current configuration. Press <F7> and enter\n" +"a file name to load a previously saved configuration.\n" "\n" -"At the end of the main menu you will find two options. One is\n" -"for saving the current configuration to a file of your choosing.\n" -"The other option is for loading a previously saved alternate\n" -"configuration.\n" "\n" -"Even if you don't use alternate configuration files, but you\n" -"find during a nconfig session that you have completely messed\n" -"up your settings, you may use the \"Load Alternate...\" option to\n" -"restore your previously saved settings from \".config\" without\n" -"restarting nconfig.\n" +"Terminal configuration\n" +"----------------------\n" +"If you use nconfig in a xterm window, make sure your TERM environment\n" +"variable specifies a terminal configuration which supports at least\n" +"16 colors. Otherwise nconfig will look rather bad.\n" "\n" -"Other information\n" -"-----------------\n" -"If you use nconfig in an XTERM window make sure you have your\n" -"$TERM variable set to point to a xterm definition which supports color.\n" -"Otherwise, nconfig will look rather bad. nconfig will not\n" -"display correctly in a RXVT window because rxvt displays only one\n" -"intensity of color, bright.\n" +"If the \"stty size\" command reports the current terminalsize correctly,\n" +"nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n" +"and display longer menus properly.\n" "\n" -"nconfig will display larger menus on screens or xterms which are\n" -"set to display more than the standard 25 row by 80 column geometry.\n" -"In order for this to work, the \"stty size\" command must be able to\n" -"display the screen's current row and column geometry. I STRONGLY\n" -"RECOMMEND that you make sure you do NOT have the shell variables\n" -"LINES and COLUMNS exported into your environment. Some distributions\n" -"export those variables via /etc/profile. Some ncurses programs can\n" -"become confused when those variables (LINES & COLUMNS) don't reflect\n" -"the true screen size.\n" "\n" -"Optional personality available\n" -"------------------------------\n" -"If you prefer to have all of the options listed in a single menu, rather\n" -"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n" -"environment variable set to single_menu. Example:\n" +"Single menu mode\n" +"----------------\n" +"If you prefer to have all of the menu entries listed in a single menu,\n" +"rather than the default multimenu hierarchy, run nconfig with\n" +"NCONFIG_MODE environment variable set to single_menu. Example:\n" "\n" "make NCONFIG_MODE=single_menu nconfig\n" "\n" -"<Enter> will then unroll the appropriate category, or enfold it if it\n" -"is already unrolled.\n" +"<Enter> will then unfold the appropriate category, or fold it if it\n" +"is already unfolded. Folded menu entries will be designated by a\n" +"leading \"++>\" and unfolded entries by a leading \"-->\".\n" "\n" -"Note that this mode can eventually be a little more CPU expensive\n" -"(especially with a larger number of unrolled categories) than the\n" -"default mode.\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_( -" You do not have function keys support. Please follow the\n" -" following instructions:\n" -" Arrow keys navigate the menu.\n" -" <Enter> or <right-arrow> selects submenus --->.\n" -" Capital Letters are hotkeys.\n" -" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" -" Pressing SpaceBar toggles between the above options.\n" -" Press <Esc> or <left-arrow> to go back one menu,\n" -" <?> or <h> for Help, </> for Search.\n" -" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n" -" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" -" <Esc> always leaves the current window.\n"), +"Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" +"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" +"\n" +"Use the following keys to navigate the menus:\n" +"Move up or down with <Up> and <Down>.\n" +"Enter a submenu with <Enter> or <Right>.\n" +"Exit a submenu to its parent menu with <Esc> or <Left>.\n" +"Pressing <y> includes, <n> excludes, <m> modularizes features.\n" +"Pressing <Space> cycles through the available options.\n" +"To search for menu entries press </>.\n" +"<Esc> always leaves the current window.\n" +"\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_( -" Arrow keys navigate the menu.\n" -" <Enter> or <right-arrow> selects submenus --->.\n" -" Capital Letters are hotkeys.\n" -" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" -" Pressing SpaceBar toggles between the above options\n" -" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n" -" <?>, <F1> or <h> for Help, </> for Search.\n" -" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n" -" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" -" <Esc> always leaves the current window\n"), +"Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" +"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" +"\n" +"Use the following keys to navigate the menus:\n" +"Move up or down with <Up> or <Down>.\n" +"Enter a submenu with <Enter> or <Right>.\n" +"Exit a submenu to its parent menu with <Esc> or <Left>.\n" +"Pressing <y> includes, <n> excludes, <m> modularizes features.\n" +"Pressing <Space> cycles through the available options.\n" +"To search for menu entries press </>.\n" +"<Esc> always leaves the current window.\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_( -" Use the arrow keys to navigate this window or\n" -" press the hotkey of the item you wish to select\n" -" followed by the <SPACE BAR>.\n" -" Press <?>, <F1> or <h> for additional information about this option.\n"), +"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_( "Please enter a decimal value.\n" "Fractions will not be accepted.\n" -"Press <RETURN> to accept, <ESC> to cancel."), +"Press <Enter> to apply, <Esc> to cancel."), inputbox_instructions_hex[] = N_( "Please enter a hexadecimal value.\n" -"Press <RETURN> to accept, <ESC> to cancel."), +"Press <Enter> to apply, <Esc> to cancel."), inputbox_instructions_string[] = N_( "Please enter a string value.\n" -"Press <RETURN> to accept, <ESC> to cancel."), +"Press <Enter> to apply, <Esc> to cancel."), setmod_text[] = N_( -"This feature depends on another which\n" -"has been configured as a module.\n" -"As a result, this feature will be built as a module."), +"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_( "Enter the name of the configuration file you wish to load.\n" -"Accept the name shown to restore the configuration you\n" -"last retrieved. Leave blank to abort."), +"Accept the name shown to restore the configuration you last\n" +"retrieved. Leave empty to abort."), load_config_help[] = N_( -"\n" "For various reasons, one may wish to keep several different\n" "configurations available on a single machine.\n" "\n" "If you have saved a previous configuration in a file other than the\n" -"default one, entering its name here will allow you to modify that\n" -"configuration.\n" +"default one, entering its name here will allow you to load and modify\n" +"that configuration.\n" "\n" -"If you are uncertain, then you have probably never used alternate\n" -"configuration files. You should therefor leave this blank to abort.\n"), +"Leave empty to abort.\n"), save_config_text[] = N_( "Enter a filename to which this configuration should be saved\n" -"as an alternate. Leave blank to abort."), +"as an alternate. Leave empty to abort."), save_config_help[] = N_( -"\n" -"For various reasons, one may wish to keep different configurations\n" -"available on a single machine.\n" +"For various reasons, one may wish to keep several different\n" +"configurations available on a single machine.\n" "\n" "Entering a file name here will allow you to later retrieve, modify\n" "and use the current configuration as an alternate to whatever\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"), +"Leave empty to abort.\n"), search_help[] = N_( -"\n" -"Search for symbols and display their relations. Regular expressions\n" -"are allowed.\n" -"Example: search for \"^FOO\"\n" +"Search for symbols (configuration variable names CONFIG_*) and display\n" +"their relations. Regular expressions are supported.\n" +"Example: Search for \"^FOO\".\n" "Result:\n" "-----------------------------------------------------------------\n" "Symbol: FOO [ = m]\n" @@ -223,32 +216,32 @@ search_help[] = N_( "Defined at drivers/pci/Kconfig:47\n" "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" "Location:\n" -" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" +" -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [ = y])\n" " -> PCI access mode (<choice> [ = y])\n" "Selects: LIBCRC32\n" "Selected by: BAR\n" "-----------------------------------------------------------------\n" -"o The line 'Prompt:' shows the text used in the menu structure for\n" -" this symbol\n" -"o The 'Defined at' line tell at what file / line number the symbol\n" -" is defined\n" -"o The 'Depends on:' line tell what symbols needs to be defined for\n" -" this symbol to be visible in the menu (selectable)\n" -"o The 'Location:' lines tell where in the menu structure this symbol\n" -" is located\n" -" A location followed by a [ = y] indicate that this is a selectable\n" -" menu item - and current value is displayed inside brackets.\n" -"o The 'Selects:' line tell what symbol will be automatically\n" -" selected if this symbol is selected (y or m)\n" -"o The 'Selected by' line tell what symbol has selected this symbol\n" +"o The line 'Prompt:' shows the text displayed for this symbol in\n" +" the menu hierarchy.\n" +"o The 'Defined at' line tells at what file / line number the symbol is\n" +" defined.\n" +"o The 'Depends on:' line lists symbols that need to be defined for\n" +" this symbol to be visible and selectable in the menu.\n" +"o The 'Location:' lines tell, where in the menu structure this symbol\n" +" is located. A location followed by a [ = y] indicates that this is\n" +" a selectable menu item, and the current value is displayed inside\n" +" brackets.\n" +"o The 'Selects:' line tells, what symbol will be automatically selected\n" +" if this symbol is selected (y or m).\n" +"o The 'Selected by' line tells what symbol has selected this symbol.\n" "\n" "Only relevant lines are shown.\n" "\n\n" "Search examples:\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" +"USB => find all symbols containing USB\n" +"^USB => find all symbols starting with USB\n" +"USB$ => find all symbols ending with USB\n" "\n"); struct mitem { @@ -319,19 +312,19 @@ struct function_keys function_keys[] = { }, { .key_str = "F2", - .func = "Sym Info", + .func = "SymInfo", .key = F_SYMBOL, .handler = handle_f2, }, { .key_str = "F3", - .func = "Insts", + .func = "Help 2", .key = F_INSTS, .handler = handle_f3, }, { .key_str = "F4", - .func = "Config", + .func = "ShowAll", .key = F_CONF, .handler = handle_f4, }, @@ -355,7 +348,7 @@ struct function_keys function_keys[] = { }, { .key_str = "F8", - .func = "Sym Search", + .func = "SymSearch", .key = F_SEARCH, .handler = handle_f8, }, @@ -372,15 +365,16 @@ static void print_function_line(void) int i; int offset = 1; const int skip = 1; + int lines = getmaxy(stdscr); for (i = 0; i < function_keys_num; i++) { (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); - mvwprintw(main_window, LINES-3, offset, + mvwprintw(main_window, lines-3, offset, "%s", function_keys[i].key_str); (void) wattrset(main_window, attributes[FUNCTION_TEXT]); offset += strlen(function_keys[i].key_str); - mvwprintw(main_window, LINES-3, + mvwprintw(main_window, lines-3, offset, "%s", function_keys[i].func); offset += strlen(function_keys[i].func) + skip; @@ -392,7 +386,7 @@ static void print_function_line(void) static void handle_f1(int *key, struct menu *current_item) { show_scroll_win(main_window, - _("README"), _(nconf_readme)); + _("Global help"), _(nconf_global_help)); return; } @@ -407,7 +401,7 @@ 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, - _("Instructions"), + _("Short help"), _(current_instructions)); return; } @@ -696,13 +690,18 @@ static void search_conf(void) { struct symbol **sym_arr; struct gstr res; + struct gstr title; char *dialog_input; int dres; + + title = str_new(); + 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"), - _("Enter " CONFIG_ " (sub)string to search for " - "(with or without \"" CONFIG_ "\")"), + str_get(&title), "", &dialog_input_result, &dialog_input_result_len); switch (dres) { case 0: @@ -712,6 +711,7 @@ again: _("Search Configuration"), search_help); goto again; default: + str_free(&title); return; } @@ -721,11 +721,12 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr); + res = get_relations_str(sym_arr, NULL); free(sym_arr); show_scroll_win(main_window, _("Search Results"), str_get(&res)); str_free(&res); + str_free(&title); } @@ -759,9 +760,9 @@ static void build_conf(struct menu *menu) indent + 1, ' ', prompt); } else item_make(menu, 'm', - " %*c%s --->", - indent + 1, - ' ', prompt); + " %*c%s %s", + indent + 1, ' ', prompt, + menu_is_empty(menu) ? "----" : "--->"); if (single_menu_mode && menu->data) goto conf_childs; @@ -903,7 +904,7 @@ static void build_conf(struct menu *menu) (sym_has_value(sym) || !sym_is_changable(sym)) ? "" : _(" (NEW)")); if (menu->prompt && menu->prompt->type == P_MENU) { - item_add_str(" --->"); + item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); return; } } @@ -954,7 +955,7 @@ static void show_menu(const char *prompt, const char *instructions, clear(); (void) wattrset(main_window, attributes[NORMAL]); - print_in_middle(stdscr, 1, 0, COLS, + print_in_middle(stdscr, 1, 0, getmaxx(stdscr), menu_backtitle, attributes[MAIN_HEADING]); @@ -1455,14 +1456,18 @@ static void conf_save(void) void setup_windows(void) { + int lines, columns; + + getmaxyx(stdscr, lines, columns); + if (main_window != NULL) delwin(main_window); /* set up the menu and menu window */ - main_window = newwin(LINES-2, COLS-2, 2, 1); + main_window = newwin(lines-2, columns-2, 2, 1); keypad(main_window, TRUE); - mwin_max_lines = LINES-7; - mwin_max_cols = COLS-6; + mwin_max_lines = lines-7; + mwin_max_cols = columns-6; /* panels order is from bottom to top */ new_panel(main_window); @@ -1470,6 +1475,7 @@ void setup_windows(void) int main(int ac, char **av) { + int lines, columns; char *mode; setlocale(LC_ALL, ""); @@ -1495,7 +1501,8 @@ int main(int ac, char **av) keypad(stdscr, TRUE); curs_set(0); - if (COLS < 75 || LINES < 20) { + getmaxyx(stdscr, lines, columns); + if (columns < 75 || lines < 20) { endwin(); printf("Your terminal should have at " "least 20 lines and 75 columns\n"); @@ -1503,7 +1510,11 @@ int main(int ac, char **av) } notimeout(stdscr, FALSE); +#if NCURSES_REENTRANT + set_escdelay(1); +#else ESCDELAY = 1; +#endif /* set btns menu */ curses_menu = new_menu(curses_menu_items); @@ -1543,4 +1554,3 @@ int main(int ac, char **av) endwin(); return 0; } - diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 3b18dd83966..8275f0e5510 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -48,7 +48,7 @@ static void set_normal_colors(void) init_pair(INPUT_FIELD, -1, -1); init_pair(FUNCTION_HIGHLIGHT, -1, -1); - init_pair(FUNCTION_TEXT, COLOR_BLUE, -1); + init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1); } /* available attributes: @@ -276,8 +276,8 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...) total_width = max(msg_width, btns_width); /* place dialog in middle of screen */ - y = (LINES-(msg_lines+4))/2; - x = (COLS-(total_width+4))/2; + y = (getmaxy(stdscr)-(msg_lines+4))/2; + x = (getmaxx(stdscr)-(total_width+4))/2; /* create the windows */ @@ -387,8 +387,8 @@ int dialog_inputbox(WINDOW *main_window, prompt_width = max(prompt_width, strlen(title)); /* place dialog in middle of screen */ - y = (LINES-(prompt_lines+4))/2; - x = (COLS-(prompt_width+4))/2; + y = (getmaxy(stdscr)-(prompt_lines+4))/2; + x = (getmaxx(stdscr)-(prompt_width+4))/2; strncpy(result, init, *result_len); @@ -545,7 +545,7 @@ void show_scroll_win(WINDOW *main_window, { int res; int total_lines = get_line_no(text); - int x, y; + int x, y, lines, columns; int start_x = 0, start_y = 0; int text_lines = 0, text_cols = 0; int total_cols = 0; @@ -556,6 +556,8 @@ void show_scroll_win(WINDOW *main_window, WINDOW *pad; PANEL *panel; + getmaxyx(stdscr, lines, columns); + /* find the widest line of msg: */ total_lines = get_line_no(text); for (i = 0; i < total_lines; i++) { @@ -569,14 +571,14 @@ void show_scroll_win(WINDOW *main_window, (void) wattrset(pad, attributes[SCROLLWIN_TEXT]); fill_window(pad, text); - win_lines = min(total_lines+4, LINES-2); - win_cols = min(total_cols+2, COLS-2); + win_lines = min(total_lines+4, lines-2); + win_cols = min(total_cols+2, columns-2); text_lines = max(win_lines-4, 0); text_cols = max(win_cols-2, 0); /* place window in middle of screen */ - y = (LINES-win_lines)/2; - x = (COLS-win_cols)/2; + y = (lines-win_lines)/2; + x = (columns-win_cols)/2; win = newwin(win_lines, win_cols, y, x); keypad(win, TRUE); @@ -604,9 +606,11 @@ void show_scroll_win(WINDOW *main_window, switch (res) { case KEY_NPAGE: case ' ': + case 'd': start_y += text_lines-2; break; case KEY_PPAGE: + case 'u': start_y -= text_lines+2; break; case KEY_HOME: @@ -632,10 +636,10 @@ void show_scroll_win(WINDOW *main_window, start_x++; break; } - if (res == 10 || res == 27 || res == 'q' - || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) { + if (res == 10 || res == 27 || res == 'q' || + res == KEY_F(F_HELP) || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) break; - } if (start_y < 0) start_y = 0; if (start_y >= total_lines-text_lines) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index df274febb3e..9d3b04b0769 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -6,6 +6,7 @@ #include <qglobal.h> #if QT_VERSION < 0x040000 +#include <stddef.h> #include <qmainwindow.h> #include <qvbox.h> #include <qvaluelist.h> @@ -68,6 +69,11 @@ static inline QString qgettext(const QString& str) return QString::fromLocal8Bit(gettext(str.latin1())); } +ConfigSettings::ConfigSettings() + : QSettings("kernel.org", "qconf") +{ +} + /** * Reads a list of integer values from the application settings. */ diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index 3715b3e7212..bde0c6b6f9e 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -32,6 +32,7 @@ class ConfigMainWindow; class ConfigSettings : public QSettings { public: + ConfigSettings(); Q3ValueList<int> readSizes(const QString& key, bool *ok); bool writeSizes(const QString& key, const Q3ValueList<int>& value); }; diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index bccf07ddd0b..9cb8522d8d2 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -45,6 +45,16 @@ use strict; use Getopt::Long; +# set the environment variable LOCALMODCONFIG_DEBUG to get +# debug output. +my $debugprint = 0; +$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG})); + +sub dprint { + return if (!$debugprint); + print STDERR @_; +} + my $config = ".config"; my $uname = `uname -r`; @@ -90,7 +100,7 @@ my @searchconfigs = ( }, ); -sub find_config { +sub read_config { foreach my $conf (@searchconfigs) { my $file = $conf->{"file"}; @@ -105,13 +115,15 @@ sub find_config { print STDERR "using config: '$file'\n"; - open(CIN, "$exec $file |") || die "Failed to run $exec $file"; - return; + open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file"; + my @x = <$infile>; + close $infile; + return @x; } die "No config file found"; } -find_config; +my @config_file = read_config; # Parse options my $localmodconfig = 0; @@ -121,7 +133,7 @@ GetOptions("localmodconfig" => \$localmodconfig, "localyesconfig" => \$localyesconfig); # Get the build source and top level Kconfig file (passed in) -my $ksource = $ARGV[0]; +my $ksource = ($ARGV[0] ? $ARGV[0] : '.'); my $kconfig = $ARGV[1]; my $lsmod_file = $ENV{'LSMOD'}; @@ -144,7 +156,6 @@ sub read_kconfig { my $state = "NONE"; my $config; - my @kconfigs; my $cont = 0; my $line; @@ -159,8 +170,8 @@ sub read_kconfig { $source =~ s/\$$env/$ENV{$env}/; } - open(KIN, "$source") || die "Can't open $kconfig"; - while (<KIN>) { + open(my $kinfile, '<', $source) || die "Can't open $kconfig"; + while (<$kinfile>) { chomp; # Make sure that lines ending with \ continue @@ -178,7 +189,13 @@ sub read_kconfig { # collect any Kconfig sources if (/^source\s*"(.*)"/) { - $kconfigs[$#kconfigs+1] = $1; + my $kconfig = $1; + # prevent reading twice. + if (!defined($read_kconfigs{$kconfig})) { + $read_kconfigs{$kconfig} = 1; + read_kconfig($kconfig); + } + next; } # configs found @@ -186,6 +203,7 @@ sub read_kconfig { $state = "NEW"; $config = $2; + # Add depends for 'if' nesting for (my $i = 0; $i < $iflevel; $i++) { if ($i) { $depends{$config} .= " " . $ifdeps[$i]; @@ -201,13 +219,21 @@ sub read_kconfig { $depends{$config} = $1; } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) { $depends{$config} .= " " . $1; + } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) { + my $dep = $3; + if ($dep !~ /^\s*(y|m|n)\s*$/) { + $dep =~ s/.*\sif\s+//; + $depends{$config} .= " " . $dep; + dprint "Added default depends $dep to $config\n"; + } # Get the configs that select this config } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) { - if (defined($selects{$1})) { - $selects{$1} .= " " . $config; + my $conf = $1; + if (defined($selects{$conf})) { + $selects{$conf} .= " " . $config; } else { - $selects{$1} = $config; + $selects{$conf} = $config; } # configs without prompts must be selected @@ -235,21 +261,14 @@ sub read_kconfig { $state = "NONE"; } } - close(KIN); - - # read in any configs that were found. - foreach $kconfig (@kconfigs) { - if (!defined($read_kconfigs{$kconfig})) { - $read_kconfigs{$kconfig} = 1; - read_kconfig($kconfig); - } - } + close($kinfile); } if ($kconfig) { read_kconfig($kconfig); } +# Makefiles can use variables to define their dependencies sub convert_vars { my ($line, %vars) = @_; @@ -278,8 +297,8 @@ foreach my $makefile (@makefiles) { my $line = ""; my %make_vars; - open(MIN,$makefile) || die "Can't open $makefile"; - while (<MIN>) { + open(my $infile, '<', $makefile) || die "Can't open $makefile"; + while (<$infile>) { # if this line ends with a backslash, continue chomp; if (/^(.*)\\$/) { @@ -293,6 +312,7 @@ foreach my $makefile (@makefiles) { my $objs; + # Convert variables in a line (could define configs) $_ = convert_vars($_, %make_vars); # collect objects after obj-$(CONFIG_FOO_BAR) @@ -325,10 +345,11 @@ foreach my $makefile (@makefiles) { } } } - close(MIN); + close($infile); } my %modules; +my $linfile; if (defined($lsmod_file)) { if ( ! -f $lsmod_file) { @@ -338,13 +359,10 @@ if (defined($lsmod_file)) { die "$lsmod_file not found"; } } - if ( -x $lsmod_file) { - # the file is executable, run it - open(LIN, "$lsmod_file|"); - } else { - # Just read the contents - open(LIN, "$lsmod_file"); - } + + my $otype = ( -x $lsmod_file) ? '-|' : '<'; + open($linfile, $otype, $lsmod_file); + } else { # see what modules are loaded on this system @@ -361,25 +379,36 @@ if (defined($lsmod_file)) { $lsmod = "lsmod"; } - open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod"; + open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod"; } -while (<LIN>) { +while (<$linfile>) { next if (/^Module/); # Skip the first line. if (/^(\S+)/) { $modules{$1} = 1; } } -close (LIN); +close ($linfile); # add to the configs hash all configs that are needed to enable -# a loaded module. +# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o +# where we know we need bar.o so we add FOO to the list. my %configs; foreach my $module (keys(%modules)) { if (defined($objects{$module})) { my @arr = @{$objects{$module}}; foreach my $conf (@arr) { $configs{$conf} = $module; + dprint "$conf added by direct ($module)\n"; + if ($debugprint) { + my $c=$conf; + $c =~ s/^CONFIG_//; + if (defined($depends{$c})) { + dprint " deps = $depends{$c}\n"; + } else { + dprint " no deps\n"; + } + } } } else { # Most likely, someone has a custom (binary?) module loaded. @@ -387,9 +416,24 @@ foreach my $module (keys(%modules)) { } } +# Read the current config, and see what is enabled. We want to +# ignore configs that we would not enable anyway. + +my %orig_configs; my $valid = "A-Za-z_0-9"; + +foreach my $line (@config_file) { + $_ = $line; + + if (/(CONFIG_[$valid]*)=(m|y)/) { + $orig_configs{$1} = $2; + } +} + my $repeat = 1; +my $depconfig; + # # Note, we do not care about operands (like: &&, ||, !) we want to add any # config that is in the depend list of another config. This script does @@ -398,7 +442,7 @@ my $repeat = 1; # to keep on. If A was on in the original config, B would not have been # and B would not be turned on by this script. # -sub parse_config_dep_select +sub parse_config_depends { my ($p) = @_; @@ -409,10 +453,16 @@ sub parse_config_dep_select $p =~ s/^[^$valid]*[$valid]+//; + # We only need to process if the depend config is a module + if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") { + next; + } + if (!defined($configs{$conf})) { # We must make sure that this config has its # dependencies met. $repeat = 1; # do again + dprint "$conf selected by depend $depconfig\n"; $configs{$conf} = 1; } } else { @@ -421,31 +471,132 @@ sub parse_config_dep_select } } -while ($repeat) { - $repeat = 0; +# Select is treated a bit differently than depends. We call this +# when a config has no prompt and requires another config to be +# selected. We use to just select all configs that selected this +# config, but found that that can balloon into enabling hundreds +# of configs that we do not care about. +# +# The idea is we look at all the configs that select it. If one +# is already in our list of configs to enable, then there's nothing +# else to do. If there isn't, we pick the first config that was +# enabled in the orignal config and use that. +sub parse_config_selects +{ + my ($config, $p) = @_; - foreach my $config (keys %configs) { - $config =~ s/^CONFIG_//; + my $next_config; + + while ($p =~ /[$valid]/) { + + if ($p =~ /^[^$valid]*([$valid]+)/) { + my $conf = "CONFIG_" . $1; + + $p =~ s/^[^$valid]*[$valid]+//; - if (defined($depends{$config})) { - # This config has dependencies. Make sure they are also included - parse_config_dep_select $depends{$config}; + # Make sure that this config exists in the current .config file + if (!defined($orig_configs{$conf})) { + dprint "$conf not set for $config select\n"; + next; + } + + # Check if something other than a module selects this config + if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") { + dprint "$conf (non module) selects config, we are good\n"; + # we are good with this + return; + } + if (defined($configs{$conf})) { + dprint "$conf selects $config so we are good\n"; + # A set config selects this config, we are good + return; + } + # Set this config to be selected + if (!defined($next_config)) { + $next_config = $conf; + } + } else { + die "this should never happen"; } + } - if (defined($prompts{$config}) || !defined($selects{$config})) { - next; + # If no possible config selected this, then something happened. + if (!defined($next_config)) { + print STDERR "WARNING: $config is required, but nothing in the\n"; + print STDERR " current config selects it.\n"; + return; + } + + # If we are here, then we found no config that is set and + # selects this config. Repeat. + $repeat = 1; + # Make this config need to be selected + $configs{$next_config} = 1; + dprint "$next_config selected by select $config\n"; +} + +my %process_selects; + +# loop through all configs, select their dependencies. +sub loop_depend { + $repeat = 1; + + while ($repeat) { + $repeat = 0; + + forloop: + foreach my $config (keys %configs) { + + # If this config is not a module, we do not need to process it + if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") { + next forloop; + } + + $config =~ s/^CONFIG_//; + $depconfig = $config; + + if (defined($depends{$config})) { + # This config has dependencies. Make sure they are also included + parse_config_depends $depends{$config}; + } + + # If the config has no prompt, then we need to check if a config + # that is enabled selected it. Or if we need to enable one. + if (!defined($prompts{$config}) && defined($selects{$config})) { + $process_selects{$config} = 1; + } } + } +} + +sub loop_select { + + foreach my $config (keys %process_selects) { + $config =~ s/^CONFIG_//; + + dprint "Process select $config\n"; # config has no prompt and must be selected. - parse_config_dep_select $selects{$config}; + parse_config_selects $config, $selects{$config}; } } +while ($repeat) { + # Get the first set of configs and their dependencies. + loop_depend; + + $repeat = 0; + + # Now we need to see if we have to check selects; + loop_select; +} + my %setconfigs; # Finally, read the .config file and turn off any module enabled that # we could not find a reason to keep enabled. -while(<CIN>) { +foreach my $line (@config_file) { + $_ = $line; if (/CONFIG_IKCONFIG/) { if (/# CONFIG_IKCONFIG is not set/) { @@ -463,6 +614,8 @@ while(<CIN>) { if (defined($configs{$1})) { if ($localyesconfig) { $setconfigs{$1} = 'y'; + print "$1=y\n"; + next; } else { $setconfigs{$1} = $2; } @@ -473,7 +626,6 @@ while(<CIN>) { } print; } -close(CIN); # Integrity check, make sure all modules that we want enabled do # indeed have their configs set. diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 071f00c3046..7caabdb51c6 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -136,7 +136,7 @@ static struct property *sym_get_range_prop(struct symbol *sym) return NULL; } -static int sym_get_range_val(struct symbol *sym, int base) +static long long sym_get_range_val(struct symbol *sym, int base) { sym_calc_value(sym); switch (sym->type) { @@ -149,13 +149,14 @@ static int sym_get_range_val(struct symbol *sym, int base) default: break; } - return strtol(sym->curr.val, NULL, base); + return strtoll(sym->curr.val, NULL, base); } static void sym_validate_range(struct symbol *sym) { struct property *prop; - int base, val, val2; + int base; + long long val, val2; char str[64]; switch (sym->type) { @@ -171,7 +172,7 @@ static void sym_validate_range(struct symbol *sym) prop = sym_get_range_prop(sym); if (!prop) return; - val = strtol(sym->curr.val, NULL, base); + val = strtoll(sym->curr.val, NULL, base); val2 = sym_get_range_val(prop->expr->left.sym, base); if (val >= val2) { val2 = sym_get_range_val(prop->expr->right.sym, base); @@ -179,9 +180,9 @@ static void sym_validate_range(struct symbol *sym) return; } if (sym->type == S_INT) - sprintf(str, "%d", val2); + sprintf(str, "%lld", val2); else - sprintf(str, "0x%x", val2); + sprintf(str, "0x%llx", val2); sym->curr.val = strdup(str); } @@ -262,11 +263,18 @@ static struct symbol *sym_calc_choice(struct symbol *sym) struct symbol *def_sym; struct property *prop; struct expr *e; + int flags; /* first calculate all choice values' visibilities */ + flags = sym->flags; prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, def_sym) + expr_list_for_each_sym(prop->expr, e, def_sym) { sym_calc_visibility(def_sym); + if (def_sym->visible != no) + flags &= def_sym->flags; + } + + sym->flags &= flags | ~SYMBOL_DEF_USER; /* is the user choice visible? */ def_sym = sym->def[S_DEF_USER].val; @@ -293,6 +301,14 @@ void sym_calc_value(struct symbol *sym) if (sym->flags & SYMBOL_VALID) return; + + if (sym_is_choice_value(sym) && + sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { + sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; + prop = sym_get_choice_prop(sym); + sym_calc_value(prop_get_symbol(prop)); + } + sym->flags |= SYMBOL_VALID; oldval = sym->curr; @@ -418,6 +434,9 @@ void sym_calc_value(struct symbol *sym) if (sym->flags & SYMBOL_AUTO) sym->flags &= ~SYMBOL_WRITE; + + if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) + set_all_choice_values(sym); } void sym_clear_all_valid(void) @@ -576,7 +595,7 @@ bool sym_string_valid(struct symbol *sym, const char *str) bool sym_string_within_range(struct symbol *sym, const char *str) { struct property *prop; - int val; + long long val; switch (sym->type) { case S_STRING: @@ -587,7 +606,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str) prop = sym_get_range_prop(sym); if (!prop) return true; - val = strtol(str, NULL, 10); + val = strtoll(str, NULL, 10); return val >= sym_get_range_val(prop->expr->left.sym, 10) && val <= sym_get_range_val(prop->expr->right.sym, 10); case S_HEX: @@ -596,7 +615,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str) prop = sym_get_range_prop(sym); if (!prop) return true; - val = strtol(str, NULL, 16); + val = strtoll(str, NULL, 16); return val >= sym_get_range_val(prop->expr->left.sym, 16) && val <= sym_get_range_val(prop->expr->right.sym, 16); case S_BOOLEAN: @@ -649,11 +668,11 @@ bool sym_set_string_value(struct symbol *sym, const char *newval) size = strlen(newval) + 1; if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { size += 2; - sym->def[S_DEF_USER].val = val = malloc(size); + sym->def[S_DEF_USER].val = val = xmalloc(size); *val++ = '0'; *val++ = 'x'; } else if (!oldval || strcmp(oldval, newval)) - sym->def[S_DEF_USER].val = val = malloc(size); + sym->def[S_DEF_USER].val = val = xmalloc(size); else return true; @@ -805,7 +824,7 @@ struct symbol *sym_lookup(const char *name, int flags) hash = 0; } - symbol = malloc(sizeof(*symbol)); + symbol = xmalloc(sizeof(*symbol)); memset(symbol, 0, sizeof(*symbol)); symbol->name = new_name; symbol->type = S_UNKNOWN; @@ -856,7 +875,7 @@ const char *sym_expand_string_value(const char *in) size_t reslen; reslen = strlen(in) + 1; - res = malloc(reslen); + res = xmalloc(reslen); res[0] = '\0'; while ((src = strchr(in, '$'))) { @@ -914,7 +933,7 @@ const char *sym_escape_string_value(const char *in) p++; } - res = malloc(reslen); + res = xmalloc(reslen); res[0] = '\0'; strcat(res, "\""); @@ -936,38 +955,89 @@ const char *sym_escape_string_value(const char *in) return res; } +struct sym_match { + struct symbol *sym; + off_t so, eo; +}; + +/* Compare matched symbols as thus: + * - first, symbols that match exactly + * - then, alphabetical sort + */ +static int sym_rel_comp(const void *sym1, const void *sym2) +{ + const struct sym_match *s1 = sym1; + const struct sym_match *s2 = sym2; + int exact1, exact2; + + /* Exact match: + * - if matched length on symbol s1 is the length of that symbol, + * then this symbol should come first; + * - if matched length on symbol s2 is the length of that symbol, + * then this symbol should come first. + * Note: since the search can be a regexp, both symbols may match + * exactly; if this is the case, we can't decide which comes first, + * and we fallback to sorting alphabetically. + */ + exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); + exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); + if (exact1 && !exact2) + return -1; + if (!exact1 && exact2) + return 1; + + /* As a fallback, sort symbols alphabetically */ + return strcmp(s1->sym->name, s2->sym->name); +} + struct symbol **sym_re_search(const char *pattern) { struct symbol *sym, **sym_arr = NULL; + struct sym_match *sym_match_arr = NULL; int i, cnt, size; regex_t re; + regmatch_t match[1]; cnt = size = 0; /* Skip if empty */ if (strlen(pattern) == 0) return NULL; - if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) + if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) return NULL; for_all_symbols(i, sym) { if (sym->flags & SYMBOL_CONST || !sym->name) continue; - if (regexec(&re, sym->name, 0, NULL, 0)) + if (regexec(&re, sym->name, 1, match, 0)) continue; - if (cnt + 1 >= size) { - void *tmp = sym_arr; + if (cnt >= size) { + void *tmp; size += 16; - sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); - if (!sym_arr) { - free(tmp); - return NULL; - } + tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); + if (!tmp) + goto sym_re_search_free; + sym_match_arr = tmp; } sym_calc_value(sym); - sym_arr[cnt++] = sym; + /* As regexec returned 0, we know we have a match, so + * we can use match[0].rm_[se]o without further checks + */ + sym_match_arr[cnt].so = match[0].rm_so; + sym_match_arr[cnt].eo = match[0].rm_eo; + sym_match_arr[cnt++].sym = sym; } - if (sym_arr) + if (sym_match_arr) { + qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); + sym_arr = malloc((cnt+1) * sizeof(struct symbol)); + if (!sym_arr) + goto sym_re_search_free; + for (i = 0; i < cnt; i++) + sym_arr[i] = sym_match_arr[i].sym; sym_arr[cnt] = NULL; + } +sym_re_search_free: + /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ + free(sym_match_arr); regfree(&re); return sym_arr; @@ -977,7 +1047,7 @@ struct symbol **sym_re_search(const char *pattern) * When we check for recursive dependencies we use a stack to save * current state so we can print out relevant info to user. * The entries are located on the call stack so no need to free memory. - * Note inser() remove() must always match to properly clear the stack. + * Note insert() remove() must always match to properly clear the stack. */ static struct dep_stack { struct dep_stack *prev, *next; @@ -1221,7 +1291,7 @@ struct property *prop_alloc(enum prop_type type, struct symbol *sym) struct property *prop; struct property **propp; - prop = malloc(sizeof(*prop)); + prop = xmalloc(sizeof(*prop)); memset(prop, 0, sizeof(*prop)); prop->type = type; prop->sym = sym; diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index d0b8b2318e4..94f9c83e324 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -23,7 +23,7 @@ struct file *file_lookup(const char *name) } } - file = malloc(sizeof(*file)); + file = xmalloc(sizeof(*file)); memset(file, 0, sizeof(*file)); file->name = file_name; file->next = file_list; @@ -81,7 +81,7 @@ int file_write_dep(const char *name) struct gstr str_new(void) { struct gstr gs; - gs.s = malloc(sizeof(char) * 64); + gs.s = xmalloc(sizeof(char) * 64); gs.len = 64; gs.max_width = 0; strcpy(gs.s, "\0"); @@ -138,3 +138,20 @@ const char *str_get(struct gstr *gs) return gs->s; } +void *xmalloc(size_t size) +{ + void *p = malloc(size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf index f14ab41154b..b6ac02d604f 100644 --- a/scripts/kconfig/zconf.gperf +++ b/scripts/kconfig/zconf.gperf @@ -44,4 +44,5 @@ 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/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped index 40df0005daa..c77a8eff1ef 100644 --- a/scripts/kconfig/zconf.hash.c_shipped +++ b/scripts/kconfig/zconf.hash.c_shipped @@ -55,10 +55,10 @@ kconf_id_hash (register const char *str, register unsigned int len) 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 25, 25, + 73, 73, 73, 73, 73, 73, 73, 5, 25, 25, 0, 0, 0, 5, 0, 0, 73, 73, 5, 0, 10, 5, 45, 73, 20, 20, 0, 15, 15, 73, - 20, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 20, 5, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, @@ -106,6 +106,7 @@ struct kconf_id_strings_t char kconf_id_strings_str23[sizeof("mainmenu")]; char kconf_id_strings_str25[sizeof("menuconfig")]; char kconf_id_strings_str27[sizeof("modules")]; + char kconf_id_strings_str28[sizeof("allnoconfig_y")]; char kconf_id_strings_str29[sizeof("menu")]; char kconf_id_strings_str31[sizeof("select")]; char kconf_id_strings_str32[sizeof("comment")]; @@ -141,6 +142,7 @@ static const struct kconf_id_strings_t kconf_id_strings_contents = "mainmenu", "menuconfig", "modules", + "allnoconfig_y", "menu", "select", "comment", @@ -170,7 +172,7 @@ kconf_id_lookup (register const char *str, register unsigned int len) { enum { - TOTAL_KEYWORDS = 32, + TOTAL_KEYWORDS = 33, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 14, MIN_HASH_VALUE = 2, @@ -219,7 +221,8 @@ kconf_id_lookup (register const char *str, register unsigned int len) {-1}, #line 44 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, - {-1}, +#line 47 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION}, #line 16 "scripts/kconfig/zconf.gperf" {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, {-1}, @@ -282,5 +285,5 @@ kconf_id_lookup (register const char *str, register unsigned int len) } return 0; } -#line 47 "scripts/kconfig/zconf.gperf" +#line 48 "scripts/kconfig/zconf.gperf" diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l index 00f9d3a9cf8..6c62d93b4ff 100644 --- a/scripts/kconfig/zconf.l +++ b/scripts/kconfig/zconf.l @@ -27,8 +27,8 @@ static char *text; static int text_size, text_asize; struct buffer { - struct buffer *parent; - YY_BUFFER_STATE state; + struct buffer *parent; + YY_BUFFER_STATE state; }; struct buffer *current_buf; @@ -40,7 +40,7 @@ static void zconf_endfile(void); static void new_string(void) { - text = malloc(START_STRSIZE); + text = xmalloc(START_STRSIZE); text_asize = START_STRSIZE; text_size = 0; *text = 0; @@ -62,13 +62,12 @@ static void append_string(const char *str, int size) static void alloc_string(const char *str, int size) { - text = malloc(size + 1); + text = xmalloc(size + 1); memcpy(text, str, size); text[size] = 0; } %} -ws [ \n\t] n [A-Za-z0-9_] %% @@ -288,7 +287,7 @@ void zconf_initscan(const char *name) exit(1); } - current_buf = malloc(sizeof(*current_buf)); + current_buf = xmalloc(sizeof(*current_buf)); memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); @@ -299,7 +298,7 @@ void zconf_nextfile(const char *name) { struct file *iter; struct file *file = file_lookup(name); - struct buffer *buf = malloc(sizeof(*buf)); + struct buffer *buf = xmalloc(sizeof(*buf)); memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; diff --git a/scripts/kconfig/zconf.lex.c_shipped b/scripts/kconfig/zconf.lex.c_shipped index c32b1a49f5a..349a7f24315 100644 --- a/scripts/kconfig/zconf.lex.c_shipped +++ b/scripts/kconfig/zconf.lex.c_shipped @@ -789,8 +789,8 @@ static char *text; static int text_size, text_asize; struct buffer { - struct buffer *parent; - YY_BUFFER_STATE state; + struct buffer *parent; + YY_BUFFER_STATE state; }; struct buffer *current_buf; @@ -802,7 +802,7 @@ static void zconf_endfile(void); static void new_string(void) { - text = malloc(START_STRSIZE); + text = xmalloc(START_STRSIZE); text_asize = START_STRSIZE; text_size = 0; *text = 0; @@ -824,7 +824,7 @@ static void append_string(const char *str, int size) static void alloc_string(const char *str, int size) { - text = malloc(size + 1); + text = xmalloc(size + 1); memcpy(text, str, size); text[size] = 0; } @@ -2343,7 +2343,7 @@ void zconf_initscan(const char *name) exit(1); } - current_buf = malloc(sizeof(*current_buf)); + current_buf = xmalloc(sizeof(*current_buf)); memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); @@ -2354,7 +2354,7 @@ void zconf_nextfile(const char *name) { struct file *iter; struct file *file = file_lookup(name); - struct buffer *buf = malloc(sizeof(*buf)); + struct buffer *buf = xmalloc(sizeof(*buf)); memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index f636141e7bf..de5e84ed3f9 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -1,9 +1,8 @@ -/* A Bison parser, made by GNU Bison 2.4.3. */ +/* A Bison parser, made by GNU Bison 2.5. */ -/* Skeleton implementation for Bison's Yacc-like parsers in C +/* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. 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 @@ -45,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.4.3" +#define YYBISON_VERSION "2.5" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -302,11 +301,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # endif @@ -329,24 +328,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined _STDLIB_H \ +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -375,23 +374,7 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif +# define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of @@ -411,6 +394,26 @@ union yyalloc #endif +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + /* YYFINAL -- State number of the termination state. */ #define YYFINAL 11 /* YYLAST -- Last index in YYTABLE. */ @@ -529,18 +532,18 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 104, 104, 104, 106, 106, 108, 110, 111, 112, - 113, 114, 115, 119, 123, 123, 123, 123, 123, 123, - 123, 123, 127, 128, 129, 130, 131, 132, 136, 137, - 143, 151, 157, 165, 175, 177, 178, 179, 180, 181, - 182, 185, 193, 199, 209, 215, 221, 224, 226, 237, - 238, 243, 252, 257, 265, 268, 270, 271, 272, 273, - 274, 277, 283, 294, 300, 310, 312, 317, 325, 333, - 336, 338, 339, 340, 345, 352, 359, 364, 372, 375, - 377, 378, 379, 382, 390, 397, 404, 410, 417, 419, - 420, 421, 424, 432, 434, 435, 438, 445, 447, 452, - 453, 456, 457, 458, 462, 463, 466, 467, 470, 471, - 472, 473, 474, 475, 476, 479, 480, 483, 484 + 0, 103, 103, 103, 105, 105, 107, 109, 110, 111, + 112, 113, 114, 118, 122, 122, 122, 122, 122, 122, + 122, 122, 126, 127, 128, 129, 130, 131, 135, 136, + 142, 150, 156, 164, 174, 176, 177, 178, 179, 180, + 181, 184, 192, 198, 208, 214, 220, 223, 225, 236, + 237, 242, 251, 256, 264, 267, 269, 270, 271, 272, + 273, 276, 282, 293, 299, 309, 311, 316, 324, 332, + 335, 337, 338, 339, 344, 351, 358, 363, 371, 374, + 376, 377, 378, 381, 389, 396, 403, 409, 416, 418, + 419, 420, 423, 431, 433, 434, 437, 444, 446, 451, + 452, 455, 456, 457, 461, 462, 465, 466, 469, 470, + 471, 472, 473, 474, 475, 478, 479, 482, 483 }; #endif @@ -615,8 +618,8 @@ static const yytype_uint8 yyr2[] = 3, 3, 2, 3, 3, 1, 1, 0, 1 }; -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { @@ -691,8 +694,7 @@ static const yytype_int16 yypgoto[] = /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ + number is the opposite. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -86 static const yytype_int16 yytable[] = { @@ -728,6 +730,12 @@ static const yytype_int16 yytable[] = 184 }; +#define yypact_value_is_default(yystate) \ + ((yystate) == (-90)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + static const yytype_int16 yycheck[] = { 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, @@ -821,7 +829,6 @@ do \ { \ yychar = (Token); \ yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ @@ -863,19 +870,10 @@ while (YYID (0)) #endif -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ +/* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif @@ -1067,7 +1065,6 @@ int yydebug; # define YYMAXDEPTH 10000 #endif - #if YYERROR_VERBOSE @@ -1170,115 +1167,142 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } - if (yysize_overflow) - return YYSIZE_MAXIMUM; + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; } #endif /* YYERROR_VERBOSE */ - /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -1341,6 +1365,7 @@ yydestruct (yymsg, yytype, yyvaluep) } } + /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus @@ -1367,10 +1392,9 @@ YYSTYPE yylval; int yynerrs; - -/*-------------------------. -| yyparse or yypush_parse. | -`-------------------------*/ +/*----------. +| yyparse. | +`----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ @@ -1394,8 +1418,6 @@ yyparse () #endif #endif { - - int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -1550,7 +1572,7 @@ yybackup: /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) + if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ @@ -1581,8 +1603,8 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; + if (yytable_value_is_error (yyn)) + goto yyerrlab; yyn = -yyn; goto yyreduce; } @@ -1637,34 +1659,34 @@ yyreduce: { case 10: - { zconf_error("unexpected end statement"); ;} + { zconf_error("unexpected end statement"); } break; case 11: - { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;} + { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); } break; case 12: { zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); -;} +} break; case 13: - { zconf_error("invalid statement"); ;} + { zconf_error("invalid statement"); } break; case 28: - { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;} + { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); } break; case 29: - { zconf_error("invalid option"); ;} + { zconf_error("invalid option"); } break; case 30: @@ -1674,7 +1696,7 @@ yyreduce: sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); -;} +} break; case 31: @@ -1682,7 +1704,7 @@ yyreduce: { menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -;} +} break; case 32: @@ -1692,7 +1714,7 @@ yyreduce: sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); -;} +} break; case 33: @@ -1704,7 +1726,7 @@ yyreduce: zconfprint("warning: menuconfig statement without prompt"); menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -;} +} break; case 41: @@ -1714,7 +1736,7 @@ yyreduce: printd(DEBUG_PARSE, "%s:%d:type(%u)\n", zconf_curname(), zconf_lineno(), (yyvsp[(1) - (3)].id)->stype); -;} +} break; case 42: @@ -1722,7 +1744,7 @@ yyreduce: { menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -;} +} break; case 43: @@ -1734,7 +1756,7 @@ yyreduce: printd(DEBUG_PARSE, "%s:%d:default(%u)\n", zconf_curname(), zconf_lineno(), (yyvsp[(1) - (4)].id)->stype); -;} +} break; case 44: @@ -1742,7 +1764,7 @@ yyreduce: { menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); -;} +} break; case 45: @@ -1750,7 +1772,7 @@ yyreduce: { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); -;} +} break; case 48: @@ -1762,17 +1784,17 @@ yyreduce: else zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); free((yyvsp[(2) - (3)].string)); -;} +} break; case 49: - { (yyval.string) = NULL; ;} + { (yyval.string) = NULL; } break; case 50: - { (yyval.string) = (yyvsp[(2) - (2)].string); ;} + { (yyval.string) = (yyvsp[(2) - (2)].string); } break; case 51: @@ -1783,14 +1805,14 @@ yyreduce: menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); -;} +} break; case 52: { (yyval.menu) = menu_add_menu(); -;} +} break; case 53: @@ -1800,7 +1822,7 @@ yyreduce: menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); } -;} +} break; case 61: @@ -1808,7 +1830,7 @@ yyreduce: { menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -;} +} break; case 62: @@ -1821,7 +1843,7 @@ yyreduce: (yyvsp[(1) - (3)].id)->stype); } else YYERROR; -;} +} break; case 63: @@ -1829,7 +1851,7 @@ yyreduce: { current_entry->sym->flags |= SYMBOL_OPTIONAL; printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); -;} +} break; case 64: @@ -1841,7 +1863,7 @@ yyreduce: zconf_curname(), zconf_lineno()); } else YYERROR; -;} +} break; case 67: @@ -1851,7 +1873,7 @@ yyreduce: menu_add_entry(NULL); menu_add_dep((yyvsp[(2) - (3)].expr)); (yyval.menu) = menu_add_menu(); -;} +} break; case 68: @@ -1861,14 +1883,14 @@ yyreduce: menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); } -;} +} break; case 74: { menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); -;} +} break; case 75: @@ -1877,14 +1899,14 @@ yyreduce: menu_add_entry(NULL); menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); -;} +} break; case 76: { (yyval.menu) = menu_add_menu(); -;} +} break; case 77: @@ -1894,7 +1916,7 @@ yyreduce: menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); } -;} +} break; case 83: @@ -1902,7 +1924,7 @@ yyreduce: { printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); zconf_nextfile((yyvsp[(2) - (3)].string)); -;} +} break; case 84: @@ -1911,14 +1933,14 @@ yyreduce: menu_add_entry(NULL); menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); -;} +} break; case 85: { menu_end_entry(); -;} +} break; case 86: @@ -1926,14 +1948,14 @@ yyreduce: { printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); zconf_starthelp(); -;} +} break; case 87: { current_entry->help = (yyvsp[(2) - (2)].string); -;} +} break; case 92: @@ -1941,102 +1963,113 @@ yyreduce: { menu_add_dep((yyvsp[(3) - (4)].expr)); printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); -;} +} break; case 96: { menu_add_visibility((yyvsp[(2) - (2)].expr)); -;} +} break; case 98: { menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); -;} +} break; case 101: - { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + { (yyval.id) = (yyvsp[(1) - (2)].id); } break; case 102: - { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + { (yyval.id) = (yyvsp[(1) - (2)].id); } break; case 103: - { (yyval.id) = (yyvsp[(1) - (2)].id); ;} + { (yyval.id) = (yyvsp[(1) - (2)].id); } break; case 106: - { (yyval.expr) = NULL; ;} + { (yyval.expr) = NULL; } break; case 107: - { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;} + { (yyval.expr) = (yyvsp[(2) - (2)].expr); } break; case 108: - { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;} + { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); } break; case 109: - { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } break; case 110: - { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } break; case 111: - { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;} + { (yyval.expr) = (yyvsp[(2) - (3)].expr); } break; case 112: - { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;} + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); } break; case 113: - { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 114: - { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 115: - { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;} + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); } break; case 116: - { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;} + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); } break; case 117: - { (yyval.string) = NULL; ;} + { (yyval.string) = NULL; } break; default: break; } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -2064,6 +2097,10 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -2071,37 +2108,36 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; } +# undef YYSYNTAX_ERROR #endif } @@ -2160,7 +2196,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) + if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -2219,8 +2255,13 @@ yyexhaustedlab: yyreturn: if (yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -2256,9 +2297,6 @@ void conf_parse(const char *name) sym_init(); _menu_init(); - modules_sym = sym_lookup(NULL, 0); - modules_sym->type = S_BOOLEAN; - modules_sym->flags |= SYMBOL_AUTO; rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); if (getenv("ZCONF_DEBUG")) @@ -2266,12 +2304,8 @@ void conf_parse(const char *name) zconfparse(); if (zconfnerrs) exit(1); - if (!modules_sym->prop) { - struct property *prop; - - prop = prop_alloc(P_DEFAULT, modules_sym); - prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0)); - } + if (!modules_sym) + modules_sym = sym_find( "n" ); rootmenu.prompt->text = _(rootmenu.prompt->text); rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); @@ -2280,7 +2314,7 @@ void conf_parse(const char *name) for_all_symbols(i, sym) { if (sym_check_deps(sym)) zconfnerrs++; - } + } if (zconfnerrs) exit(1); sym_set_change_count(1); diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 864da07ba4a..0f683cfa53e 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -493,9 +493,6 @@ void conf_parse(const char *name) sym_init(); _menu_init(); - modules_sym = sym_lookup(NULL, 0); - modules_sym->type = S_BOOLEAN; - modules_sym->flags |= SYMBOL_AUTO; rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); if (getenv("ZCONF_DEBUG")) @@ -503,12 +500,8 @@ void conf_parse(const char *name) zconfparse(); if (zconfnerrs) exit(1); - if (!modules_sym->prop) { - struct property *prop; - - prop = prop_alloc(P_DEFAULT, modules_sym); - prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0)); - } + if (!modules_sym) + modules_sym = sym_find( "n" ); rootmenu.prompt->text = _(rootmenu.prompt->text); rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); @@ -517,7 +510,7 @@ void conf_parse(const char *name) for_all_symbols(i, sym) { if (sym_check_deps(sym)) zconfnerrs++; - } + } if (zconfnerrs) exit(1); sym_set_change_count(1); diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 9b0c0b8b4ab..16a07cfa4d3 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -6,6 +6,7 @@ use strict; ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## ## Copyright (C) 2005-2012 Randy Dunlap ## +## Copyright (C) 2012 Dan Luedtke ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -35,6 +36,8 @@ use strict; # Small fixes (like spaces vs. \s in regex) # -- Tim Jansen <tim@tjansen.de> +# 25/07/2012 - Added support for HTML5 +# -- Dan Luedtke <mail@danrl.de> # # This will read a 'c' file and scan for embedded comments in the @@ -44,12 +47,16 @@ use strict; # Note: This only supports 'c'. # usage: -# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ] -# [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile +# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ] +# [ -no-doc-sections ] +# [ -function funcname [ -function funcname ...] ] +# c file(s)s > outputfile # or -# [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile +# [ -nofunction funcname [ -function funcname ...] ] +# c file(s)s > outputfile # -# Set output format using one of -docbook -html -text or -man. Default is man. +# Set output format using one of -docbook -html -html5 -text or -man. +# Default is man. # The -list format is for internal use by docproc. # # -no-doc-sections @@ -130,6 +137,8 @@ use strict; # should document the "Context:" of the function, e.g. whether the functions # can be called form interrupts. Unlike other sections you can end it with an # empty line. +# A non-void function should have a "Return:" section describing the return +# value(s). # Example-sections should contain the string EXAMPLE so that they are marked # appropriately in DocBook. # @@ -182,6 +191,14 @@ my $local_lt = "\\\\\\\\lt:"; my $local_gt = "\\\\\\\\gt:"; my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" +# html version 5 +my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>", + $type_func, "<span class=\"func\">\$1</span>", + $type_struct_xml, "<span class=\"struct\">\$1</span>", + $type_env, "<span class=\"env\">\$1</span>", + $type_param, "<span class=\"param\">\$1</span>" ); +my $blankline_html5 = $local_lt . "br /" . $local_gt; + # XML, docbook format my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>", $type_constant, "<constant>\$1</constant>", @@ -230,6 +247,7 @@ my $dohighlight = ""; my $verbose = 0; my $output_mode = "man"; +my $output_preformatted = 0; my $no_doc_sections = 0; my %highlights = %highlights_man; my $blankline = $blankline_man; @@ -239,6 +257,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')[(localtime)[4]] . " " . ((localtime)[5]+1900); +my $show_not_found = 0; # Essentially these are globals. # They probably want to be tidied up, made more localised or something. @@ -280,9 +299,10 @@ my $doc_special = "\@\%\$\&"; my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; +my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; -my $doc_content = $doc_com . '(.*)'; +my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; my %constants; @@ -298,6 +318,7 @@ my $section_default = "Description"; # default section my $section_intro = "Introduction"; my $section = $section_default; my $section_context = "Context"; +my $section_return = "Return"; my $undescribed = "-- undescribed --"; @@ -309,6 +330,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "html"; %highlights = %highlights_html; $blankline = $blankline_html; + } elsif ($cmd eq "-html5") { + $output_mode = "html5"; + %highlights = %highlights_html5; + $blankline = $blankline_html5; } elsif ($cmd eq "-man") { $output_mode = "man"; %highlights = %highlights_man; @@ -345,16 +370,19 @@ while ($ARGV[0] =~ m/^-(.*)/) { usage(); } elsif ($cmd eq '-no-doc-sections') { $no_doc_sections = 1; + } elsif ($cmd eq '-show-not-found') { + $show_not_found = 1; } } # continue execution near EOF; sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; + print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n"; print " [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; + print " [ -v ]\n"; print " c source file(s) > outputfile\n"; print " -v : verbose output, more warnings & other info listed\n"; exit 1; @@ -448,7 +476,8 @@ sub output_highlight { # confess "output_highlight got called with no args?\n"; # } - if ($output_mode eq "html" || $output_mode eq "xml") { + if ($output_mode eq "html" || $output_mode eq "html5" || + $output_mode eq "xml") { $contents = local_unescape($contents); # convert data read & converted thru xml_escape() into &xyz; format: $contents =~ s/\\\\\\/\&/g; @@ -458,9 +487,19 @@ sub output_highlight { die $@ if $@; # print STDERR "contents af:$contents\n"; +# strip whitespaces when generating html5 + if ($output_mode eq "html5") { + $contents =~ s/^\s+//; + $contents =~ s/\s+$//; + } foreach $line (split "\n", $contents) { + if (! $output_preformatted) { + $line =~ s/^\s*//; + } if ($line eq ""){ - print $lineprefix, local_unescape($blankline); + if (! $output_preformatted) { + print $lineprefix, local_unescape($blankline); + } } else { $line =~ s/\\\\\\/\&/g; if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { @@ -473,7 +512,7 @@ sub output_highlight { } } -#output sections in html +# output sections in html sub output_section_html(%) { my %args = %{$_[0]}; my $section; @@ -633,6 +672,239 @@ sub output_blockhead_html(%) { print "<hr>\n"; } +# output sections in html5 +sub output_section_html5(%) { + my %args = %{$_[0]}; + my $section; + + foreach $section (@{$args{'sectionlist'}}) { + print "<section>\n"; + print "<h1>$section</h1>\n"; + print "<p>\n"; + output_highlight($args{'sections'}{$section}); + print "</p>\n"; + print "</section>\n"; + } +} + +# output enum in html5 +sub output_enum_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $html5id; + + $html5id = $args{'enum'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"enum\" id=\"enum:". $html5id . "\">"; + print "<h1>enum " . $args{'enum'} . "</h1>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"keyword\">enum</span> "; + print "<span class=\"identifier\">" . $args{'enum'} . "</span> {"; + print "</li>\n"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + print "<span class=\"param\">" . $parameter . "</span>"; + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "</li>\n"; + } + print "<li>};</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Constants</h1>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output typedef in html5 +sub output_typedef_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $html5id; + + $html5id = $args{'typedef'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n"; + print "<h1>typedef " . $args{'typedef'} . "</h1>\n"; + + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"keyword\">typedef</span> "; + print "<span class=\"identifier\">" . $args{'typedef'} . "</span>"; + print "</li>\n"; + print "</ol>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output struct in html5 +sub output_struct_html5(%) { + my %args = %{$_[0]}; + my ($parameter); + my $html5id; + + $html5id = $args{'struct'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n"; + print "<hgroup>\n"; + print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>"; + print "<h2>". $args{'purpose'} . "</h2>\n"; + print "</hgroup>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"type\">" . $args{'type'} . "</span> "; + print "<span class=\"identifier\">" . $args{'struct'} . "</span> {"; + print "</li>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + if ($parameter =~ /^#/) { + print "<span class=\"param\">" . $parameter ."</span>\n"; + print "</li>\n"; + next; + } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"type\">)</span> "; + print "(<span class=\"args\">$2</span>);"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"bits\">$2</span>;"; + } else { + print "<span class=\"type\">$type</span> "; + print "<span class=\"param\">$parameter</span>;"; + } + print "</li>\n"; + } + print "<li>};</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Members</h1>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output function in html5 +sub output_function_html5(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $html5id; + + $html5id = $args{'function'}; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"function\" id=\"func:". $html5id . "\">\n"; + print "<hgroup>\n"; + print "<h1>" . $args{'function'} . "</h1>"; + print "<h2>" . $args{'purpose'} . "</h2>\n"; + print "</hgroup>\n"; + print "<ol class=\"code\">\n"; + print "<li>"; + print "<span class=\"type\">" . $args{'functiontype'} . "</span> "; + print "<span class=\"identifier\">" . $args{'function'} . "</span> ("; + print "</li>"; + $count = 0; + foreach $parameter (@{$args{'parameterlist'}}) { + print "<li class=\"indent\">"; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print "<span class=\"type\">$1</span> "; + print "<span class=\"param\">$parameter</span>"; + print "<span class=\"type\">)</span> "; + print "(<span class=\"args\">$2</span>)"; + } else { + print "<span class=\"type\">$type</span> "; + print "<span class=\"param\">$parameter</span>"; + } + if ($count != $#{$args{'parameterlist'}}) { + $count++; + print ","; + } + print "</li>\n"; + } + print "<li>)</li>\n"; + print "</ol>\n"; + + print "<section>\n"; + print "<h1>Arguments</h1>\n"; + print "<p>\n"; + print "<dl>\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print "<dt>" . $parameter . "</dt>\n"; + print "<dd>"; + output_highlight($args{'parameterdescs'}{$parameter_name}); + print "</dd>\n"; + } + print "</dl>\n"; + print "</section>\n"; + output_section_html5(@_); + print "</article>\n"; +} + +# output DOC: block header in html5 +sub output_blockhead_html5(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $count; + my $html5id; + + foreach $section (@{$args{'sectionlist'}}) { + $html5id = $section; + $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; + print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n"; + print "<h1>$section</h1>\n"; + print "<p>\n"; + output_highlight($args{'sections'}{$section}); + print "</p>\n"; + } + print "</article>\n"; +} + sub output_section_xml(%) { my %args = %{$_[0]}; my $section; @@ -643,10 +915,12 @@ sub output_section_xml(%) { print "<title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<informalexample><programlisting>\n"; + $output_preformatted = 1; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; if ($section =~ m/EXAMPLE/i) { print "</programlisting></informalexample>\n"; } else { @@ -949,10 +1223,12 @@ sub output_blockhead_xml(%) { } if ($section =~ m/EXAMPLE/i) { print "<example><para>\n"; + $output_preformatted = 1; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; if ($section =~ m/EXAMPLE/i) { print "</para></example>\n"; } else { @@ -1028,10 +1304,12 @@ sub output_function_gnome { print "<simplesect>\n <title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<example><programlisting>\n"; + $output_preformatted = 1; } else { } print "<para>\n"; output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; print "</para>\n"; if ($section =~ m/EXAMPLE/i) { print "</programlisting></example>\n"; @@ -1475,7 +1753,7 @@ sub dump_struct($$) { # strip kmemcheck_bitfield_{begin,end}.*; $members =~ s/kmemcheck_bitfield_.*?;//gos; # strip attributes - $members =~ s/__aligned\s*\(\d+\)//gos; + $members =~ s/__aligned\s*\(.+\)//gos; create_parameterlist($members, ';', $file); check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); @@ -1767,12 +2045,35 @@ sub check_sections($$$$$$) { } ## +# Checks the section describing the return value of a function. +sub check_return_section { + my $file = shift; + my $declaration_name = shift; + my $return_type = shift; + + # Ignore an empty return type (It's a macro) + # Ignore functions with a "void" return type. (But don't ignore "void *") + if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { + return; + } + + if (!defined($sections{$section_return}) || + $sections{$section_return} eq "") { + print STDERR "Warning(${file}:$.): " . + "No description found for return value of " . + "'$declaration_name'\n"; + ++$warnings; + } +} + +## # takes a function prototype and the name of the current file being # processed and spits out all the details stored in the global # arrays/hashes. sub dump_function($$) { my $prototype = shift; my $file = shift; + my $noret = 0; $prototype =~ s/^static +//; $prototype =~ s/^extern +//; @@ -1782,11 +2083,11 @@ sub dump_function($$) { $prototype =~ s/^__inline +//; $prototype =~ s/^__always_inline +//; $prototype =~ s/^noinline +//; - $prototype =~ s/__devinit +//; $prototype =~ s/__init +//; $prototype =~ s/__init_or_module +//; $prototype =~ s/__must_check +//; - $prototype =~ s/^#\s*define\s+//; #ak added + $prototype =~ s/__weak +//; + my $define = $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; # Yes, this truly is vile. We are looking for: @@ -1805,7 +2106,15 @@ sub dump_function($$) { # - atomic_set (macro) # - pci_match_device, __copy_to_user (long return type) - if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) { + # This is an object-like macro, it has no return type and no parameter + # list. + # Function-like macros are not allowed to have spaces between + # declaration_name and opening parenthesis (notice the \s+). + $return_type = $1; + $declaration_name = $2; + $noret = 1; + } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || @@ -1828,14 +2137,22 @@ sub dump_function($$) { create_parameterlist($args, ',', $file); } else { - print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n"; - ++$errors; + print STDERR "Warning(${file}:$.): cannot understand function prototype: '$prototype'\n"; return; } my $prms = join " ", @parameterlist; check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); + # This check emits a lot of warnings at the moment, because many + # functions don't have a 'Return' doc section. So until the number + # of warnings goes sufficiently down, the check is only performed in + # verbose mode. + # TODO: always perform the check. + if ($verbose && !$noret) { + check_return_section($file, $declaration_name, $return_type); + } + output_declaration($declaration_name, 'function', {'function' => $declaration_name, @@ -2045,6 +2362,9 @@ sub process_file($) { $section_counter = 0; while (<IN>) { + while (s/\\\s*$//) { + $_ .= <IN>; + } if ($state == 0) { if (/$doc_start/o) { $state = 1; # next line is always the function name @@ -2072,7 +2392,7 @@ sub process_file($) { $descr= $1; $descr =~ s/^\s*//; $descr =~ s/\s*$//; - $descr =~ s/\s+/ /; + $descr =~ s/\s+/ /g; $declaration_purpose = xml_escape($descr); $in_purpose = 1; } else { @@ -2164,6 +2484,7 @@ sub process_file($) { # Continued declaration purpose chomp($declaration_purpose); $declaration_purpose .= " " . xml_escape($1); + $declaration_purpose =~ s/\s+/ /g; } else { $contents .= $1 . "\n"; } @@ -2226,6 +2547,9 @@ sub process_file($) { } if ($initial_section_counter == $section_counter) { print STDERR "Warning(${file}): no structured comments found\n"; + if (($function_only == 1) && ($show_not_found == 1)) { + print STDERR " Was looking for '$_'.\n" for keys %function_table; + } if ($output_mode eq "xml") { # The template wants at least one RefEntry here; make one. print "<refentry>\n"; diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh new file mode 100755 index 00000000000..198580d245e --- /dev/null +++ b/scripts/ld-version.sh @@ -0,0 +1,8 @@ +#!/usr/bin/awk -f +# extract linker version number from stdin and turn into single number + { + gsub(".*)", ""); + split($1,a, "."); + print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5]; + exit + } diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh new file mode 100644 index 00000000000..86a4fe75f45 --- /dev/null +++ b/scripts/link-vmlinux.sh @@ -0,0 +1,240 @@ +#!/bin/sh +# +# link vmlinux +# +# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_INIT) and +# $(KBUILD_VMLINUX_MAIN). Most are built-in.o files from top-level directories +# in the kernel tree, others are specified in arch/$(ARCH)/Makefile. +# Ordering when linking is important, and $(KBUILD_VMLINUX_INIT) must be first. +# +# vmlinux +# ^ +# | +# +-< $(KBUILD_VMLINUX_INIT) +# | +--< init/version.o + more +# | +# +--< $(KBUILD_VMLINUX_MAIN) +# | +--< drivers/built-in.o mm/built-in.o + more +# | +# +-< ${kallsymso} (see description in KALLSYMS section) +# +# vmlinux version (uname -v) cannot be updated during normal +# descending-into-subdirs phase since we do not yet know if we need to +# update vmlinux. +# Therefore this step is delayed until just before final link of vmlinux. +# +# System.map is generated to document addresses of all kernel symbols + +# Error out on error +set -e + +# Nice output in kbuild format +# Will be supressed by "make -s" +info() +{ + if [ "${quiet}" != "silent_" ]; then + printf " %-7s %s\n" ${1} ${2} + fi +} + +# Link of vmlinux.o used for section mismatch analysis +# ${1} output file +modpost_link() +{ + ${LD} ${LDFLAGS} -r -o ${1} ${KBUILD_VMLINUX_INIT} \ + --start-group ${KBUILD_VMLINUX_MAIN} --end-group +} + +# Link of vmlinux +# ${1} - optional extra .o files +# ${2} - output file +vmlinux_link() +{ + local lds="${objtree}/${KBUILD_LDS}" + + if [ "${SRCARCH}" != "um" ]; then + ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + -T ${lds} ${KBUILD_VMLINUX_INIT} \ + --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1} + else + ${CC} ${CFLAGS_vmlinux} -o ${2} \ + -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \ + -Wl,--start-group \ + ${KBUILD_VMLINUX_MAIN} \ + -Wl,--end-group \ + -lutil ${1} + rm -f linux + fi +} + + +# Create ${2} .o file with all symbols from the ${1} object file +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 + + if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then + kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET" + fi + + if [ -n "${CONFIG_X86_64}" ]; then + kallsymopt="${kallsymopt} --absolute-percpu" + fi + + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + + ${NM} -n ${1} | \ + scripts/kallsyms ${kallsymopt} | \ + ${CC} ${aflags} -c -o ${2} -x assembler-with-cpp - +} + +# Create map file with all symbols from ${1} +# See mksymap for additional details +mksysmap() +{ + ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} +} + +sortextable() +{ + ${objtree}/scripts/sortextable ${1} +} + +# Delete output files in case of error +trap cleanup SIGHUP SIGINT SIGQUIT SIGTERM ERR +cleanup() +{ + rm -f .old_version + rm -f .tmp_System.map + rm -f .tmp_kallsyms* + rm -f .tmp_version + rm -f .tmp_vmlinux* + rm -f System.map + rm -f vmlinux + rm -f vmlinux.o +} + +# +# +# Use "make V=1" to debug this script +case "${KBUILD_VERBOSE}" in +*1*) + set -x + ;; +esac + +if [ "$1" = "clean" ]; then + cleanup + exit 0 +fi + +# We need access to CONFIG_ symbols +case "${KCONFIG_CONFIG}" in +*/*) + . "${KCONFIG_CONFIG}" + ;; +*) + # Force using a file from the current directory + . "./${KCONFIG_CONFIG}" +esac + +#link vmlinux.o +info LD vmlinux.o +modpost_link vmlinux.o + +# modpost vmlinux.o to check for section mismatches +${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o + +# Update version +info GEN .version +if [ ! -r .version ]; then + rm -f .version; + echo 1 >.version; +else + mv .version .old_version; + expr 0$(cat .old_version) + 1 >.version; +fi; + +# final build of init/ +${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init + +kallsymso="" +kallsyms_vmlinux="" +if [ -n "${CONFIG_KALLSYMS}" ]; then + + # kallsyms support + # Generate section listing all symbols and add it into vmlinux + # It's a three step process: + # 1) Link .tmp_vmlinux1 so it has all symbols and sections, + # but __kallsyms is empty. + # Running kallsyms on that gives us .tmp_kallsyms1.o with + # the right size + # 2) Link .tmp_vmlinux2 so it now has a __kallsyms section of + # the right size, but due to the added section, some + # addresses have shifted. + # From here, we generate a correct .tmp_kallsyms2.o + # 2a) We may use an extra pass as this has been necessary to + # woraround some alignment related bugs. + # KALLSYMS_EXTRA_PASS=1 is used to trigger this. + # 3) The correct ${kallsymso} is linked into the final vmlinux. + # + # a) Verify that the System.map from vmlinux matches the map from + # ${kallsymso}. + + kallsymso=.tmp_kallsyms2.o + kallsyms_vmlinux=.tmp_vmlinux2 + + # step 1 + vmlinux_link "" .tmp_vmlinux1 + kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o + + # step 2 + vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2 + kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o + + # step 2a + if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then + kallsymso=.tmp_kallsyms3.o + kallsyms_vmlinux=.tmp_vmlinux3 + + vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3 + + kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o + fi +fi + +info LD vmlinux +vmlinux_link "${kallsymso}" vmlinux + +if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then + info SORTEX vmlinux + sortextable vmlinux +fi + +info SYSMAP System.map +mksysmap vmlinux System.map + +# step a (see comment above) +if [ -n "${CONFIG_KALLSYMS}" ]; then + mksysmap ${kallsyms_vmlinux} .tmp_System.map + + if ! cmp -s System.map .tmp_System.map; then + echo >&2 Inconsistent kallsyms data + echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround + cleanup + exit 1 + fi +fi + +# We made a new kernel - delete old version file +rm -f .old_version diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl index 827896f5650..c21d16328d3 100644 --- a/scripts/markup_oops.pl +++ b/scripts/markup_oops.pl @@ -367,4 +367,3 @@ OPTION: EOT exit; } - diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index f221ddf6908..6fdc97ef602 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -68,7 +68,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" ( echo /\* This file is auto generated, version $VERSION \*/ if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi - + echo \#define UTS_MACHINE \"$ARCH\" echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" @@ -76,7 +76,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\" echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\" - echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\" + echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | grep ' version '`\" ) > .tmpcompile # Only replace the real compile.h if the new one is different, @@ -84,7 +84,7 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" # recompilations. # We don't consider the file changed if only the date/time changed. # A kernel config change will increase the generation number, thus -# causing compile.h to be updated (including date/time) due to the +# causing compile.h to be updated (including date/time) due to the # changed comment in the # first line. diff --git a/scripts/mkmakefile b/scripts/mkmakefile index 0cc04426074..84af27bf0f9 100644 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -42,18 +42,11 @@ MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$ MAKEFLAGS += --no-print-directory -.PHONY: all \$(MAKECMDGOALS) +.PHONY: __sub-make \$(MAKECMDGOALS) -all := \$(filter-out all Makefile,\$(MAKECMDGOALS)) +__sub-make: + \$(Q)\$(MAKE) \$(MAKEARGS) \$(MAKECMDGOALS) -all: - \$(Q)\$(MAKE) \$(MAKEARGS) \$(all) - -Makefile:; - -\$(all): all - @: - -%/: all +\$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make @: EOF diff --git a/scripts/mksysmap b/scripts/mksysmap index 6e133a0bae7..7ada35a0f47 100644 --- a/scripts/mksysmap +++ b/scripts/mksysmap @@ -16,7 +16,7 @@ # The second row specify the type of the symbol: # A = Absolute # B = Uninitialised data (.bss) -# C = Comon symbol +# C = Common symbol # D = Initialised data # G = Initialised data for small objects # I = Indirect reference to another symbol @@ -42,4 +42,3 @@ # (At least sparc64 has __crc_ in the middle). $NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2 - diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore index e9b7abe7b95..3bd11b60317 100644 --- a/scripts/mod/.gitignore +++ b/scripts/mod/.gitignore @@ -1,4 +1,4 @@ elfconfig.h mk_elfconfig modpost - +devicetable-offsets.h diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index ff954f8168c..c11212ff351 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -3,9 +3,41 @@ always := $(hostprogs-y) empty.o modpost-objs := modpost.o file2alias.o sumversion.o +devicetable-offsets-file := devicetable-offsets.h + +define sed-y + "/^->/{s:->#\(.*\):/* \1 */:; \ + s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:->::; p;}" +endef + +quiet_cmd_offsets = GEN $@ +define cmd_offsets + (set -e; \ + echo "#ifndef __DEVICETABLE_OFFSETS_H__"; \ + echo "#define __DEVICETABLE_OFFSETS_H__"; \ + echo "/*"; \ + echo " * DO NOT MODIFY."; \ + echo " *"; \ + echo " * This file was generated by Kbuild"; \ + echo " *"; \ + echo " */"; \ + echo ""; \ + sed -ne $(sed-y) $<; \ + echo ""; \ + echo "#endif" ) > $@ +endef + +$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s + $(call if_changed,offsets) + +targets += $(devicetable-offsets-file) devicetable-offsets.s + # dependencies on generated files need to be listed explicitly $(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h +$(obj)/file2alias.o: $(obj)/$(devicetable-offsets-file) quiet_cmd_elfconfig = MKELF $@ cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c new file mode 100644 index 00000000000..f282516acc7 --- /dev/null +++ b/scripts/mod/devicetable-offsets.c @@ -0,0 +1,190 @@ +#include <linux/kbuild.h> +#include <linux/mod_devicetable.h> + +#define DEVID(devid) DEFINE(SIZE_##devid, sizeof(struct devid)) +#define DEVID_FIELD(devid, field) \ + DEFINE(OFF_##devid##_##field, offsetof(struct devid, field)) + +int main(void) +{ + DEVID(usb_device_id); + DEVID_FIELD(usb_device_id, match_flags); + DEVID_FIELD(usb_device_id, idVendor); + DEVID_FIELD(usb_device_id, idProduct); + DEVID_FIELD(usb_device_id, bcdDevice_lo); + DEVID_FIELD(usb_device_id, bcdDevice_hi); + DEVID_FIELD(usb_device_id, bDeviceClass); + DEVID_FIELD(usb_device_id, bDeviceSubClass); + DEVID_FIELD(usb_device_id, bDeviceProtocol); + DEVID_FIELD(usb_device_id, bInterfaceClass); + DEVID_FIELD(usb_device_id, bInterfaceSubClass); + DEVID_FIELD(usb_device_id, bInterfaceProtocol); + DEVID_FIELD(usb_device_id, bInterfaceNumber); + + DEVID(hid_device_id); + DEVID_FIELD(hid_device_id, bus); + DEVID_FIELD(hid_device_id, group); + DEVID_FIELD(hid_device_id, vendor); + DEVID_FIELD(hid_device_id, product); + + DEVID(ieee1394_device_id); + DEVID_FIELD(ieee1394_device_id, match_flags); + DEVID_FIELD(ieee1394_device_id, vendor_id); + DEVID_FIELD(ieee1394_device_id, model_id); + DEVID_FIELD(ieee1394_device_id, specifier_id); + DEVID_FIELD(ieee1394_device_id, version); + + DEVID(pci_device_id); + DEVID_FIELD(pci_device_id, vendor); + DEVID_FIELD(pci_device_id, device); + DEVID_FIELD(pci_device_id, subvendor); + DEVID_FIELD(pci_device_id, subdevice); + DEVID_FIELD(pci_device_id, class); + DEVID_FIELD(pci_device_id, class_mask); + + DEVID(ccw_device_id); + DEVID_FIELD(ccw_device_id, match_flags); + DEVID_FIELD(ccw_device_id, cu_type); + DEVID_FIELD(ccw_device_id, cu_model); + DEVID_FIELD(ccw_device_id, dev_type); + DEVID_FIELD(ccw_device_id, dev_model); + + DEVID(ap_device_id); + DEVID_FIELD(ap_device_id, dev_type); + + DEVID(css_device_id); + DEVID_FIELD(css_device_id, type); + + DEVID(serio_device_id); + DEVID_FIELD(serio_device_id, type); + DEVID_FIELD(serio_device_id, proto); + DEVID_FIELD(serio_device_id, id); + DEVID_FIELD(serio_device_id, extra); + + DEVID(acpi_device_id); + DEVID_FIELD(acpi_device_id, id); + + DEVID(pnp_device_id); + DEVID_FIELD(pnp_device_id, id); + + DEVID(pnp_card_device_id); + DEVID_FIELD(pnp_card_device_id, devs); + + DEVID(pcmcia_device_id); + DEVID_FIELD(pcmcia_device_id, match_flags); + DEVID_FIELD(pcmcia_device_id, manf_id); + DEVID_FIELD(pcmcia_device_id, card_id); + DEVID_FIELD(pcmcia_device_id, func_id); + DEVID_FIELD(pcmcia_device_id, function); + DEVID_FIELD(pcmcia_device_id, device_no); + DEVID_FIELD(pcmcia_device_id, prod_id_hash); + + DEVID(of_device_id); + DEVID_FIELD(of_device_id, name); + DEVID_FIELD(of_device_id, type); + DEVID_FIELD(of_device_id, compatible); + + DEVID(vio_device_id); + DEVID_FIELD(vio_device_id, type); + DEVID_FIELD(vio_device_id, compat); + + DEVID(input_device_id); + DEVID_FIELD(input_device_id, flags); + DEVID_FIELD(input_device_id, bustype); + DEVID_FIELD(input_device_id, vendor); + DEVID_FIELD(input_device_id, product); + DEVID_FIELD(input_device_id, version); + DEVID_FIELD(input_device_id, evbit); + DEVID_FIELD(input_device_id, keybit); + DEVID_FIELD(input_device_id, relbit); + DEVID_FIELD(input_device_id, absbit); + DEVID_FIELD(input_device_id, mscbit); + DEVID_FIELD(input_device_id, ledbit); + DEVID_FIELD(input_device_id, sndbit); + DEVID_FIELD(input_device_id, ffbit); + DEVID_FIELD(input_device_id, swbit); + + DEVID(eisa_device_id); + DEVID_FIELD(eisa_device_id, sig); + + DEVID(parisc_device_id); + DEVID_FIELD(parisc_device_id, hw_type); + DEVID_FIELD(parisc_device_id, hversion); + DEVID_FIELD(parisc_device_id, hversion_rev); + DEVID_FIELD(parisc_device_id, sversion); + + DEVID(sdio_device_id); + DEVID_FIELD(sdio_device_id, class); + DEVID_FIELD(sdio_device_id, vendor); + DEVID_FIELD(sdio_device_id, device); + + DEVID(ssb_device_id); + DEVID_FIELD(ssb_device_id, vendor); + DEVID_FIELD(ssb_device_id, coreid); + DEVID_FIELD(ssb_device_id, revision); + + DEVID(bcma_device_id); + DEVID_FIELD(bcma_device_id, manuf); + DEVID_FIELD(bcma_device_id, id); + DEVID_FIELD(bcma_device_id, rev); + DEVID_FIELD(bcma_device_id, class); + + DEVID(virtio_device_id); + DEVID_FIELD(virtio_device_id, device); + DEVID_FIELD(virtio_device_id, vendor); + + DEVID(hv_vmbus_device_id); + DEVID_FIELD(hv_vmbus_device_id, guid); + + DEVID(i2c_device_id); + DEVID_FIELD(i2c_device_id, name); + + DEVID(spi_device_id); + DEVID_FIELD(spi_device_id, name); + + DEVID(dmi_system_id); + DEVID_FIELD(dmi_system_id, matches); + + DEVID(platform_device_id); + DEVID_FIELD(platform_device_id, name); + + DEVID(mdio_device_id); + DEVID_FIELD(mdio_device_id, phy_id); + DEVID_FIELD(mdio_device_id, phy_id_mask); + + DEVID(zorro_device_id); + DEVID_FIELD(zorro_device_id, id); + + DEVID(isapnp_device_id); + DEVID_FIELD(isapnp_device_id, vendor); + DEVID_FIELD(isapnp_device_id, function); + + DEVID(ipack_device_id); + DEVID_FIELD(ipack_device_id, format); + DEVID_FIELD(ipack_device_id, vendor); + DEVID_FIELD(ipack_device_id, device); + + DEVID(amba_id); + DEVID_FIELD(amba_id, id); + DEVID_FIELD(amba_id, mask); + + DEVID(x86_cpu_id); + DEVID_FIELD(x86_cpu_id, feature); + DEVID_FIELD(x86_cpu_id, family); + DEVID_FIELD(x86_cpu_id, model); + DEVID_FIELD(x86_cpu_id, vendor); + + DEVID(cpu_feature); + DEVID_FIELD(cpu_feature, feature); + + DEVID(mei_cl_device_id); + DEVID_FIELD(mei_cl_device_id, name); + + DEVID(rio_device_id); + DEVID_FIELD(rio_device_id, did); + DEVID_FIELD(rio_device_id, vid); + DEVID_FIELD(rio_device_id, asm_did); + DEVID_FIELD(rio_device_id, asm_vid); + + return 0; +} diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index b89efe6e4c8..e614ef689ee 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -11,6 +11,7 @@ */ #include "modpost.h" +#include "devicetable-offsets.h" /* We use the ELF typedefs for kernel_ulong_t but bite the bullet and * use either stdint.h or inttypes.h for the rest. */ @@ -41,7 +42,7 @@ typedef unsigned char __u8; /* This array collects all instances that use the generic do_table */ struct devtable { - const char *device_id; /* name of table, __mod_<name>_device_table. */ + const char *device_id; /* name of table, __mod_<name>__*_device_table. */ unsigned long id_size; void *function; }; @@ -78,19 +79,33 @@ struct devtable **__start___devtable, **__stop___devtable; extern struct devtable *__start___devtable[], *__stop___devtable[]; #endif /* __MACH__ */ -#if __GNUC__ == 3 && __GNUC_MINOR__ < 3 -# define __used __attribute__((__unused__)) -#else -# define __used __attribute__((__used__)) +#if !defined(__used) +# if __GNUC__ == 3 && __GNUC_MINOR__ < 3 +# define __used __attribute__((__unused__)) +# else +# define __used __attribute__((__used__)) +# endif #endif +/* Define a variable f that holds the value of field f of struct devid + * based at address m. + */ +#define DEF_FIELD(m, devid, f) \ + typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((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) + /* Add a table entry. We test function type matches while we're here. */ #define ADD_TO_DEVTABLE(device_id, type, function) \ static struct devtable __cat(devtable,__LINE__) = { \ device_id + 0*sizeof((function)((const char *)NULL, \ - (type *)NULL, \ + (void *)NULL, \ (char *)NULL)), \ - sizeof(type), (function) }; \ + SIZE_##type, (function) }; \ static struct devtable *SECTION(__devtable) __used \ __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) @@ -116,7 +131,6 @@ static inline void add_wildcard(char *str) strcat(str + len, "*"); } -unsigned int cross_build = 0; /** * Check that sizeof(device_id type) are consistent with size of section * in .o file. If in-consistent then userspace and kernel does not agree @@ -131,10 +145,9 @@ static void device_id_check(const char *modname, const char *device_id, int i; if (size % id_size || size < id_size) { - if (cross_build != 0) - return; fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " - "of the size of section __mod_%s_device_table=%lu.\n" + "of the size of " + "section __mod_%s__<identifier>_device_table=%lu.\n" "Fix definition of struct %s_device_id " "in mod_devicetable.h\n", modname, device_id, id_size, device_id, size, device_id); @@ -156,18 +169,30 @@ static void device_id_check(const char *modname, const char *device_id, } /* USB is special because the bcdDevice can be matched against a numeric range */ -/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */ -static void do_usb_entry(struct usb_device_id *id, +/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ +static void do_usb_entry(void *symval, unsigned int bcdDevice_initial, int bcdDevice_initial_digits, unsigned char range_lo, unsigned char range_hi, unsigned char max, struct module *mod) { char alias[500]; + DEF_FIELD(symval, usb_device_id, match_flags); + DEF_FIELD(symval, usb_device_id, idVendor); + DEF_FIELD(symval, usb_device_id, idProduct); + DEF_FIELD(symval, usb_device_id, bcdDevice_lo); + DEF_FIELD(symval, usb_device_id, bDeviceClass); + DEF_FIELD(symval, usb_device_id, bDeviceSubClass); + DEF_FIELD(symval, usb_device_id, bDeviceProtocol); + DEF_FIELD(symval, usb_device_id, bInterfaceClass); + DEF_FIELD(symval, usb_device_id, bInterfaceSubClass); + DEF_FIELD(symval, usb_device_id, bInterfaceProtocol); + DEF_FIELD(symval, usb_device_id, bInterfaceNumber); + strcpy(alias, "usb:"); - ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR, - id->idVendor); - ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT, - id->idProduct); + ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR, + idVendor); + ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT, + idProduct); strcat(alias, "d"); if (bcdDevice_initial_digits) @@ -186,30 +211,27 @@ static void do_usb_entry(struct usb_device_id *id, range_lo < 0x9 ? "[%X-9" : "[%X", range_lo); sprintf(alias + strlen(alias), - range_hi > 0xA ? "a-%X]" : "%X]", - range_lo); + range_hi > 0xA ? "A-%X]" : "%X]", + range_hi); } } - if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1)) + if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1)) strcat(alias, "*"); - ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, - id->bDeviceClass); - ADD(alias, "dsc", - id->match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, - id->bDeviceSubClass); - ADD(alias, "dp", - id->match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, - id->bDeviceProtocol); - ADD(alias, "ic", - id->match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, - id->bInterfaceClass); - ADD(alias, "isc", - id->match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, - id->bInterfaceSubClass); - ADD(alias, "ip", - id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, - id->bInterfaceProtocol); + ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, + bDeviceClass); + ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, + bDeviceSubClass); + ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, + bDeviceProtocol); + ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, + bInterfaceClass); + ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, + bInterfaceSubClass); + ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, + bInterfaceProtocol); + ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, + bInterfaceNumber); add_wildcard(alias); buf_printf(&mod->dev_table_buf, @@ -255,24 +277,28 @@ static unsigned int incbcd(unsigned int *bcd, return init; } -static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) +static void do_usb_entry_multi(void *symval, struct module *mod) { unsigned int devlo, devhi; unsigned char chi, clo, max; int ndigits; - id->match_flags = TO_NATIVE(id->match_flags); - id->idVendor = TO_NATIVE(id->idVendor); - id->idProduct = TO_NATIVE(id->idProduct); + DEF_FIELD(symval, usb_device_id, match_flags); + DEF_FIELD(symval, usb_device_id, idVendor); + DEF_FIELD(symval, usb_device_id, idProduct); + DEF_FIELD(symval, usb_device_id, bcdDevice_lo); + DEF_FIELD(symval, usb_device_id, bcdDevice_hi); + DEF_FIELD(symval, usb_device_id, bDeviceClass); + DEF_FIELD(symval, usb_device_id, bInterfaceClass); - devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? - TO_NATIVE(id->bcdDevice_lo) : 0x0U; - devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? - TO_NATIVE(id->bcdDevice_hi) : ~0x0U; + devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? + bcdDevice_lo : 0x0U; + devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? + bcdDevice_hi : ~0x0U; /* Figure out if this entry is in bcd or hex format */ max = 0x9; /* Default to decimal format */ - for (ndigits = 0 ; ndigits < sizeof(id->bcdDevice_lo) * 2 ; ndigits++) { + for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) { clo = (devlo >> (ndigits << 2)) & 0xf; chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf; if (clo > max || chi > max) { @@ -285,11 +311,11 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) * Some modules (visor) have empty slots as placeholder for * run-time specification that results in catch-all alias */ - if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass)) + if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass)) return; /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ - for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { + for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { clo = devlo & 0xf; chi = devhi & 0xf; if (chi > max) /* If we are in bcd mode, truncate if necessary */ @@ -298,20 +324,20 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) devhi >>= 4; if (devlo == devhi || !ndigits) { - do_usb_entry(id, devlo, ndigits, clo, chi, max, mod); + do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod); break; } if (clo > 0x0) - do_usb_entry(id, + do_usb_entry(symval, incbcd(&devlo, 1, max, - sizeof(id->bcdDevice_lo) * 2), + sizeof(bcdDevice_lo) * 2), ndigits, clo, max, max, mod); if (chi < max) - do_usb_entry(id, + do_usb_entry(symval, incbcd(&devhi, -1, max, - sizeof(id->bcdDevice_lo) * 2), + sizeof(bcdDevice_lo) * 2), ndigits, 0x0, chi, max, mod); } } @@ -320,7 +346,7 @@ static void do_usb_table(void *symval, unsigned long size, struct module *mod) { unsigned int i; - const unsigned long id_size = sizeof(struct usb_device_id); + const unsigned long id_size = SIZE_usb_device_id; device_id_check(mod->name, "usb", size, id_size, symval); @@ -333,78 +359,81 @@ static void do_usb_table(void *symval, unsigned long size, /* Looks like: hid:bNvNpN */ static int do_hid_entry(const char *filename, - struct hid_device_id *id, char *alias) + void *symval, char *alias) { - id->bus = TO_NATIVE(id->bus); - id->vendor = TO_NATIVE(id->vendor); - id->product = TO_NATIVE(id->product); + DEF_FIELD(symval, hid_device_id, bus); + DEF_FIELD(symval, hid_device_id, group); + DEF_FIELD(symval, hid_device_id, vendor); + DEF_FIELD(symval, hid_device_id, product); - sprintf(alias, "hid:b%04X", id->bus); - ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); - ADD(alias, "p", id->product != HID_ANY_ID, id->product); + sprintf(alias, "hid:"); + ADD(alias, "b", bus != HID_BUS_ANY, bus); + ADD(alias, "g", group != HID_GROUP_ANY, group); + ADD(alias, "v", vendor != HID_ANY_ID, vendor); + ADD(alias, "p", product != HID_ANY_ID, product); return 1; } -ADD_TO_DEVTABLE("hid", struct hid_device_id, do_hid_entry); +ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry); /* Looks like: ieee1394:venNmoNspNverN */ static int do_ieee1394_entry(const char *filename, - struct ieee1394_device_id *id, char *alias) + void *symval, char *alias) { - id->match_flags = TO_NATIVE(id->match_flags); - id->vendor_id = TO_NATIVE(id->vendor_id); - id->model_id = TO_NATIVE(id->model_id); - id->specifier_id = TO_NATIVE(id->specifier_id); - id->version = TO_NATIVE(id->version); + DEF_FIELD(symval, ieee1394_device_id, match_flags); + DEF_FIELD(symval, ieee1394_device_id, vendor_id); + DEF_FIELD(symval, ieee1394_device_id, model_id); + DEF_FIELD(symval, ieee1394_device_id, specifier_id); + DEF_FIELD(symval, ieee1394_device_id, version); strcpy(alias, "ieee1394:"); - ADD(alias, "ven", id->match_flags & IEEE1394_MATCH_VENDOR_ID, - id->vendor_id); - ADD(alias, "mo", id->match_flags & IEEE1394_MATCH_MODEL_ID, - id->model_id); - ADD(alias, "sp", id->match_flags & IEEE1394_MATCH_SPECIFIER_ID, - id->specifier_id); - ADD(alias, "ver", id->match_flags & IEEE1394_MATCH_VERSION, - id->version); + ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, + vendor_id); + ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, + model_id); + ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID, + specifier_id); + ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, + version); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ieee1394", struct ieee1394_device_id, do_ieee1394_entry); +ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry); /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ static int do_pci_entry(const char *filename, - struct pci_device_id *id, char *alias) + void *symval, char *alias) { /* Class field can be divided into these three. */ unsigned char baseclass, subclass, interface, baseclass_mask, subclass_mask, interface_mask; - id->vendor = TO_NATIVE(id->vendor); - id->device = TO_NATIVE(id->device); - id->subvendor = TO_NATIVE(id->subvendor); - id->subdevice = TO_NATIVE(id->subdevice); - id->class = TO_NATIVE(id->class); - id->class_mask = TO_NATIVE(id->class_mask); + DEF_FIELD(symval, pci_device_id, vendor); + DEF_FIELD(symval, pci_device_id, device); + DEF_FIELD(symval, pci_device_id, subvendor); + DEF_FIELD(symval, pci_device_id, subdevice); + DEF_FIELD(symval, pci_device_id, class); + DEF_FIELD(symval, pci_device_id, class_mask); strcpy(alias, "pci:"); - ADD(alias, "v", id->vendor != PCI_ANY_ID, id->vendor); - ADD(alias, "d", id->device != PCI_ANY_ID, id->device); - ADD(alias, "sv", id->subvendor != PCI_ANY_ID, id->subvendor); - ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice); - - baseclass = (id->class) >> 16; - baseclass_mask = (id->class_mask) >> 16; - subclass = (id->class) >> 8; - subclass_mask = (id->class_mask) >> 8; - interface = id->class; - interface_mask = id->class_mask; + ADD(alias, "v", vendor != PCI_ANY_ID, vendor); + ADD(alias, "d", device != PCI_ANY_ID, device); + ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor); + ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice); + + baseclass = (class) >> 16; + baseclass_mask = (class_mask) >> 16; + subclass = (class) >> 8; + subclass_mask = (class_mask) >> 8; + interface = class; + interface_mask = class_mask; if ((baseclass_mask != 0 && baseclass_mask != 0xFF) || (subclass_mask != 0 && subclass_mask != 0xFF) || (interface_mask != 0 && interface_mask != 0xFF)) { warn("Can't handle masks in %s:%04X\n", - filename, id->class_mask); + filename, class_mask); return 0; } @@ -414,101 +443,105 @@ static int do_pci_entry(const char *filename, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("pci", struct pci_device_id, do_pci_entry); +ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry); /* looks like: "ccw:tNmNdtNdmN" */ static int do_ccw_entry(const char *filename, - struct ccw_device_id *id, char *alias) + void *symval, char *alias) { - id->match_flags = TO_NATIVE(id->match_flags); - id->cu_type = TO_NATIVE(id->cu_type); - id->cu_model = TO_NATIVE(id->cu_model); - id->dev_type = TO_NATIVE(id->dev_type); - id->dev_model = TO_NATIVE(id->dev_model); + DEF_FIELD(symval, ccw_device_id, match_flags); + DEF_FIELD(symval, ccw_device_id, cu_type); + DEF_FIELD(symval, ccw_device_id, cu_model); + DEF_FIELD(symval, ccw_device_id, dev_type); + DEF_FIELD(symval, ccw_device_id, dev_model); strcpy(alias, "ccw:"); - ADD(alias, "t", id->match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, - id->cu_type); - ADD(alias, "m", id->match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, - id->cu_model); - ADD(alias, "dt", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, - id->dev_type); - ADD(alias, "dm", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, - id->dev_model); + ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, + cu_type); + ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, + cu_model); + ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, + dev_type); + ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, + dev_model); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ccw", struct ccw_device_id, do_ccw_entry); +ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry); /* looks like: "ap:tN" */ static int do_ap_entry(const char *filename, - struct ap_device_id *id, char *alias) + void *symval, char *alias) { - sprintf(alias, "ap:t%02X*", id->dev_type); + DEF_FIELD(symval, ap_device_id, dev_type); + + sprintf(alias, "ap:t%02X*", dev_type); return 1; } -ADD_TO_DEVTABLE("ap", struct ap_device_id, do_ap_entry); +ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry); /* looks like: "css:tN" */ static int do_css_entry(const char *filename, - struct css_device_id *id, char *alias) + void *symval, char *alias) { - sprintf(alias, "css:t%01X", id->type); + DEF_FIELD(symval, css_device_id, type); + + sprintf(alias, "css:t%01X", type); return 1; } -ADD_TO_DEVTABLE("css", struct css_device_id, do_css_entry); +ADD_TO_DEVTABLE("css", css_device_id, do_css_entry); /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, - struct serio_device_id *id, char *alias) + void *symval, char *alias) { - id->type = TO_NATIVE(id->type); - id->proto = TO_NATIVE(id->proto); - id->id = TO_NATIVE(id->id); - id->extra = TO_NATIVE(id->extra); + DEF_FIELD(symval, serio_device_id, type); + DEF_FIELD(symval, serio_device_id, proto); + DEF_FIELD(symval, serio_device_id, id); + DEF_FIELD(symval, serio_device_id, extra); strcpy(alias, "serio:"); - ADD(alias, "ty", id->type != SERIO_ANY, id->type); - ADD(alias, "pr", id->proto != SERIO_ANY, id->proto); - ADD(alias, "id", id->id != SERIO_ANY, id->id); - ADD(alias, "ex", id->extra != SERIO_ANY, id->extra); + ADD(alias, "ty", type != SERIO_ANY, type); + ADD(alias, "pr", proto != SERIO_ANY, proto); + ADD(alias, "id", id != SERIO_ANY, id); + ADD(alias, "ex", extra != SERIO_ANY, extra); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("serio", struct serio_device_id, do_serio_entry); +ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ static int do_acpi_entry(const char *filename, - struct acpi_device_id *id, char *alias) + void *symval, char *alias) { - sprintf(alias, "acpi*:%s:*", id->id); + DEF_FIELD_ADDR(symval, acpi_device_id, id); + sprintf(alias, "acpi*:%s:*", *id); return 1; } -ADD_TO_DEVTABLE("acpi", struct acpi_device_id, do_acpi_entry); +ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); /* looks like: "pnp:dD" */ static void do_pnp_device_entry(void *symval, unsigned long size, struct module *mod) { - const unsigned long id_size = sizeof(struct pnp_device_id); + const unsigned long id_size = SIZE_pnp_device_id; const unsigned int count = (size / id_size)-1; - const struct pnp_device_id *devs = symval; unsigned int i; device_id_check(mod->name, "pnp", size, id_size, symval); for (i = 0; i < count; i++) { - const char *id = (char *)devs[i].id; - char acpi_id[sizeof(devs[0].id)]; + DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); + char acpi_id[sizeof(*id)]; int j; buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", id); + "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); /* fix broken pnp bus lowercasing */ for (j = 0; j < sizeof(acpi_id); j++) - acpi_id[j] = toupper(id[j]); + acpi_id[j] = toupper((*id)[j]); buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); } @@ -518,19 +551,18 @@ static void do_pnp_device_entry(void *symval, unsigned long size, static void do_pnp_card_entries(void *symval, unsigned long size, struct module *mod) { - const unsigned long id_size = sizeof(struct pnp_card_device_id); + const unsigned long id_size = SIZE_pnp_card_device_id; const unsigned int count = (size / id_size)-1; - const struct pnp_card_device_id *cards = symval; unsigned int i; device_id_check(mod->name, "pnp", size, id_size, symval); for (i = 0; i < count; i++) { unsigned int j; - const struct pnp_card_device_id *card = &cards[i]; + DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs); for (j = 0; j < PNP_MAX_DEVICES; j++) { - const char *id = (char *)card->devs[j].id; + const char *id = (char *)(*devs)[j].id; int i2, j2; int dup = 0; @@ -539,10 +571,10 @@ static void do_pnp_card_entries(void *symval, unsigned long size, /* find duplicate, already added value */ for (i2 = 0; i2 < i && !dup; i2++) { - const struct pnp_card_device_id *card2 = &cards[i2]; + DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs); for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { - const char *id2 = (char *)card2->devs[j2].id; + const char *id2 = (char *)(*devs)[j2].id; if (!id2[0]) break; @@ -556,7 +588,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, /* add an individual alias for every device entry */ if (!dup) { - char acpi_id[sizeof(card->devs[0].id)]; + char acpi_id[PNP_ID_LEN]; int k; buf_printf(&mod->dev_table_buf, @@ -574,72 +606,76 @@ static void do_pnp_card_entries(void *symval, unsigned long size, /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ static int do_pcmcia_entry(const char *filename, - struct pcmcia_device_id *id, char *alias) + void *symval, char *alias) { unsigned int i; - - id->match_flags = TO_NATIVE(id->match_flags); - id->manf_id = TO_NATIVE(id->manf_id); - id->card_id = TO_NATIVE(id->card_id); - id->func_id = TO_NATIVE(id->func_id); - id->function = TO_NATIVE(id->function); - id->device_no = TO_NATIVE(id->device_no); + DEF_FIELD(symval, pcmcia_device_id, match_flags); + DEF_FIELD(symval, pcmcia_device_id, manf_id); + DEF_FIELD(symval, pcmcia_device_id, card_id); + DEF_FIELD(symval, pcmcia_device_id, func_id); + DEF_FIELD(symval, pcmcia_device_id, function); + DEF_FIELD(symval, pcmcia_device_id, device_no); + DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash); for (i=0; i<4; i++) { - id->prod_id_hash[i] = TO_NATIVE(id->prod_id_hash[i]); - } - - strcpy(alias, "pcmcia:"); - ADD(alias, "m", id->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, - id->manf_id); - ADD(alias, "c", id->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, - id->card_id); - ADD(alias, "f", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, - id->func_id); - ADD(alias, "fn", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, - id->function); - ADD(alias, "pfn", id->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, - id->device_no); - ADD(alias, "pa", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, id->prod_id_hash[0]); - ADD(alias, "pb", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, id->prod_id_hash[1]); - ADD(alias, "pc", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, id->prod_id_hash[2]); - ADD(alias, "pd", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, id->prod_id_hash[3]); + (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]); + } + + strcpy(alias, "pcmcia:"); + ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, + manf_id); + ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, + card_id); + ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, + func_id); + ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, + function); + ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, + device_no); + ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]); + ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]); + ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]); + ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]); add_wildcard(alias); - return 1; + return 1; } -ADD_TO_DEVTABLE("pcmcia", struct pcmcia_device_id, do_pcmcia_entry); +ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); -static int do_of_entry (const char *filename, struct of_device_id *of, char *alias) +static int do_of_entry (const char *filename, void *symval, char *alias) { - int len; - char *tmp; - len = sprintf (alias, "of:N%sT%s", - of->name[0] ? of->name : "*", - of->type[0] ? of->type : "*"); - - if (of->compatible[0]) - sprintf (&alias[len], "%sC%s", - of->type[0] ? "*" : "", - of->compatible); - - /* Replace all whitespace with underscores */ - for (tmp = alias; tmp && *tmp; tmp++) - if (isspace (*tmp)) - *tmp = '_'; - - add_wildcard(alias); - return 1; + int len; + char *tmp; + DEF_FIELD_ADDR(symval, of_device_id, name); + DEF_FIELD_ADDR(symval, of_device_id, type); + DEF_FIELD_ADDR(symval, of_device_id, compatible); + + len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", + (*type)[0] ? *type : "*"); + + if (compatible[0]) + sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", + *compatible); + + /* Replace all whitespace with underscores */ + for (tmp = alias; tmp && *tmp; tmp++) + if (isspace (*tmp)) + *tmp = '_'; + + add_wildcard(alias); + return 1; } -ADD_TO_DEVTABLE("of", struct of_device_id, do_of_entry); +ADD_TO_DEVTABLE("of", of_device_id, do_of_entry); -static int do_vio_entry(const char *filename, struct vio_device_id *vio, +static int do_vio_entry(const char *filename, void *symval, char *alias) { char *tmp; + DEF_FIELD_ADDR(symval, vio_device_id, type); + DEF_FIELD_ADDR(symval, vio_device_id, compat); - sprintf(alias, "vio:T%sS%s", vio->type[0] ? vio->type : "*", - vio->compat[0] ? vio->compat : "*"); + sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*", + (*compat)[0] ? *compat : "*"); /* Replace all whitespace with underscores */ for (tmp = alias; tmp && *tmp; tmp++) @@ -649,7 +685,7 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio, add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("vio", struct vio_device_id, do_vio_entry); +ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -658,154 +694,172 @@ static void do_input(char *alias, { unsigned int i; + for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++) + arr[i] = TO_NATIVE(arr[i]); for (i = min; i < max; i++) if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG))) sprintf(alias + strlen(alias), "%X,*", i); } /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ -static int do_input_entry(const char *filename, struct input_device_id *id, +static int do_input_entry(const char *filename, void *symval, char *alias) { + DEF_FIELD(symval, input_device_id, flags); + DEF_FIELD(symval, input_device_id, bustype); + DEF_FIELD(symval, input_device_id, vendor); + DEF_FIELD(symval, input_device_id, product); + DEF_FIELD(symval, input_device_id, version); + DEF_FIELD_ADDR(symval, input_device_id, evbit); + DEF_FIELD_ADDR(symval, input_device_id, keybit); + DEF_FIELD_ADDR(symval, input_device_id, relbit); + DEF_FIELD_ADDR(symval, input_device_id, absbit); + DEF_FIELD_ADDR(symval, input_device_id, mscbit); + DEF_FIELD_ADDR(symval, input_device_id, ledbit); + DEF_FIELD_ADDR(symval, input_device_id, sndbit); + DEF_FIELD_ADDR(symval, input_device_id, ffbit); + DEF_FIELD_ADDR(symval, input_device_id, swbit); + sprintf(alias, "input:"); - ADD(alias, "b", id->flags & INPUT_DEVICE_ID_MATCH_BUS, id->bustype); - ADD(alias, "v", id->flags & INPUT_DEVICE_ID_MATCH_VENDOR, id->vendor); - ADD(alias, "p", id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT, id->product); - ADD(alias, "e", id->flags & INPUT_DEVICE_ID_MATCH_VERSION, id->version); + ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); + ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); + ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); + ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version); sprintf(alias + strlen(alias), "-e*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT) - do_input(alias, id->evbit, 0, INPUT_DEVICE_ID_EV_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) + do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX); sprintf(alias + strlen(alias), "k*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT) - do_input(alias, id->keybit, + if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) + do_input(alias, *keybit, INPUT_DEVICE_ID_KEY_MIN_INTERESTING, INPUT_DEVICE_ID_KEY_MAX); sprintf(alias + strlen(alias), "r*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT) - do_input(alias, id->relbit, 0, INPUT_DEVICE_ID_REL_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) + do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX); sprintf(alias + strlen(alias), "a*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT) - do_input(alias, id->absbit, 0, INPUT_DEVICE_ID_ABS_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) + do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX); sprintf(alias + strlen(alias), "m*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT) - do_input(alias, id->mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) + do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); sprintf(alias + strlen(alias), "l*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT) - do_input(alias, id->ledbit, 0, INPUT_DEVICE_ID_LED_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) + do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX); sprintf(alias + strlen(alias), "s*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT) - do_input(alias, id->sndbit, 0, INPUT_DEVICE_ID_SND_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) + do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX); sprintf(alias + strlen(alias), "f*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT) - do_input(alias, id->ffbit, 0, INPUT_DEVICE_ID_FF_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) + do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX); sprintf(alias + strlen(alias), "w*"); - if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT) - do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX); + if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) + do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); return 1; } -ADD_TO_DEVTABLE("input", struct input_device_id, do_input_entry); +ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); -static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, +static int do_eisa_entry(const char *filename, void *symval, char *alias) { - if (eisa->sig[0]) - sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig); + DEF_FIELD_ADDR(symval, eisa_device_id, sig); + if (sig[0]) + sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); else strcat(alias, "*"); return 1; } -ADD_TO_DEVTABLE("eisa", struct eisa_device_id, do_eisa_entry); +ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry); /* Looks like: parisc:tNhvNrevNsvN */ -static int do_parisc_entry(const char *filename, struct parisc_device_id *id, +static int do_parisc_entry(const char *filename, void *symval, char *alias) { - id->hw_type = TO_NATIVE(id->hw_type); - id->hversion = TO_NATIVE(id->hversion); - id->hversion_rev = TO_NATIVE(id->hversion_rev); - id->sversion = TO_NATIVE(id->sversion); + DEF_FIELD(symval, parisc_device_id, hw_type); + DEF_FIELD(symval, parisc_device_id, hversion); + DEF_FIELD(symval, parisc_device_id, hversion_rev); + DEF_FIELD(symval, parisc_device_id, sversion); strcpy(alias, "parisc:"); - ADD(alias, "t", id->hw_type != PA_HWTYPE_ANY_ID, id->hw_type); - ADD(alias, "hv", id->hversion != PA_HVERSION_ANY_ID, id->hversion); - ADD(alias, "rev", id->hversion_rev != PA_HVERSION_REV_ANY_ID, id->hversion_rev); - ADD(alias, "sv", id->sversion != PA_SVERSION_ANY_ID, id->sversion); + ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); + ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); + ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); + ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("parisc", struct parisc_device_id, do_parisc_entry); +ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry); /* Looks like: sdio:cNvNdN. */ static int do_sdio_entry(const char *filename, - struct sdio_device_id *id, char *alias) + void *symval, char *alias) { - id->class = TO_NATIVE(id->class); - id->vendor = TO_NATIVE(id->vendor); - id->device = TO_NATIVE(id->device); + DEF_FIELD(symval, sdio_device_id, class); + DEF_FIELD(symval, sdio_device_id, vendor); + DEF_FIELD(symval, sdio_device_id, device); strcpy(alias, "sdio:"); - ADD(alias, "c", id->class != (__u8)SDIO_ANY_ID, id->class); - ADD(alias, "v", id->vendor != (__u16)SDIO_ANY_ID, id->vendor); - ADD(alias, "d", id->device != (__u16)SDIO_ANY_ID, id->device); + ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); + ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); + ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("sdio", struct sdio_device_id, do_sdio_entry); +ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry); /* Looks like: ssb:vNidNrevN. */ static int do_ssb_entry(const char *filename, - struct ssb_device_id *id, char *alias) + void *symval, char *alias) { - id->vendor = TO_NATIVE(id->vendor); - id->coreid = TO_NATIVE(id->coreid); - id->revision = TO_NATIVE(id->revision); + DEF_FIELD(symval, ssb_device_id, vendor); + DEF_FIELD(symval, ssb_device_id, coreid); + DEF_FIELD(symval, ssb_device_id, revision); strcpy(alias, "ssb:"); - ADD(alias, "v", id->vendor != SSB_ANY_VENDOR, id->vendor); - ADD(alias, "id", id->coreid != SSB_ANY_ID, id->coreid); - ADD(alias, "rev", id->revision != SSB_ANY_REV, id->revision); + ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); + ADD(alias, "id", coreid != SSB_ANY_ID, coreid); + ADD(alias, "rev", revision != SSB_ANY_REV, revision); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("ssb", struct ssb_device_id, do_ssb_entry); +ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); /* Looks like: bcma:mNidNrevNclN. */ static int do_bcma_entry(const char *filename, - struct bcma_device_id *id, char *alias) + void *symval, char *alias) { - id->manuf = TO_NATIVE(id->manuf); - id->id = TO_NATIVE(id->id); - id->rev = TO_NATIVE(id->rev); - id->class = TO_NATIVE(id->class); + DEF_FIELD(symval, bcma_device_id, manuf); + DEF_FIELD(symval, bcma_device_id, id); + DEF_FIELD(symval, bcma_device_id, rev); + DEF_FIELD(symval, bcma_device_id, class); strcpy(alias, "bcma:"); - ADD(alias, "m", id->manuf != BCMA_ANY_MANUF, id->manuf); - ADD(alias, "id", id->id != BCMA_ANY_ID, id->id); - ADD(alias, "rev", id->rev != BCMA_ANY_REV, id->rev); - ADD(alias, "cl", id->class != BCMA_ANY_CLASS, id->class); + ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); + ADD(alias, "id", id != BCMA_ANY_ID, id); + ADD(alias, "rev", rev != BCMA_ANY_REV, rev); + ADD(alias, "cl", class != BCMA_ANY_CLASS, class); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("bcma", struct bcma_device_id, do_bcma_entry); +ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry); /* Looks like: virtio:dNvN */ -static int do_virtio_entry(const char *filename, struct virtio_device_id *id, +static int do_virtio_entry(const char *filename, void *symval, char *alias) { - id->device = TO_NATIVE(id->device); - id->vendor = TO_NATIVE(id->vendor); + DEF_FIELD(symval, virtio_device_id, device); + DEF_FIELD(symval, virtio_device_id, vendor); strcpy(alias, "virtio:"); - ADD(alias, "d", id->device != VIRTIO_DEV_ANY_ID, id->device); - ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor); + ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); + ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("virtio", struct virtio_device_id, do_virtio_entry); +ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); /* * Looks like: vmbus:guid @@ -813,41 +867,44 @@ ADD_TO_DEVTABLE("virtio", struct virtio_device_id, do_virtio_entry); * in the name. */ -static int do_vmbus_entry(const char *filename, struct hv_vmbus_device_id *id, +static int do_vmbus_entry(const char *filename, void *symval, char *alias) { int i; - char guid_name[((sizeof(id->guid) + 1)) * 2]; + DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); + char guid_name[(sizeof(*guid) + 1) * 2]; - for (i = 0; i < (sizeof(id->guid) * 2); i += 2) - sprintf(&guid_name[i], "%02x", id->guid[i/2]); + for (i = 0; i < (sizeof(*guid) * 2); i += 2) + sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2])); strcpy(alias, "vmbus:"); strcat(alias, guid_name); return 1; } -ADD_TO_DEVTABLE("vmbus", struct hv_vmbus_device_id, do_vmbus_entry); +ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); /* Looks like: i2c:S */ -static int do_i2c_entry(const char *filename, struct i2c_device_id *id, +static int do_i2c_entry(const char *filename, void *symval, char *alias) { - sprintf(alias, I2C_MODULE_PREFIX "%s", id->name); + DEF_FIELD_ADDR(symval, i2c_device_id, name); + sprintf(alias, I2C_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("i2c", struct i2c_device_id, do_i2c_entry); +ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry); /* Looks like: spi:S */ -static int do_spi_entry(const char *filename, struct spi_device_id *id, +static int do_spi_entry(const char *filename, void *symval, char *alias) { - sprintf(alias, SPI_MODULE_PREFIX "%s", id->name); + DEF_FIELD_ADDR(symval, spi_device_id, name); + sprintf(alias, SPI_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("spi", struct spi_device_id, do_spi_entry); +ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry); static const struct dmifield { const char *prefix; @@ -879,21 +936,21 @@ static void dmi_ascii_filter(char *d, const char *s) } -static int do_dmi_entry(const char *filename, struct dmi_system_id *id, +static int do_dmi_entry(const char *filename, void *symval, char *alias) { int i, j; - + DEF_FIELD_ADDR(symval, dmi_system_id, matches); sprintf(alias, "dmi*"); for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { for (j = 0; j < 4; j++) { - if (id->matches[j].slot && - id->matches[j].slot == dmi_fields[i].field) { + if ((*matches)[j].slot && + (*matches)[j].slot == dmi_fields[i].field) { sprintf(alias + strlen(alias), ":%s*", dmi_fields[i].prefix); dmi_ascii_filter(alias + strlen(alias), - id->matches[j].substr); + (*matches)[j].substr); strcat(alias, "*"); } } @@ -902,27 +959,30 @@ static int do_dmi_entry(const char *filename, struct dmi_system_id *id, strcat(alias, ":"); return 1; } -ADD_TO_DEVTABLE("dmi", struct dmi_system_id, do_dmi_entry); +ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry); static int do_platform_entry(const char *filename, - struct platform_device_id *id, char *alias) + void *symval, char *alias) { - sprintf(alias, PLATFORM_MODULE_PREFIX "%s", id->name); + DEF_FIELD_ADDR(symval, platform_device_id, name); + sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("platform", struct platform_device_id, do_platform_entry); +ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry); static int do_mdio_entry(const char *filename, - struct mdio_device_id *id, char *alias) + void *symval, char *alias) { int i; + DEF_FIELD(symval, mdio_device_id, phy_id); + DEF_FIELD(symval, mdio_device_id, phy_id_mask); alias += sprintf(alias, MDIO_MODULE_PREFIX); for (i = 0; i < 32; i++) { - if (!((id->phy_id_mask >> (31-i)) & 1)) + if (!((phy_id_mask >> (31-i)) & 1)) *(alias++) = '?'; - else if ((id->phy_id >> (31-i)) & 1) + else if ((phy_id >> (31-i)) & 1) *(alias++) = '1'; else *(alias++) = '0'; @@ -933,32 +993,50 @@ static int do_mdio_entry(const char *filename, return 1; } -ADD_TO_DEVTABLE("mdio", struct mdio_device_id, do_mdio_entry); +ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry); /* Looks like: zorro:iN. */ -static int do_zorro_entry(const char *filename, struct zorro_device_id *id, +static int do_zorro_entry(const char *filename, void *symval, char *alias) { - id->id = TO_NATIVE(id->id); + DEF_FIELD(symval, zorro_device_id, id); strcpy(alias, "zorro:"); - ADD(alias, "i", id->id != ZORRO_WILDCARD, id->id); + ADD(alias, "i", id != ZORRO_WILDCARD, id); return 1; } -ADD_TO_DEVTABLE("zorro", struct zorro_device_id, do_zorro_entry); +ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry); /* looks like: "pnp:dD" */ static int do_isapnp_entry(const char *filename, - struct isapnp_device_id *id, char *alias) + void *symval, char *alias) { + DEF_FIELD(symval, isapnp_device_id, vendor); + DEF_FIELD(symval, isapnp_device_id, function); sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", - 'A' + ((id->vendor >> 2) & 0x3f) - 1, - 'A' + (((id->vendor & 3) << 3) | ((id->vendor >> 13) & 7)) - 1, - 'A' + ((id->vendor >> 8) & 0x1f) - 1, - (id->function >> 4) & 0x0f, id->function & 0x0f, - (id->function >> 12) & 0x0f, (id->function >> 8) & 0x0f); + 'A' + ((vendor >> 2) & 0x3f) - 1, + 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, + 'A' + ((vendor >> 8) & 0x1f) - 1, + (function >> 4) & 0x0f, function & 0x0f, + (function >> 12) & 0x0f, (function >> 8) & 0x0f); + return 1; +} +ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); + +/* Looks like: "ipack:fNvNdN". */ +static int do_ipack_entry(const char *filename, + void *symval, char *alias) +{ + DEF_FIELD(symval, ipack_device_id, format); + DEF_FIELD(symval, ipack_device_id, vendor); + DEF_FIELD(symval, ipack_device_id, device); + strcpy(alias, "ipack:"); + ADD(alias, "f", format != IPACK_ANY_FORMAT, format); + ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); + ADD(alias, "d", device != IPACK_ANY_ID, device); + add_wildcard(alias); return 1; } -ADD_TO_DEVTABLE("isapnp", struct isapnp_device_id, do_isapnp_entry); +ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); /* * Append a match expression for a single masked hex digit. @@ -1009,25 +1087,94 @@ static void append_nibble_mask(char **outp, * a ? or [] pattern matching exactly one digit. */ static int do_amba_entry(const char *filename, - struct amba_id *id, char *alias) + void *symval, char *alias) { unsigned int digit; char *p = alias; + DEF_FIELD(symval, amba_id, id); + DEF_FIELD(symval, amba_id, mask); - if ((id->id & id->mask) != id->id) + if ((id & mask) != id) fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: " "id=0x%08X, mask=0x%08X. Please fix this driver.\n", - filename, id->id, id->mask); + filename, id, mask); p += sprintf(alias, "amba:d"); for (digit = 0; digit < 8; digit++) append_nibble_mask(&p, - (id->id >> (4 * (7 - digit))) & 0xf, - (id->mask >> (4 * (7 - digit))) & 0xf); + (id >> (4 * (7 - digit))) & 0xf, + (mask >> (4 * (7 - digit))) & 0xf); + + return 1; +} +ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); + +/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* + * All fields are numbers. It would be nicer to use strings for vendor + * and feature, but getting those out of the build system here is too + * complicated. + */ + +static int do_x86cpu_entry(const char *filename, void *symval, + char *alias) +{ + DEF_FIELD(symval, x86_cpu_id, feature); + DEF_FIELD(symval, x86_cpu_id, family); + DEF_FIELD(symval, x86_cpu_id, model); + DEF_FIELD(symval, x86_cpu_id, vendor); + + strcpy(alias, "cpu:type:x86,"); + ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); + ADD(alias, "fam", family != X86_FAMILY_ANY, family); + ADD(alias, "mod", model != X86_MODEL_ANY, model); + strcat(alias, ":feature:*"); + if (feature != X86_FEATURE_ANY) + sprintf(alias + strlen(alias), "%04X*", feature); + return 1; +} +ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); + +/* LOOKS like cpu:type:*:feature:*FEAT* */ +static int do_cpu_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, cpu_feature, feature); + + sprintf(alias, "cpu:type:*:feature:*%04X*", feature); + return 1; +} +ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); + +/* Looks like: mei:S */ +static int do_mei_entry(const char *filename, void *symval, + char *alias) +{ + DEF_FIELD_ADDR(symval, mei_cl_device_id, name); + + sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name); return 1; } -ADD_TO_DEVTABLE("amba", struct amba_id, do_amba_entry); +ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); + +/* Looks like: rapidio:vNdNavNadN */ +static int do_rio_entry(const char *filename, + void *symval, char *alias) +{ + DEF_FIELD(symval, rio_device_id, did); + DEF_FIELD(symval, rio_device_id, vid); + DEF_FIELD(symval, rio_device_id, asm_did); + DEF_FIELD(symval, rio_device_id, asm_vid); + + strcpy(alias, "rapidio:"); + ADD(alias, "v", vid != RIO_ANY_ID, vid); + ADD(alias, "d", did != RIO_ANY_ID, did); + ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); + ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); + + add_wildcard(alias); + return 1; +} +ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) @@ -1068,14 +1215,18 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; - const char *name; + const char *name, *identifier; unsigned int namelen; /* We're looking for a section relative symbol */ if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) return; - /* All our symbols are of form <prefix>__mod_XXX_device_table. */ + /* We're looking for an object */ + 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) return; @@ -1085,7 +1236,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, return; if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) return; - namelen -= strlen("_device_table"); + identifier = strstr(name, "__"); + if (!identifier) + return; + namelen = identifier - name; /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c index 639bca7ba55..a4fd71d71d6 100644 --- a/scripts/mod/mk_elfconfig.c +++ b/scripts/mod/mk_elfconfig.c @@ -54,4 +54,3 @@ main(int argc, char **argv) return 0; } - diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 9adb667dd31..9d9c5b905b3 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -15,17 +15,13 @@ #include <stdio.h> #include <ctype.h> #include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <errno.h> #include "modpost.h" #include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" - -/* Some toolchains use a `_' prefix for all user symbols. */ -#ifdef CONFIG_SYMBOL_PREFIX -#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX -#else -#define MODULE_SYMBOL_PREFIX "" -#endif - +#include "../../include/linux/export.h" /* Are we using CONFIG_MODVERSIONS? */ int modversions = 0; @@ -42,6 +38,8 @@ static int warn_unresolved = 0; /* How a symbol is exported */ static int sec_mismatch_count = 0; static int sec_mismatch_verbose = 1; +/* ignore missing files */ +static int ignore_missing_files; enum export { export_plain, export_unused, export_gpl, @@ -85,6 +83,14 @@ PRINTF void merror(const char *fmt, ...) va_end(arglist); } +static inline bool strends(const char *str, const char *postfix) +{ + if (strlen(str) < strlen(postfix)) + return false; + + return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} + static int is_vmlinux(const char *modname) { const char *myname; @@ -120,20 +126,20 @@ static struct module *find_module(char *modname) return mod; } -static struct module *new_module(char *modname) +static struct module *new_module(const char *modname) { struct module *mod; - char *p, *s; + char *p; mod = NOFAIL(malloc(sizeof(*mod))); memset(mod, 0, sizeof(*mod)); p = NOFAIL(strdup(modname)); /* strip trailing .o */ - s = strrchr(p, '.'); - if (s != NULL) - if (strcmp(s, ".o") == 0) - *s = '\0'; + if (strends(p, ".o")) { + p[strlen(p) - 2] = '\0'; + mod->is_dot_o = 1; + } /* add to list */ mod->name = p; @@ -158,7 +164,7 @@ struct symbol { unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ unsigned int kernel:1; /* 1 if symbol is from kernel * (only for external modules) **/ - unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ + unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ enum export export; /* Type of export */ char name[0]; }; @@ -310,7 +316,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod, s->module->name, is_vmlinux(s->module->name) ?"":".ko"); } else { - /* In case Modules.symvers was out of date */ + /* In case Module.symvers was out of date */ s->module = mod; } } @@ -326,8 +332,11 @@ static void sym_update_crc(const char *name, struct module *mod, { struct symbol *s = find_symbol(name); - if (!s) + if (!s) { s = new_symbol(name, mod, export); + /* Don't complain when we find it later. */ + s->preloaded = 1; + } s->crc = crc; s->crc_valid = 1; } @@ -335,17 +344,20 @@ static void sym_update_crc(const char *name, struct module *mod, void *grab_file(const char *filename, unsigned long *size) { struct stat st; - void *map; + void *map = MAP_FAILED; int fd; fd = open(filename, O_RDONLY); - if (fd < 0 || fstat(fd, &st) != 0) + if (fd < 0) return NULL; + if (fstat(fd, &st)) + goto failed; *size = st.st_size; map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - close(fd); +failed: + close(fd); if (map == MAP_FAILED) return NULL; return map; @@ -401,6 +413,11 @@ static int parse_elf(struct elf_info *info, const char *filename) hdr = grab_file(filename, &info->size); if (!hdr) { + if (ignore_missing_files) { + fprintf(stderr, "%s: %s (ignored)\n", filename, + strerror(errno)); + return 0; + } perror(filename); exit(1); } @@ -557,7 +574,7 @@ 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, MODULE_SYMBOL_PREFIX "__this_module") == 0) + if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0) return 1; /* ignore global offset table */ if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) @@ -567,19 +584,23 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname) 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, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || + strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || + strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) 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, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || + strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || + strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) return 1; /* Do not ignore this symbol */ return 0; } -#define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_" -#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_" +#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) @@ -587,22 +608,25 @@ static void handle_modversions(struct module *mod, struct elf_info *info, unsigned int crc; enum export export; - if (!is_vmlinux(mod->name) && strncmp(symname, "__ksymtab", 9) == 0) + if ((!is_vmlinux(mod->name) || mod->is_dot_o) && + strncmp(symname, "__ksymtab", 9) == 0) 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) { + crc = (unsigned int) sym->st_value; + sym_update_crc(symname + strlen(CRC_PFX), mod, crc, + export); + } + switch (sym->st_shndx) { case SHN_COMMON: - warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); - break; - case SHN_ABS: - /* CRC'd symbol */ - if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { - crc = (unsigned int) sym->st_value; - sym_update_crc(symname + strlen(CRC_PFX), mod, crc, - export); - } + if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { + /* Should warn here, but modpost runs before the linker */ + } else + warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); break; case SHN_UNDEF: /* undefined symbol */ @@ -631,14 +655,15 @@ static void handle_modversions(struct module *mod, struct elf_info *info, } #endif - if (memcmp(symname, MODULE_SYMBOL_PREFIX, - strlen(MODULE_SYMBOL_PREFIX)) == 0) { - mod->unres = - alloc_symbol(symname + - strlen(MODULE_SYMBOL_PREFIX), - ELF_ST_BIND(sym->st_info) == STB_WEAK, - mod->unres); - } +#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX + if (symname[0] != '_') + break; + else + symname++; +#endif + mod->unres = alloc_symbol(symname, + ELF_ST_BIND(sym->st_info) == STB_WEAK, + mod->unres); break; default: /* All exported symbols */ @@ -646,9 +671,9 @@ static void handle_modversions(struct module *mod, struct elf_info *info, sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, export); } - if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) + if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) mod->has_init = 1; - if (strcmp(symname, MODULE_SYMBOL_PREFIX "cleanup_module") == 0) + if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) mod->has_cleanup = 1; break; } @@ -813,14 +838,21 @@ static const char *section_white_list[] = { ".comment*", ".debug*", + ".cranges", /* sh64 */ ".zdebug*", /* Compressed debug sections. */ ".GCC-command-line", /* mn10300 */ + ".GCC.command.line", /* record-gcc-switches, non mn10300 */ ".mdebug*", /* alpha, score, mips etc. */ ".pdr", /* alpha, score, mips etc. */ ".stab*", ".note*", ".got*", ".toc*", + ".xt.prop", /* xtensa */ + ".xt.lit", /* xtensa */ + ".arcextmap*", /* arc */ + ".gnu.linkonce.arcext*", /* arc : modules */ + ".gnu.lto*", NULL }; @@ -830,7 +862,7 @@ static const char *section_white_list[] = * without "ax" / "aw". */ static void check_section(const char *modname, struct elf_info *elf, - Elf_Shdr *sechdr) + Elf_Shdr *sechdr) { const char *sec = sech_name(elf, sechdr); @@ -848,36 +880,34 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_INIT_DATA_SECTIONS \ - ".init.setup$", ".init.rodata$", \ - ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \ - ".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$" + ".init.setup$", ".init.rodata$", ".meminit.rodata$", \ + ".init.data$", ".meminit.data$" #define ALL_EXIT_DATA_SECTIONS \ - ".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$" + ".exit.data$", ".memexit.data$" #define ALL_INIT_TEXT_SECTIONS \ - ".init.text$", ".devinit.text$", ".cpuinit.text$", ".meminit.text$" + ".init.text$", ".meminit.text$" #define ALL_EXIT_TEXT_SECTIONS \ - ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" + ".exit.text$", ".memexit.text$" + +#define ALL_PCI_INIT_SECTIONS \ + ".pci_fixup_early$", ".pci_fixup_header$", ".pci_fixup_final$", \ + ".pci_fixup_enable$", ".pci_fixup_resume$", \ + ".pci_fixup_resume_early$", ".pci_fixup_suspend$" -#define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \ - MEM_INIT_SECTIONS -#define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \ - MEM_EXIT_SECTIONS +#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS +#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS #define DATA_SECTIONS ".data$", ".data.rel$" -#define TEXT_SECTIONS ".text$" +#define TEXT_SECTIONS ".text$", ".text.unlikely$" #define INIT_SECTIONS ".init.*" -#define DEV_INIT_SECTIONS ".devinit.*" -#define CPU_INIT_SECTIONS ".cpuinit.*" #define MEM_INIT_SECTIONS ".meminit.*" #define EXIT_SECTIONS ".exit.*" -#define DEV_EXIT_SECTIONS ".devexit.*" -#define CPU_EXIT_SECTIONS ".cpuexit.*" #define MEM_EXIT_SECTIONS ".memexit.*" /* init data sections */ @@ -965,48 +995,20 @@ const struct sectioncheck sectioncheck[] = { .mismatch = DATA_TO_ANY_EXIT, .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, -/* Do not reference init code/data from devinit/cpuinit/meminit code/data */ +/* Do not reference init code/data from meminit code/data */ { .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_SOME_INIT, .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, -/* Do not reference cpuinit code/data from meminit code/data */ -{ - .fromsec = { MEM_INIT_SECTIONS, NULL }, - .tosec = { CPU_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_SOME_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference meminit code/data from cpuinit code/data */ -{ - .fromsec = { CPU_INIT_SECTIONS, NULL }, - .tosec = { MEM_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_SOME_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ +/* Do not reference exit code/data from memexit code/data */ { .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_SOME_EXIT, .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, -/* Do not reference cpuexit code/data from memexit code/data */ -{ - .fromsec = { MEM_EXIT_SECTIONS, NULL }, - .tosec = { CPU_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_SOME_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference memexit code/data from cpuexit code/data */ -{ - .fromsec = { CPU_EXIT_SECTIONS, NULL }, - .tosec = { MEM_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_SOME_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, @@ -1021,6 +1023,12 @@ const struct sectioncheck sectioncheck[] = { .mismatch = ANY_EXIT_TO_ANY_INIT, .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, +{ + .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, + .tosec = { INIT_SECTIONS, NULL }, + .mismatch = ANY_INIT_TO_ANY_EXIT, + .symbol_white_list = { NULL }, +}, /* Do not export init/exit functions or data */ { .fromsec = { "__ksymtab*", NULL }, @@ -1069,8 +1077,6 @@ static const struct sectioncheck *section_mismatch( * Pattern 2: * Many drivers utilise a *driver container with references to * add, remove, probe functions etc. - * These functions may often be marked __devinit and we do not want to - * warn here. * the pattern is identified by: * tosec = init or exit section * fromsec = data section @@ -1229,7 +1235,6 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, /* * Convert a section name to the function/data attribute * .init.text => __init - * .cpuinit.data => __cpudata * .memexitconst => __memconst * etc. * @@ -1291,12 +1296,12 @@ static void print_section_list(const char * const list[20]) */ static void report_sec_mismatch(const char *modname, const struct sectioncheck *mismatch, - const char *fromsec, - unsigned long long fromaddr, - const char *fromsym, - int from_is_func, - const char *tosec, const char *tosym, - int to_is_func) + const char *fromsec, + unsigned long long fromaddr, + const char *fromsym, + int from_is_func, + const char *tosec, const char *tosym, + int to_is_func) { const char *from, *from_p; const char *to, *to_p; @@ -1436,7 +1441,7 @@ static void report_sec_mismatch(const char *modname, } static void check_section_mismatch(const char *modname, struct elf_info *elf, - Elf_Rela *r, Elf_Sym *sym, const char *fromsec) + Elf_Rela *r, Elf_Sym *sym, const char *fromsec) { const char *tosec; const struct sectioncheck *mismatch; @@ -1454,6 +1459,10 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, to = find_elf_symbol(elf, r->r_addend, sym); tosym = sym_name(elf, to); + if (!strncmp(fromsym, "reference___initcall", + sizeof("reference___initcall")-1)) + return; + /* check whitelist - we may ignore it */ if (secref_whitelist(mismatch, fromsec, fromsym, tosec, tosym)) { @@ -1501,6 +1510,16 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) #define R_ARM_JUMP24 29 #endif +#ifndef R_ARM_THM_CALL +#define R_ARM_THM_CALL 10 +#endif +#ifndef R_ARM_THM_JUMP24 +#define R_ARM_THM_JUMP24 30 +#endif +#ifndef R_ARM_THM_JUMP19 +#define R_ARM_THM_JUMP19 51 +#endif + static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) { unsigned int r_typ = ELF_R_TYPE(r->r_info); @@ -1509,15 +1528,18 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) case R_ARM_ABS32: /* From ARM ABI: (S + A) | T */ r->r_addend = (int)(long) - (elf->symtab_start + ELF_R_SYM(r->r_info)); + (elf->symtab_start + ELF_R_SYM(r->r_info)); break; case R_ARM_PC24: case R_ARM_CALL: case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: /* From ARM ABI: ((S + A) | T) - P */ r->r_addend = (int)(long)(elf->hdr + - sechdr->sh_offset + - (r->r_offset - sechdr->sh_addr)); + sechdr->sh_offset + + (r->r_offset - sechdr->sh_addr)); break; default: return 1; @@ -1549,7 +1571,7 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) } static void section_rela(const char *modname, struct elf_info *elf, - Elf_Shdr *sechdr) + Elf_Shdr *sechdr) { Elf_Sym *sym; Elf_Rela *rela; @@ -1593,7 +1615,7 @@ static void section_rela(const char *modname, struct elf_info *elf, } static void section_rel(const char *modname, struct elf_info *elf, - Elf_Shdr *sechdr) + Elf_Shdr *sechdr) { Elf_Sym *sym; Elf_Rel *rel; @@ -1663,7 +1685,7 @@ static void section_rel(const char *modname, struct elf_info *elf, * be discarded and warns about it. **/ static void check_sec_ref(struct module *mod, const char *modname, - struct elf_info *elf) + struct elf_info *elf) { int i; Elf_Shdr *sechdrs = elf->sechdrs; @@ -1679,6 +1701,19 @@ static void check_sec_ref(struct module *mod, const char *modname, } } +static char *remove_dot(char *s) +{ + char *end; + int n = strcspn(s, "."); + + if (n > 0 && s[n] != 0) { + strtoul(s + n + 1, &end, 10); + if (end > s + n + 1 && (*end == '.' || *end == 0)) + s[n] = 0; + } + return s; +} + static void read_symbols(char *modname) { const char *symname; @@ -1717,7 +1752,7 @@ static void read_symbols(char *modname) } for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { - symname = info.strtab + sym->st_name; + symname = remove_dot(info.strtab + sym->st_name); handle_modversions(mod, &info, sym, symname); handle_moddevtable(mod, &info, sym, symname); @@ -1744,6 +1779,27 @@ static void read_symbols(char *modname) mod->unres = alloc_symbol("module_layout", 0, mod->unres); } +static void read_symbols_from_files(const char *filename) +{ + FILE *in = stdin; + char fname[PATH_MAX]; + + if (strcmp(filename, "-") != 0) { + in = fopen(filename, "r"); + if (!in) + fatal("Can't open filenames file %s: %m", filename); + } + + while (fgets(fname, PATH_MAX, in) != NULL) { + if (strends(fname, "\n")) + fname[strlen(fname)-1] = '\0'; + read_symbols(fname); + } + + if (in != stdin) + fclose(in); +} + #define SZ 500 /* We first write the generated file into memory using the @@ -1845,16 +1901,16 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); buf_printf(b, "\n"); - buf_printf(b, "struct module __this_module\n"); + buf_printf(b, "__visible struct module __this_module\n"); buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); - buf_printf(b, " .name = KBUILD_MODNAME,\n"); + buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); if (mod->has_init) - buf_printf(b, " .init = init_module,\n"); + buf_printf(b, "\t.init = init_module,\n"); if (mod->has_cleanup) buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" - " .exit = cleanup_module,\n" + "\t.exit = cleanup_module,\n" "#endif\n"); - buf_printf(b, " .arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); } @@ -1889,7 +1945,7 @@ static int add_versions(struct buffer *b, struct module *mod) s->name, mod->name); } else { merror("\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); + s->name, mod->name); err = 1; } } @@ -1916,7 +1972,8 @@ static int add_versions(struct buffer *b, struct module *mod) s->name, mod->name); continue; } - buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name); + buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", + s->crc, s->name); } buf_printf(b, "};\n"); @@ -2056,8 +2113,10 @@ static void read_dump(const char *fname, unsigned int kernel) s->preloaded = 1; sym_update_crc(symname, mod, crc, export_no(export)); } + release_file(file, size); return; fail: + release_file(file, size); fatal("parse error in symbol dump file\n"); } @@ -2104,13 +2163,13 @@ int main(int argc, char **argv) struct module *mod; struct buffer buf = { }; char *kernel_read = NULL, *module_read = NULL; - char *dump_write = NULL; + char *dump_write = NULL, *files_source = NULL; int opt; int err; struct ext_sym_list *extsym_iter; struct ext_sym_list *extsym_start = NULL; - while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) { + while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:")) != -1) { switch (opt) { case 'i': kernel_read = optarg; @@ -2119,9 +2178,6 @@ int main(int argc, char **argv) module_read = optarg; external_module = 1; break; - case 'c': - cross_build = 1; - break; case 'e': external_module = 1; extsym_iter = @@ -2133,6 +2189,9 @@ int main(int argc, char **argv) case 'm': modversions = 1; break; + case 'n': + ignore_missing_files = 1; + break; case 'o': dump_write = optarg; break; @@ -2145,6 +2204,9 @@ int main(int argc, char **argv) case 'S': sec_mismatch_verbose = 0; break; + case 'T': + files_source = optarg; + break; case 'w': warn_unresolved = 1; break; @@ -2167,6 +2229,9 @@ int main(int argc, char **argv) while (optind < argc) read_symbols(argv[optind++]); + if (files_source) + read_symbols_from_files(files_source); + for (mod = modules; mod; mod = mod->next) { if (mod->skip) continue; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 2031119080d..168b43dc0a5 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -113,6 +113,7 @@ struct module { int has_cleanup; struct buffer dev_table_buf; char srcversion[25]; + int is_dot_o; }; struct elf_info { @@ -126,7 +127,7 @@ struct elf_info { Elf_Section export_gpl_sec; Elf_Section export_unused_gpl_sec; Elf_Section export_gpl_future_sec; - const char *strtab; + char *strtab; char *modinfo; unsigned int modinfo_len; diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index 9dfcd6d988d..944418da9fe 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -214,7 +214,7 @@ static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len) mctx->block[14] = mctx->byte_count << 3; mctx->block[15] = mctx->byte_count >> 29; le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - - sizeof(uint64_t)) / sizeof(uint32_t)); + sizeof(uint64_t)) / sizeof(uint32_t)); md4_transform(mctx->hash, mctx->block); cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t)); @@ -367,7 +367,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) break; /* Terminate line at first space, to get rid of final ' \' */ while (*p) { - if (isspace(*p)) { + if (isspace(*p)) { *p = '\0'; break; } @@ -416,7 +416,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen) basename = strrchr(modname, '/') + 1; else basename = modname; - sprintf(filelist, "%s/%.*s.mod", modverdir, + snprintf(filelist, sizeof(filelist), "%s/%.*s.mod", modverdir, (int) strlen(basename) - 2, basename); file = grab_file(filelist, &len); diff --git a/scripts/objdiff b/scripts/objdiff new file mode 100755 index 00000000000..62e51dae213 --- /dev/null +++ b/scripts/objdiff @@ -0,0 +1,159 @@ +#!/bin/bash + +# objdiff - a small script for validating that a commit or series of commits +# didn't change object code. +# +# Copyright 2014, Jason Cooper <jason@lakedaemon.net> +# +# Licensed under the terms of the GNU GPL version 2 + +# usage example: +# +# $ git checkout COMMIT_A +# $ <your fancy build command here> +# $ ./scripts/objdiff record path/to/*.o +# +# $ git checkout COMMIT_B +# $ <your fancy build command here> +# $ ./scripts/objdiff record path/to/*.o +# +# $ ./scripts/objdiff diff COMMIT_A COMMIT_B +# $ + +# And to clean up (everything is in .tmp_objdiff/*) +# $ ./scripts/objdiff clean all +# +# Note: 'make mrproper' will also remove .tmp_objdiff + +SRCTREE=$(cd $(git rev-parse --show-toplevel 2>/dev/null); pwd) + +if [ -z "$SRCTREE" ]; then + echo >&2 "ERROR: Not a git repository." + exit 1 +fi + +TMPD=$SRCTREE/.tmp_objdiff + +usage() { + echo >&2 "Usage: $0 <command> <args>" + echo >&2 " record <list of object files or directories>" + echo >&2 " diff <commitA> <commitB>" + echo >&2 " clean all | <commit>" + exit 1 +} + +get_output_dir() { + dir=${1%/*} + + if [ "$dir" = "$1" ]; then + dir=. + fi + + dir=$(cd $dir; pwd) + + echo $TMPD/$CMT${dir#$SRCTREE} +} + +do_objdump() { + dir=$(get_output_dir $1) + base=${1##*/} + dis=$dir/${base%.o}.dis + + [ ! -d "$dir" ] && mkdir -p $dir + + # remove addresses for a cleaner diff + # http://dummdida.tumblr.com/post/60924060451/binary-diff-between-libc-from-scientificlinux-and + $OBJDUMP -D $1 | sed "s/^[[:space:]]\+[0-9a-f]\+//" > $dis +} + +dorecord() { + [ $# -eq 0 ] && usage + + FILES="$*" + + CMT="`git rev-parse --short HEAD`" + + OBJDUMP="${CROSS_COMPILE}objdump" + + for d in $FILES; do + if [ -d "$d" ]; then + for f in $(find $d -name '*.o') + do + do_objdump $f + done + else + do_objdump $d + fi + done +} + +dodiff() { + [ $# -ne 2 ] && [ $# -ne 0 ] && usage + + if [ $# -eq 0 ]; then + SRC="`git rev-parse --short HEAD^`" + DST="`git rev-parse --short HEAD`" + else + SRC="`git rev-parse --short $1`" + DST="`git rev-parse --short $2`" + fi + + DIFF="`which colordiff`" + + if [ ${#DIFF} -eq 0 ] || [ ! -x "$DIFF" ]; then + DIFF="`which diff`" + fi + + SRCD="$TMPD/$SRC" + DSTD="$TMPD/$DST" + + if [ ! -d "$SRCD" ]; then + echo >&2 "ERROR: $SRCD doesn't exist" + exit 1 + fi + + if [ ! -d "$DSTD" ]; then + echo >&2 "ERROR: $DSTD doesn't exist" + exit 1 + fi + + $DIFF -Nurd $SRCD $DSTD +} + +doclean() { + [ $# -eq 0 ] && usage + [ $# -gt 1 ] && usage + + if [ "x$1" = "xall" ]; then + rm -rf $TMPD/* + else + CMT="`git rev-parse --short $1`" + + if [ -d "$TMPD/$CMT" ]; then + rm -rf $TMPD/$CMT + else + echo >&2 "$CMT not found" + fi + fi +} + +[ $# -eq 0 ] && usage + +case "$1" in + record) + shift + dorecord $* + ;; + diff) + shift + dodiff $* + ;; + clean) + shift + doclean $* + ;; + *) + echo >&2 "Unrecognized command '$1'" + exit 1 + ;; +esac diff --git a/scripts/package/Makefile b/scripts/package/Makefile index 87bf08076b1..99ca6e76eb0 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -27,53 +27,44 @@ RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \ # Remove hyphens since they have special meaning in RPM filenames KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE)) +# Include only those top-level files that are needed by make, plus the GPL copy +TAR_CONTENT := $(KBUILD_ALLDIRS) kernel.spec .config .scmversion Makefile \ + Kbuild Kconfig COPYING $(wildcard localversion*) +TAR_CONTENT := $(addprefix $(KERNELPATH)/,$(TAR_CONTENT)) MKSPEC := $(srctree)/scripts/package/mkspec -PREV := set -e; cd -P ..; # rpm-pkg # --------------------------------------------------------------------------- -$(objtree)/kernel.spec: $(MKSPEC) $(srctree)/Makefile - $(CONFIG_SHELL) $(MKSPEC) > $@ - -rpm-pkg rpm: $(objtree)/kernel.spec FORCE - @if test -n "$(KBUILD_OUTPUT)"; then \ +rpm-pkg rpm: FORCE + @if test "$(objtree)" != "$(srctree)"; then \ echo "Building source + binary RPM is not possible outside the"; \ echo "kernel source tree. Don't set KBUILD_OUTPUT, or use the"; \ echo "binrpm-pkg target instead."; \ false; \ fi $(MAKE) clean - $(PREV) ln -sf $(srctree) $(KERNELPATH) + ln -sf $(srctree) $(KERNELPATH) + $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec $(CONFIG_SHELL) $(srctree)/scripts/setlocalversion --save-scmversion - $(PREV) tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/. - $(PREV) rm $(KERNELPATH) + tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(TAR_CONTENT) + rm $(KERNELPATH) rm -f $(objtree)/.scmversion - set -e; \ $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version - set -e; \ mv -f $(objtree)/.tmp_version $(objtree)/.version - - $(RPM) $(RPMOPTS) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz - rm ../$(KERNELPATH).tar.gz - -clean-files := $(objtree)/kernel.spec + $(RPM) $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz + rm $(KERNELPATH).tar.gz kernel.spec # binrpm-pkg # --------------------------------------------------------------------------- -$(objtree)/binkernel.spec: $(MKSPEC) $(srctree)/Makefile - $(CONFIG_SHELL) $(MKSPEC) prebuilt > $@ - -binrpm-pkg: $(objtree)/binkernel.spec FORCE +binrpm-pkg: FORCE $(MAKE) KBUILD_SRC= - set -e; \ + $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version - set -e; \ mv -f $(objtree)/.tmp_version $(objtree)/.version $(RPM) $(RPMOPTS) --define "_builddir $(objtree)" --target \ - $(UTS_MACHINE) -bb $< - -clean-files += $(objtree)/binkernel.spec + $(UTS_MACHINE) -bb $(objtree)/binkernel.spec + rm binkernel.spec # Deb target # --------------------------------------------------------------------------- @@ -124,7 +115,9 @@ git --git-dir=$(srctree)/.git archive --prefix=$(perf-tar)/ \ -o $(perf-tar).tar; \ mkdir -p $(perf-tar); \ git --git-dir=$(srctree)/.git rev-parse HEAD > $(perf-tar)/HEAD; \ -tar rf $(perf-tar).tar $(perf-tar)/HEAD; \ +(cd $(srctree)/tools/perf; \ +util/PERF-VERSION-GEN ../../$(perf-tar)/ 2>/dev/null); \ +tar rf $(perf-tar).tar $(perf-tar)/HEAD $(perf-tar)/PERF-VERSION-FILE; \ rm -r $(perf-tar); \ $(if $(findstring tar-src,$@),, \ $(if $(findstring bz2,$@),bzip2, \ @@ -150,4 +143,3 @@ help: FORCE @echo ' perf-targz-src-pkg - Build $(perf-tar).tar.gz source tarball' @echo ' perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball' @echo ' perf-tarxz-src-pkg - Build $(perf-tar).tar.xz source tarball' - diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 3c6c0b14c80..35d5a5877d0 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -35,15 +35,17 @@ create_package() { sparc*) debarch=sparc ;; s390*) - debarch=s390 ;; + debarch=s390$(grep -q CONFIG_64BIT=y $KCONFIG_CONFIG && echo x || true) ;; ppc*) debarch=powerpc ;; parisc*) debarch=hppa ;; mips*) - debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;; + debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;; + arm64) + debarch=arm64 ;; arm*) - debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;; + debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;; *) echo "" >&2 echo "** ** ** WARNING ** ** **" >&2 @@ -62,7 +64,7 @@ create_package() { fi # Create the package - dpkg-gencontrol -isp $forcearch -p$pname -P"$pdir" + dpkg-gencontrol -isp $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir" dpkg --build "$pdir" .. } @@ -78,62 +80,109 @@ tmpdir="$objtree/debian/tmp" fwdir="$objtree/debian/fwtmp" kernel_headers_dir="$objtree/debian/hdrtmp" libc_headers_dir="$objtree/debian/headertmp" +dbg_dir="$objtree/debian/dbgtmp" packagename=linux-image-$version -fwpackagename=linux-firmware-image +fwpackagename=linux-firmware-image-$version kernel_headers_packagename=linux-headers-$version libc_headers_packagename=linux-libc-dev +dbg_packagename=$packagename-dbg if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version fi +# Not all arches have the same installed path in debian +# XXX: have each arch Makefile export a variable of the canonical image install +# path instead +case $ARCH in +um) + installed_image_path="usr/bin/linux-$version" + ;; +parisc|mips|powerpc) + installed_image_path="boot/vmlinux-$version" + ;; +*) + installed_image_path="boot/vmlinuz-$version" +esac + +BUILD_DEBUG="$(grep -s '^CONFIG_DEBUG_INFO=y' $KCONFIG_CONFIG || true)" + # Setup the directory structure -rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" +rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" "$dbg_dir" mkdir -m 755 -p "$tmpdir/DEBIAN" mkdir -p "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" mkdir -m 755 -p "$fwdir/DEBIAN" -mkdir -p "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename" +mkdir -p "$fwdir/lib/firmware/$version/" "$fwdir/usr/share/doc/$fwpackagename" mkdir -m 755 -p "$libc_headers_dir/DEBIAN" mkdir -p "$libc_headers_dir/usr/share/doc/$libc_headers_packagename" mkdir -m 755 -p "$kernel_headers_dir/DEBIAN" mkdir -p "$kernel_headers_dir/usr/share/doc/$kernel_headers_packagename" +mkdir -p "$kernel_headers_dir/lib/modules/$version/" if [ "$ARCH" = "um" ] ; then mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" fi +if [ -n "$BUILD_DEBUG" ] ; then + mkdir -p "$dbg_dir/usr/share/doc/$dbg_packagename" + mkdir -m 755 -p "$dbg_dir/DEBIAN" +fi # Build and install the kernel if [ "$ARCH" = "um" ] ; then $MAKE linux cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map" - cp .config "$tmpdir/usr/share/doc/$packagename/config" + cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config" gzip "$tmpdir/usr/share/doc/$packagename/config" - cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version" -else +else cp System.map "$tmpdir/boot/System.map-$version" - cp .config "$tmpdir/boot/config-$version" - # Not all arches include the boot path in KBUILD_IMAGE - if [ -e $KBUILD_IMAGE ]; then - cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" - else - cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" - fi + cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version" +fi +# Not all arches include the boot path in KBUILD_IMAGE +if [ -e $KBUILD_IMAGE ]; then + cp $KBUILD_IMAGE "$tmpdir/$installed_image_path" +else + cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/$installed_image_path" fi -if grep -q '^CONFIG_MODULES=y' .config ; then - INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install +if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then + INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install + rm -f "$tmpdir/lib/modules/$version/build" + rm -f "$tmpdir/lib/modules/$version/source" if [ "$ARCH" = "um" ] ; then mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/" rmdir "$tmpdir/lib/modules/$version" fi + if [ -n "$BUILD_DEBUG" ] ; then + ( + cd $tmpdir + for module in $(find lib/modules/ -name *.ko); do + mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module) + # only keep debug symbols in the debug file + $OBJCOPY --only-keep-debug $module $dbg_dir/usr/lib/debug/$module + # strip original module from debug symbols + $OBJCOPY --strip-debug $module + # then add a link to those + $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module + done + ) + fi fi -make headers_check -make headers_install INSTALL_HDR_PATH="$libc_headers_dir/usr" +if [ "$ARCH" != "um" ]; then + $MAKE headers_check KBUILD_SRC= + $MAKE headers_install KBUILD_SRC= INSTALL_HDR_PATH="$libc_headers_dir/usr" +fi # Install the maintainer scripts # Note: hook scripts under /etc/kernel are also executed by official Debian -# kernel packages, as well as kernel packages built using make-kpkg +# kernel packages, as well as kernel packages built using make-kpkg. +# make-kpkg sets $INITRD to indicate whether an initramfs is wanted, and +# so do we; recent versions of dracut and initramfs-tools will obey this. debhookdir=${KDEB_HOOKDIR:-/etc/kernel} +if grep -q '^CONFIG_BLK_DEV_INITRD=y' $KCONFIG_CONFIG; then + want_initrd=Yes +else + want_initrd=No +fi for script in postinst postrm preinst prerm ; do mkdir -p "$tmpdir$debhookdir/$script.d" cat <<EOF > "$tmpdir/DEBIAN/$script" @@ -144,7 +193,10 @@ set -e # Pass maintainer script parameters to hook scripts export DEB_MAINT_PARAMS="\$*" -test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d +# Tell initramfs builder whether it's wanted +export INITRD=$want_initrd + +test -d $debhookdir/$script.d && run-parts --arg="$version" --arg="/$installed_image_path" $debhookdir/$script.d exit 0 EOF chmod 755 "$tmpdir/DEBIAN/$script" @@ -237,33 +289,35 @@ EOF fi -# Build header package -(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles") -(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles") -(cd $objtree; find .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") +# Build kernel header package +(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles" +(cd $srctree; find arch/$SRCARCH/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles" +(cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles" +(cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles" +(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles" destdir=$kernel_headers_dir/usr/src/linux-headers-$version mkdir -p "$destdir" -(cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -) -(cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -) +(cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -) +(cd $objtree; tar -c -f - -T -) < "$objtree/debian/hdrobjfiles" | (cd $destdir; tar -xf -) +(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be +ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build" rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles" -arch=$(dpkg --print-architecture) cat <<EOF >> debian/control Package: $kernel_headers_packagename Provides: linux-headers, linux-headers-2.6 -Architecture: $arch -Description: Linux kernel headers for $KERNELRELEASE on $arch - This package provides kernel header files for $KERNELRELEASE on $arch +Architecture: any +Description: Linux kernel headers for $KERNELRELEASE on \${kernel:debarch} + This package provides kernel header files for $KERNELRELEASE on \${kernel:debarch} . This is useful for people who need to build external modules EOF -create_package "$kernel_headers_packagename" "$kernel_headers_dir" - # Do we have firmware? Move it out of the way and build it into a package. if [ -e "$tmpdir/lib/firmware" ]; then - mv "$tmpdir/lib/firmware" "$fwdir/lib/" + mv "$tmpdir/lib/firmware"/* "$fwdir/lib/firmware/$version/" + rmdir "$tmpdir/lib/firmware" cat <<EOF >> debian/control @@ -287,7 +341,37 @@ Description: Linux support headers for userspace development are used by the installed headers for GNU glibc and other system libraries. EOF -create_package "$libc_headers_packagename" "$libc_headers_dir" +if [ "$ARCH" != "um" ]; then + create_package "$kernel_headers_packagename" "$kernel_headers_dir" + create_package "$libc_headers_packagename" "$libc_headers_dir" +fi + create_package "$packagename" "$tmpdir" +if [ -n "$BUILD_DEBUG" ] ; then + # Build debug package + # Different tools want the image in different locations + # perf + mkdir -p $dbg_dir/usr/lib/debug/lib/modules/$version/ + cp vmlinux $dbg_dir/usr/lib/debug/lib/modules/$version/ + # systemtap + mkdir -p $dbg_dir/usr/lib/debug/boot/ + ln -s ../lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/boot/vmlinux-$version + # kdump-tools + ln -s lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/vmlinux-$version + + cat <<EOF >> debian/control + +Package: $dbg_packagename +Section: debug +Provides: linux-debug, linux-debug-$version +Architecture: any +Description: Linux kernel debugging symbols for $version + This package will come in handy if you need to debug the kernel. It provides + all the necessary debug symbols for the kernel and its modules. +EOF + + create_package "$dbg_packagename" "$dbg_dir" +fi + exit 0 diff --git a/scripts/package/buildtar b/scripts/package/buildtar index 8a7b15598ea..e046bff3358 100644 --- a/scripts/package/buildtar +++ b/scripts/package/buildtar @@ -16,7 +16,7 @@ set -e # Some variables and settings used throughout the script # tmpdir="${objtree}/tar-install" -tarball="${objtree}/linux-${KERNELRELEASE}.tar" +tarball="${objtree}/linux-${KERNELRELEASE}-${ARCH}.tar" # @@ -28,15 +28,15 @@ case "${1}" in file_ext="" ;; targz-pkg) - compress="gzip -c9" + compress="gzip" file_ext=".gz" ;; tarbz2-pkg) - compress="bzip2 -c9" + compress="bzip2" file_ext=".bz2" ;; tarxz-pkg) - compress="xz -c9" + compress="xz" file_ext=".xz" ;; *) @@ -87,6 +87,27 @@ case "${ARCH}" in [ -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}" + elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" ]; then + cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" + elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.srec" ]; then + cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.srec" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}" + elif [ -f "${objtree}/vmlinux.32" ]; then + cp -v -- "${objtree}/vmlinux.32" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + elif [ -f "${objtree}/vmlinux.64" ]; then + cp -v -- "${objtree}/vmlinux.64" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + elif [ -f "${objtree}/arch/mips/boot/vmlinux.bin" ]; then + cp -v -- "${objtree}/arch/mips/boot/vmlinux.bin" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + elif [ -f "${objtree}/arch/mips/boot/vmlinux.ecoff" ]; then + cp -v -- "${objtree}/arch/mips/boot/vmlinux.ecoff" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + elif [ -f "${objtree}/arch/mips/boot/vmlinux.srec" ]; then + cp -v -- "${objtree}/arch/mips/boot/vmlinux.srec" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + elif [ -f "${objtree}/vmlinux" ]; then + cp -v -- "${objtree}/vmlinux" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}" + fi + ;; *) [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${KERNELRELEASE}" echo "" >&2 @@ -104,15 +125,13 @@ esac # Create the tarball # ( - cd "${tmpdir}" opts= if tar --owner=root --group=root --help >/dev/null 2>&1; then opts="--owner=root --group=root" fi - tar cf - . $opts | ${compress} > "${tarball}${file_ext}" + tar cf - -C "$tmpdir" boot/ lib/ $opts | ${compress} > "${tarball}${file_ext}" ) echo "Tarball successfully created in ${tarball}${file_ext}" exit 0 - diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 4bf17ddf7c7..13957602f7c 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -1,7 +1,7 @@ #!/bin/sh # -# Output a simple RPM spec file that uses no fancy features requiring -# RPM v4. This is intended to work with any RPM distro. +# Output a simple RPM spec file. +# This version assumes a minimum of RPM 4.0.3. # # The only gothic bit here is redefining install_post to avoid # stripping the symbols from files in the kernel which we want @@ -59,6 +59,14 @@ echo "header files define structures and constants that are needed for" echo "building most standard programs and are also needed for rebuilding the" echo "glibc package." echo "" +echo "%package devel" +echo "Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel" +echo "Group: System Environment/Kernel" +echo "AutoReqProv: no" +echo "%description -n kernel-devel" +echo "This package provides kernel headers and makefiles sufficient to build modules" +echo "against the $__KERNELRELEASE kernel package." +echo "" if ! $PREBUILT; then echo "%prep" @@ -74,15 +82,17 @@ echo "" fi echo "%install" +echo 'KBUILD_IMAGE=$(make image_name)' echo "%ifarch ia64" echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules' -echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware' echo "%else" echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules' -echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware' echo "%endif" +echo 'mkdir -p $RPM_BUILD_ROOT'"/lib/firmware/$KERNELRELEASE" -echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= modules_install' +echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= mod-fw= modules_install' +echo 'INSTALL_FW_PATH=$RPM_BUILD_ROOT'"/lib/firmware/$KERNELRELEASE" +echo 'make INSTALL_FW_PATH=$INSTALL_FW_PATH' firmware_install echo "%ifarch ia64" echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE" echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/" @@ -95,7 +105,7 @@ echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE" echo "%endif" echo "%endif" -echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr headers_install' +echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr KBUILD_SRC= headers_install' echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE" echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE" @@ -107,18 +117,43 @@ echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2" echo 'mv vmlinux.orig vmlinux' echo "%endif" +echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/{build,source}" +echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE" +echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=firmware --exclude .config.old --exclude .missing-syscalls.d\"" +echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)" +echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE" +echo "ln -sf /usr/src/kernels/$KERNELRELEASE build" +echo "ln -sf /usr/src/kernels/$KERNELRELEASE source" + echo "" echo "%clean" echo 'rm -rf $RPM_BUILD_ROOT' echo "" +echo "%post" +echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then" +echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm" +echo "cp /boot/System.map-$KERNELRELEASE /boot/System.map-$KERNELRELEASE-rpm" +echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE" +echo "/sbin/installkernel $KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm" +echo "rm -f /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm" +echo "fi" +echo "" echo "%files" echo '%defattr (-, root, root)' echo "%dir /lib/modules" echo "/lib/modules/$KERNELRELEASE" -echo "/lib/firmware" +echo "%exclude /lib/modules/$KERNELRELEASE/build" +echo "%exclude /lib/modules/$KERNELRELEASE/source" +echo "/lib/firmware/$KERNELRELEASE" echo "/boot/*" echo "" echo "%files headers" echo '%defattr (-, root, root)' echo "/usr/include" echo "" +echo "%files devel" +echo '%defattr (-, root, root)' +echo "/usr/src/kernels/$KERNELRELEASE" +echo "/lib/modules/$KERNELRELEASE/build" +echo "/lib/modules/$KERNELRELEASE/source" +echo "" diff --git a/scripts/patch-kernel b/scripts/patch-kernel index 20fb25c2338..49b4241e814 100755 --- a/scripts/patch-kernel +++ b/scripts/patch-kernel @@ -27,7 +27,7 @@ # Nick Holloway <Nick.Holloway@alfie.demon.co.uk>, 2nd January 1995. # # Added support for handling multiple types of compression. What includes -# gzip, bzip, bzip2, zip, compress, and plaintext. +# gzip, bzip, bzip2, zip, compress, and plaintext. # # Adam Sulmicki <adam@cfar.umd.edu>, 1st January 1997. # @@ -116,6 +116,10 @@ findFile () { ext=".bz2" name="bzip2" uncomp="bunzip2 -dc" + elif [ -r ${filebase}.xz ]; then + ext=".xz" + name="xz" + uncomp="xz -dc" elif [ -r ${filebase}.zip ]; then ext=".zip" name="zip" @@ -155,7 +159,7 @@ applyPatch () { fi # Remove backup files find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \; - + return 0; } diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c index 5c113123ed9..4718d7895f0 100644 --- a/scripts/pnmtologo.c +++ b/scripts/pnmtologo.c @@ -74,6 +74,7 @@ static unsigned int logo_height; static struct color **logo_data; static struct color logo_clut[MAX_LINUX_LOGO_COLORS]; static unsigned int logo_clutsize; +static int is_plain_pbm = 0; static void die(const char *fmt, ...) __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2))); @@ -103,6 +104,11 @@ static unsigned int get_number(FILE *fp) val = 0; while (isdigit(c)) { val = 10*val+c-'0'; + /* some PBM are 'broken'; GiMP for example exports a PBM without space + * between the digits. This is Ok cause we know a PBM can only have a '1' + * or a '0' for the digit. */ + if (is_plain_pbm) + break; c = fgetc(fp); if (c == EOF) die("%s: end of file\n", filename); @@ -167,6 +173,7 @@ static void read_image(void) switch (magic) { case '1': /* Plain PBM */ + is_plain_pbm = 1; for (i = 0; i < logo_height; i++) for (j = 0; j < logo_width; j++) logo_data[i][j].red = logo_data[i][j].green = @@ -505,4 +512,3 @@ int main(int argc, char *argv[]) } exit(0); } - diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index ee52cb8e17a..650ecc83d7d 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -33,6 +33,18 @@ #include <string.h> #include <unistd.h> +#ifndef EM_METAG +/* Remove this when these make it to the standard system elf.h. */ +#define EM_METAG 174 +#define R_METAG_ADDR32 2 +#define R_METAG_NONE 3 +#endif + +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#define R_AARCH64_ABS64 257 +#endif + static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ @@ -340,7 +352,15 @@ do_file(char const *const fname) case EM_ARM: reltype = R_ARM_ABS32; altmcount = "__gnu_mcount_nc"; break; + case EM_AARCH64: + reltype = R_AARCH64_ABS64; gpfx = '_'; break; case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break; + case EM_METAG: reltype = R_METAG_ADDR32; + altmcount = "_mcount_wrapper"; + rel_type_nop = R_METAG_NONE; + /* We happen to have the same requirement as MIPS */ + is_fake_mcount32 = MIPS32_is_fake_mcount; + break; case EM_MIPS: /* reltype: e_class */ gpfx = '_'; break; case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break; case EM_PPC64: reltype = R_PPC64_ADDR64; gpfx = '_'; break; @@ -467,5 +487,3 @@ main(int argc, char *argv[]) } return !!n_error; } - - diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 54e35c1e594..49b582a225b 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -163,11 +163,11 @@ static int mcount_adjust = 0; static int MIPS_is_fake_mcount(Elf_Rel const *rp) { - static Elf_Addr old_r_offset; + static Elf_Addr old_r_offset = ~(Elf_Addr)0; Elf_Addr current_r_offset = _w(rp->r_offset); int is_fake; - is_fake = old_r_offset && + is_fake = (old_r_offset != ~(Elf_Addr)0) && (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET); old_r_offset = current_r_offset; @@ -261,11 +261,13 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0, &sym0[Elf_r_sym(relp)]; char const *symname = &str0[w(symp->st_name)]; char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; + char const *fentry = "__fentry__"; if (symname[0] == '.') ++symname; /* ppc64 hack */ if (strcmp(mcount, symname) == 0 || - (altmcount && strcmp(altmcount, symname) == 0)) + (altmcount && strcmp(altmcount, symname) == 0) || + (strcmp(fentry, symname) == 0)) mcountsym = Elf_r_sym(relp); return mcountsym; diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 858966ab019..397b6b84e8c 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -214,13 +214,13 @@ $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; $weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)"; $section_regex = "Disassembly of section\\s+(\\S+):"; $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; -$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; +$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)\$"; $section_type = '@progbits'; $mcount_adjust = 0; $type = ".long"; if ($arch eq "x86_64") { - $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount([+-]0x[0-9a-zA-Z]+)?\$"; + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)([+-]0x[0-9a-zA-Z]+)?\$"; $type = ".quad"; $alignment = 8; $mcount_adjust = -1; @@ -279,6 +279,11 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24|THM_CALL)" . "\\s+(__gnu_mcount_nc|mcount)\$"; +} elsif ($arch eq "arm64") { + $alignment = 3; + $section_type = '%progbits'; + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+_mcount\$"; + $type = ".quad"; } elsif ($arch eq "ia64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; $type = "data8"; @@ -364,6 +369,11 @@ if ($arch eq "x86_64") { } elsif ($arch eq "blackfin") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; $mcount_adjust = -4; +} elsif ($arch eq "tilegx" || $arch eq "tile") { + # Default to the newer TILE-Gx architecture if only "tile" is given. + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; + $type = ".quad"; + $alignment = 8; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } diff --git a/scripts/rt-tester/check-all.sh b/scripts/rt-tester/check-all.sh index 43098afe743..6b5c83baf14 100644 --- a/scripts/rt-tester/check-all.sh +++ b/scripts/rt-tester/check-all.sh @@ -19,4 +19,3 @@ testit t3-l2-pi.tst testit t4-l2-pi-deboost.tst testit t5-l4-pi-boost-deboost.tst testit t5-l4-pi-boost-deboost-setsched.tst - diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py index 34186cac1d2..6d916c2a45a 100644 --- a/scripts/rt-tester/rt-tester.py +++ b/scripts/rt-tester/rt-tester.py @@ -216,5 +216,3 @@ while 1: # Normal exit pass print "Pass" sys.exit(0) - - diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh index 7b9ccf61f8f..f6a0ce71015 100644 --- a/scripts/selinux/install_policy.sh +++ b/scripts/selinux/install_policy.sh @@ -66,4 +66,3 @@ if [ "eq$dodev" != "eq" ]; then $SF file_contexts /dev mount --move /mnt /dev fi - diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 4d403844e13..63d91e22ed7 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -43,7 +43,8 @@ scm_version() fi # Check for git and a git repo. - if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then + if test -z "$(git rev-parse --show-cdup 2>/dev/null)" && + head=`git rev-parse --verify --short HEAD 2>/dev/null`; then # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore # it, because this version is defined in the top level Makefile. @@ -71,12 +72,8 @@ scm_version() printf -- '-svn%s' "`git svn find-rev $head`" fi - # Update index only on r/w media - [ -w . ] && git update-index --refresh --unmerged > /dev/null - # Check for uncommitted changes - if git diff-index --name-only HEAD | grep -v "^scripts/package" \ - | read dummy; then + if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then printf '%s' -dirty fi @@ -109,7 +106,7 @@ scm_version() fi # Check for svn and a svn repo. - if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then + if rev=`LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'`; then rev=`echo $rev | awk '{print $NF}'` printf -- '-svn%s' "$rev" diff --git a/scripts/show_delta b/scripts/show_delta index 17df3051747..5b365009e6a 100755 --- a/scripts/show_delta +++ b/scripts/show_delta @@ -13,7 +13,7 @@ import sys import string def usage(): - print """usage: show_delta [<options>] <filename> + print ("""usage: show_delta [<options>] <filename> This program parses the output from a set of printk message lines which have time data prefixed because the CONFIG_PRINTK_TIME option is set, or @@ -35,7 +35,7 @@ ex: $ dmesg >timefile will show times relative to the line in the kernel output starting with "NET4". -""" +""") sys.exit(1) # returns a tuple containing the seconds and text for each message line @@ -94,11 +94,11 @@ def main(): try: lines = open(filein,"r").readlines() except: - print "Problem opening file: %s" % filein + print ("Problem opening file: %s" % filein) sys.exit(1) if base_str: - print 'base= "%s"' % base_str + print ('base= "%s"' % base_str) # assume a numeric base. If that fails, try searching # for a matching line. try: @@ -117,13 +117,12 @@ def main(): # stop at first match break if not found: - print 'Couldn\'t find line matching base pattern "%s"' % base_str + print ('Couldn\'t find line matching base pattern "%s"' % base_str) sys.exit(1) else: base_time = 0.0 for line in lines: - print convert_line(line, base_time), + print (convert_line(line, base_time),) main() - diff --git a/scripts/sign-file b/scripts/sign-file new file mode 100755 index 00000000000..2b7c4484d46 --- /dev/null +++ b/scripts/sign-file @@ -0,0 +1,421 @@ +#!/usr/bin/perl -w +# +# Sign a module file using the given key. +# + +my $USAGE = +"Usage: scripts/sign-file [-v] <hash algo> <key> <x509> <module> [<dest>]\n" . +" scripts/sign-file [-v] -s <raw sig> <hash algo> <x509> <module> [<dest>]\n"; + +use strict; +use FileHandle; +use IPC::Open2; +use Getopt::Std; + +my %opts; +getopts('vs:', \%opts) or die $USAGE; +my $verbose = $opts{'v'}; +my $signature_file = $opts{'s'}; + +die $USAGE if ($#ARGV > 4); +die $USAGE if (!$signature_file && $#ARGV < 3 || $signature_file && $#ARGV < 2); + +my $dgst = shift @ARGV; +my $private_key; +if (!$signature_file) { + $private_key = shift @ARGV; +} +my $x509 = shift @ARGV; +my $module = shift @ARGV; +my ($dest, $keep_orig); +if (@ARGV) { + $dest = $ARGV[0]; + $keep_orig = 1; +} else { + $dest = $module . "~"; +} + +die "Can't read private key\n" if (!$signature_file && !-r $private_key); +die "Can't read signature file\n" if ($signature_file && !-r $signature_file); +die "Can't read X.509 certificate\n" unless (-r $x509); +die "Can't read module\n" unless (-r $module); + +# +# Function to read the contents of a file into a variable. +# +sub read_file($) +{ + my ($file) = @_; + my $contents; + my $len; + + open(FD, "<$file") || die $file; + binmode FD; + my @st = stat(FD); + die $file if (!@st); + $len = read(FD, $contents, $st[7]) || die $file; + close(FD) || die $file; + die "$file: Wanted length ", $st[7], ", got ", $len, "\n" + if ($len != $st[7]); + return $contents; +} + +############################################################################### +# +# First of all, we have to parse the X.509 certificate to find certain details +# about it. +# +# We read the DER-encoded X509 certificate and parse it to extract the Subject +# name and Subject Key Identifier. Theis provides the data we need to build +# the certificate identifier. +# +# The signer's name part of the identifier is fabricated from the commonName, +# the organizationName or the emailAddress components of the X.509 subject +# name. +# +# The subject key ID is used to select which of that signer's certificates +# we're intending to use to sign the module. +# +############################################################################### +my $x509_certificate = read_file($x509); + +my $UNIV = 0 << 6; +my $APPL = 1 << 6; +my $CONT = 2 << 6; +my $PRIV = 3 << 6; + +my $CONS = 0x20; + +my $BOOLEAN = 0x01; +my $INTEGER = 0x02; +my $BIT_STRING = 0x03; +my $OCTET_STRING = 0x04; +my $NULL = 0x05; +my $OBJ_ID = 0x06; +my $UTF8String = 0x0c; +my $SEQUENCE = 0x10; +my $SET = 0x11; +my $UTCTime = 0x17; +my $GeneralizedTime = 0x18; + +my %OIDs = ( + pack("CCC", 85, 4, 3) => "commonName", + pack("CCC", 85, 4, 6) => "countryName", + pack("CCC", 85, 4, 10) => "organizationName", + pack("CCC", 85, 4, 11) => "organizationUnitName", + pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", + pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", + pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", + pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", + pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", + pack("CCC", 85, 29, 19) => "basicConstraints" +); + +############################################################################### +# +# Extract an ASN.1 element from a string and return information about it. +# +############################################################################### +sub asn1_extract($$@) +{ + my ($cursor, $expected_tag, $optional) = @_; + + return [ -1 ] + if ($cursor->[1] == 0 && $optional); + + die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" + if ($cursor->[1] < 2); + + my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); + + if ($expected_tag != -1 && $tag != $expected_tag) { + return [ -1 ] + if ($optional); + die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, + " not ", $expected_tag, ")\n"; + } + + $cursor->[0] += 2; + $cursor->[1] -= 2; + + die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n" + if (($tag & 0x1f) == 0x1f); + die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n" + if ($len == 0x80); + + if ($len > 0x80) { + my $l = $len - 0x80; + die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" + if ($cursor->[1] < $l); + + if ($l == 0x1) { + $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); + } elsif ($l == 0x2) { + $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); + } elsif ($l == 0x3) { + $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; + $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); + } elsif ($l == 0x4) { + $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); + } else { + die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; + } + + $cursor->[0] += $l; + $cursor->[1] -= $l; + } + + die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" + if ($cursor->[1] < $len); + + my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; + $cursor->[0] += $len; + $cursor->[1] -= $len; + + return $ret; +} + +############################################################################### +# +# Retrieve the data referred to by a cursor +# +############################################################################### +sub asn1_retrieve($) +{ + my ($cursor) = @_; + my ($offset, $len, $data) = @$cursor; + return substr($$data, $offset, $len); +} + +############################################################################### +# +# Roughly parse the X.509 certificate +# +############################################################################### +my $cursor = [ 0, length($x509_certificate), \$x509_certificate ]; + +my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); +my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); +my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); +my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); +my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); +my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); +my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); + +my $subject_key_id = (); +my $authority_key_id = (); + +# +# Parse the extension list +# +if ($extension_list->[0] != -1) { + my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); + + while ($extensions->[1]->[1] > 0) { + my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); + my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); + my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); + my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); + + my $raw_oid = asn1_retrieve($x_oid->[1]); + next if (!exists($OIDs{$raw_oid})); + my $x_type = $OIDs{$raw_oid}; + + my $raw_value = asn1_retrieve($x_val->[1]); + + if ($x_type eq "subjectKeyIdentifier") { + my $vcursor = [ 0, length($raw_value), \$raw_value ]; + + $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); + } + } +} + +############################################################################### +# +# Determine what we're going to use as the signer's name. In order of +# preference, take one of: commonName, organizationName or emailAddress. +# +############################################################################### +my $org = ""; +my $cn = ""; +my $email = ""; + +while ($subject->[1]->[1] > 0) { + my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); + my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); + my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); + my $n_val = asn1_extract($attr->[1], -1); + + my $raw_oid = asn1_retrieve($n_oid->[1]); + next if (!exists($OIDs{$raw_oid})); + my $n_type = $OIDs{$raw_oid}; + + my $raw_value = asn1_retrieve($n_val->[1]); + + if ($n_type eq "organizationName") { + $org = $raw_value; + } elsif ($n_type eq "commonName") { + $cn = $raw_value; + } elsif ($n_type eq "emailAddress") { + $email = $raw_value; + } +} + +my $signers_name = $email; + +if ($org && $cn) { + # Don't use the organizationName if the commonName repeats it + if (length($org) <= length($cn) && + substr($cn, 0, length($org)) eq $org) { + $signers_name = $cn; + goto got_id_name; + } + + # Or a signifcant chunk of it + if (length($org) >= 7 && + length($cn) >= 7 && + substr($cn, 0, 7) eq substr($org, 0, 7)) { + $signers_name = $cn; + goto got_id_name; + } + + $signers_name = $org . ": " . $cn; +} elsif ($org) { + $signers_name = $org; +} elsif ($cn) { + $signers_name = $cn; +} + +got_id_name: + +die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" + if (!$subject_key_id); + +my $key_identifier = asn1_retrieve($subject_key_id->[1]); + +############################################################################### +# +# Create and attach the module signature +# +############################################################################### + +# +# Signature parameters +# +my $algo = 1; # Public-key crypto algorithm: RSA +my $hash = 0; # Digest algorithm +my $id_type = 1; # Identifier type: X.509 + +# +# Digest the data +# +my $prologue; +if ($dgst eq "sha1") { + $prologue = pack("C*", + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2B, 0x0E, 0x03, 0x02, 0x1A, + 0x05, 0x00, 0x04, 0x14); + $hash = 2; +} elsif ($dgst eq "sha224") { + $prologue = pack("C*", + 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, + 0x05, 0x00, 0x04, 0x1C); + $hash = 7; +} elsif ($dgst eq "sha256") { + $prologue = pack("C*", + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x20); + $hash = 4; +} elsif ($dgst eq "sha384") { + $prologue = pack("C*", + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, + 0x05, 0x00, 0x04, 0x30); + $hash = 5; +} elsif ($dgst eq "sha512") { + $prologue = pack("C*", + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, + 0x05, 0x00, 0x04, 0x40); + $hash = 6; +} else { + die "Unknown hash algorithm: $dgst\n"; +} + +my $signature; +if ($signature_file) { + $signature = read_file($signature_file); +} else { + # + # Generate the digest and read from openssl's stdout + # + my $digest; + $digest = readpipe("openssl dgst -$dgst -binary $module") || die "openssl dgst"; + + # + # Generate the binary signature, which will be just the integer that + # comprises the signature with no metadata attached. + # + my $pid; + $pid = open2(*read_from, *write_to, + "openssl rsautl -sign -inkey $private_key -keyform PEM") || + die "openssl rsautl"; + binmode write_to; + print write_to $prologue . $digest || die "pipe to openssl rsautl"; + close(write_to) || die "pipe to openssl rsautl"; + + binmode read_from; + read(read_from, $signature, 4096) || die "pipe from openssl rsautl"; + close(read_from) || die "pipe from openssl rsautl"; + waitpid($pid, 0) || die; + die "openssl rsautl died: $?" if ($? >> 8); +} +$signature = pack("n", length($signature)) . $signature, + +# +# Build the signed binary +# +my $unsigned_module = read_file($module); + +my $magic_number = "~Module signature appended~\n"; + +my $info = pack("CCCCCxxxN", + $algo, $hash, $id_type, + length($signers_name), + length($key_identifier), + length($signature)); + +if ($verbose) { + print "Size of unsigned module: ", length($unsigned_module), "\n"; + print "Size of signer's name : ", length($signers_name), "\n"; + print "Size of key identifier : ", length($key_identifier), "\n"; + print "Size of signature : ", length($signature), "\n"; + print "Size of informaton : ", length($info), "\n"; + print "Size of magic number : ", length($magic_number), "\n"; + print "Signer's name : '", $signers_name, "'\n"; + print "Digest : $dgst\n"; +} + +open(FD, ">$dest") || die $dest; +binmode FD; +print FD + $unsigned_module, + $signers_name, + $key_identifier, + $signature, + $info, + $magic_number + ; +close FD || die $dest; + +if (!$keep_orig) { + rename($dest, $module) || die $module; +} diff --git a/scripts/sortextable.c b/scripts/sortextable.c new file mode 100644 index 00000000000..1052d4834a4 --- /dev/null +++ b/scripts/sortextable.c @@ -0,0 +1,360 @@ +/* + * sortextable.c: Sort the kernel's exception table + * + * Copyright 2011 - 2012 Cavium, Inc. + * + * Based on code taken from recortmcount.c which is: + * + * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. + * Licensed under the GNU General Public License, version 2 (GPLv2). + * + * Restructured to fit Linux format, as well as other updates: + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. + */ + +/* + * Strategy: alter the vmlinux file in-place. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <getopt.h> +#include <elf.h> +#include <fcntl.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <tools/be_byteshift.h> +#include <tools/le_byteshift.h> + +#ifndef EM_ARCOMPACT +#define EM_ARCOMPACT 93 +#endif + +#ifndef EM_XTENSA +#define EM_XTENSA 94 +#endif + +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#endif + +#ifndef EM_MICROBLAZE +#define EM_MICROBLAZE 189 +#endif + +static int fd_map; /* File descriptor for file being modified. */ +static int mmap_failed; /* Boolean flag. */ +static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ +static struct stat sb; /* Remember .st_size, etc. */ +static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ + +/* setjmp() return values */ +enum { + SJ_SETJMP = 0, /* hardwired first return */ + SJ_FAIL, + SJ_SUCCEED +}; + +/* Per-file resource cleanup when multiple files. */ +static void +cleanup(void) +{ + if (!mmap_failed) + munmap(ehdr_curr, sb.st_size); + close(fd_map); +} + +static void __attribute__((noreturn)) +fail_file(void) +{ + cleanup(); + longjmp(jmpenv, SJ_FAIL); +} + +/* + * Get the whole file as a programming convenience in order to avoid + * malloc+lseek+read+free of many pieces. If successful, then mmap + * avoids copying unused pieces; else just read the whole file. + * Open for both read and write. + */ +static void *mmap_file(char const *fname) +{ + void *addr; + + fd_map = open(fname, O_RDWR); + if (fd_map < 0 || fstat(fd_map, &sb) < 0) { + perror(fname); + fail_file(); + } + if (!S_ISREG(sb.st_mode)) { + fprintf(stderr, "not a regular file: %s\n", fname); + fail_file(); + } + addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd_map, 0); + if (addr == MAP_FAILED) { + mmap_failed = 1; + fprintf(stderr, "Could not mmap file: %s\n", fname); + fail_file(); + } + return addr; +} + +static uint64_t r8be(const uint64_t *x) +{ + return get_unaligned_be64(x); +} +static uint32_t rbe(const uint32_t *x) +{ + return get_unaligned_be32(x); +} +static uint16_t r2be(const uint16_t *x) +{ + return get_unaligned_be16(x); +} +static uint64_t r8le(const uint64_t *x) +{ + return get_unaligned_le64(x); +} +static uint32_t rle(const uint32_t *x) +{ + return get_unaligned_le32(x); +} +static uint16_t r2le(const uint16_t *x) +{ + return get_unaligned_le16(x); +} + +static void w8be(uint64_t val, uint64_t *x) +{ + put_unaligned_be64(val, x); +} +static void wbe(uint32_t val, uint32_t *x) +{ + put_unaligned_be32(val, x); +} +static void w2be(uint16_t val, uint16_t *x) +{ + put_unaligned_be16(val, x); +} +static void w8le(uint64_t val, uint64_t *x) +{ + put_unaligned_le64(val, x); +} +static void wle(uint32_t val, uint32_t *x) +{ + put_unaligned_le32(val, x); +} +static void w2le(uint16_t val, uint16_t *x) +{ + put_unaligned_le16(val, x); +} + +static uint64_t (*r8)(const uint64_t *); +static uint32_t (*r)(const uint32_t *); +static uint16_t (*r2)(const uint16_t *); +static void (*w8)(uint64_t, uint64_t *); +static void (*w)(uint32_t, uint32_t *); +static void (*w2)(uint16_t, uint16_t *); + +typedef void (*table_sort_t)(char *, int); + +/* + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of + * the way to -256..-1, to avoid conflicting with real section + * indices. + */ +#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) + +static inline int is_shndx_special(unsigned int i) +{ + return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; +} + +/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ +static inline unsigned int get_secindex(unsigned int shndx, + unsigned int sym_offs, + const Elf32_Word *symtab_shndx_start) +{ + if (is_shndx_special(shndx)) + return SPECIAL(shndx); + if (shndx != SHN_XINDEX) + return shndx; + return r(&symtab_shndx_start[sym_offs]); +} + +/* 32 bit and 64 bit are very similar */ +#include "sortextable.h" +#define SORTEXTABLE_64 +#include "sortextable.h" + +static int compare_relative_table(const void *a, const void *b) +{ + int32_t av = (int32_t)r(a); + int32_t bv = (int32_t)r(b); + + if (av < bv) + return -1; + if (av > bv) + return 1; + return 0; +} + +static void sort_relative_table(char *extab_image, int image_size) +{ + int i; + + /* + * Do the same thing the runtime sort does, first normalize to + * being relative to the start of the section. + */ + i = 0; + while (i < image_size) { + uint32_t *loc = (uint32_t *)(extab_image + i); + w(r(loc) + i, loc); + i += 4; + } + + qsort(extab_image, image_size / 8, 8, compare_relative_table); + + /* Now denormalize. */ + i = 0; + while (i < image_size) { + uint32_t *loc = (uint32_t *)(extab_image + i); + w(r(loc) - i, loc); + i += 4; + } +} + +static void +do_file(char const *const fname) +{ + table_sort_t custom_sort; + Elf32_Ehdr *ehdr = mmap_file(fname); + + ehdr_curr = ehdr; + switch (ehdr->e_ident[EI_DATA]) { + default: + fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", + ehdr->e_ident[EI_DATA], fname); + fail_file(); + break; + case ELFDATA2LSB: + r = rle; + r2 = r2le; + r8 = r8le; + w = wle; + w2 = w2le; + w8 = w8le; + break; + case ELFDATA2MSB: + r = rbe; + r2 = r2be; + r8 = r8be; + w = wbe; + w2 = w2be; + w8 = w8be; + break; + } /* end switch */ + if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 + || r2(&ehdr->e_type) != ET_EXEC + || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); + fail_file(); + } + + custom_sort = NULL; + switch (r2(&ehdr->e_machine)) { + default: + fprintf(stderr, "unrecognized e_machine %d %s\n", + r2(&ehdr->e_machine), fname); + fail_file(); + break; + case EM_386: + case EM_X86_64: + case EM_S390: + custom_sort = sort_relative_table; + break; + case EM_ARCOMPACT: + case EM_ARM: + case EM_AARCH64: + case EM_MICROBLAZE: + case EM_MIPS: + case EM_XTENSA: + break; + } /* end switch */ + + switch (ehdr->e_ident[EI_CLASS]) { + default: + fprintf(stderr, "unrecognized ELF class %d %s\n", + ehdr->e_ident[EI_CLASS], fname); + fail_file(); + break; + case ELFCLASS32: + if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) + || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { + fprintf(stderr, + "unrecognized ET_EXEC file: %s\n", fname); + fail_file(); + } + do32(ehdr, fname, custom_sort); + break; + case ELFCLASS64: { + Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; + if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) + || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { + fprintf(stderr, + "unrecognized ET_EXEC file: %s\n", fname); + fail_file(); + } + do64(ghdr, fname, custom_sort); + break; + } + } /* end switch */ + + cleanup(); +} + +int +main(int argc, char *argv[]) +{ + int n_error = 0; /* gcc-4.3.0 false positive complaint */ + int i; + + if (argc < 2) { + fprintf(stderr, "usage: sortextable vmlinux...\n"); + return 0; + } + + /* Process each file in turn, allowing deep failure. */ + for (i = 1; i < argc; i++) { + char *file = argv[i]; + int const sjval = setjmp(jmpenv); + + switch (sjval) { + default: + fprintf(stderr, "internal error: %s\n", file); + exit(1); + break; + case SJ_SETJMP: /* normal sequence */ + /* Avoid problems if early cleanup() */ + fd_map = -1; + ehdr_curr = NULL; + mmap_failed = 1; + do_file(file); + break; + case SJ_FAIL: /* error in do_file or below */ + ++n_error; + break; + case SJ_SUCCEED: /* premature success */ + /* do nothing */ + break; + } /* end switch */ + } + return !!n_error; +} diff --git a/scripts/sortextable.h b/scripts/sortextable.h new file mode 100644 index 00000000000..8fac3fd697a --- /dev/null +++ b/scripts/sortextable.h @@ -0,0 +1,211 @@ +/* + * sortextable.h + * + * Copyright 2011 - 2012 Cavium, Inc. + * + * Some of this code was taken out of recordmcount.h written by: + * + * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. + * + * + * Licensed under the GNU General Public License, version 2 (GPLv2). + */ + +#undef extable_ent_size +#undef compare_extable +#undef do_func +#undef Elf_Addr +#undef Elf_Ehdr +#undef Elf_Shdr +#undef Elf_Rel +#undef Elf_Rela +#undef Elf_Sym +#undef ELF_R_SYM +#undef Elf_r_sym +#undef ELF_R_INFO +#undef Elf_r_info +#undef ELF_ST_BIND +#undef ELF_ST_TYPE +#undef fn_ELF_R_SYM +#undef fn_ELF_R_INFO +#undef uint_t +#undef _r +#undef _w + +#ifdef SORTEXTABLE_64 +# define extable_ent_size 16 +# define compare_extable compare_extable_64 +# define do_func do64 +# define Elf_Addr Elf64_Addr +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Shdr Elf64_Shdr +# define Elf_Rel Elf64_Rel +# define Elf_Rela Elf64_Rela +# define Elf_Sym Elf64_Sym +# define ELF_R_SYM ELF64_R_SYM +# define Elf_r_sym Elf64_r_sym +# define ELF_R_INFO ELF64_R_INFO +# define Elf_r_info Elf64_r_info +# define ELF_ST_BIND ELF64_ST_BIND +# define ELF_ST_TYPE ELF64_ST_TYPE +# define fn_ELF_R_SYM fn_ELF64_R_SYM +# define fn_ELF_R_INFO fn_ELF64_R_INFO +# define uint_t uint64_t +# define _r r8 +# define _w w8 +#else +# define extable_ent_size 8 +# define compare_extable compare_extable_32 +# define do_func do32 +# define Elf_Addr Elf32_Addr +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Shdr Elf32_Shdr +# define Elf_Rel Elf32_Rel +# define Elf_Rela Elf32_Rela +# define Elf_Sym Elf32_Sym +# define ELF_R_SYM ELF32_R_SYM +# define Elf_r_sym Elf32_r_sym +# define ELF_R_INFO ELF32_R_INFO +# define Elf_r_info Elf32_r_info +# define ELF_ST_BIND ELF32_ST_BIND +# define ELF_ST_TYPE ELF32_ST_TYPE +# define fn_ELF_R_SYM fn_ELF32_R_SYM +# define fn_ELF_R_INFO fn_ELF32_R_INFO +# define uint_t uint32_t +# define _r r +# define _w w +#endif + +static int compare_extable(const void *a, const void *b) +{ + Elf_Addr av = _r(a); + Elf_Addr bv = _r(b); + + if (av < bv) + return -1; + if (av > bv) + return 1; + return 0; +} + +static void +do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) +{ + Elf_Shdr *shdr; + Elf_Shdr *shstrtab_sec; + Elf_Shdr *strtab_sec = NULL; + Elf_Shdr *symtab_sec = NULL; + Elf_Shdr *extab_sec = NULL; + Elf_Sym *sym; + const Elf_Sym *symtab; + Elf32_Word *symtab_shndx_start = NULL; + Elf_Sym *sort_needed_sym; + Elf_Shdr *sort_needed_sec; + Elf_Rel *relocs = NULL; + int relocs_size; + uint32_t *sort_done_location; + const char *secstrtab; + const char *strtab; + char *extab_image; + int extab_index = 0; + int i; + int idx; + unsigned int num_sections; + unsigned int secindex_strings; + + shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); + + num_sections = r2(&ehdr->e_shnum); + if (num_sections == SHN_UNDEF) + num_sections = _r(&shdr[0].sh_size); + + secindex_strings = r2(&ehdr->e_shstrndx); + if (secindex_strings == SHN_XINDEX) + secindex_strings = r(&shdr[0].sh_link); + + shstrtab_sec = shdr + secindex_strings; + secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); + for (i = 0; i < num_sections; i++) { + idx = r(&shdr[i].sh_name); + if (strcmp(secstrtab + idx, "__ex_table") == 0) { + extab_sec = shdr + i; + extab_index = i; + } + if ((r(&shdr[i].sh_type) == SHT_REL || + r(&shdr[i].sh_type) == SHT_RELA) && + r(&shdr[i].sh_info) == extab_index) { + relocs = (void *)ehdr + _r(&shdr[i].sh_offset); + relocs_size = _r(&shdr[i].sh_size); + } + if (strcmp(secstrtab + idx, ".symtab") == 0) + symtab_sec = shdr + i; + if (strcmp(secstrtab + idx, ".strtab") == 0) + strtab_sec = shdr + i; + if (r(&shdr[i].sh_type) == SHT_SYMTAB_SHNDX) + symtab_shndx_start = (Elf32_Word *)( + (const char *)ehdr + _r(&shdr[i].sh_offset)); + } + if (strtab_sec == NULL) { + fprintf(stderr, "no .strtab in file: %s\n", fname); + fail_file(); + } + if (symtab_sec == NULL) { + fprintf(stderr, "no .symtab in file: %s\n", fname); + fail_file(); + } + symtab = (const Elf_Sym *)((const char *)ehdr + + _r(&symtab_sec->sh_offset)); + if (extab_sec == NULL) { + fprintf(stderr, "no __ex_table in file: %s\n", fname); + fail_file(); + } + strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); + + extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); + + if (custom_sort) { + custom_sort(extab_image, _r(&extab_sec->sh_size)); + } else { + int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; + qsort(extab_image, num_entries, + extable_ent_size, compare_extable); + } + /* If there were relocations, we no longer need them. */ + if (relocs) + memset(relocs, 0, relocs_size); + + /* find main_extable_sort_needed */ + sort_needed_sym = NULL; + for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { + sym = (void *)ehdr + _r(&symtab_sec->sh_offset); + sym += i; + if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) + continue; + idx = r(&sym->st_name); + if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { + sort_needed_sym = sym; + break; + } + } + if (sort_needed_sym == NULL) { + fprintf(stderr, + "no main_extable_sort_needed symbol in file: %s\n", + fname); + fail_file(); + } + sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), + sort_needed_sym - symtab, + symtab_shndx_start)]; + sort_done_location = (void *)ehdr + + _r(&sort_needed_sec->sh_offset) + + _r(&sort_needed_sym->st_value) - + _r(&sort_needed_sec->sh_addr); + +#if 0 + printf("sort done marker at %lx\n", + (unsigned long)((char *)sort_done_location - (char *)ehdr)); +#endif + /* We sorted it, clear the flag. */ + w(0, sort_done_location); +} diff --git a/scripts/tags.sh b/scripts/tags.sh index 833813a99e7..e6b011fe1d0 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -11,11 +11,10 @@ if [ "$KBUILD_VERBOSE" = "1" ]; then set -x fi -# This is a duplicate of RCS_FIND_IGNORE without escaped '()' -ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ - -name CVS -o -name .pc -o -name .hg -o \ - -name .git ) \ - -prune -o" +# RCS_FIND_IGNORE has escaped ()s -- remove them. +ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )" +# tags and cscope files should also ignore MODVERSION *.mod.c files +ignore="$ignore ( -name *.mod.c ) -prune -o" # Do not use full path if we do not use O=.. builds # Use make O=. {tags|cscope} @@ -26,6 +25,9 @@ else tree=${srctree}/ fi +# ignore userspace tools +ignore="$ignore ( -path ${tree}tools ) -prune -o" + # Find all available archs find_all_archs() { @@ -48,23 +50,26 @@ find_arch_sources() for i in $archincludedir; do prune="$prune -wholename $i -prune -o" done - find ${tree}arch/$1 $ignore $prune -name "$2" -print; + find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" \ + -not -type l -print; } # find sources in arch/$1/include find_arch_include_sources() { - include=$(find ${tree}arch/$1/ -name include -type d); + include=$(find ${tree}arch/$1/ $subarchprune \ + -name include -type d -print); if [ -n "$include" ]; then archincludedir="$archincludedir $include" - find $include $ignore -name "$2" -print; + find $include $ignore -name "$2" -not -type l -print; fi } # find sources in include/ find_include_sources() { - find ${tree}include $ignore -name config -prune -o -name "$1" -print; + find ${tree}include $ignore -name config -prune -o -name "$1" \ + -not -type l -print; } # find sources in rest of tree @@ -73,7 +78,7 @@ find_other_sources() { find ${tree}* $ignore \ \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \ - -name "$1" -print; + -name "$1" -not -type l -print; } find_sources() @@ -95,6 +100,32 @@ all_sources() find_other_sources '*.[chS]' } +all_compiled_sources() +{ + for i in $(all_sources); do + case "$i" in + *.[cS]) + j=${i/\.[cS]/\.o} + if [ -e $j ]; then + echo $i + fi + ;; + *) + echo $i + ;; + esac + done +} + +all_target_sources() +{ + if [ -n "$COMPILED_SOURCE" ]; then + all_compiled_sources + else + all_sources + fi +} + all_kconfigs() { for arch in $ALLSOURCE_ARCHS; do @@ -110,24 +141,30 @@ all_defconfigs() docscope() { - (echo \-k; echo \-q; all_sources) > cscope.files + (echo \-k; echo \-q; all_target_sources) > cscope.files cscope -b -f cscope.out } dogtags() { - all_sources | gtags -f - + all_target_sources | gtags -i -f - } exuberant() { - all_sources | xargs $1 -a \ - -I __initdata,__exitdata,__acquires,__releases \ - -I __read_mostly,____cacheline_aligned \ + all_target_sources | xargs $1 -a \ + -I __initdata,__exitdata,__initconst, \ + -I __cpuinitdata,__initdata_memblock \ + -I __refdata,__attribute,__maybe_unused,__always_unused \ + -I __acquires,__releases,__deprecated \ + -I __read_mostly,__aligned,____cacheline_aligned \ -I ____cacheline_aligned_in_smp \ + -I __cacheline_aligned,__cacheline_aligned_in_smp \ -I ____cacheline_internodealigned_in_smp \ - -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ + -I __used,__packed,__packed2__,__must_check,__must_hold \ + -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \ -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ + -I static,const \ --extra=+f --c-kinds=+px \ --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/' \ --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ @@ -153,7 +190,28 @@ exuberant() --regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \ --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ - --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' + --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ + --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ + --regex-c++='/TESTPCGFLAG\(([^,)]*).*/PageCgroup\1/' \ + --regex-c++='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ + --regex-c++='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ + --regex-c++='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ + --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \ + --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \ + --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \ + --regex-c='/DEFINE_(RAW_SPINLOCK|RWLOCK|SEQLOCK)\((\w*)/\2/v/' \ + --regex-c='/DECLARE_(RWSEM|COMPLETION)\((\w*)/\2/v/' \ + --regex-c='/DECLARE_BITMAP\((\w*)/\1/v/' \ + --regex-c='/(^|\s)(|L|H)LIST_HEAD\((\w*)/\3/v/' \ + --regex-c='/(^|\s)RADIX_TREE\((\w*)/\2/v/' \ + --regex-c='/DEFINE_PER_CPU\(([^,]*,\s*)(\w*).*\)/\2/v/' \ + --regex-c='/DEFINE_PER_CPU_SHARED_ALIGNED\(([^,]*,\s*)(\w*).*\)/\2/v/' \ + --regex-c='/DECLARE_WAIT_QUEUE_HEAD\((\w*)/\1/v/' \ + --regex-c='/DECLARE_(TASKLET|WORK|DELAYED_WORK)\((\w*)/\2/v/' \ + --regex-c='/DEFINE_PCI_DEVICE_TABLE\((\w*)/\1/v/' \ + --regex-c='/(^\s)OFFSET\((\w*)/\2/v/' \ + --regex-c='/(^\s)DEFINE\((\w*)/\2/v/' \ + --regex-c='/DEFINE_HASHTABLE\((\w*)/\1/v/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ @@ -166,39 +224,44 @@ exuberant() all_defconfigs | xargs -r $1 -a \ --langdef=dotconfig --language-force=dotconfig \ --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/' - - # Remove structure forward declarations. - LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' tags } emacs() { - all_sources | xargs $1 -a \ - --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/' \ + all_target_sources | xargs $1 -a \ + --regex='/^\(ENTRY\|_GLOBAL\)(\([^)]*\)).*/\2/' \ --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \ --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \ --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' \ - --regex='/PAGEFLAG\(([^,)]*).*/Page\1/' \ - --regex='/PAGEFLAG\(([^,)]*).*/SetPage\1/' \ - --regex='/PAGEFLAG\(([^,)]*).*/ClearPage\1/' \ - --regex='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/' \ - --regex='/TESTPAGEFLAG\(([^,)]*).*/Page\1/' \ - --regex='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/' \ - --regex='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/' \ - --regex='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/' \ - --regex='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ - --regex='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/' \ - --regex='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ - --regex='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/' \ - --regex='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/' \ - --regex='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/' \ - --regex='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \ - --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ - --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ - --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' + --regex='/PAGEFLAG(\([^,)]*\).*/Page\1/' \ + --regex='/PAGEFLAG(\([^,)]*\).*/SetPage\1/' \ + --regex='/PAGEFLAG(\([^,)]*\).*/ClearPage\1/' \ + --regex='/TESTSETFLAG(\([^,)]*\).*/TestSetPage\1/' \ + --regex='/TESTPAGEFLAG(\([^,)]*\).*/Page\1/' \ + --regex='/SETPAGEFLAG(\([^,)]*\).*/SetPage\1/' \ + --regex='/__SETPAGEFLAG(\([^,)]*\).*/__SetPage\1/' \ + --regex='/TESTCLEARFLAG(\([^,)]*\).*/TestClearPage\1/' \ + --regex='/__TESTCLEARFLAG(\([^,)]*\).*/TestClearPage\1/' \ + --regex='/CLEARPAGEFLAG(\([^,)]*\).*/ClearPage\1/' \ + --regex='/__CLEARPAGEFLAG(\([^,)]*\).*/__ClearPage\1/' \ + --regex='/__PAGEFLAG(\([^,)]*\).*/__SetPage\1/' \ + --regex='/__PAGEFLAG(\([^,)]*\).*/__ClearPage\1/' \ + --regex='/PAGEFLAG_FALSE(\([^,)]*\).*/Page\1/' \ + --regex='/TESTSCFLAG(\([^,)]*\).*/TestSetPage\1/' \ + --regex='/TESTSCFLAG(\([^,)]*\).*/TestClearPage\1/' \ + --regex='/SETPAGEFLAG_NOOP(\([^,)]*\).*/SetPage\1/' \ + --regex='/CLEARPAGEFLAG_NOOP(\([^,)]*\).*/ClearPage\1/' \ + --regex='/__CLEARPAGEFLAG_NOOP(\([^,)]*\).*/__ClearPage\1/' \ + --regex='/TESTCLEARFLAG_FALSE(\([^,)]*\).*/TestClearPage\1/' \ + --regex='/__TESTCLEARFLAG_FALSE(\([^,)]*\).*/__TestClearPage\1/' \ + --regex='/TESTPCGFLAG\(([^,)]*).*/PageCgroup\1/' \ + --regex='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ + --regex='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ + --regex='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ + --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ + --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ + --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ + --regex='/DEFINE_HASHTABLE\((\w*)/\1/v/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' @@ -217,11 +280,10 @@ xtags() elif $1 --version 2>&1 | grep -iq emacs; then emacs $1 else - all_sources | xargs $1 -a - fi + all_target_sources | xargs $1 -a + fi } - # Support um (which uses SUBARCH) if [ "${ARCH}" = "um" ]; then if [ "$SUBARCH" = "i386" ]; then @@ -231,8 +293,24 @@ if [ "${ARCH}" = "um" ]; then else archinclude=${SUBARCH} fi +elif [ "${SRCARCH}" = "arm" -a "${SUBARCH}" != "" ]; then + subarchdir=$(find ${tree}arch/$SRCARCH/ -name "mach-*" -type d -o \ + -name "plat-*" -type d); + for i in $subarchdir; do + case "$i" in + *"mach-"${SUBARCH}) + ;; + *"plat-"${SUBARCH}) + ;; + *) + subarchprune="$subarchprune \ + -wholename $i -prune -o" + ;; + esac + done fi +remove_structs= case "$1" in "cscope") docscope @@ -245,10 +323,17 @@ case "$1" in "tags") rm -f tags xtags ctags + remove_structs=y ;; "TAGS") rm -f TAGS xtags etags + remove_structs=y ;; esac + +# Remove structure forward declarations. +if [ -n "$remove_structs" ]; then + LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' $1 +fi diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh index 17a5798c29d..7a2d372f488 100644 --- a/scripts/xz_wrap.sh +++ b/scripts/xz_wrap.sh @@ -12,8 +12,8 @@ BCJ= LZMA2OPTS= -case $ARCH in - x86|x86_64) BCJ=--x86 ;; +case $SRCARCH in + x86) BCJ=--x86 ;; powerpc) BCJ=--powerpc ;; ia64) BCJ=--ia64; LZMA2OPTS=pb=4 ;; arm) BCJ=--arm ;; |
