head	1.12;
access;
symbols
	netbsd-11-0-RC5:1.6
	netbsd-11-0-RC4:1.6
	netbsd-11-0-RC3:1.6
	netbsd-11-0-RC2:1.6
	netbsd-11-0-RC1:1.6
	gcc-14-3-0:1.1.1.3
	perseant-exfatfs-base-20250801:1.6
	netbsd-11:1.6.0.2
	netbsd-11-base:1.6
	gcc-12-5-0:1.1.1.2
	perseant-exfatfs-base-20240630:1.5
	gcc-12-4-0:1.1.1.2
	perseant-exfatfs:1.5.0.2
	perseant-exfatfs-base:1.5
	gcc-12-3-0:1.1.1.2
	gcc-10-5-0:1.1.1.1
	gcc-10-4-0:1.1.1.1
	cjep_sun2x:1.2.0.4
	cjep_sun2x-base:1.2
	cjep_staticlib_x-base1:1.2
	cjep_staticlib_x:1.2.0.2
	cjep_staticlib_x-base:1.2
	gcc-10-3-0:1.1.1.1
	FSF:1.1.1;
locks; strict;
comment	@// @;


1.12
date	2025.09.24.01.23.56;	author mrg;	state Exp;
branches;
next	1.11;
commitid	t7atDO1zBFtibUbG;

1.11
date	2025.09.20.19.00.12;	author mrg;	state Exp;
branches;
next	1.10;
commitid	CD7OewfrkqOs9ubG;

1.10
date	2025.09.19.19.32.33;	author mrg;	state Exp;
branches;
next	1.9;
commitid	cPQ55GbrPvLImmbG;

1.9
date	2025.09.19.07.50.40;	author mrg;	state Exp;
branches;
next	1.8;
commitid	g7LcFAHes2g1tibG;

1.8
date	2025.09.16.22.22.40;	author mrg;	state Exp;
branches;
next	1.7;
commitid	rUqbxa9rMpT4pZaG;

1.7
date	2025.09.14.00.08.57;	author mrg;	state Exp;
branches;
next	1.6;
commitid	x9D5QEnvbeMI4CaG;

1.6
date	2024.10.20.19.53.36;	author christos;	state Exp;
branches;
next	1.5;
commitid	hPZ1tUNP77ZldruF;

1.5
date	2023.08.04.07.40.05;	author mrg;	state Exp;
branches
	1.5.2.1;
next	1.4;
commitid	eYDwr3Sks18VnrzE;

1.4
date	2023.08.03.01.36.54;	author mrg;	state Exp;
branches;
next	1.3;
commitid	94ccj90Ss370qhzE;

1.3
date	2023.07.31.01.44.56;	author mrg;	state Exp;
branches;
next	1.2;
commitid	q79F5Opf0FLsyTyE;

1.2
date	2021.04.11.23.54.27;	author mrg;	state dead;
branches;
next	1.1;
commitid	wJn7ggfUTEMOWVOC;

1.1
date	2021.04.10.22.09.22;	author mrg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	eC4g0MRpqTvEkNOC;

1.5.2.1
date	2025.08.02.05.25.50;	author perseant;	state Exp;
branches;
next	;
commitid	23j6GFaDws3O875G;

1.1.1.1
date	2021.04.10.22.09.22;	author mrg;	state Exp;
branches;
next	1.1.1.2;
commitid	eC4g0MRpqTvEkNOC;

1.1.1.2
date	2023.07.30.05.20.40;	author mrg;	state Exp;
branches;
next	1.1.1.3;
commitid	tk6nV4mbc9nVEMyE;

1.1.1.3
date	2025.09.13.23.45.04;	author mrg;	state Exp;
branches;
next	;
commitid	KwhwN4krNWa6XBaG;


desc
@@


1.12
log
@update a comment.
@
text
@//===-- sanitizer_linux.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements linux-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#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

// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
// access stat from asm/stat.h, without conflicting with definition in
// sys/stat.h, we use this trick.
#if SANITIZER_MIPS64 && !SANITIZER_NETBSD
#include <asm/unistd.h>
#include <sys/types.h>
#define stat kernel_stat
#if SANITIZER_GO
#undef st_atime
#undef st_mtime
#undef st_ctime
#define st_atime st_atim
#define st_mtime st_mtim
#define st_ctime st_ctim
#endif
#include <asm/stat.h>
#undef stat
#endif

#if SANITIZER_NETBSD
#include <lwp.h>
#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>
#include <sys/param.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 <sys/exec.h>
#include <sys/procctl.h>
#include <sys/sysctl.h>
#include <machine/atomic.h>
extern "C" {
// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
// FreeBSD 9.2 and 10.0.
#include <sys/umtx.h>
}
#include <sys/thr.h>
#endif  // SANITIZER_FREEBSD

#if SANITIZER_NETBSD
#include <limits.h>  // For NAME_MAX
#include <sys/sysctl.h>
#include <sys/exec.h>
extern struct ps_strings *__ps_strings;
#endif  // SANITIZER_NETBSD

#if SANITIZER_SOLARIS
#include <stdlib.h>
#include <thread.h>
#define environ _environ
#endif

extern char **environ;

#if SANITIZER_LINUX
// <linux/time.h>
struct kernel_timeval {
  long tv_sec;
  long tv_usec;
};

// <linux/futex.h> is broken on some linux distributions.
const int FUTEX_WAIT = 0;
const int FUTEX_WAKE = 1;
const int FUTEX_PRIVATE_FLAG = 128;
const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG;
const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
#endif  // SANITIZER_LINUX

// Are we using 32-bit or 64-bit Linux syscalls?
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
// but it still needs to use 64-bit syscalls.
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
                        SANITIZER_WORDSIZE == 64 ||                      \
                        (defined(__mips__) && _MIPS_SIM == _ABIN32))
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
#else
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
#endif

// Note : FreeBSD had implemented both
// Linux apis, available from
// future 12.x version most likely
#if SANITIZER_LINUX && defined(__NR_getrandom)
# if !defined(GRND_NONBLOCK)
#  define GRND_NONBLOCK 1
# endif
# define SANITIZER_USE_GETRANDOM 1
#else
# define SANITIZER_USE_GETRANDOM 0
#endif  // SANITIZER_LINUX && defined(__NR_getrandom)

#if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000
#  define SANITIZER_USE_GETENTROPY 1
#else
#  define SANITIZER_USE_GETENTROPY 0
#endif

namespace __sanitizer {

void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
}

void BlockSignals(__sanitizer_sigset_t *oldset) {
  __sanitizer_sigset_t set;
  internal_sigfillset(&set);
#  if SANITIZER_LINUX && !SANITIZER_ANDROID
  // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
  // on any thread, setuid call hangs.
  // See test/sanitizer_common/TestCases/Linux/setuid.c.
  internal_sigdelset(&set, 33);
#  endif
#  if SANITIZER_LINUX
  // Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
  // If this signal is blocked, such calls cannot be handled and the process may
  // hang.
  internal_sigdelset(&set, 31);
#  endif
  SetSigProcMask(&set, oldset);
}

ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
  BlockSignals(&saved_);
  if (copy)
    internal_memcpy(copy, &saved_, sizeof(saved_));
}

ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }

#  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

// --------------- sanitizer_libc.h
#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
#if !SANITIZER_S390
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                   u64 offset) {
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
  return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
                          offset);
#else
  // mmap2 specifies file offset in 4096-byte units.
  CHECK(IsAligned(offset, 4096));
  return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
                          offset / 4096);
#endif
}
#endif // !SANITIZER_S390

uptr internal_munmap(void *addr, uptr length) {
  return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
}

#if SANITIZER_LINUX
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
                     void *new_address) {
  return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
                          new_size, flags, (uptr)new_address);
}
#endif

int internal_mprotect(void *addr, uptr length, int prot) {
  return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
}

int internal_madvise(uptr addr, uptr length, int advice) {
  return internal_syscall(SYSCALL(madvise), addr, length, advice);
}

uptr internal_close(fd_t fd) {
  return internal_syscall(SYSCALL(close), fd);
}

uptr internal_open(const char *filename, int flags) {
#    if SANITIZER_LINUX
  return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
#else
  return internal_syscall(SYSCALL(open), (uptr)filename, flags);
#endif
}

uptr internal_open(const char *filename, int flags, u32 mode) {
#    if SANITIZER_LINUX
  return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
                          mode);
#else
  return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
#endif
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  sptr res;
  HANDLE_EINTR(res,
               (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count));
  return res;
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  sptr res;
  HANDLE_EINTR(res,
               (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count));
  return res;
}

uptr internal_ftruncate(fd_t fd, uptr size) {
  sptr res;
  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
               (OFF_T)size));
  return res;
}

#if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && 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
// Undefine compatibility macros from <sys/stat.h>
// so that they would not clash with the kernel_stat
// st_[a|m|c]time fields
#if !SANITIZER_GO
#undef st_atime
#undef st_mtime
#undef st_ctime
#endif
#if defined(SANITIZER_ANDROID)
// Bionic sys/stat.h defines additional macros
// for compatibility with the old NDKs and
// they clash with the kernel_stat structure
// st_[a|m|c]time_nsec fields.
#undef st_atime_nsec
#undef st_mtime_nsec
#undef st_ctime_nsec
#endif
static void kernel_stat_to_stat(struct kernel_stat *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) {
#  if SANITIZER_FREEBSD
  return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0);
#  elif SANITIZER_LINUX
#    if defined(__loongarch__)
  struct statx bufx;
  int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
                             AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx);
  statx_to_stat(&bufx, (struct stat *)buf);
  return res;
#    elif (SANITIZER_WORDSIZE == 64 || SANITIZER_X32 ||    \
           (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
        !SANITIZER_SPARC
  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                          0);
#    else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
                             (uptr)&buf64, 0);
  stat64_to_stat(&buf64, (struct stat *)buf);
  return res;
#    endif
#  else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(stat64), path, &buf64);
  stat64_to_stat(&buf64, (struct stat *)buf);
  return res;
#  endif
}

uptr internal_lstat(const char *path, void *buf) {
#  if SANITIZER_FREEBSD
  return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                          AT_SYMLINK_NOFOLLOW);
#  elif SANITIZER_LINUX
#    if defined(__loongarch__)
  struct statx bufx;
  int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
                             AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT,
                             STATX_BASIC_STATS, (uptr)&bufx);
  statx_to_stat(&bufx, (struct stat *)buf);
  return res;
#    elif (defined(_LP64) || SANITIZER_X32 ||              \
           (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
        !SANITIZER_SPARC
  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                          AT_SYMLINK_NOFOLLOW);
#    else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
                             (uptr)&buf64, AT_SYMLINK_NOFOLLOW);
  stat64_to_stat(&buf64, (struct stat *)buf);
  return res;
#    endif
#  else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
  stat64_to_stat(&buf64, (struct stat *)buf);
  return res;
#  endif
}

uptr internal_fstat(fd_t fd, void *buf) {
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
#if SANITIZER_MIPS64
  // For mips64, fstat syscall fills buffer in the format of kernel_stat
  struct kernel_stat kbuf;
  int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
  kernel_stat_to_stat(&kbuf, (struct stat *)buf);
  return res;
#      elif SANITIZER_LINUX && defined(__loongarch__)
  struct statx bufx;
  int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
                             STATX_BASIC_STATS, (uptr)&bufx);
  statx_to_stat(&bufx, (struct stat *)buf);
  return res;
#      else
  return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
#      endif
#else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
  stat64_to_stat(&buf64, (struct stat *)buf);
  return res;
#endif
}

uptr internal_filesize(fd_t fd) {
  struct stat st;
  if (internal_fstat(fd, &st))
    return -1;
  return (uptr)st.st_size;
}

uptr internal_dup(int oldfd) {
  return internal_syscall(SYSCALL(dup), oldfd);
}

uptr internal_dup2(int oldfd, int newfd) {
#    if SANITIZER_LINUX
  return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
#else
  return internal_syscall(SYSCALL(dup2), oldfd, newfd);
#endif
}

uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
#    if SANITIZER_LINUX
  return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf,
                          bufsize);
#else
  return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
#endif
}

uptr internal_unlink(const char *path) {
#    if SANITIZER_LINUX
  return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
#else
  return internal_syscall(SYSCALL(unlink), (uptr)path);
#endif
}

uptr internal_rename(const char *oldpath, const char *newpath) {
#  if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__)
  return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
                          (uptr)newpath, 0);
#  elif SANITIZER_LINUX
  return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
                          (uptr)newpath);
#  else
  return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
#  endif
}

uptr internal_sched_yield() {
  return internal_syscall(SYSCALL(sched_yield));
}

void internal_usleep(u64 useconds) {
  struct timespec ts;
  ts.tv_sec = useconds / 1000000;
  ts.tv_nsec = (useconds % 1000000) * 1000;
  internal_syscall(SYSCALL(nanosleep), &ts, &ts);
}

uptr internal_execve(const char *filename, char *const argv[],
                     char *const envp[]) {
  return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
                          (uptr)envp);
}
#endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD

#if !SANITIZER_NETBSD
void internal__exit(int exitcode) {
#if SANITIZER_FREEBSD || SANITIZER_SOLARIS
  internal_syscall(SYSCALL(exit), exitcode);
#else
  internal_syscall(SYSCALL(exit_group), exitcode);
#endif
  Die();  // Unreachable.
}
#endif  // !SANITIZER_NETBSD

// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
  if (ShouldMockFailureToOpen(filename))
    return false;
  struct stat st;
  if (internal_stat(filename, &st))
    return false;
  // Sanity check: filename is a regular file.
  return S_ISREG(st.st_mode);
}

bool DirExists(const char *path) {
  struct stat st;
  if (internal_stat(path, &st))
    return false;
  return S_ISDIR(st.st_mode);
}

#  if !SANITIZER_NETBSD
tid_t GetTid() {
#if SANITIZER_FREEBSD
  long Tid;
  thr_self(&Tid);
  return Tid;
#elif SANITIZER_SOLARIS
  return thr_self();
#else
  return internal_syscall(SYSCALL(gettid));
#endif
}

int TgKill(pid_t pid, tid_t tid, int sig) {
#if SANITIZER_LINUX
  return internal_syscall(SYSCALL(tgkill), pid, tid, sig);
#elif SANITIZER_FREEBSD
  return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig);
#elif SANITIZER_SOLARIS
  (void)pid;
  return thr_kill(tid, sig);
#endif
}
#endif

#if SANITIZER_GLIBC
u64 NanoTime() {
  kernel_timeval tv;
  internal_memset(&tv, 0, sizeof(tv));
  internal_syscall(SYSCALL(gettimeofday), &tv, 0);
  return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
}
// Used by real_clock_gettime.
uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
  return internal_syscall(SYSCALL(clock_gettime), clk_id, 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

// Like getenv, but reads env directly from /proc (on Linux) or parses the
// 'environ' array (on some others) and does not use libc. This function
// should be called first inside __asan_init.
const char *GetEnv(const char *name) {
#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS
  if (::environ != 0) {
    uptr NameLen = internal_strlen(name);
    for (char **Env = ::environ; *Env != 0; Env++) {
      if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
        return (*Env) + NameLen + 1;
    }
  }
  return 0;  // Not found.
#elif SANITIZER_LINUX
  static char *environ;
  static uptr len;
  static bool inited;
  if (!inited) {
    inited = true;
    uptr environ_size;
    if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len))
      environ = nullptr;
  }
  if (!environ || len == 0) return nullptr;
  uptr namelen = internal_strlen(name);
  const char *p = environ;
  while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    const char* endp =
        (char*)internal_memchr(p, '\0', len - (p - environ));
    if (!endp)  // this entry isn't NUL terminated
      return nullptr;
    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
      return p + namelen + 1;  // point after =
    p = endp + 1;
  }
  return nullptr;  // Not found.
#else
#error "Unsupported platform"
#endif
}

#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) {
  char *buff;
  uptr buff_size;
  uptr buff_len;
  *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
  if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) {
    (*arr)[0] = nullptr;
    return;
  }
  (*arr)[0] = buff;
  int count, i;
  for (count = 1, i = 1; ; i++) {
    if (buff[i] == 0) {
      if (buff[i+1] == 0) break;
      (*arr)[count] = &buff[i+1];
      CHECK_LE(count, arr_size - 1);  // FIXME: make this more flexible.
      count++;
    }
  }
  (*arr)[count] = nullptr;
}
#endif

#if SANITIZER_NETBSD
static char **
load_vector(int m)
{
  uptr size;
  int nv;
  char **v, **ap, *bp, *buf, *endp;
  int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), 0};
  size = sizeof(nv);
  mib[3] = m == KERN_PROC_ARGV ? KERN_PROC_NARGV : KERN_PROC_NENV;
  if (internal_sysctl(mib, 4, &nv, &size, NULL, 0) == -1) {
    Printf("sysctl KERN_PROC_N{ARGV,ENV} failed\n");
    Die();
  }
  v = (char **)MmapOrDie((nv + 1) * sizeof(char *), "Arg vector");
  buf = (char *)MmapOrDie(ARG_MAX, "Arg space");
  size = ARG_MAX;
  mib[3] = m;
  if (internal_sysctl(mib, 4, buf, &size, NULL, 0) == -1) {
    Printf("sysctl KERN_PROC_{ARGV,ENV} failed\n");
    Die();
  }
  bp = buf;
  ap = v;
  endp = bp + size;

  while (bp < endp) {
    *ap++ = bp;
    bp += internal_strlen(bp) + 1;
  }
  *ap = NULL;
  return v;
}
#endif

static void GetArgsAndEnv(char ***argv, char ***envp) {
#if SANITIZER_FREEBSD
  // On FreeBSD, retrieving the argument and environment arrays is done via the
  // kern.ps_strings sysctl, which returns a pointer to a structure containing
  // this information. See also <sys/exec.h>.
  ps_strings *pss;
  uptr sz = sizeof(pss);
  if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) {
    Printf("sysctl kern.ps_strings failed\n");
    Die();
  }
  *argv = pss->ps_argvstr;
  *envp = pss->ps_envstr;
#elif SANITIZER_NETBSD
  *argv = load_vector(KERN_PROC_ARGV);
  *envp = load_vector(KERN_PROC_ENV);
#else // SANITIZER_FREEBSD
#if !SANITIZER_GO
  if (&__libc_stack_end) {
    uptr* stack_end = (uptr*)__libc_stack_end;
    // Normally argc can be obtained from *stack_end, however, on ARM glibc's
    // _start clobbers it:
    // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
    // Do not special-case ARM and infer argc from argv everywhere.
    int argc = 0;
    while (stack_end[argc + 1]) argc++;
    *argv = (char**)(stack_end + 1);
    *envp = (char**)(stack_end + argc + 2);
  } else {
#endif // !SANITIZER_GO
    static const int kMaxArgv = 2000, kMaxEnvp = 2000;
    ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
    ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
#if !SANITIZER_GO
  }
#endif // !SANITIZER_GO
#endif // SANITIZER_FREEBSD
}

char **GetArgv() {
  char **argv, **envp;
  GetArgsAndEnv(&argv, &envp);
  return argv;
}

char **GetEnviron() {
  char **argv, **envp;
  GetArgsAndEnv(&argv, &envp);
  return envp;
}

#if !SANITIZER_SOLARIS
void FutexWait(atomic_uint32_t *p, u32 cmp) {
#    if SANITIZER_FREEBSD
  _umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0);
#    elif SANITIZER_NETBSD
  sched_yield();   /* No userspace futex-like synchronization */
#    else
  internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0);
#    endif
}

void FutexWake(atomic_uint32_t *p, u32 count) {
#    if SANITIZER_FREEBSD
  _umtx_op(p, UMTX_OP_WAKE, count, 0, 0);
#    elif SANITIZER_NETBSD
                   /* No userspace futex-like synchronization */
#    else
  internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0);
#    endif
}

#  endif  // !SANITIZER_SOLARIS

// ----------------- sanitizer_linux.h
// The actual size of this structure is specified by d_reclen.
// Note that getdents64 uses a different structure format. We only provide the
// 32-bit syscall here.
#if SANITIZER_NETBSD
// Not used
#else
struct linux_dirent {
#    if SANITIZER_X32 || SANITIZER_LINUX
  u64 d_ino;
  u64 d_off;
#    else
  unsigned long      d_ino;
  unsigned long      d_off;
#    endif
  unsigned short     d_reclen;
#    if SANITIZER_LINUX
  unsigned char      d_type;
#    endif
  char               d_name[256];
};
#endif

#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
// Syscall wrappers.
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
  return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
                          (uptr)data);
}

uptr internal_waitpid(int pid, int *status, int options) {
  return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
                          0 /* rusage */);
}

uptr internal_getpid() {
  return internal_syscall(SYSCALL(getpid));
}

uptr internal_getppid() {
  return internal_syscall(SYSCALL(getppid));
}

int internal_dlinfo(void *handle, int request, void *p) {
#if SANITIZER_FREEBSD
  return dlinfo(handle, request, p);
#else
  UNIMPLEMENTED();
#endif
}

uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
#if SANITIZER_FREEBSD
  return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
#    elif SANITIZER_LINUX
  return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
#    else
  return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
#    endif
}

uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
  return internal_syscall(SYSCALL(lseek), fd, offset, whence);
}

#if SANITIZER_LINUX
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
  return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
}
#      if defined(__x86_64__)
#        include <asm/unistd_64.h>
// Currently internal_arch_prctl() is only needed on x86_64.
uptr internal_arch_prctl(int option, uptr arg2) {
  return internal_syscall(__NR_arch_prctl, option, arg2);
}
#      endif
#    endif

uptr internal_sigaltstack(const void *ss, void *oss) {
  return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
}

int internal_fork() {
#    if SANITIZER_LINUX
#      if SANITIZER_S390
  return internal_syscall(SYSCALL(clone), 0, SIGCHLD);
#      else
  return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
#      endif
#    else
  return internal_syscall(SYSCALL(fork));
#    endif
}

#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) {
  // Note: this function can be called during startup, so we need to avoid
  // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname()
  // is a real syscall, but for older versions it calls sysctlnametomib()
  // followed by sysctl(). To avoid calling the intercepted version and
  // asserting if this happens during startup, call the real sysctlnametomib()
  // followed by internal_sysctl() if the syscall is not available.
#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 0x04000000
// Doesn't set sa_restorer if the caller did not set it, so use with caution
//(see below).
int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
  __sanitizer_kernel_sigaction_t k_act, k_oldact;
  internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
  internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t));
  const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act;
  __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact;
  if (u_act) {
    k_act.handler = u_act->handler;
    k_act.sigaction = u_act->sigaction;
    internal_memcpy(&k_act.sa_mask, &u_act->sa_mask,
                    sizeof(__sanitizer_kernel_sigset_t));
    // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL).
    k_act.sa_flags = u_act->sa_flags | SA_RESTORER;
    // FIXME: most often sa_restorer is unset, however the kernel requires it
    // to point to a valid signal restorer that calls the rt_sigreturn syscall.
    // If sa_restorer passed to the kernel is NULL, the program may crash upon
    // signal delivery or fail to unwind the stack in the signal handler.
    // libc implementation of sigaction() passes its own restorer to
    // rt_sigaction, so we need to do the same (we'll need to reimplement the
    // restorers; for x86_64 the restorer address can be obtained from
    // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
    k_act.sa_restorer = u_act->sa_restorer;
#endif
  }

  uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
      (uptr)(u_act ? &k_act : nullptr),
      (uptr)(u_oldact ? &k_oldact : nullptr),
      (uptr)sizeof(__sanitizer_kernel_sigset_t));

  if ((result == 0) && u_oldact) {
    u_oldact->handler = k_oldact.handler;
    u_oldact->sigaction = k_oldact.sigaction;
    internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
                    sizeof(__sanitizer_kernel_sigset_t));
    u_oldact->sa_flags = k_oldact.sa_flags;
#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
    u_oldact->sa_restorer = k_oldact.sa_restorer;
#endif
  }
  return result;
}
#endif  // SANITIZER_LINUX

uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
                          __sanitizer_sigset_t *oldset) {
#if SANITIZER_FREEBSD
  return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
#else
  __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
  __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
  return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set,
                          (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t));
#endif
}

void internal_sigfillset(__sanitizer_sigset_t *set) {
  internal_memset(set, 0xff, sizeof(*set));
}

void internal_sigemptyset(__sanitizer_sigset_t *set) {
  internal_memset(set, 0, sizeof(*set));
}

#if SANITIZER_LINUX
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
  signum -= 1;
  CHECK_GE(signum, 0);
  CHECK_LT(signum, sizeof(*set) * 8);
  __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
  const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
  const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
  k_set->sig[idx] &= ~((uptr)1 << bit);
}

bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
  signum -= 1;
  CHECK_GE(signum, 0);
  CHECK_LT(signum, sizeof(*set) * 8);
  __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
  const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
  const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
  return k_set->sig[idx] & ((uptr)1 << bit);
}
#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 // !SANITIZER_SOLARIS

#if !SANITIZER_NETBSD
// ThreadLister implementation.
ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) {
  char task_directory_path[80];
  internal_snprintf(task_directory_path, sizeof(task_directory_path),
                    "/proc/%d/task/", pid);
  descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
  if (internal_iserror(descriptor_)) {
    Report("Can't open /proc/%d/task for reading.\n", pid);
  }
}

ThreadLister::Result ThreadLister::ListThreads(
    InternalMmapVector<tid_t> *threads) {
  if (internal_iserror(descriptor_))
    return Error;
  internal_lseek(descriptor_, 0, SEEK_SET);
  threads->clear();

  Result result = Ok;
  for (bool first_read = true;; first_read = false) {
    // Resize to max capacity if it was downsized by IsAlive.
    buffer_.resize(buffer_.capacity());
    CHECK_GE(buffer_.size(), 4096);
    uptr read = internal_getdents(
        descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size());
    if (!read)
      return result;
    if (internal_iserror(read)) {
      Report("Can't read directory entries from /proc/%d/task.\n", pid_);
      return Error;
    }

    for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) {
      struct linux_dirent *entry = (struct linux_dirent *)begin;
      begin += entry->d_reclen;
      if (entry->d_ino == 1) {
        // Inode 1 is for bad blocks and also can be a reason for early return.
        // Should be emitted if kernel tried to output terminating thread.
        // See proc_task_readdir implementation in Linux.
        result = Incomplete;
      }
      if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9')
        threads->push_back(internal_atoll(entry->d_name));
    }

    // Now we are going to detect short-read or early EOF. In such cases Linux
    // can return inconsistent list with missing alive threads.
    // Code will just remember that the list can be incomplete but it will
    // continue reads to return as much as possible.
    if (!first_read) {
      // The first one was a short-read by definition.
      result = Incomplete;
    } else if (read > buffer_.size() - 1024) {
      // Read was close to the buffer size. So double the size and assume the
      // worst.
      buffer_.resize(buffer_.size() * 2);
      result = Incomplete;
    } else if (!threads->empty() && !IsAlive(threads->back())) {
      // Maybe Linux early returned from read on terminated thread (!pid_alive)
      // and failed to restore read position.
      // See next_tid and proc_task_instantiate in Linux.
      result = Incomplete;
    }
  }
}

