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
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
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/>. */
24 #include "coretypes.h"
28 #include "basic-block.h"
33 #include "gimple-iterator.h"
34 #include "gimple-builder.h"
36 #include "tree-pass.h"
37 #include "tree-iterator.h"
38 #include "fold-const.h"
39 #include "stringpool.h"
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*. */
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
;
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
))
68 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
69 : BUILT_IN_SANITIZER_COV_TRACE_CMP1
;
70 to_type
= unsigned_char_type_node
;
73 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
74 : BUILT_IN_SANITIZER_COV_TRACE_CMP2
;
75 to_type
= uint16_type_node
;
78 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
79 : BUILT_IN_SANITIZER_COV_TRACE_CMP4
;
80 to_type
= uint32_type_node
;
83 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
84 : BUILT_IN_SANITIZER_COV_TRACE_CMP8
;
85 to_type
= uint64_type_node
;
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
);
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
);
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. */
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)
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
)
161 tree high_case
= CASE_HIGH (label
);
162 if (high_case
!= NULL_TREE
)
167 = build_array_type (build_type_variant (uint64_type_node
, 1, 0),
168 build_index_type (size_int (num
+ 2 - 1)));
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
),
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
);
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
);
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
)
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
);
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
)
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
))
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));
285 instrument_comparison (&gsi
,
286 gimple_cond_lhs (stmt
),
287 gimple_cond_rhs (stmt
));
291 instrument_switch (&gsi
, stmt
, fun
);
303 template <bool O0
> class pass_sancov
: public gimple_opt_pass
306 pass_sancov (gcc::context
*ctxt
) : gimple_opt_pass (data
, ctxt
) {}
308 static const pass_data data
;
312 return new pass_sancov
<O0
> (m_ctxt
);
317 return flag_sanitize_coverage
&& (!O0
|| !optimize
);
320 execute (function
*fun
)
322 return sancov_pass (fun
);
324 }; // class pass_sancov
327 const pass_data pass_sancov
<O0
>::data
= {
328 GIMPLE_PASS
, /* type */
329 O0
? "sancov_O0" : "sancov", /* name */
330 OPTGROUP_NONE
, /* optinfo_flags */
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 */
342 make_pass_sancov (gcc::context
*ctxt
)
344 return new pass_sancov
<false> (ctxt
);
348 make_pass_sancov_O0 (gcc::context
*ctxt
)
350 return new pass_sancov
<true> (ctxt
);