Skip to content

Commit 93bbd25

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

File tree

6 files changed

+56
-11
lines changed

6 files changed

+56
-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: 15 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();
@@ -51,13 +50,23 @@ struct CompartmentInfo {
5150
CHERI_DBG("C18N: SET IP: %#p\n", state.pc);
5251

5352
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),
53+
int reg_num;
54+
#ifdef _LIBUNWIND_TARGET_AARCH64
55+
reg_num = UNW_ARM64_C19 + i;
56+
#elif defined(_LIBUNWIND_TARGET_RISCV)
57+
static constexpr int callee_saved[] = {
58+
UNW_RISCV_X9, UNW_RISCV_X18, UNW_RISCV_X19, UNW_RISCV_X20, UNW_RISCV_X21,
59+
UNW_RISCV_X22, UNW_RISCV_X23, UNW_RISCV_X24, UNW_RISCV_X25, UNW_RISCV_X26,
60+
UNW_RISCV_X27
61+
};
62+
reg_num = callee_saved[i];
63+
#endif
64+
registers.setCapabilityRegister(reg_num, (pint_t)state.regs[i]);
65+
CHERI_DBG("C18N: SET REGISTER: %d (%s): %#p\n",
66+
reg_num,
67+
registers.getRegisterName(reg_num),
5868
state.regs[i]);
5969
}
60-
#endif
6170
#endif // _LIBUNWIND_HAS_CHERI_LIB_C18N
6271
return UNW_STEP_SUCCESS;
6372
}

libunwind/src/Registers.hpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4552,10 +4552,21 @@ 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+
reg_t getFP() const { return _registers[8]; }
4556+
void setFP(reg_t value) { _registers[8] = value; }
4557+
#ifdef __CHERI_PURE_CAPABILITY__
4558+
reg_t getTrustedStack() const { return _registers[32]; }
4559+
void setTrustedStack(reg_t value) { _registers[32] = value; }
4560+
#endif
45554561

45564562
private:
45574563
// _registers[0] holds the pc
4564+
#ifdef __CHERI_PURE_CAPABILITY__
4565+
// _registers[32] holds the trusted stack pointer
4566+
reg_t _registers[33];
4567+
#else
45584568
reg_t _registers[32];
4569+
#endif
45594570
# if defined(__riscv_flen)
45604571
fp_t _floats[32];
45614572
# endif
@@ -4566,8 +4577,8 @@ inline Registers_riscv::Registers_riscv(const void *registers) {
45664577
"riscv registers do not fit into unw_context_t");
45674578
memcpy(&_registers, registers, sizeof(_registers));
45684579
# ifdef __CHERI_PURE_CAPABILITY__
4569-
static_assert(sizeof(_registers) == 0x200,
4570-
"expected float registers to be at offset 512");
4580+
static_assert(sizeof(_registers) == 0x210,
4581+
"expected float registers to be at offset 528");
45714582
# elif __riscv_xlen == 32
45724583
static_assert(sizeof(_registers) == 0x80,
45734584
"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 cs0, ca0
1337+
// Pass the target untrusted stack pointer
1338+
lc ca0, (__SIZEOF_CHERI_CAPABILITY__ * 2)(cs0)
1339+
// Pass the target trusted stack pointer
1340+
lc ca1, (__SIZEOF_CHERI_CAPABILITY__ * 32)(cs0)
1341+
call dl_c18n_unwind_trusted_stack
1342+
cmv ca0, cs0
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, -32
1279+
sc ca0, 0(csp)
1280+
sc cra, 16(csp)
1281+
cmv ca0, cra
1282+
call dl_c18n_get_trusted_stack
1283+
lc ca1, 0(csp)
1284+
lc cra, 16(csp)
1285+
caddi csp, csp, 32
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)