1 /* Code coverage instrumentation for fuzzing.
2    Copyright (C) 2015-2021 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
instrument_comparison(gimple_stmt_iterator * gsi,tree lhs,tree rhs)55 instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
56 {
57   tree type = TREE_TYPE (lhs);
58   enum built_in_function fncode = END_BUILTINS;
59   tree to_type = NULL_TREE;
60   bool c = false;
61 
62   if (INTEGRAL_TYPE_P (type))
63     {
64       c = (is_gimple_min_invariant (lhs)
65 	   ^ is_gimple_min_invariant (rhs));
66       switch (int_size_in_bytes (type))
67 	{
68 	case 1:
69       	  fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
70 		     : BUILT_IN_SANITIZER_COV_TRACE_CMP1;
71 	  to_type = unsigned_char_type_node;
72 	  break;
73 	case 2:
74       	  fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
75 		     : BUILT_IN_SANITIZER_COV_TRACE_CMP2;
76 	  to_type = uint16_type_node;
77 	  break;
78 	case 4:
79       	  fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
80 		     : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
81 	  to_type = uint32_type_node;
82 	  break;
83 	default:
84       	  fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
85 		     : BUILT_IN_SANITIZER_COV_TRACE_CMP8;
86 	  to_type = uint64_type_node;
87 	  break;
88 	}
89     }
90   else if (SCALAR_FLOAT_TYPE_P (type))
91     {
92       if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
93 	{
94       	  fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
95 	  to_type = float_type_node;
96 	}
97       else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
98 	{
99       	  fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
100 	  to_type = double_type_node;
101 	}
102     }
103 
104   if (to_type != NULL_TREE)
105     {
106       gimple_seq seq = NULL;
107 
108       if (!useless_type_conversion_p (to_type, type))
109 	{
110 	  if (TREE_CODE (lhs) == INTEGER_CST)
111 	    lhs = fold_convert (to_type, lhs);
112 	  else
113 	    {
114 	      gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
115 	      lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
116 	    }
117 
118 	  if (TREE_CODE (rhs) == INTEGER_CST)
119 	    rhs = fold_convert (to_type, rhs);
120 	  else
121 	    {
122 	      gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
123 	      rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
124 	    }
125 	}
126 
127       if (c && !is_gimple_min_invariant (lhs))
128 	std::swap (lhs, rhs);
129 
130       tree fndecl = builtin_decl_implicit (fncode);
131       gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
132       gimple_seq_add_stmt (&seq, gcall);
133 
134       gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
135       gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
136     }
137 }
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
instrument_switch(gimple_stmt_iterator * gsi,gimple * stmt,function * fun)144 instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
145 {
146   gswitch *switch_stmt = as_a<gswitch *> (stmt);
147   tree index = gimple_switch_index (switch_stmt);
148   HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
149   if (size_in_bytes == -1 || size_in_bytes > 8)
150     return;
151 
152   location_t loc = gimple_location (stmt);
153   unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
154   for (i = 1; i < n; ++i)
155     {
156       tree label = gimple_switch_label (switch_stmt, i);
157 
158       tree low_case = CASE_LOW (label);
159       if (low_case != NULL_TREE)
160 	num++;
161 
162       tree high_case = CASE_HIGH (label);
163       if (high_case != NULL_TREE)
164 	num++;
165     }
166 
167   tree case_array_type
168    = build_array_type (build_type_variant (uint64_type_node, 1, 0),
169 		       build_index_type (size_int (num + 2 - 1)));
170 
171   char name[64];
172   static size_t case_array_count = 0;
173   ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
174   tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
175 				    case_array_type);
176   TREE_STATIC (case_array_var) = 1;
177   TREE_PUBLIC (case_array_var) = 0;
178   TREE_CONSTANT (case_array_var) = 1;
179   TREE_READONLY (case_array_var) = 1;
180   DECL_EXTERNAL (case_array_var) = 0;
181   DECL_ARTIFICIAL (case_array_var) = 1;
182   DECL_IGNORED_P (case_array_var) = 1;
183 
184   vec <constructor_elt, va_gc> *v = NULL;
185   vec_alloc (v, num + 2);
186   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
187 			  build_int_cst (uint64_type_node, num));
188   CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
189 			  build_int_cst (uint64_type_node,
190 					 size_in_bytes * BITS_PER_UNIT));
191   for (i = 1; i < n; ++i)
192     {
193       tree label = gimple_switch_label (switch_stmt, i);
194 
195       tree low_case = CASE_LOW (label);
196       if (low_case != NULL_TREE)
197 	CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
198 				fold_convert (uint64_type_node, low_case));
199 
200       tree high_case = CASE_HIGH (label);
201       if (high_case != NULL_TREE)
202 	CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
203 				fold_convert (uint64_type_node, high_case));
204     }
205   tree ctor = build_constructor (case_array_type, v);
206   TREE_STATIC (ctor) = 1;
207   TREE_PUBLIC (ctor) = 0;
208   TREE_CONSTANT (ctor) = 1;
209   TREE_READONLY (ctor) = 1;
210   DECL_INITIAL (case_array_var) = ctor;
211   varpool_node::finalize_decl (case_array_var);
212   add_local_decl (fun, case_array_var);
213 
214   gimple_seq seq = NULL;
215 
216   if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
217     {
218       if (TREE_CODE (index) == INTEGER_CST)
219 	index = fold_convert (uint64_type_node, index);
220       else
221 	{
222 	  gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
223 	  index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
224 	}
225     }
226 
227   tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
228   gimple *gcall = gimple_build_call (fndecl, 2, index,
229 				     build_fold_addr_expr (case_array_var));
230   gimple_seq_add_stmt (&seq, gcall);
231 
232   gimple_seq_set_location (seq, loc);
233   gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
234 }
235 
236 unsigned
sancov_pass(function * fun)237 sancov_pass (function *fun)
238 {
239   initialize_sanitizer_builtins ();
240 
241   /* Insert callback into beginning of every BB. */
242   if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
243     {
244       basic_block bb;
245       tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
246       FOR_EACH_BB_FN (bb, fun)
247 	{
248 	  gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
249 	  if (gsi_end_p (gsi))
250 	    continue;
251 	  gimple *stmt = gsi_stmt (gsi);
252 	  gimple *gcall = gimple_build_call (fndecl, 0);
253 	  gimple_set_location (gcall, gimple_location (stmt));
254 	  gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
255 	}
256     }
257 
258   /* Insert callback into every comparison related operation.  */
259   if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
260     {
261       basic_block bb;
262       FOR_EACH_BB_FN (bb, fun)
263 	{
264 	  gimple_stmt_iterator gsi;
265 	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
266 	    {
267 	      gimple *stmt = gsi_stmt (gsi);
268 	      enum tree_code rhs_code;
269 	      switch (gimple_code (stmt))
270 		{
271 		case GIMPLE_ASSIGN:
272 		  rhs_code = gimple_assign_rhs_code (stmt);
273 		  if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
274 		    instrument_comparison (&gsi,
275 					   gimple_assign_rhs1 (stmt),
276 					   gimple_assign_rhs2 (stmt));
277 		  else if (rhs_code == COND_EXPR
278 			   && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
279 		    {
280 		      tree cond = gimple_assign_rhs1 (stmt);
281 		      instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
282 					     TREE_OPERAND (cond, 1));
283 		    }
284 		  break;
285 		case GIMPLE_COND:
286 		  instrument_comparison (&gsi,
287 					 gimple_cond_lhs (stmt),
288 					 gimple_cond_rhs (stmt));
289 		  break;
290 
291 		case GIMPLE_SWITCH:
292 		  instrument_switch (&gsi, stmt, fun);
293 		  break;
294 
295 		default:
296 		  break;
297 		}
298 	    }
299 	}
300     }
301   return 0;
302 }
303 
304 template <bool O0> class pass_sancov : public gimple_opt_pass
305 {
306 public:
pass_sancov(gcc::context * ctxt)307   pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
308 
309   static const pass_data data;
310   opt_pass *
clone()311   clone ()
312   {
313     return new pass_sancov<O0> (m_ctxt);
314   }
315   virtual bool
gate(function *)316   gate (function *)
317   {
318     return flag_sanitize_coverage && (!O0 || !optimize);
319   }
320   virtual unsigned int
execute(function * fun)321   execute (function *fun)
322   {
323     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 *
make_pass_sancov(gcc::context * ctxt)343 make_pass_sancov (gcc::context *ctxt)
344 {
345   return new pass_sancov<false> (ctxt);
346 }
347 
348 gimple_opt_pass *
make_pass_sancov_O0(gcc::context * ctxt)349 make_pass_sancov_O0 (gcc::context *ctxt)
350 {
351   return new pass_sancov<true> (ctxt);
352 }
353