iii updated this revision to Diff 358363. iii added a comment. Based on Ulrich's feedback I tested the series on RHEL7, which, in addition to an old kernel, contains an old glibc and an old toolchain. This uncovered a few extra issues, which are fixed here:
- Call __tls_get_offset() in order to force TLS allocation. - Align thread_registry_placeholder. - Protect the address space "tail" in two steps: until the 4-level page table boundary (this must succeed) and then until the 5-level page table boundary (this may fail). Also, the Go support is finally working (https://github.com/iii-i/go/tree/tsan-s390x), so, since we need to make another round anyway, I've included the LLVM part here as well. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D105629/new/ https://reviews.llvm.org/D105629 Files: clang/lib/Driver/ToolChains/Linux.cpp compiler-rt/cmake/config-ix.cmake compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h compiler-rt/lib/tsan/CMakeLists.txt compiler-rt/lib/tsan/go/buildgo.sh compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp compiler-rt/lib/tsan/rtl/tsan_interface.h compiler-rt/lib/tsan/rtl/tsan_platform.h compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp compiler-rt/lib/tsan/rtl/tsan_platform_posix.cpp compiler-rt/lib/tsan/rtl/tsan_rtl.cpp compiler-rt/lib/tsan/rtl/tsan_rtl_s390x.S compiler-rt/test/tsan/CMakeLists.txt compiler-rt/test/tsan/ignore_lib0.cpp compiler-rt/test/tsan/ignore_lib1.cpp compiler-rt/test/tsan/ignore_lib5.cpp compiler-rt/test/tsan/map32bit.cpp compiler-rt/test/tsan/mmap_large.cpp llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp llvm/utils/gn/secondary/compiler-rt/lib/tsan/BUILD.gn
Index: llvm/utils/gn/secondary/compiler-rt/lib/tsan/BUILD.gn =================================================================== --- llvm/utils/gn/secondary/compiler-rt/lib/tsan/BUILD.gn +++ llvm/utils/gn/secondary/compiler-rt/lib/tsan/BUILD.gn @@ -125,6 +125,8 @@ sources += [ "rtl/tsan_rtl_ppc64.S" ] } else if (target_cpu == "mips64") { sources += [ "rtl/tsan_rtl_mips64.S" ] + } else if (target_cpu == "s390x") { + sources += [ "rtl/tsan_rtl_s390x.S" ] } # To be able to include sanitizer_common. Index: llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -312,12 +312,21 @@ Type *Ty = Type::getIntNTy(M.getContext(), BitSize); Type *PtrTy = Ty->getPointerTo(); SmallString<32> AtomicLoadName("__tsan_atomic" + BitSizeStr + "_load"); - TsanAtomicLoad[i] = - M.getOrInsertFunction(AtomicLoadName, Attr, Ty, PtrTy, OrdTy); + { + AttributeList AL = Attr; + AL = AL.addParamAttribute(M.getContext(), 1, Attribute::ZExt); + TsanAtomicLoad[i] = + M.getOrInsertFunction(AtomicLoadName, AL, Ty, PtrTy, OrdTy); + } SmallString<32> AtomicStoreName("__tsan_atomic" + BitSizeStr + "_store"); - TsanAtomicStore[i] = M.getOrInsertFunction( - AtomicStoreName, Attr, IRB.getVoidTy(), PtrTy, Ty, OrdTy); + { + AttributeList AL = Attr; + AL = AL.addParamAttribute(M.getContext(), 1, Attribute::ZExt); + AL = AL.addParamAttribute(M.getContext(), 2, Attribute::ZExt); + TsanAtomicStore[i] = M.getOrInsertFunction( + AtomicStoreName, AL, IRB.getVoidTy(), PtrTy, Ty, OrdTy); + } for (unsigned Op = AtomicRMWInst::FIRST_BINOP; Op <= AtomicRMWInst::LAST_BINOP; ++Op) { @@ -340,24 +349,44 @@ else continue; SmallString<32> RMWName("__tsan_atomic" + itostr(BitSize) + NamePart); - TsanAtomicRMW[Op][i] = - M.getOrInsertFunction(RMWName, Attr, Ty, PtrTy, Ty, OrdTy); + { + AttributeList AL = Attr; + AL = AL.addParamAttribute(M.getContext(), 1, Attribute::ZExt); + AL = AL.addParamAttribute(M.getContext(), 2, Attribute::ZExt); + TsanAtomicRMW[Op][i] = + M.getOrInsertFunction(RMWName, AL, Ty, PtrTy, Ty, OrdTy); + } } SmallString<32> AtomicCASName("__tsan_atomic" + BitSizeStr + "_compare_exchange_val"); - TsanAtomicCAS[i] = M.getOrInsertFunction(AtomicCASName, Attr, Ty, PtrTy, Ty, - Ty, OrdTy, OrdTy); + { + AttributeList AL = Attr; + AL = AL.addParamAttribute(M.getContext(), 1, Attribute::ZExt); + AL = AL.addParamAttribute(M.getContext(), 2, Attribute::ZExt); + AL = AL.addParamAttribute(M.getContext(), 3, Attribute::ZExt); + AL = AL.addParamAttribute(M.getContext(), 4, Attribute::ZExt); + TsanAtomicCAS[i] = M.getOrInsertFunction(AtomicCASName, AL, Ty, PtrTy, Ty, + Ty, OrdTy, OrdTy); + } } TsanVptrUpdate = M.getOrInsertFunction("__tsan_vptr_update", Attr, IRB.getVoidTy(), IRB.getInt8PtrTy(), IRB.getInt8PtrTy()); TsanVptrLoad = M.getOrInsertFunction("__tsan_vptr_read", Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); - TsanAtomicThreadFence = M.getOrInsertFunction("__tsan_atomic_thread_fence", - Attr, IRB.getVoidTy(), OrdTy); - TsanAtomicSignalFence = M.getOrInsertFunction("__tsan_atomic_signal_fence", - Attr, IRB.getVoidTy(), OrdTy); + { + AttributeList AL = Attr; + AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt); + TsanAtomicThreadFence = M.getOrInsertFunction("__tsan_atomic_thread_fence", + AL, IRB.getVoidTy(), OrdTy); + } + { + AttributeList AL = Attr; + AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt); + TsanAtomicSignalFence = M.getOrInsertFunction("__tsan_atomic_signal_fence", + AL, IRB.getVoidTy(), OrdTy); + } MemmoveFn = M.getOrInsertFunction("memmove", Attr, IRB.getInt8PtrTy(), Index: compiler-rt/test/tsan/mmap_large.cpp =================================================================== --- compiler-rt/test/tsan/mmap_large.cpp +++ compiler-rt/test/tsan/mmap_large.cpp @@ -21,6 +21,8 @@ const size_t kLog2Size = 32; #elif defined(__powerpc64__) const size_t kLog2Size = 39; +#elif defined(__s390x__) + const size_t kLog2Size = 43; #endif const uintptr_t kLocation = 0x40ULL << kLog2Size; void *p = mmap( Index: compiler-rt/test/tsan/map32bit.cpp =================================================================== --- compiler-rt/test/tsan/map32bit.cpp +++ compiler-rt/test/tsan/map32bit.cpp @@ -11,6 +11,7 @@ // XFAIL: mips // XFAIL: aarch64 // XFAIL: powerpc64 +// XFAIL: s390x // MAP_32BIT doesn't exist on OS X and NetBSD. // UNSUPPORTED: darwin,netbsd Index: compiler-rt/test/tsan/ignore_lib5.cpp =================================================================== --- compiler-rt/test/tsan/ignore_lib5.cpp +++ compiler-rt/test/tsan/ignore_lib5.cpp @@ -1,7 +1,7 @@ // RUN: rm -rf %t-dir // RUN: mkdir %t-dir -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib1.so +// RUN: %clangxx_tsan -O1 -fno-builtin %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib1.so // RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t-dir/executable // RUN: echo running w/o suppressions: // RUN: %deflake %run %t-dir/executable | FileCheck %s --check-prefix=CHECK-NOSUPP Index: compiler-rt/test/tsan/ignore_lib1.cpp =================================================================== --- compiler-rt/test/tsan/ignore_lib1.cpp +++ compiler-rt/test/tsan/ignore_lib1.cpp @@ -1,7 +1,7 @@ // RUN: rm -rf %t-dir // RUN: mkdir %t-dir -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib1.so +// RUN: %clangxx_tsan -O1 -fno-builtin %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib1.so // RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t-dir/executable // RUN: echo running w/o suppressions: // RUN: %deflake %run %t-dir/executable | FileCheck %s --check-prefix=CHECK-NOSUPP Index: compiler-rt/test/tsan/ignore_lib0.cpp =================================================================== --- compiler-rt/test/tsan/ignore_lib0.cpp +++ compiler-rt/test/tsan/ignore_lib0.cpp @@ -1,7 +1,7 @@ // RUN: rm -rf %t-dir // RUN: mkdir %t-dir -// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib0.so +// RUN: %clangxx_tsan -O1 -fno-builtin %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib0.so // RUN: %clangxx_tsan -O1 %s -L%t-dir -lignore_lib0 %link_libcxx_tsan -o %t // RUN: echo running w/o suppressions: // RUN: env LD_LIBRARY_PATH=%t-dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP Index: compiler-rt/test/tsan/CMakeLists.txt =================================================================== --- compiler-rt/test/tsan/CMakeLists.txt +++ compiler-rt/test/tsan/CMakeLists.txt @@ -1,7 +1,7 @@ set(TSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) -if(${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "x86_64") +if(${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "(x86_64|s390x)") list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck) endif() if(NOT COMPILER_RT_STANDALONE_BUILD) Index: compiler-rt/lib/tsan/rtl/tsan_rtl_s390x.S =================================================================== --- /dev/null +++ compiler-rt/lib/tsan/rtl/tsan_rtl_s390x.S @@ -0,0 +1,47 @@ +#include "sanitizer_common/sanitizer_asm.h" + +#define CFA_OFFSET 160 +#define R2_REL_OFFSET 16 +#define R3_REL_OFFSET 24 +#define R14_REL_OFFSET 112 +#define R15_REL_OFFSET 120 +#define FRAME_SIZE 160 + +.text + +ASM_HIDDEN(__tsan_setjmp) + +.macro intercept symbol, real +.comm \real, 8, 8 +.globl ASM_SYMBOL_INTERCEPTOR(\symbol) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(\symbol)) +ASM_SYMBOL_INTERCEPTOR(\symbol): + CFI_STARTPROC + stmg %r2, %r3, R2_REL_OFFSET(%r15) + CFI_REL_OFFSET(%r2, R2_REL_OFFSET) + CFI_REL_OFFSET(%r3, R3_REL_OFFSET) + stmg %r14, %r15, R14_REL_OFFSET(%r15) + CFI_REL_OFFSET(%r14, R14_REL_OFFSET) + CFI_REL_OFFSET(%r15, R15_REL_OFFSET) + aghi %r15, -FRAME_SIZE + CFI_ADJUST_CFA_OFFSET(FRAME_SIZE) + la %r2, FRAME_SIZE(%r15) + brasl %r14, ASM_SYMBOL(__tsan_setjmp) + lmg %r14, %r15, FRAME_SIZE + R14_REL_OFFSET(%r15) + CFI_RESTORE(%r14) + CFI_RESTORE(%r15) + CFI_DEF_CFA_OFFSET(CFA_OFFSET) + lmg %r2, %r3, R2_REL_OFFSET(%r15) + CFI_RESTORE(%r2) + CFI_RESTORE(%r3) + larl %r1, \real + lg %r1, 0(%r1) + br %r1 + CFI_ENDPROC + ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(\symbol)) +.endm + +intercept setjmp, _ZN14__interception11real_setjmpE +intercept _setjmp, _ZN14__interception12real__setjmpE +intercept sigsetjmp, _ZN14__interception14real_sigsetjmpE +intercept __sigsetjmp, _ZN14__interception16real___sigsetjmpE Index: compiler-rt/lib/tsan/rtl/tsan_rtl.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -77,7 +77,7 @@ } #endif -static char thread_registry_placeholder[sizeof(ThreadRegistry)]; +static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadContextBase *CreateThreadContext(u32 tid) { // Map thread trace when context is created. Index: compiler-rt/lib/tsan/rtl/tsan_platform_posix.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_platform_posix.cpp +++ compiler-rt/lib/tsan/rtl/tsan_platform_posix.cpp @@ -72,11 +72,15 @@ InitializeShadowMemoryPlatform(); } -static void ProtectRange(uptr beg, uptr end) { +static bool TryProtectRange(uptr beg, uptr end) { CHECK_LE(beg, end); if (beg == end) - return; - if (beg != (uptr)MmapFixedNoAccess(beg, end - beg)) { + return true; + return beg == (uptr)MmapFixedNoAccess(beg, end - beg); +} + +static void ProtectRange(uptr beg, uptr end) { + if (!TryProtectRange(beg, end)) { Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end); Printf("FATAL: Make sure you are not using unlimited stack\n"); Die(); @@ -118,6 +122,16 @@ ProtectRange(TraceMemEnd(), HeapMemBeg()); ProtectRange(HeapEnd(), HiAppMemBeg()); #endif + +#if defined(__s390x__) + // Protect the rest of the address space. + const uptr user_addr_max_l4 = 0x0020000000000000ull; + const uptr user_addr_max_l5 = 0xfffffffffffff000ull; + // All the maintained s390x kernels support at least 4-level page tables. + ProtectRange(HiAppMemEnd(), user_addr_max_l4); + // Older s390x kernels may not support 5-level page tables. + TryProtectRange(user_addr_max_l4, user_addr_max_l5); +#endif } #endif Index: compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp +++ compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp @@ -391,6 +391,10 @@ return mangled_sp ^ xor_key; #elif defined(__mips__) return mangled_sp; +#elif defined(__s390x__) + // tcbhead_t.stack_guard + uptr xor_key = ((uptr *)__builtin_thread_pointer())[5]; + return mangled_sp ^ xor_key; #else #error "Unknown platform" #endif @@ -411,6 +415,8 @@ # define LONG_JMP_SP_ENV_SLOT 13 # elif defined(__mips64) # define LONG_JMP_SP_ENV_SLOT 1 +# elif defined(__s390x__) +# define LONG_JMP_SP_ENV_SLOT 9 # else # define LONG_JMP_SP_ENV_SLOT 6 # endif Index: compiler-rt/lib/tsan/rtl/tsan_platform.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_platform.h +++ compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -365,6 +365,38 @@ // Indicates the runtime will define the memory regions at runtime. #define TSAN_RUNTIME_VMA 1 +#elif defined(__s390x__) +/* +C/C++ on linux/s390x +While the kernel provides a 64-bit address space, we have to restrict ourselves +to 48 bits due to how e.g. SyncVar::GetId() works. +0000 0000 1000 - 0e00 0000 0000: binary, modules, stacks - 14 TiB +0e00 0000 0000 - 4000 0000 0000: - +4000 0000 0000 - 8000 0000 0000: shadow - 64TiB (4 * app) +8000 0000 0000 - 9000 0000 0000: - +9000 0000 0000 - 9800 0000 0000: metainfo - 8TiB (0.5 * app) +9800 0000 0000 - a000 0000 0000: - +a000 0000 0000 - b000 0000 0000: traces - 16TiB (max history * 128k threads) +b000 0000 0000 - be00 0000 0000: - +be00 0000 0000 - c000 0000 0000: heap - 2TiB (max supported by the allocator) +*/ +struct Mapping { + static const uptr kMetaShadowBeg = 0x900000000000ull; + static const uptr kMetaShadowEnd = 0x980000000000ull; + static const uptr kTraceMemBeg = 0xa00000000000ull; + static const uptr kTraceMemEnd = 0xb00000000000ull; + static const uptr kShadowBeg = 0x400000000000ull; + static const uptr kShadowEnd = 0x800000000000ull; + static const uptr kHeapMemBeg = 0xbe0000000000ull; + static const uptr kHeapMemEnd = 0xc00000000000ull; + static const uptr kLoAppMemBeg = 0x000000001000ull; + static const uptr kLoAppMemEnd = 0x0e0000000000ull; + static const uptr kHiAppMemBeg = 0xc00000004000ull; + static const uptr kHiAppMemEnd = 0xc00000004000ull; + static const uptr kAppMemMsk = 0xb00000000000ull; + static const uptr kAppMemXor = 0x100000000000ull; + static const uptr kVdsoBeg = 0xfffffffff000ull; +}; #endif #elif SANITIZER_GO && !SANITIZER_WINDOWS && HAS_48_BIT_ADDRESS_SPACE @@ -528,6 +560,28 @@ #define TSAN_RUNTIME_VMA 1 +#elif SANITIZER_GO && defined(__s390x__) +/* +Go on linux/s390x +0000 0000 1000 - 1000 0000 0000: executable and heap - 16 TiB +1000 0000 0000 - 4000 0000 0000: - +4000 0000 0000 - 8000 0000 0000: shadow - 64TiB (4 * app) +8000 0000 0000 - 9000 0000 0000: - +9000 0000 0000 - 9800 0000 0000: metainfo - 8TiB (0.5 * app) +9800 0000 0000 - a000 0000 0000: - +a000 0000 0000 - b000 0000 0000: traces - 16TiB (max history * 128k threads) +*/ +struct Mapping { + static const uptr kMetaShadowBeg = 0x900000000000ull; + static const uptr kMetaShadowEnd = 0x980000000000ull; + static const uptr kTraceMemBeg = 0xa00000000000ull; + static const uptr kTraceMemEnd = 0xb00000000000ull; + static const uptr kShadowBeg = 0x400000000000ull; + static const uptr kShadowEnd = 0x800000000000ull; + static const uptr kAppMemBeg = 0x000000001000ull; + static const uptr kAppMemEnd = 0x100000000000ull; +}; + #else # error "Unknown platform" #endif Index: compiler-rt/lib/tsan/rtl/tsan_interface.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_interface.h +++ compiler-rt/lib/tsan/rtl/tsan_interface.h @@ -196,7 +196,8 @@ typedef unsigned int a32; typedef unsigned long long a64; #if !SANITIZER_GO && (defined(__SIZEOF_INT128__) \ - || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64) + || (__clang_major__ * 100 + __clang_minor__ >= 302)) && \ + !defined(__mips64) && !defined(__s390x__) __extension__ typedef __int128 a128; # define __TSAN_HAS_INT128 1 #else Index: compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -71,7 +71,8 @@ }; #endif -#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 +#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \ + defined(__s390x__) #define PTHREAD_ABI_BASE "GLIBC_2.3.2" #elif defined(__aarch64__) || SANITIZER_PPC64V2 #define PTHREAD_ABI_BASE "GLIBC_2.17" @@ -2270,6 +2271,7 @@ #define NEED_TLS_GET_ADDR #endif #undef SANITIZER_INTERCEPT_TLS_GET_ADDR +#define SANITIZER_INTERCEPT_TLS_GET_OFFSET 1 #undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) @@ -2585,6 +2587,20 @@ #include "sanitizer_common/sanitizer_syscalls_netbsd.inc" #ifdef NEED_TLS_GET_ADDR + +static void handle_tls_addr(void *arg, void *res) { + ThreadState *thr = cur_thread(); + if (!thr) + return; + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, + thr->tls_addr + thr->tls_size); + if (!dtv) + return; + // New DTLS block has been allocated. + MemoryResetRange(thr, 0, dtv->beg, dtv->size); +} + +#if !SANITIZER_S390 // Define own interceptor instead of sanitizer_common's for three reasons: // 1. It must not process pending signals. // Signal handlers may contain MOVDQA instruction (see below). @@ -2597,18 +2613,18 @@ // execute MOVDQA with stack addresses. TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { void *res = REAL(__tls_get_addr)(arg); - ThreadState *thr = cur_thread(); - if (!thr) - return res; - DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, - thr->tls_addr + thr->tls_size); - if (!dtv) - return res; - // New DTLS block has been allocated. - MemoryResetRange(thr, 0, dtv->beg, dtv->size); + handle_tls_addr(arg, res); + return res; +} +#else // SANITIZER_S390 +TSAN_INTERCEPTOR(uptr, __tls_get_addr_internal, void *arg) { + uptr res = __tls_get_offset_wrapper(arg, REAL(__tls_get_offset)); + char *tp = static_cast<char *>(__builtin_thread_pointer()); + handle_tls_addr(arg, res + tp); return res; } #endif +#endif #if SANITIZER_NETBSD TSAN_INTERCEPTOR(void, _lwp_exit) { @@ -2830,7 +2846,12 @@ TSAN_INTERCEPT(_exit); #ifdef NEED_TLS_GET_ADDR +#if !SANITIZER_S390 TSAN_INTERCEPT(__tls_get_addr); +#else + TSAN_INTERCEPT(__tls_get_addr_internal); + TSAN_INTERCEPT(__tls_get_offset); +#endif #endif TSAN_MAYBE_INTERCEPT__LWP_EXIT; Index: compiler-rt/lib/tsan/go/buildgo.sh =================================================================== --- compiler-rt/lib/tsan/go/buildgo.sh +++ compiler-rt/lib/tsan/go/buildgo.sh @@ -72,6 +72,10 @@ SUFFIX="linux_mips64" ARCHCFLAGS="-mips64 -EB" fi + elif [ "`uname -a | grep s390x`" != "" ]; then + SRCS="$SRCS ../../sanitizer_common/sanitizer_linux_s390.cpp" + SUFFIX="linux_s390x" + ARCHCFLAGS="" fi elif [ "`uname -a | grep FreeBSD`" != "" ]; then # The resulting object still depends on libc. Index: compiler-rt/lib/tsan/CMakeLists.txt =================================================================== --- compiler-rt/lib/tsan/CMakeLists.txt +++ compiler-rt/lib/tsan/CMakeLists.txt @@ -219,6 +219,20 @@ add_asm_sources(TSAN_ASM_SOURCES rtl/tsan_rtl_mips64.S ) + elseif(arch MATCHES "s390x") + add_asm_sources(TSAN_ASM_SOURCES + rtl/tsan_rtl_s390x.S + ) + # Sanity check for Go runtime. + set(BUILDGO_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/go/buildgo.sh) + add_custom_target(GotsanRuntimeCheck + COMMAND env "CC=${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" + EXTRA_CFLAGS=${EXTRA_CFLAGS} + IN_TMPDIR=1 SILENT=1 ${BUILDGO_SCRIPT} + DEPENDS clang_rt.tsan-${arch} ${BUILDGO_SCRIPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go + COMMENT "Checking TSan Go runtime..." + VERBATIM) else() set(TSAN_ASM_SOURCES) endif() Index: compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -650,14 +650,14 @@ #endif // !SANITIZER_ANDROID #if defined(__mips__) -struct __sanitizer_kernel_sigset_t { - uptr sig[2]; -}; +#define __SANITIZER_KERNEL_NSIG 128 #else +#define __SANITIZER_KERNEL_NSIG 64 +#endif + struct __sanitizer_kernel_sigset_t { - u8 sig[8]; + uptr sig[__SANITIZER_KERNEL_NSIG / (sizeof(uptr) * 8)]; }; -#endif // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. #if SANITIZER_MIPS Index: compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp +++ compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -317,21 +317,44 @@ }; } // namespace +#ifdef __s390__ +extern "C" uptr __tls_get_offset(void *arg); + +static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) { + // The __tls_get_offset ABI requires %r12 to point to GOT and %r2 to be an + // offset of a struct tls_index inside GOT. We don't possess either of the + // two, so violate the letter of the "ELF Handling For Thread-Local + // Storage" document and assume that the implementation just dereferences + // %r2 + %r12. + uptr tls_index[2] = {ti_module, ti_offset}; + register uptr r2 asm("2") = 0; + register void *r12 asm("12") = tls_index; + asm("basr %%r14, %[__tls_get_offset]" + : "+r" (r2) + : [__tls_get_offset] "r" (__tls_get_offset), "r" (r12) + : "memory", "cc", "0", "1", "3", "4", "5", "14"); + return r2; +} +#else extern "C" void *__tls_get_addr(size_t *); +#endif static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size, void *data) { if (!info->dlpi_tls_modid) return 0; uptr begin = (uptr)info->dlpi_tls_data; -#ifndef __s390__ if (!g_use_dlpi_tls_data) { // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc // and FreeBSD. +#ifdef __s390__ + begin = (uptr)__builtin_thread_pointer() + + TlsGetOffset(info->dlpi_tls_modid, 0); +#else size_t mod_and_off[2] = {info->dlpi_tls_modid, 0}; begin = (uptr)__tls_get_addr(mod_and_off); - } #endif + } for (unsigned i = 0; i != info->dlpi_phnum; ++i) if (info->dlpi_phdr[i].p_type == PT_TLS) { static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back( Index: compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -878,7 +878,7 @@ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); - k_set->sig[idx] &= ~(1 << bit); + k_set->sig[idx] &= ~((uptr)1 << bit); } bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { @@ -888,7 +888,7 @@ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); - return k_set->sig[idx] & (1 << bit); + return k_set->sig[idx] & ((uptr)1 << bit); } #elif SANITIZER_FREEBSD void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { Index: compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -5303,6 +5303,12 @@ #define INIT_TIMES #endif +#if SANITIZER_S390 && (SANITIZER_INTERCEPT_TLS_GET_ADDR || \ + SANITIZER_INTERCEPT_TLS_GET_OFFSET) +extern "C" uptr __tls_get_offset_wrapper(void *arg, uptr (*fn)(void *arg)); +DEFINE_REAL(uptr, __tls_get_offset, void *arg) +#endif + #if SANITIZER_INTERCEPT_TLS_GET_ADDR #if !SANITIZER_S390 #define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr) @@ -5342,11 +5348,7 @@ // descriptor offset as an argument instead of a pointer. GOT address // is passed in r12, so it's necessary to write it in assembly. This is // the function used by the compiler. -extern "C" uptr __tls_get_offset_wrapper(void *arg, uptr (*fn)(void *arg)); #define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_offset) -DEFINE_REAL(uptr, __tls_get_offset, void *arg) -extern "C" uptr __tls_get_offset(void *arg); -extern "C" uptr __interceptor___tls_get_offset(void *arg); INTERCEPTOR(uptr, __tls_get_addr_internal, void *arg) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr_internal, arg); @@ -5362,6 +5364,15 @@ } return res; } +#endif // SANITIZER_S390 +#else +#define INIT_TLS_GET_ADDR +#endif + +#if SANITIZER_S390 && (SANITIZER_INTERCEPT_TLS_GET_ADDR || \ + SANITIZER_INTERCEPT_TLS_GET_OFFSET) +extern "C" uptr __tls_get_offset(void *arg); +extern "C" uptr __interceptor___tls_get_offset(void *arg); // We need a hidden symbol aliasing the above, so that we can jump // directly to it from the assembly below. extern "C" __attribute__((alias("__interceptor___tls_get_addr_internal"), @@ -5400,9 +5411,6 @@ "br %r3\n" ".size __tls_get_offset_wrapper, .-__tls_get_offset_wrapper\n" ); -#endif // SANITIZER_S390 -#else -#define INIT_TLS_GET_ADDR #endif #if SANITIZER_INTERCEPT_LISTXATTR Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -329,7 +329,7 @@ set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64}) set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64} ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9}) -set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64}) +set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9}) set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}) Index: clang/lib/Driver/ToolChains/Linux.cpp =================================================================== --- clang/lib/Driver/ToolChains/Linux.cpp +++ clang/lib/Driver/ToolChains/Linux.cpp @@ -709,7 +709,7 @@ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || IsRISCV64 || IsSystemZ) Res |= SanitizerKind::Leak; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ) Res |= SanitizerKind::Thread; if (IsX86_64) Res |= SanitizerKind::KernelMemory;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits