Skip to content

Commit e49683b

Browse files
committed
libunwind: Unwind across c18n compartment boundaries on RISC-V
1 parent b4b76b6 commit e49683b

File tree

6 files changed

+61
-11
lines changed

6 files changed

+61
-11
lines changed

libunwind/include/__libunwind_config.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@
188188
# define RISCV_FLEN 0
189189
# endif
190190
# ifdef __CHERI_PURE_CAPABILITY__
191-
# define _LIBUNWIND_CONTEXT_SIZE 96
192-
# define _LIBUNWIND_CURSOR_SIZE 120
191+
# define _LIBUNWIND_CONTEXT_SIZE 98
192+
# define _LIBUNWIND_CURSOR_SIZE 122
193193
# else
194194
# define _LIBUNWIND_CONTEXT_SIZE (32 * (__riscv_xlen + RISCV_FLEN) / 64)
195195
# if __riscv_xlen == 32

libunwind/src/CompartmentInfo.hpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ struct CompartmentInfo {
2626

2727
static int unwindIfAtBoundary(R &registers) {
2828
#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N
29-
#ifdef _LIBUNWIND_TARGET_AARCH64
3029
struct dl_c18n_compart_state state;
3130
pint_t pc = registers.getIP();
3231
pint_t tf = registers.getTrustedStack();
@@ -41,23 +40,40 @@ struct CompartmentInfo {
4140
registers.setTrustedStack(tf);
4241
CHERI_DBG("C18N: SET TRUSTED STACK %#p\n", (void *)tf);
4342

43+
#ifdef _LIBUNWIND_TARGET_AARCH64
4444
registers.setFP((pint_t)state.fp);
4545
CHERI_DBG("C18N: SET FP %#p\n", state.fp);
46+
#endif
4647

4748
registers.setSP((pint_t)state.sp);
4849
CHERI_DBG("C18N: SET SP: %#p\n", state.sp);
4950

5051
registers.setIP((pint_t)state.pc);
5152
CHERI_DBG("C18N: SET IP: %#p\n", state.pc);
5253

54+
#ifdef _LIBUNWIND_TARGET_AARCH64
55+
static constexpr int callee_saved[] = {
56+
UNW_ARM64_C19, UNW_ARM64_C20, UNW_ARM64_C21, UNW_ARM64_C22, UNW_ARM64_C23,
57+
UNW_ARM64_C24, UNW_ARM64_C26, UNW_ARM64_C27, UNW_ARM64_C28, UNW_ARM64_C29
58+
};
59+
#elif defined(_LIBUNWIND_TARGET_RISCV)
60+
static constexpr int callee_saved[] = {
61+
UNW_RISCV_X9, UNW_RISCV_X18, UNW_RISCV_X19, UNW_RISCV_X20, UNW_RISCV_X21,
62+
UNW_RISCV_X22, UNW_RISCV_X23, UNW_RISCV_X24, UNW_RISCV_X25, UNW_RISCV_X26,
63+
UNW_RISCV_X27, UNW_RISCV_X8
64+
};
65+
#endif
66+
static_assert(sizeof(callee_saved) / sizeof(*callee_saved) ==
67+
sizeof(state.regs) / sizeof(*state.regs),
68+
"unexpected number of saved registers");
69+
5370
for (size_t i = 0; i < sizeof(state.regs) / sizeof(*state.regs); ++i) {
54-
registers.setCapabilityRegister(UNW_ARM64_C19 + i, (pint_t)state.regs[i]);
55-
CHERI_DBG("C18N: SET REGISTER: %lu (%s): %#p\n",
56-
UNW_ARM64_C19 + i,
57-
registers.getRegisterName(UNW_ARM64_C19 + i),
71+
registers.setCapabilityRegister(callee_saved[i], (pint_t)state.regs[i]);
72+
CHERI_DBG("C18N: SET REGISTER: %d (%s): %#p\n",
73+
callee_saved[i],
74+
registers.getRegisterName(callee_saved[i]),
5875
state.regs[i]);
5976
}
60-
#endif
6177
#endif // _LIBUNWIND_HAS_CHERI_LIB_C18N
6278
return UNW_STEP_SUCCESS;
6379
}

libunwind/src/Registers.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4552,10 +4552,19 @@ class _LIBUNWIND_HIDDEN Registers_riscv {
45524552
void setSP(reg_t value) { _registers[2] = value; }
45534553
reg_t getIP() const { return _registers[0]; }
45544554
void setIP(reg_t value) { _registers[0] = value; }
4555+
#ifdef __CHERI_PURE_CAPABILITY__
4556+
reg_t getTrustedStack() const { return _registers[32]; }
4557+
void setTrustedStack(reg_t value) { _registers[32] = value; }
4558+
#endif
45554559

45564560
private:
45574561
// _registers[0] holds the pc
4562+
#ifdef __CHERI_PURE_CAPABILITY__
4563+
// _registers[32] holds the trusted stack pointer
4564+
reg_t _registers[33];
4565+
#else
45584566
reg_t _registers[32];
4567+
#endif
45594568
# if defined(__riscv_flen)
45604569
fp_t _floats[32];
45614570
# endif
@@ -4566,8 +4575,8 @@ inline Registers_riscv::Registers_riscv(const void *registers) {
45664575
"riscv registers do not fit into unw_context_t");
45674576
memcpy(&_registers, registers, sizeof(_registers));
45684577
# ifdef __CHERI_PURE_CAPABILITY__
4569-
static_assert(sizeof(_registers) == 0x200,
4570-
"expected float registers to be at offset 512");
4578+
static_assert(sizeof(_registers) == 0x210,
4579+
"expected float registers to be at offset 528");
45714580
# elif __riscv_xlen == 32
45724581
static_assert(sizeof(_registers) == 0x80,
45734582
"expected float registers to be at offset 128");

libunwind/src/UnwindRegistersRestore.S

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,18 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
13301330
//
13311331
.p2align 2
13321332
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
1333+
#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N
1334+
// Preserve the argument in a callee-saved register instead of pushing it onto
1335+
// the stack because stack unwinding will switch the stack.
1336+
cmv cs1, ca0
1337+
// Pass the target untrusted stack pointer
1338+
lc ca0, (__SIZEOF_CHERI_CAPABILITY__ * 2)(cs1)
1339+
// Pass the target trusted stack pointer
1340+
lc ca1, (__SIZEOF_CHERI_CAPABILITY__ * 32)(cs1)
1341+
call dl_c18n_unwind_trusted_stack
1342+
cmv ca0, cs1
1343+
#endif
1344+
13331345
# if defined(__riscv_flen)
13341346
.irp i,FROM_0_TO_31
13351347
restore_fpr \i, a0

libunwind/src/UnwindRegistersSave.S

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,19 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
12731273
.endr
12741274
# endif
12751275

1276+
#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N
1277+
// Store the trusted stack pointer
1278+
caddi csp, csp, -(__SIZEOF_CHERI_CAPABILITY__ * 2)
1279+
sc ca0, 0(csp)
1280+
sc cra, __SIZEOF_CHERI_CAPABILITY__(csp)
1281+
cmv ca0, cra
1282+
call dl_c18n_get_trusted_stack
1283+
lc ca1, 0(csp)
1284+
lc cra, __SIZEOF_CHERI_CAPABILITY__(csp)
1285+
caddi csp, csp, (__SIZEOF_CHERI_CAPABILITY__ * 2)
1286+
sc ca0, (__SIZEOF_CHERI_CAPABILITY__ * 32)(ca1)
1287+
#endif
1288+
12761289
li a0, 0 // return UNW_ESUCCESS
12771290
ret // jump to ra
12781291
END_LIBUNWIND_FUNCTION(__unw_getcontext)

libunwind/src/assembly.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#define SEPARATOR %%
3737
#elif defined(__riscv)
3838
#ifdef __CHERI_PURE_CAPABILITY__
39-
# define RISCV_FOFFSET (__SIZEOF_CHERI_CAPABILITY__ * 32)
39+
# define RISCV_FOFFSET (__SIZEOF_CHERI_CAPABILITY__ * 33)
4040
#else
4141
# define RISCV_ISIZE (__riscv_xlen / 8)
4242
# define RISCV_FOFFSET (RISCV_ISIZE * 32)

0 commit comments

Comments
 (0)