Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -182,7 +182,7 @@ filter_available_targets(MSAN_SUPPORTED_ARCH x86_64) filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64 mipsel mips64el aarch64 powerpc64 powerpc64le) -filter_available_targets(TSAN_SUPPORTED_ARCH x86_64) +filter_available_targets(TSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel) if(ANDROID) Index: lib/tsan/CMakeLists.txt =================================================================== --- lib/tsan/CMakeLists.txt +++ lib/tsan/CMakeLists.txt @@ -100,6 +100,36 @@ clang_rt.tsan-${arch}-symbols) endif() +if(CAN_TARGET_mips64 AND UNIX AND NOT APPLE) + set(arch "mips64") + add_compiler_rt_runtime(clang_rt.tsan-${arch} ${arch} STATIC + SOURCES ${TSAN_SOURCES} + $ + $ + $ + CFLAGS ${TSAN_RTL_CFLAGS} + DEFS ${TSAN_COMMON_DEFINITIONS}) + list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}) + add_sanitizer_rt_symbols(clang_rt.tsan-${arch} rtl/tsan.syms.extra) + add_dependencies(tsan clang_rt.tsan-${arch} + clang_rt.tsan-${arch}-symbols) +endif() + +if(CAN_TARGET_mips64el AND UNIX AND NOT APPLE) + set(arch "mips64el") + add_compiler_rt_runtime(clang_rt.tsan-${arch} ${arch} STATIC + SOURCES ${TSAN_SOURCES} + $ + $ + $ + CFLAGS ${TSAN_RTL_CFLAGS} + DEFS ${TSAN_COMMON_DEFINITIONS}) + list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}) + add_sanitizer_rt_symbols(clang_rt.tsan-${arch} rtl/tsan.syms.extra) + add_dependencies(tsan clang_rt.tsan-${arch} + clang_rt.tsan-${arch}-symbols) +endif() + add_dependencies(compiler-rt tsan) # Build libcxx instrumented with TSan. Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -39,17 +39,28 @@ #define stderr __stderrp #endif +#ifdef __mips__ +const int kSigCount = 128; +bool guard_aquired; +#else const int kSigCount = 65; +#endif struct my_siginfo_t { // The size is determined by looking at sizeof of real siginfo_t on linux. u64 opaque[128 / sizeof(u64)]; }; +#ifdef __mips__ +struct ucontext_t { + u64 opaque[768 / sizeof(u64) + 1]; +}; +#else struct ucontext_t { // The size is determined by looking at sizeof of real ucontext_t on linux. u64 opaque[936 / sizeof(u64) + 1]; }; +#endif extern "C" int pthread_attr_init(void *attr); extern "C" int pthread_attr_destroy(void *attr); @@ -88,8 +99,13 @@ const int SIGSEGV = 11; const int SIGPIPE = 13; const int SIGTERM = 15; +#ifdef __mips__ +const int SIGBUS = 10; +const int SIGSYS = 12; +#else const int SIGBUS = 7; const int SIGSYS = 31; +#endif void *const MAP_FAILED = (void*)-1; const int PTHREAD_BARRIER_SERIAL_THREAD = -1; const int MAP_FIXED = 0x10; @@ -106,6 +122,9 @@ #define errno (*__errno_location()) struct sigaction_t { +#ifdef __mips__ + u32 sa_flags; +#endif union { sighandler_t sa_handler; void (*sa_sigaction)(int sig, my_siginfo_t *siginfo, void *uctx); @@ -115,7 +134,9 @@ __sanitizer_sigset_t sa_mask; #else __sanitizer_sigset_t sa_mask; +#ifndef __mips__ int sa_flags; +#endif void (*sa_restorer)(); #endif }; @@ -123,8 +144,13 @@ const sighandler_t SIG_DFL = (sighandler_t)0; const sighandler_t SIG_IGN = (sighandler_t)1; const sighandler_t SIG_ERR = (sighandler_t)-1; +#ifdef __mips__ +const int SA_SIGINFO = 8; +const int SIG_SETMASK = 3; +#else const int SA_SIGINFO = 4; const int SIG_SETMASK = 2; +#endif namespace std { struct nothrow_t {}; @@ -631,9 +657,21 @@ } TSAN_INTERCEPTOR(void*, memset, void *dst, int v, uptr size) { +#ifdef __mips__ + // For mips memset gets called before a call to __cxa_guard_aquire + // which causes a crash in REAL(pthread_create) during initialization + if (!guard_aquired) { + return internal_memset(dst, v, size); + } else { + SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size); + MemoryAccessRange(thr, pc, (uptr)dst, size, true); + return internal_memset(dst, v, size); + } +#else SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size); MemoryAccessRange(thr, pc, (uptr)dst, size, true); return internal_memset(dst, v, size); +#endif } TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) { @@ -811,6 +849,9 @@ // Used in thread-safe function static initialization. extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) { +#ifdef __mips__ + guard_aquired = true; +#endif SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g); for (;;) { u32 cmp = atomic_load(g, memory_order_acquire); Index: lib/tsan/rtl/tsan_interface_atomic.cc =================================================================== --- lib/tsan/rtl/tsan_interface_atomic.cc +++ lib/tsan/rtl/tsan_interface_atomic.cc @@ -32,8 +32,8 @@ typedef unsigned short a16; // NOLINT typedef unsigned int a32; typedef unsigned long long a64; // NOLINT -#if !defined(TSAN_GO) && (defined(__SIZEOF_INT128__) \ - || (__clang_major__ * 100 + __clang_minor__ >= 302)) +#if !defined(TSAN_GO) && defined(__SIZEOF_INT128__) \ + && (__clang_major__ * 100 + __clang_minor__ >= 302) __extension__ typedef __int128 a128; # define __TSAN_HAS_INT128 1 #else @@ -42,8 +42,10 @@ #ifndef TSAN_GO // Protects emulation of 128-bit atomic operations. +#if defined(__SIZEOF_INT128__) static StaticSpinMutex mutex128; #endif +#endif // Part of ABI, do not change. // http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup @@ -125,7 +127,8 @@ // Atomic ops are executed under tsan internal mutex, // here we assume that the atomic variables are not accessed // from non-instrumented code. -#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(TSAN_GO) +#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(TSAN_GO) \ + && defined(__SIZEOF_INT128__) a128 func_xchg(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; Index: lib/tsan/rtl/tsan_platform.h =================================================================== --- lib/tsan/rtl/tsan_platform.h +++ lib/tsan/rtl/tsan_platform.h @@ -41,6 +41,22 @@ 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack */ +#if defined(__mips64) +const uptr kMetaShadowBeg = 0x3000000000ull; +const uptr kMetaShadowEnd = 0x4000000000ull; +const uptr kTraceMemBeg = 0x6000000000ull; +const uptr kTraceMemEnd = 0x6200000000ull; +const uptr kShadowBeg = 0x0200000000ull; +const uptr kShadowEnd = 0x1000000000ull; +const uptr kHeapMemBeg = 0xfd00000000ull; +const uptr kHeapMemEnd = 0xfe00000000ull; +const uptr kLoAppMemBeg = 0x0000001000ull; +const uptr kLoAppMemEnd = 0x0100000000ull; +const uptr kHiAppMemBeg = 0xfe80000000ull; +const uptr kHiAppMemEnd = 0x10000000000ull; +const uptr kAppMemMsk = 0xfc00000000ull; +const uptr kAppMemXor = 0x0200000000ull; +#elif defined(__x86_64__) const uptr kMetaShadowBeg = 0x300000000000ull; const uptr kMetaShadowEnd = 0x400000000000ull; const uptr kTraceMemBeg = 0x600000000000ull; @@ -55,6 +71,7 @@ const uptr kHiAppMemEnd = 0x800000000000ull; const uptr kAppMemMsk = 0x7c0000000000ull; const uptr kAppMemXor = 0x020000000000ull; +#endif ALWAYS_INLINE bool IsAppMem(uptr mem) { Index: lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- lib/tsan/rtl/tsan_platform_linux.cc +++ lib/tsan/rtl/tsan_platform_linux.cc @@ -66,8 +66,6 @@ static uptr g_data_start; static uptr g_data_end; -const uptr kPageSize = 4096; - enum { MemTotal = 0, MemShadow = 1, @@ -200,7 +198,7 @@ *p = kShadowRodata; internal_write(fd, marker.data(), marker.size()); // Map the file into memory. - uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE, + uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); if (internal_iserror(page)) { internal_close(fd); @@ -243,9 +241,14 @@ // a program uses a small part of large mmap. On some programs // we see 20% memory usage reduction without huge pages for this range. #ifdef MADV_NOHUGEPAGE +#if defined(__mips64) + madvise((void*)MemToShadow(0xff00000000ULL), + 0x100000000ULL * kShadowMultiplier, MADV_NOHUGEPAGE); +#elif defined(__x86_64__) madvise((void*)MemToShadow(0x7f0000000000ULL), 0x10000000000ULL * kShadowMultiplier, MADV_NOHUGEPAGE); #endif +#endif DPrintf("memory shadow: %zx-%zx (%zuGB)\n", kShadowBeg, kShadowEnd, (kShadowEnd - kShadowBeg) >> 30); @@ -312,10 +315,18 @@ while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) { if (IsAppMem(p)) continue; +#if SANITIZER_CAN_USE_ALLOCATOR64 if (p >= kHeapMemEnd && p < kHeapMemEnd + PrimaryAllocator::AdditionalSize()) +#else + if (p >= kHeapMemEnd && p < kHeapMemEnd) +#endif continue; +#if defined(__mips64) + if (p >= 0xfffff00000ull) // vdso +#elif defined(__x86_64__) if (p >= 0xf000000000000000ull) // vdso +#endif break; Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end); Die(); @@ -325,7 +336,11 @@ ProtectRange(kShadowEnd, kMetaShadowBeg); ProtectRange(kMetaShadowEnd, kTraceMemBeg); ProtectRange(kTraceMemEnd, kHeapMemBeg); +#if SANITIZER_CAN_USE_ALLOCATOR64 ProtectRange(kHeapMemEnd + PrimaryAllocator::AdditionalSize(), kHiAppMemBeg); +#else + ProtectRange(kHeapMemEnd, kHiAppMemBeg); +#endif } #endif // #ifndef TSAN_GO Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -54,8 +54,21 @@ #ifndef TSAN_GO struct MapUnmapCallback; +#ifdef __mips64 +static const uptr kAllocatorSpace = 0; +static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; +static const uptr kAllocatorRegionSizeLog = 20; +static const uptr kAllocatorNumRegions = + kAllocatorSize >> kAllocatorRegionSizeLog; +typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12, + MapUnmapCallback> ByteMap; +typedef SizeClassAllocator32 PrimaryAllocator; +#else typedef SizeClassAllocator64 PrimaryAllocator; +#endif typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator SecondaryAllocator; typedef CombinedAllocator