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

Reply via email to