bool ThreadLister::IsAlive(int tid) {
  // /proc/%d/task/%d/status uses same call to detect alive threads as
  // proc_task_readdir. See task_state implementation in Linux.
  char path[80];
  internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid);
  if (!ReadFileToVector(path, &buffer_) || buffer_.empty())
    return false;
  buffer_.push_back(0);
  static const char kPrefix[] = "\nPPid:";
  const char *field = internal_strstr(buffer_.data(), kPrefix);
  if (!field)
    return false;
  field += internal_strlen(kPrefix);
  return (int)internal_atoll(field) != 0;
}

ThreadLister::~ThreadLister() {
  if (!internal_iserror(descriptor_))
    internal_close(descriptor_);
}
#endif

#if SANITIZER_WORDSIZE == 32
// Take care of unusable kernel area in top gigabyte.
static uptr GetKernelAreaSize() {
#if SANITIZER_LINUX && !SANITIZER_X32
  const uptr gbyte = 1UL << 30;

  // Firstly check if there are writable segments
  // mapped to top gigabyte (e.g. stack).
  MemoryMappingLayout proc_maps(/*cache_enabled*/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
  // Even if nothing is mapped, top Gb may still be accessible
  // if we are running on 64-bit kernel.
  // Uname may report misleading results if personality type
  // is modified (e.g. under schroot) so check this as well.
  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  // SANITIZER_ANDROID

  // Top gigabyte is reserved for kernel.
  return gbyte;
#else
  return 0;
#endif  // SANITIZER_LINUX && !SANITIZER_X32
}
#endif  // SANITIZER_WORDSIZE == 32

uptr GetMaxVirtualAddress() {
#if SANITIZER_NETBSD && defined(__x86_64__)
  return 0x7f7ffffff000ULL;  // (0x00007f8000000000 - PAGE_SIZE)
#elif SANITIZER_WORDSIZE == 64
# if defined(__powerpc64__) || defined(__aarch64__) || defined(__loongarch__)
  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
  // We somehow need to figure out which one we are using now and choose
  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
  // of the address space, so simply checking the stack address is not enough.
  // This should (does) work for both PowerPC64 Endian modes.
  // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
  // loongarch64 also has multiple address space layouts: default is 47-bit.
  return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
#elif SANITIZER_RISCV64
  return (1ULL << 38) - 1;
# elif SANITIZER_MIPS64
  return (1ULL << 40) - 1;  // 0x000000ffffffffffUL;
# elif defined(__s390x__)
  return (1ULL << 53) - 1;  // 0x001fffffffffffffUL;
#elif defined(__sparc__)
  return ~(uptr)0;
# else
  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
# endif
#else  // SANITIZER_WORDSIZE == 32
# if defined(__s390__)
  return (1ULL << 31) - 1;  // 0x7fffffff;
# else
  return (1ULL << 32) - 1;  // 0xffffffff;
# endif
#endif  // SANITIZER_WORDSIZE
}

uptr GetMaxUserVirtualAddress() {
  uptr addr = GetMaxVirtualAddress();
#if SANITIZER_WORDSIZE == 32 && !defined(__s390__)
  if (!common_flags()->full_address_space)
    addr -= GetKernelAreaSize();
  CHECK_LT(reinterpret_cast<uptr>(&addr), addr);
#endif
  return addr;
}

#if !SANITIZER_ANDROID
uptr GetPageSize() {
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
    defined(EXEC_PAGESIZE)
  return EXEC_PAGESIZE;
#elif SANITIZER_FREEBSD || SANITIZER_NETBSD
// Use sysctl as sysconf can trigger interceptors internally.
  int pz = 0;
  uptr pzl = sizeof(pz);
  int mib[2] = {CTL_HW, HW_PAGESIZE};
  int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0);
  CHECK_EQ(rv, 0);
  return (uptr)pz;
#elif SANITIZER_USE_GETAUXVAL
  return getauxval(AT_PAGESZ);
#else
  return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
#endif
}
#endif // !SANITIZER_ANDROID

uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
#if SANITIZER_SOLARIS
  const char *default_module_name = getexecname();
  CHECK_NE(default_module_name, NULL);
  return internal_snprintf(buf, buf_len, "%s", default_module_name);
#else
#if SANITIZER_FREEBSD || SANITIZER_NETBSD
#if SANITIZER_FREEBSD
  const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
#else
  const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
#endif
  const char *default_module_name = "kern.proc.pathname";
  uptr Size = buf_len;
  bool IsErr =
      (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0);
  int readlink_error = IsErr ? errno : 0;
  uptr module_name_len = Size;
#else
  const char *default_module_name = "/proc/self/exe";
  uptr module_name_len = internal_readlink(
      default_module_name, buf, buf_len);
  int readlink_error;
  bool IsErr = internal_iserror(module_name_len, &readlink_error);
#endif  // SANITIZER_SOLARIS
  if (IsErr) {
    // We can't read binary name for some reason, assume it's unknown.
    Report("WARNING: reading executable name failed with errno %d, "
           "some stack frames may not be symbolized\n", readlink_error);
    module_name_len = internal_snprintf(buf, buf_len, "%s",
                                        default_module_name);
    CHECK_LT(module_name_len, buf_len);
  }
  return module_name_len;
#endif
}

uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
#if SANITIZER_LINUX
  char *tmpbuf;
  uptr tmpsize;
  uptr tmplen;
  if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen,
                       1024 * 1024)) {
    internal_strncpy(buf, tmpbuf, buf_len);
    UnmapOrDie(tmpbuf, tmpsize);
    return internal_strlen(buf);
  }
#endif
  return ReadBinaryName(buf, buf_len);
}

// Match full names of the form /path/to/base_name{-,.}*
bool LibraryNameIs(const char *full_name, const char *base_name) {
  const char *name = full_name;
  // Strip path.
  while (*name != '\0') name++;
  while (name > full_name && *name != '/') name--;
  if (*name == '/') name++;
  uptr base_name_length = internal_strlen(base_name);
  if (internal_strncmp(name, base_name, base_name_length)) return false;
  return (name[base_name_length] == '-' || name[base_name_length] == '.');
}

#if !SANITIZER_ANDROID
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
  CHECK_NE(map, nullptr);
#if !SANITIZER_FREEBSD
  typedef ElfW(Phdr) Elf_Phdr;
  typedef ElfW(Ehdr) Elf_Ehdr;
#endif // !SANITIZER_FREEBSD
  char *base = (char *)map->l_addr;
  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
  char *phdrs = base + ehdr->e_phoff;
  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;

  // Find the segment with the minimum base so we can "relocate" the p_vaddr
  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
  // objects have a non-zero base.
  uptr preferred_base = (uptr)-1;
  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
    Elf_Phdr *phdr = (Elf_Phdr *)iter;
    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
      preferred_base = (uptr)phdr->p_vaddr;
  }

  // Compute the delta from the real base to get a relocation delta.
  sptr delta = (uptr)base - preferred_base;
  // Now we can figure out what the loader really mapped.
  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
    Elf_Phdr *phdr = (Elf_Phdr *)iter;
    if (phdr->p_type == PT_LOAD) {
      uptr seg_start = phdr->p_vaddr + delta;
      uptr seg_end = seg_start + phdr->p_memsz;
      // None of these values are aligned.  We consider the ragged edges of the
      // load command as defined, since they are mapped from the file.
      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
      cb((void *)seg_start, seg_end - seg_start);
    }
  }
}
#endif

#if SANITIZER_LINUX
#if defined(__x86_64__)
// We cannot use glibc's clone wrapper, because it messes with the child
// task's TLS. It writes the PID and TID of the child task to its thread
// descriptor, but in our case the child task shares the thread descriptor with
// the parent (because we don't know how to allocate a new thread
// descriptor to keep glibc happy). So the stock version of clone(), when
// used with CLONE_VM, would end up corrupting the parent's thread descriptor.
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 *r8 __asm__("r8") = newtls;
  register int *r10 __asm__("r10") = child_tidptr;
  __asm__ __volatile__(
                       /* %rax = syscall(%rax = SYSCALL(clone),
                        *                %rdi = flags,
                        *                %rsi = child_stack,
                        *                %rdx = parent_tidptr,
                        *                %r8  = new_tls,
                        *                %r10 = child_tidptr)
                        */
                       "syscall\n"

                       /* if (%rax != 0)
                        *   return;
                        */
                       "testq  %%rax,%%rax\n"
                       "jnz    1f\n"

                       /* In the child. Terminate unwind chain. */
                       // XXX: We should also terminate the CFI unwind chain
                       // here. Unfortunately clang 3.2 doesn't support the
                       // necessary CFI directives, so we skip that part.
                       "xorq   %%rbp,%%rbp\n"

                       /* Call "fn(arg)". */
                       "popq   %%rax\n"
                       "popq   %%rdi\n"
                       "call   *%%rax\n"

                       /* Call _exit(%rax). */
                       "movq   %%rax,%%rdi\n"
                       "movq   %2,%%rax\n"
                       "syscall\n"

                       /* Return to parent. */
                     "1:\n"
                       : "=a" (res)
                       : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
                         "S"(child_stack),
                         "D"(flags),
                         "d"(parent_tidptr),
                         "r"(r8),
                         "r"(r10)
                       : "memory", "r11", "rcx");
  return res;
}
#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;
  // We don't have proper CFI directives here because it requires alot of code
  // for very marginal benefits.
  __asm__ __volatile__(
                       /* $v0 = syscall($v0 = __NR_clone,
                        * $a0 = flags,
                        * $a1 = child_stack,
                        * $a2 = parent_tidptr,
                        * $a3 = new_tls,
                        * $a4 = child_tidptr)
                        */
                       ".cprestore 16;\n"
                       "move $4,%1;\n"
                       "move $5,%2;\n"
                       "move $6,%3;\n"
                       "move $7,%4;\n"
                       /* Store the fifth argument on stack
                        * if we are using 32-bit abi.
                        */
#if SANITIZER_WORDSIZE == 32
                       "lw %5,16($29);\n"
#else
                       "move $8,%5;\n"
#endif
                       "li $2,%6;\n"
                       "syscall;\n"

                       /* if ($v0 != 0)
                        * return;
                        */
                       "bnez $2,1f;\n"

                       /* Call "fn(arg)". */
#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"

                       /* Call _exit($v0). */
                       "move $4,$2;\n"
                       "li $2,%7;\n"
                       "syscall;\n"

                       /* Return to parent. */
                     "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"

      /* if (a0 != 0)
       *   return a0;
       */
      "bnez a0, 1f\n"

      // In the child, now. Call "fn(arg)".
      "mv a0, a6\n"
      "jalr a5\n"

      // Call _exit(a0).
      "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" /* flags  */
                       "mov x2,x4\n" /* ptid  */
                       "mov x3,x5\n" /* tls  */
                       "mov x4,x6\n" /* ctid  */
                       "mov x8,%9\n" /* clone  */

                       "svc 0x0\n"

                       /* if (%r0 != 0)
                        *   return %r0;
                        */
                       "cmp x0, #0\n"
                       "bne 1f\n"

                       /* In the child, now. Call "fn(arg)". */
                       "ldp x1, x0, [sp], #16\n"
                       "blr x1\n"

                       /* Call _exit(%r0).  */
                       "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"

      // if ($a0 != 0)
      //   return $a0;
      "bnez $a0, 1f\n"

      // In the child, now. Call "fn(arg)".
      "move $a0, $a6\n"
      "jirl $ra, $a5, 0\n"

      // Call _exit($a0).
      "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;
// Stack frame structure.
#if SANITIZER_PPC64V1
//   Back chain == 0        (SP + 112)
// Frame (112 bytes):
//   Parameter save area    (SP + 48), 8 doublewords
//   TOC save area          (SP + 40)
//   Link editor doubleword (SP + 32)
//   Compiler doubleword    (SP + 24)
//   LR save area           (SP + 16)
//   CR save area           (SP + 8)
//   Back chain             (SP + 0)
# define FRAME_SIZE 112
# define FRAME_TOC_SAVE_OFFSET 40
#elif SANITIZER_PPC64V2
//   Back chain == 0        (SP + 32)
// Frame (32 bytes):
//   TOC save area          (SP + 24)
//   LR save area           (SP + 16)
//   CR save area           (SP + 8)
//   Back chain             (SP + 0)
# define FRAME_SIZE 32
# define FRAME_TOC_SAVE_OFFSET 24
#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__(
           /* fn and arg are saved across the syscall */
           "mr 28, %5\n\t"
           "mr 27, %8\n\t"

           /* syscall
             r0 == __NR_clone
             r3 == flags
             r4 == child_stack
             r5 == parent_tidptr
             r6 == newtls
             r7 == child_tidptr */
           "mr 3, %7\n\t"
           "mr 5, %9\n\t"
           "mr 6, %10\n\t"
           "mr 7, %11\n\t"
           "li 0, %3\n\t"
           "sc\n\t"

           /* Test if syscall was successful */
           "cmpdi  cr1, 3, 0\n\t"
           "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
           "bne-   cr1, 1f\n\t"

           /* Set up stack frame */
           "li    29, 0\n\t"
           "stdu  29, -8(1)\n\t"
           "stdu  1, -%12(1)\n\t"
           /* Do the function call */
           "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"

           /* Call _exit(r3) */
           "li 0, %4\n\t"
           "sc\n\t"

           /* Return to parent */
           "1:\n\t"
           "mr %0, 3\n\t"
             : "=r" (res)
             : "0" (-1),
               "i" (EINVAL),
               "i" (__NR_clone),
               "i" (__NR_exit),
               "r" (__fn),
               "r" (__cstack),
               "r" (__flags),
               "r" (__arg),
               "r" (__ptidptr),
               "r" (__newtls),
               "r" (__ctidptr),
               "i" (FRAME_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__(
                       /* %eax = syscall(%eax = SYSCALL(clone),
                        *                %ebx = flags,
                        *                %ecx = child_stack,
                        *                %edx = parent_tidptr,
                        *                %esi  = new_tls,
                        *                %edi = child_tidptr)
                        */

                        /* Obtain flags */
                        "movl    (%%ecx), %%ebx\n"
                        /* Do the system call */
                        "pushl   %%ebx\n"
                        "pushl   %%esi\n"
                        "pushl   %%edi\n"
                        /* Remember the flag value.  */
                        "movl    %%ebx, (%%ecx)\n"
                        "int     $0x80\n"
                        "popl    %%edi\n"
                        "popl    %%esi\n"
                        "popl    %%ebx\n"

                        /* if (%eax != 0)
                         *   return;
                         */

                        "test    %%eax,%%eax\n"
                        "jnz    1f\n"

                        /* terminate the stack frame */
                        "xorl   %%ebp,%%ebp\n"
                        /* Call FN. */
                        "call    *%%ebx\n"
#ifdef PIC
                        "call    here\n"
                        "here:\n"
                        "popl    %%ebx\n"
                        "addl    $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
#endif
                        /* Call exit */
                        "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(R) "blx "  #R "\n"
# else
#  define BLX(R) "mov lr, pc; bx " #R "\n"
# endif
#else
# define BLX(R)  "mov lr, pc; mov pc," #R "\n"
#endif

  __asm__ __volatile__(
                       /* %r0 = syscall(%r7 = SYSCALL(clone),
                        *               %r0 = flags,
                        *               %r1 = child_stack,
                        *               %r2 = parent_tidptr,
                        *               %r3  = new_tls,
                        *               %r4 = child_tidptr)
                        */

                       /* Do the system call */
                       "swi 0x0\n"

                       /* if (%r0 != 0)
                        *   return %r0;
                        */
                       "cmp r0, #0\n"
                       "bne 1f\n"

                       /* In the child, now. Call "fn(arg)". */
                       "ldr r0, [sp, #4]\n"
                       "ldr ip, [sp], #8\n"
                       BLX(ip)
                       /* Call _exit(%r0). */
                       "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  // SANITIZER_LINUX

#if SANITIZER_LINUX
int internal_uname(struct utsname *buf) {
  return internal_syscall(SYSCALL(uname), 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) {
  // Any name starting with "lib" indicates a bug in L where library base names
  // are returned instead of paths.
  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; // K or lower
  bool base_name_seen = false;
  dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
  if (base_name_seen)
    return ANDROID_LOLLIPOP_MR1; // L MR1
  return ANDROID_POST_LOLLIPOP;   // post-L
  // Plain L (API level 21) is completely broken wrt ASan and not very
  // interesting to detect.
}

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) {
  switch (signum) {
    case SIGABRT:
      return common_flags()->handle_abort;
    case SIGILL:
      return common_flags()->handle_sigill;
    case SIGTRAP:
      return common_flags()->handle_sigtrap;
    case SIGFPE:
      return common_flags()->handle_sigfpe;
    case SIGSEGV:
      return common_flags()->handle_segv;
    case SIGBUS:
      return common_flags()->handle_sigbus;
  }
  return kHandleSignalNo;
}

HandleSignalMode GetHandleSignalMode(int signum) {
  HandleSignalMode result = GetHandleSignalModeImpl(signum);
  if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)
    return kHandleSignalExclusive;
  return result;
}

#if !SANITIZER_GO
void *internal_start_thread(void *(*func)(void *arg), void *arg) {
  if (&real_pthread_create == 0)
    return nullptr;
  // Start the thread with signals blocked, otherwise it can steal user signals.
  ScopedBlockSignals block(nullptr);
  void *th;
  real_pthread_create(&th, nullptr, func, arg);
  return th;
}

void internal_join_thread(void *th) {
  if (&real_pthread_join)
    real_pthread_join(th, nullptr);
}
#else
void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }

void internal_join_thread(void *th) {}
#endif

#if SANITIZER_LINUX && defined(__aarch64__)
// Android headers in the older NDK releases miss this definition.
#if SANITIZER_LINUX
struct __sanitizer_esr_context {
  struct _aarch64_ctx head;
  uint64_t esr;
};
#endif

static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
#if SANITIZER_LINUX
  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;
  }
#endif
  return false;
}
#elif (SANITIZER_FREEBSD || SANITIZER_NETBSD) && defined(__aarch64__)
// FreeBSD/NetBSD don't provide ESR in the ucontext.
static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
  return false;
}
#endif

