tree-core.h (built_in_class): Add builtin codes to be used by Pointer Bounds Checker for instrumented builtin...

* 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.

From-SVN: r217655
This commit is contained in:
Ilya Enkovich 2014-11-17 13:45:55 +00:00 committed by Ilya Enkovich
parent 5134529b25
commit edcf72f3c9
9 changed files with 457 additions and 89 deletions

View File

@ -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)

View File

@ -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;
return expand_builtin_memcpy_args (dest, src, len, target, exp);
}
}
/* If DEST is not a pointer type, call the normal function. */
if (dest_align == 0)
return NULL_RTX;
/* 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). */
/* If either SRC is not a pointer type, don't do this
operation in-line. */
if (src_align == 0)
return NULL_RTX;
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 (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))
/* Return src bounds with the result. */
if (res)
{
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;
rtx bnd = force_reg (BNDmode,
expand_normal (CALL_EXPR_ARG (exp, 1)));
res = chkp_join_splitted_slot (res, bnd);
}
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;
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

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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,

View File

@ -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)