diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -31,7 +31,8 @@ #endif #if defined(_LIBUNWIND_TARGET_LINUX) && \ - (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_S390X)) + (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_S390X) || \ + defined(_LIBUNWIND_TARGET_RISCV)) #include #include #include @@ -994,6 +995,10 @@ #if defined(_LIBUNWIND_TARGET_S390X) bool setInfoForSigReturn(Registers_s390x &); int stepThroughSigReturn(Registers_s390x &); +#endif +#if defined(_LIBUNWIND_TARGET_RISCV) + bool setInfoForSigReturn(Registers_riscv &); + int stepThroughSigReturn(Registers_riscv &); #endif template bool setInfoForSigReturn(Registers &) { return false; @@ -2824,6 +2829,55 @@ #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && // defined(_LIBUNWIND_TARGET_S390X) +#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \ + defined(_LIBUNWIND_TARGET_RISCV) +template +bool UnwindCursor::setInfoForSigReturn(Registers_riscv &) { + const pint_t pc = static_cast(this->getReg(UNW_REG_IP)); + uint32_t instructions[2]; + struct iovec local_iov = {&instructions, sizeof instructions}; + struct iovec remote_iov = {reinterpret_cast(pc), sizeof instructions}; + long bytesRead = + syscall(SYS_process_vm_readv, getpid(), &local_iov, 1, &remote_iov, 1, 0); + // A signal frame will have a return address pointing to + // __default_sa_restorer. This code is hardwired as: + // + // 0x08b00893 li a7,0x8b + // 0x00000073 ecall + if (bytesRead != sizeof instructions || instructions[0] != 0x08b00893 || + instructions[1] != 0x00000073) + return false; + + _info = {}; + _info.start_ip = pc; + _info.end_ip = pc + 4; + _isSigReturn = true; + return true; +} + +template +int UnwindCursor::stepThroughSigReturn(Registers_riscv &) { + + const pint_t kOffsetSpToSigcontext = 176; + + // Determine current SP. + const pint_t sp = static_cast(this->getReg(UNW_REG_SP)); + // rt_sigframe contains the siginfo structure, the ucontext, and then + // the trampoline. We store the mcontext inside ucontext as sigctx. + pint_t sigctx = sp + sizeof(siginfo_t) + kOffsetSpToSigcontext; + + for (int i = 0; i <= UNW_RISCV_X31; ++i) { + uint64_t value = _addressSpace.get64(sigctx + static_cast(i * 8)); + _registers.setRegister(i, value); + } + _registers.setSP(_addressSpace.get64(sigctx + static_cast(2 * 8))); + _registers.setIP(_addressSpace.get64(sigctx)); + _isSignalFrame = true; + return UNW_STEP_SUCCESS; +} +#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && + // defined(_LIBUNWIND_TARGET_RISCV) + template int UnwindCursor::step(bool stage2) { (void)stage2; // Bottom of stack is defined is when unwind info cannot be found.