#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
# include "sanitizer_common.h"
# include "sanitizer_flags.h"
# include "sanitizer_getauxval.h"
# include "sanitizer_internal_defs.h"
# include "sanitizer_libc.h"
# include "sanitizer_linux.h"
# include "sanitizer_mutex.h"
# include "sanitizer_placement_new.h"
# include "sanitizer_procmaps.h"
# if SANITIZER_LINUX && !SANITIZER_GO
# include <asm/param.h>
# endif
# if SANITIZER_LINUX && (SANITIZER_MIPS64 || SANITIZER_SPARC64)
# include <asm/unistd.h>
# include <sys/types.h>
#define stat …
# if SANITIZER_SPARC64
#define stat64 …
# endif
# if SANITIZER_GO
# undef st_atime
# undef st_mtime
# undef st_ctime
#define st_atime …
#define st_mtime …
#define st_ctime …
# endif
# include <asm/stat.h>
# undef stat
# undef stat64
# endif
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <link.h>
# include <pthread.h>
# include <sched.h>
# include <signal.h>
# include <sys/mman.h>
# if !SANITIZER_SOLARIS
# include <sys/ptrace.h>
# endif
# include <sys/resource.h>
# include <sys/stat.h>
# include <sys/syscall.h>
# include <sys/time.h>
# include <sys/types.h>
# include <ucontext.h>
# include <unistd.h>
# if SANITIZER_LINUX
# include <sys/utsname.h>
# endif
# if SANITIZER_LINUX && !SANITIZER_ANDROID
# include <sys/personality.h>
# endif
# if SANITIZER_LINUX && defined(__loongarch__)
# include <sys/sysmacros.h>
# endif
# if SANITIZER_FREEBSD
# include <machine/atomic.h>
# include <sys/exec.h>
# include <sys/procctl.h>
# include <sys/sysctl.h>
extern "C" {
# include <sys/umtx.h>
}
# include <sys/thr.h>
# endif
# if SANITIZER_NETBSD
# include <limits.h>
# include <sys/exec.h>
# include <sys/sysctl.h>
extern struct ps_strings *__ps_strings;
# endif
# if SANITIZER_SOLARIS
# include <stddef.h>
# include <stdlib.h>
# include <sys/frame.h>
# include <thread.h>
#define environ …
# endif
extern char **environ;
# if SANITIZER_LINUX
struct kernel_timeval { … };
const int FUTEX_WAIT = …;
const int FUTEX_WAKE = …;
const int FUTEX_PRIVATE_FLAG = …;
const int FUTEX_WAIT_PRIVATE = …;
const int FUTEX_WAKE_PRIVATE = …;
# endif
# if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
SANITIZER_WORDSIZE == 64 || \
(defined(__mips__) && _MIPS_SIM == _ABIN32))
#define SANITIZER_LINUX_USES_64BIT_SYSCALLS …
# else
#define SANITIZER_LINUX_USES_64BIT_SYSCALLS …
# endif
# if SANITIZER_LINUX && defined(__NR_getrandom)
# if !defined(GRND_NONBLOCK)
#define GRND_NONBLOCK …
# endif
#define SANITIZER_USE_GETRANDOM …
# else
#define SANITIZER_USE_GETRANDOM …
# endif
# if SANITIZER_FREEBSD
#define SANITIZER_USE_GETENTROPY …
extern "C" void *__sys_mmap(void *addr, size_t len, int prot, int flags, int fd,
off_t offset);
# endif
namespace __sanitizer {
void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { … }
void BlockSignals(__sanitizer_sigset_t *oldset) { … }
ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) { … }
ScopedBlockSignals::~ScopedBlockSignals() { … }
# if SANITIZER_LINUX && defined(__x86_64__)
# include "sanitizer_syscall_linux_x86_64.inc"
# elif SANITIZER_LINUX && SANITIZER_RISCV64
# include "sanitizer_syscall_linux_riscv64.inc"
# elif SANITIZER_LINUX && defined(__aarch64__)
# include "sanitizer_syscall_linux_aarch64.inc"
# elif SANITIZER_LINUX && defined(__arm__)
# include "sanitizer_syscall_linux_arm.inc"
# elif SANITIZER_LINUX && defined(__hexagon__)
# include "sanitizer_syscall_linux_hexagon.inc"
# elif SANITIZER_LINUX && SANITIZER_LOONGARCH64
# include "sanitizer_syscall_linux_loongarch64.inc"
# else
# include "sanitizer_syscall_generic.inc"
# endif
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
# if !SANITIZER_S390
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
u64 offset) { … }
# endif
uptr internal_munmap(void *addr, uptr length) { … }
# if SANITIZER_LINUX
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
void *new_address) { … }
# endif
int internal_mprotect(void *addr, uptr length, int prot) { … }
int internal_madvise(uptr addr, uptr length, int advice) { … }
uptr internal_close(fd_t fd) { … }
uptr internal_open(const char *filename, int flags) { … }
uptr internal_open(const char *filename, int flags, u32 mode) { … }
uptr internal_read(fd_t fd, void *buf, uptr count) { … }
uptr internal_write(fd_t fd, const void *buf, uptr count) { … }
uptr internal_ftruncate(fd_t fd, uptr size) { … }
# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
out->st_dev = in->st_dev;
out->st_ino = in->st_ino;
out->st_mode = in->st_mode;
out->st_nlink = in->st_nlink;
out->st_uid = in->st_uid;
out->st_gid = in->st_gid;
out->st_rdev = in->st_rdev;
out->st_size = in->st_size;
out->st_blksize = in->st_blksize;
out->st_blocks = in->st_blocks;
out->st_atime = in->st_atime;
out->st_mtime = in->st_mtime;
out->st_ctime = in->st_ctime;
}
# endif
# if SANITIZER_LINUX && defined(__loongarch__)
static void statx_to_stat(struct statx *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
out->st_dev = makedev(in->stx_dev_major, in->stx_dev_minor);
out->st_ino = in->stx_ino;
out->st_mode = in->stx_mode;
out->st_nlink = in->stx_nlink;
out->st_uid = in->stx_uid;
out->st_gid = in->stx_gid;
out->st_rdev = makedev(in->stx_rdev_major, in->stx_rdev_minor);
out->st_size = in->stx_size;
out->st_blksize = in->stx_blksize;
out->st_blocks = in->stx_blocks;
out->st_atime = in->stx_atime.tv_sec;
out->st_atim.tv_nsec = in->stx_atime.tv_nsec;
out->st_mtime = in->stx_mtime.tv_sec;
out->st_mtim.tv_nsec = in->stx_mtime.tv_nsec;
out->st_ctime = in->stx_ctime.tv_sec;
out->st_ctim.tv_nsec = in->stx_ctime.tv_nsec;
}
# endif
# if SANITIZER_MIPS64 || SANITIZER_SPARC64
# if SANITIZER_MIPS64
typedef struct kernel_stat kstat_t;
# else
typedef struct kernel_stat64 kstat_t;
# endif
# if !SANITIZER_GO
# undef st_atime
# undef st_mtime
# undef st_ctime
# endif
# if defined(SANITIZER_ANDROID)
# undef st_atime_nsec
# undef st_mtime_nsec
# undef st_ctime_nsec
# endif
static void kernel_stat_to_stat(kstat_t *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
out->st_dev = in->st_dev;
out->st_ino = in->st_ino;
out->st_mode = in->st_mode;
out->st_nlink = in->st_nlink;
out->st_uid = in->st_uid;
out->st_gid = in->st_gid;
out->st_rdev = in->st_rdev;
out->st_size = in->st_size;
out->st_blksize = in->st_blksize;
out->st_blocks = in->st_blocks;
# if defined(__USE_MISC) || defined(__USE_XOPEN2K8) || \
defined(SANITIZER_ANDROID)
out->st_atim.tv_sec = in->st_atime;
out->st_atim.tv_nsec = in->st_atime_nsec;
out->st_mtim.tv_sec = in->st_mtime;
out->st_mtim.tv_nsec = in->st_mtime_nsec;
out->st_ctim.tv_sec = in->st_ctime;
out->st_ctim.tv_nsec = in->st_ctime_nsec;
# else
out->st_atime = in->st_atime;
out->st_atimensec = in->st_atime_nsec;
out->st_mtime = in->st_mtime;
out->st_mtimensec = in->st_mtime_nsec;
out->st_ctime = in->st_ctime;
out->st_atimensec = in->st_ctime_nsec;
# endif
}
# endif
uptr internal_stat(const char *path, void *buf) { … }
uptr internal_lstat(const char *path, void *buf) { … }
uptr internal_fstat(fd_t fd, void *buf) { … }
uptr internal_filesize(fd_t fd) { … }
uptr internal_dup(int oldfd) { … }
uptr internal_dup2(int oldfd, int newfd) { … }
uptr internal_readlink(const char *path, char *buf, uptr bufsize) { … }
uptr internal_unlink(const char *path) { … }
uptr internal_rename(const char *oldpath, const char *newpath) { … }
uptr internal_sched_yield() { … }
void internal_usleep(u64 useconds) { … }
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]) { … }
# endif
# if !SANITIZER_NETBSD
void internal__exit(int exitcode) { … }
# endif
bool FileExists(const char *filename) { … }
bool DirExists(const char *path) { … }
# if !SANITIZER_NETBSD
tid_t GetTid() { … }
int TgKill(pid_t pid, tid_t tid, int sig) { … }
# endif
# if SANITIZER_GLIBC
u64 NanoTime() { … }
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { … }
# elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
u64 NanoTime() {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
}
# endif
const char *GetEnv(const char *name) { … }
# if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO
extern "C" {
SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
}
# endif
# if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
static void ReadNullSepFileToArray(const char *path, char ***arr,
int arr_size) { … }
# endif
static void GetArgsAndEnv(char ***argv, char ***envp) { … }
char **GetArgv() { … }
char **GetEnviron() { … }
# if !SANITIZER_SOLARIS
void FutexWait(atomic_uint32_t *p, u32 cmp) { … }
void FutexWake(atomic_uint32_t *p, u32 count) { … }
# endif
# if SANITIZER_NETBSD
# else
struct linux_dirent { … };
# endif
# if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
uptr internal_ptrace(int request, int pid, void *addr, void *data) { … }
uptr internal_waitpid(int pid, int *status, int options) { … }
uptr internal_getpid() { … }
uptr internal_getppid() { … }
int internal_dlinfo(void *handle, int request, void *p) { … }
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { … }
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { … }
# if SANITIZER_LINUX
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { … }
# if defined(__x86_64__)
# include <asm/unistd_64.h>
uptr internal_arch_prctl(int option, uptr arg2) { … }
# endif
# endif
uptr internal_sigaltstack(const void *ss, void *oss) { … }
extern "C" pid_t __fork(void);
int internal_fork() { … }
# if SANITIZER_FREEBSD
int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
uptr *oldlenp, const void *newp, uptr newlen) {
return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp,
(size_t *)oldlenp, newp, (size_t)newlen);
}
int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
const void *newp, uptr newlen) {
# ifdef SYS___sysctlbyname
return internal_syscall(SYSCALL(__sysctlbyname), sname,
internal_strlen(sname), oldp, (size_t *)oldlenp, newp,
(size_t)newlen);
# else
static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr;
if (!real_sysctlnametomib)
real_sysctlnametomib =
(decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib");
CHECK(real_sysctlnametomib);
int oid[CTL_MAXNAME];
size_t len = CTL_MAXNAME;
if (real_sysctlnametomib(sname, oid, &len) == -1)
return (-1);
return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen);
# endif
}
# endif
# if SANITIZER_LINUX
#define SA_RESTORER …
int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { … }
# endif
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) { … }
void internal_sigfillset(__sanitizer_sigset_t *set) { … }
void internal_sigemptyset(__sanitizer_sigset_t *set) { … }
# if SANITIZER_LINUX
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { … }
bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { … }
# elif SANITIZER_FREEBSD
uptr internal_procctl(int type, int id, int cmd, void *data) {
return internal_syscall(SYSCALL(procctl), type, id, cmd, data);
}
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
sigset_t *rset = reinterpret_cast<sigset_t *>(set);
sigdelset(rset, signum);
}
bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
sigset_t *rset = reinterpret_cast<sigset_t *>(set);
return sigismember(rset, signum);
}
# endif
# endif
# if !SANITIZER_NETBSD
ThreadLister::ThreadLister(pid_t pid) : … { … }
ThreadLister::Result ThreadLister::ListThreads(
InternalMmapVector<tid_t> *threads) { … }
bool ThreadLister::IsAlive(int tid) { … }
ThreadLister::~ThreadLister() { … }
# endif
# if SANITIZER_WORDSIZE == 32
static uptr GetKernelAreaSize() {
# if SANITIZER_LINUX && !SANITIZER_X32
const uptr gbyte = 1UL << 30;
MemoryMappingLayout proc_maps( true);
if (proc_maps.Error())
return 0;
MemoryMappedSegment segment;
while (proc_maps.Next(&segment)) {
if ((segment.end >= 3 * gbyte) && segment.IsWritable())
return 0;
}
# if !SANITIZER_ANDROID
struct utsname uname_info;
int pers = personality(0xffffffffUL);
if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
internal_strstr(uname_info.machine, "64"))
return 0;
# endif
return gbyte;
# else
return 0;
# endif
}
# endif
uptr GetMaxVirtualAddress() { … }
uptr GetMaxUserVirtualAddress() { … }
# if !SANITIZER_ANDROID || defined(__aarch64__)
uptr GetPageSize() { … }
# endif
uptr ReadBinaryName( char *buf, uptr buf_len) { … }
uptr ReadLongProcessName( char *buf, uptr buf_len) { … }
bool LibraryNameIs(const char *full_name, const char *base_name) { … }
# if !SANITIZER_ANDROID
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { … }
# endif
# if SANITIZER_LINUX
# if defined(__x86_64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) { … }
# elif defined(__mips__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
long long res;
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
((unsigned long long *)child_stack)[0] = (uptr)fn;
((unsigned long long *)child_stack)[1] = (uptr)arg;
register void *a3 __asm__("$7") = newtls;
register int *a4 __asm__("$8") = child_tidptr;
__asm__ __volatile__(
".cprestore 16;\n"
"move $4,%1;\n"
"move $5,%2;\n"
"move $6,%3;\n"
"move $7,%4;\n"
# if SANITIZER_WORDSIZE == 32
"lw %5,16($29);\n"
# else
"move $8,%5;\n"
# endif
"li $2,%6;\n"
"syscall;\n"
"bnez $2,1f;\n"
# if SANITIZER_WORDSIZE == 32
# ifdef __BIG_ENDIAN__
"lw $25,4($29);\n"
"lw $4,12($29);\n"
# else
"lw $25,0($29);\n"
"lw $4,8($29);\n"
# endif
# else
"ld $25,0($29);\n"
"ld $4,8($29);\n"
# endif
"jal $25;\n"
"move $4,$2;\n"
"li $2,%7;\n"
"syscall;\n"
"1:\n"
: "=r"(res)
: "r"(flags), "r"(child_stack), "r"(parent_tidptr), "r"(a3), "r"(a4),
"i"(__NR_clone), "i"(__NR_exit)
: "memory", "$29");
return res;
}
# elif SANITIZER_RISCV64
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
register int res __asm__("a0");
register int __flags __asm__("a0") = flags;
register void *__stack __asm__("a1") = child_stack;
register int *__ptid __asm__("a2") = parent_tidptr;
register void *__tls __asm__("a3") = newtls;
register int *__ctid __asm__("a4") = child_tidptr;
register int (*__fn)(void *) __asm__("a5") = fn;
register void *__arg __asm__("a6") = arg;
register int nr_clone __asm__("a7") = __NR_clone;
__asm__ __volatile__(
"ecall\n"
"bnez a0, 1f\n"
"mv a0, a6\n"
"jalr a5\n"
"addi a7, zero, %9\n"
"ecall\n"
"1:\n"
: "=r"(res)
: "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
"r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
: "memory");
return res;
}
# elif defined(__aarch64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
register long long res __asm__("x0");
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
((unsigned long long *)child_stack)[0] = (uptr)fn;
((unsigned long long *)child_stack)[1] = (uptr)arg;
register int (*__fn)(void *) __asm__("x0") = fn;
register void *__stack __asm__("x1") = child_stack;
register int __flags __asm__("x2") = flags;
register void *__arg __asm__("x3") = arg;
register int *__ptid __asm__("x4") = parent_tidptr;
register void *__tls __asm__("x5") = newtls;
register int *__ctid __asm__("x6") = child_tidptr;
__asm__ __volatile__(
"mov x0,x2\n"
"mov x2,x4\n"
"mov x3,x5\n"
"mov x4,x6\n"
"mov x8,%9\n"
"svc 0x0\n"
"cmp x0, #0\n"
"bne 1f\n"
"ldp x1, x0, [sp], #16\n"
"blr x1\n"
"mov x8, %10\n"
"svc 0x0\n"
"1:\n"
: "=r"(res)
: "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
"r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
: "x30", "memory");
return res;
}
# elif SANITIZER_LOONGARCH64
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
register int res __asm__("$a0");
register int __flags __asm__("$a0") = flags;
register void *__stack __asm__("$a1") = child_stack;
register int *__ptid __asm__("$a2") = parent_tidptr;
register int *__ctid __asm__("$a3") = child_tidptr;
register void *__tls __asm__("$a4") = newtls;
register int (*__fn)(void *) __asm__("$a5") = fn;
register void *__arg __asm__("$a6") = arg;
register int nr_clone __asm__("$a7") = __NR_clone;
__asm__ __volatile__(
"syscall 0\n"
"bnez $a0, 1f\n"
"move $a0, $a6\n"
"jirl $ra, $a5, 0\n"
"addi.d $a7, $zero, %9\n"
"syscall 0\n"
"1:\n"
: "=r"(res)
: "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__ctid), "r"(__tls),
"r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
: "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
"$t8");
return res;
}
# elif defined(__powerpc64__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
long long res;
# if SANITIZER_PPC64V1
#define FRAME_SIZE …
#define FRAME_TOC_SAVE_OFFSET …
# elif SANITIZER_PPC64V2
#define FRAME_SIZE …
#define FRAME_TOC_SAVE_OFFSET …
# else
# error "Unsupported PPC64 ABI"
# endif
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
register int (*__fn)(void *) __asm__("r3") = fn;
register void *__cstack __asm__("r4") = child_stack;
register int __flags __asm__("r5") = flags;
register void *__arg __asm__("r6") = arg;
register int *__ptidptr __asm__("r7") = parent_tidptr;
register void *__newtls __asm__("r8") = newtls;
register int *__ctidptr __asm__("r9") = child_tidptr;
__asm__ __volatile__(
"mr 28, %5\n\t"
"mr 27, %8\n\t"
"mr 3, %7\n\t"
"mr 5, %9\n\t"
"mr 6, %10\n\t"
"mr 7, %11\n\t"
"li 0, %3\n\t"
"sc\n\t"
"cmpdi cr1, 3, 0\n\t"
"crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
"bne- cr1, 1f\n\t"
"li 29, 0\n\t"
"stdu 29, -8(1)\n\t"
"stdu 1, -%12(1)\n\t"
"std 2, %13(1)\n\t"
# if SANITIZER_PPC64V1
"ld 0, 0(28)\n\t"
"ld 2, 8(28)\n\t"
"mtctr 0\n\t"
# elif SANITIZER_PPC64V2
"mr 12, 28\n\t"
"mtctr 12\n\t"
# else
# error "Unsupported PPC64 ABI"
# endif
"mr 3, 27\n\t"
"bctrl\n\t"
"ld 2, %13(1)\n\t"
"li 0, %4\n\t"
"sc\n\t"
"1:\n\t"
"mr %0, 3\n\t"
: "=r"(res)
: "0"(-1), "i"(EINVAL), "i"(__NR_clone), "i"(__NR_exit), "r"(__fn),
"r"(__cstack), "r"(__flags), "r"(__arg), "r"(__ptidptr), "r"(__newtls),
"r"(__ctidptr), "i"(FRAME_SIZE), "i"(FRAME_TOC_SAVE_OFFSET)
: "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29");
return res;
}
# elif defined(__i386__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
int res;
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
child_stack = (char *)child_stack - 7 * sizeof(unsigned int);
((unsigned int *)child_stack)[0] = (uptr)flags;
((unsigned int *)child_stack)[1] = (uptr)0;
((unsigned int *)child_stack)[2] = (uptr)fn;
((unsigned int *)child_stack)[3] = (uptr)arg;
__asm__ __volatile__(
"movl (%%ecx), %%ebx\n"
"pushl %%ebx\n"
"pushl %%esi\n"
"pushl %%edi\n"
"movl %%ebx, (%%ecx)\n"
"int $0x80\n"
"popl %%edi\n"
"popl %%esi\n"
"popl %%ebx\n"
"test %%eax,%%eax\n"
"jnz 1f\n"
"xorl %%ebp,%%ebp\n"
"call *%%ebx\n"
# ifdef PIC
"call here\n"
"here:\n"
"popl %%ebx\n"
"addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
# endif
"movl %%eax, %%ebx\n"
"movl %2, %%eax\n"
"int $0x80\n"
"1:\n"
: "=a"(res)
: "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "c"(child_stack),
"d"(parent_tidptr), "S"(newtls), "D"(child_tidptr)
: "memory");
return res;
}
# elif defined(__arm__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
unsigned int res;
if (!fn || !child_stack)
return -EINVAL;
child_stack = (char *)child_stack - 2 * sizeof(unsigned int);
((unsigned int *)child_stack)[0] = (uptr)fn;
((unsigned int *)child_stack)[1] = (uptr)arg;
register int r0 __asm__("r0") = flags;
register void *r1 __asm__("r1") = child_stack;
register int *r2 __asm__("r2") = parent_tidptr;
register void *r3 __asm__("r3") = newtls;
register int *r4 __asm__("r4") = child_tidptr;
register int r7 __asm__("r7") = __NR_clone;
# if __ARM_ARCH > 4 || defined(__ARM_ARCH_4T__)
#define ARCH_HAS_BX
# endif
# if __ARM_ARCH > 4
#define ARCH_HAS_BLX
# endif
# ifdef ARCH_HAS_BX
# ifdef ARCH_HAS_BLX
#define BLX …
# else
#define BLX …
# endif
# else
#define BLX …
# endif
__asm__ __volatile__(
"swi 0x0\n"
"cmp r0, #0\n"
"bne 1f\n"
"ldr r0, [sp, #4]\n"
"ldr ip, [sp], #8\n" BLX(ip)
"mov r7, %7\n"
"swi 0x0\n"
"1:\n"
"mov %0, r0\n"
: "=r"(res)
: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), "i"(__NR_exit)
: "memory");
return res;
}
# endif
# endif
# if SANITIZER_LINUX
int internal_uname(struct utsname *buf) { … }
# endif
# if SANITIZER_ANDROID
# if __ANDROID_API__ < 21
extern "C" __attribute__((weak)) int dl_iterate_phdr(
int (*)(struct dl_phdr_info *, size_t, void *), void *);
# endif
static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
void *data) {
if (info->dlpi_name && info->dlpi_name[0] == 'l' &&
info->dlpi_name[1] == 'i' && info->dlpi_name[2] == 'b') {
*(bool *)data = true;
return 1;
}
return 0;
}
static atomic_uint32_t android_api_level;
static AndroidApiLevel AndroidDetectApiLevelStatic() {
# if __ANDROID_API__ <= 19
return ANDROID_KITKAT;
# elif __ANDROID_API__ <= 22
return ANDROID_LOLLIPOP_MR1;
# else
return ANDROID_POST_LOLLIPOP;
# endif
}
static AndroidApiLevel AndroidDetectApiLevel() {
if (!&dl_iterate_phdr)
return ANDROID_KITKAT;
bool base_name_seen = false;
dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
if (base_name_seen)
return ANDROID_LOLLIPOP_MR1;
return ANDROID_POST_LOLLIPOP;
}
extern "C" __attribute__((weak)) void *_DYNAMIC;
AndroidApiLevel AndroidGetApiLevel() {
AndroidApiLevel level =
(AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed);
if (level)
return level;
level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic()
: AndroidDetectApiLevel();
atomic_store(&android_api_level, level, memory_order_relaxed);
return level;
}
# endif
static HandleSignalMode GetHandleSignalModeImpl(int signum) { … }
HandleSignalMode GetHandleSignalMode(int signum) { … }
# if !SANITIZER_GO
void *internal_start_thread(void *(*func)(void *arg), void *arg) { … }
void internal_join_thread(void *th) { … }
# else
void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
void internal_join_thread(void *th) {}
# endif
# if SANITIZER_LINUX && defined(__aarch64__)
struct __sanitizer_esr_context {
struct _aarch64_ctx head;
uint64_t esr;
};
static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
static const u32 kEsrMagic = 0x45535201;
u8 *aux = reinterpret_cast<u8 *>(ucontext->uc_mcontext.__reserved);
while (true) {
_aarch64_ctx *ctx = (_aarch64_ctx *)aux;
if (ctx->size == 0)
break;
if (ctx->magic == kEsrMagic) {
*esr = ((__sanitizer_esr_context *)ctx)->esr;
return true;
}
aux += ctx->size;
}
return false;
}
# elif SANITIZER_FREEBSD && defined(__aarch64__)
static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { return false; }
# endif
Context;
SignalContext::WriteFlag SignalContext::GetWriteFlag() const { … }
bool SignalContext::IsTrueFaultingAddress() const { … }
UNUSED
static const char *RegNumToRegName(int reg) { … }
# if ((SANITIZER_LINUX && SANITIZER_GLIBC) || SANITIZER_NETBSD) && \
(defined(__arm__) || defined(__aarch64__))
static uptr GetArmRegister(ucontext_t *ctx, int RegNum) {
switch (RegNum) {
# if defined(__arm__) && !SANITIZER_NETBSD
# ifdef MAKE_CASE
# undef MAKE_CASE
# endif
#define MAKE_CASE …
MAKE_CASE(0);
MAKE_CASE(1);
MAKE_CASE(2);
MAKE_CASE(3);
MAKE_CASE(4);
MAKE_CASE(5);
MAKE_CASE(6);
MAKE_CASE(7);
MAKE_CASE(8);
MAKE_CASE(9);
MAKE_CASE(10);
case REG_R11:
return ctx->uc_mcontext.arm_fp;
case REG_R12:
return ctx->uc_mcontext.arm_ip;
case REG_R13:
return ctx->uc_mcontext.arm_sp;
case REG_R14:
return ctx->uc_mcontext.arm_lr;
case REG_R15:
return ctx->uc_mcontext.arm_pc;
# elif defined(__aarch64__)
# if SANITIZER_LINUX
case 0 ... 30:
return ctx->uc_mcontext.regs[RegNum];
case 31:
return ctx->uc_mcontext.sp;
# elif SANITIZER_NETBSD
case 0 ... 31:
return ctx->uc_mcontext.__gregs[RegNum];
# endif
# endif
default:
return 0;
}
return 0;
}
# endif
UNUSED
static void DumpSingleReg(ucontext_t *ctx, int RegNum) { … }
void SignalContext::DumpAllRegisters(void *context) { … }
static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { … }
void SignalContext::InitPcSpBp() { … }
void InitializePlatformEarly() { … }
void CheckASLR() { … }
void CheckMPROTECT() { … }
void CheckNoDeepBind(const char *filename, int flag) { … }
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
uptr *largest_gap_found,
uptr *max_occupied_addr) { … }
bool GetRandom(void *buffer, uptr length, bool blocking) { … }
}
#endif