Line data Source code
1 : /* Code coverage instrumentation for fuzzing.
2 : Copyright (C) 2015-2026 Free Software Foundation, Inc.
3 : Contributed by Dmitry Vyukov <dvyukov@google.com> and
4 : Wish Wu <wishwu007@gmail.com>
5 :
6 : This file is part of GCC.
7 :
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.
12 :
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.
17 :
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/>. */
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 :
46 : namespace {
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 :
54 : static void
55 112 : instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
56 : {
57 112 : tree type = TREE_TYPE (lhs);
58 112 : enum built_in_function fncode = END_BUILTINS;
59 112 : tree to_type = NULL_TREE;
60 112 : bool c = false;
61 :
62 112 : if (INTEGRAL_TYPE_P (type))
63 : {
64 96 : c = (is_gimple_min_invariant (lhs)
65 96 : ^ is_gimple_min_invariant (rhs));
66 96 : switch (int_size_in_bytes (type))
67 : {
68 8 : case 1:
69 8 : fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
70 : : BUILT_IN_SANITIZER_COV_TRACE_CMP1;
71 8 : to_type = unsigned_char_type_node;
72 8 : break;
73 8 : case 2:
74 8 : fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
75 : : BUILT_IN_SANITIZER_COV_TRACE_CMP2;
76 8 : to_type = uint16_type_node;
77 8 : break;
78 64 : case 4:
79 64 : fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
80 : : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
81 64 : to_type = uint32_type_node;
82 64 : break;
83 16 : default:
84 16 : fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
85 : : BUILT_IN_SANITIZER_COV_TRACE_CMP8;
86 16 : to_type = uint64_type_node;
87 16 : break;
88 : }
89 : }
90 16 : else if (SCALAR_FLOAT_TYPE_P (type))
91 : {
92 16 : if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
93 : {
94 8 : fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
95 8 : to_type = float_type_node;
96 : }
97 8 : else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
98 : {
99 8 : fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
100 8 : to_type = double_type_node;
101 : }
102 : }
103 :
104 112 : if (to_type != NULL_TREE)
105 : {
106 112 : gimple_seq seq = NULL;
107 :
108 112 : if (!useless_type_conversion_p (to_type, type))
109 : {
110 96 : if (TREE_CODE (lhs) == INTEGER_CST)
111 0 : lhs = fold_convert (to_type, lhs);
112 : else
113 : {
114 96 : gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
115 192 : lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
116 : }
117 :
118 96 : if (TREE_CODE (rhs) == INTEGER_CST)
119 56 : rhs = fold_convert (to_type, rhs);
120 : else
121 : {
122 40 : gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
123 80 : rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
124 : }
125 : }
126 :
127 112 : if (c && !is_gimple_min_invariant (lhs))
128 : std::swap (lhs, rhs);
129 :
130 112 : tree fndecl = builtin_decl_implicit (fncode);
131 112 : gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
132 112 : gimple_seq_add_stmt (&seq, gcall);
133 :
134 112 : gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
135 112 : gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
136 : }
137 112 : }
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 :
143 : static void
144 16 : instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
145 : {
146 16 : gswitch *switch_stmt = as_a<gswitch *> (stmt);
147 16 : tree index = gimple_switch_index (switch_stmt);
148 16 : HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
149 16 : if (size_in_bytes == -1 || size_in_bytes > 8)
150 0 : return;
151 :
152 16 : location_t loc = gimple_location (stmt);
153 16 : unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
154 128 : for (i = 1; i < n; ++i)
155 : {
156 112 : tree label = gimple_switch_label (switch_stmt, i);
157 :
158 112 : tree low_case = CASE_LOW (label);
159 112 : if (low_case != NULL_TREE)
160 112 : num++;
161 :
162 112 : tree high_case = CASE_HIGH (label);
163 112 : if (high_case != NULL_TREE)
164 8 : num++;
165 : }
166 :
167 16 : tree case_array_type
168 16 : = build_array_type (build_type_variant (uint64_type_node, 1, 0),
169 16 : build_index_type (size_int (num + 2 - 1)));
170 :
171 16 : char name[64];
172 16 : static size_t case_array_count = 0;
173 16 : ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
174 16 : tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
175 : case_array_type);
176 16 : TREE_STATIC (case_array_var) = 1;
177 16 : TREE_PUBLIC (case_array_var) = 0;
178 16 : TREE_CONSTANT (case_array_var) = 1;
179 16 : TREE_READONLY (case_array_var) = 1;
180 16 : DECL_EXTERNAL (case_array_var) = 0;
181 16 : DECL_ARTIFICIAL (case_array_var) = 1;
182 16 : DECL_IGNORED_P (case_array_var) = 1;
183 :
184 16 : vec <constructor_elt, va_gc> *v = NULL;
185 16 : vec_alloc (v, num + 2);
186 16 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
187 : build_int_cst (uint64_type_node, num));
188 16 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
189 : build_int_cst (uint64_type_node,
190 : size_in_bytes * BITS_PER_UNIT));
191 128 : for (i = 1; i < n; ++i)
192 : {
193 112 : tree label = gimple_switch_label (switch_stmt, i);
194 :
195 112 : tree low_case = CASE_LOW (label);
196 112 : if (low_case != NULL_TREE)
197 112 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
198 : fold_convert (uint64_type_node, low_case));
199 :
200 112 : tree high_case = CASE_HIGH (label);
201 112 : if (high_case != NULL_TREE)
202 8 : CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
203 : fold_convert (uint64_type_node, high_case));
204 : }
205 16 : tree ctor = build_constructor (case_array_type, v);
206 16 : TREE_STATIC (ctor) = 1;
207 16 : TREE_PUBLIC (ctor) = 0;
208 16 : TREE_CONSTANT (ctor) = 1;
209 16 : TREE_READONLY (ctor) = 1;
210 16 : DECL_INITIAL (case_array_var) = ctor;
211 16 : varpool_node::finalize_decl (case_array_var);
212 16 : add_local_decl (fun, case_array_var);
213 :
214 16 : gimple_seq seq = NULL;
215 :
216 16 : if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
217 : {
218 16 : if (TREE_CODE (index) == INTEGER_CST)
219 0 : index = fold_convert (uint64_type_node, index);
220 : else
221 : {
222 16 : gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
223 32 : index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
224 : }
225 : }
226 :
227 16 : tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
228 16 : gimple *gcall = gimple_build_call (fndecl, 2, index,
229 : build_fold_addr_expr (case_array_var));
230 16 : gimple_seq_add_stmt (&seq, gcall);
231 :
232 16 : gimple_seq_set_location (seq, loc);
233 16 : gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
234 : }
235 :
236 : unsigned
237 146 : sancov_pass (function *fun)
238 : {
239 146 : initialize_sanitizer_builtins ();
240 :
241 : /* Insert callback into beginning of every BB. */
242 146 : if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
243 : {
244 106 : basic_block bb;
245 106 : tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
246 393 : FOR_EACH_BB_FN (bb, fun)
247 : {
248 287 : gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
249 287 : if (gsi_end_p (gsi))
250 59 : continue;
251 228 : gimple *stmt = gsi_stmt (gsi);
252 228 : gimple *gcall = gimple_build_call (fndecl, 0);
253 228 : gimple_set_location (gcall, gimple_location (stmt));
254 228 : gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
255 : }
256 : }
257 :
258 : /* Insert callback into every comparison related operation. */
259 146 : if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
260 : {
261 56 : basic_block bb;
262 506 : FOR_EACH_BB_FN (bb, fun)
263 : {
264 450 : gimple_stmt_iterator gsi;
265 2192 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
266 : {
267 1292 : gimple *stmt = gsi_stmt (gsi);
268 1292 : enum tree_code rhs_code;
269 1292 : switch (gimple_code (stmt))
270 : {
271 804 : case GIMPLE_ASSIGN:
272 804 : rhs_code = gimple_assign_rhs_code (stmt);
273 804 : if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
274 40 : instrument_comparison (&gsi,
275 : gimple_assign_rhs1 (stmt),
276 : gimple_assign_rhs2 (stmt));
277 764 : else if (rhs_code == COND_EXPR
278 764 : && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
279 : {
280 0 : tree cond = gimple_assign_rhs1 (stmt);
281 0 : instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
282 0 : TREE_OPERAND (cond, 1));
283 : }
284 : break;
285 72 : case GIMPLE_COND:
286 72 : instrument_comparison (&gsi,
287 : gimple_cond_lhs (stmt),
288 : gimple_cond_rhs (stmt));
289 72 : break;
290 :
291 16 : case GIMPLE_SWITCH:
292 16 : instrument_switch (&gsi, stmt, fun);
293 16 : break;
294 :
295 : default:
296 : break;
297 : }
298 : }
299 : }
300 : }
301 146 : return 0;
302 : }
303 :
304 : template <bool O0> class pass_sancov : public gimple_opt_pass
305 : {
306 : public:
307 1714332 : pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
308 :
309 : static const pass_data data;
310 : opt_pass *
311 285722 : clone () final override
312 : {
313 285722 : return new pass_sancov<O0> (m_ctxt);
314 : }
315 : bool
316 2516289 : gate (function *fun) final override
317 : {
318 2516289 : return sanitize_coverage_p (fun->decl) && (!O0 || !optimize);
319 : }
320 : unsigned int
321 146 : execute (function *fun) final override
322 : {
323 146 : return sancov_pass (fun);
324 : }
325 : }; // class pass_sancov
326 :
327 : template <bool O0>
328 : const 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 :
342 : gimple_opt_pass *
343 285722 : make_pass_sancov (gcc::context *ctxt)
344 : {
345 285722 : return new pass_sancov<false> (ctxt);
346 : }
347 :
348 : gimple_opt_pass *
349 285722 : make_pass_sancov_O0 (gcc::context *ctxt)
350 : {
351 285722 : return new pass_sancov<true> (ctxt);
352 : }
|