libunwind: update to LLVM 22

This commit is contained in:
Alex Rønne Petersen 2026-01-17 05:24:24 +01:00
parent 7ede15da60
commit ba6adb2dc9
No known key found for this signature in database
20 changed files with 1054 additions and 193 deletions

View file

@ -73,11 +73,11 @@
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
# elif defined(__aarch64__)
# define _LIBUNWIND_TARGET_AARCH64 1
# define _LIBUNWIND_CONTEXT_SIZE 66
#define _LIBUNWIND_CONTEXT_SIZE 67
# if defined(__SEH__)
# define _LIBUNWIND_CURSOR_SIZE 164
# else
# define _LIBUNWIND_CURSOR_SIZE 78
#define _LIBUNWIND_CURSOR_SIZE 79
# endif
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
# elif defined(__arm__)
@ -212,4 +212,13 @@
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
#endif // _LIBUNWIND_IS_NATIVE_ONLY
#if defined(__has_feature)
# if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
# define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
# elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
# error "Either both or none of ptrauth_calls and ptrauth_returns "\
"is allowed to be enabled"
# endif
#endif
#endif // ____LIBUNWIND_CONFIG_H__

View file

@ -43,6 +43,109 @@
#define LIBUNWIND_AVAIL
#endif
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
#include <ptrauth.h>
// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
// support for direct application of `__ptrauth` to integer types. This
// guard is necessary to support compilation with those compiler.
#if __has_extension(ptrauth_restricted_intptr_qualifier)
#define __unwind_ptrauth_restricted_intptr(...) \
__ptrauth_restricted_intptr(__VA_ARGS__)
#else
#define __unwind_ptrauth_restricted_intptr(...) \
__ptrauth(__VA_ARGS__)
#endif
// ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
#define __ptrauth_unwind_upi_handler_disc 0x7405
#define __ptrauth_unwind_upi_handler \
__ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc)
#define __ptrauth_unwind_upi_handler_intptr \
__unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,\
__ptrauth_unwind_upi_handler_disc)
// ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
#define __ptrauth_unwind_upi_startip \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C)
// ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
#define __ptrauth_unwind_upi_endip \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183)
// ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
#define __ptrauth_unwind_upi_lsda \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE)
// ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
#define __ptrauth_unwind_upi_flags \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1)
// ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
#define __ptrauth_unwind_upi_info \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C)
// ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
#define __ptrauth_unwind_upi_extra \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF)
// ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
#define __ptrauth_unwind_registers_arm64_link_reg \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301)
// ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
#define __ptrauth_unwind_uis_dso_base \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5)
// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
#define __ptrauth_unwind_uis_dwarf_section \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974)
// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
#define __ptrauth_unwind_uis_dwarf_section_length \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A)
// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
#define __ptrauth_unwind_uis_compact_unwind_section \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B)
// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
#define __ptrauth_unwind_uis_compact_unwind_section_length \
__unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A)
// ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
#define __ptrauth_unwind_cie_info_personality_disc 0x6A40
#define __ptrauth_unwind_cie_info_personality \
__unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
__ptrauth_unwind_cie_info_personality_disc)
// ptrauth_string_discriminator("personality") == 0x7EAD)
#define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD
#else
#define __unwind_ptrauth_restricted_intptr(...)
#define __ptrauth_unwind_upi_handler
#define __ptrauth_unwind_upi_handler_intptr
#define __ptrauth_unwind_upi_startip
#define __ptrauth_unwind_upi_endip
#define __ptrauth_unwind_upi_lsda
#define __ptrauth_unwind_upi_flags
#define __ptrauth_unwind_upi_info
#define __ptrauth_unwind_upi_extra
#define __ptrauth_unwind_registers_arm64_link_reg
#define __ptrauth_unwind_uis_dso_base
#define __ptrauth_unwind_uis_dwarf_section
#define __ptrauth_unwind_uis_dwarf_section_length
#define __ptrauth_unwind_uis_compact_unwind_section
#define __ptrauth_unwind_uis_compact_unwind_section_length
#define __ptrauth_unwind_cie_info_personality
#endif
#if defined(_WIN32) && defined(__SEH__)
#define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
#else
@ -88,17 +191,18 @@ typedef double unw_fpreg_t;
#endif
struct unw_proc_info_t {
unw_word_t start_ip; /* start address of function */
unw_word_t end_ip; /* address after end of function */
unw_word_t lsda; /* address of language specific data area, */
/* or zero if not used */
unw_word_t handler; /* personality routine, or zero if not used */
unw_word_t gp; /* not used */
unw_word_t flags; /* not used */
uint32_t format; /* compact unwind encoding, or zero if none */
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
unw_word_t unwind_info; /* address of DWARF unwind info, or zero */
unw_word_t extra; /* mach_header of mach-o image containing func */
unw_word_t __ptrauth_unwind_upi_startip start_ip; /* start address of function */
unw_word_t __ptrauth_unwind_upi_endip end_ip; /* address after end of function */
unw_word_t __ptrauth_unwind_upi_lsda lsda; /* address of language specific data area, */
/* or zero if not used */
unw_word_t __ptrauth_unwind_upi_handler_intptr handler;
unw_word_t gp; /* not used */
unw_word_t __ptrauth_unwind_upi_flags flags; /* not used */
uint32_t format; /* compact unwind encoding, or zero if none */
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */
unw_word_t __ptrauth_unwind_upi_extra extra; /* mach_header of mach-o image containing func */
};
typedef struct unw_proc_info_t unw_proc_info_t;
@ -130,6 +234,7 @@ extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL;
extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL;
//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
extern const char *unw_strerror(int) LIBUNWIND_AVAIL;
extern unw_addr_space_t unw_local_addr_space;
@ -532,6 +637,7 @@ enum {
UNW_AARCH64_X31 = 31,
UNW_AARCH64_SP = 31,
UNW_AARCH64_PC = 32,
UNW_AARCH64_VG = 46,
// reserved block
UNW_AARCH64_RA_SIGN_STATE = 34,

View file

@ -125,8 +125,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t discriminator,
_Unwind_VRS_DataRepresentation representation);
extern _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *,
_Unwind_Context *);
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern __inline__
#else
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__
#endif

View file

