* asan.c (initialize_sanitizer_builtins): Add
[official-gcc.git] / gcc / sancov.c
blob2f8d5681e4f18028b738af5fbfaa6d49033359de
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 "stmt.h"
32 #include "gimple-iterator.h"
33 #include "gimple-builder.h"
34 #include "tree-cfg.h"
35 #include "tree-pass.h"
36 #include "tree-iterator.h"
37 #include "fold-const.h"
38 #include "stringpool.h"
39 #include "attribs.h"
40 #include "output.h"
41 #include "cgraph.h"
42 #include "asan.h"
44 namespace {
46 /* Instrument one comparison operation, which compares lhs and rhs.
47 Call the instrumentation function with the comparison operand.
48 For integral comparisons if exactly one of the comparison operands is
49 constant, call __sanitizer_cov_trace_const_cmp* instead of
50 __sanitizer_cov_trace_cmp*. */
52 static void
53 instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
55 tree type = TREE_TYPE (lhs);
56 enum built_in_function fncode = END_BUILTINS;
57 tree to_type = NULL_TREE;
58 bool c = false;
60 if (INTEGRAL_TYPE_P (type))
62 c = (is_gimple_min_invariant (lhs)
63 ^ is_gimple_min_invariant (rhs));
64 switch (int_size_in_bytes (type))
66 case 1:
67 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
68 : BUILT_IN_SANITIZER_COV_TRACE_CMP1;
69 to_type = unsigned_char_type_node;
70 break;
71 case 2:
72 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
73 : BUILT_IN_SANITIZER_COV_TRACE_CMP2;
74 to_type = uint16_type_node;
75 break;
76 case 4:
77 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
78 : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
79 to_type = uint32_type_node;
80 break;
81 default:
82 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
83 : BUILT_IN_SANITIZER_COV_TRACE_CMP8;
84 to_type = uint64_type_node;
85 break;
88 else if (SCALAR_FLOAT_TYPE_P (type))
90 if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
92 fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
93 to_type = float_type_node;
95 else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
97 fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
98 to_type = double_type_node;
102 if (to_type != NULL_TREE)
104 gimple_seq seq = NULL;
106 if (!useless_type_conversion_p (to_type, type))
108 if (TREE_CODE (lhs) == INTEGER_CST)
109 lhs = fold_convert (to_type, lhs);
110 else
112 gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
113 lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
116 if (TREE_CODE (rhs) == INTEGER_CST)
117 rhs = fold_convert (to_type, rhs);
118 else
120 gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
121 rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
125 if (c && !is_gimple_min_invariant (lhs))
126 std::swap (lhs, rhs);
128 tree fndecl = builtin_decl_implicit (fncode);
129 gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
130 gimple_seq_add_stmt (&seq, gcall);
132 gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
133 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
137 /* Instrument switch statement. Call __sanitizer_cov_trace_switch with
138 the value of the index and array that contains number of case values,
139 the bitsize of the index and the case values converted to uint64_t. */
141 static void
142 instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
144 gswitch *switch_stmt = as_a<gswitch *> (stmt);
145 tree index = gimple_switch_index (switch_stmt);
146 HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
147 if (size_in_bytes == -1 || size_in_bytes > 8)
148 return;
150 location_t loc = gimple_location (stmt);
151 unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
152 for (i = 1; i < n; ++i)
154 tree label = gimple_switch_label (switch_stmt, i);
156 tree low_case = CASE_LOW (label);
157 if (low_case != NULL_TREE)
158 num++;
160 tree high_case = CASE_HIGH (label);
161 if (high_case != NULL_TREE)
162 num++;
165 tree case_array_type
166 = build_array_type (build_type_variant (uint64_type_node, 1, 0),
167 build_index_type (size_int (num + 2 - 1)));
169 char name[64];
170 static size_t case_array_count = 0;
171 ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
172 tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
173 case_array_type);
174 TREE_STATIC (case_array_var) = 1;
175 TREE_PUBLIC (case_array_var) = 0;
176 TREE_CONSTANT (case_array_var) = 1;
177 TREE_READONLY (case_array_var) = 1;
178 DECL_EXTERNAL (case_array_var) = 0;
179 DECL_ARTIFICIAL (case_array_var) = 1;
180 DECL_IGNORED_P (case_array_var) = 1;
182 vec <constructor_elt, va_gc> *v = NULL;
183 vec_alloc (v, num + 2);
184 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
185 build_int_cst (uint64_type_node, num));
186 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
187 build_int_cst (uint64_type_node,
188 size_in_bytes * BITS_PER_UNIT));
189 for (i = 1; i < n; ++i)
191 tree label = gimple_switch_label (switch_stmt, i);
193 tree low_case = CASE_LOW (label);
194 if (low_case != NULL_TREE)
195 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
196 fold_convert (uint64_type_node, low_case));
198 tree high_case = CASE_HIGH (label);
199 if (high_case != NULL_TREE)
200 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
201 fold_convert (uint64_type_node, high_case));
203 tree ctor = build_constructor (case_array_type, v);
204 TREE_STATIC (ctor) = 1;
205 TREE_PUBLIC (ctor) = 0;
206 TREE_CONSTANT (ctor) = 1;
207 TREE_READONLY (ctor) = 1;
208 DECL_INITIAL (case_array_var) = ctor;
209 varpool_node::finalize_decl (case_array_var);
210 add_local_decl (fun, case_array_var);
212 gimple_seq seq = NULL;
214 if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
216 if (TREE_CODE (index) == INTEGER_CST)
217 index = fold_convert (uint64_type_node, index);
218 else
220 gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
221 index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
225 tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
226 gimple *gcall = gimple_build_call (fndecl, 2, index,
227 build_fold_addr_expr (case_array_var));
228 gimple_seq_add_stmt (&seq, gcall);
230 gimple_seq_set_location (seq, loc);
231 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
234 unsigned
235 sancov_pass (function *fun)
237 initialize_sanitizer_builtins ();
239 /* Insert callback into beginning of every BB. */
240 if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
242 basic_block bb;
243 tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
244 FOR_EACH_BB_FN (bb, fun)
246 gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
247 if (gsi_end_p (gsi))
248 continue;
249 gimple *stmt = gsi_stmt (gsi);
250 gimple *gcall = gimple_build_call (fndecl, 0);
251 gimple_set_location (gcall, gimple_location (stmt));
252 gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
256 /* Insert callback into every comparison related operation. */
257 if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
259 basic_block bb;
260 FOR_EACH_BB_FN (bb, fun)
262 gimple_stmt_iterator gsi;
263 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
265 gimple *stmt = gsi_stmt (gsi);
266 enum tree_code rhs_code;
267 switch (gimple_code (stmt))
269 case GIMPLE_ASSIGN:
270 rhs_code = gimple_assign_rhs_code (stmt);
271 if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
272 instrument_comparison (&gsi,
273 gimple_assign_rhs1 (stmt),
274 gimple_assign_rhs2 (stmt));
275 else if (rhs_code == COND_EXPR
276 && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
278 tree cond = gimple_assign_rhs1 (stmt);
279 instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
280 TREE_OPERAND (cond, 1));
282 break;
283 case GIMPLE_COND:
284 instrument_comparison (&gsi,
285 gimple_cond_lhs (stmt),
286 gimple_cond_rhs (stmt));
287 break;
289 case GIMPLE_SWITCH:
290 instrument_switch (&gsi, stmt, fun);
291 break;
293 default:
294 break;
299 return 0;
302 template <bool O0> class pass_sancov : public gimple_opt_pass
304 public:
305 pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
307 static const pass_data data;
308 opt_pass *
309 clone ()
311 return new pass_sancov<O0> (m_ctxt);
313 virtual bool
314 gate (function *)
316 return flag_sanitize_coverage && (!O0 || !optimize);
318 virtual unsigned int
319 execute (function *fun)
321 return sancov_pass (fun);
323 }; // class pass_sancov
325 template <bool O0>
326 const pass_data pass_sancov<O0>::data = {
327 GIMPLE_PASS, /* type */
328 O0 ? "sancov_O0" : "sancov", /* name */
329 OPTGROUP_NONE, /* optinfo_flags */
330 TV_NONE, /* tv_id */
331 (PROP_cfg), /* properties_required */
332 0, /* properties_provided */
333 0, /* properties_destroyed */
334 0, /* todo_flags_start */
335 TODO_update_ssa, /* todo_flags_finish */
338 } // anon namespace
340 gimple_opt_pass *
341 make_pass_sancov (gcc::context *ctxt)
343 return new pass_sancov<false> (ctxt);
346 gimple_opt_pass *
347 make_pass_sancov_O0 (gcc::context *ctxt)
349 return new pass_sancov<true> (ctxt);