1 /* GCC instrumentation plugin for ThreadSanitizer.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3 Contributed by Dmitry Vyukov <dvyukov@google.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "basic-block.h"
31 #include "tree-flow.h"
32 #include "tree-pass.h"
33 #include "tree-iterator.h"
34 #include "langhooks.h"
39 #include "diagnostic.h"
41 /* Number of instrumented memory accesses in the current function. */
43 /* Builds the following decl
44 void __tsan_read/writeX (void *addr); */
47 get_memory_access_decl (bool is_write
, unsigned size
)
49 enum built_in_function fcode
;
52 fcode
= is_write
? BUILT_IN_TSAN_WRITE_1
53 : BUILT_IN_TSAN_READ_1
;
55 fcode
= is_write
? BUILT_IN_TSAN_WRITE_2
56 : BUILT_IN_TSAN_READ_2
;
58 fcode
= is_write
? BUILT_IN_TSAN_WRITE_4
59 : BUILT_IN_TSAN_READ_4
;
61 fcode
= is_write
? BUILT_IN_TSAN_WRITE_8
62 : BUILT_IN_TSAN_READ_8
;
64 fcode
= is_write
? BUILT_IN_TSAN_WRITE_16
65 : BUILT_IN_TSAN_READ_16
;
67 return builtin_decl_implicit (fcode
);
70 /* Check as to whether EXPR refers to a store to vptr. */
73 is_vptr_store (gimple stmt
, tree expr
, bool is_write
)
76 && gimple_assign_single_p (stmt
)
77 && TREE_CODE (expr
) == COMPONENT_REF
)
79 tree field
= TREE_OPERAND (expr
, 1);
80 if (TREE_CODE (field
) == FIELD_DECL
81 && DECL_VIRTUAL_P (field
))
82 return gimple_assign_rhs1 (stmt
);
87 /* Checks as to whether EXPR refers to constant var/field/param.
88 Don't bother to instrument them. */
91 is_load_of_const_p (tree expr
, bool is_write
)
95 if (TREE_CODE (expr
) == COMPONENT_REF
)
96 expr
= TREE_OPERAND (expr
, 1);
97 if (TREE_CODE (expr
) == VAR_DECL
98 || TREE_CODE (expr
) == PARM_DECL
99 || TREE_CODE (expr
) == FIELD_DECL
)
101 if (TREE_READONLY (expr
))
107 /* Instruments EXPR if needed. If any instrumentation is inserted,
111 instrument_expr (gimple_stmt_iterator gsi
, tree expr
, bool is_write
)
113 enum tree_code tcode
;
114 tree base
, rhs
, expr_type
, expr_ptr
, builtin_decl
;
120 base
= get_base_address (expr
);
121 if (base
== NULL_TREE
122 || TREE_CODE (base
) == SSA_NAME
123 || TREE_CODE (base
) == STRING_CST
)
126 tcode
= TREE_CODE (expr
);
128 /* Below are things we do not instrument
129 (no possibility of races or not implemented yet). */
130 if (/* Compiler-emitted artificial variables. */
131 (DECL_P (expr
) && DECL_ARTIFICIAL (expr
))
132 /* The var does not live in memory -> no possibility of races. */
133 || (tcode
== VAR_DECL
134 && !TREE_ADDRESSABLE (expr
)
135 && TREE_STATIC (expr
) == 0)
136 /* Not implemented. */
137 || TREE_CODE (TREE_TYPE (expr
)) == RECORD_TYPE
138 /* Not implemented. */
139 || tcode
== CONSTRUCTOR
140 /* Not implemented. */
141 || tcode
== PARM_DECL
142 /* Load of a const variable/parameter/field. */
143 || is_load_of_const_p (expr
, is_write
))
146 size
= int_size_in_bytes (TREE_TYPE (expr
));
150 /* For now just avoid instrumenting bit field acceses.
151 TODO: handle bit-fields as if touching the whole field. */
152 HOST_WIDE_INT bitsize
, bitpos
;
154 enum machine_mode mode
;
155 int volatilep
= 0, unsignedp
= 0;
156 get_inner_reference (expr
, &bitsize
, &bitpos
, &offset
,
157 &mode
, &unsignedp
, &volatilep
, false);
158 if (bitpos
% (size
* BITS_PER_UNIT
)
159 || bitsize
!= size
* BITS_PER_UNIT
)
162 /* TODO: handle other case: ARRAY_RANGE_REF. */
163 if (tcode
!= ARRAY_REF
165 && tcode
!= COMPONENT_REF
166 && tcode
!= INDIRECT_REF
170 stmt
= gsi_stmt (gsi
);
171 loc
= gimple_location (stmt
);
172 rhs
= is_vptr_store (stmt
, expr
, is_write
);
173 gcc_checking_assert (rhs
!= NULL
|| is_gimple_addressable (expr
));
174 expr_ptr
= build_fold_addr_expr (unshare_expr (expr
));
177 expr_type
= TREE_TYPE (expr
);
178 while (TREE_CODE (expr_type
) == ARRAY_TYPE
)
179 expr_type
= TREE_TYPE (expr_type
);
180 size
= int_size_in_bytes (expr_type
);
181 g
= gimple_build_call (get_memory_access_decl (is_write
, size
),
186 builtin_decl
= builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE
);
187 g
= gimple_build_call (builtin_decl
, 1, expr_ptr
);
189 gimple_set_location (g
, loc
);
190 /* Instrumentation for assignment of a function result
191 must be inserted after the call. Instrumentation for
192 reads of function arguments must be inserted before the call.
193 That's because the call can contain synchronization. */
194 if (is_gimple_call (stmt
) && is_write
)
196 /* If the call can throw, it must be the last stmt in
197 a basic block, so the instrumented stmts need to be
198 inserted in successor bbs. */
199 if (is_ctrl_altering_stmt (stmt
))
204 e
= find_fallthru_edge (bb
->succs
);
206 gsi_insert_seq_on_edge_immediate (e
, g
);
209 gsi_insert_after (&gsi
, g
, GSI_NEW_STMT
);
212 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
217 /* Instruments the gimple pointed to by GSI. Return
218 true if func entry/exit should be instrumented. */
221 instrument_gimple (gimple_stmt_iterator gsi
)
225 bool instrumented
= false;
227 stmt
= gsi_stmt (gsi
);
228 if (is_gimple_call (stmt
)
229 && (gimple_call_fndecl (stmt
)
230 != builtin_decl_implicit (BUILT_IN_TSAN_INIT
)))
232 else if (is_gimple_assign (stmt
)
233 && !gimple_clobber_p (stmt
))
235 if (gimple_store_p (stmt
))
237 lhs
= gimple_assign_lhs (stmt
);
238 instrumented
= instrument_expr (gsi
, lhs
, true);
240 if (gimple_assign_load_p (stmt
))
242 rhs
= gimple_assign_rhs1 (stmt
);
243 instrumented
= instrument_expr (gsi
, rhs
, false);
249 /* Instruments all interesting memory accesses in the current function.
250 Return true if func entry/exit should be instrumented. */
253 instrument_memory_accesses (void)
256 gimple_stmt_iterator gsi
;
257 bool fentry_exit_instrument
= false;
260 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
261 fentry_exit_instrument
|= instrument_gimple (gsi
);
262 return fentry_exit_instrument
;
265 /* Instruments function entry. */
268 instrument_func_entry (void)
271 gimple_stmt_iterator gsi
;
272 tree ret_addr
, builtin_decl
;
275 succ_bb
= single_succ (ENTRY_BLOCK_PTR
);
276 gsi
= gsi_after_labels (succ_bb
);
278 builtin_decl
= builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS
);
279 g
= gimple_build_call (builtin_decl
, 1, integer_zero_node
);
280 ret_addr
= make_ssa_name (ptr_type_node
, NULL
);
281 gimple_call_set_lhs (g
, ret_addr
);
282 gimple_set_location (g
, cfun
->function_start_locus
);
283 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
285 builtin_decl
= builtin_decl_implicit (BUILT_IN_TSAN_FUNC_ENTRY
);
286 g
= gimple_build_call (builtin_decl
, 1, ret_addr
);
287 gimple_set_location (g
, cfun
->function_start_locus
);
288 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
291 /* Instruments function exits. */
294 instrument_func_exit (void)
298 gimple_stmt_iterator gsi
;
304 /* Find all function exits. */
305 exit_bb
= EXIT_BLOCK_PTR
;
306 FOR_EACH_EDGE (e
, ei
, exit_bb
->preds
)
308 gsi
= gsi_last_bb (e
->src
);
309 stmt
= gsi_stmt (gsi
);
310 gcc_assert (gimple_code (stmt
) == GIMPLE_RETURN
);
311 loc
= gimple_location (stmt
);
312 builtin_decl
= builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT
);
313 g
= gimple_build_call (builtin_decl
, 0);
314 gimple_set_location (g
, loc
);
315 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
319 /* ThreadSanitizer instrumentation pass. */
324 if (instrument_memory_accesses ())
326 instrument_func_entry ();
327 instrument_func_exit ();
332 /* The pass's gate. */
337 return flag_tsan
!= 0
338 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT
);
341 /* Inserts __tsan_init () into the list of CTORs. */
344 tsan_finish_file (void)
346 tree ctor_statements
;
349 ctor_statements
= NULL_TREE
;
350 init_decl
= builtin_decl_implicit (BUILT_IN_TSAN_INIT
);
351 append_to_statement_list (build_call_expr (init_decl
, 0),
353 cgraph_build_static_cdtor ('I', ctor_statements
,
354 MAX_RESERVED_INIT_PRIORITY
- 1);
357 /* The pass descriptor. */
359 struct gimple_opt_pass pass_tsan
=
364 OPTGROUP_NONE
, /* optinfo_flags */
365 tsan_gate
, /* gate */
366 tsan_pass
, /* execute */
369 0, /* static_pass_number */
371 PROP_ssa
| PROP_cfg
, /* properties_required */
372 0, /* properties_provided */
373 0, /* properties_destroyed */
374 0, /* todo_flags_start */
375 TODO_verify_all
| TODO_update_ssa
/* todo_flags_finish */
382 return flag_tsan
!= 0 && !optimize
383 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT
);
386 struct gimple_opt_pass pass_tsan_O0
=
391 OPTGROUP_NONE
, /* optinfo_flags */
392 tsan_gate_O0
, /* gate */
393 tsan_pass
, /* execute */
396 0, /* static_pass_number */
398 PROP_ssa
| PROP_cfg
, /* properties_required */
399 0, /* properties_provided */
400 0, /* properties_destroyed */
401 0, /* todo_flags_start */
402 TODO_verify_all
| TODO_update_ssa
/* todo_flags_finish */