@ -129,22 +129,27 @@ struct UnwindInfoSections {
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
// No dso_base for SEH.
uintptr_t dso_base;
uintptr_t __ptrauth_unwind_uis_dso_base
dso_base = 0;
#endif
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
size_t text_segment_length;
#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
uintptr_t dwarf_section;
size_t dwarf_section_length;
uintptr_t __ptrauth_unwind_uis_dwarf_section
dwarf_section = 0;
size_t __ptrauth_unwind_uis_dwarf_section_length
dwarf_section_length = 0;
#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
uintptr_t dwarf_index_section;
size_t dwarf_index_section_length;
#endif
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
uintptr_t compact_unwind_section;
size_t compact_unwind_section_length;
uintptr_t __ptrauth_unwind_uis_compact_unwind_section
compact_unwind_section = 0;
size_t __ptrauth_unwind_uis_compact_unwind_section_length
compact_unwind_section_length = 0;
#endif
#if defined(_LIBUNWIND_ARM_EHABI)
uintptr_t arm_section;
@ -196,11 +201,16 @@ public:
static int64_t getSLEB128(pint_t &addr, pint_t end);
pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
pint_t datarelBase = 0);
bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
unw_word_t *offset);
bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
bool findOtherFDE(pint_t targetAddr, pint_t &fde);
pint_t datarelBase = 0, pint_t *resultAddr = nullptr);
template <typename R>
bool findFunctionName(typename R::link_hardened_reg_arg_t addr, char *buf,
size_t bufLen, unw_word_t *offset);
template <typename R>
bool findUnwindSections(typename R::link_hardened_reg_arg_t targetAddr,
UnwindInfoSections &info);
template <typename R>
bool findOtherFDE(typename R::link_hardened_reg_arg_t targetAddr,
pint_t &fde);
static LocalAddressSpace sThisAddressSpace;
};
@ -269,7 +279,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
inline LocalAddressSpace::pint_t
LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
pint_t datarelBase) {
pint_t datarelBase, pint_t *resultAddr) {
pint_t startAddr = addr;
const uint8_t *p = (uint8_t *)addr;
pint_t result;
@ -353,8 +363,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
break;
}
if (encoding & DW_EH_PE_indirect)
if (encoding & DW_EH_PE_indirect) {
if (resultAddr)
*resultAddr = result;
result = getP(result);
} else {
if (resultAddr)
*resultAddr = startAddr;
}
return result;
}
@ -486,9 +502,9 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
UnwindInfoSections &info) {
template <typename R>
inline bool LocalAddressSpace::findUnwindSections(
typename R::link_hardened_reg_arg_t targetAddr, UnwindInfoSections &info) {
#ifdef __APPLE__
dyld_unwind_sections dyldInfo;
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
@ -658,16 +674,21 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
return false;
}
inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
template <typename R>
inline bool
LocalAddressSpace::findOtherFDE(typename R::link_hardened_reg_arg_t targetAddr,
pint_t &fde) {
// TO DO: if OS has way to dynamically register FDEs, check that.
(void)targetAddr;
(void)fde;
return false;
}
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
size_t bufLen,
unw_word_t *offset) {
template <typename R>
inline bool
LocalAddressSpace::findFunctionName(typename R::link_hardened_reg_arg_t addr,
char *buf, size_t bufLen,
unw_word_t *offset) {
#if _LIBUNWIND_USE_DLADDR
Dl_info dyldInfo;
if (dladdr((void *)addr, &dyldInfo)) {

View file

@ -601,11 +601,17 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
savedRegisterLoc -= 8;
}
// We load the link register prior to setting the new SP as the authentication
// schema for LR entangles the SP of the old frame into the diversifier.
Registers_arm64::reg_t linkRegister = registers.getRegister(UNW_AARCH64_LR);
// subtract stack size off of sp
registers.setSP(savedRegisterLoc);
// set pc to be value in lr
registers.setIP(registers.getRegister(UNW_AARCH64_LR));
// Set pc to be value in lr. This needs to be performed after the new SP has
// been set, as the PC authentication schema entangles the SP of the new
// frame.
registers.setIP(linkRegister);
return UNW_STEP_SUCCESS;
}
@ -614,7 +620,7 @@ template <typename A>
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
Registers_arm64 &registers) {
uint64_t savedRegisterLoc = registers.getFP() - 8;
Registers_arm64::reg_t savedRegisterLoc = registers.getFP() - 8;
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
@ -680,11 +686,16 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
savedRegisterLoc -= 8;
}
uint64_t fp = registers.getFP();
Registers_arm64::reg_t fp = registers.getFP();
// fp points to old fp
registers.setFP(addressSpace.get64(fp));
// old sp is fp less saved fp and lr
// Old sp is fp less saved fp and lr. We need to set this prior to setting
// the lr as the pointer authentication schema for the lr incorporates the
// sp as part of the diversifier.
registers.setSP(fp + 16);
// pop return address into pc
registers.setIP(addressSpace.get64(fp + 8));

View file

