Index: libunwind/include/__libunwind_config.h =================================================================== --- libunwind/include/__libunwind_config.h +++ libunwind/include/__libunwind_config.h @@ -23,6 +23,7 @@ #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64 #if defined(_LIBUNWIND_IS_NATIVE_ONLY) # if defined(__i386__) @@ -118,6 +119,15 @@ #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC #define _LIBUNWIND_CONTEXT_SIZE 16 #define _LIBUNWIND_CURSOR_SIZE 23 +# elif defined(__riscv) +# if __riscv_xlen == 64 +# define _LIBUNWIND_TARGET_RISCV 1 +# define _LIBUNWIND_CONTEXT_SIZE 64 +# define _LIBUNWIND_CURSOR_SIZE 76 +# else +# error "Unsupported RISC-V ABI" +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV # else # error "Unsupported architecture." # endif @@ -132,6 +142,7 @@ # define _LIBUNWIND_TARGET_MIPS_O32 1 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1 # define _LIBUNWIND_TARGET_SPARC 1 +# define _LIBUNWIND_TARGET_RISCV 1 # define _LIBUNWIND_CONTEXT_SIZE 167 # define _LIBUNWIND_CURSOR_SIZE 179 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 Index: libunwind/include/libunwind.h =================================================================== --- libunwind/include/libunwind.h +++ libunwind/include/libunwind.h @@ -832,4 +832,75 @@ UNW_SPARC_I7 = 31, }; +// RISC-V registers. These match the DWARF register numbers defined by section +// 4 of the RISC-V ELF psABI specification, which can be found at: +// +// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md +enum { + UNW_RISCV_X0 = 0, + UNW_RISCV_X1 = 1, + UNW_RISCV_X2 = 2, + UNW_RISCV_X3 = 3, + UNW_RISCV_X4 = 4, + UNW_RISCV_X5 = 5, + UNW_RISCV_X6 = 6, + UNW_RISCV_X7 = 7, + UNW_RISCV_X8 = 8, + UNW_RISCV_X9 = 9, + UNW_RISCV_X10 = 10, + UNW_RISCV_X11 = 11, + UNW_RISCV_X12 = 12, + UNW_RISCV_X13 = 13, + UNW_RISCV_X14 = 14, + UNW_RISCV_X15 = 15, + UNW_RISCV_X16 = 16, + UNW_RISCV_X17 = 17, + UNW_RISCV_X18 = 18, + UNW_RISCV_X19 = 19, + UNW_RISCV_X20 = 20, + UNW_RISCV_X21 = 21, + UNW_RISCV_X22 = 22, + UNW_RISCV_X23 = 23, + UNW_RISCV_X24 = 24, + UNW_RISCV_X25 = 25, + UNW_RISCV_X26 = 26, + UNW_RISCV_X27 = 27, + UNW_RISCV_X28 = 28, + UNW_RISCV_X29 = 29, + UNW_RISCV_X30 = 30, + UNW_RISCV_X31 = 31, + UNW_RISCV_F0 = 32, + UNW_RISCV_F1 = 33, + UNW_RISCV_F2 = 34, + UNW_RISCV_F3 = 35, + UNW_RISCV_F4 = 36, + UNW_RISCV_F5 = 37, + UNW_RISCV_F6 = 38, + UNW_RISCV_F7 = 39, + UNW_RISCV_F8 = 40, + UNW_RISCV_F9 = 41, + UNW_RISCV_F10 = 42, + UNW_RISCV_F11 = 43, + UNW_RISCV_F12 = 44, + UNW_RISCV_F13 = 45, + UNW_RISCV_F14 = 46, + UNW_RISCV_F15 = 47, + UNW_RISCV_F16 = 48, + UNW_RISCV_F17 = 49, + UNW_RISCV_F18 = 50, + UNW_RISCV_F19 = 51, + UNW_RISCV_F20 = 52, + UNW_RISCV_F21 = 53, + UNW_RISCV_F22 = 54, + UNW_RISCV_F23 = 55, + UNW_RISCV_F24 = 56, + UNW_RISCV_F25 = 57, + UNW_RISCV_F26 = 58, + UNW_RISCV_F27 = 59, + UNW_RISCV_F28 = 60, + UNW_RISCV_F29 = 61, + UNW_RISCV_F30 = 62, + UNW_RISCV_F31 = 63, +}; + #endif Index: libunwind/src/Registers.hpp =================================================================== --- libunwind/src/Registers.hpp +++ libunwind/src/Registers.hpp @@ -34,6 +34,7 @@ REGISTERS_MIPS_O32, REGISTERS_MIPS_NEWABI, REGISTERS_SPARC, + REGISTERS_RISCV, }; #if defined(_LIBUNWIND_TARGET_I386) @@ -3517,6 +3518,270 @@ } #endif // _LIBUNWIND_TARGET_SPARC +#if defined(_LIBUNWIND_TARGET_RISCV) +/// Registers_riscv holds the register state of a thread in a 64-bit RISC-V +/// process. +class _LIBUNWIND_HIDDEN Registers_riscv { +public: + Registers_riscv(); + Registers_riscv(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV; } + static int getArch() { return REGISTERS_RISCV; } + + uint64_t getSP() const { return _registers[2]; } + void setSP(uint64_t value) { _registers[2] = value; } + uint64_t getIP() const { return _registers[1]; } + void setIP(uint64_t value) { _registers[1] = value; } + +private: + + uint64_t _registers[32]; + double _floats[32]; +}; + +inline Registers_riscv::Registers_riscv(const void *registers) { + static_assert((check_fit::does_fit), + "riscv registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); + static_assert(sizeof(_registers) == 0x100, + "expected float registers to be at offset 256"); + memcpy(_floats, + static_cast(registers) + sizeof(_registers), + sizeof(_floats)); +} + +inline Registers_riscv::Registers_riscv() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_floats, 0, sizeof(_floats)); +} + +inline bool Registers_riscv::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > UNW_RISCV_F31) + return false; + return true; +} + +inline uint64_t Registers_riscv::getRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return _registers[1]; + if (regNum == UNW_REG_SP) + return _registers[2]; + if (regNum == UNW_RISCV_X0) + return 0; + if ((regNum > 0) && (regNum < 32)) + return _registers[regNum]; + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline void Registers_riscv::setRegister(int regNum, uint64_t value) { + if (regNum == UNW_REG_IP) + _registers[1] = value; + else if (regNum == UNW_REG_SP) + _registers[2] = value; + else if (regNum == UNW_RISCV_X0) + /* x0 is hardwired to zero */ + return; + else if ((regNum > 0) && (regNum < 32)) + _registers[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline const char *Registers_riscv::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_REG_SP: + return "sp"; + case UNW_RISCV_X0: + return "zero"; + case UNW_RISCV_X1: + return "ra"; + case UNW_RISCV_X2: + return "sp"; + case UNW_RISCV_X3: + return "gp"; + case UNW_RISCV_X4: + return "tp"; + case UNW_RISCV_X5: + return "t0"; + case UNW_RISCV_X6: + return "t1"; + case UNW_RISCV_X7: + return "t2"; + case UNW_RISCV_X8: + return "s0"; + case UNW_RISCV_X9: + return "s1"; + case UNW_RISCV_X10: + return "a0"; + case UNW_RISCV_X11: + return "a1"; + case UNW_RISCV_X12: + return "a2"; + case UNW_RISCV_X13: + return "a3"; + case UNW_RISCV_X14: + return "a4"; + case UNW_RISCV_X15: + return "a5"; + case UNW_RISCV_X16: + return "a6"; + case UNW_RISCV_X17: + return "a7"; + case UNW_RISCV_X18: + return "s2"; + case UNW_RISCV_X19: + return "s3"; + case UNW_RISCV_X20: + return "s4"; + case UNW_RISCV_X21: + return "s5"; + case UNW_RISCV_X22: + return "s6"; + case UNW_RISCV_X23: + return "s7"; + case UNW_RISCV_X24: + return "s8"; + case UNW_RISCV_X25: + return "s9"; + case UNW_RISCV_X26: + return "s10"; + case UNW_RISCV_X27: + return "s11"; + case UNW_RISCV_X28: + return "t3"; + case UNW_RISCV_X29: + return "t4"; + case UNW_RISCV_X30: + return "t5"; + case UNW_RISCV_X31: + return "t6"; + case UNW_RISCV_F0: + return "ft0"; + case UNW_RISCV_F1: + return "ft1"; + case UNW_RISCV_F2: + return "ft2"; + case UNW_RISCV_F3: + return "ft3"; + case UNW_RISCV_F4: + return "ft4"; + case UNW_RISCV_F5: + return "ft5"; + case UNW_RISCV_F6: + return "ft6"; + case UNW_RISCV_F7: + return "ft7"; + case UNW_RISCV_F8: + return "fs0"; + case UNW_RISCV_F9: + return "fs1"; + case UNW_RISCV_F10: + return "fa0"; + case UNW_RISCV_F11: + return "fa1"; + case UNW_RISCV_F12: + return "fa2"; + case UNW_RISCV_F13: + return "fa3"; + case UNW_RISCV_F14: + return "fa4"; + case UNW_RISCV_F15: + return "fa5"; + case UNW_RISCV_F16: + return "fa6"; + case UNW_RISCV_F17: + return "fa7"; + case UNW_RISCV_F18: + return "fs2"; + case UNW_RISCV_F19: + return "fs3"; + case UNW_RISCV_F20: + return "fs4"; + case UNW_RISCV_F21: + return "fs5"; + case UNW_RISCV_F22: + return "fs6"; + case UNW_RISCV_F23: + return "fs7"; + case UNW_RISCV_F24: + return "fs8"; + case UNW_RISCV_F25: + return "fs9"; + case UNW_RISCV_F26: + return "fs10"; + case UNW_RISCV_F27: + return "fs11"; + case UNW_RISCV_F28: + return "ft8"; + case UNW_RISCV_F29: + return "ft9"; + case UNW_RISCV_F30: + return "ft10"; + case UNW_RISCV_F31: + return "ft11"; + default: + return "unknown register"; + } +} + +inline bool Registers_riscv::validFloatRegister(int regNum) const { + if (regNum < UNW_RISCV_F0) + return false; + if (regNum > UNW_RISCV_F31) + return false; + return true; +} + +inline double Registers_riscv::getFloatRegister(int regNum) const { +#if defined(__riscv_flen) && __riscv_flen == 64 + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_RISCV_F0]; +#else + _LIBUNWIND_ABORT("libunwind not built with float support"); +#endif +} + +inline void Registers_riscv::setFloatRegister(int regNum, double value) { +#if defined(__riscv_flen) && __riscv_flen == 64 + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_RISCV_F0] = value; +#else + _LIBUNWIND_ABORT("libunwind not built with float support"); +#endif +} + +inline bool Registers_riscv::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_riscv::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} + +inline void Registers_riscv::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} +#endif // _LIBUNWIND_TARGET_RISCV } // namespace libunwind #endif // __REGISTERS_HPP__ Index: libunwind/src/UnwindCursor.hpp =================================================================== --- libunwind/src/UnwindCursor.hpp +++ libunwind/src/UnwindCursor.hpp @@ -995,6 +995,12 @@ int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; } #endif +#if defined (_LIBUNWIND_TARGET_RISCV) + int stepWithCompactEncoding(Registers_riscv &) { + return UNW_EINVAL; + } +#endif + bool compactSaysUseDwarf(uint32_t *offset=NULL) const { R dummy; return compactSaysUseDwarf(dummy, offset); @@ -1061,6 +1067,12 @@ bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; } #endif +#if defined (_LIBUNWIND_TARGET_RISCV) + bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const { + return true; + } +#endif + #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) @@ -1127,6 +1139,12 @@ compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; } #endif +#if defined (_LIBUNWIND_TARGET_RISCV) + compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const { + return 0; + } +#endif + #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) Index: libunwind/src/UnwindRegistersRestore.S =================================================================== --- libunwind/src/UnwindRegistersRestore.S +++ libunwind/src/UnwindRegistersRestore.S @@ -1029,6 +1029,87 @@ jmp %o7 nop +#elif defined(__riscv) && __riscv_xlen == 64 + +// +// void libunwind::Registers_riscv::jumpto() +// +// On entry: +// thread_state pointer is in a0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv) +#if defined(__riscv_flen) && __riscv_flen == 64 + fld f0, (8 * 32 + 8 * 0)(a0) + fld f1, (8 * 32 + 8 * 1)(a0) + fld f2, (8 * 32 + 8 * 2)(a0) + fld f3, (8 * 32 + 8 * 3)(a0) + fld f4, (8 * 32 + 8 * 4)(a0) + fld f5, (8 * 32 + 8 * 5)(a0) + fld f6, (8 * 32 + 8 * 6)(a0) + fld f7, (8 * 32 + 8 * 7)(a0) + fld f8, (8 * 32 + 8 * 8)(a0) + fld f9, (8 * 32 + 8 * 9)(a0) + fld f10, (8 * 32 + 8 * 10)(a0) + fld f11, (8 * 32 + 8 * 11)(a0) + fld f12, (8 * 32 + 8 * 12)(a0) + fld f13, (8 * 32 + 8 * 13)(a0) + fld f14, (8 * 32 + 8 * 14)(a0) + fld f15, (8 * 32 + 8 * 15)(a0) + fld f16, (8 * 32 + 8 * 16)(a0) + fld f17, (8 * 32 + 8 * 17)(a0) + fld f18, (8 * 32 + 8 * 18)(a0) + fld f19, (8 * 32 + 8 * 19)(a0) + fld f20, (8 * 32 + 8 * 20)(a0) + fld f21, (8 * 32 + 8 * 21)(a0) + fld f22, (8 * 32 + 8 * 22)(a0) + fld f23, (8 * 32 + 8 * 23)(a0) + fld f24, (8 * 32 + 8 * 24)(a0) + fld f25, (8 * 32 + 8 * 25)(a0) + fld f26, (8 * 32 + 8 * 26)(a0) + fld f27, (8 * 32 + 8 * 27)(a0) + fld f28, (8 * 32 + 8 * 28)(a0) + fld f29, (8 * 32 + 8 * 29)(a0) + fld f30, (8 * 32 + 8 * 30)(a0) + fld f31, (8 * 32 + 8 * 31)(a0) +#endif + + // x0 is zero + ld x1, (8 * 1)(a0) + ld x2, (8 * 2)(a0) + ld x3, (8 * 3)(a0) + ld x4, (8 * 4)(a0) + ld x5, (8 * 5)(a0) + ld x6, (8 * 6)(a0) + ld x7, (8 * 7)(a0) + ld x8, (8 * 8)(a0) + ld x9, (8 * 9)(a0) + // skip a0 for now + ld x11, (8 * 11)(a0) + ld x12, (8 * 12)(a0) + ld x13, (8 * 13)(a0) + ld x14, (8 * 14)(a0) + ld x15, (8 * 15)(a0) + ld x16, (8 * 16)(a0) + ld x17, (8 * 17)(a0) + ld x18, (8 * 18)(a0) + ld x19, (8 * 19)(a0) + ld x20, (8 * 20)(a0) + ld x21, (8 * 21)(a0) + ld x22, (8 * 22)(a0) + ld x23, (8 * 23)(a0) + ld x24, (8 * 24)(a0) + ld x25, (8 * 25)(a0) + ld x26, (8 * 26)(a0) + ld x27, (8 * 27)(a0) + ld x28, (8 * 28)(a0) + ld x29, (8 * 29)(a0) + ld x30, (8 * 30)(a0) + ld x31, (8 * 31)(a0) + ld x10, (8 * 10)(a0) // restore a0 + + ret // jump to ra + #endif #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ Index: libunwind/src/UnwindRegistersSave.S =================================================================== --- libunwind/src/UnwindRegistersSave.S +++ libunwind/src/UnwindRegistersSave.S @@ -974,6 +974,86 @@ std %i6, [%o0 + 120] jmp %o7 clr %o0 // return UNW_ESUCCESS + +#elif defined(__riscv) && __riscv_xlen == 64 + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + // x0 is zero + sd x1, (8 * 1)(a0) + sd x2, (8 * 2)(a0) + sd x3, (8 * 3)(a0) + sd x4, (8 * 4)(a0) + sd x5, (8 * 5)(a0) + sd x6, (8 * 6)(a0) + sd x7, (8 * 7)(a0) + sd x8, (8 * 8)(a0) + sd x9, (8 * 9)(a0) + sd x10, (8 * 10)(a0) + sd x11, (8 * 11)(a0) + sd x12, (8 * 12)(a0) + sd x13, (8 * 13)(a0) + sd x14, (8 * 14)(a0) + sd x15, (8 * 15)(a0) + sd x16, (8 * 16)(a0) + sd x17, (8 * 17)(a0) + sd x18, (8 * 18)(a0) + sd x19, (8 * 19)(a0) + sd x20, (8 * 20)(a0) + sd x21, (8 * 21)(a0) + sd x22, (8 * 22)(a0) + sd x23, (8 * 23)(a0) + sd x24, (8 * 24)(a0) + sd x25, (8 * 25)(a0) + sd x26, (8 * 26)(a0) + sd x27, (8 * 27)(a0) + sd x28, (8 * 28)(a0) + sd x29, (8 * 29)(a0) + sd x30, (8 * 30)(a0) + sd x31, (8 * 31)(a0) + +#if defined(__riscv_flen) && __riscv_flen == 64 + fsd f0, (8 * 32 + 8 * 0)(a0) + fsd f1, (8 * 32 + 8 * 1)(a0) + fsd f2, (8 * 32 + 8 * 2)(a0) + fsd f3, (8 * 32 + 8 * 3)(a0) + fsd f4, (8 * 32 + 8 * 4)(a0) + fsd f5, (8 * 32 + 8 * 5)(a0) + fsd f6, (8 * 32 + 8 * 6)(a0) + fsd f7, (8 * 32 + 8 * 7)(a0) + fsd f8, (8 * 32 + 8 * 8)(a0) + fsd f9, (8 * 32 + 8 * 9)(a0) + fsd f10, (8 * 32 + 8 * 10)(a0) + fsd f11, (8 * 32 + 8 * 11)(a0) + fsd f12, (8 * 32 + 8 * 12)(a0) + fsd f13, (8 * 32 + 8 * 13)(a0) + fsd f14, (8 * 32 + 8 * 14)(a0) + fsd f15, (8 * 32 + 8 * 15)(a0) + fsd f16, (8 * 32 + 8 * 16)(a0) + fsd f17, (8 * 32 + 8 * 17)(a0) + fsd f18, (8 * 32 + 8 * 18)(a0) + fsd f19, (8 * 32 + 8 * 19)(a0) + fsd f20, (8 * 32 + 8 * 20)(a0) + fsd f21, (8 * 32 + 8 * 21)(a0) + fsd f22, (8 * 32 + 8 * 22)(a0) + fsd f23, (8 * 32 + 8 * 23)(a0) + fsd f24, (8 * 32 + 8 * 24)(a0) + fsd f25, (8 * 32 + 8 * 25)(a0) + fsd f26, (8 * 32 + 8 * 26)(a0) + fsd f27, (8 * 32 + 8 * 27)(a0) + fsd f28, (8 * 32 + 8 * 28)(a0) + fsd f29, (8 * 32 + 8 * 29)(a0) + fsd f30, (8 * 32 + 8 * 30)(a0) + fsd f31, (8 * 32 + 8 * 31)(a0) +#endif + + li a0, 0 // return UNW_ESUCCESS + ret // jump to ra #endif WEAK_ALIAS(__unw_getcontext, unw_getcontext) Index: libunwind/src/config.h =================================================================== --- libunwind/src/config.h +++ libunwind/src/config.h @@ -103,7 +103,8 @@ defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \ (!defined(__APPLE__) && defined(__arm__)) || \ (defined(__arm64__) || defined(__aarch64__)) || \ - defined(__mips__) + defined(__mips__) || \ + defined(__riscv) #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS) #define _LIBUNWIND_BUILD_ZERO_COST_APIS #endif Index: libunwind/src/libunwind.cpp =================================================================== --- libunwind/src/libunwind.cpp +++ libunwind/src/libunwind.cpp @@ -58,6 +58,8 @@ # warning The MIPS architecture is not supported with this ABI and environment! #elif defined(__sparc__) # define REGISTER_KIND Registers_sparc +#elif defined(__riscv) && __riscv_xlen == 64 +# define REGISTER_KIND Registers_riscv #else # error Architecture not supported #endif