Discussion:
[PATCH, Pointer Bounds Checker 14/x] Passes [1/n] Expand interfaces
Ilya Enkovich
2014-10-08 18:50:54 UTC
Permalink
Hi,

This patch starts a series which is a result of split of Pointer Bounds Checker patch #14 (Pointer Bounds Checker passes).

This patch introduces compiler flags used by checker and helper functions mostly used by expand pass.

Thanks,
Ilya
--
2014-10-08 Ilya Enkovich <***@intel.com>

* tree-chkp.c: New.
* tree-chkp.h: New.
* rtl-chkp.c: New.
* rtl-chkp.h: New.
* Makefile.in (OBJS): Add rtl-chkp.o and tree-chkp.o.
(GTFILES): Add tree-chkp.c.
* c-family/c.opt (fchkp-check-incomplete-type): New.
(fchkp-zero-input-bounds-for-main): New.
(fchkp-first-field-has-own-bounds): New.
(fchkp-narrow-bounds): New.
(fchkp-narrow-to-innermost-array): New.
(fchkp-optimize): New.
(fchkp-use-fast-string-functions): New.
(fchkp-use-nochk-string-functions): New.
(fchkp-use-static-bounds): New.
(fchkp-use-static-const-bounds): New.
(fchkp-treat-zero-dynamic-size-as-infinite): New.
(fchkp-check-read): New.
(fchkp-check-write): New.
(fchkp-store-bounds): New.
(fchkp-instrument-calls): New.
(fchkp-instrument-marked-only): New.
* cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add
__CHKP__ macro when Pointer Bounds Checker is on.


diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 97b439a..3113a9f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1328,6 +1328,7 @@ OBJS = \
reload1.o \
reorg.o \
resource.o \
+ rtl-chkp.o \
rtl-error.o \
rtl.o \
rtlhash.o \
@@ -1386,6 +1387,7 @@ OBJS = \
tree-outof-ssa.o \
tree-parloops.o \
tree-phinodes.o \
+ tree-chkp.o \
tree-predcom.o \
tree-pretty-print.o \
tree-profile.o \
@@ -2254,6 +2256,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
$(srcdir)/gimple.h \
$(srcdir)/gimple-ssa.h \
+ $(srcdir)/tree-chkp.c \
$(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c $(srcdir)/tree-ssa-address.c \
$(srcdir)/tree-cfg.c \
$(srcdir)/tree-dfa.c \
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3c5ebc0..1ca5a95 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -955,6 +955,79 @@ Common Report Var(flag_check_pointer_bounds)
Add Pointer Bounds Checker instrumentation. fchkp-* flags are used to
control instrumentation. Currently available for C, C++ and ObjC.

+fchkp-check-incomplete-type
+C ObjC C++ ObjC++ Report Var(flag_chkp_incomplete_type) Init(1)
+Generate pointer bounds checks for variables with incomplete type
+
+fchkp-zero-input-bounds-for-main
+C ObjC C++ ObjC++ Report Var(flag_chkp_zero_input_bounds_for_main) Init(0)
+Use zero bounds for all incoming arguments in 'main' function. It helps when
+instrumented binaries are used with legacy libs.
+
+fchkp-first-field-has-own-bounds
+C ObjC C++ ObjC++ RejectNegative Report Var(flag_chkp_first_field_has_own_bounds)
+Forces Pointer Bounds Checker to use narrowed bounds for address of the first
+field in the structure. By default pointer to the first field has the same
+bounds as pointer to the whole structure.
+
+fchkp-narrow-bounds
+C ObjC C++ ObjC++ Report Var(flag_chkp_narrow_bounds) Init(1)
+Control how Pointer Bounds Checker handle pointers to object fields. When
+narrowing is on, field bounds are used. Otherwise full object bounds are used.
+
+fchkp-narrow-to-innermost-array
+C ObjC C++ ObjC++ RejectNegative Report Var(flag_chkp_narrow_to_innermost_arrray)
+Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
+nested static arryas access. By default outermost array is used.
+
+fchkp-optimize
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
+Allow Pointer Bounds Checker optimizations. By default allowed
+on optimization levels >0.
+
+fchkp-use-fast-string-functions
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_fast_string_functions) Init(0)
+Allow to use *_nobnd versions of string functions by Pointer Bounds Checker.
+
+fchkp-use-nochk-string-functions
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_nochk_string_functions) Init(0)
+Allow to use *_nochk versions of string functions by Pointer Bounds Checker.
+
+fchkp-use-static-bounds
+C ObjC C++ ObjC++ Report Var(flag_chkp_use_static_bounds) Init(1)
+Use statically initialized variable for vars bounds instead of
+generating them each time it is required.
+
+fchkp-use-static-const-bounds
+C ObjC C++ ObjC++ Report Var(flag_chkp_use_static_const_bounds) Init(-1)
+Use statically initialized variable for constant bounds instead of
+generating them each time it is required.
+
+fchkp-treat-zero-dynamic-size-as-infinite
+C ObjC C++ ObjC++ Report Var(flag_chkp_zero_dynamic_size_as_infinite) Init(0)
+With this option zero size obtained dynamically for objects with
+incomplete type will be treated as infinite.
+
+fchkp-check-read
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_check_read) Init(1)
+Generate checks for all read accesses to memory.
+
+fchkp-check-write
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_check_write) Init(1)
+Generate checks for all write accesses to memory.
+
+fchkp-store-bounds
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_store_bounds) Init(1)
+Generate bounds stores for pointer writes.
+
+fchkp-instrument-calls
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_calls) Init(1)
+Generate bounds passing for calls.
+
+fchkp-instrument-marked-only
+C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_marked_only) Init(0)
+Instrument only functions marked with bnd_instrument attribute.
+
fcilkplus
C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0)
Enable Cilk Plus
diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c
index fbcd9b0..3fc2f8a 100644
--- a/gcc/cppbuiltin.c
+++ b/gcc/cppbuiltin.c
@@ -107,6 +107,9 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile)
flag_finite_math_only);
if (flag_cilkplus)
cpp_define (pfile, "__cilk=200");
+
+ if (flag_check_pointer_bounds)
+ cpp_define (pfile, "__CHKP__");
}


diff --git a/gcc/rtl-chkp.c b/gcc/rtl-chkp.c
new file mode 100644
index 0000000..4c68119
--- /dev/null
+++ b/gcc/rtl-chkp.c
@@ -0,0 +1,299 @@
+/* RTL manipulation functions exported by Pointer Bounds Checker.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Contributed by Ilya Enkovich (***@intel.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl-chkp.h"
+#include "tree-chkp.h"
+#include "expr.h"
+#include "target.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "is-a.h"
+#include "predict.h"
+#include "basic-block.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "bitmap.h"
+
+struct hash_map<tree, rtx> *chkp_rtx_bounds_map;
+
+/* Get bounds rtx associated with NODE via
+ chkp_set_rtl_bounds call. */
+rtx
+chkp_get_rtl_bounds (tree node)
+{
+ rtx *slot;
+
+ if (!chkp_rtx_bounds_map)
+ return NULL_RTX;
+
+ slot = chkp_rtx_bounds_map->get (node);
+ return slot ? *slot : NULL_RTX;
+}
+
+/* Associate bounds rtx VAL with NODE. */
+void
+chkp_set_rtl_bounds (tree node, rtx val)
+{
+ if (!chkp_rtx_bounds_map)
+ chkp_rtx_bounds_map = new hash_map<tree, rtx>;
+
+ chkp_rtx_bounds_map->put (node, val);
+}
+
+/* Reset all bounds stored via chkp_set_rtl_bounds. */
+void
+chkp_reset_rtl_bounds ()
+{
+ if (!chkp_rtx_bounds_map)
+ return;
+
+ delete chkp_rtx_bounds_map;
+ chkp_rtx_bounds_map = NULL;
+}
+
+/* Split SLOT identifying slot for function value or
+ argument into two parts SLOT_VAL and SLOT_BND.
+ First is the slot for regular value and the other one is
+ for bounds. */
+void
+chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd)
+{
+ int i;
+ int val_num = 0;
+ int bnd_num = 0;
+ rtx *val_tmps;
+ rtx *bnd_tmps;
+
+ *slot_bnd = 0;
+
+ if (!slot
+ || GET_CODE (slot) != PARALLEL)
+ {
+ *slot_val = slot;
+ return;
+ }
+
+ val_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0));
+ bnd_tmps = XALLOCAVEC (rtx, XVECLEN (slot, 0));
+
+ for (i = 0; i < XVECLEN (slot, 0); i++)
+ {
+ rtx elem = XVECEXP (slot, 0, i);
+ rtx reg = GET_CODE (elem) == EXPR_LIST ? XEXP (elem, 0) : elem;
+
+ if (!reg)
+ continue;
+
+ if (POINTER_BOUNDS_MODE_P (GET_MODE (reg)) || CONST_INT_P (reg))
+ bnd_tmps[bnd_num++] = elem;
+ else
+ val_tmps[val_num++] = elem;
+ }
+
+ gcc_assert (val_num);
+
+ if (!bnd_num)
+ {
+ *slot_val = slot;
+ return;
+ }
+
+ if ((GET_CODE (val_tmps[0]) == EXPR_LIST) || (val_num > 1))
+ *slot_val = gen_rtx_PARALLEL (GET_MODE (slot),
+ gen_rtvec_v (val_num, val_tmps));
+ else
+ *slot_val = val_tmps[0];
+
+ if ((GET_CODE (bnd_tmps[0]) == EXPR_LIST) || (bnd_num > 1))
+ *slot_bnd = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec_v (bnd_num, bnd_tmps));
+ else
+ *slot_bnd = bnd_tmps[0];
+}
+
+/* Join previously splitted to VAL and BND rtx for function
+ value or argument and return it. */
+rtx
+chkp_join_splitted_slot (rtx val, rtx bnd)
+{
+ rtx res;
+ int i, n = 0;
+
+ if (!bnd)
+ return val;
+
+ if (GET_CODE (val) == PARALLEL)
+ n += XVECLEN (val, 0);
+ else
+ n++;
+
+ if (GET_CODE (bnd) == PARALLEL)
+ n += XVECLEN (bnd, 0);
+ else
+ n++;
+
+ res = gen_rtx_PARALLEL (GET_MODE (val), rtvec_alloc (n));
+
+ n = 0;
+
+ if (GET_CODE (val) == PARALLEL)
+ for (i = 0; i < XVECLEN (val, 0); i++)
+ XVECEXP (res, 0, n++) = XVECEXP (val, 0, i);
+ else
+ XVECEXP (res, 0, n++) = val;
+
+ if (GET_CODE (bnd) == PARALLEL)
+ for (i = 0; i < XVECLEN (bnd, 0); i++)
+ XVECEXP (res, 0, n++) = XVECEXP (bnd, 0, i);
+ else
+ XVECEXP (res, 0, n++) = bnd;
+
+ return res;
+}
+
+/* If PAR is PARALLEL holding registers then transform
+ it into PARALLEL holding EXPR_LISTs of those regs
+ and zero constant (similar to how function value
+ on multiple registers looks like). */
+void
+chkp_put_regs_to_expr_list (rtx par)
+{
+ int n;
+
+ if (GET_CODE (par) != PARALLEL
+ || GET_CODE (XVECEXP (par, 0, 0)) == EXPR_LIST)
+ return;
+
+ for (n = 0; n < XVECLEN (par, 0); n++)
+ XVECEXP (par, 0, n) = gen_rtx_EXPR_LIST (VOIDmode,
+ XVECEXP (par, 0, n),
+ const0_rtx);
+}
+
+/* Search rtx PAR describing function return value for an
+ item related to value at offset OFFS and return it.
+ Return NULL if item was not found. */
+rtx
+chkp_get_value_with_offs (rtx par, rtx offs)
+{
+ int n;
+
+ gcc_assert (GET_CODE (par) == PARALLEL);
+
+ for (n = 0; n < XVECLEN (par, 0); n++)
+ {
+ rtx par_offs = XEXP (XVECEXP (par, 0, n), 1);
+ if (INTVAL (offs) == INTVAL (par_offs))
+ return XEXP (XVECEXP (par, 0, n), 0);
+ }
+
+ return NULL;
+}
+
+/* Emit instructions to store BOUNDS for pointer VALUE
+ stored in MEM.
+ Function is used by expand to pass bounds for args
+ passed on stack. */
+void
+chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem)
+{
+ gcc_assert (MEM_P (mem));
+
+ if (REG_P (bounds) || CONST_INT_P (bounds))
+ {
+ rtx ptr;
+
+ if (REG_P (value))
+ ptr = value;
+ else
+ {
+ rtx slot = adjust_address (value, Pmode, 0);
+ ptr = gen_reg_rtx (Pmode);
+ emit_move_insn (ptr, slot);
+ }
+
+ if (CONST_INT_P (bounds))
+ bounds = targetm.calls.load_bounds_for_arg (value, ptr, bounds);
+
+ targetm.calls.store_bounds_for_arg (ptr, mem,
+ bounds, NULL);
+ }
+ else
+ {
+ int i;
+
+ gcc_assert (GET_CODE (bounds) == PARALLEL);
+ gcc_assert (GET_CODE (value) == PARALLEL || MEM_P (value) || REG_P (value));
+
+ for (i = 0; i < XVECLEN (bounds, 0); i++)
+ {
+ rtx reg = XEXP (XVECEXP (bounds, 0, i), 0);
+ rtx offs = XEXP (XVECEXP (bounds, 0, i), 1);
+ rtx slot = adjust_address (mem, Pmode, INTVAL (offs));
+ rtx ptr;
+
+ if (GET_CODE (value) == PARALLEL)
+ ptr = chkp_get_value_with_offs (value, offs);
+ else if (MEM_P (value))
+ {
+ rtx tmp = adjust_address (value, Pmode, INTVAL (offs));
+ ptr = gen_reg_rtx (Pmode);
+ emit_move_insn (ptr, tmp);
+ }
+ else
+ ptr = gen_rtx_SUBREG (Pmode, value, INTVAL (offs));
+
+ targetm.calls.store_bounds_for_arg (ptr, slot, reg, NULL);
+ }
+ }
+}
+
+/* Emit code to copy bounds for structure VALUE of type TYPE
+ copied to SLOT. */
+void
+chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type)
+{
+ bitmap have_bound = chkp_find_bound_slots (type);
+ bitmap_iterator bi;
+ unsigned i;
+ rtx tmp = NULL, bnd;
+
+ gcc_assert (TYPE_SIZE (type));
+ gcc_assert (MEM_P (value));
+ gcc_assert (MEM_P (slot));
+ gcc_assert (RECORD_OR_UNION_TYPE_P (type));
+
+ EXECUTE_IF_SET_IN_BITMAP (have_bound, 0, i, bi)
+ {
+ rtx ptr = adjust_address (value, Pmode, i * POINTER_SIZE / 8);
+ rtx to = adjust_address (slot, Pmode, i * POINTER_SIZE / 8);
+
+ if (!tmp)
+ tmp = gen_reg_rtx (Pmode);
+
+ emit_move_insn (tmp, ptr);
+ bnd = targetm.calls.load_bounds_for_arg (ptr, tmp, NULL);
+ targetm.calls.store_bounds_for_arg (tmp, to, bnd, NULL);
+ }
+
+ BITMAP_FREE (have_bound);
+}
diff --git a/gcc/rtl-chkp.h b/gcc/rtl-chkp.h
new file mode 100644
index 0000000..543cc83
--- /dev/null
+++ b/gcc/rtl-chkp.h
@@ -0,0 +1,40 @@
+/* Declaration of interface functions of Pointer Bounds Checker.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_RTL_CHKP_H
+#define GCC_RTL_CHKP_H
+
+#include "coretypes.h"
+
+#define DECL_BOUNDS_RTL(NODE) (chkp_get_rtl_bounds (DECL_WRTL_CHECK (NODE)))
+
+#define SET_DECL_BOUNDS_RTL(NODE, VAL) \
+ (chkp_set_rtl_bounds (DECL_WRTL_CHECK (NODE), VAL))
+
+extern rtx chkp_get_rtl_bounds (tree node);
+extern void chkp_set_rtl_bounds (tree node, rtx val);
+extern void chkp_reset_rtl_bounds ();
+extern void chkp_split_slot (rtx slot, rtx *slot_val, rtx *slot_bnd);
+extern rtx chkp_join_splitted_slot (rtx val, rtx bnd);
+extern rtx chkp_get_value_with_offs (rtx par, rtx offs);
+extern void chkp_copy_bounds_for_stack_parm (rtx slot, rtx value, tree type);
+extern void chkp_emit_bounds_store (rtx bounds, rtx value, rtx mem);
+extern void chkp_put_regs_to_expr_list (rtx par);
+
+#endif /* GCC_RTL_CHKP_H */
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
new file mode 100644
index 0000000..4ab8de6
--- /dev/null
+++ b/gcc/tree-chkp.c
@@ -0,0 +1,528 @@
+/* Pointer Bounds Checker insrumentation pass.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Contributed by Ilya Enkovich (***@intel.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "tree.h"
+#include "target.h"
+#include "tree-iterator.h"
+#include "tree-cfg.h"
+#include "langhooks.h"
+#include "tree-pass.h"
+#include "hashtab.h"
+#include "diagnostic.h"
+#include "ggc.h"
+#include "output.h"
+#include "internal-fn.h"
+#include "is-a.h"
+#include "predict.h"
+#include "cfgloop.h"
+#include "stringpool.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-operands.h"
+#include "tree-ssa-address.h"
+#include "tree-ssa.h"
+#include "ipa-inline.h"
+#include "basic-block.h"
+#include "tree-ssa-loop-niter.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "tree-phinodes.h"
+#include "gimple-ssa.h"
+#include "ssa-iterators.h"
+#include "gimple-pretty-print.h"
+#include "gimple-iterator.h"
+#include "gimplify.h"
+#include "gimplify-me.h"
+#include "print-tree.h"
+#include "expr.h"
+#include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
+#include "tree-chkp.h"
+#include "gimple-walk.h"
+#include "rtl.h" /* For MEM_P, assign_temp. */
+#include "tree-dfa.h"
+
+#define chkp_bndldx_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX))
+#define chkp_bndstx_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDSTX))
+#define chkp_checkl_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
+#define chkp_checku_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
+#define chkp_bndmk_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
+#define chkp_ret_bnd_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET))
+#define chkp_intersect_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
+#define chkp_narrow_bounds_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_NARROW))
+#define chkp_sizeof_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_SIZEOF))
+#define chkp_extract_lower_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_LOWER))
+#define chkp_extract_upper_fndecl \
+ (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_UPPER))
+
+static GTY (()) tree chkp_zero_bounds_var;
+
+struct hash_map<tree, tree> *chkp_bounds_map;
+
+#define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds"
+
+/* Return 1 if function FNDECL is instrumented by Pointer
+ Bounds Checker. */
+bool
+chkp_function_instrumented_p (tree fndecl)
+{
+ return fndecl
+ && lookup_attribute ("chkp instrumented", DECL_ATTRIBUTES (fndecl));
+}
+
+/* Mark function FNDECL as instrumented. */
+void
+chkp_function_mark_instrumented (tree fndecl)
+{
+ if (chkp_function_instrumented_p (fndecl))
+ return;
+
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("chkp instrumented"), NULL,
+ DECL_ATTRIBUTES (fndecl));
+}
+
+/* Return true when STMT is builtin call to instrumentation function
+ corresponding to CODE. */
+
+bool
+chkp_gimple_call_builtin_p (gimple call,
+ enum built_in_function code)
+{
+ tree fndecl;
+ if (is_gimple_call (call)
+ && (fndecl = targetm.builtin_chkp_function (code))
+ && gimple_call_fndecl (call) == fndecl)
+ return true;
+ return false;
+}
+
+/* Emit code to store zero bounds for PTR located at MEM. */
+void
+chkp_expand_bounds_reset_for_mem (tree mem, tree ptr)
+{
+ tree zero_bnd, bnd, addr, bndstx;
+
+ if (flag_chkp_use_static_const_bounds)
+ zero_bnd = chkp_get_zero_bounds_var ();
+ else
+ zero_bnd = chkp_build_make_bounds_call (integer_zero_node,
+ integer_zero_node);
+ bnd = make_tree (pointer_bounds_type_node,
+ assign_temp (pointer_bounds_type_node, 0, 1));
+ addr = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (mem)), mem);
+ bndstx = chkp_build_bndstx_call (addr, ptr, bnd);
+
+ expand_assignment (bnd, zero_bnd, false);
+ expand_normal (bndstx);
+}
+
+/* Mark statement S to not be instrumented. */
+static void
+chkp_mark_stmt (gimple s)
+{
+ gimple_set_plf (s, GF_PLF_1, true);
+}
+
+/* Mark statement S to be instrumented. */
+static void
+chkp_unmark_stmt (gimple s)
+{
+ gimple_set_plf (s, GF_PLF_1, false);
+}
+
+/* Return 1 if statement S should not be instrumented. */
+static bool
+chkp_marked_stmt_p (gimple s)
+{
+ return gimple_plf (s, GF_PLF_1);
+}
+
+/* Build and return bndmk call which creates bounds for structure
+ pointed by PTR. Structure should have complete type. */
+tree
+chkp_make_bounds_for_struct_addr (tree ptr)
+{
+ tree type = TREE_TYPE (ptr);
+ tree size;
+
+ gcc_assert (POINTER_TYPE_P (type));
+
+ size = TYPE_SIZE (TREE_TYPE (type));
+
+ gcc_assert (size);
+
+ return build_call_nary (pointer_bounds_type_node,
+ build_fold_addr_expr (chkp_bndmk_fndecl),
+ 2, ptr, size);
+}
+
+/* Return 1 if type TYPE is a pointer type or a
+ structure having a pointer type as one of its fields.
+ Otherwise return 0. */
+bool
+chkp_type_has_pointer (const_tree type)
+{
+ bool res = false;
+
+ if (BOUNDED_TYPE_P (type))
+ res = true;
+ else if (RECORD_OR_UNION_TYPE_P (type))
+ {
+ tree field;
+
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ res = res || chkp_type_has_pointer (TREE_TYPE (field));
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ res = chkp_type_has_pointer (TREE_TYPE (type));
+
+ return res;
+}
+
+unsigned
+chkp_type_bounds_count (const_tree type)
+{
+ unsigned res = 0;
+
+ if (!type)
+ res = 0;
+ else if (BOUNDED_TYPE_P (type))
+ res = 1;
+ else if (RECORD_OR_UNION_TYPE_P (type))
+ {
+ bitmap have_bound = chkp_find_bound_slots (type);
+ res = bitmap_count_bits (have_bound);
+ BITMAP_FREE (have_bound);
+ }
+
+ return res;
+}
+
+/* Get bounds associated with NODE via
+ chkp_set_bounds call. */
+tree
+chkp_get_bounds (tree node)
+{
+ tree *slot;
+
+ if (!chkp_bounds_map)
+ return NULL_TREE;
+
+ slot = chkp_bounds_map->get (node);
+ return slot ? *slot : NULL_TREE;
+}
+
+/* Associate bounds VAL with NODE. */
+void
+chkp_set_bounds (tree node, tree val)
+{
+ if (!chkp_bounds_map)
+ chkp_bounds_map = new hash_map<tree, tree>;
+
+ chkp_bounds_map->put (node, val);
+}
+
+/* Force OP to be suitable for using as an argument for call.
+ New statements (if any) go to SEQ. */
+static tree
+chkp_force_gimple_call_op (tree op, gimple_seq *seq)
+{
+ gimple_seq stmts;
+ gimple_stmt_iterator si;
+
+ op = force_gimple_operand (unshare_expr (op), &stmts, true, NULL_TREE);
+
+ for (si = gsi_start (stmts); !gsi_end_p (si); gsi_next (&si))
+ chkp_mark_stmt (gsi_stmt (si));
+
+ gimple_seq_add_seq (seq, stmts);
+
+ return op;
+}
+
+/* Fill HAVE_BOUND output bitmap with information about
+ bounds requred for object of type TYPE.
+
+ OFFS is used for recursive calls and holds basic
+ offset of TYPE in outer structure in bits.
+
+ HAVE_BOUND[i] is set to 1 if there is a field
+ in TYPE which has pointer type and offset
+ equal to i * POINTER_SIZE - OFFS in bits. */
+void
+chkp_find_bound_slots_1 (const_tree type, bitmap have_bound,
+ HOST_WIDE_INT offs)
+{
+ if (BOUNDED_TYPE_P (type))
+ bitmap_set_bit (have_bound, offs / POINTER_SIZE);
+ else if (RECORD_OR_UNION_TYPE_P (type))
+ {
+ tree field;
+
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ HOST_WIDE_INT field_offs
+ = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+ if (DECL_FIELD_OFFSET (field))
+ field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8;
+ chkp_find_bound_slots_1 (TREE_TYPE (field), have_bound,
+ offs + field_offs);
+ }
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ tree etype = TREE_TYPE (type);
+ HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype));
+ unsigned HOST_WIDE_INT cur;
+
+ if (!maxval || integer_minus_onep (maxval))
+ return;
+
+ for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++)
+ chkp_find_bound_slots_1 (etype, have_bound, offs + cur * esize);
+ }
+}
+
+/* Return bitmap holding information about bounds for
+ type TYPE. See chkp_find_bound_slots_1 for more
+ details.
+
+ Caller is responsible for deallocation of returned
+ bitmap. */
+bitmap
+chkp_find_bound_slots (const_tree type)
+{
+ bitmap res = BITMAP_ALLOC (NULL);
+ chkp_find_bound_slots_1 (type, res, 0);
+ return res;
+}
+
+/* Return constant static bounds var with specified LB and UB
+ if such var exists in varpool. Return NULL otherwise. */
+static tree
+chkp_find_const_bounds_var (HOST_WIDE_INT lb,
+ HOST_WIDE_INT ub)
+{
+ tree val = targetm.chkp_make_bounds_constant (lb, ub);
+ struct varpool_node *node;
+
+ /* We expect bounds constant is represented as a complex value
+ of two pointer sized integers. */
+ gcc_assert (TREE_CODE (val) == COMPLEX_CST);
+
+ FOR_EACH_VARIABLE (node)
+ if (POINTER_BOUNDS_P (node->decl)
+ && TREE_READONLY (node->decl)
+ && DECL_INITIAL (node->decl)
+ && TREE_CODE (DECL_INITIAL (node->decl)) == COMPLEX_CST
+ && tree_int_cst_equal (TREE_REALPART (DECL_INITIAL (node->decl)),
+ TREE_REALPART (val))
+ && tree_int_cst_equal (TREE_IMAGPART (DECL_INITIAL (node->decl)),
+ TREE_IMAGPART (val)))
+ return node->decl;
+
+ return NULL;
+}
+
+/* Return constant static bounds var with specified bounds LB and UB.
+ If such var does not exists then new var is created with specified NAME. */
+static tree
+chkp_make_static_const_bounds (HOST_WIDE_INT lb,
+ HOST_WIDE_INT ub,
+ const char *name)
+{
+ tree var;
+
+ /* With LTO we may have constant bounds already in varpool.
+ Try to find it. */
+ var = chkp_find_const_bounds_var (lb, ub);
+
+ if (var)
+ return var;
+
+ var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (name), pointer_bounds_type_node);
+
+ TREE_PUBLIC (var) = 1;
+ TREE_USED (var) = 1;
+ TREE_READONLY (var) = 1;
+ TREE_STATIC (var) = 1;
+ TREE_ADDRESSABLE (var) = 0;
+ DECL_ARTIFICIAL (var) = 1;
+ DECL_COMDAT (var) = 1;
+ DECL_READ_P (var) = 1;
+ DECL_INITIAL (var) = targetm.chkp_make_bounds_constant (lb, ub);
+ /* We may use this symbol during ctors generation in chkp_finish_file
+ when all symbols are emitted. Force output to avoid undefined
+ symbols in ctors. */
+ varpool_node::get_create (var)->set_comdat_group (DECL_ASSEMBLER_NAME (var));
+ varpool_node::get_create (var)->force_output = 1;
+ varpool_node::finalize_decl (var);
+
+ return var;
+}
+
+/* Return var holding zero bounds. */
+tree
+chkp_get_zero_bounds_var (void)
+{
+ if (!chkp_zero_bounds_var)
+ chkp_zero_bounds_var
+ = chkp_make_static_const_bounds (0, -1,
+ CHKP_ZERO_BOUNDS_VAR_NAME);
+ return chkp_zero_bounds_var;
+}
+
+/* Return bounds used as returned by call
+ which produced SSA name VAL. */
+gimple
+chkp_retbnd_call_by_val (tree val)
+{
+ if (TREE_CODE (val) != SSA_NAME)
+ return NULL;
+
+ gcc_assert (gimple_code (SSA_NAME_DEF_STMT (val)) == GIMPLE_CALL);
+
+ imm_use_iterator use_iter;
+ use_operand_p use_p;
+ FOR_EACH_IMM_USE_FAST (use_p, use_iter, val)
+ if (gimple_code (USE_STMT (use_p)) == GIMPLE_CALL
+ && gimple_call_fndecl (USE_STMT (use_p)) == chkp_ret_bnd_fndecl)
+ return USE_STMT (use_p);
+
+ return NULL;
+}
+
+/* Build and return CALL_EXPR for bndstx builtin with specified
+ arguments. */
+tree
+chkp_build_bndldx_call (tree addr, tree ptr)
+{
+ tree fn = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (chkp_bndldx_fndecl)),
+ chkp_bndldx_fndecl);
+ tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndldx_fndecl)),
+ fn, 2, addr, ptr);
+ CALL_WITH_BOUNDS_P (call) = true;
+ return call;
+}
+
+/* Build and return CALL_EXPR for bndstx builtin with specified
+ arguments. */
+tree
+chkp_build_bndstx_call (tree addr, tree ptr, tree bounds)
+{
+ tree fn = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (chkp_bndstx_fndecl)),
+ chkp_bndstx_fndecl);
+ tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndstx_fndecl)),
+ fn, 3, ptr, bounds, addr);
+ CALL_WITH_BOUNDS_P (call) = true;
+ return call;
+}
+
+/* Insert code to store BOUNDS for PTR stored by ADDR.
+ New statements are inserted after position pointed
+ by GSI. */
+void
+chkp_build_bndstx (tree addr, tree ptr, tree bounds,
+ gimple_stmt_iterator *gsi)
+{
+ gimple_seq seq;
+ gimple stmt;
+
+ seq = NULL;
+
+ addr = chkp_force_gimple_call_op (addr, &seq);
+ ptr = chkp_force_gimple_call_op (ptr, &seq);
+
+ stmt = gimple_build_call (chkp_bndstx_fndecl, 3, ptr, bounds, addr);
+ chkp_mark_stmt (stmt);
+ gimple_call_set_with_bounds (stmt, true);
+
+ gimple_seq_add_stmt (&seq, stmt);
+
+ gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Generated bndstx for pointer store ");
+ print_gimple_stmt (dump_file, gsi_stmt (*gsi), 0, TDF_VOPS|TDF_MEMSYMS);
+ print_gimple_stmt (dump_file, stmt, 2, TDF_VOPS|TDF_MEMSYMS);
+ }
+}
+
+/* Return CALL_EXPR for bndmk with specified LOWER_BOUND and SIZE. */
+tree
+chkp_build_make_bounds_call (tree lower_bound, tree size)
+{
+ tree call = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (chkp_bndmk_fndecl)),
+ chkp_bndmk_fndecl);
+ return build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndmk_fndecl)),
+ call, 2, lower_bound, size);
+}
+
+/* Return 1 if TYPE has fields with zero size or fields
+ marked with chkp_variable_size attribute. */
+bool
+chkp_variable_size_type (tree type)
+{
+ bool res = false;
+ tree field;
+
+ if (RECORD_OR_UNION_TYPE_P (type))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ res = res
+ || lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field))
+ || chkp_variable_size_type (TREE_TYPE (field));
+ }
+ else
+ res = !TYPE_SIZE (type)
+ || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+ || tree_to_uhwi (TYPE_SIZE (type)) == 0;
+
+ return res;
+}
+
+#include "gt-tree-chkp.h"
diff --git a/gcc/tree-chkp.h b/gcc/tree-chkp.h
new file mode 100644
index 0000000..0357658
--- /dev/null
+++ b/gcc/tree-chkp.h
@@ -0,0 +1,51 @@
+/* Declaration of interface functions of Pointer Bounds Checker.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_TREE_CHKP_H
+#define GCC_TREE_CHKP_H
+
+#include "tree.h"
+#include "cgraph.h"
+
+#define DECL_BOUNDS(NODE) (chkp_get_bounds (DECL_WRTL_CHECK (NODE)))
+
+#define SET_DECL_BOUNDS(NODE, VAL) \
+ (chkp_set_bounds (DECL_WRTL_CHECK (NODE), VAL))
+
+extern tree chkp_get_bounds (tree node);
+extern void chkp_set_bounds (tree node, tree val);
+extern bool chkp_type_has_pointer (const_tree type);
+extern unsigned chkp_type_bounds_count (const_tree type);
+extern tree chkp_make_bounds_for_struct_addr (tree ptr);
+extern tree chkp_get_zero_bounds_var (void);
+extern bool chkp_variable_size_type (tree type);
+extern tree chkp_build_make_bounds_call (tree lb, tree size);
+extern tree chkp_build_bndldx_call (tree addr, tree ptr);
+extern tree chkp_build_bndstx_call (tree addr, tree ptr, tree bounds);
+extern bitmap chkp_find_bound_slots (const_tree type);
+extern void chkp_build_bndstx (tree addr, tree ptr, tree bounds,
+ gimple_stmt_iterator *gsi);
+extern gimple chkp_retbnd_call_by_val (tree val);
+extern bool chkp_function_instrumented_p (tree fndecl);
+extern void chkp_function_mark_instrumented (tree fndecl);
+extern bool chkp_gimple_call_builtin_p (gimple call,
+ enum built_in_function code);
+extern void chkp_expand_bounds_reset_for_mem (tree mem, tree ptr);
+
+#endif /* GCC_TREE_CHKP_H */

Loading...