@ -22,7 +22,6 @@
#include "dwarf2.h"
#include "libunwind_ext.h"
namespace libunwind {
@ -34,8 +33,10 @@ public:
typedef typename A::pint_t pint_t;
typedef typename A::sint_t sint_t;
static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
R &registers, bool &isSignalFrame, bool stage2);
static int stepWithDwarf(A &addressSpace,
typename R::link_hardened_reg_arg_t pc,
pint_t fdeStart, R &registers, bool &isSignalFrame,
bool stage2);
private:
@ -64,9 +65,10 @@ private:
static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
const R &registers) {
if (prolog.cfaRegister != 0)
return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
prolog.cfaRegisterOffset);
if (prolog.cfaRegister != 0) {
uintptr_t cfaRegister = registers.getRegister((int)prolog.cfaRegister);
return (pint_t)(cfaRegister + prolog.cfaRegisterOffset);
}
if (prolog.cfaExpression != 0)
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
registers, 0);
@ -207,16 +209,16 @@ bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
#endif
template <typename A, typename R>
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
pint_t fdeStart, R &registers,
bool &isSignalFrame, bool stage2) {
int DwarfInstructions<A, R>::stepWithDwarf(
A &addressSpace, typename R::link_hardened_reg_arg_t pc, pint_t fdeStart,
R &registers, bool &isSignalFrame, bool stage2) {
FDE_Info fdeInfo;
CIE_Info cieInfo;
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
&cieInfo) == NULL) {
PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
R::getArch(), &prolog)) {
if (CFI_Parser<A>::template parseFDEInstructions<R>(
addressSpace, fdeInfo, cieInfo, pc, R::getArch(), &prolog)) {
// get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers);
@ -264,7 +266,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// by a CFI directive later on.
newRegisters.setSP(cfa);
pint_t returnAddress = 0;
typename R::reg_t returnAddress = 0;
constexpr int lastReg = R::lastDwarfRegNum();
static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
lastReg,
@ -300,7 +302,16 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
isSignalFrame = cieInfo.isSignalFrame;
#if defined(_LIBUNWIND_TARGET_AARCH64)
#if defined(_LIBUNWIND_TARGET_AARCH64) && \
!defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
// There are two ways of return address signing: pac-ret (enabled via
// -mbranch-protection=pac-ret) and ptrauth-returns (enabled as part of
// Apple's arm64e or experimental pauthtest ABI on Linux). The code
// below handles signed RA for pac-ret, while ptrauth-returns uses
// different logic.
// TODO: unify logic for both cases, see
// https://github.com/llvm/llvm-project/issues/160110
//
// If the target is aarch64 then the return address may have been signed
// using the v8.3 pointer authentication extensions. The original
// return address needs to be authenticated before the return address is

View file

@ -23,6 +23,10 @@
#include "config.h"
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
#include <ptrauth.h>
#endif
namespace libunwind {
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
@ -33,6 +37,7 @@ template <typename A>
class CFI_Parser {
public:
typedef typename A::pint_t pint_t;
typedef pint_t __ptrauth_unwind_cie_info_personality personality_t;
/// Information encoded in a CIE (Common Information Entry)
struct CIE_Info {
@ -43,7 +48,7 @@ public:
uint8_t lsdaEncoding;
uint8_t personalityEncoding;
uint8_t personalityOffsetInCIE;
pint_t personality;
personality_t personality;
uint32_t codeAlignFactor;
int dataAlignFactor;
bool isSignalFrame;
@ -155,14 +160,17 @@ public:
}
};
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
CIE_Info *cieInfo);
template <typename R>
static bool findFDE(A &addressSpace, typename R::link_hardened_reg_arg_t pc,
pint_t ehSectionStart, size_t sectionLength,
pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo);
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
FDE_Info *fdeInfo, CIE_Info *cieInfo,
bool useCIEInfo = false);
template <typename R>
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
const CIE_Info &cieInfo,
typename R::link_hardened_reg_arg_t upToPC,
int arch, PrologInfo *results);
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
@ -234,9 +242,12 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
/// Scan an eh_frame section to find an FDE for a pc
template <typename A>
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
size_t sectionLength, pint_t fdeHint,
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
template <typename R>
bool CFI_Parser<A>::findFDE(A &addressSpace,
typename R::link_hardened_reg_arg_t pc,
pint_t ehSectionStart, size_t sectionLength,
pint_t fdeHint, FDE_Info *fdeInfo,
CIE_Info *cieInfo) {
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
@ -273,7 +284,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
pint_t pcRange = addressSpace.getEncodedP(
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
// Test if pc is within the function this FDE covers.
if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
if ((pcStart <= pc) && (pc < pcStart + pcRange)) {
// parse rest of info
fdeInfo->lsda = 0;
// check for augmentation length
@ -369,6 +380,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
cieInfo->returnAddressRegister = (uint8_t)raReg;
// parse augmentation data based on augmentation string
const char *result = NULL;
pint_t resultAddr = 0;
if (addressSpace.get8(strStart) == 'z') {
// parse augmentation data length
addressSpace.getULEB128(p, cieContentEnd);
@ -377,13 +389,41 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
case 'z':
cieInfo->fdesHaveAugmentationData = true;
break;
case 'P':
case 'P': {
cieInfo->personalityEncoding = addressSpace.get8(p);
++p;
cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
cieInfo->personality = addressSpace
.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
pint_t personality = addressSpace.getEncodedP(
p, cieContentEnd, cieInfo->personalityEncoding,
/*datarelBase=*/0, &resultAddr);
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
if (personality) {
// The GOT for the personality function was signed address
// authenticated. Manually re-sign with the CIE_Info::personality
// schema. If we could guarantee the encoding of the personality we
// could avoid this by simply giving resultAddr the correct ptrauth
// schema and performing an assignment.
#if defined(__arm64e__)
const auto oldDiscriminator = resultAddr;
#else
const auto oldDiscriminator = ptrauth_blend_discriminator(
(void *)resultAddr, __ptrauth_unwind_pauthtest_personality_disc);
#endif
const auto discriminator = ptrauth_blend_discriminator(
&cieInfo->personality,
__ptrauth_unwind_cie_info_personality_disc);
void *signedPtr = ptrauth_auth_and_resign(
(void *)personality, ptrauth_key_function_pointer,
oldDiscriminator, ptrauth_key_function_pointer, discriminator);
personality = (pint_t)signedPtr;
}
#endif
// We use memmove to set the CIE personality as we have already
// re-signed the pointer to the correct schema.
memmove((void *)&cieInfo->personality, (void *)&personality,
sizeof(personality));
break;
}
case 'L':
cieInfo->lsdaEncoding = addressSpace.get8(p);
++p;
@ -417,10 +457,10 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
template <typename A>
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
int arch, PrologInfo *results) {
template <typename R>
bool CFI_Parser<A>::parseFDEInstructions(
A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo,
typename R::link_hardened_reg_arg_t upToPC, int arch, PrologInfo *results) {
// Alloca is used for the allocation of the rememberStack entries. It removes
// the dependency on new/malloc but the below for loop can not be refactored
// into functions. Entry could be saved during the processing of a CIE and
@ -808,12 +848,10 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
initialState);
// When calculating the value of the PC, it is assumed that the CFI
// instruction is placed before the signing instruction, however it is
// placed after. Because of this, we need to take into account the CFI
// instruction is one instruction call later than expected, and reduce
// the PC value by 4 bytes to compensate.
results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
// When using Feat_PAuthLR, the PC value needs to be captured so that
// during unwinding, the correct PC value is used for re-authentication.
// It is assumed that the CFI is placed before the signing instruction.
results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset;
_LIBUNWIND_TRACE_DWARF(
"DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
static_cast<uint64_t>(results->ptrAuthDiversifier));

View file

@ -37,8 +37,9 @@ public:
static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
EHHeaderInfo &ehHdrInfo);
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
uint32_t sectionLength,
template <typename R>
static bool findFDE(A &addressSpace, typename R::link_hardened_reg_arg_t pc,
pint_t ehHdrStart, uint32_t sectionLength,
typename CFI_Parser<A>::FDE_Info *fdeInfo,
typename CFI_Parser<A>::CIE_Info *cieInfo);
@ -112,8 +113,10 @@ bool EHHeaderParser<A>::decodeTableEntry(
}
template <typename A>
bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
uint32_t sectionLength,
template <typename R>
bool EHHeaderParser<A>::findFDE(A &addressSpace,
typename R::link_hardened_reg_arg_t pc,
pint_t ehHdrStart, uint32_t sectionLength,
typename CFI_Parser<A>::FDE_Info *fdeInfo,
typename CFI_Parser<A>::CIE_Info *cieInfo) {
pint_t ehHdrEnd = ehHdrStart + sectionLength;

View file

@ -17,8 +17,14 @@
#include "config.h"
#include "libunwind.h"
#include "libunwind_ext.h"
#include "shadow_stack_unwind.h"
#if __has_include(<sys/auxv.h>)
#include <sys/auxv.h>
#define HAVE_SYS_AUXV_H
#endif
namespace libunwind {
// For emulating 128-bit registers
@ -60,6 +66,10 @@ public:
Registers_x86();
Registers_x86(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -278,6 +288,10 @@ public:
Registers_x86_64();
Registers_x86_64(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);
@ -597,6 +611,10 @@ public:
Registers_ppc();
Registers_ppc(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -1169,6 +1187,10 @@ public:
Registers_ppc64();
Registers_ppc64(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);
@ -1814,7 +1836,9 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) {
/// Registers_arm64 holds the register state of a thread in a 64-bit arm
/// process.
class _LIBUNWIND_HIDDEN Registers_arm64;
extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
extern "C" int64_t __libunwind_Registers_arm64_za_disable();
extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *,
unsigned walkedFrames);
#if defined(_LIBUNWIND_USE_GCS)
extern "C" void *__libunwind_shstk_get_jump_target() {
@ -1824,8 +1848,21 @@ extern "C" void *__libunwind_shstk_get_jump_target() {
class _LIBUNWIND_HIDDEN Registers_arm64 {
public:
Registers_arm64();
Registers_arm64() = default;
Registers_arm64(const void *registers);
Registers_arm64(const Registers_arm64 &);
Registers_arm64 &operator=(const Registers_arm64 &);
typedef uint64_t reg_t;
typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
// Use `link_hardened_reg_arg_t` to pass values of `link_reg_t` type as
// function arguments. We need to use a const l-value reference to keep
// signature of `__ptrauth`-qualified values of `link_reg_t` type on AArch64
// PAuth-enabled ABI intact. Passing the raw pointer by value would cause
// authentication on the caller side and make the pointer prone to
// substitution if spilled to the stack in the callee.
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
@ -1837,7 +1874,14 @@ public:
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
void jumpto() { __libunwind_Registers_arm64_jumpto(this); }
void jumpto(unsigned walkedFrames = 0) {
zaDisable();
__libunwind_Registers_arm64_jumpto(this, walkedFrames);
}
#ifdef _LIBUNWIND_TRACE_RET_INJECT
_LIBUNWIND_TRACE_NO_INLINE
void returnto(unsigned walkedFrames) { jumpto(walkedFrames); }
#endif
static constexpr int lastDwarfRegNum() {
return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64;
}
@ -1845,27 +1889,94 @@ public:
uint64_t getSP() const { return _registers.__sp; }
void setSP(uint64_t value) { _registers.__sp = value; }
uint64_t getIP() const { return _registers.__pc; }
void setIP(uint64_t value) { _registers.__pc = value; }
uint64_t getFP() const { return _registers.__fp; }
void setFP(uint64_t value) { _registers.__fp = value; }
uint64_t getIP() const {
uint64_t value = _registers.__pc;
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
// Note the value of the PC was signed to its address in the register state
// but everyone else expects it to be sign by the SP, so convert on return.
value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc,
ptrauth_key_return_address,
&_registers.__pc,
ptrauth_key_return_address,
getSP());
#endif
return value;
}
void setIP(uint64_t value) {
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
// Note the value which was set should have been signed with the SP.
// We then resign with the slot we are being stored in to so that both SP
// and LR can't be spoofed at the same time.
value = (uint64_t)ptrauth_auth_and_resign((void *)value,
ptrauth_key_return_address,
getSP(),
ptrauth_key_return_address,
&_registers.__pc);
#endif
_registers.__pc = value;
}
uint64_t getFP() const { return _registers.__fp; }
void setFP(uint64_t value) { _registers.__fp = value; }
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
void
loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
link_reg_t *referenceAuthedLinkRegister) {
// If we are in an arm64/arm64e frame, then the PC should have been signed
// with the SP
*referenceAuthedLinkRegister =
(uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister,
ptrauth_key_return_address,
_registers.__sp);
}
#endif
private:
uint64_t lazyGetVG() const;
void zaDisable() const {
if (!_misc_registers.__has_sme)
return;
if (__libunwind_Registers_arm64_za_disable() != 0)
_LIBUNWIND_ABORT("SME ZA disable failed");
}
static bool checkHasSME() {
#if defined(HAVE_SYS_AUXV_H)
constexpr int hwcap2_sme = (1 << 23);
unsigned long hwcap2 = getauxval(AT_HWCAP2);
return (hwcap2 & hwcap2_sme) != 0;
#endif
// TODO: Support other platforms.
return false;
}
struct GPRs {
uint64_t __x[29]; // x0-x28
uint64_t __fp; // Frame pointer x29
uint64_t __lr; // Link register x30
uint64_t __sp; // Stack pointer x31
uint64_t __pc; // Program counter
uint64_t __ra_sign_state; // RA sign state register
uint64_t __x[29] = {}; // x0-x28
uint64_t __fp = 0; // Frame pointer x29
uint64_t __lr = 0; // Link register x30
uint64_t __sp = 0; // Stack pointer x31
uint64_t __pc = 0; // Program counter
uint64_t __ra_sign_state = 0; // RA sign state register
};
GPRs _registers;
double _vectorHalfRegisters[32];
struct Misc {
mutable uint32_t __vg = 0; // Vector Granule
bool __has_sme = checkHasSME();
};
GPRs _registers = {};
// Currently only the lower double in 128-bit vectore registers
// is perserved during unwinding. We could define new register
// numbers (> 96) which mean whole vector registers, then this
// struct would need to change to contain whole vector registers.
double _vectorHalfRegisters[32] = {};
// Miscellaneous/virtual registers. These are stored below the GPRs and FPRs
// as they do not correspond to physical registers, so do not need to be
// saved/restored in UnwindRegistersRestore.S and UnwindRegistersSave.S, and
// we don't want to modify the existing offsets for GPRs and FPRs.
Misc _misc_registers;
};
inline Registers_arm64::Registers_arm64(const void *registers) {
@ -1877,11 +1988,31 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
memcpy(_vectorHalfRegisters,
static_cast<const uint8_t *>(registers) + sizeof(GPRs),
sizeof(_vectorHalfRegisters));
_misc_registers.__vg = 0;
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
// We have to do some pointer authentication fixups after this copy,
// and as part of that we need to load the source pc without
// authenticating so that we maintain the signature for the resigning
// performed by setIP.
uint64_t pcRegister = 0;
memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
sizeof(pcRegister));
setIP(pcRegister);
#endif
}
inline Registers_arm64::Registers_arm64() {
memset(&_registers, 0, sizeof(_registers));
memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters));
inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
*this = other;
}
inline Registers_arm64 &
Registers_arm64::operator=(const Registers_arm64 &other) {
memmove(static_cast<void *>(this), &other, sizeof(*this));
// We perform this step to ensure that we correctly authenticate and re-sign
// the pc after the bitwise copy.
setIP(other.getIP());
return *this;
}
inline bool Registers_arm64::validRegister(int regNum) const {
@ -1895,22 +2026,40 @@ inline bool Registers_arm64::validRegister(int regNum) const {
return false;
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
return true;
if (regNum == UNW_AARCH64_VG)
return true;
if ((regNum > 32) && (regNum < 64))
return false;
return true;
}
inline uint64_t Registers_arm64::lazyGetVG() const {
if (!_misc_registers.__vg) {
#if defined(__aarch64__)
register uint64_t vg asm("x0");
asm(".inst 0x04e0e3e0" // CNTD x0
: "=r"(vg));
_misc_registers.__vg = vg;
#else
_LIBUNWIND_ABORT("arm64 VG undefined");
#endif
}
return _misc_registers.__vg;
}
inline uint64_t Registers_arm64::getRegister(int regNum) const {
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
return _registers.__pc;
return getIP();
if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
return _registers.__sp;
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
return _registers.__ra_sign_state;
if (regNum == UNW_AARCH64_FP)
return _registers.__fp;
return getFP();
if (regNum == UNW_AARCH64_LR)
return _registers.__lr;
if (regNum == UNW_AARCH64_VG)
return lazyGetVG();
if ((regNum >= 0) && (regNum < 29))
return _registers.__x[regNum];
_LIBUNWIND_ABORT("unsupported arm64 register");
@ -1918,15 +2067,17 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const {
inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
_registers.__pc = value;
setIP(value);
else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
_registers.__sp = value;
else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
_registers.__ra_sign_state = value;
else if (regNum == UNW_AARCH64_FP)
_registers.__fp = value;
setFP(value);
else if (regNum == UNW_AARCH64_LR)
_registers.__lr = value;
else if (regNum == UNW_AARCH64_VG)
_misc_registers.__vg = value;
else if ((regNum >= 0) && (regNum < 29))
_registers.__x[regNum] = value;
else
@ -2116,6 +2267,10 @@ public:
Registers_arm();
Registers_arm(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -2621,6 +2776,10 @@ public:
Registers_or1k();
Registers_or1k(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -2820,6 +2979,10 @@ public:
Registers_mips_o32();
Registers_mips_o32(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -3155,6 +3318,10 @@ public:
Registers_mips_newabi();
Registers_mips_newabi(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);
@ -3458,6 +3625,10 @@ public:
Registers_sparc();
Registers_sparc(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -3644,6 +3815,10 @@ public:
Registers_sparc64() = default;
Registers_sparc64(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);
@ -3829,6 +4004,10 @@ public:
Registers_hexagon();
Registers_hexagon(const void *registers);
typedef uint32_t reg_t;
typedef uint32_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
@ -4044,6 +4223,10 @@ public:
Registers_riscv();
Registers_riscv(const void *registers);
typedef ::libunwind::reg_t reg_t;
typedef ::libunwind::reg_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
reg_t getRegister(int num) const;
void setRegister(int num, reg_t value);
@ -4341,6 +4524,10 @@ public:
Registers_ve();
Registers_ve(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);
@ -4784,6 +4971,10 @@ public:
Registers_s390x();
Registers_s390x(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);
@ -5072,6 +5263,10 @@ public:
Registers_loongarch();
Registers_loongarch(const void *registers);
typedef uint64_t reg_t;
typedef uint64_t link_reg_t;
typedef const link_reg_t &link_hardened_reg_arg_t;
bool validRegister(int num) const;
uint64_t getRegister(int num) const;
void setRegister(int num, uint64_t value);

View file

@ -37,13 +37,13 @@ struct _Unwind_LandingPadContext {
// function
thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
/// Calls to this function is in landing pads in compiler-generated user code.
/// Calls to this function are in landing pads in compiler-generated user code.
/// In other EH schemes, stack unwinding is done by libunwind library, which
/// calls the personality function for each each frame it lands. On the other
/// hand, WebAssembly stack unwinding process is performed by a VM, and the
/// personality function cannot be called from there. So the compiler inserts
/// a call to this function in landing pads in the user code, which in turn
/// calls the personality function.
/// calls the personality function for each frame it lands. On the other hand,
/// WebAssembly stack unwinding process is performed by a VM, and the
/// personality function cannot be called from there. So the compiler inserts a
/// call to this function in landing pads in the user code, which in turn calls
/// the personality function.
_Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
struct _Unwind_Exception *exception_object =
(struct _Unwind_Exception *)exception_ptr;
@ -92,7 +92,7 @@ _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
/// Called by personality handler to get instruction pointer.
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
// The result will be used as an 1-based index after decrementing 1, so we
// The result will be used as a 1-based index after decrementing 1, so we
// increment 2 here
uintptr_t result =
((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;

View file

@ -41,7 +41,8 @@
#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
#endif
#if defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
#if defined(_LIBUNWIND_TARGET_HAIKU) && \
(defined(_LIBUNWIND_TARGET_I386) || defined(_LIBUNWIND_TARGET_X86_64))
#include <OS.h>
#include <signal.h>
#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1
@ -120,7 +121,9 @@ class _LIBUNWIND_HIDDEN DwarfFDECache {
typedef typename A::pint_t pint_t;
public:
static constexpr pint_t kSearchAll = static_cast<pint_t>(-1);
static pint_t findFDE(pint_t mh, pint_t pc);
template <typename R>
static pint_t findFDE(pint_t mh, typename R::link_hardened_reg_arg_t pc);
static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
static void removeAllIn(pint_t mh);
static void iterateCacheEntries(void (*func)(unw_word_t ip_start,
@ -173,7 +176,9 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
#endif
template <typename A>
typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
template <typename R>
typename DwarfFDECache<A>::pint_t
DwarfFDECache<A>::findFDE(pint_t mh, typename R::link_hardened_reg_arg_t pc) {
pint_t result = 0;
_LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
for (entry *p = _buffer; p < _bufferUsed; ++p) {
@ -471,7 +476,9 @@ public:
virtual void getInfo(unw_proc_info_t *) {
_LIBUNWIND_ABORT("getInfo not implemented");
}
virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); }
_LIBUNWIND_TRACE_NO_INLINE virtual void jumpto() {
_LIBUNWIND_ABORT("jumpto not implemented");
}
virtual bool isSignalFrame() {
_LIBUNWIND_ABORT("isSignalFrame not implemented");
}
@ -488,6 +495,12 @@ public:
virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); }
#endif
#ifdef _LIBUNWIND_TRACE_RET_INJECT
virtual void setWalkedFrames(unsigned) {
_LIBUNWIND_ABORT("setWalkedFrames not implemented");
}
#endif
#ifdef _AIX
virtual uintptr_t getDataRelBase() {
_LIBUNWIND_ABORT("getDataRelBase not implemented");
@ -964,7 +977,8 @@ public:
virtual void setFloatReg(int, unw_fpreg_t);
virtual int step(bool stage2 = false);
virtual void getInfo(unw_proc_info_t *);
virtual void jumpto();
_LIBUNWIND_TRACE_NO_INLINE
virtual void jumpto();
virtual bool isSignalFrame();
virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off);
virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false);
@ -973,6 +987,10 @@ public:
virtual void saveVFPAsX();
#endif
#ifdef _LIBUNWIND_TRACE_RET_INJECT
virtual void setWalkedFrames(unsigned);
#endif
#ifdef _AIX
virtual uintptr_t getDataRelBase();
#endif
@ -1045,19 +1063,28 @@ private:
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
const typename CFI_Parser<A>::CIE_Info &cieInfo,
pint_t pc, uintptr_t dso_base);
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint=0);
typename R::link_hardened_reg_arg_t pc,
uintptr_t dso_base);
bool getInfoFromDwarfSection(typename R::link_hardened_reg_arg_t pc,
const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint = 0);
int stepWithDwarfFDE(bool stage2) {
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
typename R::link_reg_t pc;
_registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
#else
typename R::link_reg_t pc = this->getReg(UNW_REG_IP);
#endif
return DwarfInstructions<A, R>::stepWithDwarf(
_addressSpace, (pint_t)this->getReg(UNW_REG_IP),
(pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2);
_addressSpace, pc, (pint_t)_info.unwind_info, _registers,
_isSignalFrame, stage2);
}
#endif
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
bool getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections &sects);
bool getInfoFromCompactEncodingSection(typename R::link_hardened_reg_arg_t pc,
const UnwindInfoSections &sects);
int stepWithCompactEncoding(bool stage2 = false) {
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
if ( compactSaysUseDwarf() )
@ -1344,9 +1371,12 @@ private:
bool _unwindInfoMissing;
bool _isSignalFrame;
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
defined(_LIBUNWIND_TARGET_HAIKU)
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
bool _isSigReturn = false;
#endif
#ifdef _LIBUNWIND_TRACE_RET_INJECT
uint32_t _walkedFrames;
#endif
};
@ -1358,13 +1388,13 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
"UnwindCursor<> does not fit in unw_cursor_t");
static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
"UnwindCursor<> requires more alignment than unw_cursor_t");
memset(&_info, 0, sizeof(_info));
memset(static_cast<void *>(&_info), 0, sizeof(_info));
}
template <typename A, typename R>
UnwindCursor<A, R>::UnwindCursor(A &as, void *)
: _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
memset(&_info, 0, sizeof(_info));
memset(static_cast<void *>(&_info), 0, sizeof(_info));
// FIXME
// fill in _registers from thread arg
}
@ -1401,7 +1431,46 @@ void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
}
template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
#ifdef _LIBUNWIND_TRACE_RET_INJECT
/*
The value of `_walkedFrames` is computed in `unwind_phase2` and represents the
number of frames walked starting `unwind_phase2` to get to the landing pad.
```
// uc is initialized by __unw_getcontext in the parent frame.
// The first stack frame walked is unwind_phase2.
unsigned framesWalked = 1;
```
To that, we need to add the number of function calls in libunwind between
`unwind_phase2` & `__libunwind_Registers_arm64_jumpto` which performs the long
jump, to rebalance the execution flow.
```
frame #0: libunwind.1.dylib`__libunwind_Registers_arm64_jumpto at UnwindRegistersRestore.S:646
frame #1: libunwind.1.dylib`libunwind::Registers_arm64::returnto at Registers.hpp:2291:3
frame #2: libunwind.1.dylib`libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_arm64>::jumpto at UnwindCursor.hpp:1474:14
frame #3: libunwind.1.dylib`__unw_resume at libunwind.cpp:375:7
frame #4: libunwind.1.dylib`__unw_resume_with_frames_walked at libunwind.cpp:363:10
frame #5: libunwind.1.dylib`unwind_phase2 at UnwindLevel1.c:328:9
frame #6: libunwind.1.dylib`_Unwind_RaiseException at UnwindLevel1.c:480:10
frame #7: libc++abi.dylib`__cxa_throw at cxa_exception.cpp:295:5
...
```
If we look at the backtrace from `__libunwind_Registers_arm64_jumpto`, we see
there are 5 frames on the stack to reach `unwind_phase2`. However, only 4 of
them will never return, since `__libunwind_Registers_arm64_jumpto` returns
back to the landing pad, so we need to subtract 1 to the number of
`_EXTRA_LIBUNWIND_FRAMES_WALKED`.
*/
static constexpr size_t _EXTRA_LIBUNWIND_FRAMES_WALKED = 5 - 1;
_registers.returnto(_walkedFrames + _EXTRA_LIBUNWIND_FRAMES_WALKED);
#else
_registers.jumpto();
#endif
}
#ifdef __arm__
@ -1410,6 +1479,13 @@ template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {
}
#endif
#ifdef _LIBUNWIND_TRACE_RET_INJECT
template <typename A, typename R>
void UnwindCursor<A, R>::setWalkedFrames(unsigned walkedFrames) {
_walkedFrames = walkedFrames;
}
#endif
#ifdef _AIX
template <typename A, typename R>
uintptr_t UnwindCursor<A, R>::getDataRelBase() {
@ -1658,11 +1734,11 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromFdeCie(
const typename CFI_Parser<A>::FDE_Info &fdeInfo,
const typename CFI_Parser<A>::CIE_Info &cieInfo, pint_t pc,
uintptr_t dso_base) {
const typename CFI_Parser<A>::CIE_Info &cieInfo,
typename R::link_hardened_reg_arg_t pc, uintptr_t dso_base) {
typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
R::getArch(), &prolog)) {
if (CFI_Parser<A>::template parseFDEInstructions<R>(
_addressSpace, fdeInfo, cieInfo, pc, R::getArch(), &prolog)) {
// Save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
@ -1682,43 +1758,42 @@ bool UnwindCursor<A, R>::getInfoFromFdeCie(
}
template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint) {
bool UnwindCursor<A, R>::getInfoFromDwarfSection(
typename R::link_hardened_reg_arg_t pc, const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint) {
typename CFI_Parser<A>::FDE_Info fdeInfo;
typename CFI_Parser<A>::CIE_Info cieInfo;
bool foundFDE = false;
bool foundInCache = false;
// If compact encoding table gave offset into dwarf section, go directly there
if (fdeSectionOffsetHint != 0) {
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
sects.dwarf_section_length,
sects.dwarf_section + fdeSectionOffsetHint,
&fdeInfo, &cieInfo);
foundFDE = CFI_Parser<A>::template findFDE<R>(
_addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length,
sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo);
}
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
if (!foundFDE && (sects.dwarf_index_section != 0)) {
foundFDE = EHHeaderParser<A>::findFDE(
foundFDE = EHHeaderParser<A>::template findFDE<R>(
_addressSpace, pc, sects.dwarf_index_section,
(uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo);
}
#endif
if (!foundFDE) {
// otherwise, search cache of previously found FDEs.
pint_t cachedFDE = DwarfFDECache<A>::findFDE(sects.dso_base, pc);
pint_t cachedFDE =
DwarfFDECache<A>::template findFDE<R>(sects.dso_base, pc);
if (cachedFDE != 0) {
foundFDE =
CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
sects.dwarf_section_length,
cachedFDE, &fdeInfo, &cieInfo);
foundFDE = CFI_Parser<A>::template findFDE<R>(
_addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length,
cachedFDE, &fdeInfo, &cieInfo);
foundInCache = foundFDE;
}
}
if (!foundFDE) {
// Still not found, do full scan of __eh_frame section.
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
sects.dwarf_section_length, 0,
&fdeInfo, &cieInfo);
foundFDE = CFI_Parser<A>::template findFDE<R>(
_addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length, 0,
&fdeInfo, &cieInfo);
}
if (foundFDE) {
if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) {
@ -1742,8 +1817,8 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections &sects) {
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
typename R::link_hardened_reg_arg_t pc, const UnwindInfoSections &sects) {
const bool log = false;
if (log)
fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n",
@ -1974,6 +2049,16 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
personalityIndex * sizeof(uint32_t));
pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
personality = _addressSpace.getP(personalityPointer);
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
// The GOT for the personality function was signed address authenticated.
// Resign it as a regular function pointer.
const auto discriminator = ptrauth_blend_discriminator(
&_info.handler, __ptrauth_unwind_upi_handler_disc);
void *signedPtr = ptrauth_auth_and_resign(
(void *)personality, ptrauth_key_function_pointer, personalityPointer,
ptrauth_key_function_pointer, discriminator);
personality = (__typeof(personality))signedPtr;
#endif
if (log)
fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
"personalityDelta=0x%08X, personality=0x%08llX\n",
@ -1987,7 +2072,11 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
_info.start_ip = funcStart;
_info.end_ip = funcEnd;
_info.lsda = lsda;
_info.handler = personality;
// We use memmove to copy the personality function as we have already manually
// re-signed the pointer, and assigning directly will attempt to incorrectly
// sign the already signed value.
memmove(reinterpret_cast<void *>(&_info.handler),
reinterpret_cast<void *>(&personality), sizeof(personality));
_info.gp = 0;
_info.flags = 0;
_info.format = encoding;
@ -2640,11 +2729,19 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
_isSigReturn = false;
#endif
pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
#if defined(_LIBUNWIND_ARM_EHABI)
// Remove the thumb bit so the IP represents the actual instruction address.
// This matches the behaviour of _Unwind_GetIP on arm.
pc &= (pint_t)~0x1;
rawPC &= (pint_t)~0x1;
#endif
typename R::link_reg_t pc;
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
_registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
#else
pc = rawPC;
#endif
// Exit early if at the top of the stack.
@ -2679,7 +2776,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Ask address space object to find unwind sections for this pc.
UnwindInfoSections sects;
if (_addressSpace.findUnwindSections(pc, sects)) {
if (_addressSpace.template findUnwindSections<R>(pc, sects)) {
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
// If there is a compact unwind encoding table, look there first.
if (sects.compact_unwind_section != 0) {
@ -2735,8 +2832,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
// There is no static unwind info for this pc. Look to see if an FDE was
// dynamically registered for it.
pint_t cachedFDE = DwarfFDECache<A>::findFDE(DwarfFDECache<A>::kSearchAll,
pc);
pint_t cachedFDE =
DwarfFDECache<A>::template findFDE<R>(DwarfFDECache<A>::kSearchAll, pc);
if (cachedFDE != 0) {
typename CFI_Parser<A>::FDE_Info fdeInfo;
typename CFI_Parser<A>::CIE_Info cieInfo;
@ -2748,7 +2845,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Lastly, ask AddressSpace object about platform specific ways to locate
// other FDEs.
pint_t fde;
if (_addressSpace.findOtherFDE(pc, fde)) {
if (_addressSpace.template findOtherFDE<R>(pc, fde)) {
typename CFI_Parser<A>::FDE_Info fdeInfo;
typename CFI_Parser<A>::CIE_Info cieInfo;
if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) {
@ -2772,6 +2869,21 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
defined(_LIBUNWIND_TARGET_AARCH64)
/*
* The linux sigreturn restorer stub will always have the form:
*
* d2801168 movz x8, #0x8b
* d4000001 svc #0x0
*/
#if defined(__AARCH64EB__)
#define MOVZ_X8_8B 0x681180d2
#define SVC_0 0x010000d4
#else
#define MOVZ_X8_8B 0xd2801168
#define SVC_0 0xd4000001
#endif
template <typename A, typename R>
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
// Look for the sigreturn trampoline. The trampoline's body is two
@ -2796,7 +2908,7 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
return false;
auto *instructions = reinterpret_cast<const uint32_t *>(pc);
// Look for instructions: mov x8, #0x8b; svc #0x0
if (instructions[0] != 0xd2801168 || instructions[1] != 0xd4000001)
if (instructions[0] != MOVZ_X8_8B || instructions[1] != SVC_0)
return false;
_info = {};
@ -3188,16 +3300,22 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
template <typename A, typename R>
void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
if (_unwindInfoMissing)
memset(info, 0, sizeof(*info));
memset(static_cast<void *>(info), 0, sizeof(*info));
else
*info = _info;
}
template <typename A, typename R>
bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
unw_word_t *offset) {
return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
buf, bufLen, offset);
unw_word_t *offset) {
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
typename R::link_reg_t pc;
_registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
#else
typename R::link_reg_t pc = this->getReg(UNW_REG_IP);
#endif
return _addressSpace.template findFunctionName<R>(pc, buf, bufLen, offset);
}
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)

View file

@ -48,16 +48,15 @@
// avoided when invoking the `jumpto()` function. To do this, we use inline
// assemblies to "goto" the `jumpto()` for these architectures.
#if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)
#define __unw_phase2_resume(cursor, fn) \
#define __unw_phase2_resume(cursor, payload) \
do { \
(void)fn; \
__unw_resume((cursor)); \
__unw_resume_with_frames_walked((cursor), (payload)); \
} while (0)
#elif defined(_LIBUNWIND_TARGET_I386)
#define __shstk_step_size (4)
#define __unw_phase2_resume(cursor, fn) \
#define __unw_phase2_resume(cursor, payload) \
do { \
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
_LIBUNWIND_POP_SHSTK_SSP((payload)); \
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
__asm__ volatile("push %%edi\n\t" \
@ -67,9 +66,9 @@
} while (0)
#elif defined(_LIBUNWIND_TARGET_X86_64)
#define __shstk_step_size (8)
#define __unw_phase2_resume(cursor, fn) \
#define __unw_phase2_resume(cursor, payload) \
do { \
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
_LIBUNWIND_POP_SHSTK_SSP((payload)); \
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
__asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \
@ -77,19 +76,37 @@
} while (0)
#elif defined(_LIBUNWIND_TARGET_AARCH64)
#define __shstk_step_size (8)
#define __unw_phase2_resume(cursor, fn) \
#define __unw_phase2_resume(cursor, payload) \
do { \
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
_LIBUNWIND_POP_SHSTK_SSP((payload)); \
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
__asm__ volatile("mov x0, %0\n\t" \
"mov x1, #0\n\t" \
"br %1\n\t" \
: \
: "r"(shstkRegContext), "r"(shstkJumpAddress) \
: "x0"); \
: "x0", "x1"); \
} while (0)
#endif
// We need this helper function as the semantics of casting between integers and
// function pointers mean that we end up with a function pointer without the
// correct signature. Instead we assign to an integer with a matching schema,
// and then memmove the result into a variable of the correct type. This memmove
// is possible as `_Unwind_Personality_Fn` is a standard function pointer, and
// as such is not address diversified.
static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer,
0,
ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
reauthenticatedIntegerHandler = frameInfo->handler;
_Unwind_Personality_Fn handler;
memmove(&handler, (void *)&reauthenticatedIntegerHandler,
sizeof(_Unwind_Personality_Fn));
return handler;
}
static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
__unw_init_local(cursor, uc);
@ -147,8 +164,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
// If there is a personality routine, ask it if it will want to stop at
// this frame.
if (frameInfo.handler != 0) {
_Unwind_Personality_Fn p =
(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
_Unwind_Personality_Fn p = get_handler_function(&frameInfo);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_obj=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p);
@ -184,11 +200,12 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
}
return _URC_NO_REASON;
}
extern int __unw_step_stage2(unw_cursor_t *);
#if defined(_LIBUNWIND_USE_GCS)
// Enable the GCS target feature to permit gcspop instructions to be used.
__attribute__((target("+gcs")))
#else
_LIBUNWIND_TRACE_NO_INLINE
#endif
static _Unwind_Reason_Code
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
@ -276,8 +293,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
++framesWalked;
// If there is a personality routine, tell it we are unwinding.
if (frameInfo.handler != 0) {
_Unwind_Personality_Fn p =
(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
_Unwind_Personality_Fn p = get_handler_function(&frameInfo);
_Unwind_Action action = _UA_CLEANUP_PHASE;
if (sp == exception_object->private_2) {
// Tell personality this was the frame it marked in phase 1.
@ -334,6 +350,8 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
#if defined(_LIBUNWIND_USE_GCS)
// Enable the GCS target feature to permit gcspop instructions to be used.
__attribute__((target("+gcs")))
#else
_LIBUNWIND_TRACE_NO_INLINE
#endif
static _Unwind_Reason_Code
unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
@ -394,8 +412,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
++framesWalked;
// If there is a personality routine, tell it we are unwinding.
if (frameInfo.handler != 0) {
_Unwind_Personality_Fn p =
(_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
_Unwind_Personality_Fn p = get_handler_function(&frameInfo);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase2_forced(ex_obj=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p);
@ -597,6 +614,18 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result;
__unw_get_reg(cursor, UNW_REG_IP, &result);
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
// If we are in an arm64e frame, then the PC should have been signed with the
// sp
{
unw_word_t sp;
__unw_get_reg(cursor, UNW_REG_SP, &sp);
result = (unw_word_t)ptrauth_auth_data((void *)result,
ptrauth_key_return_address, sp);
}
#endif
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
(void *)context, result);
return (uintptr_t)result;

View file

@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
#if !defined(__wasm__)
#include "assembly.h"
#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
@ -16,13 +18,17 @@
#if defined(_AIX)
.toc
#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE)
.section .text,"axy",@progbits,unique,0
#else
.text
#endif
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__)
.att_syntax
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
#
# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
@ -67,6 +73,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
# skip gs
#elif defined(__x86_64__) && !defined(__arm64ec__)
.att_syntax
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
#
@ -629,18 +636,35 @@ Lnovec:
#elif defined(__aarch64__)
#ifndef __has_feature
#define __has_feature(__feature) 0
#endif
#if defined(__ARM_FEATURE_GCS_DEFAULT)
.arch_extension gcs
#endif
//
// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *, unsigned);
//
// On entry:
// thread_state pointer is in x0
// walked_frames counter is in x1
//
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
#if defined(_LIBUNWIND_TRACE_RET_INJECT)
cbz w1, 1f
0:
subs w1, w1, #1
adr x16, #8
ret x16
b.ne 0b
1:
#endif
// skip restore of x0,x1 for now
ldp x2, x3, [x0, #0x010]
ldp x4, x5, [x0, #0x020]
@ -657,7 +681,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
ldp x24,x25, [x0, #0x0C0]
ldp x26,x27, [x0, #0x0D0]
ldp x28,x29, [x0, #0x0E0]
ldr x30, [x0, #0x100] // restore pc into lr
#if defined(__ARM_FP) && __ARM_FP != 0
ldp d0, d1, [x0, #0x110]
ldp d2, d3, [x0, #0x120]
@ -681,7 +705,18 @@ 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 sp has been
// restored.
ldr x16, [x0, #0x0F8]
ldr x16, [x0, #0x0F8] // load sp into scratch
ldr lr, [x0, #0x100] // restore pc into lr
#if __has_feature(ptrauth_calls)
// The LR is signed with its address inside the register state. Time
// to resign to be a regular ROP protected signed pointer
add x1, x0, #0x100
autib lr, x1
pacib lr, x16 // signed the scratch register for sp
#endif
ldp x0, x1, [x0, #0x000] // restore x0,x1
mov sp,x16 // restore sp
#if defined(__ARM_FEATURE_GCS_DEFAULT)
@ -694,7 +729,12 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
gcspushm x30
Lnogcs:
#endif
#if __has_feature(ptrauth_calls)
retab
#else
ret x30 // jump to pc
#endif
#elif defined(__arm__) && !defined(__APPLE__)
@ -1253,7 +1293,8 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE
#endif /* !defined(__wasm__) */

View file

@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
#if !defined(__wasm__)
#include "assembly.h"
#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
@ -16,13 +18,16 @@
#if defined(_AIX)
.toc
#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE)
.section .text,"axy",@progbits,unique,0
#else
.text
#endif
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__)
.att_syntax
#
# extern int __unw_getcontext(unw_context_t* thread_state)
@ -107,6 +112,7 @@ DEFINE_LIBUNWIND_FUNCTION("#__unw_getcontext")
.text
#elif defined(__x86_64__)
.att_syntax
#
# extern int __unw_getcontext(unw_context_t* thread_state)
@ -759,6 +765,10 @@ LnoR2Fix:
#elif defined(__aarch64__)
#ifndef __has_feature
#define __has_feature(__feature) 0
#endif
//
// extern int __unw_getcontext(unw_context_t* thread_state)
//
@ -767,6 +777,11 @@ LnoR2Fix:
//
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
#if __has_feature(ptrauth_calls)
pacibsp
#endif
stp x0, x1, [x0, #0x000]
stp x2, x3, [x0, #0x010]
stp x4, x5, [x0, #0x020]
@ -807,7 +822,74 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
str d31, [x0, #0x208]
#endif
mov x0, #0 // return UNW_ESUCCESS
#if __has_feature(ptrauth_calls)
retab
#else
ret
#endif
//
// extern "C" int64_t __libunwind_Registers_arm64_za_disable()
//
// This function implements the requirements of the __arm_za_disable ABI
// routine, except that it will not abort; it will return a non-zero value
// to signify the routine failed.
//
// Note: This function uses SME instructions. It must only be called if SME
// has been confirmed to be available.
//
// On return:
//
// A status is placed in x0. A zero value indicates success; any non-zero
// value indicates failure.
//
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_za_disable)
.variant_pcs __libunwind_Registers_arm64_za_disable
#if __has_feature(ptrauth_calls)
pacibsp
#endif
// If TPIDR2_EL0 is null, the subroutine just disables ZA.
.inst 0xd53bd0b0 // mrs x16, TPIDR2_EL0
cbz x16, 1f
// If any of the reserved bytes in the first 16 bytes of the TPIDR2 block are
// nonzero, return a non-zero value (libunwind will then abort).
ldrh w0, [x16, #10]
cbnz w0, 2f
ldr w0, [x16, #12]
cbnz w0, 2f
// If num_za_save_slices is zero, the subroutine just disables ZA.
ldrh w0, [x16, #8]
cbz x0, 1f
// If za_save_buffer is NULL, the subroutine just disables ZA.
ldr x16, [x16]
cbz x16, 1f
// Store ZA to za_save_buffer.
mov x15, xzr
0:
.inst 0xe1206200 // str za[w15,0], [x16]
.inst 0x04305830 // addsvl x16, x16, #1
add x15, x15, #1
cmp x0, x15
b.ne 0b
1:
// * Set TPIDR2_EL0 to null.
.inst 0xd51bd0bf // msr TPIDR2_EL0, xzr
// * Set PSTATE.ZA to 0.
.inst 0xd503447f // smstop za
// * Return zero (success)
mov x0, xzr
2:
#if __has_feature(ptrauth_calls)
retab
#else
ret
#endif
#elif defined(__arm__) && !defined(__APPLE__)
@ -1232,6 +1314,8 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
NO_EXEC_STACK_DIRECTIVE
#endif /* !defined(__wasm__) */

View file

@ -15,7 +15,7 @@
#ifndef UNWIND_ASSEMBLY_H
#define UNWIND_ASSEMBLY_H
#if defined(__linux__) && defined(__CET__)
#if defined(__CET__)
#include <cet.h>
#define _LIBUNWIND_CET_ENDBR _CET_ENDBR
#else
@ -132,6 +132,10 @@
#if defined(__APPLE__)
#if defined(__aarch64__) || defined(__arm64__) || defined(__arm64e__)
#define _LIBUNWIND_TRACE_RET_INJECT 1
#endif
#define SYMBOL_IS_FUNC(name)
#define HIDDEN_SYMBOL(name) .private_extern name
#if defined(_LIBUNWIND_HIDE_SYMBOLS)

View file

@ -28,6 +28,9 @@
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#endif
#if defined(__aarch64__) || defined(__arm64__) || defined(__arm64e__)
#define _LIBUNWIND_TRACE_RET_INJECT 1
#endif
#elif defined(_WIN32)
#ifdef __SEH__
#define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
@ -61,6 +64,12 @@
#endif
#endif
#ifdef _LIBUNWIND_TRACE_RET_INJECT
#define _LIBUNWIND_TRACE_NO_INLINE __attribute__((noinline, disable_tail_calls))
#else
#define _LIBUNWIND_TRACE_NO_INLINE
#endif
#if defined(_LIBUNWIND_HIDE_SYMBOLS)
// The CMake file passes -fvisibility=hidden to control ELF/Mach-O visibility.
#define _LIBUNWIND_EXPORT

View file

@ -31,6 +31,58 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
_Unwind_Personality_Fn);
#endif
#ifndef __has_feature
#define __has_feature(__feature) 0
#endif
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
// support for direct application of `__ptrauth` to integer types. This
// guard is necessary to support compilation with those compiler.
#if __has_feature(ptrauth_restricted_intptr_qualifier)
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
discriminator) \
__ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
#else
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
discriminator) \
__ptrauth(key, addressDiscriminated, discriminator)
#endif
#else
#define __ptrauth_gcc_personality_intptr(...)
#endif
#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer
// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
#define __ptrauth_gcc_personality_func_start \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0xDFEB)
// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
#define __ptrauth_gcc_personality_start \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0x52DC)
// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
#define __ptrauth_gcc_personality_length \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0xFFF7)
// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") ==
// 0x6498
#define __ptrauth_gcc_personality_lpoffset \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0x6498)
// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
#define __ptrauth_gcc_personality_lpad_disc 0xA134
#define __ptrauth_gcc_personality_lpad \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
__ptrauth_gcc_personality_lpad_disc)
// Pointer encodings documented at:
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
@ -206,7 +258,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
return continueUnwind(exceptionObject, context);
uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t __ptrauth_gcc_personality_func_start funcStart =
(uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t pcOffset = pc - funcStart;
// Parse LSDA header.
@ -225,11 +278,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
const uint8_t *p = callSiteTableStart;
while (p < callSiteTableEnd) {
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
size_t length = readEncodedPointer(&p, callSiteEncoding);
size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
uintptr_t __ptrauth_gcc_personality_start start =
readEncodedPointer(&p, callSiteEncoding);
size_t __ptrauth_gcc_personality_length length =
readEncodedPointer(&p, callSiteEncoding);
size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
readEncodedPointer(&p, callSiteEncoding);
readULEB128(&p); // action value not used for C code
if (landingPad == 0)
if (landingPadOffset == 0)
continue; // no landing pad for this entry
if ((start <= pcOffset) && (pcOffset < (start + length))) {
// Found landing pad for the PC.
@ -239,7 +295,24 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
(uintptr_t)exceptionObject);
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
_Unwind_SetIP(context, (funcStart + landingPad));
size_t __ptrauth_gcc_personality_lpad landingPad =
funcStart + landingPadOffset;
#if __has_feature(ptrauth_calls)
uintptr_t stackPointer = _Unwind_GetGR(context, -2);
const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
&landingPad, __ptrauth_gcc_personality_lpad_disc);
// newIP is authenticated as if it were qualified with a pseudo qualifier
// along the lines of:
// __ptrauth(ptrauth_key_return_address, <stackPointer>, 0)
// where the stack pointer is used in place of the strict storage
// address.
uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
*(void **)&landingPad, __ptrauth_gcc_personality_func_key,
existingDiscriminator, ptrauth_key_return_address, stackPointer);
_Unwind_SetIP(context, newIP);
#else
_Unwind_SetIP(context, landingPad);
#endif
return _URC_INSTALL_CONTEXT;
}
}

View file

@ -118,14 +118,55 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
typedef LocalAddressSpace::pint_t pint_t;
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
if (co->validReg(regNum)) {
co->setReg(regNum, (pint_t)value);
// special case altering IP to re-find info (being called by personality
// function)
if (regNum == UNW_REG_IP) {
unw_proc_info_t info;
// First, get the FDE for the old location and then update it.
co->getInfo(&info);
co->setInfoBasedOnIPRegister(false);
pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
{
// It is only valid to set the IP within the current function. This is
// important for ptrauth, otherwise the IP cannot be correctly signed.
// The current signature of `value` is via the schema:
// __ptrauth(ptrauth_key_return_address, <<sp>>, 0)
// For this to be generally usable we manually re-sign it to the
// directly supported schema:
// __ptrauth(ptrauth_key_return_address, 1, 0)
unw_word_t
__unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1,
0) authenticated_value;
unw_word_t opaque_value = (uint64_t)ptrauth_auth_and_resign(
(void *)value, ptrauth_key_return_address, sp,
ptrauth_key_return_address, &authenticated_value);
memmove(reinterpret_cast<void *>(&authenticated_value),
reinterpret_cast<void *>(&opaque_value),
sizeof(authenticated_value));
if (authenticated_value < info.start_ip ||
authenticated_value > info.end_ip)
_LIBUNWIND_ABORT("PC vs frame info mismatch");
// PC should have been signed with the sp, so we verify that
// roundtripping does not fail. The `ptrauth_auth_and_resign` is
// guaranteed to trap on authentication failure even without FPAC
// feature.
pint_t pc = (pint_t)co->getReg(UNW_REG_IP);
if (ptrauth_auth_and_resign((void *)pc, ptrauth_key_return_address, sp,
ptrauth_key_return_address,
sp) != (void *)pc) {
_LIBUNWIND_LOG(
"Bad unwind with PAuth-enabled ABI (0x%zX, 0x%zX)->0x%zX\n", pc,
sp,
(pint_t)ptrauth_auth_data((void *)pc, ptrauth_key_return_address,
sp));
_LIBUNWIND_ABORT("Bad unwind with PAuth-enabled ABI");
}
}
#endif
// If the original call expects stack adjustment, perform this now.
// Normal frame unwinding would have included the offset already in the
// CFA computation.
@ -133,7 +174,11 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
// this should actually be - info.gp. LLVM doesn't currently support
// any such platforms and Clang doesn't export a macro for them.
if (info.gp)
co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
co->setReg(UNW_REG_SP, sp + info.gp);
co->setReg(UNW_REG_IP, value);
co->setInfoBasedOnIPRegister(false);
} else {
co->setReg(regNum, (pint_t)value);
}
return UNW_ESUCCESS;
}
@ -205,7 +250,27 @@ _LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor,
}
_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info)
/// Resume execution at cursor position (aka longjump).
/// Rebalance the execution flow by injecting the right amount of `ret`
/// instruction relatively to the amount of `walkedFrames` then resume execution
/// at cursor position (aka longjump).
_LIBUNWIND_HIDDEN int __unw_resume_with_frames_walked(unw_cursor_t *cursor,
unsigned walkedFrames) {
_LIBUNWIND_TRACE_API("__unw_resume(cursor=%p, walkedFrames=%u)",
static_cast<void *>(cursor), walkedFrames);
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
// Inform the ASan runtime that now might be a good time to clean stuff up.
__asan_handle_no_return();
#endif
#ifdef _LIBUNWIND_TRACE_RET_INJECT
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
co->setWalkedFrames(walkedFrames);
#endif
return __unw_resume(cursor);
}
_LIBUNWIND_WEAK_ALIAS(__unw_resume_with_frames_walked,
unw_resume_with_frames_walked)
/// Legacy function. Resume execution at cursor position (aka longjump).
_LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) {
_LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor));
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
@ -347,6 +412,41 @@ void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
}
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
/// Maps the UNW_* error code to a textual representation
_LIBUNWIND_HIDDEN const char *__unw_strerror(int error_code) {
switch (error_code) {
case UNW_ESUCCESS:
return "no error";
case UNW_EUNSPEC:
return "unspecified (general) error";
case UNW_ENOMEM:
return "out of memory";
case UNW_EBADREG:
return "bad register number";
case UNW_EREADONLYREG:
return "attempt to write read-only register";
case UNW_ESTOPUNWIND:
return "stop unwinding";
case UNW_EINVALIDIP:
return "invalid IP";
case UNW_EBADFRAME:
return "bad frame";
case UNW_EINVAL:
return "unsupported operation or bad value";
case UNW_EBADVERSION:
return "unwind info has unsupported version";
case UNW_ENOINFO:
return "no unwind info found";
#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
case UNW_ECROSSRASIGNING:
return "cross unwind with return address signing";
#endif
}
return "invalid error code";
}
_LIBUNWIND_WEAK_ALIAS(__unw_strerror, unw_strerror)
#endif // !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)
#ifdef __APPLE__

View file

@ -26,11 +26,16 @@ extern "C" {
extern int __unw_getcontext(unw_context_t *);
extern int __unw_init_local(unw_cursor_t *, unw_context_t *);
extern int __unw_step(unw_cursor_t *);
extern int __unw_step_stage2(unw_cursor_t *);
extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *);
extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t);
extern int __unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t);
extern int __unw_resume(unw_cursor_t *);
_LIBUNWIND_TRACE_NO_INLINE
extern int __unw_resume_with_frames_walked(unw_cursor_t *, unsigned);
// `__unw_resume` is a legacy function. Use `__unw_resume_with_frames_walked` instead.
_LIBUNWIND_TRACE_NO_INLINE
extern int __unw_resume(unw_cursor_t *);
#ifdef __arm__
/* Save VFP registers in FSTMX format (instead of FSTMD). */
@ -42,6 +47,7 @@ extern int __unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *);
extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t);
extern int __unw_is_signal_frame(unw_cursor_t *);
extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);
extern const char *__unw_strerror(int);
#if defined(_AIX)
extern uintptr_t __unw_get_data_rel_base(unw_cursor_t *);

View file

@ -12,8 +12,8 @@
#include "libunwind.h"
// Currently, CET is implemented on Linux x86 platforms.
#if defined(_LIBUNWIND_TARGET_LINUX) && defined(__CET__) && defined(__SHSTK__)
// Currently, CET is implemented on some ELF x86 platforms.
#if defined(__CET__) && defined(__SHSTK__)
#define _LIBUNWIND_USE_CET 1
#endif