alexfanqi created this revision. Herald added subscribers: luke, Enna1, VincentWu, vkmr, frasercrmck, evandro, luismarques, apazos, sameer.abuasal, s.egerton, Jim, benna, psnobl, jocewei, PkmX, the_o, brucehoult, MartinMosbeck, rogfer01, edward-jones, zzheng, jrtc27, shiva0217, kito-cheng, niosHD, sabuasal, simoncook, johnrusso, rbar, asb, fedor.sergeev, arichardson. Herald added a project: All. alexfanqi updated this revision to Diff 502351. alexfanqi added a comment. alexfanqi retitled this revision from "[TSAN] add RISCV support" to "[TSAN] add support for riscv64". alexfanqi edited the summary of this revision. alexfanqi added reviewers: MaskRay, dvyukov, asb, StephenFan. alexfanqi published this revision for review. Herald added subscribers: Sanitizers, cfe-commits, pcwang-thead, eopXD. Herald added projects: clang, Sanitizers.
fix tsan_rtl_riscv64.S and test failures remaining test failure: ThreadSanitizer-riscv64 :: custom_mutex5.cpp The debuginfo line reported is slightly off. custom_mutex5.cpp:14 -> 15 custom_mutex5.cpp:22 -> 23 ThreadSanitizer-riscv64 :: mmap_lots.cpp flaky, the last 1000 sized mmap can get allocated to 0x0000-0x1000 Implements for sv39 and sv48 VMA layout. Userspace only has access to the bottom half of vma range. The top half is used by kernel. There is no dedicated vsyscall or heap segment. PIE program is allocated to start at TASK_SIZE/3*2. Maximum ASLR is ARCH_MMAP_RND_BITS_MAX+PAGE_SHIFT=24+12=36 Loader, vdso and other libraries are allocated below stack from the top. Both riscv32 and riscv64 need libatomic for 1,2 bytes atomic ops. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D145214 Files: clang/lib/Driver/ToolChains/Linux.cpp compiler-rt/CMakeLists.txt compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake compiler-rt/lib/tsan/rtl/CMakeLists.txt compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp compiler-rt/lib/tsan/rtl/tsan_platform.h compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp compiler-rt/lib/tsan/rtl/tsan_rtl.h compiler-rt/lib/tsan/rtl/tsan_rtl_riscv64.S compiler-rt/lib/tsan/tests/CMakeLists.txt compiler-rt/test/tsan/map32bit.cpp compiler-rt/test/tsan/mmap_large.cpp compiler-rt/test/tsan/test.h
Index: compiler-rt/test/tsan/test.h =================================================================== --- compiler-rt/test/tsan/test.h +++ compiler-rt/test/tsan/test.h @@ -73,6 +73,8 @@ const int kPCInc = 1; #elif defined(__sparc__) || defined(__mips__) const int kPCInc = 8; +#elif defined(__riscv) && __riscv_xlen == 64 +const int kPCInc = 2; #else const int kPCInc = 4; #endif Index: compiler-rt/test/tsan/mmap_large.cpp =================================================================== --- compiler-rt/test/tsan/mmap_large.cpp +++ compiler-rt/test/tsan/mmap_large.cpp @@ -17,7 +17,8 @@ int main() { #ifdef __x86_64__ const size_t kLog2Size = 39; -#elif defined(__mips64) || defined(__aarch64__) || defined(__loongarch_lp64) +#elif defined(__mips64) || defined(__aarch64__) || \ + defined(__loongarch_lp64) || (defined(__riscv) && __riscv_xlen == 64) const size_t kLog2Size = 32; #elif defined(__powerpc64__) const size_t kLog2Size = 39; Index: compiler-rt/test/tsan/map32bit.cpp =================================================================== --- compiler-rt/test/tsan/map32bit.cpp +++ compiler-rt/test/tsan/map32bit.cpp @@ -13,6 +13,7 @@ // XFAIL: target=powerpc64{{.*}} // XFAIL: target=s390x{{.*}} // XFAIL: target=loongarch64{{.*}} +// XFAIL: target=riscv64{{.*}} // MAP_32BIT doesn't exist on OS X and NetBSD. // UNSUPPORTED: darwin,target={{.*netbsd.*}} Index: compiler-rt/lib/tsan/tests/CMakeLists.txt =================================================================== --- compiler-rt/lib/tsan/tests/CMakeLists.txt +++ compiler-rt/lib/tsan/tests/CMakeLists.txt @@ -55,6 +55,9 @@ else() list(APPEND TSAN_UNITTEST_LINK_FLAGS -fsanitize=thread) list(APPEND TSAN_UNITTEST_LINK_FLAGS -lm) + if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "riscv") + list(APPEND TSAN_UNITTEST_LINK_FLAGS -latomic) + endif() list(APPEND TSAN_UNITTEST_LINK_FLAGS ${COMPILER_RT_TEST_LIBDISPATCH_CFLAGS}) endif() Index: compiler-rt/lib/tsan/rtl/tsan_rtl_riscv64.S =================================================================== --- /dev/null +++ compiler-rt/lib/tsan/rtl/tsan_rtl_riscv64.S @@ -0,0 +1,203 @@ +#include "sanitizer_common/sanitizer_asm.h" + +.section .text + +.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 sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + CFI_OFFSET (10, -24) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + CFI_RESTORE (10) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception11real_setjmpE + ld t1, 0(t1) + jr t1 + + 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 sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + CFI_OFFSET (10, -24) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + CFI_RESTORE (10) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception12real__setjmpE + ld t1, 0(t1) + jr t1 + + 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 sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + sd a1, 0(sp) + CFI_OFFSET (10, -24) + CFI_OFFSET (11, -32) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + ld a1, 0(sp) + CFI_RESTORE (10) + CFI_RESTORE (11) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception14real_sigsetjmpE + ld t1, 0(t1) + jr t1 + + 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 sp, sp, -32 + sd ra, 24(sp) + sd s0, 16(sp) + CFI_DEF_CFA_OFFSET (32) + CFI_OFFSET (1, -8) + CFI_OFFSET (8, -16) + + // Adjust the SP for previous frame + addi s0, sp, 32 + CFI_DEF_CFA_REGISTER (8) + + // Save env parameter + sd a0, 8(sp) + sd a1, 0(sp) + CFI_OFFSET (10, -24) + CFI_OFFSET (11, -32) + + // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)` + addi a0, s0, 0 + + // call tsan interceptor + call ASM_SYMBOL(__tsan_setjmp) + + // Restore env parameter + ld a0, 8(sp) + ld a1, 0(sp) + CFI_RESTORE (10) + CFI_RESTORE (11) + + // Restore frame/link register + ld s0, 16(sp) + ld ra, 24(sp) + addi sp, sp, 32 + CFI_RESTORE (8) + CFI_RESTORE (1) + CFI_DEF_CFA (2, 0) + + // tail jump to libc setjmp + la t1, _ZN14__interception16real___sigsetjmpE + ld t1, 0(t1) + jr t1 + + CFI_ENDPROC +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) Index: compiler-rt/lib/tsan/rtl/tsan_rtl.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -57,7 +57,7 @@ #if !SANITIZER_GO struct MapUnmapCallback; #if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \ - defined(__powerpc__) + defined(__powerpc__) || SANITIZER_RISCV64 struct AP32 { static const uptr kSpaceBeg = 0; Index: compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp +++ compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp @@ -266,6 +266,16 @@ Die(); } # endif +#elif SANITIZER_RISCV64 + // the bottom half of vma is allocated for userspace + vmaSize = vmaSize + 1; +# if !SANITIZER_GO + if (vmaSize != 39 && vmaSize != 48) { + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %zd - Supported 39 and 48\n", vmaSize); + Die(); + } +# endif #endif } @@ -398,6 +408,8 @@ return mangled_sp ^ xor_key; #elif defined(__mips__) return mangled_sp; +#elif SANITIZER_RISCV64 + return mangled_sp; #elif defined(__s390x__) // tcbhead_t.stack_guard uptr xor_key = ((uptr *)__builtin_thread_pointer())[5]; @@ -428,6 +440,8 @@ # define LONG_JMP_SP_ENV_SLOT 1 # elif defined(__mips64) # define LONG_JMP_SP_ENV_SLOT 1 +# elif SANITIZER_RISCV64 +# define LONG_JMP_SP_ENV_SLOT 13 # elif defined(__s390x__) # define LONG_JMP_SP_ENV_SLOT 9 # else Index: compiler-rt/lib/tsan/rtl/tsan_platform.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_platform.h +++ compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -377,6 +377,71 @@ static const uptr kMidAppMemEnd = 0; }; +/* +C/C++ on linux/riscv64 (39-bit VMA) +0000 0010 00 - 0200 0000 00: main binary ( 8 GB) +0200 0000 00 - 1000 0000 00: - +1000 0000 00 - 4000 0000 00: shadow memory (64 GB) +4000 0000 00 - 4800 0000 00: metainfo (16 GB) +4800 0000 00 - 5500 0000 00: - +5500 0000 00 - 5a00 0000 00: main binary (PIE) (~8 GB) +5600 0000 00 - 7c00 0000 00: - +7d00 0000 00 - 7fff ffff ff: libraries and main thread stack ( 8 GB) + +mmap by default allocates from top downwards +VDSO sits below loader and above dynamic libraries, within HiApp region. +Heap starts after program region whose position depends on pie or non-pie. +Disable tracking them since their locations are not fixed. +*/ +struct MappingRiscv64_39 { + static const uptr kLoAppMemBeg = 0x0000001000ull; + static const uptr kLoAppMemEnd = 0x0200000000ull; + static const uptr kShadowBeg = 0x1000000000ull; + static const uptr kShadowEnd = 0x2000000000ull; + static const uptr kMetaShadowBeg = 0x2000000000ull; + static const uptr kMetaShadowEnd = 0x2400000000ull; + static const uptr kMidAppMemBeg = 0x2aaaaaa000ull; + static const uptr kMidAppMemEnd = 0x2c00000000ull; + static const uptr kHeapMemBeg = 0x2c00000000ull; + static const uptr kHeapMemEnd = 0x2c00000000ull; + static const uptr kHiAppMemBeg = 0x3c00000000ull; + static const uptr kHiAppMemEnd = 0x3fffffffffull; + static const uptr kShadowMsk = 0x3800000000ull; + static const uptr kShadowXor = 0x0800000000ull; + static const uptr kShadowAdd = 0x0000000000ull; + static const uptr kVdsoBeg = 0x4000000000ull; +}; + +/* +C/C++ on linux/riscv64 (48-bit VMA) +0000 0000 1000 - 0500 0000 0000: main binary ( 5 TB) +0500 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 4000 0000 0000: shadow memory (32 TB) +4000 0000 0000 - 4800 0000 0000: metainfo ( 8 TB) +4800 0000 0000 - 5555 5555 5000: - +5555 5555 5000 - 5a00 0000 0000: main binary (PIE) (~5 TB) +5a00 0000 0000 - 7a00 0000 0000: - +7a00 0000 0000 - 7fff ffff ffff: libraries and main thread stack ( 5 TB) +*/ +struct MappingRiscv64_48 { + static const uptr kLoAppMemBeg = 0x000000001000ull; + static const uptr kLoAppMemEnd = 0x050000000000ull; + static const uptr kShadowBeg = 0x200000000000ull; + static const uptr kShadowEnd = 0x400000000000ull; + static const uptr kMetaShadowBeg = 0x400000000000ull; + static const uptr kMetaShadowEnd = 0x480000000000ull; + static const uptr kMidAppMemBeg = 0x555555555000ull; + static const uptr kMidAppMemEnd = 0x5a0000000000ull; + static const uptr kHeapMemBeg = 0x5a0000000000ull; + static const uptr kHeapMemEnd = 0x5a0000000000ull; + static const uptr kHiAppMemBeg = 0x7a0000000000ull; + static const uptr kHiAppMemEnd = 0x7fffffffffffull; + static const uptr kShadowMsk = 0x700000000000ull; + static const uptr kShadowXor = 0x100000000000ull; + static const uptr kShadowAdd = 0x000000000000ull; + static const uptr kVdsoBeg = 0x800000000000ull; +}; + /* C/C++ on linux/s390x While the kernel provides a 64-bit address space, we have to restrict ourselves @@ -665,6 +730,13 @@ } # elif defined(__mips64) return Func::template Apply<MappingMips64_40>(arg); +# elif SANITIZER_RISCV64 + switch (vmaSize) { + case 39: + return Func::template Apply<MappingRiscv64_39>(arg); + case 48: + return Func::template Apply<MappingRiscv64_48>(arg); + } # elif defined(__s390x__) return Func::template Apply<MappingS390x>(arg); # else @@ -686,6 +758,8 @@ Func::template Apply<MappingPPC64_44>(); Func::template Apply<MappingPPC64_46>(); Func::template Apply<MappingPPC64_47>(); + Func::template Apply<MappingRiscv64_39>(); + Func::template Apply<MappingRiscv64_48>(); Func::template Apply<MappingS390x>(); Func::template Apply<MappingGo48>(); Func::template Apply<MappingGoWindows>(); @@ -894,7 +968,7 @@ Mapping::kMidAppMemEnd, Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd, Mapping::kHeapMemBeg, Mapping::kHeapMemEnd, }; - const uptr indicator = 0x0e0000000000ull; + const uptr indicator = 0x0f0000000000ull; const uptr ind_lsb = 1ull << LeastSignificantSetBitIndex(indicator); for (uptr i = 0; i < ARRAY_SIZE(ranges); i += 2) { uptr beg = ranges[i]; Index: compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp +++ compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cpp @@ -57,7 +57,7 @@ } template<typename T> T func_xchg(volatile T *v, T op) { - T res = __sync_lock_test_and_set(v, op); + T res = __atomic_test_and_set(v, op); // __sync_lock_test_and_set does not contain full barrier. __sync_synchronize(); return res; Index: compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -78,6 +78,8 @@ #define PTHREAD_ABI_BASE "GLIBC_2.17" #elif SANITIZER_LOONGARCH64 #define PTHREAD_ABI_BASE "GLIBC_2.36" +#elif SANITIZER_RISCV64 +#define PTHREAD_ABI_BASE "GLIBC_2.27" #endif extern "C" int pthread_attr_init(void *attr); Index: compiler-rt/lib/tsan/rtl/CMakeLists.txt =================================================================== --- compiler-rt/lib/tsan/rtl/CMakeLists.txt +++ compiler-rt/lib/tsan/rtl/CMakeLists.txt @@ -2,7 +2,7 @@ set(TSAN_RTL_CFLAGS ${TSAN_CFLAGS}) append_list_if(COMPILER_RT_HAS_MSSE4_2_FLAG -msse4.2 TSAN_RTL_CFLAGS) -append_list_if(SANITIZER_LIMIT_FRAME_SIZE -Wframe-larger-than=530 +append_list_if(SANITIZER_LIMIT_FRAME_SIZE -Wframe-larger-than=656 TSAN_RTL_CFLAGS) append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors TSAN_RTL_CFLAGS) @@ -219,6 +219,10 @@ add_asm_sources(TSAN_ASM_SOURCES tsan_rtl_mips64.S ) + elseif(arch MATCHES "riscv64") + add_asm_sources(TSAN_ASM_SOURCES + tsan_rtl_riscv64.S + ) elseif(arch MATCHES "s390x") add_asm_sources(TSAN_ASM_SOURCES tsan_rtl_s390x.S Index: compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake =================================================================== --- compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -61,7 +61,7 @@ ${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} ${RISCV32} ${RISCV64}) set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X} - ${LOONGARCH64}) + ${LOONGARCH64} ${RISCV64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} ${LOONGARCH64}) Index: compiler-rt/CMakeLists.txt =================================================================== --- compiler-rt/CMakeLists.txt +++ compiler-rt/CMakeLists.txt @@ -526,7 +526,7 @@ # Only necessary for 32-bit SPARC. Solaris 11.2+ ld uses -z ignore/-z record # natively, but supports --as-needed/--no-as-needed for GNU ld compatibility. -if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "sparc") +if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "sparc|riscv") list(APPEND SANITIZER_COMMON_LINK_LIBS -Wl,--as-needed atomic -Wl,--no-as-needed) endif() Index: clang/lib/Driver/ToolChains/Linux.cpp =================================================================== --- clang/lib/Driver/ToolChains/Linux.cpp +++ clang/lib/Driver/ToolChains/Linux.cpp @@ -769,7 +769,7 @@ IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ || - IsLoongArch64) + IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Thread; if (IsX86_64) Res |= SanitizerKind::KernelMemory;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits