Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libunwind/include/__libunwind_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 0 additions & 4 deletions libunwind/include/libunwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
27 changes: 20 additions & 7 deletions libunwind/src/CompartmentInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ struct CompartmentInfo {

static int unwindIfAtBoundary(R &registers) {
#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();
Expand All @@ -41,23 +40,37 @@ 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);

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;
}
Expand Down
29 changes: 23 additions & 6 deletions libunwind/src/Registers.hpp
Comment thread
qwattash marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down Expand Up @@ -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
Expand All @@ -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<const uint8_t *>(registers) + sizeof(_registers),
sizeof(_floats));
#ifdef __CHERI_PURE_CAPABILITY__
memcpy(&_tsp, static_cast<const uint8_t *>(registers) + sizeof(_registers),
sizeof(_tsp));
#endif

#if defined(__riscv_flen)
const uint8_t *floats = static_cast<const uint8_t *>(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
Expand Down
18 changes: 15 additions & 3 deletions libunwind/src/UnwindRegistersRestore.S
Original file line number Diff line number Diff line change
Expand Up @@ -1308,15 +1308,15 @@ 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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split the RVY-compatible mnemonic changes out from the c18n changes

@jrtc27 jrtc27 Oct 15, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also at this point the ifdef isn't needed? Nor are the GPR ones needed, so long as ILOAD/ISTORE/RISCV_ISIZE are appropriately renamed to not be I for Integer, and defined to be LY/SY/__SIZEOF_CHERI_CAPABILITY__ CHERI?

Edit: Meant to include this in the original review but it was left pending... so will just do this myself :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be fixed now.

#else
FLOAD f\num, (RISCV_FOFFSET + RISCV_FSIZE * \num)(\ctxreg)
#endif
.endm

.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
Expand All @@ -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
Expand All @@ -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
Expand Down
19 changes: 16 additions & 3 deletions libunwind/src/UnwindRegistersSave.S
Original file line number Diff line number Diff line change
Expand Up @@ -1237,15 +1237,15 @@ 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
.endm

.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
Expand All @@ -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
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion libunwind/src/assembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading