]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/tsan.c
gensupport.c (maybe_eval_c_test): Remove not-null check for expr.
[thirdparty/gcc.git] / gcc / tsan.c
CommitLineData
32b4b7f5
DV
1/* GCC instrumentation plugin for ThreadSanitizer.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3 Contributed by Dmitry Vyukov <dvyukov@google.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "tree.h"
26#include "intl.h"
27#include "tm.h"
28#include "basic-block.h"
29#include "gimple.h"
30#include "function.h"
31#include "tree-flow.h"
32#include "tree-pass.h"
33#include "tree-iterator.h"
34#include "langhooks.h"
35#include "output.h"
36#include "options.h"
37#include "target.h"
38#include "cgraph.h"
39#include "diagnostic.h"
40
41/* Number of instrumented memory accesses in the current function. */
42
43/* Builds the following decl
44 void __tsan_read/writeX (void *addr); */
45
46static tree
47get_memory_access_decl (bool is_write, unsigned size)
48{
49 enum built_in_function fcode;
50
51 if (size <= 1)
52 fcode = is_write ? BUILT_IN_TSAN_WRITE_1
53 : BUILT_IN_TSAN_READ_1;
54 else if (size <= 3)
55 fcode = is_write ? BUILT_IN_TSAN_WRITE_2
56 : BUILT_IN_TSAN_READ_2;
57 else if (size <= 7)
58 fcode = is_write ? BUILT_IN_TSAN_WRITE_4
59 : BUILT_IN_TSAN_READ_4;
60 else if (size <= 15)
61 fcode = is_write ? BUILT_IN_TSAN_WRITE_8
62 : BUILT_IN_TSAN_READ_8;
63 else
64 fcode = is_write ? BUILT_IN_TSAN_WRITE_16
65 : BUILT_IN_TSAN_READ_16;
66
67 return builtin_decl_implicit (fcode);
68}
69
70/* Check as to whether EXPR refers to a store to vptr. */
71
72static tree
73is_vptr_store (gimple stmt, tree expr, bool is_write)
74{
75 if (is_write == true
76 && gimple_assign_single_p (stmt)
77 && TREE_CODE (expr) == COMPONENT_REF)
78 {
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);
83 }
84 return NULL;
85}
86
87/* Checks as to whether EXPR refers to constant var/field/param.
88 Don't bother to instrument them. */
89
90static bool
91is_load_of_const_p (tree expr, bool is_write)
92{
93 if (is_write)
94 return false;
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)
100 {
101 if (TREE_READONLY (expr))
102 return true;
103 }
104 return false;
105}
106
107/* Instruments EXPR if needed. If any instrumentation is inserted,
8ddf5c28 108 return true. */
32b4b7f5
DV
109
110static bool
111instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write)
112{
113 enum tree_code tcode;
114 tree base, rhs, expr_type, expr_ptr, builtin_decl;
115 basic_block bb;
116 HOST_WIDE_INT size;
117 gimple stmt, g;
118 location_t loc;
119
120 base = get_base_address (expr);
121 if (base == NULL_TREE
122 || TREE_CODE (base) == SSA_NAME
123 || TREE_CODE (base) == STRING_CST)
124 return false;
125
126 tcode = TREE_CODE (expr);
127
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))
144 return false;
145
146 size = int_size_in_bytes (TREE_TYPE (expr));
147 if (size == -1)
148 return false;
149
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;
153 tree offset;
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)
160 return false;
161
8ddf5c28 162 /* TODO: handle other case: ARRAY_RANGE_REF. */
32b4b7f5
DV
163 if (tcode != ARRAY_REF
164 && tcode != VAR_DECL
165 && tcode != COMPONENT_REF
166 && tcode != INDIRECT_REF
167 && tcode != MEM_REF)
168 return false;
169
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));
175 if (rhs == NULL)
176 {
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),
182 1, expr_ptr);
183 }
184 else
185 {
186 builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE);
187 g = gimple_build_call (builtin_decl, 1, expr_ptr);
188 }
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)
195 {
196 /* If the call can throw, it must be the last stmt in
197 a basic block, so the instrumented stmts need to be
8ddf5c28 198 inserted in successor bbs. */
32b4b7f5
DV
199 if (is_ctrl_altering_stmt (stmt))
200 {
201 edge e;
202
203 bb = gsi_bb (gsi);
204 e = find_fallthru_edge (bb->succs);
205 if (e)
206 gsi_insert_seq_on_edge_immediate (e, g);
207 }
208 else
209 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
210 }
211 else
212 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
213
214 return true;
215}
216
217/* Instruments the gimple pointed to by GSI. Return
8ddf5c28 218 true if func entry/exit should be instrumented. */
32b4b7f5
DV
219
220static bool
221instrument_gimple (gimple_stmt_iterator gsi)
222{
223 gimple stmt;
224 tree rhs, lhs;
225 bool instrumented = false;
226
227 stmt = gsi_stmt (gsi);
228 if (is_gimple_call (stmt)
229 && (gimple_call_fndecl (stmt)
230 != builtin_decl_implicit (BUILT_IN_TSAN_INIT)))
231 return true;
8ddf5c28
JJ
232 else if (is_gimple_assign (stmt)
233 && !gimple_clobber_p (stmt))
32b4b7f5
DV
234 {
235 if (gimple_store_p (stmt))
236 {
237 lhs = gimple_assign_lhs (stmt);
238 instrumented = instrument_expr (gsi, lhs, true);
239 }
240 if (gimple_assign_load_p (stmt))
241 {
242 rhs = gimple_assign_rhs1 (stmt);
243 instrumented = instrument_expr (gsi, rhs, false);
244 }
245 }
246 return instrumented;
247}
248
249/* Instruments all interesting memory accesses in the current function.
8ddf5c28 250 Return true if func entry/exit should be instrumented. */
32b4b7f5
DV
251
252static bool
253instrument_memory_accesses (void)
254{
255 basic_block bb;
256 gimple_stmt_iterator gsi;
257 bool fentry_exit_instrument = false;
258
259 FOR_EACH_BB (bb)
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;
263}
264
265/* Instruments function entry. */
266
267static void
268instrument_func_entry (void)
269{
270 basic_block succ_bb;
271 gimple_stmt_iterator gsi;
272 tree ret_addr, builtin_decl;
273 gimple g;
274
275 succ_bb = single_succ (ENTRY_BLOCK_PTR);
276 gsi = gsi_after_labels (succ_bb);
277
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);
284
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);
289}
290
291/* Instruments function exits. */
292
293static void
294instrument_func_exit (void)
295{
296 location_t loc;
297 basic_block exit_bb;
298 gimple_stmt_iterator gsi;
299 gimple stmt, g;
300 tree builtin_decl;
301 edge e;
302 edge_iterator ei;
303
304 /* Find all function exits. */
305 exit_bb = EXIT_BLOCK_PTR;
306 FOR_EACH_EDGE (e, ei, exit_bb->preds)
307 {
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);
316 }
317}
318
319/* ThreadSanitizer instrumentation pass. */
320
321static unsigned
322tsan_pass (void)
323{
324 if (instrument_memory_accesses ())
325 {
326 instrument_func_entry ();
327 instrument_func_exit ();
328 }
329 return 0;
330}
331
332/* The pass's gate. */
333
334static bool
335tsan_gate (void)
336{
337 return flag_tsan != 0
338 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
339}
340
341/* Inserts __tsan_init () into the list of CTORs. */
342
343void
344tsan_finish_file (void)
345{
346 tree ctor_statements;
347 tree init_decl;
348
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),
352 &ctor_statements);
353 cgraph_build_static_cdtor ('I', ctor_statements,
354 MAX_RESERVED_INIT_PRIORITY - 1);
355}
356
357/* The pass descriptor. */
358
359struct gimple_opt_pass pass_tsan =
360{
361 {
362 GIMPLE_PASS,
363 "tsan", /* name */
364 OPTGROUP_NONE, /* optinfo_flags */
365 tsan_gate, /* gate */
366 tsan_pass, /* execute */
367 NULL, /* sub */
368 NULL, /* next */
369 0, /* static_pass_number */
370 TV_NONE, /* tv_id */
371 PROP_ssa | PROP_cfg, /* properties_required */
372 0, /* properties_provided */
373 0, /* properties_destroyed */
374 0, /* todo_flags_start */
8ddf5c28 375 TODO_verify_all | TODO_update_ssa /* todo_flags_finish */
32b4b7f5
DV
376 }
377};
378
379static bool
380tsan_gate_O0 (void)
381{
382 return flag_tsan != 0 && !optimize
383 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
384}
385
386struct gimple_opt_pass pass_tsan_O0 =
387{
388 {
389 GIMPLE_PASS,
390 "tsan0", /* name */
391 OPTGROUP_NONE, /* optinfo_flags */
392 tsan_gate_O0, /* gate */
393 tsan_pass, /* execute */
394 NULL, /* sub */
395 NULL, /* next */
396 0, /* static_pass_number */
397 TV_NONE, /* tv_id */
398 PROP_ssa | PROP_cfg, /* properties_required */
399 0, /* properties_provided */
400 0, /* properties_destroyed */
401 0, /* todo_flags_start */
8ddf5c28 402 TODO_verify_all | TODO_update_ssa /* todo_flags_finish */
32b4b7f5
DV
403 }
404};