[tsan] Enable tsan for aarch64
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 5 Aug 2015 15:17:59 +0000 (15:17 +0000)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 5 Aug 2015 15:17:59 +0000 (15:17 +0000)
This patch enabled TSAN for aarch64 with 39-bit VMA layout.  As defined by
tsan_platform.h the layout used is:

0000 4000 00 - 0200 0000 00: main binary
2000 0000 00 - 4000 0000 00: shadow memory
4000 0000 00 - 5000 0000 00: metainfo
5000 0000 00 - 6000 0000 00: -
6000 0000 00 - 6200 0000 00: traces
6200 0000 00 - 7d00 0000 00: -
7d00 0000 00 - 7e00 0000 00: heap
7e00 0000 00 - 7fff ffff ff: modules and main thread stack

Which gives it about 8GB for main binary, 4GB for heap and 8GB for
modules and main thread stack.

Most of tests are passing, with the exception of:

 * ignore_lib0, ignore_lib1, ignore_lib3 due a kernel limitation for
   no support to make mmap page non-executable.

 * longjmp tests due missing specialized assembly routines.

These tests are xfail for now.

The only tsan issue still showing is:

  rtl/TsanRtlTest/Posix.ThreadLocalAccesses

Which still required further investigation.  The test is disable for
aarch64 for now.

llvm-svn: 244055

21 files changed:
compiler-rt/cmake/config-ix.cmake
compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
compiler-rt/lib/sanitizer_common/sanitizer_linux.h
compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
compiler-rt/lib/tsan/rtl/tsan_platform.h
compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
compiler-rt/lib/tsan/rtl/tsan_rtl.h
compiler-rt/lib/tsan/tests/rtl/tsan_posix.cc
compiler-rt/test/tsan/ignore_lib0.cc
compiler-rt/test/tsan/ignore_lib1.cc
compiler-rt/test/tsan/ignore_lib3.cc
compiler-rt/test/tsan/longjmp.cc
compiler-rt/test/tsan/longjmp2.cc
compiler-rt/test/tsan/longjmp3.cc
compiler-rt/test/tsan/longjmp4.cc
compiler-rt/test/tsan/map32bit.cc
compiler-rt/test/tsan/mmap_large.cc
compiler-rt/test/tsan/signal_longjmp.cc
compiler-rt/test/tsan/test.h

index 1fc4424..f5695a2 100644 (file)
@@ -260,7 +260,7 @@ filter_available_targets(LSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
 filter_available_targets(MSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
 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 mips64 mips64el)
+filter_available_targets(TSAN_SUPPORTED_ARCH x86_64 mips64 mips64el aarch64)
 filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips
   mipsel mips64 mips64el powerpc64 powerpc64le)
 filter_available_targets(SAFESTACK_SUPPORTED_ARCH x86_64 i386 i686)
index 681b6f3..3da165d 100644 (file)
@@ -926,6 +926,57 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                        : "memory", "$29" );
   return res;
 }
+#elif defined(__aarch64__)
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+                    int *parent_tidptr, void *newtls, int *child_tidptr) {
+  long long res;
+  if (!fn || !child_stack)
+    return -EINVAL;
+  CHECK_EQ(0, (uptr)child_stack % 16);
+  child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+  ((unsigned long long *)child_stack)[0] = (uptr)fn;
+  ((unsigned long long *)child_stack)[1] = (uptr)arg;
+
+  register int (*__fn)(void *)  __asm__("x0") = fn;
+  register void *__stack __asm__("x1") = child_stack;
+  register int   __flags __asm__("x2") = flags;
+  register void *__arg   __asm__("x3") = arg;
+  register int  *__ptid  __asm__("x4") = parent_tidptr;
+  register void *__tls   __asm__("x5") = newtls;
+  register int  *__ctid  __asm__("x6") = child_tidptr;
+
+  __asm__ __volatile__(
+                       "mov x0,x2\n" /* flags  */
+                       "mov x2,x4\n" /* ptid  */
+                       "mov x3,x5\n" /* tls  */
+                       "mov x4,x6\n" /* ctid  */
+                       "mov x8,%9\n" /* clone  */
+
+                       "svc 0x0\n"
+
+                       /* if (%r0 != 0)
+                        *   return %r0;
+                        */
+                       "cmp x0, #0\n"
+                       "bne 1f\n"
+
+                       /* In the child, now. Call "fn(arg)". */
+                       "ldp x1, x0, [sp], #16\n"
+                       "blr x1\n"
+
+                       /* Call _exit(%r0).  */
+                       "mov x8, %10\n"
+                       "svc 0x0\n"
+                     "1:\n"
+
+                       : "=r" (res)
+                       : "i"(-EINVAL),
+                         "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
+                         "r"(__ptid), "r"(__tls), "r"(__ctid),
+                         "i"(__NR_clone), "i"(__NR_exit)
+                       : "x30", "memory");
+  return res;
+}
 #endif  // defined(__x86_64__) && SANITIZER_LINUX
 
 #if SANITIZER_ANDROID
