diff options
author | Dmitry Vyukov <dvyukov@google.com> | 2012-07-05 16:18:28 +0000 |
---|---|---|
committer | Dmitry Vyukov <dvyukov@google.com> | 2012-07-05 16:18:28 +0000 |
commit | 03d32ecd4f5a8061b6a56e512f05f74a4775b228 (patch) | |
tree | 4ea38d23a04ffa574bcc85b708695b6f6ad802bf /compiler-rt | |
parent | 72244b6e4f711566b749e018af4b18feb4c45108 (diff) | |
download | bcm5719-llvm-03d32ecd4f5a8061b6a56e512f05f74a4775b228.tar.gz bcm5719-llvm-03d32ecd4f5a8061b6a56e512f05f74a4775b228.zip |
tsan: Go language support
llvm-svn: 159754
Diffstat (limited to 'compiler-rt')
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc | 7 | ||||
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_common.h | 10 | ||||
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_interface_defs.h | 7 | ||||
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_posix.cc | 4 | ||||
-rwxr-xr-x | compiler-rt/lib/tsan/go/buildgo.sh | 49 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/go/tsan_go.cc | 193 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_defs.h | 8 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_flags.cc | 1 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_mutex.cc | 8 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_platform.h | 18 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc | 44 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl.cc | 16 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl.h | 13 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc | 26 |
14 files changed, 362 insertions, 42 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc index be2f94c8dd2..816fddf1c5a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc @@ -31,13 +31,18 @@ namespace __sanitizer { const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; void *InternalAlloc(uptr size) { + if (size + sizeof(u64) < size) + return 0; void *p = LIBC_MALLOC(size + sizeof(u64)); + if (p == 0) + return 0; ((u64*)p)[0] = kBlockMagic; return (char*)p + sizeof(u64); } void InternalFree(void *addr) { - if (!addr) return; + if (addr == 0) + return; addr = (char*)addr - sizeof(u64); CHECK_EQ(((u64*)addr)[0], kBlockMagic); ((u64*)addr)[0] = 0; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 380fe8c7545..a6a40cb1672 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -83,10 +83,10 @@ int Atexit(void (*function)(void)); void SortArray(uptr *array, uptr size); // Math -inline bool IsPowerOfTwo(uptr x) { +INLINE bool IsPowerOfTwo(uptr x) { return (x & (x - 1)) == 0; } -inline uptr RoundUpTo(uptr size, uptr boundary) { +INLINE uptr RoundUpTo(uptr size, uptr boundary) { CHECK(IsPowerOfTwo(boundary)); return (size + boundary - 1) & ~(boundary - 1); } @@ -95,14 +95,14 @@ template<class T> T Min(T a, T b) { return a < b ? a : b; } template<class T> T Max(T a, T b) { return a > b ? a : b; } // Char handling -inline bool IsSpace(int c) { +INLINE bool IsSpace(int c) { return (c == ' ') || (c == '\n') || (c == '\t') || (c == '\f') || (c == '\r') || (c == '\v'); } -inline bool IsDigit(int c) { +INLINE bool IsDigit(int c) { return (c >= '0') && (c <= '9'); } -inline int ToLower(int c) { +INLINE int ToLower(int c) { return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_interface_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_interface_defs.h index ae532768625..2395ea50565 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_interface_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_interface_defs.h @@ -22,10 +22,13 @@ // FIXME find out what we need on Windows. __declspec(dllexport) ? # define SANITIZER_INTERFACE_ATTRIBUTE # define SANITIZER_WEAK_ATTRIBUTE -#else // _WIN32 +#elif defined(SANITIZER_GO) +# define SANITIZER_INTERFACE_ATTRIBUTE +# define SANITIZER_WEAK_ATTRIBUTE +#else # define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default"))) # define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) -#endif // _WIN32 +#endif // __has_feature #if !defined(__has_feature) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index a6d56838a93..4caee3ba68c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -152,7 +152,11 @@ void Abort() { } int Atexit(void (*function)(void)) { +#ifndef SANITIZER_GO return atexit(function); +#else + return 0; +#endif } } // namespace __sanitizer diff --git a/compiler-rt/lib/tsan/go/buildgo.sh b/compiler-rt/lib/tsan/go/buildgo.sh new file mode 100755 index 00000000000..948390949e6 --- /dev/null +++ b/compiler-rt/lib/tsan/go/buildgo.sh @@ -0,0 +1,49 @@ +#!/bin/bash +set -e + +SRCS=" + tsan_go.cc + ../rtl/tsan_clock.cc + ../rtl/tsan_flags.cc + ../rtl/tsan_md5.cc + ../rtl/tsan_mutex.cc + ../rtl/tsan_platform_linux.cc + ../rtl/tsan_printf.cc + ../rtl/tsan_report.cc + ../rtl/tsan_rtl.cc + ../rtl/tsan_rtl_mutex.cc + ../rtl/tsan_rtl_report.cc + ../rtl/tsan_rtl_thread.cc + ../rtl/tsan_stat.cc + ../rtl/tsan_suppressions.cc + ../rtl/tsan_symbolize.cc + ../rtl/tsan_sync.cc + ../../sanitizer_common/sanitizer_allocator.cc + ../../sanitizer_common/sanitizer_common.cc + ../../sanitizer_common/sanitizer_libc.cc + ../../sanitizer_common/sanitizer_linux.cc + ../../sanitizer_common/sanitizer_posix.cc + ../../sanitizer_common/sanitizer_printf.cc + ../../sanitizer_common/sanitizer_symbolizer.cc +" + +#ASMS="../rtl/tsan_rtl_amd64.S" + +rm -f gotsan.cc +for F in $SRCS; do + cat $F >> gotsan.cc +done + +CFLAGS=" -I../rtl -I../.. -I../../sanitizer_common -fPIC -g -Wall -Werror -ffreestanding -fno-exceptions -DTSAN_GO -DSANITIZER_GO" +if [ "$DEBUG" == "" ]; then + CFLAGS+=" -DTSAN_DEBUG=0 -O3 -fno-omit-frame-pointer" +else + CFLAGS+=" -DTSAN_DEBUG=1 -g" +fi + +echo gcc gotsan.cc -S -o tmp.s $CFLAGS +gcc gotsan.cc -S -o tmp.s $CFLAGS +cat tmp.s $ASMS > gotsan.s +echo as gotsan.s -o gotsan.syso +as gotsan.s -o gotsan.syso + diff --git a/compiler-rt/lib/tsan/go/tsan_go.cc b/compiler-rt/lib/tsan/go/tsan_go.cc new file mode 100644 index 00000000000..bd264c9ad7f --- /dev/null +++ b/compiler-rt/lib/tsan/go/tsan_go.cc @@ -0,0 +1,193 @@ +//===-- tsan_go.cc --------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ThreadSanitizer runtime for Go language. +// +//===----------------------------------------------------------------------===// + +#include "tsan_rtl.h" +#include "tsan_symbolize.h" +#include "sanitizer_common/sanitizer_common.h" +#include <stdlib.h> + +namespace __tsan { + +struct ThreadStatePlaceholder { + uptr opaque[sizeof(ThreadState) / sizeof(uptr) + kCacheLineSize]; +}; + +static ThreadStatePlaceholder *threads; + +void InitializeInterceptors() { +} + +void InitializeDynamicAnnotations() { +} + +bool IsExpectedReport(uptr addr, uptr size) { + return false; +} + +void internal_start_thread(void(*func)(void*), void *arg) { +} + +ReportStack *SymbolizeCodeAddr2Line(uptr addr) { + return NewReportStackEntry(addr); +} + +ReportStack *SymbolizeDataAddr2Line(uptr addr) { + return 0; +} + +void *internal_alloc(MBlockType typ, uptr sz) { + return InternalAlloc(sz); +} + +void internal_free(void *p) { + InternalFree(p); +} + +extern "C" { + +enum Tsan1EventType { + NOOP, // Should not appear. + READ, // {tid, pc, addr, size} + WRITE, // {tid, pc, addr, size} + READER_LOCK, // {tid, pc, lock, 0} + WRITER_LOCK, // {tid, pc, lock, 0} + UNLOCK, // {tid, pc, lock, 0} + UNLOCK_OR_INIT, // {tid, pc, lock, 0} + LOCK_CREATE, // {tid, pc, lock, 0} + LOCK_DESTROY, // {tid, pc, lock, 0} + THR_CREATE_BEFORE, // Parent thread's event. {tid, pc, 0, 0} + THR_CREATE_AFTER, // Parent thread's event. {tid, 0, 0, child_tid}/* 10 */ + THR_START, // Child thread's event {tid, CallStack, 0, parent_tid} + THR_FIRST_INSN, // Used only by valgrind. + THR_END, // {tid, 0, 0, 0} + THR_JOIN_AFTER, // {tid, pc, joined_tid} + THR_STACK_TOP, // {tid, pc, stack_top, stack_size_if_known} + RTN_EXIT, // {tid, 0, 0, 0} + RTN_CALL, // {tid, pc, 0, 0} + SBLOCK_ENTER, // {tid, pc, 0, 0} + SIGNAL, // {tid, pc, obj, 0} + WAIT, // {tid, pc, obj, 0} /* 20 */ + CYCLIC_BARRIER_INIT, // {tid, pc, obj, n} + CYCLIC_BARRIER_WAIT_BEFORE, // {tid, pc, obj, 0} + CYCLIC_BARRIER_WAIT_AFTER, // {tid, pc, obj, 0} + PCQ_CREATE, // {tid, pc, pcq_addr, 0} + PCQ_DESTROY, // {tid, pc, pcq_addr, 0} + PCQ_PUT, // {tid, pc, pcq_addr, 0} + PCQ_GET, // {tid, pc, pcq_addr, 0} + STACK_MEM_DIE, // deprecated. + MALLOC, // {tid, pc, addr, size} + FREE, // {tid, pc, addr, 0} /* 30 */ + MMAP, // {tid, pc, addr, size} + MUNMAP, // {tid, pc, addr, size} + PUBLISH_RANGE, // may be deprecated later. + UNPUBLISH_RANGE, // deprecated. TODO(kcc): get rid of this. + HB_LOCK, // {tid, pc, addr, 0} + NON_HB_LOCK, // {tid, pc, addr, 0} + IGNORE_READS_BEG, // {tid, pc, 0, 0} + IGNORE_READS_END, // {tid, pc, 0, 0} + IGNORE_WRITES_BEG, // {tid, pc, 0, 0} + IGNORE_WRITES_END, // {tid, pc, 0, 0} + SET_THREAD_NAME, // {tid, pc, name_str, 0} + SET_LOCK_NAME, // {tid, pc, lock, lock_name_str} + TRACE_MEM, // {tid, pc, addr, 0} + EXPECT_RACE, // {tid, descr_str, ptr, size} + BENIGN_RACE, // {tid, descr_str, ptr, size} + EXPECT_RACE_BEGIN, // {tid, pc, 0, 0} + EXPECT_RACE_END, // {tid, pc, 0, 0} + VERBOSITY, // Used for debugging. + STACK_TRACE, // {tid, pc, 0, 0}, for debugging. + FLUSH_STATE, // {tid, pc, 0, 0} + PC_DESCRIPTION, // {0, pc, descr_str, 0}, for ts_offline. + PRINT_MESSAGE, // {tid, pc, message_str, 0}, for ts_offline. + FLUSH_EXPECTED_RACES, // {0, 0, 0, 0} + LAST_EVENT // Should not appear. +}; + +void __tsan_init() { + threads = (ThreadStatePlaceholder*)internal_alloc(MBlockThreadContex, + kMaxTid * sizeof(ThreadStatePlaceholder)); + //!!! internal_memset(threads, 0, kMaxTid * sizeof(ThreadStatePlaceholder)); + ThreadState *thr = (ThreadState*)&threads[0]; + thr->in_rtl++; + Initialize(thr); + thr->in_rtl--; +} + +void __tsan_fini() { + // FIXME: Not necessary thread 0. + ThreadState *thr = (ThreadState*)&threads[0]; + thr->in_rtl++; + int res = Finalize(thr); + thr->in_rtl--; + exit(res); +} + +void __tsan_event(int typ, int tid, void *pc, void *addr, int info) { + //if (typ != READ && typ != WRITE && typ != SBLOCK_ENTER) + // Printf("typ=%d tid=%d pc=%p addr=%p info=%d\n", typ, tid, pc, addr, info); + ThreadState *thr = (ThreadState*)&threads[tid]; + switch (typ) { + case READ: + MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, false); + break; + case WRITE: + MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, true); + break; + case RTN_EXIT: + FuncExit(thr); + break; + case RTN_CALL: + FuncEntry(thr, (uptr)pc); + break; + case SBLOCK_ENTER: + break; + case SIGNAL: + thr->in_rtl++; + Release(thr, (uptr)pc, (uptr)addr); + thr->in_rtl--; + break; + case WAIT: + thr->in_rtl++; + Acquire(thr, (uptr)pc, (uptr)addr); + thr->in_rtl--; + break; + case MALLOC: + thr->in_rtl++; + MemoryResetRange(thr, (uptr)pc, (uptr)addr, (uptr)info); + thr->in_rtl--; + break; + case FREE: + break; + case THR_START: { + //Printf("typ=%d tid=%d pc=%p addr=%p info=%d\n", typ, tid, pc, addr, info); + if (tid == 0) + return; + ThreadState *parent = (ThreadState*)&threads[info]; + thr->in_rtl++; + parent->in_rtl++; + int tid2 = ThreadCreate(parent, (uptr)pc, 0, true); + CHECK_EQ(tid2, tid); + ThreadStart(thr, tid2); + parent->in_rtl--; + thr->in_rtl--; + break; + } + default: + thr->in_rtl++; + Printf("Event: typ=%d thr=%d\n", typ, tid); + thr->in_rtl--; + } +} + +} // extern "C" +} // namespace __tsan diff --git a/compiler-rt/lib/tsan/rtl/tsan_defs.h b/compiler-rt/lib/tsan/rtl/tsan_defs.h index 3d9cd54b5ea..6406cdc5f2d 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_defs.h +++ b/compiler-rt/lib/tsan/rtl/tsan_defs.h @@ -28,7 +28,11 @@ const int kTidBits = 13; const unsigned kMaxTid = 1 << kTidBits; const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit. const int kClkBits = 43; +#ifdef TSAN_GO +const int kShadowStackSize = 8 * 1024; +#else const int kShadowStackSize = 1024; +#endif #ifdef TSAN_SHADOW_COUNT # if TSAN_SHADOW_COUNT == 2 \ @@ -119,9 +123,7 @@ T RoundUp(T p, int align) { struct MD5Hash { u64 hash[2]; - bool operator==(const MD5Hash &other) const { - return hash[0] == other.hash[0] && hash[1] == other.hash[1]; - } + bool operator==(const MD5Hash &other) const; }; MD5Hash md5_hash(const void *data, uptr size); diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/compiler-rt/lib/tsan/rtl/tsan_flags.cc index 1474450b1f4..f2987c48897 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc @@ -53,7 +53,6 @@ void InitializeFlags(Flags *f, const char *env) { f->running_on_valgrind = false; f->use_internal_symbolizer = false; - // Let a frontend override. OverrideFlags(f); diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc index 68eab5d6c8f..1a70f8fe443 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc @@ -198,7 +198,7 @@ Mutex::~Mutex() { } void Mutex::Lock() { -#if TSAN_DEBUG +#if TSAN_DEBUG && !TSAN_GO cur_thread()->deadlock_detector.Lock(type_); #endif uptr cmp = kUnlocked; @@ -223,13 +223,13 @@ void Mutex::Unlock() { uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release); (void)prev; DCHECK_NE(prev & kWriteLock, 0); -#if TSAN_DEBUG +#if TSAN_DEBUG && !TSAN_GO cur_thread()->deadlock_detector.Unlock(type_); #endif } void Mutex::ReadLock() { -#if TSAN_DEBUG +#if TSAN_DEBUG && !TSAN_GO cur_thread()->deadlock_detector.Lock(type_); #endif uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire); @@ -251,7 +251,7 @@ void Mutex::ReadUnlock() { (void)prev; DCHECK_EQ(prev & kWriteLock, 0); DCHECK_GT(prev & ~kWriteLock, 0); -#if TSAN_DEBUG +#if TSAN_DEBUG && !TSAN_GO cur_thread()->deadlock_detector.Unlock(type_); #endif } diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h index b469437bef3..15051454497 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform.h +++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -21,26 +21,30 @@ #if __LP64__ namespace __tsan { +#if defined(TSAN_GO) +static const uptr kLinuxAppMemBeg = 0x000000000000ULL; +static const uptr kLinuxAppMemEnd = 0x00fcffffffffULL; +static const uptr kLinuxShadowMsk = 0x100000000000ULL; // TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout, // when memory addresses are of the 0x2axxxxxxxxxx form. // The option is enabled with 'setarch x86_64 -L'. -#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW - +#elif defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW static const uptr kLinuxAppMemBeg = 0x2a0000000000ULL; static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL; - #else - static const uptr kLinuxAppMemBeg = 0x7ef000000000ULL; static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL; - #endif static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL; // This has to be a macro to allow constant initialization of constants below. +#ifndef TSAN_GO #define MemToShadow(addr) \ (((addr) & ~(kLinuxAppMemMsk | (kShadowCell - 1))) * kShadowCnt) +#else +#define MemToShadow(addr) (((addr) * kShadowCnt) | kLinuxShadowMsk) +#endif static const uptr kLinuxShadowBeg = MemToShadow(kLinuxAppMemBeg); static const uptr kLinuxShadowEnd = @@ -56,7 +60,9 @@ static inline bool IsShadowMem(uptr mem) { static inline uptr ShadowToMem(uptr shadow) { CHECK(IsShadowMem(shadow)); -#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW +#ifdef TSAN_GO + return (shadow & ~kLinuxShadowMsk) / kShadowCnt; +#elif defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW // COMPAT mapping is not quite one-to-one. return (shadow / kShadowCnt) | 0x280000000000ULL; #else diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc index e2fe3e8ac23..269f9ee56e4 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc @@ -51,8 +51,7 @@ void Die() { namespace __tsan { -static uptr g_tls_size; - +#ifndef TSAN_GO ScopedInRtl::ScopedInRtl() : thr_(cur_thread()) { in_rtl_ = thr_->in_rtl; @@ -65,6 +64,13 @@ ScopedInRtl::~ScopedInRtl() { errno = errno_; CHECK_EQ(in_rtl_, thr_->in_rtl); } +#else +ScopedInRtl::ScopedInRtl() { +} + +ScopedInRtl::~ScopedInRtl() { +} +#endif uptr GetShadowMemoryConsumption() { return 0; @@ -76,6 +82,7 @@ void FlushShadowMemory() { MADV_DONTNEED); } +#ifndef TSAN_GO static void ProtectRange(uptr beg, uptr end) { ScopedInRtl in_rtl; CHECK_LE(beg, end); @@ -87,12 +94,9 @@ static void ProtectRange(uptr beg, uptr end) { Die(); } } +#endif void InitializeShadowMemory() { - const uptr kClosedLowBeg = 0x200000; - const uptr kClosedLowEnd = kLinuxShadowBeg - 1; - const uptr kClosedMidBeg = kLinuxShadowEnd + 1; - const uptr kClosedMidEnd = kLinuxAppMemBeg - 1; uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg); if (shadow != kLinuxShadowBeg) { @@ -101,21 +105,32 @@ void InitializeShadowMemory() { "to link with -pie.\n"); Die(); } +#ifndef TSAN_GO + const uptr kClosedLowBeg = 0x200000; + const uptr kClosedLowEnd = kLinuxShadowBeg - 1; + const uptr kClosedMidBeg = kLinuxShadowEnd + 1; + const uptr kClosedMidEnd = kLinuxAppMemBeg - 1; ProtectRange(kClosedLowBeg, kClosedLowEnd); ProtectRange(kClosedMidBeg, kClosedMidEnd); +#endif +#ifndef TSAN_GO DPrintf("kClosedLow %zx-%zx (%zuGB)\n", kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30); +#endif DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n", kLinuxShadowBeg, kLinuxShadowEnd, (kLinuxShadowEnd - kLinuxShadowBeg) >> 30); +#ifndef TSAN_GO DPrintf("kClosedMid %zx-%zx (%zuGB)\n", kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30); +#endif DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n", kLinuxAppMemBeg, kLinuxAppMemEnd, (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30); DPrintf("stack %zx\n", (uptr)&shadow); } +#ifndef TSAN_GO static void CheckPIE() { // Ensure that the binary is indeed compiled with -pie. ProcessMaps proc_maps; @@ -133,6 +148,8 @@ static void CheckPIE() { } } +static uptr g_tls_size; + #ifdef __i386__ # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) #else @@ -152,6 +169,7 @@ static int InitTlsSize() { get_tls(&tls_size, &tls_align); return tls_size; } +#endif // #ifndef TSAN_GO const char *InitializePlatform() { void *p = 0; @@ -164,8 +182,10 @@ const char *InitializePlatform() { setrlimit(RLIMIT_CORE, (rlimit*)&lim); } +#ifndef TSAN_GO CheckPIE(); g_tls_size = (uptr)InitTlsSize(); +#endif return getenv("TSAN_OPTIONS"); } @@ -174,11 +194,16 @@ void FinalizePlatform() { } uptr GetTlsSize() { +#ifndef TSAN_GO return g_tls_size; +#else + return 0; +#endif } void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, uptr *tls_addr, uptr *tls_size) { +#ifndef TSAN_GO arch_prctl(ARCH_GET_FS, tls_addr); *tls_addr -= g_tls_size; *tls_size = g_tls_size; @@ -197,6 +222,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, *tls_addr = *stk_addr + *stk_size; } } +#else + *stk_addr = 0; + *stk_size = 0; + *tls_addr = 0; + *tls_size = 0; +#endif } + } // namespace __tsan diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc index 822dfa164df..f27a5410fe3 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc @@ -31,7 +31,9 @@ extern "C" void __tsan_resume() { namespace __tsan { +#ifndef TSAN_GO THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64); +#endif static char ctx_placeholder[sizeof(Context)] ALIGNED(64); static Context *ctx; @@ -218,7 +220,7 @@ int Finalize(ThreadState *thr) { return failed ? flags()->exitcode : 0; } -static void TraceSwitch(ThreadState *thr) { +void TraceSwitch(ThreadState *thr) { thr->nomalloc++; ScopedInRtl in_rtl; Lock l(&thr->trace.mtx); @@ -229,6 +231,7 @@ static void TraceSwitch(ThreadState *thr) { thr->nomalloc--; } +#ifndef TSAN_GO extern "C" void __tsan_trace_switch() { TraceSwitch(cur_thread()); } @@ -236,6 +239,7 @@ extern "C" void __tsan_trace_switch() { extern "C" void __tsan_report_race() { ReportRace(cur_thread()); } +#endif ALWAYS_INLINE static Shadow LoadShadow(u64 *p) { @@ -259,7 +263,11 @@ static inline void HandleRace(ThreadState *thr, u64 *shadow_mem, thr->racy_state[0] = cur.raw(); thr->racy_state[1] = old.raw(); thr->racy_shadow_addr = shadow_mem; +#ifndef TSAN_GO HACKY_CALL(__tsan_report_race); +#else + ReportRace(thr); +#endif } static inline bool BothReads(Shadow s, int kAccessIsWrite) { @@ -477,6 +485,10 @@ void IgnoreCtl(ThreadState *thr, bool write, bool begin) { thr->fast_state.ClearIgnoreBit(); } +bool MD5Hash::operator==(const MD5Hash &other) const { + return hash[0] == other.hash[0] && hash[1] == other.hash[1]; +} + #if TSAN_DEBUG void build_consistency_debug() {} #else @@ -501,5 +513,7 @@ void build_consistency_shadow8() {} } // namespace __tsan +#ifndef TSAN_GO // Must be included in this file to make sure everything is inlined. #include "tsan_interface_inl.h" +#endif diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index 71ca5d47a57..0d717d3a793 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -254,11 +254,13 @@ struct ThreadState { }; Context *CTX(); -extern THREADLOCAL char cur_thread_placeholder[]; +#ifndef TSAN_GO +extern THREADLOCAL char cur_thread_placeholder[]; INLINE ThreadState *cur_thread() { return reinterpret_cast<ThreadState *>(&cur_thread_placeholder); } +#endif enum ThreadStatus { ThreadStatusInvalid, // Non-existent thread, data is invalid. @@ -457,12 +459,19 @@ void Release(ThreadState *thr, uptr pc, uptr addr); #define HACKY_CALL(f) f() #endif +void TraceSwitch(ThreadState *thr); + extern "C" void __tsan_trace_switch(); void ALWAYS_INLINE INLINE TraceAddEvent(ThreadState *thr, u64 epoch, EventType typ, uptr addr) { StatInc(thr, StatEvents); - if (UNLIKELY((epoch % kTracePartSize) == 0)) + if (UNLIKELY((epoch % kTracePartSize) == 0)) { +#ifndef TSAN_GO HACKY_CALL(__tsan_trace_switch); +#else + TraceSwitch(thr); +#endif + } Event *evp = &thr->trace.events[epoch % kTraceSize]; Event ev = (u64)addr | ((u64)typ << 61); *evp = ev; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc index 68a5c3e2917..42cd523480c 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc @@ -142,18 +142,22 @@ void ThreadStart(ThreadState *thr, int tid) { GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size); if (tid) { - MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size); + if (stk_addr && stk_size) { + MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size); + } - // Check that the thr object is in tls; - const uptr thr_beg = (uptr)thr; - const uptr thr_end = (uptr)thr + sizeof(*thr); - CHECK_GE(thr_beg, tls_addr); - CHECK_LE(thr_beg, tls_addr + tls_size); - CHECK_GE(thr_end, tls_addr); - CHECK_LE(thr_end, tls_addr + tls_size); - // Since the thr object is huge, skip it. - MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr); - MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end); + if (tls_addr && tls_size) { + // Check that the thr object is in tls; + const uptr thr_beg = (uptr)thr; + const uptr thr_end = (uptr)thr + sizeof(*thr); + CHECK_GE(thr_beg, tls_addr); + CHECK_LE(thr_beg, tls_addr + tls_size); + CHECK_GE(thr_end, tls_addr); + CHECK_LE(thr_end, tls_addr + tls_size); + // Since the thr object is huge, skip it. + MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr); + MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end); + } } Lock l(&CTX()->thread_mtx); |