summaryrefslogtreecommitdiff
path: root/scripts/gcc-plugins
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gcc-plugins')
-rw-r--r--scripts/gcc-plugins/.gitignore3
-rw-r--r--scripts/gcc-plugins/Kconfig168
-rw-r--r--scripts/gcc-plugins/Makefile88
-rw-r--r--scripts/gcc-plugins/arm_ssp_per_task_plugin.c122
-rw-r--r--scripts/gcc-plugins/cyc_complexity_plugin.c69
-rw-r--r--scripts/gcc-plugins/gcc-common.h624
-rw-r--r--scripts/gcc-plugins/gcc-generate-gimple-pass.h31
-rw-r--r--scripts/gcc-plugins/gcc-generate-ipa-pass.h42
-rw-r--r--scripts/gcc-plugins/gcc-generate-rtl-pass.h36
-rw-r--r--scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h36
-rw-r--r--scripts/gcc-plugins/gen-random-seed.sh9
-rw-r--r--scripts/gcc-plugins/latent_entropy_plugin.c66
-rw-r--r--scripts/gcc-plugins/randomize_layout_plugin.c171
-rw-r--r--scripts/gcc-plugins/sancov_plugin.c140
-rw-r--r--scripts/gcc-plugins/stackleak_plugin.c318
-rw-r--r--scripts/gcc-plugins/structleak_plugin.c250
16 files changed, 440 insertions, 1733 deletions
diff --git a/scripts/gcc-plugins/.gitignore b/scripts/gcc-plugins/.gitignore
index de92ed9e3d83..5cc385b9eb97 100644
--- a/scripts/gcc-plugins/.gitignore
+++ b/scripts/gcc-plugins/.gitignore
@@ -1 +1,2 @@
-randomize_layout_seed.h
+# SPDX-License-Identifier: GPL-2.0-only
+/randomize_layout_seed.h
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index d45f7f36b859..6b34ba19358d 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -1,12 +1,4 @@
-preferred-plugin-hostcc := $(if-success,[ $(gcc-version) -ge 40800 ],$(HOSTCXX),$(HOSTCC))
-
-config PLUGIN_HOSTCC
- string
- default "$(shell,$(srctree)/scripts/gcc-plugin.sh "$(preferred-plugin-hostcc)" "$(HOSTCXX)" "$(CC)")" if CC_IS_GCC
- help
- Host compiler used to build GCC plugins. This can be $(HOSTCXX),
- $(HOSTCC), or a null string if GCC plugin is unsupported.
-
+# SPDX-License-Identifier: GPL-2.0-only
config HAVE_GCC_PLUGINS
bool
help
@@ -16,39 +8,17 @@ config HAVE_GCC_PLUGINS
menuconfig GCC_PLUGINS
bool "GCC plugins"
depends on HAVE_GCC_PLUGINS
- depends on PLUGIN_HOSTCC != ""
+ depends on CC_IS_GCC
+ depends on $(success,test -e $(shell,$(CC) -print-file-name=plugin)/include/plugin-version.h)
+ default y
help
GCC plugins are loadable modules that provide extra features to the
compiler. They are useful for runtime instrumentation and static analysis.
- See Documentation/gcc-plugins.txt for details.
+ See Documentation/kbuild/gcc-plugins.rst for details.
if GCC_PLUGINS
-config GCC_PLUGIN_CYC_COMPLEXITY
- bool "Compute the cyclomatic complexity of a function" if EXPERT
- depends on !COMPILE_TEST # too noisy
- help
- The complexity M of a function's control flow graph is defined as:
- M = E - N + 2P
- where
-
- E = the number of edges
- N = the number of nodes
- P = the number of connected components (exit nodes).
-
- Enabling this plugin reports the complexity to stderr during the
- build. It mainly serves as a simple example of how to create a
- gcc plugin for the kernel.
-
-config GCC_PLUGIN_SANCOV
- bool
- help
- This plugin inserts a __sanitizer_cov_trace_pc() call at the start of
- basic blocks. It supports all gcc versions with plugin support (from
- gcc-4.5 on). It is based on the commit "Add fuzzing coverage support"
- by Dmitry Vyukov <dvyukov@google.com>.
-
config GCC_PLUGIN_LATENT_ENTROPY
bool "Generate some entropy during boot and runtime"
help
@@ -66,132 +36,4 @@ config GCC_PLUGIN_LATENT_ENTROPY
* https://grsecurity.net/
* https://pax.grsecurity.net/
-config GCC_PLUGIN_STRUCTLEAK
- bool "Force initialization of variables containing userspace addresses"
- # Currently STRUCTLEAK inserts initialization out of live scope of
- # variables from KASAN point of view. This leads to KASAN false
- # positive reports. Prohibit this combination for now.
- depends on !KASAN_EXTRA
- help
- This plugin zero-initializes any structures containing a
- __user attribute. This can prevent some classes of information
- exposures.
-
- This plugin was ported from grsecurity/PaX. More information at:
- * https://grsecurity.net/
- * https://pax.grsecurity.net/
-
-config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL
- bool "Force initialize all struct type variables passed by reference"
- depends on GCC_PLUGIN_STRUCTLEAK
- depends on !COMPILE_TEST
- help
- Zero initialize any struct type local variable that may be passed by
- reference without having been initialized.
-
-config GCC_PLUGIN_STRUCTLEAK_VERBOSE
- bool "Report forcefully initialized variables"
- depends on GCC_PLUGIN_STRUCTLEAK
- depends on !COMPILE_TEST # too noisy
- help
- This option will cause a warning to be printed each time the
- structleak plugin finds a variable it thinks needs to be
- initialized. Since not all existing initializers are detected
- by the plugin, this can produce false positive warnings.
-
-config GCC_PLUGIN_RANDSTRUCT
- bool "Randomize layout of sensitive kernel structures"
- select MODVERSIONS if MODULES
- help
- If you say Y here, the layouts of structures that are entirely
- function pointers (and have not been manually annotated with
- __no_randomize_layout), or structures that have been explicitly
- marked with __randomize_layout, will be randomized at compile-time.
- This can introduce the requirement of an additional information
- exposure vulnerability for exploits targeting these structure
- types.
-
- Enabling this feature will introduce some performance impact,
- slightly increase memory usage, and prevent the use of forensic
- tools like Volatility against the system (unless the kernel
- source tree isn't cleaned after kernel installation).
-
- The seed used for compilation is located at
- scripts/gcc-plgins/randomize_layout_seed.h. It remains after
- a make clean to allow for external modules to be compiled with
- the existing seed and will be removed by a make mrproper or
- make distclean.
-
- Note that the implementation requires gcc 4.7 or newer.
-
- This plugin was ported from grsecurity/PaX. More information at:
- * https://grsecurity.net/
- * https://pax.grsecurity.net/
-
-config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
- bool "Use cacheline-aware structure randomization"
- depends on GCC_PLUGIN_RANDSTRUCT
- depends on !COMPILE_TEST # do not reduce test coverage
- help
- If you say Y here, the RANDSTRUCT randomization will make a
- best effort at restricting randomization to cacheline-sized
- groups of elements. It will further not randomize bitfields
- in structures. This reduces the performance hit of RANDSTRUCT
- at the cost of weakened randomization.
-
-config GCC_PLUGIN_STACKLEAK
- bool "Erase the kernel stack before returning from syscalls"
- depends on GCC_PLUGINS
- depends on HAVE_ARCH_STACKLEAK
- help
- This option makes the kernel erase the kernel stack before
- returning from system calls. That reduces the information which
- kernel stack leak bugs can reveal and blocks some uninitialized
- stack variable attacks.
-
- The tradeoff is the performance impact: on a single CPU system kernel
- compilation sees a 1% slowdown, other systems and workloads may vary
- and you are advised to test this feature on your expected workload
- before deploying it.
-
- This plugin was ported from grsecurity/PaX. More information at:
- * https://grsecurity.net/
- * https://pax.grsecurity.net/
-
-config STACKLEAK_TRACK_MIN_SIZE
- int "Minimum stack frame size of functions tracked by STACKLEAK"
- default 100
- range 0 4096
- depends on GCC_PLUGIN_STACKLEAK
- help
- The STACKLEAK gcc plugin instruments the kernel code for tracking
- the lowest border of the kernel stack (and for some other purposes).
- It inserts the stackleak_track_stack() call for the functions with
- a stack frame size greater than or equal to this parameter.
- If unsure, leave the default value 100.
-
-config STACKLEAK_METRICS
- bool "Show STACKLEAK metrics in the /proc file system"
- depends on GCC_PLUGIN_STACKLEAK
- depends on PROC_FS
- help
- If this is set, STACKLEAK metrics for every task are available in
- the /proc file system. In particular, /proc/<pid>/stack_depth
- shows the maximum kernel stack consumption for the current and
- previous syscalls. Although this information is not precise, it
- can be useful for estimating the STACKLEAK performance impact for
- your workloads.
-
-config STACKLEAK_RUNTIME_DISABLE
- bool "Allow runtime disabling of kernel stack erasing"
- depends on GCC_PLUGIN_STACKLEAK
- help
- This option provides 'stack_erasing' sysctl, which can be used in
- runtime to control kernel stack erasing for kernels built with
- CONFIG_GCC_PLUGIN_STACKLEAK.
-
-config GCC_PLUGIN_ARM_SSP_PER_TASK
- bool
- depends on GCC_PLUGINS && ARM
-
endif
diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile
index aa0d0ec6936d..05b14aba41ef 100644
--- a/scripts/gcc-plugins/Makefile
+++ b/scripts/gcc-plugins/Makefile
@@ -1,30 +1,72 @@
# SPDX-License-Identifier: GPL-2.0
-PLUGINCC := $(CONFIG_PLUGIN_HOSTCC:"%"=%)
-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
- HOST_EXTRACXXFLAGS += -fno-exceptions -fasynchronous-unwind-tables -ggdb
- HOST_EXTRACXXFLAGS += -Wno-narrowing -Wno-unused-variable
- export HOST_EXTRACXXFLAGS
-endif
-
-$(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h
-quiet_cmd_create_randomize_layout_seed = GENSEED $@
+
+$(obj)/randomize_layout_plugin.so: $(obj)/randomize_layout_seed.h
+quiet_cmd_create_randomize_layout_seed = SEEDHDR $@
cmd_create_randomize_layout_seed = \
- $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h
-$(objtree)/$(obj)/randomize_layout_seed.h: FORCE
+ SEED=$$(cat $(filter-out FORCE,$^) </dev/null); \
+ echo '/*' > $@; \
+ echo ' * This file is automatically generated. Keep it private.' >> $@; \
+ echo ' * Exposing this value will expose the layout of randomized structures.' >> $@; \
+ echo ' */' >> $@; \
+ echo "const char *randstruct_seed = \"$$SEED\";" >> $@
+$(obj)/randomize_layout_seed.h: $(objtree)/scripts/basic/randstruct.seed FORCE
$(call if_changed,create_randomize_layout_seed)
-targets = randomize_layout_seed.h randomize_layout_hash.h
+targets += randomize_layout_seed.h
+
+# Build rules for plugins
+#
+# No extra code is needed for single-file plugins.
+# For multi-file plugins, use *-objs syntax to list the objects.
+#
+# If the plugin foo.so is compiled from foo.c and foo2.c, you can do:
+#
+# foo-objs := foo.o foo2.o
+
+always-y += $(GCC_PLUGIN)
+
+GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin)
-$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
-always := $($(HOSTLIBS)-y)
+plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \
+ -include $(srctree)/include/linux/compiler-version.h \
+ -DPLUGIN_VERSION=$(call stringify,$(KERNELVERSION)) \
+ -I $(GCC_PLUGINS_DIR)/include -I $(obj) \
+ -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \
+ -ggdb -Wno-narrowing -Wno-unused-variable \
+ -Wno-format-diag
-$(foreach p,$($(HOSTLIBS)-y:%.so=%),$(eval $(p)-objs := $(p).o))
+plugin_ldflags = -shared
+plugin-single := $(foreach m, $(GCC_PLUGIN), $(if $($(m:%.so=%-objs)),,$(m)))
+plugin-multi := $(filter-out $(plugin-single), $(GCC_PLUGIN))
+plugin-objs := $(sort $(foreach m, $(plugin-multi), $($(m:%.so=%-objs))))
+
+targets += $(plugin-single) $(plugin-multi) $(plugin-objs)
clean-files += *.so
+
+plugin-single := $(addprefix $(obj)/, $(plugin-single))
+plugin-multi := $(addprefix $(obj)/, $(plugin-multi))
+plugin-objs := $(addprefix $(obj)/, $(plugin-objs))
+
+quiet_cmd_plugin_cxx_so_c = HOSTCXX $@
+ cmd_plugin_cxx_so_c = $(HOSTCXX) $(plugin_cxxflags) $(plugin_ldflags) -o $@ $<
+
+$(plugin-single): $(obj)/%.so: $(src)/%.c FORCE
+ $(call if_changed_dep,plugin_cxx_so_c)
+
+quiet_cmd_plugin_ld_so_o = HOSTLD $@
+ cmd_plugin_ld_so_o = $(HOSTCXX) $(plugin_ldflags) -o $@ \
+ $(addprefix $(obj)/, $($(target-stem)-objs))
+
+$(plugin-multi): FORCE
+ $(call if_changed,plugin_ld_so_o)
+$(foreach m, $(notdir $(plugin-multi)), $(eval $(obj)/$m: $(addprefix $(obj)/, $($(m:%.so=%-objs)))))
+
+quiet_cmd_plugin_cxx_o_c = HOSTCXX $@
+ cmd_plugin_cxx_o_c = $(HOSTCXX) $(plugin_cxxflags) -c -o $@ $<
+
+$(plugin-objs): $(obj)/%.o: $(src)/%.c FORCE
+ $(call if_changed_dep,plugin_cxx_o_c)
+
+$(obj)/../../include/generated/gcc-plugins.h: $(plugin-single) $(plugin-multi) FORCE
+ $(call if_changed,touch)
+always-y += ../../include/generated/gcc-plugins.h
diff --git a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c
deleted file mode 100644
index 89c47f57d1ce..000000000000
--- a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "gcc-common.h"
-
-__visible int plugin_is_GPL_compatible;
-
-static unsigned int sp_mask, canary_offset;
-
-static unsigned int arm_pertask_ssp_rtl_execute(void)
-{
- rtx_insn *insn;
-
- for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) {
- const char *sym;
- rtx body;
- rtx mask, masked_sp;
-
- /*
- * Find a SET insn involving a SYMBOL_REF to __stack_chk_guard
- */
- if (!INSN_P(insn))
- continue;
- body = PATTERN(insn);
- if (GET_CODE(body) != SET ||
- GET_CODE(SET_SRC(body)) != SYMBOL_REF)
- continue;
- sym = XSTR(SET_SRC(body), 0);
- if (strcmp(sym, "__stack_chk_guard"))
- continue;
-
- /*
- * Replace the source of the SET insn with an expression that
- * produces the address of the copy of the stack canary value
- * stored in struct thread_info
- */
- mask = GEN_INT(sext_hwi(sp_mask, GET_MODE_PRECISION(Pmode)));
- masked_sp = gen_reg_rtx(Pmode);
-
- emit_insn_before(gen_rtx_SET(masked_sp,
- gen_rtx_AND(Pmode,
- stack_pointer_rtx,
- mask)),
- insn);
-
- SET_SRC(body) = gen_rtx_PLUS(Pmode, masked_sp,
- GEN_INT(canary_offset));
- }
- return 0;
-}
-
-#define PASS_NAME arm_pertask_ssp_rtl
-
-#define NO_GATE
-#include "gcc-generate-rtl-pass.h"
-
-#if BUILDING_GCC_VERSION >= 9000
-static bool no(void)
-{
- return false;
-}
-
-static void arm_pertask_ssp_start_unit(void *gcc_data, void *user_data)
-{
- targetm.have_stack_protect_combined_set = no;
- targetm.have_stack_protect_combined_test = no;
-}
-#endif
-
-__visible int plugin_init(struct plugin_name_args *plugin_info,
- struct plugin_gcc_version *version)
-{
- const char * const plugin_name = plugin_info->base_name;
- const int argc = plugin_info->argc;
- const struct plugin_argument *argv = plugin_info->argv;
- int tso = 0;
- int i;
-
- 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, "disable"))
- return 0;
-
- /* all remaining options require a value */
- if (!argv[i].value) {
- error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
- plugin_name, argv[i].key);
- return 1;
- }
-
- if (!strcmp(argv[i].key, "tso")) {
- tso = atoi(argv[i].value);
- continue;
- }
-
- if (!strcmp(argv[i].key, "offset")) {
- canary_offset = atoi(argv[i].value);
- continue;
- }
- error(G_("unknown option '-fplugin-arg-%s-%s'"),
- plugin_name, argv[i].key);
- return 1;
- }
-
- /* create the mask that produces the base of the stack */
- sp_mask = ~((1U << (12 + tso)) - 1);
-
- PASS_INFO(arm_pertask_ssp_rtl, "expand", 1, PASS_POS_INSERT_AFTER);
-
- register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP,
- NULL, &arm_pertask_ssp_rtl_pass_info);
-
-#if BUILDING_GCC_VERSION >= 9000
- register_callback(plugin_info->base_name, PLUGIN_START_UNIT,
- arm_pertask_ssp_start_unit, NULL);
-#endif
-
- return 0;
-}
diff --git a/scripts/gcc-plugins/cyc_complexity_plugin.c b/scripts/gcc-plugins/cyc_complexity_plugin.c
deleted file mode 100644
index 1909ec617431..000000000000
--- a/scripts/gcc-plugins/cyc_complexity_plugin.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
- * 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"
-
-__visible 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"
-
-__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
-{
- const char * const plugin_name = plugin_info->base_name;
-
- PASS_INFO(cyc_complexity, "ssa", 1, 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;
-}
diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h
index 552d5efd7cb7..8f1b3500f8e2 100644
--- a/scripts/gcc-plugins/gcc-common.h
+++ b/scripts/gcc-plugins/gcc-common.h
@@ -3,11 +3,7 @@
#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"
@@ -27,25 +23,19 @@
#include "except.h"
#include "function.h"
#include "toplev.h"
-#if BUILDING_GCC_VERSION >= 5000
#include "expr.h"
-#endif
#include "basic-block.h"
#include "intl.h"
#include "ggc.h"
#include "timevar.h"
+#if BUILDING_GCC_VERSION < 10000
#include "params.h"
+#endif
-#if BUILDING_GCC_VERSION <= 4009
-#include "pointer-set.h"
-#else
#include "hash-map.h"
-#endif
-#if BUILDING_GCC_VERSION >= 7000
#include "memmodel.h"
-#endif
#include "emit-rtl.h"
#include "debug.h"
#include "target.h"
@@ -53,105 +43,54 @@
#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
-/*
- * The c-family headers were moved into a subdirectory in GCC version
- * 4.7, but most plugin-building users of GCC 4.6 are using the Debian
- * or Ubuntu package, which has an out-of-tree patch to move this to the
- * same location as found in 4.7 and later:
- * https://sources.debian.net/src/gcc-4.6/4.6.3-14/debian/patches/pr45078.diff/
- */
#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"
-#if BUILDING_GCC_VERSION >= 4009
#include "pass_manager.h"
-#endif
#include "predict.h"
#include "ipa-utils.h"
-
-#if BUILDING_GCC_VERSION >= 8000
#include "stringpool.h"
-#endif
-
-#if BUILDING_GCC_VERSION >= 4009
#include "attribs.h"
#include "varasm.h"
#include "stor-layout.h"
#include "internal-fn.h"
+#include "gimple.h"
#include "gimple-expr.h"
+#include "gimple-iterator.h"
#include "gimple-fold.h"
#include "context.h"
#include "tree-ssa-alias.h"
#include "tree-ssa.h"
-#include "stringpool.h"
-#if BUILDING_GCC_VERSION >= 7000
#include "tree-vrp.h"
-#endif
#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
/* missing from basic_block.h... */
void debug_dominance_info(enum cdi_direction dir);
void debug_dominance_tree(enum cdi_direction dir, basic_block root);
-#if BUILDING_GCC_VERSION == 4006
-void debug_gimple_stmt(gimple);
-void debug_gimple_seq(gimple_seq);
-void print_gimple_seq(FILE *, gimple_seq, int, int);
-void print_gimple_stmt(FILE *, gimple, int, int);
-void print_gimple_expr(FILE *, gimple, int, int);
-void dump_gimple_stmt(pretty_printer *, gimple, int, int);
-#endif
-
+#ifndef __unused
#define __unused __attribute__((__unused__))
+#endif
+#ifndef __visible
#define __visible __attribute__((visibility("default")))
+#endif
#define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node))
#define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node))
@@ -176,501 +115,53 @@ static inline tree build_const_char_string(int len, const char *str)
return cstr;
}
-#define PASS_INFO(NAME, REF, ID, POS) \
-struct register_pass_info NAME##_pass_info = { \
- .pass = make_##NAME##_pass(), \
- .reference_pass_name = REF, \
- .ref_pass_instance_number = ID, \
- .pos_op = POS, \
-}
-
-#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)
+static inline void __add_type_attr(tree type, const char *attr, tree args)
{
- unsigned i;
+ tree oldattr;
- 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;
+ if (type == NULL_TREE)
+ return;
+ oldattr = lookup_attribute(attr, TYPE_ATTRIBUTES(type));
+ if (oldattr != NULL_TREE) {
+ gcc_assert(TREE_VALUE(oldattr) == args || TREE_VALUE(TREE_VALUE(oldattr)) == TREE_VALUE(args));
+ return;
}
- return false;
+ TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type));
+ TYPE_ATTRIBUTES(type) = tree_cons(get_identifier(attr), args, TYPE_ATTRIBUTES(type));
}
-static inline tree builtin_decl_implicit(enum built_in_function fncode)
+static inline void add_type_attr(tree type, const char *attr, tree args)
{
- return implicit_built_in_decls[fncode];
-}
+ tree main_variant = TYPE_MAIN_VARIANT(type);
-static inline int ipa_reverse_postorder(struct cgraph_node **order)
-{
- return cgraph_postorder(order);
-}
+ __add_type_attr(TYPE_CANONICAL(type), attr, args);
+ __add_type_attr(TYPE_CANONICAL(main_variant), attr, args);
+ __add_type_attr(main_variant, attr, args);
-static inline struct cgraph_node *cgraph_create_node(tree decl)
-{
- return cgraph_node(decl);
-}
+ for (type = TYPE_NEXT_VARIANT(main_variant); type; type = TYPE_NEXT_VARIANT(type)) {
+ if (!lookup_attribute(attr, TYPE_ATTRIBUTES(type)))
+ TYPE_ATTRIBUTES(type) = TYPE_ATTRIBUTES(main_variant);
-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;
-}
-
-static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable)
-{
- cgraph_node_ptr alias;
-
- if (callback(node, data))
- return true;
-
- for (alias = node->same_body; alias; alias = alias->next) {
- if (include_overwritable || cgraph_function_body_availability(alias) > AVAIL_OVERWRITABLE)
- if (cgraph_for_node_and_aliases(alias, callback, data, include_overwritable))
- return true;
+ __add_type_attr(TYPE_CANONICAL(type), attr, args);
}
-
- return false;
-}
-
-#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 <= 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 ggoto;
-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 ggoto *as_a_ggoto(gimple stmt)
-{
- return stmt;
-}
-
-static inline const ggoto *as_a_const_ggoto(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;
+#define PASS_INFO(NAME, REF, ID, POS) \
+struct register_pass_info NAME##_pass_info = { \
+ .pass = make_##NAME##_pass(), \
+ .reference_pass_name = REF, \
+ .ref_pass_instance_number = ID, \
+ .pos_op = POS, \
}
-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__)
-
-rtx emit_move_insn(rtx x, rtx y);
-
-typedef struct rtx_def rtx_insn;
-
-static inline const char *get_decl_section_name(const_tree decl)
-{
- if (DECL_SECTION_NAME(decl) == NULL_TREE)
- return NULL;
-
- return TREE_STRING_POINTER(DECL_SECTION_NAME(decl));
-}
-
-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_base ggoto;
-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 ggoto *as_a_ggoto(gimple stmt)
-{
- return stmt;
-}
-
-static inline const ggoto *as_a_const_ggoto(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
@@ -681,23 +172,18 @@ static inline opt_pass *get_pass_for_id(int id)
{
return g->get_passes()->get_pass_for_id(id);
}
-#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
+#if BUILDING_GCC_VERSION < 16000
#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
+#else
+#define TODO_verify_ssa 0
+#define TODO_verify_flow 0
+#define TODO_verify_stmts 0
+#define TODO_verify_rtl_sharing 0
+#endif
#define INSN_DELETED_P(insn) (insn)->deleted()
@@ -716,7 +202,6 @@ static inline const char *get_decl_section_name(const_tree decl)
#define varpool_get_node(decl) varpool_node::get(decl)
#define dump_varpool_node(file, node) (node)->dump(file)
-#if BUILDING_GCC_VERSION >= 8000
#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \
(caller)->create_edge((callee), (call_stmt), (count))
@@ -724,15 +209,6 @@ static inline const char *get_decl_section_name(const_tree decl)
old_call_stmt, call_stmt, count, freq, reason) \
(caller)->create_edge_including_clones((callee), \
(old_call_stmt), (call_stmt), (count), (reason))
-#else
-#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \
- (caller)->create_edge((callee), (call_stmt), (count), (freq))
-
-#define cgraph_create_edge_including_clones(caller, callee, \
- old_call_stmt, call_stmt, count, freq, reason) \
- (caller)->create_edge_including_clones((callee), \
- (old_call_stmt), (call_stmt), (count), (freq), (reason))
-#endif
typedef struct cgraph_node *cgraph_node_ptr;
typedef struct cgraph_edge *cgraph_edge_p;
@@ -828,14 +304,12 @@ static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_e
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)
@@ -843,6 +317,7 @@ static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree l
return gimple_build_assign(lhs, subcode, op1, op2 PASS_MEM_STAT);
}
+#if BUILDING_GCC_VERSION < 10000
template <>
template <>
inline bool is_a_helper<const ggoto *>::test(const_gimple gs)
@@ -856,6 +331,7 @@ inline bool is_a_helper<const greturn *>::test(const_gimple gs)
{
return gs->code == GIMPLE_RETURN;
}
+#endif
static inline gasm *as_a_gasm(gimple stmt)
{
@@ -932,17 +408,8 @@ static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimpl
{
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)
@@ -959,14 +426,11 @@ static inline void debug_gimple_stmt(const_gimple s)
#define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s))
#endif
-#if BUILDING_GCC_VERSION >= 7000
#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \
get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep)
-#endif
-#if BUILDING_GCC_VERSION < 7000
-#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align)
-#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode)
+#if BUILDING_GCC_VERSION >= 14000
+#define last_stmt(x) last_nondebug_stmt(x)
#endif
#endif
diff --git a/scripts/gcc-plugins/gcc-generate-gimple-pass.h b/scripts/gcc-plugins/gcc-generate-gimple-pass.h
index f20797e80b6d..503c07496396 100644
--- a/scripts/gcc-plugins/gcc-generate-gimple-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-gimple-pass.h
@@ -73,62 +73,31 @@
#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
};
}
diff --git a/scripts/gcc-plugins/gcc-generate-ipa-pass.h b/scripts/gcc-plugins/gcc-generate-ipa-pass.h
index 92bb4f3a87a4..1e7f064e8f6e 100644
--- a/scripts/gcc-plugins/gcc-generate-ipa-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-ipa-pass.h
@@ -141,52 +141,19 @@
#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,
@@ -202,21 +169,12 @@ public:
_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
};
}
diff --git a/scripts/gcc-plugins/gcc-generate-rtl-pass.h b/scripts/gcc-plugins/gcc-generate-rtl-pass.h
index d69cd80b6c10..7cd46e8d5049 100644
--- a/scripts/gcc-plugins/gcc-generate-rtl-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-rtl-pass.h
@@ -73,61 +73,31 @@
#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
};
}
@@ -136,12 +106,6 @@ 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
diff --git a/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
index 06800bc477e0..33093ccc947a 100644
--- a/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
@@ -73,61 +73,31 @@
#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
};
}
@@ -136,12 +106,6 @@ 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
diff --git a/scripts/gcc-plugins/gen-random-seed.sh b/scripts/gcc-plugins/gen-random-seed.sh
deleted file mode 100644
index 68af5cc20a64..000000000000
--- a/scripts/gcc-plugins/gen-random-seed.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-if [ ! -f "$1" ]; then
- SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
- echo "const char *randstruct_seed = \"$SEED\";" > "$1"
- HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'`
- echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
-fi
diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c
index cbe1d6c4b1a5..ff0b192be91f 100644
--- a/scripts/gcc-plugins/latent_entropy_plugin.c
+++ b/scripts/gcc-plugins/latent_entropy_plugin.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu>
* Copyright 2016 by Emese Revfy <re.emese@gmail.com>
- * Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
@@ -17,7 +17,7 @@
* if (argc <= 1)
* printf("%s: no command arguments :(\n", *argv);
* else
- * printf("%s: %d command arguments!\n", *argv, args - 1);
+ * printf("%s: %d command arguments!\n", *argv, argc - 1);
* }
*
* after:
@@ -47,7 +47,7 @@
* // perturb_local_entropy()
* } else {
* local_entropy ^= 3896280633962944730;
- * printf("%s: %d command arguments!\n", *argv, args - 1);
+ * printf("%s: %d command arguments!\n", *argv, argc - 1);
* }
*
* // latent_entropy_execute() 4.
@@ -82,29 +82,35 @@ __visible int plugin_is_GPL_compatible;
static GTY(()) tree latent_entropy_decl;
static struct plugin_info latent_entropy_plugin_info = {
- .version = "201606141920vanilla",
+ .version = PLUGIN_VERSION,
.help = "disable\tturn off latent entropy instrumentation\n",
};
-static unsigned HOST_WIDE_INT seed;
-/*
- * get_random_seed() (this is a GCC function) generates the seed.
- * This is a simple random generator without any cryptographic security because
- * the entropy doesn't come from here.
- */
+static unsigned HOST_WIDE_INT deterministic_seed;
+static unsigned HOST_WIDE_INT rnd_buf[32];
+static size_t rnd_idx = ARRAY_SIZE(rnd_buf);
+static int urandom_fd = -1;
+
static unsigned HOST_WIDE_INT get_random_const(void)
{
- unsigned int i;
- unsigned HOST_WIDE_INT ret = 0;
-
- for (i = 0; i < 8 * sizeof(ret); i++) {
- ret = (ret << 1) | (seed & 1);
- seed >>= 1;
- if (ret & 1)
- seed ^= 0xD800000000000000ULL;
+ if (deterministic_seed) {
+ unsigned HOST_WIDE_INT w = deterministic_seed;
+ w ^= w << 13;
+ w ^= w >> 7;
+ w ^= w << 17;
+ deterministic_seed = w;
+ return deterministic_seed;
}
- return ret;
+ if (urandom_fd < 0) {
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ gcc_assert(urandom_fd >= 0);
+ }
+ if (rnd_idx >= ARRAY_SIZE(rnd_buf)) {
+ gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf));
+ rnd_idx = 0;
+ }
+ return rnd_buf[rnd_idx++];
}
static tree tree_get_random_const(tree type)
@@ -125,11 +131,7 @@ static tree handle_latent_entropy_attribute(tree *node, tree name,
bool *no_add_attrs)
{
tree type;
-#if BUILDING_GCC_VERSION <= 4007
- VEC(constructor_elt, gc) *vals;
-#else
vec<constructor_elt, va_gc> *vals;
-#endif
switch (TREE_CODE(*node)) {
default:
@@ -181,11 +183,7 @@ static tree handle_latent_entropy_attribute(tree *node, tree name,
if (fld)
break;
-#if BUILDING_GCC_VERSION <= 4007
- vals = VEC_alloc(constructor_elt, gc, nelt);
-#else
vec_alloc(vals, nelt);
-#endif
for (fld = lst; fld; fld = TREE_CHAIN(fld)) {
tree random_const, fld_t = TREE_TYPE(fld);
@@ -225,11 +223,7 @@ static tree handle_latent_entropy_attribute(tree *node, tree name,
elt_size_int = TREE_INT_CST_LOW(elt_size);
nelt = array_size_int / elt_size_int;
-#if BUILDING_GCC_VERSION <= 4007
- vals = VEC_alloc(constructor_elt, gc, nelt);
-#else
vec_alloc(vals, nelt);
-#endif
for (i = 0; i < nelt; i++) {
tree cst = size_int(i);
@@ -536,7 +530,7 @@ static unsigned int latent_entropy_execute(void)
while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) {
perturb_local_entropy(bb, local_entropy);
bb = bb->next_bb;
- };
+ }
/* 4. mix local entropy into the global entropy variable */
perturb_latent_entropy(local_entropy);
@@ -549,8 +543,6 @@ static void latent_entropy_start_unit(void *gcc_data __unused,
tree type, id;
int quals;
- seed = get_random_seed(false);
-
if (in_lto_p)
return;
@@ -585,6 +577,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
const struct plugin_argument * const argv = plugin_info->argv;
int i;
+ /*
+ * Call get_random_seed() with noinit=true, so that this returns
+ * 0 in the case where no seed has been passed via -frandom-seed.
+ */
+ deterministic_seed = get_random_seed(true);
+
static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = {
{
.base = &latent_entropy_decl,
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 6d5bbd31db7f..ff65a4f87f24 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -19,10 +19,6 @@
#include "gcc-common.h"
#include "randomize_layout_seed.h"
-#if BUILDING_GCC_MAJOR < 4 || (BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR < 7)
-#error "The RANDSTRUCT plugin requires GCC 4.7 or newer."
-#endif
-
#define ORIG_TYPE_NAME(node) \
(TYPE_NAME(TYPE_MAIN_VARIANT(node)) != NULL_TREE ? ((const unsigned char *)IDENTIFIER_POINTER(TYPE_NAME(TYPE_MAIN_VARIANT(node)))) : (const unsigned char *)"anonymous")
@@ -34,29 +30,11 @@ __visible int plugin_is_GPL_compatible;
static int performance_mode;
static struct plugin_info randomize_layout_plugin_info = {
- .version = "201402201816vanilla",
+ .version = PLUGIN_VERSION,
.help = "disable\t\t\tdo not activate plugin\n"
"performance-mode\tenable cacheline-aware layout randomization\n"
};
-struct whitelist_entry {
- const char *pathname;
- const char *lhs;
- const char *rhs;
-};
-
-static const struct whitelist_entry whitelist[] = {
- /* NIU overloads mapping with page struct */
- { "drivers/net/ethernet/sun/niu.c", "page", "address_space" },
- /* unix_skb_parms via UNIXCB() buffer */
- { "net/unix/af_unix.c", "unix_skb_parms", "char" },
- /* big_key payload.data struct splashing */
- { "security/keys/big_key.c", "path", "void *" },
- /* walk struct security_hook_heads as an array of struct hlist_head */
- { "security/security.c", "hlist_head", "security_hook_heads" },
- { }
-};
-
/* from old Linux dcache.h */
static inline unsigned long
partial_name_hash(unsigned long c, unsigned long prevhash)
@@ -95,6 +73,9 @@ static tree handle_randomize_layout_attr(tree *node, tree name, tree args, int f
if (TYPE_P(*node)) {
type = *node;
+ } else if (TREE_CODE(*node) == FIELD_DECL) {
+ *no_add_attrs = false;
+ return NULL_TREE;
} else {
gcc_assert(TREE_CODE(*node) == TYPE_DECL);
type = TREE_TYPE(*node);
@@ -209,12 +190,14 @@ static void partition_struct(tree *fields, unsigned long length, struct partitio
static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
{
- unsigned long i, x;
+ unsigned long i, x, index;
struct partition_group size_group[length];
unsigned long num_groups = 0;
unsigned long randnum;
partition_struct(newtree, length, (struct partition_group *)&size_group, &num_groups);
+
+ /* FIXME: this group shuffle is currently a no-op. */
for (i = num_groups - 1; i > 0; i--) {
struct partition_group tmp;
randnum = ranval(prng_state) % (i + 1);
@@ -224,11 +207,14 @@ static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prn
}
for (x = 0; x < num_groups; x++) {
- for (i = size_group[x].start + size_group[x].length - 1; i > size_group[x].start; i--) {
+ for (index = size_group[x].length - 1; index > 0; index--) {
tree tmp;
+
+ i = size_group[x].start + index;
if (DECL_BIT_FIELD_TYPE(newtree[i]))
continue;
- randnum = ranval(prng_state) % (i + 1);
+ randnum = ranval(prng_state) % (index + 1);
+ randnum += size_group[x].start;
// we could handle this case differently if desired
if (DECL_BIT_FIELD_TYPE(newtree[randnum]))
continue;
@@ -291,8 +277,6 @@ static bool is_flexible_array(const_tree field)
{
const_tree fieldtype;
const_tree typesize;
- const_tree elemtype;
- const_tree elemsize;
fieldtype = TREE_TYPE(field);
typesize = TYPE_SIZE(fieldtype);
@@ -300,20 +284,12 @@ static bool is_flexible_array(const_tree field)
if (TREE_CODE(fieldtype) != ARRAY_TYPE)
return false;
- elemtype = TREE_TYPE(fieldtype);
- elemsize = TYPE_SIZE(elemtype);
-
/* size of type is represented in bits */
if (typesize == NULL_TREE && TYPE_DOMAIN(fieldtype) != NULL_TREE &&
TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype)) == NULL_TREE)
return true;
- if (typesize != NULL_TREE &&
- (TREE_CONSTANT(typesize) && (!tree_to_uhwi(typesize) ||
- tree_to_uhwi(typesize) == tree_to_uhwi(elemsize))))
- return true;
-
return false;
}
@@ -362,8 +338,7 @@ static int relayout_struct(tree type)
/*
* enforce that we don't randomize the layout of the last
- * element of a struct if it's a 0 or 1-length array
- * or a proper flexible array
+ * element of a struct if it's a proper flexible array
*/
if (is_flexible_array(newtree[num_fields - 1])) {
has_flexarray = true;
@@ -372,35 +347,18 @@ static int relayout_struct(tree type)
shuffle(type, (tree *)newtree, shuffle_length);
- /*
- * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
- * as gcc provides no other way to detect such code
- */
- list = make_node(FIELD_DECL);
- TREE_CHAIN(list) = newtree[0];
- TREE_TYPE(list) = void_type_node;
- DECL_SIZE(list) = bitsize_zero_node;
- DECL_NONADDRESSABLE_P(list) = 1;
- DECL_FIELD_BIT_OFFSET(list) = bitsize_zero_node;
- DECL_SIZE_UNIT(list) = size_zero_node;
- DECL_FIELD_OFFSET(list) = size_zero_node;
- DECL_CONTEXT(list) = type;
- // to satisfy the constify plugin
- TREE_READONLY(list) = 1;
-
for (i = 0; i < num_fields - 1; i++)
TREE_CHAIN(newtree[i]) = newtree[i+1];
TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE;
+ add_type_attr(type, "randomize_performed", NULL_TREE);
+ add_type_attr(type, "designated_init", NULL_TREE);
+ if (has_flexarray)
+ add_type_attr(type, "has_flexarray", NULL_TREE);
+
main_variant = TYPE_MAIN_VARIANT(type);
- for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) {
- TYPE_FIELDS(variant) = list;
- TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant));
- TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant));
- TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("designated_init"), NULL_TREE, TYPE_ATTRIBUTES(variant));
- if (has_flexarray)
- TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("has_flexarray"), NULL_TREE, TYPE_ATTRIBUTES(type));
- }
+ for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant))
+ TYPE_FIELDS(variant) = newtree[0];
/*
* force a re-layout of the main variant
@@ -443,13 +401,13 @@ static int is_pure_ops_struct(const_tree node)
if (node == fieldtype)
continue;
- if (!is_fptr(fieldtype))
- return 0;
-
- if (code != RECORD_TYPE && code != UNION_TYPE)
+ if (code == RECORD_TYPE || code == UNION_TYPE) {
+ if (!is_pure_ops_struct(fieldtype))
+ return 0;
continue;
+ }
- if (!is_pure_ops_struct(fieldtype))
+ if (!is_fptr(fieldtype))
return 0;
}
@@ -468,10 +426,8 @@ static void randomize_type(tree type)
if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))) || is_pure_ops_struct(type))
relayout_struct(type);
- for (variant = TYPE_MAIN_VARIANT(type); variant; variant = TYPE_NEXT_VARIANT(variant)) {
- TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type));
- TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("randomize_considered"), NULL_TREE, TYPE_ATTRIBUTES(type));
- }
+ add_type_attr(type, "randomize_considered", NULL_TREE);
+
#ifdef __DEBUG_PLUGIN
fprintf(stderr, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type));
#ifdef __DEBUG_VERBOSE
@@ -590,16 +546,12 @@ static void register_attributes(void *event_data, void *data)
randomize_layout_attr.name = "randomize_layout";
randomize_layout_attr.type_required = true;
randomize_layout_attr.handler = handle_randomize_layout_attr;
-#if BUILDING_GCC_VERSION >= 4007
randomize_layout_attr.affects_type_identity = true;
-#endif
no_randomize_layout_attr.name = "no_randomize_layout";
no_randomize_layout_attr.type_required = true;
no_randomize_layout_attr.handler = handle_randomize_layout_attr;
-#if BUILDING_GCC_VERSION >= 4007
no_randomize_layout_attr.affects_type_identity = true;
-#endif
randomize_considered_attr.name = "randomize_considered";
randomize_considered_attr.type_required = true;
@@ -746,60 +698,6 @@ static void handle_local_var_initializers(void)
}
}
-static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_name)
-{
- const char *type_name;
-
- if (type_tree == NULL_TREE)
- return false;
-
- switch (TREE_CODE(type_tree)) {
- case RECORD_TYPE:
- type_name = TYPE_NAME_POINTER(type_tree);
- break;
- case INTEGER_TYPE:
- if (TYPE_PRECISION(type_tree) == CHAR_TYPE_SIZE)
- type_name = "char";
- else {
- INFORM(gimple_location(stmt), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree);
- debug_tree(type_tree);
- return false;
- }
- break;
- case POINTER_TYPE:
- if (TREE_CODE(TREE_TYPE(type_tree)) == VOID_TYPE) {
- type_name = "void *";
- break;
- } else {
- INFORM(gimple_location(stmt), "found non-void POINTER_TYPE cast comparison %qT\n", type_tree);
- debug_tree(type_tree);
- return false;
- }
- default:
- INFORM(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree);
- debug_tree(type_tree);
- return false;
- }
-
- return strcmp(type_name, wanted_name) == 0;
-}
-
-static bool whitelisted_cast(gimple stmt, const_tree lhs_tree, const_tree rhs_tree)
-{
- const struct whitelist_entry *entry;
- expanded_location xloc = expand_location(gimple_location(stmt));
-
- for (entry = whitelist; entry->pathname; entry++) {
- if (!strstr(xloc.file, entry->pathname))
- continue;
-
- if (type_name_eq(stmt, lhs_tree, entry->lhs) && type_name_eq(stmt, rhs_tree, entry->rhs))
- return true;
- }
-
- return false;
-}
-
/*
* iterate over all statements to find "bad" casts:
* those where the address of the start of a structure is cast
@@ -876,10 +774,7 @@ static unsigned int find_bad_casts_execute(void)
#ifndef __DEBUG_PLUGIN
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
#endif
- {
- if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type))
- MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type);
- }
+ MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type);
continue;
}
@@ -902,10 +797,7 @@ static unsigned int find_bad_casts_execute(void)
#ifndef __DEBUG_PLUGIN
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
#endif
- {
- if (!whitelisted_cast(stmt, ptr_lhs_type, op0_type))
- MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type);
- }
+ MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type);
} else {
const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
/* skip bogus type casts introduced by container_of */
@@ -915,10 +807,7 @@ static unsigned int find_bad_casts_execute(void)
#ifndef __DEBUG_PLUGIN
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))
#endif
- {
- if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type))
- MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type);
- }
+ MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type);
}
}
diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c
deleted file mode 100644
index 0f98634c20a0..000000000000
--- a/scripts/gcc-plugins/sancov_plugin.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
- * 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 <dvyukov@google.com>.
- *
- * 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"
-
-__visible int plugin_is_GPL_compatible;
-
-tree sancov_fndecl;
-
-static struct plugin_info sancov_plugin_info = {
- .version = "20160402",
- .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);
-
- DECL_ASSEMBLER_NAME(sancov_fndecl);
- TREE_PUBLIC(sancov_fndecl) = 1;
- DECL_EXTERNAL(sancov_fndecl) = 1;
- DECL_ARTIFICIAL(sancov_fndecl) = 1;
- DECL_PRESERVE_P(sancov_fndecl) = 1;
- DECL_UNINLINABLE(sancov_fndecl) = 1;
- TREE_USED(sancov_fndecl) = 1;
-
- nothrow_attr = tree_cons(get_identifier("nothrow"), NULL, NULL);
- decl_attributes(&sancov_fndecl, nothrow_attr, 0);
- gcc_assert(TREE_NOTHROW(sancov_fndecl));
-#if BUILDING_GCC_VERSION > 4005
- leaf_attr = tree_cons(get_identifier("leaf"), NULL, NULL);
- decl_attributes(&sancov_fndecl, leaf_attr, 0);
-#endif
-}
-
-__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
-{
- int i;
- 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?? */
-#if BUILDING_GCC_VERSION >= 4009
- PASS_INFO(sancov, "asan", 0, PASS_POS_INSERT_BEFORE);
-#else
- PASS_INFO(sancov, "nrv", 1, PASS_POS_INSERT_BEFORE);
-#endif
-
- 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_("unknown 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_pass_info);
-#endif
-
- return 0;
-}
diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c
index dbd37460c573..e486488c867d 100644
--- a/scripts/gcc-plugins/stackleak_plugin.c
+++ b/scripts/gcc-plugins/stackleak_plugin.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu>
* Modified by Alexander Popov <alex.popov@linux.com>
- * Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
@@ -9,7 +9,7 @@
* any of the gcc libraries
*
* This gcc plugin is needed for tracking the lowest border of the kernel stack.
- * It instruments the kernel code inserting stackleak_track_stack() calls:
+ * It instruments the kernel code inserting __sanitizer_cov_stack_depth() calls:
* - after alloca();
* - for the functions with a stack frame size greater than or equal
* to the "track-min-size" plugin parameter.
@@ -20,7 +20,7 @@
*
* Debugging:
* - use fprintf() to stderr, debug_generic_expr(), debug_gimple_stmt(),
- * print_rtl() and print_simple_rtl();
+ * print_rtl_single() and debug_rtx();
* - add "-fdump-tree-all -fdump-rtl-all" to the plugin CFLAGS in
* Makefile.gcc-plugins to see the verbose dumps of the gcc passes;
* - use gcc -E to understand the preprocessing shenanigans;
@@ -32,7 +32,10 @@
__visible int plugin_is_GPL_compatible;
static int track_frame_size = -1;
-static const char track_function[] = "stackleak_track_stack";
+static bool build_for_x86 = false;
+static const char track_function[] = "__sanitizer_cov_stack_depth";
+static bool disable = false;
+static bool verbose = false;
/*
* Mark these global variables (roots) for gcc garbage collector since
@@ -41,36 +44,35 @@ static const char track_function[] = "stackleak_track_stack";
static GTY(()) tree track_function_decl;
static struct plugin_info stackleak_plugin_info = {
- .version = "201707101337",
+ .version = PLUGIN_VERSION,
.help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n"
+ "arch=target_arch\tspecify target build arch\n"
"disable\t\tdo not activate the plugin\n"
+ "verbose\t\tprint info about the instrumentation\n"
};
-static void stackleak_add_track_stack(gimple_stmt_iterator *gsi, bool after)
+static void add_stack_tracking_gcall(gimple_stmt_iterator *gsi, bool after)
{
gimple stmt;
- gcall *stackleak_track_stack;
+ gcall *gimple_call;
cgraph_node_ptr node;
- int frequency;
basic_block bb;
- /* Insert call to void stackleak_track_stack(void) */
+ /* Insert calling __sanitizer_cov_stack_depth() */
stmt = gimple_build_call(track_function_decl, 0);
- stackleak_track_stack = as_a_gcall(stmt);
- if (after) {
- gsi_insert_after(gsi, stackleak_track_stack,
- GSI_CONTINUE_LINKING);
- } else {
- gsi_insert_before(gsi, stackleak_track_stack, GSI_SAME_STMT);
- }
+ gimple_call = as_a_gcall(stmt);
+ if (after)
+ gsi_insert_after(gsi, gimple_call, GSI_CONTINUE_LINKING);
+ else
+ gsi_insert_before(gsi, gimple_call, GSI_SAME_STMT);
/* Update the cgraph */
- bb = gimple_bb(stackleak_track_stack);
+ bb = gimple_bb(gimple_call);
node = cgraph_get_create_node(track_function_decl);
gcc_assert(node);
- frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
cgraph_create_edge(cgraph_get_node(current_function_decl), node,
- stackleak_track_stack, bb->count, frequency);
+ gimple_call, bb->count,
+ compute_call_stmt_bb_frequency(current_function_decl, bb));
}
static bool is_alloca(gimple stmt)
@@ -78,24 +80,99 @@ static bool is_alloca(gimple stmt)
if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA))
return true;
-#if BUILDING_GCC_VERSION >= 4007
if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
return true;
-#endif
return false;
}
+static tree get_current_stack_pointer_decl(void)
+{
+ varpool_node_ptr node;
+
+ FOR_EACH_VARIABLE(node) {
+ tree var = NODE_DECL(node);
+ tree name = DECL_NAME(var);
+
+ if (DECL_NAME_LENGTH(var) != sizeof("current_stack_pointer") - 1)
+ continue;
+
+ if (strcmp(IDENTIFIER_POINTER(name), "current_stack_pointer"))
+ continue;
+
+ return var;
+ }
+
+ if (verbose) {
+ fprintf(stderr, "stackleak: missing current_stack_pointer in %s()\n",
+ DECL_NAME_POINTER(current_function_decl));
+ }
+ return NULL_TREE;
+}
+
+static void add_stack_tracking_gasm(gimple_stmt_iterator *gsi, bool after)
+{
+ gasm *asm_call = NULL;
+ tree sp_decl, input;
+ vec<tree, va_gc> *inputs = NULL;
+
+ /* 'no_caller_saved_registers' is currently supported only for x86 */
+ gcc_assert(build_for_x86);
+
+ /*
+ * Insert calling __sanitizer_cov_stack_depth() in asm:
+ * asm volatile("call __sanitizer_cov_stack_depth"
+ * :: "r" (current_stack_pointer))
+ * Use ASM_CALL_CONSTRAINT trick from arch/x86/include/asm/asm.h.
+ * This constraint is taken into account during gcc shrink-wrapping
+ * optimization. It is needed to be sure that __sanitizer_cov_stack_depth()
+ * call is inserted after the prologue of the containing function,
+ * when the stack frame is prepared.
+ */
+ sp_decl = get_current_stack_pointer_decl();
+ if (sp_decl == NULL_TREE) {
+ add_stack_tracking_gcall(gsi, after);
+ return;
+ }
+ input = build_tree_list(NULL_TREE, build_const_char_string(2, "r"));
+ input = chainon(NULL_TREE, build_tree_list(input, sp_decl));
+ vec_safe_push(inputs, input);
+ asm_call = gimple_build_asm_vec("call __sanitizer_cov_stack_depth",
+ inputs, NULL, NULL, NULL);
+ gimple_asm_set_volatile(asm_call, true);
+ if (after)
+ gsi_insert_after(gsi, asm_call, GSI_CONTINUE_LINKING);
+ else
+ gsi_insert_before(gsi, asm_call, GSI_SAME_STMT);
+ update_stmt(asm_call);
+}
+
+static void add_stack_tracking(gimple_stmt_iterator *gsi, bool after)
+{
+ /*
+ * The 'no_caller_saved_registers' attribute is used for
+ * __sanitizer_cov_stack_depth(). If the compiler supports this attribute for
+ * the target arch, we can add calling __sanitizer_cov_stack_depth() in asm.
+ * That improves performance: we avoid useless operations with the
+ * caller-saved registers in the functions from which we will remove
+ * __sanitizer_cov_stack_depth() call during the stackleak_cleanup pass.
+ */
+ if (lookup_attribute_spec(get_identifier("no_caller_saved_registers")))
+ add_stack_tracking_gasm(gsi, after);
+ else
+ add_stack_tracking_gcall(gsi, after);
+}
+
/*
* Work with the GIMPLE representation of the code. Insert the
- * stackleak_track_stack() call after alloca() and into the beginning
+ * __sanitizer_cov_stack_depth() call after alloca() and into the beginning
* of the function if it is not instrumented.
*/
static unsigned int stackleak_instrument_execute(void)
{
basic_block bb, entry_bb;
bool prologue_instrumented = false, is_leaf = true;
- gimple_stmt_iterator gsi;
+ gimple_stmt_iterator gsi = { 0 };
/*
* ENTRY_BLOCK_PTR is a basic block which represents possible entry
@@ -123,8 +200,13 @@ static unsigned int stackleak_instrument_execute(void)
if (!is_alloca(stmt))
continue;
- /* Insert stackleak_track_stack() call after alloca() */
- stackleak_add_track_stack(&gsi, true);
+ if (verbose) {
+ fprintf(stderr, "stackleak: be careful, alloca() in %s()\n",
+ DECL_NAME_POINTER(current_function_decl));
+ }
+
+ /* Insert __sanitizer_cov_stack_depth() call after alloca() */
+ add_stack_tracking(&gsi, true);
if (bb == entry_bb)
prologue_instrumented = true;
}
@@ -159,7 +241,7 @@ static unsigned int stackleak_instrument_execute(void)
return 0;
}
- /* Insert stackleak_track_stack() call at the function beginning */
+ /* Insert __sanitizer_cov_stack_depth() call at the function beginning */
bb = entry_bb;
if (!single_pred_p(bb)) {
/* gcc_assert(bb_loop_depth(bb) ||
@@ -169,7 +251,7 @@ static unsigned int stackleak_instrument_execute(void)
bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
}
gsi = gsi_after_labels(bb);
- stackleak_add_track_stack(&gsi, false);
+ add_stack_tracking(&gsi, false);
return 0;
}
@@ -183,31 +265,20 @@ static bool large_stack_frame(void)
#endif
}
-/*
- * Work with the RTL representation of the code.
- * Remove the unneeded stackleak_track_stack() calls from the functions
- * which don't call alloca() and don't have a large enough stack frame size.
- */
-static unsigned int stackleak_cleanup_execute(void)
+static void remove_stack_tracking_gcall(void)
{
rtx_insn *insn, *next;
- if (cfun->calls_alloca)
- return 0;
-
- if (large_stack_frame())
- return 0;
-
/*
- * Find stackleak_track_stack() calls. Loop through the chain of insns,
+ * Find __sanitizer_cov_stack_depth() calls. Loop through the chain of insns,
* which is an RTL representation of the code for a function.
*
* The example of a matching insn:
- * (call_insn 8 4 10 2 (call (mem (symbol_ref ("stackleak_track_stack")
- * [flags 0x41] <function_decl 0x7f7cd3302a80 stackleak_track_stack>)
- * [0 stackleak_track_stack S1 A8]) (0)) 675 {*call} (expr_list
- * (symbol_ref ("stackleak_track_stack") [flags 0x41] <function_decl
- * 0x7f7cd3302a80 stackleak_track_stack>) (expr_list (0) (nil))) (nil))
+ * (call_insn 8 4 10 2 (call (mem (symbol_ref ("__sanitizer_cov_stack_depth")
+ * [flags 0x41] <function_decl 0x7f7cd3302a80 __sanitizer_cov_stack_depth>)
+ * [0 __sanitizer_cov_stack_depth S1 A8]) (0)) 675 {*call} (expr_list
+ * (symbol_ref ("__sanitizer_cov_stack_depth") [flags 0x41] <function_decl
+ * 0x7f7cd3302a80 __sanitizer_cov_stack_depth>) (expr_list (0) (nil))) (nil))
*/
for (insn = get_insns(); insn; insn = next) {
rtx body;
@@ -247,9 +318,9 @@ static unsigned int stackleak_cleanup_execute(void)
if (SYMBOL_REF_DECL(body) != track_function_decl)
continue;
- /* Delete the stackleak_track_stack() call */
+ /* Delete the __sanitizer_cov_stack_depth() call */
delete_insn_and_edges(insn);
-#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION < 8000
+#if BUILDING_GCC_VERSION < 8000
if (GET_CODE(next) == NOTE &&
NOTE_KIND(next) == NOTE_INSN_CALL_ARG_LOCATION) {
insn = next;
@@ -258,10 +329,123 @@ static unsigned int stackleak_cleanup_execute(void)
}
#endif
}
+}
+
+static bool remove_stack_tracking_gasm(void)
+{
+ bool removed = false;
+ rtx_insn *insn, *next;
+
+ /* 'no_caller_saved_registers' is currently supported only for x86 */
+ gcc_assert(build_for_x86);
+
+ /*
+ * Find __sanitizer_cov_stack_depth() asm calls. Loop through the chain of
+ * insns, which is an RTL representation of the code for a function.
+ *
+ * The example of a matching insn:
+ * (insn 11 5 12 2 (parallel [ (asm_operands/v
+ * ("call __sanitizer_cov_stack_depth") ("") 0
+ * [ (reg/v:DI 7 sp [ current_stack_pointer ]) ]
+ * [ (asm_input:DI ("r")) ] [])
+ * (clobber (reg:CC 17 flags)) ]) -1 (nil))
+ */
+ for (insn = get_insns(); insn; insn = next) {
+ rtx body;
+
+ next = NEXT_INSN(insn);
+
+ /* Check the expression code of the insn */
+ if (!NONJUMP_INSN_P(insn))
+ continue;
+
+ /*
+ * Check the expression code of the insn body, which is an RTL
+ * Expression (RTX) describing the side effect performed by
+ * that insn.
+ */
+ body = PATTERN(insn);
+
+ if (GET_CODE(body) != PARALLEL)
+ continue;
+
+ body = XVECEXP(body, 0, 0);
+
+ if (GET_CODE(body) != ASM_OPERANDS)
+ continue;
+
+ if (strcmp(ASM_OPERANDS_TEMPLATE(body),
+ "call __sanitizer_cov_stack_depth")) {
+ continue;
+ }
+
+ delete_insn_and_edges(insn);
+ gcc_assert(!removed);
+ removed = true;
+ }
+
+ return removed;
+}
+
+/*
+ * Work with the RTL representation of the code.
+ * Remove the unneeded __sanitizer_cov_stack_depth() calls from the functions
+ * which don't call alloca() and don't have a large enough stack frame size.
+ */
+static unsigned int stackleak_cleanup_execute(void)
+{
+ const char *fn = DECL_NAME_POINTER(current_function_decl);
+ bool removed = false;
+
+ /*
+ * Leave stack tracking in functions that call alloca().
+ * Additional case:
+ * gcc before version 7 called allocate_dynamic_stack_space() from
+ * expand_stack_vars() for runtime alignment of constant-sized stack
+ * variables. That caused cfun->calls_alloca to be set for functions
+ * that in fact don't use alloca().
+ * For more info see gcc commit 7072df0aae0c59ae437e.
+ * Let's leave such functions instrumented as well.
+ */
+ if (cfun->calls_alloca) {
+ if (verbose)
+ fprintf(stderr, "stackleak: instrument %s(): calls_alloca\n", fn);
+ return 0;
+ }
+
+ /* Leave stack tracking in functions with large stack frame */
+ if (large_stack_frame()) {
+ if (verbose)
+ fprintf(stderr, "stackleak: instrument %s()\n", fn);
+ return 0;
+ }
+
+ if (lookup_attribute_spec(get_identifier("no_caller_saved_registers")))
+ removed = remove_stack_tracking_gasm();
+
+ if (!removed)
+ remove_stack_tracking_gcall();
return 0;
}
+/*
+ * STRING_CST may or may not be NUL terminated:
+ * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html
+ */
+static inline bool string_equal(tree node, const char *string, int length)
+{
+ if (TREE_STRING_LENGTH(node) < length)
+ return false;
+ if (TREE_STRING_LENGTH(node) > length + 1)
+ return false;
+ if (TREE_STRING_LENGTH(node) == length + 1 &&
+ TREE_STRING_POINTER(node)[length] != '\0')
+ return false;
+ return !memcmp(TREE_STRING_POINTER(node), string, length);
+}
+#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str))
+
static bool stackleak_gate(void)
{
tree section;
@@ -271,26 +455,32 @@ static bool stackleak_gate(void)
if (section && TREE_VALUE(section)) {
section = TREE_VALUE(TREE_VALUE(section));
- if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10))
+ if (STRING_EQUAL(section, ".init.text"))
return false;
- if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13))
+ if (STRING_EQUAL(section, ".devinit.text"))
return false;
- if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13))
+ if (STRING_EQUAL(section, ".cpuinit.text"))
return false;
- if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13))
+ if (STRING_EQUAL(section, ".meminit.text"))
+ return false;
+ if (STRING_EQUAL(section, ".noinstr.text"))
+ return false;
+ if (STRING_EQUAL(section, ".entry.text"))
+ return false;
+ if (STRING_EQUAL(section, ".head.text"))
return false;
}
return track_frame_size >= 0;
}
-/* Build the function declaration for stackleak_track_stack() */
+/* Build the function declaration for __sanitizer_cov_stack_depth() */
static void stackleak_start_unit(void *gcc_data __unused,
void *user_data __unused)
{
tree fntype;
- /* void stackleak_track_stack(void) */
+ /* void __sanitizer_cov_stack_depth(void) */
fntype = build_function_type_list(void_type_node, NULL_TREE);
track_function_decl = build_fn_decl(track_function, fntype);
DECL_ASSEMBLER_NAME(track_function_decl); /* for LTO */
@@ -377,9 +567,6 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
/* Parse the plugin arguments */
for (i = 0; i < argc; i++) {
- if (!strcmp(argv[i].key, "disable"))
- return 0;
-
if (!strcmp(argv[i].key, "track-min-size")) {
if (!argv[i].value) {
error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
@@ -393,6 +580,19 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
plugin_name, argv[i].key, argv[i].value);
return 1;
}
+ } else if (!strcmp(argv[i].key, "arch")) {
+ if (!argv[i].value) {
+ error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
+ plugin_name, argv[i].key);
+ return 1;
+ }
+
+ if (!strcmp(argv[i].value, "x86"))
+ build_for_x86 = true;
+ } else if (!strcmp(argv[i].key, "disable")) {
+ disable = true;
+ } else if (!strcmp(argv[i].key, "verbose")) {
+ verbose = true;
} else {
error(G_("unknown option '-fplugin-arg-%s-%s'"),
plugin_name, argv[i].key);
@@ -400,6 +600,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
}
}
+ if (disable) {
+ if (verbose)
+ fprintf(stderr, "stackleak: disabled for this translation unit\n");
+ return 0;
+ }
+
/* Give the information about the plugin */
register_callback(plugin_name, PLUGIN_INFO, NULL,
&stackleak_plugin_info);
diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c
deleted file mode 100644
index 10292f791e99..000000000000
--- a/scripts/gcc-plugins/structleak_plugin.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright 2013-2017 by PaX Team <pageexec@freemail.hu>
- * Licensed under the GPL v2
- *
- * Note: the choice of the license means that the compilation process is
- * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
- * but for the kernel it doesn't matter since it doesn't link against
- * any of the gcc libraries
- *
- * gcc plugin to forcibly initialize certain local variables that could
- * otherwise leak kernel stack to userland if they aren't properly initialized
- * by later code
- *
- * Homepage: http://pax.grsecurity.net/
- *
- * Options:
- * -fplugin-arg-structleak_plugin-disable
- * -fplugin-arg-structleak_plugin-verbose
- * -fplugin-arg-structleak_plugin-byref-all
- *
- * Usage:
- * $ # for 4.5/4.6/C based 4.7
- * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c
- * $ # for C++ based 4.7/4.8+
- * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c
- * $ gcc -fplugin=./structleak_plugin.so test.c -O2
- *
- * TODO: eliminate redundant initializers
- * increase type coverage
- */
-
-#include "gcc-common.h"
-
-/* unused C type flag in all versions 4.5-6 */
-#define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE)
-
-__visible int plugin_is_GPL_compatible;
-
-static struct plugin_info structleak_plugin_info = {
- .version = "201607271510vanilla",
- .help = "disable\tdo not activate plugin\n"
- "verbose\tprint all initialized variables\n",
-};
-
-static bool verbose;
-static bool byref_all;
-
-static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
-{
- *no_add_attrs = true;
-
- /* check for types? for now accept everything linux has to offer */
- if (TREE_CODE(*node) != FIELD_DECL)
- return NULL_TREE;
-
- *no_add_attrs = false;
- return NULL_TREE;
-}
-
-static struct attribute_spec user_attr = { };
-
-static void register_attributes(void *event_data, void *data)
-{
- user_attr.name = "user";
- user_attr.handler = handle_user_attribute;
-#if BUILDING_GCC_VERSION >= 4007
- user_attr.affects_type_identity = true;
-#endif
-
- register_attribute(&user_attr);
-}
-
-static tree get_field_type(tree field)
-{
- return strip_array_types(TREE_TYPE(field));
-}
-
-static bool is_userspace_type(tree type)
-{
- tree field;
-
- for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) {
- tree fieldtype = get_field_type(field);
- enum tree_code code = TREE_CODE(fieldtype);
-
- if (code == RECORD_TYPE || code == UNION_TYPE)
- if (is_userspace_type(fieldtype))
- return true;
-
- if (lookup_attribute("user", DECL_ATTRIBUTES(field)))
- return true;
- }
- return false;
-}
-
-static void finish_type(void *event_data, void *data)
-{
- tree type = (tree)event_data;
-
- if (type == NULL_TREE || type == error_mark_node)
- return;
-
-#if BUILDING_GCC_VERSION >= 5000
- if (TREE_CODE(type) == ENUMERAL_TYPE)
- return;
-#endif
-
- if (TYPE_USERSPACE(type))
- return;
-
- if (is_userspace_type(type))
- TYPE_USERSPACE(type) = 1;
-}
-
-static void initialize(tree var)
-{
- basic_block bb;
- gimple_stmt_iterator gsi;
- tree initializer;
- gimple init_stmt;
-
- /* this is the original entry bb before the forced split */
- bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
-
- /* first check if variable is already initialized, warn otherwise */
- for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
- gimple stmt = gsi_stmt(gsi);
- tree rhs1;
-
- /* we're looking for an assignment of a single rhs... */
- if (!gimple_assign_single_p(stmt))
- continue;
- rhs1 = gimple_assign_rhs1(stmt);
-#if BUILDING_GCC_VERSION >= 4007
- /* ... of a non-clobbering expression... */
- if (TREE_CLOBBER_P(rhs1))
- continue;
-#endif
- /* ... to our variable... */
- if (gimple_get_lhs(stmt) != var)
- continue;
- /* if it's an initializer then we're good */
- if (TREE_CODE(rhs1) == CONSTRUCTOR)
- return;
- }
-
- /* these aren't the 0days you're looking for */
- if (verbose)
- inform(DECL_SOURCE_LOCATION(var),
- "%s variable will be forcibly initialized",
- (byref_all && TREE_ADDRESSABLE(var)) ? "byref"
- : "userspace");
-
- /* build the initializer expression */
- initializer = build_constructor(TREE_TYPE(var), NULL);
-
- /* build the initializer stmt */
- init_stmt = gimple_build_assign(var, initializer);
- gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
- gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT);
- update_stmt(init_stmt);
-}
-
-static unsigned int structleak_execute(void)
-{
- basic_block bb;
- unsigned int ret = 0;
- tree var;
- unsigned int i;
-
- /* split the first bb where we can put the forced initializers */
- gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
- bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
- if (!single_pred_p(bb)) {
- split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
- gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
- }
-
- /* enumerate all local variables and forcibly initialize our targets */
- FOR_EACH_LOCAL_DECL(cfun, i, var) {
- tree type = TREE_TYPE(var);
-
- gcc_assert(DECL_P(var));
- if (!auto_var_in_fn_p(var, current_function_decl))
- continue;
-
- /* only care about structure types */
- if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
- continue;
-
- /* if the type is of interest, examine the variable */
- if (TYPE_USERSPACE(type) ||
- (byref_all && TREE_ADDRESSABLE(var)))
- initialize(var);
- }
-
- return ret;
-}
-
-#define PASS_NAME structleak
-#define NO_GATE
-#define PROPERTIES_REQUIRED PROP_cfg
-#define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow
-#include "gcc-generate-gimple-pass.h"
-
-__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
-{
- int i;
- 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;
-
- PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE);
-
- if (!plugin_default_version_check(version, &gcc_version)) {
- error(G_("incompatible gcc/plugin versions"));
- return 1;
- }
-
- if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) {
- inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name);
- enable = false;
- }
-
- for (i = 0; i < argc; ++i) {
- if (!strcmp(argv[i].key, "disable")) {
- enable = false;
- continue;
- }
- if (!strcmp(argv[i].key, "verbose")) {
- verbose = true;
- continue;
- }
- if (!strcmp(argv[i].key, "byref-all")) {
- byref_all = true;
- continue;
- }
- error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
- }
-
- register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info);
- if (enable) {
- register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info);
- register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL);
- }
- register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
-
- return 0;
-}