1373 lines
57 KiB
Diff
1373 lines
57 KiB
Diff
From e9ff5810cfbc76b24adefcfd024d69c19789119c Mon Sep 17 00:00:00 2001
|
|
From: ticat_fp <fanpeng@loongson.cn>
|
|
Date: Wed, 28 Feb 2024 15:13:42 +0800
|
|
Subject: [PATCH 124/124] libsanitizer: add LoongArch support
|
|
|
|
Signed-off-by: ticat_fp <fanpeng@loongson.cn>
|
|
---
|
|
libsanitizer/asan/asan_interceptors.h | 2 +-
|
|
libsanitizer/asan/asan_interceptors_vfork.S | 1 +
|
|
libsanitizer/asan/asan_mapping.h | 3 +
|
|
libsanitizer/configure.tgt | 7 +
|
|
libsanitizer/lsan/lsan_allocator.h | 3 +-
|
|
libsanitizer/lsan/lsan_common.cpp | 4 +
|
|
.../sanitizer_common/sanitizer_common.h | 3 +
|
|
...ommon_interceptors_vfork_loongarch64.inc.S | 57 +++++
|
|
.../sanitizer_common_syscalls.inc | 4 +-
|
|
.../sanitizer_common/sanitizer_linux.cpp | 111 +++++++++-
|
|
.../sanitizer_common/sanitizer_linux.h | 2 +-
|
|
.../sanitizer_linux_libcdep.cpp | 19 +-
|
|
.../sanitizer_common/sanitizer_platform.h | 10 +-
|
|
.../sanitizer_platform_limits_linux.cpp | 3 +-
|
|
.../sanitizer_platform_limits_posix.cpp | 13 +-
|
|
.../sanitizer_platform_limits_posix.h | 7 +-
|
|
.../sanitizer_common/sanitizer_stacktrace.cpp | 4 +-
|
|
.../sanitizer_stoptheworld_linux_libcdep.cpp | 11 +-
|
|
.../sanitizer_symbolizer_libcdep.cpp | 2 +
|
|
.../sanitizer_syscall_linux_loongarch64.inc | 171 +++++++++++++++
|
|
...ommon_interceptors_vfork_loongarch64.inc.S | 57 +++++
|
|
libsanitizer/tsan/Makefile.am | 2 +-
|
|
libsanitizer/tsan/Makefile.in | 3 +-
|
|
libsanitizer/tsan/tsan_interceptors_posix.cpp | 2 +
|
|
libsanitizer/tsan/tsan_platform.h | 55 +++++
|
|
libsanitizer/tsan/tsan_platform_linux.cpp | 21 +-
|
|
libsanitizer/tsan/tsan_rtl.h | 3 +-
|
|
libsanitizer/tsan/tsan_rtl_loongarch64.S | 196 ++++++++++++++++++
|
|
28 files changed, 749 insertions(+), 27 deletions(-)
|
|
create mode 100644 libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S
|
|
create mode 100644 libsanitizer/sanitizer_common/sanitizer_syscall_linux_loongarch64.inc
|
|
create mode 100644 libsanitizer/sanitizer_common_interceptors_vfork_loongarch64.inc.S
|
|
create mode 100644 libsanitizer/tsan/tsan_rtl_loongarch64.S
|
|
|
|
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
|
|
index 105c672cc..c5534d7f6 100644
|
|
--- a/libsanitizer/asan/asan_interceptors.h
|
|
+++ b/libsanitizer/asan/asan_interceptors.h
|
|
@@ -119,7 +119,7 @@ void InitializePlatformInterceptors();
|
|
|
|
#if SANITIZER_LINUX && \
|
|
(defined(__arm__) || defined(__aarch64__) || defined(__i386__) || \
|
|
- defined(__x86_64__) || SANITIZER_RISCV64)
|
|
+ defined(__x86_64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64)
|
|
# define ASAN_INTERCEPT_VFORK 1
|
|
#else
|
|
# define ASAN_INTERCEPT_VFORK 0
|
|
diff --git a/libsanitizer/asan/asan_interceptors_vfork.S b/libsanitizer/asan/asan_interceptors_vfork.S
|
|
index 3ae5503e8..ec29adc7b 100644
|
|
--- a/libsanitizer/asan/asan_interceptors_vfork.S
|
|
+++ b/libsanitizer/asan/asan_interceptors_vfork.S
|
|
@@ -6,6 +6,7 @@
|
|
#include "sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S"
|
|
#include "sanitizer_common/sanitizer_common_interceptors_vfork_arm.inc.S"
|
|
#include "sanitizer_common/sanitizer_common_interceptors_vfork_i386.inc.S"
|
|
+#include "sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S"
|
|
#include "sanitizer_common/sanitizer_common_interceptors_vfork_riscv64.inc.S"
|
|
#include "sanitizer_common/sanitizer_common_interceptors_vfork_x86_64.inc.S"
|
|
#endif
|
|
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
|
|
index 4b0037fce..6d89a9352 100644
|
|
--- a/libsanitizer/asan/asan_mapping.h
|
|
+++ b/libsanitizer/asan/asan_mapping.h
|
|
@@ -173,6 +173,7 @@ static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
|
|
static const u64 kNetBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
|
|
static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
|
|
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
|
+static const u64 kLoongArch64_ShadowOffset64 = 0x0000400000000000;
|
|
|
|
#define SHADOW_SCALE kDefaultShadowScale
|
|
|
|
@@ -217,6 +218,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
|
# define SHADOW_OFFSET kMIPS64_ShadowOffset64
|
|
#elif defined(__sparc__)
|
|
#define SHADOW_OFFSET kSPARC64_ShadowOffset64
|
|
+#elif defined(__loongarch__)
|
|
+# define SHADOW_OFFSET kLoongArch64_ShadowOffset64
|
|
# elif SANITIZER_WINDOWS64
|
|
# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
|
|
# else
|
|
diff --git a/libsanitizer/configure.tgt b/libsanitizer/configure.tgt
|
|
index fb89df493..9d42662d3 100644
|
|
--- a/libsanitizer/configure.tgt
|
|
+++ b/libsanitizer/configure.tgt
|
|
@@ -72,6 +72,13 @@ case "${target}" in
|
|
;;
|
|
riscv64-*-linux*)
|
|
;;
|
|
+ loongarch64-*-linux*)
|
|
+ if test x$ac_cv_sizeof_void_p = x8; then
|
|
+ TSAN_SUPPORTED=yes
|
|
+ LSAN_SUPPORTED=yes
|
|
+ TSAN_TARGET_DEPENDENT_OBJECTS=tsan_rtl_loongarch64.lo
|
|
+ fi
|
|
+ ;;
|
|
*)
|
|
UNSUPPORTED=1
|
|
;;
|
|
diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
|
|
index 45c6ac406..dc9a02b19 100644
|
|
--- a/libsanitizer/lsan/lsan_allocator.h
|
|
+++ b/libsanitizer/lsan/lsan_allocator.h
|
|
@@ -50,7 +50,8 @@ struct ChunkMetadata {
|
|
};
|
|
|
|
#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
|
|
- defined(__arm__) || SANITIZER_RISCV64 || defined(__hexagon__)
|
|
+ defined(__arm__) || SANITIZER_RISCV64 || defined(__hexagon__) || \
|
|
+ defined(__loongarch__)
|
|
template <typename AddressSpaceViewTy>
|
|
struct AP32 {
|
|
static const uptr kSpaceBeg = 0;
|
|
diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
|
|
index 308dbb3e4..9a78ed92c 100644
|
|
--- a/libsanitizer/lsan/lsan_common.cpp
|
|
+++ b/libsanitizer/lsan/lsan_common.cpp
|
|
@@ -167,6 +167,10 @@ static inline bool CanBeAHeapPointer(uptr p) {
|
|
unsigned runtimeVMA =
|
|
(MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
|
|
return ((p >> runtimeVMA) == 0);
|
|
+#elif defined(__loongarch_lp64)
|
|
+ // Allow 47-bit user-space VMA at current.
|
|
+ return ((p >> 47) == 0);
|
|
+
|
|
#else
|
|
return true;
|
|
#endif
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
|
|
index 065154496..5f68e4994 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
|
|
@@ -696,6 +696,7 @@ enum ModuleArch {
|
|
kModuleArchARMV7S,
|
|
kModuleArchARMV7K,
|
|
kModuleArchARM64,
|
|
+ kModuleArchLoongArch64,
|
|
kModuleArchRISCV64,
|
|
kModuleArchHexagon
|
|
};
|
|
@@ -765,6 +766,8 @@ inline const char *ModuleArchToString(ModuleArch arch) {
|
|
return "armv7k";
|
|
case kModuleArchARM64:
|
|
return "arm64";
|
|
+ case kModuleArchLoongArch64:
|
|
+ return "loongarch64";
|
|
case kModuleArchRISCV64:
|
|
return "riscv64";
|
|
case kModuleArchHexagon:
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S
|
|
new file mode 100644
|
|
index 000000000..dae72b5ac
|
|
--- /dev/null
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_loongarch64.inc.S
|
|
@@ -0,0 +1,57 @@
|
|
+#if defined(__loongarch64) && defined(__linux__)
|
|
+
|
|
+#include "sanitizer_common/sanitizer_asm.h"
|
|
+
|
|
+ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
|
|
+ASM_HIDDEN(_ZN14__interception10real_vforkE)
|
|
+
|
|
+.text
|
|
+.globl ASM_WRAPPER_NAME(vfork)
|
|
+ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
|
|
+ASM_WRAPPER_NAME(vfork):
|
|
+ // Save ra in the off-stack spill area.
|
|
+ // allocate space on stack
|
|
+ addi.d $sp, $sp, -16
|
|
+ // store $ra value
|
|
+ st.d $ra, $sp, 8
|
|
+ bl COMMON_INTERCEPTOR_SPILL_AREA
|
|
+ // restore previous values from stack
|
|
+ ld.d $ra, $sp, 8
|
|
+ // adjust stack
|
|
+ addi.d $sp, $sp, 16
|
|
+ // store $ra by $a0
|
|
+ st.d $ra, $a0, 0
|
|
+
|
|
+ // Call real vfork. This may return twice. User code that runs between the first and the second return
|
|
+ // may clobber the stack frame of the interceptor; that's why it does not have a frame.
|
|
+ la.local $a0, _ZN14__interception10real_vforkE
|
|
+ ld.d $a0, $a0, 0
|
|
+ jirl $ra, $a0, 0
|
|
+
|
|
+ // adjust stack
|
|
+ addi.d $sp, $sp, -16
|
|
+ // store $a0 by adjusted stack
|
|
+ st.d $a0, $sp, 8
|
|
+ // jump to exit label if $a0 is 0
|
|
+ beqz $a0, .L_exit
|
|
+
|
|
+ // $a0 != 0 => parent process. Clear stack shadow.
|
|
+ // put old $sp to $a0
|
|
+ addi.d $a0, $sp, 16
|
|
+ bl %plt(COMMON_INTERCEPTOR_HANDLE_VFORK)
|
|
+
|
|
+.L_exit:
|
|
+ // Restore $ra
|
|
+ bl COMMON_INTERCEPTOR_SPILL_AREA
|
|
+ ld.d $ra, $a0, 0
|
|
+ // load value by stack
|
|
+ ld.d $a0, $sp, 8
|
|
+ // adjust stack
|
|
+ addi.d $sp, $sp, 16
|
|
+ jr $ra
|
|
+ASM_SIZE(vfork)
|
|
+
|
|
+.weak vfork
|
|
+.set vfork, ASM_WRAPPER_NAME(vfork)
|
|
+
|
|
+#endif
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
|
|
index a38b13408..954c2ea8c 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
|
|
@@ -2512,7 +2512,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
|
|
# if !SANITIZER_ANDROID && \
|
|
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
|
defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
|
|
- SANITIZER_RISCV64)
|
|
+ SANITIZER_RISCV64 || defined(__loongarch__))
|
|
if (data) {
|
|
if (request == ptrace_setregs) {
|
|
PRE_READ((void *)data, struct_user_regs_struct_sz);
|
|
@@ -2534,7 +2534,7 @@ POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
|
|
# if !SANITIZER_ANDROID && \
|
|
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
|
defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
|
|
- SANITIZER_RISCV64)
|
|
+ SANITIZER_RISCV64 || defined(__loongarch__))
|
|
if (res >= 0 && data) {
|
|
// Note that this is different from the interceptor in
|
|
// sanitizer_common_interceptors.inc.
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
|
|
index aa59d9718..a3c90bca9 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
|
|
@@ -30,6 +30,10 @@
|
|
#include <asm/param.h>
|
|
#endif
|
|
|
|
+#if SANITIZER_LINUX && defined(__loongarch__)
|
|
+# include <sys/sysmacros.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
|
|
@@ -180,6 +184,8 @@ ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }
|
|
# 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
|
|
@@ -282,6 +288,28 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
|
|
}
|
|
#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 defined(__mips64)
|
|
// Undefine compatibility macros from <sys/stat.h>
|
|
// so that they would not clash with the kernel_stat
|
|
@@ -336,8 +364,16 @@ 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_USES_CANONICAL_LINUX_SYSCALLS
|
|
+# if SANITIZER_LINUX && 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;
|
|
+#else
|
|
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
0);
|
|
+#endif
|
|
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
|
# if defined(__mips64)
|
|
// For mips64, stat syscall fills buffer in the format of kernel_stat
|
|
@@ -361,8 +397,17 @@ uptr internal_lstat(const char *path, void *buf) {
|
|
return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
AT_SYMLINK_NOFOLLOW);
|
|
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
+# if SANITIZER_LINUX && 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;
|
|
+#else
|
|
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
|
AT_SYMLINK_NOFOLLOW);
|
|
+#endif
|
|
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
|
# if SANITIZER_MIPS64
|
|
// For mips64, lstat syscall fills buffer in the format of kernel_stat
|
|
@@ -389,6 +434,12 @@ uptr internal_fstat(fd_t fd, void *buf) {
|
|
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
|
|
@@ -437,7 +488,7 @@ uptr internal_unlink(const char *path) {
|
|
}
|
|
|
|
uptr internal_rename(const char *oldpath, const char *newpath) {
|
|
-#if defined(__riscv) && defined(__linux__)
|
|
+#if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__)
|
|
return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
|
|
(uptr)newpath, 0);
|
|
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
@@ -482,7 +533,7 @@ bool FileExists(const char *filename) {
|
|
if (ShouldMockFailureToOpen(filename))
|
|
return false;
|
|
struct stat st;
|
|
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS && !defined(__loongarch__)
|
|
if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0))
|
|
#else
|
|
if (internal_stat(filename, &st))
|
|
@@ -1032,7 +1083,7 @@ uptr GetMaxVirtualAddress() {
|
|
#if SANITIZER_NETBSD && defined(__x86_64__)
|
|
return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE)
|
|
#elif SANITIZER_WORDSIZE == 64
|
|
-# if defined(__powerpc64__) || defined(__aarch64__)
|
|
+# 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.
|
|
@@ -1040,6 +1091,7 @@ uptr GetMaxVirtualAddress() {
|
|
// 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;
|
|
@@ -1260,6 +1312,47 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
: "memory", "r11", "rcx");
|
|
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(__mips__)
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
int *parent_tidptr, void *newtls, int *child_tidptr) {
|
|
@@ -1874,6 +1967,13 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
|
|
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).
|
|
@@ -2128,6 +2228,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
|
*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
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
|
|
index 6a235db0e..a6bc01482 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
|
|
@@ -73,7 +73,7 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
|
|
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
|
|
#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
|
|
defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
|
|
- defined(__arm__) || SANITIZER_RISCV64
|
|
+ defined(__arm__) || SANITIZER_RISCV64 || defined(__loongarch__)
|
|
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
|
|
int *parent_tidptr, void *newtls, int *child_tidptr);
|
|
#endif
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
|
|
index 4f22c78a1..0fc1d2d44 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
|
|
@@ -203,7 +203,8 @@ void InitTlsSize() {
|
|
g_use_dlpi_tls_data =
|
|
GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
|
|
|
|
-#if defined(__aarch64__) || defined(__x86_64__) || defined(__powerpc64__)
|
|
+#if defined(__aarch64__) || defined(__x86_64__) || defined(__powerpc64__) || \
|
|
+ defined(__loongarch__)
|
|
void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
|
|
size_t tls_align;
|
|
((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
|
|
@@ -262,6 +263,8 @@ static uptr ThreadDescriptorSizeFallback() {
|
|
#elif defined(__mips__)
|
|
// TODO(sagarthakur): add more values as per different glibc versions.
|
|
val = FIRST_32_SECOND_64(1152, 1776);
|
|
+#elif SANITIZER_LOONGARCH64
|
|
+ val = 1856; // from glibc 2.36
|
|
#elif SANITIZER_RISCV64
|
|
int major;
|
|
int minor;
|
|
@@ -301,7 +304,8 @@ uptr ThreadDescriptorSize() {
|
|
return val;
|
|
}
|
|
|
|
-#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
|
|
+#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 || \
|
|
+ SANITIZER_LOONGARCH64
|
|
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
|
|
// head structure. It lies before the static tls blocks.
|
|
static uptr TlsPreTcbSize() {
|
|
@@ -311,6 +315,8 @@ static uptr TlsPreTcbSize() {
|
|
const uptr kTcbHead = 88; // sizeof (tcbhead_t)
|
|
#elif SANITIZER_RISCV64
|
|
const uptr kTcbHead = 16; // sizeof (tcbhead_t)
|
|
+#elif SANITIZER_LOONGARCH64
|
|
+ const uptr kTcbHead = 16; // sizeof (tcbhead_t)
|
|
#endif
|
|
const uptr kTlsAlign = 16;
|
|
const uptr kTlsPreTcbSize =
|
|
@@ -475,6 +481,15 @@ static void GetTls(uptr *addr, uptr *size) {
|
|
*addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
|
|
ThreadDescriptorSize();
|
|
*size = g_tls_size + ThreadDescriptorSize();
|
|
+#elif SANITIZER_GLIBC && defined(__loongarch__)
|
|
+# ifdef __clang__
|
|
+ *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
|
|
+ ThreadDescriptorSize();
|
|
+# else
|
|
+ asm("or %0,$tp,$zero" : "=r"(*addr));
|
|
+ *addr -= ThreadDescriptorSize();
|
|
+# endif
|
|
+ *size = g_tls_size + ThreadDescriptorSize();
|
|
#elif SANITIZER_GLIBC && defined(__powerpc64__)
|
|
// Workaround for glibc<2.25(?). 2.27 is known to not need this.
|
|
uptr tp;
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
|
|
index 3153de34e..ed2d47ddf 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
|
|
@@ -225,6 +225,12 @@
|
|
#define SANITIZER_RISCV64 0
|
|
#endif
|
|
|
|
+#if defined(__loongarch_lp64)
|
|
+# define SANITIZER_LOONGARCH64 1
|
|
+#else
|
|
+# define SANITIZER_LOONGARCH64 0
|
|
+#endif
|
|
+
|
|
// By default we allow to use SizeClassAllocator64 on 64-bit platform.
|
|
// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
|
|
// does not work well and we need to fallback to SizeClassAllocator32.
|
|
@@ -281,8 +287,8 @@
|
|
// mandated by the upstream linux community for all new ports. Other ports
|
|
// may still use legacy syscalls.
|
|
#ifndef SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
|
|
-# if (defined(__aarch64__) || defined(__riscv) || defined(__hexagon__)) && \
|
|
- SANITIZER_LINUX
|
|
+# if (defined(__aarch64__) || defined(__riscv) || defined(__hexagon__) || \
|
|
+ defined(__loongarch__)) && SANITIZER_LINUX
|
|
# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1
|
|
# else
|
|
# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 0
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
|
|
index 2b1a2f793..5962df751 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
|
|
@@ -68,7 +68,8 @@ namespace __sanitizer {
|
|
|
|
# if !defined(__powerpc64__) && !defined(__x86_64__) && \
|
|
!defined(__aarch64__) && !defined(__mips__) && !defined(__s390__) && \
|
|
- !defined(__sparc__) && !defined(__riscv) && !defined(__hexagon__)
|
|
+ !defined(__sparc__) && !defined(__riscv) && !defined(__hexagon__) && \
|
|
+ !defined(__loongarch__)
|
|
COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
|
|
#endif
|
|
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
|
|
index c335f33dd..f5d775839 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
|
|
@@ -94,7 +94,7 @@
|
|
# include <utime.h>
|
|
# include <sys/ptrace.h>
|
|
# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \
|
|
- defined(__hexagon__) || SANITIZER_RISCV64
|
|
+ defined(__hexagon__) || SANITIZER_RISCV64 || defined(__loongarch__)
|
|
# include <asm/ptrace.h>
|
|
# ifdef __arm__
|
|
typedef struct user_fpregs elf_fpregset_t;
|
|
@@ -248,6 +248,10 @@ namespace __sanitizer {
|
|
defined(__powerpc__) || defined(__s390__) || defined(__sparc__) || \
|
|
defined(__hexagon__)
|
|
# define SIZEOF_STRUCT_USTAT 20
|
|
+# elif defined(__loongarch__)
|
|
+ // Not used. The minimum Glibc version available for LoongArch is 2.36
|
|
+ // so ustat() wrapper is already gone.
|
|
+# define SIZEOF_STRUCT_USTAT 0
|
|
# else
|
|
# error Unknown size of struct ustat
|
|
# endif
|
|
@@ -322,7 +326,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
|
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
|
|
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
|
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
|
|
- defined(__s390__) || SANITIZER_RISCV64)
|
|
+ defined(__s390__) || SANITIZER_RISCV64) || defined(__loongarch__)
|
|
#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
|
|
unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
|
|
unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
|
|
@@ -332,6 +336,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
|
#elif defined(__aarch64__)
|
|
unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
|
|
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state);
|
|
+#elif defined(__loongarch__)
|
|
+ unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
|
|
+ unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fp_state);
|
|
#elif defined(__s390__)
|
|
unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct);
|
|
unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct);
|
|
@@ -341,7 +348,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
|
|
#endif // __mips64 || __powerpc64__ || __aarch64__
|
|
#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
|
|
defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \
|
|
- SANITIZER_RISCV64
|
|
+ SANITIZER_RISCV64 || defined(__loongarch__)
|
|
unsigned struct_user_fpxregs_struct_sz = 0;
|
|
#else
|
|
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
|
|
index da53b5abe..f50827d9a 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
|
|
@@ -99,6 +99,9 @@ const unsigned struct_kernel_stat64_sz = 144;
|
|
const unsigned struct___old_kernel_stat_sz = 0;
|
|
const unsigned struct_kernel_stat_sz = 64;
|
|
const unsigned struct_kernel_stat64_sz = 104;
|
|
+# elif defined(__loongarch__)
|
|
+const unsigned struct_kernel_stat_sz = 128;
|
|
+const unsigned struct_kernel_stat64_sz = 0;
|
|
#elif SANITIZER_RISCV64
|
|
const unsigned struct_kernel_stat_sz = 128;
|
|
const unsigned struct_kernel_stat64_sz = 0; // RISCV64 does not use stat64
|
|
@@ -125,7 +128,7 @@ const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
|
|
|
|
#if SANITIZER_LINUX
|
|
|
|
-#if defined(__powerpc64__) || defined(__s390__)
|
|
+#if defined(__powerpc64__) || defined(__s390__) || defined(__loongarch__)
|
|
const unsigned struct___old_kernel_stat_sz = 0;
|
|
#elif !defined(__sparc__)
|
|
const unsigned struct___old_kernel_stat_sz = 32;
|
|
@@ -820,7 +823,7 @@ typedef void __sanitizer_FILE;
|
|
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
|
|
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
|
|
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
|
|
- defined(__s390__) || SANITIZER_RISCV64)
|
|
+ defined(__s390__) || SANITIZER_RISCV64) || defined(__loongarch__)
|
|
extern unsigned struct_user_regs_struct_sz;
|
|
extern unsigned struct_user_fpregs_struct_sz;
|
|
extern unsigned struct_user_fpxregs_struct_sz;
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
|
|
index 5a12422fc..42182d88e 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
|
|
@@ -127,7 +127,7 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
|
|
#endif
|
|
#elif defined(__s390__)
|
|
uhwptr pc1 = frame[14];
|
|
-#elif defined(__riscv)
|
|
+#elif defined(__riscv) || defined(__loongarch__)
|
|
// frame[-1] contains the return address
|
|
uhwptr pc1 = frame[-1];
|
|
#else
|
|
@@ -142,7 +142,7 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
|
|
trace_buffer[size++] = (uptr) pc1;
|
|
}
|
|
bottom = (uptr)frame;
|
|
-#if defined(__riscv)
|
|
+#if defined(__riscv) || defined(__loongarch__)
|
|
// frame[-2] contain fp of the previous frame
|
|
uptr new_bp = (uptr)frame[-2];
|
|
#else
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
|
|
index 403bda117..d6918f69f 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
|
|
@@ -16,7 +16,7 @@
|
|
#if SANITIZER_LINUX && \
|
|
(defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
|
|
defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
|
|
- defined(__arm__) || SANITIZER_RISCV64)
|
|
+ defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64)
|
|
|
|
#include "sanitizer_stoptheworld.h"
|
|
|
|
@@ -31,7 +31,8 @@
|
|
#include <sys/types.h> // for pid_t
|
|
#include <sys/uio.h> // for iovec
|
|
#include <elf.h> // for NT_PRSTATUS
|
|
-#if (defined(__aarch64__) || SANITIZER_RISCV64) && !SANITIZER_ANDROID
|
|
+#if (defined(__aarch64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) && \
|
|
+ !SANITIZER_ANDROID
|
|
// GLIBC 2.20+ sys/user does not include asm/ptrace.h
|
|
# include <asm/ptrace.h>
|
|
#endif
|
|
@@ -522,6 +523,12 @@ typedef struct user_regs_struct regs_struct;
|
|
static constexpr uptr kExtraRegs[] = {0};
|
|
#define ARCH_IOVEC_FOR_GETREGSET
|
|
|
|
+#elif defined(__loongarch__)
|
|
+typedef struct user_pt_regs regs_struct;
|
|
+#define REG_SP regs[3]
|
|
+static constexpr uptr kExtraRegs[] = {0};
|
|
+#define ARCH_IOVEC_FOR_GETREGSET
|
|
+
|
|
#elif defined(__s390__)
|
|
typedef _user_regs_struct regs_struct;
|
|
#define REG_SP gprs[15]
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
|
|
index 3fc994fd3..1b6c0d5c0 100644
|
|
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
|
|
@@ -261,6 +261,8 @@ class LLVMSymbolizerProcess final : public SymbolizerProcess {
|
|
const char* const kSymbolizerArch = "--default-arch=i386";
|
|
#elif SANITIZER_RISCV64
|
|
const char *const kSymbolizerArch = "--default-arch=riscv64";
|
|
+#elif SANITIZER_LOONGARCH64
|
|
+ const char *const kSymbolizerArch = "--default-arch=loongarch64";
|
|
#elif defined(__aarch64__)
|
|
const char* const kSymbolizerArch = "--default-arch=arm64";
|
|
#elif defined(__arm__)
|
|
diff --git a/libsanitizer/sanitizer_common/sanitizer_syscall_linux_loongarch64.inc b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_loongarch64.inc
|
|
new file mode 100644
|
|
index 000000000..80f5e6be8
|
|
--- /dev/null
|
|
+++ b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_loongarch64.inc
|
|
@@ -0,0 +1,171 @@
|
|
+//===-- sanitizer_syscall_linux_loongarch64.inc -----------------*- C++ -*-===//
|
|
+//
|
|
+// 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
|
|
+//
|
|
+//===----------------------------------------------------------------------===//
|
|
+//
|
|
+// Implementations of internal_syscall and internal_iserror for
|
|
+// Linux/loongarch64.
|
|
+//
|
|
+//===----------------------------------------------------------------------===//
|
|
+
|
|
+// About local register variables:
|
|
+// https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables
|
|
+//
|
|
+// Kernel ABI:
|
|
+// https://lore.kernel.org/loongarch/1f353678-3398-e30b-1c87-6edb278f74db@xen0n.name/T/#m1613bc86c2d7bf5f6da92bd62984302bfd699a2f
|
|
+// syscall number is placed in a7
|
|
+// parameters, if present, are placed in a0-a6
|
|
+// upon return:
|
|
+// the return value is placed in a0
|
|
+// t0-t8 should be considered clobbered
|
|
+// all other registers are preserved
|
|
+#define SYSCALL(name) __NR_##name
|
|
+
|
|
+#define INTERNAL_SYSCALL_CLOBBERS \
|
|
+ "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8"
|
|
+
|
|
+static uptr __internal_syscall(u64 nr) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0");
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "=r"(a0)
|
|
+ : "r"(a7)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall0(n) (__internal_syscall)(n)
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall1(n, a1) (__internal_syscall)(n, (u64)(a1))
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ register u64 a1 asm("$a1") = arg2;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7), "r"(a1)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall2(n, a1, a2) \
|
|
+ (__internal_syscall)(n, (u64)(a1), (long)(a2))
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ register u64 a1 asm("$a1") = arg2;
|
|
+ register u64 a2 asm("$a2") = arg3;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7), "r"(a1), "r"(a2)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall3(n, a1, a2, a3) \
|
|
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3))
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3,
|
|
+ u64 arg4) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ register u64 a1 asm("$a1") = arg2;
|
|
+ register u64 a2 asm("$a2") = arg3;
|
|
+ register u64 a3 asm("$a3") = arg4;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7), "r"(a1), "r"(a2), "r"(a3)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall4(n, a1, a2, a3, a4) \
|
|
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4))
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4,
|
|
+ long arg5) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ register u64 a1 asm("$a1") = arg2;
|
|
+ register u64 a2 asm("$a2") = arg3;
|
|
+ register u64 a3 asm("$a3") = arg4;
|
|
+ register u64 a4 asm("$a4") = arg5;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall5(n, a1, a2, a3, a4, a5) \
|
|
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
|
|
+ (u64)(a5))
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4,
|
|
+ long arg5, long arg6) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ register u64 a1 asm("$a1") = arg2;
|
|
+ register u64 a2 asm("$a2") = arg3;
|
|
+ register u64 a3 asm("$a3") = arg4;
|
|
+ register u64 a4 asm("$a4") = arg5;
|
|
+ register u64 a5 asm("$a5") = arg6;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \
|
|
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
|
|
+ (u64)(a5), (long)(a6))
|
|
+
|
|
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4,
|
|
+ long arg5, long arg6, long arg7) {
|
|
+ register u64 a7 asm("$a7") = nr;
|
|
+ register u64 a0 asm("$a0") = arg1;
|
|
+ register u64 a1 asm("$a1") = arg2;
|
|
+ register u64 a2 asm("$a2") = arg3;
|
|
+ register u64 a3 asm("$a3") = arg4;
|
|
+ register u64 a4 asm("$a4") = arg5;
|
|
+ register u64 a5 asm("$a5") = arg6;
|
|
+ register u64 a6 asm("$a6") = arg7;
|
|
+ __asm__ volatile("syscall 0\n\t"
|
|
+ : "+r"(a0)
|
|
+ : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
|
|
+ "r"(a6)
|
|
+ : INTERNAL_SYSCALL_CLOBBERS);
|
|
+ return a0;
|
|
+}
|
|
+#define __internal_syscall7(n, a1, a2, a3, a4, a5, a6, a7) \
|
|
+ (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
|
|
+ (u64)(a5), (long)(a6), (long)(a7))
|
|
+
|
|
+#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n
|
|
+#define __SYSCALL_NARGS(...) \
|
|
+ __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, )
|
|
+#define __SYSCALL_CONCAT_X(a, b) a##b
|
|
+#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b)
|
|
+#define __SYSCALL_DISP(b, ...) \
|
|
+ __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
|
|
+
|
|
+#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__)
|
|
+
|
|
+// Helper function used to avoid clobbering of errno.
|
|
+bool internal_iserror(uptr retval, int *internal_errno) {
|
|
+ if (retval >= (uptr)-4095) {
|
|
+ if (internal_errno)
|
|
+ *internal_errno = -retval;
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
diff --git a/libsanitizer/sanitizer_common_interceptors_vfork_loongarch64.inc.S b/libsanitizer/sanitizer_common_interceptors_vfork_loongarch64.inc.S
|
|
new file mode 100644
|
|
index 000000000..dae72b5ac
|
|
--- /dev/null
|
|
+++ b/libsanitizer/sanitizer_common_interceptors_vfork_loongarch64.inc.S
|
|
@@ -0,0 +1,57 @@
|
|
+#if defined(__loongarch64) && defined(__linux__)
|
|
+
|
|
+#include "sanitizer_common/sanitizer_asm.h"
|
|
+
|
|
+ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
|
|
+ASM_HIDDEN(_ZN14__interception10real_vforkE)
|
|
+
|
|
+.text
|
|
+.globl ASM_WRAPPER_NAME(vfork)
|
|
+ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
|
|
+ASM_WRAPPER_NAME(vfork):
|
|
+ // Save ra in the off-stack spill area.
|
|
+ // allocate space on stack
|
|
+ addi.d $sp, $sp, -16
|
|
+ // store $ra value
|
|
+ st.d $ra, $sp, 8
|
|
+ bl COMMON_INTERCEPTOR_SPILL_AREA
|
|
+ // restore previous values from stack
|
|
+ ld.d $ra, $sp, 8
|
|
+ // adjust stack
|
|
+ addi.d $sp, $sp, 16
|
|
+ // store $ra by $a0
|
|
+ st.d $ra, $a0, 0
|
|
+
|
|
+ // Call real vfork. This may return twice. User code that runs between the first and the second return
|
|
+ // may clobber the stack frame of the interceptor; that's why it does not have a frame.
|
|
+ la.local $a0, _ZN14__interception10real_vforkE
|
|
+ ld.d $a0, $a0, 0
|
|
+ jirl $ra, $a0, 0
|
|
+
|
|
+ // adjust stack
|
|
+ addi.d $sp, $sp, -16
|
|
+ // store $a0 by adjusted stack
|
|
+ st.d $a0, $sp, 8
|
|
+ // jump to exit label if $a0 is 0
|
|
+ beqz $a0, .L_exit
|
|
+
|
|
+ // $a0 != 0 => parent process. Clear stack shadow.
|
|
+ // put old $sp to $a0
|
|
+ addi.d $a0, $sp, 16
|
|
+ bl %plt(COMMON_INTERCEPTOR_HANDLE_VFORK)
|
|
+
|
|
+.L_exit:
|
|
+ // Restore $ra
|
|
+ bl COMMON_INTERCEPTOR_SPILL_AREA
|
|
+ ld.d $ra, $a0, 0
|
|
+ // load value by stack
|
|
+ ld.d $a0, $sp, 8
|
|
+ // adjust stack
|
|
+ addi.d $sp, $sp, 16
|
|
+ jr $ra
|
|
+ASM_SIZE(vfork)
|
|
+
|
|
+.weak vfork
|
|
+.set vfork, ASM_WRAPPER_NAME(vfork)
|
|
+
|
|
+#endif
|
|
diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am
|
|
index ae588a67d..709cdcdea 100644
|
|
--- a/libsanitizer/tsan/Makefile.am
|
|
+++ b/libsanitizer/tsan/Makefile.am
|
|
@@ -50,7 +50,7 @@ tsan_files = \
|
|
tsan_vector_clock.cpp
|
|
|
|
libtsan_la_SOURCES = $(tsan_files)
|
|
-EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S
|
|
+EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S tsan_rtl_loongarch64.S
|
|
libtsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS)
|
|
libtsan_la_DEPENDENCIES = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS)
|
|
if LIBBACKTRACE_SUPPORTED
|
|
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
|
|
index 538d2e8eb..194ed946d 100644
|
|
--- a/libsanitizer/tsan/Makefile.in
|
|
+++ b/libsanitizer/tsan/Makefile.in
|
|
@@ -456,7 +456,7 @@ tsan_files = \
|
|
tsan_vector_clock.cpp
|
|
|
|
libtsan_la_SOURCES = $(tsan_files)
|
|
-EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S
|
|
+EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S tsan_rtl_s390x.S tsan_rtl_loongarch64.S
|
|
libtsan_la_LIBADD = \
|
|
$(top_builddir)/sanitizer_common/libsanitizer_common.la \
|
|
$(top_builddir)/interception/libinterception.la \
|
|
@@ -609,6 +609,7 @@ distclean-compile:
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_report.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_aarch64.Plo@am__quote@
|
|
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_loongarch64.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_access.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_amd64.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_mips64.Plo@am__quote@
|
|
diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
|
|
index 9a85ee00d..ada8fd031 100644
|
|
--- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
|
|
+++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
|
|
@@ -76,6 +76,8 @@ struct ucontext_t {
|
|
#define PTHREAD_ABI_BASE "GLIBC_2.3.2"
|
|
#elif defined(__aarch64__) || SANITIZER_PPC64V2
|
|
#define PTHREAD_ABI_BASE "GLIBC_2.17"
|
|
+#elif SANITIZER_LOONGARCH64
|
|
+#define PTHREAD_ABI_BASE "GLIBC_2.36"
|
|
#endif
|
|
|
|
extern "C" int pthread_attr_init(void *attr);
|
|
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
|
|
index 7ff0acace..0ec562dac 100644
|
|
--- a/libsanitizer/tsan/tsan_platform.h
|
|
+++ b/libsanitizer/tsan/tsan_platform.h
|
|
@@ -85,6 +85,58 @@ struct Mapping48AddressSpace {
|
|
static const uptr kVdsoBeg = 0xf000000000000000ull;
|
|
};
|
|
|
|
+/* C/C++ on linux/loongarch64 (47-bit VMA)
|
|
+0000 0000 4000 - 0080 0000 0000: main binary
|
|
+0080 0000 0000 - 0100 0000 0000: -
|
|
+0100 0000 0000 - 1000 0000 0000: shadow memory
|
|
+1000 0000 0000 - 3000 0000 0000: -
|
|
+3000 0000 0000 - 3400 0000 0000: metainfo
|
|
+3400 0000 0000 - 5555 0000 0000: -
|
|
+5555 0000 0000 - 5556 0000 0000: main binary (PIE)
|
|
+5556 0000 0000 - 7ffe 0000 0000: -
|
|
+7ffe 0000 0000 - 7fff 0000 0000: heap
|
|
+7fff 0000 0000 - 7fff 8000 0000: -
|
|
+7fff 8000 0000 - 8000 0000 0000: modules and main thread stack
|
|
+*/
|
|
+// struct MappingLoongArch64_47 {
|
|
+// static const uptr kMetaShadowBeg = 0x300000000000ull;
|
|
+// static const uptr kMetaShadowEnd = 0x340000000000ull;
|
|
+// static const uptr kShadowBeg = 0x010000000000ull;
|
|
+// static const uptr kShadowEnd = 0x100000000000ull;
|
|
+// static const uptr kHeapMemBeg = 0x7ffe00000000ull;
|
|
+// static const uptr kHeapMemEnd = 0x7fff00000000ull;
|
|
+// static const uptr kLoAppMemBeg = 0x000000004000ull;
|
|
+// static const uptr kLoAppMemEnd = 0x008000000000ull;
|
|
+// static const uptr kMidAppMemBeg = 0x555500000000ull;
|
|
+// static const uptr kMidAppMemEnd = 0x555600000000ull;
|
|
+// static const uptr kHiAppMemBeg = 0x7fff80000000ull;
|
|
+// static const uptr kHiAppMemEnd = 0x800000000000ull;
|
|
+// static const uptr kShadowMsk = 0x780000000000ull;
|
|
+// static const uptr kShadowXor = 0x040000000000ull;
|
|
+// static const uptr kShadowAdd = 0x000000000000ull;
|
|
+// static const uptr kVdsoBeg = 0x7fffffffc000ull;
|
|
+// };
|
|
+struct MappingLoongArch64_47 {
|
|
+ static const uptr kMetaShadowBeg = 0x300000000000ull;
|
|
+ static const uptr kMetaShadowEnd = 0x340000000000ull;
|
|
+ static const uptr kShadowBeg = 0x010000000000ull;
|
|
+ static const uptr kShadowEnd = 0x100000000000ull;
|
|
+ static const uptr kHeapMemBeg = 0x7ffe00000000ull;
|
|
+ static const uptr kHeapMemEnd = 0x7fff00000000ull;
|
|
+ static const uptr kLoAppMemBeg = 0x000000004000ull;
|
|
+ static const uptr kLoAppMemEnd = 0x008000000000ull;
|
|
+ static const uptr kMidAppMemBeg = 0x555500000000ull;
|
|
+ static const uptr kMidAppMemEnd = 0x555600000000ull;
|
|
+ static const uptr kHiAppMemBeg = 0x7fff80000000ull;
|
|
+ static const uptr kHiAppMemEnd = 0x800000000000ull;
|
|
+ static const uptr kTraceMemBeg = 0x600000000000ull;
|
|
+ static const uptr kTraceMemEnd = 0x620000000000ull;
|
|
+ static const uptr kShadowMsk = 0x780000000000ull;
|
|
+ static const uptr kShadowXor = 0x040000000000ull;
|
|
+ static const uptr kShadowAdd = 0x000000000000ull;
|
|
+ static const uptr kVdsoBeg = 0x7fffffffc000ull;
|
|
+};
|
|
+
|
|
/*
|
|
C/C++ on linux/mips64 (40-bit VMA)
|
|
0000 0000 00 - 0100 0000 00: - (4 GB)
|
|
@@ -674,6 +726,8 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) {
|
|
return Func::template Apply<MappingMips64_40>(arg);
|
|
# elif defined(__s390x__)
|
|
return Func::template Apply<MappingS390x>(arg);
|
|
+# elif SANITIZER_LOONGARCH64
|
|
+ return Func::template Apply<MappingLoongArch64_47>(arg);
|
|
# else
|
|
# error "unsupported platform"
|
|
# endif
|
|
@@ -684,6 +738,7 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) {
|
|
template <typename Func>
|
|
void ForEachMapping() {
|
|
Func::template Apply<Mapping48AddressSpace>();
|
|
+ Func::template Apply<MappingLoongArch64_47>();
|
|
Func::template Apply<MappingMips64_40>();
|
|
Func::template Apply<MappingAppleAarch64>();
|
|
Func::template Apply<MappingAarch64_39>();
|
|
diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
|
|
index 73ec14892..995634b9c 100644
|
|
--- a/libsanitizer/tsan/tsan_platform_linux.cpp
|
|
+++ b/libsanitizer/tsan/tsan_platform_linux.cpp
|
|
@@ -66,7 +66,8 @@ extern "C" void *__libc_stack_end;
|
|
void *__libc_stack_end = 0;
|
|
#endif
|
|
|
|
-#if SANITIZER_LINUX && defined(__aarch64__) && !SANITIZER_GO
|
|
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64)) && \
|
|
+ !SANITIZER_GO
|
|
# define INIT_LONGJMP_XOR_KEY 1
|
|
#else
|
|
# define INIT_LONGJMP_XOR_KEY 0
|
|
@@ -242,6 +243,14 @@ void InitializePlatformEarly() {
|
|
Die();
|
|
}
|
|
#endif
|
|
+#elif SANITIZER_LOONGARCH64
|
|
+# if !SANITIZER_GO
|
|
+ if (vmaSize != 47) {
|
|
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
|
|
+ Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
|
|
+ Die();
|
|
+ }
|
|
+# endif
|
|
#elif defined(__powerpc64__)
|
|
# if !SANITIZER_GO
|
|
if (vmaSize != 44 && vmaSize != 46 && vmaSize != 47) {
|
|
@@ -302,7 +311,7 @@ void InitializePlatform() {
|
|
SetAddressSpaceUnlimited();
|
|
reexec = true;
|
|
}
|
|
-#if SANITIZER_LINUX && defined(__aarch64__)
|
|
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64))
|
|
// After patch "arm64: mm: support ARCH_MMAP_RND_BITS." is introduced in
|
|
// linux kernel, the random gap between stack and mapped area is increased
|
|
// from 128M to 36G on 39-bit aarch64. As it is almost impossible to cover
|
|
@@ -387,6 +396,8 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
|
|
# else
|
|
return mangled_sp;
|
|
# endif
|
|
+#elif defined(__loongarch_lp64)
|
|
+ return mangled_sp ^ longjmp_xor_key;
|
|
#elif defined(__powerpc64__)
|
|
// Reverse of:
|
|
// ld r4, -28696(r13)
|
|
@@ -418,6 +429,8 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
|
|
#elif SANITIZER_LINUX
|
|
# ifdef __aarch64__
|
|
# define LONG_JMP_SP_ENV_SLOT 13
|
|
+# elif defined(__loongarch__)
|
|
+# define LONG_JMP_SP_ENV_SLOT 1
|
|
# elif defined(__mips64)
|
|
# define LONG_JMP_SP_ENV_SLOT 1
|
|
# elif defined(__s390x__)
|
|
@@ -444,7 +457,11 @@ static void InitializeLongjmpXorKey() {
|
|
|
|
// 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.
|
|
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
|
|
index eab837042..6a7e255ad 100644
|
|
--- a/libsanitizer/tsan/tsan_rtl.h
|
|
+++ b/libsanitizer/tsan/tsan_rtl.h
|
|
@@ -55,7 +55,8 @@ namespace __tsan {
|
|
|
|
#if !SANITIZER_GO
|
|
struct MapUnmapCallback;
|
|
-#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
|
|
+#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__) || \
|
|
+ defined(__loongarch__)
|
|
|
|
struct AP32 {
|
|
static const uptr kSpaceBeg = 0;
|
|
diff --git a/libsanitizer/tsan/tsan_rtl_loongarch64.S b/libsanitizer/tsan/tsan_rtl_loongarch64.S
|
|
new file mode 100644
|
|
index 000000000..12856bd11
|
|
--- /dev/null
|
|
+++ b/libsanitizer/tsan/tsan_rtl_loongarch64.S
|
|
@@ -0,0 +1,196 @@
|
|
+#include "sanitizer_common/sanitizer_asm.h"
|
|
+
|
|
+.section .text
|
|
+
|
|
+ASM_HIDDEN(__tsan_setjmp)
|
|
+.comm _ZN14__interception11real_setjmpE,8,8
|
|
+.globl ASM_SYMBOL_INTERCEPTOR(setjmp)
|
|
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp))
|
|
+ASM_SYMBOL_INTERCEPTOR(setjmp):
|
|
+ CFI_STARTPROC
|
|
+
|
|
+ // Save frame pointer and return address register
|
|
+ addi.d $sp, $sp, -32
|
|
+ st.d $ra, $sp, 24
|
|
+ st.d $fp, $sp, 16
|
|
+ CFI_DEF_CFA_OFFSET (32)
|
|
+ CFI_OFFSET (1, -8)
|
|
+ CFI_OFFSET (22, -16)
|
|
+
|
|
+ // Adjust the SP for previous frame
|
|
+ addi.d $fp, $sp, 32
|
|
+ CFI_DEF_CFA_REGISTER (22)
|
|
+
|
|
+ // Save env parameter
|
|
+ st.d $a0, $sp, 8
|
|
+ CFI_OFFSET (4, -24)
|
|
+
|
|
+ // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
|
|
+ addi.d $a0, $fp, 0
|
|
+
|
|
+ // call tsan interceptor
|
|
+ bl ASM_SYMBOL(__tsan_setjmp)
|
|
+
|
|
+ // Restore env parameter
|
|
+ ld.d $a0, $sp, 8
|
|
+ CFI_RESTORE (4)
|
|
+
|
|
+ // Restore frame/link register
|
|
+ ld.d $fp, $sp, 16
|
|
+ ld.d $ra, $sp, 24
|
|
+ addi.d $sp, $sp, 32
|
|
+ CFI_RESTORE (22)
|
|
+ CFI_RESTORE (1)
|
|
+ CFI_DEF_CFA (3, 0)
|
|
+
|
|
+ // tail jump to libc setjmp
|
|
+ la.local $a1, _ZN14__interception11real_setjmpE
|
|
+ ld.d $a1, $a1, 0
|
|
+ jr $a1
|
|
+
|
|
+ CFI_ENDPROC
|
|
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp))
|
|
+
|
|
+.comm _ZN14__interception12real__setjmpE,8,8
|
|
+.globl ASM_SYMBOL_INTERCEPTOR(_setjmp)
|
|
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp))
|
|
+ASM_SYMBOL_INTERCEPTOR(_setjmp):
|
|
+ CFI_STARTPROC
|
|
+
|
|
+ // Save frame pointer and return address register
|
|
+ addi.d $sp, $sp, -32
|
|
+ st.d $ra, $sp, 24
|
|
+ st.d $fp, $sp, 16
|
|
+ CFI_DEF_CFA_OFFSET (32)
|
|
+ CFI_OFFSET (1, -8)
|
|
+ CFI_OFFSET (22, -16)
|
|
+
|
|
+ // Adjust the SP for previous frame
|
|
+ addi.d $fp, $sp, 32
|
|
+ CFI_DEF_CFA_REGISTER (22)
|
|
+
|
|
+ // Save env parameter
|
|
+ st.d $a0, $sp, 8
|
|
+ CFI_OFFSET (4, -24)
|
|
+
|
|
+ // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
|
|
+ addi.d $a0, $fp, 0
|
|
+
|
|
+ // call tsan interceptor
|
|
+ bl ASM_SYMBOL(__tsan_setjmp)
|
|
+
|
|
+ // Restore env parameter
|
|
+ ld.d $a0, $sp, 8
|
|
+ CFI_RESTORE (4)
|
|
+
|
|
+ // Restore frame/link register
|
|
+ ld.d $fp, $sp, 16
|
|
+ ld.d $ra, $sp, 24
|
|
+ addi.d $sp, $sp, 32
|
|
+ CFI_RESTORE (22)
|
|
+ CFI_RESTORE (1)
|
|
+ CFI_DEF_CFA (3, 0)
|
|
+
|
|
+ // tail jump to libc setjmp
|
|
+ la.local $a1, _ZN14__interception12real__setjmpE
|
|
+ ld.d $a1, $a1, 0
|
|
+ jr $a1
|
|
+
|
|
+ CFI_ENDPROC
|
|
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp))
|
|
+
|
|
+.comm _ZN14__interception14real_sigsetjmpE,8,8
|
|
+.globl ASM_SYMBOL_INTERCEPTOR(sigsetjmp)
|
|
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp))
|
|
+ASM_SYMBOL_INTERCEPTOR(sigsetjmp):
|
|
+ CFI_STARTPROC
|
|
+
|
|
+ // Save frame pointer and return address register
|
|
+ addi.d $sp, $sp, -32
|
|
+ st.d $ra, $sp, 24
|
|
+ st.d $fp, $sp, 16
|
|
+ CFI_DEF_CFA_OFFSET (32)
|
|
+ CFI_OFFSET (1, -8)
|
|
+ CFI_OFFSET (22, -16)
|
|
+
|
|
+ // Adjust the SP for previous frame
|
|
+ addi.d $fp, $sp, 32
|
|
+ CFI_DEF_CFA_REGISTER (22)
|
|
+
|
|
+ // Save env parameter
|
|
+ st.d $a0, $sp, 8
|
|
+ CFI_OFFSET (4, -24)
|
|
+
|
|
+ // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
|
|
+ addi.d $a0, $fp, 0
|
|
+
|
|
+ // call tsan interceptor
|
|
+ bl ASM_SYMBOL(__tsan_setjmp)
|
|
+
|
|
+ // Restore env parameter
|
|
+ ld.d $a0, $sp, 8
|
|
+ CFI_RESTORE (4)
|
|
+
|
|
+ // Restore frame/link register
|
|
+ ld.d $fp, $sp, 16
|
|
+ ld.d $ra, $sp, 24
|
|
+ addi.d $sp, $sp, 32
|
|
+ CFI_RESTORE (22)
|
|
+ CFI_RESTORE (1)
|
|
+ CFI_DEF_CFA (3, 0)
|
|
+
|
|
+ // tail jump to libc setjmp
|
|
+ la.local $a1, _ZN14__interception14real_sigsetjmpE
|
|
+ ld.d $a1, $a1, 0
|
|
+ jr $a1
|
|
+
|
|
+ CFI_ENDPROC
|
|
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp))
|
|
+
|
|
+.comm _ZN14__interception16real___sigsetjmpE,8,8
|
|
+.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)
|
|
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp))
|
|
+ASM_SYMBOL_INTERCEPTOR(__sigsetjmp):
|
|
+ CFI_STARTPROC
|
|
+
|
|
+ // Save frame pointer and return address register
|
|
+ addi.d $sp, $sp, -32
|
|
+ st.d $ra, $sp, 24
|
|
+ st.d $fp, $sp, 16
|
|
+ CFI_DEF_CFA_OFFSET (32)
|
|
+ CFI_OFFSET (1, -8)
|
|
+ CFI_OFFSET (22, -16)
|
|
+
|
|
+ // Adjust the SP for previous frame
|
|
+ addi.d $fp, $sp, 32
|
|
+ CFI_DEF_CFA_REGISTER (22)
|
|
+
|
|
+ // Save env parameter
|
|
+ st.d $a0, $sp, 8
|
|
+ CFI_OFFSET (4, -24)
|
|
+
|
|
+ // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
|
|
+ addi.d $a0, $fp, 0
|
|
+
|
|
+ // call tsan interceptor
|
|
+ bl ASM_SYMBOL(__tsan_setjmp)
|
|
+
|
|
+ // Restore env parameter
|
|
+ ld.d $a0, $sp, 8
|
|
+ CFI_RESTORE (4)
|
|
+
|
|
+ // Restore frame/link register
|
|
+ ld.d $fp, $sp, 16
|
|
+ ld.d $ra, $sp, 24
|
|
+ addi.d $sp, $sp, 32
|
|
+ CFI_RESTORE (22)
|
|
+ CFI_RESTORE (1)
|
|
+ CFI_DEF_CFA (3, 0)
|
|
+
|
|
+ // tail jump to libc setjmp
|
|
+ la.local $a1, _ZN14__interception16real___sigsetjmpE
|
|
+ ld.d $a1, $a1, 0
|
|
+ jr $a1
|
|
+
|
|
+ CFI_ENDPROC
|
|
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp))
|
|
--
|
|
2.33.0
|
|
|