Commit 32b4b7f5 by Dmitry Vyukov Committed by Wei Mi

builtins.def (DEF_SANITIZER_BUILTIN): Define tsan builtins.

2012-11-22  Dmitry Vyukov  <dvyukov@google.com>
	    Wei Mi  <wmi@google.com>

	* builtins.def (DEF_SANITIZER_BUILTIN): Define tsan builtins. 
	* sanitizer.def: Ditto. 
	* Makefile.in (tsan.o): Add tsan.o target. 
	(BUILTINS_DEF): Add sanitizer.def.
	* passes.c (init_optimization_passes): Add tsan passes.
	* tree-pass.h (register_pass_info): Ditto.
	* toplev.c (compile_file): Ditto. 
	* doc/invoke.texi: Document tsan related options.
	* gcc.c (LINK_COMMAND_SPEC): Add LIBTSAN_SPEC in link command if
	-fsanitize=thread.
	* tsan.c: New file about tsan.
	* tsan.h: Ditto.
	* common.opt: Add -fsanitize=thread.


Co-Authored-By: Wei Mi <wmi@google.com>

From-SVN: r193736
parent bdb6985c
2012-11-22 Dmitry Vyukov <dvyukov@google.com>
Wei Mi <wmi@google.com>
* builtins.def (DEF_SANITIZER_BUILTIN): Define tsan builtins.
* sanitizer.def: Ditto.
* Makefile.in (tsan.o): Add tsan.o target.
(BUILTINS_DEF): Add sanitizer.def.
* passes.c (init_optimization_passes): Add tsan passes.
* tree-pass.h (register_pass_info): Ditto.
* toplev.c (compile_file): Ditto.
* doc/invoke.texi: Document tsan related options.
* gcc.c (LINK_COMMAND_SPEC): Add LIBTSAN_SPEC in link command if
-fsanitize=thread.
* tsan.c: New file about tsan.
* tsan.h: Ditto.
* common.opt: Add -fsanitize=thread.
2012-11-22 Uros Bizjak <ubizjak@gmail.com> 2012-11-22 Uros Bizjak <ubizjak@gmail.com>
* doc/md.texi (RTL Templates Transformation): Use @pxref for * doc/md.texi (RTL Templates Transformation): Use @pxref for
...@@ -863,7 +863,7 @@ RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H) ...@@ -863,7 +863,7 @@ RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
PARAMS_H = params.h params.def PARAMS_H = params.h params.def
BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \ BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \
gtm-builtins.def gtm-builtins.def sanitizer.def
INTERNAL_FN_DEF = internal-fn.def INTERNAL_FN_DEF = internal-fn.def
INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF) INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \ TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
...@@ -1365,6 +1365,7 @@ OBJS = \ ...@@ -1365,6 +1365,7 @@ OBJS = \
trans-mem.o \ trans-mem.o \
tree-affine.o \ tree-affine.o \
asan.o \ asan.o \
tsan.o \
tree-call-cdce.o \ tree-call-cdce.o \
tree-cfg.o \ tree-cfg.o \
tree-cfgcleanup.o \ tree-cfgcleanup.o \
...@@ -2228,6 +2229,12 @@ asan.o : asan.c asan.h $(CONFIG_H) $(SYSTEM_H) $(GIMPLE_H) \ ...@@ -2228,6 +2229,12 @@ asan.o : asan.c asan.h $(CONFIG_H) $(SYSTEM_H) $(GIMPLE_H) \
output.h coretypes.h $(GIMPLE_PRETTY_PRINT_H) \ output.h coretypes.h $(GIMPLE_PRETTY_PRINT_H) \
tree-iterator.h $(TREE_FLOW_H) $(TREE_PASS_H) \ tree-iterator.h $(TREE_FLOW_H) $(TREE_PASS_H) \
$(TARGET_H) $(EXPR_H) $(OPTABS_H) $(TM_P_H) $(TARGET_H) $(EXPR_H) $(OPTABS_H) $(TM_P_H)
tsan.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
$(GIMPLE_H) $(DIAGNOSTIC_H) langhooks.h \
$(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(CGRAPH_H) $(GGC_H) \
$(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) \
$(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) tree-iterator.h \
intl.h cfghooks.h output.h options.h c-family/c-common.h tsan.h
tree-ssa-tail-merge.o: tree-ssa-tail-merge.c \ tree-ssa-tail-merge.o: tree-ssa-tail-merge.c \
$(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_H) \ $(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_H) \
$(FLAGS_H) $(TM_P_H) $(BASIC_BLOCK_H) \ $(FLAGS_H) $(TM_P_H) $(BASIC_BLOCK_H) \
...@@ -2689,7 +2696,8 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ ...@@ -2689,7 +2696,8 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) \ $(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) \
$(OPTS_H) params.def tree-mudflap.h $(TREE_PASS_H) $(GIMPLE_H) \ $(OPTS_H) params.def tree-mudflap.h $(TREE_PASS_H) $(GIMPLE_H) \
tree-ssa-alias.h $(PLUGIN_H) realmpfr.h tree-diagnostic.h \ tree-ssa-alias.h $(PLUGIN_H) realmpfr.h tree-diagnostic.h \
$(TREE_PRETTY_PRINT_H) opts-diagnostic.h $(COMMON_TARGET_H) $(TREE_PRETTY_PRINT_H) opts-diagnostic.h $(COMMON_TARGET_H) \
tsan.h
hwint.o : hwint.c $(CONFIG_H) $(SYSTEM_H) $(DIAGNOSTIC_CORE_H) hwint.o : hwint.c $(CONFIG_H) $(SYSTEM_H) $(DIAGNOSTIC_CORE_H)
...@@ -3740,6 +3748,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ ...@@ -3740,6 +3748,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/target-globals.h \ $(srcdir)/target-globals.h \
$(srcdir)/ipa-inline.h \ $(srcdir)/ipa-inline.h \
$(srcdir)/asan.c \ $(srcdir)/asan.c \
$(srcdir)/tsan.c \
@all_gtfiles@ @all_gtfiles@
# Compute the list of GT header files from the corresponding C sources, # Compute the list of GT header files from the corresponding C sources,
......
...@@ -149,6 +149,15 @@ along with GCC; see the file COPYING3. If not see ...@@ -149,6 +149,15 @@ along with GCC; see the file COPYING3. If not see
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
true, true, true, ATTRS, false, flag_tm) true, true, true, ATTRS, false, flag_tm)
/* Builtin used by the implementation of libsanitizer. These
functions are mapped to the actual implementation of the
libtsan library. */
#undef DEF_SANITIZER_BUILTIN
#define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
true, true, true, ATTRS, true, \
flag_tsan)
/* Define an attribute list for math functions that are normally /* Define an attribute list for math functions that are normally
"impure" because some of them may write into global memory for "impure" because some of them may write into global memory for
`errno'. If !flag_errno_math they are instead "const". */ `errno'. If !flag_errno_math they are instead "const". */
...@@ -825,3 +834,7 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST) ...@@ -825,3 +834,7 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
/* GTM builtins. */ /* GTM builtins. */
#include "gtm-builtins.def" #include "gtm-builtins.def"
/* Sanitizer builtins. */
#include "sanitizer.def"
...@@ -844,6 +844,10 @@ fsanitize=address ...@@ -844,6 +844,10 @@ fsanitize=address
Common Report Var(flag_asan) Common Report Var(flag_asan)
Enable AddressSanitizer, a memory error detector Enable AddressSanitizer, a memory error detector
fsanitize=thread
Common Report Var(flag_tsan)
Enable ThreadSanitizer, a data race detector
fasynchronous-unwind-tables fasynchronous-unwind-tables
Common Report Var(flag_asynchronous_unwind_tables) Optimization Common Report Var(flag_asynchronous_unwind_tables) Optimization
Generate unwind tables that are exact at each instruction boundary Generate unwind tables that are exact at each instruction boundary
...@@ -2519,6 +2523,9 @@ Driver ...@@ -2519,6 +2523,9 @@ Driver
static-libasan static-libasan
Driver Driver
static-libtsan
Driver
symbolic symbolic
Driver Driver
......
...@@ -453,7 +453,8 @@ Objective-C and Objective-C++ Dialects}. ...@@ -453,7 +453,8 @@ Objective-C and Objective-C++ Dialects}.
@xref{Link Options,,Options for Linking}. @xref{Link Options,,Options for Linking}.
@gccoptlist{@var{object-file-name} -l@var{library} @gol @gccoptlist{@var{object-file-name} -l@var{library} @gol
-nostartfiles -nodefaultlibs -nostdlib -pie -rdynamic @gol -nostartfiles -nodefaultlibs -nostdlib -pie -rdynamic @gol
-s -static -static-libgcc -static-libasan -static-libstdc++ @gol -s -static -static-libgcc -static-libstdc++ @gol
-static-libasan -static-libtsan @gol
-shared -shared-libgcc -symbolic @gol -shared -shared-libgcc -symbolic @gol
-T @var{script} -Wl,@var{option} -Xlinker @var{option} @gol -T @var{script} -Wl,@var{option} -Xlinker @var{option} @gol
-u @var{symbol}} -u @var{symbol}}
...@@ -6862,6 +6863,12 @@ Memory access instructions will be instrumented to detect ...@@ -6862,6 +6863,12 @@ Memory access instructions will be instrumented to detect
out-of-bounds and use-after-free bugs. So far only heap bugs will be detected. out-of-bounds and use-after-free bugs. So far only heap bugs will be detected.
See @uref{http://code.google.com/p/address-sanitizer/} for more details. See @uref{http://code.google.com/p/address-sanitizer/} for more details.
@item -fsanitize=thread
Enable ThreadSanitizer, a fast data race detector.
Memory access instructions will be instrumented to detect
data race bugs.
See @uref{http://code.google.com/p/data-race-test/wiki/ThreadSanitizer} for more details.
@item -fmudflap -fmudflapth -fmudflapir @item -fmudflap -fmudflapth -fmudflapir
@opindex fmudflap @opindex fmudflap
@opindex fmudflapth @opindex fmudflapth
...@@ -9947,6 +9954,15 @@ option is not used, then this links against the shared version of ...@@ -9947,6 +9954,15 @@ option is not used, then this links against the shared version of
driver to link @file{libasan} statically, without necessarily linking driver to link @file{libasan} statically, without necessarily linking
other libraries statically. other libraries statically.
@item -static-libtsan
When the @option{-fsanitize=thread} option is used to link a program,
the GCC driver automatically links against @option{libtsan}. If
@file{libtsan} is available as a shared library, and the @option{-static}
option is not used, then this links against the shared version of
@file{libtsan}. The @option{-static-libtsan} option directs the GCC
driver to link @file{libtsan} statically, without necessarily linking
other libraries statically.
@item -static-libstdc++ @item -static-libstdc++
When the @command{g++} program is used to link a C++ program, it When the @command{g++} program is used to link a C++ program, it
normally automatically links against @option{libstdc++}. If normally automatically links against @option{libstdc++}. If
......
...@@ -560,6 +560,15 @@ proper position among the other output files. */ ...@@ -560,6 +560,15 @@ proper position among the other output files. */
#endif #endif
#endif #endif
#ifndef LIBTSAN_SPEC
#ifdef HAVE_LD_STATIC_DYNAMIC
#define LIBTSAN_SPEC "%{static-libtsan:" LD_STATIC_OPTION \
"} -ltsan %{static-libtsan:" LD_DYNAMIC_OPTION "}"
#else
#define LIBTSAN_SPEC "-ltsan"
#endif
#endif
/* config.h can define LIBGCC_SPEC to override how and when libgcc.a is /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
included. */ included. */
#ifndef LIBGCC_SPEC #ifndef LIBGCC_SPEC
...@@ -704,6 +713,7 @@ proper position among the other output files. */ ...@@ -704,6 +713,7 @@ proper position among the other output files. */
%(mflib) " STACK_SPLIT_SPEC "\ %(mflib) " STACK_SPLIT_SPEC "\
%{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\ %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
%{fsanitize=address:" LIBASAN_SPEC "%{static:%ecannot specify -static with -fsanitize=address}}\ %{fsanitize=address:" LIBASAN_SPEC "%{static:%ecannot specify -static with -fsanitize=address}}\
%{fsanitize=thread:" LIBTSAN_SPEC "}\
%{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\ %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
%{!nostdlib:%{!nostartfiles:%E}} %{T*} }}}}}}" %{!nostdlib:%{!nostartfiles:%E}} %{T*} }}}}}}"
#endif #endif
......
...@@ -1450,6 +1450,7 @@ init_optimization_passes (void) ...@@ -1450,6 +1450,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_pre); NEXT_PASS (pass_pre);
NEXT_PASS (pass_sink_code); NEXT_PASS (pass_sink_code);
NEXT_PASS (pass_asan); NEXT_PASS (pass_asan);
NEXT_PASS (pass_tsan);
NEXT_PASS (pass_tree_loop); NEXT_PASS (pass_tree_loop);
{ {
struct opt_pass **p = &pass_tree_loop.pass.sub; struct opt_pass **p = &pass_tree_loop.pass.sub;
...@@ -1556,6 +1557,7 @@ init_optimization_passes (void) ...@@ -1556,6 +1557,7 @@ init_optimization_passes (void)
} }
NEXT_PASS (pass_lower_complex_O0); NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_asan_O0); NEXT_PASS (pass_asan_O0);
NEXT_PASS (pass_tsan_O0);
NEXT_PASS (pass_cleanup_eh); NEXT_PASS (pass_cleanup_eh);
NEXT_PASS (pass_lower_resx); NEXT_PASS (pass_lower_resx);
NEXT_PASS (pass_nrv); NEXT_PASS (pass_nrv);
......
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_FUNC_ENTRY, "__tsan_func_entry",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_FUNC_EXIT, "__tsan_func_exit",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_VPTR_UPDATE, "__tsan_vptr_update",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_1, "__tsan_read1",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_2, "__tsan_read2",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_4, "__tsan_read4",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_8, "__tsan_read8",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_16, "__tsan_read16",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_1, "__tsan_write1",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_2, "__tsan_write2",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_4, "__tsan_write4",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_8, "__tsan_write8",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_16, "__tsan_write16",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
...@@ -73,6 +73,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -73,6 +73,7 @@ along with GCC; see the file COPYING3. If not see
#include "alloc-pool.h" #include "alloc-pool.h"
#include "tree-mudflap.h" #include "tree-mudflap.h"
#include "asan.h" #include "asan.h"
#include "tsan.h"
#include "gimple.h" #include "gimple.h"
#include "tree-ssa-alias.h" #include "tree-ssa-alias.h"
#include "plugin.h" #include "plugin.h"
...@@ -575,6 +576,9 @@ compile_file (void) ...@@ -575,6 +576,9 @@ compile_file (void)
if (flag_asan) if (flag_asan)
asan_finish_file (); asan_finish_file ();
if (flag_tsan)
tsan_finish_file ();
output_shared_constant_pool (); output_shared_constant_pool ();
output_object_blocks (); output_object_blocks ();
finish_tm_clone_pairs (); finish_tm_clone_pairs ();
......
...@@ -261,6 +261,8 @@ extern struct gimple_opt_pass pass_mudflap_1; ...@@ -261,6 +261,8 @@ extern struct gimple_opt_pass pass_mudflap_1;
extern struct gimple_opt_pass pass_mudflap_2; extern struct gimple_opt_pass pass_mudflap_2;
extern struct gimple_opt_pass pass_asan; extern struct gimple_opt_pass pass_asan;
extern struct gimple_opt_pass pass_asan_O0; extern struct gimple_opt_pass pass_asan_O0;
extern struct gimple_opt_pass pass_tsan;
extern struct gimple_opt_pass pass_tsan_O0;
extern struct gimple_opt_pass pass_lower_cf; extern struct gimple_opt_pass pass_lower_cf;
extern struct gimple_opt_pass pass_refactor_eh; extern struct gimple_opt_pass pass_refactor_eh;
extern struct gimple_opt_pass pass_lower_eh; extern struct gimple_opt_pass pass_lower_eh;
......
/* GCC instrumentation plugin for ThreadSanitizer.
Copyright (C) 2011, 2012 Free Software Foundation, Inc.
Contributed by Dmitry Vyukov <dvyukov@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "intl.h"
#include "tm.h"
#include "basic-block.h"
#include "gimple.h"
#include "function.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "tree-iterator.h"
#include "langhooks.h"
#include "output.h"
#include "options.h"
#include "target.h"
#include "cgraph.h"
#include "diagnostic.h"
/* Number of instrumented memory accesses in the current function. */
/* Builds the following decl
void __tsan_read/writeX (void *addr); */
static tree
get_memory_access_decl (bool is_write, unsigned size)
{
enum built_in_function fcode;
if (size <= 1)
fcode = is_write ? BUILT_IN_TSAN_WRITE_1
: BUILT_IN_TSAN_READ_1;
else if (size <= 3)
fcode = is_write ? BUILT_IN_TSAN_WRITE_2
: BUILT_IN_TSAN_READ_2;
else if (size <= 7)
fcode = is_write ? BUILT_IN_TSAN_WRITE_4
: BUILT_IN_TSAN_READ_4;
else if (size <= 15)
fcode = is_write ? BUILT_IN_TSAN_WRITE_8
: BUILT_IN_TSAN_READ_8;
else
fcode = is_write ? BUILT_IN_TSAN_WRITE_16
: BUILT_IN_TSAN_READ_16;
return builtin_decl_implicit (fcode);
}
/* Check as to whether EXPR refers to a store to vptr. */
static tree
is_vptr_store (gimple stmt, tree expr, bool is_write)
{
if (is_write == true
&& gimple_assign_single_p (stmt)
&& TREE_CODE (expr) == COMPONENT_REF)
{
tree field = TREE_OPERAND (expr, 1);
if (TREE_CODE (field) == FIELD_DECL
&& DECL_VIRTUAL_P (field))
return gimple_assign_rhs1 (stmt);
}
return NULL;
}
/* Checks as to whether EXPR refers to constant var/field/param.
Don't bother to instrument them. */
static bool
is_load_of_const_p (tree expr, bool is_write)
{
if (is_write)
return false;
if (TREE_CODE (expr) == COMPONENT_REF)
expr = TREE_OPERAND (expr, 1);
if (TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL
|| TREE_CODE (expr) == FIELD_DECL)
{
if (TREE_READONLY (expr))
return true;
}
return false;
}
/* Instruments EXPR if needed. If any instrumentation is inserted,
* return true. */
static bool
instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write)
{
enum tree_code tcode;
tree base, rhs, expr_type, expr_ptr, builtin_decl;
basic_block bb;
HOST_WIDE_INT size;
gimple stmt, g;
location_t loc;
base = get_base_address (expr);
if (base == NULL_TREE
|| TREE_CODE (base) == SSA_NAME
|| TREE_CODE (base) == STRING_CST)
return false;
tcode = TREE_CODE (expr);
/* Below are things we do not instrument
(no possibility of races or not implemented yet). */
if (/* Compiler-emitted artificial variables. */
(DECL_P (expr) && DECL_ARTIFICIAL (expr))
/* The var does not live in memory -> no possibility of races. */
|| (tcode == VAR_DECL
&& !TREE_ADDRESSABLE (expr)
&& TREE_STATIC (expr) == 0)
/* Not implemented. */
|| TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE
/* Not implemented. */
|| tcode == CONSTRUCTOR
/* Not implemented. */
|| tcode == PARM_DECL
/* Load of a const variable/parameter/field. */
|| is_load_of_const_p (expr, is_write))
return false;
size = int_size_in_bytes (TREE_TYPE (expr));
if (size == -1)
return false;
/* For now just avoid instrumenting bit field acceses.
TODO: handle bit-fields as if touching the whole field. */
HOST_WIDE_INT bitsize, bitpos;
tree offset;
enum machine_mode mode;
int volatilep = 0, unsignedp = 0;
get_inner_reference (expr, &bitsize, &bitpos, &offset,
&mode, &unsignedp, &volatilep, false);
if (bitpos % (size * BITS_PER_UNIT)
|| bitsize != size * BITS_PER_UNIT)
return false;
/* TODO: handle other case: ARRAY_RANGE_REF. */
if (tcode != ARRAY_REF
&& tcode != VAR_DECL
&& tcode != COMPONENT_REF
&& tcode != INDIRECT_REF
&& tcode != MEM_REF)
return false;
stmt = gsi_stmt (gsi);
loc = gimple_location (stmt);
rhs = is_vptr_store (stmt, expr, is_write);
gcc_checking_assert (rhs != NULL || is_gimple_addressable (expr));
expr_ptr = build_fold_addr_expr (unshare_expr (expr));
if (rhs == NULL)
{
expr_type = TREE_TYPE (expr);
while (TREE_CODE (expr_type) == ARRAY_TYPE)
expr_type = TREE_TYPE (expr_type);
size = int_size_in_bytes (expr_type);
g = gimple_build_call (get_memory_access_decl (is_write, size),
1, expr_ptr);
}
else
{
builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE);
g = gimple_build_call (builtin_decl, 1, expr_ptr);
}
gimple_set_location (g, loc);
/* Instrumentation for assignment of a function result
must be inserted after the call. Instrumentation for
reads of function arguments must be inserted before the call.
That's because the call can contain synchronization. */
if (is_gimple_call (stmt) && is_write)
{
/* If the call can throw, it must be the last stmt in
a basic block, so the instrumented stmts need to be
inserted in successor bbs. */
if (is_ctrl_altering_stmt (stmt))
{
edge e;
bb = gsi_bb (gsi);
e = find_fallthru_edge (bb->succs);
if (e)
gsi_insert_seq_on_edge_immediate (e, g);
}
else
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
}
else
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
return true;
}
/* Instruments the gimple pointed to by GSI. Return
* true if func entry/exit should be instrumented. */
static bool
instrument_gimple (gimple_stmt_iterator gsi)
{
gimple stmt;
tree rhs, lhs;
bool instrumented = false;
stmt = gsi_stmt (gsi);
if (is_gimple_call (stmt)
&& (gimple_call_fndecl (stmt)
!= builtin_decl_implicit (BUILT_IN_TSAN_INIT)))
return true;
else if (is_gimple_assign (stmt))
{
if (gimple_store_p (stmt))
{
lhs = gimple_assign_lhs (stmt);
instrumented = instrument_expr (gsi, lhs, true);
}
if (gimple_assign_load_p (stmt))
{
rhs = gimple_assign_rhs1 (stmt);
instrumented = instrument_expr (gsi, rhs, false);
}
}
return instrumented;
}
/* Instruments all interesting memory accesses in the current function.
* Return true if func entry/exit should be instrumented. */
static bool
instrument_memory_accesses (void)
{
basic_block bb;
gimple_stmt_iterator gsi;
bool fentry_exit_instrument = false;
FOR_EACH_BB (bb)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
fentry_exit_instrument |= instrument_gimple (gsi);
return fentry_exit_instrument;
}
/* Instruments function entry. */
static void
instrument_func_entry (void)
{
basic_block succ_bb;
gimple_stmt_iterator gsi;
tree ret_addr, builtin_decl;
gimple g;
succ_bb = single_succ (ENTRY_BLOCK_PTR);
gsi = gsi_after_labels (succ_bb);
builtin_decl = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
g = gimple_build_call (builtin_decl, 1, integer_zero_node);
ret_addr = make_ssa_name (ptr_type_node, NULL);
gimple_call_set_lhs (g, ret_addr);
gimple_set_location (g, cfun->function_start_locus);
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_ENTRY);
g = gimple_build_call (builtin_decl, 1, ret_addr);
gimple_set_location (g, cfun->function_start_locus);
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
}
/* Instruments function exits. */
static void
instrument_func_exit (void)
{
location_t loc;
basic_block exit_bb;
gimple_stmt_iterator gsi;
gimple stmt, g;
tree builtin_decl;
edge e;
edge_iterator ei;
/* Find all function exits. */
exit_bb = EXIT_BLOCK_PTR;
FOR_EACH_EDGE (e, ei, exit_bb->preds)
{
gsi = gsi_last_bb (e->src);
stmt = gsi_stmt (gsi);
gcc_assert (gimple_code (stmt) == GIMPLE_RETURN);
loc = gimple_location (stmt);
builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT);
g = gimple_build_call (builtin_decl, 0);
gimple_set_location (g, loc);
gsi_insert_before (&gsi, g, GSI_SAME_STMT);
}
}
/* ThreadSanitizer instrumentation pass. */
static unsigned
tsan_pass (void)
{
if (instrument_memory_accesses ())
{
instrument_func_entry ();
instrument_func_exit ();
}
return 0;
}
/* The pass's gate. */
static bool
tsan_gate (void)
{
return flag_tsan != 0
&& builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
}
/* Inserts __tsan_init () into the list of CTORs. */
void
tsan_finish_file (void)
{
tree ctor_statements;
tree init_decl;
ctor_statements = NULL_TREE;
init_decl = builtin_decl_implicit (BUILT_IN_TSAN_INIT);
append_to_statement_list (build_call_expr (init_decl, 0),
&ctor_statements);
cgraph_build_static_cdtor ('I', ctor_statements,
MAX_RESERVED_INIT_PRIORITY - 1);
}
/* The pass descriptor. */
struct gimple_opt_pass pass_tsan =
{
{
GIMPLE_PASS,
"tsan", /* name */
OPTGROUP_NONE, /* optinfo_flags */
tsan_gate, /* gate */
tsan_pass, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_NONE, /* tv_id */
PROP_ssa | PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_verify_all | TODO_update_ssa
| TODO_update_address_taken /* todo_flags_finish */
}
};
static bool
tsan_gate_O0 (void)
{
return flag_tsan != 0 && !optimize
&& builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
}
struct gimple_opt_pass pass_tsan_O0 =
{
{
GIMPLE_PASS,
"tsan0", /* name */
OPTGROUP_NONE, /* optinfo_flags */
tsan_gate_O0, /* gate */
tsan_pass, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_NONE, /* tv_id */
PROP_ssa | PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_verify_all | TODO_update_ssa
| TODO_update_address_taken /* todo_flags_finish */
}
};
/* ThreadSanitizer, a data race detector.
Copyright (C) 2011, 2012 Free Software Foundation, Inc.
Contributed by Dmitry Vyukov <dvyukov@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef TREE_TSAN
#define TREE_TSAN
extern void tsan_finish_file (void);
#endif /* TREE_TSAN */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment