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
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along 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
46namespace {
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
54static void
55instrument_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
143static void
144instrument_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
236unsigned
237sancov_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
304template <bool O0> class pass_sancov : public gimple_opt_pass
305{
306public:
307  pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
308
309  static const pass_data data;
310  opt_pass *
311  clone ()
312  {
313    return new pass_sancov<O0> (m_ctxt);
314  }
315  virtual bool
316  gate (function *)
317  {
318    return flag_sanitize_coverage && (!O0 || !optimize);
319  }
320  virtual unsigned int
321  execute (function *fun)
322  {
323    return sancov_pass (fun);
324  }
325}; // class pass_sancov
326
327template <bool O0>
328const 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
342gimple_opt_pass *
343make_pass_sancov (gcc::context *ctxt)
344{
345  return new pass_sancov<false> (ctxt);
346}
347
348gimple_opt_pass *
349make_pass_sancov_O0 (gcc::context *ctxt)
350{
351  return new pass_sancov<true> (ctxt);
352}
353