tree-core.h (built_in_class): Add builtin codes to be used by Pointer Bounds Checker...
authorIlya Enkovich <ilya.enkovich@intel.com>
Mon, 17 Nov 2014 13:45:55 +0000 (13:45 +0000)
committerIlya Enkovich <ienkovich@gcc.gnu.org>
Mon, 17 Nov 2014 13:45:55 +0000 (13:45 +0000)
* 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

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.h
gcc/expr.c
gcc/ipa-chkp.c
gcc/ipa-chkp.h
gcc/tree-chkp.c
gcc/tree-core.h
gcc/tree-streamer-in.c

index 660838cde7827a5abe42b95ca3bcc0690343bb06..123166c95629c6ce32bfe9f6964bca6381aee20b 100644 (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)
index 311c0e382797807fd04cd78a86570a3dfde74fc2..7ec2d5f8e8c61be692b5489825834a8ec3c0510c 100644 (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;
-
-      /* 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
index 7960b0158db918c975d11e7924509c920f512cf2..44bc5dfb2e1260f20a7f855287f9b65c051b8884 100644 (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);
index 093f544a993ef9c0f79a8f5d4675bfe6c283c706..c7621b0e9c851dca270b8b055a5219006dd47aae 100644 (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);
index 19a989453b699e2667936f86db4972f60060682c..46b2139758aaf2e918bfe73b484856a942f49c2c 100644 (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);
     }
 
index d4ad113893a5564dd064df5a0764f4ff3ef091f0..b2d03ad194ac037149a2baa7afc9bf613fa082c8 100644 (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 */
index df7d425fe66bdb0cf70458158fd061256c39fc4f..0fb78ccf0765cf7e39d4e7ee5b41a0430e10ee7b 100644 (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;
     }
 
index 58bdffff6ad18e77edac5e5d58f7ddcad5ffa8b6..fe3fbb4e38996a600f7e8aa70017cb5d4999846a 100644 (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,
index a11a46e168d93f12a87cb80f55f864cddcc6e8e2..fba60483f5e7313a76c31746702ec677a5379b8b 100644 (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)