Skip to content

Commit

Permalink
[PPC64, TSAN] LLVM basic enablement of thread sanitizer for PPC64 (BE…
Browse files Browse the repository at this point in the history
… 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.

llvm-svn: 255057
  • Loading branch information
wschmidt-ibm committed Dec 8, 2015
1 parent 48eaa54 commit 2979162
Show file tree
Hide file tree
Showing 18 changed files with 270 additions and 11 deletions.
2 changes: 1 addition & 1 deletion compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
85 changes: 84 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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__)
6 changes: 4 additions & 2 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
127 changes: 127 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,79 @@ struct Mapping42 {
static const uptr kVdsoBeg = 0x37f00000000ull;
};

// 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
12 changes: 12 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_platform_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/tsan/rtl/tsan_rtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 2979162

Please sign in to comment.