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..e901ac1aa576d 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,29 @@ struct CompartmentInfo { registers.setIP((pint_t)state.pc); CHERI_DBG("C18N: SET IP: %#p\n", state.pc); +#ifdef _LIBUNWIND_TARGET_AARCH64 + static constexpr int callee_saved[] = { + 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 callee_saved[] = { + 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(callee_saved) / sizeof(*callee_saved) == + 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), + registers.setCapabilityRegister(callee_saved[i], (pint_t)state.regs[i]); + CHERI_DBG("C18N: SET REGISTER: %d (%s): %#p\n", + callee_saved[i], + registers.getRegisterName(callee_saved[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..5c5ad1ce1ddb3 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,19 @@ 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 _registers[32]; } + void setTrustedStack(reg_t value) { _registers[32] = value; } +#endif private: // _registers[0] holds the pc +#ifdef __CHERI_PURE_CAPABILITY__ + // _registers[32] holds the trusted stack pointer + reg_t _registers[33]; +#else reg_t _registers[32]; +#endif # if defined(__riscv_flen) fp_t _floats[32]; # endif @@ -4568,8 +4575,8 @@ inline Registers_riscv::Registers_riscv(const void *registers) { "riscv registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); # ifdef __CHERI_PURE_CAPABILITY__ - static_assert(sizeof(_registers) == 0x200, - "expected float registers to be at offset 512"); + static_assert(sizeof(_registers) == 0x210, + "expected float registers to be at offset 528"); # elif __riscv_xlen == 32 static_assert(sizeof(_registers) == 0x80, "expected float registers to be at offset 128"); diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index c602c91d2f6cf..02c0da3bc016f 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -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. + cmv cs1, ca0 + // Pass the target untrusted stack pointer + lc ca0, (__SIZEOF_CHERI_CAPABILITY__ * 2)(cs1) + // Pass the target trusted stack pointer + lc ca1, (__SIZEOF_CHERI_CAPABILITY__ * 32)(cs1) + call dl_c18n_unwind_trusted_stack + cmv ca0, cs1 +#endif + # if defined(__riscv_flen) .irp i,FROM_0_TO_31 restore_fpr \i, a0 diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 9f89ac31f0496..caea172861799 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -1273,6 +1273,19 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) .endr # endif +#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N + // Store the trusted stack pointer + caddi csp, csp, -(__SIZEOF_CHERI_CAPABILITY__ * 2) + sc ca0, 0(csp) + sc cra, __SIZEOF_CHERI_CAPABILITY__(csp) + cmv ca0, cra + call dl_c18n_get_trusted_stack + lc ca1, 0(csp) + lc cra, __SIZEOF_CHERI_CAPABILITY__(csp) + caddi csp, csp, (__SIZEOF_CHERI_CAPABILITY__ * 2) + sc ca0, (__SIZEOF_CHERI_CAPABILITY__ * 32)(ca1) +#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)