LCOV - code coverage report
Current view: top level - gcc - sancov.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 96.2 % 159 153
Test Date: 2024-04-13 14:00:49 Functions: 90.9 % 11 10
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-2024 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                 :         112 : instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
      56                 :             : {
      57                 :         112 :   tree type = TREE_TYPE (lhs);
      58                 :         112 :   enum built_in_function fncode = END_BUILTINS;
      59                 :         112 :   tree to_type = NULL_TREE;
      60                 :         112 :   bool c = false;
      61                 :             : 
      62                 :         112 :   if (INTEGRAL_TYPE_P (type))
      63                 :             :     {
      64                 :          96 :       c = (is_gimple_min_invariant (lhs)
      65                 :          96 :            ^ is_gimple_min_invariant (rhs));
      66                 :          96 :       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                 :          64 :         case 4:
      79                 :          64 :           fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
      80                 :             :                      : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
      81                 :          64 :           to_type = uint32_type_node;
      82                 :          64 :           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                 :         112 :   if (to_type != NULL_TREE)
     105                 :             :     {
     106                 :         112 :       gimple_seq seq = NULL;
     107                 :             : 
     108                 :         112 :       if (!useless_type_conversion_p (to_type, type))
     109                 :             :         {
     110                 :          96 :           if (TREE_CODE (lhs) == INTEGER_CST)
     111                 :           0 :             lhs = fold_convert (to_type, lhs);
     112                 :             :           else
     113                 :             :             {
     114                 :          96 :               gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
     115                 :         192 :               lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
     116                 :             :             }
     117                 :             : 
     118                 :          96 :           if (TREE_CODE (rhs) == INTEGER_CST)
     119                 :          56 :             rhs = fold_convert (to_type, rhs);
     120                 :             :           else
     121                 :             :             {
     122                 :          40 :               gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
     123                 :          80 :               rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
     124                 :             :             }
     125                 :             :         }
     126                 :             : 
     127                 :         112 :       if (c && !is_gimple_min_invariant (lhs))
     128                 :             :         std::swap (lhs, rhs);
     129                 :             : 
     130                 :         112 :       tree fndecl = builtin_decl_implicit (fncode);
     131                 :         112 :       gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
     132                 :         112 :       gimple_seq_add_stmt (&seq, gcall);
     133                 :             : 
     134                 :         112 :       gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
     135                 :         112 :       gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
     136                 :             :     }
     137                 :         112 : }
     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                 :         147 : sancov_pass (function *fun)
     238                 :             : {
     239                 :         147 :   initialize_sanitizer_builtins ();
     240                 :             : 
     241                 :             :   /* Insert callback into beginning of every BB. */
     242                 :         147 :   if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
     243                 :             :     {
     244                 :         107 :       basic_block bb;
     245                 :         107 :       tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
     246                 :         411 :       FOR_EACH_BB_FN (bb, fun)
     247                 :             :         {
     248                 :         304 :           gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
     249                 :         304 :           if (gsi_end_p (gsi))
     250                 :          82 :             continue;
     251                 :         222 :           gimple *stmt = gsi_stmt (gsi);
     252                 :         222 :           gimple *gcall = gimple_build_call (fndecl, 0);
     253                 :         222 :           gimple_set_location (gcall, gimple_location (stmt));
     254                 :         222 :           gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
     255                 :             :         }
     256                 :             :     }
     257                 :             : 
     258                 :             :   /* Insert callback into every comparison related operation.  */
     259                 :         147 :   if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
     260                 :             :     {
     261                 :          56 :       basic_block bb;
     262                 :         506 :       FOR_EACH_BB_FN (bb, fun)
     263                 :             :         {
     264                 :         450 :           gimple_stmt_iterator gsi;
     265                 :        2192 :           for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     266                 :             :             {
     267                 :        1292 :               gimple *stmt = gsi_stmt (gsi);
     268                 :        1292 :               enum tree_code rhs_code;
     269                 :        1292 :               switch (gimple_code (stmt))
     270                 :             :                 {
     271                 :         804 :                 case GIMPLE_ASSIGN:
     272                 :         804 :                   rhs_code = gimple_assign_rhs_code (stmt);
     273                 :         804 :                   if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
     274                 :          40 :                     instrument_comparison (&gsi,
     275                 :             :                                            gimple_assign_rhs1 (stmt),
     276                 :             :                                            gimple_assign_rhs2 (stmt));
     277                 :         764 :                   else if (rhs_code == COND_EXPR
     278                 :         764 :                            && 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                 :         147 :   return 0;
     302                 :             : }
     303                 :             : 
     304                 :             : template <bool O0> class pass_sancov : public gimple_opt_pass
     305                 :             : {
     306                 :             : public:
     307                 :     1682730 :   pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
     308                 :             : 
     309                 :             :   static const pass_data data;
     310                 :             :   opt_pass *
     311                 :      280455 :   clone () final override
     312                 :             :   {
     313                 :      280455 :     return new pass_sancov<O0> (m_ctxt);
     314                 :             :   }
     315                 :             :   bool
     316                 :     2367737 :   gate (function *fun) final override
     317                 :             :   {
     318                 :     2367737 :     return sanitize_coverage_p (fun->decl) && (!O0 || !optimize);
     319                 :             :   }
     320                 :             :   unsigned int
     321                 :         147 :   execute (function *fun) final override
     322                 :             :   {
     323                 :         147 :     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                 :      280455 : make_pass_sancov (gcc::context *ctxt)
     344                 :             : {
     345                 :      280455 :   return new pass_sancov<false> (ctxt);
     346                 :             : }
     347                 :             : 
     348                 :             : gimple_opt_pass *
     349                 :      280455 : make_pass_sancov_O0 (gcc::context *ctxt)
     350                 :             : {
     351                 :      280455 :   return new pass_sancov<true> (ctxt);
     352                 :             : }
        

Generated by: LCOV version 2.1-beta

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,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.