mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-07 00:38:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
290
scripts/Kbuild.include
Normal file
290
scripts/Kbuild.include
Normal file
|
@ -0,0 +1,290 @@
|
|||
####
|
||||
# kbuild: Generic definitions
|
||||
|
||||
# Convenient variables
|
||||
comma := ,
|
||||
quote := "
|
||||
squote := '
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
|
||||
###
|
||||
# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
|
||||
dot-target = $(dir $@).$(notdir $@)
|
||||
|
||||
###
|
||||
# The temporary file to save gcc -MD generated dependencies must not
|
||||
# contain a comma
|
||||
depfile = $(subst $(comma),_,$(dot-target).d)
|
||||
|
||||
###
|
||||
# filename of target with directory and extension stripped
|
||||
basetarget = $(basename $(notdir $@))
|
||||
|
||||
###
|
||||
# filename of first prerequisite with directory and extension stripped
|
||||
baseprereq = $(basename $(notdir $<))
|
||||
|
||||
###
|
||||
# Escape single quote for use in echo statements
|
||||
escsq = $(subst $(squote),'\$(squote)',$1)
|
||||
|
||||
###
|
||||
# Easy method for doing a status message
|
||||
kecho := :
|
||||
quiet_kecho := echo
|
||||
silent_kecho := :
|
||||
kecho := $($(quiet)kecho)
|
||||
|
||||
###
|
||||
# filechk is used to check if the content of a generated file is updated.
|
||||
# Sample usage:
|
||||
# define filechk_sample
|
||||
# echo $KERNELRELEASE
|
||||
# endef
|
||||
# version.h : Makefile
|
||||
# $(call filechk,sample)
|
||||
# The rule defined shall write to stdout the content of the new file.
|
||||
# The existing file will be compared with the new one.
|
||||
# - If no file exist it is created
|
||||
# - If the content differ the new file is used
|
||||
# - If they are equal no change, and no timestamp update
|
||||
# - stdin is piped in from the first prerequisite ($<) so one has
|
||||
# to specify a valid file as first prerequisite (often the kbuild file)
|
||||
define filechk
|
||||
$(Q)set -e; \
|
||||
$(kecho) ' CHK $@'; \
|
||||
mkdir -p $(dir $@); \
|
||||
$(filechk_$(1)) < $< > $@.tmp; \
|
||||
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
|
||||
rm -f $@.tmp; \
|
||||
else \
|
||||
$(kecho) ' UPD $@'; \
|
||||
mv -f $@.tmp $@; \
|
||||
fi
|
||||
endef
|
||||
|
||||
######
|
||||
# gcc support functions
|
||||
# See documentation in Documentation/kbuild/makefiles.txt
|
||||
|
||||
# cc-cross-prefix
|
||||
# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
|
||||
# Return first prefix where a prefix$(CC) is found in PATH.
|
||||
# If no $(CC) found in PATH with listed prefixes return nothing
|
||||
cc-cross-prefix = \
|
||||
$(word 1, $(foreach c,$(1), \
|
||||
$(shell set -e; \
|
||||
if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \
|
||||
echo $(c); \
|
||||
fi)))
|
||||
|
||||
# output directory for tests below
|
||||
TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
|
||||
|
||||
# try-run
|
||||
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
|
||||
# Exit code chooses option. "$$TMP" is can be used as temporary file and
|
||||
# is automatically cleaned up.
|
||||
try-run = $(shell set -e; \
|
||||
TMP="$(TMPOUT).$$$$.tmp"; \
|
||||
TMPO="$(TMPOUT).$$$$.o"; \
|
||||
if ($(1)) >/dev/null 2>&1; \
|
||||
then echo "$(2)"; \
|
||||
else echo "$(3)"; \
|
||||
fi; \
|
||||
rm -f "$$TMP" "$$TMPO")
|
||||
|
||||
# as-option
|
||||
# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
|
||||
|
||||
as-option = $(call try-run,\
|
||||
$(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2))
|
||||
|
||||
# as-instr
|
||||
# Usage: cflags-y += $(call as-instr,instr,option1,option2)
|
||||
|
||||
as-instr = $(call try-run,\
|
||||
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 -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 -x c /dev/null -o "$$TMP",y,n)
|
||||
|
||||
# cc-option-align
|
||||
# Prefix align with either -falign or -malign
|
||||
cc-option-align = $(subst -functions=0,,\
|
||||
$(call cc-option,-falign-functions=0,-malign-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 -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
|
||||
|
||||
# cc-version
|
||||
# Usage gcc-ver := $(call cc-version)
|
||||
cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
|
||||
|
||||
# cc-fullversion
|
||||
# Usage gcc-ver := $(call cc-fullversion)
|
||||
cc-fullversion = $(shell $(CONFIG_SHELL) \
|
||||
$(srctree)/scripts/gcc-version.sh -p $(CC))
|
||||
|
||||
# cc-ifversion
|
||||
# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
|
||||
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 -x c /dev/null -o "$$TMP",$(1),$(2))
|
||||
|
||||
# ld-option
|
||||
# Usage: LDFLAGS += $(call ld-option, -X)
|
||||
ld-option = $(call try-run,\
|
||||
$(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))
|
||||
|
||||
######
|
||||
|
||||
###
|
||||
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
|
||||
# Usage:
|
||||
# $(Q)$(MAKE) $(build)=dir
|
||||
build := -f $(srctree)/scripts/Makefile.build obj
|
||||
|
||||
###
|
||||
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj=
|
||||
# Usage:
|
||||
# $(Q)$(MAKE) $(modbuiltin)=dir
|
||||
modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj
|
||||
|
||||
# Prefix -I with $(srctree) if it is not an absolute path.
|
||||
# skip if -I has no parameter
|
||||
addtree = $(if $(patsubst -I%,%,$(1)), \
|
||||
$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1))
|
||||
|
||||
# Find all -I options and call addtree
|
||||
flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
|
||||
|
||||
# echo command.
|
||||
# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
|
||||
echo-cmd = $(if $($(quiet)cmd_$(1)),\
|
||||
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
|
||||
|
||||
# printing commands
|
||||
cmd = @$(echo-cmd) $(cmd_$(1))
|
||||
|
||||
# Add $(obj)/ for paths that are not absolute
|
||||
objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
|
||||
|
||||
###
|
||||
# if_changed - execute command if any prerequisite is newer than
|
||||
# target, or command line has changed
|
||||
# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
|
||||
# including used config symbols
|
||||
# if_changed_rule - as if_changed but execute rule instead
|
||||
# See Documentation/kbuild/makefiles.txt for more info
|
||||
|
||||
ifneq ($(KBUILD_NOCMDDEP),1)
|
||||
# Check if both arguments has same arguments. Result is empty string if equal.
|
||||
# User may override this check using make KBUILD_NOCMDDEP=1
|
||||
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
|
||||
$(filter-out $(cmd_$@), $(cmd_$(1))) )
|
||||
else
|
||||
arg-check = $(if $(strip $(cmd_$@)),,1)
|
||||
endif
|
||||
|
||||
# Replace >$< with >$$< to preserve $ when reloading the .cmd file
|
||||
# (needed for make)
|
||||
# Replace >#< with >\#< to avoid starting a comment in the .cmd file
|
||||
# (needed for make)
|
||||
# Replace >'< with >'\''< to be able to enclose the whole string in '...'
|
||||
# (needed for the shell)
|
||||
make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1)))))
|
||||
|
||||
# Find any prerequisites that is newer than target or that does not exist.
|
||||
# PHONY targets skipped in both cases.
|
||||
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
|
||||
|
||||
# Execute command if command has changed or prerequisite(s) are updated.
|
||||
#
|
||||
if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
|
||||
@set -e; \
|
||||
$(echo-cmd) $(cmd_$(1)); \
|
||||
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
|
||||
|
||||
# Execute the command and also postprocess generated .d dependencies file.
|
||||
if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
|
||||
@set -e; \
|
||||
$(echo-cmd) $(cmd_$(1)); \
|
||||
scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
|
||||
rm -f $(depfile); \
|
||||
mv -f $(dot-target).tmp $(dot-target).cmd)
|
||||
|
||||
# Usage: $(call if_changed_rule,foo)
|
||||
# Will check if $(cmd_foo) or any of the prerequisites changed,
|
||||
# and if so will execute $(rule_foo).
|
||||
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
|
||||
@set -e; \
|
||||
$(rule_$(1)))
|
||||
|
||||
###
|
||||
# why - tell why a a target got build
|
||||
# enabled by make V=2
|
||||
# Output (listed in the order they are checked):
|
||||
# (1) - due to target is PHONY
|
||||
# (2) - due to target missing
|
||||
# (3) - due to: file1.h file2.h
|
||||
# (4) - due to command line change
|
||||
# (5) - due to missing .cmd file
|
||||
# (6) - due to target not in $(targets)
|
||||
# (1) PHONY targets are always build
|
||||
# (2) No target, so we better build it
|
||||
# (3) Prerequisite is newer than target
|
||||
# (4) The command line stored in the file named dir/.target.cmd
|
||||
# differed from actual command line. This happens when compiler
|
||||
# options changes
|
||||
# (5) No dir/.target.cmd file (used to store command line)
|
||||
# (6) No dir/.target.cmd file and target not listed in $(targets)
|
||||
# This is a good hint that there is a bug in the kbuild file
|
||||
ifeq ($(KBUILD_VERBOSE),2)
|
||||
why = \
|
||||
$(if $(filter $@, $(PHONY)),- due to target is PHONY, \
|
||||
$(if $(wildcard $@), \
|
||||
$(if $(strip $(any-prereq)),- due to: $(any-prereq), \
|
||||
$(if $(arg-check), \
|
||||
$(if $(cmd_$@),- due to command line change, \
|
||||
$(if $(filter $@, $(targets)), \
|
||||
- due to missing .cmd file, \
|
||||
- due to $(notdir $@) not in $$(targets) \
|
||||
) \
|
||||
) \
|
||||
) \
|
||||
), \
|
||||
- due to target missing \
|
||||
) \
|
||||
)
|
||||
|
||||
echo-why = $(call escsq, $(strip $(why)))
|
||||
endif
|
18
scripts/Lindent
Executable file
18
scripts/Lindent
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/sh
|
||||
PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
|
||||
RES=`indent --version`
|
||||
V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1`
|
||||
V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2`
|
||||
V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3`
|
||||
if [ $V1 -gt 2 ]; then
|
||||
PARAM="$PARAM -il0"
|
||||
elif [ $V1 -eq 2 ]; then
|
||||
if [ $V2 -gt 2 ]; then
|
||||
PARAM="$PARAM -il0";
|
||||
elif [ $V2 -eq 2 ]; then
|
||||
if [ $V3 -ge 10 ]; then
|
||||
PARAM="$PARAM -il0"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
indent $PARAM "$@"
|
41
scripts/Makefile
Normal file
41
scripts/Makefile
Normal file
|
@ -0,0 +1,41 @@
|
|||
###
|
||||
# scripts contains sources for various helper programs used throughout
|
||||
# the kernel for the build process.
|
||||
# ---------------------------------------------------------------------------
|
||||
# kallsyms: Find all symbols in vmlinux
|
||||
# pnmttologo: Convert pnm files to logo files
|
||||
# conmakehash: Create chartable
|
||||
# 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-$(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)
|
||||
|
||||
# The following hostprogs-y programs are only build on demand
|
||||
hostprogs-y += unifdef docproc
|
||||
|
||||
# These targets are used internally to avoid "is up to date" messages
|
||||
PHONY += build_unifdef build_docproc
|
||||
build_unifdef: $(obj)/unifdef
|
||||
@:
|
||||
build_docproc: $(obj)/docproc
|
||||
@:
|
||||
|
||||
subdir-$(CONFIG_MODVERSIONS) += genksyms
|
||||
subdir-y += mod
|
||||
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
|
||||
subdir-$(CONFIG_DTC) += dtc
|
||||
|
||||
# Let clean descend into subdirs
|
||||
subdir- += basic kconfig package
|
23
scripts/Makefile.asm-generic
Normal file
23
scripts/Makefile.asm-generic
Normal file
|
@ -0,0 +1,23 @@
|
|||
# include/asm-generic contains a lot of files that are used
|
||||
# verbatim by several architectures.
|
||||
#
|
||||
# This Makefile reads the file arch/$(SRCARCH)/include/asm/Kbuild
|
||||
# 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/$(src)/Kbuild
|
||||
-include $(kbuild-file)
|
||||
|
||||
include scripts/Kbuild.include
|
||||
|
||||
# Create output directory if not already present
|
||||
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
|
||||
|
||||
quiet_cmd_wrap = WRAP $@
|
||||
cmd_wrap = echo "\#include <asm-generic/$*.h>" >$@
|
||||
|
||||
all: $(patsubst %, $(obj)/%, $(generic-y))
|
||||
@:
|
||||
|
||||
$(obj)/%.h:
|
||||
$(call cmd,wrap)
|
426
scripts/Makefile.build
Normal file
426
scripts/Makefile.build
Normal file
|
@ -0,0 +1,426 @@
|
|||
# ==========================================================================
|
||||
# Building
|
||||
# ==========================================================================
|
||||
|
||||
src := $(obj)
|
||||
|
||||
PHONY := __build
|
||||
__build:
|
||||
|
||||
# Init all relevant variables used in kbuild files so
|
||||
# 1) they have correct type
|
||||
# 2) they do not inherit any value from the environment
|
||||
obj-y :=
|
||||
obj-m :=
|
||||
lib-y :=
|
||||
lib-m :=
|
||||
always :=
|
||||
targets :=
|
||||
subdir-y :=
|
||||
subdir-m :=
|
||||
EXTRA_AFLAGS :=
|
||||
EXTRA_CFLAGS :=
|
||||
EXTRA_CPPFLAGS :=
|
||||
EXTRA_LDFLAGS :=
|
||||
asflags-y :=
|
||||
ccflags-y :=
|
||||
cppflags-y :=
|
||||
ldflags-y :=
|
||||
|
||||
subdir-asflags-y :=
|
||||
subdir-ccflags-y :=
|
||||
|
||||
# Read auto.conf if it exists, otherwise ignore
|
||||
-include include/config/auto.conf
|
||||
|
||||
include scripts/Kbuild.include
|
||||
|
||||
# For backward compatibility check that these variables do not change
|
||||
save-cflags := $(CFLAGS)
|
||||
|
||||
# The filename Kbuild has precedence over Makefile
|
||||
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
|
||||
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
|
||||
include $(kbuild-file)
|
||||
|
||||
# If the save-* variables changed error out
|
||||
ifeq ($(KBUILD_NOPEDANTIC),)
|
||||
ifneq ("$(save-cflags)","$(CFLAGS)")
|
||||
$(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y)
|
||||
endif
|
||||
endif
|
||||
|
||||
include scripts/Makefile.lib
|
||||
|
||||
ifdef host-progs
|
||||
ifneq ($(hostprogs-y),$(host-progs))
|
||||
$(warning kbuild: $(obj)/Makefile - Usage of host-progs is deprecated. Please replace with hostprogs-y!)
|
||||
hostprogs-y += $(host-progs)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Do not include host rules unless needed
|
||||
ifneq ($(hostprogs-y)$(hostprogs-m),)
|
||||
include scripts/Makefile.host
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_SRC),)
|
||||
# Create output directory if not already present
|
||||
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
|
||||
|
||||
# Create directories for object files if directory does not exist
|
||||
# Needed when obj-y := dir/file.o syntax is used
|
||||
_dummy := $(foreach d,$(obj-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))
|
||||
endif
|
||||
|
||||
ifndef obj
|
||||
$(warning kbuild: Makefile.build is included improperly)
|
||||
endif
|
||||
|
||||
# ===========================================================================
|
||||
|
||||
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
|
||||
lib-target := $(obj)/lib.a
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
|
||||
builtin-target := $(obj)/built-in.o
|
||||
endif
|
||||
|
||||
modorder-target := $(obj)/modules.order
|
||||
|
||||
# We keep a list of all modules in $(MODVERDIR)
|
||||
|
||||
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
|
||||
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
|
||||
$(subdir-ym) $(always)
|
||||
@:
|
||||
|
||||
# Linus' kernel sanity checking tool
|
||||
ifneq ($(KBUILD_CHECKSRC),0)
|
||||
ifeq ($(KBUILD_CHECKSRC),2)
|
||||
quiet_cmd_force_checksrc = CHECK $<
|
||||
cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
|
||||
else
|
||||
quiet_cmd_checksrc = CHECK $<
|
||||
cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
|
||||
endif
|
||||
endif
|
||||
|
||||
# Do section mismatch analysis for each module/built-in.o
|
||||
ifdef CONFIG_DEBUG_SECTION_MISMATCH
|
||||
cmd_secanalysis = ; scripts/mod/modpost $@
|
||||
endif
|
||||
|
||||
# Compile C sources (.c)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Default is built-in, unless we know otherwise
|
||||
modkern_cflags = \
|
||||
$(if $(part-of-module), \
|
||||
$(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
|
||||
$(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL))
|
||||
quiet_modtag := $(empty) $(empty)
|
||||
|
||||
$(real-objs-m) : part-of-module := y
|
||||
$(real-objs-m:.o=.i) : part-of-module := y
|
||||
$(real-objs-m:.o=.s) : part-of-module := y
|
||||
$(real-objs-m:.o=.lst): part-of-module := y
|
||||
|
||||
$(real-objs-m) : quiet_modtag := [M]
|
||||
$(real-objs-m:.o=.i) : quiet_modtag := [M]
|
||||
$(real-objs-m:.o=.s) : quiet_modtag := [M]
|
||||
$(real-objs-m:.o=.lst): quiet_modtag := [M]
|
||||
|
||||
$(obj-m) : quiet_modtag := [M]
|
||||
|
||||
# Default for not multi-part modules
|
||||
modname = $(basetarget)
|
||||
|
||||
$(multi-objs-m) : modname = $(modname-multi)
|
||||
$(multi-objs-m:.o=.i) : modname = $(modname-multi)
|
||||
$(multi-objs-m:.o=.s) : modname = $(modname-multi)
|
||||
$(multi-objs-m:.o=.lst) : modname = $(modname-multi)
|
||||
$(multi-objs-y) : modname = $(modname-multi)
|
||||
$(multi-objs-y:.o=.i) : modname = $(modname-multi)
|
||||
$(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) $(DISABLE_LTO) -fverbose-asm -S -o $@ $<
|
||||
|
||||
$(obj)/%.s: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,cc_s_c)
|
||||
|
||||
quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@
|
||||
cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $<
|
||||
|
||||
$(obj)/%.i: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,cc_i_c)
|
||||
|
||||
cmd_gensymtypes = \
|
||||
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
|
||||
$(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))
|
||||
|
||||
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
|
||||
cmd_cc_symtypes_c = \
|
||||
set -e; \
|
||||
$(call cmd_gensymtypes,true,$@) >/dev/null; \
|
||||
test -s $@ || rm -f $@
|
||||
|
||||
$(obj)/%.symtypes : $(src)/%.c FORCE
|
||||
$(call cmd,cc_symtypes_c)
|
||||
|
||||
# C (.c) files
|
||||
# The C file is compiled and updated dependency information is generated.
|
||||
# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
|
||||
|
||||
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
|
||||
|
||||
ifndef CONFIG_MODVERSIONS
|
||||
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
|
||||
|
||||
else
|
||||
# When module versioning is enabled the following steps are executed:
|
||||
# o compile a .tmp_<file>.o from <file>.c
|
||||
# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
|
||||
# not export symbols, we just rename .tmp_<file>.o to <file>.o and
|
||||
# are done.
|
||||
# o otherwise, we calculate symbol versions using the good old
|
||||
# genksyms on the preprocessed source and postprocess them in a way
|
||||
# that they are usable as a linker script
|
||||
# o generate <file>.o from .tmp_<file>.o using the linker to
|
||||
# replace the unresolved symbols __crc_exported_symbol with
|
||||
# the actual value of the checksum generated by genksyms
|
||||
|
||||
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
|
||||
cmd_modversions = \
|
||||
if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
|
||||
$(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
|
||||
> $(@D)/.tmp_$(@F:.o=.ver); \
|
||||
\
|
||||
$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
|
||||
-T $(@D)/.tmp_$(@F:.o=.ver); \
|
||||
rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
|
||||
else \
|
||||
mv -f $(@D)/.tmp_$(@F) $@; \
|
||||
fi;
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
ifdef BUILD_C_RECORDMCOUNT
|
||||
ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
|
||||
RECORDMCOUNT_FLAGS = -w
|
||||
endif
|
||||
# Due to recursion, we must skip empty.o.
|
||||
# The empty.o file is created in the make process in order to determine
|
||||
# the target endianness and word size. It is made before all other C
|
||||
# files, including recordmcount.
|
||||
sub_cmd_record_mcount = \
|
||||
if [ $(@) != "scripts/mod/empty.o" ]; then \
|
||||
$(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
|
||||
fi;
|
||||
recordmcount_source := $(srctree)/scripts/recordmcount.c \
|
||||
$(srctree)/scripts/recordmcount.h
|
||||
else
|
||||
sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
|
||||
"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
|
||||
"$(if $(CONFIG_64BIT),64,32)" \
|
||||
"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
|
||||
"$(LD)" "$(NM)" "$(RM)" "$(MV)" \
|
||||
"$(if $(part-of-module),1,0)" "$(@)";
|
||||
recordmcount_source := $(srctree)/scripts/recordmcount.pl
|
||||
endif
|
||||
cmd_record_mcount = \
|
||||
if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then \
|
||||
$(sub_cmd_record_mcount) \
|
||||
fi;
|
||||
endif
|
||||
|
||||
define rule_cc_o_c
|
||||
$(call echo-cmd,checksrc) $(cmd_checksrc) \
|
||||
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
|
||||
$(cmd_modversions) \
|
||||
$(call echo-cmd,record_mcount) \
|
||||
$(cmd_record_mcount) \
|
||||
scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
|
||||
$(dot-target).tmp; \
|
||||
rm -f $(depfile); \
|
||||
mv -f $(dot-target).tmp $(dot-target).cmd
|
||||
endef
|
||||
|
||||
# Built-in and composite module parts
|
||||
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
|
||||
$(call cmd,force_checksrc)
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
# Single-part modules are special since we need to mark them in $(MODVERDIR)
|
||||
|
||||
$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
|
||||
$(call cmd,force_checksrc)
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
|
||||
|
||||
quiet_cmd_cc_lst_c = MKLST $@
|
||||
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
|
||||
$(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
|
||||
System.map $(OBJDUMP) > $@
|
||||
|
||||
$(obj)/%.lst: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,cc_lst_c)
|
||||
|
||||
# Compile assembler sources (.S)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
|
||||
|
||||
$(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 $@ $<
|
||||
|
||||
$(obj)/%.s: $(src)/%.S FORCE
|
||||
$(call if_changed_dep,as_s_S)
|
||||
|
||||
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
|
||||
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
|
||||
|
||||
$(obj)/%.o: $(src)/%.S FORCE
|
||||
$(call if_changed_dep,as_o_S)
|
||||
|
||||
targets += $(real-objs-y) $(real-objs-m) $(lib-y)
|
||||
targets += $(extra-y) $(MAKECMDGOALS) $(always)
|
||||
|
||||
# Linker scripts preprocessor (.lds.S -> .lds)
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_cpp_lds_S = LDS $@
|
||||
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
|
||||
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
|
||||
|
||||
$(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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# To build objects in subdirs, we need to descend into the directories
|
||||
$(sort $(subdir-obj-y)): $(subdir-ym) ;
|
||||
|
||||
#
|
||||
# Rule to compile a set of .o files into one .o file
|
||||
#
|
||||
ifdef builtin-target
|
||||
quiet_cmd_link_o_target = LD $@
|
||||
# If the list of objects to link is empty, just create an empty built-in.o
|
||||
cmd_link_o_target = $(if $(strip $(obj-y)),\
|
||||
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
|
||||
$(cmd_secanalysis),\
|
||||
rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
|
||||
|
||||
$(builtin-target): $(obj-y) FORCE
|
||||
$(call if_changed,link_o_target)
|
||||
|
||||
targets += $(builtin-target)
|
||||
endif # builtin-target
|
||||
|
||||
#
|
||||
# Rule to create modules.order file
|
||||
#
|
||||
# Create commands to either record .ko file or cat modules.order from
|
||||
# a subdirectory
|
||||
modorder-cmds = \
|
||||
$(foreach m, $(modorder), \
|
||||
$(if $(filter %/modules.order, $m), \
|
||||
cat $m;, echo kernel/$m;))
|
||||
|
||||
$(modorder-target): $(subdir-ym) FORCE
|
||||
$(Q)(cat /dev/null; $(modorder-cmds)) > $@
|
||||
|
||||
#
|
||||
# Rule to compile a set of .o files into one .a file
|
||||
#
|
||||
ifdef lib-target
|
||||
quiet_cmd_link_l_target = AR $@
|
||||
cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
|
||||
|
||||
$(lib-target): $(lib-y) FORCE
|
||||
$(call if_changed,link_l_target)
|
||||
|
||||
targets += $(lib-target)
|
||||
endif
|
||||
|
||||
#
|
||||
# Rule to link composite objects
|
||||
#
|
||||
# Composite objects are specified in kbuild makefile as follows:
|
||||
# <composite-object>-objs := <list of .o files>
|
||||
# or
|
||||
# <composite-object>-y := <list of .o files>
|
||||
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)
|
||||
|
||||
quiet_cmd_link_multi-m = LD [M] $@
|
||||
cmd_link_multi-m = $(cmd_link_multi-y)
|
||||
|
||||
$(multi-used-y): FORCE
|
||||
$(call if_changed,link_multi-y)
|
||||
$(call multi_depend, $(multi-used-y), .o, -objs -y)
|
||||
|
||||
$(multi-used-m): FORCE
|
||||
$(call if_changed,link_multi-m)
|
||||
@{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
|
||||
$(call multi_depend, $(multi-used-m), .o, -objs -y)
|
||||
|
||||
targets += $(multi-used-y) $(multi-used-m)
|
||||
|
||||
|
||||
# Descending
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += $(subdir-ym)
|
||||
$(subdir-ym):
|
||||
$(Q)$(MAKE) $(build)=$@
|
||||
|
||||
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += FORCE
|
||||
|
||||
FORCE:
|
||||
|
||||
# Read all saved command lines and dependencies for the $(targets) we
|
||||
# may be building above, using $(if_changed{,_dep}). As an
|
||||
# optimization, we don't need to read them if the target does not
|
||||
# exist, we will rebuild anyway in that case.
|
||||
|
||||
targets := $(wildcard $(sort $(targets)))
|
||||
cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
endif
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable se we can use it in if_changed and friends.
|
||||
|
||||
.PHONY: $(PHONY)
|
102
scripts/Makefile.clean
Normal file
102
scripts/Makefile.clean
Normal file
|
@ -0,0 +1,102 @@
|
|||
# ==========================================================================
|
||||
# Cleaning up
|
||||
# ==========================================================================
|
||||
|
||||
src := $(obj)
|
||||
|
||||
PHONY := __clean
|
||||
__clean:
|
||||
|
||||
# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
|
||||
# Usage:
|
||||
# $(Q)$(MAKE) $(clean)=dir
|
||||
clean := -f $(srctree)/scripts/Makefile.clean obj
|
||||
|
||||
# The filename Kbuild has precedence over Makefile
|
||||
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
|
||||
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
|
||||
|
||||
# Figure out what we need to build from the various variables
|
||||
# ==========================================================================
|
||||
|
||||
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
|
||||
subdir-y += $(__subdir-y)
|
||||
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
|
||||
subdir-m += $(__subdir-m)
|
||||
__subdir- := $(patsubst %/,%,$(filter %/, $(obj-)))
|
||||
subdir- += $(__subdir-)
|
||||
|
||||
# Subdirectories we need to descend into
|
||||
|
||||
subdir-ym := $(sort $(subdir-y) $(subdir-m))
|
||||
subdir-ymn := $(sort $(subdir-ym) $(subdir-))
|
||||
|
||||
# Add subdir path
|
||||
|
||||
subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
|
||||
|
||||
# build a list of files to remove, usually relative to the current
|
||||
# directory
|
||||
|
||||
__clean-files := $(extra-y) $(extra-m) $(extra-) \
|
||||
$(always) $(targets) $(clean-files) \
|
||||
$(host-progs) \
|
||||
$(hostprogs-y) $(hostprogs-m) $(hostprogs-)
|
||||
|
||||
__clean-files := $(filter-out $(no-clean-files), $(__clean-files))
|
||||
|
||||
# clean-files is given relative to the current directory, unless it
|
||||
# starts with $(objtree)/ (which means "./", so do not add "./" unless
|
||||
# you want to delete a file from the toplevel object directory).
|
||||
|
||||
__clean-files := $(wildcard \
|
||||
$(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \
|
||||
$(filter $(objtree)/%, $(__clean-files)))
|
||||
|
||||
# same as clean-files
|
||||
|
||||
__clean-dirs := $(wildcard \
|
||||
$(addprefix $(obj)/, $(filter-out $(objtree)/%, $(clean-dirs))) \
|
||||
$(filter $(objtree)/%, $(clean-dirs)))
|
||||
|
||||
# ==========================================================================
|
||||
|
||||
quiet_cmd_clean = CLEAN $(obj)
|
||||
cmd_clean = rm -f $(__clean-files)
|
||||
quiet_cmd_cleandir = CLEAN $(__clean-dirs)
|
||||
cmd_cleandir = rm -rf $(__clean-dirs)
|
||||
|
||||
|
||||
__clean: $(subdir-ymn)
|
||||
ifneq ($(strip $(__clean-files)),)
|
||||
+$(call cmd,clean)
|
||||
endif
|
||||
ifneq ($(strip $(__clean-dirs)),)
|
||||
+$(call cmd,cleandir)
|
||||
endif
|
||||
ifneq ($(strip $(clean-rule)),)
|
||||
+$(clean-rule)
|
||||
endif
|
||||
@:
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Generic stuff
|
||||
# ===========================================================================
|
||||
|
||||
# Descending
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += $(subdir-ymn)
|
||||
$(subdir-ymn):
|
||||
$(Q)$(MAKE) $(clean)=$@
|
||||
|
||||
# If quiet is set, only print short version of command
|
||||
|
||||
cmd = @$(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
|
||||
|
||||
|
||||
# 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)
|
68
scripts/Makefile.extrawarn
Normal file
68
scripts/Makefile.extrawarn
Normal file
|
@ -0,0 +1,68 @@
|
|||
# ==========================================================================
|
||||
#
|
||||
# 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)
|
||||
|
||||
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)
|
||||
else
|
||||
|
||||
ifeq ($(COMPILER),clang)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, unused-value)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, format)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, unknown-warning-option)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, sign-compare)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, format-zero-length)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, uninitialized)
|
||||
endif
|
||||
endif
|
70
scripts/Makefile.fwinst
Normal file
70
scripts/Makefile.fwinst
Normal file
|
@ -0,0 +1,70 @@
|
|||
# ==========================================================================
|
||||
# Installing firmware
|
||||
#
|
||||
# We don't include the .config, so all firmware files are in $(fw-shipped-)
|
||||
# rather than in $(fw-shipped-y) or $(fw-shipped-m).
|
||||
# ==========================================================================
|
||||
|
||||
INSTALL := install
|
||||
src := $(obj)
|
||||
|
||||
# For modules_install installing firmware, we want to see .config
|
||||
# But for firmware_install, we don't care, but don't want to require it.
|
||||
-include $(objtree)/.config
|
||||
|
||||
include scripts/Kbuild.include
|
||||
include $(srctree)/$(obj)/Makefile
|
||||
|
||||
include scripts/Makefile.host
|
||||
|
||||
mod-fw := $(fw-shipped-m)
|
||||
# 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))
|
||||
|
||||
quiet_cmd_install = INSTALL $(subst $(srctree)/,,$@)
|
||||
cmd_install = mkdir -p $(@D); $(INSTALL) -m0644 $< $@
|
||||
|
||||
$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/%
|
||||
$(call cmd,install)
|
||||
|
||||
PHONY += __fw_install __fw_modinst FORCE
|
||||
|
||||
.PHONY: $(PHONY)
|
||||
|
||||
__fw_install: $(installed-fw)
|
||||
|
||||
__fw_modinst: $(installed-mod-fw)
|
||||
@:
|
||||
|
||||
__fw_modbuild: $(addprefix $(obj)/,$(mod-fw))
|
||||
@:
|
||||
|
||||
FORCE:
|
||||
|
||||
# Read all saved command lines and dependencies for the $(targets) we
|
||||
# may be building using $(if_changed{,_dep}). As an optimization, we
|
||||
# don't need to read them if the target does not exist; we will rebuild
|
||||
# anyway in that case.
|
||||
|
||||
targets := $(wildcard $(sort $(targets)))
|
||||
cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
endif
|
140
scripts/Makefile.headersinst
Normal file
140
scripts/Makefile.headersinst
Normal file
|
@ -0,0 +1,140 @@
|
|||
# ==========================================================================
|
||||
# Installing headers
|
||||
#
|
||||
# header-y - list files to be installed. They are preprocessed
|
||||
# to remove __KERNEL__ section of the file
|
||||
# genhdr-y - Same as header-y but in a generated/ directory
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
# generated header directory
|
||||
gen := $(if $(gen),$(gen),$(subst include/,include/generated/,$(obj)))
|
||||
|
||||
kbuild-file := $(srctree)/$(obj)/Kbuild
|
||||
include $(kbuild-file)
|
||||
|
||||
# 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
|
||||
|
||||
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 := $(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) $(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 $(installdir)/%,%,$(wildcard $(installdir)/*.h))
|
||||
unwanted := $(filter-out $(all-files),$(oldheaders))
|
||||
|
||||
# Prefix unwanted with full paths to $(INSTALL_HDR_PATH)
|
||||
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 = \
|
||||
$(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>" > $(installdir)/$$F; \
|
||||
done; \
|
||||
touch $@
|
||||
|
||||
quiet_cmd_remove = REMOVE $(unwanted)
|
||||
cmd_remove = rm -f $(unwanted-file)
|
||||
|
||||
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 "$(installdir)/$${f}"; done \
|
||||
| xargs \
|
||||
$(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH); \
|
||||
touch $@
|
||||
|
||||
PHONY += __headersinst __headerscheck
|
||||
|
||||
ifndef HDRCHECK
|
||||
# Rules for installing headers
|
||||
__headersinst: $(subdirs) $(install-file)
|
||||
@:
|
||||
|
||||
targets += $(install-file)
|
||||
$(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)
|
||||
|
||||
else
|
||||
__headerscheck: $(subdirs) $(check-file)
|
||||
@:
|
||||
|
||||
targets += $(check-file)
|
||||
$(check-file): scripts/headers_check.pl $(output-files) FORCE
|
||||
$(call if_changed,check)
|
||||
|
||||
endif
|
||||
|
||||
# Recursion
|
||||
hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
|
||||
.PHONY: $(subdirs)
|
||||
$(subdirs):
|
||||
$(Q)$(MAKE) $(hdr-inst)=$(obj)/$@ dst=$(_dst)/$@
|
||||
|
||||
targets := $(wildcard $(sort $(targets)))
|
||||
cmd_files := $(wildcard \
|
||||
$(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
endif
|
||||
|
||||
.PHONY: $(PHONY)
|
||||
PHONY += FORCE
|
||||
FORCE: ;
|
3
scripts/Makefile.help
Normal file
3
scripts/Makefile.help
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
checker-help:
|
||||
@echo ' coccicheck - Check with Coccinelle.'
|
128
scripts/Makefile.host
Normal file
128
scripts/Makefile.host
Normal file
|
@ -0,0 +1,128 @@
|
|||
# ==========================================================================
|
||||
# Building binaries on the host system
|
||||
# Binaries are used during the compilation of the kernel, for example
|
||||
# to preprocess a data file.
|
||||
#
|
||||
# Both C and C++ are supported, but preferred language is C for such utilities.
|
||||
#
|
||||
# Sample syntax (see Documentation/kbuild/makefiles.txt for reference)
|
||||
# hostprogs-y := bin2hex
|
||||
# Will compile bin2hex.c and create an executable named bin2hex
|
||||
#
|
||||
# hostprogs-y := lxdialog
|
||||
# lxdialog-objs := checklist.o lxdialog.o
|
||||
# Will compile lxdialog.c and checklist.c, and then link the executable
|
||||
# lxdialog, based on checklist.o and lxdialog.o
|
||||
#
|
||||
# hostprogs-y := qconf
|
||||
# qconf-cxxobjs := qconf.o
|
||||
# qconf-objs := menu.o
|
||||
# Will compile qconf as a C++ program, and menu as a C program.
|
||||
# They are linked as C++ code to the executable qconf
|
||||
|
||||
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
|
||||
|
||||
# C code
|
||||
# Executables compiled from a single .c file
|
||||
host-csingle := $(foreach m,$(__hostprogs), \
|
||||
$(if $($(m)-objs)$($(m)-cxxobjs),,$(m)))
|
||||
|
||||
# C executables linked based on several .o files
|
||||
host-cmulti := $(foreach m,$(__hostprogs),\
|
||||
$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
|
||||
|
||||
# Object (.o) files compiled from .c files
|
||||
host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
|
||||
|
||||
# C++ code
|
||||
# C++ executables compiled from at least one .cc file
|
||||
# and zero or more .c files
|
||||
host-cxxmulti := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
|
||||
|
||||
# C++ Object (.o) files compiled from .cc files
|
||||
host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
|
||||
|
||||
# output directory for programs/.o files
|
||||
# hostprogs-y := tools/build may have been specified.
|
||||
# Retrieve also directory of .o files from prog-objs or prog-cxxobjs notation
|
||||
host-objdirs := $(dir $(__hostprogs) $(host-cobjs) $(host-cxxobjs))
|
||||
|
||||
host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
|
||||
|
||||
|
||||
__hostprogs := $(addprefix $(obj)/,$(__hostprogs))
|
||||
host-csingle := $(addprefix $(obj)/,$(host-csingle))
|
||||
host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
|
||||
host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
|
||||
host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti))
|
||||
host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs))
|
||||
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
|
||||
|
||||
obj-dirs += $(host-objdirs)
|
||||
|
||||
#####
|
||||
# Handle options to gcc. Support building with separate output directory
|
||||
|
||||
_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
|
||||
$(HOSTCFLAGS_$(basetarget).o)
|
||||
_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
|
||||
$(HOSTCXXFLAGS_$(basetarget).o)
|
||||
|
||||
ifeq ($(KBUILD_SRC),)
|
||||
__hostc_flags = $(_hostc_flags)
|
||||
__hostcxx_flags = $(_hostcxx_flags)
|
||||
else
|
||||
__hostc_flags = -I$(obj) $(call flags,_hostc_flags)
|
||||
__hostcxx_flags = -I$(obj) $(call flags,_hostcxx_flags)
|
||||
endif
|
||||
|
||||
hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags)
|
||||
hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags)
|
||||
|
||||
#####
|
||||
# Compile programs on the host
|
||||
|
||||
# Create executable from a single .c file
|
||||
# host-csingle -> Executable
|
||||
quiet_cmd_host-csingle = HOSTCC $@
|
||||
cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
|
||||
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
|
||||
$(host-csingle): $(obj)/%: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,host-csingle)
|
||||
|
||||
# Link an executable based on list of .o files, all plain c
|
||||
# host-cmulti -> executable
|
||||
quiet_cmd_host-cmulti = HOSTLD $@
|
||||
cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
|
||||
$(addprefix $(obj)/,$($(@F)-objs)) \
|
||||
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
|
||||
$(host-cmulti): FORCE
|
||||
$(call if_changed,host-cmulti)
|
||||
$(call multi_depend, $(host-cmulti), , -objs)
|
||||
|
||||
# Create .o file from a single .c file
|
||||
# host-cobjs -> .o
|
||||
quiet_cmd_host-cobjs = HOSTCC $@
|
||||
cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $<
|
||||
$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
|
||||
$(call if_changed_dep,host-cobjs)
|
||||
|
||||
# Link an executable based on list of .o files, a mixture of .c and .cc
|
||||
# host-cxxmulti -> executable
|
||||
quiet_cmd_host-cxxmulti = HOSTLD $@
|
||||
cmd_host-cxxmulti = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
|
||||
$(foreach o,objs cxxobjs,\
|
||||
$(addprefix $(obj)/,$($(@F)-$(o)))) \
|
||||
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
|
||||
$(host-cxxmulti): FORCE
|
||||
$(call if_changed,host-cxxmulti)
|
||||
$(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs)
|
||||
|
||||
# Create .o file from a single .cc (C++) file
|
||||
quiet_cmd_host-cxxobjs = HOSTCXX $@
|
||||
cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
|
||||
$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
|
||||
$(call if_changed_dep,host-cxxobjs)
|
||||
|
||||
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
|
||||
$(host-cxxmulti) $(host-cxxobjs)
|
398
scripts/Makefile.lib
Normal file
398
scripts/Makefile.lib
Normal file
|
@ -0,0 +1,398 @@
|
|||
# Backward compatibility
|
||||
asflags-y += $(EXTRA_AFLAGS)
|
||||
ccflags-y += $(EXTRA_CFLAGS)
|
||||
cppflags-y += $(EXTRA_CPPFLAGS)
|
||||
ldflags-y += $(EXTRA_LDFLAGS)
|
||||
|
||||
#
|
||||
# flags that take effect in sub directories
|
||||
export KBUILD_SUBDIR_ASFLAGS := $(KBUILD_SUBDIR_ASFLAGS) $(subdir-asflags-y)
|
||||
export KBUILD_SUBDIR_CCFLAGS := $(KBUILD_SUBDIR_CCFLAGS) $(subdir-ccflags-y)
|
||||
|
||||
# Figure out what we need to build from the various variables
|
||||
# ===========================================================================
|
||||
|
||||
# When an object is listed to be built compiled-in and modular,
|
||||
# only build the compiled-in version
|
||||
|
||||
obj-m := $(filter-out $(obj-y),$(obj-m))
|
||||
|
||||
# Libraries are always collected in one lib file.
|
||||
# Filter out objects already built-in
|
||||
|
||||
lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
|
||||
|
||||
|
||||
# Handle objects in subdirs
|
||||
# ---------------------------------------------------------------------------
|
||||
# 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)
|
||||
# and add the directory to the list of dirs to descend into: $(subdir-m)
|
||||
|
||||
# Determine modorder.
|
||||
# Unfortunately, we don't have information about ordering between -y
|
||||
# and -m subdirs. Just put -y's first.
|
||||
modorder := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko))
|
||||
|
||||
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
|
||||
subdir-y += $(__subdir-y)
|
||||
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
|
||||
subdir-m += $(__subdir-m)
|
||||
obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
|
||||
obj-m := $(filter-out %/, $(obj-m))
|
||||
|
||||
# Subdirectories we need to descend into
|
||||
|
||||
subdir-ym := $(sort $(subdir-y) $(subdir-m))
|
||||
|
||||
# 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)
|
||||
single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
|
||||
|
||||
# Build list of the parts of our composite objects, our composite
|
||||
# objects depend on those (obviously)
|
||||
multi-objs-y := $(foreach m, $(multi-used-y), $($(m:.o=-objs)) $($(m:.o=-y)))
|
||||
multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
|
||||
multi-objs := $(multi-objs-y) $(multi-objs-m)
|
||||
|
||||
# $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to
|
||||
# tell kbuild to descend
|
||||
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) $(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)
|
||||
real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
|
||||
|
||||
# Add subdir path
|
||||
|
||||
extra-y := $(addprefix $(obj)/,$(extra-y))
|
||||
always := $(addprefix $(obj)/,$(always))
|
||||
targets := $(addprefix $(obj)/,$(targets))
|
||||
modorder := $(addprefix $(obj)/,$(modorder))
|
||||
obj-y := $(addprefix $(obj)/,$(obj-y))
|
||||
obj-m := $(addprefix $(obj)/,$(obj-m))
|
||||
lib-y := $(addprefix $(obj)/,$(lib-y))
|
||||
subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y))
|
||||
real-objs-y := $(addprefix $(obj)/,$(real-objs-y))
|
||||
real-objs-m := $(addprefix $(obj)/,$(real-objs-m))
|
||||
single-used-m := $(addprefix $(obj)/,$(single-used-m))
|
||||
multi-used-y := $(addprefix $(obj)/,$(multi-used-y))
|
||||
multi-used-m := $(addprefix $(obj)/,$(multi-used-m))
|
||||
multi-objs-y := $(addprefix $(obj)/,$(multi-objs-y))
|
||||
multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m))
|
||||
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
|
||||
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
|
||||
# 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
|
||||
# differ in different configs.
|
||||
name-fix = $(subst $(comma),_,$(subst -,_,$1))
|
||||
basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
|
||||
modname_flags = $(if $(filter 1,$(words $(modname))),\
|
||||
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
|
||||
|
||||
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
|
||||
$(ccflags-y) $(CFLAGS_$(basetarget).o)
|
||||
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
|
||||
_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
|
||||
$(asflags-y) $(AFLAGS_$(basetarget).o)
|
||||
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
|
||||
|
||||
#
|
||||
# Enable gcov profiling flags for a file, directory or for all files depending
|
||||
# on variables GCOV_PROFILE_obj.o, GCOV_PROFILE and CONFIG_GCOV_PROFILE_ALL
|
||||
# (in this order)
|
||||
#
|
||||
ifeq ($(CONFIG_GCOV_KERNEL),y)
|
||||
_c_flags += $(if $(patsubst n%,, \
|
||||
$(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
|
||||
$(CFLAGS_GCOV))
|
||||
endif
|
||||
|
||||
# If building the kernel in a separate objtree expand all occurrences
|
||||
# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/').
|
||||
|
||||
ifeq ($(KBUILD_SRC),)
|
||||
__c_flags = $(_c_flags)
|
||||
__a_flags = $(_a_flags)
|
||||
__cpp_flags = $(_cpp_flags)
|
||||
else
|
||||
|
||||
# -I$(obj) locates generated .h files
|
||||
# $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files
|
||||
# and locates generated .h files
|
||||
# FIXME: Replace both with specific CFLAGS* statements in the makefiles
|
||||
__c_flags = $(call addtree,-I$(obj)) $(call flags,_c_flags)
|
||||
__a_flags = $(call flags,_a_flags)
|
||||
__cpp_flags = $(call flags,_cpp_flags)
|
||||
endif
|
||||
|
||||
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
|
||||
$(__c_flags) $(modkern_cflags) \
|
||||
-D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
|
||||
|
||||
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
|
||||
$(__a_flags) $(modkern_aflags)
|
||||
|
||||
cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
|
||||
$(__cpp_flags)
|
||||
|
||||
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)/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=))))
|
||||
|
||||
# Useful for describing the dependency of composite objects
|
||||
# Usage:
|
||||
# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add)
|
||||
define multi_depend
|
||||
$(foreach m, $(notdir $1), \
|
||||
$(eval $(obj)/$m: \
|
||||
$(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s)))))))
|
||||
endef
|
||||
|
||||
ifdef REGENERATE_PARSERS
|
||||
|
||||
# GPERF
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_gperf = GPERF $@
|
||||
cmd_gperf = gperf -t --output-file $@ -a -C -E -g -k 1,3,$$ -p -t $<
|
||||
|
||||
.PRECIOUS: $(src)/%.hash.c_shipped
|
||||
$(src)/%.hash.c_shipped: $(src)/%.gperf
|
||||
$(call cmd,gperf)
|
||||
|
||||
# LEX
|
||||
# ---------------------------------------------------------------------------
|
||||
LEX_PREFIX = $(if $(LEX_PREFIX_${baseprereq}),$(LEX_PREFIX_${baseprereq}),yy)
|
||||
|
||||
quiet_cmd_flex = LEX $@
|
||||
cmd_flex = flex -o$@ -L -P $(LEX_PREFIX) $<
|
||||
|
||||
.PRECIOUS: $(src)/%.lex.c_shipped
|
||||
$(src)/%.lex.c_shipped: $(src)/%.l
|
||||
$(call cmd,flex)
|
||||
|
||||
# YACC
|
||||
# ---------------------------------------------------------------------------
|
||||
YACC_PREFIX = $(if $(YACC_PREFIX_${baseprereq}),$(YACC_PREFIX_${baseprereq}),yy)
|
||||
|
||||
quiet_cmd_bison = YACC $@
|
||||
cmd_bison = bison -o$@ -t -l -p $(YACC_PREFIX) $<
|
||||
|
||||
.PRECIOUS: $(src)/%.tab.c_shipped
|
||||
$(src)/%.tab.c_shipped: $(src)/%.y
|
||||
$(call cmd,bison)
|
||||
|
||||
quiet_cmd_bison_h = YACC $@
|
||||
cmd_bison_h = bison -o/dev/null --defines=$@ -t -l -p $(YACC_PREFIX) $<
|
||||
|
||||
.PRECIOUS: $(src)/%.tab.h_shipped
|
||||
$(src)/%.tab.h_shipped: $(src)/%.y
|
||||
$(call cmd,bison_h)
|
||||
|
||||
endif
|
||||
|
||||
# Shipped files
|
||||
# ===========================================================================
|
||||
|
||||
quiet_cmd_shipped = SHIPPED $@
|
||||
cmd_shipped = cat $< > $@
|
||||
|
||||
$(obj)/%: $(src)/%_shipped
|
||||
$(call cmd,shipped)
|
||||
|
||||
# Commands useful for building a boot image
|
||||
# ===========================================================================
|
||||
#
|
||||
# Use as following:
|
||||
#
|
||||
# target: source(s) FORCE
|
||||
# $(if_changed,ld/objcopy/gzip)
|
||||
#
|
||||
# and add target to extra-y so that we know we have to
|
||||
# read in the saved command line
|
||||
|
||||
# Linking
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_ld = LD $@
|
||||
cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \
|
||||
$(filter-out FORCE,$^) -o $@
|
||||
|
||||
# Objcopy
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_objcopy = OBJCOPY $@
|
||||
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
|
||||
|
||||
# Gzip
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_gzip = GZIP $@
|
||||
cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
|
||||
(rm -f $@ ; false)
|
||||
|
||||
# DTC
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Generate an assembly file to wrap the output of the device tree compiler
|
||||
quiet_cmd_dt_S_dtb= DTB $@
|
||||
cmd_dt_S_dtb= \
|
||||
( \
|
||||
echo '\#include <asm-generic/vmlinux.lds.h>'; \
|
||||
echo '.section .dtb.init.rodata,"a"'; \
|
||||
echo '.balign STRUCT_ALIGNMENT'; \
|
||||
echo '.global __dtb_$(*F)_begin'; \
|
||||
echo '__dtb_$(*F)_begin:'; \
|
||||
echo '.incbin "$<" '; \
|
||||
echo '__dtb_$(*F)_end:'; \
|
||||
echo '.global __dtb_$(*F)_end'; \
|
||||
echo '.balign STRUCT_ALIGNMENT'; \
|
||||
) > $@
|
||||
|
||||
$(obj)/%.dtb.S: $(obj)/%.dtb
|
||||
$(call cmd,dt_S_dtb)
|
||||
|
||||
quiet_cmd_dtc = DTC $@
|
||||
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))
|
||||
|
||||
# cat
|
||||
# ---------------------------------------------------------------------------
|
||||
# Concatentate multiple files together
|
||||
quiet_cmd_cat = CAT $@
|
||||
cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false)
|
||||
|
||||
# Bzip2
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Bzip2 and LZMA do not include size in file... so we have to fake that;
|
||||
# append the size as a 32-bit littleendian number as gzip does.
|
||||
size_append = printf $(shell \
|
||||
dec_size=0; \
|
||||
for F in $1; do \
|
||||
fsize=$$(stat -c "%s" $$F); \
|
||||
dec_size=$$(expr $$dec_size + $$fsize); \
|
||||
done; \
|
||||
printf "%08x\n" $$dec_size | \
|
||||
sed 's/\(..\)/\1 /g' | { \
|
||||
read ch0 ch1 ch2 ch3; \
|
||||
for ch in $$ch3 $$ch2 $$ch1 $$ch0; do \
|
||||
printf '%s%03o' '\\' $$((0x$$ch)); \
|
||||
done; \
|
||||
} \
|
||||
)
|
||||
|
||||
quiet_cmd_bzip2 = BZIP2 $@
|
||||
cmd_bzip2 = (cat $(filter-out FORCE,$^) | \
|
||||
bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
(rm -f $@ ; false)
|
||||
|
||||
# Lzma
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_lzma = LZMA $@
|
||||
cmd_lzma = (cat $(filter-out FORCE,$^) | \
|
||||
lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
(rm -f $@ ; false)
|
||||
|
||||
quiet_cmd_lzo = LZO $@
|
||||
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.
|
||||
#
|
||||
# xzkern uses a big LZMA2 dictionary since it doesn't increase memory usage
|
||||
# of the kernel decompressor. A BCJ filter is used if it is available for
|
||||
# the target architecture. xzkern also appends uncompressed size of the data
|
||||
# using size_append. The .xz format has the size information available at
|
||||
# the end of the file too, but it's in more complex format and it's good to
|
||||
# avoid changing the part of the boot code that reads the uncompressed size.
|
||||
# Note that the bytes added by size_append will make the xz tool think that
|
||||
# the file is corrupt. This is expected.
|
||||
#
|
||||
# xzmisc doesn't use size_append, so it can be used to create normal .xz
|
||||
# files. xzmisc uses smaller LZMA2 dictionary than xzkern, because a very
|
||||
# big dictionary would increase the memory usage too much in the multi-call
|
||||
# decompression mode. A BCJ filter isn't used either.
|
||||
quiet_cmd_xzkern = XZKERN $@
|
||||
cmd_xzkern = (cat $(filter-out FORCE,$^) | \
|
||||
sh $(srctree)/scripts/xz_wrap.sh && \
|
||||
$(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
(rm -f $@ ; false)
|
||||
|
||||
quiet_cmd_xzmisc = XZMISC $@
|
||||
cmd_xzmisc = (cat $(filter-out FORCE,$^) | \
|
||||
xz --check=crc32 --lzma2=dict=1MiB) > $@ || \
|
||||
(rm -f $@ ; false)
|
60
scripts/Makefile.modbuiltin
Normal file
60
scripts/Makefile.modbuiltin
Normal file
|
@ -0,0 +1,60 @@
|
|||
# ==========================================================================
|
||||
# Generating modules.builtin
|
||||
# ==========================================================================
|
||||
|
||||
src := $(obj)
|
||||
|
||||
PHONY := __modbuiltin
|
||||
__modbuiltin:
|
||||
|
||||
-include include/config/auto.conf
|
||||
# tristate.conf sets tristate variables to uppercase 'Y' or 'M'
|
||||
# That way, we get the list of built-in modules in obj-Y
|
||||
-include include/config/tristate.conf
|
||||
|
||||
include scripts/Kbuild.include
|
||||
|
||||
ifneq ($(KBUILD_SRC),)
|
||||
# Create output directory if not already present
|
||||
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
|
||||
endif
|
||||
|
||||
# The filename Kbuild has precedence over Makefile
|
||||
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
|
||||
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
|
||||
include $(kbuild-file)
|
||||
|
||||
include scripts/Makefile.lib
|
||||
__subdir-Y := $(patsubst %/,%,$(filter %/, $(obj-Y)))
|
||||
subdir-Y += $(__subdir-Y)
|
||||
subdir-ym := $(sort $(subdir-y) $(subdir-Y) $(subdir-m))
|
||||
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
|
||||
obj-Y := $(addprefix $(obj)/,$(obj-Y))
|
||||
|
||||
modbuiltin-subdirs := $(patsubst %,%/modules.builtin, $(subdir-ym))
|
||||
modbuiltin-mods := $(filter %.ko, $(obj-Y:.o=.ko))
|
||||
modbuiltin-target := $(obj)/modules.builtin
|
||||
|
||||
__modbuiltin: $(modbuiltin-target) $(subdir-ym)
|
||||
@:
|
||||
|
||||
$(modbuiltin-target): $(subdir-ym) FORCE
|
||||
$(Q)(for m in $(modbuiltin-mods); do echo kernel/$$m; done; \
|
||||
cat /dev/null $(modbuiltin-subdirs)) > $@
|
||||
|
||||
PHONY += FORCE
|
||||
|
||||
FORCE:
|
||||
|
||||
# Descending
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += $(subdir-ym)
|
||||
$(subdir-ym):
|
||||
$(Q)$(MAKE) $(modbuiltin)=$@
|
||||
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable se we can use it in if_changed and friends.
|
||||
|
||||
.PHONY: $(PHONY)
|
41
scripts/Makefile.modinst
Normal file
41
scripts/Makefile.modinst
Normal file
|
@ -0,0 +1,41 @@
|
|||
# ==========================================================================
|
||||
# Installing modules
|
||||
# ==========================================================================
|
||||
|
||||
PHONY := __modinst
|
||||
__modinst:
|
||||
|
||||
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)
|
||||
__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 $@) ; \
|
||||
$(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \
|
||||
$(mod_compress_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,modules_install,$(MODLIB)/$(modinst_dir))
|
||||
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable so we can use it in if_changed and friends.
|
||||
|
||||
.PHONY: $(PHONY)
|
152
scripts/Makefile.modpost
Normal file
152
scripts/Makefile.modpost
Normal file
|
@ -0,0 +1,152 @@
|
|||
# ===========================================================================
|
||||
# Module versions
|
||||
# ===========================================================================
|
||||
#
|
||||
# Stage one of module building created the following:
|
||||
# a) The individual .o files used for the module
|
||||
# b) A <module>.o file which is the .o files above linked together
|
||||
# c) A <module>.mod file in $(MODVERDIR)/, listing the name of the
|
||||
# the preliminary <module>.o file, plus all .o files
|
||||
|
||||
# Stage 2 is handled by this file and does the following
|
||||
# 1) Find all modules from the files listed in $(MODVERDIR)/
|
||||
# 2) modpost is then used to
|
||||
# 3) create one <module>.mod.c file pr. module
|
||||
# 4) create one Module.symvers file with CRC for all exported symbols
|
||||
# 5) compile all <module>.mod.c files
|
||||
# 6) final link of the module to a <module.ko> file
|
||||
|
||||
# Step 3 is used to place certain information in the module's ELF
|
||||
# section, including information such as:
|
||||
# Version magic (see include/linux/vermagic.h for full details)
|
||||
# - Kernel release
|
||||
# - SMP is CONFIG_SMP
|
||||
# - PREEMPT is CONFIG_PREEMPT
|
||||
# - GCC Version
|
||||
# Module info
|
||||
# - Module version (MODULE_VERSION)
|
||||
# - Module alias'es (MODULE_ALIAS)
|
||||
# - Module license (MODULE_LICENSE)
|
||||
# - See include/linux/module.h for more details
|
||||
|
||||
# Step 4 is solely used to allow module versioning in external modules,
|
||||
# where the CRC of each module is retrieved from the Module.symvers file.
|
||||
|
||||
# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
|
||||
# symbols in the final module linking stage
|
||||
# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
|
||||
# This is solely useful to speed up test compiles
|
||||
PHONY := _modpost
|
||||
_modpost: __modpost
|
||||
|
||||
include include/config/auto.conf
|
||||
include scripts/Kbuild.include
|
||||
|
||||
# When building external modules load the Kbuild file to retrieve EXTRA_SYMBOLS info
|
||||
ifneq ($(KBUILD_EXTMOD),)
|
||||
|
||||
# set src + obj - they may be used when building the .mod.c file
|
||||
obj := $(KBUILD_EXTMOD)
|
||||
src := $(obj)
|
||||
|
||||
# Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS
|
||||
include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \
|
||||
$(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile)
|
||||
endif
|
||||
|
||||
include scripts/Makefile.lib
|
||||
|
||||
kernelsymfile := $(objtree)/Module.symvers
|
||||
modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
|
||||
|
||||
# Step 1), find all modules listed in $(MODVERDIR)/
|
||||
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))
|
||||
|
||||
# Step 2), invoke modpost
|
||||
# Includes step 3,4
|
||||
modpost = scripts/mod/modpost \
|
||||
$(if $(CONFIG_MODVERSIONS),-m) \
|
||||
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \
|
||||
$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
|
||||
$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
|
||||
$(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)
|
||||
|
||||
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 = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) $(MODPOST_OPT) -s -T -
|
||||
|
||||
PHONY += __modpost
|
||||
__modpost: $(modules:.ko=.o) FORCE
|
||||
$(call cmd,modpost) $(wildcard vmlinux)
|
||||
|
||||
quiet_cmd_kernel-mod = MODPOST $@
|
||||
cmd_kernel-mod = $(modpost) $@
|
||||
|
||||
vmlinux.o: FORCE
|
||||
$(call cmd,kernel-mod)
|
||||
|
||||
# Declare generated files as targets for modpost
|
||||
$(symverfile): __modpost ;
|
||||
$(modules:.ko=.mod.c): __modpost ;
|
||||
|
||||
|
||||
# Step 5), compile all *.mod.c files
|
||||
|
||||
# modname is set to make c_flags define KBUILD_MODNAME
|
||||
modname = $(notdir $(@:.mod.o=))
|
||||
|
||||
quiet_cmd_cc_o_c = CC $@
|
||||
cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \
|
||||
-c -o $@ $<
|
||||
|
||||
$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
|
||||
$(call if_changed_dep,cc_o_c)
|
||||
|
||||
targets += $(modules:.ko=.mod.o)
|
||||
|
||||
# Step 6), final link of the modules
|
||||
quiet_cmd_ld_ko_o = LD [M] $@
|
||||
cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
|
||||
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
|
||||
-o $@ $(filter-out FORCE,$^)
|
||||
|
||||
$(modules): %.ko :%.o %.mod.o FORCE
|
||||
$(call if_changed,ld_ko_o)
|
||||
|
||||
targets += $(modules)
|
||||
|
||||
|
||||
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += FORCE
|
||||
|
||||
FORCE:
|
||||
|
||||
# Read all saved command lines and dependencies for the $(targets) we
|
||||
# may be building above, using $(if_changed{,_dep}). As an
|
||||
# optimization, we don't need to read them if the target does not
|
||||
# exist, we will rebuild anyway in that case.
|
||||
|
||||
targets := $(wildcard $(sort $(targets)))
|
||||
cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
endif
|
||||
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable se we can use it in if_changed and friends.
|
||||
|
||||
.PHONY: $(PHONY)
|
32
scripts/Makefile.modsign
Normal file
32
scripts/Makefile.modsign
Normal file
|
@ -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)
|
3591
scripts/analyze_suspend.py
Executable file
3591
scripts/analyze_suspend.py
Executable file
File diff suppressed because it is too large
Load diff
1547
scripts/asn1_compiler.c
Normal file
1547
scripts/asn1_compiler.c
Normal file
File diff suppressed because it is too large
Load diff
16
scripts/basic/Makefile
Normal file
16
scripts/basic/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
###
|
||||
# Makefile.basic lists the most basic programs used during the build process.
|
||||
# The programs listed herein are what are needed to do the basic stuff,
|
||||
# such as fix file dependencies.
|
||||
# This initial step is needed to avoid files to be recompiled
|
||||
# when kernel configuration changes (which is what happens when
|
||||
# .config is included by main Makefile.
|
||||
# ---------------------------------------------------------------------------
|
||||
# fixdep: Used to generate dependency information during build process
|
||||
|
||||
hostprogs-y := fixdep
|
||||
hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c
|
||||
always := $(hostprogs-y)
|
||||
|
||||
# fixdep is needed to compile other host programs
|
||||
$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
|
35
scripts/basic/bin2c.c
Normal file
35
scripts/basic/bin2c.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Unloved program to convert a binary on stdin to a C include on stdout
|
||||
*
|
||||
* Jan 1999 Matt Mackall <mpm@selenic.com>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ch, total = 0;
|
||||
|
||||
if (argc > 1)
|
||||
printf("const char %s[] %s=\n",
|
||||
argv[1], argc > 2 ? argv[2] : "");
|
||||
|
||||
do {
|
||||
printf("\t\"");
|
||||
while ((ch = getchar()) != EOF) {
|
||||
total++;
|
||||
printf("\\x%02x", ch);
|
||||
if (total % 16 == 0)
|
||||
break;
|
||||
}
|
||||
printf("\"\n");
|
||||
} while (ch != EOF);
|
||||
|
||||
if (argc > 1)
|
||||
printf("\t;\n\nconst int %s_size = %d;\n", argv[1], total);
|
||||
|
||||
return 0;
|
||||
}
|
462
scripts/basic/fixdep.c
Normal file
462
scripts/basic/fixdep.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* "Optimize" a list of dependencies as spit out by gcc -MD
|
||||
* for the kernel build
|
||||
* ===========================================================================
|
||||
*
|
||||
* Author Kai Germaschewski
|
||||
* Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*
|
||||
* Introduction:
|
||||
*
|
||||
* gcc produces a very nice and correct list of dependencies which
|
||||
* tells make when to remake a file.
|
||||
*
|
||||
* To use this list as-is however has the drawback that virtually
|
||||
* every file in the kernel includes autoconf.h.
|
||||
*
|
||||
* If the user re-runs make *config, autoconf.h will be
|
||||
* regenerated. make notices that and will rebuild every file which
|
||||
* includes autoconf.h, i.e. basically all files. This is extremely
|
||||
* annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
|
||||
*
|
||||
* So we play the same trick that "mkdep" played before. We replace
|
||||
* the dependency on autoconf.h by a dependency on every config
|
||||
* option which is mentioned in any of the listed prequisites.
|
||||
*
|
||||
* kconfig populates a tree in include/config/ with an empty file
|
||||
* for each config symbol and when the configuration is updated
|
||||
* the files representing changed config options are touched
|
||||
* which then let make pick up the changes and the files that use
|
||||
* the config symbols are rebuilt.
|
||||
*
|
||||
* So if the user changes his CONFIG_HIS_DRIVER option, only the objects
|
||||
* which depend on "include/linux/config/his/driver.h" will be rebuilt,
|
||||
* so most likely only his driver ;-)
|
||||
*
|
||||
* The idea above dates, by the way, back to Michael E Chastain, AFAIK.
|
||||
*
|
||||
* So to get dependencies right, there are two issues:
|
||||
* o if any of the files the compiler read changed, we need to rebuild
|
||||
* o if the command line given to the compile the file changed, we
|
||||
* better rebuild as well.
|
||||
*
|
||||
* The former is handled by using the -MD output, the later by saving
|
||||
* the command line used to compile the old object and comparing it
|
||||
* to the one we would now use.
|
||||
*
|
||||
* Again, also this idea is pretty old and has been discussed on
|
||||
* kbuild-devel a long time ago. I don't have a sensibly working
|
||||
* internet connection right now, so I rather don't mention names
|
||||
* without double checking.
|
||||
*
|
||||
* This code here has been based partially based on mkdep.c, which
|
||||
* says the following about its history:
|
||||
*
|
||||
* Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
|
||||
* This is a C version of syncdep.pl by Werner Almesberger.
|
||||
*
|
||||
*
|
||||
* It is invoked as
|
||||
*
|
||||
* fixdep <depfile> <target> <cmdline>
|
||||
*
|
||||
* and will read the dependency file <depfile>
|
||||
*
|
||||
* The transformed dependency snipped is written to stdout.
|
||||
*
|
||||
* It first generates a line
|
||||
*
|
||||
* cmd_<target> = <cmdline>
|
||||
*
|
||||
* and then basically copies the .<target>.d file to stdout, in the
|
||||
* process filtering out the dependency on autoconf.h and adding
|
||||
* dependencies on include/config/my/option.h for every
|
||||
* CONFIG_MY_OPTION encountered in any of the prequisites.
|
||||
*
|
||||
* It will also filter out all the dependencies on *.ver. We need
|
||||
* to make sure that the generated version checksum are globally up
|
||||
* to date before even starting the recursive build, so it's too late
|
||||
* at this point anyway.
|
||||
*
|
||||
* The algorithm to grep for "CONFIG_..." is bit unusual, but should
|
||||
* be fast ;-) We don't even try to really parse the header files, but
|
||||
* merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
|
||||
* be picked up as well. It's not a problem with respect to
|
||||
* correctness, since that can only give too many dependencies, thus
|
||||
* we cannot miss a rebuild. Since people tend to not mention totally
|
||||
* unrelated CONFIG_ options all over the place, it's not an
|
||||
* efficiency problem either.
|
||||
*
|
||||
* (Note: it'd be easy to port over the complete mkdep state machine,
|
||||
* but I don't think the added complexity is worth it)
|
||||
*/
|
||||
/*
|
||||
* Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
|
||||
* CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
|
||||
* fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
|
||||
* UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
|
||||
* through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
|
||||
* those files will have correct dependencies.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define INT_CONF ntohl(0x434f4e46)
|
||||
#define INT_ONFI ntohl(0x4f4e4649)
|
||||
#define INT_NFIG ntohl(0x4e464947)
|
||||
#define INT_FIG_ ntohl(0x4649475f)
|
||||
|
||||
char *target;
|
||||
char *depfile;
|
||||
char *cmdline;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the commandline prefixed with cmd_<target filename> :=
|
||||
*/
|
||||
static void print_cmdline(void)
|
||||
{
|
||||
printf("cmd_%s := %s\n\n", target, cmdline);
|
||||
}
|
||||
|
||||
struct item {
|
||||
struct item *next;
|
||||
unsigned int len;
|
||||
unsigned int hash;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
#define HASHSZ 256
|
||||
static struct item *hashtab[HASHSZ];
|
||||
|
||||
static unsigned int strhash(const char *str, unsigned int sz)
|
||||
{
|
||||
/* fnv32 hash */
|
||||
unsigned int i, hash = 2166136261U;
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
hash = (hash ^ str[i]) * 0x01000193;
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a value in the configuration string.
|
||||
*/
|
||||
static int is_defined_config(const char *name, int len, unsigned int hash)
|
||||
{
|
||||
struct item *aux;
|
||||
|
||||
for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
|
||||
if (aux->hash == hash && aux->len == len &&
|
||||
memcmp(aux->name, name, len) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new value to the configuration string.
|
||||
*/
|
||||
static void define_config(const char *name, int len, unsigned int hash)
|
||||
{
|
||||
struct item *aux = malloc(sizeof(*aux) + len);
|
||||
|
||||
if (!aux) {
|
||||
perror("fixdep:malloc");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(aux->name, name, len);
|
||||
aux->len = len;
|
||||
aux->hash = hash;
|
||||
aux->next = hashtab[hash % HASHSZ];
|
||||
hashtab[hash % HASHSZ] = aux;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the set of configuration strings.
|
||||
*/
|
||||
static void clear_config(void)
|
||||
{
|
||||
struct item *aux, *next;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < HASHSZ; i++) {
|
||||
for (aux = hashtab[i]; aux; aux = next) {
|
||||
next = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
hashtab[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Record the use of a CONFIG_* word.
|
||||
*/
|
||||
static void use_config(const char *m, int slen)
|
||||
{
|
||||
unsigned int hash = strhash(m, slen);
|
||||
int c, i;
|
||||
|
||||
if (is_defined_config(m, slen, hash))
|
||||
return;
|
||||
|
||||
define_config(m, slen, hash);
|
||||
|
||||
printf(" $(wildcard include/config/");
|
||||
for (i = 0; i < slen; i++) {
|
||||
c = m[i];
|
||||
if (c == '_')
|
||||
c = '/';
|
||||
else
|
||||
c = tolower(c);
|
||||
putchar(c);
|
||||
}
|
||||
printf(".h) \\\n");
|
||||
}
|
||||
|
||||
static void parse_config_file(const char *map, size_t len)
|
||||
{
|
||||
const int *end = (const int *) (map + len);
|
||||
/* start at +1, so that p can never be < map */
|
||||
const int *m = (const int *) map + 1;
|
||||
const char *p, *q;
|
||||
|
||||
for (; m < end; m++) {
|
||||
if (*m == INT_CONF) { p = (char *) m ; goto conf; }
|
||||
if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
|
||||
if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
|
||||
if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
|
||||
continue;
|
||||
conf:
|
||||
if (p > map + len - 7)
|
||||
continue;
|
||||
if (memcmp(p, "CONFIG_", 7))
|
||||
continue;
|
||||
for (q = p + 7; q < map + len; q++) {
|
||||
if (!(isalnum(*q) || *q == '_'))
|
||||
goto found;
|
||||
}
|
||||
continue;
|
||||
|
||||
found:
|
||||
if (!memcmp(q - 7, "_MODULE", 7))
|
||||
q -= 7;
|
||||
if( (q-p-7) < 0 )
|
||||
continue;
|
||||
use_config(p+7, q-p-7);
|
||||
}
|
||||
}
|
||||
|
||||
/* test is s ends in sub */
|
||||
static int strrcmp(char *s, char *sub)
|
||||
{
|
||||
int slen = strlen(s);
|
||||
int sublen = strlen(sub);
|
||||
|
||||
if (sublen > slen)
|
||||
return 1;
|
||||
|
||||
return memcmp(s + slen - sublen, sub, sublen);
|
||||
}
|
||||
|
||||
static void do_config_file(const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
int fd;
|
||||
void *map;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "fixdep: error opening config file: ");
|
||||
perror(filename);
|
||||
exit(2);
|
||||
}
|
||||
fstat(fd, &st);
|
||||
if (st.st_size == 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if ((long) map == -1) {
|
||||
perror("fixdep: mmap");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_config_file(map, st.st_size);
|
||||
|
||||
munmap(map, st.st_size);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Important: The below generated source_foo.o and deps_foo.o variable
|
||||
* assignments are parsed not only by make, but also by the rather simple
|
||||
* parser in scripts/mod/sumversion.c.
|
||||
*/
|
||||
static void parse_dep_file(void *map, size_t len)
|
||||
{
|
||||
char *m = map;
|
||||
char *end = m + len;
|
||||
char *p;
|
||||
char s[PATH_MAX];
|
||||
int is_target;
|
||||
int saw_any_target = 0;
|
||||
int is_first_dep = 0;
|
||||
|
||||
clear_config();
|
||||
|
||||
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 != '\\' && *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);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static void print_deps(void)
|
||||
{
|
||||
struct stat st;
|
||||
int fd;
|
||||
void *map;
|
||||
|
||||
fd = open(depfile, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "fixdep: error opening depfile: ");
|
||||
perror(depfile);
|
||||
exit(2);
|
||||
}
|
||||
if (fstat(fd, &st) < 0) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if ((long) map == -1) {
|
||||
perror("fixdep: mmap");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_dep_file(map, st.st_size);
|
||||
|
||||
munmap(map, st.st_size);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void traps(void)
|
||||
{
|
||||
static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
|
||||
int *p = (int *)test;
|
||||
|
||||
if (*p != INT_CONF) {
|
||||
fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianness? %#x\n",
|
||||
*p);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
traps();
|
||||
|
||||
if (argc != 4)
|
||||
usage();
|
||||
|
||||
depfile = argv[1];
|
||||
target = argv[2];
|
||||
cmdline = argv[3];
|
||||
|
||||
print_cmdline();
|
||||
print_deps();
|
||||
|
||||
return 0;
|
||||
}
|
65
scripts/bloat-o-meter
Executable file
65
scripts/bloat-o-meter
Executable file
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright 2004 Matt Mackall <mpm@selenic.com>
|
||||
#
|
||||
# inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
|
||||
#
|
||||
# This software may be used and distributed according to the terms
|
||||
# of the GNU General Public License, incorporated herein by reference.
|
||||
|
||||
import sys, os, re
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
sys.stderr.write("usage: %s file1 file2\n" % sys.argv[0])
|
||||
sys.exit(-1)
|
||||
|
||||
def getsizes(file):
|
||||
sym = {}
|
||||
for l in os.popen("nm --size-sort " + file).readlines():
|
||||
size, type, name = l[:-1].split()
|
||||
if type in "tTdDbBrR":
|
||||
# strip generated symbols
|
||||
if name.startswith("__mod_"): continue
|
||||
if name.startswith("SyS_"): continue
|
||||
if name.startswith("compat_SyS_"): 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
|
||||
|
||||
old = getsizes(sys.argv[1])
|
||||
new = getsizes(sys.argv[2])
|
||||
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
|
||||
delta, common = [], {}
|
||||
|
||||
for a in old:
|
||||
if a in new:
|
||||
common[a] = 1
|
||||
|
||||
for name in old:
|
||||
if name not in common:
|
||||
remove += 1
|
||||
down += old[name]
|
||||
delta.append((-old[name], name))
|
||||
|
||||
for name in new:
|
||||
if name not in common:
|
||||
add += 1
|
||||
up += new[name]
|
||||
delta.append((new[name], name))
|
||||
|
||||
for name in common:
|
||||
d = new.get(name, 0) - old.get(name, 0)
|
||||
if d>0: grow, up = grow+1, up+d
|
||||
if d<0: shrink, down = shrink+1, down-d
|
||||
delta.append((d, name))
|
||||
|
||||
delta.sort()
|
||||
delta.reverse()
|
||||
|
||||
print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
|
||||
(add, remove, grow, shrink, up, -down, up-down)
|
||||
print "%-40s %7s %7s %+7s" % ("function", "old", "new", "delta")
|
||||
for d, n in delta:
|
||||
if d: print "%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d)
|
238
scripts/bootgraph.pl
Executable file
238
scripts/bootgraph.pl
Executable file
|
@ -0,0 +1,238 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2008, Intel Corporation
|
||||
#
|
||||
# This file is part of the Linux kernel
|
||||
#
|
||||
# This program file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# 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 in a file named COPYING; if not, write to the
|
||||
# Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Authors:
|
||||
# Arjan van de Ven <arjan@linux.intel.com>
|
||||
|
||||
|
||||
#
|
||||
# This script turns a dmesg output into a SVG graphic that shows which
|
||||
# functions take how much time. You can view SVG graphics with various
|
||||
# programs, including Inkscape, The Gimp and Firefox.
|
||||
#
|
||||
#
|
||||
# For this script to work, the kernel needs to be compiled with the
|
||||
# CONFIG_PRINTK_TIME configuration option enabled, and with
|
||||
# "initcall_debug" passed on the kernel command line.
|
||||
#
|
||||
# usage:
|
||||
# dmesg | perl scripts/bootgraph.pl > output.svg
|
||||
#
|
||||
|
||||
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;
|
||||
my %type;
|
||||
my $done = 0;
|
||||
my $maxtime = 0;
|
||||
my $firsttime = 99999;
|
||||
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\_\.]+)\+/) {
|
||||
my $func = $2;
|
||||
if ($done == 0) {
|
||||
$start{$func} = $1;
|
||||
$type{$func} = 0;
|
||||
if ($1 < $firsttime) {
|
||||
$firsttime = $1;
|
||||
}
|
||||
}
|
||||
if ($line =~ /\@ ([0-9]+)/) {
|
||||
$pids{$func} = $1;
|
||||
}
|
||||
$count = $count + 1;
|
||||
}
|
||||
|
||||
if ($line =~ /([0-9\.]+)\] async_waiting @ ([0-9]+)/) {
|
||||
my $pid = $2;
|
||||
my $func;
|
||||
if (!defined($pidctr{$pid})) {
|
||||
$func = "wait_" . $pid . "_1";
|
||||
$pidctr{$pid} = 1;
|
||||
} else {
|
||||
$pidctr{$pid} = $pidctr{$pid} + 1;
|
||||
$func = "wait_" . $pid . "_" . $pidctr{$pid};
|
||||
}
|
||||
if ($done == 0) {
|
||||
$start{$func} = $1;
|
||||
$type{$func} = 1;
|
||||
if ($1 < $firsttime) {
|
||||
$firsttime = $1;
|
||||
}
|
||||
}
|
||||
$pids{$func} = $pid;
|
||||
$count = $count + 1;
|
||||
}
|
||||
|
||||
if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_\.]+)\+.*returned/) {
|
||||
if ($done == 0) {
|
||||
$end{$2} = $1;
|
||||
$maxtime = $1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($line =~ /([0-9\.]+)\] async_continuing @ ([0-9]+)/) {
|
||||
my $pid = $2;
|
||||
my $func = "wait_" . $pid . "_" . $pidctr{$pid};
|
||||
$end{$func} = $1;
|
||||
$maxtime = $1;
|
||||
}
|
||||
if ($line =~ /Write protecting the/) {
|
||||
$done = 1;
|
||||
}
|
||||
if ($line =~ /Freeing unused kernel memory/) {
|
||||
$done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
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)";
|
||||
$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[8] = "fill:rgb(255,0,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[9] = "fill:rgb(255,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[10] = "fill:rgb(255,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
$styles[11] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
|
||||
|
||||
my $style_wait = "fill:rgb(128,128,128);fill-opacity:0.5;stroke-width:0;stroke:rgb(0,0,0)";
|
||||
|
||||
my $mult = 1950.0 / ($maxtime - $firsttime);
|
||||
my $threshold2 = ($maxtime - $firsttime) / 120.0;
|
||||
my $threshold = $threshold2/10;
|
||||
my $stylecounter = 0;
|
||||
my %rows;
|
||||
my $rowscount = 1;
|
||||
my @initcalls = sort { $start{$a} <=> $start{$b} } keys(%start);
|
||||
|
||||
foreach my $key (@initcalls) {
|
||||
my $duration = $end{$key} - $start{$key};
|
||||
|
||||
if ($duration >= $threshold) {
|
||||
my ($s, $s2, $s3, $e, $w, $y, $y2, $style);
|
||||
my $pid = $pids{$key};
|
||||
|
||||
if (!defined($rows{$pid})) {
|
||||
$rows{$pid} = $rowscount;
|
||||
$rowscount = $rowscount + 1;
|
||||
}
|
||||
$s = ($start{$key} - $firsttime) * $mult;
|
||||
$s2 = $s + 6;
|
||||
$s3 = $s + 1;
|
||||
$e = ($end{$key} - $firsttime) * $mult;
|
||||
$w = $e - $s;
|
||||
|
||||
$y = $rows{$pid} * 150;
|
||||
$y2 = $y + 4;
|
||||
|
||||
$style = $styles[$stylecounter];
|
||||
$stylecounter = $stylecounter + 1;
|
||||
if ($stylecounter > 11) {
|
||||
$stylecounter = 0;
|
||||
};
|
||||
|
||||
if ($type{$key} == 1) {
|
||||
$y = $y + 15;
|
||||
print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"115\" style=\"$style_wait\"/>\n";
|
||||
} else {
|
||||
print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"145\" style=\"$style\"/>\n";
|
||||
if ($duration >= $threshold2) {
|
||||
print "<text transform=\"translate($s2,$y2) rotate(90)\">$key</text>\n";
|
||||
} else {
|
||||
print "<text transform=\"translate($s3,$y2) rotate(90)\" font-size=\"3pt\">$key</text>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# print the time line on top
|
||||
my $time = $firsttime;
|
||||
my $step = ($maxtime - $firsttime) / 15;
|
||||
while ($time < $maxtime) {
|
||||
my $s3 = ($time - $firsttime) * $mult;
|
||||
my $tm = int($time * 100) / 100.0;
|
||||
print "<text transform=\"translate($s3,89) rotate(90)\">$tm</text>\n";
|
||||
$time = $time + $step;
|
||||
}
|
||||
|
||||
print "</svg>\n";
|
89
scripts/checkincludes.pl
Executable file
89
scripts/checkincludes.pl
Executable file
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# checkincludes: find/remove files included more than once
|
||||
#
|
||||
# Copyright abandoned, 2000, Niels Kristian Bech Jensen <nkbj@image.dk>.
|
||||
# Copyright 2009 Luis R. Rodriguez <mcgrof@gmail.com>
|
||||
#
|
||||
# This script checks for duplicate includes. It also has support
|
||||
# to remove them in place. Note that this will not take into
|
||||
# consideration macros so you should run this only if you know
|
||||
# you do have real dups and do not have them under #ifdef's. You
|
||||
# could also just review the results.
|
||||
|
||||
use strict;
|
||||
|
||||
sub usage {
|
||||
print "Usage: checkincludes.pl [-r]\n";
|
||||
print "By default we just warn of duplicates\n";
|
||||
print "To remove duplicated includes in place use -r\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $remove = 0;
|
||||
|
||||
if ($#ARGV < 0) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if ($#ARGV >= 1) {
|
||||
if ($ARGV[0] =~ /^-/) {
|
||||
if ($ARGV[0] eq "-r") {
|
||||
$remove = 1;
|
||||
shift;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $file (@ARGV) {
|
||||
open(my $f, '<', $file)
|
||||
or die "Cannot open $file: $!.\n";
|
||||
|
||||
my %includedfiles = ();
|
||||
my @file_lines = ();
|
||||
|
||||
while (<$f>) {
|
||||
if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) {
|
||||
++$includedfiles{$1};
|
||||
}
|
||||
push(@file_lines, $_);
|
||||
}
|
||||
|
||||
close($f);
|
||||
|
||||
if (!$remove) {
|
||||
foreach my $filename (keys %includedfiles) {
|
||||
if ($includedfiles{$filename} > 1) {
|
||||
print "$file: $filename is included more than once.\n";
|
||||
}
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
open($f, '>', $file)
|
||||
or die("Cannot write to $file: $!");
|
||||
|
||||
my $dups = 0;
|
||||
foreach (@file_lines) {
|
||||
if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) {
|
||||
foreach my $filename (keys %includedfiles) {
|
||||
if ($1 eq $filename) {
|
||||
if ($includedfiles{$filename} > 1) {
|
||||
$includedfiles{$filename}--;
|
||||
$dups++;
|
||||
} else {
|
||||
print {$f} $_;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print {$f} $_;
|
||||
}
|
||||
}
|
||||
if ($dups > 0) {
|
||||
print "$file: removed $dups duplicate includes\n";
|
||||
}
|
||||
close($f);
|
||||
}
|
59
scripts/checkkconfigsymbols.sh
Executable file
59
scripts/checkkconfigsymbols.sh
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/bin/sh
|
||||
# Find Kconfig variables used in source code but never defined in Kconfig
|
||||
# Copyright (C) 2007, Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
|
||||
|
||||
# Tested with dash.
|
||||
paths="$@"
|
||||
[ -z "$paths" ] && paths=.
|
||||
|
||||
# Doing this once at the beginning saves a lot of time, on a cache-hot tree.
|
||||
Kconfigs="`find . -name 'Kconfig' -o -name 'Kconfig*[^~]'`"
|
||||
|
||||
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
|
||||
# the end is not removed here (would need perl an not-hungry regexp for that).
|
||||
sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Za-z_]\+\).*!\2 '$i'!p' < $i
|
||||
done | \
|
||||
# Smart "sort|uniq" implemented in awk and tuned to collect the names of all
|
||||
# files which use a given symbol
|
||||
awk '{map[$1, count[$1]++] = $2; }
|
||||
END {
|
||||
for (combIdx in map) {
|
||||
split(combIdx, separate, SUBSEP);
|
||||
# The value may have been removed.
|
||||
if (! ( (separate[1], separate[2]) in map ) )
|
||||
continue;
|
||||
symb=separate[1];
|
||||
printf "%s ", symb;
|
||||
#Use gawk extension to delete the names vector
|
||||
delete names;
|
||||
#Portably delete the names vector
|
||||
#split("", names);
|
||||
for (i=0; i < count[symb]; i++) {
|
||||
names[map[symb, i]] = 1;
|
||||
# Unfortunately, we may still encounter symb, i in the
|
||||
# outside iteration.
|
||||
delete map[symb, i];
|
||||
}
|
||||
i=0;
|
||||
for (name in names) {
|
||||
if (i > 0)
|
||||
printf ", %s", name;
|
||||
else
|
||||
printf "%s", name;
|
||||
i++;
|
||||
}
|
||||
printf "\n";
|
||||
}
|
||||
}' |
|
||||
while read symb files; do
|
||||
# Remove the _MODULE suffix when checking the variable name. This should
|
||||
# be done only on tristate symbols, actually, but Kconfig parsing is
|
||||
# beyond the purpose of this script.
|
||||
symb_bare=`echo $symb | sed -e 's/_MODULE//'`
|
||||
if ! grep -q "\<$symb_bare\>" $Kconfigs; then
|
||||
printf "$files: \t$symb\n"
|
||||
fi
|
||||
done|sort
|
5250
scripts/checkpatch.pl
Executable file
5250
scripts/checkpatch.pl
Executable file
File diff suppressed because it is too large
Load diff
176
scripts/checkstack.pl
Executable file
176
scripts/checkstack.pl
Executable file
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Check the stack usage of functions
|
||||
#
|
||||
# Copyright Joern Engel <joern@lazybastard.org>
|
||||
# Inspired by Linus Torvalds
|
||||
# Original idea maybe from Keith Owens
|
||||
# s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
|
||||
# Mips port by Juan Quintela <quintela@mandrakesoft.com>
|
||||
# IA64 port via Andreas Dilger
|
||||
# Arm port by Holger Schurig
|
||||
# sh64 port by Paul Mundt
|
||||
# Random bits by Matt Mackall <mpm@selenic.com>
|
||||
# M68k port by Geert Uytterhoeven and Andreas Schwab
|
||||
# AVR32 port by Haavard Skinnemoen (Atmel)
|
||||
# AArch64, PARISC ports by Kyle McMartin
|
||||
# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
|
||||
#
|
||||
# Usage:
|
||||
# objdump -d vmlinux | scripts/checkstack.pl [arch]
|
||||
#
|
||||
# TODO : Port to all architectures (one regex per arch)
|
||||
|
||||
use strict;
|
||||
|
||||
# check for arch
|
||||
#
|
||||
# $re is used for two matches:
|
||||
# $& (whole re) matches the complete objdump line with the stack growth
|
||||
# $1 (first bracket) matches the size of the stack growth
|
||||
#
|
||||
# $dre is similar, but for dynamic stack redutions:
|
||||
# $& (whole re) matches the complete objdump line with the stack growth
|
||||
# $1 (first bracket) matches the dynamic amount of the stack growth
|
||||
#
|
||||
# use anything else and feel the pain ;)
|
||||
my (@stack, $re, $dre, $x, $xs, $funcre);
|
||||
{
|
||||
my $arch = shift;
|
||||
if ($arch eq "") {
|
||||
$arch = `uname -m`;
|
||||
chomp($arch);
|
||||
}
|
||||
|
||||
$x = "[0-9a-f]"; # hex character
|
||||
$xs = "[0-9a-f ]"; # hex character or space
|
||||
$funcre = qr/^$x* <(.*)>:$/;
|
||||
if ($arch eq 'aarch64') {
|
||||
#ffffffc0006325cc: a9bb7bfd stp x29, x30, [sp,#-80]!
|
||||
$re = qr/^.*stp.*sp,\#-([0-9]{1,8})\]\!/o;
|
||||
} elsif ($arch eq 'arm') {
|
||||
#c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64
|
||||
$re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
|
||||
} elsif ($arch eq 'avr32') {
|
||||
#8000008a: 20 1d sub sp,4
|
||||
#80000ca8: fa cd 05 b0 sub sp,sp,1456
|
||||
$re = qr/^.*sub.*sp.*,([0-9]{1,8})/o;
|
||||
} elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) {
|
||||
#c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp
|
||||
# or
|
||||
# 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
|
||||
$re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o;
|
||||
$dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o;
|
||||
} elsif ($arch eq 'ia64') {
|
||||
#e0000000044011fc: 01 0f fc 8c adds r12=-384,r12
|
||||
$re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
|
||||
} elsif ($arch eq 'm68k') {
|
||||
# 2b6c: 4e56 fb70 linkw %fp,#-1168
|
||||
# 1df770: defc ffe4 addaw #-28,%sp
|
||||
$re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o;
|
||||
} elsif ($arch eq '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;
|
||||
} elsif ($arch eq 'mips') {
|
||||
#88003254: 27bdffe0 addiu sp,sp,-32
|
||||
$re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
|
||||
} elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
|
||||
$re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
|
||||
} elsif ($arch eq 'ppc') {
|
||||
#c00029f4: 94 21 ff 30 stwu r1,-208(r1)
|
||||
$re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
|
||||
} elsif ($arch eq 'ppc64') {
|
||||
#XXX
|
||||
$re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
|
||||
} elsif ($arch eq 'powerpc') {
|
||||
$re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
|
||||
} elsif ($arch =~ /^s390x?$/) {
|
||||
# 11160: a7 fb ff 60 aghi %r15,-160
|
||||
# or
|
||||
# 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15)
|
||||
$re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
|
||||
(?:\(\%r15\))?$/ox;
|
||||
} elsif ($arch =~ /^sh64$/) {
|
||||
#XXX: we only check for the immediate case presently,
|
||||
# though we will want to check for the movi/sub
|
||||
# pair for larger users. -- PFM.
|
||||
#a00048e0: d4fc40f0 addi.l r15,-240,r15
|
||||
$re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
|
||||
} elsif ($arch =~ /^blackfin$/) {
|
||||
# 0: 00 e8 38 01 LINK 0x4e0;
|
||||
$re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o;
|
||||
} elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
|
||||
# f0019d10: 9d e3 bf 90 save %sp, -112, %sp
|
||||
$re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
|
||||
} else {
|
||||
print("wrong or unknown architecture \"$arch\"\n");
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# main()
|
||||
#
|
||||
my ($func, $file, $lastslash);
|
||||
|
||||
while (my $line = <STDIN>) {
|
||||
if ($line =~ m/$funcre/) {
|
||||
$func = $1;
|
||||
}
|
||||
elsif ($line =~ m/(.*):\s*file format/) {
|
||||
$file = $1;
|
||||
$file =~ s/\.ko//;
|
||||
$lastslash = rindex($file, "/");
|
||||
if ($lastslash != -1) {
|
||||
$file = substr($file, $lastslash + 1);
|
||||
}
|
||||
}
|
||||
elsif ($line =~ m/$re/) {
|
||||
my $size = $1;
|
||||
$size = hex($size) if ($size =~ /^0x/);
|
||||
|
||||
if ($size > 0xf0000000) {
|
||||
$size = - $size;
|
||||
$size += 0x80000000;
|
||||
$size += 0x80000000;
|
||||
}
|
||||
next if ($size > 0x10000000);
|
||||
|
||||
next if $line !~ m/^($xs*)/;
|
||||
my $addr = $1;
|
||||
$addr =~ s/ /0/g;
|
||||
$addr = "0x$addr";
|
||||
|
||||
my $intro = "$addr $func [$file]:";
|
||||
my $padlen = 56 - length($intro);
|
||||
while ($padlen > 0) {
|
||||
$intro .= ' ';
|
||||
$padlen -= 8;
|
||||
}
|
||||
next if ($size < 100);
|
||||
push @stack, "$intro$size\n";
|
||||
}
|
||||
elsif (defined $dre && $line =~ m/$dre/) {
|
||||
my $size = "Dynamic ($1)";
|
||||
|
||||
next if $line !~ m/^($xs*)/;
|
||||
my $addr = $1;
|
||||
$addr =~ s/ /0/g;
|
||||
$addr = "0x$addr";
|
||||
|
||||
my $intro = "$addr $func [$file]:";
|
||||
my $padlen = 56 - length($intro);
|
||||
while ($padlen > 0) {
|
||||
$intro .= ' ';
|
||||
$padlen -= 8;
|
||||
}
|
||||
push @stack, "$intro$size\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Sort output by size (last field)
|
||||
print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;
|
216
scripts/checksyscalls.sh
Executable file
216
scripts/checksyscalls.sh
Executable file
|
@ -0,0 +1,216 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Check if current architecture are missing any function calls compared
|
||||
# to i386.
|
||||
# i386 define a number of legacy system calls that are i386 specific
|
||||
# and listed below so they are ignored.
|
||||
#
|
||||
# Usage:
|
||||
# checksyscalls.sh gcc gcc-options
|
||||
#
|
||||
|
||||
ignore_list() {
|
||||
cat << EOF
|
||||
#include <asm/types.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/* *at */
|
||||
#define __IGNORE_open /* openat */
|
||||
#define __IGNORE_link /* linkat */
|
||||
#define __IGNORE_unlink /* unlinkat */
|
||||
#define __IGNORE_mknod /* mknodat */
|
||||
#define __IGNORE_chmod /* fchmodat */
|
||||
#define __IGNORE_chown /* fchownat */
|
||||
#define __IGNORE_mkdir /* mkdirat */
|
||||
#define __IGNORE_rmdir /* unlinkat */
|
||||
#define __IGNORE_lchown /* fchownat */
|
||||
#define __IGNORE_access /* faccessat */
|
||||
#define __IGNORE_rename /* renameat2 */
|
||||
#define __IGNORE_readlink /* readlinkat */
|
||||
#define __IGNORE_symlink /* symlinkat */
|
||||
#define __IGNORE_utimes /* futimesat */
|
||||
#if BITS_PER_LONG == 64
|
||||
#define __IGNORE_stat /* fstatat */
|
||||
#define __IGNORE_lstat /* fstatat */
|
||||
#else
|
||||
#define __IGNORE_stat64 /* fstatat64 */
|
||||
#define __IGNORE_lstat64 /* fstatat64 */
|
||||
#endif
|
||||
|
||||
/* Missing flags argument */
|
||||
#define __IGNORE_renameat /* renameat2 */
|
||||
|
||||
/* CLOEXEC flag */
|
||||
#define __IGNORE_pipe /* pipe2 */
|
||||
#define __IGNORE_dup2 /* dup3 */
|
||||
#define __IGNORE_epoll_create /* epoll_create1 */
|
||||
#define __IGNORE_inotify_init /* inotify_init1 */
|
||||
#define __IGNORE_eventfd /* eventfd2 */
|
||||
#define __IGNORE_signalfd /* signalfd4 */
|
||||
|
||||
/* MMU */
|
||||
#ifndef CONFIG_MMU
|
||||
#define __IGNORE_madvise
|
||||
#define __IGNORE_mbind
|
||||
#define __IGNORE_mincore
|
||||
#define __IGNORE_mlock
|
||||
#define __IGNORE_mlockall
|
||||
#define __IGNORE_munlock
|
||||
#define __IGNORE_munlockall
|
||||
#define __IGNORE_mprotect
|
||||
#define __IGNORE_msync
|
||||
#define __IGNORE_migrate_pages
|
||||
#define __IGNORE_move_pages
|
||||
#define __IGNORE_remap_file_pages
|
||||
#define __IGNORE_get_mempolicy
|
||||
#define __IGNORE_set_mempolicy
|
||||
#define __IGNORE_swapoff
|
||||
#define __IGNORE_swapon
|
||||
#endif
|
||||
|
||||
/* System calls for 32-bit kernels only */
|
||||
#if BITS_PER_LONG == 64
|
||||
#define __IGNORE_sendfile64
|
||||
#define __IGNORE_ftruncate64
|
||||
#define __IGNORE_truncate64
|
||||
#define __IGNORE_stat64
|
||||
#define __IGNORE_lstat64
|
||||
#define __IGNORE_fstat64
|
||||
#define __IGNORE_fcntl64
|
||||
#define __IGNORE_fadvise64_64
|
||||
#define __IGNORE_fstatat64
|
||||
#define __IGNORE_fstatfs64
|
||||
#define __IGNORE_statfs64
|
||||
#define __IGNORE_llseek
|
||||
#define __IGNORE_mmap2
|
||||
#else
|
||||
#define __IGNORE_sendfile
|
||||
#define __IGNORE_ftruncate
|
||||
#define __IGNORE_truncate
|
||||
#define __IGNORE_stat
|
||||
#define __IGNORE_lstat
|
||||
#define __IGNORE_fstat
|
||||
#define __IGNORE_fcntl
|
||||
#define __IGNORE_fadvise64
|
||||
#define __IGNORE_newfstatat
|
||||
#define __IGNORE_fstatfs
|
||||
#define __IGNORE_statfs
|
||||
#define __IGNORE_lseek
|
||||
#define __IGNORE_mmap
|
||||
#endif
|
||||
|
||||
/* i386-specific or historical system calls */
|
||||
#define __IGNORE_break
|
||||
#define __IGNORE_stty
|
||||
#define __IGNORE_gtty
|
||||
#define __IGNORE_ftime
|
||||
#define __IGNORE_prof
|
||||
#define __IGNORE_lock
|
||||
#define __IGNORE_mpx
|
||||
#define __IGNORE_ulimit
|
||||
#define __IGNORE_profil
|
||||
#define __IGNORE_ioperm
|
||||
#define __IGNORE_iopl
|
||||
#define __IGNORE_idle
|
||||
#define __IGNORE_modify_ldt
|
||||
#define __IGNORE_ugetrlimit
|
||||
#define __IGNORE_vm86
|
||||
#define __IGNORE_vm86old
|
||||
#define __IGNORE_set_thread_area
|
||||
#define __IGNORE_get_thread_area
|
||||
#define __IGNORE_madvise1
|
||||
#define __IGNORE_oldstat
|
||||
#define __IGNORE_oldfstat
|
||||
#define __IGNORE_oldlstat
|
||||
#define __IGNORE_oldolduname
|
||||
#define __IGNORE_olduname
|
||||
#define __IGNORE_umount
|
||||
#define __IGNORE_waitpid
|
||||
#define __IGNORE_stime
|
||||
#define __IGNORE_nice
|
||||
#define __IGNORE_signal
|
||||
#define __IGNORE_sigaction
|
||||
#define __IGNORE_sgetmask
|
||||
#define __IGNORE_sigsuspend
|
||||
#define __IGNORE_sigpending
|
||||
#define __IGNORE_ssetmask
|
||||
#define __IGNORE_readdir
|
||||
#define __IGNORE_socketcall
|
||||
#define __IGNORE_ipc
|
||||
#define __IGNORE_sigreturn
|
||||
#define __IGNORE_sigprocmask
|
||||
#define __IGNORE_bdflush
|
||||
#define __IGNORE__llseek
|
||||
#define __IGNORE__newselect
|
||||
#define __IGNORE_create_module
|
||||
#define __IGNORE_query_module
|
||||
#define __IGNORE_get_kernel_syms
|
||||
#define __IGNORE_sysfs
|
||||
#define __IGNORE_uselib
|
||||
#define __IGNORE__sysctl
|
||||
|
||||
/* ... including the "new" 32-bit uid syscalls */
|
||||
#define __IGNORE_lchown32
|
||||
#define __IGNORE_getuid32
|
||||
#define __IGNORE_getgid32
|
||||
#define __IGNORE_geteuid32
|
||||
#define __IGNORE_getegid32
|
||||
#define __IGNORE_setreuid32
|
||||
#define __IGNORE_setregid32
|
||||
#define __IGNORE_getgroups32
|
||||
#define __IGNORE_setgroups32
|
||||
#define __IGNORE_fchown32
|
||||
#define __IGNORE_setresuid32
|
||||
#define __IGNORE_getresuid32
|
||||
#define __IGNORE_setresgid32
|
||||
#define __IGNORE_getresgid32
|
||||
#define __IGNORE_chown32
|
||||
#define __IGNORE_setuid32
|
||||
#define __IGNORE_setgid32
|
||||
#define __IGNORE_setfsuid32
|
||||
#define __IGNORE_setfsgid32
|
||||
|
||||
/* these can be expressed using other calls */
|
||||
#define __IGNORE_alarm /* setitimer */
|
||||
#define __IGNORE_creat /* open */
|
||||
#define __IGNORE_fork /* clone */
|
||||
#define __IGNORE_futimesat /* utimensat */
|
||||
#define __IGNORE_getpgrp /* getpgid */
|
||||
#define __IGNORE_getdents /* getdents64 */
|
||||
#define __IGNORE_pause /* sigsuspend */
|
||||
#define __IGNORE_poll /* ppoll */
|
||||
#define __IGNORE_select /* pselect6 */
|
||||
#define __IGNORE_epoll_wait /* epoll_pwait */
|
||||
#define __IGNORE_time /* gettimeofday */
|
||||
#define __IGNORE_uname /* newuname */
|
||||
#define __IGNORE_ustat /* statfs */
|
||||
#define __IGNORE_utime /* utimes */
|
||||
#define __IGNORE_vfork /* clone */
|
||||
|
||||
/* sync_file_range had a stupid ABI. Allow sync_file_range2 instead */
|
||||
#ifdef __NR_sync_file_range2
|
||||
#define __IGNORE_sync_file_range
|
||||
#endif
|
||||
|
||||
/* Unmerged syscalls for AFS, STREAMS, etc. */
|
||||
#define __IGNORE_afs_syscall
|
||||
#define __IGNORE_getpmsg
|
||||
#define __IGNORE_putpmsg
|
||||
#define __IGNORE_vserver
|
||||
EOF
|
||||
}
|
||||
|
||||
syscall_list() {
|
||||
grep '^[0-9]' "$1" | sort -n | (
|
||||
while read nr abi name entry ; do
|
||||
cat <<EOF
|
||||
#if !defined(__NR_${name}) && !defined(__IGNORE_${name})
|
||||
#warning syscall ${name} not implemented
|
||||
#endif
|
||||
EOF
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
(ignore_list && syscall_list $(dirname $0)/../arch/x86/syscalls/syscall_32.tbl) | \
|
||||
$* -E -x c - > /dev/null
|
71
scripts/checkversion.pl
Executable file
71
scripts/checkversion.pl
Executable file
|
@ -0,0 +1,71 @@
|
|||
#! /usr/bin/perl
|
||||
#
|
||||
# checkversion find uses of LINUX_VERSION_CODE or KERNEL_VERSION
|
||||
# without including <linux/version.h>, or cases of
|
||||
# including <linux/version.h> that don't need it.
|
||||
# Copyright (C) 2003, Randy Dunlap <rdunlap@xenotime.net>
|
||||
|
||||
use strict;
|
||||
|
||||
$| = 1;
|
||||
|
||||
my $debugging;
|
||||
|
||||
foreach my $file (@ARGV) {
|
||||
next if $file =~ "include/linux/version\.h";
|
||||
# Open this file.
|
||||
open( my $f, '<', $file )
|
||||
or die "Can't open $file: $!\n";
|
||||
|
||||
# Initialize variables.
|
||||
my ($fInComment, $fInString, $fUseVersion);
|
||||
my $iLinuxVersion = 0;
|
||||
|
||||
while (<$f>) {
|
||||
# Strip comments.
|
||||
$fInComment && (s+^.*?\*/+ +o ? ($fInComment = 0) : next);
|
||||
m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1)));
|
||||
|
||||
# Pick up definitions.
|
||||
if ( m/^\s*#/o ) {
|
||||
$iLinuxVersion = $. if m/^\s*#\s*include\s*"linux\/version\.h"/o;
|
||||
}
|
||||
|
||||
# Strip strings.
|
||||
$fInString && (s+^.*?"+ +o ? ($fInString = 0) : next);
|
||||
m+"+o && (s+".*?"+ +go, (s+".*$+ +o && ($fInString = 1)));
|
||||
|
||||
# Pick up definitions.
|
||||
if ( m/^\s*#/o ) {
|
||||
$iLinuxVersion = $. if m/^\s*#\s*include\s*<linux\/version\.h>/o;
|
||||
}
|
||||
|
||||
# Look for uses: LINUX_VERSION_CODE, KERNEL_VERSION, UTS_RELEASE
|
||||
if (($_ =~ /LINUX_VERSION_CODE/) || ($_ =~ /\WKERNEL_VERSION/)) {
|
||||
$fUseVersion = 1;
|
||||
last if $iLinuxVersion;
|
||||
}
|
||||
}
|
||||
|
||||
# Report used version IDs without include?
|
||||
if ($fUseVersion && ! $iLinuxVersion) {
|
||||
print "$file: $.: need linux/version.h\n";
|
||||
}
|
||||
|
||||
# Report superfluous includes.
|
||||
if ($iLinuxVersion && ! $fUseVersion) {
|
||||
print "$file: $iLinuxVersion linux/version.h not needed.\n";
|
||||
}
|
||||
|
||||
# debug: report OK results:
|
||||
if ($debugging) {
|
||||
if ($iLinuxVersion && $fUseVersion) {
|
||||
print "$file: version use is OK ($iLinuxVersion)\n";
|
||||
}
|
||||
if (! $iLinuxVersion && ! $fUseVersion) {
|
||||
print "$file: version use is OK (none)\n";
|
||||
}
|
||||
}
|
||||
|
||||
close($f);
|
||||
}
|
176
scripts/cleanfile
Executable file
176
scripts/cleanfile
Executable file
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Clean a text file -- or directory of text files -- of stealth whitespace.
|
||||
# WARNING: this can be a highly destructive operation. Use with caution.
|
||||
#
|
||||
|
||||
use bytes;
|
||||
use File::Basename;
|
||||
|
||||
# Default options
|
||||
$max_width = 79;
|
||||
|
||||
# Clean up space-tab sequences, either by removing spaces or
|
||||
# replacing them with tabs.
|
||||
sub clean_space_tabs($)
|
||||
{
|
||||
no bytes; # Tab alignment depends on characters
|
||||
|
||||
my($li) = @_;
|
||||
my($lo) = '';
|
||||
my $pos = 0;
|
||||
my $nsp = 0;
|
||||
my($i, $c);
|
||||
|
||||
for ($i = 0; $i < length($li); $i++) {
|
||||
$c = substr($li, $i, 1);
|
||||
if ($c eq "\t") {
|
||||
my $npos = ($pos+$nsp+8) & ~7;
|
||||
my $ntab = ($npos >> 3) - ($pos >> 3);
|
||||
$lo .= "\t" x $ntab;
|
||||
$pos = $npos;
|
||||
$nsp = 0;
|
||||
} elsif ($c eq "\n" || $c eq "\r") {
|
||||
$lo .= " " x $nsp;
|
||||
$pos += $nsp;
|
||||
$nsp = 0;
|
||||
$lo .= $c;
|
||||
$pos = 0;
|
||||
} elsif ($c eq " ") {
|
||||
$nsp++;
|
||||
} else {
|
||||
$lo .= " " x $nsp;
|
||||
$pos += $nsp;
|
||||
$nsp = 0;
|
||||
$lo .= $c;
|
||||
$pos++;
|
||||
}
|
||||
}
|
||||
$lo .= " " x $nsp;
|
||||
return $lo;
|
||||
}
|
||||
|
||||
# Compute the visual width of a string
|
||||
sub strwidth($) {
|
||||
no bytes; # Tab alignment depends on characters
|
||||
|
||||
my($li) = @_;
|
||||
my($c, $i);
|
||||
my $pos = 0;
|
||||
my $mlen = 0;
|
||||
|
||||
for ($i = 0; $i < length($li); $i++) {
|
||||
$c = substr($li,$i,1);
|
||||
if ($c eq "\t") {
|
||||
$pos = ($pos+8) & ~7;
|
||||
} elsif ($c eq "\n") {
|
||||
$mlen = $pos if ($pos > $mlen);
|
||||
$pos = 0;
|
||||
} else {
|
||||
$pos++;
|
||||
}
|
||||
}
|
||||
|
||||
$mlen = $pos if ($pos > $mlen);
|
||||
return $mlen;
|
||||
}
|
||||
|
||||
$name = basename($0);
|
||||
|
||||
@files = ();
|
||||
|
||||
while (defined($a = shift(@ARGV))) {
|
||||
if ($a =~ /^-/) {
|
||||
if ($a eq '-width' || $a eq '-w') {
|
||||
$max_width = shift(@ARGV)+0;
|
||||
} else {
|
||||
print STDERR "Usage: $name [-width #] files...\n";
|
||||
exit 1;
|
||||
}
|
||||
} else {
|
||||
push(@files, $a);
|
||||
}
|
||||
}
|
||||
|
||||
foreach $f ( @files ) {
|
||||
print STDERR "$name: $f\n";
|
||||
|
||||
if (! -f $f) {
|
||||
print STDERR "$f: not a file\n";
|
||||
next;
|
||||
}
|
||||
|
||||
if (!open(FILE, '+<', $f)) {
|
||||
print STDERR "$name: Cannot open file: $f: $!\n";
|
||||
next;
|
||||
}
|
||||
|
||||
binmode FILE;
|
||||
|
||||
# First, verify that it is not a binary file; consider any file
|
||||
# with a zero byte to be a binary file. Is there any better, or
|
||||
# additional, heuristic that should be applied?
|
||||
$is_binary = 0;
|
||||
|
||||
while (read(FILE, $data, 65536) > 0) {
|
||||
if ($data =~ /\0/) {
|
||||
$is_binary = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_binary) {
|
||||
print STDERR "$name: $f: binary file\n";
|
||||
next;
|
||||
}
|
||||
|
||||
seek(FILE, 0, 0);
|
||||
|
||||
$in_bytes = 0;
|
||||
$out_bytes = 0;
|
||||
$blank_bytes = 0;
|
||||
|
||||
@blanks = ();
|
||||
@lines = ();
|
||||
$lineno = 0;
|
||||
|
||||
while ( defined($line = <FILE>) ) {
|
||||
$lineno++;
|
||||
$in_bytes += length($line);
|
||||
$line =~ s/[ \t\r]*$//; # Remove trailing spaces
|
||||
$line = clean_space_tabs($line);
|
||||
|
||||
if ( $line eq "\n" ) {
|
||||
push(@blanks, $line);
|
||||
$blank_bytes += length($line);
|
||||
} else {
|
||||
push(@lines, @blanks);
|
||||
$out_bytes += $blank_bytes;
|
||||
push(@lines, $line);
|
||||
$out_bytes += length($line);
|
||||
@blanks = ();
|
||||
$blank_bytes = 0;
|
||||
}
|
||||
|
||||
$l_width = strwidth($line);
|
||||
if ($max_width && $l_width > $max_width) {
|
||||
print STDERR
|
||||
"$f:$lineno: line exceeds $max_width characters ($l_width)\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Any blanks at the end of the file are discarded
|
||||
|
||||
if ($in_bytes != $out_bytes) {
|
||||
# Only write to the file if changed
|
||||
seek(FILE, 0, 0);
|
||||
print FILE @lines;
|
||||
|
||||
if ( !defined($where = tell(FILE)) ||
|
||||
!truncate(FILE, $where) ) {
|
||||
die "$name: Failed to truncate modified file: $f: $!\n";
|
||||
}
|
||||
}
|
||||
|
||||
close(FILE);
|
||||
}
|
258
scripts/cleanpatch
Executable file
258
scripts/cleanpatch
Executable file
|
@ -0,0 +1,258 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Clean a patch file -- or directory of patch files -- of stealth whitespace.
|
||||
# WARNING: this can be a highly destructive operation. Use with caution.
|
||||
#
|
||||
|
||||
use bytes;
|
||||
use File::Basename;
|
||||
|
||||
# Default options
|
||||
$max_width = 79;
|
||||
|
||||
# Clean up space-tab sequences, either by removing spaces or
|
||||
# replacing them with tabs.
|
||||
sub clean_space_tabs($)
|
||||
{
|
||||
no bytes; # Tab alignment depends on characters
|
||||
|
||||
my($li) = @_;
|
||||
my($lo) = '';
|
||||
my $pos = 0;
|
||||
my $nsp = 0;
|
||||
my($i, $c);
|
||||
|
||||
for ($i = 0; $i < length($li); $i++) {
|
||||
$c = substr($li, $i, 1);
|
||||
if ($c eq "\t") {
|
||||
my $npos = ($pos+$nsp+8) & ~7;
|
||||
my $ntab = ($npos >> 3) - ($pos >> 3);
|
||||
$lo .= "\t" x $ntab;
|
||||
$pos = $npos;
|
||||
$nsp = 0;
|
||||
} elsif ($c eq "\n" || $c eq "\r") {
|
||||
$lo .= " " x $nsp;
|
||||
$pos += $nsp;
|
||||
$nsp = 0;
|
||||
$lo .= $c;
|
||||
$pos = 0;
|
||||
} elsif ($c eq " ") {
|
||||
$nsp++;
|
||||
} else {
|
||||
$lo .= " " x $nsp;
|
||||
$pos += $nsp;
|
||||
$nsp = 0;
|
||||
$lo .= $c;
|
||||
$pos++;
|
||||
}
|
||||
}
|
||||
$lo .= " " x $nsp;
|
||||
return $lo;
|
||||
}
|
||||
|
||||
# Compute the visual width of a string
|
||||
sub strwidth($) {
|
||||
no bytes; # Tab alignment depends on characters
|
||||
|
||||
my($li) = @_;
|
||||
my($c, $i);
|
||||
my $pos = 0;
|
||||
my $mlen = 0;
|
||||
|
||||
for ($i = 0; $i < length($li); $i++) {
|
||||
$c = substr($li,$i,1);
|
||||
if ($c eq "\t") {
|
||||
$pos = ($pos+8) & ~7;
|
||||
} elsif ($c eq "\n") {
|
||||
$mlen = $pos if ($pos > $mlen);
|
||||
$pos = 0;
|
||||
} else {
|
||||
$pos++;
|
||||
}
|
||||
}
|
||||
|
||||
$mlen = $pos if ($pos > $mlen);
|
||||
return $mlen;
|
||||
}
|
||||
|
||||
$name = basename($0);
|
||||
|
||||
@files = ();
|
||||
|
||||
while (defined($a = shift(@ARGV))) {
|
||||
if ($a =~ /^-/) {
|
||||
if ($a eq '-width' || $a eq '-w') {
|
||||
$max_width = shift(@ARGV)+0;
|
||||
} else {
|
||||
print STDERR "Usage: $name [-width #] files...\n";
|
||||
exit 1;
|
||||
}
|
||||
} else {
|
||||
push(@files, $a);
|
||||
}
|
||||
}
|
||||
|
||||
foreach $f ( @files ) {
|
||||
print STDERR "$name: $f\n";
|
||||
|
||||
if (! -f $f) {
|
||||
print STDERR "$f: not a file\n";
|
||||
next;
|
||||
}
|
||||
|
||||
if (!open(FILE, '+<', $f)) {
|
||||
print STDERR "$name: Cannot open file: $f: $!\n";
|
||||
next;
|
||||
}
|
||||
|
||||
binmode FILE;
|
||||
|
||||
# First, verify that it is not a binary file; consider any file
|
||||
# with a zero byte to be a binary file. Is there any better, or
|
||||
# additional, heuristic that should be applied?
|
||||
$is_binary = 0;
|
||||
|
||||
while (read(FILE, $data, 65536) > 0) {
|
||||
if ($data =~ /\0/) {
|
||||
$is_binary = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_binary) {
|
||||
print STDERR "$name: $f: binary file\n";
|
||||
next;
|
||||
}
|
||||
|
||||
seek(FILE, 0, 0);
|
||||
|
||||
$in_bytes = 0;
|
||||
$out_bytes = 0;
|
||||
$lineno = 0;
|
||||
|
||||
@lines = ();
|
||||
|
||||
$in_hunk = 0;
|
||||
$err = 0;
|
||||
|
||||
while ( defined($line = <FILE>) ) {
|
||||
$lineno++;
|
||||
$in_bytes += length($line);
|
||||
|
||||
if (!$in_hunk) {
|
||||
if ($line =~
|
||||
/^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
|
||||
$minus_lines = $2;
|
||||
$plus_lines = $4;
|
||||
if ($minus_lines || $plus_lines) {
|
||||
$in_hunk = 1;
|
||||
@hunk_lines = ($line);
|
||||
}
|
||||
} else {
|
||||
push(@lines, $line);
|
||||
$out_bytes += length($line);
|
||||
}
|
||||
} else {
|
||||
# We're in a hunk
|
||||
|
||||
if ($line =~ /^\+/) {
|
||||
$plus_lines--;
|
||||
|
||||
$text = substr($line, 1);
|
||||
$text =~ s/[ \t\r]*$//; # Remove trailing spaces
|
||||
$text = clean_space_tabs($text);
|
||||
|
||||
$l_width = strwidth($text);
|
||||
if ($max_width && $l_width > $max_width) {
|
||||
print STDERR
|
||||
"$f:$lineno: adds line exceeds $max_width ",
|
||||
"characters ($l_width)\n";
|
||||
}
|
||||
|
||||
push(@hunk_lines, '+'.$text);
|
||||
} elsif ($line =~ /^\-/) {
|
||||
$minus_lines--;
|
||||
push(@hunk_lines, $line);
|
||||
} elsif ($line =~ /^ /) {
|
||||
$plus_lines--;
|
||||
$minus_lines--;
|
||||
push(@hunk_lines, $line);
|
||||
} else {
|
||||
print STDERR "$name: $f: malformed patch\n";
|
||||
$err = 1;
|
||||
last;
|
||||
}
|
||||
|
||||
if ($plus_lines < 0 || $minus_lines < 0) {
|
||||
print STDERR "$name: $f: malformed patch\n";
|
||||
$err = 1;
|
||||
last;
|
||||
} elsif ($plus_lines == 0 && $minus_lines == 0) {
|
||||
# End of a hunk. Process this hunk.
|
||||
my $i;
|
||||
my $l;
|
||||
my @h = ();
|
||||
my $adj = 0;
|
||||
my $done = 0;
|
||||
|
||||
for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
|
||||
$l = $hunk_lines[$i];
|
||||
if (!$done && $l eq "+\n") {
|
||||
$adj++; # Skip this line
|
||||
} elsif ($l =~ /^[ +]/) {
|
||||
$done = 1;
|
||||
unshift(@h, $l);
|
||||
} else {
|
||||
unshift(@h, $l);
|
||||
}
|
||||
}
|
||||
|
||||
$l = $hunk_lines[0]; # Hunk header
|
||||
undef @hunk_lines; # Free memory
|
||||
|
||||
if ($adj) {
|
||||
die unless
|
||||
($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
|
||||
my $mstart = $1;
|
||||
my $mlin = $2;
|
||||
my $pstart = $3;
|
||||
my $plin = $4;
|
||||
my $tail = $5; # doesn't include the final newline
|
||||
|
||||
$l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
|
||||
$mstart, $mlin, $pstart, $plin-$adj,
|
||||
$tail);
|
||||
}
|
||||
unshift(@h, $l);
|
||||
|
||||
# Transfer to the output array
|
||||
foreach $l (@h) {
|
||||
$out_bytes += length($l);
|
||||
push(@lines, $l);
|
||||
}
|
||||
|
||||
$in_hunk = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($in_hunk) {
|
||||
print STDERR "$name: $f: malformed patch\n";
|
||||
$err = 1;
|
||||
}
|
||||
|
||||
if (!$err) {
|
||||
if ($in_bytes != $out_bytes) {
|
||||
# Only write to the file if changed
|
||||
seek(FILE, 0, 0);
|
||||
print FILE @lines;
|
||||
|
||||
if ( !defined($where = tell(FILE)) ||
|
||||
!truncate(FILE, $where) ) {
|
||||
die "$name: Failed to truncate modified file: $f: $!\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(FILE);
|
||||
}
|
179
scripts/coccicheck
Executable file
179
scripts/coccicheck
Executable file
|
@ -0,0 +1,179 @@
|
|||
#!/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
|
||||
|
||||
# Take only the last argument, which is the C file to test
|
||||
shift $(( $# - 1 ))
|
||||
OPTIONS="$COCCIINCLUDE $1"
|
||||
else
|
||||
ONLINE=0
|
||||
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
||||
OPTIONS="--dir $srctree $COCCIINCLUDE"
|
||||
else
|
||||
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
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "" ] ; then
|
||||
if [ "$ONLINE" = "0" ] ; then
|
||||
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
|
||||
elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
|
||||
FLAGS="$FLAGS --no-show-diff"
|
||||
fi
|
||||
|
||||
if [ "$ONLINE" = "0" ] ; then
|
||||
echo ''
|
||||
echo 'Please check for false positives in the output before submitting a patch.'
|
||||
echo 'When using "patch" mode, carefully review the patch before submitting it.'
|
||||
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.
|
||||
#
|
||||
# $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
|
||||
|
||||
if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then
|
||||
|
||||
FILE=`echo $COCCI | sed "s|$srctree/||"`
|
||||
|
||||
echo "Processing `basename $COCCI`"
|
||||
echo "with option(s) \"$OPT\""
|
||||
echo ''
|
||||
echo 'Message example to submit a patch:'
|
||||
|
||||
sed -ne 's|^///||p' $COCCI
|
||||
|
||||
if [ "$MODE" = "patch" ] ; then
|
||||
echo ' The semantic patch that makes this change is available'
|
||||
elif [ "$MODE" = "report" ] ; then
|
||||
echo ' The semantic patch that makes this report is available'
|
||||
elif [ "$MODE" = "context" ] ; then
|
||||
echo ' The semantic patch that spots this code is available'
|
||||
elif [ "$MODE" = "org" ] ; then
|
||||
echo ' The semantic patch that makes this Org report is available'
|
||||
else
|
||||
echo ' The semantic patch that makes this output is available'
|
||||
fi
|
||||
echo " in $FILE."
|
||||
echo ''
|
||||
echo ' More information about semantic patching is available at'
|
||||
echo ' http://coccinelle.lip6.fr/'
|
||||
echo ''
|
||||
|
||||
if [ "`sed -ne 's|^//#||p' $COCCI`" ] ; then
|
||||
echo 'Semantic patch information:'
|
||||
sed -ne 's|^//#||p' $COCCI
|
||||
echo ''
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$MODE" = "chain" ] ; then
|
||||
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
|
||||
run_cmd $SPATCH -D $MODE $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
if [ "$COCCI" = "" ] ; then
|
||||
for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
|
||||
coccinelle $f
|
||||
done
|
||||
else
|
||||
coccinelle $COCCI
|
||||
fi
|
72
scripts/coccinelle/api/alloc/alloc_cast.cocci
Normal file
72
scripts/coccinelle/api/alloc/alloc_cast.cocci
Normal file
|
@ -0,0 +1,72 @@
|
|||
/// Remove casting the values returned by memory allocation functions
|
||||
/// like kmalloc, kzalloc, kmem_cache_alloc, kmem_cache_zalloc etc.
|
||||
///
|
||||
//# This makes an effort to find cases of casting of values returned by
|
||||
//# kmalloc, kzalloc, kcalloc, kmem_cache_alloc, kmem_cache_zalloc,
|
||||
//# kmem_cache_alloc_node, kmalloc_node and kzalloc_node and removes
|
||||
//# the casting as it is not required. The result in the patch case may
|
||||
//#need some reformatting.
|
||||
//
|
||||
// Confidence: High
|
||||
// Copyright: 2014, Himangi Saraogi GPLv2.
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
//
|
||||
|
||||
virtual context
|
||||
virtual patch
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For context mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on context@
|
||||
type T;
|
||||
@@
|
||||
|
||||
* (T *)
|
||||
\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
|
||||
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...)
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For patch mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on patch@
|
||||
type T;
|
||||
@@
|
||||
|
||||
- (T *)
|
||||
(\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
|
||||
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...))
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For org and report mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r depends on org || report@
|
||||
type T;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(T@p *)\(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|
|
||||
kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...)
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
t << r.T;
|
||||
@@
|
||||
|
||||
coccilib.org.print_safe_todo(p[0], t)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
t << r.T;
|
||||
@@
|
||||
|
||||
msg="WARNING: casting value returned by memory allocation function to (%s *) is useless." % (t)
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
||||
|
86
scripts/coccinelle/api/alloc/kzalloc-simple.cocci
Normal file
86
scripts/coccinelle/api/alloc/kzalloc-simple.cocci
Normal file
|
@ -0,0 +1,86 @@
|
|||
///
|
||||
/// Use kzalloc rather than kmalloc followed by memset with 0
|
||||
///
|
||||
/// This considers some simple cases that are common and easy to validate
|
||||
/// Note in particular that there are no ...s in the rule, so all of the
|
||||
/// matched code has to be contiguous
|
||||
///
|
||||
// Confidence: High
|
||||
// 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
|
||||
//
|
||||
// Keywords: kmalloc, kzalloc
|
||||
// Version min: < 2.6.12 kmalloc
|
||||
// Version min: 2.6.14 kzalloc
|
||||
//
|
||||
|
||||
virtual context
|
||||
virtual patch
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For context mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on context@
|
||||
type T, T2;
|
||||
expression x;
|
||||
expression E1,E2;
|
||||
statement S;
|
||||
@@
|
||||
|
||||
* x = (T)kmalloc(E1,E2);
|
||||
if ((x==NULL) || ...) S
|
||||
* memset((T2)x,0,E1);
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For patch mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on patch@
|
||||
type T, T2;
|
||||
expression x;
|
||||
expression E1,E2;
|
||||
statement S;
|
||||
@@
|
||||
|
||||
- x = (T)kmalloc(E1,E2);
|
||||
+ x = kzalloc(E1,E2);
|
||||
if ((x==NULL) || ...) S
|
||||
- memset((T2)x,0,E1);
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For org mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r depends on org || report@
|
||||
type T, T2;
|
||||
expression x;
|
||||
expression E1,E2;
|
||||
statement S;
|
||||
position p;
|
||||
@@
|
||||
|
||||
x = (T)kmalloc@p(E1,E2);
|
||||
if ((x==NULL) || ...) S
|
||||
memset((T2)x,0,E1);
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
|
||||
msg="%s" % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
coccilib.org.print_todo(p[0], msg_safe)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
|
||||
msg="WARNING: kzalloc should be used for %s, instead of kmalloc/memset" % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
80
scripts/coccinelle/api/d_find_alias.cocci
Normal file
80
scripts/coccinelle/api/d_find_alias.cocci
Normal file
|
@ -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))
|
56
scripts/coccinelle/api/err_cast.cocci
Normal file
56
scripts/coccinelle/api/err_cast.cocci
Normal file
|
@ -0,0 +1,56 @@
|
|||
///
|
||||
/// Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...))
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2009, 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Options:
|
||||
//
|
||||
// Keywords: ERR_PTR, PTR_ERR, ERR_CAST
|
||||
// Version min: 2.6.25
|
||||
//
|
||||
|
||||
virtual context
|
||||
virtual patch
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
|
||||
@ depends on context && !patch && !org && !report@
|
||||
expression x;
|
||||
@@
|
||||
|
||||
* ERR_PTR(PTR_ERR(x))
|
||||
|
||||
@ depends on !context && patch && !org && !report @
|
||||
expression x;
|
||||
@@
|
||||
|
||||
- ERR_PTR(PTR_ERR(x))
|
||||
+ ERR_CAST(x)
|
||||
|
||||
@r depends on !context && !patch && (org || report)@
|
||||
expression x;
|
||||
position p;
|
||||
@@
|
||||
|
||||
ERR_PTR@p(PTR_ERR(x))
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
|
||||
msg="WARNING ERR_CAST can be used with %s" % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
coccilib.org.print_todo(p[0], msg_safe)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
x << r.x;
|
||||
@@
|
||||
|
||||
msg="WARNING: ERR_CAST can be used with %s" % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
104
scripts/coccinelle/api/kstrdup.cocci
Normal file
104
scripts/coccinelle/api/kstrdup.cocci
Normal file
|
@ -0,0 +1,104 @@
|
|||
/// Use kstrdup rather than duplicating its implementation
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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
|
||||
|
||||
@depends on patch@
|
||||
expression from,to;
|
||||
expression flag,E1,E2;
|
||||
statement S;
|
||||
@@
|
||||
|
||||
- to = kmalloc(strlen(from) + 1,flag);
|
||||
+ to = kstrdup(from, flag);
|
||||
... when != \(from = E1 \| to = E1 \)
|
||||
if (to==NULL || ...) S
|
||||
... when != \(from = E2 \| to = E2 \)
|
||||
- strcpy(to, from);
|
||||
|
||||
@depends on patch@
|
||||
expression x,from,to;
|
||||
expression flag,E1,E2,E3;
|
||||
statement S;
|
||||
@@
|
||||
|
||||
- x = strlen(from) + 1;
|
||||
... when != \( x = E1 \| from = E1 \)
|
||||
- to = \(kmalloc\|kzalloc\)(x,flag);
|
||||
+ to = kstrdup(from, flag);
|
||||
... when != \(x = E2 \| from = E2 \| to = E2 \)
|
||||
if (to==NULL || ...) S
|
||||
... when != \(x = E3 \| from = E3 \| to = E3 \)
|
||||
- memcpy(to, from, x);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@r1 depends on !patch exists@
|
||||
expression from,to;
|
||||
expression flag,E1,E2;
|
||||
statement S;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
* to = kmalloc@p1(strlen(from) + 1,flag);
|
||||
... when != \(from = E1 \| to = E1 \)
|
||||
if (to==NULL || ...) S
|
||||
... when != \(from = E2 \| to = E2 \)
|
||||
* strcpy@p2(to, from);
|
||||
|
||||
@r2 depends on !patch exists@
|
||||
expression x,from,to;
|
||||
expression flag,E1,E2,E3;
|
||||
statement S;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
* x = strlen(from) + 1;
|
||||
... when != \( x = E1 \| from = E1 \)
|
||||
* to = \(kmalloc@p1\|kzalloc@p2\)(x,flag);
|
||||
... when != \(x = E2 \| from = E2 \| to = E2 \)
|
||||
if (to==NULL || ...) S
|
||||
... when != \(x = E3 \| from = E3 \| to = E3 \)
|
||||
* memcpy@p2(to, from, x);
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r1.p1;
|
||||
p2 << r1.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("WARNING opportunity for kstrdep",p1)
|
||||
cocci.print_secs("strcpy",p2)
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r2.p1;
|
||||
p2 << r2.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("WARNING opportunity for kstrdep",p1)
|
||||
cocci.print_secs("memcpy",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r1.p1;
|
||||
p2 << r1.p2;
|
||||
@@
|
||||
|
||||
msg = "WARNING opportunity for kstrdep (strcpy on line %s)" % (p2[0].line)
|
||||
coccilib.report.print_report(p1[0], msg)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r2.p1;
|
||||
p2 << r2.p2;
|
||||
@@
|
||||
|
||||
msg = "WARNING opportunity for kstrdep (memcpy on line %s)" % (p2[0].line)
|
||||
coccilib.report.print_report(p1[0], msg)
|
66
scripts/coccinelle/api/memdup.cocci
Normal file
66
scripts/coccinelle/api/memdup.cocci
Normal file
|
@ -0,0 +1,66 @@
|
|||
/// Use kmemdup rather than duplicating its implementation
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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
|
||||
|
||||
@r1@
|
||||
expression from,to;
|
||||
expression flag;
|
||||
position p;
|
||||
@@
|
||||
|
||||
to = \(kmalloc@p\|kzalloc@p\)(strlen(from) + 1,flag);
|
||||
|
||||
@r2@
|
||||
expression x,from,to;
|
||||
expression flag,E1;
|
||||
position p;
|
||||
@@
|
||||
|
||||
x = strlen(from) + 1;
|
||||
... when != \( x = E1 \| from = E1 \)
|
||||
to = \(kmalloc@p\|kzalloc@p\)(x,flag);
|
||||
|
||||
@depends on patch@
|
||||
expression from,to,size,flag;
|
||||
position p != {r1.p,r2.p};
|
||||
statement S;
|
||||
@@
|
||||
|
||||
- to = \(kmalloc@p\|kzalloc@p\)(size,flag);
|
||||
+ to = kmemdup(from,size,flag);
|
||||
if (to==NULL || ...) S
|
||||
- memcpy(to, from, size);
|
||||
|
||||
@r depends on !patch@
|
||||
expression from,to,size,flag;
|
||||
position p != {r1.p,r2.p};
|
||||
statement S;
|
||||
@@
|
||||
|
||||
* to = \(kmalloc@p\|kzalloc@p\)(size,flag);
|
||||
to = kmemdup(from,size,flag);
|
||||
if (to==NULL || ...) S
|
||||
* memcpy(to, from, size);
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdep")
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.report.print_report(p[0], "WARNING opportunity for kmemdep")
|
60
scripts/coccinelle/api/memdup_user.cocci
Normal file
60
scripts/coccinelle/api/memdup_user.cocci
Normal file
|
@ -0,0 +1,60 @@
|
|||
/// Use memdup_user rather than duplicating its implementation
|
||||
/// This is a little bit restricted to reduce false positives
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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
|
||||
|
||||
@depends on patch@
|
||||
expression from,to,size,flag;
|
||||
identifier l1,l2;
|
||||
@@
|
||||
|
||||
- to = \(kmalloc\|kzalloc\)(size,flag);
|
||||
+ to = memdup_user(from,size);
|
||||
if (
|
||||
- to==NULL
|
||||
+ IS_ERR(to)
|
||||
|| ...) {
|
||||
<+... when != goto l1;
|
||||
- -ENOMEM
|
||||
+ PTR_ERR(to)
|
||||
...+>
|
||||
}
|
||||
- if (copy_from_user(to, from, size) != 0) {
|
||||
- <+... when != goto l2;
|
||||
- -EFAULT
|
||||
- ...+>
|
||||
- }
|
||||
|
||||
@r depends on !patch@
|
||||
expression from,to,size,flag;
|
||||
position p;
|
||||
statement S1,S2;
|
||||
@@
|
||||
|
||||
* to = \(kmalloc@p\|kzalloc@p\)(size,flag);
|
||||
if (to==NULL || ...) S1
|
||||
if (copy_from_user(to, from, size) != 0)
|
||||
S2
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
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 memdup_user")
|
109
scripts/coccinelle/api/pm_runtime.cocci
Normal file
109
scripts/coccinelle/api/pm_runtime.cocci
Normal file
|
@ -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)
|
96
scripts/coccinelle/api/ptr_ret.cocci
Normal file
96
scripts/coccinelle/api/ptr_ret.cocci
Normal file
|
@ -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")
|
93
scripts/coccinelle/api/resource_size.cocci
Normal file
93
scripts/coccinelle/api/resource_size.cocci
Normal file
|
@ -0,0 +1,93 @@
|
|||
///
|
||||
/// Use resource_size function on resource object
|
||||
/// instead of explicit computation.
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2009, 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Options:
|
||||
//
|
||||
// Keywords: resource_size
|
||||
// Version min: 2.6.27 resource_size
|
||||
//
|
||||
|
||||
virtual context
|
||||
virtual patch
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For context mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r_context depends on context && !patch && !org@
|
||||
struct resource *res;
|
||||
@@
|
||||
|
||||
* (res->end - res->start) + 1
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For patch mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r_patch depends on !context && patch && !org@
|
||||
struct resource *res;
|
||||
@@
|
||||
|
||||
- (res->end - res->start) + 1
|
||||
+ resource_size(res)
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For org mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
|
||||
@r_org depends on !context && !patch && (org || report)@
|
||||
struct resource *res;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(res->end@p - res->start) + 1
|
||||
|
||||
@rbad_org depends on !context && !patch && (org || report)@
|
||||
struct resource *res;
|
||||
position p != r_org.p;
|
||||
@@
|
||||
|
||||
res->end@p - res->start
|
||||
|
||||
@script:python depends on org@
|
||||
p << r_org.p;
|
||||
x << r_org.res;
|
||||
@@
|
||||
|
||||
msg="ERROR with %s" % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
coccilib.org.print_todo(p[0], msg_safe)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r_org.p;
|
||||
x << r_org.res;
|
||||
@@
|
||||
|
||||
msg="ERROR: Missing resource_size with %s" % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
||||
@script:python depends on org@
|
||||
p << rbad_org.p;
|
||||
x << rbad_org.res;
|
||||
@@
|
||||
|
||||
msg="WARNING with %s" % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
coccilib.org.print_todo(p[0], msg_safe)
|
||||
|
||||
@script:python depends on report@
|
||||
p << rbad_org.p;
|
||||
x << rbad_org.res;
|
||||
@@
|
||||
|
||||
msg="WARNING: Suspicious code. resource_size is maybe missing with %s" % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
70
scripts/coccinelle/api/simple_open.cocci
Normal file
70
scripts/coccinelle/api/simple_open.cocci
Normal file
|
@ -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))
|
67
scripts/coccinelle/free/clk_put.cocci
Normal file
67
scripts/coccinelle/free/clk_put.cocci
Normal file
|
@ -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)
|
71
scripts/coccinelle/free/devm_free.cocci
Normal file
71
scripts/coccinelle/free/devm_free.cocci
Normal file
|
@ -0,0 +1,71 @@
|
|||
/// Find uses of standard freeing functons on values allocated using devm_
|
||||
/// functions. Values allocated using the devm_functions are freed when
|
||||
/// the device is detached, and thus the use of the standard freeing
|
||||
/// function would cause a double free.
|
||||
/// See Documentation/driver-model/devres.txt for more information.
|
||||
///
|
||||
/// A difficulty of detecting this problem is that the standard freeing
|
||||
/// function might be called from a different function than the one
|
||||
/// containing the allocation function. It is thus necessary to make the
|
||||
/// connection between the allocation function and the freeing function.
|
||||
/// Here this is done using the specific argument text, which is prone to
|
||||
/// false positives. There is no rule for the request_region and
|
||||
/// request_mem_region variants because this heuristic seems to be a bit
|
||||
/// less reliable in these cases.
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// 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 org
|
||||
virtual report
|
||||
virtual context
|
||||
|
||||
@r depends on context || org || report@
|
||||
expression x;
|
||||
@@
|
||||
|
||||
(
|
||||
x = devm_kzalloc(...)
|
||||
|
|
||||
x = devm_request_irq(...)
|
||||
|
|
||||
x = devm_ioremap(...)
|
||||
|
|
||||
x = devm_ioremap_nocache(...)
|
||||
|
|
||||
x = devm_ioport_map(...)
|
||||
)
|
||||
|
||||
@pb@
|
||||
expression r.x;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(
|
||||
* kfree@p(x)
|
||||
|
|
||||
* free_irq@p(x)
|
||||
|
|
||||
* iounmap@p(x)
|
||||
|
|
||||
* ioport_unmap@p(x)
|
||||
)
|
||||
|
||||
@script:python depends on org@
|
||||
p << pb.p;
|
||||
@@
|
||||
|
||||
msg="WARNING: invalid free of devm_ allocated data"
|
||||
coccilib.org.print_todo(p[0], msg)
|
||||
|
||||
@script:python depends on report@
|
||||
p << pb.p;
|
||||
@@
|
||||
|
||||
msg="WARNING: invalid free of devm_ allocated data"
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
53
scripts/coccinelle/free/ifnullfree.cocci
Normal file
53
scripts/coccinelle/free/ifnullfree.cocci
Normal file
|
@ -0,0 +1,53 @@
|
|||
/// NULL check before some freeing functions is not needed.
|
||||
///
|
||||
/// Based on checkpatch warning
|
||||
/// "kfree(NULL) is safe this check is probably not required"
|
||||
/// and kfreeaddr.cocci by Julia Lawall.
|
||||
///
|
||||
// Copyright: (C) 2014 Fabian Frederick. GPLv2.
|
||||
// Comments: -
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual patch
|
||||
virtual org
|
||||
virtual report
|
||||
virtual context
|
||||
|
||||
@r2 depends on patch@
|
||||
expression E;
|
||||
@@
|
||||
- if (E)
|
||||
(
|
||||
- kfree(E);
|
||||
+ kfree(E);
|
||||
|
|
||||
- debugfs_remove(E);
|
||||
+ debugfs_remove(E);
|
||||
|
|
||||
- debugfs_remove_recursive(E);
|
||||
+ debugfs_remove_recursive(E);
|
||||
|
|
||||
- usb_free_urb(E);
|
||||
+ usb_free_urb(E);
|
||||
)
|
||||
|
||||
@r depends on context || report || org @
|
||||
expression E;
|
||||
position p;
|
||||
@@
|
||||
|
||||
* if (E)
|
||||
* \(kfree@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|usb_free_urb\)(E);
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
cocci.print_main("NULL check before that freeing function is not needed", p)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
msg = "WARNING: NULL check before freeing functions like kfree, debugfs_remove, debugfs_remove_recursive or usb_free_urb is not needed. Maybe consider reorganizing relevant code to avoid passing NULL values."
|
||||
coccilib.report.print_report(p[0], msg)
|
67
scripts/coccinelle/free/iounmap.cocci
Normal file
67
scripts/coccinelle/free/iounmap.cocci
Normal file
|
@ -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)
|
121
scripts/coccinelle/free/kfree.cocci
Normal file
121
scripts/coccinelle/free/kfree.cocci
Normal file
|
@ -0,0 +1,121 @@
|
|||
/// Find a use after free.
|
||||
//# Values of variables may imply that some
|
||||
//# execution paths are not possible, resulting in false positives.
|
||||
//# Another source of false positives are macros such as
|
||||
//# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@free@
|
||||
expression E;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
kfree@p1(E)
|
||||
|
||||
@print expression@
|
||||
constant char [] c;
|
||||
expression free.E,E2;
|
||||
type T;
|
||||
position p;
|
||||
identifier f;
|
||||
@@
|
||||
|
||||
(
|
||||
f(...,c,...,(T)E@p,...)
|
||||
|
|
||||
E@p == E2
|
||||
|
|
||||
E@p != E2
|
||||
|
|
||||
E2 == E@p
|
||||
|
|
||||
E2 != E@p
|
||||
|
|
||||
!E@p
|
||||
|
|
||||
E@p || ...
|
||||
)
|
||||
|
||||
@sz@
|
||||
expression free.E;
|
||||
position p;
|
||||
@@
|
||||
|
||||
sizeof(<+...E@p...+>)
|
||||
|
||||
@loop exists@
|
||||
expression E;
|
||||
identifier l;
|
||||
position ok;
|
||||
@@
|
||||
|
||||
while (1) { ...
|
||||
kfree@ok(E)
|
||||
... when != break;
|
||||
when != goto l;
|
||||
when forall
|
||||
}
|
||||
|
||||
@r exists@
|
||||
expression free.E, subE<=free.E, E2;
|
||||
expression E1;
|
||||
iterator iter;
|
||||
statement S;
|
||||
position free.p1!=loop.ok,p2!={print.p,sz.p};
|
||||
@@
|
||||
|
||||
kfree@p1(E,...)
|
||||
...
|
||||
(
|
||||
iter(...,subE,...) S // no use
|
||||
|
|
||||
list_remove_head(E1,subE,...)
|
||||
|
|
||||
subE = E2
|
||||
|
|
||||
subE++
|
||||
|
|
||||
++subE
|
||||
|
|
||||
--subE
|
||||
|
|
||||
subE--
|
||||
|
|
||||
&subE
|
||||
|
|
||||
BUG(...)
|
||||
|
|
||||
BUG_ON(...)
|
||||
|
|
||||
return_VALUE(...)
|
||||
|
|
||||
return_ACPI_STATUS(...)
|
||||
|
|
||||
E@p2 // bad use
|
||||
)
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << free.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("kfree",p1)
|
||||
cocci.print_secs("ref",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << free.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
msg = "ERROR: reference preceded by free on line %s" % (p1[0].line)
|
||||
coccilib.report.print_report(p2[0],msg)
|
32
scripts/coccinelle/free/kfreeaddr.cocci
Normal file
32
scripts/coccinelle/free/kfreeaddr.cocci
Normal file
|
@ -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)
|
52
scripts/coccinelle/free/pci_free_consistent.cocci
Normal file
52
scripts/coccinelle/free/pci_free_consistent.cocci
Normal file
|
@ -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)
|
123
scripts/coccinelle/iterators/fen.cocci
Normal file
123
scripts/coccinelle/iterators/fen.cocci
Normal file
|
@ -0,0 +1,123 @@
|
|||
/// These iterators only exit normally when the loop cursor is NULL, so there
|
||||
/// is no point to call of_node_put on the final value.
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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
|
||||
|
||||
@depends on patch@
|
||||
iterator name for_each_node_by_name;
|
||||
expression np,E;
|
||||
identifier l;
|
||||
@@
|
||||
|
||||
for_each_node_by_name(np,...) {
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
... when != np = E
|
||||
- of_node_put(np);
|
||||
|
||||
@depends on patch@
|
||||
iterator name for_each_node_by_type;
|
||||
expression np,E;
|
||||
identifier l;
|
||||
@@
|
||||
|
||||
for_each_node_by_type(np,...) {
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
... when != np = E
|
||||
- of_node_put(np);
|
||||
|
||||
@depends on patch@
|
||||
iterator name for_each_compatible_node;
|
||||
expression np,E;
|
||||
identifier l;
|
||||
@@
|
||||
|
||||
for_each_compatible_node(np,...) {
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
... when != np = E
|
||||
- of_node_put(np);
|
||||
|
||||
@depends on patch@
|
||||
iterator name for_each_matching_node;
|
||||
expression np,E;
|
||||
identifier l;
|
||||
@@
|
||||
|
||||
for_each_matching_node(np,...) {
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
... when != np = E
|
||||
- of_node_put(np);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@r depends on !patch forall@
|
||||
//iterator name for_each_node_by_name;
|
||||
//iterator name for_each_node_by_type;
|
||||
//iterator name for_each_compatible_node;
|
||||
//iterator name for_each_matching_node;
|
||||
expression np,E;
|
||||
identifier l;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
(
|
||||
*for_each_node_by_name@p1(np,...)
|
||||
{
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
|
|
||||
*for_each_node_by_type@p1(np,...)
|
||||
{
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
|
|
||||
*for_each_compatible_node@p1(np,...)
|
||||
{
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
|
|
||||
*for_each_matching_node@p1(np,...)
|
||||
{
|
||||
... when != break;
|
||||
when != goto l;
|
||||
}
|
||||
)
|
||||
... when != np = E
|
||||
* of_node_put@p2(np);
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("unneeded of_node_put",p2)
|
||||
cocci.print_secs("iterator",p1)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
msg = "ERROR: of_node_put not needed after iterator on line %s" % (p1[0].line)
|
||||
coccilib.report.print_report(p2[0], msg)
|
94
scripts/coccinelle/iterators/itnull.cocci
Normal file
94
scripts/coccinelle/iterators/itnull.cocci
Normal file
|
@ -0,0 +1,94 @@
|
|||
/// Many iterators have the property that the first argument is always bound
|
||||
/// to a real list element, never NULL.
|
||||
//# False positives arise for some iterators that do not have this property,
|
||||
//# or in cases when the loop cursor is reassigned. The latter should only
|
||||
//# happen when the matched code is on the way to a loop exit (break, goto,
|
||||
//# or return).
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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
|
||||
|
||||
@depends on patch@
|
||||
iterator I;
|
||||
expression x,E,E1,E2;
|
||||
statement S,S1,S2;
|
||||
@@
|
||||
|
||||
I(x,...) { <...
|
||||
(
|
||||
- if (x == NULL && ...) S
|
||||
|
|
||||
- if (x != NULL || ...)
|
||||
S
|
||||
|
|
||||
- (x == NULL) ||
|
||||
E
|
||||
|
|
||||
- (x != NULL) &&
|
||||
E
|
||||
|
|
||||
- (x == NULL && ...) ? E1 :
|
||||
E2
|
||||
|
|
||||
- (x != NULL || ...) ?
|
||||
E1
|
||||
- : E2
|
||||
|
|
||||
- if (x == NULL && ...) S1 else
|
||||
S2
|
||||
|
|
||||
- if (x != NULL || ...)
|
||||
S1
|
||||
- else S2
|
||||
|
|
||||
+ BAD(
|
||||
x == NULL
|
||||
+ )
|
||||
|
|
||||
+ BAD(
|
||||
x != NULL
|
||||
+ )
|
||||
)
|
||||
...> }
|
||||
|
||||
@r depends on !patch exists@
|
||||
iterator I;
|
||||
expression x,E;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
*I@p1(x,...)
|
||||
{ ... when != x = E
|
||||
(
|
||||
* x@p2 == NULL
|
||||
|
|
||||
* x@p2 != NULL
|
||||
)
|
||||
... when any
|
||||
}
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("iterator-bound variable",p1)
|
||||
cocci.print_secs("useless NULL test",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line)
|
||||
coccilib.report.print_report(p2[0], msg)
|
62
scripts/coccinelle/iterators/list_entry_update.cocci
Normal file
62
scripts/coccinelle/iterators/list_entry_update.cocci
Normal file
|
@ -0,0 +1,62 @@
|
|||
/// list_for_each_entry uses its first argument to get from one element of
|
||||
/// the list to the next, so it is usually not a good idea to reassign it.
|
||||
/// The first rule finds such a reassignment and the second rule checks
|
||||
/// that there is a path from the reassignment back to the top of the loop.
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r@
|
||||
iterator name list_for_each_entry;
|
||||
expression x,E;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
list_for_each_entry@p1(x,...) { <... x =@p2 E ...> }
|
||||
|
||||
@depends on context && !org && !report@
|
||||
expression x,E;
|
||||
position r.p1,r.p2;
|
||||
statement S;
|
||||
@@
|
||||
|
||||
*x =@p2 E
|
||||
...
|
||||
list_for_each_entry@p1(x,...) S
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@back depends on (org || report) && !context exists@
|
||||
expression x,E;
|
||||
position r.p1,r.p2;
|
||||
statement S;
|
||||
@@
|
||||
|
||||
x =@p2 E
|
||||
...
|
||||
list_for_each_entry@p1(x,...) S
|
||||
|
||||
@script:python depends on back && org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("iterator",p1)
|
||||
cocci.print_secs("update",p2)
|
||||
|
||||
@script:python depends on back && report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
msg = "iterator with update on line %s" % (p2[0].line)
|
||||
coccilib.report.print_report(p1[0],msg)
|
147
scripts/coccinelle/iterators/use_after_iter.cocci
Normal file
147
scripts/coccinelle/iterators/use_after_iter.cocci
Normal file
|
@ -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)
|
105
scripts/coccinelle/locks/call_kern.cocci
Normal file
105
scripts/coccinelle/locks/call_kern.cocci
Normal file
|
@ -0,0 +1,105 @@
|
|||
/// Find functions that refer to GFP_KERNEL but are called with locks held.
|
||||
//# The proposed change of converting the GFP_KERNEL is not necessarily the
|
||||
//# correct one. It may be desired to unlock the lock, or to not call the
|
||||
//# function under the lock in the first place.
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2012 Nicolas Palix. GPLv2.
|
||||
// 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
|
||||
|
||||
@gfp exists@
|
||||
identifier fn;
|
||||
position p;
|
||||
@@
|
||||
|
||||
fn(...) {
|
||||
... when != read_unlock_irq(...)
|
||||
when != write_unlock_irq(...)
|
||||
when != read_unlock_irqrestore(...)
|
||||
when != write_unlock_irqrestore(...)
|
||||
when != spin_unlock(...)
|
||||
when != spin_unlock_irq(...)
|
||||
when != spin_unlock_irqrestore(...)
|
||||
when != local_irq_enable(...)
|
||||
when any
|
||||
GFP_KERNEL@p
|
||||
... when any
|
||||
}
|
||||
|
||||
@locked exists@
|
||||
identifier gfp.fn;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
(
|
||||
read_lock_irq@p1
|
||||
|
|
||||
write_lock_irq@p1
|
||||
|
|
||||
read_lock_irqsave@p1
|
||||
|
|
||||
write_lock_irqsave@p1
|
||||
|
|
||||
spin_lock@p1
|
||||
|
|
||||
spin_trylock@p1
|
||||
|
|
||||
spin_lock_irq@p1
|
||||
|
|
||||
spin_lock_irqsave@p1
|
||||
|
|
||||
local_irq_disable@p1
|
||||
)
|
||||
(...)
|
||||
... when != read_unlock_irq(...)
|
||||
when != write_unlock_irq(...)
|
||||
when != read_unlock_irqrestore(...)
|
||||
when != write_unlock_irqrestore(...)
|
||||
when != spin_unlock(...)
|
||||
when != spin_unlock_irq(...)
|
||||
when != spin_unlock_irqrestore(...)
|
||||
when != local_irq_enable(...)
|
||||
fn@p2(...)
|
||||
|
||||
@depends on locked && patch@
|
||||
position gfp.p;
|
||||
@@
|
||||
|
||||
- GFP_KERNEL@p
|
||||
+ GFP_ATOMIC
|
||||
|
||||
@depends on locked && !patch@
|
||||
position gfp.p;
|
||||
@@
|
||||
|
||||
* GFP_KERNEL@p
|
||||
|
||||
@script:python depends on !patch && org@
|
||||
p << gfp.p;
|
||||
fn << gfp.fn;
|
||||
p1 << locked.p1;
|
||||
p2 << locked.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("lock",p1)
|
||||
cocci.print_secs("call",p2)
|
||||
cocci.print_secs("GFP_KERNEL",p)
|
||||
|
||||
@script:python depends on !patch && report@
|
||||
p << gfp.p;
|
||||
fn << gfp.fn;
|
||||
p1 << locked.p1;
|
||||
p2 << locked.p2;
|
||||
@@
|
||||
|
||||
msg = "ERROR: function %s called on line %s inside lock on line %s but uses GFP_KERNEL" % (fn,p2[0].line,p1[0].line)
|
||||
coccilib.report.print_report(p[0], msg)
|
92
scripts/coccinelle/locks/double_lock.cocci
Normal file
92
scripts/coccinelle/locks/double_lock.cocci
Normal file
|
@ -0,0 +1,92 @@
|
|||
/// Find double locks. False positives may occur when some paths cannot
|
||||
/// occur at execution, due to the values of variables, and when there is
|
||||
/// an intervening function call that releases the lock.
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@locked@
|
||||
position p1;
|
||||
expression E1;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(
|
||||
mutex_lock@p1
|
||||
|
|
||||
mutex_trylock@p1
|
||||
|
|
||||
spin_lock@p1
|
||||
|
|
||||
spin_trylock@p1
|
||||
|
|
||||
read_lock@p1
|
||||
|
|
||||
read_trylock@p1
|
||||
|
|
||||
write_lock@p1
|
||||
|
|
||||
write_trylock@p1
|
||||
) (E1@p,...);
|
||||
|
||||
@balanced@
|
||||
position p1 != locked.p1;
|
||||
position locked.p;
|
||||
identifier lock,unlock;
|
||||
expression x <= locked.E1;
|
||||
expression E,locked.E1;
|
||||
expression E2;
|
||||
@@
|
||||
|
||||
if (E) {
|
||||
<+... when != E1
|
||||
lock(E1@p,...)
|
||||
...+>
|
||||
}
|
||||
... when != E1
|
||||
when != \(x = E2\|&x\)
|
||||
when forall
|
||||
if (E) {
|
||||
<+... when != E1
|
||||
unlock@p1(E1,...)
|
||||
...+>
|
||||
}
|
||||
|
||||
@r depends on !balanced exists@
|
||||
expression x <= locked.E1;
|
||||
expression locked.E1;
|
||||
expression E2;
|
||||
identifier lock;
|
||||
position locked.p,p1,p2;
|
||||
@@
|
||||
|
||||
lock@p1 (E1@p,...);
|
||||
... when != E1
|
||||
when != \(x = E2\|&x\)
|
||||
lock@p2 (E1,...);
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
lock << r.lock;
|
||||
@@
|
||||
|
||||
cocci.print_main(lock,p1)
|
||||
cocci.print_secs("second lock",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
lock << r.lock;
|
||||
@@
|
||||
|
||||
msg = "second lock on line %s" % (p2[0].line)
|
||||
coccilib.report.print_report(p1[0],msg)
|
80
scripts/coccinelle/locks/flags.cocci
Normal file
80
scripts/coccinelle/locks/flags.cocci
Normal file
|
@ -0,0 +1,80 @@
|
|||
/// Find nested lock+irqsave functions that use the same flags variables
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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@
|
||||
expression lock1,lock2,flags;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
(
|
||||
spin_lock_irqsave@p1(lock1,flags)
|
||||
|
|
||||
read_lock_irqsave@p1(lock1,flags)
|
||||
|
|
||||
write_lock_irqsave@p1(lock1,flags)
|
||||
)
|
||||
... when != flags
|
||||
(
|
||||
spin_lock_irqsave(lock1,flags)
|
||||
|
|
||||
read_lock_irqsave(lock1,flags)
|
||||
|
|
||||
write_lock_irqsave(lock1,flags)
|
||||
|
|
||||
spin_lock_irqsave@p2(lock2,flags)
|
||||
|
|
||||
read_lock_irqsave@p2(lock2,flags)
|
||||
|
|
||||
write_lock_irqsave@p2(lock2,flags)
|
||||
)
|
||||
|
||||
@d exists@
|
||||
expression f <= r.flags;
|
||||
expression lock1,lock2,flags;
|
||||
position r.p1, r.p2;
|
||||
@@
|
||||
|
||||
(
|
||||
*spin_lock_irqsave@p1(lock1,flags)
|
||||
|
|
||||
*read_lock_irqsave@p1(lock1,flags)
|
||||
|
|
||||
*write_lock_irqsave@p1(lock1,flags)
|
||||
)
|
||||
... when != f
|
||||
(
|
||||
*spin_lock_irqsave@p2(lock2,flags)
|
||||
|
|
||||
*read_lock_irqsave@p2(lock2,flags)
|
||||
|
|
||||
*write_lock_irqsave@p2(lock2,flags)
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@script:python depends on d && org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("original lock",p1)
|
||||
cocci.print_secs("nested lock+irqsave that reuses flags",p2)
|
||||
|
||||
@script:python depends on d && report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
msg="ERROR: nested lock+irqsave that reuses flags from line %s." % (p1[0].line)
|
||||
coccilib.report.print_report(p2[0], msg)
|
96
scripts/coccinelle/locks/mini_lock.cocci
Normal file
96
scripts/coccinelle/locks/mini_lock.cocci
Normal file
|
@ -0,0 +1,96 @@
|
|||
/// Find missing unlocks. This semantic match considers the specific case
|
||||
/// where the unlock is missing from an if branch, and there is a lock
|
||||
/// before the if and an unlock after the if. False positives are due to
|
||||
/// cases where the if branch represents a case where the function is
|
||||
/// supposed to exit with the lock held, or where there is some preceding
|
||||
/// function call that releases the lock.
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@prelocked@
|
||||
position p1,p;
|
||||
expression E1;
|
||||
@@
|
||||
|
||||
(
|
||||
mutex_lock@p1
|
||||
|
|
||||
mutex_trylock@p1
|
||||
|
|
||||
spin_lock@p1
|
||||
|
|
||||
spin_trylock@p1
|
||||
|
|
||||
read_lock@p1
|
||||
|
|
||||
read_trylock@p1
|
||||
|
|
||||
write_lock@p1
|
||||
|
|
||||
write_trylock@p1
|
||||
|
|
||||
read_lock_irq@p1
|
||||
|
|
||||
write_lock_irq@p1
|
||||
|
|
||||
read_lock_irqsave@p1
|
||||
|
|
||||
write_lock_irqsave@p1
|
||||
|
|
||||
spin_lock_irq@p1
|
||||
|
|
||||
spin_lock_irqsave@p1
|
||||
) (E1@p,...);
|
||||
|
||||
@looped@
|
||||
position r;
|
||||
@@
|
||||
|
||||
for(...;...;...) { <+... return@r ...; ...+> }
|
||||
|
||||
@err exists@
|
||||
expression E1;
|
||||
position prelocked.p;
|
||||
position up != prelocked.p1;
|
||||
position r!=looped.r;
|
||||
identifier lock,unlock;
|
||||
@@
|
||||
|
||||
*lock(E1@p,...);
|
||||
<+... when != E1
|
||||
if (...) {
|
||||
... when != E1
|
||||
* return@r ...;
|
||||
}
|
||||
...+>
|
||||
*unlock@up(E1,...);
|
||||
|
||||
@script:python depends on org@
|
||||
p << prelocked.p1;
|
||||
lock << err.lock;
|
||||
unlock << err.unlock;
|
||||
p2 << err.r;
|
||||
@@
|
||||
|
||||
cocci.print_main(lock,p)
|
||||
cocci.print_secs(unlock,p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p << prelocked.p1;
|
||||
lock << err.lock;
|
||||
unlock << err.unlock;
|
||||
p2 << err.r;
|
||||
@@
|
||||
|
||||
msg = "preceding lock on line %s" % (p[0].line)
|
||||
coccilib.report.print_report(p2[0],msg)
|
87
scripts/coccinelle/misc/array_size.cocci
Normal file
87
scripts/coccinelle/misc/array_size.cocci
Normal file
|
@ -0,0 +1,87 @@
|
|||
/// Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element
|
||||
///
|
||||
//# This makes an effort to find cases where ARRAY_SIZE can be used such as
|
||||
//# where there is a division of sizeof the array by the sizeof its first
|
||||
//# element or by any indexed element or the element type. It replaces the
|
||||
//# division of the two sizeofs by ARRAY_SIZE.
|
||||
//
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2014 Himangi Saraogi. GPLv2.
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual patch
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@i@
|
||||
@@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For context mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on i&&context@
|
||||
type T;
|
||||
T[] E;
|
||||
@@
|
||||
(
|
||||
* (sizeof(E)/sizeof(*E))
|
||||
|
|
||||
* (sizeof(E)/sizeof(E[...]))
|
||||
|
|
||||
* (sizeof(E)/sizeof(T))
|
||||
)
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For patch mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on i&&patch@
|
||||
type T;
|
||||
T[] E;
|
||||
@@
|
||||
(
|
||||
- (sizeof(E)/sizeof(*E))
|
||||
+ ARRAY_SIZE(E)
|
||||
|
|
||||
- (sizeof(E)/sizeof(E[...]))
|
||||
+ ARRAY_SIZE(E)
|
||||
|
|
||||
- (sizeof(E)/sizeof(T))
|
||||
+ ARRAY_SIZE(E)
|
||||
)
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For org and report mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r@
|
||||
type T;
|
||||
T[] E;
|
||||
position p;
|
||||
@@
|
||||
(
|
||||
(sizeof(E)@p /sizeof(*E))
|
||||
|
|
||||
(sizeof(E)@p /sizeof(E[...]))
|
||||
|
|
||||
(sizeof(E)@p /sizeof(T))
|
||||
)
|
||||
|
||||
@script:python depends on i&&org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.org.print_todo(p[0], "WARNING should use ARRAY_SIZE")
|
||||
|
||||
@script:python depends on i&&report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
msg="WARNING: Use ARRAY_SIZE"
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
76
scripts/coccinelle/misc/badty.cocci
Normal file
76
scripts/coccinelle/misc/badty.cocci
Normal file
|
@ -0,0 +1,76 @@
|
|||
/// Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element
|
||||
///
|
||||
//# This makes an effort to find cases where the argument to sizeof is wrong
|
||||
//# in memory allocation functions by checking the type of the allocated memory
|
||||
//# when it is a double pointer and ensuring the sizeof argument takes a pointer
|
||||
//# to the the memory being allocated. There are false positives in cases the
|
||||
//# sizeof argument is not used in constructing the return value. The result
|
||||
//# may need some reformatting.
|
||||
//
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2014 Himangi Saraogi. GPLv2.
|
||||
// Comments:
|
||||
// Options:
|
||||
|
||||
virtual patch
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For context mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on context disable sizeof_type_expr@
|
||||
type T;
|
||||
T **x;
|
||||
@@
|
||||
|
||||
x =
|
||||
<+...sizeof(
|
||||
* T
|
||||
)...+>
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For patch mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on patch disable sizeof_type_expr@
|
||||
type T;
|
||||
T **x;
|
||||
@@
|
||||
|
||||
x =
|
||||
<+...sizeof(
|
||||
- T
|
||||
+ *x
|
||||
)...+>
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For org and report mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r disable sizeof_type_expr@
|
||||
type T;
|
||||
T **x;
|
||||
position p;
|
||||
@@
|
||||
|
||||
x =
|
||||
<+...sizeof(
|
||||
T@p
|
||||
)...+>
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.org.print_todo(p[0], "WARNING sizeof argument should be pointer type, not structure type")
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
msg="WARNING: Use correct pointer type argument for sizeof"
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
178
scripts/coccinelle/misc/boolinit.cocci
Normal file
178
scripts/coccinelle/misc/boolinit.cocci
Normal file
|
@ -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")
|
58
scripts/coccinelle/misc/boolreturn.cocci
Normal file
58
scripts/coccinelle/misc/boolreturn.cocci
Normal file
|
@ -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)
|
62
scripts/coccinelle/misc/bugon.cocci
Normal file
62
scripts/coccinelle/misc/bugon.cocci
Normal file
|
@ -0,0 +1,62 @@
|
|||
/// Use BUG_ON instead of a if condition followed by BUG.
|
||||
///
|
||||
//# This makes an effort to find cases where BUG() follows an if
|
||||
//# condition on an expression and replaces the if condition and BUG()
|
||||
//# with a BUG_ON having the conditional expression of the if statement
|
||||
//# as argument.
|
||||
//
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2014 Himangi Saraogi. GPLv2.
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual patch
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For context mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on context@
|
||||
expression e;
|
||||
@@
|
||||
|
||||
*if (e) BUG();
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For patch mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@depends on patch@
|
||||
expression e;
|
||||
@@
|
||||
|
||||
-if (e) BUG();
|
||||
+BUG_ON(e);
|
||||
|
||||
//----------------------------------------------------------
|
||||
// For org and report mode
|
||||
//----------------------------------------------------------
|
||||
|
||||
@r@
|
||||
expression e;
|
||||
position p;
|
||||
@@
|
||||
|
||||
if (e) BUG@p ();
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.org.print_todo(p[0], "WARNING use BUG_ON")
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
msg="WARNING: Use BUG_ON"
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
41
scripts/coccinelle/misc/cstptr.cocci
Normal file
41
scripts/coccinelle/misc/cstptr.cocci
Normal file
|
@ -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)
|
53
scripts/coccinelle/misc/doubleinit.cocci
Normal file
53
scripts/coccinelle/misc/doubleinit.cocci
Normal file
|
@ -0,0 +1,53 @@
|
|||
/// Find duplicate field initializations. This has a high rate of false
|
||||
/// positives due to #ifdefs, which Coccinelle is not aware of in a structure
|
||||
/// initialization.
|
||||
///
|
||||
// Confidence: Low
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// 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
|
||||
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r@
|
||||
identifier I, s, fld;
|
||||
position p0,p;
|
||||
expression E;
|
||||
@@
|
||||
|
||||
struct I s =@p0 { ..., .fld@p = E, ...};
|
||||
|
||||
@s@
|
||||
identifier I, s, r.fld;
|
||||
position r.p0,p;
|
||||
expression E;
|
||||
@@
|
||||
|
||||
struct I s =@p0 { ..., .fld@p = E, ...};
|
||||
|
||||
@script:python depends on org@
|
||||
p0 << r.p0;
|
||||
fld << r.fld;
|
||||
ps << s.p;
|
||||
pr << r.p;
|
||||
@@
|
||||
|
||||
if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
|
||||
cocci.print_main(fld,p0)
|
||||
cocci.print_secs("s",ps)
|
||||
cocci.print_secs("r",pr)
|
||||
|
||||
@script:python depends on report@
|
||||
p0 << r.p0;
|
||||
fld << r.fld;
|
||||
ps << s.p;
|
||||
pr << r.p;
|
||||
@@
|
||||
|
||||
if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
|
||||
msg = "%s: first occurrence line %s, second occurrence line %s" % (fld,ps[0].line,pr[0].line)
|
||||
coccilib.report.print_report(p0[0],msg)
|
35
scripts/coccinelle/misc/ifaddr.cocci
Normal file
35
scripts/coccinelle/misc/ifaddr.cocci
Normal file
|
@ -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)
|
48
scripts/coccinelle/misc/ifcol.cocci
Normal file
48
scripts/coccinelle/misc/ifcol.cocci
Normal file
|
@ -0,0 +1,48 @@
|
|||
/// Find confusingly indented code in or after an if. An if branch should
|
||||
/// be indented. The code following an if should not be indented.
|
||||
/// Sometimes, code after an if that is indented is actually intended to be
|
||||
/// part of the if branch.
|
||||
///
|
||||
/// This has a high rate of false positives, because Coccinelle's column
|
||||
/// calculation does not distinguish between spaces and tabs, so code that
|
||||
/// is not visually aligned may be considered to be in the same column.
|
||||
///
|
||||
// Confidence: Low
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r disable braces4@
|
||||
position p1,p2;
|
||||
statement S1,S2;
|
||||
@@
|
||||
|
||||
(
|
||||
if (...) { ... }
|
||||
|
|
||||
if (...) S1@p1 S2@p2
|
||||
)
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
if (p1[0].column == p2[0].column):
|
||||
cocci.print_main("branch",p1)
|
||||
cocci.print_secs("after",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
if (p1[0].column == p2[0].column):
|
||||
msg = "code aligned with following code on line %s" % (p2[0].line)
|
||||
coccilib.report.print_report(p1[0],msg)
|
65
scripts/coccinelle/misc/irqf_oneshot.cocci
Normal file
65
scripts/coccinelle/misc/irqf_oneshot.cocci
Normal file
|
@ -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)
|
65
scripts/coccinelle/misc/noderef.cocci
Normal file
65
scripts/coccinelle/misc/noderef.cocci
Normal file
|
@ -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)
|
62
scripts/coccinelle/misc/of_table.cocci
Normal file
62
scripts/coccinelle/misc/of_table.cocci
Normal file
|
@ -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)
|
55
scripts/coccinelle/misc/orplus.cocci
Normal file
55
scripts/coccinelle/misc/orplus.cocci
Normal file
|
@ -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)
|
66
scripts/coccinelle/misc/returnvar.cocci
Normal file
66
scripts/coccinelle/misc/returnvar.cocci
Normal file
|
@ -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)
|
83
scripts/coccinelle/misc/semicolon.cocci
Normal file
83
scripts/coccinelle/misc/semicolon.cocci
Normal file
|
@ -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)
|
180
scripts/coccinelle/misc/simple_return.cocci
Normal file
180
scripts/coccinelle/misc/simple_return.cocci
Normal file
|
@ -0,0 +1,180 @@
|
|||
/// Simplify a trivial if-return sequence. Possibly combine with a
|
||||
/// preceding function call.
|
||||
//
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2014 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2014 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual patch
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r depends on patch@
|
||||
local idexpression e;
|
||||
identifier i,f,fn;
|
||||
@@
|
||||
|
||||
fn(...) { <...
|
||||
- e@i =
|
||||
+ return
|
||||
f(...);
|
||||
-if (i != 0) return i;
|
||||
-return 0;
|
||||
...> }
|
||||
|
||||
@depends on patch@
|
||||
identifier r.i;
|
||||
type t;
|
||||
@@
|
||||
|
||||
-t i;
|
||||
... when != i
|
||||
|
||||
@depends on patch@
|
||||
expression e;
|
||||
@@
|
||||
|
||||
-if (e != 0)
|
||||
return e;
|
||||
-return 0;
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@s1 depends on context || org || report@
|
||||
local idexpression e;
|
||||
identifier i,f,fn;
|
||||
position p,p1,p2;
|
||||
@@
|
||||
|
||||
fn(...) { <...
|
||||
* e@i@p = f(...);
|
||||
if (\(i@p1 != 0\|i@p2 < 0\))
|
||||
return i;
|
||||
return 0;
|
||||
...> }
|
||||
|
||||
@s2 depends on context || org || report forall@
|
||||
identifier s1.i;
|
||||
type t;
|
||||
position q,s1.p;
|
||||
expression e,f;
|
||||
@@
|
||||
|
||||
* t i@q;
|
||||
... when != i
|
||||
e@p = f(...);
|
||||
|
||||
@s3 depends on context || org || report@
|
||||
expression e;
|
||||
position p1!=s1.p1;
|
||||
position p2!=s1.p2;
|
||||
@@
|
||||
|
||||
*if (\(e@p1 != 0\|e@p2 < 0\))
|
||||
return e;
|
||||
return 0;
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@script:python depends on org@
|
||||
p << s1.p;
|
||||
p1 << s1.p1;
|
||||
q << s2.q;
|
||||
@@
|
||||
|
||||
cocci.print_main("decl",q)
|
||||
cocci.print_secs("use",p)
|
||||
cocci.include_match(False)
|
||||
|
||||
@script:python depends on org@
|
||||
p << s1.p;
|
||||
p2 << s1.p2;
|
||||
q << s2.q;
|
||||
@@
|
||||
|
||||
cocci.print_main("decl",q)
|
||||
cocci.print_secs("use with questionable test",p)
|
||||
cocci.include_match(False)
|
||||
|
||||
@script:python depends on org@
|
||||
p << s1.p;
|
||||
p1 << s1.p1;
|
||||
@@
|
||||
|
||||
cocci.print_main("use",p)
|
||||
|
||||
@script:python depends on org@
|
||||
p << s1.p;
|
||||
p2 << s1.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("use with questionable test",p)
|
||||
|
||||
@script:python depends on org@
|
||||
p << s3.p1;
|
||||
@@
|
||||
|
||||
cocci.print_main("test",p)
|
||||
|
||||
@script:python depends on org@
|
||||
p << s3.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("questionable test",p)
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@script:python depends on report@
|
||||
p << s1.p;
|
||||
p1 << s1.p1;
|
||||
q << s2.q;
|
||||
@@
|
||||
|
||||
msg = "WARNING: end returns can be simpified and declaration on line %s can be dropped" % (q[0].line)
|
||||
coccilib.report.print_report(p[0],msg)
|
||||
cocci.include_match(False)
|
||||
|
||||
@script:python depends on report@
|
||||
p << s1.p;
|
||||
p1 << s1.p1;
|
||||
q << s2.q
|
||||
;
|
||||
@@
|
||||
|
||||
msg = "WARNING: end returns may be simpified if negative or 0 value and declaration on line %s can be dropped" % (q[0].line)
|
||||
coccilib.report.print_report(p[0],msg)
|
||||
cocci.include_match(False)
|
||||
|
||||
@script:python depends on report@
|
||||
p << s1.p;
|
||||
p1 << s1.p1;
|
||||
@@
|
||||
|
||||
msg = "WARNING: end returns can be simpified"
|
||||
coccilib.report.print_report(p[0],msg)
|
||||
|
||||
@script:python depends on report@
|
||||
p << s1.p;
|
||||
p2 << s1.p2;
|
||||
@@
|
||||
|
||||
msg = "WARNING: end returns can be simpified if negative or 0 value"
|
||||
coccilib.report.print_report(p[0],msg)
|
||||
|
||||
@script:python depends on report@
|
||||
p << s3.p1;
|
||||
@@
|
||||
|
||||
msg = "WARNING: end returns can be simpified"
|
||||
coccilib.report.print_report(p[0],msg)
|
||||
|
||||
@script:python depends on report@
|
||||
p << s3.p2;
|
||||
@@
|
||||
|
||||
msg = "WARNING: end returns can be simpified if tested value is negative or 0"
|
||||
coccilib.report.print_report(p[0],msg)
|
109
scripts/coccinelle/misc/warn.cocci
Normal file
109
scripts/coccinelle/misc/warn.cocci
Normal file
|
@ -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);
|
||||
- }
|
238
scripts/coccinelle/null/badzero.cocci
Normal file
238
scripts/coccinelle/null/badzero.cocci
Normal file
|
@ -0,0 +1,238 @@
|
|||
/// 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: Requires Coccinelle version 1.0.0-rc20 or later
|
||||
// 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")
|
282
scripts/coccinelle/null/deref_null.cocci
Normal file
282
scripts/coccinelle/null/deref_null.cocci
Normal file
|
@ -0,0 +1,282 @@
|
|||
///
|
||||
/// A variable is dereference under a NULL test.
|
||||
/// Even though it is know to be NULL.
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments: -I ... -all_includes can give more complete results
|
||||
// Options:
|
||||
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@ifm@
|
||||
expression *E;
|
||||
statement S1,S2;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
if@p1 ((E == NULL && ...) || ...) S1 else S2
|
||||
|
||||
// The following two rules are separate, because both can match a single
|
||||
// expression in different ways
|
||||
@pr1 expression@
|
||||
expression *ifm.E;
|
||||
identifier f;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
(E != NULL && ...) ? <+...E->f@p1...+> : ...
|
||||
|
||||
@pr2 expression@
|
||||
expression *ifm.E;
|
||||
identifier f;
|
||||
position p2;
|
||||
@@
|
||||
|
||||
(
|
||||
(E != NULL) && ... && <+...E->f@p2...+>
|
||||
|
|
||||
(E == NULL) || ... || <+...E->f@p2...+>
|
||||
|
|
||||
sizeof(<+...E->f@p2...+>)
|
||||
)
|
||||
|
||||
// For org and report modes
|
||||
|
||||
@r depends on !context && (org || report) exists@
|
||||
expression subE <= ifm.E;
|
||||
expression *ifm.E;
|
||||
expression E1,E2;
|
||||
identifier f;
|
||||
statement S1,S2,S3,S4;
|
||||
iterator iter;
|
||||
position p!={pr1.p1,pr2.p2};
|
||||
position ifm.p1;
|
||||
@@
|
||||
|
||||
if@p1 ((E == NULL && ...) || ...)
|
||||
{
|
||||
... when != if (...) S1 else S2
|
||||
(
|
||||
iter(subE,...) S4 // no use
|
||||
|
|
||||
list_remove_head(E2,subE,...)
|
||||
|
|
||||
subE = E1
|
||||
|
|
||||
for(subE = E1;...;...) S4
|
||||
|
|
||||
subE++
|
||||
|
|
||||
++subE
|
||||
|
|
||||
--subE
|
||||
|
|
||||
subE--
|
||||
|
|
||||
&subE
|
||||
|
|
||||
E->f@p // bad use
|
||||
)
|
||||
... when any
|
||||
return ...;
|
||||
}
|
||||
else S3
|
||||
|
||||
@script:python depends on !context && !org && report@
|
||||
p << r.p;
|
||||
p1 << ifm.p1;
|
||||
x << ifm.E;
|
||||
@@
|
||||
|
||||
msg="ERROR: %s is NULL but dereferenced." % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
cocci.include_match(False)
|
||||
|
||||
@script:python depends on !context && org && !report@
|
||||
p << r.p;
|
||||
p1 << ifm.p1;
|
||||
x << ifm.E;
|
||||
@@
|
||||
|
||||
msg="ERROR: %s is NULL but dereferenced." % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
cocci.print_main(msg_safe,p)
|
||||
cocci.include_match(False)
|
||||
|
||||
@s depends on !context && (org || report) exists@
|
||||
expression subE <= ifm.E;
|
||||
expression *ifm.E;
|
||||
expression E1,E2;
|
||||
identifier f;
|
||||
statement S1,S2,S3,S4;
|
||||
iterator iter;
|
||||
position p!={pr1.p1,pr2.p2};
|
||||
position ifm.p1;
|
||||
@@
|
||||
|
||||
if@p1 ((E == NULL && ...) || ...)
|
||||
{
|
||||
... when != if (...) S1 else S2
|
||||
(
|
||||
iter(subE,...) S4 // no use
|
||||
|
|
||||
list_remove_head(E2,subE,...)
|
||||
|
|
||||
subE = E1
|
||||
|
|
||||
for(subE = E1;...;...) S4
|
||||
|
|
||||
subE++
|
||||
|
|
||||
++subE
|
||||
|
|
||||
--subE
|
||||
|
|
||||
subE--
|
||||
|
|
||||
&subE
|
||||
|
|
||||
E->f@p // bad use
|
||||
)
|
||||
... when any
|
||||
}
|
||||
else S3
|
||||
|
||||
@script:python depends on !context && !org && report@
|
||||
p << s.p;
|
||||
p1 << ifm.p1;
|
||||
x << ifm.E;
|
||||
@@
|
||||
|
||||
msg="ERROR: %s is NULL but dereferenced." % (x)
|
||||
coccilib.report.print_report(p[0], msg)
|
||||
|
||||
@script:python depends on !context && org && !report@
|
||||
p << s.p;
|
||||
p1 << ifm.p1;
|
||||
x << ifm.E;
|
||||
@@
|
||||
|
||||
msg="ERROR: %s is NULL but dereferenced." % (x)
|
||||
msg_safe=msg.replace("[","@(").replace("]",")")
|
||||
cocci.print_main(msg_safe,p)
|
||||
|
||||
// For context mode
|
||||
|
||||
@depends on context && !org && !report exists@
|
||||
expression subE <= ifm.E;
|
||||
expression *ifm.E;
|
||||
expression E1,E2;
|
||||
identifier f;
|
||||
statement S1,S2,S3,S4;
|
||||
iterator iter;
|
||||
position p!={pr1.p1,pr2.p2};
|
||||
position ifm.p1;
|
||||
@@
|
||||
|
||||
if@p1 ((E == NULL && ...) || ...)
|
||||
{
|
||||
... when != if (...) S1 else S2
|
||||
(
|
||||
iter(subE,...) S4 // no use
|
||||
|
|
||||
list_remove_head(E2,subE,...)
|
||||
|
|
||||
subE = E1
|
||||
|
|
||||
for(subE = E1;...;...) S4
|
||||
|
|
||||
subE++
|
||||
|
|
||||
++subE
|
||||
|
|
||||
--subE
|
||||
|
|
||||
subE--
|
||||
|
|
||||
&subE
|
||||
|
|
||||
* E->f@p // bad use
|
||||
)
|
||||
... when any
|
||||
return ...;
|
||||
}
|
||||
else S3
|
||||
|
||||
// The following three rules are duplicates of ifm, pr1 and pr2 respectively.
|
||||
// It is need because the previous rule as already made a "change".
|
||||
|
||||
@ifm1@
|
||||
expression *E;
|
||||
statement S1,S2;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
if@p1 ((E == NULL && ...) || ...) S1 else S2
|
||||
|
||||
@pr11 expression@
|
||||
expression *ifm1.E;
|
||||
identifier f;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
(E != NULL && ...) ? <+...E->f@p1...+> : ...
|
||||
|
||||
@pr12 expression@
|
||||
expression *ifm1.E;
|
||||
identifier f;
|
||||
position p2;
|
||||
@@
|
||||
|
||||
(
|
||||
(E != NULL) && ... && <+...E->f@p2...+>
|
||||
|
|
||||
(E == NULL) || ... || <+...E->f@p2...+>
|
||||
|
|
||||
sizeof(<+...E->f@p2...+>)
|
||||
)
|
||||
|
||||
@depends on context && !org && !report exists@
|
||||
expression subE <= ifm1.E;
|
||||
expression *ifm1.E;
|
||||
expression E1,E2;
|
||||
identifier f;
|
||||
statement S1,S2,S3,S4;
|
||||
iterator iter;
|
||||
position p!={pr11.p1,pr12.p2};
|
||||
position ifm1.p1;
|
||||
@@
|
||||
|
||||
if@p1 ((E == NULL && ...) || ...)
|
||||
{
|
||||
... when != if (...) S1 else S2
|
||||
(
|
||||
iter(subE,...) S4 // no use
|
||||
|
|
||||
list_remove_head(E2,subE,...)
|
||||
|
|
||||
subE = E1
|
||||
|
|
||||
for(subE = E1;...;...) S4
|
||||
|
|
||||
subE++
|
||||
|
|
||||
++subE
|
||||
|
|
||||
--subE
|
||||
|
|
||||
subE--
|
||||
|
|
||||
&subE
|
||||
|
|
||||
* E->f@p // bad use
|
||||
)
|
||||
... when any
|
||||
}
|
||||
else S3
|
48
scripts/coccinelle/null/eno.cocci
Normal file
48
scripts/coccinelle/null/eno.cocci
Normal file
|
@ -0,0 +1,48 @@
|
|||
/// The various basic memory allocation functions don't return ERR_PTR
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
|
||||
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2010-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
|
||||
|
||||
@depends on patch@
|
||||
expression x,E;
|
||||
@@
|
||||
|
||||
x = \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...)
|
||||
... when != x = E
|
||||
- IS_ERR(x)
|
||||
+ !x
|
||||
|
||||
@r depends on !patch exists@
|
||||
expression x,E;
|
||||
position p1,p2;
|
||||
@@
|
||||
|
||||
*x = \(kmalloc@p1\|kzalloc@p1\|kcalloc@p1\|kmem_cache_alloc@p1\|kmem_cache_zalloc@p1\|kmem_cache_alloc_node@p1\|kmalloc_node@p1\|kzalloc_node@p1\)(...)
|
||||
... when != x = E
|
||||
* IS_ERR@p2(x)
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("alloc call",p1)
|
||||
cocci.print_secs("IS_ERR that should be NULL tests",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << r.p1;
|
||||
p2 << r.p2;
|
||||
@@
|
||||
|
||||
msg = "ERROR: allocation function on line %s returns NULL not ERR_PTR on failure" % (p1[0].line)
|
||||
coccilib.report.print_report(p2[0], msg)
|
72
scripts/coccinelle/null/kmerr.cocci
Normal file
72
scripts/coccinelle/null/kmerr.cocci
Normal file
|
@ -0,0 +1,72 @@
|
|||
/// This semantic patch looks for kmalloc etc that are not followed by a
|
||||
/// NULL check. It only gives a report in the case where there is some
|
||||
/// error handling code later in the function, which may be helpful
|
||||
/// in determining what the error handling code for the call to kmalloc etc
|
||||
/// should be.
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@withtest@
|
||||
expression x;
|
||||
position p;
|
||||
identifier f,fld;
|
||||
@@
|
||||
|
||||
x@p = f(...);
|
||||
... when != x->fld
|
||||
\(x == NULL \| x != NULL\)
|
||||
|
||||
@fixed depends on context && !org && !report@
|
||||
expression x,x1;
|
||||
position p1 != withtest.p;
|
||||
statement S;
|
||||
position any withtest.p;
|
||||
identifier f;
|
||||
@@
|
||||
|
||||
*x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...);
|
||||
...
|
||||
*x1@p = f(...);
|
||||
if (!x1) S
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@rfixed depends on (org || report) && !context exists@
|
||||
expression x,x1;
|
||||
position p1 != withtest.p;
|
||||
position p2;
|
||||
statement S;
|
||||
position any withtest.p;
|
||||
identifier f;
|
||||
@@
|
||||
|
||||
x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...);
|
||||
...
|
||||
x1@p = f@p2(...);
|
||||
if (!x1) S
|
||||
|
||||
@script:python depends on org@
|
||||
p1 << rfixed.p1;
|
||||
p2 << rfixed.p2;
|
||||
@@
|
||||
|
||||
cocci.print_main("alloc call",p1)
|
||||
cocci.print_secs("possible model",p2)
|
||||
|
||||
@script:python depends on report@
|
||||
p1 << rfixed.p1;
|
||||
p2 << rfixed.p2;
|
||||
@@
|
||||
|
||||
msg = "alloc with no test, possible model on line %s" % (p2[0].line)
|
||||
coccilib.report.print_report(p1[0],msg)
|
54
scripts/coccinelle/tests/doublebitand.cocci
Normal file
54
scripts/coccinelle/tests/doublebitand.cocci
Normal file
|
@ -0,0 +1,54 @@
|
|||
/// Find bit operations that include the same argument more than once
|
||||
//# One source of false positives is when the argument performs a side
|
||||
//# effect. Another source of false positives is when a neutral value
|
||||
//# such as 0 for | is used to indicate no information, to maintain the
|
||||
//# same structure as other similar expressions
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r expression@
|
||||
expression E;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(
|
||||
* E@p
|
||||
& ... & E
|
||||
|
|
||||
* E@p
|
||||
| ... | E
|
||||
|
|
||||
* E@p
|
||||
& ... & !E
|
||||
|
|
||||
* E@p
|
||||
| ... | !E
|
||||
|
|
||||
* !E@p
|
||||
& ... & E
|
||||
|
|
||||
* !E@p
|
||||
| ... | E
|
||||
)
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
cocci.print_main("duplicated argument to & or |",p)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.report.print_report(p[0],"duplicated argument to & or |")
|
40
scripts/coccinelle/tests/doubletest.cocci
Normal file
40
scripts/coccinelle/tests/doubletest.cocci
Normal file
|
@ -0,0 +1,40 @@
|
|||
/// Find &&/|| operations that include the same argument more than once
|
||||
//# A common source of false positives is when the argument performs a side
|
||||
//# effect.
|
||||
///
|
||||
// Confidence: Moderate
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments:
|
||||
// Options: --no-includes --include-headers
|
||||
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r expression@
|
||||
expression E;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(
|
||||
* E@p
|
||||
|| ... || E
|
||||
|
|
||||
* E@p
|
||||
&& ... && E
|
||||
)
|
||||
|
||||
@script:python depends on org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
cocci.print_main("duplicated argument to && or ||",p)
|
||||
|
||||
@script:python depends on report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
coccilib.report.print_report(p[0],"duplicated argument to && or ||")
|
65
scripts/coccinelle/tests/odd_ptr_err.cocci
Normal file
65
scripts/coccinelle/tests/odd_ptr_err.cocci
Normal file
|
@ -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)
|
225
scripts/config
Executable file
225
scripts/config
Executable file
|
@ -0,0 +1,225 @@
|
|||
#!/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:
|
||||
$myname options command ...
|
||||
commands:
|
||||
--enable|-e option Enable option
|
||||
--disable|-d option Disable option
|
||||
--module|-m option Turn option into a module
|
||||
--set-str option string
|
||||
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
|
||||
Enable option directly after other option
|
||||
--disable-after|-D beforeopt option
|
||||
Disable option directly after other option
|
||||
--module-after|-M beforeopt option
|
||||
Turn option into module directly after other option
|
||||
|
||||
commands can be repeated multiple times
|
||||
|
||||
options:
|
||||
--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.
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
checkarg() {
|
||||
ARG="$1"
|
||||
if [ "$ARG" = "" ] ; then
|
||||
usage
|
||||
fi
|
||||
case "$ARG" in
|
||||
${CONFIG_}*)
|
||||
ARG="${ARG/${CONFIG_}/}"
|
||||
;;
|
||||
esac
|
||||
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() {
|
||||
local name=$1 new=$2 before=$3
|
||||
|
||||
name_re="^($name=|# $name is not set)"
|
||||
before_re="^($before=|# $before is not set)"
|
||||
if test -n "$before" && grep -Eq "$before_re" "$FN"; then
|
||||
txt_append "^$before=" "$new" "$FN"
|
||||
txt_append "^# $before is not set" "$new" "$FN"
|
||||
elif grep -Eq "$name_re" "$FN"; then
|
||||
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
|
||||
usage
|
||||
fi
|
||||
shift 2
|
||||
else
|
||||
FN=.config
|
||||
fi
|
||||
|
||||
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|-E|-D|-M)
|
||||
checkarg "$1"
|
||||
A=$ARG
|
||||
checkarg "$2"
|
||||
B=$ARG
|
||||
shift 2
|
||||
;;
|
||||
-*)
|
||||
checkarg "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
case "$CMD" in
|
||||
--enable|-e)
|
||||
set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=y"
|
||||
;;
|
||||
|
||||
--disable|-d)
|
||||
set_var "${CONFIG_}$ARG" "# ${CONFIG_}$ARG is not set"
|
||||
;;
|
||||
|
||||
--module|-m)
|
||||
set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=m"
|
||||
;;
|
||||
|
||||
--set-str)
|
||||
# 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"
|
||||
shift
|
||||
;;
|
||||
--undefine|-u)
|
||||
undef_var "${CONFIG_}$ARG"
|
||||
;;
|
||||
|
||||
--state|-s)
|
||||
if grep -q "# ${CONFIG_}$ARG is not set" $FN ; then
|
||||
echo n
|
||||
else
|
||||
V="$(grep "^${CONFIG_}$ARG=" $FN)"
|
||||
if [ $? != 0 ] ; then
|
||||
echo undef
|
||||
else
|
||||
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"
|
||||
;;
|
||||
|
||||
--disable-after|-D)
|
||||
set_var "${CONFIG_}$B" "# ${CONFIG_}$B is not set" "${CONFIG_}$A"
|
||||
;;
|
||||
|
||||
--module-after|-M)
|
||||
set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A"
|
||||
;;
|
||||
|
||||
# undocumented because it ignores --file (fixme)
|
||||
--refresh)
|
||||
yes "" | make oldconfig
|
||||
;;
|
||||
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
293
scripts/conmakehash.c
Normal file
293
scripts/conmakehash.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* conmakehash.c
|
||||
*
|
||||
* Create arrays for initializing the kernel folded tables (using a hash
|
||||
* table turned out to be to limiting...) Unfortunately we can't simply
|
||||
* preinitialize the tables at compile time since kfree() cannot accept
|
||||
* memory not allocated by kmalloc(), and doing our own memory management
|
||||
* just for this seems like massive overkill.
|
||||
*
|
||||
* Copyright (C) 1995-1997 H. Peter Anvin
|
||||
*
|
||||
* This program is a part of the Linux kernel, and may be freely
|
||||
* copied under the terms of the GNU General Public License (GPL),
|
||||
* version 2, or at your option any later version.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAX_FONTLEN 256
|
||||
|
||||
typedef unsigned short unicode;
|
||||
|
||||
static void usage(char *argv0)
|
||||
{
|
||||
fprintf(stderr, "Usage: \n"
|
||||
" %s chartable [hashsize] [hashstep] [maxhashlevel]\n", argv0);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
|
||||
static int getunicode(char **p0)
|
||||
{
|
||||
char *p = *p0;
|
||||
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if (*p != 'U' || p[1] != '+' ||
|
||||
!isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
|
||||
!isxdigit(p[5]) || isxdigit(p[6]))
|
||||
return -1;
|
||||
*p0 = p+6;
|
||||
return strtol(p+2,0,16);
|
||||
}
|
||||
|
||||
unicode unitable[MAX_FONTLEN][255];
|
||||
/* Massive overkill, but who cares? */
|
||||
int unicount[MAX_FONTLEN];
|
||||
|
||||
static void addpair(int fp, int un)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( un <= 0xfffe )
|
||||
{
|
||||
/* Check it isn't a duplicate */
|
||||
|
||||
for ( i = 0 ; i < unicount[fp] ; i++ )
|
||||
if ( unitable[fp][i] == un )
|
||||
return;
|
||||
|
||||
/* Add to list */
|
||||
|
||||
if ( unicount[fp] > 254 )
|
||||
{
|
||||
fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
|
||||
unitable[fp][unicount[fp]] = un;
|
||||
unicount[fp]++;
|
||||
}
|
||||
|
||||
/* otherwise: ignore */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *ctbl;
|
||||
char *tblname;
|
||||
char buffer[65536];
|
||||
int fontlen;
|
||||
int i, nuni, nent;
|
||||
int fp0, fp1, un0, un1;
|
||||
char *p, *p1;
|
||||
|
||||
if ( argc < 2 || argc > 5 )
|
||||
usage(argv[0]);
|
||||
|
||||
if ( !strcmp(argv[1],"-") )
|
||||
{
|
||||
ctbl = stdin;
|
||||
tblname = "stdin";
|
||||
}
|
||||
else
|
||||
{
|
||||
ctbl = fopen(tblname = argv[1], "r");
|
||||
if ( !ctbl )
|
||||
{
|
||||
perror(tblname);
|
||||
exit(EX_NOINPUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* For now we assume the default font is always 256 characters. */
|
||||
fontlen = 256;
|
||||
|
||||
/* Initialize table */
|
||||
|
||||
for ( i = 0 ; i < fontlen ; i++ )
|
||||
unicount[i] = 0;
|
||||
|
||||
/* Now we come to the tricky part. Parse the input table. */
|
||||
|
||||
while ( fgets(buffer, sizeof(buffer), ctbl) != NULL )
|
||||
{
|
||||
if ( (p = strchr(buffer, '\n')) != NULL )
|
||||
*p = '\0';
|
||||
else
|
||||
fprintf(stderr, "%s: Warning: line too long\n", tblname);
|
||||
|
||||
p = buffer;
|
||||
|
||||
/*
|
||||
* Syntax accepted:
|
||||
* <fontpos> <unicode> <unicode> ...
|
||||
* <range> idem
|
||||
* <range> <unicode range>
|
||||
*
|
||||
* where <range> ::= <fontpos>-<fontpos>
|
||||
* and <unicode> ::= U+<h><h><h><h>
|
||||
* and <h> ::= <hexadecimal digit>
|
||||
*/
|
||||
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if (!*p || *p == '#')
|
||||
continue; /* skip comment or blank line */
|
||||
|
||||
fp0 = strtol(p, &p1, 0);
|
||||
if (p1 == p)
|
||||
{
|
||||
fprintf(stderr, "Bad input line: %s\n", buffer);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
p = p1;
|
||||
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if (*p == '-')
|
||||
{
|
||||
p++;
|
||||
fp1 = strtol(p, &p1, 0);
|
||||
if (p1 == p)
|
||||
{
|
||||
fprintf(stderr, "Bad input line: %s\n", buffer);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
p = p1;
|
||||
}
|
||||
else
|
||||
fp1 = 0;
|
||||
|
||||
if ( fp0 < 0 || fp0 >= fontlen )
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: Glyph number (0x%x) larger than font length\n",
|
||||
tblname, fp0);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) )
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: Bad end of range (0x%x)\n",
|
||||
tblname, fp1);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
|
||||
if (fp1)
|
||||
{
|
||||
/* we have a range; expect the word "idem" or a Unicode range of the
|
||||
same length */
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if (!strncmp(p, "idem", 4))
|
||||
{
|
||||
for (i=fp0; i<=fp1; i++)
|
||||
addpair(i,i);
|
||||
p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
un0 = getunicode(&p);
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if (*p != '-')
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: Corresponding to a range of font positions, there should be a Unicode range\n",
|
||||
tblname);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
p++;
|
||||
un1 = getunicode(&p);
|
||||
if (un0 < 0 || un1 < 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
|
||||
tblname, fp0, fp1);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
if (un1 - un0 != fp1 - fp0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n",
|
||||
tblname, un0, un1, fp0, fp1);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
for(i=fp0; i<=fp1; i++)
|
||||
addpair(i,un0-fp0+i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no range; expect a list of unicode values for a single font position */
|
||||
|
||||
while ( (un0 = getunicode(&p)) >= 0 )
|
||||
addpair(fp0, un0);
|
||||
}
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if (*p && *p != '#')
|
||||
fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
|
||||
}
|
||||
|
||||
/* 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\
|
||||
*\n\
|
||||
* conmakehash %s > [this file]\n\
|
||||
*\n\
|
||||
*/\n\
|
||||
\n\
|
||||
#include <linux/types.h>\n\
|
||||
\n\
|
||||
u8 dfont_unicount[%d] = \n\
|
||||
{\n\t", argv[1], fontlen);
|
||||
|
||||
for ( i = 0 ; i < fontlen ; i++ )
|
||||
{
|
||||
printf("%3d", unicount[i]);
|
||||
if ( i == fontlen-1 )
|
||||
printf("\n};\n");
|
||||
else if ( i % 8 == 7 )
|
||||
printf(",\n\t");
|
||||
else
|
||||
printf(", ");
|
||||
}
|
||||
|
||||
printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni);
|
||||
|
||||
fp0 = 0;
|
||||
nent = 0;
|
||||
for ( i = 0 ; i < nuni ; i++ )
|
||||
{
|
||||
while ( nent >= unicount[fp0] )
|
||||
{
|
||||
fp0++;
|
||||
nent = 0;
|
||||
}
|
||||
printf("0x%04x", unitable[fp0][nent++]);
|
||||
if ( i == nuni-1 )
|
||||
printf("\n};\n");
|
||||
else if ( i % 8 == 7 )
|
||||
printf(",\n\t");
|
||||
else
|
||||
printf(", ");
|
||||
}
|
||||
|
||||
exit(EX_OK);
|
||||
}
|
126
scripts/decode_stacktrace.sh
Executable file
126
scripts/decode_stacktrace.sh
Executable file
|
@ -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
|
104
scripts/decodecode
Executable file
104
scripts/decodecode
Executable file
|
@ -0,0 +1,104 @@
|
|||
#!/bin/sh
|
||||
# Disassemble the Code: line in Linux oopses
|
||||
# usage: decodecode < oops.file
|
||||
#
|
||||
# options: set env. variable AFLAGS=options to pass options to "as";
|
||||
# e.g., to decode an i386 oops on an x86_64 system, use:
|
||||
# AFLAGS=--32 decodecode < 386.oops
|
||||
|
||||
cleanup() {
|
||||
rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
|
||||
exit 1
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
T=`mktemp` || die "cannot create temp file"
|
||||
code=
|
||||
|
||||
while read i ; do
|
||||
|
||||
case "$i" in
|
||||
*Code:*)
|
||||
code=$i
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
if [ -z "$code" ]; then
|
||||
rm $T
|
||||
exit
|
||||
fi
|
||||
|
||||
echo $code
|
||||
code=`echo $code | sed -e 's/.*Code: //'`
|
||||
|
||||
width=`expr index "$code" ' '`
|
||||
width=$((($width-1)/2))
|
||||
case $width in
|
||||
1) type=byte ;;
|
||||
2) type=2byte ;;
|
||||
4) type=4byte ;;
|
||||
esac
|
||||
|
||||
disas() {
|
||||
${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s > /dev/null 2>&1
|
||||
|
||||
if [ "$ARCH" = "arm" ]; then
|
||||
if [ $width -eq 2 ]; then
|
||||
OBJDUMPFLAGS="-M force-thumb"
|
||||
fi
|
||||
|
||||
${CROSS_COMPILE}strip $1.o
|
||||
fi
|
||||
|
||||
${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \
|
||||
grep -v "/tmp\|Disassembly\|\.text\|^$" > $1.dis 2>&1
|
||||
}
|
||||
|
||||
marker=`expr index "$code" "\<"`
|
||||
if [ $marker -eq 0 ]; then
|
||||
marker=`expr index "$code" "\("`
|
||||
fi
|
||||
|
||||
touch $T.oo
|
||||
if [ $marker -ne 0 ]; then
|
||||
echo All code >> $T.oo
|
||||
echo ======== >> $T.oo
|
||||
beforemark=`echo "$code"`
|
||||
echo -n " .$type 0x" > $T.s
|
||||
echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
|
||||
disas $T
|
||||
cat $T.dis >> $T.oo
|
||||
rm -f $T.o $T.s $T.dis
|
||||
|
||||
# and fix code at-and-after marker
|
||||
code=`echo "$code" | cut -c$((${marker} + 1))-`
|
||||
fi
|
||||
echo Code starting with the faulting instruction > $T.aa
|
||||
echo =========================================== >> $T.aa
|
||||
code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
|
||||
echo -n " .$type 0x" > $T.s
|
||||
echo $code >> $T.s
|
||||
disas $T
|
||||
cat $T.dis >> $T.aa
|
||||
|
||||
# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
|
||||
# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is
|
||||
# special)
|
||||
faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \
|
||||
$(wc -l $T.aa | cut -d" " -f1) + 3))
|
||||
|
||||
faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
|
||||
faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
|
||||
|
||||
cat $T.oo | sed -e "${faultlinenum}s/^\(.*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
|
||||
echo
|
||||
cat $T.aa
|
||||
cleanup
|
64
scripts/depmod.sh
Executable file
64
scripts/depmod.sh
Executable file
|
@ -0,0 +1,64 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# A depmod wrapper used by the toplevel Makefile
|
||||
|
||||
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
|
||||
tmp_dir=$(mktemp -d ${TMPDIR:-/tmp}/depmod.XXXXXX)
|
||||
mkdir -p "$tmp_dir/lib/modules/$KERNELRELEASE"
|
||||
if "$DEPMOD" -b "$tmp_dir" $KERNELRELEASE 2>/dev/null; then
|
||||
if test -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep" -o \
|
||||
-e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep.bin"; then
|
||||
depmod_hack_needed=false
|
||||
fi
|
||||
fi
|
||||
rm -rf "$tmp_dir"
|
||||
if $depmod_hack_needed; then
|
||||
symlink="$INSTALL_MOD_PATH/lib/modules/99.98.$KERNELRELEASE"
|
||||
ln -s "$KERNELRELEASE" "$symlink"
|
||||
KERNELRELEASE=99.98.$KERNELRELEASE
|
||||
fi
|
||||
|
||||
set -- -ae -F System.map
|
||||
if test -n "$INSTALL_MOD_PATH"; then
|
||||
set -- "$@" -b "$INSTALL_MOD_PATH"
|
||||
fi
|
||||
"$DEPMOD" "$@" "$KERNELRELEASE" $SYMBOL_PREFIX
|
||||
ret=$?
|
||||
|
||||
if $depmod_hack_needed; then
|
||||
rm -f "$symlink"
|
||||
fi
|
||||
|
||||
exit $ret
|
132
scripts/diffconfig
Executable file
132
scripts/diffconfig
Executable file
|
@ -0,0 +1,132 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# diffconfig - a tool to compare .config files.
|
||||
#
|
||||
# originally written in 2006 by Matt Mackall
|
||||
# (at least, this was in his bloatwatch source code)
|
||||
# last worked on 2008 by Tim Bird
|
||||
#
|
||||
|
||||
import sys, os
|
||||
|
||||
def usage():
|
||||
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
|
||||
distracting information. This utility produces sorted output with only the
|
||||
changes in configuration values between the two files.
|
||||
|
||||
Added and removed items are shown with a leading plus or minus, respectively.
|
||||
Changed items show the old and new values on a single line.
|
||||
|
||||
If -m is specified, then output will be in "merge" style, which has the
|
||||
changed and new values in kernel config option format.
|
||||
|
||||
If no config files are specified, .config and .config.old are used.
|
||||
|
||||
Example usage:
|
||||
$ diffconfig .config config-with-some-changes
|
||||
-EXT2_FS_XATTR n
|
||||
-EXT2_FS_XIP n
|
||||
CRAMFS n -> y
|
||||
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
|
||||
def readconfig(config_file):
|
||||
d = {}
|
||||
for line in config_file:
|
||||
line = line[:-1]
|
||||
if line[:7] == "CONFIG_":
|
||||
name, val = line[7:].split("=", 1)
|
||||
d[name] = val
|
||||
if line[-11:] == " is not set":
|
||||
d[line[9:-11]] = "n"
|
||||
return d
|
||||
|
||||
def print_config(op, config, value, new_value):
|
||||
global merge_style
|
||||
|
||||
if merge_style:
|
||||
if new_value:
|
||||
if new_value=="n":
|
||||
print("# CONFIG_%s is not set" % config)
|
||||
else:
|
||||
print("CONFIG_%s=%s" % (config, new_value))
|
||||
else:
|
||||
if op=="-":
|
||||
print("-%s %s" % (config, value))
|
||||
elif op=="+":
|
||||
print("+%s %s" % (config, new_value))
|
||||
else:
|
||||
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()
|
||||
|
||||
merge_style = 0
|
||||
if "-m" in sys.argv:
|
||||
merge_style = 1
|
||||
sys.argv.remove("-m")
|
||||
|
||||
argc = len(sys.argv)
|
||||
if not (argc==1 or argc == 3):
|
||||
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 "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]
|
||||
|
||||
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 = []
|
||||
for config in a:
|
||||
if config not in b:
|
||||
old.append(config)
|
||||
old.sort()
|
||||
for config in old:
|
||||
print_config("-", config, a[config], None)
|
||||
del a[config]
|
||||
|
||||
# print items that changed (accumulate, sort, and print)
|
||||
changed = []
|
||||
for config in a:
|
||||
if a[config] != b[config]:
|
||||
changed.append(config)
|
||||
else:
|
||||
del b[config]
|
||||
changed.sort()
|
||||
for config in changed:
|
||||
print_config("->", config, a[config], b[config])
|
||||
del b[config]
|
||||
|
||||
# now print items in b but not in a
|
||||
# (items from b that were in a were removed above)
|
||||
new = sorted(b.keys())
|
||||
for config in new:
|
||||
print_config("+", config, None, b[config])
|
||||
|
||||
main()
|
580
scripts/docproc.c
Normal file
580
scripts/docproc.c
Normal file
|
@ -0,0 +1,580 @@
|
|||
/*
|
||||
* docproc is a simple preprocessor for the template files
|
||||
* used as placeholders for the kernel internal documentation.
|
||||
* docproc is used for documentation-frontend and
|
||||
* dependency-generator.
|
||||
* The two usages have in common that they require
|
||||
* some knowledge of the .tmpl syntax, therefore they
|
||||
* are kept together.
|
||||
*
|
||||
* documentation-frontend
|
||||
* Scans the template file and call kernel-doc for
|
||||
* all occurrences of ![EIF]file
|
||||
* Beforehand each referenced file is scanned for
|
||||
* any symbols that are exported via these macros:
|
||||
* EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), &
|
||||
* EXPORT_SYMBOL_GPL_FUTURE()
|
||||
* This is used to create proper -function and
|
||||
* -nofunction arguments in calls to kernel-doc.
|
||||
* Usage: docproc doc file.tmpl
|
||||
*
|
||||
* dependency-generator:
|
||||
* Scans the template file and list all files
|
||||
* referenced in a format recognized by make.
|
||||
* Usage: docproc depend file.tmpl
|
||||
* Writes dependency information to stdout
|
||||
* in the following format:
|
||||
* file.tmpl src.c src2.c
|
||||
* The filenames are obtained from the following constructs:
|
||||
* !Efilename
|
||||
* !Ifilename
|
||||
* !Dfilename
|
||||
* !Ffilename
|
||||
* !Pfilename
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* exitstatus is used to keep track of any failing calls to kernel-doc,
|
||||
* but execution continues. */
|
||||
int exitstatus = 0;
|
||||
|
||||
typedef void DFL(char *);
|
||||
DFL *defaultline;
|
||||
|
||||
typedef void FILEONLY(char * file);
|
||||
FILEONLY *internalfunctions;
|
||||
FILEONLY *externalfunctions;
|
||||
FILEONLY *symbolsonly;
|
||||
FILEONLY *findall;
|
||||
|
||||
typedef void FILELINE(char * file, char * line);
|
||||
FILELINE * singlefunctions;
|
||||
FILELINE * entity_system;
|
||||
FILELINE * docsection;
|
||||
|
||||
#define MAXLINESZ 2048
|
||||
#define MAXFILES 250
|
||||
#define KERNELDOCPATH "scripts/"
|
||||
#define KERNELDOC "kernel-doc"
|
||||
#define DOCBOOK "-docbook"
|
||||
#define LIST "-list"
|
||||
#define FUNCTION "-function"
|
||||
#define NOFUNCTION "-nofunction"
|
||||
#define NODOCSECTIONS "-no-doc-sections"
|
||||
#define SHOWNOTFOUND "-show-not-found"
|
||||
|
||||
static char *srctree, *kernsrctree;
|
||||
|
||||
static char **all_list = NULL;
|
||||
static int all_list_len = 0;
|
||||
|
||||
static void consume_symbol(const char *sym)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < all_list_len; i++) {
|
||||
if (!all_list[i])
|
||||
continue;
|
||||
if (strcmp(sym, all_list[i]))
|
||||
continue;
|
||||
all_list[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void usage (void)
|
||||
{
|
||||
fprintf(stderr, "Usage: docproc {doc|depend} file\n");
|
||||
fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
|
||||
fprintf(stderr, "doc: frontend when generating kernel documentation\n");
|
||||
fprintf(stderr, "depend: generate list of files referenced within file\n");
|
||||
fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
|
||||
fprintf(stderr, " KBUILD_SRC: absolute path to kernel source tree.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute kernel-doc with parameters given in svec
|
||||
*/
|
||||
static void exec_kernel_doc(char **svec)
|
||||
{
|
||||
pid_t pid;
|
||||
int ret;
|
||||
char real_filename[PATH_MAX + 1];
|
||||
/* Make sure output generated so far are flushed */
|
||||
fflush(stdout);
|
||||
switch (pid=fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
case 0:
|
||||
memset(real_filename, 0, sizeof(real_filename));
|
||||
strncat(real_filename, kernsrctree, PATH_MAX);
|
||||
strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
|
||||
PATH_MAX - strlen(real_filename));
|
||||
execvp(real_filename, svec);
|
||||
fprintf(stderr, "exec ");
|
||||
perror(real_filename);
|
||||
exit(1);
|
||||
default:
|
||||
waitpid(pid, &ret ,0);
|
||||
}
|
||||
if (WIFEXITED(ret))
|
||||
exitstatus |= WEXITSTATUS(ret);
|
||||
else
|
||||
exitstatus = 0xff;
|
||||
}
|
||||
|
||||
/* Types used to create list of all exported symbols in a number of files */
|
||||
struct symbols
|
||||
{
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct symfile
|
||||
{
|
||||
char *filename;
|
||||
struct symbols *symbollist;
|
||||
int symbolcnt;
|
||||
};
|
||||
|
||||
struct symfile symfilelist[MAXFILES];
|
||||
int symfilecnt = 0;
|
||||
|
||||
static void add_new_symbol(struct symfile *sym, char * symname)
|
||||
{
|
||||
sym->symbollist =
|
||||
realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
|
||||
sym->symbollist[sym->symbolcnt++].name = strdup(symname);
|
||||
}
|
||||
|
||||
/* Add a filename to the list */
|
||||
static struct symfile * add_new_file(char * filename)
|
||||
{
|
||||
symfilelist[symfilecnt++].filename = strdup(filename);
|
||||
return &symfilelist[symfilecnt - 1];
|
||||
}
|
||||
|
||||
/* Check if file already are present in the list */
|
||||
static struct symfile * filename_exist(char * filename)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < symfilecnt; i++)
|
||||
if (strcmp(symfilelist[i].filename, filename) == 0)
|
||||
return &symfilelist[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* List all files referenced within the template file.
|
||||
* Files are separated by tabs.
|
||||
*/
|
||||
static void adddep(char * file) { printf("\t%s", file); }
|
||||
static void adddep2(char * file, char * line) { line = line; adddep(file); }
|
||||
static void noaction(char * line) { line = line; }
|
||||
static void noaction2(char * file, char * line) { file = file; line = line; }
|
||||
|
||||
/* Echo the line without further action */
|
||||
static void printline(char * line) { printf("%s", line); }
|
||||
|
||||
/*
|
||||
* Find all symbols in filename that are exported with EXPORT_SYMBOL &
|
||||
* EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
|
||||
* All symbols located are stored in symfilelist.
|
||||
*/
|
||||
static void find_export_symbols(char * filename)
|
||||
{
|
||||
FILE * fp;
|
||||
struct symfile *sym;
|
||||
char line[MAXLINESZ];
|
||||
if (filename_exist(filename) == NULL) {
|
||||
char real_filename[PATH_MAX + 1];
|
||||
memset(real_filename, 0, sizeof(real_filename));
|
||||
strncat(real_filename, srctree, PATH_MAX);
|
||||
strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
|
||||
strncat(real_filename, filename,
|
||||
PATH_MAX - strlen(real_filename));
|
||||
sym = add_new_file(filename);
|
||||
fp = fopen(real_filename, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "docproc: ");
|
||||
perror(real_filename);
|
||||
exit(1);
|
||||
}
|
||||
while (fgets(line, MAXLINESZ, fp)) {
|
||||
char *p;
|
||||
char *e;
|
||||
if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
|
||||
((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
|
||||
/* Skip EXPORT_SYMBOL{_GPL} */
|
||||
while (isalnum(*p) || *p == '_')
|
||||
p++;
|
||||
/* Remove parentheses & additional whitespace */
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
if (*p != '(')
|
||||
continue; /* Syntax error? */
|
||||
else
|
||||
p++;
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
e = p;
|
||||
while (isalnum(*e) || *e == '_')
|
||||
e++;
|
||||
*e = '\0';
|
||||
add_new_symbol(sym, p);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Document all external or internal functions in a file.
|
||||
* Call kernel-doc with following parameters:
|
||||
* kernel-doc -docbook -nofunction function_name1 filename
|
||||
* Function names are obtained from all the src files
|
||||
* by find_export_symbols.
|
||||
* intfunc uses -nofunction
|
||||
* extfunc uses -function
|
||||
*/
|
||||
static void docfunctions(char * filename, char * type)
|
||||
{
|
||||
int i,j;
|
||||
int symcnt = 0;
|
||||
int idx = 0;
|
||||
char **vec;
|
||||
|
||||
for (i=0; i <= symfilecnt; i++)
|
||||
symcnt += symfilelist[i].symbolcnt;
|
||||
vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
|
||||
if (vec == NULL) {
|
||||
perror("docproc: ");
|
||||
exit(1);
|
||||
}
|
||||
vec[idx++] = KERNELDOC;
|
||||
vec[idx++] = DOCBOOK;
|
||||
vec[idx++] = NODOCSECTIONS;
|
||||
for (i=0; i < symfilecnt; i++) {
|
||||
struct symfile * sym = &symfilelist[i];
|
||||
for (j=0; j < sym->symbolcnt; j++) {
|
||||
vec[idx++] = type;
|
||||
consume_symbol(sym->symbollist[j].name);
|
||||
vec[idx++] = sym->symbollist[j].name;
|
||||
}
|
||||
}
|
||||
vec[idx++] = filename;
|
||||
vec[idx] = NULL;
|
||||
printf("<!-- %s -->\n", filename);
|
||||
exec_kernel_doc(vec);
|
||||
fflush(stdout);
|
||||
free(vec);
|
||||
}
|
||||
static void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); }
|
||||
static void extfunc(char * filename) { docfunctions(filename, FUNCTION); }
|
||||
|
||||
/*
|
||||
* Document specific function(s) in a file.
|
||||
* Call kernel-doc with the following parameters:
|
||||
* kernel-doc -docbook -function function1 [-function function2]
|
||||
*/
|
||||
static void singfunc(char * filename, char * line)
|
||||
{
|
||||
char *vec[200]; /* Enough for specific functions */
|
||||
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];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < idx; i++) {
|
||||
if (strcmp(vec[i], FUNCTION))
|
||||
continue;
|
||||
consume_symbol(vec[i + 1]);
|
||||
}
|
||||
vec[idx++] = filename;
|
||||
vec[idx] = NULL;
|
||||
exec_kernel_doc(vec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert specific documentation section from a file.
|
||||
* Call kernel-doc with the following parameters:
|
||||
* kernel-doc -docbook -function "doc section" filename
|
||||
*/
|
||||
static void docsect(char *filename, char *line)
|
||||
{
|
||||
/* kerneldoc -docbook -show-not-found -function "section" file NULL */
|
||||
char *vec[7];
|
||||
char *s;
|
||||
|
||||
for (s = line; *s; s++)
|
||||
if (*s == '\n')
|
||||
*s = '\0';
|
||||
|
||||
if (asprintf(&s, "DOC: %s", line) < 0) {
|
||||
perror("asprintf");
|
||||
exit(1);
|
||||
}
|
||||
consume_symbol(s);
|
||||
free(s);
|
||||
|
||||
vec[0] = KERNELDOC;
|
||||
vec[1] = DOCBOOK;
|
||||
vec[2] = SHOWNOTFOUND;
|
||||
vec[3] = FUNCTION;
|
||||
vec[4] = line;
|
||||
vec[5] = filename;
|
||||
vec[6] = NULL;
|
||||
exec_kernel_doc(vec);
|
||||
}
|
||||
|
||||
static void find_all_symbols(char *filename)
|
||||
{
|
||||
char *vec[4]; /* kerneldoc -list file NULL */
|
||||
pid_t pid;
|
||||
int ret, i, count, start;
|
||||
char real_filename[PATH_MAX + 1];
|
||||
int pipefd[2];
|
||||
char *data, *str;
|
||||
size_t data_len = 0;
|
||||
|
||||
vec[0] = KERNELDOC;
|
||||
vec[1] = LIST;
|
||||
vec[2] = filename;
|
||||
vec[3] = NULL;
|
||||
|
||||
if (pipe(pipefd)) {
|
||||
perror("pipe");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (pid=fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
case 0:
|
||||
close(pipefd[0]);
|
||||
dup2(pipefd[1], 1);
|
||||
memset(real_filename, 0, sizeof(real_filename));
|
||||
strncat(real_filename, kernsrctree, PATH_MAX);
|
||||
strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
|
||||
PATH_MAX - strlen(real_filename));
|
||||
execvp(real_filename, vec);
|
||||
fprintf(stderr, "exec ");
|
||||
perror(real_filename);
|
||||
exit(1);
|
||||
default:
|
||||
close(pipefd[1]);
|
||||
data = malloc(4096);
|
||||
do {
|
||||
while ((ret = read(pipefd[0],
|
||||
data + data_len,
|
||||
4096)) > 0) {
|
||||
data_len += ret;
|
||||
data = realloc(data, data_len + 4096);
|
||||
}
|
||||
} while (ret == -EAGAIN);
|
||||
if (ret != 0) {
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
waitpid(pid, &ret ,0);
|
||||
}
|
||||
if (WIFEXITED(ret))
|
||||
exitstatus |= WEXITSTATUS(ret);
|
||||
else
|
||||
exitstatus = 0xff;
|
||||
|
||||
count = 0;
|
||||
/* poor man's strtok, but with counting */
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if (data[i] == '\n') {
|
||||
count++;
|
||||
data[i] = '\0';
|
||||
}
|
||||
}
|
||||
start = all_list_len;
|
||||
all_list_len += count;
|
||||
all_list = realloc(all_list, sizeof(char *) * all_list_len);
|
||||
str = data;
|
||||
for (i = 0; i < data_len && start != all_list_len; i++) {
|
||||
if (data[i] == '\0') {
|
||||
all_list[start] = str;
|
||||
str = data + i + 1;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse file, calling action specific functions for:
|
||||
* 1) Lines containing !E
|
||||
* 2) Lines containing !I
|
||||
* 3) Lines containing !D
|
||||
* 4) Lines containing !F
|
||||
* 5) Lines containing !P
|
||||
* 6) Lines containing !C
|
||||
* 7) Default lines - lines not matching the above
|
||||
*/
|
||||
static void parse_file(FILE *infile)
|
||||
{
|
||||
char line[MAXLINESZ];
|
||||
char * s;
|
||||
while (fgets(line, MAXLINESZ, infile)) {
|
||||
if (line[0] == '!') {
|
||||
s = line + 2;
|
||||
switch (line[1]) {
|
||||
case 'E':
|
||||
while (*s && !isspace(*s)) s++;
|
||||
*s = '\0';
|
||||
externalfunctions(line+2);
|
||||
break;
|
||||
case 'I':
|
||||
while (*s && !isspace(*s)) s++;
|
||||
*s = '\0';
|
||||
internalfunctions(line+2);
|
||||
break;
|
||||
case 'D':
|
||||
while (*s && !isspace(*s)) s++;
|
||||
*s = '\0';
|
||||
symbolsonly(line+2);
|
||||
break;
|
||||
case 'F':
|
||||
/* filename */
|
||||
while (*s && !isspace(*s)) s++;
|
||||
*s++ = '\0';
|
||||
/* function names */
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
singlefunctions(line +2, s);
|
||||
break;
|
||||
case 'P':
|
||||
/* filename */
|
||||
while (*s && !isspace(*s)) s++;
|
||||
*s++ = '\0';
|
||||
/* DOC: section name */
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
docsection(line + 2, s);
|
||||
break;
|
||||
case 'C':
|
||||
while (*s && !isspace(*s)) s++;
|
||||
*s = '\0';
|
||||
if (findall)
|
||||
findall(line+2);
|
||||
break;
|
||||
default:
|
||||
defaultline(line);
|
||||
}
|
||||
} else {
|
||||
defaultline(line);
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE * infile;
|
||||
int i;
|
||||
|
||||
srctree = getenv("SRCTREE");
|
||||
if (!srctree)
|
||||
srctree = getcwd(NULL, 0);
|
||||
kernsrctree = getenv("KBUILD_SRC");
|
||||
if (!kernsrctree || !*kernsrctree)
|
||||
kernsrctree = srctree;
|
||||
if (argc != 3) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
/* Open file, exit on error */
|
||||
infile = fopen(argv[2], "r");
|
||||
if (infile == NULL) {
|
||||
fprintf(stderr, "docproc: ");
|
||||
perror(argv[2]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (strcmp("doc", argv[1]) == 0) {
|
||||
/* Need to do this in two passes.
|
||||
* First pass is used to collect all symbols exported
|
||||
* in the various files;
|
||||
* Second pass generate the documentation.
|
||||
* This is required because some functions are declared
|
||||
* and exported in different files :-((
|
||||
*/
|
||||
/* Collect symbols */
|
||||
defaultline = noaction;
|
||||
internalfunctions = find_export_symbols;
|
||||
externalfunctions = find_export_symbols;
|
||||
symbolsonly = find_export_symbols;
|
||||
singlefunctions = noaction2;
|
||||
docsection = noaction2;
|
||||
findall = find_all_symbols;
|
||||
parse_file(infile);
|
||||
|
||||
/* Rewind to start from beginning of file again */
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
defaultline = printline;
|
||||
internalfunctions = intfunc;
|
||||
externalfunctions = extfunc;
|
||||
symbolsonly = printline;
|
||||
singlefunctions = singfunc;
|
||||
docsection = docsect;
|
||||
findall = NULL;
|
||||
|
||||
parse_file(infile);
|
||||
|
||||
for (i = 0; i < all_list_len; i++) {
|
||||
if (!all_list[i])
|
||||
continue;
|
||||
fprintf(stderr, "Warning: didn't use docs for %s\n",
|
||||
all_list[i]);
|
||||
}
|
||||
} else if (strcmp("depend", argv[1]) == 0) {
|
||||
/* Create first part of dependency chain
|
||||
* file.tmpl */
|
||||
printf("%s\t", argv[2]);
|
||||
defaultline = noaction;
|
||||
internalfunctions = adddep;
|
||||
externalfunctions = adddep;
|
||||
symbolsonly = adddep;
|
||||
singlefunctions = adddep2;
|
||||
docsection = adddep2;
|
||||
findall = adddep;
|
||||
parse_file(infile);
|
||||
printf("\n");
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
fclose(infile);
|
||||
fflush(stdout);
|
||||
return exitstatus;
|
||||
}
|
31
scripts/dtc/Makefile
Normal file
31
scripts/dtc/Makefile
Normal file
|
@ -0,0 +1,31 @@
|
|||
# scripts/dtc makefile
|
||||
|
||||
hostprogs-y := dtc
|
||||
always := $(hostprogs-y)
|
||||
|
||||
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
|
||||
srcpos.o checks.o util.o
|
||||
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
|
||||
|
||||
# Source files need to get at the userspace version of libfdt_env.h to compile
|
||||
|
||||
HOSTCFLAGS_DTC := -I$(src) -I$(src)/libfdt
|
||||
|
||||
HOSTCFLAGS_checks.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_data.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_dtc.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_flattree.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
|
||||
|
||||
HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC)
|
||||
|
||||
# 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
|
18
scripts/dtc/Makefile.dtc
Normal file
18
scripts/dtc/Makefile.dtc
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Makefile.dtc
|
||||
#
|
||||
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||
# be easily embeddable into other systems of Makefiles.
|
||||
#
|
||||
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)
|
759
scripts/dtc/checks.c
Normal file
759
scripts/dtc/checks.c
Normal file
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007.
|
||||
*
|
||||
*
|
||||
* 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 "dtc.h"
|
||||
|
||||
#ifdef TRACE_CHECKS
|
||||
#define TRACE(c, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "=== %s: ", (c)->name); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define TRACE(c, fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
enum checkstatus {
|
||||
UNCHECKED = 0,
|
||||
PREREQ,
|
||||
PASSED,
|
||||
FAILED,
|
||||
};
|
||||
|
||||
struct check;
|
||||
|
||||
typedef void (*tree_check_fn)(struct check *c, struct node *dt);
|
||||
typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
|
||||
typedef void (*prop_check_fn)(struct check *c, struct node *dt,
|
||||
struct node *node, struct property *prop);
|
||||
|
||||
struct check {
|
||||
const char *name;
|
||||
tree_check_fn tree_fn;
|
||||
node_check_fn node_fn;
|
||||
prop_check_fn prop_fn;
|
||||
void *data;
|
||||
bool warn, error;
|
||||
enum checkstatus status;
|
||||
int inprogress;
|
||||
int num_prereqs;
|
||||
struct check **prereq;
|
||||
};
|
||||
|
||||
#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
|
||||
static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
|
||||
static struct check nm = { \
|
||||
.name = #nm, \
|
||||
.tree_fn = (tfn), \
|
||||
.node_fn = (nfn), \
|
||||
.prop_fn = (pfn), \
|
||||
.data = (d), \
|
||||
.warn = (w), \
|
||||
.error = (e), \
|
||||
.status = UNCHECKED, \
|
||||
.num_prereqs = ARRAY_SIZE(nm##_prereqs), \
|
||||
.prereq = nm##_prereqs, \
|
||||
};
|
||||
#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)));
|
||||
#endif
|
||||
static inline void check_msg(struct check *c, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
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, ...) \
|
||||
do { \
|
||||
TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
|
||||
(c)->status = FAILED; \
|
||||
check_msg((c), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
|
||||
{
|
||||
struct node *child;
|
||||
struct property *prop;
|
||||
|
||||
TRACE(c, "%s", node->fullpath);
|
||||
if (c->node_fn)
|
||||
c->node_fn(c, dt, node);
|
||||
|
||||
if (c->prop_fn)
|
||||
for_each_property(node, prop) {
|
||||
TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
|
||||
c->prop_fn(c, dt, node, prop);
|
||||
}
|
||||
|
||||
for_each_child(node, child)
|
||||
check_nodes_props(c, dt, child);
|
||||
}
|
||||
|
||||
static int run_check(struct check *c, struct node *dt)
|
||||
{
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
assert(!c->inprogress);
|
||||
|
||||
if (c->status != UNCHECKED)
|
||||
goto out;
|
||||
|
||||
c->inprogress = 1;
|
||||
|
||||
for (i = 0; i < c->num_prereqs; i++) {
|
||||
struct check *prq = c->prereq[i];
|
||||
error |= run_check(prq, dt);
|
||||
if (prq->status != PASSED) {
|
||||
c->status = PREREQ;
|
||||
check_msg(c, "Failed prerequisite '%s'",
|
||||
c->prereq[i]->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (c->status != UNCHECKED)
|
||||
goto out;
|
||||
|
||||
if (c->node_fn || c->prop_fn)
|
||||
check_nodes_props(c, dt, dt);
|
||||
|
||||
if (c->tree_fn)
|
||||
c->tree_fn(c, dt);
|
||||
if (c->status == UNCHECKED)
|
||||
c->status = PASSED;
|
||||
|
||||
TRACE(c, "\tCompleted, status %d", c->status);
|
||||
|
||||
out:
|
||||
c->inprogress = 0;
|
||||
if ((c->status != PASSED) && (c->error))
|
||||
error = 1;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
struct property *prop;
|
||||
char *propname = c->data;
|
||||
|
||||
prop = get_property(node, propname);
|
||||
if (!prop)
|
||||
return; /* Not present, assumed ok */
|
||||
|
||||
if (!data_is_one_string(prop->val))
|
||||
FAIL(c, "\"%s\" property in %s is not a string",
|
||||
propname, node->fullpath);
|
||||
}
|
||||
#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)
|
||||
{
|
||||
struct property *prop;
|
||||
char *propname = c->data;
|
||||
|
||||
prop = get_property(node, propname);
|
||||
if (!prop)
|
||||
return; /* Not present, assumed ok */
|
||||
|
||||
if (prop->val.len != sizeof(cell_t))
|
||||
FAIL(c, "\"%s\" property in %s is not a single cell",
|
||||
propname, node->fullpath);
|
||||
}
|
||||
#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
|
||||
*/
|
||||
|
||||
static void check_duplicate_node_names(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
struct node *child, *child2;
|
||||
|
||||
for_each_child(node, child)
|
||||
for (child2 = child->next_sibling;
|
||||
child2;
|
||||
child2 = child2->next_sibling)
|
||||
if (streq(child->name, child2->name))
|
||||
FAIL(c, "Duplicate node name %s",
|
||||
child->fullpath);
|
||||
}
|
||||
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) {
|
||||
if (prop2->deleted)
|
||||
continue;
|
||||
if (streq(prop->name, prop2->name))
|
||||
FAIL(c, "Duplicate property name %s in %s",
|
||||
prop->name, node->fullpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
NODE_ERROR(duplicate_property_names, NULL);
|
||||
|
||||
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
|
||||
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
#define DIGITS "0123456789"
|
||||
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
|
||||
|
||||
static void check_node_name_chars(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
int n = strspn(node->name, c->data);
|
||||
|
||||
if (n < strlen(node->name))
|
||||
FAIL(c, "Bad character '%c' in node %s",
|
||||
node->name[n], node->fullpath);
|
||||
}
|
||||
NODE_ERROR(node_name_chars, PROPNODECHARS "@");
|
||||
|
||||
static void check_node_name_format(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
if (strchr(get_unitname(node), '@'))
|
||||
FAIL(c, "Node %s has multiple '@' characters in name",
|
||||
node->fullpath);
|
||||
}
|
||||
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)
|
||||
{
|
||||
int n = strspn(prop->name, c->data);
|
||||
|
||||
if (n < strlen(prop->name))
|
||||
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
|
||||
prop->name[n], prop->name, node->fullpath);
|
||||
}
|
||||
PROP_ERROR(property_name_chars, PROPNODECHARS);
|
||||
|
||||
#define DESCLABEL_FMT "%s%s%s%s%s"
|
||||
#define DESCLABEL_ARGS(node,prop,mark) \
|
||||
((mark) ? "value of " : ""), \
|
||||
((prop) ? "'" : ""), \
|
||||
((prop) ? (prop)->name : ""), \
|
||||
((prop) ? "' in " : ""), (node)->fullpath
|
||||
|
||||
static void check_duplicate_label(struct check *c, struct node *dt,
|
||||
const char *label, struct node *node,
|
||||
struct property *prop, struct marker *mark)
|
||||
{
|
||||
struct node *othernode = NULL;
|
||||
struct property *otherprop = NULL;
|
||||
struct marker *othermark = NULL;
|
||||
|
||||
othernode = get_node_by_label(dt, label);
|
||||
|
||||
if (!othernode)
|
||||
otherprop = get_property_by_label(dt, label, &othernode);
|
||||
if (!othernode)
|
||||
othermark = get_marker_label(dt, label, &othernode,
|
||||
&otherprop);
|
||||
|
||||
if (!othernode)
|
||||
return;
|
||||
|
||||
if ((othernode != node) || (otherprop != prop) || (othermark != mark))
|
||||
FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
|
||||
" and " DESCLABEL_FMT,
|
||||
label, DESCLABEL_ARGS(node, prop, mark),
|
||||
DESCLABEL_ARGS(othernode, otherprop, othermark));
|
||||
}
|
||||
|
||||
static void check_duplicate_label_node(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
struct label *l;
|
||||
|
||||
for_each_label(node->labels, l)
|
||||
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
|
||||
}
|
||||
static void check_duplicate_label_prop(struct check *c, struct node *dt,
|
||||
struct node *node, struct property *prop)
|
||||
{
|
||||
struct marker *m = prop->val.markers;
|
||||
struct label *l;
|
||||
|
||||
for_each_label(prop->labels, l)
|
||||
check_duplicate_label(c, dt, l->label, node, prop, NULL);
|
||||
|
||||
for_each_marker_of_type(m, LABEL)
|
||||
check_duplicate_label(c, dt, m->ref, node, prop, m);
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct marker *m;
|
||||
struct node *other;
|
||||
cell_t phandle;
|
||||
|
||||
if (!streq(prop->name, "phandle")
|
||||
&& !streq(prop->name, "linux,phandle"))
|
||||
return;
|
||||
|
||||
if (prop->val.len != sizeof(cell_t)) {
|
||||
FAIL(c, "%s has bad length (%d) %s property",
|
||||
node->fullpath, prop->val.len, prop->name);
|
||||
return;
|
||||
}
|
||||
|
||||
m = prop->val.markers;
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
assert(m->offset == 0);
|
||||
if (node != get_node_by_ref(root, m->ref))
|
||||
/* "Set this node's phandle equal to some
|
||||
* other node's phandle". That's nonsensical
|
||||
* by construction. */ {
|
||||
FAIL(c, "%s in %s is a reference to another node",
|
||||
prop->name, node->fullpath);
|
||||
return;
|
||||
}
|
||||
/* But setting this node's phandle equal to its own
|
||||
* phandle is allowed - that means allocate a unique
|
||||
* phandle for this node, even if it's not otherwise
|
||||
* referenced. The value will be filled in later, so
|
||||
* no further checking for now. */
|
||||
return;
|
||||
}
|
||||
|
||||
phandle = propval_cell(prop);
|
||||
|
||||
if ((phandle == 0) || (phandle == -1)) {
|
||||
FAIL(c, "%s has bad value (0x%x) in %s property",
|
||||
node->fullpath, phandle, prop->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->phandle && (node->phandle != phandle))
|
||||
FAIL(c, "%s has %s property which replaces existing phandle information",
|
||||
node->fullpath, prop->name);
|
||||
|
||||
other = get_node_by_phandle(root, phandle);
|
||||
if (other && (other != node)) {
|
||||
FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
|
||||
node->fullpath, phandle, other->fullpath);
|
||||
return;
|
||||
}
|
||||
|
||||
node->phandle = phandle;
|
||||
}
|
||||
PROP_ERROR(explicit_phandles, NULL);
|
||||
|
||||
static void check_name_properties(struct check *c, struct node *root,
|
||||
struct node *node)
|
||||
{
|
||||
struct property **pp, *prop = NULL;
|
||||
|
||||
for (pp = &node->proplist; *pp; pp = &((*pp)->next))
|
||||
if (streq((*pp)->name, "name")) {
|
||||
prop = *pp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prop)
|
||||
return; /* No name property, that's fine */
|
||||
|
||||
if ((prop->val.len != node->basenamelen+1)
|
||||
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
|
||||
FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
|
||||
" of base node name)", node->fullpath, prop->val.val);
|
||||
} else {
|
||||
/* The name property is correct, and therefore redundant.
|
||||
* Delete it */
|
||||
*pp = prop->next;
|
||||
free(prop->name);
|
||||
data_free(prop->val);
|
||||
free(prop);
|
||||
}
|
||||
}
|
||||
ERROR_IF_NOT_STRING(name_is_string, "name");
|
||||
NODE_ERROR(name_properties, NULL, &name_is_string);
|
||||
|
||||
/*
|
||||
* Reference fixup functions
|
||||
*/
|
||||
|
||||
static void fixup_phandle_references(struct check *c, struct node *dt,
|
||||
struct node *node, struct property *prop)
|
||||
{
|
||||
struct marker *m = prop->val.markers;
|
||||
struct node *refnode;
|
||||
cell_t phandle;
|
||||
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
assert(m->offset + sizeof(cell_t) <= prop->val.len);
|
||||
|
||||
refnode = get_node_by_ref(dt, m->ref);
|
||||
if (! refnode) {
|
||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||||
m->ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
phandle = get_node_phandle(dt, refnode);
|
||||
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||||
}
|
||||
}
|
||||
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,
|
||||
struct node *node, struct property *prop)
|
||||
{
|
||||
struct marker *m = prop->val.markers;
|
||||
struct node *refnode;
|
||||
char *path;
|
||||
|
||||
for_each_marker_of_type(m, REF_PATH) {
|
||||
assert(m->offset <= prop->val.len);
|
||||
|
||||
refnode = get_node_by_ref(dt, m->ref);
|
||||
if (!refnode) {
|
||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||||
m->ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
path = refnode->fullpath;
|
||||
prop->val = data_insert_at_marker(prop->val, m, path,
|
||||
strlen(path) + 1);
|
||||
}
|
||||
}
|
||||
ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
|
||||
&duplicate_node_names);
|
||||
|
||||
/*
|
||||
* Semantic checks
|
||||
*/
|
||||
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");
|
||||
|
||||
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)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
node->addr_cells = -1;
|
||||
node->size_cells = -1;
|
||||
|
||||
prop = get_property(node, "#address-cells");
|
||||
if (prop)
|
||||
node->addr_cells = propval_cell(prop);
|
||||
|
||||
prop = get_property(node, "#size-cells");
|
||||
if (prop)
|
||||
node->size_cells = propval_cell(prop);
|
||||
}
|
||||
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)
|
||||
#define node_size_cells(n) \
|
||||
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
|
||||
|
||||
static void check_reg_format(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
int addr_cells, size_cells, entrylen;
|
||||
|
||||
prop = get_property(node, "reg");
|
||||
if (!prop)
|
||||
return; /* No "reg", that's fine */
|
||||
|
||||
if (!node->parent) {
|
||||
FAIL(c, "Root node has a \"reg\" property");
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop->val.len == 0)
|
||||
FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
|
||||
|
||||
addr_cells = node_addr_cells(node->parent);
|
||||
size_cells = node_size_cells(node->parent);
|
||||
entrylen = (addr_cells + size_cells) * sizeof(cell_t);
|
||||
|
||||
if ((prop->val.len % entrylen) != 0)
|
||||
FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
|
||||
"(#address-cells == %d, #size-cells == %d)",
|
||||
node->fullpath, prop->val.len, addr_cells, size_cells);
|
||||
}
|
||||
NODE_WARNING(reg_format, NULL, &addr_size_cells);
|
||||
|
||||
static void check_ranges_format(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
|
||||
|
||||
prop = get_property(node, "ranges");
|
||||
if (!prop)
|
||||
return;
|
||||
|
||||
if (!node->parent) {
|
||||
FAIL(c, "Root node has a \"ranges\" property");
|
||||
return;
|
||||
}
|
||||
|
||||
p_addr_cells = node_addr_cells(node->parent);
|
||||
p_size_cells = node_size_cells(node->parent);
|
||||
c_addr_cells = node_addr_cells(node);
|
||||
c_size_cells = node_size_cells(node);
|
||||
entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
|
||||
|
||||
if (prop->val.len == 0) {
|
||||
if (p_addr_cells != c_addr_cells)
|
||||
FAIL(c, "%s has empty \"ranges\" property but its "
|
||||
"#address-cells (%d) differs from %s (%d)",
|
||||
node->fullpath, c_addr_cells, node->parent->fullpath,
|
||||
p_addr_cells);
|
||||
if (p_size_cells != c_size_cells)
|
||||
FAIL(c, "%s has empty \"ranges\" property but its "
|
||||
"#size-cells (%d) differs from %s (%d)",
|
||||
node->fullpath, c_size_cells, node->parent->fullpath,
|
||||
p_size_cells);
|
||||
} else if ((prop->val.len % entrylen) != 0) {
|
||||
FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
|
||||
"(parent #address-cells == %d, child #address-cells == %d, "
|
||||
"#size-cells == %d)", node->fullpath, prop->val.len,
|
||||
p_addr_cells, c_addr_cells, c_size_cells);
|
||||
}
|
||||
}
|
||||
NODE_WARNING(ranges_format, NULL, &addr_size_cells);
|
||||
|
||||
/*
|
||||
* Style checks
|
||||
*/
|
||||
static void check_avoid_default_addr_size(struct check *c, struct node *dt,
|
||||
struct node *node)
|
||||
{
|
||||
struct property *reg, *ranges;
|
||||
|
||||
if (!node->parent)
|
||||
return; /* Ignore root node */
|
||||
|
||||
reg = get_property(node, "reg");
|
||||
ranges = get_property(node, "ranges");
|
||||
|
||||
if (!reg && !ranges)
|
||||
return;
|
||||
|
||||
if ((node->parent->addr_cells == -1))
|
||||
FAIL(c, "Relying on default #address-cells value for %s",
|
||||
node->fullpath);
|
||||
|
||||
if ((node->parent->size_cells == -1))
|
||||
FAIL(c, "Relying on default #size-cells value for %s",
|
||||
node->fullpath);
|
||||
}
|
||||
NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
|
||||
|
||||
static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||
struct node *dt)
|
||||
{
|
||||
struct node *chosen;
|
||||
struct property *prop;
|
||||
|
||||
chosen = get_node_by_path(dt, "/chosen");
|
||||
if (!chosen)
|
||||
return;
|
||||
|
||||
prop = get_property(chosen, "interrupt-controller");
|
||||
if (prop)
|
||||
FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
|
||||
"property");
|
||||
}
|
||||
TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
|
||||
|
||||
static struct check *check_table[] = {
|
||||
&duplicate_node_names, &duplicate_property_names,
|
||||
&node_name_chars, &node_name_format, &property_name_chars,
|
||||
&name_is_string, &name_properties,
|
||||
|
||||
&duplicate_label,
|
||||
|
||||
&explicit_phandles,
|
||||
&phandle_references, &path_references,
|
||||
|
||||
&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
|
||||
&device_type_is_string, &model_is_string, &status_is_string,
|
||||
|
||||
&addr_size_cells, ®_format, &ranges_format,
|
||||
|
||||
&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;
|
||||
int i;
|
||||
int error = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
|
||||
struct check *c = check_table[i];
|
||||
|
||||
if (c->warn || c->error)
|
||||
error = error || run_check(c, dt);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
if (!force) {
|
||||
fprintf(stderr, "ERROR: Input tree has errors, aborting "
|
||||
"(use -f to force output)\n");
|
||||
exit(2);
|
||||
} else if (quiet < 3) {
|
||||
fprintf(stderr, "Warning: Input tree has errors, "
|
||||
"output forced\n");
|
||||
}
|
||||
}
|
||||
}
|
269
scripts/dtc/data.c
Normal file
269
scripts/dtc/data.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
|
||||
void data_free(struct data d)
|
||||
{
|
||||
struct marker *m, *nm;
|
||||
|
||||
m = d.markers;
|
||||
while (m) {
|
||||
nm = m->next;
|
||||
free(m->ref);
|
||||
free(m);
|
||||
m = nm;
|
||||
}
|
||||
|
||||
if (d.val)
|
||||
free(d.val);
|
||||
}
|
||||
|
||||
struct data data_grow_for(struct data d, int xlen)
|
||||
{
|
||||
struct data nd;
|
||||
int newsize;
|
||||
|
||||
if (xlen == 0)
|
||||
return d;
|
||||
|
||||
nd = d;
|
||||
|
||||
newsize = xlen;
|
||||
|
||||
while ((d.len + xlen) > newsize)
|
||||
newsize *= 2;
|
||||
|
||||
nd.val = xrealloc(d.val, newsize);
|
||||
|
||||
return nd;
|
||||
}
|
||||
|
||||
struct data data_copy_mem(const char *mem, int len)
|
||||
{
|
||||
struct data d;
|
||||
|
||||
d = data_grow_for(empty_data, len);
|
||||
|
||||
d.len = len;
|
||||
memcpy(d.val, mem, len);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_copy_escape_string(const char *s, int len)
|
||||
{
|
||||
int i = 0;
|
||||
struct data d;
|
||||
char *q;
|
||||
|
||||
d = data_grow_for(empty_data, strlen(s)+1);
|
||||
|
||||
q = d.val;
|
||||
while (i < len) {
|
||||
char c = s[i++];
|
||||
|
||||
if (c == '\\')
|
||||
c = get_escape_char(s, &i);
|
||||
|
||||
q[d.len++] = c;
|
||||
}
|
||||
|
||||
q[d.len++] = '\0';
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_copy_file(FILE *f, size_t maxlen)
|
||||
{
|
||||
struct data d = empty_data;
|
||||
|
||||
while (!feof(f) && (d.len < maxlen)) {
|
||||
size_t chunksize, ret;
|
||||
|
||||
if (maxlen == -1)
|
||||
chunksize = 4096;
|
||||
else
|
||||
chunksize = maxlen - d.len;
|
||||
|
||||
d = data_grow_for(d, chunksize);
|
||||
ret = fread(d.val + d.len, 1, chunksize, f);
|
||||
|
||||
if (ferror(f))
|
||||
die("Error reading file into data: %s", strerror(errno));
|
||||
|
||||
if (d.len + ret < d.len)
|
||||
die("Overflow reading file into data\n");
|
||||
|
||||
d.len += ret;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_append_data(struct data d, const void *p, int len)
|
||||
{
|
||||
d = data_grow_for(d, len);
|
||||
memcpy(d.val + d.len, p, len);
|
||||
d.len += len;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_insert_at_marker(struct data d, struct marker *m,
|
||||
const void *p, int len)
|
||||
{
|
||||
d = data_grow_for(d, len);
|
||||
memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
|
||||
memcpy(d.val + m->offset, p, len);
|
||||
d.len += len;
|
||||
|
||||
/* Adjust all markers after the one we're inserting at */
|
||||
m = m->next;
|
||||
for_each_marker(m)
|
||||
m->offset += len;
|
||||
return d;
|
||||
}
|
||||
|
||||
static struct data data_append_markers(struct data d, struct marker *m)
|
||||
{
|
||||
struct marker **mp = &d.markers;
|
||||
|
||||
/* Find the end of the markerlist */
|
||||
while (*mp)
|
||||
mp = &((*mp)->next);
|
||||
*mp = m;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_merge(struct data d1, struct data d2)
|
||||
{
|
||||
struct data d;
|
||||
struct marker *m2 = d2.markers;
|
||||
|
||||
d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
|
||||
|
||||
/* Adjust for the length of d1 */
|
||||
for_each_marker(m2)
|
||||
m2->offset += d1.len;
|
||||
|
||||
d2.markers = NULL; /* So data_free() doesn't clobber them */
|
||||
data_free(d2);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_append_integer(struct data d, uint64_t value, int bits)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct fdt_reserve_entry bere;
|
||||
|
||||
bere.address = cpu_to_fdt64(re->address);
|
||||
bere.size = cpu_to_fdt64(re->size);
|
||||
|
||||
return data_append_data(d, &bere, sizeof(bere));
|
||||
}
|
||||
|
||||
struct data data_append_cell(struct data d, cell_t word)
|
||||
{
|
||||
return data_append_integer(d, word, sizeof(word) * 8);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return data_append_data(d, &byte, 1);
|
||||
}
|
||||
|
||||
struct data data_append_zeroes(struct data d, int len)
|
||||
{
|
||||
d = data_grow_for(d, len);
|
||||
|
||||
memset(d.val + d.len, 0, len);
|
||||
d.len += len;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct data data_append_align(struct data d, int align)
|
||||
{
|
||||
int newlen = ALIGN(d.len, align);
|
||||
return data_append_zeroes(d, newlen - d.len);
|
||||
}
|
||||
|
||||
struct data data_add_marker(struct data d, enum markertype type, char *ref)
|
||||
{
|
||||
struct marker *m;
|
||||
|
||||
m = xmalloc(sizeof(*m));
|
||||
m->offset = d.len;
|
||||
m->type = type;
|
||||
m->ref = ref;
|
||||
m->next = NULL;
|
||||
|
||||
return data_append_markers(d, m);
|
||||
}
|
||||
|
||||
int data_is_one_string(struct data d)
|
||||
{
|
||||
int i;
|
||||
int len = d.len;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < len-1; i++)
|
||||
if (d.val[i] == '\0')
|
||||
return 0;
|
||||
|
||||
if (d.val[len-1] != '\0')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
250
scripts/dtc/dtc-lexer.l
Normal file
250
scripts/dtc/dtc-lexer.l
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
%option noyywrap nounput noinput never-interactive
|
||||
|
||||
%x INCLUDE
|
||||
%x BYTESTRING
|
||||
%x PROPNODENAME
|
||||
%s V1
|
||||
|
||||
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
|
||||
PATHCHAR ({PROPNODECHAR}|[/])
|
||||
LABEL [a-zA-Z_][a-zA-Z0-9_]*
|
||||
STRING \"([^\\"]|\\.)*\"
|
||||
CHAR_LITERAL '([^']|\\')*'
|
||||
WS [[:space:]]
|
||||
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
|
||||
LINECOMMENT "//".*\n
|
||||
|
||||
%{
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
#include "dtc-parser.tab.h"
|
||||
|
||||
YYLTYPE yylloc;
|
||||
|
||||
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
|
||||
#define YY_USER_ACTION \
|
||||
{ \
|
||||
srcpos_update(&yylloc, yytext, yyleng); \
|
||||
}
|
||||
|
||||
/*#define LEXDEBUG 1*/
|
||||
|
||||
#ifdef LEXDEBUG
|
||||
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DPRINT(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static int dts_version = 1;
|
||||
|
||||
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
|
||||
BEGIN(V1); \
|
||||
|
||||
static void push_input_file(const char *filename);
|
||||
static int pop_input_file(void);
|
||||
%}
|
||||
|
||||
%%
|
||||
<*>"/include/"{WS}*{STRING} {
|
||||
char *name = strchr(yytext, '\"') + 1;
|
||||
yytext[yyleng-1] = '\0';
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
<*>{STRING} {
|
||||
DPRINT("String: %s\n", yytext);
|
||||
yylval.data = data_copy_escape_string(yytext+1,
|
||||
yyleng-2);
|
||||
return DT_STRING;
|
||||
}
|
||||
|
||||
<*>"/dts-v1/" {
|
||||
DPRINT("Keyword: /dts-v1/\n");
|
||||
dts_version = 1;
|
||||
BEGIN_DEFAULT();
|
||||
return DT_V1;
|
||||
}
|
||||
|
||||
<*>"/memreserve/" {
|
||||
DPRINT("Keyword: /memreserve/\n");
|
||||
BEGIN_DEFAULT();
|
||||
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);
|
||||
yylval.labelref[yyleng-1] = '\0';
|
||||
return DT_LABEL;
|
||||
}
|
||||
|
||||
<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);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
<*>"&{/"{PATHCHAR}+\} { /* new-style path reference */
|
||||
yytext[yyleng-1] = '\0';
|
||||
DPRINT("Ref: %s\n", yytext+2);
|
||||
yylval.labelref = xstrdup(yytext+2);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
<BYTESTRING>[0-9a-fA-F]{2} {
|
||||
yylval.byte = strtol(yytext, NULL, 16);
|
||||
DPRINT("Byte: %02x\n", (int)yylval.byte);
|
||||
return DT_BYTE;
|
||||
}
|
||||
|
||||
<BYTESTRING>"]" {
|
||||
DPRINT("/BYTESTRING\n");
|
||||
BEGIN_DEFAULT();
|
||||
return ']';
|
||||
}
|
||||
|
||||
<PROPNODENAME>\\?{PROPNODECHAR}+ {
|
||||
DPRINT("PropNodeName: %s\n", yytext);
|
||||
yylval.propnodename = xstrdup((yytext[0] == '\\') ?
|
||||
yytext + 1 : yytext);
|
||||
BEGIN_DEFAULT();
|
||||
return DT_PROPNODENAME;
|
||||
}
|
||||
|
||||
"/incbin/" {
|
||||
DPRINT("Binary Include\n");
|
||||
return DT_INCBIN;
|
||||
}
|
||||
|
||||
<*>{WS}+ /* eat whitespace */
|
||||
<*>{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]);
|
||||
if (yytext[0] == '[') {
|
||||
DPRINT("<BYTESTRING>\n");
|
||||
BEGIN(BYTESTRING);
|
||||
}
|
||||
if ((yytext[0] == '{')
|
||||
|| (yytext[0] == ';')) {
|
||||
DPRINT("<PROPNODENAME>\n");
|
||||
BEGIN(PROPNODENAME);
|
||||
}
|
||||
return yytext[0];
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
static void push_input_file(const char *filename)
|
||||
{
|
||||
assert(filename);
|
||||
|
||||
srcfile_push(filename);
|
||||
|
||||
yyin = current_srcfile->f;
|
||||
|
||||
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
}
|
||||
|
||||
|
||||
static int pop_input_file(void)
|
||||
{
|
||||
if (srcfile_pop() == 0)
|
||||
return 0;
|
||||
|
||||
yypop_buffer_state();
|
||||
yyin = current_srcfile->f;
|
||||
|
||||
return 1;
|
||||
}
|
2195
scripts/dtc/dtc-lexer.lex.c_shipped
Normal file
2195
scripts/dtc/dtc-lexer.lex.c_shipped
Normal file
File diff suppressed because it is too large
Load diff
2366
scripts/dtc/dtc-parser.tab.c_shipped
Normal file
2366
scripts/dtc/dtc-parser.tab.c_shipped
Normal file
File diff suppressed because it is too large
Load diff
125
scripts/dtc/dtc-parser.tab.h_shipped
Normal file
125
scripts/dtc/dtc-parser.tab.h_shipped
Normal file
|
@ -0,0 +1,125 @@
|
|||
/* A Bison parser, made by GNU Bison 2.7.12-4996. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
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
|
||||
the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
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
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
DT_V1 = 258,
|
||||
DT_MEMRESERVE = 259,
|
||||
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;
|
||||
char *labelref;
|
||||
unsigned int cbase;
|
||||
uint8_t byte;
|
||||
struct data data;
|
||||
|
||||
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 */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
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 */
|
532
scripts/dtc/dtc-parser.y
Normal file
532
scripts/dtc/dtc-parser.y
Normal file
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
YYLTYPE yylloc;
|
||||
|
||||
extern int yylex(void);
|
||||
extern void print_error(char const *fmt, ...);
|
||||
extern void yyerror(char const *s);
|
||||
|
||||
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 {
|
||||
char *propnodename;
|
||||
char *literal;
|
||||
char *labelref;
|
||||
unsigned int cbase;
|
||||
uint8_t byte;
|
||||
struct data data;
|
||||
|
||||
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
|
||||
%token <labelref> DT_LABEL
|
||||
%token <labelref> DT_REF
|
||||
%token DT_INCBIN
|
||||
|
||||
%type <data> propdata
|
||||
%type <data> propdataprefix
|
||||
%type <re> memreserve
|
||||
%type <re> memreserves
|
||||
%type <array> arrayprefix
|
||||
%type <data> bytestring
|
||||
%type <prop> propdef
|
||||
%type <proplist> proplist
|
||||
|
||||
%type <node> devicetree
|
||||
%type <node> nodedef
|
||||
%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:
|
||||
DT_V1 ';' memreserves devicetree
|
||||
{
|
||||
the_boot_info = build_boot_info($3, $4,
|
||||
guess_boot_cpuid($4));
|
||||
}
|
||||
;
|
||||
|
||||
memreserves:
|
||||
/* empty */
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| memreserve memreserves
|
||||
{
|
||||
$$ = chain_reserve_entry($1, $2);
|
||||
}
|
||||
;
|
||||
|
||||
memreserve:
|
||||
DT_MEMRESERVE integer_prim integer_prim ';'
|
||||
{
|
||||
$$ = build_reserve_entry($2, $3);
|
||||
}
|
||||
| DT_LABEL memreserve
|
||||
{
|
||||
add_label(&$2->labels, $1);
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
devicetree:
|
||||
'/' nodedef
|
||||
{
|
||||
$$ = name_node($2, "");
|
||||
}
|
||||
| devicetree '/' nodedef
|
||||
{
|
||||
$$ = merge_nodes($1, $3);
|
||||
}
|
||||
| devicetree DT_REF nodedef
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $2);
|
||||
|
||||
if (target)
|
||||
merge_nodes(target, $3);
|
||||
else
|
||||
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:
|
||||
'{' proplist subnodes '}' ';'
|
||||
{
|
||||
$$ = build_node($2, $3);
|
||||
}
|
||||
;
|
||||
|
||||
proplist:
|
||||
/* empty */
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| proplist propdef
|
||||
{
|
||||
$$ = chain_property($2, $1);
|
||||
}
|
||||
;
|
||||
|
||||
propdef:
|
||||
DT_PROPNODENAME '=' propdata ';'
|
||||
{
|
||||
$$ = build_property($1, $3);
|
||||
}
|
||||
| DT_PROPNODENAME ';'
|
||||
{
|
||||
$$ = build_property($1, empty_data);
|
||||
}
|
||||
| DT_DEL_PROP DT_PROPNODENAME ';'
|
||||
{
|
||||
$$ = build_property_delete($2);
|
||||
}
|
||||
| DT_LABEL propdef
|
||||
{
|
||||
add_label(&$2->labels, $1);
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
propdata:
|
||||
propdataprefix DT_STRING
|
||||
{
|
||||
$$ = data_merge($1, $2);
|
||||
}
|
||||
| propdataprefix arrayprefix '>'
|
||||
{
|
||||
$$ = data_merge($1, $2.data);
|
||||
}
|
||||
| propdataprefix '[' bytestring ']'
|
||||
{
|
||||
$$ = data_merge($1, $3);
|
||||
}
|
||||
| propdataprefix DT_REF
|
||||
{
|
||||
$$ = data_add_marker($1, REF_PATH, $2);
|
||||
}
|
||||
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
|
||||
{
|
||||
FILE *f = srcfile_relative_open($4.val, NULL);
|
||||
struct data d;
|
||||
|
||||
if ($6 != 0)
|
||||
if (fseek(f, $6, SEEK_SET) != 0)
|
||||
print_error("Couldn't seek to offset %llu in \"%s\": %s",
|
||||
(unsigned long long)$6,
|
||||
$4.val,
|
||||
strerror(errno));
|
||||
|
||||
d = data_copy_file(f, $8);
|
||||
|
||||
$$ = data_merge($1, d);
|
||||
fclose(f);
|
||||
}
|
||||
| propdataprefix DT_INCBIN '(' DT_STRING ')'
|
||||
{
|
||||
FILE *f = srcfile_relative_open($4.val, NULL);
|
||||
struct data d = empty_data;
|
||||
|
||||
d = data_copy_file(f, -1);
|
||||
|
||||
$$ = data_merge($1, d);
|
||||
fclose(f);
|
||||
}
|
||||
| propdata DT_LABEL
|
||||
{
|
||||
$$ = data_add_marker($1, LABEL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
propdataprefix:
|
||||
/* empty */
|
||||
{
|
||||
$$ = empty_data;
|
||||
}
|
||||
| propdata ','
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| propdataprefix DT_LABEL
|
||||
{
|
||||
$$ = data_add_marker($1, LABEL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
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
|
||||
{
|
||||
$$.data = data_add_marker($1.data, LABEL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
integer_prim:
|
||||
DT_LITERAL
|
||||
{
|
||||
$$ = eval_literal($1, 0, 64);
|
||||
}
|
||||
| DT_CHAR_LITERAL
|
||||
{
|
||||
$$ = eval_char_literal($1);
|
||||
}
|
||||
| '(' integer_expr ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
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:
|
||||
/* empty */
|
||||
{
|
||||
$$ = empty_data;
|
||||
}
|
||||
| bytestring DT_BYTE
|
||||
{
|
||||
$$ = data_append_byte($1, $2);
|
||||
}
|
||||
| bytestring DT_LABEL
|
||||
{
|
||||
$$ = data_add_marker($1, LABEL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
subnodes:
|
||||
/* empty */
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| subnode subnodes
|
||||
{
|
||||
$$ = chain_node($1, $2);
|
||||
}
|
||||
| subnode propdef
|
||||
{
|
||||
print_error("syntax error: properties must precede subnodes");
|
||||
YYERROR;
|
||||
}
|
||||
;
|
||||
|
||||
subnode:
|
||||
DT_PROPNODENAME nodedef
|
||||
{
|
||||
$$ = name_node($2, $1);
|
||||
}
|
||||
| DT_DEL_NODE DT_PROPNODENAME ';'
|
||||
{
|
||||
$$ = name_node(build_node_delete(), $2);
|
||||
}
|
||||
| DT_LABEL subnode
|
||||
{
|
||||
add_label(&$2->labels, $1);
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
void print_error(char const *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
srcpos_verror(&yylloc, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
treesource_error = 1;
|
||||
}
|
||||
|
||||
void yyerror(char const *s) {
|
||||
print_error("%s", s);
|
||||
}
|
||||
|
||||
static unsigned long long eval_literal(const char *s, int base, int bits)
|
||||
{
|
||||
unsigned long long val;
|
||||
char *e;
|
||||
|
||||
errno = 0;
|
||||
val = strtoull(s, &e, base);
|
||||
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;
|
||||
}
|
259
scripts/dtc/dtc.c
Normal file
259
scripts/dtc/dtc.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
/*
|
||||
* Command line options
|
||||
*/
|
||||
int quiet; /* Level of quietness */
|
||||
int reservenum; /* Number of memory reservation slots */
|
||||
int minsize; /* Minimum blob size */
|
||||
int padsize; /* Additional padding to blob */
|
||||
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
|
||||
|
||||
static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
{
|
||||
struct node *child;
|
||||
const char *unit;
|
||||
|
||||
tree->fullpath = join_path(prefix, tree->name);
|
||||
|
||||
unit = strchr(tree->name, '@');
|
||||
if (unit)
|
||||
tree->basenamelen = unit - tree->name;
|
||||
else
|
||||
tree->basenamelen = strlen(tree->name);
|
||||
|
||||
for_each_child(tree, child)
|
||||
fill_fullpaths(child, tree->fullpath);
|
||||
}
|
||||
|
||||
/* 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[])
|
||||
{
|
||||
struct boot_info *bi;
|
||||
const char *inform = "dts";
|
||||
const char *outform = "dts";
|
||||
const char *outname = "-";
|
||||
const char *depname = NULL;
|
||||
int force = 0, sort = 0;
|
||||
const char *arg;
|
||||
int opt;
|
||||
FILE *outf = NULL;
|
||||
int outversion = DEFAULT_FDT_VERSION;
|
||||
long long cmdline_boot_cpuid = -1;
|
||||
|
||||
quiet = 0;
|
||||
reservenum = 0;
|
||||
minsize = 0;
|
||||
padsize = 0;
|
||||
|
||||
while ((opt = util_getopt_long()) != EOF) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
inform = optarg;
|
||||
break;
|
||||
case 'O':
|
||||
outform = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
outname = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
outversion = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'd':
|
||||
depname = optarg;
|
||||
break;
|
||||
case 'R':
|
||||
reservenum = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'S':
|
||||
minsize = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'p':
|
||||
padsize = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'f':
|
||||
force = 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':
|
||||
util_version();
|
||||
case 'H':
|
||||
if (streq(optarg, "legacy"))
|
||||
phandle_format = PHANDLE_LEGACY;
|
||||
else if (streq(optarg, "epapr"))
|
||||
phandle_format = PHANDLE_EPAPR;
|
||||
else if (streq(optarg, "both"))
|
||||
phandle_format = PHANDLE_BOTH;
|
||||
else
|
||||
die("Invalid argument \"%s\" to -H option\n",
|
||||
optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
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("unknown option");
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > (optind+1))
|
||||
usage("missing files");
|
||||
else if (argc < (optind+1))
|
||||
arg = "-";
|
||||
else
|
||||
arg = argv[optind];
|
||||
|
||||
/* minsize and padsize are mutually exclusive */
|
||||
if (minsize && padsize)
|
||||
die("Can't set both -p and -S\n");
|
||||
|
||||
if (depname) {
|
||||
depfile = fopen(depname, "w");
|
||||
if (!depfile)
|
||||
die("Couldn't open dependency file %s: %s\n", depname,
|
||||
strerror(errno));
|
||||
fprintf(depfile, "%s:", outname);
|
||||
}
|
||||
|
||||
if (streq(inform, "dts"))
|
||||
bi = dt_from_source(arg);
|
||||
else if (streq(inform, "fs"))
|
||||
bi = dt_from_fs(arg);
|
||||
else if(streq(inform, "dtb"))
|
||||
bi = dt_from_blob(arg);
|
||||
else
|
||||
die("Unknown input format \"%s\"\n", inform);
|
||||
|
||||
if (depfile) {
|
||||
fputc('\n', depfile);
|
||||
fclose(depfile);
|
||||
}
|
||||
|
||||
if (cmdline_boot_cpuid != -1)
|
||||
bi->boot_cpuid_phys = cmdline_boot_cpuid;
|
||||
|
||||
fill_fullpaths(bi->dt, "");
|
||||
process_checks(force, bi);
|
||||
|
||||
if (sort)
|
||||
sort_tree(bi);
|
||||
|
||||
if (streq(outname, "-")) {
|
||||
outf = stdout;
|
||||
} else {
|
||||
outf = fopen(outname, "w");
|
||||
if (! outf)
|
||||
die("Couldn't open output file %s: %s\n",
|
||||
outname, strerror(errno));
|
||||
}
|
||||
|
||||
if (streq(outform, "dts")) {
|
||||
dt_to_source(outf, bi);
|
||||
} else if (streq(outform, "dtb")) {
|
||||
dt_to_blob(outf, bi, outversion);
|
||||
} else if (streq(outform, "asm")) {
|
||||
dt_to_asm(outf, bi, outversion);
|
||||
} else if (streq(outform, "null")) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
die("Unknown output format \"%s\"\n", outform);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
269
scripts/dtc/dtc.h
Normal file
269
scripts/dtc/dtc.h
Normal file
|
@ -0,0 +1,269 @@
|
|||
#ifndef _DTC_H
|
||||
#define _DTC_H
|
||||
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libfdt_env.h>
|
||||
#include <fdt.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(fmt,args...) printf(fmt, ##args)
|
||||
#else
|
||||
#define debug(fmt,args...)
|
||||
#endif
|
||||
|
||||
|
||||
#define DEFAULT_FDT_VERSION 17
|
||||
|
||||
/*
|
||||
* Command line options
|
||||
*/
|
||||
extern int quiet; /* Level of quietness */
|
||||
extern int reservenum; /* Number of memory reservation slots */
|
||||
extern int minsize; /* Minimum blob size */
|
||||
extern int padsize; /* Additional padding to blob */
|
||||
extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||
|
||||
#define PHANDLE_LEGACY 0x1
|
||||
#define PHANDLE_EPAPR 0x2
|
||||
#define PHANDLE_BOTH 0x3
|
||||
|
||||
typedef uint32_t cell_t;
|
||||
|
||||
|
||||
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
||||
|
||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
|
||||
/* Data blobs */
|
||||
enum markertype {
|
||||
REF_PHANDLE,
|
||||
REF_PATH,
|
||||
LABEL,
|
||||
};
|
||||
|
||||
struct marker {
|
||||
enum markertype type;
|
||||
int offset;
|
||||
char *ref;
|
||||
struct marker *next;
|
||||
};
|
||||
|
||||
struct data {
|
||||
int len;
|
||||
char *val;
|
||||
struct marker *markers;
|
||||
};
|
||||
|
||||
|
||||
#define empty_data ((struct data){ /* all .members = 0 or NULL */ })
|
||||
|
||||
#define for_each_marker(m) \
|
||||
for (; (m); (m) = (m)->next)
|
||||
#define for_each_marker_of_type(m, t) \
|
||||
for_each_marker(m) \
|
||||
if ((m)->type == (t))
|
||||
|
||||
void data_free(struct data d);
|
||||
|
||||
struct data data_grow_for(struct data d, int xlen);
|
||||
|
||||
struct data data_copy_mem(const char *mem, int len);
|
||||
struct data data_copy_escape_string(const char *s, int len);
|
||||
struct data data_copy_file(FILE *f, size_t len);
|
||||
|
||||
struct data data_append_data(struct data d, const void *p, int len);
|
||||
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);
|
||||
struct data data_append_zeroes(struct data d, int len);
|
||||
struct data data_append_align(struct data d, int align);
|
||||
|
||||
struct data data_add_marker(struct data d, enum markertype type, char *ref);
|
||||
|
||||
int data_is_one_string(struct data d);
|
||||
|
||||
/* DT constraints */
|
||||
|
||||
#define MAX_PROPNAME_LEN 31
|
||||
#define MAX_NODENAME_LEN 31
|
||||
|
||||
/* Live trees */
|
||||
struct label {
|
||||
int deleted;
|
||||
char *label;
|
||||
struct label *next;
|
||||
};
|
||||
|
||||
struct property {
|
||||
int deleted;
|
||||
char *name;
|
||||
struct data val;
|
||||
|
||||
struct property *next;
|
||||
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
struct node {
|
||||
int deleted;
|
||||
char *name;
|
||||
struct property *proplist;
|
||||
struct node *children;
|
||||
|
||||
struct node *parent;
|
||||
struct node *next_sibling;
|
||||
|
||||
char *fullpath;
|
||||
int basenamelen;
|
||||
|
||||
cell_t phandle;
|
||||
int addr_cells, size_cells;
|
||||
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
#define for_each_label_withdel(l0, l) \
|
||||
for ((l) = (l0); (l); (l) = (l)->next)
|
||||
|
||||
#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_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);
|
||||
cell_t propval_cell(struct property *prop);
|
||||
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||
struct node **node);
|
||||
struct marker *get_marker_label(struct node *tree, const char *label,
|
||||
struct node **node, struct property **prop);
|
||||
struct node *get_subnode(struct node *node, const char *nodename);
|
||||
struct node *get_node_by_path(struct node *tree, const char *path);
|
||||
struct node *get_node_by_label(struct node *tree, const char *label);
|
||||
struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
|
||||
struct node *get_node_by_ref(struct node *tree, const char *ref);
|
||||
cell_t get_node_phandle(struct node *root, struct node *node);
|
||||
|
||||
uint32_t guess_boot_cpuid(struct node *tree);
|
||||
|
||||
/* Boot info (tree plus memreserve information */
|
||||
|
||||
struct reserve_info {
|
||||
struct fdt_reserve_entry re;
|
||||
|
||||
struct reserve_info *next;
|
||||
|
||||
struct label *labels;
|
||||
};
|
||||
|
||||
struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
|
||||
struct reserve_info *chain_reserve_entry(struct reserve_info *first,
|
||||
struct reserve_info *list);
|
||||
struct reserve_info *add_reserve_entry(struct reserve_info *list,
|
||||
struct reserve_info *new);
|
||||
|
||||
|
||||
struct boot_info {
|
||||
struct reserve_info *reservelist;
|
||||
struct node *dt; /* the device tree */
|
||||
uint32_t boot_cpuid_phys;
|
||||
};
|
||||
|
||||
struct boot_info *build_boot_info(struct reserve_info *reservelist,
|
||||
struct node *tree, uint32_t boot_cpuid_phys);
|
||||
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 */
|
||||
|
||||
void dt_to_blob(FILE *f, struct boot_info *bi, int version);
|
||||
void dt_to_asm(FILE *f, struct boot_info *bi, int version);
|
||||
|
||||
struct boot_info *dt_from_blob(const char *fname);
|
||||
|
||||
/* Tree source */
|
||||
|
||||
void dt_to_source(FILE *f, struct boot_info *bi);
|
||||
struct boot_info *dt_from_source(const char *f);
|
||||
|
||||
/* FS trees */
|
||||
|
||||
struct boot_info *dt_from_fs(const char *dirname);
|
||||
|
||||
#endif /* _DTC_H */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue