2016-03-06 23:04:13

by Emese Revfy

[permalink] [raw]
Subject: [PATCH v5 0/5] Introduce GCC plugin infrastructure

This patch set introduce the GCC plugin infrastructure with examples for testing
and documentation.

GCC plugins are loadable modules that provide extra features to the compiler.
They are useful for runtime instrumentation and static analysis.

The infrastructure supports all gcc versions from 4.5 to 6.0, building
out-of-tree modules and building in a separate directory. Cross-compilation
is supported too but currently only the x86 architecture enables plugins.

This infrastructure was ported from grsecurity/PaX. It is a CII project
supported by the Linux Foundation.

Emese Revfy (5):
Shared library support
GCC plugin infrastructure
Add Cyclomatic complexity plugin
Documentations of the GCC plugin infrastructre
Add sancov plugin


Changes from v4:
* Moved shared library support from the GCC plugin infrastructure patch into
a different patch
* Update gcc-*.h from PaX
* Fixed gcc-common.h for gcc 6
* Added pass cloning support to the gcc pass generators
* Disable all plugins in vdso because it is userland code
* Add sancov gcc plugin: another use case for gcc plugin support in the kernel
is when there is a feature in the latest gcc version and we would like to use
it with older gcc versions as well (e.g., distros).

Changes from v3:
* Fix some indentation related warnings
(Suggested by checkpatch.pl)
* Add maintainer entries
* Don't run gcc_plugin.sh when the GCC_PLUGINS option is disabled or unsupported
(Reported-by: Fengguang Wu <[email protected]>)

Changes from v2:
* Fixed incorrectly encoded characters
* Generate the GIMPLE, IPA, SIMPLE_IPA and RTL pass structures
(Suggested-by: Rasmus Villemoes <[email protected]>)
* Write plugin related warning messages to stderr instead of stdout
(Suggested-by: Kees Cook <[email protected]>)
* Mention the installation of the gcc plugin headers (Documentation)

Changes from v1:
* Move the gcc-plugins make target into a separate Makefile because there may
be a lot of plugins (Suggested-by: Rasmus Villemoes)
* Simplify the dependencies of the plugin related config option
(Suggested-by: Kees Cook <[email protected]>)
* Removed the unnecessary example plugin

---
Documentation/dontdiff | 1 +
Documentation/gcc-plugins.txt | 82 ++++++++++++++++++
MAINTAINERS | 8 ++
Makefile | 41 ++++++---
arch/Kconfig | 36 ++++++++
arch/x86/Kconfig | 1 +
arch/x86/entry/vdso/Makefile | 2 +-
init/Makefile | 3 +
scripts/Makefile.gcc-plugins | 35 ++++++++
scripts/gcc-plugin.sh | 51 +++++++++++
scripts/link-vmlinux.sh | 2 +-
scripts/package/builddeb | 1 +
tools/gcc/Makefile | 21 +++++
tools/gcc/cyc_complexity_plugin.c | 73 ++++++++++++++++
tools/gcc/gcc-common.h | 830 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/gcc/gcc-generate-gimple-pass.h | 175 ++++++++++++++++++++++++++++++++++++++
tools/gcc/gcc-generate-ipa-pass.h | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/gcc/gcc-generate-rtl-pass.h | 175 ++++++++++++++++++++++++++++++++++++++
tools/gcc/gcc-generate-simple_ipa-pass.h | 175 ++++++++++++++++++++++++++++++++++++++
tools/gcc/sancov_plugin.c | 133 +++++++++++++++++++++++++++++
20 files changed, 2121 insertions(+), 13 deletions(-)


2016-03-06 23:05:37

by Emese Revfy

[permalink] [raw]
Subject: [PATCH v5 1/5] Shared library support

Infrastructure for building independent shared library targets.
This effectively also reverts commit 62e2210798ed38928ab24841e8b4878a
(Masahiro Yamada, kbuild: drop shared library support from Makefile.host).

Signed-off-by: Emese Revfy <[email protected]>
---
scripts/Makefile.build | 2 +-
scripts/Makefile.clean | 3 ++-
scripts/Makefile.host | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 130a452..bd2a31e 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -60,7 +60,7 @@ endif
endif

# Do not include host rules unless needed
-ifneq ($(hostprogs-y)$(hostprogs-m),)
+ifneq ($(hostprogs-y)$(hostprogs-m)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(hostcxxlibs-m),)
include scripts/Makefile.host
endif

diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index 55c96cb..e4e88ab 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -38,7 +38,8 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
__clean-files := $(extra-y) $(extra-m) $(extra-) \
$(always) $(targets) $(clean-files) \
$(host-progs) \
- $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
+ $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
+ $(hostlibs-y) $(hostlibs-m) $(hostlibs-)

__clean-files := $(filter-out $(no-clean-files), $(__clean-files))

diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 133edfa..4d180d9 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -20,7 +20,25 @@
# Will compile qconf as a C++ program, and menu as a C program.
# They are linked as C++ code to the executable qconf

+# hostprogs-y := conf
+# conf-objs := conf.o libkconfig.so
+# libkconfig-objs := expr.o type.o
+# Will create a shared library named libkconfig.so that consists of
+# expr.o and type.o (they are both compiled as C code and the object files
+# are made as position independent code).
+# conf.c is compiled as a C program, and conf.o is linked together with
+# libkconfig.so as the executable conf.
+# Note: Shared libraries consisting of C++ files are not supported
+
+# hostcc-option
+# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
+
+hostcc-option = $(call try-run,\
+ $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
+__hostlibs := $(sort $(hostlibs-y) $(hostlibs-m))
+__hostcxxlibs := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))

# C code
# Executables compiled from a single .c file
@@ -42,6 +60,19 @@ 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)))

+# Shared libaries (only .c supported)
+# Shared libraries (.so) - all .so files referenced in "xxx-objs"
+host-cshlib := $(sort $(filter %.so, $(host-cobjs)))
+host-cshlib += $(sort $(filter %.so, $(__hostlibs)))
+host-cxxshlib := $(sort $(filter %.so, $(__hostcxxlibs)))
+# Remove .so files from "xxx-objs"
+host-cobjs := $(filter-out %.so,$(host-cobjs))
+host-cxxobjs := $(filter-out %.so,$(host-cxxobjs))
+
+# Object (.o) files used by the shared libaries
+host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
+
# 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
@@ -56,6 +87,10 @@ 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-cshlib := $(addprefix $(obj)/,$(host-cshlib))
+host-cxxshlib := $(addprefix $(obj)/,$(host-cxxshlib))
+host-cshobjs := $(addprefix $(obj)/,$(host-cshobjs))
+host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))

obj-dirs += $(host-objdirs)
@@ -124,5 +159,37 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@
$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
$(call if_changed_dep,host-cxxobjs)

+# Compile .c file, create position independent .o file
+# host-cshobjs -> .o
+quiet_cmd_host-cshobjs = HOSTCC -fPIC $@
+ cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
+$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
+ $(call if_changed_dep,host-cshobjs)
+
+# Compile .c file, create position independent .o file
+# host-cxxshobjs -> .o
+quiet_cmd_host-cxxshobjs = HOSTCXX -fPIC $@
+ cmd_host-cxxshobjs = $(HOSTCXX) $(hostcxx_flags) -fPIC -c -o $@ $<
+$(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE
+ $(call if_changed_dep,host-cxxshobjs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cshlib)
+quiet_cmd_host-cshlib = HOSTLLD -shared $@
+ cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
+ $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+ $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
+ $(call if_changed,host-cshlib)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cxxshlib)
+quiet_cmd_host-cxxshlib = HOSTLLD -shared $@
+ cmd_host-cxxshlib = $(HOSTCXX) $(HOSTLDFLAGS) -shared -o $@ \
+ $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+ $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cxxshlib): $(obj)/%: $(host-cxxshobjs) FORCE
+ $(call if_changed,host-cxxshlib)
+
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
- $(host-cxxmulti) $(host-cxxobjs)
+ $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) $(host-cxxshlib) $(host-cxxshobjs)
--
2.4.1

2016-03-06 23:06:37

by Emese Revfy

[permalink] [raw]
Subject: [PATCH v5 2/5] GCC plugin infrastructure

This patch allows to build the whole kernel with GCC plugins. It was ported from
grsecurity/PaX. The infrastructure supports building out-of-tree modules and
building in a separate directory. Cross-compilation is supported too but
currently only the x86 architecture enables plugins.

The directory of the gcc plugins is tools/gcc. You can use a file or a directory
there. The plugins compile with these options:
* -fno-rtti: gcc is compiled with this option so the plugins must use it too
* -fno-exceptions: this is inherited from gcc too
* -fasynchronous-unwind-tables: this is inherited from gcc too
* -ggdb: it is useful for debugging a plugin (better backtrace on internal
errors)
* -Wno-narrowing: to suppress warnings from gcc headers (ipa-utils.h)
* -Wno-unused-variable: to suppress warnings from gcc headers (gcc_version
variable, plugin-version.h)

The infrastructure introduces a new Makefile target called gcc-plugins. It
supports all gcc versions from 4.5 to 6.0. The scripts/gcc-plugin.sh script
chooses the proper host compiler (gcc-4.7 can be built by either gcc or g++).
This script also checks the availability of the included headers in
tools/gcc/gcc-common.h.

The gcc-common.h header contains frequently included headers for GCC plugins
and it has a compatibility layer for the supported gcc versions.

The gcc-generate-*-pass.h headers automatically generate the registration
structures for GIMPLE, SIMPLE_IPA, IPA and RTL passes.

Note that 'make clean' keeps the *.so files (only the distclean or mrproper
targets clean all) because they are needed for out-of-tree modules.

Signed-off-by: Emese Revfy <[email protected]>
---
Documentation/dontdiff | 1 +
MAINTAINERS | 8 +
Makefile | 41 +-
arch/Kconfig | 13 +
arch/x86/Kconfig | 1 +
arch/x86/entry/vdso/Makefile | 2 +-
init/Makefile | 3 +
scripts/Makefile.gcc-plugins | 28 ++
scripts/gcc-plugin.sh | 51 ++
scripts/link-vmlinux.sh | 2 +-
scripts/package/builddeb | 1 +
tools/gcc/Makefile | 15 +
tools/gcc/gcc-common.h | 830 +++++++++++++++++++++++++++++++
tools/gcc/gcc-generate-gimple-pass.h | 175 +++++++
tools/gcc/gcc-generate-ipa-pass.h | 289 +++++++++++
tools/gcc/gcc-generate-rtl-pass.h | 175 +++++++
tools/gcc/gcc-generate-simple_ipa-pass.h | 175 +++++++
17 files changed, 1797 insertions(+), 13 deletions(-)
create mode 100644 scripts/Makefile.gcc-plugins
create mode 100644 scripts/gcc-plugin.sh
create mode 100644 tools/gcc/Makefile
create mode 100644 tools/gcc/gcc-common.h
create mode 100644 tools/gcc/gcc-generate-gimple-pass.h
create mode 100644 tools/gcc/gcc-generate-ipa-pass.h
create mode 100644 tools/gcc/gcc-generate-rtl-pass.h
create mode 100644 tools/gcc/gcc-generate-simple_ipa-pass.h

diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 8ea834f..5385cba 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -3,6 +3,7 @@
*.bc
*.bin
*.bz2
+*.c.[012]*.*
*.cis
*.cpio
*.csp
diff --git a/MAINTAINERS b/MAINTAINERS
index 4a4edae..91fdb96 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4760,6 +4760,14 @@ L: [email protected]
S: Odd Fixes (e.g., new signatures)
F: drivers/scsi/fdomain.*

+GCC PLUGINS
+M: Kees Cook <[email protected]>
+R: Emese Revfy <[email protected]>
+L: [email protected]
+S: Maintained
+F: tools/gcc
+F: Documentation/gcc-plugins.txt
+
GCOV BASED KERNEL PROFILING
M: Peter Oberparleiter <[email protected]>
S: Maintained
diff --git a/Makefile b/Makefile
index 1ac31dc..b1be4c8 100644
--- a/Makefile
+++ b/Makefile
@@ -435,8 +435,8 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
# Rules shared between *config targets and build targets

# Basic helpers built in scripts/
-PHONY += scripts_basic
-scripts_basic:
+PHONY += scripts_basic gcc-plugins
+scripts_basic: gcc-plugins
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount

@@ -623,6 +623,8 @@ endif
# Tell gcc to never replace conditional load with a non-conditional one
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)

+include scripts/Makefile.gcc-plugins
+
ifdef CONFIG_READABLE_ASM
# Disable optimizations that make assembler listings hard to read.
# reorder blocks reorders the control in the function
@@ -949,6 +951,8 @@ endif

# The actual objects are generated when descending,
# make sure no implicit rule kicks in
+$(filter-out $(init-y),$(vmlinux-deps)): KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+$(filter-out $(init-y),$(vmlinux-deps)): KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;

# Handle descending into subdirectories listed in $(vmlinux-dirs)
@@ -958,7 +962,7 @@ $(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
# Error messages still appears in the original language

PHONY += $(vmlinux-dirs)
-$(vmlinux-dirs): prepare scripts
+$(vmlinux-dirs): gcc-plugins prepare scripts
$(Q)$(MAKE) $(build)=$@

define filechk_kernel.release
@@ -1001,10 +1005,13 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \

archprepare: archheaders archscripts prepare1 scripts_basic

+prepare0: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+prepare0: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.

# All the preparing..
+prepare: KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS))
prepare: prepare0 prepare-objtool

PHONY += prepare-objtool
@@ -1126,6 +1133,8 @@ all: modules
# using awk while concatenating to the final file.

PHONY += modules
+modules: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+modules: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
@$(kecho) ' Building modules, stage 2.';
@@ -1141,7 +1150,7 @@ modules.builtin: $(vmlinux-dirs:%=%/modules.builtin)

# Target to prepare building external modules
PHONY += modules_prepare
-modules_prepare: prepare scripts
+modules_prepare: gcc-plugins prepare scripts

# Target to install modules
PHONY += modules_install
@@ -1246,7 +1255,7 @@ distclean: mrproper
@find $(srctree) $(RCS_FIND_IGNORE) \
\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
- -o -name '.*.rej' -o -name '*%' -o -name 'core' \) \
+ -o -name '.*.rej' -o -name '*.so' -o -name '*%' -o -name 'core' \) \
-type f -print | xargs rm -f


@@ -1415,6 +1424,8 @@ PHONY += $(module-dirs) modules
$(module-dirs): crmodverdir $(objtree)/Module.symvers
$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)

+modules: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+modules: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
modules: $(module-dirs)
@$(kecho) ' Building modules, stage 2.';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
@@ -1556,17 +1567,21 @@ else
target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@))
endif

-%.s: %.c prepare scripts FORCE
+%.s: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+%.s: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
+%.s: %.c gcc-plugins prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
%.i: %.c prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
-%.o: %.c prepare scripts FORCE
+%.o: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+%.o: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
+%.o: %.c gcc-plugins prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
%.lst: %.c prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
-%.s: %.S prepare scripts FORCE
+%.s: %.S gcc-plugins prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
-%.o: %.S prepare scripts FORCE
+%.o: %.S gcc-plugins prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
%.symtypes: %.c prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
@@ -1578,11 +1593,15 @@ endif
$(build)=$(build-dir)
# Make sure the latest headers are built for Documentation
Documentation/: headers_install
-%/: prepare scripts FORCE
+%/: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+%/: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
+%/: gcc-plugins prepare scripts FORCE
$(cmd_crmodverdir)
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
$(build)=$(build-dir)
-%.ko: prepare scripts FORCE
+%.ko: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+%.ko: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
+%.ko: gcc-plugins prepare scripts FORCE
$(cmd_crmodverdir)
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
$(build)=$(build-dir) $(@:.ko=.o)
diff --git a/arch/Kconfig b/arch/Kconfig
index 049f243..e090642 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -357,6 +357,19 @@ config SECCOMP_FILTER

See Documentation/prctl/seccomp_filter.txt for details.

+config HAVE_GCC_PLUGINS
+ bool
+ help
+ An arch should select this symbol if it supports building with
+ GCC plugins.
+
+menuconfig GCC_PLUGINS
+ bool "GCC plugins"
+ depends on HAVE_GCC_PLUGINS
+ help
+ GCC plugins are loadable modules that provide extra features to the
+ compiler. They are useful for runtime instrumentation and static analysis.
+
config HAVE_CC_STACKPROTECTOR
bool
help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ab242f5..9a5af44 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -160,6 +160,7 @@ config X86
select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS
select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS
select HAVE_STACK_VALIDATION if X86_64
+ select HAVE_GCC_PLUGINS

config INSTRUCTION_DECODER
def_bool y
diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index 93216b5..3bddfa4 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -74,7 +74,7 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
-fno-omit-frame-pointer -foptimize-sibling-calls \
-DDISABLE_BRANCH_PROFILING -DBUILD_VDSO

-$(vobjs): KBUILD_CFLAGS += $(CFL)
+$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)

#
# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
diff --git a/init/Makefile b/init/Makefile
index 7bc47ee..6da2dc7 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -2,6 +2,9 @@
# Makefile for the linux kernel.
#

+ccflags-y := $(GCC_PLUGINS_CFLAGS)
+asflags-y := $(GCC_PLUGINS_AFLAGS)
+
obj-y := main.o version.o mounts.o
ifneq ($(CONFIG_BLK_DEV_INITRD),y)
obj-y += noinitramfs.o
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
new file mode 100644
index 0000000..7c85bf2
--- /dev/null
+++ b/scripts/Makefile.gcc-plugins
@@ -0,0 +1,28 @@
+ifdef CONFIG_GCC_PLUGINS
+ifeq ($(call cc-ifversion, -ge, 0408, y), y)
+PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)")
+else
+PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
+endif
+ifneq ($(PLUGINCC),)
+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
+ifeq ($(KBUILD_EXTMOD),)
+gcc-plugins:
+ $(Q)$(MAKE) $(build)=tools/gcc
+else
+gcc-plugins: ;
+endif
+else
+gcc-plugins:
+ifeq ($(call cc-ifversion, -ge, 0405, y), y)
+ $(warning warning, your gcc installation does not support plugins, perhaps the necessary headers are missing?)
+ifeq ($(call cc-ifversion, -ge, 0408, y), y)
+ $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)"
+else
+ $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)"
+endif
+else
+ $(warning warning, your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least)
+endif
+endif
+endif
diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh
new file mode 100644
index 0000000..eaa4fce
--- /dev/null
+++ b/scripts/gcc-plugin.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+srctree=$(dirname "$0")
+gccplugins_dir=$($3 -print-file-name=plugin)
+plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <<EOF
+#include "gcc-common.h"
+#if BUILDING_GCC_VERSION >= 4008 || defined(ENABLE_BUILD_WITH_CXX)
+#warning $2 CXX
+#else
+#warning $1 CC
+#endif
+EOF
+)
+
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+case "$plugincc" in
+ *"$1 CC"*)
+ echo "$1"
+ exit 0
+ ;;
+
+ *"$2 CXX"*)
+ # the c++ compiler needs another test, see below
+ ;;
+
+ *)
+ exit 1
+ ;;
+esac
+
+# we need a c++ compiler that supports the designated initializer GNU extension
+plugincc=$($2 -c -x c++ -std=gnu++98 - -fsyntax-only -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <<EOF
+#include "gcc-common.h"
+class test {
+public:
+ int test;
+} test = {
+ .test = 1
+};
+EOF
+)
+
+if [ $? -eq 0 ]
+then
+ echo "$2"
+ exit 0
+fi
+exit 1
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 49d61ad..69ee2cf 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -184,7 +184,7 @@ else
fi;

# final build of init/
-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init
+${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" GCC_PLUGINS_AFLAGS="${GCC_PLUGINS_AFLAGS}"

kallsymso=""
kallsyms_vmlinux=""
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 6c3b038..54e0b5e 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -326,6 +326,7 @@ fi
(cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles"
(cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles"
+(cd $objtree; find tools/gcc -name \*.so -o -name gcc-common.h) >> "$objtree/debian/hdrobjfiles"
destdir=$kernel_headers_dir/usr/src/linux-headers-$version
mkdir -p "$destdir"
(cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -)
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
new file mode 100644
index 0000000..b2d64af
--- /dev/null
+++ b/tools/gcc/Makefile
@@ -0,0 +1,15 @@
+GCC_PLUGINS_DIR := $(shell $(CC) -print-file-name=plugin)
+
+ifeq ($(PLUGINCC),$(HOSTCC))
+HOSTLIBS := hostlibs
+HOST_EXTRACFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb
+export HOST_EXTRACFLAGS
+else
+HOSTLIBS := hostcxxlibs
+HOST_EXTRACXXFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti -fno-exceptions -fasynchronous-unwind-tables -ggdb -Wno-narrowing -Wno-unused-variable
+export HOST_EXTRACXXFLAGS
+endif
+
+export GCCPLUGINS_DIR HOSTLIBS
+
+always := $($(HOSTLIBS)-y)
diff --git a/tools/gcc/gcc-common.h b/tools/gcc/gcc-common.h
new file mode 100644
index 0000000..172850b
--- /dev/null
+++ b/tools/gcc/gcc-common.h
@@ -0,0 +1,830 @@
+#ifndef GCC_COMMON_H_INCLUDED
+#define GCC_COMMON_H_INCLUDED
+
+#include "bversion.h"
+#if BUILDING_GCC_VERSION >= 6000
+#include "gcc-plugin.h"
+#else
+#include "plugin.h"
+#endif
+#include "plugin-version.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "line-map.h"
+#include "input.h"
+#include "tree.h"
+
+#include "tree-inline.h"
+#include "version.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "hard-reg-set.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "intl.h"
+#include "ggc.h"
+#include "timevar.h"
+
+#include "params.h"
+
+#if BUILDING_GCC_VERSION <= 4009
+#include "pointer-set.h"
+#else
+#include "hash-map.h"
+#endif
+
+#include "emit-rtl.h"
+#include "debug.h"
+#include "target.h"
+#include "langhooks.h"
+#include "cfgloop.h"
+#include "cgraph.h"
+#include "opts.h"
+
+#if BUILDING_GCC_VERSION == 4005
+#include <sys/mman.h>
+#endif
+
+#if BUILDING_GCC_VERSION >= 4007
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4006
+#include "c-family/c-common.h"
+#else
+#include "c-common.h"
+#endif
+
+#if BUILDING_GCC_VERSION <= 4008
+#include "tree-flow.h"
+#else
+#include "tree-cfgcleanup.h"
+#include "tree-ssa-operands.h"
+#include "tree-into-ssa.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
+#include "is-a.h"
+#endif
+
+#include "diagnostic.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "predict.h"
+#include "ipa-utils.h"
+
+#if BUILDING_GCC_VERSION >= 4009
+#include "attribs.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple-fold.h"
+#include "context.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssa.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "print-tree.h"
+#include "tree-eh.h"
+#include "stmt.h"
+#include "gimplify.h"
+#endif
+
+#include "gimple.h"
+
+#if BUILDING_GCC_VERSION >= 4009
+#include "tree-ssa-operands.h"
+#include "tree-phinodes.h"
+#include "tree-cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "ssa-iterators.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000
+#include "builtins.h"
+#endif
+
+/* #include "expr.h" where are you... */
+extern rtx emit_move_insn(rtx x, rtx y);
+
+/* missing from basic_block.h... */
+extern void debug_dominance_info(enum cdi_direction dir);
+extern void debug_dominance_tree(enum cdi_direction dir, basic_block root);
+
+#if BUILDING_GCC_VERSION == 4006
+extern void debug_gimple_stmt(gimple);
+extern void debug_gimple_seq(gimple_seq);
+extern void print_gimple_seq(FILE *, gimple_seq, int, int);
+extern void print_gimple_stmt(FILE *, gimple, int, int);
+extern void print_gimple_expr(FILE *, gimple, int, int);
+extern void dump_gimple_stmt(pretty_printer *, gimple, int, int);
+#endif
+
+#define __unused __attribute__((__unused__))
+
+#define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node))
+#define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node))
+#define TYPE_NAME_POINTER(node) IDENTIFIER_POINTER(TYPE_NAME(node))
+#define TYPE_NAME_LENGTH(node) IDENTIFIER_LENGTH(TYPE_NAME(node))
+
+/* should come from c-tree.h if only it were installed for gcc 4.5... */
+#define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1(TYPE)
+
+#if BUILDING_GCC_VERSION == 4005
+#define FOR_EACH_LOCAL_DECL(FUN, I, D) \
+ for (tree vars = (FUN)->local_decls, (I) = 0; \
+ vars && ((D) = TREE_VALUE(vars)); \
+ vars = TREE_CHAIN(vars), (I)++)
+#define DECL_CHAIN(NODE) (TREE_CHAIN(DECL_MINIMAL_CHECK(NODE)))
+#define FOR_EACH_VEC_ELT(T, V, I, P) \
+ for (I = 0; VEC_iterate(T, (V), (I), (P)); ++(I))
+#define TODO_rebuild_cgraph_edges 0
+#define SCOPE_FILE_SCOPE_P(EXP) (!(EXP))
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+typedef struct varpool_node *varpool_node_ptr;
+
+static inline bool gimple_call_builtin_p(gimple stmt, enum built_in_function code)
+{
+ tree fndecl;
+
+ if (!is_gimple_call(stmt))
+ return false;
+ fndecl = gimple_call_fndecl(stmt);
+ if (!fndecl || DECL_BUILT_IN_CLASS(fndecl) != BUILT_IN_NORMAL)
+ return false;
+ return DECL_FUNCTION_CODE(fndecl) == code;
+}
+
+static inline bool is_simple_builtin(tree decl)
+{
+ if (decl && DECL_BUILT_IN_CLASS(decl) != BUILT_IN_NORMAL)
+ return false;
+
+ switch (DECL_FUNCTION_CODE(decl)) {
+ /* Builtins that expand to constants. */
+ case BUILT_IN_CONSTANT_P:
+ case BUILT_IN_EXPECT:
+ case BUILT_IN_OBJECT_SIZE:
+ case BUILT_IN_UNREACHABLE:
+ /* Simple register moves or loads from stack. */
+ case BUILT_IN_RETURN_ADDRESS:
+ case BUILT_IN_EXTRACT_RETURN_ADDR:
+ case BUILT_IN_FROB_RETURN_ADDR:
+ case BUILT_IN_RETURN:
+ case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+ case BUILT_IN_FRAME_ADDRESS:
+ case BUILT_IN_VA_END:
+ case BUILT_IN_STACK_SAVE:
+ case BUILT_IN_STACK_RESTORE:
+ /* Exception state returns or moves registers around. */
+ case BUILT_IN_EH_FILTER:
+ case BUILT_IN_EH_POINTER:
+ case BUILT_IN_EH_COPY_VALUES:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static inline void add_local_decl(struct function *fun, tree d)
+{
+ gcc_assert(TREE_CODE(d) == VAR_DECL);
+ fun->local_decls = tree_cons(NULL_TREE, d, fun->local_decls);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4006
+#define ANY_RETURN_P(rtx) (GET_CODE(rtx) == RETURN)
+#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4(EXP)
+#define EDGE_PRESERVE 0ULL
+#define HOST_WIDE_INT_PRINT_HEX_PURE "%" HOST_WIDE_INT_PRINT "x"
+#define flag_fat_lto_objects true
+
+#define get_random_seed(noinit) ({ \
+ unsigned HOST_WIDE_INT seed; \
+ sscanf(get_random_seed(noinit), "%" HOST_WIDE_INT_PRINT "x", &seed); \
+ seed * seed; })
+
+#define int_const_binop(code, arg1, arg2) \
+ int_const_binop((code), (arg1), (arg2), 0)
+
+static inline bool gimple_clobber_p(gimple s __unused)
+{
+ return false;
+}
+
+static inline bool gimple_asm_clobbers_memory_p(const_gimple stmt)
+{
+ unsigned i;
+
+ for (i = 0; i < gimple_asm_nclobbers(stmt); i++) {
+ tree op = gimple_asm_clobber_op(stmt, i);
+
+ if (!strcmp(TREE_STRING_POINTER(TREE_VALUE(op)), "memory"))
+ return true;
+ }
+
+ return false;
+}
+
+static inline tree builtin_decl_implicit(enum built_in_function fncode)
+{
+ return implicit_built_in_decls[fncode];
+}
+
+static inline int ipa_reverse_postorder(struct cgraph_node **order)
+{
+ return cgraph_postorder(order);
+}
+
+static inline struct cgraph_node *cgraph_create_node(tree decl)
+{
+ return cgraph_node(decl);
+}
+
+static inline struct cgraph_node *cgraph_get_create_node(tree decl)
+{
+ struct cgraph_node *node = cgraph_get_node(decl);
+
+ return node ? node : cgraph_node(decl);
+}
+
+static inline bool cgraph_function_with_gimple_body_p(struct cgraph_node *node)
+{
+ return node->analyzed && !node->thunk.thunk_p && !node->alias;
+}
+
+static inline struct cgraph_node *cgraph_first_function_with_gimple_body(void)
+{
+ struct cgraph_node *node;
+
+ for (node = cgraph_nodes; node; node = node->next)
+ if (cgraph_function_with_gimple_body_p(node))
+ return node;
+ return NULL;
+}
+
+static inline struct cgraph_node *cgraph_next_function_with_gimple_body(struct cgraph_node *node)
+{
+ for (node = node->next; node; node = node->next)
+ if (cgraph_function_with_gimple_body_p(node))
+ return node;
+ return NULL;
+}
+
+#define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \
+ for ((node) = cgraph_first_function_with_gimple_body(); (node); \
+ (node) = cgraph_next_function_with_gimple_body(node))
+
+static inline void varpool_add_new_variable(tree decl)
+{
+ varpool_finalize_decl(decl);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4007
+#define FOR_EACH_FUNCTION(node) \
+ for (node = cgraph_nodes; node; node = node->next)
+#define FOR_EACH_VARIABLE(node) \
+ for (node = varpool_nodes; node; node = node->next)
+#define PROP_loops 0
+#define NODE_SYMBOL(node) (node)
+#define NODE_DECL(node) (node)->decl
+#define INSN_LOCATION(INSN) RTL_LOCATION(INSN)
+#define vNULL NULL
+
+static inline int bb_loop_depth(const_basic_block bb)
+{
+ return bb->loop_father ? loop_depth(bb->loop_father) : 0;
+}
+
+static inline bool gimple_store_p(gimple gs)
+{
+ tree lhs = gimple_get_lhs(gs);
+
+ return lhs && !is_gimple_reg(lhs);
+}
+
+static inline void gimple_init_singleton(gimple g __unused)
+{
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4007 || BUILDING_GCC_VERSION == 4008
+static inline struct cgraph_node *cgraph_alias_target(struct cgraph_node *n)
+{
+ return cgraph_alias_aliased_node(n);
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION <= 4009
+#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \
+ cgraph_create_edge((caller), (callee), (call_stmt), (count), (freq))
+#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \
+ cgraph_create_edge_including_clones((caller), (callee), (old_call_stmt), (call_stmt), (count), (freq), (reason))
+#endif
+
+#if BUILDING_GCC_VERSION <= 4008
+#define ENTRY_BLOCK_PTR_FOR_FN(FN) ENTRY_BLOCK_PTR_FOR_FUNCTION(FN)
+#define EXIT_BLOCK_PTR_FOR_FN(FN) EXIT_BLOCK_PTR_FOR_FUNCTION(FN)
+#define basic_block_info_for_fn(FN) ((FN)->cfg->x_basic_block_info)
+#define n_basic_blocks_for_fn(FN) ((FN)->cfg->x_n_basic_blocks)
+#define n_edges_for_fn(FN) ((FN)->cfg->x_n_edges)
+#define last_basic_block_for_fn(FN) ((FN)->cfg->x_last_basic_block)
+#define label_to_block_map_for_fn(FN) ((FN)->cfg->x_label_to_block_map)
+#define profile_status_for_fn(FN) ((FN)->cfg->x_profile_status)
+#define BASIC_BLOCK_FOR_FN(FN, N) BASIC_BLOCK_FOR_FUNCTION((FN), (N))
+#define NODE_IMPLICIT_ALIAS(node) (node)->same_body_alias
+#define VAR_P(NODE) (TREE_CODE(NODE) == VAR_DECL)
+
+static inline bool tree_fits_shwi_p(const_tree t)
+{
+ if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST)
+ return false;
+
+ if (TREE_INT_CST_HIGH(t) == 0 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) >= 0)
+ return true;
+
+ if (TREE_INT_CST_HIGH(t) == -1 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) < 0 && !TYPE_UNSIGNED(TREE_TYPE(t)))
+ return true;
+
+ return false;
+}
+
+static inline bool tree_fits_uhwi_p(const_tree t)
+{
+ if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST)
+ return false;
+
+ return TREE_INT_CST_HIGH(t) == 0;
+}
+
+static inline HOST_WIDE_INT tree_to_shwi(const_tree t)
+{
+ gcc_assert(tree_fits_shwi_p(t));
+ return TREE_INT_CST_LOW(t);
+}
+
+static inline unsigned HOST_WIDE_INT tree_to_uhwi(const_tree t)
+{
+ gcc_assert(tree_fits_uhwi_p(t));
+ return TREE_INT_CST_LOW(t);
+}
+
+static inline const char *get_tree_code_name(enum tree_code code)
+{
+ gcc_assert(code < MAX_TREE_CODES);
+ return tree_code_name[code];
+}
+
+#define ipa_remove_stmt_references(cnode, stmt)
+
+typedef union gimple_statement_d gasm;
+typedef union gimple_statement_d gassign;
+typedef union gimple_statement_d gcall;
+typedef union gimple_statement_d gcond;
+typedef union gimple_statement_d gdebug;
+typedef union gimple_statement_d gphi;
+typedef union gimple_statement_d greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gcond *as_a_gcond(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gdebug *as_a_gdebug(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+ return stmt;
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4008
+#define NODE_SYMBOL(node) (&(node)->symbol)
+#define NODE_DECL(node) (node)->symbol.decl
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
+#define add_referenced_var(var)
+#define mark_sym_for_renaming(var)
+#define varpool_mark_needed_node(node)
+#define create_var_ann(var)
+#define TODO_dump_func 0
+#define TODO_dump_cgraph 0
+#endif
+
+#if BUILDING_GCC_VERSION <= 4009
+#define TODO_verify_il 0
+#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE
+
+#define section_name_prefix LTO_SECTION_NAME_PREFIX
+#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__)
+
+typedef struct rtx_def rtx_insn;
+
+static inline void set_decl_section_name(tree node, const char *value)
+{
+ if (value)
+ DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value);
+ else
+ DECL_SECTION_NAME(node) = NULL;
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4009
+typedef struct gimple_statement_asm gasm;
+typedef struct gimple_statement_base gassign;
+typedef struct gimple_statement_call gcall;
+typedef struct gimple_statement_base gcond;
+typedef struct gimple_statement_base gdebug;
+typedef struct gimple_statement_phi gphi;
+typedef struct gimple_statement_base greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+ return as_a<gasm>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+ return as_a<const gasm>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+ return as_a<gcall>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+ return as_a<const gcall>(stmt);
+}
+
+static inline gcond *as_a_gcond(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gdebug *as_a_gdebug(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
+{
+ return stmt;
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+ return as_a<gphi>(stmt);
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+ return as_a<const gphi>(stmt);
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return stmt;
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+ return stmt;
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+#define TODO_ggc_collect 0
+#define NODE_SYMBOL(node) (node)
+#define NODE_DECL(node) (node)->decl
+#define cgraph_node_name(node) (node)->name()
+#define NODE_IMPLICIT_ALIAS(node) (node)->cpp_implicit_alias
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000 && BUILDING_GCC_VERSION < 6000
+/* gimple related */
+template <>
+template <>
+inline bool is_a_helper<const gassign *>::test(const_gimple gs)
+{
+ return gs->code == GIMPLE_ASSIGN;
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000
+#define TODO_verify_ssa TODO_verify_il
+#define TODO_verify_flow TODO_verify_il
+#define TODO_verify_stmts TODO_verify_il
+#define TODO_verify_rtl_sharing TODO_verify_il
+
+#define INSN_DELETED_P(insn) (insn)->deleted()
+
+/* symtab/cgraph related */
+#define debug_cgraph_node(node) (node)->debug()
+#define cgraph_get_node(decl) cgraph_node::get(decl)
+#define cgraph_get_create_node(decl) cgraph_node::get_create(decl)
+#define cgraph_create_node(decl) cgraph_node::create(decl)
+#define cgraph_n_nodes symtab->cgraph_count
+#define cgraph_max_uid symtab->cgraph_max_uid
+#define varpool_get_node(decl) varpool_node::get(decl)
+
+#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \
+ (caller)->create_edge((callee), (call_stmt), (count), (freq))
+#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \
+ (caller)->create_edge_including_clones((callee), (old_call_stmt), (call_stmt), (count), (freq), (reason))
+
+typedef struct cgraph_node *cgraph_node_ptr;
+typedef struct cgraph_edge *cgraph_edge_p;
+typedef struct varpool_node *varpool_node_ptr;
+
+static inline void change_decl_assembler_name(tree decl, tree name)
+{
+ symtab->change_decl_assembler_name(decl, name);
+}
+
+static inline void varpool_finalize_decl(tree decl)
+{
+ varpool_node::finalize_decl(decl);
+}
+
+static inline void varpool_add_new_variable(tree decl)
+{
+ varpool_node::add(decl);
+}
+
+static inline unsigned int rebuild_cgraph_edges(void)
+{
+ return cgraph_edge::rebuild_edges();
+}
+
+static inline cgraph_node_ptr cgraph_function_node(cgraph_node_ptr node, enum availability *availability)
+{
+ return node->function_symbol(availability);
+}
+
+static inline cgraph_node_ptr cgraph_function_or_thunk_node(cgraph_node_ptr node, enum availability *availability = NULL)
+{
+ return node->ultimate_alias_target(availability);
+}
+
+static inline bool cgraph_only_called_directly_p(cgraph_node_ptr node)
+{
+ return node->only_called_directly_p();
+}
+
+static inline enum availability cgraph_function_body_availability(cgraph_node_ptr node)
+{
+ return node->get_availability();
+}
+
+static inline cgraph_node_ptr cgraph_alias_target(cgraph_node_ptr node)
+{
+ return node->get_alias_target();
+}
+
+static inline struct cgraph_node_hook_list *cgraph_add_function_insertion_hook(cgraph_node_hook hook, void *data)
+{
+ return symtab->add_cgraph_insertion_hook(hook, data);
+}
+
+static inline void cgraph_remove_function_insertion_hook(struct cgraph_node_hook_list *entry)
+{
+ symtab->remove_cgraph_insertion_hook(entry);
+}
+
+static inline struct cgraph_node_hook_list *cgraph_add_node_removal_hook(cgraph_node_hook hook, void *data)
+{
+ return symtab->add_cgraph_removal_hook(hook, data);
+}
+
+static inline void cgraph_remove_node_removal_hook(struct cgraph_node_hook_list *entry)
+{
+ symtab->remove_cgraph_removal_hook(entry);
+}
+
+static inline struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook(cgraph_2node_hook hook, void *data)
+{
+ return symtab->add_cgraph_duplication_hook(hook, data);
+}
+
+static inline void cgraph_remove_node_duplication_hook(struct cgraph_2node_hook_list *entry)
+{
+ symtab->remove_cgraph_duplication_hook(entry);
+}
+
+static inline void cgraph_call_node_duplication_hooks(cgraph_node_ptr node, cgraph_node_ptr node2)
+{
+ symtab->call_cgraph_duplication_hooks(node, node2);
+}
+
+static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_edge *cs2)
+{
+ symtab->call_edge_duplication_hooks(cs1, cs2);
+}
+
+#if BUILDING_GCC_VERSION >= 6000
+typedef gimple *gimple_ptr;
+typedef const gimple *const_gimple_ptr;
+#define gimple gimple_ptr
+#define const_gimple const_gimple_ptr
+#undef CONST_CAST_GIMPLE
+#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X))
+#endif
+
+/* gimple related */
+static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL)
+{
+ return gimple_build_assign(lhs, subcode, op1, op2 PASS_MEM_STAT);
+}
+
+template <>
+template <>
+inline bool is_a_helper<const greturn *>::test(const_gimple gs)
+{
+ return gs->code == GIMPLE_RETURN;
+}
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+ return as_a<gasm *>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+ return as_a<const gasm *>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+ return as_a<gassign *>(stmt);
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+ return as_a<const gassign *>(stmt);
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+ return as_a<gcall *>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+ return as_a<const gcall *>(stmt);
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+ return as_a<gphi *>(stmt);
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+ return as_a<const gphi *>(stmt);
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+ return as_a<greturn *>(stmt);
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+ return as_a<const greturn *>(stmt);
+}
+
+/* IPA/LTO related */
+#define ipa_ref_list_referring_iterate(L, I, P) \
+ (L)->referring.iterate((I), &(P))
+#define ipa_ref_list_reference_iterate(L, I, P) \
+ (L)->reference.iterate((I), &(P))
+
+static inline cgraph_node_ptr ipa_ref_referring_node(struct ipa_ref *ref)
+{
+ return dyn_cast<cgraph_node_ptr>(ref->referring);
+}
+
+static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimple stmt)
+{
+ referring_node->remove_stmt_references(stmt);
+}
+#endif
+
+#if BUILDING_GCC_VERSION < 6000
+#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \
+ get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, pvolatilep, keep_aligning)
+#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET(VOIDmode, (ARG0), (ARG1))
+#endif
+
+#if BUILDING_GCC_VERSION >= 6000
+#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET((ARG0), (ARG1))
+#endif
+
+#ifdef __cplusplus
+static inline void debug_tree(const_tree t)
+{
+ debug_tree(CONST_CAST_TREE(t));
+}
+
+static inline void debug_gimple_stmt(const_gimple s)
+{
+ debug_gimple_stmt(CONST_CAST_GIMPLE(s));
+}
+#else
+#define debug_tree(t) debug_tree(CONST_CAST_TREE(t))
+#define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s))
+#endif
+
+#endif
diff --git a/tools/gcc/gcc-generate-gimple-pass.h b/tools/gcc/gcc-generate-gimple-pass.h
new file mode 100644
index 0000000..526c3c7
--- /dev/null
+++ b/tools/gcc/gcc-generate-gimple-pass.h
@@ -0,0 +1,175 @@
+/*
+ * Generator for GIMPLE pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ * NO_GATE
+ * NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override
+ * the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n) #n
+#define _GCC_PLUGIN_STRINGIFY(n) __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y) x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z) x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n) _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n) _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n) _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct gimple_opt_pass _PASS_NAME_PASS = {
+ .pass = {
+#endif
+ .type = GIMPLE_PASS,
+ .name = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = _HAS_GATE,
+ .has_execute = _HAS_EXECUTE,
+#else
+ .gate = _GATE,
+ .execute = _EXECUTE,
+ .sub = NULL,
+ .next = NULL,
+ .static_pass_number = 0,
+#endif
+ .tv_id = TV_NONE,
+ .properties_required = PROPERTIES_REQUIRED,
+ .properties_provided = PROPERTIES_PROVIDED,
+ .properties_destroyed = PROPERTIES_DESTROYED,
+ .todo_flags_start = TODO_FLAGS_START,
+ .todo_flags_finish = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+ }
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public gimple_opt_pass {
+public:
+ _PASS_NAME_PASS() : gimple_opt_pass(_PASS_NAME_PASS_DATA, g) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual bool gate(function *) { return _GATE(); }
+#else
+ virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+ virtual opt_pass * clone () { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+ virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+
+#endif /* PASS_NAME */
diff --git a/tools/gcc/gcc-generate-ipa-pass.h b/tools/gcc/gcc-generate-ipa-pass.h
new file mode 100644
index 0000000..9bd926e
--- /dev/null
+++ b/tools/gcc/gcc-generate-ipa-pass.h
@@ -0,0 +1,289 @@
+/*
+ * Generator for IPA pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ * NO_GENERATE_SUMMARY
+ * NO_READ_SUMMARY
+ * NO_WRITE_SUMMARY
+ * NO_READ_OPTIMIZATION_SUMMARY
+ * NO_WRITE_OPTIMIZATION_SUMMARY
+ * NO_STMT_FIXUP
+ * NO_FUNCTION_TRANSFORM
+ * NO_VARIABLE_TRANSFORM
+ * NO_GATE
+ * NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and *TODO_FLAGS_* to override
+ * the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n) #n
+#define _GCC_PLUGIN_STRINGIFY(n) __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y) x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z) x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n) _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GENERATE_SUMMARY
+#define _GENERATE_SUMMARY NULL
+#else
+#define __GENERATE_SUMMARY(n) _GCC_PLUGIN_CONCAT2(n, _generate_summary)
+#define _GENERATE_SUMMARY __GENERATE_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_READ_SUMMARY
+#define _READ_SUMMARY NULL
+#else
+#define __READ_SUMMARY(n) _GCC_PLUGIN_CONCAT2(n, _read_summary)
+#define _READ_SUMMARY __READ_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_WRITE_SUMMARY
+#define _WRITE_SUMMARY NULL
+#else
+#define __WRITE_SUMMARY(n) _GCC_PLUGIN_CONCAT2(n, _write_summary)
+#define _WRITE_SUMMARY __WRITE_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_READ_OPTIMIZATION_SUMMARY
+#define _READ_OPTIMIZATION_SUMMARY NULL
+#else
+#define __READ_OPTIMIZATION_SUMMARY(n) _GCC_PLUGIN_CONCAT2(n, _read_optimization_summary)
+#define _READ_OPTIMIZATION_SUMMARY __READ_OPTIMIZATION_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_WRITE_OPTIMIZATION_SUMMARY
+#define _WRITE_OPTIMIZATION_SUMMARY NULL
+#else
+#define __WRITE_OPTIMIZATION_SUMMARY(n) _GCC_PLUGIN_CONCAT2(n, _write_optimization_summary)
+#define _WRITE_OPTIMIZATION_SUMMARY __WRITE_OPTIMIZATION_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_STMT_FIXUP
+#define _STMT_FIXUP NULL
+#else
+#define __STMT_FIXUP(n) _GCC_PLUGIN_CONCAT2(n, _stmt_fixup)
+#define _STMT_FIXUP __STMT_FIXUP(PASS_NAME)
+#endif
+
+#ifdef NO_FUNCTION_TRANSFORM
+#define _FUNCTION_TRANSFORM NULL
+#else
+#define __FUNCTION_TRANSFORM(n) _GCC_PLUGIN_CONCAT2(n, _function_transform)
+#define _FUNCTION_TRANSFORM __FUNCTION_TRANSFORM(PASS_NAME)
+#endif
+
+#ifdef NO_VARIABLE_TRANSFORM
+#define _VARIABLE_TRANSFORM NULL
+#else
+#define __VARIABLE_TRANSFORM(n) _GCC_PLUGIN_CONCAT2(n, _variable_transform)
+#define _VARIABLE_TRANSFORM __VARIABLE_TRANSFORM(PASS_NAME)
+#endif
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n) _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n) _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#ifndef FUNCTION_TRANSFORM_TODO_FLAGS_START
+#define FUNCTION_TRANSFORM_TODO_FLAGS_START 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct ipa_opt_pass_d _PASS_NAME_PASS = {
+ .pass = {
+#endif
+ .type = IPA_PASS,
+ .name = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = _HAS_GATE,
+ .has_execute = _HAS_EXECUTE,
+#else
+ .gate = _GATE,
+ .execute = _EXECUTE,
+ .sub = NULL,
+ .next = NULL,
+ .static_pass_number = 0,
+#endif
+ .tv_id = TV_NONE,
+ .properties_required = PROPERTIES_REQUIRED,
+ .properties_provided = PROPERTIES_PROVIDED,
+ .properties_destroyed = PROPERTIES_DESTROYED,
+ .todo_flags_start = TODO_FLAGS_START,
+ .todo_flags_finish = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+ },
+ .generate_summary = _GENERATE_SUMMARY,
+ .write_summary = _WRITE_SUMMARY,
+ .read_summary = _READ_SUMMARY,
+#if BUILDING_GCC_VERSION >= 4006
+ .write_optimization_summary = _WRITE_OPTIMIZATION_SUMMARY,
+ .read_optimization_summary = _READ_OPTIMIZATION_SUMMARY,
+#endif
+ .stmt_fixup = _STMT_FIXUP,
+ .function_transform_todo_flags_start = FUNCTION_TRANSFORM_TODO_FLAGS_START,
+ .function_transform = _FUNCTION_TRANSFORM,
+ .variable_transform = _VARIABLE_TRANSFORM,
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public ipa_opt_pass_d {
+public:
+ _PASS_NAME_PASS() : ipa_opt_pass_d(_PASS_NAME_PASS_DATA,
+ g,
+ _GENERATE_SUMMARY,
+ _WRITE_SUMMARY,
+ _READ_SUMMARY,
+ _WRITE_OPTIMIZATION_SUMMARY,
+ _READ_OPTIMIZATION_SUMMARY,
+ _STMT_FIXUP,
+ FUNCTION_TRANSFORM_TODO_FLAGS_START,
+ _FUNCTION_TRANSFORM,
+ _VARIABLE_TRANSFORM) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual bool gate(function *) { return _GATE(); }
+#else
+ virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+ virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+ virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GENERATE_SUMMARY
+#undef NO_WRITE_SUMMARY
+#undef NO_READ_SUMMARY
+#undef NO_WRITE_OPTIMIZATION_SUMMARY
+#undef NO_READ_OPTIMIZATION_SUMMARY
+#undef NO_STMT_FIXUP
+#undef NO_FUNCTION_TRANSFORM
+#undef NO_VARIABLE_TRANSFORM
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef FUNCTION_TRANSFORM_TODO_FLAGS_START
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _FUNCTION_TRANSFORM
+#undef __FUNCTION_TRANSFORM
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _GENERATE_SUMMARY
+#undef __GENERATE_SUMMARY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+#undef _READ_OPTIMIZATION_SUMMARY
+#undef __READ_OPTIMIZATION_SUMMARY
+#undef _READ_SUMMARY
+#undef __READ_SUMMARY
+#undef _STMT_FIXUP
+#undef __STMT_FIXUP
+#undef _VARIABLE_TRANSFORM
+#undef __VARIABLE_TRANSFORM
+#undef _WRITE_OPTIMIZATION_SUMMARY
+#undef __WRITE_OPTIMIZATION_SUMMARY
+#undef _WRITE_SUMMARY
+#undef __WRITE_SUMMARY
+
+#endif /* PASS_NAME */
diff --git a/tools/gcc/gcc-generate-rtl-pass.h b/tools/gcc/gcc-generate-rtl-pass.h
new file mode 100644
index 0000000..1dc67a5
--- /dev/null
+++ b/tools/gcc/gcc-generate-rtl-pass.h
@@ -0,0 +1,175 @@
+/*
+ * Generator for RTL pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ * NO_GATE
+ * NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override
+ * the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n) #n
+#define _GCC_PLUGIN_STRINGIFY(n) __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y) x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z) x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n) _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n) _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n) _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct rtl_opt_pass _PASS_NAME_PASS = {
+ .pass = {
+#endif
+ .type = RTL_PASS,
+ .name = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = _HAS_GATE,
+ .has_execute = _HAS_EXECUTE,
+#else
+ .gate = _GATE,
+ .execute = _EXECUTE,
+ .sub = NULL,
+ .next = NULL,
+ .static_pass_number = 0,
+#endif
+ .tv_id = TV_NONE,
+ .properties_required = PROPERTIES_REQUIRED,
+ .properties_provided = PROPERTIES_PROVIDED,
+ .properties_destroyed = PROPERTIES_DESTROYED,
+ .todo_flags_start = TODO_FLAGS_START,
+ .todo_flags_finish = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+ }
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public rtl_opt_pass {
+public:
+ _PASS_NAME_PASS() : rtl_opt_pass(_PASS_NAME_PASS_DATA, g) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual bool gate(function *) { return _GATE(); }
+#else
+ virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+ virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+ virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+
+#endif /* PASS_NAME */
diff --git a/tools/gcc/gcc-generate-simple_ipa-pass.h b/tools/gcc/gcc-generate-simple_ipa-pass.h
new file mode 100644
index 0000000..a27e2b3
--- /dev/null
+++ b/tools/gcc/gcc-generate-simple_ipa-pass.h
@@ -0,0 +1,175 @@
+/*
+ * Generator for SIMPLE_IPA pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ * NO_GATE
+ * NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override
+ * the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n) #n
+#define _GCC_PLUGIN_STRINGIFY(n) __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y) x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z) x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n) _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n) _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n) _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct simple_ipa_opt_pass _PASS_NAME_PASS = {
+ .pass = {
+#endif
+ .type = SIMPLE_IPA_PASS,
+ .name = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+ .optinfo_flags = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+ .has_gate = _HAS_GATE,
+ .has_execute = _HAS_EXECUTE,
+#else
+ .gate = _GATE,
+ .execute = _EXECUTE,
+ .sub = NULL,
+ .next = NULL,
+ .static_pass_number = 0,
+#endif
+ .tv_id = TV_NONE,
+ .properties_required = PROPERTIES_REQUIRED,
+ .properties_provided = PROPERTIES_PROVIDED,
+ .properties_destroyed = PROPERTIES_DESTROYED,
+ .todo_flags_start = TODO_FLAGS_START,
+ .todo_flags_finish = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+ }
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public simple_ipa_opt_pass {
+public:
+ _PASS_NAME_PASS() : simple_ipa_opt_pass(_PASS_NAME_PASS_DATA, g) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual bool gate(function *) { return _GATE(); }
+#else
+ virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+ virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+ virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+ virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+ return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+
+#endif /* PASS_NAME */
--
2.4.1

2016-03-06 23:07:39

by Emese Revfy

[permalink] [raw]
Subject: [PATCH v5 3/5] Add Cyclomatic complexity GCC plugin

Add a very simple plugin to demonstrate the GCC plugin infrastructure. This GCC
plugin computes the cyclomatic complexity of each function.

The complexity M of a function's control flow graph is defined as:
M = E - N + 2P
where
E = the number of edges
N = the number of nodes
P = the number of connected components (exit nodes).

Signed-off-by: Emese Revfy <[email protected]>
---
arch/Kconfig | 12 +++++++
scripts/Makefile.gcc-plugins | 6 +++-
tools/gcc/Makefile | 4 +++
tools/gcc/cyc_complexity_plugin.c | 73 +++++++++++++++++++++++++++++++++++++++
4 files changed, 94 insertions(+), 1 deletion(-)
create mode 100644 tools/gcc/cyc_complexity_plugin.c

diff --git a/arch/Kconfig b/arch/Kconfig
index e090642..59bde9b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -370,6 +370,18 @@ menuconfig GCC_PLUGINS
GCC plugins are loadable modules that provide extra features to the
compiler. They are useful for runtime instrumentation and static analysis.

+config GCC_PLUGIN_CYC_COMPLEXITY
+ bool "Compute the cyclomatic complexity of a function"
+ depends on GCC_PLUGINS
+ help
+ The complexity M of a function's control flow graph is defined as:
+ M = E - N + 2P
+ where
+
+ E = the number of edges
+ N = the number of nodes
+ P = the number of connected components (exit nodes).
+
config HAVE_CC_STACKPROTECTOR
bool
help
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 7c85bf2..dd7b56d 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -5,7 +5,11 @@ else
PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
endif
ifneq ($(PLUGINCC),)
-export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
+ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
+GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so
+endif
+GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
ifeq ($(KBUILD_EXTMOD),)
gcc-plugins:
$(Q)$(MAKE) $(build)=tools/gcc
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
index b2d64af..31c72bf 100644
--- a/tools/gcc/Makefile
+++ b/tools/gcc/Makefile
@@ -12,4 +12,8 @@ endif

export GCCPLUGINS_DIR HOSTLIBS

+$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) := cyc_complexity_plugin.so
+
always := $($(HOSTLIBS)-y)
+
+cyc_complexity_plugin-objs := cyc_complexity_plugin.o
diff --git a/tools/gcc/cyc_complexity_plugin.c b/tools/gcc/cyc_complexity_plugin.c
new file mode 100644
index 0000000..34df974
--- /dev/null
+++ b/tools/gcc/cyc_complexity_plugin.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2016 by Emese Revfy <[email protected]>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
+ *
+ * http://en.wikipedia.org/wiki/Cyclomatic_complexity
+ * The complexity M is then defined as:
+ * M = E - N + 2P
+ * where
+ *
+ * E = the number of edges of the graph
+ * N = the number of nodes of the graph
+ * P = the number of connected components (exit nodes).
+ *
+ * Usage (4.5 - 5):
+ * $ make clean; make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+static struct plugin_info cyc_complexity_plugin_info = {
+ .version = "20160225",
+ .help = "Cyclomatic Complexity\n",
+};
+
+static unsigned int cyc_complexity_execute(void)
+{
+ int complexity;
+ expanded_location xloc;
+
+ /* M = E - N + 2P */
+ complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
+
+ xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+ fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity,
+ xloc.file, DECL_NAME_POINTER(current_function_decl));
+
+ return 0;
+}
+
+#define PASS_NAME cyc_complexity
+
+#define NO_GATE
+#define TODO_FLAGS_FINISH TODO_dump_func
+
+#include "gcc-generate-gimple-pass.h"
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+ const char * const plugin_name = plugin_info->base_name;
+ struct register_pass_info cyc_complexity_pass_info;
+
+ cyc_complexity_pass_info.pass = make_cyc_complexity_pass();
+ cyc_complexity_pass_info.reference_pass_name = "ssa";
+ cyc_complexity_pass_info.ref_pass_instance_number = 1;
+ cyc_complexity_pass_info.pos_op = PASS_POS_INSERT_AFTER;
+
+ if (!plugin_default_version_check(version, &gcc_version)) {
+ error(G_("incompatible gcc/plugin versions"));
+ return 1;
+ }
+
+ register_callback(plugin_name, PLUGIN_INFO, NULL,
+ &cyc_complexity_plugin_info);
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+ &cyc_complexity_pass_info);
+
+ return 0;
+}
--
2.4.1

2016-03-06 23:08:37

by Emese Revfy

[permalink] [raw]
Subject: [PATCH v5 4/5] Documentation for the GCC plugin infrastructure

This is the GCC infrastructure documentation about its operation, how to add
and use a new plugin with an example.

Signed-off-by: Emese Revfy <[email protected]>
---
Documentation/gcc-plugins.txt | 82 +++++++++++++++++++++++++++++++++++++++++++
arch/Kconfig | 2 ++
2 files changed, 84 insertions(+)
create mode 100644 Documentation/gcc-plugins.txt

diff --git a/Documentation/gcc-plugins.txt b/Documentation/gcc-plugins.txt
new file mode 100644
index 0000000..ffb56a3
--- /dev/null
+++ b/Documentation/gcc-plugins.txt
@@ -0,0 +1,82 @@
+GCC plugin infrastructure
+=========================
+
+
+1. Introduction
+===============
+
+GCC plugins are loadable modules that provide extra features to the
+compiler [1]. They are useful for runtime instrumentation and static analysis.
+We can analyse, change and add further code during compilation via
+callbacks [2], GIMPLE [3], IPA [4] and RTL passes [5].
+
+The GCC plugin infrastructure of the kernel supports all gcc versions from
+4.5 to 6.0, building out-of-tree modules, cross-compilation and building in a
+separate directory.
+
+Currently the GCC plugin infrastructure supports only the x86 architecture.
+
+This infrastructure was ported from grsecurity [6] and PaX [7].
+
+--
+[1] https://gcc.gnu.org/onlinedocs/gccint/Plugins.html
+[2] https://gcc.gnu.org/onlinedocs/gccint/Plugin-API.html#Plugin-API
+[3] https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
+[4] https://gcc.gnu.org/onlinedocs/gccint/IPA.html
+[5] https://gcc.gnu.org/onlinedocs/gccint/RTL.html
+[6] https://grsecurity.net/
+[7] https://pax.grsecurity.net/
+
+
+2. Files
+========
+
+$(src)/tools/gcc
+ This is the directory of the GCC plugins.
+
+$(src)/tools/gcc/gcc-common.h
+ This is a compatibility header for GCC plugins.
+ It should be always included instead of individual gcc headers.
+
+$(src)/scripts/gcc-plugin.sh
+ This script checks the availability of the included headers in
+ gcc-common.h and chooses the proper host compiler to build the plugins
+ (gcc-4.7 can be built by either gcc or g++).
+
+$(src)/tools/gcc/gcc-generate-gimple-pass.h
+$(src)/tools/gcc/gcc-generate-ipa-pass.h
+$(src)/tools/gcc/gcc-generate-simple_ipa-pass.h
+$(src)/tools/gcc/gcc-generate-rtl-pass.h
+ These headers automatically generate the registration structures for
+ GIMPLE, SIMPLE_IPA, IPA and RTL passes. They support all gcc versions
+ from 4.5 to 6.0.
+ They should be preferred to creating the structures by hand.
+
+
+3. Usage
+========
+
+You must install the gcc plugin headers for your gcc version,
+e.g., on Ubuntu for gcc-4.9:
+
+ apt-get install gcc-4.9-plugin-dev
+
+Enable a GCC plugin based feature in the kernel config:
+
+ CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y
+
+To compile only the plugin(s):
+
+ make gcc-plugins
+
+or just run the kernel make and compile the whole kernel with
+the cyclomatic complexity GCC plugin.
+
+
+4. How to add a new GCC plugin
+==============================
+
+The GCC plugins are in $(src)/tools/gcc/. You can use a file or a directory
+here. It must be added to $(src)/tools/gcc/Makefile,
+$(src)/scripts/Makefile.gcc-plugins and $(src)/arch/Kconfig.
+See the cyc_complexity_plugin.c (CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) GCC plugin.
diff --git a/arch/Kconfig b/arch/Kconfig
index 59bde9b..32583b7 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -370,6 +370,8 @@ menuconfig GCC_PLUGINS
GCC plugins are loadable modules that provide extra features to the
compiler. They are useful for runtime instrumentation and static analysis.

