Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -260,7 +260,7 @@ 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: lib/sanitizer_common/sanitizer_linux.h =================================================================== --- lib/sanitizer_common/sanitizer_linux.h +++ lib/sanitizer_common/sanitizer_linux.h @@ -44,7 +44,7 @@ // 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: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -926,6 +926,57 @@ : "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: lib/sanitizer_common/sanitizer_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -194,6 +194,8 @@ void InitTlsSize() { #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO +// all current supported platforms have 16 bytes stack alignment +# define STACK_ALIGN 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 @@ size_t tls_size = 0; size_t tls_align = 0; get_tls(&tls_size, &tls_align); - g_tls_size = tls_size; -#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO + if (tls_align < STACK_ALIGN) + tls_align = STACK_ALIGN; + g_tls_size = RoundUpTo(tls_size, tls_align); +#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID } -#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 @@ 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 @@ rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); +# elif defined(__aarch64__) + descr_addr = reinterpret_cast(__builtin_thread_pointer()); # else # error "unsupported CPU arch" # endif @@ -315,7 +327,7 @@ #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: lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -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 // for PR_* definitions #include // for PTRACE_* definitions #include // for pid_t +#include // for iovec +#include // for NT_PRSTATUS #if SANITIZER_ANDROID && defined(__arm__) # include // for pt_regs #else @@ -469,6 +472,11 @@ 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 @@ pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; - if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, ®s), - &pterrno)) { +#ifdef ARCH_IOVEC_FOR_GETREGSET + struct iovec regset_io; + regset_io.iov_base = ®s; + regset_io.iov_len = sizeof(regs_struct); + bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void*)NT_PRSTATUS, (void*)®set_io), + &pterrno); +#else + bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, + ®s), &pterrno); +#endif + if (isErr) { VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); return -1; @@ -496,4 +514,5 @@ } } // namespace __sanitizer -#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)) +#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) + // || defined(__aarch64__) Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -67,6 +67,12 @@ }; #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 @@ 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: lib/tsan/rtl/tsan_platform.h =================================================================== --- lib/tsan/rtl/tsan_platform.h +++ lib/tsan/rtl/tsan_platform.h @@ -86,6 +86,33 @@ 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: lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- lib/tsan/rtl/tsan_platform_linux.cc +++ lib/tsan/rtl/tsan_platform_linux.cc @@ -221,6 +221,9 @@ #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: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -54,7 +54,7 @@ #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: lib/tsan/tests/rtl/tsan_posix.cc =================================================================== --- lib/tsan/tests/rtl/tsan_posix.cc +++ lib/tsan/tests/rtl/tsan_posix.cc @@ -71,6 +71,7 @@ EXPECT_EQ(6, cnt); } +#ifndef __aarch64__ static __thread int local_var; static void *local_thread(void *p) { @@ -87,9 +88,14 @@ EXPECT_EQ(pthread_join(th[i], 0), 0); return 0; } +#endif TEST(Posix, ThreadLocalAccesses) { +// The test is failing with high thread count for aarch64. +// TODO(azanella): track down the issue and re-enable the test. +#ifndef __aarch64__ local_thread((void*)2); +#endif } struct CondContext { Index: test/tsan/ignore_lib0.cc =================================================================== --- test/tsan/ignore_lib0.cc +++ test/tsan/ignore_lib0.cc @@ -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: test/tsan/ignore_lib1.cc =================================================================== --- test/tsan/ignore_lib1.cc +++ test/tsan/ignore_lib1.cc @@ -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 Index: test/tsan/ignore_lib3.cc =================================================================== --- test/tsan/ignore_lib3.cc +++ test/tsan/ignore_lib3.cc @@ -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 Index: test/tsan/longjmp.cc =================================================================== --- test/tsan/longjmp.cc +++ test/tsan/longjmp.cc @@ -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 #include Index: test/tsan/longjmp2.cc =================================================================== --- test/tsan/longjmp2.cc +++ test/tsan/longjmp2.cc @@ -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 #include Index: test/tsan/longjmp3.cc =================================================================== --- test/tsan/longjmp3.cc +++ test/tsan/longjmp3.cc @@ -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 #include Index: test/tsan/longjmp4.cc =================================================================== --- test/tsan/longjmp4.cc +++ test/tsan/longjmp4.cc @@ -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 #include Index: test/tsan/map32bit.cc =================================================================== --- test/tsan/map32bit.cc +++ test/tsan/map32bit.cc @@ -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: test/tsan/mmap_large.cc =================================================================== --- test/tsan/mmap_large.cc +++ test/tsan/mmap_large.cc @@ -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: test/tsan/signal_longjmp.cc =================================================================== --- test/tsan/signal_longjmp.cc +++ test/tsan/signal_longjmp.cc @@ -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 #include Index: test/tsan/test.h =================================================================== --- test/tsan/test.h +++ test/tsan/test.h @@ -40,7 +40,7 @@ // 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 }