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 /* Instruments EXPR if needed. If any instrumentation is inserted,
91 instrument_expr (gimple_stmt_iterator gsi
, tree expr
, bool is_write
)
93 tree base
, rhs
, expr_type
, expr_ptr
, builtin_decl
;
99 size
= int_size_in_bytes (TREE_TYPE (expr
));
103 /* For now just avoid instrumenting bit field acceses.
104 TODO: handle bit-fields as if touching the whole field. */
105 HOST_WIDE_INT bitsize
, bitpos
;
107 enum machine_mode mode
;
108 int volatilep
= 0, unsignedp
= 0;
109 base
= get_inner_reference (expr
, &bitsize
, &bitpos
, &offset
,
110 &mode
, &unsignedp
, &volatilep
, false);
112 /* No need to instrument accesses to decls that don't escape,
113 they can't escape to other threads then. */
116 struct pt_solution pt
;
117 memset (&pt
, 0, sizeof (pt
));
119 pt
.ipa_escaped
= flag_ipa_pta
!= 0;
121 if (!pt_solution_includes (&pt
, base
))
123 if (!is_global_var (base
) && !may_be_aliased (base
))
127 if (TREE_READONLY (base
))
130 if (bitpos
% (size
* BITS_PER_UNIT
)
131 || bitsize
!= size
* BITS_PER_UNIT
)
134 stmt
= gsi_stmt (gsi
);
135 loc
= gimple_location (stmt
);
136 rhs
= is_vptr_store (stmt
, expr
, is_write
);
137 gcc_checking_assert (rhs
!= NULL
|| is_gimple_addressable (expr
));
138 expr_ptr
= build_fold_addr_expr (unshare_expr (expr
));
141 expr_type
= TREE_TYPE (expr
);
142 while (TREE_CODE (expr_type
) == ARRAY_TYPE
)
143 expr_type
= TREE_TYPE (expr_type
);
144 size
= int_size_in_bytes (expr_type
);
145 g
= gimple_build_call (get_memory_access_decl (is_write
, size
),
150 builtin_decl
= builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE
);
151 g
= gimple_build_call (builtin_decl
, 1, expr_ptr
);
153 gimple_set_location (g
, loc
);
154 /* Instrumentation for assignment of a function result
155 must be inserted after the call. Instrumentation for
156 reads of function arguments must be inserted before the call.
157 That's because the call can contain synchronization. */
158 if (is_gimple_call (stmt
) && is_write
)
160 /* If the call can throw, it must be the last stmt in
161 a basic block, so the instrumented stmts need to be
162 inserted in successor bbs. */
163 if (is_ctrl_altering_stmt (stmt
))
168 e
= find_fallthru_edge (bb
->succs
);
170 gsi_insert_seq_on_edge_immediate (e
, g
);
173 gsi_insert_after (&gsi
, g
, GSI_NEW_STMT
);
176 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
181 /* Instruments the gimple pointed to by GSI. Return
182 true if func entry/exit should be instrumented. */
185 instrument_gimple (gimple_stmt_iterator gsi
)
189 bool instrumented
= false;
191 stmt
= gsi_stmt (gsi
);
192 if (is_gimple_call (stmt
)
193 && (gimple_call_fndecl (stmt
)
194 != builtin_decl_implicit (BUILT_IN_TSAN_INIT
)))
196 else if (is_gimple_assign (stmt
)
197 && !gimple_clobber_p (stmt
))
199 if (gimple_store_p (stmt
))
201 lhs
= gimple_assign_lhs (stmt
);
202 instrumented
= instrument_expr (gsi
, lhs
, true);
204 if (gimple_assign_load_p (stmt
))
206 rhs
= gimple_assign_rhs1 (stmt
);
207 instrumented
= instrument_expr (gsi
, rhs
, false);
213 /* Instruments all interesting memory accesses in the current function.
214 Return true if func entry/exit should be instrumented. */
217 instrument_memory_accesses (void)
220 gimple_stmt_iterator gsi
;
221 bool fentry_exit_instrument
= false;
224 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
225 fentry_exit_instrument
|= instrument_gimple (gsi
);
226 return fentry_exit_instrument
;
229 /* Instruments function entry. */
232 instrument_func_entry (void)
235 gimple_stmt_iterator gsi
;
236 tree ret_addr
, builtin_decl
;
239 succ_bb
= single_succ (ENTRY_BLOCK_PTR
);
240 gsi
= gsi_after_labels (succ_bb
);
242 builtin_decl
= builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS
);
243 g
= gimple_build_call (builtin_decl
, 1, integer_zero_node
);
244 ret_addr
= make_ssa_name (ptr_type_node
, NULL
);
245 gimple_call_set_lhs (g
, ret_addr
);
246 gimple_set_location (g
, cfun
->function_start_locus
);
247 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
249 builtin_decl
= builtin_decl_implicit (BUILT_IN_TSAN_FUNC_ENTRY
);
250 g
= gimple_build_call (builtin_decl
, 1, ret_addr
);
251 gimple_set_location (g
, cfun
->function_start_locus
);
252 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
255 /* Instruments function exits. */
258 instrument_func_exit (void)
262 gimple_stmt_iterator gsi
;
268 /* Find all function exits. */
269 exit_bb
= EXIT_BLOCK_PTR
;
270 FOR_EACH_EDGE (e
, ei
, exit_bb
->preds
)
272 gsi
= gsi_last_bb (e
->src
);
273 stmt
= gsi_stmt (gsi
);
274 gcc_assert (gimple_code (stmt
) == GIMPLE_RETURN
);
275 loc
= gimple_location (stmt
);
276 builtin_decl
= builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT
);
277 g
= gimple_build_call (builtin_decl
, 0);
278 gimple_set_location (g
, loc
);
279 gsi_insert_before (&gsi
, g
, GSI_SAME_STMT
);
283 /* ThreadSanitizer instrumentation pass. */
288 if (instrument_memory_accesses ())
290 instrument_func_entry ();
291 instrument_func_exit ();
296 /* The pass's gate. */
301 return flag_tsan
!= 0
302 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT
);
305 /* Inserts __tsan_init () into the list of CTORs. */
308 tsan_finish_file (void)
310 tree ctor_statements
;
313 ctor_statements
= NULL_TREE
;
314 init_decl
= builtin_decl_implicit (BUILT_IN_TSAN_INIT
);
315 append_to_statement_list (build_call_expr (init_decl
, 0),
317 cgraph_build_static_cdtor ('I', ctor_statements
,
318 MAX_RESERVED_INIT_PRIORITY
- 1);
321 /* The pass descriptor. */
323 struct gimple_opt_pass pass_tsan
=
328 OPTGROUP_NONE
, /* optinfo_flags */
329 tsan_gate
, /* gate */
330 tsan_pass
, /* execute */
333 0, /* static_pass_number */
335 PROP_ssa
| PROP_cfg
, /* properties_required */
336 0, /* properties_provided */
337 0, /* properties_destroyed */
338 0, /* todo_flags_start */
339 TODO_verify_all
| TODO_update_ssa
/* todo_flags_finish */
346 return flag_tsan
!= 0 && !optimize
347 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT
);
350 struct gimple_opt_pass pass_tsan_O0
=
355 OPTGROUP_NONE
, /* optinfo_flags */
356 tsan_gate_O0
, /* gate */
357 tsan_pass
, /* execute */
360 0, /* static_pass_number */
362 PROP_ssa
| PROP_cfg
, /* properties_required */
363 0, /* properties_provided */
364 0, /* properties_destroyed */
365 0, /* todo_flags_start */
366 TODO_verify_all
| TODO_update_ssa
/* todo_flags_finish */