+ See Documentation/gcc-plugins.txt for details.
+
config GCC_PLUGIN_CYC_COMPLEXITY
bool "Compute the cyclomatic complexity of a function"
depends on GCC_PLUGINS
--
2.4.1

2016-03-06 23:09:37

by Emese Revfy

[permalink] [raw]
Subject: [PATCH v5 5/5] Add sancov plugin

The sancov gcc plugin inserts a __sanitizer_cov_trace_pc() call
at the start of basic blocks.

This plugin is a helper plugin for the kcov feature. It supports
all gcc versions with plugin support (from gcc-4.5 on).
It is based on the gcc commit "Add fuzzing coverage support" by Dmitry Vyukov
(https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296).

Signed-off-by: Emese Revfy <[email protected]>
---
arch/Kconfig | 9 +++
scripts/Makefile.gcc-plugins | 7 ++-
tools/gcc/Makefile | 2 +
tools/gcc/sancov_plugin.c | 133 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 149 insertions(+), 2 deletions(-)
create mode 100644 tools/gcc/sancov_plugin.c

diff --git a/arch/Kconfig b/arch/Kconfig
index 32583b7..30632fa 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -384,6 +384,15 @@ config GCC_PLUGIN_CYC_COMPLEXITY
N = the number of nodes
P = the number of connected components (exit nodes).

+config GCC_PLUGIN_SANCOV
+ bool "Helper plugin for the kcov feature"
+ depends on GCC_PLUGINS
+ help
+ This plugin inserts a __sanitizer_cov_trace_pc() call at the start of
+ basic blocks. It supports all gcc versions with plugin support (from
+ gcc-4.5 on). It is based on the commit "Add fuzzing coverage support"
+ by Dmitry Vyukov <[email protected]>.
+
config HAVE_CC_STACKPROTECTOR
bool
help
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index dd7b56d..dc11503 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -8,8 +8,11 @@ ifneq ($(PLUGINCC),)
ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so
endif
-GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
-export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
+ifdef CONFIG_GCC_PLUGIN_SANCOV
+GCC_PLUGIN_SANCOV_CFLAGS := -fplugin=$(objtree)/tools/gcc/sancov_plugin.so
+endif
+GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS) $(GCC_PLUGIN_SANCOV_CFLAGS)
+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY GCC_PLUGIN_SANCOV
ifeq ($(KBUILD_EXTMOD),)
gcc-plugins:
$(Q)$(MAKE) $(build)=tools/gcc
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
index 31c72bf..97a923f 100644
--- a/tools/gcc/Makefile
+++ b/tools/gcc/Makefile
@@ -13,7 +13,9 @@ endif
export GCCPLUGINS_DIR HOSTLIBS

$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) := cyc_complexity_plugin.so
+$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so

always := $($(HOSTLIBS)-y)

cyc_complexity_plugin-objs := cyc_complexity_plugin.o
+sancov_plugin-objs := sancov_plugin.o
diff --git a/tools/gcc/sancov_plugin.c b/tools/gcc/sancov_plugin.c
new file mode 100644
index 0000000..5a9179b
--- /dev/null
+++ b/tools/gcc/sancov_plugin.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2011-2016 by Emese Revfy <[email protected]>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/sancov
+ *
+ * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks.
+ * It supports all gcc versions with plugin support (from gcc-4.5 on).
+ * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov <[email protected]>.
+ *
+ * You can read about it more here:
+ * https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296
+ * http://lwn.net/Articles/674854/
+ * https://github.com/google/syzkaller
+ * https://lwn.net/Articles/677764/
+ *
+ * Usage:
+ * make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+tree sancov_fndecl;
+
+static struct plugin_info sancov_plugin_info = {
+ .version = "20160305",
+ .help = "sancov plugin\n",
+};
+
+static unsigned int sancov_execute(void)
+{
+ basic_block bb;
+
+ /* Remove this line when this plugin and kcov will be in the kernel. */
+ if (!strcmp(DECL_NAME_POINTER(current_function_decl), DECL_NAME_POINTER(sancov_fndecl)))
+ return 0;
+
+ FOR_EACH_BB_FN(bb, cfun) {
+ const_gimple stmt;
+ gcall *gcall;
+ gimple_stmt_iterator gsi = gsi_after_labels(bb);
+
+ if (gsi_end_p(gsi))
+ continue;
+
+ stmt = gsi_stmt(gsi);
+ gcall = as_a_gcall(gimple_build_call(sancov_fndecl, 0));
+ gimple_set_location(gcall, gimple_location(stmt));
+ gsi_insert_before(&gsi, gcall, GSI_SAME_STMT);
+ }
+ return 0;
+}
+
+#define PASS_NAME sancov
+
+#define NO_GATE
+#define TODO_FLAGS_FINISH TODO_dump_func | TODO_verify_stmts | TODO_update_ssa_no_phi | TODO_verify_flow
+
+#include "gcc-generate-gimple-pass.h"
+
+static void sancov_start_unit(void __unused *gcc_data, void __unused *user_data)
+{
+ tree leaf_attr, nothrow_attr;
+ tree BT_FN_VOID = build_function_type_list(void_type_node, NULL_TREE);
+
+ sancov_fndecl = build_fn_decl("__sanitizer_cov_trace_pc", BT_FN_VOID);
+
+ nothrow_attr = tree_cons(get_identifier("nothrow"), NULL, NULL);
+ decl_attributes(&sancov_fndecl, nothrow_attr, 0);
+ gcc_assert(TREE_NOTHROW(sancov_fndecl));
+ leaf_attr = tree_cons(get_identifier("leaf"), NULL, NULL);
+ decl_attributes(&sancov_fndecl, leaf_attr, 0);
+}
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+ int i;
+ struct register_pass_info sancov_plugin_pass_info;
+ const char * const plugin_name = plugin_info->base_name;
+ const int argc = plugin_info->argc;
+ const struct plugin_argument * const argv = plugin_info->argv;
+ bool enable = true;
+
+ static const struct ggc_root_tab gt_ggc_r_gt_sancov[] = {
+ {
+ .base = &sancov_fndecl,
+ .nelt = 1,
+ .stride = sizeof(sancov_fndecl),
+ .cb = &gt_ggc_mx_tree_node,
+ .pchw = &gt_pch_nx_tree_node
+ },
+ LAST_GGC_ROOT_TAB
+ };
+
+ /* BBs can be split afterwards?? */
+ sancov_plugin_pass_info.pass = make_sancov_pass();
+#if BUILDING_GCC_VERSION >= 4009
+ sancov_plugin_pass_info.reference_pass_name = "asan";
+#else
+ sancov_plugin_pass_info.reference_pass_name = "nrv";
+#endif
+ sancov_plugin_pass_info.ref_pass_instance_number = 0;
+ sancov_plugin_pass_info.pos_op = PASS_POS_INSERT_BEFORE;
+
+ if (!plugin_default_version_check(version, &gcc_version)) {
+ error(G_("incompatible gcc/plugin versions"));
+ return 1;
+ }
+
+ for (i = 0; i < argc; ++i) {
+ if (!strcmp(argv[i].key, "no-sancov")) {
+ enable = false;
+ continue;
+ }
+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
+ }
+
+ register_callback(plugin_name, PLUGIN_INFO, NULL, &sancov_plugin_info);
+
+ if (!enable)
+ return 0;
+
+#if BUILDING_GCC_VERSION < 6000
+ register_callback(plugin_name, PLUGIN_START_UNIT, &sancov_start_unit, NULL);
+ register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)&gt_ggc_r_gt_sancov);
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &sancov_plugin_pass_info);
+#endif
+
+ return 0;
+}
--
2.4.1

2016-03-07 21:05:25

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v5 1/5] Shared library support

On Sun, Mar 6, 2016 at 3:03 PM, Emese Revfy <[email protected]> wrote:
> Infrastructure for building independent shared library targets.
> This effectively also reverts commit 62e2210798ed38928ab24841e8b4878a
> (Masahiro Yamada, kbuild: drop shared library support from Makefile.host).

Should this literally be a revert? If so, we'd gain the Documentation
changes back too.

-Kees

>
> Signed-off-by: Emese Revfy <[email protected]>
> ---
> scripts/Makefile.build | 2 +-
> scripts/Makefile.clean | 3 ++-
> scripts/Makefile.host | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 71 insertions(+), 3 deletions(-)

--
Kees Cook
Chrome OS & Brillo Security

2016-03-07 21:07:52

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v5 5/5] Add sancov plugin

On Sun, Mar 6, 2016 at 3:07 PM, Emese Revfy <[email protected]> wrote:
> The sancov gcc plugin inserts a __sanitizer_cov_trace_pc() call
> at the start of basic blocks.
>
> This plugin is a helper plugin for the kcov feature. It supports
> all gcc versions with plugin support (from gcc-4.5 on).
> It is based on the gcc commit "Add fuzzing coverage support" by Dmitry Vyukov
> (https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296).

Very cool! Dmitry, is this something you could put to good use?

