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)
: "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
// 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
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");
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;
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;
}
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
#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;
#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"
#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
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__)
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;
}
} // namespace __sanitizer
-#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
+#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
+ // || defined(__aarch64__)
};
#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 *)
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);
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
#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);
#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;
EXPECT_EQ(6, cnt);
}
+#ifndef __aarch64__
static __thread int local_var;
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 {
// 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();
// Tests that interceptors coming from a dynamically loaded library specified
// in called_from_lib suppression are ignored.
+// XFAIL: aarch64
+
#ifndef LIB
#include <dlfcn.h>
// 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>
// 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>
// 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>
// 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>
// 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>
// MAP_32BIT flag for mmap is supported only for x86_64.
// XFAIL: mips64
+// XFAIL: aarch64
void *Thread(void *ptr) {
*(int*)ptr = 42;
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;
// 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>
// 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
}