168d75effSDimitry Andric //===-- sanitizer_linux.cpp -----------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries and implements linux-specific functions from 1168d75effSDimitry Andric // sanitizer_libc.h. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "sanitizer_platform.h" 1568d75effSDimitry Andric 1668d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 17e8d8bef9SDimitry Andric SANITIZER_SOLARIS 1868d75effSDimitry Andric 1968d75effSDimitry Andric # include "sanitizer_common.h" 2068d75effSDimitry Andric # include "sanitizer_flags.h" 2168d75effSDimitry Andric # include "sanitizer_getauxval.h" 2268d75effSDimitry Andric # include "sanitizer_internal_defs.h" 2368d75effSDimitry Andric # include "sanitizer_libc.h" 2468d75effSDimitry Andric # include "sanitizer_linux.h" 2568d75effSDimitry Andric # include "sanitizer_mutex.h" 2668d75effSDimitry Andric # include "sanitizer_placement_new.h" 2768d75effSDimitry Andric # include "sanitizer_procmaps.h" 2868d75effSDimitry Andric 295ffd83dbSDimitry Andric # if SANITIZER_LINUX && !SANITIZER_GO 3068d75effSDimitry Andric # include <asm/param.h> 3168d75effSDimitry Andric # endif 3268d75effSDimitry Andric 3368d75effSDimitry Andric // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' 3468d75effSDimitry Andric // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To 3568d75effSDimitry Andric // access stat from asm/stat.h, without conflicting with definition in 3662987288SDimitry Andric // sys/stat.h, we use this trick. sparc64 is similar, using 3762987288SDimitry Andric // syscall(__NR_stat64) and struct kernel_stat64. 386c4b055cSDimitry Andric # if SANITIZER_LINUX && (SANITIZER_MIPS64 || SANITIZER_SPARC64) 3968d75effSDimitry Andric # include <asm/unistd.h> 4068d75effSDimitry Andric # include <sys/types.h> 4168d75effSDimitry Andric # define stat kernel_stat 4262987288SDimitry Andric # if SANITIZER_SPARC64 4362987288SDimitry Andric # define stat64 kernel_stat64 4462987288SDimitry Andric # endif 45e8d8bef9SDimitry Andric # if SANITIZER_GO 46e8d8bef9SDimitry Andric # undef st_atime 47e8d8bef9SDimitry Andric # undef st_mtime 48e8d8bef9SDimitry Andric # undef st_ctime 49e8d8bef9SDimitry Andric # define st_atime st_atim 50e8d8bef9SDimitry Andric # define st_mtime st_mtim 51e8d8bef9SDimitry Andric # define st_ctime st_ctim 52e8d8bef9SDimitry Andric # endif 5368d75effSDimitry Andric # include <asm/stat.h> 5468d75effSDimitry Andric # undef stat 5562987288SDimitry Andric # undef stat64 5668d75effSDimitry Andric # endif 5768d75effSDimitry Andric 5868d75effSDimitry Andric # include <dlfcn.h> 5968d75effSDimitry Andric # include <errno.h> 6068d75effSDimitry Andric # include <fcntl.h> 6168d75effSDimitry Andric # include <link.h> 6268d75effSDimitry Andric # include <pthread.h> 6368d75effSDimitry Andric # include <sched.h> 6468d75effSDimitry Andric # include <signal.h> 6568d75effSDimitry Andric # include <sys/mman.h> 6668d75effSDimitry Andric # if !SANITIZER_SOLARIS 6768d75effSDimitry Andric # include <sys/ptrace.h> 6868d75effSDimitry Andric # endif 6968d75effSDimitry Andric # include <sys/resource.h> 7068d75effSDimitry Andric # include <sys/stat.h> 7168d75effSDimitry Andric # include <sys/syscall.h> 7268d75effSDimitry Andric # include <sys/time.h> 7368d75effSDimitry Andric # include <sys/types.h> 7468d75effSDimitry Andric # include <ucontext.h> 7568d75effSDimitry Andric # include <unistd.h> 7668d75effSDimitry Andric 7768d75effSDimitry Andric # if SANITIZER_LINUX 7868d75effSDimitry Andric # include <sys/utsname.h> 7968d75effSDimitry Andric # endif 8068d75effSDimitry Andric 8168d75effSDimitry Andric # if SANITIZER_LINUX && !SANITIZER_ANDROID 8268d75effSDimitry Andric # include <sys/personality.h> 8368d75effSDimitry Andric # endif 8468d75effSDimitry Andric 85fcaf7f86SDimitry Andric # if SANITIZER_LINUX && defined(__loongarch__) 86fcaf7f86SDimitry Andric # include <sys/sysmacros.h> 87fcaf7f86SDimitry Andric # endif 88fcaf7f86SDimitry Andric 8968d75effSDimitry Andric # if SANITIZER_FREEBSD 905f757f3fSDimitry Andric # include <machine/atomic.h> 9168d75effSDimitry Andric # include <sys/exec.h> 927cafe89fSEd Maste # include <sys/procctl.h> 9368d75effSDimitry Andric # include <sys/sysctl.h> 9468d75effSDimitry Andric extern "C" { 9568d75effSDimitry Andric // <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on 9668d75effSDimitry Andric // FreeBSD 9.2 and 10.0. 9768d75effSDimitry Andric # include <sys/umtx.h> 9868d75effSDimitry Andric } 9968d75effSDimitry Andric # include <sys/thr.h> 10068d75effSDimitry Andric # endif // SANITIZER_FREEBSD 10168d75effSDimitry Andric 10268d75effSDimitry Andric # if SANITIZER_NETBSD 10368d75effSDimitry Andric # include <limits.h> // For NAME_MAX 10468d75effSDimitry Andric # include <sys/exec.h> 1055f757f3fSDimitry Andric # include <sys/sysctl.h> 10668d75effSDimitry Andric extern struct ps_strings *__ps_strings; 10768d75effSDimitry Andric # endif // SANITIZER_NETBSD 10868d75effSDimitry Andric 10968d75effSDimitry Andric # if SANITIZER_SOLARIS 11068d75effSDimitry Andric # include <stdlib.h> 11168d75effSDimitry Andric # include <thread.h> 11268d75effSDimitry Andric # define environ _environ 11368d75effSDimitry Andric # endif 11468d75effSDimitry Andric 11568d75effSDimitry Andric extern char **environ; 11668d75effSDimitry Andric 11768d75effSDimitry Andric # if SANITIZER_LINUX 11868d75effSDimitry Andric // <linux/time.h> 11968d75effSDimitry Andric struct kernel_timeval { 12068d75effSDimitry Andric long tv_sec; 12168d75effSDimitry Andric long tv_usec; 12268d75effSDimitry Andric }; 12368d75effSDimitry Andric 12468d75effSDimitry Andric // <linux/futex.h> is broken on some linux distributions. 12568d75effSDimitry Andric const int FUTEX_WAIT = 0; 12668d75effSDimitry Andric const int FUTEX_WAKE = 1; 12768d75effSDimitry Andric const int FUTEX_PRIVATE_FLAG = 128; 12868d75effSDimitry Andric const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; 12968d75effSDimitry Andric const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; 13068d75effSDimitry Andric # endif // SANITIZER_LINUX 13168d75effSDimitry Andric 13268d75effSDimitry Andric // Are we using 32-bit or 64-bit Linux syscalls? 13368d75effSDimitry Andric // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 13468d75effSDimitry Andric // but it still needs to use 64-bit syscalls. 13568d75effSDimitry Andric # if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ 136753f127fSDimitry Andric SANITIZER_WORDSIZE == 64 || \ 137753f127fSDimitry Andric (defined(__mips__) && _MIPS_SIM == _ABIN32)) 13868d75effSDimitry Andric # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 13968d75effSDimitry Andric # else 14068d75effSDimitry Andric # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 14168d75effSDimitry Andric # endif 14268d75effSDimitry Andric 143647cbc5dSDimitry Andric // Note : FreeBSD implemented both Linux and OpenBSD apis. 14468d75effSDimitry Andric # if SANITIZER_LINUX && defined(__NR_getrandom) 14568d75effSDimitry Andric # if !defined(GRND_NONBLOCK) 14668d75effSDimitry Andric # define GRND_NONBLOCK 1 14768d75effSDimitry Andric # endif 14868d75effSDimitry Andric # define SANITIZER_USE_GETRANDOM 1 14968d75effSDimitry Andric # else 15068d75effSDimitry Andric # define SANITIZER_USE_GETRANDOM 0 15168d75effSDimitry Andric # endif // SANITIZER_LINUX && defined(__NR_getrandom) 15268d75effSDimitry Andric 153647cbc5dSDimitry Andric # if SANITIZER_FREEBSD 15468d75effSDimitry Andric # define SANITIZER_USE_GETENTROPY 1 15568d75effSDimitry Andric # endif 15668d75effSDimitry Andric 15768d75effSDimitry Andric namespace __sanitizer { 15868d75effSDimitry Andric 15906c3fb27SDimitry Andric void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { 16006c3fb27SDimitry Andric CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset)); 161349cc55cSDimitry Andric } 162349cc55cSDimitry Andric 163*415efcecSDimitry Andric # if SANITIZER_LINUX 164*415efcecSDimitry Andric // Deletes the specified signal from newset, if it is not present in oldset 165*415efcecSDimitry Andric // Equivalently: newset[signum] = newset[signum] & oldset[signum] 166*415efcecSDimitry Andric static void KeepUnblocked(__sanitizer_sigset_t &newset, 167*415efcecSDimitry Andric __sanitizer_sigset_t &oldset, int signum) { 168*415efcecSDimitry Andric // FIXME: https://github.com/google/sanitizers/issues/1816 169*415efcecSDimitry Andric if (SANITIZER_ANDROID || !internal_sigismember(&oldset, signum)) 170*415efcecSDimitry Andric internal_sigdelset(&newset, signum); 171*415efcecSDimitry Andric } 172*415efcecSDimitry Andric # endif 173*415efcecSDimitry Andric 1740fca6ea1SDimitry Andric // Block asynchronous signals 17506c3fb27SDimitry Andric void BlockSignals(__sanitizer_sigset_t *oldset) { 176*415efcecSDimitry Andric __sanitizer_sigset_t newset; 177*415efcecSDimitry Andric internal_sigfillset(&newset); 178*415efcecSDimitry Andric 179*415efcecSDimitry Andric # if SANITIZER_LINUX 180*415efcecSDimitry Andric __sanitizer_sigset_t currentset; 181*415efcecSDimitry Andric 182*415efcecSDimitry Andric # if !SANITIZER_ANDROID 183*415efcecSDimitry Andric // FIXME: https://github.com/google/sanitizers/issues/1816 184*415efcecSDimitry Andric SetSigProcMask(NULL, ¤tset); 185*415efcecSDimitry Andric 186349cc55cSDimitry Andric // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked 187349cc55cSDimitry Andric // on any thread, setuid call hangs. 188349cc55cSDimitry Andric // See test/sanitizer_common/TestCases/Linux/setuid.c. 189*415efcecSDimitry Andric KeepUnblocked(newset, currentset, 33); 190*415efcecSDimitry Andric # endif // !SANITIZER_ANDROID 191*415efcecSDimitry Andric 1920eae32dcSDimitry Andric // Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls. 1930eae32dcSDimitry Andric // If this signal is blocked, such calls cannot be handled and the process may 1940eae32dcSDimitry Andric // hang. 195*415efcecSDimitry Andric KeepUnblocked(newset, currentset, 31); 1960fca6ea1SDimitry Andric 197*415efcecSDimitry Andric # if !SANITIZER_ANDROID 1980fca6ea1SDimitry Andric // Don't block synchronous signals 199*415efcecSDimitry Andric // but also don't unblock signals that the user had deliberately blocked. 200*415efcecSDimitry Andric // FIXME: https://github.com/google/sanitizers/issues/1816 201*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGSEGV); 202*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGBUS); 203*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGILL); 204*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGTRAP); 205*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGABRT); 206*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGFPE); 207*415efcecSDimitry Andric KeepUnblocked(newset, currentset, SIGPIPE); 208*415efcecSDimitry Andric # endif //! SANITIZER_ANDROID 2090fca6ea1SDimitry Andric 210*415efcecSDimitry Andric # endif // SANITIZER_LINUX 211*415efcecSDimitry Andric 212*415efcecSDimitry Andric SetSigProcMask(&newset, oldset); 21306c3fb27SDimitry Andric } 21406c3fb27SDimitry Andric 21506c3fb27SDimitry Andric ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) { 21606c3fb27SDimitry Andric BlockSignals(&saved_); 217349cc55cSDimitry Andric if (copy) 218349cc55cSDimitry Andric internal_memcpy(copy, &saved_, sizeof(saved_)); 219349cc55cSDimitry Andric } 220349cc55cSDimitry Andric 221349cc55cSDimitry Andric ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); } 222349cc55cSDimitry Andric 22368d75effSDimitry Andric # if SANITIZER_LINUX && defined(__x86_64__) 22468d75effSDimitry Andric # include "sanitizer_syscall_linux_x86_64.inc" 225e8d8bef9SDimitry Andric # elif SANITIZER_LINUX && SANITIZER_RISCV64 226e8d8bef9SDimitry Andric # include "sanitizer_syscall_linux_riscv64.inc" 22768d75effSDimitry Andric # elif SANITIZER_LINUX && defined(__aarch64__) 22868d75effSDimitry Andric # include "sanitizer_syscall_linux_aarch64.inc" 22968d75effSDimitry Andric # elif SANITIZER_LINUX && defined(__arm__) 23068d75effSDimitry Andric # include "sanitizer_syscall_linux_arm.inc" 231349cc55cSDimitry Andric # elif SANITIZER_LINUX && defined(__hexagon__) 232349cc55cSDimitry Andric # include "sanitizer_syscall_linux_hexagon.inc" 233fcaf7f86SDimitry Andric # elif SANITIZER_LINUX && SANITIZER_LOONGARCH64 234fcaf7f86SDimitry Andric # include "sanitizer_syscall_linux_loongarch64.inc" 23568d75effSDimitry Andric # else 23668d75effSDimitry Andric # include "sanitizer_syscall_generic.inc" 23768d75effSDimitry Andric # endif 23868d75effSDimitry Andric 23968d75effSDimitry Andric // --------------- sanitizer_libc.h 24068d75effSDimitry Andric # if !SANITIZER_SOLARIS && !SANITIZER_NETBSD 241e8d8bef9SDimitry Andric # if !SANITIZER_S390 24268d75effSDimitry Andric uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, 243480093f4SDimitry Andric u64 offset) { 24468d75effSDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS 24568d75effSDimitry Andric return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, 24668d75effSDimitry Andric offset); 24768d75effSDimitry Andric # else 24868d75effSDimitry Andric // mmap2 specifies file offset in 4096-byte units. 24968d75effSDimitry Andric CHECK(IsAligned(offset, 4096)); 25068d75effSDimitry Andric return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, 25152418fc2SDimitry Andric (OFF_T)(offset / 4096)); 25268d75effSDimitry Andric # endif 25368d75effSDimitry Andric } 254e8d8bef9SDimitry Andric # endif // !SANITIZER_S390 25568d75effSDimitry Andric 25668d75effSDimitry Andric uptr internal_munmap(void *addr, uptr length) { 25768d75effSDimitry Andric return internal_syscall(SYSCALL(munmap), (uptr)addr, length); 25868d75effSDimitry Andric } 25968d75effSDimitry Andric 260fe6060f1SDimitry Andric # if SANITIZER_LINUX 261fe6060f1SDimitry Andric uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags, 262fe6060f1SDimitry Andric void *new_address) { 263fe6060f1SDimitry Andric return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size, 264fe6060f1SDimitry Andric new_size, flags, (uptr)new_address); 265fe6060f1SDimitry Andric } 266fe6060f1SDimitry Andric # endif 267fe6060f1SDimitry Andric 26868d75effSDimitry Andric int internal_mprotect(void *addr, uptr length, int prot) { 26968d75effSDimitry Andric return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); 27068d75effSDimitry Andric } 271e8d8bef9SDimitry Andric 272e8d8bef9SDimitry Andric int internal_madvise(uptr addr, uptr length, int advice) { 273e8d8bef9SDimitry Andric return internal_syscall(SYSCALL(madvise), addr, length, advice); 274e8d8bef9SDimitry Andric } 27568d75effSDimitry Andric 2765f757f3fSDimitry Andric uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); } 27768d75effSDimitry Andric 27868d75effSDimitry Andric uptr internal_open(const char *filename, int flags) { 27981ad6265SDimitry Andric # if SANITIZER_LINUX 28068d75effSDimitry Andric return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); 28168d75effSDimitry Andric # else 28268d75effSDimitry Andric return internal_syscall(SYSCALL(open), (uptr)filename, flags); 28368d75effSDimitry Andric # endif 28468d75effSDimitry Andric } 28568d75effSDimitry Andric 28668d75effSDimitry Andric uptr internal_open(const char *filename, int flags, u32 mode) { 28781ad6265SDimitry Andric # if SANITIZER_LINUX 28868d75effSDimitry Andric return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, 28968d75effSDimitry Andric mode); 29068d75effSDimitry Andric # else 29168d75effSDimitry Andric return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); 29268d75effSDimitry Andric # endif 29368d75effSDimitry Andric } 29468d75effSDimitry Andric 29568d75effSDimitry Andric uptr internal_read(fd_t fd, void *buf, uptr count) { 29668d75effSDimitry Andric sptr res; 29768d75effSDimitry Andric HANDLE_EINTR(res, 29868d75effSDimitry Andric (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); 29968d75effSDimitry Andric return res; 30068d75effSDimitry Andric } 30168d75effSDimitry Andric 30268d75effSDimitry Andric uptr internal_write(fd_t fd, const void *buf, uptr count) { 30368d75effSDimitry Andric sptr res; 30468d75effSDimitry Andric HANDLE_EINTR(res, 30568d75effSDimitry Andric (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); 30668d75effSDimitry Andric return res; 30768d75effSDimitry Andric } 30868d75effSDimitry Andric 30968d75effSDimitry Andric uptr internal_ftruncate(fd_t fd, uptr size) { 31068d75effSDimitry Andric sptr res; 3115f757f3fSDimitry Andric HANDLE_EINTR(res, 3125f757f3fSDimitry Andric (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size)); 31368d75effSDimitry Andric return res; 31468d75effSDimitry Andric } 31568d75effSDimitry Andric 31662987288SDimitry Andric # if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX 31768d75effSDimitry Andric static void stat64_to_stat(struct stat64 *in, struct stat *out) { 31868d75effSDimitry Andric internal_memset(out, 0, sizeof(*out)); 31968d75effSDimitry Andric out->st_dev = in->st_dev; 32068d75effSDimitry Andric out->st_ino = in->st_ino; 32168d75effSDimitry Andric out->st_mode = in->st_mode; 32268d75effSDimitry Andric out->st_nlink = in->st_nlink; 32368d75effSDimitry Andric out->st_uid = in->st_uid; 32468d75effSDimitry Andric out->st_gid = in->st_gid; 32568d75effSDimitry Andric out->st_rdev = in->st_rdev; 32668d75effSDimitry Andric out->st_size = in->st_size; 32768d75effSDimitry Andric out->st_blksize = in->st_blksize; 32868d75effSDimitry Andric out->st_blocks = in->st_blocks; 32968d75effSDimitry Andric out->st_atime = in->st_atime; 33068d75effSDimitry Andric out->st_mtime = in->st_mtime; 33168d75effSDimitry Andric out->st_ctime = in->st_ctime; 33268d75effSDimitry Andric } 33368d75effSDimitry Andric # endif 33468d75effSDimitry Andric 335fcaf7f86SDimitry Andric # if SANITIZER_LINUX && defined(__loongarch__) 336fcaf7f86SDimitry Andric static void statx_to_stat(struct statx *in, struct stat *out) { 337fcaf7f86SDimitry Andric internal_memset(out, 0, sizeof(*out)); 338fcaf7f86SDimitry Andric out->st_dev = makedev(in->stx_dev_major, in->stx_dev_minor); 339fcaf7f86SDimitry Andric out->st_ino = in->stx_ino; 340fcaf7f86SDimitry Andric out->st_mode = in->stx_mode; 341fcaf7f86SDimitry Andric out->st_nlink = in->stx_nlink; 342fcaf7f86SDimitry Andric out->st_uid = in->stx_uid; 343fcaf7f86SDimitry Andric out->st_gid = in->stx_gid; 344fcaf7f86SDimitry Andric out->st_rdev = makedev(in->stx_rdev_major, in->stx_rdev_minor); 345fcaf7f86SDimitry Andric out->st_size = in->stx_size; 346fcaf7f86SDimitry Andric out->st_blksize = in->stx_blksize; 347fcaf7f86SDimitry Andric out->st_blocks = in->stx_blocks; 348fcaf7f86SDimitry Andric out->st_atime = in->stx_atime.tv_sec; 349fcaf7f86SDimitry Andric out->st_atim.tv_nsec = in->stx_atime.tv_nsec; 350fcaf7f86SDimitry Andric out->st_mtime = in->stx_mtime.tv_sec; 351fcaf7f86SDimitry Andric out->st_mtim.tv_nsec = in->stx_mtime.tv_nsec; 352fcaf7f86SDimitry Andric out->st_ctime = in->stx_ctime.tv_sec; 353fcaf7f86SDimitry Andric out->st_ctim.tv_nsec = in->stx_ctime.tv_nsec; 354fcaf7f86SDimitry Andric } 355fcaf7f86SDimitry Andric # endif 356fcaf7f86SDimitry Andric 35762987288SDimitry Andric # if SANITIZER_MIPS64 || SANITIZER_SPARC64 358753f127fSDimitry Andric # if SANITIZER_MIPS64 35962987288SDimitry Andric typedef struct kernel_stat kstat_t; 36062987288SDimitry Andric # else 36162987288SDimitry Andric typedef struct kernel_stat64 kstat_t; 36262987288SDimitry Andric # endif 36368d75effSDimitry Andric // Undefine compatibility macros from <sys/stat.h> 36468d75effSDimitry Andric // so that they would not clash with the kernel_stat 36568d75effSDimitry Andric // st_[a|m|c]time fields 366e8d8bef9SDimitry Andric # if !SANITIZER_GO 36768d75effSDimitry Andric # undef st_atime 36868d75effSDimitry Andric # undef st_mtime 36968d75effSDimitry Andric # undef st_ctime 370e8d8bef9SDimitry Andric # endif 37168d75effSDimitry Andric # if defined(SANITIZER_ANDROID) 37268d75effSDimitry Andric // Bionic sys/stat.h defines additional macros 37368d75effSDimitry Andric // for compatibility with the old NDKs and 37468d75effSDimitry Andric // they clash with the kernel_stat structure 37568d75effSDimitry Andric // st_[a|m|c]time_nsec fields. 37668d75effSDimitry Andric # undef st_atime_nsec 37768d75effSDimitry Andric # undef st_mtime_nsec 37868d75effSDimitry Andric # undef st_ctime_nsec 37968d75effSDimitry Andric # endif 38062987288SDimitry Andric static void kernel_stat_to_stat(kstat_t *in, struct stat *out) { 38168d75effSDimitry Andric internal_memset(out, 0, sizeof(*out)); 38268d75effSDimitry Andric out->st_dev = in->st_dev; 38368d75effSDimitry Andric out->st_ino = in->st_ino; 38468d75effSDimitry Andric out->st_mode = in->st_mode; 38568d75effSDimitry Andric out->st_nlink = in->st_nlink; 38668d75effSDimitry Andric out->st_uid = in->st_uid; 38768d75effSDimitry Andric out->st_gid = in->st_gid; 38868d75effSDimitry Andric out->st_rdev = in->st_rdev; 38968d75effSDimitry Andric out->st_size = in->st_size; 39068d75effSDimitry Andric out->st_blksize = in->st_blksize; 39168d75effSDimitry Andric out->st_blocks = in->st_blocks; 3925f757f3fSDimitry Andric # if defined(__USE_MISC) || defined(__USE_XOPEN2K8) || \ 39368d75effSDimitry Andric defined(SANITIZER_ANDROID) 39468d75effSDimitry Andric out->st_atim.tv_sec = in->st_atime; 39568d75effSDimitry Andric out->st_atim.tv_nsec = in->st_atime_nsec; 39668d75effSDimitry Andric out->st_mtim.tv_sec = in->st_mtime; 39768d75effSDimitry Andric out->st_mtim.tv_nsec = in->st_mtime_nsec; 39868d75effSDimitry Andric out->st_ctim.tv_sec = in->st_ctime; 39968d75effSDimitry Andric out->st_ctim.tv_nsec = in->st_ctime_nsec; 40068d75effSDimitry Andric # else 40168d75effSDimitry Andric out->st_atime = in->st_atime; 40268d75effSDimitry Andric out->st_atimensec = in->st_atime_nsec; 40368d75effSDimitry Andric out->st_mtime = in->st_mtime; 40468d75effSDimitry Andric out->st_mtimensec = in->st_mtime_nsec; 40568d75effSDimitry Andric out->st_ctime = in->st_ctime; 40668d75effSDimitry Andric out->st_atimensec = in->st_ctime_nsec; 40768d75effSDimitry Andric # endif 40868d75effSDimitry Andric } 40968d75effSDimitry Andric # endif 41068d75effSDimitry Andric 41168d75effSDimitry Andric uptr internal_stat(const char *path, void *buf) { 412e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD 41368d75effSDimitry Andric return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); 41481ad6265SDimitry Andric # elif SANITIZER_LINUX 415fcaf7f86SDimitry Andric # if defined(__loongarch__) 416fcaf7f86SDimitry Andric struct statx bufx; 417fcaf7f86SDimitry Andric int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path, 418fcaf7f86SDimitry Andric AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx); 419fcaf7f86SDimitry Andric statx_to_stat(&bufx, (struct stat *)buf); 420fcaf7f86SDimitry Andric return res; 421fcaf7f86SDimitry Andric # elif (SANITIZER_WORDSIZE == 64 || SANITIZER_X32 || \ 422753f127fSDimitry Andric (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \ 423753f127fSDimitry Andric !SANITIZER_SPARC 42468d75effSDimitry Andric return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 42568d75effSDimitry Andric 0); 42662987288SDimitry Andric # elif SANITIZER_SPARC64 42762987288SDimitry Andric kstat_t buf64; 42862987288SDimitry Andric int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, 42962987288SDimitry Andric (uptr)&buf64, 0); 43062987288SDimitry Andric kernel_stat_to_stat(&buf64, (struct stat *)buf); 43162987288SDimitry Andric return res; 43268d75effSDimitry Andric # else 43381ad6265SDimitry Andric struct stat64 buf64; 43481ad6265SDimitry Andric int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, 43581ad6265SDimitry Andric (uptr)&buf64, 0); 43681ad6265SDimitry Andric stat64_to_stat(&buf64, (struct stat *)buf); 43781ad6265SDimitry Andric return res; 43868d75effSDimitry Andric # endif 43968d75effSDimitry Andric # else 44068d75effSDimitry Andric struct stat64 buf64; 44168d75effSDimitry Andric int res = internal_syscall(SYSCALL(stat64), path, &buf64); 44268d75effSDimitry Andric stat64_to_stat(&buf64, (struct stat *)buf); 44368d75effSDimitry Andric return res; 44468d75effSDimitry Andric # endif 44568d75effSDimitry Andric } 44668d75effSDimitry Andric 44768d75effSDimitry Andric uptr internal_lstat(const char *path, void *buf) { 448e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD 44968d75effSDimitry Andric return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 45068d75effSDimitry Andric AT_SYMLINK_NOFOLLOW); 45181ad6265SDimitry Andric # elif SANITIZER_LINUX 452fcaf7f86SDimitry Andric # if defined(__loongarch__) 453fcaf7f86SDimitry Andric struct statx bufx; 454fcaf7f86SDimitry Andric int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path, 455fcaf7f86SDimitry Andric AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, 456fcaf7f86SDimitry Andric STATX_BASIC_STATS, (uptr)&bufx); 457fcaf7f86SDimitry Andric statx_to_stat(&bufx, (struct stat *)buf); 458fcaf7f86SDimitry Andric return res; 459fcaf7f86SDimitry Andric # elif (defined(_LP64) || SANITIZER_X32 || \ 460753f127fSDimitry Andric (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \ 461753f127fSDimitry Andric !SANITIZER_SPARC 46268d75effSDimitry Andric return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 46368d75effSDimitry Andric AT_SYMLINK_NOFOLLOW); 46462987288SDimitry Andric # elif SANITIZER_SPARC64 46562987288SDimitry Andric kstat_t buf64; 46662987288SDimitry Andric int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, 46762987288SDimitry Andric (uptr)&buf64, AT_SYMLINK_NOFOLLOW); 46862987288SDimitry Andric kernel_stat_to_stat(&buf64, (struct stat *)buf); 46962987288SDimitry Andric return res; 47068d75effSDimitry Andric # else 47181ad6265SDimitry Andric struct stat64 buf64; 47281ad6265SDimitry Andric int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, 47381ad6265SDimitry Andric (uptr)&buf64, AT_SYMLINK_NOFOLLOW); 47481ad6265SDimitry Andric stat64_to_stat(&buf64, (struct stat *)buf); 47581ad6265SDimitry Andric return res; 47668d75effSDimitry Andric # endif 47768d75effSDimitry Andric # else 47868d75effSDimitry Andric struct stat64 buf64; 47968d75effSDimitry Andric int res = internal_syscall(SYSCALL(lstat64), path, &buf64); 48068d75effSDimitry Andric stat64_to_stat(&buf64, (struct stat *)buf); 48168d75effSDimitry Andric return res; 48268d75effSDimitry Andric # endif 48368d75effSDimitry Andric } 48468d75effSDimitry Andric 48568d75effSDimitry Andric uptr internal_fstat(fd_t fd, void *buf) { 486e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS 487e8d8bef9SDimitry Andric # if SANITIZER_MIPS64 48868d75effSDimitry Andric // For mips64, fstat syscall fills buffer in the format of kernel_stat 48962987288SDimitry Andric kstat_t kbuf; 49068d75effSDimitry Andric int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); 49168d75effSDimitry Andric kernel_stat_to_stat(&kbuf, (struct stat *)buf); 49268d75effSDimitry Andric return res; 49362987288SDimitry Andric # elif SANITIZER_LINUX && SANITIZER_SPARC64 49462987288SDimitry Andric // For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64 49562987288SDimitry Andric kstat_t kbuf; 49662987288SDimitry Andric int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf); 49762987288SDimitry Andric kernel_stat_to_stat(&kbuf, (struct stat *)buf); 49862987288SDimitry Andric return res; 499fcaf7f86SDimitry Andric # elif SANITIZER_LINUX && defined(__loongarch__) 500fcaf7f86SDimitry Andric struct statx bufx; 501bdd1243dSDimitry Andric int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH, 502fcaf7f86SDimitry Andric STATX_BASIC_STATS, (uptr)&bufx); 503fcaf7f86SDimitry Andric statx_to_stat(&bufx, (struct stat *)buf); 504fcaf7f86SDimitry Andric return res; 50568d75effSDimitry Andric # else 50668d75effSDimitry Andric return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); 50768d75effSDimitry Andric # endif 50868d75effSDimitry Andric # else 50968d75effSDimitry Andric struct stat64 buf64; 51068d75effSDimitry Andric int res = internal_syscall(SYSCALL(fstat64), fd, &buf64); 51168d75effSDimitry Andric stat64_to_stat(&buf64, (struct stat *)buf); 51268d75effSDimitry Andric return res; 51368d75effSDimitry Andric # endif 51468d75effSDimitry Andric } 51568d75effSDimitry Andric 51668d75effSDimitry Andric uptr internal_filesize(fd_t fd) { 51768d75effSDimitry Andric struct stat st; 51868d75effSDimitry Andric if (internal_fstat(fd, &st)) 51968d75effSDimitry Andric return -1; 52068d75effSDimitry Andric return (uptr)st.st_size; 52168d75effSDimitry Andric } 52268d75effSDimitry Andric 5235f757f3fSDimitry Andric uptr internal_dup(int oldfd) { return internal_syscall(SYSCALL(dup), oldfd); } 52468d75effSDimitry Andric 52568d75effSDimitry Andric uptr internal_dup2(int oldfd, int newfd) { 52681ad6265SDimitry Andric # if SANITIZER_LINUX 52768d75effSDimitry Andric return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); 52868d75effSDimitry Andric # else 52968d75effSDimitry Andric return internal_syscall(SYSCALL(dup2), oldfd, newfd); 53068d75effSDimitry Andric # endif 53168d75effSDimitry Andric } 53268d75effSDimitry Andric 53368d75effSDimitry Andric uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 53481ad6265SDimitry Andric # if SANITIZER_LINUX 53568d75effSDimitry Andric return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, 53668d75effSDimitry Andric bufsize); 53768d75effSDimitry Andric # else 53868d75effSDimitry Andric return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); 53968d75effSDimitry Andric # endif 54068d75effSDimitry Andric } 54168d75effSDimitry Andric 54268d75effSDimitry Andric uptr internal_unlink(const char *path) { 54381ad6265SDimitry Andric # if SANITIZER_LINUX 54468d75effSDimitry Andric return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); 54568d75effSDimitry Andric # else 54668d75effSDimitry Andric return internal_syscall(SYSCALL(unlink), (uptr)path); 54768d75effSDimitry Andric # endif 54868d75effSDimitry Andric } 54968d75effSDimitry Andric 55068d75effSDimitry Andric uptr internal_rename(const char *oldpath, const char *newpath) { 551fcaf7f86SDimitry Andric # if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__) 552480093f4SDimitry Andric return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD, 553480093f4SDimitry Andric (uptr)newpath, 0); 55481ad6265SDimitry Andric # elif SANITIZER_LINUX 55568d75effSDimitry Andric return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, 55668d75effSDimitry Andric (uptr)newpath); 55768d75effSDimitry Andric # else 55868d75effSDimitry Andric return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); 55968d75effSDimitry Andric # endif 56068d75effSDimitry Andric } 56168d75effSDimitry Andric 5625f757f3fSDimitry Andric uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); } 56368d75effSDimitry Andric 564fe6060f1SDimitry Andric void internal_usleep(u64 useconds) { 56568d75effSDimitry Andric struct timespec ts; 566fe6060f1SDimitry Andric ts.tv_sec = useconds / 1000000; 567fe6060f1SDimitry Andric ts.tv_nsec = (useconds % 1000000) * 1000; 568fe6060f1SDimitry Andric internal_syscall(SYSCALL(nanosleep), &ts, &ts); 56968d75effSDimitry Andric } 57068d75effSDimitry Andric 57168d75effSDimitry Andric uptr internal_execve(const char *filename, char *const argv[], 57268d75effSDimitry Andric char *const envp[]) { 57368d75effSDimitry Andric return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, 57468d75effSDimitry Andric (uptr)envp); 57568d75effSDimitry Andric } 57668d75effSDimitry Andric # endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD 57768d75effSDimitry Andric 578e8d8bef9SDimitry Andric # if !SANITIZER_NETBSD 579e8d8bef9SDimitry Andric void internal__exit(int exitcode) { 580e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_SOLARIS 581e8d8bef9SDimitry Andric internal_syscall(SYSCALL(exit), exitcode); 582e8d8bef9SDimitry Andric # else 583e8d8bef9SDimitry Andric internal_syscall(SYSCALL(exit_group), exitcode); 584e8d8bef9SDimitry Andric # endif 585e8d8bef9SDimitry Andric Die(); // Unreachable. 586e8d8bef9SDimitry Andric } 587e8d8bef9SDimitry Andric # endif // !SANITIZER_NETBSD 588e8d8bef9SDimitry Andric 58968d75effSDimitry Andric // ----------------- sanitizer_common.h 59068d75effSDimitry Andric bool FileExists(const char *filename) { 59168d75effSDimitry Andric if (ShouldMockFailureToOpen(filename)) 59268d75effSDimitry Andric return false; 59368d75effSDimitry Andric struct stat st; 59468d75effSDimitry Andric if (internal_stat(filename, &st)) 59568d75effSDimitry Andric return false; 59668d75effSDimitry Andric // Sanity check: filename is a regular file. 59768d75effSDimitry Andric return S_ISREG(st.st_mode); 59868d75effSDimitry Andric } 59968d75effSDimitry Andric 60081ad6265SDimitry Andric bool DirExists(const char *path) { 60181ad6265SDimitry Andric struct stat st; 60281ad6265SDimitry Andric if (internal_stat(path, &st)) 60381ad6265SDimitry Andric return false; 60481ad6265SDimitry Andric return S_ISDIR(st.st_mode); 60581ad6265SDimitry Andric } 60681ad6265SDimitry Andric 60768d75effSDimitry Andric # if !SANITIZER_NETBSD 60868d75effSDimitry Andric tid_t GetTid() { 60968d75effSDimitry Andric # if SANITIZER_FREEBSD 61068d75effSDimitry Andric long Tid; 61168d75effSDimitry Andric thr_self(&Tid); 61268d75effSDimitry Andric return Tid; 61368d75effSDimitry Andric # elif SANITIZER_SOLARIS 61468d75effSDimitry Andric return thr_self(); 61568d75effSDimitry Andric # else 61668d75effSDimitry Andric return internal_syscall(SYSCALL(gettid)); 61768d75effSDimitry Andric # endif 61868d75effSDimitry Andric } 61968d75effSDimitry Andric 62068d75effSDimitry Andric int TgKill(pid_t pid, tid_t tid, int sig) { 62168d75effSDimitry Andric # if SANITIZER_LINUX 62268d75effSDimitry Andric return internal_syscall(SYSCALL(tgkill), pid, tid, sig); 62368d75effSDimitry Andric # elif SANITIZER_FREEBSD 62468d75effSDimitry Andric return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); 62568d75effSDimitry Andric # elif SANITIZER_SOLARIS 62668d75effSDimitry Andric (void)pid; 6270fca6ea1SDimitry Andric errno = thr_kill(tid, sig); 6280fca6ea1SDimitry Andric // TgKill is expected to return -1 on error, not an errno. 6290fca6ea1SDimitry Andric return errno != 0 ? -1 : 0; 63068d75effSDimitry Andric # endif 63168d75effSDimitry Andric } 63268d75effSDimitry Andric # endif 63368d75effSDimitry Andric 634fe6060f1SDimitry Andric # if SANITIZER_GLIBC 63568d75effSDimitry Andric u64 NanoTime() { 63668d75effSDimitry Andric kernel_timeval tv; 63768d75effSDimitry Andric internal_memset(&tv, 0, sizeof(tv)); 63868d75effSDimitry Andric internal_syscall(SYSCALL(gettimeofday), &tv, 0); 63968d75effSDimitry Andric return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000; 64068d75effSDimitry Andric } 641fe6060f1SDimitry Andric // Used by real_clock_gettime. 64268d75effSDimitry Andric uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { 64368d75effSDimitry Andric return internal_syscall(SYSCALL(clock_gettime), clk_id, tp); 64468d75effSDimitry Andric } 645fe6060f1SDimitry Andric # elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD 646fe6060f1SDimitry Andric u64 NanoTime() { 647fe6060f1SDimitry Andric struct timespec ts; 648fe6060f1SDimitry Andric clock_gettime(CLOCK_REALTIME, &ts); 649fe6060f1SDimitry Andric return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 650fe6060f1SDimitry Andric } 651fe6060f1SDimitry Andric # endif 65268d75effSDimitry Andric 65368d75effSDimitry Andric // Like getenv, but reads env directly from /proc (on Linux) or parses the 65468d75effSDimitry Andric // 'environ' array (on some others) and does not use libc. This function 65568d75effSDimitry Andric // should be called first inside __asan_init. 65668d75effSDimitry Andric const char *GetEnv(const char *name) { 657e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS 65868d75effSDimitry Andric if (::environ != 0) { 65968d75effSDimitry Andric uptr NameLen = internal_strlen(name); 66068d75effSDimitry Andric for (char **Env = ::environ; *Env != 0; Env++) { 66168d75effSDimitry Andric if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') 66268d75effSDimitry Andric return (*Env) + NameLen + 1; 66368d75effSDimitry Andric } 66468d75effSDimitry Andric } 66568d75effSDimitry Andric return 0; // Not found. 66668d75effSDimitry Andric # elif SANITIZER_LINUX 66768d75effSDimitry Andric static char *environ; 66868d75effSDimitry Andric static uptr len; 66968d75effSDimitry Andric static bool inited; 67068d75effSDimitry Andric if (!inited) { 67168d75effSDimitry Andric inited = true; 67268d75effSDimitry Andric uptr environ_size; 67368d75effSDimitry Andric if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len)) 67468d75effSDimitry Andric environ = nullptr; 67568d75effSDimitry Andric } 6765f757f3fSDimitry Andric if (!environ || len == 0) 6775f757f3fSDimitry Andric return nullptr; 67868d75effSDimitry Andric uptr namelen = internal_strlen(name); 67968d75effSDimitry Andric const char *p = environ; 68068d75effSDimitry Andric while (*p != '\0') { // will happen at the \0\0 that terminates the buffer 68168d75effSDimitry Andric // proc file has the format NAME=value\0NAME=value\0NAME=value\0... 6825f757f3fSDimitry Andric const char *endp = (char *)internal_memchr(p, '\0', len - (p - environ)); 68368d75effSDimitry Andric if (!endp) // this entry isn't NUL terminated 68468d75effSDimitry Andric return nullptr; 68568d75effSDimitry Andric else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. 68668d75effSDimitry Andric return p + namelen + 1; // point after = 68768d75effSDimitry Andric p = endp + 1; 68868d75effSDimitry Andric } 68968d75effSDimitry Andric return nullptr; // Not found. 69068d75effSDimitry Andric # else 69168d75effSDimitry Andric # error "Unsupported platform" 69268d75effSDimitry Andric # endif 69368d75effSDimitry Andric } 69468d75effSDimitry Andric 695e8d8bef9SDimitry Andric # if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO 69668d75effSDimitry Andric extern "C" { 69768d75effSDimitry Andric SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; 69868d75effSDimitry Andric } 69968d75effSDimitry Andric # endif 70068d75effSDimitry Andric 701e8d8bef9SDimitry Andric # if !SANITIZER_FREEBSD && !SANITIZER_NETBSD 70268d75effSDimitry Andric static void ReadNullSepFileToArray(const char *path, char ***arr, 70368d75effSDimitry Andric int arr_size) { 70468d75effSDimitry Andric char *buff; 70568d75effSDimitry Andric uptr buff_size; 70668d75effSDimitry Andric uptr buff_len; 70768d75effSDimitry Andric *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); 70868d75effSDimitry Andric if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) { 70968d75effSDimitry Andric (*arr)[0] = nullptr; 71068d75effSDimitry Andric return; 71168d75effSDimitry Andric } 71268d75effSDimitry Andric (*arr)[0] = buff; 71368d75effSDimitry Andric int count, i; 71468d75effSDimitry Andric for (count = 1, i = 1;; i++) { 71568d75effSDimitry Andric if (buff[i] == 0) { 7165f757f3fSDimitry Andric if (buff[i + 1] == 0) 7175f757f3fSDimitry Andric break; 71868d75effSDimitry Andric (*arr)[count] = &buff[i + 1]; 71968d75effSDimitry Andric CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible. 72068d75effSDimitry Andric count++; 72168d75effSDimitry Andric } 72268d75effSDimitry Andric } 72368d75effSDimitry Andric (*arr)[count] = nullptr; 72468d75effSDimitry Andric } 72568d75effSDimitry Andric # endif 72668d75effSDimitry Andric 72768d75effSDimitry Andric static void GetArgsAndEnv(char ***argv, char ***envp) { 72868d75effSDimitry Andric # if SANITIZER_FREEBSD 72968d75effSDimitry Andric // On FreeBSD, retrieving the argument and environment arrays is done via the 73068d75effSDimitry Andric // kern.ps_strings sysctl, which returns a pointer to a structure containing 73168d75effSDimitry Andric // this information. See also <sys/exec.h>. 73268d75effSDimitry Andric ps_strings *pss; 73368d75effSDimitry Andric uptr sz = sizeof(pss); 73468d75effSDimitry Andric if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { 73568d75effSDimitry Andric Printf("sysctl kern.ps_strings failed\n"); 73668d75effSDimitry Andric Die(); 73768d75effSDimitry Andric } 73868d75effSDimitry Andric *argv = pss->ps_argvstr; 73968d75effSDimitry Andric *envp = pss->ps_envstr; 74068d75effSDimitry Andric # elif SANITIZER_NETBSD 74168d75effSDimitry Andric *argv = __ps_strings->ps_argvstr; 74268d75effSDimitry Andric *envp = __ps_strings->ps_envstr; 74368d75effSDimitry Andric # else // SANITIZER_FREEBSD 74468d75effSDimitry Andric # if !SANITIZER_GO 74568d75effSDimitry Andric if (&__libc_stack_end) { 74668d75effSDimitry Andric uptr *stack_end = (uptr *)__libc_stack_end; 7475ffd83dbSDimitry Andric // Normally argc can be obtained from *stack_end, however, on ARM glibc's 7485ffd83dbSDimitry Andric // _start clobbers it: 7495ffd83dbSDimitry Andric // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75 7505ffd83dbSDimitry Andric // Do not special-case ARM and infer argc from argv everywhere. 7515ffd83dbSDimitry Andric int argc = 0; 7525ffd83dbSDimitry Andric while (stack_end[argc + 1]) argc++; 75368d75effSDimitry Andric *argv = (char **)(stack_end + 1); 75468d75effSDimitry Andric *envp = (char **)(stack_end + argc + 2); 75568d75effSDimitry Andric } else { 7565ffd83dbSDimitry Andric # endif // !SANITIZER_GO 75768d75effSDimitry Andric static const int kMaxArgv = 2000, kMaxEnvp = 2000; 75868d75effSDimitry Andric ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); 75968d75effSDimitry Andric ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); 7605ffd83dbSDimitry Andric # if !SANITIZER_GO 76168d75effSDimitry Andric } 76268d75effSDimitry Andric # endif // !SANITIZER_GO 76368d75effSDimitry Andric # endif // SANITIZER_FREEBSD 76468d75effSDimitry Andric } 76568d75effSDimitry Andric 76668d75effSDimitry Andric char **GetArgv() { 76768d75effSDimitry Andric char **argv, **envp; 76868d75effSDimitry Andric GetArgsAndEnv(&argv, &envp); 76968d75effSDimitry Andric return argv; 77068d75effSDimitry Andric } 77168d75effSDimitry Andric 77268d75effSDimitry Andric char **GetEnviron() { 77368d75effSDimitry Andric char **argv, **envp; 77468d75effSDimitry Andric GetArgsAndEnv(&argv, &envp); 77568d75effSDimitry Andric return envp; 77668d75effSDimitry Andric } 77768d75effSDimitry Andric 77868d75effSDimitry Andric # if !SANITIZER_SOLARIS 779fe6060f1SDimitry Andric void FutexWait(atomic_uint32_t *p, u32 cmp) { 780fe6060f1SDimitry Andric # if SANITIZER_FREEBSD 781fe6060f1SDimitry Andric _umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0); 782fe6060f1SDimitry Andric # elif SANITIZER_NETBSD 783fe6060f1SDimitry Andric sched_yield(); /* No userspace futex-like synchronization */ 784fe6060f1SDimitry Andric # else 785fe6060f1SDimitry Andric internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0); 786fe6060f1SDimitry Andric # endif 787fe6060f1SDimitry Andric } 788fe6060f1SDimitry Andric 789fe6060f1SDimitry Andric void FutexWake(atomic_uint32_t *p, u32 count) { 790fe6060f1SDimitry Andric # if SANITIZER_FREEBSD 791fe6060f1SDimitry Andric _umtx_op(p, UMTX_OP_WAKE, count, 0, 0); 792fe6060f1SDimitry Andric # elif SANITIZER_NETBSD 793fe6060f1SDimitry Andric /* No userspace futex-like synchronization */ 794fe6060f1SDimitry Andric # else 795fe6060f1SDimitry Andric internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0); 796fe6060f1SDimitry Andric # endif 797fe6060f1SDimitry Andric } 798fe6060f1SDimitry Andric 79968d75effSDimitry Andric # endif // !SANITIZER_SOLARIS 80068d75effSDimitry Andric 80168d75effSDimitry Andric // ----------------- sanitizer_linux.h 80268d75effSDimitry Andric // The actual size of this structure is specified by d_reclen. 80368d75effSDimitry Andric // Note that getdents64 uses a different structure format. We only provide the 80468d75effSDimitry Andric // 32-bit syscall here. 80568d75effSDimitry Andric # if SANITIZER_NETBSD 80668d75effSDimitry Andric // Not used 80768d75effSDimitry Andric # else 80868d75effSDimitry Andric struct linux_dirent { 80981ad6265SDimitry Andric # if SANITIZER_X32 || SANITIZER_LINUX 81068d75effSDimitry Andric u64 d_ino; 81168d75effSDimitry Andric u64 d_off; 81268d75effSDimitry Andric # else 81368d75effSDimitry Andric unsigned long d_ino; 81468d75effSDimitry Andric unsigned long d_off; 81568d75effSDimitry Andric # endif 81668d75effSDimitry Andric unsigned short d_reclen; 81781ad6265SDimitry Andric # if SANITIZER_LINUX 81868d75effSDimitry Andric unsigned char d_type; 81968d75effSDimitry Andric # endif 82068d75effSDimitry Andric char d_name[256]; 82168d75effSDimitry Andric }; 82268d75effSDimitry Andric # endif 82368d75effSDimitry Andric 82468d75effSDimitry Andric # if !SANITIZER_SOLARIS && !SANITIZER_NETBSD 82568d75effSDimitry Andric // Syscall wrappers. 82668d75effSDimitry Andric uptr internal_ptrace(int request, int pid, void *addr, void *data) { 82768d75effSDimitry Andric return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, 82868d75effSDimitry Andric (uptr)data); 82968d75effSDimitry Andric } 83068d75effSDimitry Andric 83168d75effSDimitry Andric uptr internal_waitpid(int pid, int *status, int options) { 83268d75effSDimitry Andric return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, 83368d75effSDimitry Andric 0 /* rusage */); 83468d75effSDimitry Andric } 83568d75effSDimitry Andric 8365f757f3fSDimitry Andric uptr internal_getpid() { return internal_syscall(SYSCALL(getpid)); } 83768d75effSDimitry Andric 8385f757f3fSDimitry Andric uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); } 83968d75effSDimitry Andric 8405ffd83dbSDimitry Andric int internal_dlinfo(void *handle, int request, void *p) { 8415ffd83dbSDimitry Andric # if SANITIZER_FREEBSD 8425ffd83dbSDimitry Andric return dlinfo(handle, request, p); 8435ffd83dbSDimitry Andric # else 8445ffd83dbSDimitry Andric UNIMPLEMENTED(); 8455ffd83dbSDimitry Andric # endif 8465ffd83dbSDimitry Andric } 8475ffd83dbSDimitry Andric 84868d75effSDimitry Andric uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { 84968d75effSDimitry Andric # if SANITIZER_FREEBSD 85068d75effSDimitry Andric return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); 85181ad6265SDimitry Andric # elif SANITIZER_LINUX 85268d75effSDimitry Andric return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); 85368d75effSDimitry Andric # else 85468d75effSDimitry Andric return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); 85568d75effSDimitry Andric # endif 85668d75effSDimitry Andric } 85768d75effSDimitry Andric 85868d75effSDimitry Andric uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { 85968d75effSDimitry Andric return internal_syscall(SYSCALL(lseek), fd, offset, whence); 86068d75effSDimitry Andric } 86168d75effSDimitry Andric 86268d75effSDimitry Andric # if SANITIZER_LINUX 86368d75effSDimitry Andric uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { 86468d75effSDimitry Andric return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5); 86568d75effSDimitry Andric } 866753f127fSDimitry Andric # if defined(__x86_64__) 867753f127fSDimitry Andric # include <asm/unistd_64.h> 868753f127fSDimitry Andric // Currently internal_arch_prctl() is only needed on x86_64. 869753f127fSDimitry Andric uptr internal_arch_prctl(int option, uptr arg2) { 870753f127fSDimitry Andric return internal_syscall(__NR_arch_prctl, option, arg2); 871753f127fSDimitry Andric } 872753f127fSDimitry Andric # endif 87368d75effSDimitry Andric # endif 87468d75effSDimitry Andric 87568d75effSDimitry Andric uptr internal_sigaltstack(const void *ss, void *oss) { 87668d75effSDimitry Andric return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); 87768d75effSDimitry Andric } 87868d75effSDimitry Andric 87962987288SDimitry Andric extern "C" pid_t __fork(void); 88062987288SDimitry Andric 88168d75effSDimitry Andric int internal_fork() { 88281ad6265SDimitry Andric # if SANITIZER_LINUX 88381ad6265SDimitry Andric # if SANITIZER_S390 88481ad6265SDimitry Andric return internal_syscall(SYSCALL(clone), 0, SIGCHLD); 88562987288SDimitry Andric # elif SANITIZER_SPARC 88662987288SDimitry Andric // The clone syscall interface on SPARC differs massively from the rest, 88762987288SDimitry Andric // so fall back to __fork. 88862987288SDimitry Andric return __fork(); 88981ad6265SDimitry Andric # else 89068d75effSDimitry Andric return internal_syscall(SYSCALL(clone), SIGCHLD, 0); 89181ad6265SDimitry Andric # endif 89268d75effSDimitry Andric # else 89368d75effSDimitry Andric return internal_syscall(SYSCALL(fork)); 89468d75effSDimitry Andric # endif 89568d75effSDimitry Andric } 89668d75effSDimitry Andric 897e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD 89868d75effSDimitry Andric int internal_sysctl(const int *name, unsigned int namelen, void *oldp, 89968d75effSDimitry Andric uptr *oldlenp, const void *newp, uptr newlen) { 90068d75effSDimitry Andric return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, 90168d75effSDimitry Andric (size_t *)oldlenp, newp, (size_t)newlen); 90268d75effSDimitry Andric } 90368d75effSDimitry Andric 90468d75effSDimitry Andric int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, 90568d75effSDimitry Andric const void *newp, uptr newlen) { 906e8d8bef9SDimitry Andric // Note: this function can be called during startup, so we need to avoid 907e8d8bef9SDimitry Andric // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname() 908e8d8bef9SDimitry Andric // is a real syscall, but for older versions it calls sysctlnametomib() 909e8d8bef9SDimitry Andric // followed by sysctl(). To avoid calling the intercepted version and 910e8d8bef9SDimitry Andric // asserting if this happens during startup, call the real sysctlnametomib() 911e8d8bef9SDimitry Andric // followed by internal_sysctl() if the syscall is not available. 912e8d8bef9SDimitry Andric # ifdef SYS___sysctlbyname 913e8d8bef9SDimitry Andric return internal_syscall(SYSCALL(__sysctlbyname), sname, 914e8d8bef9SDimitry Andric internal_strlen(sname), oldp, (size_t *)oldlenp, newp, 915e8d8bef9SDimitry Andric (size_t)newlen); 916e8d8bef9SDimitry Andric # else 917e8d8bef9SDimitry Andric static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr; 918e8d8bef9SDimitry Andric if (!real_sysctlnametomib) 919e8d8bef9SDimitry Andric real_sysctlnametomib = 920e8d8bef9SDimitry Andric (decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib"); 921e8d8bef9SDimitry Andric CHECK(real_sysctlnametomib); 922e8d8bef9SDimitry Andric 923e8d8bef9SDimitry Andric int oid[CTL_MAXNAME]; 924e8d8bef9SDimitry Andric size_t len = CTL_MAXNAME; 925e8d8bef9SDimitry Andric if (real_sysctlnametomib(sname, oid, &len) == -1) 926e8d8bef9SDimitry Andric return (-1); 927e8d8bef9SDimitry Andric return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen); 92868d75effSDimitry Andric # endif 929e8d8bef9SDimitry Andric } 93068d75effSDimitry Andric # endif 93168d75effSDimitry Andric 93268d75effSDimitry Andric # if SANITIZER_LINUX 93368d75effSDimitry Andric # define SA_RESTORER 0x04000000 93468d75effSDimitry Andric // Doesn't set sa_restorer if the caller did not set it, so use with caution 93568d75effSDimitry Andric //(see below). 93668d75effSDimitry Andric int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { 93768d75effSDimitry Andric __sanitizer_kernel_sigaction_t k_act, k_oldact; 93868d75effSDimitry Andric internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); 93968d75effSDimitry Andric internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); 94068d75effSDimitry Andric const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; 94168d75effSDimitry Andric __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; 94268d75effSDimitry Andric if (u_act) { 94368d75effSDimitry Andric k_act.handler = u_act->handler; 94468d75effSDimitry Andric k_act.sigaction = u_act->sigaction; 94568d75effSDimitry Andric internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, 94668d75effSDimitry Andric sizeof(__sanitizer_kernel_sigset_t)); 94768d75effSDimitry Andric // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL). 94868d75effSDimitry Andric k_act.sa_flags = u_act->sa_flags | SA_RESTORER; 94968d75effSDimitry Andric // FIXME: most often sa_restorer is unset, however the kernel requires it 95068d75effSDimitry Andric // to point to a valid signal restorer that calls the rt_sigreturn syscall. 95168d75effSDimitry Andric // If sa_restorer passed to the kernel is NULL, the program may crash upon 95268d75effSDimitry Andric // signal delivery or fail to unwind the stack in the signal handler. 95368d75effSDimitry Andric // libc implementation of sigaction() passes its own restorer to 95468d75effSDimitry Andric // rt_sigaction, so we need to do the same (we'll need to reimplement the 95568d75effSDimitry Andric // restorers; for x86_64 the restorer address can be obtained from 95668d75effSDimitry Andric // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). 95768d75effSDimitry Andric # if !SANITIZER_ANDROID || !SANITIZER_MIPS32 95868d75effSDimitry Andric k_act.sa_restorer = u_act->sa_restorer; 95968d75effSDimitry Andric # endif 96068d75effSDimitry Andric } 96168d75effSDimitry Andric 96268d75effSDimitry Andric uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, 96368d75effSDimitry Andric (uptr)(u_act ? &k_act : nullptr), 96468d75effSDimitry Andric (uptr)(u_oldact ? &k_oldact : nullptr), 96568d75effSDimitry Andric (uptr)sizeof(__sanitizer_kernel_sigset_t)); 96668d75effSDimitry Andric 96768d75effSDimitry Andric if ((result == 0) && u_oldact) { 96868d75effSDimitry Andric u_oldact->handler = k_oldact.handler; 96968d75effSDimitry Andric u_oldact->sigaction = k_oldact.sigaction; 97068d75effSDimitry Andric internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, 97168d75effSDimitry Andric sizeof(__sanitizer_kernel_sigset_t)); 97268d75effSDimitry Andric u_oldact->sa_flags = k_oldact.sa_flags; 97368d75effSDimitry Andric # if !SANITIZER_ANDROID || !SANITIZER_MIPS32 97468d75effSDimitry Andric u_oldact->sa_restorer = k_oldact.sa_restorer; 97568d75effSDimitry Andric # endif 97668d75effSDimitry Andric } 97768d75effSDimitry Andric return result; 97868d75effSDimitry Andric } 97968d75effSDimitry Andric # endif // SANITIZER_LINUX 98068d75effSDimitry Andric 98168d75effSDimitry Andric uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, 98268d75effSDimitry Andric __sanitizer_sigset_t *oldset) { 983e8d8bef9SDimitry Andric # if SANITIZER_FREEBSD 98468d75effSDimitry Andric return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); 98568d75effSDimitry Andric # else 98668d75effSDimitry Andric __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; 98768d75effSDimitry Andric __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; 9885ffd83dbSDimitry Andric return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set, 9895ffd83dbSDimitry Andric (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t)); 99068d75effSDimitry Andric # endif 99168d75effSDimitry Andric } 99268d75effSDimitry Andric 99368d75effSDimitry Andric void internal_sigfillset(__sanitizer_sigset_t *set) { 99468d75effSDimitry Andric internal_memset(set, 0xff, sizeof(*set)); 99568d75effSDimitry Andric } 99668d75effSDimitry Andric 99768d75effSDimitry Andric void internal_sigemptyset(__sanitizer_sigset_t *set) { 99868d75effSDimitry Andric internal_memset(set, 0, sizeof(*set)); 99968d75effSDimitry Andric } 100068d75effSDimitry Andric 100168d75effSDimitry Andric # if SANITIZER_LINUX 100268d75effSDimitry Andric void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { 100368d75effSDimitry Andric signum -= 1; 100468d75effSDimitry Andric CHECK_GE(signum, 0); 100568d75effSDimitry Andric CHECK_LT(signum, sizeof(*set) * 8); 100668d75effSDimitry Andric __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; 100768d75effSDimitry Andric const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); 100868d75effSDimitry Andric const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); 1009fe6060f1SDimitry Andric k_set->sig[idx] &= ~((uptr)1 << bit); 101068d75effSDimitry Andric } 101168d75effSDimitry Andric 101268d75effSDimitry Andric bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { 101368d75effSDimitry Andric signum -= 1; 101468d75effSDimitry Andric CHECK_GE(signum, 0); 101568d75effSDimitry Andric CHECK_LT(signum, sizeof(*set) * 8); 101668d75effSDimitry Andric __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; 101768d75effSDimitry Andric const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); 101868d75effSDimitry Andric const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); 1019fe6060f1SDimitry Andric return k_set->sig[idx] & ((uptr)1 << bit); 102068d75effSDimitry Andric } 102168d75effSDimitry Andric # elif SANITIZER_FREEBSD 102281ad6265SDimitry Andric uptr internal_procctl(int type, int id, int cmd, void *data) { 102381ad6265SDimitry Andric return internal_syscall(SYSCALL(procctl), type, id, cmd, data); 102481ad6265SDimitry Andric } 102581ad6265SDimitry Andric 102668d75effSDimitry Andric void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { 102768d75effSDimitry Andric sigset_t *rset = reinterpret_cast<sigset_t *>(set); 102868d75effSDimitry Andric sigdelset(rset, signum); 102968d75effSDimitry Andric } 103068d75effSDimitry Andric 103168d75effSDimitry Andric bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { 103268d75effSDimitry Andric sigset_t *rset = reinterpret_cast<sigset_t *>(set); 103368d75effSDimitry Andric return sigismember(rset, signum); 103468d75effSDimitry Andric } 103568d75effSDimitry Andric # endif 103668d75effSDimitry Andric # endif // !SANITIZER_SOLARIS 103768d75effSDimitry Andric 103868d75effSDimitry Andric # if !SANITIZER_NETBSD 103968d75effSDimitry Andric // ThreadLister implementation. 104068d75effSDimitry Andric ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { 104168d75effSDimitry Andric char task_directory_path[80]; 104268d75effSDimitry Andric internal_snprintf(task_directory_path, sizeof(task_directory_path), 104368d75effSDimitry Andric "/proc/%d/task/", pid); 104468d75effSDimitry Andric descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); 104568d75effSDimitry Andric if (internal_iserror(descriptor_)) { 104668d75effSDimitry Andric Report("Can't open /proc/%d/task for reading.\n", pid); 104768d75effSDimitry Andric } 104868d75effSDimitry Andric } 104968d75effSDimitry Andric 105068d75effSDimitry Andric ThreadLister::Result ThreadLister::ListThreads( 105168d75effSDimitry Andric InternalMmapVector<tid_t> *threads) { 105268d75effSDimitry Andric if (internal_iserror(descriptor_)) 105368d75effSDimitry Andric return Error; 105468d75effSDimitry Andric internal_lseek(descriptor_, 0, SEEK_SET); 105568d75effSDimitry Andric threads->clear(); 105668d75effSDimitry Andric 105768d75effSDimitry Andric Result result = Ok; 105868d75effSDimitry Andric for (bool first_read = true;; first_read = false) { 105968d75effSDimitry Andric // Resize to max capacity if it was downsized by IsAlive. 106068d75effSDimitry Andric buffer_.resize(buffer_.capacity()); 106168d75effSDimitry Andric CHECK_GE(buffer_.size(), 4096); 106268d75effSDimitry Andric uptr read = internal_getdents( 106368d75effSDimitry Andric descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); 106468d75effSDimitry Andric if (!read) 106568d75effSDimitry Andric return result; 106668d75effSDimitry Andric if (internal_iserror(read)) { 106768d75effSDimitry Andric Report("Can't read directory entries from /proc/%d/task.\n", pid_); 106868d75effSDimitry Andric return Error; 106968d75effSDimitry Andric } 107068d75effSDimitry Andric 107168d75effSDimitry Andric for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { 107268d75effSDimitry Andric struct linux_dirent *entry = (struct linux_dirent *)begin; 107368d75effSDimitry Andric begin += entry->d_reclen; 107468d75effSDimitry Andric if (entry->d_ino == 1) { 107568d75effSDimitry Andric // Inode 1 is for bad blocks and also can be a reason for early return. 107668d75effSDimitry Andric // Should be emitted if kernel tried to output terminating thread. 107768d75effSDimitry Andric // See proc_task_readdir implementation in Linux. 107868d75effSDimitry Andric result = Incomplete; 107968d75effSDimitry Andric } 108068d75effSDimitry Andric if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') 108168d75effSDimitry Andric threads->push_back(internal_atoll(entry->d_name)); 108268d75effSDimitry Andric } 108368d75effSDimitry Andric 108468d75effSDimitry Andric // Now we are going to detect short-read or early EOF. In such cases Linux 108568d75effSDimitry Andric // can return inconsistent list with missing alive threads. 108668d75effSDimitry Andric // Code will just remember that the list can be incomplete but it will 108768d75effSDimitry Andric // continue reads to return as much as possible. 108868d75effSDimitry Andric if (!first_read) { 108968d75effSDimitry Andric // The first one was a short-read by definition. 109068d75effSDimitry Andric result = Incomplete; 109168d75effSDimitry Andric } else if (read > buffer_.size() - 1024) { 109268d75effSDimitry Andric // Read was close to the buffer size. So double the size and assume the 109368d75effSDimitry Andric // worst. 109468d75effSDimitry Andric buffer_.resize(buffer_.size() * 2); 109568d75effSDimitry Andric result = Incomplete; 109668d75effSDimitry Andric } else if (!threads->empty() && !IsAlive(threads->back())) { 109768d75effSDimitry Andric // Maybe Linux early returned from read on terminated thread (!pid_alive) 109868d75effSDimitry Andric // and failed to restore read position. 109968d75effSDimitry Andric // See next_tid and proc_task_instantiate in Linux. 110068d75effSDimitry Andric result = Incomplete; 110168d75effSDimitry Andric } 110268d75effSDimitry Andric } 110368d75effSDimitry Andric } 110468d75effSDimitry Andric 110568d75effSDimitry Andric bool ThreadLister::IsAlive(int tid) { 110668d75effSDimitry Andric // /proc/%d/task/%d/status uses same call to detect alive threads as 110768d75effSDimitry Andric // proc_task_readdir. See task_state implementation in Linux. 110868d75effSDimitry Andric char path[80]; 110968d75effSDimitry Andric internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); 111068d75effSDimitry Andric if (!ReadFileToVector(path, &buffer_) || buffer_.empty()) 111168d75effSDimitry Andric return false; 111268d75effSDimitry Andric buffer_.push_back(0); 111368d75effSDimitry Andric static const char kPrefix[] = "\nPPid:"; 111468d75effSDimitry Andric const char *field = internal_strstr(buffer_.data(), kPrefix); 111568d75effSDimitry Andric if (!field) 111668d75effSDimitry Andric return false; 111768d75effSDimitry Andric field += internal_strlen(kPrefix); 111868d75effSDimitry Andric return (int)internal_atoll(field) != 0; 111968d75effSDimitry Andric } 112068d75effSDimitry Andric 112168d75effSDimitry Andric ThreadLister::~ThreadLister() { 112268d75effSDimitry Andric if (!internal_iserror(descriptor_)) 112368d75effSDimitry Andric internal_close(descriptor_); 112468d75effSDimitry Andric } 112568d75effSDimitry Andric # endif 112668d75effSDimitry Andric 112768d75effSDimitry Andric # if SANITIZER_WORDSIZE == 32 112868d75effSDimitry Andric // Take care of unusable kernel area in top gigabyte. 112968d75effSDimitry Andric static uptr GetKernelAreaSize() { 113068d75effSDimitry Andric # if SANITIZER_LINUX && !SANITIZER_X32 113168d75effSDimitry Andric const uptr gbyte = 1UL << 30; 113268d75effSDimitry Andric 113368d75effSDimitry Andric // Firstly check if there are writable segments 113468d75effSDimitry Andric // mapped to top gigabyte (e.g. stack). 113568d75effSDimitry Andric MemoryMappingLayout proc_maps(/*cache_enabled*/ true); 113668d75effSDimitry Andric if (proc_maps.Error()) 113768d75effSDimitry Andric return 0; 113868d75effSDimitry Andric MemoryMappedSegment segment; 113968d75effSDimitry Andric while (proc_maps.Next(&segment)) { 11405f757f3fSDimitry Andric if ((segment.end >= 3 * gbyte) && segment.IsWritable()) 11415f757f3fSDimitry Andric return 0; 114268d75effSDimitry Andric } 114368d75effSDimitry Andric 114468d75effSDimitry Andric # if !SANITIZER_ANDROID 114568d75effSDimitry Andric // Even if nothing is mapped, top Gb may still be accessible 114668d75effSDimitry Andric // if we are running on 64-bit kernel. 114768d75effSDimitry Andric // Uname may report misleading results if personality type 114868d75effSDimitry Andric // is modified (e.g. under schroot) so check this as well. 114968d75effSDimitry Andric struct utsname uname_info; 115068d75effSDimitry Andric int pers = personality(0xffffffffUL); 11515ffd83dbSDimitry Andric if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 && 11525ffd83dbSDimitry Andric internal_strstr(uname_info.machine, "64")) 115368d75effSDimitry Andric return 0; 115468d75effSDimitry Andric # endif // SANITIZER_ANDROID 115568d75effSDimitry Andric 115668d75effSDimitry Andric // Top gigabyte is reserved for kernel. 115768d75effSDimitry Andric return gbyte; 115868d75effSDimitry Andric # else 115968d75effSDimitry Andric return 0; 116068d75effSDimitry Andric # endif // SANITIZER_LINUX && !SANITIZER_X32 116168d75effSDimitry Andric } 116268d75effSDimitry Andric # endif // SANITIZER_WORDSIZE == 32 116368d75effSDimitry Andric 116468d75effSDimitry Andric uptr GetMaxVirtualAddress() { 1165e8d8bef9SDimitry Andric # if SANITIZER_NETBSD && defined(__x86_64__) 116668d75effSDimitry Andric return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) 116768d75effSDimitry Andric # elif SANITIZER_WORDSIZE == 64 11680fca6ea1SDimitry Andric # if defined(__powerpc64__) || defined(__aarch64__) || \ 11690fca6ea1SDimitry Andric defined(__loongarch__) || SANITIZER_RISCV64 117068d75effSDimitry Andric // On PowerPC64 we have two different address space layouts: 44- and 46-bit. 117168d75effSDimitry Andric // We somehow need to figure out which one we are using now and choose 117268d75effSDimitry Andric // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. 117368d75effSDimitry Andric // Note that with 'ulimit -s unlimited' the stack is moved away from the top 117468d75effSDimitry Andric // of the address space, so simply checking the stack address is not enough. 117568d75effSDimitry Andric // This should (does) work for both PowerPC64 Endian modes. 117668d75effSDimitry Andric // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. 1177bdd1243dSDimitry Andric // loongarch64 also has multiple address space layouts: default is 47-bit. 11780fca6ea1SDimitry Andric // RISC-V 64 also has multiple address space layouts: 39, 48 and 57-bit. 117968d75effSDimitry Andric return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; 1180753f127fSDimitry Andric # elif SANITIZER_MIPS64 118168d75effSDimitry Andric return (1ULL << 40) - 1; // 0x000000ffffffffffUL; 118268d75effSDimitry Andric # elif defined(__s390x__) 118368d75effSDimitry Andric return (1ULL << 53) - 1; // 0x001fffffffffffffUL; 118468d75effSDimitry Andric # elif defined(__sparc__) 118568d75effSDimitry Andric return ~(uptr)0; 118668d75effSDimitry Andric # else 118768d75effSDimitry Andric return (1ULL << 47) - 1; // 0x00007fffffffffffUL; 118868d75effSDimitry Andric # endif 118968d75effSDimitry Andric # else // SANITIZER_WORDSIZE == 32 119068d75effSDimitry Andric # if defined(__s390__) 119168d75effSDimitry Andric return (1ULL << 31) - 1; // 0x7fffffff; 119268d75effSDimitry Andric # else 119368d75effSDimitry Andric return (1ULL << 32) - 1; // 0xffffffff; 119468d75effSDimitry Andric # endif 119568d75effSDimitry Andric # endif // SANITIZER_WORDSIZE 119668d75effSDimitry Andric } 119768d75effSDimitry Andric 119868d75effSDimitry Andric uptr GetMaxUserVirtualAddress() { 119968d75effSDimitry Andric uptr addr = GetMaxVirtualAddress(); 120068d75effSDimitry Andric # if SANITIZER_WORDSIZE == 32 && !defined(__s390__) 120168d75effSDimitry Andric if (!common_flags()->full_address_space) 120268d75effSDimitry Andric addr -= GetKernelAreaSize(); 120368d75effSDimitry Andric CHECK_LT(reinterpret_cast<uptr>(&addr), addr); 120468d75effSDimitry Andric # endif 120568d75effSDimitry Andric return addr; 120668d75effSDimitry Andric } 120768d75effSDimitry Andric 12080fca6ea1SDimitry Andric # if !SANITIZER_ANDROID || defined(__aarch64__) 120968d75effSDimitry Andric uptr GetPageSize() { 12105ffd83dbSDimitry Andric # if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \ 12115ffd83dbSDimitry Andric defined(EXEC_PAGESIZE) 121268d75effSDimitry Andric return EXEC_PAGESIZE; 121368d75effSDimitry Andric # elif SANITIZER_FREEBSD || SANITIZER_NETBSD 121468d75effSDimitry Andric // Use sysctl as sysconf can trigger interceptors internally. 121568d75effSDimitry Andric int pz = 0; 121668d75effSDimitry Andric uptr pzl = sizeof(pz); 121768d75effSDimitry Andric int mib[2] = {CTL_HW, HW_PAGESIZE}; 121868d75effSDimitry Andric int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); 121968d75effSDimitry Andric CHECK_EQ(rv, 0); 122068d75effSDimitry Andric return (uptr)pz; 122168d75effSDimitry Andric # elif SANITIZER_USE_GETAUXVAL 122268d75effSDimitry Andric return getauxval(AT_PAGESZ); 122368d75effSDimitry Andric # else 122468d75effSDimitry Andric return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. 122568d75effSDimitry Andric # endif 122668d75effSDimitry Andric } 12270fca6ea1SDimitry Andric # endif 122868d75effSDimitry Andric 122968d75effSDimitry Andric uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) { 123068d75effSDimitry Andric # if SANITIZER_SOLARIS 123168d75effSDimitry Andric const char *default_module_name = getexecname(); 123268d75effSDimitry Andric CHECK_NE(default_module_name, NULL); 123368d75effSDimitry Andric return internal_snprintf(buf, buf_len, "%s", default_module_name); 123468d75effSDimitry Andric # else 123568d75effSDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_NETBSD 123668d75effSDimitry Andric # if SANITIZER_FREEBSD 123768d75effSDimitry Andric const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; 123868d75effSDimitry Andric # else 123968d75effSDimitry Andric const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; 124068d75effSDimitry Andric # endif 124168d75effSDimitry Andric const char *default_module_name = "kern.proc.pathname"; 124268d75effSDimitry Andric uptr Size = buf_len; 124368d75effSDimitry Andric bool IsErr = 124468d75effSDimitry Andric (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); 124568d75effSDimitry Andric int readlink_error = IsErr ? errno : 0; 124668d75effSDimitry Andric uptr module_name_len = Size; 124768d75effSDimitry Andric # else 124868d75effSDimitry Andric const char *default_module_name = "/proc/self/exe"; 12495f757f3fSDimitry Andric uptr module_name_len = internal_readlink(default_module_name, buf, buf_len); 125068d75effSDimitry Andric int readlink_error; 125168d75effSDimitry Andric bool IsErr = internal_iserror(module_name_len, &readlink_error); 12520fca6ea1SDimitry Andric # endif 125368d75effSDimitry Andric if (IsErr) { 125468d75effSDimitry Andric // We can't read binary name for some reason, assume it's unknown. 12555f757f3fSDimitry Andric Report( 12565f757f3fSDimitry Andric "WARNING: reading executable name failed with errno %d, " 12575f757f3fSDimitry Andric "some stack frames may not be symbolized\n", 12585f757f3fSDimitry Andric readlink_error); 12595f757f3fSDimitry Andric module_name_len = 12605f757f3fSDimitry Andric internal_snprintf(buf, buf_len, "%s", default_module_name); 126168d75effSDimitry Andric CHECK_LT(module_name_len, buf_len); 126268d75effSDimitry Andric } 126368d75effSDimitry Andric return module_name_len; 126468d75effSDimitry Andric # endif 126568d75effSDimitry Andric } 126668d75effSDimitry Andric 126768d75effSDimitry Andric uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { 126868d75effSDimitry Andric # if SANITIZER_LINUX 126968d75effSDimitry Andric char *tmpbuf; 127068d75effSDimitry Andric uptr tmpsize; 127168d75effSDimitry Andric uptr tmplen; 127268d75effSDimitry Andric if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen, 127368d75effSDimitry Andric 1024 * 1024)) { 127468d75effSDimitry Andric internal_strncpy(buf, tmpbuf, buf_len); 127568d75effSDimitry Andric UnmapOrDie(tmpbuf, tmpsize); 127668d75effSDimitry Andric return internal_strlen(buf); 127768d75effSDimitry Andric } 127868d75effSDimitry Andric # endif 127968d75effSDimitry Andric return ReadBinaryName(buf, buf_len); 128068d75effSDimitry Andric } 128168d75effSDimitry Andric 128268d75effSDimitry Andric // Match full names of the form /path/to/base_name{-,.}* 128368d75effSDimitry Andric bool LibraryNameIs(const char *full_name, const char *base_name) { 128468d75effSDimitry Andric const char *name = full_name; 128568d75effSDimitry Andric // Strip path. 128668d75effSDimitry Andric while (*name != '\0') name++; 128768d75effSDimitry Andric while (name > full_name && *name != '/') name--; 12885f757f3fSDimitry Andric if (*name == '/') 12895f757f3fSDimitry Andric name++; 129068d75effSDimitry Andric uptr base_name_length = internal_strlen(base_name); 12915f757f3fSDimitry Andric if (internal_strncmp(name, base_name, base_name_length)) 12925f757f3fSDimitry Andric return false; 129368d75effSDimitry Andric return (name[base_name_length] == '-' || name[base_name_length] == '.'); 129468d75effSDimitry Andric } 129568d75effSDimitry Andric 129668d75effSDimitry Andric # if !SANITIZER_ANDROID 129768d75effSDimitry Andric // Call cb for each region mapped by map. 129868d75effSDimitry Andric void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { 129968d75effSDimitry Andric CHECK_NE(map, nullptr); 1300e8d8bef9SDimitry Andric # if !SANITIZER_FREEBSD 130168d75effSDimitry Andric typedef ElfW(Phdr) Elf_Phdr; 130268d75effSDimitry Andric typedef ElfW(Ehdr) Elf_Ehdr; 1303e8d8bef9SDimitry Andric # endif // !SANITIZER_FREEBSD 130468d75effSDimitry Andric char *base = (char *)map->l_addr; 130568d75effSDimitry Andric Elf_Ehdr *ehdr = (Elf_Ehdr *)base; 130668d75effSDimitry Andric char *phdrs = base + ehdr->e_phoff; 130768d75effSDimitry Andric char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; 130868d75effSDimitry Andric 130968d75effSDimitry Andric // Find the segment with the minimum base so we can "relocate" the p_vaddr 131068d75effSDimitry Andric // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC 131168d75effSDimitry Andric // objects have a non-zero base. 131268d75effSDimitry Andric uptr preferred_base = (uptr)-1; 131368d75effSDimitry Andric for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { 131468d75effSDimitry Andric Elf_Phdr *phdr = (Elf_Phdr *)iter; 131568d75effSDimitry Andric if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr) 131668d75effSDimitry Andric preferred_base = (uptr)phdr->p_vaddr; 131768d75effSDimitry Andric } 131868d75effSDimitry Andric 131968d75effSDimitry Andric // Compute the delta from the real base to get a relocation delta. 132068d75effSDimitry Andric sptr delta = (uptr)base - preferred_base; 132168d75effSDimitry Andric // Now we can figure out what the loader really mapped. 132268d75effSDimitry Andric for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { 132368d75effSDimitry Andric Elf_Phdr *phdr = (Elf_Phdr *)iter; 132468d75effSDimitry Andric if (phdr->p_type == PT_LOAD) { 132568d75effSDimitry Andric uptr seg_start = phdr->p_vaddr + delta; 132668d75effSDimitry Andric uptr seg_end = seg_start + phdr->p_memsz; 132768d75effSDimitry Andric // None of these values are aligned. We consider the ragged edges of the 132868d75effSDimitry Andric // load command as defined, since they are mapped from the file. 132968d75effSDimitry Andric seg_start = RoundDownTo(seg_start, GetPageSizeCached()); 133068d75effSDimitry Andric seg_end = RoundUpTo(seg_end, GetPageSizeCached()); 133168d75effSDimitry Andric cb((void *)seg_start, seg_end - seg_start); 133268d75effSDimitry Andric } 133368d75effSDimitry Andric } 133468d75effSDimitry Andric } 133568d75effSDimitry Andric # endif 133668d75effSDimitry Andric 13373781e779SPiotr Kubaj # if SANITIZER_LINUX 13383781e779SPiotr Kubaj # if defined(__x86_64__) 133968d75effSDimitry Andric // We cannot use glibc's clone wrapper, because it messes with the child 134068d75effSDimitry Andric // task's TLS. It writes the PID and TID of the child task to its thread 134168d75effSDimitry Andric // descriptor, but in our case the child task shares the thread descriptor with 134268d75effSDimitry Andric // the parent (because we don't know how to allocate a new thread 134368d75effSDimitry Andric // descriptor to keep glibc happy). So the stock version of clone(), when 134468d75effSDimitry Andric // used with CLONE_VM, would end up corrupting the parent's thread descriptor. 134568d75effSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 134668d75effSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 134768d75effSDimitry Andric long long res; 134868d75effSDimitry Andric if (!fn || !child_stack) 134968d75effSDimitry Andric return -EINVAL; 135068d75effSDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 135168d75effSDimitry Andric child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); 135268d75effSDimitry Andric ((unsigned long long *)child_stack)[0] = (uptr)fn; 135368d75effSDimitry Andric ((unsigned long long *)child_stack)[1] = (uptr)arg; 135468d75effSDimitry Andric register void *r8 __asm__("r8") = newtls; 135568d75effSDimitry Andric register int *r10 __asm__("r10") = child_tidptr; 135668d75effSDimitry Andric __asm__ __volatile__( 135768d75effSDimitry Andric /* %rax = syscall(%rax = SYSCALL(clone), 135868d75effSDimitry Andric * %rdi = flags, 135968d75effSDimitry Andric * %rsi = child_stack, 136068d75effSDimitry Andric * %rdx = parent_tidptr, 136168d75effSDimitry Andric * %r8 = new_tls, 136268d75effSDimitry Andric * %r10 = child_tidptr) 136368d75effSDimitry Andric */ 136468d75effSDimitry Andric "syscall\n" 136568d75effSDimitry Andric 136668d75effSDimitry Andric /* if (%rax != 0) 136768d75effSDimitry Andric * return; 136868d75effSDimitry Andric */ 136968d75effSDimitry Andric "testq %%rax,%%rax\n" 137068d75effSDimitry Andric "jnz 1f\n" 137168d75effSDimitry Andric 137268d75effSDimitry Andric /* In the child. Terminate unwind chain. */ 137368d75effSDimitry Andric // XXX: We should also terminate the CFI unwind chain 137468d75effSDimitry Andric // here. Unfortunately clang 3.2 doesn't support the 137568d75effSDimitry Andric // necessary CFI directives, so we skip that part. 137668d75effSDimitry Andric "xorq %%rbp,%%rbp\n" 137768d75effSDimitry Andric 137868d75effSDimitry Andric /* Call "fn(arg)". */ 137968d75effSDimitry Andric "popq %%rax\n" 138068d75effSDimitry Andric "popq %%rdi\n" 138168d75effSDimitry Andric "call *%%rax\n" 138268d75effSDimitry Andric 138368d75effSDimitry Andric /* Call _exit(%rax). */ 138468d75effSDimitry Andric "movq %%rax,%%rdi\n" 138568d75effSDimitry Andric "movq %2,%%rax\n" 138668d75effSDimitry Andric "syscall\n" 138768d75effSDimitry Andric 138868d75effSDimitry Andric /* Return to parent. */ 138968d75effSDimitry Andric "1:\n" 139068d75effSDimitry Andric : "=a"(res) 13915f757f3fSDimitry Andric : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "S"(child_stack), "D"(flags), 13925f757f3fSDimitry Andric "d"(parent_tidptr), "r"(r8), "r"(r10) 139368d75effSDimitry Andric : "memory", "r11", "rcx"); 139468d75effSDimitry Andric return res; 139568d75effSDimitry Andric } 139668d75effSDimitry Andric # elif defined(__mips__) 139768d75effSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 139868d75effSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 139968d75effSDimitry Andric long long res; 140068d75effSDimitry Andric if (!fn || !child_stack) 140168d75effSDimitry Andric return -EINVAL; 140268d75effSDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 140368d75effSDimitry Andric child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); 140468d75effSDimitry Andric ((unsigned long long *)child_stack)[0] = (uptr)fn; 140568d75effSDimitry Andric ((unsigned long long *)child_stack)[1] = (uptr)arg; 140668d75effSDimitry Andric register void *a3 __asm__("$7") = newtls; 140768d75effSDimitry Andric register int *a4 __asm__("$8") = child_tidptr; 140868d75effSDimitry Andric // We don't have proper CFI directives here because it requires alot of code 140968d75effSDimitry Andric // for very marginal benefits. 141068d75effSDimitry Andric __asm__ __volatile__( 141168d75effSDimitry Andric /* $v0 = syscall($v0 = __NR_clone, 141268d75effSDimitry Andric * $a0 = flags, 141368d75effSDimitry Andric * $a1 = child_stack, 141468d75effSDimitry Andric * $a2 = parent_tidptr, 141568d75effSDimitry Andric * $a3 = new_tls, 141668d75effSDimitry Andric * $a4 = child_tidptr) 141768d75effSDimitry Andric */ 141868d75effSDimitry Andric ".cprestore 16;\n" 141968d75effSDimitry Andric "move $4,%1;\n" 142068d75effSDimitry Andric "move $5,%2;\n" 142168d75effSDimitry Andric "move $6,%3;\n" 142268d75effSDimitry Andric "move $7,%4;\n" 142368d75effSDimitry Andric /* Store the fifth argument on stack 142468d75effSDimitry Andric * if we are using 32-bit abi. 142568d75effSDimitry Andric */ 142668d75effSDimitry Andric # if SANITIZER_WORDSIZE == 32 142768d75effSDimitry Andric "lw %5,16($29);\n" 142868d75effSDimitry Andric # else 142968d75effSDimitry Andric "move $8,%5;\n" 143068d75effSDimitry Andric # endif 143168d75effSDimitry Andric "li $2,%6;\n" 143268d75effSDimitry Andric "syscall;\n" 143368d75effSDimitry Andric 143468d75effSDimitry Andric /* if ($v0 != 0) 143568d75effSDimitry Andric * return; 143668d75effSDimitry Andric */ 143768d75effSDimitry Andric "bnez $2,1f;\n" 143868d75effSDimitry Andric 143968d75effSDimitry Andric /* Call "fn(arg)". */ 144068d75effSDimitry Andric # if SANITIZER_WORDSIZE == 32 144168d75effSDimitry Andric # ifdef __BIG_ENDIAN__ 144268d75effSDimitry Andric "lw $25,4($29);\n" 144368d75effSDimitry Andric "lw $4,12($29);\n" 144468d75effSDimitry Andric # else 144568d75effSDimitry Andric "lw $25,0($29);\n" 144668d75effSDimitry Andric "lw $4,8($29);\n" 144768d75effSDimitry Andric # endif 144868d75effSDimitry Andric # else 144968d75effSDimitry Andric "ld $25,0($29);\n" 145068d75effSDimitry Andric "ld $4,8($29);\n" 145168d75effSDimitry Andric # endif 145268d75effSDimitry Andric "jal $25;\n" 145368d75effSDimitry Andric 145468d75effSDimitry Andric /* Call _exit($v0). */ 145568d75effSDimitry Andric "move $4,$2;\n" 145668d75effSDimitry Andric "li $2,%7;\n" 145768d75effSDimitry Andric "syscall;\n" 145868d75effSDimitry Andric 145968d75effSDimitry Andric /* Return to parent. */ 146068d75effSDimitry Andric "1:\n" 146168d75effSDimitry Andric : "=r"(res) 14625f757f3fSDimitry Andric : "r"(flags), "r"(child_stack), "r"(parent_tidptr), "r"(a3), "r"(a4), 14635f757f3fSDimitry Andric "i"(__NR_clone), "i"(__NR_exit) 146468d75effSDimitry Andric : "memory", "$29"); 146568d75effSDimitry Andric return res; 146668d75effSDimitry Andric } 1467e8d8bef9SDimitry Andric # elif SANITIZER_RISCV64 1468e8d8bef9SDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 1469e8d8bef9SDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 1470e8d8bef9SDimitry Andric if (!fn || !child_stack) 1471e8d8bef9SDimitry Andric return -EINVAL; 1472e8d8bef9SDimitry Andric 1473fe6060f1SDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 1474fe6060f1SDimitry Andric 1475fe6060f1SDimitry Andric register int res __asm__("a0"); 1476fe6060f1SDimitry Andric register int __flags __asm__("a0") = flags; 1477e8d8bef9SDimitry Andric register void *__stack __asm__("a1") = child_stack; 1478fe6060f1SDimitry Andric register int *__ptid __asm__("a2") = parent_tidptr; 1479fe6060f1SDimitry Andric register void *__tls __asm__("a3") = newtls; 1480fe6060f1SDimitry Andric register int *__ctid __asm__("a4") = child_tidptr; 1481fe6060f1SDimitry Andric register int (*__fn)(void *) __asm__("a5") = fn; 1482fe6060f1SDimitry Andric register void *__arg __asm__("a6") = arg; 1483fe6060f1SDimitry Andric register int nr_clone __asm__("a7") = __NR_clone; 1484e8d8bef9SDimitry Andric 1485e8d8bef9SDimitry Andric __asm__ __volatile__( 1486e8d8bef9SDimitry Andric "ecall\n" 1487e8d8bef9SDimitry Andric 1488fe6060f1SDimitry Andric /* if (a0 != 0) 1489fe6060f1SDimitry Andric * return a0; 1490e8d8bef9SDimitry Andric */ 1491e8d8bef9SDimitry Andric "bnez a0, 1f\n" 1492e8d8bef9SDimitry Andric 1493fe6060f1SDimitry Andric // In the child, now. Call "fn(arg)". 1494fe6060f1SDimitry Andric "mv a0, a6\n" 1495fe6060f1SDimitry Andric "jalr a5\n" 1496e8d8bef9SDimitry Andric 1497fe6060f1SDimitry Andric // Call _exit(a0). 1498fe6060f1SDimitry Andric "addi a7, zero, %9\n" 1499e8d8bef9SDimitry Andric "ecall\n" 1500e8d8bef9SDimitry Andric "1:\n" 1501e8d8bef9SDimitry Andric 1502e8d8bef9SDimitry Andric : "=r"(res) 1503fe6060f1SDimitry Andric : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid), 1504fe6060f1SDimitry Andric "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit) 1505fe6060f1SDimitry Andric : "memory"); 1506e8d8bef9SDimitry Andric return res; 1507e8d8bef9SDimitry Andric } 150868d75effSDimitry Andric # elif defined(__aarch64__) 150968d75effSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 151068d75effSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 1511349cc55cSDimitry Andric register long long res __asm__("x0"); 151268d75effSDimitry Andric if (!fn || !child_stack) 151368d75effSDimitry Andric return -EINVAL; 151468d75effSDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 151568d75effSDimitry Andric child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); 151668d75effSDimitry Andric ((unsigned long long *)child_stack)[0] = (uptr)fn; 151768d75effSDimitry Andric ((unsigned long long *)child_stack)[1] = (uptr)arg; 151868d75effSDimitry Andric 151968d75effSDimitry Andric register int (*__fn)(void *) __asm__("x0") = fn; 152068d75effSDimitry Andric register void *__stack __asm__("x1") = child_stack; 152168d75effSDimitry Andric register int __flags __asm__("x2") = flags; 152268d75effSDimitry Andric register void *__arg __asm__("x3") = arg; 152368d75effSDimitry Andric register int *__ptid __asm__("x4") = parent_tidptr; 152468d75effSDimitry Andric register void *__tls __asm__("x5") = newtls; 152568d75effSDimitry Andric register int *__ctid __asm__("x6") = child_tidptr; 152668d75effSDimitry Andric 152768d75effSDimitry Andric __asm__ __volatile__( 152868d75effSDimitry Andric "mov x0,x2\n" /* flags */ 152968d75effSDimitry Andric "mov x2,x4\n" /* ptid */ 153068d75effSDimitry Andric "mov x3,x5\n" /* tls */ 153168d75effSDimitry Andric "mov x4,x6\n" /* ctid */ 153268d75effSDimitry Andric "mov x8,%9\n" /* clone */ 153368d75effSDimitry Andric 153468d75effSDimitry Andric "svc 0x0\n" 153568d75effSDimitry Andric 153668d75effSDimitry Andric /* if (%r0 != 0) 153768d75effSDimitry Andric * return %r0; 153868d75effSDimitry Andric */ 153968d75effSDimitry Andric "cmp x0, #0\n" 154068d75effSDimitry Andric "bne 1f\n" 154168d75effSDimitry Andric 154268d75effSDimitry Andric /* In the child, now. Call "fn(arg)". */ 154368d75effSDimitry Andric "ldp x1, x0, [sp], #16\n" 154468d75effSDimitry Andric "blr x1\n" 154568d75effSDimitry Andric 154668d75effSDimitry Andric /* Call _exit(%r0). */ 154768d75effSDimitry Andric "mov x8, %10\n" 154868d75effSDimitry Andric "svc 0x0\n" 154968d75effSDimitry Andric "1:\n" 155068d75effSDimitry Andric 155168d75effSDimitry Andric : "=r"(res) 15525f757f3fSDimitry Andric : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), 15535f757f3fSDimitry Andric "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit) 155468d75effSDimitry Andric : "x30", "memory"); 155568d75effSDimitry Andric return res; 155668d75effSDimitry Andric } 1557bdd1243dSDimitry Andric # elif SANITIZER_LOONGARCH64 1558bdd1243dSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 1559bdd1243dSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 1560bdd1243dSDimitry Andric if (!fn || !child_stack) 1561bdd1243dSDimitry Andric return -EINVAL; 1562bdd1243dSDimitry Andric 1563bdd1243dSDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 1564bdd1243dSDimitry Andric 1565bdd1243dSDimitry Andric register int res __asm__("$a0"); 1566bdd1243dSDimitry Andric register int __flags __asm__("$a0") = flags; 1567bdd1243dSDimitry Andric register void *__stack __asm__("$a1") = child_stack; 1568bdd1243dSDimitry Andric register int *__ptid __asm__("$a2") = parent_tidptr; 1569bdd1243dSDimitry Andric register int *__ctid __asm__("$a3") = child_tidptr; 1570bdd1243dSDimitry Andric register void *__tls __asm__("$a4") = newtls; 1571bdd1243dSDimitry Andric register int (*__fn)(void *) __asm__("$a5") = fn; 1572bdd1243dSDimitry Andric register void *__arg __asm__("$a6") = arg; 1573bdd1243dSDimitry Andric register int nr_clone __asm__("$a7") = __NR_clone; 1574bdd1243dSDimitry Andric 1575bdd1243dSDimitry Andric __asm__ __volatile__( 1576bdd1243dSDimitry Andric "syscall 0\n" 1577bdd1243dSDimitry Andric 1578bdd1243dSDimitry Andric // if ($a0 != 0) 1579bdd1243dSDimitry Andric // return $a0; 1580bdd1243dSDimitry Andric "bnez $a0, 1f\n" 1581bdd1243dSDimitry Andric 1582bdd1243dSDimitry Andric // In the child, now. Call "fn(arg)". 1583bdd1243dSDimitry Andric "move $a0, $a6\n" 1584bdd1243dSDimitry Andric "jirl $ra, $a5, 0\n" 1585bdd1243dSDimitry Andric 1586bdd1243dSDimitry Andric // Call _exit($a0). 1587bdd1243dSDimitry Andric "addi.d $a7, $zero, %9\n" 1588bdd1243dSDimitry Andric "syscall 0\n" 1589bdd1243dSDimitry Andric 1590bdd1243dSDimitry Andric "1:\n" 1591bdd1243dSDimitry Andric 1592bdd1243dSDimitry Andric : "=r"(res) 1593bdd1243dSDimitry Andric : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__ctid), "r"(__tls), 1594bdd1243dSDimitry Andric "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit) 15955f757f3fSDimitry Andric : "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", 15965f757f3fSDimitry Andric "$t8"); 1597bdd1243dSDimitry Andric return res; 1598bdd1243dSDimitry Andric } 159968d75effSDimitry Andric # elif defined(__powerpc64__) 160068d75effSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 160168d75effSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 160268d75effSDimitry Andric long long res; 160368d75effSDimitry Andric // Stack frame structure. 160468d75effSDimitry Andric # if SANITIZER_PPC64V1 160568d75effSDimitry Andric // Back chain == 0 (SP + 112) 160668d75effSDimitry Andric // Frame (112 bytes): 160768d75effSDimitry Andric // Parameter save area (SP + 48), 8 doublewords 160868d75effSDimitry Andric // TOC save area (SP + 40) 160968d75effSDimitry Andric // Link editor doubleword (SP + 32) 161068d75effSDimitry Andric // Compiler doubleword (SP + 24) 161168d75effSDimitry Andric // LR save area (SP + 16) 161268d75effSDimitry Andric // CR save area (SP + 8) 161368d75effSDimitry Andric // Back chain (SP + 0) 161468d75effSDimitry Andric # define FRAME_SIZE 112 161568d75effSDimitry Andric # define FRAME_TOC_SAVE_OFFSET 40 161668d75effSDimitry Andric # elif SANITIZER_PPC64V2 161768d75effSDimitry Andric // Back chain == 0 (SP + 32) 161868d75effSDimitry Andric // Frame (32 bytes): 161968d75effSDimitry Andric // TOC save area (SP + 24) 162068d75effSDimitry Andric // LR save area (SP + 16) 162168d75effSDimitry Andric // CR save area (SP + 8) 162268d75effSDimitry Andric // Back chain (SP + 0) 162368d75effSDimitry Andric # define FRAME_SIZE 32 162468d75effSDimitry Andric # define FRAME_TOC_SAVE_OFFSET 24 162568d75effSDimitry Andric # else 162668d75effSDimitry Andric # error "Unsupported PPC64 ABI" 162768d75effSDimitry Andric # endif 162868d75effSDimitry Andric if (!fn || !child_stack) 162968d75effSDimitry Andric return -EINVAL; 163068d75effSDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 163168d75effSDimitry Andric 163268d75effSDimitry Andric register int (*__fn)(void *) __asm__("r3") = fn; 163368d75effSDimitry Andric register void *__cstack __asm__("r4") = child_stack; 163468d75effSDimitry Andric register int __flags __asm__("r5") = flags; 163568d75effSDimitry Andric register void *__arg __asm__("r6") = arg; 163668d75effSDimitry Andric register int *__ptidptr __asm__("r7") = parent_tidptr; 163768d75effSDimitry Andric register void *__newtls __asm__("r8") = newtls; 163868d75effSDimitry Andric register int *__ctidptr __asm__("r9") = child_tidptr; 163968d75effSDimitry Andric 164068d75effSDimitry Andric __asm__ __volatile__( 164168d75effSDimitry Andric /* fn and arg are saved across the syscall */ 164268d75effSDimitry Andric "mr 28, %5\n\t" 164368d75effSDimitry Andric "mr 27, %8\n\t" 164468d75effSDimitry Andric 164568d75effSDimitry Andric /* syscall 164668d75effSDimitry Andric r0 == __NR_clone 164768d75effSDimitry Andric r3 == flags 164868d75effSDimitry Andric r4 == child_stack 164968d75effSDimitry Andric r5 == parent_tidptr 165068d75effSDimitry Andric r6 == newtls 165168d75effSDimitry Andric r7 == child_tidptr */ 165268d75effSDimitry Andric "mr 3, %7\n\t" 165368d75effSDimitry Andric "mr 5, %9\n\t" 165468d75effSDimitry Andric "mr 6, %10\n\t" 165568d75effSDimitry Andric "mr 7, %11\n\t" 165668d75effSDimitry Andric "li 0, %3\n\t" 165768d75effSDimitry Andric "sc\n\t" 165868d75effSDimitry Andric 165968d75effSDimitry Andric /* Test if syscall was successful */ 166068d75effSDimitry Andric "cmpdi cr1, 3, 0\n\t" 166168d75effSDimitry Andric "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" 166268d75effSDimitry Andric "bne- cr1, 1f\n\t" 166368d75effSDimitry Andric 166468d75effSDimitry Andric /* Set up stack frame */ 166568d75effSDimitry Andric "li 29, 0\n\t" 166668d75effSDimitry Andric "stdu 29, -8(1)\n\t" 166768d75effSDimitry Andric "stdu 1, -%12(1)\n\t" 166868d75effSDimitry Andric /* Do the function call */ 166968d75effSDimitry Andric "std 2, %13(1)\n\t" 167068d75effSDimitry Andric # if SANITIZER_PPC64V1 167168d75effSDimitry Andric "ld 0, 0(28)\n\t" 167268d75effSDimitry Andric "ld 2, 8(28)\n\t" 167368d75effSDimitry Andric "mtctr 0\n\t" 167468d75effSDimitry Andric # elif SANITIZER_PPC64V2 167568d75effSDimitry Andric "mr 12, 28\n\t" 167668d75effSDimitry Andric "mtctr 12\n\t" 167768d75effSDimitry Andric # else 167868d75effSDimitry Andric # error "Unsupported PPC64 ABI" 167968d75effSDimitry Andric # endif 168068d75effSDimitry Andric "mr 3, 27\n\t" 168168d75effSDimitry Andric "bctrl\n\t" 168268d75effSDimitry Andric "ld 2, %13(1)\n\t" 168368d75effSDimitry Andric 168468d75effSDimitry Andric /* Call _exit(r3) */ 168568d75effSDimitry Andric "li 0, %4\n\t" 168668d75effSDimitry Andric "sc\n\t" 168768d75effSDimitry Andric 168868d75effSDimitry Andric /* Return to parent */ 168968d75effSDimitry Andric "1:\n\t" 169068d75effSDimitry Andric "mr %0, 3\n\t" 169168d75effSDimitry Andric : "=r"(res) 16925f757f3fSDimitry Andric : "0"(-1), "i"(EINVAL), "i"(__NR_clone), "i"(__NR_exit), "r"(__fn), 16935f757f3fSDimitry Andric "r"(__cstack), "r"(__flags), "r"(__arg), "r"(__ptidptr), "r"(__newtls), 16945f757f3fSDimitry Andric "r"(__ctidptr), "i"(FRAME_SIZE), "i"(FRAME_TOC_SAVE_OFFSET) 169568d75effSDimitry Andric : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29"); 169668d75effSDimitry Andric return res; 169768d75effSDimitry Andric } 16983781e779SPiotr Kubaj # elif defined(__i386__) 169968d75effSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 170068d75effSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 170168d75effSDimitry Andric int res; 170268d75effSDimitry Andric if (!fn || !child_stack) 170368d75effSDimitry Andric return -EINVAL; 170468d75effSDimitry Andric CHECK_EQ(0, (uptr)child_stack % 16); 170568d75effSDimitry Andric child_stack = (char *)child_stack - 7 * sizeof(unsigned int); 170668d75effSDimitry Andric ((unsigned int *)child_stack)[0] = (uptr)flags; 170768d75effSDimitry Andric ((unsigned int *)child_stack)[1] = (uptr)0; 170868d75effSDimitry Andric ((unsigned int *)child_stack)[2] = (uptr)fn; 170968d75effSDimitry Andric ((unsigned int *)child_stack)[3] = (uptr)arg; 171068d75effSDimitry Andric __asm__ __volatile__( 171168d75effSDimitry Andric /* %eax = syscall(%eax = SYSCALL(clone), 171268d75effSDimitry Andric * %ebx = flags, 171368d75effSDimitry Andric * %ecx = child_stack, 171468d75effSDimitry Andric * %edx = parent_tidptr, 171568d75effSDimitry Andric * %esi = new_tls, 171668d75effSDimitry Andric * %edi = child_tidptr) 171768d75effSDimitry Andric */ 171868d75effSDimitry Andric 171968d75effSDimitry Andric /* Obtain flags */ 172068d75effSDimitry Andric "movl (%%ecx), %%ebx\n" 172168d75effSDimitry Andric /* Do the system call */ 172268d75effSDimitry Andric "pushl %%ebx\n" 172368d75effSDimitry Andric "pushl %%esi\n" 172468d75effSDimitry Andric "pushl %%edi\n" 172568d75effSDimitry Andric /* Remember the flag value. */ 172668d75effSDimitry Andric "movl %%ebx, (%%ecx)\n" 172768d75effSDimitry Andric "int $0x80\n" 172868d75effSDimitry Andric "popl %%edi\n" 172968d75effSDimitry Andric "popl %%esi\n" 173068d75effSDimitry Andric "popl %%ebx\n" 173168d75effSDimitry Andric 173268d75effSDimitry Andric /* if (%eax != 0) 173368d75effSDimitry Andric * return; 173468d75effSDimitry Andric */ 173568d75effSDimitry Andric 173668d75effSDimitry Andric "test %%eax,%%eax\n" 173768d75effSDimitry Andric "jnz 1f\n" 173868d75effSDimitry Andric 173968d75effSDimitry Andric /* terminate the stack frame */ 174068d75effSDimitry Andric "xorl %%ebp,%%ebp\n" 174168d75effSDimitry Andric /* Call FN. */ 174268d75effSDimitry Andric "call *%%ebx\n" 174368d75effSDimitry Andric # ifdef PIC 174468d75effSDimitry Andric "call here\n" 174568d75effSDimitry Andric "here:\n" 174668d75effSDimitry Andric "popl %%ebx\n" 174768d75effSDimitry Andric "addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n" 174868d75effSDimitry Andric # endif 174968d75effSDimitry Andric /* Call exit */ 175068d75effSDimitry Andric "movl %%eax, %%ebx\n" 175168d75effSDimitry Andric "movl %2, %%eax\n" 175268d75effSDimitry Andric "int $0x80\n" 175368d75effSDimitry Andric "1:\n" 175468d75effSDimitry Andric : "=a"(res) 17555f757f3fSDimitry Andric : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "c"(child_stack), 17565f757f3fSDimitry Andric "d"(parent_tidptr), "S"(newtls), "D"(child_tidptr) 175768d75effSDimitry Andric : "memory"); 175868d75effSDimitry Andric return res; 175968d75effSDimitry Andric } 17603781e779SPiotr Kubaj # elif defined(__arm__) 176168d75effSDimitry Andric uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, 176268d75effSDimitry Andric int *parent_tidptr, void *newtls, int *child_tidptr) { 176368d75effSDimitry Andric unsigned int res; 176468d75effSDimitry Andric if (!fn || !child_stack) 176568d75effSDimitry Andric return -EINVAL; 176668d75effSDimitry Andric child_stack = (char *)child_stack - 2 * sizeof(unsigned int); 176768d75effSDimitry Andric ((unsigned int *)child_stack)[0] = (uptr)fn; 176868d75effSDimitry Andric ((unsigned int *)child_stack)[1] = (uptr)arg; 176968d75effSDimitry Andric register int r0 __asm__("r0") = flags; 177068d75effSDimitry Andric register void *r1 __asm__("r1") = child_stack; 177168d75effSDimitry Andric register int *r2 __asm__("r2") = parent_tidptr; 177268d75effSDimitry Andric register void *r3 __asm__("r3") = newtls; 177368d75effSDimitry Andric register int *r4 __asm__("r4") = child_tidptr; 177468d75effSDimitry Andric register int r7 __asm__("r7") = __NR_clone; 177568d75effSDimitry Andric 177668d75effSDimitry Andric # if __ARM_ARCH > 4 || defined(__ARM_ARCH_4T__) 177768d75effSDimitry Andric # define ARCH_HAS_BX 177868d75effSDimitry Andric # endif 177968d75effSDimitry Andric # if __ARM_ARCH > 4 178068d75effSDimitry Andric # define ARCH_HAS_BLX 178168d75effSDimitry Andric # endif 178268d75effSDimitry Andric 178368d75effSDimitry Andric # ifdef ARCH_HAS_BX 178468d75effSDimitry Andric # ifdef ARCH_HAS_BLX 178568d75effSDimitry Andric # define BLX(R) "blx " #R "\n" 178668d75effSDimitry Andric # else 178768d75effSDimitry Andric # define BLX(R) "mov lr, pc; bx " #R "\n" 178868d75effSDimitry Andric # endif 178968d75effSDimitry Andric # else 179068d75effSDimitry Andric # define BLX(R) "mov lr, pc; mov pc," #R "\n" 179168d75effSDimitry Andric # endif 179268d75effSDimitry Andric 179368d75effSDimitry Andric __asm__ __volatile__( 179468d75effSDimitry Andric /* %r0 = syscall(%r7 = SYSCALL(clone), 179568d75effSDimitry Andric * %r0 = flags, 179668d75effSDimitry Andric * %r1 = child_stack, 179768d75effSDimitry Andric * %r2 = parent_tidptr, 179868d75effSDimitry Andric * %r3 = new_tls, 179968d75effSDimitry Andric * %r4 = child_tidptr) 180068d75effSDimitry Andric */ 180168d75effSDimitry Andric 180268d75effSDimitry Andric /* Do the system call */ 180368d75effSDimitry Andric "swi 0x0\n" 180468d75effSDimitry Andric 180568d75effSDimitry Andric /* if (%r0 != 0) 180668d75effSDimitry Andric * return %r0; 180768d75effSDimitry Andric */ 180868d75effSDimitry Andric "cmp r0, #0\n" 180968d75effSDimitry Andric "bne 1f\n" 181068d75effSDimitry Andric 181168d75effSDimitry Andric /* In the child, now. Call "fn(arg)". */ 181268d75effSDimitry Andric "ldr r0, [sp, #4]\n" 18135f757f3fSDimitry Andric "ldr ip, [sp], #8\n" BLX(ip) 181468d75effSDimitry Andric /* Call _exit(%r0). */ 181568d75effSDimitry Andric "mov r7, %7\n" 181668d75effSDimitry Andric "swi 0x0\n" 181768d75effSDimitry Andric "1:\n" 181868d75effSDimitry Andric "mov %0, r0\n" 181968d75effSDimitry Andric : "=r"(res) 18205f757f3fSDimitry Andric : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), "i"(__NR_exit) 182168d75effSDimitry Andric : "memory"); 182268d75effSDimitry Andric return res; 182368d75effSDimitry Andric } 18243781e779SPiotr Kubaj # endif 18253781e779SPiotr Kubaj # endif // SANITIZER_LINUX 182668d75effSDimitry Andric 18275ffd83dbSDimitry Andric # if SANITIZER_LINUX 18285ffd83dbSDimitry Andric int internal_uname(struct utsname *buf) { 18295ffd83dbSDimitry Andric return internal_syscall(SYSCALL(uname), buf); 18305ffd83dbSDimitry Andric } 18315ffd83dbSDimitry Andric # endif 18325ffd83dbSDimitry Andric 183368d75effSDimitry Andric # if SANITIZER_ANDROID 183468d75effSDimitry Andric # if __ANDROID_API__ < 21 183568d75effSDimitry Andric extern "C" __attribute__((weak)) int dl_iterate_phdr( 183668d75effSDimitry Andric int (*)(struct dl_phdr_info *, size_t, void *), void *); 183768d75effSDimitry Andric # endif 183868d75effSDimitry Andric 183968d75effSDimitry Andric static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, 184068d75effSDimitry Andric void *data) { 184168d75effSDimitry Andric // Any name starting with "lib" indicates a bug in L where library base names 184268d75effSDimitry Andric // are returned instead of paths. 184368d75effSDimitry Andric if (info->dlpi_name && info->dlpi_name[0] == 'l' && 184468d75effSDimitry Andric info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') { 184568d75effSDimitry Andric *(bool *)data = true; 184668d75effSDimitry Andric return 1; 184768d75effSDimitry Andric } 184868d75effSDimitry Andric return 0; 184968d75effSDimitry Andric } 185068d75effSDimitry Andric 185168d75effSDimitry Andric static atomic_uint32_t android_api_level; 185268d75effSDimitry Andric 185368d75effSDimitry Andric static AndroidApiLevel AndroidDetectApiLevelStatic() { 185468d75effSDimitry Andric # if __ANDROID_API__ <= 19 185568d75effSDimitry Andric return ANDROID_KITKAT; 185668d75effSDimitry Andric # elif __ANDROID_API__ <= 22 185768d75effSDimitry Andric return ANDROID_LOLLIPOP_MR1; 185868d75effSDimitry Andric # else 185968d75effSDimitry Andric return ANDROID_POST_LOLLIPOP; 186068d75effSDimitry Andric # endif 186168d75effSDimitry Andric } 186268d75effSDimitry Andric 186368d75effSDimitry Andric static AndroidApiLevel AndroidDetectApiLevel() { 186468d75effSDimitry Andric if (!&dl_iterate_phdr) 186568d75effSDimitry Andric return ANDROID_KITKAT; // K or lower 186668d75effSDimitry Andric bool base_name_seen = false; 186768d75effSDimitry Andric dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen); 186868d75effSDimitry Andric if (base_name_seen) 186968d75effSDimitry Andric return ANDROID_LOLLIPOP_MR1; // L MR1 187068d75effSDimitry Andric return ANDROID_POST_LOLLIPOP; // post-L 187168d75effSDimitry Andric // Plain L (API level 21) is completely broken wrt ASan and not very 187268d75effSDimitry Andric // interesting to detect. 187368d75effSDimitry Andric } 187468d75effSDimitry Andric 187568d75effSDimitry Andric extern "C" __attribute__((weak)) void *_DYNAMIC; 187668d75effSDimitry Andric 187768d75effSDimitry Andric AndroidApiLevel AndroidGetApiLevel() { 187868d75effSDimitry Andric AndroidApiLevel level = 187968d75effSDimitry Andric (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed); 18805f757f3fSDimitry Andric if (level) 18815f757f3fSDimitry Andric return level; 188268d75effSDimitry Andric level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic() 188368d75effSDimitry Andric : AndroidDetectApiLevel(); 188468d75effSDimitry Andric atomic_store(&android_api_level, level, memory_order_relaxed); 188568d75effSDimitry Andric return level; 188668d75effSDimitry Andric } 188768d75effSDimitry Andric 188868d75effSDimitry Andric # endif 188968d75effSDimitry Andric 189068d75effSDimitry Andric static HandleSignalMode GetHandleSignalModeImpl(int signum) { 189168d75effSDimitry Andric switch (signum) { 189268d75effSDimitry Andric case SIGABRT: 189368d75effSDimitry Andric return common_flags()->handle_abort; 189468d75effSDimitry Andric case SIGILL: 189568d75effSDimitry Andric return common_flags()->handle_sigill; 189668d75effSDimitry Andric case SIGTRAP: 189768d75effSDimitry Andric return common_flags()->handle_sigtrap; 189868d75effSDimitry Andric case SIGFPE: 189968d75effSDimitry Andric return common_flags()->handle_sigfpe; 190068d75effSDimitry Andric case SIGSEGV: 190168d75effSDimitry Andric return common_flags()->handle_segv; 190268d75effSDimitry Andric case SIGBUS: 190368d75effSDimitry Andric return common_flags()->handle_sigbus; 190468d75effSDimitry Andric } 190568d75effSDimitry Andric return kHandleSignalNo; 190668d75effSDimitry Andric } 190768d75effSDimitry Andric 190868d75effSDimitry Andric HandleSignalMode GetHandleSignalMode(int signum) { 190968d75effSDimitry Andric HandleSignalMode result = GetHandleSignalModeImpl(signum); 191068d75effSDimitry Andric if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) 191168d75effSDimitry Andric return kHandleSignalExclusive; 191268d75effSDimitry Andric return result; 191368d75effSDimitry Andric } 191468d75effSDimitry Andric 191568d75effSDimitry Andric # if !SANITIZER_GO 19165ffd83dbSDimitry Andric void *internal_start_thread(void *(*func)(void *arg), void *arg) { 19170fca6ea1SDimitry Andric if (&internal_pthread_create == 0) 19184824e7fdSDimitry Andric return nullptr; 191968d75effSDimitry Andric // Start the thread with signals blocked, otherwise it can steal user signals. 1920349cc55cSDimitry Andric ScopedBlockSignals block(nullptr); 192168d75effSDimitry Andric void *th; 19220fca6ea1SDimitry Andric internal_pthread_create(&th, nullptr, func, arg); 192368d75effSDimitry Andric return th; 192468d75effSDimitry Andric } 192568d75effSDimitry Andric 192668d75effSDimitry Andric void internal_join_thread(void *th) { 19270fca6ea1SDimitry Andric if (&internal_pthread_join) 19280fca6ea1SDimitry Andric internal_pthread_join(th, nullptr); 192968d75effSDimitry Andric } 193068d75effSDimitry Andric # else 19315ffd83dbSDimitry Andric void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } 193268d75effSDimitry Andric 193368d75effSDimitry Andric void internal_join_thread(void *th) {} 193468d75effSDimitry Andric # endif 193568d75effSDimitry Andric 193681ad6265SDimitry Andric # if SANITIZER_LINUX && defined(__aarch64__) 193768d75effSDimitry Andric // Android headers in the older NDK releases miss this definition. 193868d75effSDimitry Andric struct __sanitizer_esr_context { 193968d75effSDimitry Andric struct _aarch64_ctx head; 194068d75effSDimitry Andric uint64_t esr; 194168d75effSDimitry Andric }; 194268d75effSDimitry Andric 194368d75effSDimitry Andric static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { 194468d75effSDimitry Andric static const u32 kEsrMagic = 0x45535201; 1945349cc55cSDimitry Andric u8 *aux = reinterpret_cast<u8 *>(ucontext->uc_mcontext.__reserved); 194668d75effSDimitry Andric while (true) { 194768d75effSDimitry Andric _aarch64_ctx *ctx = (_aarch64_ctx *)aux; 19485f757f3fSDimitry Andric if (ctx->size == 0) 19495f757f3fSDimitry Andric break; 195068d75effSDimitry Andric if (ctx->magic == kEsrMagic) { 195168d75effSDimitry Andric *esr = ((__sanitizer_esr_context *)ctx)->esr; 195268d75effSDimitry Andric return true; 195368d75effSDimitry Andric } 195468d75effSDimitry Andric aux += ctx->size; 195568d75effSDimitry Andric } 195668d75effSDimitry Andric return false; 195768d75effSDimitry Andric } 195881ad6265SDimitry Andric # elif SANITIZER_FREEBSD && defined(__aarch64__) 195981ad6265SDimitry Andric // FreeBSD doesn't provide ESR in the ucontext. 19605f757f3fSDimitry Andric static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { return false; } 196168d75effSDimitry Andric # endif 196268d75effSDimitry Andric 196368d75effSDimitry Andric using Context = ucontext_t; 196468d75effSDimitry Andric 196568d75effSDimitry Andric SignalContext::WriteFlag SignalContext::GetWriteFlag() const { 196668d75effSDimitry Andric Context *ucontext = (Context *)context; 196768d75effSDimitry Andric # if defined(__x86_64__) || defined(__i386__) 196868d75effSDimitry Andric static const uptr PF_WRITE = 1U << 1; 196968d75effSDimitry Andric # if SANITIZER_FREEBSD 197068d75effSDimitry Andric uptr err = ucontext->uc_mcontext.mc_err; 197168d75effSDimitry Andric # elif SANITIZER_NETBSD 197268d75effSDimitry Andric uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; 197368d75effSDimitry Andric # elif SANITIZER_SOLARIS && defined(__i386__) 197468d75effSDimitry Andric const int Err = 13; 197568d75effSDimitry Andric uptr err = ucontext->uc_mcontext.gregs[Err]; 197668d75effSDimitry Andric # else 197768d75effSDimitry Andric uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; 197868d75effSDimitry Andric # endif // SANITIZER_FREEBSD 1979d56accc7SDimitry Andric return err & PF_WRITE ? Write : Read; 198068d75effSDimitry Andric # elif defined(__mips__) 198168d75effSDimitry Andric uint32_t *exception_source; 198268d75effSDimitry Andric uint32_t faulty_instruction; 198368d75effSDimitry Andric uint32_t op_code; 198468d75effSDimitry Andric 198568d75effSDimitry Andric exception_source = (uint32_t *)ucontext->uc_mcontext.pc; 198668d75effSDimitry Andric faulty_instruction = (uint32_t)(*exception_source); 198768d75effSDimitry Andric 198868d75effSDimitry Andric op_code = (faulty_instruction >> 26) & 0x3f; 198968d75effSDimitry Andric 199068d75effSDimitry Andric // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. 199168d75effSDimitry Andric switch (op_code) { 199268d75effSDimitry Andric case 0x28: // sb 199368d75effSDimitry Andric case 0x29: // sh 199468d75effSDimitry Andric case 0x2b: // sw 199568d75effSDimitry Andric case 0x3f: // sd 199668d75effSDimitry Andric # if __mips_isa_rev < 6 199768d75effSDimitry Andric case 0x2c: // sdl 199868d75effSDimitry Andric case 0x2d: // sdr 199968d75effSDimitry Andric case 0x2a: // swl 200068d75effSDimitry Andric case 0x2e: // swr 200168d75effSDimitry Andric # endif 2002d56accc7SDimitry Andric return SignalContext::Write; 200368d75effSDimitry Andric 200468d75effSDimitry Andric case 0x20: // lb 200568d75effSDimitry Andric case 0x24: // lbu 200668d75effSDimitry Andric case 0x21: // lh 200768d75effSDimitry Andric case 0x25: // lhu 200868d75effSDimitry Andric case 0x23: // lw 200968d75effSDimitry Andric case 0x27: // lwu 201068d75effSDimitry Andric case 0x37: // ld 201168d75effSDimitry Andric # if __mips_isa_rev < 6 201268d75effSDimitry Andric case 0x1a: // ldl 201368d75effSDimitry Andric case 0x1b: // ldr 201468d75effSDimitry Andric case 0x22: // lwl 201568d75effSDimitry Andric case 0x26: // lwr 201668d75effSDimitry Andric # endif 2017d56accc7SDimitry Andric return SignalContext::Read; 201868d75effSDimitry Andric # if __mips_isa_rev == 6 201968d75effSDimitry Andric case 0x3b: // pcrel 202068d75effSDimitry Andric op_code = (faulty_instruction >> 19) & 0x3; 202168d75effSDimitry Andric switch (op_code) { 202268d75effSDimitry Andric case 0x1: // lwpc 202368d75effSDimitry Andric case 0x2: // lwupc 2024d56accc7SDimitry Andric return SignalContext::Read; 202568d75effSDimitry Andric } 202668d75effSDimitry Andric # endif 202768d75effSDimitry Andric } 2028d56accc7SDimitry Andric return SignalContext::Unknown; 202968d75effSDimitry Andric # elif defined(__arm__) 203068d75effSDimitry Andric static const uptr FSR_WRITE = 1U << 11; 203168d75effSDimitry Andric uptr fsr = ucontext->uc_mcontext.error_code; 2032d56accc7SDimitry Andric return fsr & FSR_WRITE ? Write : Read; 203368d75effSDimitry Andric # elif defined(__aarch64__) 203468d75effSDimitry Andric static const u64 ESR_ELx_WNR = 1U << 6; 203568d75effSDimitry Andric u64 esr; 20365f757f3fSDimitry Andric if (!Aarch64GetESR(ucontext, &esr)) 20375f757f3fSDimitry Andric return Unknown; 2038d56accc7SDimitry Andric return esr & ESR_ELx_WNR ? Write : Read; 2039bdd1243dSDimitry Andric # elif defined(__loongarch__) 20406e516c87SDimitry Andric // In the musl environment, the Linux kernel uapi sigcontext.h is not 20416e516c87SDimitry Andric // included in signal.h. To avoid missing the SC_ADDRERR_{RD,WR} macros, 20426e516c87SDimitry Andric // copy them here. The LoongArch Linux kernel uapi is already stable, 20436e516c87SDimitry Andric // so there's no need to worry about the value changing. 20446e516c87SDimitry Andric # ifndef SC_ADDRERR_RD 20456e516c87SDimitry Andric // Address error was due to memory load 20466e516c87SDimitry Andric # define SC_ADDRERR_RD (1 << 30) 20476e516c87SDimitry Andric # endif 20486e516c87SDimitry Andric # ifndef SC_ADDRERR_WR 20496e516c87SDimitry Andric // Address error was due to memory store 20506e516c87SDimitry Andric # define SC_ADDRERR_WR (1 << 31) 20516e516c87SDimitry Andric # endif 2052bdd1243dSDimitry Andric u32 flags = ucontext->uc_mcontext.__flags; 2053bdd1243dSDimitry Andric if (flags & SC_ADDRERR_RD) 2054bdd1243dSDimitry Andric return SignalContext::Read; 2055bdd1243dSDimitry Andric if (flags & SC_ADDRERR_WR) 2056bdd1243dSDimitry Andric return SignalContext::Write; 2057bdd1243dSDimitry Andric return SignalContext::Unknown; 205868d75effSDimitry Andric # elif defined(__sparc__) 205968d75effSDimitry Andric // Decode the instruction to determine the access type. 206068d75effSDimitry Andric // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype). 206168d75effSDimitry Andric # if SANITIZER_SOLARIS 206268d75effSDimitry Andric uptr pc = ucontext->uc_mcontext.gregs[REG_PC]; 206368d75effSDimitry Andric # else 206468d75effSDimitry Andric // Historical BSDism here. 206568d75effSDimitry Andric struct sigcontext *scontext = (struct sigcontext *)context; 206668d75effSDimitry Andric # if defined(__arch64__) 206768d75effSDimitry Andric uptr pc = scontext->sigc_regs.tpc; 206868d75effSDimitry Andric # else 206968d75effSDimitry Andric uptr pc = scontext->si_regs.pc; 207068d75effSDimitry Andric # endif 207168d75effSDimitry Andric # endif 207268d75effSDimitry Andric u32 instr = *(u32 *)pc; 2073d56accc7SDimitry Andric return (instr >> 21) & 1 ? Write : Read; 20745ffd83dbSDimitry Andric # elif defined(__riscv) 20753781e779SPiotr Kubaj # if SANITIZER_FREEBSD 20763781e779SPiotr Kubaj unsigned long pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc; 20773781e779SPiotr Kubaj # else 20785ffd83dbSDimitry Andric unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC]; 20793781e779SPiotr Kubaj # endif 20805ffd83dbSDimitry Andric unsigned faulty_instruction = *(uint16_t *)pc; 20815ffd83dbSDimitry Andric 20825ffd83dbSDimitry Andric # if defined(__riscv_compressed) 20835ffd83dbSDimitry Andric if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction 20845ffd83dbSDimitry Andric // set op_bits to the instruction bits [1, 0, 15, 14, 13] 20855ffd83dbSDimitry Andric unsigned op_bits = 20865ffd83dbSDimitry Andric ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13); 20875ffd83dbSDimitry Andric unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive 20885ffd83dbSDimitry Andric switch (op_bits) { 20895ffd83dbSDimitry Andric case 0b10'010: // c.lwsp (rd != x0) 20905ffd83dbSDimitry Andric # if __riscv_xlen == 64 20915ffd83dbSDimitry Andric case 0b10'011: // c.ldsp (rd != x0) 20925ffd83dbSDimitry Andric # endif 2093d56accc7SDimitry Andric return rd ? SignalContext::Read : SignalContext::Unknown; 20945ffd83dbSDimitry Andric case 0b00'010: // c.lw 20955ffd83dbSDimitry Andric # if __riscv_flen >= 32 && __riscv_xlen == 32 20965ffd83dbSDimitry Andric case 0b10'011: // c.flwsp 20975ffd83dbSDimitry Andric # endif 20985ffd83dbSDimitry Andric # if __riscv_flen >= 32 || __riscv_xlen == 64 20995ffd83dbSDimitry Andric case 0b00'011: // c.flw / c.ld 21005ffd83dbSDimitry Andric # endif 21015ffd83dbSDimitry Andric # if __riscv_flen == 64 21025ffd83dbSDimitry Andric case 0b00'001: // c.fld 21035ffd83dbSDimitry Andric case 0b10'001: // c.fldsp 21045ffd83dbSDimitry Andric # endif 2105d56accc7SDimitry Andric return SignalContext::Read; 21065ffd83dbSDimitry Andric case 0b00'110: // c.sw 21075ffd83dbSDimitry Andric case 0b10'110: // c.swsp 21085ffd83dbSDimitry Andric # if __riscv_flen >= 32 || __riscv_xlen == 64 21095ffd83dbSDimitry Andric case 0b00'111: // c.fsw / c.sd 21105ffd83dbSDimitry Andric case 0b10'111: // c.fswsp / c.sdsp 21115ffd83dbSDimitry Andric # endif 21125ffd83dbSDimitry Andric # if __riscv_flen == 64 21135ffd83dbSDimitry Andric case 0b00'101: // c.fsd 21145ffd83dbSDimitry Andric case 0b10'101: // c.fsdsp 21155ffd83dbSDimitry Andric # endif 2116d56accc7SDimitry Andric return SignalContext::Write; 21175ffd83dbSDimitry Andric default: 2118d56accc7SDimitry Andric return SignalContext::Unknown; 21195ffd83dbSDimitry Andric } 21205ffd83dbSDimitry Andric } 21215ffd83dbSDimitry Andric # endif 21225ffd83dbSDimitry Andric 21235ffd83dbSDimitry Andric unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits 21245ffd83dbSDimitry Andric unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive 21255ffd83dbSDimitry Andric switch (opcode) { 21265ffd83dbSDimitry Andric case 0b0000011: // loads 21275ffd83dbSDimitry Andric switch (funct3) { 21285ffd83dbSDimitry Andric case 0b000: // lb 21295ffd83dbSDimitry Andric case 0b001: // lh 21305ffd83dbSDimitry Andric case 0b010: // lw 21315ffd83dbSDimitry Andric # if __riscv_xlen == 64 21325ffd83dbSDimitry Andric case 0b011: // ld 21335ffd83dbSDimitry Andric # endif 21345ffd83dbSDimitry Andric case 0b100: // lbu 21355ffd83dbSDimitry Andric case 0b101: // lhu 2136d56accc7SDimitry Andric return SignalContext::Read; 21375ffd83dbSDimitry Andric default: 2138d56accc7SDimitry Andric return SignalContext::Unknown; 21395ffd83dbSDimitry Andric } 21405ffd83dbSDimitry Andric case 0b0100011: // stores 21415ffd83dbSDimitry Andric switch (funct3) { 21425ffd83dbSDimitry Andric case 0b000: // sb 21435ffd83dbSDimitry Andric case 0b001: // sh 21445ffd83dbSDimitry Andric case 0b010: // sw 21455ffd83dbSDimitry Andric # if __riscv_xlen == 64 21465ffd83dbSDimitry Andric case 0b011: // sd 21475ffd83dbSDimitry Andric # endif 2148d56accc7SDimitry Andric return SignalContext::Write; 21495ffd83dbSDimitry Andric default: 2150d56accc7SDimitry Andric return SignalContext::Unknown; 21515ffd83dbSDimitry Andric } 21525ffd83dbSDimitry Andric # if __riscv_flen >= 32 21535ffd83dbSDimitry Andric case 0b0000111: // floating-point loads 21545ffd83dbSDimitry Andric switch (funct3) { 21555ffd83dbSDimitry Andric case 0b010: // flw 21565ffd83dbSDimitry Andric # if __riscv_flen == 64 21575ffd83dbSDimitry Andric case 0b011: // fld 21585ffd83dbSDimitry Andric # endif 2159d56accc7SDimitry Andric return SignalContext::Read; 21605ffd83dbSDimitry Andric default: 2161d56accc7SDimitry Andric return SignalContext::Unknown; 21625ffd83dbSDimitry Andric } 21635ffd83dbSDimitry Andric case 0b0100111: // floating-point stores 21645ffd83dbSDimitry Andric switch (funct3) { 21655ffd83dbSDimitry Andric case 0b010: // fsw 21665ffd83dbSDimitry Andric # if __riscv_flen == 64 21675ffd83dbSDimitry Andric case 0b011: // fsd 21685ffd83dbSDimitry Andric # endif 2169d56accc7SDimitry Andric return SignalContext::Write; 21705ffd83dbSDimitry Andric default: 2171d56accc7SDimitry Andric return SignalContext::Unknown; 21725ffd83dbSDimitry Andric } 21735ffd83dbSDimitry Andric # endif 21745ffd83dbSDimitry Andric default: 2175d56accc7SDimitry Andric return SignalContext::Unknown; 21765ffd83dbSDimitry Andric } 217768d75effSDimitry Andric # else 217868d75effSDimitry Andric (void)ucontext; 2179d56accc7SDimitry Andric return Unknown; // FIXME: Implement. 218068d75effSDimitry Andric # endif 218168d75effSDimitry Andric } 218268d75effSDimitry Andric 218368d75effSDimitry Andric bool SignalContext::IsTrueFaultingAddress() const { 218468d75effSDimitry Andric auto si = static_cast<const siginfo_t *>(siginfo); 218568d75effSDimitry Andric // SIGSEGV signals without a true fault address have si_code set to 128. 218668d75effSDimitry Andric return si->si_signo == SIGSEGV && si->si_code != 128; 218768d75effSDimitry Andric } 218868d75effSDimitry Andric 21890fca6ea1SDimitry Andric UNUSED 21900fca6ea1SDimitry Andric static const char *RegNumToRegName(int reg) { 21910fca6ea1SDimitry Andric switch (reg) { 21920fca6ea1SDimitry Andric # if SANITIZER_LINUX 21930fca6ea1SDimitry Andric # if defined(__x86_64__) 21940fca6ea1SDimitry Andric case REG_RAX: 21950fca6ea1SDimitry Andric return "rax"; 21960fca6ea1SDimitry Andric case REG_RBX: 21970fca6ea1SDimitry Andric return "rbx"; 21980fca6ea1SDimitry Andric case REG_RCX: 21990fca6ea1SDimitry Andric return "rcx"; 22000fca6ea1SDimitry Andric case REG_RDX: 22010fca6ea1SDimitry Andric return "rdx"; 22020fca6ea1SDimitry Andric case REG_RDI: 22030fca6ea1SDimitry Andric return "rdi"; 22040fca6ea1SDimitry Andric case REG_RSI: 22050fca6ea1SDimitry Andric return "rsi"; 22060fca6ea1SDimitry Andric case REG_RBP: 22070fca6ea1SDimitry Andric return "rbp"; 22080fca6ea1SDimitry Andric case REG_RSP: 22090fca6ea1SDimitry Andric return "rsp"; 22100fca6ea1SDimitry Andric case REG_R8: 22110fca6ea1SDimitry Andric return "r8"; 22120fca6ea1SDimitry Andric case REG_R9: 22130fca6ea1SDimitry Andric return "r9"; 22140fca6ea1SDimitry Andric case REG_R10: 22150fca6ea1SDimitry Andric return "r10"; 22160fca6ea1SDimitry Andric case REG_R11: 22170fca6ea1SDimitry Andric return "r11"; 22180fca6ea1SDimitry Andric case REG_R12: 22190fca6ea1SDimitry Andric return "r12"; 22200fca6ea1SDimitry Andric case REG_R13: 22210fca6ea1SDimitry Andric return "r13"; 22220fca6ea1SDimitry Andric case REG_R14: 22230fca6ea1SDimitry Andric return "r14"; 22240fca6ea1SDimitry Andric case REG_R15: 22250fca6ea1SDimitry Andric return "r15"; 22260fca6ea1SDimitry Andric # elif defined(__i386__) 22270fca6ea1SDimitry Andric case REG_EAX: 22280fca6ea1SDimitry Andric return "eax"; 22290fca6ea1SDimitry Andric case REG_EBX: 22300fca6ea1SDimitry Andric return "ebx"; 22310fca6ea1SDimitry Andric case REG_ECX: 22320fca6ea1SDimitry Andric return "ecx"; 22330fca6ea1SDimitry Andric case REG_EDX: 22340fca6ea1SDimitry Andric return "edx"; 22350fca6ea1SDimitry Andric case REG_EDI: 22360fca6ea1SDimitry Andric return "edi"; 22370fca6ea1SDimitry Andric case REG_ESI: 22380fca6ea1SDimitry Andric return "esi"; 22390fca6ea1SDimitry Andric case REG_EBP: 22400fca6ea1SDimitry Andric return "ebp"; 22410fca6ea1SDimitry Andric case REG_ESP: 22420fca6ea1SDimitry Andric return "esp"; 22430fca6ea1SDimitry Andric # endif 22440fca6ea1SDimitry Andric # endif 22450fca6ea1SDimitry Andric default: 22460fca6ea1SDimitry Andric return NULL; 22470fca6ea1SDimitry Andric } 22480fca6ea1SDimitry Andric return NULL; 22490fca6ea1SDimitry Andric } 22500fca6ea1SDimitry Andric 22510fca6ea1SDimitry Andric # if SANITIZER_LINUX 22520fca6ea1SDimitry Andric UNUSED 22530fca6ea1SDimitry Andric static void DumpSingleReg(ucontext_t *ctx, int RegNum) { 22540fca6ea1SDimitry Andric const char *RegName = RegNumToRegName(RegNum); 22550fca6ea1SDimitry Andric # if defined(__x86_64__) 22560fca6ea1SDimitry Andric Printf("%s%s = 0x%016llx ", internal_strlen(RegName) == 2 ? " " : "", 22570fca6ea1SDimitry Andric RegName, ctx->uc_mcontext.gregs[RegNum]); 22580fca6ea1SDimitry Andric # elif defined(__i386__) 22590fca6ea1SDimitry Andric Printf("%s = 0x%08x ", RegName, ctx->uc_mcontext.gregs[RegNum]); 22600fca6ea1SDimitry Andric # else 22610fca6ea1SDimitry Andric (void)RegName; 22620fca6ea1SDimitry Andric # endif 22630fca6ea1SDimitry Andric } 22640fca6ea1SDimitry Andric # endif 22650fca6ea1SDimitry Andric 226668d75effSDimitry Andric void SignalContext::DumpAllRegisters(void *context) { 22670fca6ea1SDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 22680fca6ea1SDimitry Andric # if SANITIZER_LINUX 22690fca6ea1SDimitry Andric # if defined(__x86_64__) 22700fca6ea1SDimitry Andric Report("Register values:\n"); 22710fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RAX); 22720fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RBX); 22730fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RCX); 22740fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RDX); 22750fca6ea1SDimitry Andric Printf("\n"); 22760fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RDI); 22770fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RSI); 22780fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RBP); 22790fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_RSP); 22800fca6ea1SDimitry Andric Printf("\n"); 22810fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R8); 22820fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R9); 22830fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R10); 22840fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R11); 22850fca6ea1SDimitry Andric Printf("\n"); 22860fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R12); 22870fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R13); 22880fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R14); 22890fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_R15); 22900fca6ea1SDimitry Andric Printf("\n"); 22910fca6ea1SDimitry Andric # elif defined(__i386__) 22920fca6ea1SDimitry Andric // Duplication of this report print is caused by partial support 22930fca6ea1SDimitry Andric // of register values dumping. In case of unsupported yet architecture let's 22940fca6ea1SDimitry Andric // avoid printing 'Register values:' without actual values in the following 22950fca6ea1SDimitry Andric // output. 22960fca6ea1SDimitry Andric Report("Register values:\n"); 22970fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_EAX); 22980fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_EBX); 22990fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_ECX); 23000fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_EDX); 23010fca6ea1SDimitry Andric Printf("\n"); 23020fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_EDI); 23030fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_ESI); 23040fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_EBP); 23050fca6ea1SDimitry Andric DumpSingleReg(ucontext, REG_ESP); 23060fca6ea1SDimitry Andric Printf("\n"); 23070fca6ea1SDimitry Andric # else 23080fca6ea1SDimitry Andric (void)ucontext; 23090fca6ea1SDimitry Andric # endif 23100fca6ea1SDimitry Andric # elif SANITIZER_FREEBSD 23110fca6ea1SDimitry Andric # if defined(__x86_64__) 23120fca6ea1SDimitry Andric Report("Register values:\n"); 23130fca6ea1SDimitry Andric Printf("rax = 0x%016lx ", ucontext->uc_mcontext.mc_rax); 23140fca6ea1SDimitry Andric Printf("rbx = 0x%016lx ", ucontext->uc_mcontext.mc_rbx); 23150fca6ea1SDimitry Andric Printf("rcx = 0x%016lx ", ucontext->uc_mcontext.mc_rcx); 23160fca6ea1SDimitry Andric Printf("rdx = 0x%016lx ", ucontext->uc_mcontext.mc_rdx); 23170fca6ea1SDimitry Andric Printf("\n"); 23180fca6ea1SDimitry Andric Printf("rdi = 0x%016lx ", ucontext->uc_mcontext.mc_rdi); 23190fca6ea1SDimitry Andric Printf("rsi = 0x%016lx ", ucontext->uc_mcontext.mc_rsi); 23200fca6ea1SDimitry Andric Printf("rbp = 0x%016lx ", ucontext->uc_mcontext.mc_rbp); 23210fca6ea1SDimitry Andric Printf("rsp = 0x%016lx ", ucontext->uc_mcontext.mc_rsp); 23220fca6ea1SDimitry Andric Printf("\n"); 23230fca6ea1SDimitry Andric Printf(" r8 = 0x%016lx ", ucontext->uc_mcontext.mc_r8); 23240fca6ea1SDimitry Andric Printf(" r9 = 0x%016lx ", ucontext->uc_mcontext.mc_r9); 23250fca6ea1SDimitry Andric Printf("r10 = 0x%016lx ", ucontext->uc_mcontext.mc_r10); 23260fca6ea1SDimitry Andric Printf("r11 = 0x%016lx ", ucontext->uc_mcontext.mc_r11); 23270fca6ea1SDimitry Andric Printf("\n"); 23280fca6ea1SDimitry Andric Printf("r12 = 0x%016lx ", ucontext->uc_mcontext.mc_r12); 23290fca6ea1SDimitry Andric Printf("r13 = 0x%016lx ", ucontext->uc_mcontext.mc_r13); 23300fca6ea1SDimitry Andric Printf("r14 = 0x%016lx ", ucontext->uc_mcontext.mc_r14); 23310fca6ea1SDimitry Andric Printf("r15 = 0x%016lx ", ucontext->uc_mcontext.mc_r15); 23320fca6ea1SDimitry Andric Printf("\n"); 23330fca6ea1SDimitry Andric # elif defined(__i386__) 23340fca6ea1SDimitry Andric Report("Register values:\n"); 23350fca6ea1SDimitry Andric Printf("eax = 0x%08x ", ucontext->uc_mcontext.mc_eax); 23360fca6ea1SDimitry Andric Printf("ebx = 0x%08x ", ucontext->uc_mcontext.mc_ebx); 23370fca6ea1SDimitry Andric Printf("ecx = 0x%08x ", ucontext->uc_mcontext.mc_ecx); 23380fca6ea1SDimitry Andric Printf("edx = 0x%08x ", ucontext->uc_mcontext.mc_edx); 23390fca6ea1SDimitry Andric Printf("\n"); 23400fca6ea1SDimitry Andric Printf("edi = 0x%08x ", ucontext->uc_mcontext.mc_edi); 23410fca6ea1SDimitry Andric Printf("esi = 0x%08x ", ucontext->uc_mcontext.mc_esi); 23420fca6ea1SDimitry Andric Printf("ebp = 0x%08x ", ucontext->uc_mcontext.mc_ebp); 23430fca6ea1SDimitry Andric Printf("esp = 0x%08x ", ucontext->uc_mcontext.mc_esp); 23440fca6ea1SDimitry Andric Printf("\n"); 23450fca6ea1SDimitry Andric # else 23460fca6ea1SDimitry Andric (void)ucontext; 23470fca6ea1SDimitry Andric # endif 23480fca6ea1SDimitry Andric # endif 23490fca6ea1SDimitry Andric // FIXME: Implement this for other OSes and architectures. 235068d75effSDimitry Andric } 235168d75effSDimitry Andric 235268d75effSDimitry Andric static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { 235368d75effSDimitry Andric # if SANITIZER_NETBSD 235468d75effSDimitry Andric // This covers all NetBSD architectures 235568d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 235668d75effSDimitry Andric *pc = _UC_MACHINE_PC(ucontext); 235768d75effSDimitry Andric *bp = _UC_MACHINE_FP(ucontext); 235868d75effSDimitry Andric *sp = _UC_MACHINE_SP(ucontext); 235968d75effSDimitry Andric # elif defined(__arm__) 236068d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 236168d75effSDimitry Andric *pc = ucontext->uc_mcontext.arm_pc; 236268d75effSDimitry Andric *bp = ucontext->uc_mcontext.arm_fp; 236368d75effSDimitry Andric *sp = ucontext->uc_mcontext.arm_sp; 236468d75effSDimitry Andric # elif defined(__aarch64__) 236581ad6265SDimitry Andric # if SANITIZER_FREEBSD 236681ad6265SDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 236781ad6265SDimitry Andric *pc = ucontext->uc_mcontext.mc_gpregs.gp_elr; 236881ad6265SDimitry Andric *bp = ucontext->uc_mcontext.mc_gpregs.gp_x[29]; 236981ad6265SDimitry Andric *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp; 237081ad6265SDimitry Andric # else 237168d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 237268d75effSDimitry Andric *pc = ucontext->uc_mcontext.pc; 237368d75effSDimitry Andric *bp = ucontext->uc_mcontext.regs[29]; 237468d75effSDimitry Andric *sp = ucontext->uc_mcontext.sp; 237581ad6265SDimitry Andric # endif 237668d75effSDimitry Andric # elif defined(__hppa__) 237768d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 237868d75effSDimitry Andric *pc = ucontext->uc_mcontext.sc_iaoq[0]; 237968d75effSDimitry Andric /* GCC uses %r3 whenever a frame pointer is needed. */ 238068d75effSDimitry Andric *bp = ucontext->uc_mcontext.sc_gr[3]; 238168d75effSDimitry Andric *sp = ucontext->uc_mcontext.sc_gr[30]; 238268d75effSDimitry Andric # elif defined(__x86_64__) 238368d75effSDimitry Andric # if SANITIZER_FREEBSD 238468d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 238568d75effSDimitry Andric *pc = ucontext->uc_mcontext.mc_rip; 238668d75effSDimitry Andric *bp = ucontext->uc_mcontext.mc_rbp; 238768d75effSDimitry Andric *sp = ucontext->uc_mcontext.mc_rsp; 238868d75effSDimitry Andric # else 238968d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 239068d75effSDimitry Andric *pc = ucontext->uc_mcontext.gregs[REG_RIP]; 239168d75effSDimitry Andric *bp = ucontext->uc_mcontext.gregs[REG_RBP]; 239268d75effSDimitry Andric *sp = ucontext->uc_mcontext.gregs[REG_RSP]; 239368d75effSDimitry Andric # endif 239468d75effSDimitry Andric # elif defined(__i386__) 239568d75effSDimitry Andric # if SANITIZER_FREEBSD 239668d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 239768d75effSDimitry Andric *pc = ucontext->uc_mcontext.mc_eip; 239868d75effSDimitry Andric *bp = ucontext->uc_mcontext.mc_ebp; 239968d75effSDimitry Andric *sp = ucontext->uc_mcontext.mc_esp; 240068d75effSDimitry Andric # else 240168d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 240268d75effSDimitry Andric # if SANITIZER_SOLARIS 240368d75effSDimitry Andric /* Use the numeric values: the symbolic ones are undefined by llvm 240468d75effSDimitry Andric include/llvm/Support/Solaris.h. */ 240568d75effSDimitry Andric # ifndef REG_EIP 240668d75effSDimitry Andric # define REG_EIP 14 // REG_PC 240768d75effSDimitry Andric # endif 240868d75effSDimitry Andric # ifndef REG_EBP 240968d75effSDimitry Andric # define REG_EBP 6 // REG_FP 241068d75effSDimitry Andric # endif 24115ffd83dbSDimitry Andric # ifndef REG_UESP 24125ffd83dbSDimitry Andric # define REG_UESP 17 // REG_SP 241368d75effSDimitry Andric # endif 241468d75effSDimitry Andric # endif 241568d75effSDimitry Andric *pc = ucontext->uc_mcontext.gregs[REG_EIP]; 241668d75effSDimitry Andric *bp = ucontext->uc_mcontext.gregs[REG_EBP]; 24175ffd83dbSDimitry Andric *sp = ucontext->uc_mcontext.gregs[REG_UESP]; 241868d75effSDimitry Andric # endif 241968d75effSDimitry Andric # elif defined(__powerpc__) || defined(__powerpc64__) 2420f5024381SPiotr Kubaj # if SANITIZER_FREEBSD 2421f5024381SPiotr Kubaj ucontext_t *ucontext = (ucontext_t *)context; 2422f5024381SPiotr Kubaj *pc = ucontext->uc_mcontext.mc_srr0; 2423f5024381SPiotr Kubaj *sp = ucontext->uc_mcontext.mc_frame[1]; 2424f5024381SPiotr Kubaj *bp = ucontext->uc_mcontext.mc_frame[31]; 2425f5024381SPiotr Kubaj # else 242668d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 242768d75effSDimitry Andric *pc = ucontext->uc_mcontext.regs->nip; 242868d75effSDimitry Andric *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; 242968d75effSDimitry Andric // The powerpc{,64}-linux ABIs do not specify r31 as the frame 243068d75effSDimitry Andric // pointer, but GCC always uses r31 when we need a frame pointer. 243168d75effSDimitry Andric *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; 2432f5024381SPiotr Kubaj # endif 243368d75effSDimitry Andric # elif defined(__sparc__) 243468d75effSDimitry Andric # if defined(__arch64__) || defined(__sparcv9) 243568d75effSDimitry Andric # define STACK_BIAS 2047 243668d75effSDimitry Andric # else 243768d75effSDimitry Andric # define STACK_BIAS 0 243868d75effSDimitry Andric # endif 243968d75effSDimitry Andric # if SANITIZER_SOLARIS 244068d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 244168d75effSDimitry Andric *pc = ucontext->uc_mcontext.gregs[REG_PC]; 244268d75effSDimitry Andric *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS; 244368d75effSDimitry Andric # else 244468d75effSDimitry Andric // Historical BSDism here. 244568d75effSDimitry Andric struct sigcontext *scontext = (struct sigcontext *)context; 244668d75effSDimitry Andric # if defined(__arch64__) 244768d75effSDimitry Andric *pc = scontext->sigc_regs.tpc; 244868d75effSDimitry Andric *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS; 244968d75effSDimitry Andric # else 245068d75effSDimitry Andric *pc = scontext->si_regs.pc; 245168d75effSDimitry Andric *sp = scontext->si_regs.u_regs[14]; 245268d75effSDimitry Andric # endif 245368d75effSDimitry Andric # endif 245468d75effSDimitry Andric *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS; 245568d75effSDimitry Andric # elif defined(__mips__) 245668d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 245768d75effSDimitry Andric *pc = ucontext->uc_mcontext.pc; 245868d75effSDimitry Andric *bp = ucontext->uc_mcontext.gregs[30]; 245968d75effSDimitry Andric *sp = ucontext->uc_mcontext.gregs[29]; 246068d75effSDimitry Andric # elif defined(__s390__) 246168d75effSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 246268d75effSDimitry Andric # if defined(__s390x__) 246368d75effSDimitry Andric *pc = ucontext->uc_mcontext.psw.addr; 246468d75effSDimitry Andric # else 246568d75effSDimitry Andric *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff; 246668d75effSDimitry Andric # endif 246768d75effSDimitry Andric *bp = ucontext->uc_mcontext.gregs[11]; 246868d75effSDimitry Andric *sp = ucontext->uc_mcontext.gregs[15]; 2469480093f4SDimitry Andric # elif defined(__riscv) 2470480093f4SDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 24713781e779SPiotr Kubaj # if SANITIZER_FREEBSD 24723781e779SPiotr Kubaj *pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc; 24733781e779SPiotr Kubaj *bp = ucontext->uc_mcontext.mc_gpregs.gp_s[0]; 24743781e779SPiotr Kubaj *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp; 24753781e779SPiotr Kubaj # else 2476480093f4SDimitry Andric *pc = ucontext->uc_mcontext.__gregs[REG_PC]; 2477480093f4SDimitry Andric *bp = ucontext->uc_mcontext.__gregs[REG_S0]; 2478480093f4SDimitry Andric *sp = ucontext->uc_mcontext.__gregs[REG_SP]; 24793781e779SPiotr Kubaj # endif 2480349cc55cSDimitry Andric # elif defined(__hexagon__) 2481349cc55cSDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 2482349cc55cSDimitry Andric *pc = ucontext->uc_mcontext.pc; 2483349cc55cSDimitry Andric *bp = ucontext->uc_mcontext.r30; 2484349cc55cSDimitry Andric *sp = ucontext->uc_mcontext.r29; 2485fcaf7f86SDimitry Andric # elif defined(__loongarch__) 2486fcaf7f86SDimitry Andric ucontext_t *ucontext = (ucontext_t *)context; 2487fcaf7f86SDimitry Andric *pc = ucontext->uc_mcontext.__pc; 2488fcaf7f86SDimitry Andric *bp = ucontext->uc_mcontext.__gregs[22]; 2489fcaf7f86SDimitry Andric *sp = ucontext->uc_mcontext.__gregs[3]; 249068d75effSDimitry Andric # else 249168d75effSDimitry Andric # error "Unsupported arch" 249268d75effSDimitry Andric # endif 249368d75effSDimitry Andric } 249468d75effSDimitry Andric 249568d75effSDimitry Andric void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } 249668d75effSDimitry Andric 249768d75effSDimitry Andric void InitializePlatformEarly() { 249868d75effSDimitry Andric // Do nothing. 249968d75effSDimitry Andric } 250068d75effSDimitry Andric 250168d75effSDimitry Andric void CheckASLR() { 250268d75effSDimitry Andric # if SANITIZER_NETBSD 250368d75effSDimitry Andric int mib[3]; 250468d75effSDimitry Andric int paxflags; 250568d75effSDimitry Andric uptr len = sizeof(paxflags); 250668d75effSDimitry Andric 250768d75effSDimitry Andric mib[0] = CTL_PROC; 250868d75effSDimitry Andric mib[1] = internal_getpid(); 250968d75effSDimitry Andric mib[2] = PROC_PID_PAXFLAGS; 251068d75effSDimitry Andric 251168d75effSDimitry Andric if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { 251268d75effSDimitry Andric Printf("sysctl failed\n"); 251368d75effSDimitry Andric Die(); 251468d75effSDimitry Andric } 251568d75effSDimitry Andric 251668d75effSDimitry Andric if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { 25175f757f3fSDimitry Andric Printf( 25185f757f3fSDimitry Andric "This sanitizer is not compatible with enabled ASLR.\n" 25195ffd83dbSDimitry Andric "To disable ASLR, please run \"paxctl +a %s\" and try again.\n", 25205ffd83dbSDimitry Andric GetArgv()[0]); 252168d75effSDimitry Andric Die(); 252268d75effSDimitry Andric } 252368d75effSDimitry Andric # elif SANITIZER_FREEBSD 25247cafe89fSEd Maste int aslr_status; 252581ad6265SDimitry Andric int r = internal_procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status); 252681ad6265SDimitry Andric if (UNLIKELY(r == -1)) { 252768d75effSDimitry Andric // We're making things less 'dramatic' here since 25287cafe89fSEd Maste // the cmd is not necessarily guaranteed to be here 252968d75effSDimitry Andric // just yet regarding FreeBSD release 253068d75effSDimitry Andric return; 253168d75effSDimitry Andric } 25327cafe89fSEd Maste if ((aslr_status & PROC_ASLR_ACTIVE) != 0) { 25335f757f3fSDimitry Andric VReport(1, 25345f757f3fSDimitry Andric "This sanitizer is not compatible with enabled ASLR " 2535930a7c2aSEd Maste "and binaries compiled with PIE\n" 2536930a7c2aSEd Maste "ASLR will be disabled and the program re-executed.\n"); 2537930a7c2aSEd Maste int aslr_ctl = PROC_ASLR_FORCE_DISABLE; 25384c9a0adaSDimitry Andric CHECK_NE(internal_procctl(P_PID, 0, PROC_ASLR_CTL, &aslr_ctl), -1); 2539930a7c2aSEd Maste ReExec(); 254068d75effSDimitry Andric } 2541f5024381SPiotr Kubaj # elif SANITIZER_PPC64V2 2542f5024381SPiotr Kubaj // Disable ASLR for Linux PPC64LE. 2543f5024381SPiotr Kubaj int old_personality = personality(0xffffffff); 2544f5024381SPiotr Kubaj if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) { 2545f5024381SPiotr Kubaj VReport(1, 2546f5024381SPiotr Kubaj "WARNING: Program is being run with address space layout " 2547f5024381SPiotr Kubaj "randomization (ASLR) enabled which prevents the thread and " 2548f5024381SPiotr Kubaj "memory sanitizers from working on powerpc64le.\n" 2549f5024381SPiotr Kubaj "ASLR will be disabled and the program re-executed.\n"); 2550f5024381SPiotr Kubaj CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); 2551f5024381SPiotr Kubaj ReExec(); 2552f5024381SPiotr Kubaj } 255368d75effSDimitry Andric # else 255468d75effSDimitry Andric // Do nothing 255568d75effSDimitry Andric # endif 255668d75effSDimitry Andric } 255768d75effSDimitry Andric 255868d75effSDimitry Andric void CheckMPROTECT() { 255968d75effSDimitry Andric # if SANITIZER_NETBSD 256068d75effSDimitry Andric int mib[3]; 256168d75effSDimitry Andric int paxflags; 256268d75effSDimitry Andric uptr len = sizeof(paxflags); 256368d75effSDimitry Andric 256468d75effSDimitry Andric mib[0] = CTL_PROC; 256568d75effSDimitry Andric mib[1] = internal_getpid(); 256668d75effSDimitry Andric mib[2] = PROC_PID_PAXFLAGS; 256768d75effSDimitry Andric 256868d75effSDimitry Andric if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { 256968d75effSDimitry Andric Printf("sysctl failed\n"); 257068d75effSDimitry Andric Die(); 257168d75effSDimitry Andric } 257268d75effSDimitry Andric 257368d75effSDimitry Andric if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) { 257468d75effSDimitry Andric Printf("This sanitizer is not compatible with enabled MPROTECT\n"); 257568d75effSDimitry Andric Die(); 257668d75effSDimitry Andric } 257768d75effSDimitry Andric # else 257868d75effSDimitry Andric // Do nothing 257968d75effSDimitry Andric # endif 258068d75effSDimitry Andric } 258168d75effSDimitry Andric 258268d75effSDimitry Andric void CheckNoDeepBind(const char *filename, int flag) { 258368d75effSDimitry Andric # ifdef RTLD_DEEPBIND 258468d75effSDimitry Andric if (flag & RTLD_DEEPBIND) { 258568d75effSDimitry Andric Report( 258668d75effSDimitry Andric "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag" 25875ffd83dbSDimitry Andric " which is incompatible with sanitizer runtime " 258868d75effSDimitry Andric "(see https://github.com/google/sanitizers/issues/611 for details" 258968d75effSDimitry Andric "). If you want to run %s library under sanitizers please remove " 259068d75effSDimitry Andric "RTLD_DEEPBIND from dlopen flags.\n", 259168d75effSDimitry Andric filename, filename); 259268d75effSDimitry Andric Die(); 259368d75effSDimitry Andric } 259468d75effSDimitry Andric # endif 259568d75effSDimitry Andric } 259668d75effSDimitry Andric 259768d75effSDimitry Andric uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, 259868d75effSDimitry Andric uptr *largest_gap_found, 259968d75effSDimitry Andric uptr *max_occupied_addr) { 260068d75effSDimitry Andric UNREACHABLE("FindAvailableMemoryRange is not available"); 260168d75effSDimitry Andric return 0; 260268d75effSDimitry Andric } 260368d75effSDimitry Andric 260468d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) { 260568d75effSDimitry Andric if (!buffer || !length || length > 256) 260668d75effSDimitry Andric return false; 260768d75effSDimitry Andric # if SANITIZER_USE_GETENTROPY 260868d75effSDimitry Andric uptr rnd = getentropy(buffer, length); 260968d75effSDimitry Andric int rverrno = 0; 261068d75effSDimitry Andric if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) 261168d75effSDimitry Andric return false; 261268d75effSDimitry Andric else if (rnd == 0) 261368d75effSDimitry Andric return true; 261468d75effSDimitry Andric # endif // SANITIZER_USE_GETENTROPY 261568d75effSDimitry Andric 261668d75effSDimitry Andric # if SANITIZER_USE_GETRANDOM 261768d75effSDimitry Andric static atomic_uint8_t skip_getrandom_syscall; 261868d75effSDimitry Andric if (!atomic_load_relaxed(&skip_getrandom_syscall)) { 261968d75effSDimitry Andric // Up to 256 bytes, getrandom will not be interrupted. 262068d75effSDimitry Andric uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, 262168d75effSDimitry Andric blocking ? 0 : GRND_NONBLOCK); 262268d75effSDimitry Andric int rverrno = 0; 262368d75effSDimitry Andric if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) 262468d75effSDimitry Andric atomic_store_relaxed(&skip_getrandom_syscall, 1); 262568d75effSDimitry Andric else if (res == length) 262668d75effSDimitry Andric return true; 262768d75effSDimitry Andric } 262868d75effSDimitry Andric # endif // SANITIZER_USE_GETRANDOM 262968d75effSDimitry Andric // Up to 256 bytes, a read off /dev/urandom will not be interrupted. 263068d75effSDimitry Andric // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. 263168d75effSDimitry Andric uptr fd = internal_open("/dev/urandom", O_RDONLY); 263268d75effSDimitry Andric if (internal_iserror(fd)) 263368d75effSDimitry Andric return false; 263468d75effSDimitry Andric uptr res = internal_read(fd, buffer, length); 263568d75effSDimitry Andric if (internal_iserror(res)) 263668d75effSDimitry Andric return false; 263768d75effSDimitry Andric internal_close(fd); 263868d75effSDimitry Andric return true; 263968d75effSDimitry Andric } 264068d75effSDimitry Andric 264168d75effSDimitry Andric } // namespace __sanitizer 264268d75effSDimitry Andric 264368d75effSDimitry Andric #endif 2644