diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h index 0e7fe98996948..1a94fe815c09b 100644 --- a/libunwind/include/__libunwind_config.h +++ b/libunwind/include/__libunwind_config.h @@ -188,8 +188,8 @@ # define RISCV_FLEN 0 # endif # ifdef __CHERI_PURE_CAPABILITY__ -# define _LIBUNWIND_CONTEXT_SIZE 96 -# define _LIBUNWIND_CURSOR_SIZE 120 +# define _LIBUNWIND_CONTEXT_SIZE 98 +# define _LIBUNWIND_CURSOR_SIZE 122 # else # define _LIBUNWIND_CONTEXT_SIZE (32 * (__riscv_xlen + RISCV_FLEN) / 64) # if __riscv_xlen == 32 diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index 530596552637b..a027f770d577d 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -679,10 +679,6 @@ enum { UNW_ARM64_CLR = 228, UNW_ARM64_C31 = 229, UNW_ARM64_CSP = 229, - // Use 240 for ECSP (executive stack pointer). ECSP is not a real DWARF - // register, but we need it to implement c18n-aware unwinding. We pick 240 - // because it is far enough away from the range of reserved registers on Arm. - UNW_ARM64_ECSP = 240, }; // 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. diff --git a/libunwind/src/CompartmentInfo.hpp b/libunwind/src/CompartmentInfo.hpp index 2d050038aceee..c3e1030f51521 100644 --- a/libunwind/src/CompartmentInfo.hpp +++ b/libunwind/src/CompartmentInfo.hpp @@ -26,7 +26,6 @@ struct CompartmentInfo { static int unwindIfAtBoundary(R ®isters) { #ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N -#ifdef _LIBUNWIND_TARGET_AARCH64 struct dl_c18n_compart_state state; pint_t pc = registers.getIP(); pint_t tf = registers.getTrustedStack(); @@ -41,8 +40,10 @@ struct CompartmentInfo { registers.setTrustedStack(tf); CHERI_DBG("C18N: SET TRUSTED STACK %#p\n", (void *)tf); +#ifdef _LIBUNWIND_TARGET_AARCH64 registers.setFP((pint_t)state.fp); CHERI_DBG("C18N: SET FP %#p\n", state.fp); +#endif registers.setSP((pint_t)state.sp); CHERI_DBG("C18N: SET SP: %#p\n", state.sp); @@ -50,14 +51,26 @@ struct CompartmentInfo { registers.setIP((pint_t)state.pc); CHERI_DBG("C18N: SET IP: %#p\n", state.pc); +#ifdef _LIBUNWIND_TARGET_AARCH64 + static constexpr int calleeSaved[] = { + UNW_ARM64_C19, UNW_ARM64_C20, UNW_ARM64_C21, UNW_ARM64_C22, + UNW_ARM64_C23, UNW_ARM64_C24, UNW_ARM64_C26, UNW_ARM64_C27, + UNW_ARM64_C28, UNW_ARM64_C29}; +#elif defined(_LIBUNWIND_TARGET_RISCV) + static constexpr int calleeSaved[] = { + UNW_RISCV_X9, UNW_RISCV_X18, UNW_RISCV_X19, UNW_RISCV_X20, + UNW_RISCV_X21, UNW_RISCV_X22, UNW_RISCV_X23, UNW_RISCV_X24, + UNW_RISCV_X25, UNW_RISCV_X26, UNW_RISCV_X27, UNW_RISCV_X8}; +#endif + static_assert(sizeof(calleeSaved) / sizeof(*calleeSaved) == + sizeof(state.regs) / sizeof(*state.regs), + "unexpected number of saved registers"); + for (size_t i = 0; i < sizeof(state.regs) / sizeof(*state.regs); ++i) { - registers.setCapabilityRegister(UNW_ARM64_C19 + i, (pint_t)state.regs[i]); - CHERI_DBG("C18N: SET REGISTER: %lu (%s): %#p\n", - UNW_ARM64_C19 + i, - registers.getRegisterName(UNW_ARM64_C19 + i), - state.regs[i]); + registers.setCapabilityRegister(calleeSaved[i], (pint_t)state.regs[i]); + CHERI_DBG("C18N: SET REGISTER: %d (%s): %#p\n", calleeSaved[i], + registers.getRegisterName(calleeSaved[i]), state.regs[i]); } -#endif #endif // _LIBUNWIND_HAS_CHERI_LIB_C18N return UNW_STEP_SUCCESS; } diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 9112ee28bd7a0..cda1b34d5fca8 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -2206,8 +2206,6 @@ inline const char *Registers_arm64::getRegisterName(int regNum) { return "clr"; case UNW_ARM64_C31: return "csp"; - case UNW_ARM64_ECSP: - return "ecsp"; default: return "unknown register"; } @@ -4554,10 +4552,18 @@ class _LIBUNWIND_HIDDEN Registers_riscv { void setSP(reg_t value) { _registers[2] = value; } reg_t getIP() const { return _registers[0]; } void setIP(reg_t value) { _registers[0] = value; } +#ifdef __CHERI_PURE_CAPABILITY__ + reg_t getTrustedStack() const { return _tsp; } + void setTrustedStack(reg_t value) { _tsp = value; } +#endif private: // _registers[0] holds the pc reg_t _registers[32]; +#ifdef __CHERI_PURE_CAPABILITY__ + // Trusted stack pointer + reg_t _tsp; +#endif # if defined(__riscv_flen) fp_t _floats[32]; # endif @@ -4580,15 +4586,26 @@ inline Registers_riscv::Registers_riscv(const void *registers) { # error "Unexpected float registers." # endif -# if defined(__riscv_flen) - memcpy(_floats, - static_cast(registers) + sizeof(_registers), - sizeof(_floats)); +#ifdef __CHERI_PURE_CAPABILITY__ + memcpy(&_tsp, static_cast(registers) + sizeof(_registers), + sizeof(_tsp)); +#endif + +#if defined(__riscv_flen) + const uint8_t *floats = static_cast(registers); + floats += sizeof(_registers); +#ifdef __CHERI_PURE_CAPABILITY__ + floats += sizeof(_tsp); +#endif + memcpy(_floats, floats, sizeof(_floats)); # endif } inline Registers_riscv::Registers_riscv() { memset(&_registers, 0, sizeof(_registers)); +#ifdef __CHERI_PURE_CAPABILITY__ + memset(&_tsp, 0, sizeof(_tsp)); +#endif # if defined(__riscv_flen) memset(&_floats, 0, sizeof(_floats)); # endif diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index c602c91d2f6cf..4fec7049502a5 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -1308,7 +1308,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) .macro restore_fpr num, ctxreg #ifdef __CHERI_PURE_CAPABILITY__ - fld f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(c\ctxreg) + fld f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(\ctxreg) #else FLOAD f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(\ctxreg) #endif @@ -1316,7 +1316,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) .macro restore_gpr num, ctxreg #ifdef __CHERI_PURE_CAPABILITY__ - lc c\num, (__SIZEOF_CHERI_CAPABILITY__ * \num)(c\ctxreg) + ly x\num, (__SIZEOF_CHERI_CAPABILITY__ * \num)(\ctxreg) #else ILOAD x\num, (RISCV_ISIZE * \num)(\ctxreg) #endif @@ -1330,6 +1330,18 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) // .p2align 2 DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv) +#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N + // Preserve the argument in a callee-saved register instead of pushing it onto + // the stack because stack unwinding will switch the stack. + ymv s1, a0 + // Pass the target untrusted stack pointer + ly a0, (__SIZEOF_CHERI_CAPABILITY__ * 2)(s1) + // Pass the target trusted stack pointer + ly a1, (__SIZEOF_CHERI_CAPABILITY__ * 32)(s1) + call dl_c18n_unwind_trusted_stack + ymv a0, s1 +#endif + # if defined(__riscv_flen) .irp i,FROM_0_TO_31 restore_fpr \i, a0 @@ -1338,7 +1350,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv) // x0 is zero #ifdef __CHERI_PURE_CAPABILITY__ - lc c1, (__SIZEOF_CHERI_CAPABILITY__ * 0)(ca0) // restore pc into ra + ly x1, (__SIZEOF_CHERI_CAPABILITY__ * 0)(a0) // restore pc into ra #else ILOAD x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra #endif diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 9f89ac31f0496..2763c5cb87b26 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -1237,7 +1237,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) .macro save_fpr num, ctxreg #ifdef __CHERI_PURE_CAPABILITY__ - fsd f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(c\ctxreg) + fsd f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(\ctxreg) #else FSTORE f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(\ctxreg) #endif @@ -1245,7 +1245,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) .macro save_gpr num, ctxreg #ifdef __CHERI_PURE_CAPABILITY__ - sc c\num, (__SIZEOF_CHERI_CAPABILITY__ * \num)(c\ctxreg) + sy x\num, (__SIZEOF_CHERI_CAPABILITY__ * \num)(\ctxreg) #else ISTORE x\num, (RISCV_ISIZE * \num)(\ctxreg) #endif @@ -1259,7 +1259,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) # DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #ifdef __CHERI_PURE_CAPABILITY__ - sc c1, (__SIZEOF_CHERI_CAPABILITY__ * 0)(ca0) // store ra as pc + sy x1, (__SIZEOF_CHERI_CAPABILITY__ * 0)(a0) // store ra as pc #else ISTORE x1, (RISCV_ISIZE * 0)(a0) // store ra as pc #endif @@ -1273,6 +1273,19 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) .endr # endif +#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N + // Store the trusted stack pointer + yaddi sp, sp, -(__SIZEOF_CHERI_CAPABILITY__ * 2) + sy a0, 0(sp) + sy ra, __SIZEOF_CHERI_CAPABILITY__(sp) + ymv a0, ra + call dl_c18n_get_trusted_stack + ly a1, 0(sp) + ly ra, __SIZEOF_CHERI_CAPABILITY__(sp) + yaddi sp, sp, (__SIZEOF_CHERI_CAPABILITY__ * 2) + sy a0, (__SIZEOF_CHERI_CAPABILITY__ * 32)(a1) +#endif + li a0, 0 // return UNW_ESUCCESS ret // jump to ra END_LIBUNWIND_FUNCTION(__unw_getcontext) diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h index 8da72ce22c788..2252e646a5502 100644 --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -36,7 +36,7 @@ #define SEPARATOR %% #elif defined(__riscv) #ifdef __CHERI_PURE_CAPABILITY__ -# define RISCV_FOFFSET (__SIZEOF_CHERI_CAPABILITY__ * 32) +# define RISCV_FOFFSET (__SIZEOF_CHERI_CAPABILITY__ * 33) #else # define RISCV_ISIZE (__riscv_xlen / 8) # define RISCV_FOFFSET (RISCV_ISIZE * 32)