diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -1915,6 +1915,69 @@ static const uptr FSR_WRITE = 1U << 11; uptr fsr = ucontext->uc_mcontext.error_code; return fsr & FSR_WRITE ? WRITE : READ; +#elif (defined(__riscv) && (__riscv_xlen == 64)) + const auto *exception_source = + reinterpret_cast(ucontext->uc_mcontext.__gregs[REG_PC]); + // check if instruction is 2 bytes long + bool isCompressed = ((exception_source[0] & 0x3) != 0x3); + + if (!isCompressed) { + // FIXME: Add support for FPU, Atomic, etc + // opcode is located in lower 7 bits + uint8_t op_code = exception_source[0] & ((1 << 7) - 1); + // bits [12-14] + uint8_t funct3 = (exception_source[1] >> 4u) & 0b111u; + + const uint8_t READ_OPCODE = 0b0000011u; // loads + const uint8_t WRITE_OPCODE = 0b0100011u; // stores + + if (op_code == READ_OPCODE) { + switch (funct3) { + case 0b000: // lb + case 0b001: // lh + case 0b010: // lw + case 0b100: // lbu + case 0b101: // lhu + case 0b110: // lwu + case 0b011: // ld + return READ; + } + } + + if (op_code == WRITE_OPCODE) { + switch (funct3) { + case 0b000: // sb + case 0b001: // sh + case 0b010: // sw + case 0b011: // sd + return WRITE; + } + } + + return UNKNOWN; + } + uint8_t insn_byte_lo = exception_source[0]; + uint8_t insn_byte_hi = exception_source[1]; + // reconstruct the actual short instruction + uint16_t faulty_instruction = (insn_byte_lo << 0) | (insn_byte_hi << 8); + uint8_t op_code = faulty_instruction & 0x3u; + uint8_t funct = faulty_instruction >> 13u; + // RCV quadrant 0 or 2 + if (op_code == 0x0 || op_code == 0x2) { + switch (funct) { + case 0b001: // c.fld / c.fldsp + case 0b010: // c.lw / c.lwsp + case 0b011: // c.ld / c.ldsp + return READ; + case 0b101: // c.fsd / c.fsdsp + case 0b110: // c.sw / c.swsp + case 0b111: // c.sd / c.sdsp + return WRITE; + } + return UNKNOWN; + } + return UNKNOWN; + #elif defined(__aarch64__) static const u64 ESR_ELx_WNR = 1U << 6; u64 esr;