LCOV - code coverage report
Current view: top level - gcc - sancov.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 154 160 96.2 %
Date: 2020-04-04 11:58:09 Functions: 10 11 90.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* Code coverage instrumentation for fuzzing.
       2                 :            :    Copyright (C) 2015-2020 Free Software Foundation, Inc.
       3                 :            :    Contributed by Dmitry Vyukov <dvyukov@google.com> and
       4                 :            :    Wish Wu <wishwu007@gmail.com>
       5                 :            : 
       6                 :            : This file is part of GCC.
       7                 :            : 
       8                 :            : GCC is free software; you can redistribute it and/or modify it under
       9                 :            : the terms of the GNU General Public License as published by the Free
      10                 :            : Software Foundation; either version 3, or (at your option) any later
      11                 :            : version.
      12                 :            : 
      13                 :            : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      14                 :            : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15                 :            : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16                 :            : for more details.
      17                 :            : 
      18                 :            : You should have received a copy of the GNU General Public License
      19                 :            : along with GCC; see the file COPYING3.  If not see
      20                 :            : <http://www.gnu.org/licenses/>.  */
      21                 :            : 
      22                 :            : #include "config.h"
      23                 :            : #include "system.h"
      24                 :            : #include "coretypes.h"
      25                 :            : #include "backend.h"
      26                 :            : #include "tree.h"
      27                 :            : #include "gimple.h"
      28                 :            : #include "basic-block.h"
      29                 :            : #include "options.h"
      30                 :            : #include "flags.h"
      31                 :            : #include "memmodel.h"
      32                 :            : #include "tm_p.h"
      33                 :            : #include "stmt.h"
      34                 :            : #include "gimple-iterator.h"
      35                 :            : #include "gimple-builder.h"
      36                 :            : #include "tree-cfg.h"
      37                 :            : #include "tree-pass.h"
      38                 :            : #include "tree-iterator.h"
      39                 :            : #include "fold-const.h"
      40                 :            : #include "stringpool.h"
      41                 :            : #include "attribs.h"
      42                 :            : #include "output.h"
      43                 :            : #include "cgraph.h"
      44                 :            : #include "asan.h"
      45                 :            : 
      46                 :            : namespace {
      47                 :            : 
      48                 :            : /* Instrument one comparison operation, which compares lhs and rhs.
      49                 :            :    Call the instrumentation function with the comparison operand.
      50                 :            :    For integral comparisons if exactly one of the comparison operands is
      51                 :            :    constant, call __sanitizer_cov_trace_const_cmp* instead of
      52                 :            :    __sanitizer_cov_trace_cmp*.  */
      53                 :            : 
      54                 :            : static void
      55                 :         80 : instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
      56                 :            : {
      57                 :         80 :   tree type = TREE_TYPE (lhs);
      58                 :         80 :   enum built_in_function fncode = END_BUILTINS;
      59                 :         80 :   tree to_type = NULL_TREE;
      60                 :         80 :   bool c = false;
      61                 :            : 
      62                 :         80 :   if (INTEGRAL_TYPE_P (type))
      63                 :            :     {
      64                 :         64 :       c = (is_gimple_min_invariant (lhs)
      65                 :         64 :            ^ is_gimple_min_invariant (rhs));
      66                 :         64 :       switch (int_size_in_bytes (type))
      67                 :            :         {
      68                 :          8 :         case 1:
      69                 :          8 :           fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
      70                 :            :                      : BUILT_IN_SANITIZER_COV_TRACE_CMP1;
      71                 :          8 :           to_type = unsigned_char_type_node;
      72                 :          8 :           break;
      73                 :          8 :         case 2:
      74                 :          8 :           fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
      75                 :            :                      : BUILT_IN_SANITIZER_COV_TRACE_CMP2;
      76                 :          8 :           to_type = uint16_type_node;
      77                 :          8 :           break;
      78                 :         32 :         case 4:
      79                 :         32 :           fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
      80                 :            :                      : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
      81                 :         32 :           to_type = uint32_type_node;
      82                 :         32 :           break;
      83                 :         16 :         default:
      84                 :         16 :           fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
      85                 :            :                      : BUILT_IN_SANITIZER_COV_TRACE_CMP8;
      86                 :         16 :           to_type = uint64_type_node;
      87                 :         16 :           break;
      88                 :            :         }
      89                 :            :     }
      90                 :         16 :   else if (SCALAR_FLOAT_TYPE_P (type))
      91                 :            :     {
      92                 :         16 :       if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
      93                 :            :         {
      94                 :          8 :           fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
      95                 :          8 :           to_type = float_type_node;
      96                 :            :         }
      97                 :          8 :       else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
      98                 :            :         {
      99                 :          8 :           fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
     100                 :          8 :           to_type = double_type_node;
     101                 :            :         }
     102                 :            :     }
     103                 :            : 
     104                 :         80 :   if (to_type != NULL_TREE)
     105                 :            :     {
     106                 :         80 :       gimple_seq seq = NULL;
     107                 :            : 
     108                 :         80 :       if (!useless_type_conversion_p (to_type, type))
     109                 :            :         {
     110                 :         64 :           if (TREE_CODE (lhs) == INTEGER_CST)
     111                 :          0 :             lhs = fold_convert (to_type, lhs);
     112                 :            :           else
     113                 :            :             {
     114                 :         64 :               gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
     115                 :        128 :               lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
     116                 :            :             }
     117                 :            : 
     118                 :         64 :           if (TREE_CODE (rhs) == INTEGER_CST)
     119                 :         56 :             rhs = fold_convert (to_type, rhs);
     120                 :            :           else
     121                 :            :             {
     122                 :          8 :               gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
     123                 :         16 :               rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
     124                 :            :             }
     125                 :            :         }
     126                 :            : 
     127                 :         80 :       if (c && !is_gimple_min_invariant (lhs))
     128                 :         80 :         std::swap (lhs, rhs);
     129                 :            : 
     130                 :         80 :       tree fndecl = builtin_decl_implicit (fncode);
     131                 :         80 :       gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
     132                 :         80 :       gimple_seq_add_stmt (&seq, gcall);
     133                 :            : 
     134                 :         80 :       gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
     135                 :         80 :       gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
     136                 :            :     }
     137                 :         80 : }
     138                 :            : 
     139                 :            : /* Instrument switch statement.  Call __sanitizer_cov_trace_switch with
     140                 :            :    the value of the index and array that contains number of case values,
     141                 :            :    the bitsize of the index and the case values converted to uint64_t.  */
     142                 :            : 
     143                 :            : static void
     144                 :         16 : instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
     145                 :            : {
     146                 :         16 :   gswitch *switch_stmt = as_a<gswitch *> (stmt);
     147                 :         16 :   tree index = gimple_switch_index (switch_stmt);
     148                 :         16 :   HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
     149                 :         16 :   if (size_in_bytes == -1 || size_in_bytes > 8)
     150                 :          0 :     return;
     151                 :            : 
     152                 :         16 :   location_t loc = gimple_location (stmt);
     153                 :         16 :   unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
     154                 :        128 :   for (i = 1; i < n; ++i)
     155                 :            :     {
     156                 :        112 :       tree label = gimple_switch_label (switch_stmt, i);
     157                 :            : 
     158                 :        112 :       tree low_case = CASE_LOW (label);
     159                 :        112 :       if (low_case != NULL_TREE)
     160                 :        112 :         num++;
     161                 :            : 
     162                 :        112 :       tree high_case = CASE_HIGH (label);
     163                 :        112 :       if (high_case != NULL_TREE)
     164                 :          8 :         num++;
     165                 :            :     }
     166                 :            : 
     167                 :         16 :   tree case_array_type
     168                 :         16 :    = build_array_type (build_type_variant (uint64_type_node, 1, 0),
     169                 :         16 :                        build_index_type (size_int (num + 2 - 1)));
     170                 :            : 
     171                 :         16 :   char name[64];
     172                 :         16 :   static size_t case_array_count = 0;
     173                 :         16 :   ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
     174                 :         16 :   tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
     175                 :            :                                     case_array_type);
     176                 :         16 :   TREE_STATIC (case_array_var) = 1;
     177                 :         16 :   TREE_PUBLIC (case_array_var) = 0;
     178                 :         16 :   TREE_CONSTANT (case_array_var) = 1;
     179                 :         16 :   TREE_READONLY (case_array_var) = 1;
     180                 :         16 :   DECL_EXTERNAL (case_array_var) = 0;
     181                 :         16 :   DECL_ARTIFICIAL (case_array_var) = 1;
     182                 :         16 :   DECL_IGNORED_P (case_array_var) = 1;
     183                 :            : 
     184                 :         16 :   vec <constructor_elt, va_gc> *v = NULL;
     185                 :         16 :   vec_alloc (v, num + 2);
     186                 :         16 :   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
     187                 :            :                           build_int_cst (uint64_type_node, num));
     188                 :         16 :   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
     189                 :            :                           build_int_cst (uint64_type_node,
     190                 :            :                                          size_in_bytes * BITS_PER_UNIT));
     191                 :        128 :   for (i = 1; i < n; ++i)
     192                 :            :     {
     193                 :        112 :       tree label = gimple_switch_label (switch_stmt, i);
     194                 :            : 
     195                 :        112 :       tree low_case = CASE_LOW (label);
     196                 :        112 :       if (low_case != NULL_TREE)
     197                 :        112 :         CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
     198                 :            :                                 fold_convert (uint64_type_node, low_case));
     199                 :            : 
     200                 :        112 :       tree high_case = CASE_HIGH (label);
     201                 :        112 :       if (high_case != NULL_TREE)
     202                 :          8 :         CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
     203                 :            :                                 fold_convert (uint64_type_node, high_case));
     204                 :            :     }
     205                 :         16 :   tree ctor = build_constructor (case_array_type, v);
     206                 :         16 :   TREE_STATIC (ctor) = 1;
     207                 :         16 :   TREE_PUBLIC (ctor) = 0;
     208                 :         16 :   TREE_CONSTANT (ctor) = 1;
     209                 :         16 :   TREE_READONLY (ctor) = 1;
     210                 :         16 :   DECL_INITIAL (case_array_var) = ctor;
     211                 :         16 :   varpool_node::finalize_decl (case_array_var);
     212                 :         16 :   add_local_decl (fun, case_array_var);
     213                 :            : 
     214                 :         16 :   gimple_seq seq = NULL;
     215                 :            : 
     216                 :         16 :   if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
     217                 :            :     {
     218                 :         16 :       if (TREE_CODE (index) == INTEGER_CST)
     219                 :          0 :         index = fold_convert (uint64_type_node, index);
     220                 :            :       else
     221                 :            :         {
     222                 :         16 :           gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
     223                 :         32 :           index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
     224                 :            :         }
     225                 :            :     }
     226                 :            : 
     227                 :         16 :   tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
     228                 :         16 :   gimple *gcall = gimple_build_call (fndecl, 2, index,
     229                 :            :                                      build_fold_addr_expr (case_array_var));
     230                 :         16 :   gimple_seq_add_stmt (&seq, gcall);
     231                 :            : 
     232                 :         16 :   gimple_seq_set_location (seq, loc);
     233                 :         16 :   gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
     234                 :            : }
     235                 :            : 
     236                 :            : unsigned
     237                 :         86 : sancov_pass (function *fun)
     238                 :            : {
     239                 :         86 :   initialize_sanitizer_builtins ();
     240                 :            : 
     241                 :            :   /* Insert callback into beginning of every BB. */
     242                 :         86 :   if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
     243                 :            :     {
     244                 :         62 :       basic_block bb;
     245                 :         62 :       tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
     246                 :        268 :       FOR_EACH_BB_FN (bb, fun)
     247                 :            :         {
     248                 :        206 :           gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
     249                 :        206 :           if (gsi_end_p (gsi))
     250                 :         70 :             continue;
     251                 :        136 :           gimple *stmt = gsi_stmt (gsi);
     252                 :        136 :           gimple *gcall = gimple_build_call (fndecl, 0);
     253                 :        136 :           gimple_set_location (gcall, gimple_location (stmt));
     254                 :        136 :           gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
     255                 :            :         }
     256                 :            :     }
     257                 :            : 
     258                 :            :   /* Insert callback into every comparison related operation.  */
     259                 :         86 :   if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
     260                 :            :     {
     261                 :         24 :       basic_block bb;
     262                 :        428 :       FOR_EACH_BB_FN (bb, fun)
     263                 :            :         {
     264                 :        404 :           gimple_stmt_iterator gsi;
     265                 :       1967 :           for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     266                 :            :             {
     267                 :       1159 :               gimple *stmt = gsi_stmt (gsi);
     268                 :       1159 :               enum tree_code rhs_code;
     269                 :       1159 :               switch (gimple_code (stmt))
     270                 :            :                 {
     271                 :        740 :                 case GIMPLE_ASSIGN:
     272                 :        740 :                   rhs_code = gimple_assign_rhs_code (stmt);
     273                 :        740 :                   if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
     274                 :          8 :                     instrument_comparison (&gsi,
     275                 :            :                                            gimple_assign_rhs1 (stmt),
     276                 :            :                                            gimple_assign_rhs2 (stmt));
     277                 :        732 :                   else if (rhs_code == COND_EXPR
     278                 :        732 :                            && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
     279                 :            :                     {
     280                 :          0 :                       tree cond = gimple_assign_rhs1 (stmt);
     281                 :          0 :                       instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
     282                 :          0 :                                              TREE_OPERAND (cond, 1));
     283                 :            :                     }
     284                 :            :                   break;
     285                 :         72 :                 case GIMPLE_COND:
     286                 :         72 :                   instrument_comparison (&gsi,
     287                 :            :                                          gimple_cond_lhs (stmt),
     288                 :            :                                          gimple_cond_rhs (stmt));
     289                 :         72 :                   break;
     290                 :            : 
     291                 :         16 :                 case GIMPLE_SWITCH:
     292                 :         16 :                   instrument_switch (&gsi, stmt, fun);
     293                 :         16 :                   break;
     294                 :            : 
     295                 :            :                 default:
     296                 :            :                   break;
     297                 :            :                 }
     298                 :            :             }
     299                 :            :         }
     300                 :            :     }
     301                 :         86 :   return 0;
     302                 :            : }
     303                 :            : 
     304                 :            : template <bool O0> class pass_sancov : public gimple_opt_pass
     305                 :            : {
     306                 :            : public:
     307                 :    1204640 :   pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
     308                 :            : 
     309                 :            :   static const pass_data data;
     310                 :            :   opt_pass *
     311                 :     200773 :   clone ()
     312                 :            :   {
     313                 :     200773 :     return new pass_sancov<O0> (m_ctxt);
     314                 :            :   }
     315                 :            :   virtual bool
     316                 :    1633250 :   gate (function *)
     317                 :            :   {
     318                 :    1633250 :     return flag_sanitize_coverage && (!O0 || !optimize);
     319                 :            :   }
     320                 :            :   virtual unsigned int
     321                 :         86 :   execute (function *fun)
     322                 :            :   {
     323                 :         86 :     return sancov_pass (fun);
     324                 :            :   }
     325                 :            : }; // class pass_sancov
     326                 :            : 
     327                 :            : template <bool O0>
     328                 :            : const pass_data pass_sancov<O0>::data = {
     329                 :            :   GIMPLE_PASS,                 /* type */
     330                 :            :   O0 ? "sancov_O0" : "sancov", /* name */
     331                 :            :   OPTGROUP_NONE,               /* optinfo_flags */
     332                 :            :   TV_NONE,                     /* tv_id */
     333                 :            :   (PROP_cfg),                  /* properties_required */
     334                 :            :   0,                           /* properties_provided */
     335                 :            :   0,                           /* properties_destroyed */
     336                 :            :   0,                           /* todo_flags_start */
     337                 :            :   TODO_update_ssa,           /* todo_flags_finish */
     338                 :            : };
     339                 :            : 
     340                 :            : } // anon namespace
     341                 :            : 
     342                 :            : gimple_opt_pass *
     343                 :     200773 : make_pass_sancov (gcc::context *ctxt)
     344                 :            : {
     345                 :     200773 :   return new pass_sancov<false> (ctxt);
     346                 :            : }
     347                 :            : 
     348                 :            : gimple_opt_pass *
     349                 :     200773 : make_pass_sancov_O0 (gcc::context *ctxt)
     350                 :            : {
     351                 :     200773 :   return new pass_sancov<true> (ctxt);
     352                 :            : }

Generated by: LCOV version 1.0

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto --enable-host-shared. GCC test suite is run with the built compiler.