summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);