diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt index 1e29c8c0f354..83d8db1c6166 100644 --- a/libunwind/CMakeLists.txt +++ b/libunwind/CMakeLists.txt @@ -50,6 +50,7 @@ option(LIBUNWIND_IS_BAREMETAL "Build libunwind for baremetal targets." OFF) option(LIBUNWIND_USE_FRAME_HEADER_CACHE "Cache frame headers for unwinding. Requires locking dl_iterate_phdr." OFF) option(LIBUNWIND_REMEMBER_HEAP_ALLOC "Use heap instead of the stack for .cfi_remember_state." OFF) option(LIBUNWIND_INSTALL_HEADERS "Install the libunwind headers." OFF) +option(LIBUNWIND_CHERI_C18N_SUPPORT "Use a libunwind implementation that supports a CHERI c18n RTLD." OFF) set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING "Define suffix of library directory name (32/64)") @@ -293,6 +294,14 @@ if (NOT LIBUNWIND_ENABLE_THREADS) add_compile_flags(-D_LIBUNWIND_HAS_NO_THREADS) endif() +# Sandboxing and c18n support +if (LIBUNWIND_CHERI_C18N_SUPPORT) + if (NOT CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64" OR NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + message(FATAL_ERROR "LIBUNWIND_CHERI_C18N_SUPPORT is not supported for ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") + endif() + add_compile_flags(-D_LIBUNWIND_CHERI_C18N_SUPPORT) +endif() + # ARM WMMX register support if (LIBUNWIND_ENABLE_ARM_WMMX) # __ARM_WMMX is a compiler pre-define (as per the ACLE 2.0). Clang does not diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h index fd5fec8c0b27..5b3f0bff628c 100644 --- a/libunwind/include/__libunwind_config.h +++ b/libunwind/include/__libunwind_config.h @@ -76,11 +76,11 @@ # elif defined(__aarch64__) # define _LIBUNWIND_TARGET_AARCH64 1 # if defined(__CHERI_PURE_CAPABILITY__) -# define _LIBUNWIND_CONTEXT_SIZE 100 +# define _LIBUNWIND_CONTEXT_SIZE 102 # if defined(__SEH__) # error "Pure-capability aarch64 SEH not supported" # else -# define _LIBUNWIND_CURSOR_SIZE 124 +# define _LIBUNWIND_CURSOR_SIZE 126 # endif # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MORELLO # else @@ -235,4 +235,9 @@ # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 #endif // _LIBUNWIND_IS_NATIVE_ONLY +#if defined(_LIBUNWIND_CHERI_C18N_SUPPORT) && \ + !defined(_LIBUNWIND_TARGET_AARCH64) +# error "LIBUNWIND_CHERI_C18N_SUPPORT is only supported on Morello" +#endif + #endif // ____LIBUNWIND_CONFIG_H__ diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index fb38d3fe53f7..951cf560ca0e 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -678,7 +678,11 @@ enum { UNW_ARM64_C30 = 228, UNW_ARM64_CLR = 228, UNW_ARM64_C31 = 229, - UNW_ARM64_CSP = 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/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 56e5de51e334..a6d1ebab9660 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -320,6 +320,12 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace { return get(addr); } capability_t getCapability(pint_t addr) { return get(addr); } +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) + static pint_t getUnwindSealer(); + static bool isValidSealer(pint_t sealer) { + return __builtin_cheri_tag_get(sealer); + } +#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT __attribute__((always_inline)) uintptr_t getP(pint_t addr); uint64_t getRegister(pint_t addr); @@ -408,6 +414,24 @@ inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { #endif } +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) +extern "C" { +/// Call into the RTLD to get a sealer capability. This sealer will be used to +/// seal information in the unwinding context. +uintptr_t _rtld_unw_getsealer(); +uintptr_t __rtld_unw_getsealer(); +_LIBUNWIND_HIDDEN uintptr_t __rtld_unw_getsealer() { + return (uintptr_t)0; +} +_LIBUNWIND_WEAK_ALIAS(__rtld_unw_getsealer, _rtld_unw_getsealer) +} + +/// C++ wrapper for calling into RTLD. +inline LocalAddressSpace::pint_t LocalAddressSpace::getUnwindSealer() { + return _rtld_unw_getsealer(); +} +#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT + /// Read a ULEB128 into a 64-bit word. inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { const uint8_t *p = (uint8_t *)addr; @@ -932,7 +956,8 @@ inline bool LocalAddressSpace::findUnwindSections(pc_t targetAddr, return true; #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) dl_iterate_cb_data cb_data = {this, &info, targetAddr}; - CHERI_DBG("Calling dl_iterate_phdr()\n"); + CHERI_DBG("Calling dl_iterate_phdr(0x%jx)\n", + (uintmax_t)targetAddr.address()); int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); return static_cast(found); #endif diff --git a/libunwind/src/CompartmentInfo.hpp b/libunwind/src/CompartmentInfo.hpp new file mode 100644 index 000000000000..08ff723c7220 --- /dev/null +++ b/libunwind/src/CompartmentInfo.hpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Abstracts unwind information when used with a compartmentalizing runtime +// linker. +// +//===----------------------------------------------------------------------===// + +#ifndef __COMPARTMENT_INFO_HPP__ +#define __COMPARTMENT_INFO_HPP__ + +namespace libunwind { +class _LIBUNWIND_HIDDEN CompartmentInfo { +public: +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) + static CompartmentInfo sThisCompartmentInfo; + // Per-architecture trusted stack frame layout. +#if defined(_LIBUNWIND_TARGET_AARCH64) + static const uint32_t kNewSPOffset = 12 * sizeof(void *); + static const uint32_t kNextOffset = 14 * sizeof(void *); + static const uint32_t kCalleeSavedOffset = 2 * sizeof(void *); + static const uint32_t kCalleeSavedCount = 10; + static const uint32_t kReturnAddressOffset = 15 * sizeof(void *) + 8; + static const uint32_t kPCOffset = sizeof(void *); +#endif // _LIBUNWIND_TARGET_AARCH64 +#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT +}; +} // namespace libunwind +#endif // __COMPARTMENT_INFO_HPP__ diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index e19383a4027e..b446a28eb59b 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -20,6 +20,7 @@ #include "Registers.hpp" #include "DwarfParser.hpp" #include "config.h" +#include "CompartmentInfo.hpp" namespace libunwind { @@ -54,6 +55,14 @@ class DwarfInstructions { typedef typename CFI_Parser::FDE_Info FDE_Info; typedef typename CFI_Parser::CIE_Info CIE_Info; +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) + static pint_t restoreRegistersFromSandbox(pint_t csp, A &addressSpace, + R &newRegisters, + CompartmentInfo &CI, pint_t sealer); + static bool isCompartmentTransitionTrampoline(pint_t ecsp, A &addressSpace, + CompartmentInfo &CI, + pint_t returnAddress); +#endif static pint_t evaluateExpression(pint_t expression, A &addressSpace, const R ®isters, pint_t initialStackValue); @@ -246,6 +255,76 @@ bool DwarfInstructions::getRA_SIGN_STATE(A &addressSpace, R registers, } #endif +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) +#if defined(_LIBUNWIND_TARGET_AARCH64) +template +typename A::pint_t DwarfInstructions::restoreRegistersFromSandbox( + pint_t csp, A &addressSpace, R &newRegisters, CompartmentInfo &CI, + pint_t sealer) { + // Get the unsealed executive CSP + assert(__builtin_cheri_tag_get((void *)csp) && + "Executive stack should be tagged!"); + // Derive the new executive CSP + pint_t nextCSP = addressSpace.getP(csp + CI.kNextOffset); + // Seal ECSP + nextCSP = __builtin_cheri_seal(nextCSP, sealer); + assert(__builtin_cheri_tag_get((void *)nextCSP) && + "Next executive stack should be tagged!"); + CHERI_DBG("SANDBOX: SETTING EXECUTIVE CSP %#p\n", (void *)nextCSP); + newRegisters.setTrustedStack(nextCSP); + // Restore the next RCSP + pint_t nextRCSP = addressSpace.getP(csp + CI.kNewSPOffset); + newRegisters.setSP(nextRCSP); + CHERI_DBG("SANDBOX: SETTING RESTRICTED CSP: %#p\n", + (void *)newRegisters.getSP()); + // Restore callee-saved registers + size_t offset; + // Restore: c19-c28 + for (size_t i = 0, offset = CI.kCalleeSavedOffset; i < CI.kCalleeSavedCount; + ++i, offset += sizeof(void *)) { + pint_t regValue = addressSpace.getP(csp + offset); + newRegisters.setCapabilityRegister(UNW_ARM64_C19 + i, regValue); + CHERI_DBG("SETTING CALLEE SAVED CAPABILITY REGISTER: %lu (%s): %#p " + "(offset=%zu)\n", + UNW_ARM64_C19 + i, + newRegisters.getRegisterName(UNW_ARM64_C19 + i), (void *)regValue, + offset); + } + // Restore the frame pointer + pint_t newFP = addressSpace.getP(csp); + CHERI_DBG("SANDBOX: SETTING CFP %#p\n", (void *)newFP); + newRegisters.setFP(newFP); + // Get the new return address. + return addressSpace.getP(csp + CI.kPCOffset); +} + +template +bool DwarfInstructions::isCompartmentTransitionTrampoline( + pint_t ecsp, A &addressSpace, CompartmentInfo &CI, pint_t returnAddress) { + ptraddr_t expectedReturnAddress = + addressSpace.template get(ecsp + CI.kReturnAddressOffset); + CHERI_DBG( + "isCompartmentTransitionTrampoline(): expectedReturnAddress: 0x%lx\n", + expectedReturnAddress); + return expectedReturnAddress == returnAddress; +} +#else // _LIBUNWIND_TARGET_AARCH64 +template +typename A::pint_t DwarfInstructions::restoreRegistersFromSandbox( + pint_t csp, A &addressSpace, R &newRegisters, CompartmentInfo &CI, + pint_t sealer) { + assert(0 && "not implemented on this architecture"); + return (pint_t)0; +} +template +bool DwarfInstructions::isCompartmentTransitionTrampoline( + pint_t ecsp, A &addressSpace, CompartmentInfo &CI, pint_t returnAddress) { + assert(0 && "not implemented on this architecture"); + return false; +} +#endif // _LIBUNWIND_TARGET_AARCH64 +#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT + template int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, pint_t fdeStart, R ®isters, @@ -274,6 +353,7 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, // // We set the SP here to the CFA, allowing for it to be overridden // by a CFI directive later on. + CHERI_DBG("SETTING SP: %#p\n", (void *)cfa); newRegisters.setSP(cfa); pint_t returnAddress = 0; @@ -297,15 +377,14 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, else if (i == (int)cieInfo.returnAddressRegister) { returnAddress = getSavedRegister(i, addressSpace, registers, cfa, prolog.savedRegisters[i]); - CHERI_DBG("SETTING RETURN REGISTER %d (%s): %#p \n", - i, newRegisters.getRegisterName(i), (void*)returnAddress); + CHERI_DBG("GETTING RETURN ADDRESS (saved) %d (%s): %#p \n", i, + newRegisters.getRegisterName(i), (void *)returnAddress); } else if (registers.validCapabilityRegister(i)) { - newRegisters.setCapabilityRegister( - i, getSavedCapabilityRegister(addressSpace, registers, cfa, - prolog.savedRegisters[i])); - CHERI_DBG("SETTING CAPABILITY REGISTER %d (%s): %#p \n", - i, newRegisters.getRegisterName(i), - (void*)A::to_pint_t(newRegisters.getCapabilityRegister(i))); + capability_t savedReg = getSavedCapabilityRegister( + addressSpace, registers, cfa, prolog.savedRegisters[i]); + newRegisters.setCapabilityRegister(i, savedReg); + CHERI_DBG("SETTING CAPABILITY REGISTER %d (%s): %#p \n", i, + newRegisters.getRegisterName(i), (void *)savedReg); } else if (registers.validRegister(i)) newRegisters.setRegister( i, getSavedRegister(i, addressSpace, registers, cfa, @@ -313,9 +392,11 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, else return UNW_EBADREG; } else if (i == (int)cieInfo.returnAddressRegister) { - // Leaf function keeps the return address in register and there is no - // explicit intructions how to restore it. - returnAddress = registers.getRegister(cieInfo.returnAddressRegister); + // Leaf function keeps the return address in register and there is no + // explicit intructions how to restore it. + returnAddress = registers.getRegister(cieInfo.returnAddressRegister); + CHERI_DBG("GETTING RETURN ADDRESS (leaf) %d (%s): %#p \n", i, + registers.getRegisterName(i), (void *)returnAddress); } } @@ -403,9 +484,32 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, } #endif +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) + // If the sealer is not valid (only the case when we're running without + // c18n), check if the return address has the executive mode bit set. + // If so, we should be calling into the c18n RTLD as this is a + // compartment boundary. We need to restore registers from the executive + // stack and ask rtld for it. + uintptr_t sealer = addressSpace.getUnwindSealer(); + if (addressSpace.isValidSealer(sealer)) { + pint_t csp = registers.getTrustedStack(); + if (__builtin_cheri_sealed_get(csp)) + csp = __builtin_cheri_unseal(csp, sealer); + CompartmentInfo &CI = CompartmentInfo::sThisCompartmentInfo; + if (csp != 0 && isCompartmentTransitionTrampoline(csp, addressSpace, CI, + returnAddress)) { + CHERI_DBG("%#p: detected a trampoline, unwinding from sandbox\n", + (void *)returnAddress); + returnAddress = restoreRegistersFromSandbox( + csp, addressSpace, newRegisters, CI, sealer); + } + } +#endif + // Return address is address after call site instruction, so setting IP to // that does simualates a return. newRegisters.setIP(returnAddress); + CHERI_DBG("SETTING RETURN ADDRESS %#p\n", (void *)returnAddress); // Simulate the step by replacing the register set with the new ones. registers = newRegisters; diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 92b0b8b9bb9a..7dda2e106fdc 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -1866,7 +1866,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { void setCapabilityRegister(int num, uintcap_t value); #else CAPABILITIES_NOT_SUPPORTED -#endif +#endif // __CHERI_PURE_CAPABILITY__ uintptr_t getSP() const { return _registers.__sp; } void setSP(uintptr_t value) { _registers.__sp = value; } @@ -1874,6 +1874,10 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { void setIP(uintptr_t value) { _registers.__pc = value; } uintptr_t getFP() const { return _registers.__fp; } void setFP(uintptr_t value) { _registers.__fp = value; } +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) + uintptr_t getTrustedStack() const { return _registers.__ecsp; } + void setTrustedStack(uintptr_t value) { _registers.__ecsp = value; } +#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT private: struct GPRs { @@ -1882,6 +1886,9 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { uintptr_t __lr; // Link register r30 uintptr_t __sp; // Stack pointer r31 uintptr_t __pc; // Program counter +#ifdef __CHERI_PURE_CAPABILITY__ + uintptr_t __ecsp; // Executive stack pointer. +#endif uint64_t __ra_sign_state; // RA sign state register }; @@ -1898,8 +1905,8 @@ inline Registers_arm64::Registers_arm64(const void *registers) { "arm64 registers do not fit into unw_context_t"); memcpy(&_registers, registers, sizeof(_registers)); #ifdef __CHERI_PURE_CAPABILITY__ - static_assert(sizeof(GPRs) == 0x220, - "expected VFP registers to be at offset 544"); + static_assert(sizeof(GPRs) == 0x230, + "expected VFP registers to be at offset 560"); #else static_assert(sizeof(GPRs) == 0x110, "expected VFP registers to be at offset 272"); @@ -2198,6 +2205,8 @@ 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"; } diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index dde5fd117307..db55b2a5a71a 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -703,6 +703,25 @@ Lnovec: #elif defined(__aarch64__) +// +// extern "C" void __rtld_unw_setcontext(void *c0, void *c1, +// void *rcsp, void **sealed_ecsp); +// +#if defined(__CHERI_PURE_CAPABILITY__) +DEFINE_LIBUNWIND_FUNCTION(__rtld_unw_setcontext) + mov c16, c2 + ldp c2, c3, [c3, #(-0x210 + 0x20)] + mov csp, c16 +#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI + and x30, x30, #~1 + ret x30 +#else + ret +#endif +END_LIBUNWIND_FUNCTION(__rtld_unw_setcontext) +WEAK_ALIAS(__rtld_unw_setcontext, _rtld_unw_setcontext) +#endif + // // extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); // @@ -713,7 +732,7 @@ Lnovec: DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) #ifdef __CHERI_PURE_CAPABILITY__ // skip restore of c0,c1 for now - ldp c2, c3, [c0, #0x020] + // also skip restoring c2 and c3 because they will get clobbered later on ldp c4, c5, [c0, #0x040] ldp c6, c7, [c0, #0x060] ldp c8, c9, [c0, #0x080] @@ -730,7 +749,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) ldp c28,c29, [c0, #0x1c0] ldr c30, [c0, #0x200] // restore pcc into clr - add c16,c0, #0x220 + add c16,c0, #0x230 ldp d0, d1, [c16, #0x000] ldp d2, d3, [c16, #0x010] ldp d4, d5, [c16, #0x020] @@ -753,15 +772,10 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) // context struct, because it is allocated on the stack, and an exception // could clobber the de-allocated portion of the stack after csp has been // restored. - ldr c16, [c0, #0x1f0] - ldp c0, c1, [c0, #0x000] // restore c0,c1 - mov csp,c16 // restore csp -#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI - and x30, x30, #~1 - ret x30 // jump to pc -#else - ret // jump to pcc -#endif + ldr c2, [c0, #0x1f0] + add c3, c0, #0x210 + ldp c0, c1, [c0, #0x000] + b _rtld_unw_setcontext #else // skip restore of x0,x1 for now ldp x2, x3, [x0, #0x010] diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 61c8c9d16b73..8edcd4cb51d0 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -837,6 +837,15 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #elif defined(__aarch64__) +#if defined(__CHERI_PURE_CAPABILITY__) +DEFINE_LIBUNWIND_FUNCTION(__rtld_unw_getcontext) + mov c2, csp + str c2, [c1] + ret c30 +END_LIBUNWIND_FUNCTION(__rtld_unw_getcontext) +WEAK_ALIAS(__rtld_unw_getcontext, _rtld_unw_getcontext) +#endif + // // extern int __unw_getcontext(unw_context_t* thread_state) // @@ -865,8 +874,12 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) mov c1,csp str c1, [c0, #0x1f0] str c30, [c0, #0x200] // store return address as pcc + + // Prepare c1 to get our executive stack. + add c1, c0, #0x210 + // skip cpsr - add c0, c0, #0x220 + add c0, c0, #0x230 stp d0, d1, [c0, #0x000] stp d2, d3, [c0, #0x010] stp d4, d5, [c0, #0x020] @@ -885,7 +898,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) str d30, [c0, #0x0f0] str d31, [c0, #0x0f8] mov x0, #0 // return UNW_ESUCCESS - ret + b _rtld_unw_getcontext #else stp x0, x1, [x0, #0x000] stp x2, x3, [x0, #0x010] diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index 83648894a740..4b5748c3bab7 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -28,6 +28,7 @@ #if !defined(__USING_SJLJ_EXCEPTIONS__) #include "AddressSpace.hpp" +#include "CompartmentInfo.hpp" #include "UnwindCursor.hpp" @@ -42,6 +43,11 @@ using namespace libunwind; /// internal object to represent this processes address space LocalAddressSpace LocalAddressSpace::sThisAddressSpace; +#if defined(__CHERI_PURE_CAPABILITY__) && defined(_LIBUNWIND_CHERI_C18N_SUPPORT) +/// internal object to represent this processes compartment information +CompartmentInfo CompartmentInfo::sThisCompartmentInfo; +#endif // __CHERI_PURE_CAPABILITY__ && _LIBUNWIND_CHERI_C18N_SUPPORT + _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;