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>
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"
34 #include "gimple-iterator.h"
35 #include "gimple-builder.h"
37 #include "tree-pass.h"
38 #include "tree-iterator.h"
39 #include "fold-const.h"
40 #include "stringpool.h"
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*. */
55 instrument_comparison (gimple_stmt_iterator
*gsi
, tree lhs
, tree rhs
)
57 tree type
= TREE_TYPE (lhs
);
58 enum built_in_function fncode
= END_BUILTINS
;
59 tree to_type
= NULL_TREE
;
62 if (INTEGRAL_TYPE_P (type
))
64 c
= (is_gimple_min_invariant (lhs
)
65 ^ is_gimple_min_invariant (rhs
));
66 switch (int_size_in_bytes (type
))
69 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
70 : BUILT_IN_SANITIZER_COV_TRACE_CMP1
;
71 to_type
= unsigned_char_type_node
;
74 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
75 : BUILT_IN_SANITIZER_COV_TRACE_CMP2
;
76 to_type
= uint16_type_node
;
79 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
80 : BUILT_IN_SANITIZER_COV_TRACE_CMP4
;
81 to_type
= uint32_type_node
;
84 fncode
= c
? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
85 : BUILT_IN_SANITIZER_COV_TRACE_CMP8
;
86 to_type
= uint64_type_node
;
90 else if (SCALAR_FLOAT_TYPE_P (type
))
92 if (TYPE_MODE (type
) == TYPE_MODE (float_type_node
))
94 fncode
= BUILT_IN_SANITIZER_COV_TRACE_CMPF
;
95 to_type
= float_type_node
;
97 else if (TYPE_MODE (type
) == TYPE_MODE (double_type_node
))
99 fncode
= BUILT_IN_SANITIZER_COV_TRACE_CMPD
;
100 to_type
= double_type_node
;
104 if (to_type
!= NULL_TREE
)
106 gimple_seq seq
= NULL
;
108 if (!useless_type_conversion_p (to_type
, type
))
110 if (TREE_CODE (lhs
) == INTEGER_CST
)
111 lhs
= fold_convert (to_type
, lhs
);
114 gimple_seq_add_stmt (&seq
, build_type_cast (to_type
, lhs
));
115 lhs
= gimple_assign_lhs (gimple_seq_last_stmt (seq
));
118 if (TREE_CODE (rhs
) == INTEGER_CST
)
119 rhs
= fold_convert (to_type
, rhs
);
122 gimple_seq_add_stmt (&seq
, build_type_cast (to_type
, rhs
));
123 rhs
= gimple_assign_lhs (gimple_seq_last_stmt (seq
));
127 if (c
&& !is_gimple_min_invariant (lhs
))
128 std::swap (lhs
, rhs
);
130 tree fndecl
= builtin_decl_implicit (fncode
);
131 gimple
*gcall
= gimple_build_call (fndecl
, 2, lhs
, rhs
);
132 gimple_seq_add_stmt (&seq
, gcall
);
134 gimple_seq_set_location (seq
, gimple_location (gsi_stmt (*gsi
)));
135 gsi_insert_seq_before (gsi
, seq
, GSI_SAME_STMT
);
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. */
144 instrument_switch (gimple_stmt_iterator
*gsi
, gimple
*stmt
, function
*fun
)
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)
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
)
156 tree label
= gimple_switch_label (switch_stmt
, i
);
158 tree low_case
= CASE_LOW (label
);
159 if (low_case
!= NULL_TREE
)
162 tree high_case
= CASE_HIGH (label
);
163 if (high_case
!= NULL_TREE
)
168 = build_array_type (build_type_variant (uint64_type_node
, 1, 0),
169 build_index_type (size_int (num
+ 2 - 1)));
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
),
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;
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
)
193 tree label
= gimple_switch_label (switch_stmt
, i
);
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
));
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
));
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
);
214 gimple_seq seq
= NULL
;
216 if (!useless_type_conversion_p (uint64_type_node
, TREE_TYPE (index
)))
218 if (TREE_CODE (index
) == INTEGER_CST
)
219 index
= fold_convert (uint64_type_node
, index
);
222 gimple_seq_add_stmt (&seq
, build_type_cast (uint64_type_node
, index
));
223 index
= gimple_assign_lhs (gimple_seq_last_stmt (seq
));
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
);
232 gimple_seq_set_location (seq
, loc
);
233 gsi_insert_seq_before (gsi
, seq
, GSI_SAME_STMT
);
237 sancov_pass (function
*fun
)
239 initialize_sanitizer_builtins ();
241 /* Insert callback into beginning of every BB. */
242 if (flag_sanitize_coverage
& SANITIZE_COV_TRACE_PC
)
245 tree fndecl
= builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC
);
246 FOR_EACH_BB_FN (bb
, fun
)
248 gimple_stmt_iterator gsi
= gsi_start_nondebug_after_labels_bb (bb
);
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
);
258 /* Insert callback into every comparison related operation. */
259 if (flag_sanitize_coverage
& SANITIZE_COV_TRACE_CMP
)
262 FOR_EACH_BB_FN (bb
, fun
)
264 gimple_stmt_iterator gsi
;
265 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
267 gimple
*stmt
= gsi_stmt (gsi
);
268 enum tree_code rhs_code
;
269 switch (gimple_code (stmt
))
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
)))
280 tree cond
= gimple_assign_rhs1 (stmt
);
281 instrument_comparison (&gsi
, TREE_OPERAND (cond
, 0),
282 TREE_OPERAND (cond
, 1));
286 instrument_comparison (&gsi
,
287 gimple_cond_lhs (stmt
),
288 gimple_cond_rhs (stmt
));
292 instrument_switch (&gsi
, stmt
, fun
);
304 template <bool O0
> class pass_sancov
: public gimple_opt_pass
307 pass_sancov (gcc::context
*ctxt
) : gimple_opt_pass (data
, ctxt
) {}
309 static const pass_data data
;
313 return new pass_sancov
<O0
> (m_ctxt
);
318 return sanitize_coverage_p (fun
->decl
) && (!O0
|| !optimize
);
321 execute (function
*fun
)
323 return sancov_pass (fun
);
325 }; // class pass_sancov
328 const pass_data pass_sancov
<O0
>::data
= {
329 GIMPLE_PASS
, /* type */
330 O0
? "sancov_O0" : "sancov", /* name */
331 OPTGROUP_NONE
, /* optinfo_flags */
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 */
343 make_pass_sancov (gcc::context
*ctxt
)
345 return new pass_sancov
<false> (ctxt
);
349 make_pass_sancov_O0 (gcc::context
*ctxt
)
351 return new pass_sancov
<true> (ctxt
);