using Context = ucontext_t;

SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
  Context *ucontext = (Context *)context;
#if defined(__x86_64__) || defined(__i386__)
  static const uptr PF_WRITE = 1U << 1;
#if SANITIZER_FREEBSD
  uptr err = ucontext->uc_mcontext.mc_err;
#elif SANITIZER_NETBSD
  uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
#elif SANITIZER_SOLARIS && defined(__i386__)
  const int Err = 13;
  uptr err = ucontext->uc_mcontext.gregs[Err];
#else
  uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
#endif // SANITIZER_FREEBSD
  return err & PF_WRITE ? Write : Read;
#elif defined(__mips__)
  uint32_t *exception_source;
  uint32_t faulty_instruction;
  uint32_t op_code;

#if SANITIZER_NETBSD
  ucontext_t *nucontext = (ucontext_t *)ucontext;
  exception_source = (uint32_t *)_UC_MACHINE_PC(nucontext);
#else
  exception_source = (uint32_t *)ucontext->uc_mcontext.pc;
#endif
  faulty_instruction = (uint32_t)(*exception_source);

  op_code = (faulty_instruction >> 26) & 0x3f;

  // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions.
  switch (op_code) {
    case 0x28:  // sb
    case 0x29:  // sh
    case 0x2b:  // sw
    case 0x3f:  // sd
#if __mips_isa_rev < 6
    case 0x2c:  // sdl
    case 0x2d:  // sdr
    case 0x2a:  // swl
    case 0x2e:  // swr
#endif
      return SignalContext::Write;

    case 0x20:  // lb
    case 0x24:  // lbu
    case 0x21:  // lh
    case 0x25:  // lhu
    case 0x23:  // lw
    case 0x27:  // lwu
    case 0x37:  // ld
#if __mips_isa_rev < 6
    case 0x1a:  // ldl
    case 0x1b:  // ldr
    case 0x22:  // lwl
    case 0x26:  // lwr
#endif
      return SignalContext::Read;
#if __mips_isa_rev == 6
    case 0x3b:  // pcrel
      op_code = (faulty_instruction >> 19) & 0x3;
      switch (op_code) {
        case 0x1:  // lwpc
        case 0x2:  // lwupc
          return SignalContext::Read;
      }
#endif
  }
  return SignalContext::Unknown;
#elif defined(__arm__) && !SANITIZER_NETBSD
  static const uptr FSR_WRITE = 1U << 11;
  uptr fsr = ucontext->uc_mcontext.error_code;
  return fsr & FSR_WRITE ? Write : Read;
#elif defined(__aarch64__)
  static const u64 ESR_ELx_WNR = 1U << 6;
  u64 esr;
  if (!Aarch64GetESR(ucontext, &esr)) return Unknown;
  return esr & ESR_ELx_WNR ? Write : Read;
#elif defined(__loongarch__)
  u32 flags = ucontext->uc_mcontext.__flags;
  if (flags & SC_ADDRERR_RD)
    return SignalContext::Read;
  if (flags & SC_ADDRERR_WR)
    return SignalContext::Write;
  return SignalContext::Unknown;
#elif defined(__sparc__)
  // Decode the instruction to determine the access type.
  // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype).
#if SANITIZER_SOLARIS
  uptr pc = ucontext->uc_mcontext.gregs[REG_PC];
#elif SANITIZER_NETBSD
  uptr pc = ucontext->uc_mcontext.__gregs[_REG_PC];
#else
  // Historical BSDism here.
  struct sigcontext *scontext = (struct sigcontext *)context;
#if defined(__arch64__)
  uptr pc = scontext->sigc_regs.tpc;
#else
  uptr pc = scontext->si_regs.pc;
#endif
#endif
  u32 instr = *(u32 *)pc;
  return (instr >> 21) & 1 ? Write: Read;
#elif defined(__riscv)
#if SANITIZER_FREEBSD
  unsigned long pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
#elif SANITIZER_NETBSD
  uptr pc = ucontext->uc_mcontext.__gregs[_REG_PC];
#else
  unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
#endif
  unsigned faulty_instruction = *(uint16_t *)pc;

#if defined(__riscv_compressed)
  if ((faulty_instruction & 0x3) != 0x3) {  // it's a compressed instruction
    // set op_bits to the instruction bits [1, 0, 15, 14, 13]
    unsigned op_bits =
        ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
    unsigned rd = faulty_instruction & 0xF80;  // bits 7-11, inclusive
    switch (op_bits) {
      case 0b10'010:  // c.lwsp (rd != x0)
#if __riscv_xlen == 64
      case 0b10'011:  // c.ldsp (rd != x0)
#endif
        return rd ? SignalContext::Read : SignalContext::Unknown;
      case 0b00'010:  // c.lw
#if __riscv_flen >= 32 && __riscv_xlen == 32
      case 0b10'011:  // c.flwsp
#endif
#if __riscv_flen >= 32 || __riscv_xlen == 64
      case 0b00'011:  // c.flw / c.ld
#endif
#if __riscv_flen == 64
      case 0b00'001:  // c.fld
      case 0b10'001:  // c.fldsp
#endif
        return SignalContext::Read;
      case 0b00'110:  // c.sw
      case 0b10'110:  // c.swsp
#if __riscv_flen >= 32 || __riscv_xlen == 64
      case 0b00'111:  // c.fsw / c.sd
      case 0b10'111:  // c.fswsp / c.sdsp
#endif
#if __riscv_flen == 64
      case 0b00'101:  // c.fsd
      case 0b10'101:  // c.fsdsp
#endif
        return SignalContext::Write;
      default:
        return SignalContext::Unknown;
    }
  }
#endif

  unsigned opcode = faulty_instruction & 0x7f;         // lower 7 bits
  unsigned funct3 = (faulty_instruction >> 12) & 0x7;  // bits 12-14, inclusive
  switch (opcode) {
    case 0b0000011:  // loads
      switch (funct3) {
        case 0b000:  // lb
        case 0b001:  // lh
        case 0b010:  // lw
#if __riscv_xlen == 64
        case 0b011:  // ld
#endif
        case 0b100:  // lbu
        case 0b101:  // lhu
          return SignalContext::Read;
        default:
          return SignalContext::Unknown;
      }
    case 0b0100011:  // stores
      switch (funct3) {
        case 0b000:  // sb
        case 0b001:  // sh
        case 0b010:  // sw
#if __riscv_xlen == 64
        case 0b011:  // sd
#endif
          return SignalContext::Write;
        default:
          return SignalContext::Unknown;
      }
#if __riscv_flen >= 32
    case 0b0000111:  // floating-point loads
      switch (funct3) {
        case 0b010:  // flw
#if __riscv_flen == 64
        case 0b011:  // fld
#endif
          return SignalContext::Read;
        default:
          return SignalContext::Unknown;
      }
    case 0b0100111:  // floating-point stores
      switch (funct3) {
        case 0b010:  // fsw
#if __riscv_flen == 64
        case 0b011:  // fsd
#endif
          return SignalContext::Write;
        default:
          return SignalContext::Unknown;
      }
#endif
    default:
      return SignalContext::Unknown;
  }
#else
  (void)ucontext;
  return Unknown;  // FIXME: Implement.
#endif
}

bool SignalContext::IsTrueFaultingAddress() const {
  auto si = static_cast<const siginfo_t *>(siginfo);
  // SIGSEGV signals without a true fault address have si_code set to 128.
  return si->si_signo == SIGSEGV && si->si_code != 128;
}

void SignalContext::DumpAllRegisters(void *context) {
  // FIXME: Implement this.
}

static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if SANITIZER_NETBSD
  // This covers all NetBSD architectures
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = _UC_MACHINE_PC(ucontext);
  *bp = _UC_MACHINE_FP(ucontext);
  *sp = _UC_MACHINE_SP(ucontext);
#elif defined(__arm__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.arm_pc;
  *bp = ucontext->uc_mcontext.arm_fp;
  *sp = ucontext->uc_mcontext.arm_sp;
#elif defined(__aarch64__)
# if SANITIZER_FREEBSD
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.mc_gpregs.gp_elr;
  *bp = ucontext->uc_mcontext.mc_gpregs.gp_x[29];
  *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
# else
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.pc;
  *bp = ucontext->uc_mcontext.regs[29];
  *sp = ucontext->uc_mcontext.sp;
# endif
#elif defined(__hppa__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.sc_iaoq[0];
  /* GCC uses %r3 whenever a frame pointer is needed.  */
  *bp = ucontext->uc_mcontext.sc_gr[3];
  *sp = ucontext->uc_mcontext.sc_gr[30];
#elif defined(__x86_64__)
# if SANITIZER_FREEBSD
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.mc_rip;
  *bp = ucontext->uc_mcontext.mc_rbp;
  *sp = ucontext->uc_mcontext.mc_rsp;
# else
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
# endif
#elif defined(__i386__)
# if SANITIZER_FREEBSD
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.mc_eip;
  *bp = ucontext->uc_mcontext.mc_ebp;
  *sp = ucontext->uc_mcontext.mc_esp;
# else
  ucontext_t *ucontext = (ucontext_t*)context;
# if SANITIZER_SOLARIS
  /* Use the numeric values: the symbolic ones are undefined by llvm
     include/llvm/Support/Solaris.h.  */
# ifndef REG_EIP
#  define REG_EIP 14 // REG_PC
# endif
# ifndef REG_EBP
#  define REG_EBP  6 // REG_FP
# endif
# ifndef REG_UESP
#  define REG_UESP 17 // REG_SP
# endif
# endif
  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
  *sp = ucontext->uc_mcontext.gregs[REG_UESP];
# endif
#elif defined(__powerpc__) || defined(__powerpc64__)
#    if SANITIZER_FREEBSD
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.mc_srr0;
  *sp = ucontext->uc_mcontext.mc_frame[1];
  *bp = ucontext->uc_mcontext.mc_frame[31];
#    else
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.regs->nip;
  *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
  // The powerpc{,64}-linux ABIs do not specify r31 as the frame
  // pointer, but GCC always uses r31 when we need a frame pointer.
  *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
#    endif
#elif defined(__sparc__)
#if defined(__arch64__) || defined(__sparcv9)
#define STACK_BIAS 2047
#else
#define STACK_BIAS 0
# endif
# if SANITIZER_SOLARIS
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.gregs[REG_PC];
  *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS;
#else
  // Historical BSDism here.
  struct sigcontext *scontext = (struct sigcontext *)context;
#if defined(__arch64__)
  *pc = scontext->sigc_regs.tpc;
  *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS;
#else
  *pc = scontext->si_regs.pc;
  *sp = scontext->si_regs.u_regs[14];
#endif
# endif
  *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS;
#elif defined(__mips__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.pc;
  *bp = ucontext->uc_mcontext.gregs[30];
  *sp = ucontext->uc_mcontext.gregs[29];
#elif defined(__s390__)
  ucontext_t *ucontext = (ucontext_t*)context;
# if defined(__s390x__)
  *pc = ucontext->uc_mcontext.psw.addr;
# else
  *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff;
# endif
  *bp = ucontext->uc_mcontext.gregs[11];
  *sp = ucontext->uc_mcontext.gregs[15];
#elif defined(__riscv)
  ucontext_t *ucontext = (ucontext_t*)context;
#    if SANITIZER_FREEBSD
  *pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
  *bp = ucontext->uc_mcontext.mc_gpregs.gp_s[0];
  *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
#    else
  *pc = ucontext->uc_mcontext.__gregs[REG_PC];
  *bp = ucontext->uc_mcontext.__gregs[REG_S0];
  *sp = ucontext->uc_mcontext.__gregs[REG_SP];
#    endif
#  elif defined(__hexagon__)
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.pc;
  *bp = ucontext->uc_mcontext.r30;
  *sp = ucontext->uc_mcontext.r29;
#  elif defined(__loongarch__)
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.__pc;
  *bp = ucontext->uc_mcontext.__gregs[22];
  *sp = ucontext->uc_mcontext.__gregs[3];
#  else
#    error "Unsupported arch"
#  endif
}

void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }

void InitializePlatformEarly() {
  // Do nothing.
}

void CheckASLR() {
#if SANITIZER_NETBSD
  int mib[3];
  int paxflags;
  uptr len = sizeof(paxflags);

  mib[0] = CTL_PROC;
  mib[1] = internal_getpid();
  mib[2] = PROC_PID_PAXFLAGS;

  if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) {
    Printf("sysctl failed\n");
    Die();
  }

  if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
    Printf("This sanitizer is not compatible with enabled ASLR.\n"
           "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
           GetArgv()[0]);
    Die();
  }
#elif SANITIZER_FREEBSD
  int aslr_status;
  int r = internal_procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status);
  if (UNLIKELY(r == -1)) {
    // We're making things less 'dramatic' here since
    // the cmd is not necessarily guaranteed to be here
    // just yet regarding FreeBSD release
    return;
  }
  if ((aslr_status & PROC_ASLR_ACTIVE) != 0) {
    Printf("This sanitizer is not compatible with enabled ASLR "
           "and binaries compiled with PIE\n");
    Die();
  }
#  elif SANITIZER_PPC64V2
  // Disable ASLR for Linux PPC64LE.
  int old_personality = personality(0xffffffff);
  if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) {
    VReport(1,
            "WARNING: Program is being run with address space layout "
            "randomization (ASLR) enabled which prevents the thread and "
            "memory sanitizers from working on powerpc64le.\n"
            "ASLR will be disabled and the program re-executed.\n");
    CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
    ReExec();
  }
#  else
  // Do nothing
#  endif
}

void CheckMPROTECT() {
#if SANITIZER_NETBSD
  int mib[3];
  int paxflags;
  uptr len = sizeof(paxflags);

  mib[0] = CTL_PROC;
  mib[1] = internal_getpid();
  mib[2] = PROC_PID_PAXFLAGS;

  if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) {
    Printf("sysctl failed\n");
    Die();
  }

  if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) {
    Printf("This sanitizer is not compatible with enabled MPROTECT\n");
    Die();
  }
#else
  // Do nothing
#endif
}

void CheckNoDeepBind(const char *filename, int flag) {
#ifdef RTLD_DEEPBIND
  if (flag & RTLD_DEEPBIND) {
    Report(
        "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag"
        " which is incompatible with sanitizer runtime "
        "(see https://github.com/google/sanitizers/issues/611 for details"
        "). If you want to run %s library under sanitizers please remove "
        "RTLD_DEEPBIND from dlopen flags.\n",
        filename, filename);
    Die();
  }
#endif
}

uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
                              uptr *largest_gap_found,
                              uptr *max_occupied_addr) {
  UNREACHABLE("FindAvailableMemoryRange is not available");
  return 0;
}

bool GetRandom(void *buffer, uptr length, bool blocking) {
  if (!buffer || !length || length > 256)
    return false;
#if SANITIZER_USE_GETENTROPY
  uptr rnd = getentropy(buffer, length);
  int rverrno = 0;
  if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT)
    return false;
  else if (rnd == 0)
    return true;
#endif // SANITIZER_USE_GETENTROPY

#if SANITIZER_USE_GETRANDOM
  static atomic_uint8_t skip_getrandom_syscall;
  if (!atomic_load_relaxed(&skip_getrandom_syscall)) {
    // Up to 256 bytes, getrandom will not be interrupted.
    uptr res = internal_syscall(SYSCALL(getrandom), buffer, length,
                                blocking ? 0 : GRND_NONBLOCK);
    int rverrno = 0;
    if (internal_iserror(res, &rverrno) && rverrno == ENOSYS)
      atomic_store_relaxed(&skip_getrandom_syscall, 1);
    else if (res == length)
      return true;
  }
#endif // SANITIZER_USE_GETRANDOM
  // Up to 256 bytes, a read off /dev/urandom will not be interrupted.
  // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom.
  uptr fd = internal_open("/dev/urandom", O_RDONLY);
  if (internal_iserror(fd))
    return false;
  uptr res = internal_read(fd, buffer, length);
  if (internal_iserror(res))
    return false;
  internal_close(fd);
  return true;
}

} // namespace __sanitizer

#endif
@


1.11
log
@fix netbsd/arm64 support

only built on arm64eb so far, as arm64el has a libgcc vs ctf issue.
@
text
@d1966 1
a1966 1
// FreeBSD doesn't provide ESR in the ucontext.
@


1.10
log
@avoid linux/mips-isms.
@
text
@d1965 1
a1965 1
#elif SANITIZER_FREEBSD && defined(__aarch64__)
@


1.9
log
@some sanitizer ports updates.

- use the 32-bit OK kMaxAllowedMallocSize for !_LP64 ports
- fix an argument type to internal_sysctl()
- use -Wno-format on sparc and sparc64

the latter will probably be necessary for more ports, and maybe a more
correct solution will be better, from new comment:

# XXX GCC 14 hard codes types and printf formats causing various errors,
# so this is the ugly method to avoid it.
#
# XXX If this list gets too huge, consider removing it, or at least moving
# into per-file issues (there are a lot of files.)
@
text
@d37 1
a37 1
#if SANITIZER_MIPS64
@


1.8
log
@fix merge botch.
@
text
@d682 1
a682 1
  size_t size;
@


1.7
log
@merge GCC 14.3.0.
@
text
@a51 1
#endif
@


1.6
log
@Can't use __ps_strings because we are called from a constructor and rtld
has not ran the csu code yes to initialize __ps_strings.
@
text
@d37 1
a37 2
#if SANITIZER_LINUX
#if defined(__mips64)
d86 4
d92 1
d136 3
a138 2
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) ||       \
                        SANITIZER_WORDSIZE == 64)
d164 2
a165 2
void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *old) {
  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, old));
d168 1
a168 1
ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
d177 11
a187 1
  SetSigProcMask(&set, &saved_);
d204 2
d252 1
a252 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d260 1
a260 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d289 1
a289 1
#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
d308 23
a330 1
#if defined(__mips64)
d381 1
a381 1
#if SANITIZER_FREEBSD
d383 10
a392 1
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d395 5
a399 6
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
# if defined(__mips64)
  // For mips64, stat syscall fills buffer in the format of kernel_stat
  struct kernel_stat kbuf;
  int res = internal_syscall(SYSCALL(stat), path, &kbuf);
  kernel_stat_to_stat(&kbuf, (struct stat *)buf);
d401 2
a402 4
# else
  return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf);
# endif
#else
d407 1
a407 1
#endif
d411 1
a411 1
#if SANITIZER_FREEBSD
d414 11
a424 1
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d427 5
a431 6
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
# if SANITIZER_MIPS64
  // For mips64, lstat syscall fills buffer in the format of kernel_stat
  struct kernel_stat kbuf;
  int res = internal_syscall(SYSCALL(lstat), path, &kbuf);
  kernel_stat_to_stat(&kbuf, (struct stat *)buf);
d433 2
a434 4
# else
  return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf);
# endif
#else
d439 1
a439 1
#endif
d450 7
a456 1
# else
d458 1
a458 1
# endif
d479 1
a479 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d487 1
a487 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d496 1
a496 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d504 1
a504 1
#if defined(__riscv) && defined(__linux__)
d507 1
a507 1
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d510 1
a510 1
#else
d512 1
a512 1
#endif
a548 3
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
  if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0))
#else
a549 1
#endif
d555 8
a562 1
#if !SANITIZER_NETBSD
d796 1
a796 1
#if SANITIZER_X32 || defined(__aarch64__) || SANITIZER_RISCV64
d799 1
a799 1
#else
d802 1
a802 1
#endif
d804 1
a804 1
#if defined(__aarch64__) || SANITIZER_RISCV64
d806 1
a806 1
#endif
d842 1
a842 1
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d844 1
a844 1
#else
d846 1
a846 1
#endif
d857 8
a864 1
#endif
d871 4
a874 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d876 2
a877 1
#else
d879 1
a879 1
#endif
d1007 4
d1152 1
a1152 1
# if defined(__powerpc64__) || defined(__aarch64__)
d1160 1
d1164 1
a1164 1
# elif defined(__mips64)
d1501 1
a1501 1
  long long res;
d1549 41
d1922 2
d1932 2
a1933 1
  real_pthread_join(th, nullptr);
d1941 1
a1941 1
#if defined(__aarch64__)
d1966 5
d1989 1
a1989 1
  return err & PF_WRITE ? WRITE : READ;
d2017 1
a2017 1
      return SignalContext::WRITE;
d2032 1
a2032 1
      return SignalContext::READ;
d2039 1
a2039 1
          return SignalContext::READ;
d2043 1
a2043 1
  return SignalContext::UNKNOWN;
d2047 1
a2047 1
  return fsr & FSR_WRITE ? WRITE : READ;
d2051 9
a2059 2
  if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN;
  return esr & ESR_ELx_WNR ? WRITE : READ;
d2077 1
a2077 1
  return (instr >> 21) & 1 ? WRITE: READ;
d2099 1
a2099 1
        return rd ? SignalContext::READ : SignalContext::UNKNOWN;
d2111 1
a2111 1
        return SignalContext::READ;
d2122 1
a2122 1
        return SignalContext::WRITE;
d2124 1
a2124 1
        return SignalContext::UNKNOWN;
d2142 1
a2142 1
          return SignalContext::READ;
d2144 1
a2144 1
          return SignalContext::UNKNOWN;
d2154 1
a2154 1
          return SignalContext::WRITE;
d2156 1
a2156 1
          return SignalContext::UNKNOWN;
