[compiler-rt] move tsan's Android __get_tls() to sanitizer_common

Summary:
TSan's Android `__get_tls()` and `TLS_SLOT_TSAN` can be used by other sanitizers as well (see D32649), this change moves them to sanitizer_common.
I picked sanitizer_linux.h as their new home.
In the process, add the 32-bit versions for ARM, i386 & MIPS.

Can the address of `__get_tls()[TLS_SLOT_TSAN]` change in between the calls?
I am not sure if there is a need to repeat the construct as opposed to using a variable. So I left things as they were.

Testing on my side was restricted to a successful cross-compilation.

Reviewers: dvyukov, kubamracek

Reviewed By: dvyukov

Subscribers: aemerson, rengolin, srhines, dberris, arichardson, llvm-commits

Differential Revision: https://reviews.llvm.org/D32705

llvm-svn: 301926
This commit is contained in:
Kostya Kortchinsky 2017-05-02 15:13:36 +00:00
parent 6c3d19ba45
commit 7fc481e561
2 changed files with 45 additions and 19 deletions

View File

@ -88,6 +88,46 @@ bool LibraryNameIs(const char *full_name, const char *base_name);
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
#if SANITIZER_ANDROID
#if defined(__aarch64__)
# define __get_tls() \
({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; })
#elif defined(__arm__)
# define __get_tls() \
({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; })
#elif defined(__mips__)
// On mips32r1, this goes via a kernel illegal instruction trap that's
// optimized for v1.
# define __get_tls() \
({ register void** __v asm("v1"); \
__asm__(".set push\n" \
".set mips32r2\n" \
"rdhwr %0,$29\n" \
".set pop\n" : "=r"(__v)); \
__v; })
#elif defined(__i386__)
# define __get_tls() \
({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; })
#elif defined(__x86_64__)
# define __get_tls() \
({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; })
#else
#error "Unsupported architecture."
#endif
// The Android Bionic team has allocated a TLS slot for TSan starting with N,
// given that Android currently doesn't support ELF TLS. It is used to store
// Sanitizers thread specific data.
static const int TLS_SLOT_TSAN = 8;
ALWAYS_INLINE uptr *get_android_tls_ptr() {
return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_TSAN]);
}
#endif // SANITIZER_ANDROID
} // namespace __sanitizer
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX

View File

@ -341,36 +341,22 @@ void ReplaceSystemMalloc() { }
#if !SANITIZER_GO
#if SANITIZER_ANDROID
#if defined(__aarch64__)
# define __get_tls() \
({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
#elif defined(__x86_64__)
# define __get_tls() \
({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
#else
#error unsupported architecture
#endif
// On Android, __thread is not supported. So we store the pointer to ThreadState
// in TLS_SLOT_TSAN, which is the tls slot allocated by Android bionic for tsan.
static const int TLS_SLOT_TSAN = 8;
// On Android, one thread can call intercepted functions after
// DestroyThreadState(), so add a fake thread state for "dead" threads.
static ThreadState *dead_thread_state = nullptr;
ThreadState *cur_thread() {
ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr == nullptr) {
__sanitizer_sigset_t emptyset;
internal_sigfillset(&emptyset);
__sanitizer_sigset_t oldset;
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
thr = reinterpret_cast<ThreadState*>(__get_tls()[TLS_SLOT_TSAN]);
thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr == nullptr) {
thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),
"ThreadState"));
__get_tls()[TLS_SLOT_TSAN] = thr;
*get_android_tls_ptr() = reinterpret_cast<uptr>(thr);
if (dead_thread_state == nullptr) {
dead_thread_state = reinterpret_cast<ThreadState*>(
MmapOrDie(sizeof(ThreadState), "ThreadState"));
@ -392,9 +378,9 @@ void cur_thread_finalize() {
internal_sigfillset(&emptyset);
__sanitizer_sigset_t oldset;
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr != dead_thread_state) {
__get_tls()[TLS_SLOT_TSAN] = dead_thread_state;
*get_android_tls_ptr() = reinterpret_cast<uptr>(dead_thread_state);
UnmapOrDie(thr, sizeof(ThreadState));
}
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));