[compiler-rt] 38b04fd - [RISC-V][HWASAN] Add runtime support for HWASAN for RISC-V

Alexey Baturo via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 28 10:44:53 PDT 2022


Author: Alexey Baturo
Date: 2022-08-28T20:43:31+03:00
New Revision: 38b04fd9c0698531c9a7f5a214d39cf1642fe536

URL: https://github.com/llvm/llvm-project/commit/38b04fd9c0698531c9a7f5a214d39cf1642fe536
DIFF: https://github.com/llvm/llvm-project/commit/38b04fd9c0698531c9a7f5a214d39cf1642fe536.diff

LOG: [RISC-V][HWASAN] Add runtime support for HWASAN for RISC-V

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D131342

Added: 
    

Modified: 
    compiler-rt/lib/hwasan/hwasan.h
    compiler-rt/lib/hwasan/hwasan_allocator.h
    compiler-rt/lib/hwasan/hwasan_checks.h
    compiler-rt/lib/hwasan/hwasan_exceptions.cpp
    compiler-rt/lib/hwasan/hwasan_interceptors.cpp
    compiler-rt/lib/hwasan/hwasan_linux.cpp
    compiler-rt/lib/hwasan/hwasan_report.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h
index 3cc2fc40b5f6..6747efaef8e2 100644
--- a/compiler-rt/lib/hwasan/hwasan.h
+++ b/compiler-rt/lib/hwasan/hwasan.h
@@ -181,6 +181,13 @@ typedef unsigned long __hw_sigset_t;
 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_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h
index 35c3d6b4bf43..bae53b565592 100644
--- 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
index ab543ea88beb..b0b37d7a2e2b 100644
--- a/compiler-rt/lib/hwasan/hwasan_checks.h
+++ b/compiler-rt/lib/hwasan/hwasan_checks.h
@@ -36,6 +36,15 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
       "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
+  register uptr x10 asm("x10") = p;
+  asm volatile(
+      "ebreak\n"
+      "addiw x0, x0, %1\n" ::"r"(x10),
+      "I"(0x40 + X));
 #else
   // FIXME: not always sigill.
   __builtin_trap();
@@ -56,6 +65,14 @@ __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
       "int3\n"
       "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
       "D"(p), "S"(size));
+#elif SANITIZER_RISCV64
+  // Put access size into x11
+  register uptr x10 asm("x10") = p;
+  register uptr x11 asm("x11") = size;
+  asm volatile(
+      "ebreak\n"
+      "addiw x0, x0, %2\n" ::"r"(x10),
+      "r"(x11), "I"(0x40 + X));
 #else
   __builtin_trap();
 #endif
@@ -71,7 +88,7 @@ __attribute__((always_inline, nodebug)) static bool PossiblyShortTagMatches(
     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
index 6ed1da335428..c9968a5e3603 100644
--- a/compiler-rt/lib/hwasan/hwasan_exceptions.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_exceptions.cpp
@@ -56,6 +56,8 @@ __hwasan_personality_wrapper(int version, _Unwind_Action actions,
     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
index 8dc886e587e7..c67927dc9f60 100644
--- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp
@@ -75,6 +75,8 @@ InternalLongjmp(__hw_register_buf env, int retval) {
   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,49 @@ InternalLongjmp(__hw_register_buf env, int retval) {
       "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];
+  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);"
+#      if __riscv_float_abi_double
+      "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);"
+#      elif __riscv_float_abi_soft
+#      else
+#        error "Unsupported case"
+#      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
index 42db0aedf8e3..88ccfde007d3 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp
@@ -403,6 +403,47 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
   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
@@ -421,6 +462,19 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) {
 #  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
index 66d3d155d409..fe7695891868 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -746,7 +746,7 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
 }
 
 // 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 @@ void ReportRegisters(uptr *frame, uptr pc) {
   // 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<u8 *>(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 @@ void ReportRegisters(uptr *frame, uptr pc) {
        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<u8 *>(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


        


More information about the llvm-commits mailing list