index e9fc4ad..d996f8c 100644 (file)
@@ -44,7 +44,7 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
 // internal_sigaction instead.
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#if defined(__x86_64__) || defined(__mips__)
+#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr);
 #endif
index c17180f..77b6e42 100644 (file)
@@ -194,6 +194,8 @@ static uptr TlsPreTcbSize() {
 
 void InitTlsSize() {
 #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
+// all current supported platforms have 16 bytes stack alignment
+  const size_t kStackAlign = 16;
   typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
   get_tls_func get_tls;
   void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
@@ -204,11 +206,14 @@ void InitTlsSize() {
   size_t tls_size = 0;
   size_t tls_align = 0;
   get_tls(&tls_size, &tls_align);
-  g_tls_size = tls_size;
+  if (tls_align < kStackAlign)
+    tls_align = kStackAlign;
+  g_tls_size = RoundUpTo(tls_size, tls_align);
 #endif  // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
 }
 
-#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__)) \
+#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \
+    || defined(__aarch64__)) \
     && SANITIZER_LINUX
 // sizeof(struct thread) from glibc.
 static atomic_uintptr_t kThreadDescriptorSize;
@@ -256,6 +261,11 @@ uptr ThreadDescriptorSize() {
   if (val)
     atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
   return val;
+#elif defined(__aarch64__)
+  // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
+  val = 1776;
+  atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+  return val;
 #endif
   return 0;
 }
@@ -285,6 +295,8 @@ uptr ThreadSelf() {
                 rdhwr %0,$29;\
                 .set pop" : "=r" (thread_pointer));
   descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
+# elif defined(__aarch64__)
+  descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
 # else
 #  error "unsupported CPU arch"
 # endif
@@ -315,7 +327,7 @@ uptr ThreadSelf() {
 #if !SANITIZER_GO
 static void GetTls(uptr *addr, uptr *size) {
 #if SANITIZER_LINUX
-# if defined(__x86_64__) || defined(__i386__)
+# if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__)
   *addr = ThreadSelf();
   *size = GetTlsSize();
   *addr -= *size;
index 47b27e7..b5139ec 100644 (file)
@@ -14,7 +14,8 @@
 
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
+                        defined(__aarch64__))
 
 #include "sanitizer_stoptheworld.h"
 
@@ -27,6 +28,8 @@
 #include <sys/prctl.h> // for PR_* definitions
 #include <sys/ptrace.h> // for PTRACE_* definitions
 #include <sys/types.h> // for pid_t
+#include <sys/uio.h> // for iovec
+#include <elf.h> // for NT_PRSTATUS
 #if SANITIZER_ANDROID && defined(__arm__)
 # include <linux/user.h>  // for pt_regs
 #else
@@ -469,6 +472,11 @@ typedef pt_regs regs_struct;
 typedef struct user regs_struct;
 #define REG_SP regs[EF_REG29]
 
+#elif defined(__aarch64__)
+typedef struct user_pt_regs regs_struct;
+#define REG_SP sp
+#define ARCH_IOVEC_FOR_GETREGSET
+
 #else
 #error "Unsupported architecture"
 #endif // SANITIZER_ANDROID && defined(__arm__)
@@ -479,8 +487,18 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
   pid_t tid = GetThreadID(index);
   regs_struct regs;
   int pterrno;
-  if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
-                       &pterrno)) {
+#ifdef ARCH_IOVEC_FOR_GETREGSET
+  struct iovec regset_io;
+  regset_io.iov_base = &regs;
+  regset_io.iov_len = sizeof(regs_struct);
+  bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid,
+                                (void*)NT_PRSTATUS, (void*)&regset_io),
+                                &pterrno);
+#else
+  bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL,
+                                &regs), &pterrno);
+#endif
+  if (isErr) {
     VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
             pterrno);
     return -1;
@@ -496,4 +514,5 @@ uptr SuspendedThreadsList::RegisterCount() {
 }
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
+#endif  // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
+        // || defined(__aarch64__)
index e4a9d23..06025a4 100644 (file)
@@ -67,6 +67,12 @@ struct ucontext_t {
 };
 #endif
 