> [...]
> diff --git a/tools/gcc/sancov_plugin.c b/tools/gcc/sancov_plugin.c
> new file mode 100644
> index 0000000..5a9179b
> --- /dev/null
> +++ b/tools/gcc/sancov_plugin.c
> @@ -0,0 +1,133 @@
> +/*
> + * Copyright 2011-2016 by Emese Revfy <[email protected]>
> + * Licensed under the GPL v2, or (at your option) v3
> + *
> + * Homepage:
> + * https://github.com/ephox-gcc-plugins/sancov
> + *
> + * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks.
> + * It supports all gcc versions with plugin support (from gcc-4.5 on).
> + * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov <[email protected]>.
> + *
> + * You can read about it more here:
> + * https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296
> + * http://lwn.net/Articles/674854/
> + * https://github.com/google/syzkaller
> + * https://lwn.net/Articles/677764/
> + *
> + * Usage:
> + * make run

Is this accurate? Wouldn't it just be selected from CONFIGs during kernel build?

-Kees

--
Kees Cook
Chrome OS & Brillo Security

2016-03-07 21:31:41

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 5/5] Add sancov plugin

On Mon, 7 Mar 2016 13:07:32 -0800
Kees Cook <[email protected]> wrote:

> > diff --git a/tools/gcc/sancov_plugin.c b/tools/gcc/sancov_plugin.c
> > new file mode 100644
> > index 0000000..5a9179b
> > --- /dev/null
> > +++ b/tools/gcc/sancov_plugin.c
> > @@ -0,0 +1,133 @@
> > +/*
> > + * Copyright 2011-2016 by Emese Revfy <[email protected]>
> > + * Licensed under the GPL v2, or (at your option) v3
> > + *
> > + * Homepage:
> > + * https://github.com/ephox-gcc-plugins/sancov
> > + *
> > + * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks.
> > + * It supports all gcc versions with plugin support (from gcc-4.5 on).
> > + * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov <[email protected]>.
> > + *
> > + * You can read about it more here:
> > + * https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296
> > + * http://lwn.net/Articles/674854/
> > + * https://github.com/google/syzkaller
> > + * https://lwn.net/Articles/677764/
> > + *
> > + * Usage:
> > + * make run
>
> Is this accurate? Wouldn't it just be selected from CONFIGs during kernel build?

This is just a usage example when someone clones the plugin from github. Every plugin written by me contains this. :)

For now it can be enabled from menuconfig for testing because I'm waiting for the reactions.
Later I think the best way would be when kcov is enabled that it also enables the plugin automatically
if the target gcc version doesn't support the -fsanitize-coverage=trace-pc option but it supports plugins.

--
Emese

2016-03-07 21:34:42

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 1/5] Shared library support

On Mon, 7 Mar 2016 13:05:16 -0800
Kees Cook <[email protected]> wrote:

> On Sun, Mar 6, 2016 at 3:03 PM, Emese Revfy <[email protected]> wrote:
> > Infrastructure for building independent shared library targets.
> > This effectively also reverts commit 62e2210798ed38928ab24841e8b4878a
> > (Masahiro Yamada, kbuild: drop shared library support from Makefile.host).
>
> Should this literally be a revert? If so, we'd gain the Documentation
> changes back too.

Sure, I'll do it in the next patch set.

--
Emese

2016-03-08 10:54:59

by Dmitry Vyukov

[permalink] [raw]
Subject: Re: [PATCH v5 5/5] Add sancov plugin

On Mon, Mar 7, 2016 at 10:07 PM, Kees Cook <[email protected]> wrote:
> On Sun, Mar 6, 2016 at 3:07 PM, Emese Revfy <[email protected]> wrote:
>> The sancov gcc plugin inserts a __sanitizer_cov_trace_pc() call
>> at the start of basic blocks.
>>
>> This plugin is a helper plugin for the kcov feature. It supports
>> all gcc versions with plugin support (from gcc-4.5 on).
>> It is based on the gcc commit "Add fuzzing coverage support" by Dmitry Vyukov
>> (https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296).
>
> Very cool! Dmitry, is this something you could put to good use?

I am using gcc with sancov as a regular pass, so I don't a good use
for this right now. Maybe it will help with deployment for Android. I
don't know. Though, it will require backporting this plugin support.

2016-03-09 09:01:28

by David Brown

[permalink] [raw]
Subject: Re: [kernel-hardening] [PATCH v5 2/5] GCC plugin infrastructure

On Mon, Mar 07, 2016 at 12:04:27AM +0100, Emese Revfy wrote:

>This patch allows to build the whole kernel with GCC plugins. It was ported from
>grsecurity/PaX. The infrastructure supports building out-of-tree modules and
>building in a separate directory. Cross-compilation is supported too but
>currently only the x86 architecture enables plugins.

I've tested this with both ARM and ARM64. There are some missing
headers in the arm64 gcc, reported here:
https://bugs.linaro.org/show_bug.cgi?id=2123 (also upstream), but this
should work once that is fixed.

Feel free to fold these into your patch, or, if you prefer, I can send
out separate patches for them.

Signed-off-by: David Brown <[email protected]>

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4f799e5..67ee8e3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -54,6 +54,7 @@ config ARM
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
select HAVE_GENERIC_DMA_COHERENT
+ select HAVE_GCC_PLUGINS
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
select HAVE_IDE if PCI || ISA || PCMCIA
select HAVE_IRQ_TIME_ACCOUNTING
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8cc6228..6d6e4f8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -70,6 +70,7 @@ config ARM64
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if PERF_EVENTS
select HAVE_IRQ_TIME_ACCOUNTING
--

2016-03-09 20:50:36

by Kees Cook

[permalink] [raw]
Subject: Re: [kernel-hardening] [PATCH v5 2/5] GCC plugin infrastructure

On Wed, Mar 9, 2016 at 1:01 AM, David Brown <[email protected]> wrote:
> On Mon, Mar 07, 2016 at 12:04:27AM +0100, Emese Revfy wrote:
>
>> This patch allows to build the whole kernel with GCC plugins. It was
>> ported from
>> grsecurity/PaX. The infrastructure supports building out-of-tree modules
>> and
>> building in a separate directory. Cross-compilation is supported too but
>> currently only the x86 architecture enables plugins.
>
>
> I've tested this with both ARM and ARM64. There are some missing
> headers in the arm64 gcc, reported here:
> https://bugs.linaro.org/show_bug.cgi?id=2123 (also upstream), but this
> should work once that is fixed.
>
> Feel free to fold these into your patch, or, if you prefer, I can send
> out separate patches for them.

Ah-ha, great! Thanks for testing!

Emese, if you're not interested in carrying this, I can add it to my tree.

-Kees

>
> Signed-off-by: David Brown <[email protected]>
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 4f799e5..67ee8e3 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -54,6 +54,7 @@ config ARM
> select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
> select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
> select HAVE_GENERIC_DMA_COHERENT
> + select HAVE_GCC_PLUGINS
> select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K ||
> CPU_V7))
> select HAVE_IDE if PCI || ISA || PCMCIA
> select HAVE_IRQ_TIME_ACCOUNTING
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 8cc6228..6d6e4f8 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -70,6 +70,7 @@ config ARM64
> select HAVE_FTRACE_MCOUNT_RECORD
> select HAVE_FUNCTION_TRACER
> select HAVE_FUNCTION_GRAPH_TRACER
> + select HAVE_GCC_PLUGINS
> select HAVE_GENERIC_DMA_COHERENT
> select HAVE_HW_BREAKPOINT if PERF_EVENTS
> select HAVE_IRQ_TIME_ACCOUNTING
> --



--
Kees Cook
Chrome OS & Brillo Security

2016-03-09 22:05:24

by Emese Revfy

[permalink] [raw]
Subject: Re: [kernel-hardening] [PATCH v5 2/5] GCC plugin infrastructure

On Wed, 9 Mar 2016 02:01:15 -0700
David Brown <[email protected]> wrote:

> Feel free to fold these into your patch, or, if you prefer, I can send
> out separate patches for them.

Thanks, I'll take it.

--
Emese

2016-03-09 22:09:49

by Emese Revfy

[permalink] [raw]
Subject: Re: [kernel-hardening] [PATCH v5 2/5] GCC plugin infrastructure

On Wed, 9 Mar 2016 12:50:26 -0800
Kees Cook <[email protected]> wrote:

> > Feel free to fold these into your patch, or, if you prefer, I can send
> > out separate patches for them.
>
> Ah-ha, great! Thanks for testing!
>
> Emese, if you're not interested in carrying this, I can add it to my tree.

I think it is easier if it is in my patch set.

--
Emese

2016-03-11 06:20:08

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 1/5] Shared library support

Hi Emese,

2016-03-07 8:03 GMT+09:00 Emese Revfy <[email protected]>:
> Infrastructure for building independent shared library targets.
> This effectively also reverts commit 62e2210798ed38928ab24841e8b4878a
> (Masahiro Yamada, kbuild: drop shared library support from Makefile.host).
>
> Signed-off-by: Emese Revfy <[email protected]>
> ---
> scripts/Makefile.build | 2 +-
> scripts/Makefile.clean | 3 ++-
> scripts/Makefile.host | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 71 insertions(+), 3 deletions(-)
>
> diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> index 130a452..bd2a31e 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -60,7 +60,7 @@ endif
> endif
>
> # Do not include host rules unless needed
> -ifneq ($(hostprogs-y)$(hostprogs-m),)
> +ifneq ($(hostprogs-y)$(hostprogs-m)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(hostcxxlibs-m),)
> include scripts/Makefile.host
> endif
>
> diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
> index 55c96cb..e4e88ab 100644
> --- a/scripts/Makefile.clean
> +++ b/scripts/Makefile.clean
> @@ -38,7 +38,8 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
> __clean-files := $(extra-y) $(extra-m) $(extra-) \
> $(always) $(targets) $(clean-files) \
> $(host-progs) \
> - $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
> + $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
> + $(hostlibs-y) $(hostlibs-m) $(hostlibs-)
>
> __clean-files := $(filter-out $(no-clean-files), $(__clean-files))
>
> diff --git a/scripts/Makefile.host b/scripts/Makefile.host
> index 133edfa..4d180d9 100644
> --- a/scripts/Makefile.host
> +++ b/scripts/Makefile.host
> @@ -20,7 +20,25 @@
> # Will compile qconf as a C++ program, and menu as a C program.
> # They are linked as C++ code to the executable qconf
>
> +# hostprogs-y := conf
> +# conf-objs := conf.o libkconfig.so
> +# libkconfig-objs := expr.o type.o
> +# Will create a shared library named libkconfig.so that consists of
> +# expr.o and type.o (they are both compiled as C code and the object files
> +# are made as position independent code).
> +# conf.c is compiled as a C program, and conf.o is linked together with
> +# libkconfig.so as the executable conf.
> +# Note: Shared libraries consisting of C++ files are not supported

I do not see any use-case for the above.

This series adds cases for "foo.so" as a final target.


As an alternative, you can add needed build rules
into tools/gcc/Makefile, not scripts/Makefile.host

I guess these rule won't be used in other places.



> +# hostcc-option
> +# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
> +
> +hostcc-option = $(call try-run,\
> + $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
> +
> __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
> +__hostlibs := $(sort $(hostlibs-y) $(hostlibs-m))
> +__hostcxxlibs := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
>
> # C code
> # Executables compiled from a single .c file
> @@ -42,6 +60,19 @@ 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)))
>
> +# Shared libaries (only .c supported)
> +# Shared libraries (.so) - all .so files referenced in "xxx-objs"
> +host-cshlib := $(sort $(filter %.so, $(host-cobjs)))

useless.

> +host-cshlib += $(sort $(filter %.so, $(__hostlibs)))
> +host-cxxshlib := $(sort $(filter %.so, $(__hostcxxlibs)))
> +# Remove .so files from "xxx-objs"
> +host-cobjs := $(filter-out %.so,$(host-cobjs))
> +host-cxxobjs := $(filter-out %.so,$(host-cxxobjs))
> +
> +# Object (.o) files used by the shared libaries
> +host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
> +host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
> +
> # 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
> @@ -56,6 +87,10 @@ 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-cshlib := $(addprefix $(obj)/,$(host-cshlib))
> +host-cxxshlib := $(addprefix $(obj)/,$(host-cxxshlib))
> +host-cshobjs := $(addprefix $(obj)/,$(host-cshobjs))
> +host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
> host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
>
> obj-dirs += $(host-objdirs)
> @@ -124,5 +159,37 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@
> $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
> $(call if_changed_dep,host-cxxobjs)
>
> +# Compile .c file, create position independent .o file
> +# host-cshobjs -> .o
> +quiet_cmd_host-cshobjs = HOSTCC -fPIC $@
> + cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
> +$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
> + $(call if_changed_dep,host-cshobjs)
> +
> +# Compile .c file, create position independent .o file
> +# host-cxxshobjs -> .o
> +quiet_cmd_host-cxxshobjs = HOSTCXX -fPIC $@
> + cmd_host-cxxshobjs = $(HOSTCXX) $(hostcxx_flags) -fPIC -c -o $@ $<
> +$(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE
> + $(call if_changed_dep,host-cxxshobjs)
> +
> +# Link a shared library, based on position independent .o files
> +# *.o -> .so shared library (host-cshlib)
> +quiet_cmd_host-cshlib = HOSTLLD -shared $@
> + cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
> + $(addprefix $(obj)/,$($(@F:.so=-objs))) \
> + $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
> +$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
> + $(call if_changed,host-cshlib)


Could you use $(call multi-depend, ...)
if you need to handle multi-object please?

Please refer to commit c8589d1e9e01 and commit 97e3226e6e984c8.

But, I still do not see any gcc-plugin that is large enough
to be linked from multiple objects.





--
Best Regards
Masahiro Yamada

2016-03-11 06:25:39

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

Hi Emese,

I am not familiar with GCC plugins.

Comments from the view of Kbuild.


2016-03-07 8:04 GMT+09:00 Emese Revfy <[email protected]>:
> This patch allows to build the whole kernel with GCC plugins. It was ported from
> grsecurity/PaX. The infrastructure supports building out-of-tree modules and
> building in a separate directory. Cross-compilation is supported too but
> currently only the x86 architecture enables plugins.
>
> The directory of the gcc plugins is tools/gcc. You can use a file or a directory


Maybe scripts/gcc-plugins/ is better than tools/gcc ?

In the directory "scripts/", we have several tools used during
building the kernel image.
We have some optional programs in the directory "tools/", which are not used
for building the kernel image itself.

Please correct me if I am wrong.



You sprinkle "gcc-plugins" target in the top Makefile, which I do not like.

Can you descend into scripts/gcc-plugins from scripts/Makefile?


subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-y += mod
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
+subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins


This is how other host tools do, I think.





>
> +ccflags-y := $(GCC_PLUGINS_CFLAGS)
> +asflags-y := $(GCC_PLUGINS_AFLAGS)
> +
> obj-y := main.o version.o mounts.o
> ifneq ($(CONFIG_BLK_DEV_INITRD),y)
> obj-y += noinitramfs.o
> diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
> new file mode 100644
> index 0000000..7c85bf2
> --- /dev/null
> +++ b/scripts/Makefile.gcc-plugins
> @@ -0,0 +1,28 @@
> +ifdef CONFIG_GCC_PLUGINS
> +ifeq ($(call cc-ifversion, -ge, 0408, y), y)
> +PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)")
> +else
> +PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
> +endif

The difference is only the first argument.

Can you make it as follows?

__HOSTCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC))

PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh
"$(__HOSTCC)" "$(HOSTCXX)" "$(CC)")


I did not come up with a good name for __HOSTCC.
Feel free to replace it with a better one.





> +ifneq ($(PLUGINCC),)
> +export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
> +ifeq ($(KBUILD_EXTMOD),)
> +gcc-plugins:
> + $(Q)$(MAKE) $(build)=tools/gcc
> +else
> +gcc-plugins: ;
> +endif
> +else
> +gcc-plugins:
> +ifeq ($(call cc-ifversion, -ge, 0405, y), y)
> + $(warning warning, your gcc installation does not support plugins, perhaps the necessary headers are missing?)
> +ifeq ($(call cc-ifversion, -ge, 0408, y), y)
> + $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)"
> +else
> + $(CONFIG_SHELL) -x $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)"
> +endif
> +else
> + $(warning warning, your gcc version does not support plugins, you should upgrade it to gcc 4.5 at least)
> +endif
> +endif
> +endif


These ifdef's are really unreadable.
I wondered if it could be a bit simpler.
At least, the deepest one can be resolved with the "__HOSTCC" set above.




> diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh
> new file mode 100644
> index 0000000..eaa4fce
> --- /dev/null
> +++ b/scripts/gcc-plugin.sh
> @@ -0,0 +1,51 @@
> +#!/bin/sh
> +srctree=$(dirname "$0")
> +gccplugins_dir=$($3 -print-file-name=plugin)
> +plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <<EOF
> +#include "gcc-common.h"


Maybe <gcc-common.h> because it is not located at the same directory?



> diff --git a/tools/gcc/gcc-common.h b/tools/gcc/gcc-common.h
> new file mode 100644
> index 0000000..172850b
> --- /dev/null
> +++ b/tools/gcc/gcc-common.h
> @@ -0,0 +1,830 @@
> +#ifndef GCC_COMMON_H_INCLUDED
> +#define GCC_COMMON_H_INCLUDED
> +
> +#include "bversion.h"
> +#if BUILDING_GCC_VERSION >= 6000
> +#include "gcc-plugin.h"
> +#else
> +#include "plugin.h"
> +#endif
> +#include "plugin-version.h"
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "line-map.h"
> +#include "input.h"
> +#include "tree.h"
> +
> +#include "tree-inline.h"
> +#include "version.h"
> +#include "rtl.h"
> +#include "tm_p.h"
> +#include "flags.h"
> +#include "hard-reg-set.h"
> +#include "output.h"
> +#include "except.h"
> +#include "function.h"
> +#include "toplev.h"
> +#include "basic-block.h"
> +#include "intl.h"
> +#include "ggc.h"
> +#include "timevar.h"
> +
> +#include "params.h"
> +
> +#if BUILDING_GCC_VERSION <= 4009
> +#include "pointer-set.h"
> +#else
> +#include "hash-map.h"
> +#endif
> +
> +#include "emit-rtl.h"
> +#include "debug.h"
> +#include "target.h"
> +#include "langhooks.h"
> +#include "cfgloop.h"
> +#include "cgraph.h"
> +#include "opts.h"

All of these are included by "...", not <...>.


As mentioned above, I want you to use "..." style
when you need to use relative path from the source.

I do not see most of them in tools/gcc/.




--
Best Regards
Masahiro Yamada

2016-03-11 06:27:13

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 3/5] Add Cyclomatic complexity GCC plugin

Hi Emese,


2016-03-07 8:05 GMT+09:00 Emese Revfy <[email protected]>:
> Add a very simple plugin to demonstrate the GCC plugin infrastructure. This GCC
> plugin computes the cyclomatic complexity of each function.
>
> The complexity M of a function's control flow graph is defined as:
> M = E - N + 2P
> where
> E = the number of edges
> N = the number of nodes
> P = the number of connected components (exit nodes).
>
> Signed-off-by: Emese Revfy <[email protected]>
> ---
> arch/Kconfig | 12 +++++++
> scripts/Makefile.gcc-plugins | 6 +++-
> tools/gcc/Makefile | 4 +++
> tools/gcc/cyc_complexity_plugin.c | 73 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 94 insertions(+), 1 deletion(-)
> create mode 100644 tools/gcc/cyc_complexity_plugin.c
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index e090642..59bde9b 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -370,6 +370,18 @@ menuconfig GCC_PLUGINS
> GCC plugins are loadable modules that provide extra features to the
> compiler. They are useful for runtime instrumentation and static analysis.
>
> +config GCC_PLUGIN_CYC_COMPLEXITY
> + bool "Compute the cyclomatic complexity of a function"
> + depends on GCC_PLUGINS
> + help
> + The complexity M of a function's control flow graph is defined as:
> + M = E - N + 2P
> + where
> +
> + E = the number of edges
> + N = the number of nodes
> + P = the number of connected components (exit nodes).
> +
> config HAVE_CC_STACKPROTECTOR
> bool
> help
> diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
> index 7c85bf2..dd7b56d 100644
> --- a/scripts/Makefile.gcc-plugins
> +++ b/scripts/Makefile.gcc-plugins
> @@ -5,7 +5,11 @@ else
> PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
> endif
> ifneq ($(PLUGINCC),)
> -export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
> +ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
> +GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so
> +endif
> +GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
> +export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY


Do you need to export "GCC_PLUGIN_CYC_COMPLEXITY"?
I do not see any reference to it.

If we expect more and more plugins in the future,
is it better to do like this?

gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so
gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so
gcc-plugin-$(CONFIG_GCC_PLUGIN_FOO) += foo_plugin.so


GCC_PLUGINS_CFLAGS := $(addprefix -fplugin=$(objtree)/tools/gcc/,
$(gcc-plugin-y))








--
Best Regards
Masahiro Yamada

2016-03-14 20:16:58

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 1/5] Shared library support

On Fri, 11 Mar 2016 15:19:33 +0900
Masahiro Yamada <[email protected]> wrote:

> As an alternative, you can add needed build rules
> into tools/gcc/Makefile, not scripts/Makefile.host
>
> I guess these rule won't be used in other places.

I think it is better if the rules stay under scripts/ because I expect that there will also be clang and llvm plugins
in the future (e.g., clang plugins can access the frontend that gcc plugins can't do). In this case these rules would
either have to be duplicated or moved back under scripts/ (which makes it difficult to backport).

> > +# hostcc-option
> > +# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
> > +
> > +hostcc-option = $(call try-run,\
> > + $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
> > +
> > __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
> > +__hostlibs := $(sort $(hostlibs-y) $(hostlibs-m))
> > +__hostcxxlibs := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
> >
> > # C code
> > # Executables compiled from a single .c file
> > @@ -42,6 +60,19 @@ 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)))
> >
> > +# Shared libaries (only .c supported)
> > +# Shared libraries (.so) - all .so files referenced in "xxx-objs"
> > +host-cshlib := $(sort $(filter %.so, $(host-cobjs)))
>
> useless.

Which part do you think is useless and why?

> > +host-cshlib += $(sort $(filter %.so, $(__hostlibs)))
> > +host-cxxshlib := $(sort $(filter %.so, $(__hostcxxlibs)))
> > +# Remove .so files from "xxx-objs"
> > +host-cobjs := $(filter-out %.so,$(host-cobjs))
> > +host-cxxobjs := $(filter-out %.so,$(host-cxxobjs))
> > +
> > +# Object (.o) files used by the shared libaries
> > +host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
> > +host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
> > +
> > # 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
> > @@ -56,6 +87,10 @@ 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-cshlib := $(addprefix $(obj)/,$(host-cshlib))
> > +host-cxxshlib := $(addprefix $(obj)/,$(host-cxxshlib))
> > +host-cshobjs := $(addprefix $(obj)/,$(host-cshobjs))
> > +host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
> > host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
> >
> > obj-dirs += $(host-objdirs)
> > @@ -124,5 +159,37 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@
> > $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
> > $(call if_changed_dep,host-cxxobjs)
> >
> > +# Compile .c file, create position independent .o file
> > +# host-cshobjs -> .o
> > +quiet_cmd_host-cshobjs = HOSTCC -fPIC $@
> > + cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
> > +$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
> > + $(call if_changed_dep,host-cshobjs)
> > +
> > +# Compile .c file, create position independent .o file
> > +# host-cxxshobjs -> .o
> > +quiet_cmd_host-cxxshobjs = HOSTCXX -fPIC $@
> > + cmd_host-cxxshobjs = $(HOSTCXX) $(hostcxx_flags) -fPIC -c -o $@ $<
> > +$(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE
> > + $(call if_changed_dep,host-cxxshobjs)
> > +
> > +# Link a shared library, based on position independent .o files
> > +# *.o -> .so shared library (host-cshlib)
> > +quiet_cmd_host-cshlib = HOSTLLD -shared $@
> > + cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
> > + $(addprefix $(obj)/,$($(@F:.so=-objs))) \
> > + $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
> > +$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
> > + $(call if_changed,host-cshlib)
>
>
> Could you use $(call multi-depend, ...)
> if you need to handle multi-object please?
>
> Please refer to commit c8589d1e9e01 and commit 97e3226e6e984c8.

Ok, I will check it out.

> But, I still do not see any gcc-plugin that is large enough
> to be linked from multiple objects.

There will be large plugins later (typically if the plugin has more passes e.g., my size_overflow plugin).

--
Emese

2016-03-14 20:54:26

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

On Fri, 11 Mar 2016 15:25:19 +0900
Masahiro Yamada <[email protected]> wrote:

> Maybe scripts/gcc-plugins/ is better than tools/gcc ?
>
> In the directory "scripts/", we have several tools used during
> building the kernel image.
> We have some optional programs in the directory "tools/", which are not used
> for building the kernel image itself.
>
> Please correct me if I am wrong.

I think scripts isn't the right place because there are tools there which don't get used
during the building of vmlinux (e.g., coccinelle, checkpatch).
The scripts name also doesn't describe gcc plugins well. Plugins take part in the image building process
in a different way than these tools and scripts do.
Since there doesn't seen to be a good place for compiler plugins, maybe we should create a new toplevel directory
called "build". Compiler plugins and other existing build tools could live there. What do you think?

> > +ccflags-y := $(GCC_PLUGINS_CFLAGS)
> > +asflags-y := $(GCC_PLUGINS_AFLAGS)
> > +
> > obj-y := main.o version.o mounts.o
> > ifneq ($(CONFIG_BLK_DEV_INITRD),y)
> > obj-y += noinitramfs.o
> > diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
> > new file mode 100644
> > index 0000000..7c85bf2
> > --- /dev/null
> > +++ b/scripts/Makefile.gcc-plugins
> > @@ -0,0 +1,28 @@
> > +ifdef CONFIG_GCC_PLUGINS
> > +ifeq ($(call cc-ifversion, -ge, 0408, y), y)
> > +PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCXX)" "$(HOSTCXX)" "$(CC)")
> > +else
> > +PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
> > +endif
>
> The difference is only the first argument.
>
> Can you make it as follows?
>
> __HOSTCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC))
>
> PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh
> "$(__HOSTCC)" "$(HOSTCXX)" "$(CC)")
>
>
> I did not come up with a good name for __HOSTCC.
> Feel free to replace it with a better one.

Sure, I will do it.

--
Emese

2016-03-14 21:04:55

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 3/5] Add Cyclomatic complexity GCC plugin

On Fri, 11 Mar 2016 15:26:39 +0900
Masahiro Yamada <[email protected]> wrote:

> > diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
> > index 7c85bf2..dd7b56d 100644
> > --- a/scripts/Makefile.gcc-plugins
> > +++ b/scripts/Makefile.gcc-plugins
> > @@ -5,7 +5,11 @@ else
> > PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
> > endif
> > ifneq ($(PLUGINCC),)
> > -export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
> > +ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
> > +GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so
> > +endif
> > +GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
> > +export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
>
>
> Do you need to export "GCC_PLUGIN_CYC_COMPLEXITY"?
> I do not see any reference to it.

This is a demo plugin. I just want to demonstrate how to use this infrastructure but I can remove it.
In my project there would be other plugins which use the export.

> If we expect more and more plugins in the future,
> is it better to do like this?
>
> gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so
> gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so
> gcc-plugin-$(CONFIG_GCC_PLUGIN_FOO) += foo_plugin.so
>
>
> GCC_PLUGINS_CFLAGS := $(addprefix -fplugin=$(objtree)/tools/gcc/,
> $(gcc-plugin-y))

Yes, it is better, I will do it.

--
Emese

2016-03-14 21:26:13

by PaX Team

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

On 11 Mar 2016 at 15:25, Masahiro Yamada wrote:

> > diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh
> > new file mode 100644
> > index 0000000..eaa4fce
> > --- /dev/null
> > +++ b/scripts/gcc-plugin.sh
> > @@ -0,0 +1,51 @@
> > +#!/bin/sh
> > +srctree=$(dirname "$0")
> > +gccplugins_dir=$($3 -print-file-name=plugin)
> > +plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <<EOF
> > +#include "gcc-common.h"
>
>
> Maybe <gcc-common.h> because it is not located at the same directory?

[snip]
> > +#include "emit-rtl.h"
> > +#include "debug.h"
> > +#include "target.h"
> > +#include "langhooks.h"
> > +#include "cfgloop.h"
> > +#include "cgraph.h"
> > +#include "opts.h"
>
> All of these are included by "...", not <...>.
>
>
> As mentioned above, I want you to use "..." style
> when you need to use relative path from the source.
>
> I do not see most of them in tools/gcc/.

no, that'd be incorrect for several reasons. first, the rule to use <...> vs. "..."
include directives is not about the header being in the same directory but whether
the header is a system header or one provided by the given program. roughly speaking,
system headers are those that are available through the compiler's default include
paths (gcc's own headers, those of glibc and other libraries under /usr/include, etc).
gcc plugin headers are *not* available by default, one has to query the compiler about
their path (see -print-file-name=plugin above) and explicitly add it to the compiler's
include search path.

second, regardless of whether plugin headers are available by default or not, we
still couldn't use them during cross-compilation as the plugin headers we want are
those of the target compiler (that will load the plugin eventually), not that of
the host compiler (which merely compiles the plugin and in theory doesn't even have
to be gcc or a plugin capable gcc).

for these reasons the correct include directive is "..." and not <...>. if it helps
to understand the situation better, consider that gcc plugins are to gcc as kernel
modules are to vmlinux and all kernel headers are included via "..." as well, regardless
of whether they're in the same directory or not.

cheers,
PaX Team

2016-03-16 07:34:11

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

Hi PaX,


2016-03-15 6:25 GMT+09:00 PaX Team <[email protected]>:
> On 11 Mar 2016 at 15:25, Masahiro Yamada wrote:
>
>> > diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh
>> > new file mode 100644
>> > index 0000000..eaa4fce
>> > --- /dev/null
>> > +++ b/scripts/gcc-plugin.sh
>> > @@ -0,0 +1,51 @@
>> > +#!/bin/sh
>> > +srctree=$(dirname "$0")
>> > +gccplugins_dir=$($3 -print-file-name=plugin)
>> > +plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/../tools/gcc -I"${gccplugins_dir}"/include 2>&1 <<EOF
>> > +#include "gcc-common.h"
>>
>>
>> Maybe <gcc-common.h> because it is not located at the same directory?
>
> [snip]
>> > +#include "emit-rtl.h"
>> > +#include "debug.h"
>> > +#include "target.h"
>> > +#include "langhooks.h"
>> > +#include "cfgloop.h"
>> > +#include "cgraph.h"
>> > +#include "opts.h"
>>
>> All of these are included by "...", not <...>.
>>
>>
>> As mentioned above, I want you to use "..." style
>> when you need to use relative path from the source.
>>
>> I do not see most of them in tools/gcc/.
>
> no, that'd be incorrect for several reasons. first, the rule to use <...> vs. "..."
> include directives is not about the header being in the same directory but whether
> the header is a system header or one provided by the given program. roughly speaking,
> system headers are those that are available through the compiler's default include
> paths (gcc's own headers, those of glibc and other libraries under /usr/include, etc).
> gcc plugin headers are *not* available by default, one has to query the compiler about
> their path (see -print-file-name=plugin above) and explicitly add it to the compiler's
> include search path.

Are you sure?

I'd recommend you to read the following:
https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html


scripts/gcc-plugin.sh adds
- ${srctree}"/../tools/gcc
- ${gccplugins_dir}/include

to the header search path with "-I" option.


GCC looks for headers requested with #include <file>
in directories specified with "-I" as well as in the default ones.



> second, regardless of whether plugin headers are available by default or not, we
> still couldn't use them during cross-compilation as the plugin headers we want are
> those of the target compiler (that will load the plugin eventually), not that of
> the host compiler (which merely compiles the plugin and in theory doesn't even have
> to be gcc or a plugin capable gcc).

So, how could this be the reason why we should avoid #include <file>?



> for these reasons the correct include directive is "..." and not <...>. if it helps
> to understand the situation better, consider that gcc plugins are to gcc as kernel
> modules are to vmlinux and all kernel headers are included via "..." as well, regardless
> of whether they're in the same directory or not.

Of course, you could use #include "..." as well to include kernel headers,
but you should not do that.

You should do so only when you need to include headers that are local
to your directory.


--
Best Regards
Masahiro Yamada

2016-03-16 07:41:44

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

Hi Emese,

2016-03-15 5:52 GMT+09:00 Emese Revfy <[email protected]>:
> On Fri, 11 Mar 2016 15:25:19 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> Maybe scripts/gcc-plugins/ is better than tools/gcc ?
>>
>> In the directory "scripts/", we have several tools used during
>> building the kernel image.
>> We have some optional programs in the directory "tools/", which are not used
>> for building the kernel image itself.
>>
>> Please correct me if I am wrong.
>
> I think scripts isn't the right place because there are tools there which don't get used
> during the building of vmlinux (e.g., coccinelle, checkpatch).

No, this is not what I meant.

What I want to say is:
All the host tools used for building vmlinux should be located in the
directory "scripts/",
but the directory may also other host tools that are not used for
building vmlinux (such as checkpatch).


> The scripts name also doesn't describe gcc plugins well.

With my suggestion "scripts/gcc-plugins/",
the sub-directory name describes it very well.


> Plugins take part in the image building process
> in a different way than these tools and scripts do.
> Since there doesn't seen to be a good place for compiler plugins, maybe we should create a new toplevel directory
> called "build". Compiler plugins and other existing build tools could live there. What do you think?

In my understanding, they are plug-in'ed into the cross-compiler that
compiles vmlinux.

If so, GCC plugins should be happy in "scripts/"
because Kbuild descends into "scripts/" before building any objects for vmlinux.


--
Best Regards
Masahiro Yamada

2016-03-16 07:50:53

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 1/5] Shared library support

Hi Emese,


2016-03-15 5:14 GMT+09:00 Emese Revfy <[email protected]>:
> On Fri, 11 Mar 2016 15:19:33 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> As an alternative, you can add needed build rules
>> into tools/gcc/Makefile, not scripts/Makefile.host
>>
>> I guess these rule won't be used in other places.
>
> I think it is better if the rules stay under scripts/ because I expect that there will also be clang and llvm plugins
> in the future (e.g., clang plugins can access the frontend that gcc plugins can't do). In this case these rules would
> either have to be duplicated or moved back under scripts/ (which makes it difficult to backport).
>
>> > +# hostcc-option
>> > +# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
>> > +
>> > +hostcc-option = $(call try-run,\
>> > + $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
>> > +
>> > __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
>> > +__hostlibs := $(sort $(hostlibs-y) $(hostlibs-m))
>> > +__hostcxxlibs := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
>> >
>> > # C code
>> > # Executables compiled from a single .c file
>> > @@ -42,6 +60,19 @@ 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)))
>> >
>> > +# Shared libaries (only .c supported)
>> > +# Shared libraries (.so) - all .so files referenced in "xxx-objs"
>> > +host-cshlib := $(sort $(filter %.so, $(host-cobjs)))
>>
>> useless.
>
> Which part do you think is useless and why?


The line

host-cshlib := $(sort $(filter %.so, $(host-cobjs)))

is useless because there is no host program that consists of .so files.


Your intention is to generate shared objects as final targets,
not host tools that call shared objects.





--
Best Regards
Masahiro Yamada

2016-03-16 12:50:21

by PaX Team

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

On 16 Mar 2016 at 16:34, Masahiro Yamada wrote:

Hi,

> >> As mentioned above, I want you to use "..." style
> >> when you need to use relative path from the source.
> >>
> >> I do not see most of them in tools/gcc/.
> >
> > no, that'd be incorrect for several reasons. first, the rule to use <...> vs. "..."
> > include directives is not about the header being in the same directory but whether
> > the header is a system header or one provided by the given program. roughly speaking,
> > system headers are those that are available through the compiler's default include
> > paths (gcc's own headers, those of glibc and other libraries under /usr/include, etc).
> > gcc plugin headers are *not* available by default, one has to query the compiler about
> > their path (see -print-file-name=plugin above) and explicitly add it to the compiler's
> > include search path.
>
> Are you sure?

sure about which part? ;) the use of <...> vs "..." is a matter of convention (to
differentiate between 'system' headers from the program's own) and for gcc the plugin
headers don't count as 'system' headers, gcc uses "..." throughout its codebase itself
(so does clang/llvm). it'd look weird and inconsistent if compiler plugins used <...>.

at the end of the day this comes down to whether gcc plugins are considered kernel
code and thus the kernel style applies to them (the kernel itself uses <...> because
it's a freestanding program so its 'system' headers are mostly what it provides
itself, not those of the compiler let alone userland libs) or gcc extensions and thus
the gcc include style applies to them. as you can guess, i'm arguing for the latter,
because gcc plugins are meant for the compiler, not the kernel per se, and in fact
we have several plugins already that can be used in userland as well (e.g., Emese's
size overflow plugin).

the one thing for plugins that i borrowed from the kernel instead of gcc is the code
formatting style as the GNU one is as bad as Linus argued decades ago ;).

> > second, regardless of whether plugin headers are available by default or not, we
> > still couldn't use them during cross-compilation as the plugin headers we want are
> > those of the target compiler (that will load the plugin eventually), not that of
> > the host compiler (which merely compiles the plugin and in theory doesn't even have
> > to be gcc or a plugin capable gcc).
>
> So, how could this be the reason why we should avoid #include <file>?

because <...> is meant for headers that are on the compiler's default search path
and even if gcc plugin headers were there (they aren't) they'd be the wrong ones
to use, you'd have to specifically override the include path with that of the target
compiler which is a sign that you're no longer including 'system' headers (again,
this convention holds for hosted programs, freestanding ones don't have anything
but 'system' headers usually).

> > for these reasons the correct include directive is "..." and not <...>. if it helps
> > to understand the situation better, consider that gcc plugins are to gcc as kernel
> > modules are to vmlinux and all kernel headers are included via "..." as well, regardless
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sorry, i take that back, the kernel uses <...> but for a reason that in my opinion
doesn't apply to compiler plugins (see above).

> > of whether they're in the same directory or not.
>
> Of course, you could use #include "..." as well to include kernel headers,
> but you should not do that.
>
> You should do so only when you need to include headers that are local
> to your directory.

sure, a header in the same directory is a sign that it's not a 'system' header but
i'm also saying that there can be other non-system headers in a program in other
directories as well. FWIW, the kernel itself has several "..." directives that
reference headers outside of the same directory, e.g., try this in a kernel tree:

grep "#include.*\"\." -rn

cheers,
PaX Team

2016-03-16 21:08:15

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

On Wed, 16 Mar 2016 16:41:36 +0900
Masahiro Yamada <[email protected]> wrote:

> > The scripts name also doesn't describe gcc plugins well.
>
> With my suggestion "scripts/gcc-plugins/",
> the sub-directory name describes it very well.
>
>
> > Plugins take part in the image building process
> > in a different way than these tools and scripts do.
> > Since there doesn't seen to be a good place for compiler plugins, maybe we should create a new toplevel directory
> > called "build". Compiler plugins and other existing build tools could live there. What do you think?
>
> In my understanding, they are plug-in'ed into the cross-compiler that
> compiles vmlinux.
>
> If so, GCC plugins should be happy in "scripts/"
> because Kbuild descends into "scripts/" before building any objects for vmlinux.

Ok, I'll move them under scripts/ in the next patch set.

--
Emese

2016-03-17 04:10:03

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

2016-03-16 21:49 GMT+09:00 PaX Team <[email protected]>:
> On 16 Mar 2016 at 16:34, Masahiro Yamada wrote:
>
> Hi,
>
>> >> As mentioned above, I want you to use "..." style
>> >> when you need to use relative path from the source.
>> >>
>> >> I do not see most of them in tools/gcc/.
>> >
>> > no, that'd be incorrect for several reasons. first, the rule to use <...> vs. "..."
>> > include directives is not about the header being in the same directory but whether
>> > the header is a system header or one provided by the given program. roughly speaking,
>> > system headers are those that are available through the compiler's default include
>> > paths (gcc's own headers, those of glibc and other libraries under /usr/include, etc).
>> > gcc plugin headers are *not* available by default, one has to query the compiler about
>> > their path (see -print-file-name=plugin above) and explicitly add it to the compiler's
>> > include search path.
>>
>> Are you sure?
>
> sure about which part? ;)

You said "that'd be incorrect", but
there is no "correct" or "incorrect" in either way as long as it works.

This decision varies from project to project.

At least in Linux, it generally uses #include <file> style
except ones in local directories.
I guess it is debatable if this rule also applies to host tools or not.


> the use of <...> vs "..." is a matter of convention (to
> differentiate between 'system' headers from the program's own) and for gcc the plugin
> headers don't count as 'system' headers, gcc uses "..." throughout its codebase itself
> (so does clang/llvm). it'd look weird and inconsistent if compiler plugins used <...>.
>
> at the end of the day this comes down to whether gcc plugins are considered kernel
> code and thus the kernel style applies to them (the kernel itself uses <...> because
> it's a freestanding program so its 'system' headers are mostly what it provides
> itself, not those of the compiler let alone userland libs) or gcc extensions and thus
> the gcc include style applies to them. as you can guess, i'm arguing for the latter,
> because gcc plugins are meant for the compiler, not the kernel per se, and in fact
> we have several plugins already that can be used in userland as well (e.g., Emese's
> size overflow plugin).
>
> the one thing for plugins that i borrowed from the kernel instead of gcc is the code
> formatting style as the GNU one is as bad as Linus argued decades ago ;).
>
>> > second, regardless of whether plugin headers are available by default or not, we
>> > still couldn't use them during cross-compilation as the plugin headers we want are
>> > those of the target compiler (that will load the plugin eventually), not that of
>> > the host compiler (which merely compiles the plugin and in theory doesn't even have
>> > to be gcc or a plugin capable gcc).
>>
>> So, how could this be the reason why we should avoid #include <file>?
>
> because <...> is meant for headers that are on the compiler's default search path
> and even if gcc plugin headers were there (they aren't) they'd be the wrong ones
> to use, you'd have to specifically override the include path with that of the target
> compiler which is a sign that you're no longer including 'system' headers (again,
> this convention holds for hosted programs, freestanding ones don't have anything
> but 'system' headers usually).
>
>> > for these reasons the correct include directive is "..." and not <...>. if it helps
>> > to understand the situation better, consider that gcc plugins are to gcc as kernel
>> > modules are to vmlinux and all kernel headers are included via "..." as well, regardless
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> sorry, i take that back, the kernel uses <...> but for a reason that in my opinion
> doesn't apply to compiler plugins (see above).
>
>> > of whether they're in the same directory or not.
>>
>> Of course, you could use #include "..." as well to include kernel headers,
>> but you should not do that.
>>
>> You should do so only when you need to include headers that are local
>> to your directory.
>
> sure, a header in the same directory is a sign that it's not a 'system' header but
> i'm also saying that there can be other non-system headers in a program in other
> directories as well. FWIW, the kernel itself has several "..." directives that
> reference headers outside of the same directory, e.g., try this in a kernel tree:
>
> grep "#include.*\"\." -rn
>

To sum up, your suggestion for GCC plugins is

- Use #include <...> to include header files provided by the host compiler
- Use #include "..." to include header files provided by the cross
compiler (plugin directory)
- Use #include "..." to include header files in the local project

Correct?

I leave the final decision to others.


--
Best Regards
Masahiro Yamada

2016-03-24 00:10:11

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

On Fri, 11 Mar 2016 15:25:19 +0900
Masahiro Yamada <[email protected]> wrote:

> You sprinkle "gcc-plugins" target in the top Makefile, which I do not like.
>
> Can you descend into scripts/gcc-plugins from scripts/Makefile?
>
>
> subdir-$(CONFIG_MODVERSIONS) += genksyms
> subdir-y += mod
> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
> subdir-$(CONFIG_DTC) += dtc
> subdir-$(CONFIG_GDB_SCRIPTS) += gdb
> +subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
>
>
> This is how other host tools do, I think.

Hi,

I tried to remove the gcc-plugins target but sadly in this case the plugins aren't complied.
I don't know if I understand how it should work. I pushed a commit:
https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next/commit/0b005b886bde6c4b9134d01f830d88d464911a65
Could you please help me with what I did wrong?

Thanks
--
Emese

2016-03-26 02:39:39

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

Hi Emese,



2016-03-24 9:07 GMT+09:00 Emese Revfy <[email protected]>:
> On Fri, 11 Mar 2016 15:25:19 +0900
> Masahiro Yamada <[email protected]> wrote:
>
>> You sprinkle "gcc-plugins" target in the top Makefile, which I do not like.
>>
>> Can you descend into scripts/gcc-plugins from scripts/Makefile?
>>
>>
>> subdir-$(CONFIG_MODVERSIONS) += genksyms
>> subdir-y += mod
>> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
>> subdir-$(CONFIG_DTC) += dtc
>> subdir-$(CONFIG_GDB_SCRIPTS) += gdb
>> +subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
>>
>>
>> This is how other host tools do, I think.
>
> Hi,
>
> I tried to remove the gcc-plugins target but sadly in this case the plugins aren't complied.
> I don't know if I understand how it should work. I pushed a commit:
> https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next/commit/0b005b886bde6c4b9134d01f830d88d464911a65
> Could you please help me with what I did wrong?
>


Sorry, I missed this problem.

GCC-plugins must be compiled before descending into ./Kbuild.


Please apply the following on top of commit 0b005b88
and check if it works.




diff --git a/Makefile b/Makefile
index 1c7a379..bd643d3 100644
--- a/Makefile
+++ b/Makefile
@@ -1009,6 +1009,9 @@ archprepare: archheaders archscripts prepare1
scripts_basic
prepare0: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
prepare0: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
prepare0: archprepare FORCE
+ifdef CONFIG_GCC_PLUGINS
+ $(Q)$(MAKE) $(build)=scripts/gcc-plugins
+endif
$(Q)$(MAKE) $(build)=.

# All the preparing..
diff --git a/scripts/Makefile b/scripts/Makefile
index 0ba652c..1d80897 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -45,7 +45,6 @@ subdir-y += mod
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
-subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins

# Let clean descend into subdirs
-subdir- += basic kconfig package
+subdir- += basic kconfig package gcc-plugins





--
Best Regards
Masahiro Yamada

2016-03-27 21:11:38

by Emese Revfy

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

On Sat, 26 Mar 2016 11:39:32 +0900
Masahiro Yamada <[email protected]> wrote:

> > I tried to remove the gcc-plugins target but sadly in this case the plugins aren't complied.
> > I don't know if I understand how it should work. I pushed a commit:
> > https://github.com/ephox-gcc-plugins/gcc-plugins_linux-next/commit/0b005b886bde6c4b9134d01f830d88d464911a65
> > Could you please help me with what I did wrong?
> >
> Sorry, I missed this problem.
>
> GCC-plugins must be compiled before descending into ./Kbuild.
>
>
> Please apply the following on top of commit 0b005b88
> and check if it works.
>
> diff --git a/Makefile b/Makefile
> index 1c7a379..bd643d3 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1009,6 +1009,9 @@ archprepare: archheaders archscripts prepare1
> scripts_basic
> prepare0: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
> prepare0: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
> prepare0: archprepare FORCE
> +ifdef CONFIG_GCC_PLUGINS
> + $(Q)$(MAKE) $(build)=scripts/gcc-plugins
> +endif
> $(Q)$(MAKE) $(build)=.
>
> # All the preparing..
> diff --git a/scripts/Makefile b/scripts/Makefile
> index 0ba652c..1d80897 100644
> --- a/scripts/Makefile
> +++ b/scripts/Makefile
> @@ -45,7 +45,6 @@ subdir-y += mod
> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
> subdir-$(CONFIG_DTC) += dtc
> subdir-$(CONFIG_GDB_SCRIPTS) += gdb
> -subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
>
> # Let clean descend into subdirs
> -subdir- += basic kconfig package
> +subdir- += basic kconfig package gcc-plugins

Thanks for the patch. I tested it and there is a problem when I run a parallel make.
The plugins are compiled later than needed (e.g., scripts/mod/empty.o). There is a lot of important
code under scripts/mod which may need the plugins. If the plugins were compiled when the "scripts_basic"
target runs it would be good but unfortunately the config symbol CONFIG_GCC_PLUGINS doesn't seem to be defined yet.
Could you please help me solve this problem?

--
Emese

2016-04-02 04:32:55

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v5 2/5] GCC plugin infrastructure

Hi Emese,

Sorry for my late reply.


> Thanks for the patch. I tested it and there is a problem when I run a parallel make.
> The plugins are compiled later than needed (e.g., scripts/mod/empty.o). There is a lot of important
> code under scripts/mod which may need the plugins.

Ah, I missed that.


> If the plugins were compiled when the "scripts_basic"
> target runs it would be good but unfortunately the config symbol CONFIG_GCC_PLUGINS doesn't seem to be defined yet.
> Could you please help me solve this problem?


How about this?

It should apply on commit 0b005b886bde6c4b9134d01f830d88d464911a65
of your tree.



diff --git a/Makefile b/Makefile
index 1c7a379..d3518e0 100644
--- a/Makefile
+++ b/Makefile
@@ -550,7 +550,7 @@ ifeq ($(KBUILD_EXTMOD),)
# in parallel
PHONY += scripts
scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
- asm-generic
+ asm-generic gcc-plugins
$(Q)$(MAKE) $(build)=$(@)

# Objects we will link into vmlinux / subdirs we need to visit
@@ -625,6 +625,13 @@ endif
# Tell gcc to never replace conditional load with a non-conditional one
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)

+PHONY += gcc-plugins
+gcc-plugins: scripts_basic
+ifdef CONFIG_GCC_PLUGINS
+ $(Q)$(MAKE) $(build)=scripts/gcc-plugins
+endif
+ @:
+
include scripts/Makefile.gcc-plugins

ifdef CONFIG_READABLE_ASM
@@ -1008,7 +1015,7 @@ archprepare: archheaders archscripts prepare1
scripts_basic

prepare0: KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
prepare0: KBUILD_AFLAGS += $(GCC_PLUGINS_AFLAGS)
-prepare0: archprepare FORCE
+prepare0: archprepare gcc-plugins FORCE
$(Q)$(MAKE) $(build)=.

# All the preparing..
diff --git a/scripts/Makefile b/scripts/Makefile
index 0ba652c..1d80897 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -45,7 +45,6 @@ subdir-y += mod
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
-subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins

# Let clean descend into subdirs
-subdir- += basic kconfig package
+subdir- += basic kconfig package gcc-plugins





--
Best Regards
Masahiro Yamada