* sancov.c: Include tm_p.h.
[official-gcc.git] / gcc / sancov.c
blob1c8906d731ca22d6717b36cb82444b9d65db97ea
1 /* Code coverage instrumentation for fuzzing.
2 Copyright (C) 2015-2017 Free Software Foundation, Inc.
3 Contributed by Dmitry Vyukov <dvyukov@google.com> and
4 Wish Wu <wishwu007@gmail.com>
6 This file is part of GCC.
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.
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.
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/>. */
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 "tm_p.h"
32 #include "stmt.h"
33 #include "gimple-iterator.h"
34 #include "gimple-builder.h"
35 #include "tree-cfg.h"
36 #include "tree-pass.h"
37 #include "tree-iterator.h"
38 #include "fold-const.h"
39 #include "stringpool.h"
40 #include "attribs.h"
41 #include "output.h"
42 #include "cgraph.h"
43 #include "asan.h"
45 namespace {
47 /* Instrument one comparison operation, which compares lhs and rhs.
48 Call the instrumentation function with the comparison operand.
49 For integral comparisons if exactly one of the comparison operands is
50 constant, call __sanitizer_cov_trace_const_cmp* instead of
51 __sanitizer_cov_trace_cmp*. */
53 static void
54 instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
56 tree type = TREE_TYPE (lhs);
57 enum built_in_function fncode = END_BUILTINS;
58 tree to_type = NULL_TREE;
59 bool c = false;
61 if (INTEGRAL_TYPE_P (type))
63 c = (is_gimple_min_invariant (lhs)
64 ^ is_gimple_min_invariant (rhs));
65 switch (int_size_in_bytes (type))
67 case 1:
68 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
69 : BUILT_IN_SANITIZER_COV_TRACE_CMP1;
70 to_type = unsigned_char_type_node;
71 break;
72 case 2:
73 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
74 : BUILT_IN_SANITIZER_COV_TRACE_CMP2;
75 to_type = uint16_type_node;
76 break;
77 case 4:
78 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
79 : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
80 to_type = uint32_type_node;
81 break;
82 default:
83 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
84 : BUILT_IN_SANITIZER_COV_TRACE_CMP8;
85 to_type = uint64_type_node;
86 break;
89 else if (SCALAR_FLOAT_TYPE_P (type))
91 if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
93 fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
94 to_type = float_type_node;
96 else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
98 fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
99 to_type = double_type_node;
103 if (to_type != NULL_TREE)
105 gimple_seq seq = NULL;
107 if (!useless_type_conversion_p (to_type, type))
109 if (TREE_CODE (lhs) == INTEGER_CST)
110 lhs = fold_convert (to_type, lhs);
111 else
113 gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
114 lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
117 if (TREE_CODE (rhs) == INTEGER_CST)
118 rhs = fold_convert (to_type, rhs);
119 else
121 gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
122 rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
126 if (c && !is_gimple_min_invariant (lhs))
127 std::swap (lhs, rhs);
129 tree fndecl = builtin_decl_implicit (fncode);
130 gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
131 gimple_seq_add_stmt (&seq, gcall);
133 gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
134 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
138 /* Instrument switch statement. Call __sanitizer_cov_trace_switch with
139 the value of the index and array that contains number of case values,
140 the bitsize of the index and the case values converted to uint64_t. */
142 static void
143 instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
145 gswitch *switch_stmt = as_a<gswitch *> (stmt);
146 tree index = gimple_switch_index (switch_stmt);
147 HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
148 if (size_in_bytes == -1 || size_in_bytes > 8)
149 return;
151 location_t loc = gimple_location (stmt);
152 unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
153 for (i = 1; i < n; ++i)
155 tree label = gimple_switch_label (switch_stmt, i);
157 tree low_case = CASE_LOW (label);
158 if (low_case != NULL_TREE)
159 num++;
161 tree high_case = CASE_HIGH (label);
162 if (high_case != NULL_TREE)
163 num++;
166 tree case_array_type
167 = build_array_type (build_type_variant (uint64_type_node, 1, 0),
168 build_index_type (size_int (num + 2 - 1)));
170 char name[64];
171 static size_t case_array_count = 0;
172 ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
173 tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
174 case_array_type);
175 TREE_STATIC (case_array_var) = 1;
176 TREE_PUBLIC (case_array_var) = 0;
177 TREE_CONSTANT (case_array_var) = 1;
178 TREE_READONLY (case_array_var) = 1;
179 DECL_EXTERNAL (case_array_var) = 0;
180 DECL_ARTIFICIAL (case_array_var) = 1;
181 DECL_IGNORED_P (case_array_var) = 1;
183 vec <constructor_elt, va_gc> *v = NULL;
184 vec_alloc (v, num + 2);
185 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
186 build_int_cst (uint64_type_node, num));
187 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
188 build_int_cst (uint64_type_node,
189 size_in_bytes * BITS_PER_UNIT));
190 for (i = 1; i < n; ++i)
192 tree label = gimple_switch_label (switch_stmt, i);
194 tree low_case = CASE_LOW (label);
195 if (low_case != NULL_TREE)
196 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
197 fold_convert (uint64_type_node, low_case));
199 tree high_case = CASE_HIGH (label);
200 if (high_case != NULL_TREE)
201 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
202 fold_convert (uint64_type_node, high_case));
204 tree ctor = build_constructor (case_array_type, v);
205 TREE_STATIC (ctor) = 1;
206 TREE_PUBLIC (ctor) = 0;
207 TREE_CONSTANT (ctor) = 1;
208 TREE_READONLY (ctor) = 1;
209 DECL_INITIAL (case_array_var) = ctor;
210 varpool_node::finalize_decl (case_array_var);
211 add_local_decl (fun, case_array_var);
213 gimple_seq seq = NULL;
215 if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
217 if (TREE_CODE (index) == INTEGER_CST)
218 index = fold_convert (uint64_type_node, index);
219 else
221 gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
222 index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
226 tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
227 gimple *gcall = gimple_build_call (fndecl, 2, index,
228 build_fold_addr_expr (case_array_var));
229 gimple_seq_add_stmt (&seq, gcall);
231 gimple_seq_set_location (seq, loc);
232 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
235 unsigned
236 sancov_pass (function *fun)
238 initialize_sanitizer_builtins ();
240 /* Insert callback into beginning of every BB. */
241 if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
243 basic_block bb;
244 tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
245 FOR_EACH_BB_FN (bb, fun)
247 gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
248 if (gsi_end_p (gsi))
249 continue;
250 gimple *stmt = gsi_stmt (gsi);
251 gimple *gcall = gimple_build_call (fndecl, 0);
252 gimple_set_location (gcall, gimple_location (stmt));
253 gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
257 /* Insert callback into every comparison related operation. */
258 if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
260 basic_block bb;
261 FOR_EACH_BB_FN (bb, fun)
263 gimple_stmt_iterator gsi;
264 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
266 gimple *stmt = gsi_stmt (gsi);
267 enum tree_code rhs_code;
268 switch (gimple_code (stmt))
270 case GIMPLE_ASSIGN:
271 rhs_code = gimple_assign_rhs_code (stmt);
272 if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
273 instrument_comparison (&gsi,
274 gimple_assign_rhs1 (stmt),
275 gimple_assign_rhs2 (stmt));
276 else if (rhs_code == COND_EXPR
277 && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
279 tree cond = gimple_assign_rhs1 (stmt);
280 instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
281 TREE_OPERAND (cond, 1));
283 break;
284 case GIMPLE_COND:
285 instrument_comparison (&gsi,
286 gimple_cond_lhs (stmt),
287 gimple_cond_rhs (stmt));
288 break;
290 case GIMPLE_SWITCH:
291 instrument_switch (&gsi, stmt, fun);
292 break;
294 default:
295 break;
300 return 0;
303 template <bool O0> class pass_sancov : public gimple_opt_pass
305 public:
306 pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
308 static const pass_data data;
309 opt_pass *
310 clone ()
312 return new pass_sancov<O0> (m_ctxt);
314 virtual bool
315 gate (function *)
317 return flag_sanitize_coverage && (!O0 || !optimize);
319 virtual unsigned int
320 execute (function *fun)
322 return sancov_pass (fun);
324 }; // class pass_sancov
326 template <bool O0>
327 const pass_data pass_sancov<O0>::data = {
328 GIMPLE_PASS, /* type */
329 O0 ? "sancov_O0" : "sancov", /* name */
330 OPTGROUP_NONE, /* optinfo_flags */
331 TV_NONE, /* tv_id */
332 (PROP_cfg), /* properties_required */
333 0, /* properties_provided */
334 0, /* properties_destroyed */
335 0, /* todo_flags_start */
336 TODO_update_ssa, /* todo_flags_finish */
339 } // anon namespace
341 gimple_opt_pass *
342 make_pass_sancov (gcc::context *ctxt)
344 return new pass_sancov<false> (ctxt);
347 gimple_opt_pass *
348 make_pass_sancov_O0 (gcc::context *ctxt)
350 return new pass_sancov<true> (ctxt);