d2165 1
a2165 1
          return SignalContext::READ;
d2167 1
a2167 1
          return SignalContext::UNKNOWN;
d2175 1
a2175 1
          return SignalContext::WRITE;
d2177 1
a2177 1
          return SignalContext::UNKNOWN;
d2181 1
a2181 1
      return SignalContext::UNKNOWN;
d2185 1
a2185 1
  return UNKNOWN;  // FIXME: Implement.
d2212 6
d2222 1
d2267 6
d2279 1
d2332 5
a2347 4
void MaybeReexec() {
  // No need to re-exec on Linux.
}

a2368 11
#elif SANITIZER_PPC64V2
  // Disable ASLR for Linux PPC64LE.
  int old_personality = personality(0xffffffff);
  if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) {
    VReport(1, "WARNING: Program is being run with address space layout "
               "randomization (ASLR) enabled which prevents the thread and "
               "memory sanitizers from working on powerpc64le.\n"
               "ASLR will be disabled and the program re-executed.\n");
    CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
    ReExec();
  }
d2370 3
a2372 5
  int aslr_pie;
  uptr len = sizeof(aslr_pie);
#if SANITIZER_WORDSIZE == 64
  if (UNLIKELY(internal_sysctlbyname("kern.elf64.aslr.pie_enable",
      &aslr_pie, &len, NULL, 0) == -1)) {
d2374 1
a2374 1
    // the OID is not necessarily guaranteed to be here
d2378 1
a2378 2

  if (aslr_pie > 0) {
d2383 11
a2393 5
#endif
  // there might be 32 bits compat for 64 bits
  if (UNLIKELY(internal_sysctlbyname("kern.elf32.aslr.pie_enable",
      &aslr_pie, &len, NULL, 0) == -1)) {
    return;
d2395 1
a2395 7

  if (aslr_pie > 0) {
    Printf("This sanitizer is not compatible with enabled ASLR "
           "and binaries compiled with PIE\n");
    Die();
  }
#else
d2397 1
a2397 1
#endif
@


1.5
log
@make sanitizers build for some more platforms

m68k (but not m68000), riscv{32,64}, and arm32.
@
text
@d618 35
d667 2
a668 2
  *argv = __ps_strings->ps_argvstr;
  *envp = __ps_strings->ps_envstr;
@


1.5.2.1
log
@Sync with HEAD
@
text
@a617 35
#if SANITIZER_NETBSD
static char **
load_vector(int m)
{
  size_t size;
  int nv;
  char **v, **ap, *bp, *buf, *endp;
  int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), 0};
  size = sizeof(nv);
  mib[3] = m == KERN_PROC_ARGV ? KERN_PROC_NARGV : KERN_PROC_NENV;
  if (internal_sysctl(mib, 4, &nv, &size, NULL, 0) == -1) {
    Printf("sysctl KERN_PROC_N{ARGV,ENV} failed\n");
    Die();
  }
  v = (char **)MmapOrDie((nv + 1) * sizeof(char *), "Arg vector");
  buf = (char *)MmapOrDie(ARG_MAX, "Arg space");
  size = ARG_MAX;
  mib[3] = m;
  if (internal_sysctl(mib, 4, buf, &size, NULL, 0) == -1) {
    Printf("sysctl KERN_PROC_{ARGV,ENV} failed\n");
    Die();
  }
  bp = buf;
  ap = v;
  endp = bp + size;

  while (bp < endp) {
    *ap++ = bp;
    bp += internal_strlen(bp) + 1;
  }
  *ap = NULL;
  return v;
}
#endif

d632 2
a633 2
  *argv = load_vector(KERN_PROC_ARGV);
  *envp = load_vector(KERN_PROC_ENV);
@


1.4
log
@many fixes for native GCC 12 builds

- default to dwarf4 since out ctf tools fail with dwarf5.  i tried to
  do this via subtarget options as other ports do, but this would
  require adjusting several of the targets non-netbsd code, and ideally
  we'll fix our tools sooner than later, so just hack it here for now.
- catch up config/rs6000/netbsd64.h (mostly delete things)
- remove some more upstream diffs in config/vax, though it does not work
  currently - libc.so link fails due to weird relocations.
- include some headers to ensure types are available
- add missing sanitizer netbsd files to the 'dist' tree
- remove no longer present TIOCRCVFRAME and TIOCXMTFRAME interceptors
- expanding the sanitizer OS/cpu defs to cover more netbsd platforms
- copy across a few minor changes from gcc.old's sanitizer's (eg,
  disabling linux-specific code, adding netbsd specific code.)
- add (untested, but building) tsan support for arm64
- re-enable the sanitzers, at least simple -fsanitize=address builds a
  working application on amd64 now
- fix the source lists (mostly .cc -> .cpp rename here)
- add some missing new defines, -f*, and -W*
- bump sanitizer shlib version
- apply -fno-jump-tables in some more places on m68k
- update the list in README.gcc12 to note many things now work or a few
  things to do not work (although there are many uncommited changes at
  this point across the rest of 'src' and 'xsrc'.)  main points are that
  vax, hppa, ppc, and sh3 don't build yet, but most other things are
  either testing and working or at least building.
@
text
@d1883 1
a1883 1
#elif defined(__arm__)
d1913 2
@


1.3
log
@make this actually be GCC 12.3.0's libsanitizer.

the libsanitizer we used with GCC 9 and GCC 10 was significantly
ahead of the GCC 9 and GCC 10 provided versions.
@
text
@d37 1
d53 5
d1787 1
d1792 1
d1795 1
d1807 1
d1834 4
d1839 1
d1897 2
@


1.2
log
@revert sanitizer back to the version we were using with GCC 9, since
that one was already newer than the GCC 10 version.
@
text
@d17 1
a17 1
    SANITIZER_OPENBSD || SANITIZER_SOLARIS
d29 1
a29 1
#if SANITIZER_LINUX
d41 8
a69 1
#if !SANITIZER_OPENBSD
a70 5
#endif
#if SANITIZER_OPENBSD
#include <sys/futex.h>
#include <sys/sysctl.h>
#endif
d134 1
a134 1
// Linux and OpenBSD apis, available from
d145 2
a146 2
#if SANITIZER_OPENBSD
# define SANITIZER_USE_GETENTROPY 1
d148 2
a149 6
# if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000
#   define SANITIZER_USE_GETENTROPY 1
# else
#   define SANITIZER_USE_GETENTROPY 0
# endif
#endif // SANITIZER_USE_GETENTROPY
d153 33
a185 9
#if SANITIZER_LINUX && defined(__x86_64__)
#include "sanitizer_syscall_linux_x86_64.inc"
#elif SANITIZER_LINUX && defined(__aarch64__)
#include "sanitizer_syscall_linux_aarch64.inc"
#elif SANITIZER_LINUX && defined(__arm__)
#include "sanitizer_syscall_linux_arm.inc"
#else
#include "sanitizer_syscall_generic.inc"
#endif
d189 1
a189 1
#if !SANITIZER_S390 && !SANITIZER_OPENBSD
d191 1
a191 1
                   OFF_T offset) {
d202 1
a202 1
#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD
a203 1
#if !SANITIZER_OPENBSD
d208 8
d219 4
a222 1
#endif
d289 1
d293 1
d336 1
a336 1
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
d360 1
a360 1
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
d385 2
a386 3
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \
    SANITIZER_LINUX_USES_64BIT_SYSCALLS
#if SANITIZER_MIPS64 && !SANITIZER_OPENBSD
a425 3
#elif SANITIZER_OPENBSD
  return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf,
                          bufsize);
d432 1
a432 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD
d440 1
a440 1
#if defined(__riscv)
d443 1
a443 1
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD
d455 1
a455 10
void internal__exit(int exitcode) {
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
  internal_syscall(SYSCALL(exit), exitcode);
#else
  internal_syscall(SYSCALL(exit_group), exitcode);
#endif
  Die();  // Unreachable.
}

unsigned int internal_sleep(unsigned int seconds) {
d457 3
a459 5
  ts.tv_sec = seconds;
  ts.tv_nsec = 0;
  int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts);
  if (res) return ts.tv_sec;
  return 0;
d469 11
a500 2
#elif SANITIZER_OPENBSD
  return internal_syscall(SYSCALL(getthrid));
a512 3
#elif SANITIZER_OPENBSD
  (void)pid;
  return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr);
d520 1
a520 1
#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
a521 3
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
  timeval tv;
#else
a522 1
#endif
d525 1
a525 1
  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
d527 1
a527 1

d531 7
a537 1
#endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
d543 1
a543 2
#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \
    SANITIZER_SOLARIS
d581 1
a581 1
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD
d587 1
a587 2
#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD &&                \
    !SANITIZER_OPENBSD
a611 1
#if !SANITIZER_OPENBSD
a630 1
#endif // !SANITIZER_GO
d632 6
a637 1
    int argc = *stack_end;
a639 1
#if !SANITIZER_GO
d641 1
d645 1
a662 2
#endif  // !SANITIZER_OPENBSD

d664 8
a671 8
enum MutexState {
  MtxUnlocked = 0,
  MtxLocked = 1,
  MtxSleeping = 2
};

BlockingMutex::BlockingMutex() {
  internal_memset(this, 0, sizeof(*this));
d674 4
a677 25
void BlockingMutex::Lock() {
  CHECK_EQ(owner_, 0);
  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
  if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
    return;
  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
#if SANITIZER_FREEBSD
    _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
#elif SANITIZER_NETBSD
    sched_yield(); /* No userspace futex-like synchronization */
#else
    internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping,
                     0, 0, 0);
#endif
  }
}

void BlockingMutex::Unlock() {
  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
  u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
  CHECK_NE(v, MtxUnlocked);
  if (v == MtxSleeping) {
#if SANITIZER_FREEBSD
    _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
#elif SANITIZER_NETBSD
d679 3
a681 4
#else
    internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0);
#endif
  }
d684 1
a684 5
void BlockingMutex::CheckLocked() {
  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
  CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
}
#endif // !SANITIZER_SOLARIS
a691 10
#elif SANITIZER_OPENBSD
// struct dirent is different for Linux and us. At this moment, we use only
// d_fileno (Linux call this d_ino), d_reclen, and d_name.
struct linux_dirent {
  u64 d_ino;  // d_fileno
  u16 d_reclen;
  u16 d_namlen;  // not used
  u8 d_type;     // not used
  char d_name[NAME_MAX + 1];
};
d694 1
a694 1
#if SANITIZER_X32 || defined(__aarch64__)
d702 1
a702 1
#ifdef __aarch64__
d729 8
d769 1
a769 1
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
a771 4
#if SANITIZER_OPENBSD
  return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp,
                (size_t)newlen);
#else
a773 1
#endif
a775 1
#if SANITIZER_FREEBSD
d778 23
a800 5
  static decltype(sysctlbyname) *real = nullptr;
  if (!real)
    real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname");
  CHECK(real);
  return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen);
a802 1
#endif
d855 1
a855 1
#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
d860 2
a861 3
  return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how,
                          (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0],
                          sizeof(__sanitizer_kernel_sigset_t));
d881 1
a881 1
  k_set->sig[idx] &= ~(1 << bit);
d891 1
a891 1
  return k_set->sig[idx] & (1 << bit);
d1018 2
a1019 3
  if (!(pers & PER_MASK)
      && uname(&uname_info) == 0
      && internal_strstr(uname_info.machine, "64"))
d1032 1
a1032 1
#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__)
d1044 2
d1076 2
a1077 1
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
a1094 1
#if !SANITIZER_OPENBSD
a1130 1
#endif // !SANITIZER_OPENBSD
d1163 1
a1163 1
#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
d1166 1
a1166 1
#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
d1200 2
a1201 1
#if defined(__x86_64__) && SANITIZER_LINUX
d1339 41
d1540 1
a1540 1
#elif defined(__i386__) && SANITIZER_LINUX
d1605 1
a1605 1
#elif defined(__arm__) && SANITIZER_LINUX
d1671 8
a1678 1
#endif  // defined(__x86_64__) && SANITIZER_LINUX
d1762 1
a1762 1
void *internal_start_thread(void(*func)(void *arg), void *arg) {
d1764 1
a1764 8
  __sanitizer_sigset_t set, old;
  internal_sigfillset(&set);
#if SANITIZER_LINUX && !SANITIZER_ANDROID
  // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
  // on any thread, setuid call hangs (see test/tsan/setuid.c).
  internal_sigdelset(&set, 33);
#endif
  internal_sigprocmask(SIG_SETMASK, &set, &old);
d1766 1
a1766 2
  real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
  internal_sigprocmask(SIG_SETMASK, &old, nullptr);
d1774 1
a1774 1
void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
d1788 1
a1788 1
  u8 *aux = ucontext->uc_mcontext.__reserved;
a1801 3
#if SANITIZER_OPENBSD
using Context = sigcontext;
#else
a1802 1
#endif
a1811 2
#elif SANITIZER_OPENBSD
  uptr err = ucontext->sc_err;
d1893 103
a2040 5
#elif SANITIZER_OPENBSD
  sigcontext *ucontext = (sigcontext *)context;
  *pc = ucontext->sc_rip;
  *bp = ucontext->sc_rbp;
  *sp = ucontext->sc_rsp;
a2052 5
#elif SANITIZER_OPENBSD
  sigcontext *ucontext = (sigcontext *)context;
  *pc = ucontext->sc_eip;
  *bp = ucontext->sc_ebp;
  *sp = ucontext->sc_esp;
d2117 5
d2125 9
a2133 3
#else
# error "Unsupported arch"
#endif
d2162 3
a2164 1
    Printf("This sanitizer is not compatible with enabled ASLR\n");
a2235 2
void PrintModuleMap() { }

d2241 1
a2241 1
        " which is incompatibe with sanitizer runtime "
@


1.1
log
@Initial revision
@
text
@@


1.1.1.1
log
@initial import of GCC 10.3.0.  main changes include:

caveats:
- ABI issue between c++14 and c++17 fixed
- profile mode is removed from libstdc++
- -fno-common is now the default

new features:
- new flags -fallocation-dce, -fprofile-partial-training,
  -fprofile-reproducible, -fprofile-prefix-path, and -fanalyzer
- many new compile and link time optimisations
- enhanced drive optimisations
- openacc 2.6 support
- openmp 5.0 features
- new warnings: -Wstring-compare and -Wzero-length-bounds
- extended warnings: -Warray-bounds, -Wformat-overflow,
  -Wrestrict, -Wreturn-local-addr, -Wstringop-overflow,
  -Warith-conversion, -Wmismatched-tags, and -Wredundant-tags
- some likely C2X features implemented
- more C++20 implemented
- many new arm & intel CPUs known

hundreds of reported bugs are fixed.  full list of changes
can be found at:

   https://gcc.gnu.org/gcc-10/changes.html
@
text
@@


1.1.1.2
log
@initial import of GCC 12.3.0.

major changes in GCC 11 included:

- The default mode for C++ is now -std=gnu++17 instead of -std=gnu++14.
- When building GCC itself, the host compiler must now support C++11,
  rather than C++98.
- Some short options of the gcov tool have been renamed: -i to -j and
  -j to -H.
- ThreadSanitizer improvements.
- Introduce Hardware-assisted AddressSanitizer support.
- For targets that produce DWARF debugging information GCC now defaults
  to DWARF version 5. This can produce up to 25% more compact debug
  information compared to earlier versions.
- Many optimisations.
- The existing malloc attribute has been extended so that it can be
  used to identify allocator/deallocator API pairs. A pair of new
  -Wmismatched-dealloc and -Wmismatched-new-delete warnings are added.
- Other new warnings:
  -Wsizeof-array-div, enabled by -Wall, warns about divisions of two
    sizeof operators when the first one is applied to an array and the
    divisor does not equal the size of the array element.
  -Wstringop-overread, enabled by default, warns about calls to string
    functions reading past the end of the arrays passed to them as
    arguments.
  -Wtsan, enabled by default, warns about unsupported features in
    ThreadSanitizer (currently std::atomic_thread_fence).
- Enchanced warnings:
  -Wfree-nonheap-object detects many more instances of calls to
    deallocation functions with pointers not returned from a dynamic
    memory allocation function.
  -Wmaybe-uninitialized diagnoses passing pointers or references to
    uninitialized memory to functions taking const-qualified arguments.
  -Wuninitialized detects reads from uninitialized dynamically
    allocated memory.
  -Warray-parameter warns about functions with inconsistent array forms.
  -Wvla-parameter warns about functions with inconsistent VLA forms.
- Several new features from the upcoming C2X revision of the ISO C
  standard are supported with -std=c2x and -std=gnu2x.
- Several C++20 features have been implemented.
- The C++ front end has experimental support for some of the upcoming
  C++23 draft.
- Several new C++ warnings.
- Enhanced Arm, AArch64, x86, and RISC-V CPU support.
- The implementation of how program state is tracked within
  -fanalyzer has been completely rewritten with many enhancements.

see https://gcc.gnu.org/gcc-11/changes.html for a full list.

major changes in GCC 12 include:

- An ABI incompatibility between C and C++ when passing or returning
  by value certain aggregates containing zero width bit-fields has
  been discovered on various targets. x86-64, ARM and AArch64
  will always ignore them (so there is a C ABI incompatibility
  between GCC 11 and earlier with GCC 12 or later), PowerPC64 ELFv2
  always take them into account (so there is a C++ ABI
  incompatibility, GCC 4.4 and earlier compatible with GCC 12 or
  later, incompatible with GCC 4.5 through GCC 11). RISC-V has
  changed the handling of these already starting with GCC 10. As
  the ABI requires, MIPS takes them into account handling function
  return values so there is a C++ ABI incompatibility with GCC 4.5
  through 11.
- STABS: Support for emitting the STABS debugging format is
  deprecated and will be removed in the next release. All ports now
  default to emit DWARF (version 2 or later) debugging info or are
  obsoleted.
- Vectorization is enabled at -O2 which is now equivalent to the
  original -O2 -ftree-vectorize -fvect-cost-model=very-cheap.
- GCC now supports the ShadowCallStack sanitizer.
- Support for __builtin_shufflevector compatible with the clang
  language extension was added.
- Support for attribute unavailable was added.
- Support for __builtin_dynamic_object_size compatible with the
  clang language extension was added.
- New warnings:
  -Wbidi-chars warns about potentially misleading UTF-8
    bidirectional control characters.
  -Warray-compare warns about comparisons between two operands of
    array type.
- Some new features from the upcoming C2X revision of the ISO C
  standard are supported with -std=c2x and -std=gnu2x.
- Several C++23 features have been implemented.
- Many C++ enhancements across warnings and -f options.

see https://gcc.gnu.org/gcc-12/changes.html for a full list.
@
text
@d17 1
a17 1
    SANITIZER_SOLARIS
d29 1
a29 1
#if SANITIZER_LINUX && !SANITIZER_GO
a40 8
#if SANITIZER_GO
#undef st_atime
#undef st_mtime
#undef st_ctime
#define st_atime st_atim
#define st_mtime st_mtim
#define st_ctime st_ctim
#endif
d62 1
d64 5
d132 1
a132 1
// Linux apis, available from
d143 2
a144 2
#if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000
#  define SANITIZER_USE_GETENTROPY 1
d146 6
a151 2
#  define SANITIZER_USE_GETENTROPY 0
#endif
d155 9
a163 33
void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *old) {
  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, old));
}

ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
  __sanitizer_sigset_t set;
  internal_sigfillset(&set);
#  if SANITIZER_LINUX && !SANITIZER_ANDROID
  // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
  // on any thread, setuid call hangs.
  // See test/sanitizer_common/TestCases/Linux/setuid.c.
  internal_sigdelset(&set, 33);
#  endif
  SetSigProcMask(&set, &saved_);
  if (copy)
    internal_memcpy(copy, &saved_, sizeof(saved_));
}

ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }

#  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"
#  else
#    include "sanitizer_syscall_generic.inc"
#  endif
d167 1
a167 1
#if !SANITIZER_S390
d169 1
a169 1
                   u64 offset) {
d180 1
a180 1
#endif // !SANITIZER_S390
d182 1
a186 8
#if SANITIZER_LINUX
uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
                     void *new_address) {
  return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
                          new_size, flags, (uptr)new_address);
}
#endif

d190 1
a190 4

int internal_madvise(uptr addr, uptr length, int advice) {
  return internal_syscall(SYSCALL(madvise), addr, length, advice);
}
a256 1
#if !SANITIZER_GO
a259 1
#endif
d302 1
a302 1
#if SANITIZER_FREEBSD
d326 1
a326 1
#if SANITIZER_FREEBSD
d351 3
a353 2
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
#if SANITIZER_MIPS64
d393 3
d402 1
a402 1
#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d410 1
a410 1
#if defined(__riscv) && defined(__linux__)
d413 1
a413 1
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
d425 10
a434 1
void internal_usleep(u64 useconds) {
d436 5
a440 3
  ts.tv_sec = useconds / 1000000;
  ts.tv_nsec = (useconds % 1000000) * 1000;
  internal_syscall(SYSCALL(nanosleep), &ts, &ts);
a449 11
#if !SANITIZER_NETBSD
void internal__exit(int exitcode) {
#if SANITIZER_FREEBSD || SANITIZER_SOLARIS
  internal_syscall(SYSCALL(exit), exitcode);
#else
  internal_syscall(SYSCALL(exit_group), exitcode);
#endif
  Die();  // Unreachable.
}
#endif  // !SANITIZER_NETBSD

d471 2
d485 3
d495 1
a495 1
#if SANITIZER_GLIBC
d497 3
d501 1
d504 1
a504 1
  return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
d506 1
a506 1
// Used by real_clock_gettime.
d510 1
a510 7
#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
d516 2
a517 1
#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS
d555 1
a555 1
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO
d561 2
a562 1
#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
d587 1
d607 1
d609 1
a609 6
    // Normally argc can be obtained from *stack_end, however, on ARM glibc's
    // _start clobbers it:
    // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
    // Do not special-case ARM and infer argc from argv everywhere.
    int argc = 0;
    while (stack_end[argc + 1]) argc++;
d612 1
a613 1
#endif // !SANITIZER_GO
a616 1
#if !SANITIZER_GO
d634 2
d637 8
a644 8
void FutexWait(atomic_uint32_t *p, u32 cmp) {
#    if SANITIZER_FREEBSD
  _umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0);
#    elif SANITIZER_NETBSD
  sched_yield();   /* No userspace futex-like synchronization */
#    else
  internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0);
#    endif
d647 25
a671 4
void FutexWake(atomic_uint32_t *p, u32 count) {
#    if SANITIZER_FREEBSD
  _umtx_op(p, UMTX_OP_WAKE, count, 0, 0);
#    elif SANITIZER_NETBSD
d673 4
a676 3
#    else
  internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0);
#    endif
d679 5
a683 1
#  endif  // !SANITIZER_SOLARIS
d691 10
d703 1
a703 1
#if SANITIZER_X32 || defined(__aarch64__) || SANITIZER_RISCV64
d711 1
a711 1
#if defined(__aarch64__) || SANITIZER_RISCV64
a737 8
int internal_dlinfo(void *handle, int request, void *p) {
#if SANITIZER_FREEBSD
  return dlinfo(handle, request, p);
#else
  UNIMPLEMENTED();
#endif
}

d770 1
a770 1
#if SANITIZER_FREEBSD
d773 4
d779 1
d782 1
d785 6
a790 22
  // Note: this function can be called during startup, so we need to avoid
  // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname()
  // is a real syscall, but for older versions it calls sysctlnametomib()
  // followed by sysctl(). To avoid calling the intercepted version and
  // asserting if this happens during startup, call the real sysctlnametomib()
  // followed by internal_sysctl() if the syscall is not available.
#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);
a791 1
}
d845 1
a845 1
#if SANITIZER_FREEBSD
d850 3
a852 2
  return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set,
                          (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t));
d872 1
a872 1
  k_set->sig[idx] &= ~((uptr)1 << bit);
d882 1
a882 1
  return k_set->sig[idx] & ((uptr)1 << bit);
d1009 3
a1011 2
  if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
      internal_strstr(uname_info.machine, "64"))
d1024 1
a1024 1
#if SANITIZER_NETBSD && defined(__x86_64__)
a1035 2
#elif SANITIZER_RISCV64
  return (1ULL << 38) - 1;
d1066 1
a1066 2
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
    defined(EXEC_PAGESIZE)
d1084 1
d1121 1
d1154 1
a1154 1
#if !SANITIZER_FREEBSD
d1157 1
a1157 1
#endif // !SANITIZER_FREEBSD
d1191 1
a1191 2
#if SANITIZER_LINUX
#if defined(__x86_64__)
a1328 41
#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"

      /* if (a0 != 0)
       *   return a0;
       */
      "bnez a0, 1f\n"

      // In the child, now. Call "fn(arg)".
      "mv a0, a6\n"
      "jalr a5\n"

      // Call _exit(a0).
      "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;
}
d1489 1
a1489 1
#elif defined(__i386__)
d1554 1
a1554 1
#elif defined(__arm__)
d1620 1
a1620 8
#endif
#endif  // SANITIZER_LINUX

#if SANITIZER_LINUX
int internal_uname(struct utsname *buf) {
  return internal_syscall(SYSCALL(uname), buf);
}
#endif
d1704 1
a1704 1
void *internal_start_thread(void *(*func)(void *arg), void *arg) {
d1706 8
a1713 1
  ScopedBlockSignals block(nullptr);
d1715 2
a1716 1
  real_pthread_create(&th, nullptr, func, arg);
d1724 1
a1724 1
void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
d1738 1
a1738 1
  u8 *aux = reinterpret_cast<u8 *>(ucontext->uc_mcontext.__reserved);
d1752 3
d1756 1
d1766 2
a1848 103
#elif defined(__riscv)
#if SANITIZER_FREEBSD
  unsigned long pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
#else
  unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
#endif
  unsigned faulty_instruction = *(uint16_t *)pc;

#if defined(__riscv_compressed)
  if ((faulty_instruction & 0x3) != 0x3) {  // it's a compressed instruction
    // set op_bits to the instruction bits [1, 0, 15, 14, 13]
    unsigned op_bits =
        ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
    unsigned rd = faulty_instruction & 0xF80;  // bits 7-11, inclusive
    switch (op_bits) {
      case 0b10'010:  // c.lwsp (rd != x0)
#if __riscv_xlen == 64
      case 0b10'011:  // c.ldsp (rd != x0)
#endif
        return rd ? SignalContext::READ : SignalContext::UNKNOWN;
      case 0b00'010:  // c.lw
#if __riscv_flen >= 32 && __riscv_xlen == 32
      case 0b10'011:  // c.flwsp
#endif
#if __riscv_flen >= 32 || __riscv_xlen == 64
      case 0b00'011:  // c.flw / c.ld
#endif
#if __riscv_flen == 64
      case 0b00'001:  // c.fld
      case 0b10'001:  // c.fldsp
#endif
        return SignalContext::READ;
      case 0b00'110:  // c.sw
      case 0b10'110:  // c.swsp
#if __riscv_flen >= 32 || __riscv_xlen == 64
      case 0b00'111:  // c.fsw / c.sd
      case 0b10'111:  // c.fswsp / c.sdsp
#endif
#if __riscv_flen == 64
      case 0b00'101:  // c.fsd
      case 0b10'101:  // c.fsdsp
#endif
        return SignalContext::WRITE;
      default:
        return SignalContext::UNKNOWN;
    }
  }
#endif

  unsigned opcode = faulty_instruction & 0x7f;         // lower 7 bits
  unsigned funct3 = (faulty_instruction >> 12) & 0x7;  // bits 12-14, inclusive
  switch (opcode) {
    case 0b0000011:  // loads
      switch (funct3) {
        case 0b000:  // lb
        case 0b001:  // lh
        case 0b010:  // lw
#if __riscv_xlen == 64
        case 0b011:  // ld
#endif
        case 0b100:  // lbu
        case 0b101:  // lhu
          return SignalContext::READ;
        default:
          return SignalContext::UNKNOWN;
      }
    case 0b0100011:  // stores
      switch (funct3) {
        case 0b000:  // sb
        case 0b001:  // sh
        case 0b010:  // sw
#if __riscv_xlen == 64
        case 0b011:  // sd
#endif
          return SignalContext::WRITE;
        default:
          return SignalContext::UNKNOWN;
      }
#if __riscv_flen >= 32
    case 0b0000111:  // floating-point loads
      switch (funct3) {
        case 0b010:  // flw
#if __riscv_flen == 64
        case 0b011:  // fld
#endif
          return SignalContext::READ;
        default:
          return SignalContext::UNKNOWN;
      }
    case 0b0100111:  // floating-point stores
      switch (funct3) {
        case 0b010:  // fsw
#if __riscv_flen == 64
        case 0b011:  // fsd
#endif
          return SignalContext::WRITE;
        default:
          return SignalContext::UNKNOWN;
      }
#endif
    default:
      return SignalContext::UNKNOWN;
  }
d1894 5
d1911 5
a1979 5
#    if SANITIZER_FREEBSD
  *pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
  *bp = ucontext->uc_mcontext.mc_gpregs.gp_s[0];
  *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
#    else
d1983 3
a1985 9
#    endif
#  elif defined(__hexagon__)
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.pc;
  *bp = ucontext->uc_mcontext.r30;
  *sp = ucontext->uc_mcontext.r29;
#  else
#    error "Unsupported arch"
#  endif
d2014 1
a2014 3
    Printf("This sanitizer is not compatible with enabled ASLR.\n"
           "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
           GetArgv()[0]);
d2086 2
d2093 1
a2093 1
        " which is incompatible with sanitizer runtime "
@


1.1.1.3
log
@initial import of GCC 14.3.0.

major changes in GCC 13:
- improved sanitizer
- zstd debug info compression
- LTO improvements
- SARIF based diagnostic support
- new warnings: -Wxor-used-as-pow, -Wenum-int-mismatch, -Wself-move,
  -Wdangling-reference
- many new -Wanalyzer* specific warnings
- enhanced warnings: -Wpessimizing-move, -Wredundant-move
- new attributes to mark file descriptors, c++23 "assume"
- several C23 features added
- several C++23 features added
- many new features for Arm, x86, RISC-V

major changes in GCC 14:
- more strict C99 or newer support
- ia64* marked deprecated (but seemingly still in GCC 15.)
- several new hardening features
- support for "hardbool", which can have user supplied values of true/false
- explicit support for stack scrubbing upon function exit
- better auto-vectorisation support
- added clang-compatible __has_feature and __has_extension
- more C23, including -std=c23
- several C++26 features added
- better diagnostics in C++ templates
- new warnings: -Wnrvo, Welaborated-enum-base
- many new features for Arm, x86, RISC-V
- possible ABI breaking change for SPARC64 and small structures with arrays
  of floats.
@
text
@d37 1
a37 1
#if SANITIZER_MIPS64
a80 4
#if SANITIZER_LINUX && defined(__loongarch__)
#  include <sys/sysmacros.h>
#endif

a82 1
#include <sys/procctl.h>
d126 2
a127 3
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
                        SANITIZER_WORDSIZE == 64 ||                      \
                        (defined(__mips__) && _MIPS_SIM == _ABIN32))
d153 2
a154 2
void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
d157 1
a157 1
void BlockSignals(__sanitizer_sigset_t *oldset) {
d166 1
a166 11
#  if SANITIZER_LINUX
  // Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
  // If this signal is blocked, such calls cannot be handled and the process may
  // hang.
  internal_sigdelset(&set, 31);
#  endif
  SetSigProcMask(&set, oldset);
}

ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
  BlockSignals(&saved_);
a182 2
#  elif SANITIZER_LINUX && SANITIZER_LOONGARCH64
#    include "sanitizer_syscall_linux_loongarch64.inc"
d229 1
a229 1
#    if SANITIZER_LINUX
d237 1
a237 1
#    if SANITIZER_LINUX
d266 1
a266 1
#if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && SANITIZER_LINUX
d285 1
a285 23
#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
d336 1
a336 1
#  if SANITIZER_FREEBSD
d338 1
a338 10
#  elif SANITIZER_LINUX
#    if defined(__loongarch__)
  struct statx bufx;
  int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
                             AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx);
  statx_to_stat(&bufx, (struct stat *)buf);
  return res;
#    elif (SANITIZER_WORDSIZE == 64 || SANITIZER_X32 ||    \
           (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
        !SANITIZER_SPARC
d341 6
a346 5
#    else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
                             (uptr)&buf64, 0);
  stat64_to_stat(&buf64, (struct stat *)buf);
d348 4
a351 2
#    endif
#  else
d356 1
a356 1
#  endif
d360 1
a360 1
#  if SANITIZER_FREEBSD
d363 1
a363 11
#  elif SANITIZER_LINUX
#    if defined(__loongarch__)
  struct statx bufx;
  int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
                             AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT,
                             STATX_BASIC_STATS, (uptr)&bufx);
  statx_to_stat(&bufx, (struct stat *)buf);
  return res;
#    elif (defined(_LP64) || SANITIZER_X32 ||              \
           (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
        !SANITIZER_SPARC
d366 6
a371 5
#    else
  struct stat64 buf64;
  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
                             (uptr)&buf64, AT_SYMLINK_NOFOLLOW);
  stat64_to_stat(&buf64, (struct stat *)buf);
d373 4
a376 2
#    endif
#  else
d381 1
a381 1
#  endif
d392 1
a392 7
#      elif SANITIZER_LINUX && defined(__loongarch__)
  struct statx bufx;
  int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
                             STATX_BASIC_STATS, (uptr)&bufx);
  statx_to_stat(&bufx, (struct stat *)buf);
  return res;
#      else
d394 1
a394 1
#      endif
d415 1
a415 1
#    if SANITIZER_LINUX
d423 1
a423 1
#    if SANITIZER_LINUX
d432 1
a432 1
#    if SANITIZER_LINUX
d440 1
a440 1
#  if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__)
d443 1
a443 1
#  elif SANITIZER_LINUX
d446 1
a446 1
#  else
d448 1
a448 1
#  endif
d485 3
d489 1
d495 1
a495 8
bool DirExists(const char *path) {
  struct stat st;
  if (internal_stat(path, &st))
    return false;
  return S_ISDIR(st.st_mode);
}

#  if !SANITIZER_NETBSD
d694 1
a694 1
#    if SANITIZER_X32 || SANITIZER_LINUX
d697 1
a697 1
#    else
d700 1
a700 1
#    endif
d702 1
a702 1
#    if SANITIZER_LINUX
d704 1
a704 1
#    endif
d740 1
a740 1
#    elif SANITIZER_LINUX
d742 1
a742 1
#    else
d744 1
a744 1
#    endif
d755 1
a755 8
#      if defined(__x86_64__)
#        include <asm/unistd_64.h>
// Currently internal_arch_prctl() is only needed on x86_64.
uptr internal_arch_prctl(int option, uptr arg2) {
  return internal_syscall(__NR_arch_prctl, option, arg2);
}
#      endif
#    endif
d762 1
a762 4
#    if SANITIZER_LINUX
#      if SANITIZER_S390
  return internal_syscall(SYSCALL(clone), 0, SIGCHLD);
#      else
d764 1
a764 2
#      endif
#    else
d766 1
a766 1
#    endif
a893 4
uptr internal_procctl(int type, int id, int cmd, void *data) {
  return internal_syscall(SYSCALL(procctl), type, id, cmd, data);
}

d1035 1
a1035 1
# if defined(__powerpc64__) || defined(__aarch64__) || defined(__loongarch__)
a1042 1
  // loongarch64 also has multiple address space layouts: default is 47-bit.
d1046 1
a1046 1
# elif SANITIZER_MIPS64
d1383 1
a1383 1
  register long long res __asm__("x0");
a1430 41
#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"

      // if ($a0 != 0)
      //   return $a0;
      "bnez $a0, 1f\n"

      // In the child, now. Call "fn(arg)".
      "move $a0, $a6\n"
      "jirl $ra, $a5, 0\n"

      // Call _exit($a0).
      "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;
}
a1762 2
  if (&real_pthread_create == 0)
    return nullptr;
d1771 1
a1771 2
  if (&real_pthread_join)
    real_pthread_join(th, nullptr);
d1779 1
a1779 1
#if SANITIZER_LINUX && defined(__aarch64__)
a1799 5
#elif SANITIZER_FREEBSD && defined(__aarch64__)
// FreeBSD doesn't provide ESR in the ucontext.
static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
  return false;
}
d1818 1
a1818 1
  return err & PF_WRITE ? Write : Read;
d1841 1
a1841 1
      return SignalContext::Write;
d1856 1
a1856 1
      return SignalContext::Read;
d1863 1
a1863 1
          return SignalContext::Read;
d1867 1
a1867 1
  return SignalContext::Unknown;
d1871 1
a1871 1
  return fsr & FSR_WRITE ? Write : Read;
d1875 2
a1876 9
  if (!Aarch64GetESR(ucontext, &esr)) return Unknown;
  return esr & ESR_ELx_WNR ? Write : Read;
#elif defined(__loongarch__)
  u32 flags = ucontext->uc_mcontext.__flags;
  if (flags & SC_ADDRERR_RD)
    return SignalContext::Read;
  if (flags & SC_ADDRERR_WR)
    return SignalContext::Write;
  return SignalContext::Unknown;
d1892 1
a1892 1
  return (instr >> 21) & 1 ? Write: Read;
d1912 1
a1912 1
        return rd ? SignalContext::Read : SignalContext::Unknown;
d1924 1
a1924 1
        return SignalContext::Read;
d1935 1
a1935 1
        return SignalContext::Write;
d1937 1
a1937 1
        return SignalContext::Unknown;
d1955 1
a1955 1
          return SignalContext::Read;
d1957 1
a1957 1
          return SignalContext::Unknown;
d1967 1
a1967 1
          return SignalContext::Write;
d1969 1
a1969 1
          return SignalContext::Unknown;
d1978 1
a1978 1
          return SignalContext::Read;
d1980 1
a1980 1
          return SignalContext::Unknown;
d1988 1
a1988 1
          return SignalContext::Write;
d1990 1
a1990 1
          return SignalContext::Unknown;
d1994 1
a1994 1
      return SignalContext::Unknown;
d1998 1
a1998 1
  return Unknown;  // FIXME: Implement.
a2024 6
# if SANITIZER_FREEBSD
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.mc_gpregs.gp_elr;
  *bp = ucontext->uc_mcontext.mc_gpregs.gp_x[29];
  *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
# else
a2028 1
# endif
a2072 6
#    if SANITIZER_FREEBSD
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.mc_srr0;
  *sp = ucontext->uc_mcontext.mc_frame[1];
  *bp = ucontext->uc_mcontext.mc_frame[31];
#    else
a2078 1
#    endif
a2130 5
#  elif defined(__loongarch__)
  ucontext_t *ucontext = (ucontext_t *)context;
  *pc = ucontext->uc_mcontext.__pc;
  *bp = ucontext->uc_mcontext.__gregs[22];
  *sp = ucontext->uc_mcontext.__gregs[3];
d2142 4
d2167 11
d2179 5
a2183 3
  int aslr_status;
  int r = internal_procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status);
  if (UNLIKELY(r == -1)) {
d2185 1
a2185 1
    // the cmd is not necessarily guaranteed to be here
d2189 2
a2190 1
  if ((aslr_status & PROC_ASLR_ACTIVE) != 0) {
d2195 11
a2205 11
#  elif SANITIZER_PPC64V2
  // Disable ASLR for Linux PPC64LE.
  int old_personality = personality(0xffffffff);
  if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) {
    VReport(1,
            "WARNING: Program is being run with address space layout "
            "randomization (ASLR) enabled which prevents the thread and "
            "memory sanitizers from working on powerpc64le.\n"
            "ASLR will be disabled and the program re-executed.\n");
    CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
    ReExec();
d2207 1
a2207 1
#  else
d2209 1
a2209 1
#  endif
@


