tsan: Go language support
llvm-svn: 159754
diff --git a/compiler-rt/lib/tsan/rtl/tsan_defs.h b/compiler-rt/lib/tsan/rtl/tsan_defs.h
index 3d9cd54..6406cdc 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_defs.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_defs.h
@@ -28,7 +28,11 @@
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 @@
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 1474450..f2987c4 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc
@@ -53,7 +53,6 @@
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 68eab5d..1a70f8f 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
@@ -198,7 +198,7 @@
}
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 @@
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)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 b469437..1505145 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 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 e2fe3e8..269f9ee 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 @@
namespace __tsan {
-static uptr g_tls_size;
-
+#ifndef TSAN_GO
ScopedInRtl::ScopedInRtl()
: thr_(cur_thread()) {
in_rtl_ = thr_->in_rtl;
@@ -65,6 +64,13 @@
errno = errno_;
CHECK_EQ(in_rtl_, thr_->in_rtl);
}
+#else
+ScopedInRtl::ScopedInRtl() {
+}
+
+ScopedInRtl::~ScopedInRtl() {
+}
+#endif
uptr GetShadowMemoryConsumption() {
return 0;
@@ -76,6 +82,7 @@
MADV_DONTNEED);
}
+#ifndef TSAN_GO
static void ProtectRange(uptr beg, uptr end) {
ScopedInRtl in_rtl;
CHECK_LE(beg, end);
@@ -87,12 +94,9 @@
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 @@
"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 uptr g_tls_size;
+
#ifdef __i386__
# define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
#else
@@ -152,6 +169,7 @@
get_tls(&tls_size, &tls_align);
return tls_size;
}
+#endif // #ifndef TSAN_GO
const char *InitializePlatform() {
void *p = 0;
@@ -164,8 +182,10 @@
setrlimit(RLIMIT_CORE, (rlimit*)&lim);
}
+#ifndef TSAN_GO
CheckPIE();
g_tls_size = (uptr)InitTlsSize();
+#endif
return getenv("TSAN_OPTIONS");
}
@@ -174,11 +194,16 @@
}
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 @@
*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 822dfa1..f27a541 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
@@ -31,7 +31,9 @@
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 @@
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 @@
thr->nomalloc--;
}
+#ifndef TSAN_GO
extern "C" void __tsan_trace_switch() {
TraceSwitch(cur_thread());
}
@@ -236,6 +239,7 @@
extern "C" void __tsan_report_race() {
ReportRace(cur_thread());
}
+#endif
ALWAYS_INLINE
static Shadow LoadShadow(u64 *p) {
@@ -259,7 +263,11 @@
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 @@
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 @@
} // 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 71ca5d4..0d717d3 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -254,11 +254,13 @@
};
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 @@
#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 68a5c3e2..42cd523 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 @@
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);