1 /* ThreadSanitizer, a data race detector.
2 Copyright (C) 2011 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
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
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/>. */
23 #include "coretypes.h"
27 #include "basic-block.h"
30 #include "tree-flow.h"
31 #include "tree-pass.h"
32 #include "tree-tsan.h"
33 #include "tree-iterator.h"
35 #include "langhooks.h"
40 #include "diagnostic.h"
42 /* ThreadSanitizer is a data race detector for C/C++ programs.
43 http://code.google.com/p/data-race-test/wiki/ThreadSanitizer
45 The tool consists of two parts:
46 instrumentation module (this file) and a run-time library.
47 The instrumentation module maintains shadow call stacks
48 and intercepts interesting memory accesses.
49 The instrumentation is enabled with -ftsan flag.
51 Instrumentation for shadow stack maintenance is as follows:
54 __tsan_shadow_stack [-1] = __builtin_return_address (0);
55 __tsan_shadow_stack++;
57 __tsan_shadow_stack--;
60 Interception for memory access interception is as follows:
62 __tsan_handle_mop (addr, flags);
63 where flags are (is_sblock | (is_store << 1) | ((sizeof (*addr) - 1) << 2).
64 is_sblock is used merely for optimization purposes and can always
65 be set to 1, see comments in instrument_mops function.
67 Ignore files can be used to selectively non instrument some functions.
68 Ignore file is specified with -ftsan-ignore=filename flag.
69 There are 3 types of ignores: (1) do not instrument memory accesses
70 in the function, (2) do not create sblocks in the function
71 and (3) recursively ignore memory accesses in the function.
72 That last ignore type requires additional instrumentation of the form:
75 __tsan_thread_ignore++;
77 __tsan_thread_ignore--;
80 The run-time library provides __tsan_handle_mop function,
81 definitions of __tsan_shadow_stack and __tsan_thread_ignore variables,
82 and intercepts synchronization related functions. */
84 #define TSAN_IGNORE "__tsan_thread_ignore"
85 #define TSAN_STACK "__tsan_shadow_stack"
86 #define TSAN_MOP "__tsan_handle_mop"
87 #define TSAN_INIT "__tsan_init"
88 #define TSAN_PERFIX "__tsan_"
89 #define MAX_MOP_BYTES 16
94 tsan_ignore_none
= 1 << 0, /* Do not ignore. */
95 tsan_ignore_func
= 1 << 1, /* Completely ignore the whole func. */
96 tsan_ignore_mop
= 1 << 2, /* Do not instrument accesses. */
97 tsan_ignore_rec
= 1 << 3, /* Do not instrument accesses recursively. */
98 tsan_ignore_hist
= 1 << 4 /* Do not create superblocks. */
101 /* Info associated with each basic block.
102 Used to determine super-blocks (see instrument_mops ()). */
113 /* Memory access descriptor. */
119 gimple_stmt_iterator gsi
;
123 /* Descriptor of an ignore file entry. */
125 struct tsan_ignore_desc
127 struct tsan_ignore_desc
*next
;
128 enum tsan_ignore_type type
;
132 /* Number of instrumented memory accesses in the current function. */
134 static int func_mops
;
136 /* Number of function calls in the current function. */
138 static int func_calls
;
140 /* Ignore status for the current function (see tsan_ignore_type). */
142 static enum tsan_ignore_type func_ignore
;
144 static int ignore_init
= 0;
145 static struct tsan_ignore_desc
*ignore_head
;
147 typedef struct mop_desc mop_desc
;
148 DEF_VEC_O (mop_desc
);
149 DEF_VEC_ALLOC_O (mop_desc
, heap
);
150 static VEC (mop_desc
, heap
) *mop_list
;
152 /* Returns a definition of a runtime variable with type TYPE and name NAME. */
155 build_var_decl (tree type
, const char *name
)
159 varpool_node_ptr var
;
161 /* Check if a user has defined it for testing. */
162 id
= get_identifier (name
);
163 var
= varpool_node_for_asm (id
);
167 gcc_assert (TREE_CODE (decl
) == VAR_DECL
);
171 decl
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
, id
, type
);
172 TREE_STATIC (decl
) = 1;
173 TREE_PUBLIC (decl
) = 1;
174 DECL_EXTERNAL (decl
) = 1;
175 if (targetm
.have_tls
)
176 DECL_TLS_MODEL (decl
) = decl_default_tls_model (decl
);
177 TREE_USED (decl
) = 1;
178 TREE_THIS_VOLATILE (decl
) = 1;
179 SET_DECL_ASSEMBLER_NAME (decl
, id
);
183 /* Builds the following decl
184 extern __thread void **__tsan_shadow_stack; */
187 get_shadow_stack_decl (void)
192 decl
= build_var_decl (build_pointer_type (ptr_type_node
), TSAN_STACK
);
196 /* Builds the following decl
197 extern __thread int __tsan_thread_ignore; */
200 get_thread_ignore_decl (void)
205 decl
= build_var_decl (integer_type_node
, TSAN_IGNORE
);
209 /* Returns a definition of a runtime function with type TYPE and name NAME. */
212 build_func_decl (tree type
, const char *name
)
215 cgraph_node_ptr func
;
218 /* Check if a user has defined it for testing. */
219 id
= get_identifier (name
);
220 func
= cgraph_node_for_asm (id
);
224 gcc_assert (TREE_CODE (decl
) == FUNCTION_DECL
);
228 decl
= build_fn_decl (name
, type
);
229 TREE_NOTHROW (decl
) = 1;
230 DECL_ATTRIBUTES (decl
) = tree_cons (get_identifier ("leaf"),
231 NULL
, DECL_ATTRIBUTES (decl
));
232 DECL_ASSEMBLER_NAME (decl
);
236 /* Builds the following decl
237 void __tsan_handle_mop (void *addr, unsigned flags); */
240 get_handle_mop_decl (void)
248 typ
= build_function_type_list (void_type_node
, ptr_type_node
,
249 integer_type_node
, NULL_TREE
);
250 decl
= build_func_decl (typ
, TSAN_MOP
);
254 /* Builds the following decl
255 void __tsan_init (void); */
266 typ
= build_function_type_list (void_type_node
, NULL_TREE
);
267 decl
= build_func_decl (typ
, TSAN_INIT
);
271 /* Adds new ignore definition to the global list.
272 TYPE is the ignore type (see tsan_ignore_type).
273 NAME is the ignore pattern (e.g. "std*string*insert"). */
276 ignore_append (enum tsan_ignore_type type
, char *name
)
278 struct tsan_ignore_desc
*desc
;
280 desc
= XCNEW (struct tsan_ignore_desc
);
282 desc
->name
= xstrdup (name
);
283 desc
->next
= ignore_head
;
287 /* Checks as to whether identifier STR matches template TEMPL.
288 Templates can only contain '*', e.g. 'std*string*insert'.
289 Templates implicitly start and end with '*'
290 since they are matched against mangled names.
291 Returns non-zero if STR is matched against TEMPL. */
294 ignore_match (char *templ
, const char *str
)
299 while (templ
&& templ
[0])
301 if (templ
[0] == '*')
308 tpos
= strchr (templ
, '*');
311 spos
= strstr (str
, templ
);
312 str
= spos
+ strlen (templ
);
322 /* Loads ignore definitions from the file specified by -ftsan-ignore=filename.
323 The result is stored in the global ignore_head list.
324 Ignore files have the following format:
326 # This is a comment - ignored
328 # The below line says to not instrument memory accesses
329 # in all functions that match 'std*string*insert'
330 fun:std*string*insert
332 # The below line says to not instrument memory accesses
333 # in the function called 'foobar' *and* in all functions
334 # that it calls recursively
337 # The below line says to not create superblocks
338 # in the function called 'barbaz'
341 # Ignore all functions in the source file
344 # Everything else is uninteresting for us (e.g. obj:)
356 if (flag_tsan_ignore
== NULL
|| flag_tsan_ignore
[0] == 0)
359 f
= fopen (flag_tsan_ignore
, "r");
362 /* Try to open it relative to main_input_filename. */
363 strncpy (buf
, main_input_filename
, sizeof (buf
));
364 buf
[sizeof (buf
) - 1] = 0;
365 line
= strrchr (buf
, '/');
369 strncpy (line
, flag_tsan_ignore
, sizeof (buf
) - (line
- buf
));
370 buf
[sizeof (buf
) - 1] = 0;
371 f
= fopen (buf
, "r");
376 fatal_error ("failed to open ignore file '%s'\n", flag_tsan_ignore
);
382 while ((sz
= getline (&line
, &linesz
, f
)) != -1)
386 /* Strip line terminator. */
387 if (line
[sz
- 1] == '\r' || line
[sz
- 1] == '\n')
389 if (strncmp (line
, "src:", sizeof ("src:") - 1) == 0)
390 ignore_append (tsan_ignore_func
, line
+ sizeof ("src:") - 1);
391 else if (strncmp (line
, "fun:", sizeof ("fun:") - 1) == 0)
392 ignore_append (tsan_ignore_mop
, line
+ sizeof ("fun:") - 1);
393 else if (strncmp (line
, "fun_r:", sizeof ("fun_r:") - 1) == 0)
394 ignore_append (tsan_ignore_rec
, line
+ sizeof ("fun_r:") - 1);
395 else if (strncmp (line
, "fun_hist:", sizeof ("fun_hist:") - 1) == 0)
396 ignore_append (tsan_ignore_hist
, line
+ sizeof ("fun_hist:") - 1);
397 /* Other lines are not interesting. */
404 /* Returns ignore status for the current function. */
406 static enum tsan_ignore_type
409 const char *func_name
;
410 const char *src_name
;
411 struct tsan_ignore_desc
*desc
;
413 if (ignore_init
== 0)
419 /* Must be some artificial thunk function. */
420 if (DECL_ARTIFICIAL (cfun
->decl
) && DECL_IGNORED_P (cfun
->decl
))
421 return tsan_ignore_func
;
423 src_name
= expand_location (cfun
->function_start_locus
).file
;
424 if (src_name
== NULL
)
427 func_name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun
->decl
));
428 /* Ignore all functions starting with __tsan_ - intended for testing. */
429 if (strncmp (func_name
, TSAN_PERFIX
, sizeof (TSAN_PERFIX
) - 1) == 0)
430 return tsan_ignore_func
;
432 /* Ignore global ctors. */
433 if (strncmp (func_name
, "_GLOBAL", sizeof ("_GLOBAL") - 1) == 0)
434 return tsan_ignore_func
;
436 for (desc
= ignore_head
; desc
; desc
= desc
->next
)
438 if (desc
->type
== tsan_ignore_func
)
440 if (ignore_match (desc
->name
, src_name
))
443 else if (ignore_match (desc
->name
, func_name
))
446 return tsan_ignore_none
;
449 /* Builds either (__tsan_shadow_stack += 1) or (__tsan_shadow_stack -= 1)
450 expression depending on DO_DEC parameter. Appends the result to SEQ. */
453 build_stack_op (gimple_seq
*seq
, bool do_dec
)
456 double_int op_size_cst
;
457 unsigned long long size_val
;
458 unsigned long long size_valhi
;
464 op_size
= TYPE_SIZE (ptr_type_node
);
465 op_size_cst
= tree_to_double_int (op_size
);
466 size_val
= op_size_cst
.low
/ BITS_PER_UNIT
;
470 size_val
= -size_val
;
473 op_size
= build_int_cst_wide (sizetype
, size_val
, size_valhi
);
474 sstack_decl
= get_shadow_stack_decl ();
475 op_expr
= build2 (POINTER_PLUS_EXPR
, ptr_type_node
, sstack_decl
, op_size
);
478 op_expr
= force_gimple_operand (op_expr
, &s
, true, NULL_TREE
);
479 gimple_seq_add_seq (seq
, s
);
481 assign
= gimple_build_assign (sstack_decl
, op_expr
);
482 gimple_seq_add_stmt (seq
, assign
);
485 /* Builds either (__tsan_thread_ignore += 1) or (__tsan_thread_ignore -= 1)
486 expression depending on OP parameter. Stores the result in SEQ. */
489 build_rec_ignore_op (gimple_seq
*seq
, enum tree_code op
)
496 ignore_decl
= get_thread_ignore_decl ();
497 rec_expr
= build2 (op
, integer_type_node
, ignore_decl
, integer_one_node
);
499 rec_expr
= force_gimple_operand (rec_expr
, &rec_inc
, true, NULL_TREE
);
500 gimple_seq_add_seq (seq
, rec_inc
);
501 rec_assign
= gimple_build_assign (ignore_decl
, rec_expr
);
502 gimple_seq_add_stmt (seq
, rec_assign
);
505 /* Build the following gimple sequence:
506 __tsan_shadow_stack [-1] = __builtin_return_address (0);
507 Stores the result in SEQ. */
510 build_stack_assign (gimple_seq
*seq
)
519 retaddr_decl
= implicit_built_in_decls
[BUILT_IN_RETURN_ADDRESS
];
520 pc_addr
= build_call_expr (retaddr_decl
, 1, integer_zero_node
);
521 op_size
= build_int_cst_wide (sizetype
, -(POINTER_SIZE
/ BITS_PER_UNIT
), -1);
522 op_expr
= build2 (POINTER_PLUS_EXPR
, ptr_type_node
,
523 get_shadow_stack_decl (), op_size
);
524 stack_op
= build1 (INDIRECT_REF
, ptr_type_node
, op_expr
);
525 assign
= build2 (MODIFY_EXPR
, ptr_type_node
, stack_op
, pc_addr
);
526 force_gimple_operand (assign
, seq
, true, NULL_TREE
);
529 /* Builds the following gimple sequence:
530 __tsan_handle_mop (&EXPR,
531 (IS_SBLOCK | (IS_STORE << 1) | ((sizeof (EXPR) - 1) << 2);
532 The result is stored in GSEQ. */
535 instr_mop (tree expr
, int is_store
, int is_sblock
, gimple_seq
*gseq
)
544 gcc_assert (gseq
!= 0 && *gseq
== 0);
545 gcc_assert (is_gimple_addressable (expr
));
547 addr_expr
= build_addr (unshare_expr (expr
), current_function_decl
);
548 expr_type
= TREE_TYPE (expr
);
549 while (TREE_CODE (expr_type
) == ARRAY_TYPE
)
550 expr_type
= TREE_TYPE (expr_type
);
551 size
= TREE_INT_CST_LOW (TYPE_SIZE (expr_type
));
552 size
= size
/ BITS_PER_UNIT
;
553 if (size
> MAX_MOP_BYTES
)
554 size
= MAX_MOP_BYTES
;
556 flags
= ((!!is_sblock
<< 0) + (!!is_store
<< 1) + (size
<< 2));
557 flags_expr
= build_int_cst (unsigned_type_node
, flags
);
558 call_expr
= build_call_expr (get_handle_mop_decl (),
559 2, addr_expr
, flags_expr
);
560 force_gimple_operand (call_expr
, gseq
, true, 0);
563 /* Builds the following gimple sequence:
564 int is_store = (EXPR != RHS); // The temp is not actually introduced.
565 __tsan_handle_mop (&EXPR,
566 (IS_SBLOCK | (IS_STORE << 1) | ((sizeof (EXPR) - 1) << 2);
567 The result is stored in GSEQ. */
570 instr_vptr_store (tree expr
, tree rhs
, int is_sblock
, gimple_seq
*gseq
)
578 gimple_seq flags_seq
;
582 expr_ptr
= build_addr (unshare_expr (expr
), current_function_decl
);
583 addr_expr
= force_gimple_operand (expr_ptr
, gseq
, true, NULL_TREE
);
584 expr_type
= TREE_TYPE (expr
);
585 while (TREE_CODE (expr_type
) == ARRAY_TYPE
)
586 expr_type
= TREE_TYPE (expr_type
);
587 size
= TREE_INT_CST_LOW (TYPE_SIZE (expr_type
));
588 size
= size
/ BITS_PER_UNIT
;
589 if (size
> MAX_MOP_BYTES
)
590 size
= MAX_MOP_BYTES
;
592 flags
= ((!!is_sblock
<< 0) + (size
<< 2));
593 flags_expr
= build_int_cst (unsigned_type_node
, flags
);
594 is_store_expr
= build2 (NE_EXPR
, unsigned_type_node
,
595 build1 (VIEW_CONVERT_EXPR
, size_type_node
, expr
),
596 build1 (VIEW_CONVERT_EXPR
, size_type_node
, rhs
));
597 is_store_expr
= build2 (LSHIFT_EXPR
, unsigned_type_node
,
598 is_store_expr
, integer_one_node
);
599 flags_expr
= build2 (BIT_IOR_EXPR
, unsigned_type_node
,
600 is_store_expr
, flags_expr
);
602 flags_expr
= force_gimple_operand (flags_expr
, &flags_seq
, true, NULL_TREE
);
603 gimple_seq_add_seq (gseq
, flags_seq
);
604 collect
= gimple_build_call (
605 get_handle_mop_decl (), 2, addr_expr
, flags_expr
);
606 gimple_seq_add_stmt (gseq
, collect
);
609 /* Returns true if function entry and exit need to be instrumented. */
612 is_func_instrumentation_required (void)
614 if (func_calls
== 0 && func_mops
== 0)
616 if (func_ignore
!= tsan_ignore_rec
)
618 if (func_ignore
== tsan_ignore_rec
&& func_calls
!= 0)
623 /* Returns gimple seq that needs to be inserted at function entry. */
626 build_func_entry_instr (void)
631 gcc_assert (is_func_instrumentation_required ());
632 if (func_ignore
!= tsan_ignore_rec
)
634 build_stack_assign (&gs
);
635 build_stack_op (&gs
, false);
638 build_rec_ignore_op (&gs
, PLUS_EXPR
);
642 /* Returns gimple seq that needs to be inserted before function exit. */
645 build_func_exit_instr (void)
650 gcc_assert (is_func_instrumentation_required ());
651 if (func_ignore
!= tsan_ignore_rec
)
652 build_stack_op (&gs
, true);
654 build_rec_ignore_op (&gs
, MINUS_EXPR
);
658 /* Sets location LOC for all gimples in the SEQ. */
661 set_location (gimple_seq seq
, location_t loc
)
665 for (n
= gimple_seq_first (seq
); n
!= NULL
; n
= n
->next
)
666 gimple_set_location (n
->stmt
, loc
);
669 /* Check as to whether EXPR refers to a store to vptr. */
672 is_vptr_store (gimple stmt
, tree expr
, int is_store
)
675 && gimple_assign_single_p (stmt
)
676 && TREE_CODE (expr
) == COMPONENT_REF
)
678 tree field
= TREE_OPERAND (expr
, 1);
679 if (TREE_CODE (field
) == FIELD_DECL
680 && DECL_VIRTUAL_P (field
))
681 return gimple_assign_rhs1 (stmt
);
686 /* Checks as to whether EXPR refers to constant var/field/param.
687 Don't bother to instrument them. */
690 is_load_of_const (tree expr
, int is_store
)
694 if (TREE_CODE (expr
) == COMPONENT_REF
)
695 expr
= TREE_OPERAND (expr
, 1);
696 if (TREE_CODE (expr
) == VAR_DECL
697 || TREE_CODE (expr
) == PARM_DECL
698 || TREE_CODE (expr
) == FIELD_DECL
)
700 if (TREE_READONLY (expr
))
706 /* Checks as to whether EXPR needs to be instrumented,
707 if so puts it into the MOP_LIST.
708 GSI is the iterator from which EXPR was extracted.
709 IS_STORE says as to whether EXPR refers to a memory store
713 handle_expr (gimple_stmt_iterator gsi
, tree expr
, int is_store
,
714 VEC (mop_desc
, heap
) **mop_list
)
716 enum tree_code tcode
;
722 base
= get_base_address (expr
);
723 if (base
== NULL_TREE
724 || TREE_CODE (base
) == SSA_NAME
725 || TREE_CODE (base
) == STRING_CST
)
728 tcode
= TREE_CODE (expr
);
730 /* Below are things we do not instrument
731 (no possibility of races or not implemented yet). */
732 if ((func_ignore
& (tsan_ignore_mop
| tsan_ignore_rec
))
733 /* Compiler-emitted artificial variables. */
734 || (DECL_P (expr
) && DECL_ARTIFICIAL (expr
))
735 /* The var does not live in memory -> no possibility of races. */
736 || (tcode
== VAR_DECL
737 && TREE_ADDRESSABLE (expr
) == 0
738 && DECL_EXTERNAL (expr
) == 0)
739 /* TODO (dvyukov): not implemented. */
740 || TREE_CODE (TREE_TYPE (expr
)) == RECORD_TYPE
741 /* TODO (dvyukov): not implemented. */
742 || tcode
== CONSTRUCTOR
743 /* TODO (dvyukov): not implemented. */
744 || tcode
== PARM_DECL
745 /* Load of a const variable/parameter/field. */
746 || is_load_of_const (expr
, is_store
))
749 if (tcode
== COMPONENT_REF
)
751 tree field
= TREE_OPERAND (expr
, 1);
752 if (TREE_CODE (field
) == FIELD_DECL
)
754 fld_off
= TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field
));
755 fld_size
= TREE_INT_CST_LOW (DECL_SIZE (field
));
756 if (((fld_off
% BITS_PER_UNIT
) != 0)
757 || ((fld_size
% BITS_PER_UNIT
) != 0))
759 /* As of now it crashes compilation.
760 TODO (dvyukov): handle bit-fields as if touching
767 /* TODO (dvyukov): handle other cases
768 (FIELD_DECL, MEM_REF, ARRAY_RANGE_REF, TARGET_MEM_REF, ADDR_EXPR). */
769 if (tcode
!= ARRAY_REF
771 && tcode
!= COMPONENT_REF
772 && tcode
!= INDIRECT_REF
779 mop
.is_store
= is_store
;
780 VEC_safe_push (mop_desc
, heap
, *mop_list
, &mop
);
783 /* Collects all interesting memory accesses from the gimple pointed to by GSI
787 handle_gimple (gimple_stmt_iterator gsi
, VEC (mop_desc
, heap
) **mop_list
)
792 enum gimple_code gcode
;
796 stmt
= gsi_stmt (gsi
);
797 gcode
= gimple_code (stmt
);
798 gcc_assert (gcode
< LAST_AND_UNUSED_GIMPLE_CODE
);
805 memset (&mop
, 0, sizeof (mop
));
807 VEC_safe_push (mop_desc
, heap
, *mop_list
, &mop
);
813 /* Handle assignment lhs as store. */
814 lhs
= gimple_assign_lhs (stmt
);
815 handle_expr (gsi
, lhs
, 1, mop_list
);
817 /* Handle operands as loads. */
818 for (i
= 1; i
< gimple_num_ops (stmt
); i
++)
820 rhs
= gimple_op (stmt
, i
);
821 handle_expr (gsi
, rhs
, 0, mop_list
);
831 /* Instruments single basic block BB.
832 BBD is the sblock info associated with the block. */
835 instrument_bblock (struct bb_data
*bbd
, basic_block bb
)
839 gimple_stmt_iterator gsi
;
840 struct mop_desc
*mop
;
843 expanded_location eloc
;
844 gimple_seq instr_seq
;
847 /* Iterate over all gimples and collect interesting mops into mop_list. */
848 VEC_free (mop_desc
, heap
, mop_list
);
849 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
851 handle_gimple (gsi
, &mop_list
);
855 for (ix
= 0; VEC_iterate (mop_desc
, mop_list
, ix
, mop
); ix
+= 1)
857 if (mop
->is_call
!= 0)
859 /* After a function call we must start a brand new sblock,
860 because the function can contain synchronization. */
866 stmt
= gsi_stmt (mop
->gsi
);
867 loc
= gimple_location (stmt
);
868 eloc
= expand_location (loc
);
870 /* Check as to whether we may not set sblock flag for the access. */
871 is_sblock
= (bbd
->has_sb
== 0
874 && strcmp (eloc
.file
, bbd
->sb_file
) == 0
875 && eloc
.line
>= bbd
->sb_line_min
876 && eloc
.line
<= bbd
->sb_line_max
));
878 if (func_ignore
== tsan_ignore_hist
)
883 /* Start new sblock with new source info. */
885 bbd
->sb_file
= eloc
.file
;
886 bbd
->sb_line_min
= eloc
.line
;
887 bbd
->sb_line_max
= eloc
.line
+ SBLOCK_SIZE
;
891 rhs
= is_vptr_store (stmt
, mop
->expr
, mop
->is_store
);
893 instr_mop (mop
->expr
, mop
->is_store
, is_sblock
, &instr_seq
);
895 instr_vptr_store (mop
->expr
, rhs
, is_sblock
, &instr_seq
);
896 gcc_assert (instr_seq
!= 0);
897 set_location (instr_seq
, loc
);
898 /* Instrumentation for assignment of a function result
899 must be inserted after the call. Instrumentation for
900 reads of function arguments must be inserted before the call.
901 That's because the call can contain synchronization. */
902 if (is_gimple_call (stmt
) && mop
->is_store
== 1)
903 gsi_insert_seq_after (&mop
->gsi
, instr_seq
, GSI_NEW_STMT
);
905 gsi_insert_seq_before (&mop
->gsi
, instr_seq
, GSI_SAME_STMT
);
909 /* Instruments all interesting memory accesses in the current function. */
912 instrument_mops (void)
915 int *blocks_inverted
;
916 struct bb_data
*bb_data
;
917 struct bb_data
*pred
;
921 int sb_line_min
, sb_line_max
;
924 /* The function does basic block traversal in reverse top sort order
925 of the inverted CFG. Such order is required to properly mark super-blocks.
926 The idea behind super-blocks is as follows.
927 If several memory accesses happen within SBLOCK_SIZE source code lines
928 from each other, then we only mark the first access as SBLOCK.
929 This allows the runtime library to memorize a stack trace
930 only for the first access and do not memorize for others.
931 This significantly reduces memory consumption in exchange for slightly
932 imprecise stack traces for previous accesses. */
934 blocks_inverted
= XNEWVEC (int, last_basic_block
+ NUM_FIXED_BLOCKS
);
935 bb_data
= XCNEWVEC (struct bb_data
, last_basic_block
+ NUM_FIXED_BLOCKS
);
936 cnt
= inverted_post_order_compute (blocks_inverted
);
937 for (i
= 0; i
< cnt
; i
++)
939 bb
= BASIC_BLOCK (blocks_inverted
[i
]);
940 bbd
= &bb_data
[bb
->index
];
941 /* Iterate over all predecessors and merge their sblock info. */
942 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
944 pred
= &bb_data
[e
->src
->index
];
945 if (!pred
->is_visited
|| !pred
->has_sb
|| pred
== bbd
)
947 /* If there is a not visited predecessor,
948 or a predecessor with no active sblock info,
949 or a self-loop, then we will have to start
950 a brand new sblock on next memory access. */
954 else if (bbd
->has_sb
== 0)
956 /* If it's a first predecessor, just copy the info. */
958 bbd
->sb_file
= pred
->sb_file
;
959 bbd
->sb_line_min
= pred
->sb_line_min
;
960 bbd
->sb_line_max
= pred
->sb_line_max
;
964 /* Otherwise, find the interception
965 between two sblock descriptors. */
967 if (bbd
->sb_file
!= 0 && pred
->sb_file
!= 0
968 && strcmp (bbd
->sb_file
, pred
->sb_file
) == 0)
970 sb_line_min
= MAX (bbd
->sb_line_min
, pred
->sb_line_min
);
971 sb_line_max
= MIN (bbd
->sb_line_max
, pred
->sb_line_max
);
972 if (sb_line_min
<= sb_line_max
)
975 bbd
->sb_line_min
= sb_line_min
;
976 bbd
->sb_line_max
= sb_line_max
;
979 /* No interception, have to start new sblock. */
980 if (bbd
->has_sb
== 0)
985 instrument_bblock (bbd
, bb
);
989 free (blocks_inverted
);
993 /* Instruments function entry. */
996 instrument_func_entry (void)
999 basic_block entry_bb
;
1001 gimple_stmt_iterator gsi
;
1003 /* Insert new BB before the first BB. */
1004 seq
= build_func_entry_instr ();
1005 gcc_assert (seq
!= NULL
);
1006 entry_bb
= ENTRY_BLOCK_PTR
;
1007 entry_edge
= single_succ_edge (entry_bb
);
1008 set_location (seq
, cfun
->function_start_locus
);
1009 entry_bb
= split_edge (entry_edge
);
1010 gsi
= gsi_start_bb (entry_bb
);
1011 gsi_insert_seq_after (&gsi
, seq
, GSI_NEW_STMT
);
1014 /* Instruments function exits. */
1017 instrument_func_exit (void)
1021 basic_block exit_bb
;
1022 gimple_stmt_iterator gsi
;
1027 /* Find all function exits. */
1028 exit_bb
= EXIT_BLOCK_PTR
;
1029 FOR_EACH_EDGE (e
, ei
, exit_bb
->preds
)
1031 gsi
= gsi_last_bb (e
->src
);
1032 stmt
= gsi_stmt (gsi
);
1033 gcc_assert (gimple_code (stmt
) == GIMPLE_RETURN
);
1034 loc
= gimple_location (stmt
);
1035 seq
= build_func_exit_instr ();
1036 gcc_assert (seq
!= NULL
);
1037 set_location (seq
, loc
);
1038 gsi_insert_seq_before (&gsi
, seq
, GSI_SAME_STMT
);
1042 /* ThreadSanitizer instrumentation pass. */
1047 struct gimplify_ctx gctx
;
1049 func_ignore
= tsan_ignore ();
1050 if (func_ignore
== tsan_ignore_func
)
1056 push_gimplify_context (&gctx
);
1060 if (is_func_instrumentation_required ())
1062 instrument_func_entry ();
1063 instrument_func_exit ();
1066 pop_gimplify_context (NULL
);
1071 /* The pass's gate. */
1076 return flag_tsan
!= 0;
1079 /* Inserts __tsan_init () into the list of CTORs. */
1081 void tsan_finish_file (void)
1083 tree ctor_statements
;
1085 ctor_statements
= NULL_TREE
;
1086 append_to_statement_list (build_call_expr (get_init_decl (), 0),
1088 cgraph_build_static_cdtor ('I', ctor_statements
,
1089 MAX_RESERVED_INIT_PRIORITY
- 1);
1092 /* The pass descriptor. */
1094 struct gimple_opt_pass pass_tsan
= {{
1097 tsan_gate
, /* gate */
1098 tsan_pass
, /* execute */
1101 0, /* static_pass_number */
1102 TV_NONE
, /* tv_id */
1103 PROP_ssa
| PROP_cfg
, /* properties_required */
1104 0, /* properties_provided */
1105 0, /* properties_destroyed */
1106 0, /* todo_flags_start */
1107 TODO_dump_cgraph
| TODO_dump_func
| TODO_verify_all
1108 | TODO_update_ssa
| TODO_update_address_taken
/* todo_flags_finish */