llvm/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp

//===-- tsan_platform_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 a part of ThreadSanitizer (TSan), a race detector.
//
// Linux- and BSD-specific code.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD

#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "tsan_flags.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"

#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
#if SANITIZER_LINUX
#include <sys/personality.h>
#include <setjmp.h>
#endif
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sched.h>
#include <dlfcn.h>
#if SANITIZER_LINUX
#define __need_res_state
#include <resolv.h>
#endif

#ifdef sa_handler
# undef sa_handler
#endif

#ifdef sa_sigaction
# undef sa_sigaction
#endif

#if SANITIZER_FREEBSD
extern "C" void *__libc_stack_end;
void *__libc_stack_end = 0;
#endif

#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64)) && \
    !SANITIZER_GO
#define INIT_LONGJMP_XOR_KEY
#else
#define INIT_LONGJMP_XOR_KEY
#endif

#if INIT_LONGJMP_XOR_KEY
#include "interception/interception.h"
// Must be declared outside of other namespaces.
DECLARE_REAL(int, _setjmp, void *env)
#endif

namespace __tsan {

#if INIT_LONGJMP_XOR_KEY
static void InitializeLongjmpXorKey();
static uptr longjmp_xor_key;
#endif

// Runtime detected VMA size.
uptr vmaSize;

enum {};

void FillProfileCallback(uptr p, uptr rss, bool file, uptr *mem) {}

void WriteMemoryProfile(char *buf, uptr buf_size, u64 uptime_ns) {}

#if !SANITIZER_GO
// Mark shadow for .rodata sections with the special Shadow::kRodata marker.
// Accesses to .rodata can't race, so this saves time, memory and trace space.
static NOINLINE void MapRodata(char* buffer, uptr size) {}

void InitializeShadowMemoryPlatform() {}

#endif  // #if !SANITIZER_GO

#  if !SANITIZER_GO
static void ReExecIfNeeded(bool ignore_heap) {}
#  endif

void InitializePlatformEarly() {}

void InitializePlatform() {}

#if !SANITIZER_GO
// Extract file descriptors passed to glibc internal __res_iclose function.
// This is required to properly "close" the fds, because we do not see internal
// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {}

// Extract file descriptors passed via UNIX domain sockets.
// This is required to properly handle "open" of these fds.
// see 'man recvmsg' and 'man 3 cmsg'.
int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {}

// Reverse operation of libc stack pointer mangling
static uptr UnmangleLongJmpSp(uptr mangled_sp) {}

#if SANITIZER_NETBSD
# ifdef __x86_64__
#define LONG_JMP_SP_ENV_SLOT
# else
#  error unsupported
# endif
#elif defined(__powerpc__)
#define LONG_JMP_SP_ENV_SLOT
#elif SANITIZER_FREEBSD
# ifdef __aarch64__
#define LONG_JMP_SP_ENV_SLOT
# else
#define LONG_JMP_SP_ENV_SLOT
# endif
#elif SANITIZER_LINUX
# ifdef __aarch64__
#define LONG_JMP_SP_ENV_SLOT
# elif defined(__loongarch__)
#define LONG_JMP_SP_ENV_SLOT
# elif defined(__mips64)
#define LONG_JMP_SP_ENV_SLOT
#      elif SANITIZER_RISCV64
#define LONG_JMP_SP_ENV_SLOT
#      elif defined(__s390x__)
#define LONG_JMP_SP_ENV_SLOT
#      else
#define LONG_JMP_SP_ENV_SLOT
#      endif
#endif

uptr ExtractLongJmpSp(uptr *env) {}

#if INIT_LONGJMP_XOR_KEY
// GLIBC mangles the function pointers in jmp_buf (used in {set,long}*jmp
// functions) by XORing them with a random key.  For AArch64 it is a global
// variable rather than a TCB one (as for x86_64/powerpc).  We obtain the key by
// issuing a setjmp and XORing the SP pointer values to derive the key.
static void InitializeLongjmpXorKey() {
  // 1. Call REAL(setjmp), which stores the mangled SP in env.
  jmp_buf env;
  REAL(_setjmp)(env);

  // 2. Retrieve vanilla/mangled SP.
  uptr sp;
#ifdef __loongarch__
  asm("move  %0, $sp" : "=r" (sp));
#else
  asm("mov  %0, sp" : "=r" (sp));
#endif
  uptr mangled_sp = ((uptr *)&env)[LONG_JMP_SP_ENV_SLOT];

  // 3. xor SPs to obtain key.
  longjmp_xor_key = mangled_sp ^ sp;
}
#endif

extern "C" void __tsan_tls_initialization() {}

void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {}

// Note: this function runs with async signals enabled,
// so it must not touch any tsan state.
int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
                                     void (*cleanup)(void *arg), void *arg) {}
#endif  // !SANITIZER_GO

#if !SANITIZER_GO
void ReplaceSystemMalloc() {}
#endif

#if !SANITIZER_GO
#if SANITIZER_ANDROID
// On Android, one thread can call intercepted functions after
// DestroyThreadState(), so add a fake thread state for "dead" threads.
static ThreadState *dead_thread_state = nullptr;

ThreadState *cur_thread() {
  ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
  if (thr == nullptr) {
    __sanitizer_sigset_t emptyset;
    internal_sigfillset(&emptyset);
    __sanitizer_sigset_t oldset;
    CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
    thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
    if (thr == nullptr) {
      thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),
                                                     "ThreadState"));
      *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);
      if (dead_thread_state == nullptr) {
        dead_thread_state = reinterpret_cast<ThreadState*>(
            MmapOrDie(sizeof(ThreadState), "ThreadState"));
        dead_thread_state->fast_state.SetIgnoreBit();
        dead_thread_state->ignore_interceptors = 1;
        dead_thread_state->is_dead = true;
        *const_cast<u32*>(&dead_thread_state->tid) = -1;
        CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
                                      PROT_READ));
      }
    }
    CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
  }
  return thr;
}

void set_cur_thread(ThreadState *thr) {
  *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);
}

void cur_thread_finalize() {
  __sanitizer_sigset_t emptyset;
  internal_sigfillset(&emptyset);
  __sanitizer_sigset_t oldset;
  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
  ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
  if (thr != dead_thread_state) {
    *get_android_tls_ptr() = reinterpret_cast<uptr>(dead_thread_state);
    UnmapOrDie(thr, sizeof(ThreadState));
  }
  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
}
#endif  // SANITIZER_ANDROID
#endif  // if !SANITIZER_GO

}  // namespace __tsan

#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD