[RISCV][ASAN] implementation of ThreadSelf for riscv64

[6/11] patch series to port ASAN for riscv64

Depends On D87574

Reviewed By: eugenis

Differential Revision: https://reviews.llvm.org/D87575
This commit is contained in:
Anatoly Parshintsev 2020-09-22 22:27:40 -07:00 committed by Vitaly Buka
parent aa1b1d35cb
commit 00f6ebef6e
1 changed files with 118 additions and 113 deletions

View File

@ -16,6 +16,13 @@
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_OPENBSD || SANITIZER_SOLARIS SANITIZER_OPENBSD || SANITIZER_SOLARIS
#include <dlfcn.h> // for dlsym()
#include <link.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#include <syslog.h>
#include "sanitizer_allocator_internal.h" #include "sanitizer_allocator_internal.h"
#include "sanitizer_atomic.h" #include "sanitizer_atomic.h"
#include "sanitizer_common.h" #include "sanitizer_common.h"
@ -28,20 +35,13 @@
#include "sanitizer_placement_new.h" #include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h" #include "sanitizer_procmaps.h"
#include <dlfcn.h> // for dlsym()
#include <link.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#include <syslog.h>
#if !defined(ElfW) #if !defined(ElfW)
#define ElfW(type) Elf_##type #define ElfW(type) Elf_##type
#endif #endif
#if SANITIZER_FREEBSD #if SANITIZER_FREEBSD
#include <pthread_np.h>
#include <osreldate.h> #include <osreldate.h>
#include <pthread_np.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#define pthread_getattr_np pthread_attr_get_np #define pthread_getattr_np pthread_attr_get_np
#endif #endif
@ -52,9 +52,9 @@
#endif #endif
#if SANITIZER_NETBSD #if SANITIZER_NETBSD
#include <lwp.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/tls.h> #include <sys/tls.h>
#include <lwp.h>
#endif #endif
#if SANITIZER_SOLARIS #if SANITIZER_SOLARIS
@ -83,8 +83,8 @@ struct __sanitizer::linux_dirent {
namespace __sanitizer { namespace __sanitizer {
SANITIZER_WEAK_ATTRIBUTE int SANITIZER_WEAK_ATTRIBUTE int real_sigaction(int signum, const void *act,
real_sigaction(int signum, const void *act, void *oldact); void *oldact);
int internal_sigaction(int signum, const void *act, void *oldact) { int internal_sigaction(int signum, const void *act, void *oldact) {
#if !SANITIZER_GO #if !SANITIZER_GO
@ -113,7 +113,8 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
MemoryMappedSegment segment; MemoryMappedSegment segment;
uptr prev_end = 0; uptr prev_end = 0;
while (proc_maps.Next(&segment)) { while (proc_maps.Next(&segment)) {
if ((uptr)&rl < segment.end) break; if ((uptr)&rl < segment.end)
break;
prev_end = segment.end; prev_end = segment.end;
} }
CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end); CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
@ -121,7 +122,8 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
// Get stacksize from rlimit, but clip it so that it does not overlap // Get stacksize from rlimit, but clip it so that it does not overlap
// with other mappings. // with other mappings.
uptr stacksize = rl.rlim_cur; uptr stacksize = rl.rlim_cur;
if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end; if (stacksize > segment.end - prev_end)
stacksize = segment.end - prev_end;
// When running with unlimited stack size, we still want to set some limit. // When running with unlimited stack size, we still want to set some limit.
// The unlimited stack size is caused by 'ulimit -s unlimited'. // The unlimited stack size is caused by 'ulimit -s unlimited'.
// Also, for some reason, GNU make spawns subprocesses with unlimited stack. // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
@ -251,11 +253,11 @@ void InitTlsSize() {
// __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
// function in 2.27 and later. // function in 2.27 and later.
if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0)) if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr, CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr, &tls_size,
&tls_size, &tls_align); &tls_align);
else else
CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr, CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr, &tls_size,
&tls_size, &tls_align); &tls_align);
if (tls_align < kStackAlign) if (tls_align < kStackAlign)
tls_align = kStackAlign; tls_align = kStackAlign;
g_tls_size = RoundUpTo(tls_size, tls_align); g_tls_size = RoundUpTo(tls_size, tls_align);
@ -323,11 +325,9 @@ uptr ThreadDescriptorSize() {
// The offset at which pointer to self is located in the thread descriptor. // The offset at which pointer to self is located in the thread descriptor.
const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16); const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
uptr ThreadSelfOffset() { uptr ThreadSelfOffset() { return kThreadSelfOffset; }
return kThreadSelfOffset;
}
#if defined(__mips__) || defined(__powerpc64__) #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
// head structure. It lies before the static tls blocks. // head structure. It lies before the static tls blocks.
static uptr TlsPreTcbSize() { static uptr TlsPreTcbSize() {
@ -335,6 +335,8 @@ static uptr TlsPreTcbSize() {
const uptr kTcbHead = 16; // sizeof (tcbhead_t) const uptr kTcbHead = 16; // sizeof (tcbhead_t)
#elif defined(__powerpc64__) #elif defined(__powerpc64__)
const uptr kTcbHead = 88; // sizeof (tcbhead_t) const uptr kTcbHead = 88; // sizeof (tcbhead_t)
#elif SANITIZER_RISCV64
const uptr kTcbHead = 16; // sizeof (tcbhead_t)
#endif #endif
const uptr kTlsAlign = 16; const uptr kTlsAlign = 16;
const uptr kTlsPreTcbSize = const uptr kTlsPreTcbSize =
@ -356,14 +358,23 @@ uptr ThreadSelf() {
// TCB and the size of pthread_descr. // TCB and the size of pthread_descr.
const uptr kTlsTcbOffset = 0x7000; const uptr kTlsTcbOffset = 0x7000;
uptr thread_pointer; uptr thread_pointer;
asm volatile(".set push;\ asm volatile(
".set push;\
.set mips64r2;\ .set mips64r2;\
rdhwr %0,$29;\ rdhwr %0,$29;\
.set pop" : "=r" (thread_pointer)); .set pop"
: "=r"(thread_pointer));
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
#elif defined(__aarch64__) || defined(__arm__) #elif defined(__aarch64__) || defined(__arm__)
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) - descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
ThreadDescriptorSize(); ThreadDescriptorSize();
#elif SANITIZER_RISCV64
uptr tcb_end;
asm volatile("mv %0, tp;\n" : "=r"(tcb_end));
// https://github.com/riscv/riscv-elf-psabi-doc/issues/53
const uptr kTlsTcbOffset = 0x800;
descr_addr =
reinterpret_cast<uptr>(tcb_end - kTlsTcbOffset - TlsPreTcbSize());
#elif defined(__s390__) #elif defined(__s390__)
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()); descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
#elif defined(__powerpc64__) #elif defined(__powerpc64__)
@ -397,9 +408,7 @@ static void **ThreadSelfSegbase() {
return segbase; return segbase;
} }
uptr ThreadSelf() { uptr ThreadSelf() { return (uptr)ThreadSelfSegbase()[2]; }
return (uptr)ThreadSelfSegbase()[2];
}
#endif // SANITIZER_FREEBSD #endif // SANITIZER_FREEBSD
#if SANITIZER_NETBSD #if SANITIZER_NETBSD
@ -407,9 +416,7 @@ static struct tls_tcb * ThreadSelfTlsTcb() {
return (struct tls_tcb *)_lwp_getprivate(); return (struct tls_tcb *)_lwp_getprivate();
} }
uptr ThreadSelf() { uptr ThreadSelf() { return (uptr)ThreadSelfTlsTcb()->tcb_pthread; }
return (uptr)ThreadSelfTlsTcb()->tcb_pthread;
}
int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) { int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
const Elf_Phdr *hdr = info->dlpi_phdr; const Elf_Phdr *hdr = info->dlpi_phdr;
@ -433,8 +440,8 @@ static void GetTls(uptr *addr, uptr *size) {
*size = GetTlsSize(); *size = GetTlsSize();
*addr -= *size; *addr -= *size;
*addr += ThreadDescriptorSize(); *addr += ThreadDescriptorSize();
# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \ #elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
|| defined(__arm__) defined(__arm__)
*addr = ThreadSelf(); *addr = ThreadSelf();
*size = GetTlsSize(); *size = GetTlsSize();
#else #else
@ -558,8 +565,7 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
uptr cur_end = cur_beg + phdr->p_memsz; uptr cur_end = cur_beg + phdr->p_memsz;
bool executable = phdr->p_flags & PF_X; bool executable = phdr->p_flags & PF_X;
bool writable = phdr->p_flags & PF_W; bool writable = phdr->p_flags & PF_W;
cur_module.addAddressRange(cur_beg, cur_end, executable, cur_module.addAddressRange(cur_beg, cur_end, executable, writable);
writable);
} }
} }
data->modules->push_back(cur_module); data->modules->push_back(cur_module);
@ -635,15 +641,12 @@ uptr GetRSS() {
// We need the second number which is RSS in pages. // We need the second number which is RSS in pages.
char *pos = buf; char *pos = buf;
// Skip the first number. // Skip the first number.
while (*pos >= '0' && *pos <= '9') while (*pos >= '0' && *pos <= '9') pos++;
pos++;
// Skip whitespaces. // Skip whitespaces.
while (!(*pos >= '0' && *pos <= '9') && *pos != 0) while (!(*pos >= '0' && *pos <= '9') && *pos != 0) pos++;
pos++;
// Read the number. // Read the number.
uptr rss = 0; uptr rss = 0;
while (*pos >= '0' && *pos <= '9') while (*pos >= '0' && *pos <= '9') rss = rss * 10 + *pos++ - '0';
rss = rss * 10 + *pos++ - '0';
return rss * GetPageSizeCached(); return rss * GetPageSizeCached();
} }
@ -686,8 +689,8 @@ u32 GetNumberOfCPUs() {
break; break;
if (entry->d_ino != 0 && *d_type == DT_DIR) { if (entry->d_ino != 0 && *d_type == DT_DIR) {
if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' && if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' &&
entry->d_name[2] == 'u' && entry->d_name[2] == 'u' && entry->d_name[3] >= '0' &&
entry->d_name[3] >= '0' && entry->d_name[3] <= '9') entry->d_name[3] <= '9')
n_cpus++; n_cpus++;
} }
entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen); entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen);
@ -717,10 +720,12 @@ static bool ShouldLogAfterPrintf() {
return atomic_load(&android_log_initialized, memory_order_acquire); return atomic_load(&android_log_initialized, memory_order_acquire);
} }
extern "C" SANITIZER_WEAK_ATTRIBUTE extern "C" SANITIZER_WEAK_ATTRIBUTE int async_safe_write_log(int pri,
int async_safe_write_log(int pri, const char* tag, const char* msg); const char *tag,
extern "C" SANITIZER_WEAK_ATTRIBUTE const char *msg);
int __android_log_write(int prio, const char* tag, const char* msg); extern "C" SANITIZER_WEAK_ATTRIBUTE int __android_log_write(int prio,
const char *tag,
const char *msg);
// ANDROID_LOG_INFO is 4, but can't be resolved at runtime. // ANDROID_LOG_INFO is 4, but can't be resolved at runtime.
#define SANITIZER_ANDROID_LOG_INFO 4 #define SANITIZER_ANDROID_LOG_INFO 4
@ -742,8 +747,8 @@ void WriteOneLineToSyslog(const char *s) {
} }
} }
extern "C" SANITIZER_WEAK_ATTRIBUTE extern "C" SANITIZER_WEAK_ATTRIBUTE void android_set_abort_message(
void android_set_abort_message(const char *); const char *);
void SetAbortMessage(const char *str) { void SetAbortMessage(const char *str) {
if (&android_set_abort_message) if (&android_set_abort_message)
@ -784,8 +789,8 @@ inline bool CanUseVDSO() {
// MonotonicNanoTime is a timing function that can leverage the vDSO by calling // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
// clock_gettime. real_clock_gettime only exists if clock_gettime is // clock_gettime. real_clock_gettime only exists if clock_gettime is
// intercepted, so define it weakly and use it if available. // intercepted, so define it weakly and use it if available.
extern "C" SANITIZER_WEAK_ATTRIBUTE extern "C" SANITIZER_WEAK_ATTRIBUTE int real_clock_gettime(u32 clk_id,
int real_clock_gettime(u32 clk_id, void *tp); void *tp);
u64 MonotonicNanoTime() { u64 MonotonicNanoTime() {
timespec ts; timespec ts;
if (CanUseVDSO()) { if (CanUseVDSO()) {