summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Schmidt <wschmidt@linux.vnet.ibm.com>2015-12-08 21:54:39 +0000
committerBill Schmidt <wschmidt@linux.vnet.ibm.com>2015-12-08 21:54:39 +0000
commit686cdf076959ee468a6777e9bed157291dc8445a (patch)
tree5e429770241a69d0b39d84e46e67ad1ff1ae1518
parent1f3b4537c406d7dca8b1c43b6dee5e0eaa9148d8 (diff)
[PPC64, TSAN] LLVM basic enablement of thread sanitizer for PPC64 (BE and LE)
This patch is by Simone Atzeni with portions by Adhemerval Zanella. This contains the LLVM patches to enable the thread sanitizer for PPC64, both big- and little-endian. Two different virtual memory sizes are supported: Old kernels use a 44-bit address space, while newer kernels require a 46-bit address space. There are two companion patches that will be added shortly. There is a Clang patch to actually turn on the use of the thread sanitizer for PPC64. There is also a patch that I wrote to provide interceptor support for setjmp/longjmp on PPC64. Patch discussion at reviews.llvm.org/D12841. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@255057 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--cmake/config-ix.cmake2
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc85
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h3
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc6
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc6
-rw-r--r--lib/tsan/rtl/tsan_platform.h127
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc8
-rw-r--r--lib/tsan/rtl/tsan_platform_posix.cc12
-rw-r--r--lib/tsan/rtl/tsan_rtl.h2
-rw-r--r--test/tsan/CMakeLists.txt2
-rw-r--r--test/tsan/cond_cancel.c8
-rw-r--r--test/tsan/java_race_pc.cc4
-rw-r--r--test/tsan/map32bit.cc1
-rw-r--r--test/tsan/mmap_large.cc2
-rw-r--r--test/tsan/race_on_mutex.c3
-rw-r--r--test/tsan/signal_errno.cc4
-rw-r--r--test/tsan/signal_longjmp.cc4
-rw-r--r--test/tsan/test.h2
18 files changed, 270 insertions, 11 deletions
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index 50e59c79e..f953704c6 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -278,7 +278,7 @@ set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
${MIPS32} ${MIPS64})
-set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
+set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
${MIPS32} ${MIPS64} ${PPC64})
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64})
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 2e685acc4..9239d1e6b 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -89,7 +89,8 @@ const int FUTEX_WAKE = 1;
// Are we using 32-bit or 64-bit Linux syscalls?
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
// but it still needs to use 64-bit syscalls.
-#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64)
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
+ SANITIZER_WORDSIZE == 64)
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
#else
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
@@ -983,6 +984,88 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
: "x30", "memory");
return res;
}
+#elif defined(__powerpc64__)
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ long long res;
+/* Stack frame offsets. */
+#if _CALL_ELF != 2
+#define FRAME_MIN_SIZE 112
+#define FRAME_TOC_SAVE 40
+#else
+#define FRAME_MIN_SIZE 32
+#define FRAME_TOC_SAVE 24
+#endif
+ 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__("r3") = fn;
+ register void *__cstack __asm__("r4") = child_stack;
+ register int __flags __asm__("r5") = flags;
+ register void * __arg __asm__("r6") = arg;
+ register int * __ptidptr __asm__("r7") = parent_tidptr;
+ register void * __newtls __asm__("r8") = newtls;
+ register int * __ctidptr __asm__("r9") = child_tidptr;
+
+ __asm__ __volatile__(
+ /* fn, arg, child_stack are saved acrVoss the syscall */
+ "mr 28, %5\n\t"
+ "mr 29, %6\n\t"
+ "mr 27, %8\n\t"
+
+ /* syscall
+ r3 == flags
+ r4 == child_stack
+ r5 == parent_tidptr
+ r6 == newtls
+ r7 == child_tidptr */
+ "mr 3, %7\n\t"
+ "mr 5, %9\n\t"
+ "mr 6, %10\n\t"
+ "mr 7, %11\n\t"
+ "li 0, %3\n\t"
+ "sc\n\t"
+
+ /* Test if syscall was successful */
+ "cmpdi cr1, 3, 0\n\t"
+ "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
+ "bne- cr1, 1f\n\t"
+
+ /* Do the function call */
+ "std 2, %13(1)\n\t"
+#if _CALL_ELF != 2
+ "ld 0, 0(28)\n\t"
+ "ld 2, 8(28)\n\t"
+ "mtctr 0\n\t"
+#else
+ "mr 12, 28\n\t"
+ "mtctr 12\n\t"
+#endif
+ "mr 3, 27\n\t"
+ "bctrl\n\t"
+ "ld 2, %13(1)\n\t"
+
+ /* Call _exit(r3) */
+ "li 0, %4\n\t"
+ "sc\n\t"
+
+ /* Return to parent */
+ "1:\n\t"
+ "mr %0, 3\n\t"
+ : "=r" (res)
+ : "0" (-1), "i" (EINVAL),
+ "i" (__NR_clone), "i" (__NR_exit),
+ "r" (__fn), "r" (__cstack), "r" (__flags),
+ "r" (__arg), "r" (__ptidptr), "r" (__newtls),
+ "r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE)
+ : "cr0", "cr1", "memory", "ctr",
+ "r0", "r29", "r27", "r28");
+ return res;
+}
#endif // defined(__x86_64__) && SANITIZER_LINUX
#if SANITIZER_ANDROID
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index d996f8c32..77bfbd156 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -44,7 +44,8 @@ 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__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
+ || defined(__powerpc64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 6fd63126f..2376ee56e 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -15,7 +15,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
- defined(__aarch64__))
+ defined(__aarch64__) || defined(__powerpc64__))
#include "sanitizer_stoptheworld.h"
@@ -511,5 +511,5 @@ uptr SuspendedThreadsList::RegisterCount() {
}
} // namespace __sanitizer
-#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
- // || defined(__aarch64__)
+#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
+ // || defined(__aarch64__) || defined(__powerpc64__)
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 57a676f8d..bc31075c7 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -79,9 +79,11 @@ struct ucontext_t {
};
#endif
-#if defined(__x86_64__) || defined(__mips__)
+#if defined(__x86_64__) || defined(__mips__) \
+ || (defined(__powerpc64__) && defined(__BIG_ENDIAN__))
#define PTHREAD_ABI_BASE "GLIBC_2.3.2"
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || (defined(__powerpc64__) \
+ && defined(__LITTLE_ENDIAN__))
#define PTHREAD_ABI_BASE "GLIBC_2.17"
#endif
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index 254ea7985..b6bd8b0f5 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -161,6 +161,79 @@ struct Mapping42 {
// Indicates the runtime will define the memory regions at runtime.
#define TSAN_RUNTIME_VMA 1
+#elif defined(__powerpc64__)
+// PPC64 supports multiple VMA which leads to multiple address transformation
+// functions. To support these multiple VMAS transformations and mappings TSAN
+// runtime for PPC64 uses an external memory read (vmaSize) to select which
+// mapping to use. Although slower, it make a same instrumented binary run on
+// multiple kernels.
+
+/*
+C/C++ on linux/powerpc64 (44-bit VMA)
+0000 0000 0100 - 0001 0000 0000: main binary
+0001 0000 0000 - 0001 0000 0000: -
+0001 0000 0000 - 0b00 0000 0000: shadow
+0b00 0000 0000 - 0b00 0000 0000: -
+0b00 0000 0000 - 0d00 0000 0000: metainfo (memory blocks and sync objects)
+0d00 0000 0000 - 0d00 0000 0000: -
+0d00 0000 0000 - 0f00 0000 0000: traces
+0f00 0000 0000 - 0f00 0000 0000: -
+0f00 0000 0000 - 0f50 0000 0000: heap
+0f50 0000 0000 - 0f60 0000 0000: -
+0f60 0000 0000 - 1000 0000 0000: modules and main thread stack
+*/
+struct Mapping44 {
+ static const uptr kMetaShadowBeg = 0x0b0000000000ull;
+ static const uptr kMetaShadowEnd = 0x0d0000000000ull;
+ static const uptr kTraceMemBeg = 0x0d0000000000ull;
+ static const uptr kTraceMemEnd = 0x0f0000000000ull;
+ static const uptr kShadowBeg = 0x000100000000ull;
+ static const uptr kShadowEnd = 0x0b0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000000100ull;
+ static const uptr kLoAppMemEnd = 0x000100000000ull;
+ static const uptr kHeapMemBeg = 0x0f0000000000ull;
+ static const uptr kHeapMemEnd = 0x0f5000000000ull;
+ static const uptr kHiAppMemBeg = 0x0f6000000000ull;
+ static const uptr kHiAppMemEnd = 0x100000000000ull; // 44 bits
+ static const uptr kAppMemMsk = 0x0f0000000000ull;
+ static const uptr kAppMemXor = 0x002100000000ull;
+ static const uptr kVdsoBeg = 0x3c0000000000000ull;
+};
+
+/*
+C/C++ on linux/powerpc64 (46-bit VMA)
+0000 0000 1000 - 0100 0000 0000: main binary
+0100 0000 0000 - 0200 0000 0000: -
+0100 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 1000 0000 0000: -
+1000 0000 0000 - 2000 0000 0000: metainfo (memory blocks and sync objects)
+2000 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2200 0000 0000: traces
+2200 0000 0000 - 3d00 0000 0000: -
+3d00 0000 0000 - 3e00 0000 0000: heap
+3e00 0000 0000 - 3e80 0000 0000: -
+3e80 0000 0000 - 4000 0000 0000: modules and main thread stack
+*/
+struct Mapping46 {
+ static const uptr kMetaShadowBeg = 0x100000000000ull;
+ static const uptr kMetaShadowEnd = 0x200000000000ull;
+ static const uptr kTraceMemBeg = 0x200000000000ull;
+ static const uptr kTraceMemEnd = 0x220000000000ull;
+ static const uptr kShadowBeg = 0x010000000000ull;
+ static const uptr kShadowEnd = 0x100000000000ull;
+ static const uptr kHeapMemBeg = 0x3d0000000000ull;
+ static const uptr kHeapMemEnd = 0x3e0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000001000ull;
+ static const uptr kLoAppMemEnd = 0x010000000000ull;
+ static const uptr kHiAppMemBeg = 0x3e8000000000ull;
+ static const uptr kHiAppMemEnd = 0x400000000000ull; // 46 bits
+ static const uptr kAppMemMsk = 0x3c0000000000ull;
+ static const uptr kAppMemXor = 0x020000000000ull;
+ static const uptr kVdsoBeg = 0x7800000000000000ull;
+};
+
+// Indicates the runtime will define the memory regions at runtime.
+#define TSAN_RUNTIME_VMA 1
#endif
#elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS
@@ -274,6 +347,12 @@ uptr MappingArchImpl(void) {
else
return MappingImpl<Mapping42, Type>();
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MappingImpl<Mapping44, Type>();
+ else
+ return MappingImpl<Mapping46, Type>();
+ DCHECK(0);
#else
return MappingImpl<Mapping, Type>();
#endif
@@ -399,6 +478,12 @@ bool IsAppMem(uptr mem) {
else
return IsAppMemImpl<Mapping42>(mem);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsAppMemImpl<Mapping44>(mem);
+ else
+ return IsAppMemImpl<Mapping46>(mem);
+ DCHECK(0);
#else
return IsAppMemImpl<Mapping>(mem);
#endif
@@ -418,6 +503,12 @@ bool IsShadowMem(uptr mem) {
else
return IsShadowMemImpl<Mapping42>(mem);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsShadowMemImpl<Mapping44>(mem);
+ else
+ return IsShadowMemImpl<Mapping46>(mem);
+ DCHECK(0);
#else
return IsShadowMemImpl<Mapping>(mem);
#endif
@@ -437,6 +528,12 @@ bool IsMetaMem(uptr mem) {
else
return IsMetaMemImpl<Mapping42>(mem);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsMetaMemImpl<Mapping44>(mem);
+ else
+ return IsMetaMemImpl<Mapping46>(mem);
+ DCHECK(0);
#else
return IsMetaMemImpl<Mapping>(mem);
#endif
@@ -462,6 +559,12 @@ uptr MemToShadow(uptr x) {
else
return MemToShadowImpl<Mapping42>(x);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MemToShadowImpl<Mapping44>(x);
+ else
+ return MemToShadowImpl<Mapping46>(x);
+ DCHECK(0);
#else
return MemToShadowImpl<Mapping>(x);
#endif
@@ -489,6 +592,12 @@ u32 *MemToMeta(uptr x) {
else
return MemToMetaImpl<Mapping42>(x);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MemToMetaImpl<Mapping44>(x);
+ else
+ return MemToMetaImpl<Mapping46>(x);
+ DCHECK(0);
#else
return MemToMetaImpl<Mapping>(x);
#endif
@@ -522,6 +631,12 @@ uptr ShadowToMem(uptr s) {
else
return ShadowToMemImpl<Mapping42>(s);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return ShadowToMemImpl<Mapping44>(s);
+ else
+ return ShadowToMemImpl<Mapping46>(s);
+ DCHECK(0);
#else
return ShadowToMemImpl<Mapping>(s);
#endif
@@ -549,6 +664,12 @@ uptr GetThreadTrace(int tid) {
else
return GetThreadTraceImpl<Mapping42>(tid);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return GetThreadTraceImpl<Mapping44>(tid);
+ else
+ return GetThreadTraceImpl<Mapping46>(tid);
+ DCHECK(0);
#else
return GetThreadTraceImpl<Mapping>(tid);
#endif
@@ -571,6 +692,12 @@ uptr GetThreadTraceHeader(int tid) {
else
return GetThreadTraceHeaderImpl<Mapping42>(tid);
DCHECK(0);
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return GetThreadTraceHeaderImpl<Mapping44>(tid);
+ else
+ return GetThreadTraceHeaderImpl<Mapping46>(tid);
+ DCHECK(0);
#else
return GetThreadTraceHeaderImpl<Mapping>(tid);
#endif
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index a635f4e74..ff7a4b975 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -244,11 +244,19 @@ void InitializePlatformEarly() {
#ifdef TSAN_RUNTIME_VMA
vmaSize =
(MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+#if defined(__aarch64__)
if (vmaSize != 39 && vmaSize != 42) {
Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
Printf("FATAL: Found %d - Supported 39 and 42\n", vmaSize);
Die();
}
+#elif defined(__powerpc64__)
+ if (vmaSize != 44 && vmaSize != 46) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 42 and 46\n", vmaSize);
+ Die();
+ }
+#endif
#endif
}
diff --git a/lib/tsan/rtl/tsan_platform_posix.cc b/lib/tsan/rtl/tsan_platform_posix.cc
index 968dd4093..7c9acf5b5 100644
--- a/lib/tsan/rtl/tsan_platform_posix.cc
+++ b/lib/tsan/rtl/tsan_platform_posix.cc
@@ -58,6 +58,18 @@ void InitializeShadowMemory() {
} else {
DCHECK(0);
}
+#elif defined(__powerpc64__)
+ uptr kMadviseRangeBeg = 0;
+ uptr kMadviseRangeSize = 0;
+ if (vmaSize == 44) {
+ kMadviseRangeBeg = 0x0f60000000ull;
+ kMadviseRangeSize = 0x0010000000ull;
+ } else if (vmaSize == 46) {
+ kMadviseRangeBeg = 0x3f0000000000ull;
+ kMadviseRangeSize = 0x010000000000ull;
+ } else {
+ DCHECK(0);
+ }
#endif
NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
kMadviseRangeSize * kShadowMultiplier);
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index a709b4f8f..04104b162 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -54,7 +54,7 @@ namespace __tsan {
#ifndef SANITIZER_GO
struct MapUnmapCallback;
-#if defined(__mips64) || defined(__aarch64__)
+#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
static const uptr kAllocatorSpace = 0;
static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kAllocatorRegionSizeLog = 20;
diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
index d4fed1d16..01e80388b 100644
--- a/test/tsan/CMakeLists.txt
+++ b/test/tsan/CMakeLists.txt
@@ -1,5 +1,5 @@
set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
-if(NOT ${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "mips")
+if(${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "x86_64")
list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck)
endif()
if(NOT COMPILER_RT_STANDALONE_BUILD)
diff --git a/test/tsan/cond_cancel.c b/test/tsan/cond_cancel.c
index ddfb74517..ca56e8ee9 100644
--- a/test/tsan/cond_cancel.c
+++ b/test/tsan/cond_cancel.c
@@ -1,6 +1,14 @@
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
// CHECK-NOT: WARNING
// CHECK: OK
+// This test is failing on powerpc64 (VMA=44). After calling pthread_cancel,
+// the Thread-specific data destructors are not called, so the destructor
+// "thread_finalize" (defined in tsan_interceptors.cc) can not set the status
+// of the thread to "ThreadStatusFinished" failing a check in "SetJoined"
+// (defined in sanitizer_thread_registry.cc). It might seem a bug on glibc,
+// however the same version GLIBC-2.17 will not make fail the test on
+// powerpc64 (VMA=46)
+// XFAIL: powerpc64
#include "test.h"
diff --git a/test/tsan/java_race_pc.cc b/test/tsan/java_race_pc.cc
index 015a0b1f4..0745ade6c 100644
--- a/test/tsan/java_race_pc.cc
+++ b/test/tsan/java_race_pc.cc
@@ -1,4 +1,8 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// This test fails on powerpc64 on both VMA (44 and 46).
+// The Tsan report is returning wrong information about
+// the location of the race.
+// XFAIL: powerpc64
#include "java.h"
void foobar() {
diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc
index 9f933bc4e..0411f29a9 100644
--- a/test/tsan/map32bit.cc
+++ b/test/tsan/map32bit.cc
@@ -10,6 +10,7 @@
// MAP_32BIT flag for mmap is supported only for x86_64.
// XFAIL: mips64
// XFAIL: aarch64
+// XFAIL: powerpc64
// MAP_32BIT doesn't exist on OS X.
// UNSUPPORTED: darwin
diff --git a/test/tsan/mmap_large.cc b/test/tsan/mmap_large.cc
index de32d911f..764e954f2 100644
--- a/test/tsan/mmap_large.cc
+++ b/test/tsan/mmap_large.cc
@@ -16,6 +16,8 @@ int main() {
const size_t kLog2Size = 39;
#elif defined(__mips64) || defined(__aarch64__)
const size_t kLog2Size = 32;
+#elif defined(__powerpc64__)
+ const size_t kLog2Size = 39;
#endif
const uintptr_t kLocation = 0x40ULL << kLog2Size;
void *p = mmap(
diff --git a/test/tsan/race_on_mutex.c b/test/tsan/race_on_mutex.c
index 7bd461bf3..ec705dee9 100644
--- a/test/tsan/race_on_mutex.c
+++ b/test/tsan/race_on_mutex.c
@@ -1,4 +1,7 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// This test fails on powerpc64 (VMA=46).
+// The size of the write reported by Tsan for T1 is 8 instead of 1.
+// XFAIL: powerpc64
#include "test.h"
pthread_mutex_t Mtx;
diff --git a/test/tsan/signal_errno.cc b/test/tsan/signal_errno.cc
index 5354cdeeb..ce19950be 100644
--- a/test/tsan/signal_errno.cc
+++ b/test/tsan/signal_errno.cc
@@ -1,4 +1,8 @@
// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// This test fails on powerpc64 (VMA=44), it does not appear to be
+// a functional problem, but the Tsan report is missing some info.
+// XFAIL: powerpc64
+
#include "test.h"
#include <signal.h>
#include <sys/types.h>
diff --git a/test/tsan/signal_longjmp.cc b/test/tsan/signal_longjmp.cc
index 556928ae9..fb4d2781d 100644
--- a/test/tsan/signal_longjmp.cc
+++ b/test/tsan/signal_longjmp.cc
@@ -5,6 +5,10 @@
// Longjmp assembly has not been implemented for mips64 yet
// XFAIL: mips64
+// This test fails on powerpc64 (VMA=44), a segmentation fault
+// error happens at the second assignment
+// "((volatile int *volatile)mem)[1] = 1".
+// XFAIL: powerpc64
#include <setjmp.h>
#include <signal.h>
diff --git a/test/tsan/test.h b/test/tsan/test.h
index cec7c0d32..a681daa32 100644
--- a/test/tsan/test.h
+++ b/test/tsan/test.h
@@ -43,7 +43,7 @@ void print_address(const char *str, int n, ...) {
va_start(ap, n);
while (n--) {
void *p = va_arg(ap, void *);
-#if defined(__x86_64__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
// On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
// match to the format used in the diagnotic message.
fprintf(stderr, "0x%012lx ", (unsigned long) p);