Skip to content

Commit fd8bb84

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

File tree

6 files changed

+63
-12
lines changed

6 files changed

+63
-12
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: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,26 @@ 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;
30+
31+
#ifdef _LIBUNWIND_TARGET_AARCH64
32+
static constexpr int fp_num = UNW_AARCH64_FP;
33+
static constexpr int callee_saved[] = {
34+
UNW_ARM64_C19, UNW_ARM64_C20, UNW_ARM64_C21, UNW_ARM64_C22, UNW_ARM64_C23,
35+
UNW_ARM64_C24, UNW_ARM64_C26, UNW_ARM64_C27, UNW_ARM64_C28, UNW_ARM64_C29
36+
};
37+
#elif defined(_LIBUNWIND_TARGET_RISCV)
38+
static constexpr int fp_num = UNW_RISCV_X8;
39+
static constexpr int callee_saved[] = {
40+
UNW_RISCV_X9, UNW_RISCV_X18, UNW_RISCV_X19, UNW_RISCV_X20, UNW_RISCV_X21,
41+
UNW_RISCV_X22, UNW_RISCV_X23, UNW_RISCV_X24, UNW_RISCV_X25, UNW_RISCV_X26,
42+
UNW_RISCV_X27
43+
};
44+
#endif
45+
static_assert(sizeof(callee_saved) / sizeof(*callee_saved) ==
46+
sizeof(state.regs) / sizeof(*state.regs),
47+
"unexpected number of saved registers");
48+
3149
pint_t pc = registers.getIP();
3250
pint_t tf = registers.getTrustedStack();
3351

@@ -41,7 +59,7 @@ struct CompartmentInfo {
4159
registers.setTrustedStack(tf);
4260
CHERI_DBG("C18N: SET TRUSTED STACK %#p\n", (void *)tf);
4361

44-
registers.setFP((pint_t)state.fp);
62+
registers.setCapabilityRegister(fp_num, (pint_t)state.fp);
4563
CHERI_DBG("C18N: SET FP %#p\n", state.fp);
4664

4765
registers.setSP((pint_t)state.sp);
@@ -51,13 +69,12 @@ struct CompartmentInfo {
5169
CHERI_DBG("C18N: SET IP: %#p\n", state.pc);
5270

5371
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),
72+
registers.setCapabilityRegister(callee_saved[i], (pint_t)state.regs[i]);
73+
CHERI_DBG("C18N: SET REGISTER: %d (%s): %#p\n",
74+
callee_saved[i],
75+
registers.getRegisterName(callee_saved[i]),
5876
state.regs[i]);
5977
}
60-
#endif
6178
#endif // _LIBUNWIND_HAS_CHERI_LIB_C18N
6279
return UNW_STEP_SUCCESS;
6380
}

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)