summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorienkovich <ienkovich@138bc75d-0d04-0410-961f-82ee72b054a4>2014-11-17 13:45:55 +0000
committerienkovich <ienkovich@138bc75d-0d04-0410-961f-82ee72b054a4>2014-11-17 13:45:55 +0000
commitf21337ef57463b10070852e9e38f4b364c29a616 (patch)
treebc2f2a46968faabdbe890355b0f2b9b151a106bb
parent3bbe8db09c0e074f83a19566ba596679f8a50cd2 (diff)
downloadgcc-f21337ef57463b10070852e9e38f4b364c29a616.tar.gz
* tree-core.h (built_in_class): Add builtin codes to be used
by Pointer Bounds Checker for instrumented builtin functions. * tree-streamer-in.c: Include ipa-chkp.h. (streamer_get_builtin_tree): Created instrumented decl if required. * ipa-chkp.h (chkp_maybe_clone_builtin_fndecl): New. * ipa-chkp.c (chkp_build_instrumented_fndecl): Support builtin function decls. (chkp_maybe_clone_builtin_fndecl): New. (chkp_maybe_create_clone): Support builtin function decls. (chkp_versioning): Clone builtin functions. * tree-chkp.c (chkp_instrument_normal_builtin): New. (chkp_add_bounds_to_call_stmt): Support builtin functions. (chkp_replace_function_pointer): Likewise. * builtins.c (expand_builtin_memcpy_args): New. (expand_builtin_memcpy): Call expand_builtin_memcpy_args. (expand_builtin_memcpy_with_bounds): New. (expand_builtin_mempcpy_with_bounds): New. (expand_builtin_mempcpy_args): Add orig_exp arg. Support BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK (expand_builtin_memset_with_bounds): New. (expand_builtin_memset_args): Support BUILT_IN_CHKP_MEMSET_NOBND_NOCHK. (expand_builtin_with_bounds): New. * builtins.h (expand_builtin_with_bounds): New. * expr.c (expand_expr_real_1): Support instrumented builtin calls. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217655 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog28
-rw-r--r--gcc/builtins.c307
-rw-r--r--gcc/builtins.h1
-rw-r--r--gcc/expr.c6
-rw-r--r--gcc/ipa-chkp.c99
-rw-r--r--gcc/ipa-chkp.h1
-rw-r--r--gcc/tree-chkp.c87
-rw-r--r--gcc/tree-core.h8
-rw-r--r--gcc/tree-streamer-in.c9
9 files changed, 457 insertions, 89 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 660838cde78..123166c9562 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,31 @@
+2014-11-17 Ilya Enkovich <ilya.enkovich@intel.com>
+
+ * tree-core.h (built_in_class): Add builtin codes to be used
+ by Pointer Bounds Checker for instrumented builtin functions.
+ * tree-streamer-in.c: Include ipa-chkp.h.
+ (streamer_get_builtin_tree): Created instrumented decl if
+ required.
+ * ipa-chkp.h (chkp_maybe_clone_builtin_fndecl): New.
+ * ipa-chkp.c (chkp_build_instrumented_fndecl): Support builtin
+ function decls.
+ (chkp_maybe_clone_builtin_fndecl): New.
+ (chkp_maybe_create_clone): Support builtin function decls.
+ (chkp_versioning): Clone builtin functions.
+ * tree-chkp.c (chkp_instrument_normal_builtin): New.
+ (chkp_add_bounds_to_call_stmt): Support builtin functions.
+ (chkp_replace_function_pointer): Likewise.
+ * builtins.c (expand_builtin_memcpy_args): New.
+ (expand_builtin_memcpy): Call expand_builtin_memcpy_args.
+ (expand_builtin_memcpy_with_bounds): New.
+ (expand_builtin_mempcpy_with_bounds): New.
+ (expand_builtin_mempcpy_args): Add orig_exp arg. Support
+ BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
+ (expand_builtin_memset_with_bounds): New.
+ (expand_builtin_memset_args): Support BUILT_IN_CHKP_MEMSET_NOBND_NOCHK.
+ (expand_builtin_with_bounds): New.
+ * builtins.h (expand_builtin_with_bounds): New.
+ * expr.c (expand_expr_real_1): Support instrumented builtin calls.
+
2014-11-17 Dodji Seketeli <dodji@redhat.com>
* gimple.h (gimple_set_visited, gimple_visited_p)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 311c0e38279..7ec2d5f8e8c 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -132,15 +132,19 @@ static rtx expand_builtin_strcmp (tree, rtx);
static rtx expand_builtin_strncmp (tree, rtx, machine_mode);
static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, machine_mode);
static rtx expand_builtin_memcpy (tree, rtx);
+static rtx expand_builtin_memcpy_with_bounds (tree, rtx);
+static rtx expand_builtin_memcpy_args (tree, tree, tree, rtx, tree);
static rtx expand_builtin_mempcpy (tree, rtx, machine_mode);
+static rtx expand_builtin_mempcpy_with_bounds (tree, rtx, machine_mode);
static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx,
- machine_mode, int);
+ machine_mode, int, tree);
static rtx expand_builtin_strcpy (tree, rtx);
static rtx expand_builtin_strcpy_args (tree, tree, rtx);
static rtx expand_builtin_stpcpy (tree, rtx, machine_mode);
static rtx expand_builtin_strncpy (tree, rtx);
static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, machine_mode);
static rtx expand_builtin_memset (tree, rtx, machine_mode);
+static rtx expand_builtin_memset_with_bounds (tree, rtx, machine_mode);
static rtx expand_builtin_memset_args (tree, tree, tree, rtx, machine_mode, tree);
static rtx expand_builtin_bzero (tree);
static rtx expand_builtin_strlen (tree, rtx, machine_mode);
@@ -3175,6 +3179,81 @@ determine_block_size (tree len, rtx len_rtx,
GET_MODE_MASK (GET_MODE (len_rtx)));
}
+/* Helper function to do the actual work for expand_builtin_memcpy. */
+
+static rtx
+expand_builtin_memcpy_args (tree dest, tree src, tree len, rtx target, tree exp)
+{
+ const char *src_str;
+ unsigned int src_align = get_pointer_alignment (src);
+ unsigned int dest_align = get_pointer_alignment (dest);
+ rtx dest_mem, src_mem, dest_addr, len_rtx;
+ HOST_WIDE_INT expected_size = -1;
+ unsigned int expected_align = 0;
+ unsigned HOST_WIDE_INT min_size;
+ unsigned HOST_WIDE_INT max_size;
+ unsigned HOST_WIDE_INT probable_max_size;
+
+ /* If DEST is not a pointer type, call the normal function. */
+ if (dest_align == 0)
+ return NULL_RTX;
+
+ /* If either SRC is not a pointer type, don't do this
+ operation in-line. */
+ if (src_align == 0)
+ return NULL_RTX;
+
+ if (currently_expanding_gimple_stmt)
+ stringop_block_profile (currently_expanding_gimple_stmt,
+ &expected_align, &expected_size);
+
+ if (expected_align < dest_align)
+ expected_align = dest_align;
+ dest_mem = get_memory_rtx (dest, len);
+ set_mem_align (dest_mem, dest_align);
+ len_rtx = expand_normal (len);
+ determine_block_size (len, len_rtx, &min_size, &max_size,
+ &probable_max_size);
+ src_str = c_getstr (src);
+
+ /* If SRC is a string constant and block move would be done
+ by pieces, we can avoid loading the string from memory
+ and only stored the computed constants. */
+ if (src_str
+ && CONST_INT_P (len_rtx)
+ && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
+ && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
+ CONST_CAST (char *, src_str),
+ dest_align, false))
+ {
+ dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+ builtin_memcpy_read_str,
+ CONST_CAST (char *, src_str),
+ dest_align, false, 0);
+ dest_mem = force_operand (XEXP (dest_mem, 0), target);
+ dest_mem = convert_memory_address (ptr_mode, dest_mem);
+ return dest_mem;
+ }
+
+ src_mem = get_memory_rtx (src, len);
+ set_mem_align (src_mem, src_align);
+
+ /* Copy word part most expediently. */
+ dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx,
+ CALL_EXPR_TAILCALL (exp)
+ ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
+ expected_align, expected_size,
+ min_size, max_size, probable_max_size);
+
+ if (dest_addr == 0)
+ {
+ dest_addr = force_operand (XEXP (dest_mem, 0), target);
+ dest_addr = convert_memory_address (ptr_mode, dest_addr);
+ }
+
+ return dest_addr;
+}
+
/* Expand a call EXP to the memcpy builtin.
Return NULL_RTX if we failed, the caller should emit a normal call,
otherwise try to get the result in TARGET, if convenient (and in
@@ -3191,73 +3270,38 @@ expand_builtin_memcpy (tree exp, rtx target)
tree dest = CALL_EXPR_ARG (exp, 0);
tree src = CALL_EXPR_ARG (exp, 1);
tree len = CALL_EXPR_ARG (exp, 2);
- const char *src_str;
- unsigned int src_align = get_pointer_alignment (src);
- unsigned int dest_align = get_pointer_alignment (dest);
- rtx dest_mem, src_mem, dest_addr, len_rtx;
- HOST_WIDE_INT expected_size = -1;
- unsigned int expected_align = 0;
- unsigned HOST_WIDE_INT min_size;
- unsigned HOST_WIDE_INT max_size;
- unsigned HOST_WIDE_INT probable_max_size;
-
- /* If DEST is not a pointer type, call the normal function. */
- if (dest_align == 0)
- return NULL_RTX;
-
- /* If either SRC is not a pointer type, don't do this
- operation in-line. */
- if (src_align == 0)
- return NULL_RTX;
-
- if (currently_expanding_gimple_stmt)
- stringop_block_profile (currently_expanding_gimple_stmt,
- &expected_align, &expected_size);
-
- if (expected_align < dest_align)
- expected_align = dest_align;
- dest_mem = get_memory_rtx (dest, len);
- set_mem_align (dest_mem, dest_align);
- len_rtx = expand_normal (len);
- determine_block_size (len, len_rtx, &min_size, &max_size,
- &probable_max_size);
- src_str = c_getstr (src);
-
- /* If SRC is a string constant and block move would be done
- by pieces, we can avoid loading the string from memory
- and only stored the computed constants. */
- if (src_str
- && CONST_INT_P (len_rtx)
- && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
- && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
- CONST_CAST (char *, src_str),
- dest_align, false))
- {
- dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
- builtin_memcpy_read_str,
- CONST_CAST (char *, src_str),
- dest_align, false, 0);
- dest_mem = force_operand (XEXP (dest_mem, 0), target);
- dest_mem = convert_memory_address (ptr_mode, dest_mem);
- return dest_mem;
- }
+ return expand_builtin_memcpy_args (dest, src, len, target, exp);
+ }
+}
- src_mem = get_memory_rtx (src, len);
- set_mem_align (src_mem, src_align);
+/* Expand an instrumented call EXP to the memcpy builtin.
+ Return NULL_RTX if we failed, the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient (and in
+ mode MODE if that's convenient). */
- /* Copy word part most expediently. */
- dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx,
- CALL_EXPR_TAILCALL (exp)
- ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
- expected_align, expected_size,
- min_size, max_size, probable_max_size);
+static rtx
+expand_builtin_memcpy_with_bounds (tree exp, rtx target)
+{
+ if (!validate_arglist (exp,
+ POINTER_TYPE, POINTER_BOUNDS_TYPE,
+ POINTER_TYPE, POINTER_BOUNDS_TYPE,
+ INTEGER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+ else
+ {
+ tree dest = CALL_EXPR_ARG (exp, 0);
+ tree src = CALL_EXPR_ARG (exp, 2);
+ tree len = CALL_EXPR_ARG (exp, 4);
+ rtx res = expand_builtin_memcpy_args (dest, src, len, target, exp);
- if (dest_addr == 0)
+ /* Return src bounds with the result. */
+ if (res)
{
- dest_addr = force_operand (XEXP (dest_mem, 0), target);
- dest_addr = convert_memory_address (ptr_mode, dest_addr);
+ rtx bnd = force_reg (BNDmode,
+ expand_normal (CALL_EXPR_ARG (exp, 1)));
+ res = chkp_join_splitted_slot (res, bnd);
}
- return dest_addr;
+ return res;
}
}
@@ -3281,7 +3325,40 @@ expand_builtin_mempcpy (tree exp, rtx target, machine_mode mode)
tree src = CALL_EXPR_ARG (exp, 1);
tree len = CALL_EXPR_ARG (exp, 2);
return expand_builtin_mempcpy_args (dest, src, len,
- target, mode, /*endp=*/ 1);
+ target, mode, /*endp=*/ 1,
+ exp);
+ }
+}
+
+/* Expand an instrumented call EXP to the mempcpy builtin.
+ Return NULL_RTX if we failed, the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient (and in
+ mode MODE if that's convenient). */
+
+static rtx
+expand_builtin_mempcpy_with_bounds (tree exp, rtx target, machine_mode mode)
+{
+ if (!validate_arglist (exp,
+ POINTER_TYPE, POINTER_BOUNDS_TYPE,
+ POINTER_TYPE, POINTER_BOUNDS_TYPE,
+ INTEGER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+ else
+ {
+ tree dest = CALL_EXPR_ARG (exp, 0);
+ tree src = CALL_EXPR_ARG (exp, 2);
+ tree len = CALL_EXPR_ARG (exp, 4);
+ rtx res = expand_builtin_mempcpy_args (dest, src, len, target,
+ mode, 1, exp);
+
+ /* Return src bounds with the result. */
+ if (res)
+ {
+ rtx bnd = force_reg (BNDmode,
+ expand_normal (CALL_EXPR_ARG (exp, 1)));
+ res = chkp_join_splitted_slot (res, bnd);
+ }
+ return res;
}
}
@@ -3293,10 +3370,23 @@ expand_builtin_mempcpy (tree exp, rtx target, machine_mode mode)
static rtx
expand_builtin_mempcpy_args (tree dest, tree src, tree len,
- rtx target, machine_mode mode, int endp)
+ rtx target, machine_mode mode, int endp,
+ tree orig_exp)
{
+ tree fndecl = get_callee_fndecl (orig_exp);
+
/* If return value is ignored, transform mempcpy into memcpy. */
- if (target == const0_rtx && builtin_decl_implicit_p (BUILT_IN_MEMCPY))
+ if (target == const0_rtx
+ && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP
+ && builtin_decl_implicit_p (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP))
+ {
+ tree fn = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP);
+ tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
+ dest, src, len);
+ return expand_expr (result, target, mode, EXPAND_NORMAL);
+ }
+ else if (target == const0_rtx
+ && builtin_decl_implicit_p (BUILT_IN_MEMCPY))
{
tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
@@ -3481,7 +3571,8 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
ret = expand_builtin_mempcpy_args (dst, src, lenp1,
- target, mode, /*endp=*/2);
+ target, mode, /*endp=*/2,
+ exp);
if (ret)
return ret;
@@ -3647,6 +3738,36 @@ expand_builtin_memset (tree exp, rtx target, machine_mode mode)
}
}
+/* Expand expression EXP, which is an instrumented call to the memset builtin.
+ Return NULL_RTX if we failed the caller should emit a normal call, otherwise
+ try to get the result in TARGET, if convenient (and in mode MODE if that's
+ convenient). */
+
+static rtx
+expand_builtin_memset_with_bounds (tree exp, rtx target, machine_mode mode)
+{
+ if (!validate_arglist (exp,
+ POINTER_TYPE, POINTER_BOUNDS_TYPE,
+ INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+ else
+ {
+ tree dest = CALL_EXPR_ARG (exp, 0);
+ tree val = CALL_EXPR_ARG (exp, 2);
+ tree len = CALL_EXPR_ARG (exp, 3);
+ rtx res = expand_builtin_memset_args (dest, val, len, target, mode, exp);
+
+ /* Return src bounds with the result. */
+ if (res)
+ {
+ rtx bnd = force_reg (BNDmode,
+ expand_normal (CALL_EXPR_ARG (exp, 1)));
+ res = chkp_join_splitted_slot (res, bnd);
+ }
+ return res;
+ }
+}
+
/* Helper function to do the actual work for expand_builtin_memset. The
arguments to the builtin_memset call DEST, VAL, and LEN are broken out
so that this can also be called without constructing an actual CALL_EXPR.
@@ -3775,7 +3896,8 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
do_libcall:
fndecl = get_callee_fndecl (orig_exp);
fcode = DECL_FUNCTION_CODE (fndecl);
- if (fcode == BUILT_IN_MEMSET)
+ if (fcode == BUILT_IN_MEMSET
+ || fcode == BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP)
fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3,
dest, val, len);
else if (fcode == BUILT_IN_BZERO)
@@ -5848,6 +5970,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
}
}
+ /* expand_builtin_with_bounds is supposed to be used for
+ instrumented builtin calls. */
gcc_assert (!CALL_WITH_BOUNDS_P (exp));
switch (fcode)
@@ -6908,6 +7032,53 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
return expand_call (exp, target, ignore);
}
+/* Similar to expand_builtin but is used for instrumented calls. */
+
+rtx
+expand_builtin_with_bounds (tree exp, rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ machine_mode mode, int ignore)
+{
+ tree fndecl = get_callee_fndecl (exp);
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+
+ gcc_assert (CALL_WITH_BOUNDS_P (exp));
+
+ if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+ return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
+
+ gcc_assert (fcode > BEGIN_CHKP_BUILTINS
+ && fcode < END_CHKP_BUILTINS);
+
+ switch (fcode)
+ {
+ case BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP:
+ target = expand_builtin_memcpy_with_bounds (exp, target);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP:
+ target = expand_builtin_mempcpy_with_bounds (exp, target, mode);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP:
+ target = expand_builtin_memset_with_bounds (exp, target, mode);
+ if (target)
+ return target;
+ break;
+
+ default:
+ break;
+ }
+
+ /* The switch statement above can drop through to cause the function
+ to be called normally. */
+ return expand_call (exp, target, ignore);
+ }
+
/* Determine whether a tree node represents a call to a built-in
function. If the tree T is a call to a built-in function with
the right number of arguments of the appropriate types, return
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 7960b0158db..44bc5dfb2e1 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -69,6 +69,7 @@ extern tree std_canonical_va_list_type (tree);
extern void std_expand_builtin_va_start (tree, rtx);
extern void expand_builtin_trap (void);
extern rtx expand_builtin (tree, rtx, rtx, machine_mode, int);
+extern rtx expand_builtin_with_bounds (tree, rtx, rtx, machine_mode, int);
extern enum built_in_function builtin_mathfn_code (const_tree);
extern tree fold_builtin_expect (location_t, tree, tree, tree);
extern tree fold_fma (location_t, tree, tree, tree, tree);
diff --git a/gcc/expr.c b/gcc/expr.c
index 093f544a993..c7621b0e9c8 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -10462,7 +10462,11 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
if (fndecl && DECL_BUILT_IN (fndecl))
{
gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
- return expand_builtin (exp, target, subtarget, tmode, ignore);
+ if (CALL_WITH_BOUNDS_P (exp))
+ return expand_builtin_with_bounds (exp, target, subtarget,
+ tmode, ignore);
+ else
+ return expand_builtin (exp, target, subtarget, tmode, ignore);
}
}
return expand_call (exp, target, ignore);
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
index 19a989453b6..46b2139758a 100644
--- a/gcc/ipa-chkp.c
+++ b/gcc/ipa-chkp.c
@@ -129,6 +129,16 @@ chkp_build_instrumented_fndecl (tree fndecl)
make own copy. */
DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
+ /* Change builtin function code. */
+ if (DECL_BUILT_IN (new_decl))
+ {
+ gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
+ gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
+ DECL_FUNCTION_CODE (new_decl)
+ = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
+ + BEGIN_CHKP_BUILTINS + 1);
+ }
+
return new_decl;
}
@@ -354,6 +364,33 @@ chkp_add_bounds_params_to_function (tree fndecl)
chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
}
+/* Return an instrumentation clone for builtin function
+ FNDECL. Create one if needed. */
+
+tree
+chkp_maybe_clone_builtin_fndecl (tree fndecl)
+{
+ tree clone;
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+
+ gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && fcode < BEGIN_CHKP_BUILTINS);
+
+ fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
+ clone = builtin_decl_explicit (fcode);
+ if (clone)
+ return clone;
+
+ clone = chkp_build_instrumented_fndecl (fndecl);
+ chkp_add_bounds_params_to_function (clone);
+
+ gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
+
+ set_builtin_decl (fcode, clone, false);
+
+ return clone;
+}
+
/* Return clone created for instrumentation of NODE or NULL. */
cgraph_node *
@@ -364,6 +401,54 @@ chkp_maybe_create_clone (tree fndecl)
gcc_assert (!node->instrumentation_clone);
+ if (DECL_BUILT_IN (fndecl)
+ && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
+ || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
+ return NULL;
+
+ clone = node->instrumented_version;
+
+ /* Some instrumented builtin function calls may be optimized and
+ cgraph nodes may be removed as unreachable. Later optimizations
+ may generate new calls to removed functions and in this case
+ we have to recreate cgraph node. FUNCTION_DECL for instrumented
+ builtin still exists and should be reused in such case. */
+ if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
+ && !clone)
+ {
+ enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
+ tree new_decl;
+
+ fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
+ new_decl = builtin_decl_explicit (fncode);
+
+ /* We've actually already created an instrumented clone once.
+ Restore it. */
+ if (new_decl)
+ {
+ clone = cgraph_node::get (new_decl);
+
+ if (!clone)
+ {
+ gcc_assert (!gimple_has_body_p (fndecl));
+ clone = cgraph_node::get_create (new_decl);
+ clone->externally_visible = node->externally_visible;
+ clone->local = node->local;
+ clone->address_taken = node->address_taken;
+ clone->thunk = node->thunk;
+ clone->alias = node->alias;
+ clone->weakref = node->weakref;
+ clone->cpp_implicit_alias = node->cpp_implicit_alias;
+ clone->orig_decl = fndecl;
+ clone->instrumentation_clone = true;
+ }
+
+ clone->instrumented_version = node;
+ node->instrumented_version = clone;
+ }
+ }
+
if (!clone)
{
tree new_decl = chkp_build_instrumented_fndecl (fndecl);
@@ -408,6 +493,15 @@ chkp_maybe_create_clone (tree fndecl)
actually copies args list from the original decl. */
chkp_add_bounds_params_to_function (new_decl);
+ /* Remember builtin fndecl. */
+ if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
+ && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
+ {
+ gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
+ set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
+ clone->decl, false);
+ }
+
/* Clones have the same comdat group as originals. */
if (node->same_comdat_group
|| DECL_ONE_ONLY (node->decl))
@@ -487,8 +581,9 @@ chkp_versioning (void)
&& (!flag_chkp_instrument_marked_only
|| lookup_attribute ("bnd_instrument",
DECL_ATTRIBUTES (node->decl)))
- /* No builtins instrumentation for now. */
- && DECL_BUILT_IN_CLASS (node->decl) == NOT_BUILT_IN)
+ && (!DECL_BUILT_IN (node->decl)
+ || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
chkp_maybe_create_clone (node->decl);
}
diff --git a/gcc/ipa-chkp.h b/gcc/ipa-chkp.h
index d4ad113893a..b2d03ad194a 100644
--- a/gcc/ipa-chkp.h
+++ b/gcc/ipa-chkp.h
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_IPA_CHKP_H
extern tree chkp_copy_function_type_adding_bounds (tree orig_type);
+extern tree chkp_maybe_clone_builtin_fndecl (tree fndecl);
extern cgraph_node *chkp_maybe_create_clone (tree fndecl);
#endif /* GCC_IPA_CHKP_H */
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index df7d425fe66..0fb78ccf076 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -1586,6 +1586,50 @@ chkp_find_bound_slots (const_tree type, bitmap res)
chkp_find_bound_slots_1 (type, res, 0);
}
+/* Return 1 if call to FNDECL should be instrumented
+ and 0 otherwise. */
+
+static bool
+chkp_instrument_normal_builtin (tree fndecl)
+{
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case BUILT_IN_STRLEN:
+ case BUILT_IN_STRCPY:
+ case BUILT_IN_STRNCPY:
+ case BUILT_IN_STPCPY:
+ case BUILT_IN_STPNCPY:
+ case BUILT_IN_STRCAT:
+ case BUILT_IN_STRNCAT:
+ case BUILT_IN_MEMCPY:
+ case BUILT_IN_MEMPCPY:
+ case BUILT_IN_MEMSET:
+ case BUILT_IN_MEMMOVE:
+ case BUILT_IN_BZERO:
+ case BUILT_IN_STRCMP:
+ case BUILT_IN_STRNCMP:
+ case BUILT_IN_BCMP:
+ case BUILT_IN_MEMCMP:
+ case BUILT_IN_MEMCPY_CHK:
+ case BUILT_IN_MEMPCPY_CHK:
+ case BUILT_IN_MEMMOVE_CHK:
+ case BUILT_IN_MEMSET_CHK:
+ case BUILT_IN_STRCPY_CHK:
+ case BUILT_IN_STRNCPY_CHK:
+ case BUILT_IN_STPCPY_CHK:
+ case BUILT_IN_STPNCPY_CHK:
+ case BUILT_IN_STRCAT_CHK:
+ case BUILT_IN_STRNCAT_CHK:
+ case BUILT_IN_MALLOC:
+ case BUILT_IN_CALLOC:
+ case BUILT_IN_REALLOC:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
/* Add bound arguments to call statement pointed by GSI.
Also performs a replacement of user checker builtins calls
with internal ones. */
@@ -1619,7 +1663,7 @@ chkp_add_bounds_to_call_stmt (gimple_stmt_iterator *gsi)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_OBJECT_SIZE)
return;
- /* Donothing for calls to legacy functions. */
+ /* Do nothing for calls to legacy functions. */
if (fndecl
&& lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl)))
return;
@@ -1686,11 +1730,20 @@ chkp_add_bounds_to_call_stmt (gimple_stmt_iterator *gsi)
if (!flag_chkp_instrument_calls)
return;
- /* Avoid instrumented builtin functions for now. Due to IPA
- it also means we have to avoid instrumentation of indirect
- calls. */
- if (fndecl && DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN)
- return;
+ /* We instrument only some subset of builtins. We also instrument
+ builtin calls to be inlined. */
+ if (fndecl
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && !chkp_instrument_normal_builtin (fndecl))
+ {
+ if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)))
+ return;
+
+ struct cgraph_node *clone = chkp_maybe_create_clone (fndecl);
+ if (!clone
+ || !gimple_has_body_p (clone->decl))
+ return;
+ }
/* If function decl is available then use it for
formal arguments list. Otherwise use function type. */
@@ -1764,14 +1817,6 @@ chkp_add_bounds_to_call_stmt (gimple_stmt_iterator *gsi)
}
new_args.release ();
- /* If we call built-in function and pass no bounds then
- we do not need to change anything. */
- if (new_call == call
- && fndecl
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
- return;
-
/* For direct calls fndecl is replaced with instrumented version. */
if (fndecl)
{
@@ -3905,15 +3950,21 @@ chkp_replace_function_pointer (tree *op, int *walk_subtrees,
{
if (TREE_CODE (*op) == FUNCTION_DECL
&& !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (*op))
- /* Do not replace builtins for now. */
- && DECL_BUILT_IN_CLASS (*op) == NOT_BUILT_IN)
+ && (DECL_BUILT_IN_CLASS (*op) == NOT_BUILT_IN
+ /* For builtins we replace pointers only for selected
+ function and functions having definitions. */
+ || (DECL_BUILT_IN_CLASS (*op) == BUILT_IN_NORMAL
+ && (chkp_instrument_normal_builtin (*op)
+ || gimple_has_body_p (*op)))))
{
struct cgraph_node *node = cgraph_node::get_create (*op);
+ struct cgraph_node *clone = NULL;
if (!node->instrumentation_clone)
- chkp_maybe_create_clone (*op);
+ clone = chkp_maybe_create_clone (*op);
- *op = node->instrumented_version->decl;
+ if (clone)
+ *op = clone->decl;
*walk_subtrees = 0;
}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 58bdffff6ad..fe3fbb4e389 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -168,6 +168,14 @@ enum built_in_class {
enum built_in_function {
#include "builtins.def"
+ BEGIN_CHKP_BUILTINS,
+
+#undef DEF_BUILTIN
+#define DEF_BUILTIN(ENUM, N, C, T, LT, B, F, NA, AT, IM, COND) ENUM##_CHKP,
+#include "builtins.def"
+
+ END_CHKP_BUILTINS,
+
/* Complex division routines in libgcc. These are done via builtins
because emit_library_call_value can't handle complex values. */
BUILT_IN_COMPLEX_MUL_MIN,
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index a11a46e168d..fba60483f5e 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
#include "streamer-hooks.h"
#include "lto-streamer.h"
#include "builtins.h"
+#include "ipa-chkp.h"
/* Read a STRING_CST from the string table in DATA_IN using input
block IB. */
@@ -1113,6 +1114,14 @@ streamer_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
if (fcode >= END_BUILTINS)
fatal_error ("machine independent builtin code out of range");
result = builtin_decl_explicit (fcode);
+ if (!result
+ && fcode > BEGIN_CHKP_BUILTINS
+ && fcode < END_CHKP_BUILTINS)
+ {
+ fcode = (enum built_in_function) (fcode - BEGIN_CHKP_BUILTINS - 1);
+ result = builtin_decl_explicit (fcode);
+ result = chkp_maybe_clone_builtin_fndecl (result);
+ }
gcc_assert (result);
}
else if (fclass == BUILT_IN_MD)