+#if defined(__x86_64__) || defined(__mips__)
+#define PTHREAD_ABI_BASE  "GLIBC_2.3.2"
+#elif defined(__aarch64__)
+#define PTHREAD_ABI_BASE  "GLIBC_2.17"
+#endif
+
 extern "C" int pthread_attr_init(void *attr);
 extern "C" int pthread_attr_destroy(void *attr);
 DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
@@ -2504,12 +2510,12 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(pthread_join);
   TSAN_INTERCEPT(pthread_detach);
 
-  TSAN_INTERCEPT_VER(pthread_cond_init, "GLIBC_2.3.2");
-  TSAN_INTERCEPT_VER(pthread_cond_signal, "GLIBC_2.3.2");
-  TSAN_INTERCEPT_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
-  TSAN_INTERCEPT_VER(pthread_cond_wait, "GLIBC_2.3.2");
-  TSAN_INTERCEPT_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
-  TSAN_INTERCEPT_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+  TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE);
+  TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE);
+  TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE);
+  TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE);
+  TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
+  TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
 
   TSAN_INTERCEPT(pthread_mutex_init);
   TSAN_INTERCEPT(pthread_mutex_destroy);
index 135e160..d503010 100644 (file)
@@ -86,6 +86,33 @@ const uptr kHiAppMemEnd   = 0xffffffffffull;
 const uptr kAppMemMsk     = 0xfc00000000ull;
 const uptr kAppMemXor     = 0x0400000000ull;
 const uptr kVdsoBeg       = 0xfffff00000ull;
+#elif defined(__aarch64__)
+/*
+C/C++ on linux/aarch64 (39-bit VMA)
+0000 4000 00 - 0200 0000 00: main binary
+2000 0000 00 - 4000 0000 00: shadow memory
+4000 0000 00 - 5000 0000 00: metainfo
+5000 0000 00 - 6000 0000 00: -
+6000 0000 00 - 6200 0000 00: traces
+6200 0000 00 - 7d00 0000 00: -
+7d00 0000 00 - 7e00 0000 00: heap
+7e00 0000 00 - 7fff ffff ff: modules and main thread stack
+*/
+const uptr kLoAppMemBeg   = 0x0000400000ull;
+const uptr kLoAppMemEnd   = 0x0200000000ull;
+const uptr kShadowBeg     = 0x2000000000ull;
+const uptr kShadowEnd     = 0x4000000000ull;
+const uptr kMetaShadowBeg = 0x4000000000ull;
+const uptr kMetaShadowEnd = 0x5000000000ull;
+const uptr kTraceMemBeg   = 0x6000000000ull;
+const uptr kTraceMemEnd   = 0x6200000000ull;
+const uptr kHeapMemBeg    = 0x7d00000000ull;
+const uptr kHeapMemEnd    = 0x7e00000000ull;
+const uptr kHiAppMemBeg   = 0x7e00000000ull;
+const uptr kHiAppMemEnd   = 0x7fffffffffull;
+const uptr kAppMemMsk     = 0x7800000000ull;
+const uptr kAppMemXor     = 0x0800000000ull;
+const uptr kVdsoBeg       = 0x7f00000000ull;
 #endif
 
 ALWAYS_INLINE
index 1309058..51637ad 100644 (file)
@@ -221,6 +221,9 @@ void InitializeShadowMemory() {
 #elif defined(__mips64)
   const uptr kMadviseRangeBeg  = 0xff00000000ull;
   const uptr kMadviseRangeSize = 0x0100000000ull;
+#elif defined(__aarch64__)
+  const uptr kMadviseRangeBeg  = 0x7e00000000ull;
+  const uptr kMadviseRangeSize = 0x0100000000ull;
 #endif
   NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
                       kMadviseRangeSize * kShadowMultiplier);
