diff --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h --- a/compiler-rt/lib/hwasan/hwasan.h +++ b/compiler-rt/lib/hwasan/hwasan.h @@ -167,8 +167,8 @@ // This dispatches to HandleTagMismatch but sets up the AccessInfo, program // counter, and frame pointer. -void HwasanTagMismatch(uptr addr, uptr access_info, uptr *registers_frame, - size_t outsize); +void HwasanTagMismatch(uptr addr, uptr pc, uptr frame, uptr access_info, + uptr *registers_frame, size_t outsize); } // namespace __hwasan @@ -181,6 +181,13 @@ constexpr size_t kHwRegisterBufSize = 22; # elif defined(__x86_64__) constexpr size_t kHwRegisterBufSize = 8; +# elif SANITIZER_RISCV64 +// saving PC, 12 int regs, sp, 12 fp regs +# ifndef __riscv_float_abi_soft +constexpr size_t kHwRegisterBufSize = 1 + 12 + 1 + 12; +# else +constexpr size_t kHwRegisterBufSize = 1 + 12 + 1; +# endif # endif typedef unsigned long long __hw_register_buf[kHwRegisterBufSize]; struct __hw_jmp_buf_struct { diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp --- a/compiler-rt/lib/hwasan/hwasan.cpp +++ b/compiler-rt/lib/hwasan/hwasan.cpp @@ -218,8 +218,8 @@ registers_frame); } -void HwasanTagMismatch(uptr addr, uptr access_info, uptr *registers_frame, - size_t outsize) { +void HwasanTagMismatch(uptr addr, uptr pc, uptr frame, uptr access_info, + uptr *registers_frame, size_t outsize) { __hwasan::AccessInfo ai; ai.is_store = access_info & 0x10; ai.is_load = !ai.is_store; @@ -230,8 +230,7 @@ else ai.size = 1 << (access_info & 0xf); - HandleTagMismatch(ai, (uptr)__builtin_return_address(0), - (uptr)__builtin_frame_address(0), nullptr, registers_frame); + HandleTagMismatch(ai, pc, frame, nullptr, registers_frame); } Thread *GetCurrentThread() { @@ -599,7 +598,9 @@ // rest of the mismatch handling code (C++). void __hwasan_tag_mismatch4(uptr addr, uptr access_info, uptr *registers_frame, size_t outsize) { - __hwasan::HwasanTagMismatch(addr, access_info, registers_frame, outsize); + __hwasan::HwasanTagMismatch(addr, (uptr)__builtin_return_address(0), + (uptr)__builtin_frame_address(0), access_info, + registers_frame, outsize); } } // extern "C" diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -24,8 +24,8 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_ring_buffer.h" -#if !defined(__aarch64__) && !defined(__x86_64__) -#error Unsupported platform +#if !defined(__aarch64__) && !defined(__x86_64__) && !(SANITIZER_RISCV64) +# error Unsupported platform #endif namespace __hwasan { diff --git a/compiler-rt/lib/hwasan/hwasan_checks.h b/compiler-rt/lib/hwasan/hwasan_checks.h --- a/compiler-rt/lib/hwasan/hwasan_checks.h +++ b/compiler-rt/lib/hwasan/hwasan_checks.h @@ -36,6 +36,17 @@ "int3\n" "nopl %c0(%%rax)\n" ::"n"(0x40 + X), "D"(p)); +#elif SANITIZER_RISCV64 + // Put pointer into x10 + // addiw contains immediate of 0x40 + X, where 0x40 is magic number and X + // encodes access size + asm volatile( + "mv x10, %0\n" + "ebreak\n" + "addiw x0, x0, %1\n" + : + : "r"(p), "n"(0x40 + X) + : "memory", "x10"); #else // FIXME: not always sigill. __builtin_trap(); @@ -56,6 +67,16 @@ "int3\n" "nopl %c0(%%rax)\n" ::"n"(0x40 + X), "D"(p), "S"(size)); +#elif SANITIZER_RISCV64 + // Put access size into x11 + asm volatile( + "mv x10, %0\n" + "mv x11, %1\n" + "ebreak\n" + "addiw x0, x0, %2\n" + : + : "r"(p), "r"(size), "n"(0x40 + X) + : "memory", "x10", "x11"); #else __builtin_trap(); #endif @@ -71,7 +92,7 @@ return false; if ((ptr & (kShadowAlignment - 1)) + sz > mem_tag) return false; -#ifndef __aarch64__ +#if !defined(__aarch64__) && !(SANITIZER_RISCV64) ptr = UntagAddr(ptr); #endif return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag; diff --git a/compiler-rt/lib/hwasan/hwasan_exceptions.cpp b/compiler-rt/lib/hwasan/hwasan_exceptions.cpp --- a/compiler-rt/lib/hwasan/hwasan_exceptions.cpp +++ b/compiler-rt/lib/hwasan/hwasan_exceptions.cpp @@ -56,6 +56,8 @@ uptr fp = get_gr(context, 6); // rbp #elif defined(__aarch64__) uptr fp = get_gr(context, 29); // x29 +#elif SANITIZER_RISCV64 + uptr fp = get_gr(context, 8); // x8 #else #error Unsupported architecture #endif diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -75,6 +75,8 @@ constexpr size_t kSpIndex = 13; # elif defined(__x86_64__) constexpr size_t kSpIndex = 6; +# elif SANITIZER_RISCV64 + constexpr size_t kSpIndex = 13; # endif // Clear all memory tags on the stack between here and where we're going. @@ -131,6 +133,51 @@ "cmovnz %1,%%rax;" "jmp *%%rdx;" ::"r"(env_address), "r"(retval_tmp)); +# elif SANITIZER_RISCV64 + register long int retval_tmp asm("x11") = retval; + register void *env_address asm("x10") = &env[0]; + // Currently only common case for fp registers is supported: + // no rv64if or lp64f +# if (__riscv_flen == 32) || defined(__riscv_float_abi_single) +# error "Unsupported case" +# endif + asm volatile( + "ld ra, 0<<3(%0);" + "ld s0, 1<<3(%0);" + "ld s1, 2<<3(%0);" + "ld s2, 3<<3(%0);" + "ld s3, 4<<3(%0);" + "ld s4, 5<<3(%0);" + "ld s5, 6<<3(%0);" + "ld s6, 7<<3(%0);" + "ld s7, 8<<3(%0);" + "ld s8, 9<<3(%0);" + "ld s9, 10<<3(%0);" + "ld s10, 11<<3(%0);" + "ld s11, 12<<3(%0);" +# ifndef __riscv_float_abi_soft + "fld fs0, 14<<3(%0);" + "fld fs1, 15<<3(%0);" + "fld fs2, 16<<3(%0);" + "fld fs3, 17<<3(%0);" + "fld fs4, 18<<3(%0);" + "fld fs5, 19<<3(%0);" + "fld fs6, 20<<3(%0);" + "fld fs7, 21<<3(%0);" + "fld fs8, 22<<3(%0);" + "fld fs9, 23<<3(%0);" + "fld fs10, 24<<3(%0);" + "fld fs11, 25<<3(%0);" +# endif + "ld a4, 13<<3(%0);" + "mv sp, a4;" + // Return the value requested to return through arguments. + // This should be in x11 given what we requested above. + "seqz a0, %1;" + "add a0, a0, %1;" + "ret;" + : "+r"(env_address) + : "r"(retval_tmp)); # endif } diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp --- a/compiler-rt/lib/hwasan/hwasan_linux.cpp +++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp @@ -363,6 +363,47 @@ const uptr size = size_log == 0xf ? uc->uc_mcontext.gregs[REG_RSI] : 1U << size_log; +# elif SANITIZER_RISCV64 + // Access type is encoded in the instruction following EBREAK as + // ADDI x0, x0, [0x40 + 0xXY]. For Y == 0xF, access size is stored in + // X11 register. Access address is always in X10 register. + uptr pc = (uptr)uc->uc_mcontext.__gregs[REG_PC]; + uint8_t byte1 = *((u8 *)(pc + 0)); + uint8_t byte2 = *((u8 *)(pc + 1)); + uint8_t byte3 = *((u8 *)(pc + 2)); + uint8_t byte4 = *((u8 *)(pc + 3)); + uint32_t ebreak = (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)); + bool isFaultShort = false; + bool isEbreak = (ebreak == 0x100073); + bool isShortEbreak = false; +# if defined(__riscv_compressed) + isFaultShort = ((ebreak & 0x3) != 0x3); + isShortEbreak = ((ebreak & 0xffff) == 0x9002); +# endif + // faulted insn is not ebreak, not our case + if (!(isEbreak || isShortEbreak)) + return AccessInfo{}; + // advance pc to point after ebreak and reconstruct addi instruction + pc += isFaultShort ? 2 : 4; + byte1 = *((u8 *)(pc + 0)); + byte2 = *((u8 *)(pc + 1)); + byte3 = *((u8 *)(pc + 2)); + byte4 = *((u8 *)(pc + 3)); + // reconstruct instruction + uint32_t instr = (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)); + // check if this is really 32 bit instruction + // code is encoded in top 12 bits, since instruction is supposed to be with + // imm + const unsigned code = (instr >> 20) & 0xffff; + const uptr addr = uc->uc_mcontext.__gregs[10]; + const bool is_store = code & 0x10; + const bool recover = code & 0x20; + const unsigned size_log = code & 0xf; + if (size_log > 4 && size_log != 0xf) + return AccessInfo{}; // Not our case + const uptr size = + size_log == 0xf ? uc->uc_mcontext.__gregs[11] : 1U << size_log; + # else # error Unsupported architecture # endif @@ -381,6 +422,19 @@ # if defined(__aarch64__) uc->uc_mcontext.pc += 4; # elif defined(__x86_64__) +# elif SANITIZER_RISCV64 + // pc points to EBREAK which is 2 bytes long + uint8_t *exception_source = (uint8_t *)(uc->uc_mcontext.__gregs[REG_PC]); + uint8_t byte1 = (uint8_t)(*(exception_source + 0)); + uint8_t byte2 = (uint8_t)(*(exception_source + 1)); + uint8_t byte3 = (uint8_t)(*(exception_source + 2)); + uint8_t byte4 = (uint8_t)(*(exception_source + 3)); + uint32_t faulted = (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)); + bool isFaultShort = false; +# if defined(__riscv_compressed) + isFaultShort = ((faulted & 0x3) != 0x3); +# endif + uc->uc_mcontext.__gregs[REG_PC] += isFaultShort ? 2 : 4; # else # error Unsupported architecture # endif diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -746,7 +746,7 @@ } // See the frame breakdown defined in __hwasan_tag_mismatch (from -// hwasan_tag_mismatch_aarch64.S). +// hwasan_tag_mismatch_{aarch64,riscv64}.S). void ReportRegisters(uptr *frame, uptr pc) { Printf("Registers where the failure occurred (pc %p):\n", pc); @@ -754,8 +754,13 @@ // reduce the amount of logcat error messages printed. Each Printf() will // result in a new logcat line, irrespective of whether a newline is present, // and so we wish to reduce the number of Printf() calls we have to make. +#if defined(__aarch64__) Printf(" x0 %016llx x1 %016llx x2 %016llx x3 %016llx\n", frame[0], frame[1], frame[2], frame[3]); +#elif SANITIZER_RISCV64 + Printf(" sp %016llx x1 %016llx x2 %016llx x3 %016llx\n", + reinterpret_cast(frame) + 256, frame[1], frame[2], frame[3]); +#endif Printf(" x4 %016llx x5 %016llx x6 %016llx x7 %016llx\n", frame[4], frame[5], frame[6], frame[7]); Printf(" x8 %016llx x9 %016llx x10 %016llx x11 %016llx\n", @@ -770,8 +775,14 @@ frame[24], frame[25], frame[26], frame[27]); // hwasan_check* reduces the stack pointer by 256, then __hwasan_tag_mismatch // passes it to this function. +#if defined(__aarch64__) Printf(" x28 %016llx x29 %016llx x30 %016llx sp %016llx\n", frame[28], frame[29], frame[30], reinterpret_cast(frame) + 256); +#elif SANITIZER_RISCV64 + Printf(" x28 %016llx x29 %016llx x30 %016llx x31 %016llx\n", frame[28], + frame[29], frame[30], frame[31]); +#else +#endif } } // namespace __hwasan