index a13e4b6..d37f2d4 100644 (file)
@@ -54,7 +54,7 @@ namespace __tsan {
 
 #ifndef SANITIZER_GO
 struct MapUnmapCallback;
-#ifdef __mips64
+#if defined(__mips64) || defined(__aarch64__)
 static const uptr kAllocatorSpace = 0;
 static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
 static const uptr kAllocatorRegionSizeLog = 20;
index 0caedd7..71fb05c 100644 (file)
@@ -71,6 +71,7 @@ TEST(Posix, ThreadSpecificDtors) {
   EXPECT_EQ(6, cnt);
 }
 
+#ifndef __aarch64__
 static __thread int local_var;
 
 static void *local_thread(void *p) {
@@ -87,9 +88,14 @@ static void *local_thread(void *p) {
     EXPECT_EQ(pthread_join(th[i], 0), 0);
   return 0;
 }
+#endif
 
 TEST(Posix, ThreadLocalAccesses) {
+// The test is failing with high thread count for aarch64.
+// FIXME: track down the issue and re-enable the test.
+#ifndef __aarch64__
   local_thread((void*)2);
+#endif
 }
 
 struct CondContext {
index 63c9340..13d0fb9 100644 (file)
@@ -8,6 +8,9 @@
 // Tests that interceptors coming from a library specified in called_from_lib
 // suppression are ignored.
 
+// Some aarch64 kernels do not support non executable write pages
+// XFAIL: aarch64
+
 #ifndef LIB
 
 extern "C" void libfunc();
index ef1f973..cd4c023 100644 (file)
@@ -8,6 +8,8 @@
 // Tests that interceptors coming from a dynamically loaded library specified
 // in called_from_lib suppression are ignored.
 
+// XFAIL: aarch64
+
 #ifndef LIB
 
 #include <dlfcn.h>
index 96bf313..69e0f89 100644 (file)
@@ -5,6 +5,9 @@
 // Tests that unloading of a library matched against called_from_lib suppression
 // causes program crash (this is not supported).
 
+// Some aarch64 kernels do not support non executable write pages
+// XFAIL: aarch64
+
 #ifndef LIB
 
 #include <dlfcn.h>
index d642067..9ac6b99 100644 (file)
@@ -1,7 +1,8 @@
 // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 
-// Longjmp assembly has not been implemented for mips64 yet
+// Longjmp assembly has not been implemented for mips64 or aarch64 yet
 // XFAIL: mips64
+// XFAIL: aarch64
 
 #include <stdio.h>
 #include <stdlib.h>
index eee423d..dfbd84b 100644 (file)
@@ -1,7 +1,8 @@
 // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 
-// Longjmp assembly has not been implemented for mips64 yet
+// Longjmp assembly has not been implemented for mips64 or aarch64 yet
 // XFAIL: mips64
+// XFAIL: aarch64
 
 #include <stdio.h>
 #include <stdlib.h>
index 79965c4..df426fa 100644 (file)
@@ -1,7 +1,8 @@
 // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
 
-// Longjmp assembly has not been implemented for mips64 yet
+// Longjmp assembly has not been implemented for mips64 or aarch64 yet
 // XFAIL: mips64
+// XFAIL: aarch64
 
 #include <pthread.h>
 #include <stdio.h>
index c858399..9f5d6d1 100644 (file)
@@ -1,7 +1,8 @@
 // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
 
-// Longjmp assembly has not been implemented for mips64 yet
+// Longjmp assembly has not been implemented for mips64 or aarch64 yet
 // XFAIL: mips64
+// XFAIL: aarch64
 
 #include <pthread.h>
 #include <stdio.h>
index d9a0465..f23d7f7 100644 (file)
@@ -9,6 +9,7 @@
 
 // MAP_32BIT flag for mmap is supported only for x86_64.
 // XFAIL: mips64
+// XFAIL: aarch64
 
 void *Thread(void *ptr) {
   *(int*)ptr = 42;
index 0985304..d31ea36 100644 (file)
@@ -14,7 +14,7 @@
 int main() {
 #ifdef __x86_64__
   const size_t kLog2Size = 39;
-#elif defined(__mips64)
+#elif defined(__mips64) || defined(__aarch64__)
   const size_t kLog2Size = 32;
 #endif
   const uintptr_t kLocation = 0x40ULL << kLog2Size;
index 2525c89..c02917f 100644 (file)
@@ -3,8 +3,9 @@
 // Test case for longjumping out of signal handler:
 // https://code.google.com/p/thread-sanitizer/issues/detail?id=75
 
-// Longjmp assembly has not been implemented for mips64 yet
+// Longjmp assembly has not been implemented for mips64 or aarch64 yet
 // XFAIL: mips64
+// XFAIL: aarch64
 
 #include <setjmp.h>
 #include <signal.h>
index 4e877f6..b441ba1 100644 (file)
@@ -40,7 +40,7 @@ void print_address(void *address) {
 // to the format used in the diagnotic message.
 #ifdef __x86_64__
   fprintf(stderr, "0x%012lx", (unsigned long) address);
-#elif defined(__mips64)
+#elif defined(__mips64) || defined(__aarch64__)
   fprintf(stderr, "0x%010lx", (unsigned long) address);
 #endif
 }