mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-26 13:01:34 +03:00
libunwind: update to LLVM 22
This commit is contained in:
+11
-2
@@ -73,11 +73,11 @@
|
|||||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
|
||||||
# elif defined(__aarch64__)
|
# elif defined(__aarch64__)
|
||||||
# define _LIBUNWIND_TARGET_AARCH64 1
|
# define _LIBUNWIND_TARGET_AARCH64 1
|
||||||
# define _LIBUNWIND_CONTEXT_SIZE 66
|
#define _LIBUNWIND_CONTEXT_SIZE 67
|
||||||
# if defined(__SEH__)
|
# if defined(__SEH__)
|
||||||
# define _LIBUNWIND_CURSOR_SIZE 164
|
# define _LIBUNWIND_CURSOR_SIZE 164
|
||||||
# else
|
# else
|
||||||
# define _LIBUNWIND_CURSOR_SIZE 78
|
#define _LIBUNWIND_CURSOR_SIZE 79
|
||||||
# endif
|
# endif
|
||||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
|
||||||
# elif defined(__arm__)
|
# elif defined(__arm__)
|
||||||
@@ -212,4 +212,13 @@
|
|||||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
|
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
|
||||||
#endif // _LIBUNWIND_IS_NATIVE_ONLY
|
#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__
|
#endif // ____LIBUNWIND_CONFIG_H__
|
||||||
|
|||||||
Vendored
+117
-11
@@ -43,6 +43,109 @@
|
|||||||
#define LIBUNWIND_AVAIL
|
#define LIBUNWIND_AVAIL
|
||||||
#endif
|
#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__)
|
#if defined(_WIN32) && defined(__SEH__)
|
||||||
#define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
|
#define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
|
||||||
#else
|
#else
|
||||||
@@ -88,17 +191,18 @@ typedef double unw_fpreg_t;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct unw_proc_info_t {
|
struct unw_proc_info_t {
|
||||||
unw_word_t start_ip; /* start address of function */
|
unw_word_t __ptrauth_unwind_upi_startip start_ip; /* start address of function */
|
||||||
unw_word_t end_ip; /* address after end of function */
|
unw_word_t __ptrauth_unwind_upi_endip end_ip; /* address after end of function */
|
||||||
unw_word_t lsda; /* address of language specific data area, */
|
unw_word_t __ptrauth_unwind_upi_lsda lsda; /* address of language specific data area, */
|
||||||
/* or zero if not used */
|
/* 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 __ptrauth_unwind_upi_handler_intptr handler;
|
||||||
unw_word_t flags; /* not used */
|
unw_word_t gp; /* not used */
|
||||||
uint32_t format; /* compact unwind encoding, or zero if none */
|
unw_word_t __ptrauth_unwind_upi_flags flags; /* not used */
|
||||||
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
|
uint32_t format; /* compact unwind encoding, or zero if none */
|
||||||
unw_word_t unwind_info; /* address of DWARF unwind info, or zero */
|
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
|
||||||
unw_word_t extra; /* mach_header of mach-o image containing func */
|
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;
|
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_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_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 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;
|
extern unw_addr_space_t unw_local_addr_space;
|
||||||
|
|
||||||
@@ -532,6 +637,7 @@ enum {
|
|||||||
UNW_AARCH64_X31 = 31,
|
UNW_AARCH64_X31 = 31,
|
||||||
UNW_AARCH64_SP = 31,
|
UNW_AARCH64_SP = 31,
|
||||||
UNW_AARCH64_PC = 32,
|
UNW_AARCH64_PC = 32,
|
||||||
|
UNW_AARCH64_VG = 46,
|
||||||
|
|
||||||
// reserved block
|
// reserved block
|
||||||
UNW_AARCH64_RA_SIGN_STATE = 34,
|
UNW_AARCH64_RA_SIGN_STATE = 34,
|
||||||
|
|||||||
+4
-1
@@ -125,8 +125,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
|||||||
uint32_t discriminator,
|
uint32_t discriminator,
|
||||||
_Unwind_VRS_DataRepresentation representation);
|
_Unwind_VRS_DataRepresentation representation);
|
||||||
|
|
||||||
|
extern _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *,
|
||||||
|
_Unwind_Context *);
|
||||||
|
|
||||||
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
|
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
|
||||||
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
|
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern __inline__
|
||||||
#else
|
#else
|
||||||
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__
|
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Vendored
+40
-19
@@ -129,22 +129,27 @@ struct UnwindInfoSections {
|
|||||||
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
|
defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
|
||||||
defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
||||||
// No dso_base for SEH.
|
// No dso_base for SEH.
|
||||||
uintptr_t dso_base;
|
uintptr_t __ptrauth_unwind_uis_dso_base
|
||||||
|
dso_base = 0;
|
||||||
#endif
|
#endif
|
||||||
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
||||||
size_t text_segment_length;
|
size_t text_segment_length;
|
||||||
#endif
|
#endif
|
||||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
uintptr_t dwarf_section;
|
uintptr_t __ptrauth_unwind_uis_dwarf_section
|
||||||
size_t dwarf_section_length;
|
dwarf_section = 0;
|
||||||
|
size_t __ptrauth_unwind_uis_dwarf_section_length
|
||||||
|
dwarf_section_length = 0;
|
||||||
#endif
|
#endif
|
||||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||||
uintptr_t dwarf_index_section;
|
uintptr_t dwarf_index_section;
|
||||||
size_t dwarf_index_section_length;
|
size_t dwarf_index_section_length;
|
||||||
#endif
|
#endif
|
||||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||||
uintptr_t compact_unwind_section;
|
uintptr_t __ptrauth_unwind_uis_compact_unwind_section
|
||||||
size_t compact_unwind_section_length;
|
compact_unwind_section = 0;
|
||||||
|
size_t __ptrauth_unwind_uis_compact_unwind_section_length
|
||||||
|
compact_unwind_section_length = 0;
|
||||||
#endif
|
#endif
|
||||||
#if defined(_LIBUNWIND_ARM_EHABI)
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
uintptr_t arm_section;
|
uintptr_t arm_section;
|
||||||
@@ -196,11 +201,16 @@ public:
|
|||||||
static int64_t getSLEB128(pint_t &addr, pint_t end);
|
static int64_t getSLEB128(pint_t &addr, pint_t end);
|
||||||
|
|
||||||
pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
||||||
pint_t datarelBase = 0);
|
pint_t datarelBase = 0, pint_t *resultAddr = nullptr);
|
||||||
bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
|
template <typename R>
|
||||||
unw_word_t *offset);
|
bool findFunctionName(typename R::link_hardened_reg_arg_t addr, char *buf,
|
||||||
bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
|
size_t bufLen, unw_word_t *offset);
|
||||||
bool findOtherFDE(pint_t targetAddr, pint_t &fde);
|
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;
|
static LocalAddressSpace sThisAddressSpace;
|
||||||
};
|
};
|
||||||
@@ -269,7 +279,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
|
|||||||
|
|
||||||
inline LocalAddressSpace::pint_t
|
inline LocalAddressSpace::pint_t
|
||||||
LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
||||||
pint_t datarelBase) {
|
pint_t datarelBase, pint_t *resultAddr) {
|
||||||
pint_t startAddr = addr;
|
pint_t startAddr = addr;
|
||||||
const uint8_t *p = (uint8_t *)addr;
|
const uint8_t *p = (uint8_t *)addr;
|
||||||
pint_t result;
|
pint_t result;
|
||||||
@@ -353,8 +363,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encoding & DW_EH_PE_indirect)
|
if (encoding & DW_EH_PE_indirect) {
|
||||||
|
if (resultAddr)
|
||||||
|
*resultAddr = result;
|
||||||
result = getP(result);
|
result = getP(result);
|
||||||
|
} else {
|
||||||
|
if (resultAddr)
|
||||||
|
*resultAddr = startAddr;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -486,9 +502,9 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
|||||||
|
|
||||||
#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
inline bool LocalAddressSpace::findUnwindSections(
|
||||||
UnwindInfoSections &info) {
|
typename R::link_hardened_reg_arg_t targetAddr, UnwindInfoSections &info) {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
dyld_unwind_sections dyldInfo;
|
dyld_unwind_sections dyldInfo;
|
||||||
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
|
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
|
||||||
@@ -658,16 +674,21 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
|
|||||||
return false;
|
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.
|
// TO DO: if OS has way to dynamically register FDEs, check that.
|
||||||
(void)targetAddr;
|
(void)targetAddr;
|
||||||
(void)fde;
|
(void)fde;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
|
template <typename R>
|
||||||
size_t bufLen,
|
inline bool
|
||||||
unw_word_t *offset) {
|
LocalAddressSpace::findFunctionName(typename R::link_hardened_reg_arg_t addr,
|
||||||
|
char *buf, size_t bufLen,
|
||||||
|
unw_word_t *offset) {
|
||||||
#if _LIBUNWIND_USE_DLADDR
|
#if _LIBUNWIND_USE_DLADDR
|
||||||
Dl_info dyldInfo;
|
Dl_info dyldInfo;
|
||||||
if (dladdr((void *)addr, &dyldInfo)) {
|
if (dladdr((void *)addr, &dyldInfo)) {
|
||||||
|
|||||||
+16
-5
@@ -601,11 +601,17 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
|
|||||||
savedRegisterLoc -= 8;
|
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
|
// subtract stack size off of sp
|
||||||
registers.setSP(savedRegisterLoc);
|
registers.setSP(savedRegisterLoc);
|
||||||
|
|
||||||
// set pc to be value in lr
|
// Set pc to be value in lr. This needs to be performed after the new SP has
|
||||||
registers.setIP(registers.getRegister(UNW_AARCH64_LR));
|
// been set, as the PC authentication schema entangles the SP of the new
|
||||||
|
// frame.
|
||||||
|
registers.setIP(linkRegister);
|
||||||
|
|
||||||
return UNW_STEP_SUCCESS;
|
return UNW_STEP_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -614,7 +620,7 @@ template <typename A>
|
|||||||
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
|
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
|
||||||
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
|
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
|
||||||
Registers_arm64 ®isters) {
|
Registers_arm64 ®isters) {
|
||||||
uint64_t savedRegisterLoc = registers.getFP() - 8;
|
Registers_arm64::reg_t savedRegisterLoc = registers.getFP() - 8;
|
||||||
|
|
||||||
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
|
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
|
||||||
registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
|
registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
|
||||||
@@ -680,11 +686,16 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
|
|||||||
savedRegisterLoc -= 8;
|
savedRegisterLoc -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t fp = registers.getFP();
|
Registers_arm64::reg_t fp = registers.getFP();
|
||||||
|
|
||||||
// fp points to old fp
|
// fp points to old fp
|
||||||
registers.setFP(addressSpace.get64(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);
|
registers.setSP(fp + 16);
|
||||||
|
|
||||||
// pop return address into pc
|
// pop return address into pc
|
||||||
registers.setIP(addressSpace.get64(fp + 8));
|
registers.setIP(addressSpace.get64(fp + 8));
|
||||||
|
|
||||||
|
|||||||
+24
-13
@@ -22,7 +22,6 @@
|
|||||||
#include "dwarf2.h"
|
#include "dwarf2.h"
|
||||||
#include "libunwind_ext.h"
|
#include "libunwind_ext.h"
|
||||||
|
|
||||||
|
|
||||||
namespace libunwind {
|
namespace libunwind {
|
||||||
|
|
||||||
|
|
||||||
@@ -34,8 +33,10 @@ public:
|
|||||||
typedef typename A::pint_t pint_t;
|
typedef typename A::pint_t pint_t;
|
||||||
typedef typename A::sint_t sint_t;
|
typedef typename A::sint_t sint_t;
|
||||||
|
|
||||||
static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
|
static int stepWithDwarf(A &addressSpace,
|
||||||
R ®isters, bool &isSignalFrame, bool stage2);
|
typename R::link_hardened_reg_arg_t pc,
|
||||||
|
pint_t fdeStart, R ®isters, bool &isSignalFrame,
|
||||||
|
bool stage2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -64,9 +65,10 @@ private:
|
|||||||
|
|
||||||
static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
|
static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
|
||||||
const R ®isters) {
|
const R ®isters) {
|
||||||
if (prolog.cfaRegister != 0)
|
if (prolog.cfaRegister != 0) {
|
||||||
return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
|
uintptr_t cfaRegister = registers.getRegister((int)prolog.cfaRegister);
|
||||||
prolog.cfaRegisterOffset);
|
return (pint_t)(cfaRegister + prolog.cfaRegisterOffset);
|
||||||
|
}
|
||||||
if (prolog.cfaExpression != 0)
|
if (prolog.cfaExpression != 0)
|
||||||
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
|
return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
|
||||||
registers, 0);
|
registers, 0);
|
||||||
@@ -207,16 +209,16 @@ bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
int DwarfInstructions<A, R>::stepWithDwarf(
|
||||||
pint_t fdeStart, R ®isters,
|
A &addressSpace, typename R::link_hardened_reg_arg_t pc, pint_t fdeStart,
|
||||||
bool &isSignalFrame, bool stage2) {
|
R ®isters, bool &isSignalFrame, bool stage2) {
|
||||||
FDE_Info fdeInfo;
|
FDE_Info fdeInfo;
|
||||||
CIE_Info cieInfo;
|
CIE_Info cieInfo;
|
||||||
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
|
if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
|
||||||
&cieInfo) == NULL) {
|
&cieInfo) == NULL) {
|
||||||
PrologInfo prolog;
|
PrologInfo prolog;
|
||||||
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
|
if (CFI_Parser<A>::template parseFDEInstructions<R>(
|
||||||
R::getArch(), &prolog)) {
|
addressSpace, fdeInfo, cieInfo, pc, R::getArch(), &prolog)) {
|
||||||
// get pointer to cfa (architecture specific)
|
// get pointer to cfa (architecture specific)
|
||||||
pint_t cfa = getCFA(addressSpace, prolog, registers);
|
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.
|
// by a CFI directive later on.
|
||||||
newRegisters.setSP(cfa);
|
newRegisters.setSP(cfa);
|
||||||
|
|
||||||
pint_t returnAddress = 0;
|
typename R::reg_t returnAddress = 0;
|
||||||
constexpr int lastReg = R::lastDwarfRegNum();
|
constexpr int lastReg = R::lastDwarfRegNum();
|
||||||
static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
|
static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
|
||||||
lastReg,
|
lastReg,
|
||||||
@@ -300,7 +302,16 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
|||||||
|
|
||||||
isSignalFrame = cieInfo.isSignalFrame;
|
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
|
// If the target is aarch64 then the return address may have been signed
|
||||||
// using the v8.3 pointer authentication extensions. The original
|
// using the v8.3 pointer authentication extensions. The original
|
||||||
// return address needs to be authenticated before the return address is
|
// return address needs to be authenticated before the return address is
|
||||||
|
|||||||
Vendored
+60
-22
@@ -23,6 +23,10 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
|
||||||
|
#include <ptrauth.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace libunwind {
|
namespace libunwind {
|
||||||
|
|
||||||
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
|
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
|
||||||
@@ -33,6 +37,7 @@ template <typename A>
|
|||||||
class CFI_Parser {
|
class CFI_Parser {
|
||||||
public:
|
public:
|
||||||
typedef typename A::pint_t pint_t;
|
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)
|
/// Information encoded in a CIE (Common Information Entry)
|
||||||
struct CIE_Info {
|
struct CIE_Info {
|
||||||
@@ -43,7 +48,7 @@ public:
|
|||||||
uint8_t lsdaEncoding;
|
uint8_t lsdaEncoding;
|
||||||
uint8_t personalityEncoding;
|
uint8_t personalityEncoding;
|
||||||
uint8_t personalityOffsetInCIE;
|
uint8_t personalityOffsetInCIE;
|
||||||
pint_t personality;
|
personality_t personality;
|
||||||
uint32_t codeAlignFactor;
|
uint32_t codeAlignFactor;
|
||||||
int dataAlignFactor;
|
int dataAlignFactor;
|
||||||
bool isSignalFrame;
|
bool isSignalFrame;
|
||||||
@@ -155,14 +160,17 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
template <typename R>
|
||||||
size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
|
static bool findFDE(A &addressSpace, typename R::link_hardened_reg_arg_t pc,
|
||||||
CIE_Info *cieInfo);
|
pint_t ehSectionStart, size_t sectionLength,
|
||||||
|
pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo);
|
||||||
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
|
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
|
||||||
FDE_Info *fdeInfo, CIE_Info *cieInfo,
|
FDE_Info *fdeInfo, CIE_Info *cieInfo,
|
||||||
bool useCIEInfo = false);
|
bool useCIEInfo = false);
|
||||||
|
template <typename R>
|
||||||
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
|
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);
|
int arch, PrologInfo *results);
|
||||||
|
|
||||||
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
|
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
|
/// Scan an eh_frame section to find an FDE for a pc
|
||||||
template <typename A>
|
template <typename A>
|
||||||
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
|
template <typename R>
|
||||||
size_t sectionLength, pint_t fdeHint,
|
bool CFI_Parser<A>::findFDE(A &addressSpace,
|
||||||
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
|
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);
|
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
|
||||||
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
|
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
|
||||||
const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
|
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(
|
pint_t pcRange = addressSpace.getEncodedP(
|
||||||
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
|
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
|
||||||
// Test if pc is within the function this FDE covers.
|
// 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
|
// parse rest of info
|
||||||
fdeInfo->lsda = 0;
|
fdeInfo->lsda = 0;
|
||||||
// check for augmentation length
|
// check for augmentation length
|
||||||
@@ -369,6 +380,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
|
|||||||
cieInfo->returnAddressRegister = (uint8_t)raReg;
|
cieInfo->returnAddressRegister = (uint8_t)raReg;
|
||||||
// parse augmentation data based on augmentation string
|
// parse augmentation data based on augmentation string
|
||||||
const char *result = NULL;
|
const char *result = NULL;
|
||||||
|
pint_t resultAddr = 0;
|
||||||
if (addressSpace.get8(strStart) == 'z') {
|
if (addressSpace.get8(strStart) == 'z') {
|
||||||
// parse augmentation data length
|
// parse augmentation data length
|
||||||
addressSpace.getULEB128(p, cieContentEnd);
|
addressSpace.getULEB128(p, cieContentEnd);
|
||||||
@@ -377,13 +389,41 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
|
|||||||
case 'z':
|
case 'z':
|
||||||
cieInfo->fdesHaveAugmentationData = true;
|
cieInfo->fdesHaveAugmentationData = true;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P': {
|
||||||
cieInfo->personalityEncoding = addressSpace.get8(p);
|
cieInfo->personalityEncoding = addressSpace.get8(p);
|
||||||
++p;
|
++p;
|
||||||
cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
|
cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
|
||||||
cieInfo->personality = addressSpace
|
pint_t personality = addressSpace.getEncodedP(
|
||||||
.getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
|
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;
|
break;
|
||||||
|
}
|
||||||
case 'L':
|
case 'L':
|
||||||
cieInfo->lsdaEncoding = addressSpace.get8(p);
|
cieInfo->lsdaEncoding = addressSpace.get8(p);
|
||||||
++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
|
/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
|
||||||
template <typename A>
|
template <typename A>
|
||||||
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
template <typename R>
|
||||||
const FDE_Info &fdeInfo,
|
bool CFI_Parser<A>::parseFDEInstructions(
|
||||||
const CIE_Info &cieInfo, pint_t upToPC,
|
A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo,
|
||||||
int arch, PrologInfo *results) {
|
typename R::link_hardened_reg_arg_t upToPC, int arch, PrologInfo *results) {
|
||||||
// Alloca is used for the allocation of the rememberStack entries. It removes
|
// 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
|
// 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
|
// 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->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
|
||||||
results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
|
results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
|
||||||
initialState);
|
initialState);
|
||||||
// When calculating the value of the PC, it is assumed that the CFI
|
// When using Feat_PAuthLR, the PC value needs to be captured so that
|
||||||
// instruction is placed before the signing instruction, however it is
|
// during unwinding, the correct PC value is used for re-authentication.
|
||||||
// placed after. Because of this, we need to take into account the CFI
|
// It is assumed that the CFI is placed before the signing instruction.
|
||||||
// instruction is one instruction call later than expected, and reduce
|
results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset;
|
||||||
// the PC value by 4 bytes to compensate.
|
|
||||||
results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
|
|
||||||
_LIBUNWIND_TRACE_DWARF(
|
_LIBUNWIND_TRACE_DWARF(
|
||||||
"DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
|
"DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
|
||||||
static_cast<uint64_t>(results->ptrAuthDiversifier));
|
static_cast<uint64_t>(results->ptrAuthDiversifier));
|
||||||
|
|||||||
Vendored
+7
-4
@@ -37,8 +37,9 @@ public:
|
|||||||
|
|
||||||
static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
|
static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
|
||||||
EHHeaderInfo &ehHdrInfo);
|
EHHeaderInfo &ehHdrInfo);
|
||||||
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
|
template <typename R>
|
||||||
uint32_t sectionLength,
|
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>::FDE_Info *fdeInfo,
|
||||||
typename CFI_Parser<A>::CIE_Info *cieInfo);
|
typename CFI_Parser<A>::CIE_Info *cieInfo);
|
||||||
|
|
||||||
@@ -112,8 +113,10 @@ bool EHHeaderParser<A>::decodeTableEntry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename A>
|
template <typename A>
|
||||||
bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
|
template <typename R>
|
||||||
uint32_t sectionLength,
|
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>::FDE_Info *fdeInfo,
|
||||||
typename CFI_Parser<A>::CIE_Info *cieInfo) {
|
typename CFI_Parser<A>::CIE_Info *cieInfo) {
|
||||||
pint_t ehHdrEnd = ehHdrStart + sectionLength;
|
pint_t ehHdrEnd = ehHdrStart + sectionLength;
|
||||||
|
|||||||
Vendored
+226
-22
@@ -17,8 +17,13 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libunwind.h"
|
#include "libunwind.h"
|
||||||
|
#include "libunwind_ext.h"
|
||||||
#include "shadow_stack_unwind.h"
|
#include "shadow_stack_unwind.h"
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_HAVE_GETAUXVAL) || defined(_LIBUNWIND_HAVE_ELF_AUX_INFO)
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace libunwind {
|
namespace libunwind {
|
||||||
|
|
||||||
// For emulating 128-bit registers
|
// For emulating 128-bit registers
|
||||||
@@ -60,6 +65,10 @@ public:
|
|||||||
Registers_x86();
|
Registers_x86();
|
||||||
Registers_x86(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -278,6 +287,10 @@ public:
|
|||||||
Registers_x86_64();
|
Registers_x86_64();
|
||||||
Registers_x86_64(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
@@ -597,6 +610,10 @@ public:
|
|||||||
Registers_ppc();
|
Registers_ppc();
|
||||||
Registers_ppc(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -1169,6 +1186,10 @@ public:
|
|||||||
Registers_ppc64();
|
Registers_ppc64();
|
||||||
Registers_ppc64(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
@@ -1814,7 +1835,9 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) {
|
|||||||
/// Registers_arm64 holds the register state of a thread in a 64-bit arm
|
/// Registers_arm64 holds the register state of a thread in a 64-bit arm
|
||||||
/// process.
|
/// process.
|
||||||
class _LIBUNWIND_HIDDEN Registers_arm64;
|
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)
|
#if defined(_LIBUNWIND_USE_GCS)
|
||||||
extern "C" void *__libunwind_shstk_get_jump_target() {
|
extern "C" void *__libunwind_shstk_get_jump_target() {
|
||||||
@@ -1824,8 +1847,21 @@ extern "C" void *__libunwind_shstk_get_jump_target() {
|
|||||||
|
|
||||||
class _LIBUNWIND_HIDDEN Registers_arm64 {
|
class _LIBUNWIND_HIDDEN Registers_arm64 {
|
||||||
public:
|
public:
|
||||||
Registers_arm64();
|
Registers_arm64() = default;
|
||||||
Registers_arm64(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
@@ -1837,7 +1873,14 @@ public:
|
|||||||
v128 getVectorRegister(int num) const;
|
v128 getVectorRegister(int num) const;
|
||||||
void setVectorRegister(int num, v128 value);
|
void setVectorRegister(int num, v128 value);
|
||||||
static const char *getRegisterName(int num);
|
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() {
|
static constexpr int lastDwarfRegNum() {
|
||||||
return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64;
|
return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64;
|
||||||
}
|
}
|
||||||
@@ -1845,27 +1888,104 @@ public:
|
|||||||
|
|
||||||
uint64_t getSP() const { return _registers.__sp; }
|
uint64_t getSP() const { return _registers.__sp; }
|
||||||
void setSP(uint64_t value) { _registers.__sp = value; }
|
void setSP(uint64_t value) { _registers.__sp = value; }
|
||||||
uint64_t getIP() const { return _registers.__pc; }
|
uint64_t getIP() const {
|
||||||
void setIP(uint64_t value) { _registers.__pc = value; }
|
uint64_t value = _registers.__pc;
|
||||||
uint64_t getFP() const { return _registers.__fp; }
|
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
|
||||||
void setFP(uint64_t value) { _registers.__fp = value; }
|
// 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:
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_LIBUNWIND_HAVE_GETAUXVAL)
|
||||||
|
static bool checkHasSME() {
|
||||||
|
constexpr int hwcap2_sme = (1 << 23);
|
||||||
|
unsigned long hwcap2 = getauxval(AT_HWCAP2);
|
||||||
|
return (hwcap2 & hwcap2_sme) != 0;
|
||||||
|
}
|
||||||
|
#elif defined(_LIBUNWIND_HAVE_ELF_AUX_INFO)
|
||||||
|
static bool checkHasSME() {
|
||||||
|
constexpr int hwcap2_sme = (1 << 23);
|
||||||
|
unsigned long hwcap2 = 0;
|
||||||
|
elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2));
|
||||||
|
return (hwcap2 & hwcap2_sme) != 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static bool checkHasSME() {
|
||||||
|
// TODO: Support other platforms.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct GPRs {
|
struct GPRs {
|
||||||
uint64_t __x[29]; // x0-x28
|
uint64_t __x[29] = {}; // x0-x28
|
||||||
uint64_t __fp; // Frame pointer x29
|
uint64_t __fp = 0; // Frame pointer x29
|
||||||
uint64_t __lr; // Link register x30
|
uint64_t __lr = 0; // Link register x30
|
||||||
uint64_t __sp; // Stack pointer x31
|
uint64_t __sp = 0; // Stack pointer x31
|
||||||
uint64_t __pc; // Program counter
|
uint64_t __pc = 0; // Program counter
|
||||||
uint64_t __ra_sign_state; // RA sign state register
|
uint64_t __ra_sign_state = 0; // RA sign state register
|
||||||
};
|
};
|
||||||
|
|
||||||
GPRs _registers;
|
struct Misc {
|
||||||
double _vectorHalfRegisters[32];
|
mutable uint32_t __vg = 0; // Vector Granule
|
||||||
|
bool __has_sme = checkHasSME();
|
||||||
|
};
|
||||||
|
|
||||||
|
GPRs _registers = {};
|
||||||
// Currently only the lower double in 128-bit vectore registers
|
// Currently only the lower double in 128-bit vectore registers
|
||||||
// is perserved during unwinding. We could define new register
|
// is perserved during unwinding. We could define new register
|
||||||
// numbers (> 96) which mean whole vector registers, then this
|
// numbers (> 96) which mean whole vector registers, then this
|
||||||
// struct would need to change to contain whole vector registers.
|
// 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) {
|
inline Registers_arm64::Registers_arm64(const void *registers) {
|
||||||
@@ -1877,11 +1997,31 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
|
|||||||
memcpy(_vectorHalfRegisters,
|
memcpy(_vectorHalfRegisters,
|
||||||
static_cast<const uint8_t *>(registers) + sizeof(GPRs),
|
static_cast<const uint8_t *>(registers) + sizeof(GPRs),
|
||||||
sizeof(_vectorHalfRegisters));
|
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() {
|
inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
|
||||||
memset(&_registers, 0, sizeof(_registers));
|
*this = other;
|
||||||
memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters));
|
}
|
||||||
|
|
||||||
|
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 {
|
inline bool Registers_arm64::validRegister(int regNum) const {
|
||||||
@@ -1895,22 +2035,40 @@ inline bool Registers_arm64::validRegister(int regNum) const {
|
|||||||
return false;
|
return false;
|
||||||
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
|
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
|
||||||
return true;
|
return true;
|
||||||
|
if (regNum == UNW_AARCH64_VG)
|
||||||
|
return true;
|
||||||
if ((regNum > 32) && (regNum < 64))
|
if ((regNum > 32) && (regNum < 64))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
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 {
|
inline uint64_t Registers_arm64::getRegister(int regNum) const {
|
||||||
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
|
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
|
||||||
return _registers.__pc;
|
return getIP();
|
||||||
if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
|
if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
|
||||||
return _registers.__sp;
|
return _registers.__sp;
|
||||||
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
|
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
|
||||||
return _registers.__ra_sign_state;
|
return _registers.__ra_sign_state;
|
||||||
if (regNum == UNW_AARCH64_FP)
|
if (regNum == UNW_AARCH64_FP)
|
||||||
return _registers.__fp;
|
return getFP();
|
||||||
if (regNum == UNW_AARCH64_LR)
|
if (regNum == UNW_AARCH64_LR)
|
||||||
return _registers.__lr;
|
return _registers.__lr;
|
||||||
|
if (regNum == UNW_AARCH64_VG)
|
||||||
|
return lazyGetVG();
|
||||||
if ((regNum >= 0) && (regNum < 29))
|
if ((regNum >= 0) && (regNum < 29))
|
||||||
return _registers.__x[regNum];
|
return _registers.__x[regNum];
|
||||||
_LIBUNWIND_ABORT("unsupported arm64 register");
|
_LIBUNWIND_ABORT("unsupported arm64 register");
|
||||||
@@ -1918,15 +2076,17 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const {
|
|||||||
|
|
||||||
inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
|
inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
|
||||||
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
|
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
|
||||||
_registers.__pc = value;
|
setIP(value);
|
||||||
else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
|
else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
|
||||||
_registers.__sp = value;
|
_registers.__sp = value;
|
||||||
else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
|
else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
|
||||||
_registers.__ra_sign_state = value;
|
_registers.__ra_sign_state = value;
|
||||||
else if (regNum == UNW_AARCH64_FP)
|
else if (regNum == UNW_AARCH64_FP)
|
||||||
_registers.__fp = value;
|
setFP(value);
|
||||||
else if (regNum == UNW_AARCH64_LR)
|
else if (regNum == UNW_AARCH64_LR)
|
||||||
_registers.__lr = value;
|
_registers.__lr = value;
|
||||||
|
else if (regNum == UNW_AARCH64_VG)
|
||||||
|
_misc_registers.__vg = value;
|
||||||
else if ((regNum >= 0) && (regNum < 29))
|
else if ((regNum >= 0) && (regNum < 29))
|
||||||
_registers.__x[regNum] = value;
|
_registers.__x[regNum] = value;
|
||||||
else
|
else
|
||||||
@@ -2116,6 +2276,10 @@ public:
|
|||||||
Registers_arm();
|
Registers_arm();
|
||||||
Registers_arm(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -2621,6 +2785,10 @@ public:
|
|||||||
Registers_or1k();
|
Registers_or1k();
|
||||||
Registers_or1k(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -2820,6 +2988,10 @@ public:
|
|||||||
Registers_mips_o32();
|
Registers_mips_o32();
|
||||||
Registers_mips_o32(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -3155,6 +3327,10 @@ public:
|
|||||||
Registers_mips_newabi();
|
Registers_mips_newabi();
|
||||||
Registers_mips_newabi(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
@@ -3458,6 +3634,10 @@ public:
|
|||||||
Registers_sparc();
|
Registers_sparc();
|
||||||
Registers_sparc(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -3644,6 +3824,10 @@ public:
|
|||||||
Registers_sparc64() = default;
|
Registers_sparc64() = default;
|
||||||
Registers_sparc64(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
@@ -3829,6 +4013,10 @@ public:
|
|||||||
Registers_hexagon();
|
Registers_hexagon();
|
||||||
Registers_hexagon(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint32_t getRegister(int num) const;
|
uint32_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint32_t value);
|
void setRegister(int num, uint32_t value);
|
||||||
@@ -4044,6 +4232,10 @@ public:
|
|||||||
Registers_riscv();
|
Registers_riscv();
|
||||||
Registers_riscv(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
reg_t getRegister(int num) const;
|
reg_t getRegister(int num) const;
|
||||||
void setRegister(int num, reg_t value);
|
void setRegister(int num, reg_t value);
|
||||||
@@ -4341,6 +4533,10 @@ public:
|
|||||||
Registers_ve();
|
Registers_ve();
|
||||||
Registers_ve(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
@@ -4784,6 +4980,10 @@ public:
|
|||||||
Registers_s390x();
|
Registers_s390x();
|
||||||
Registers_s390x(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
@@ -5072,6 +5272,10 @@ public:
|
|||||||
Registers_loongarch();
|
Registers_loongarch();
|
||||||
Registers_loongarch(const void *registers);
|
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;
|
bool validRegister(int num) const;
|
||||||
uint64_t getRegister(int num) const;
|
uint64_t getRegister(int num) const;
|
||||||
void setRegister(int num, uint64_t value);
|
void setRegister(int num, uint64_t value);
|
||||||
|
|||||||
Vendored
+6
-7
@@ -163,7 +163,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
|
|||||||
// If we were called by __libunwind_seh_personality(), indicate that
|
// If we were called by __libunwind_seh_personality(), indicate that
|
||||||
// a handler was found; otherwise, initiate phase 2 by unwinding.
|
// a handler was found; otherwise, initiate phase 2 by unwinding.
|
||||||
if (ours && ms_exc->NumberParameters > 1)
|
if (ours && ms_exc->NumberParameters > 1)
|
||||||
return 4 /* ExceptionExecuteHandler in mingw */;
|
return static_cast<EXCEPTION_DISPOSITION>(4);
|
||||||
// This should never happen in phase 2.
|
// This should never happen in phase 2.
|
||||||
if (IS_UNWINDING(ms_exc->ExceptionFlags))
|
if (IS_UNWINDING(ms_exc->ExceptionFlags))
|
||||||
_LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
|
_LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
|
||||||
@@ -182,7 +182,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
|
|||||||
// a handler was found; otherwise, it's time to initiate a collided
|
// a handler was found; otherwise, it's time to initiate a collided
|
||||||
// unwind to the target.
|
// unwind to the target.
|
||||||
if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
|
if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
|
||||||
return 4 /* ExceptionExecuteHandler in mingw */;
|
return static_cast<EXCEPTION_DISPOSITION>(4);
|
||||||
// This should never happen in phase 1.
|
// This should never happen in phase 1.
|
||||||
if (!IS_UNWINDING(ms_exc->ExceptionFlags))
|
if (!IS_UNWINDING(ms_exc->ExceptionFlags))
|
||||||
_LIBUNWIND_ABORT("Personality installed context during phase 1!");
|
_LIBUNWIND_ABORT("Personality installed context during phase 1!");
|
||||||
@@ -259,13 +259,12 @@ __libunwind_seh_personality(int version, _Unwind_Action state,
|
|||||||
(void *)disp_ctx->LanguageHandler, (void *)&ms_exc,
|
(void *)disp_ctx->LanguageHandler, (void *)&ms_exc,
|
||||||
(void *)disp_ctx->EstablisherFrame,
|
(void *)disp_ctx->EstablisherFrame,
|
||||||
(void *)disp_ctx->ContextRecord, (void *)disp_ctx);
|
(void *)disp_ctx->ContextRecord, (void *)disp_ctx);
|
||||||
EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc,
|
int ms_act = static_cast<int>(
|
||||||
(PVOID)disp_ctx->EstablisherFrame,
|
disp_ctx->LanguageHandler(&ms_exc, (PVOID)disp_ctx->EstablisherFrame,
|
||||||
disp_ctx->ContextRecord,
|
disp_ctx->ContextRecord, disp_ctx));
|
||||||
disp_ctx);
|
|
||||||
_LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() LanguageHandler "
|
_LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() LanguageHandler "
|
||||||
"returned %d",
|
"returned %d",
|
||||||
(int)ms_act);
|
ms_act);
|
||||||
switch (ms_act) {
|
switch (ms_act) {
|
||||||
case ExceptionContinueExecution: return _URC_END_OF_STACK;
|
case ExceptionContinueExecution: return _URC_END_OF_STACK;
|
||||||
case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND;
|
case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND;
|
||||||
|
|||||||
Vendored
+7
-7
@@ -37,13 +37,13 @@ struct _Unwind_LandingPadContext {
|
|||||||
// function
|
// function
|
||||||
thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
|
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
|
/// 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
|
/// calls the personality function for each frame it lands. On the other hand,
|
||||||
/// hand, WebAssembly stack unwinding process is performed by a VM, and the
|
/// WebAssembly stack unwinding process is performed by a VM, and the
|
||||||
/// personality function cannot be called from there. So the compiler inserts
|
/// personality function cannot be called from there. So the compiler inserts a
|
||||||
/// a call to this function in landing pads in the user code, which in turn
|
/// call to this function in landing pads in the user code, which in turn calls
|
||||||
/// calls the personality function.
|
/// the personality function.
|
||||||
_Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
|
_Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
|
||||||
struct _Unwind_Exception *exception_object =
|
struct _Unwind_Exception *exception_object =
|
||||||
(struct _Unwind_Exception *)exception_ptr;
|
(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.
|
/// Called by personality handler to get instruction pointer.
|
||||||
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
|
_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
|
// increment 2 here
|
||||||
uintptr_t result =
|
uintptr_t result =
|
||||||
((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;
|
((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;
|
||||||
|
|||||||
Vendored
+167
-49
@@ -41,7 +41,8 @@
|
|||||||
#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
|
#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
|
||||||
#endif
|
#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 <OS.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1
|
#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1
|
||||||
@@ -120,7 +121,9 @@ class _LIBUNWIND_HIDDEN DwarfFDECache {
|
|||||||
typedef typename A::pint_t pint_t;
|
typedef typename A::pint_t pint_t;
|
||||||
public:
|
public:
|
||||||
static constexpr pint_t kSearchAll = static_cast<pint_t>(-1);
|
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 add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
|
||||||
static void removeAllIn(pint_t mh);
|
static void removeAllIn(pint_t mh);
|
||||||
static void iterateCacheEntries(void (*func)(unw_word_t ip_start,
|
static void iterateCacheEntries(void (*func)(unw_word_t ip_start,
|
||||||
@@ -173,7 +176,9 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename A>
|
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;
|
pint_t result = 0;
|
||||||
_LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
|
_LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
|
||||||
for (entry *p = _buffer; p < _bufferUsed; ++p) {
|
for (entry *p = _buffer; p < _bufferUsed; ++p) {
|
||||||
@@ -471,7 +476,9 @@ public:
|
|||||||
virtual void getInfo(unw_proc_info_t *) {
|
virtual void getInfo(unw_proc_info_t *) {
|
||||||
_LIBUNWIND_ABORT("getInfo not implemented");
|
_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() {
|
virtual bool isSignalFrame() {
|
||||||
_LIBUNWIND_ABORT("isSignalFrame not implemented");
|
_LIBUNWIND_ABORT("isSignalFrame not implemented");
|
||||||
}
|
}
|
||||||
@@ -488,6 +495,12 @@ public:
|
|||||||
virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); }
|
virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _LIBUNWIND_TRACE_RET_INJECT
|
||||||
|
virtual void setWalkedFrames(unsigned) {
|
||||||
|
_LIBUNWIND_ABORT("setWalkedFrames not implemented");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _AIX
|
#ifdef _AIX
|
||||||
virtual uintptr_t getDataRelBase() {
|
virtual uintptr_t getDataRelBase() {
|
||||||
_LIBUNWIND_ABORT("getDataRelBase not implemented");
|
_LIBUNWIND_ABORT("getDataRelBase not implemented");
|
||||||
@@ -964,7 +977,8 @@ public:
|
|||||||
virtual void setFloatReg(int, unw_fpreg_t);
|
virtual void setFloatReg(int, unw_fpreg_t);
|
||||||
virtual int step(bool stage2 = false);
|
virtual int step(bool stage2 = false);
|
||||||
virtual void getInfo(unw_proc_info_t *);
|
virtual void getInfo(unw_proc_info_t *);
|
||||||
virtual void jumpto();
|
_LIBUNWIND_TRACE_NO_INLINE
|
||||||
|
virtual void jumpto();
|
||||||
virtual bool isSignalFrame();
|
virtual bool isSignalFrame();
|
||||||
virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off);
|
virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off);
|
||||||
virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false);
|
virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false);
|
||||||
@@ -973,6 +987,10 @@ public:
|
|||||||
virtual void saveVFPAsX();
|
virtual void saveVFPAsX();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _LIBUNWIND_TRACE_RET_INJECT
|
||||||
|
virtual void setWalkedFrames(unsigned);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _AIX
|
#ifdef _AIX
|
||||||
virtual uintptr_t getDataRelBase();
|
virtual uintptr_t getDataRelBase();
|
||||||
#endif
|
#endif
|
||||||
@@ -1045,19 +1063,28 @@ private:
|
|||||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
|
bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
|
||||||
const typename CFI_Parser<A>::CIE_Info &cieInfo,
|
const typename CFI_Parser<A>::CIE_Info &cieInfo,
|
||||||
pint_t pc, uintptr_t dso_base);
|
typename R::link_hardened_reg_arg_t pc,
|
||||||
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s,
|
uintptr_t dso_base);
|
||||||
uint32_t fdeSectionOffsetHint=0);
|
bool getInfoFromDwarfSection(typename R::link_hardened_reg_arg_t pc,
|
||||||
|
const UnwindInfoSections §s,
|
||||||
|
uint32_t fdeSectionOffsetHint = 0);
|
||||||
int stepWithDwarfFDE(bool stage2) {
|
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(
|
return DwarfInstructions<A, R>::stepWithDwarf(
|
||||||
_addressSpace, (pint_t)this->getReg(UNW_REG_IP),
|
_addressSpace, pc, (pint_t)_info.unwind_info, _registers,
|
||||||
(pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2);
|
_isSignalFrame, stage2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||||
bool getInfoFromCompactEncodingSection(pint_t pc,
|
bool getInfoFromCompactEncodingSection(typename R::link_hardened_reg_arg_t pc,
|
||||||
const UnwindInfoSections §s);
|
const UnwindInfoSections §s);
|
||||||
int stepWithCompactEncoding(bool stage2 = false) {
|
int stepWithCompactEncoding(bool stage2 = false) {
|
||||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
if ( compactSaysUseDwarf() )
|
if ( compactSaysUseDwarf() )
|
||||||
@@ -1344,9 +1371,12 @@ private:
|
|||||||
bool _unwindInfoMissing;
|
bool _unwindInfoMissing;
|
||||||
bool _isSignalFrame;
|
bool _isSignalFrame;
|
||||||
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
|
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \
|
||||||
defined(_LIBUNWIND_TARGET_HAIKU)
|
defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
|
||||||
bool _isSigReturn = false;
|
bool _isSigReturn = false;
|
||||||
#endif
|
#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");
|
"UnwindCursor<> does not fit in unw_cursor_t");
|
||||||
static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
|
static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
|
||||||
"UnwindCursor<> requires more alignment than 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>
|
template <typename A, typename R>
|
||||||
UnwindCursor<A, R>::UnwindCursor(A &as, void *)
|
UnwindCursor<A, R>::UnwindCursor(A &as, void *)
|
||||||
: _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
|
: _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
|
||||||
memset(&_info, 0, sizeof(_info));
|
memset(static_cast<void *>(&_info), 0, sizeof(_info));
|
||||||
// FIXME
|
// FIXME
|
||||||
// fill in _registers from thread arg
|
// 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() {
|
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();
|
_registers.jumpto();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __arm__
|
#ifdef __arm__
|
||||||
@@ -1410,6 +1479,13 @@ template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _LIBUNWIND_TRACE_RET_INJECT
|
||||||
|
template <typename A, typename R>
|
||||||
|
void UnwindCursor<A, R>::setWalkedFrames(unsigned walkedFrames) {
|
||||||
|
_walkedFrames = walkedFrames;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _AIX
|
#ifdef _AIX
|
||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
uintptr_t UnwindCursor<A, R>::getDataRelBase() {
|
uintptr_t UnwindCursor<A, R>::getDataRelBase() {
|
||||||
@@ -1658,11 +1734,11 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
|
|||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
bool UnwindCursor<A, R>::getInfoFromFdeCie(
|
bool UnwindCursor<A, R>::getInfoFromFdeCie(
|
||||||
const typename CFI_Parser<A>::FDE_Info &fdeInfo,
|
const typename CFI_Parser<A>::FDE_Info &fdeInfo,
|
||||||
const typename CFI_Parser<A>::CIE_Info &cieInfo, pint_t pc,
|
const typename CFI_Parser<A>::CIE_Info &cieInfo,
|
||||||
uintptr_t dso_base) {
|
typename R::link_hardened_reg_arg_t pc, uintptr_t dso_base) {
|
||||||
typename CFI_Parser<A>::PrologInfo prolog;
|
typename CFI_Parser<A>::PrologInfo prolog;
|
||||||
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
|
if (CFI_Parser<A>::template parseFDEInstructions<R>(
|
||||||
R::getArch(), &prolog)) {
|
_addressSpace, fdeInfo, cieInfo, pc, R::getArch(), &prolog)) {
|
||||||
// Save off parsed FDE info
|
// Save off parsed FDE info
|
||||||
_info.start_ip = fdeInfo.pcStart;
|
_info.start_ip = fdeInfo.pcStart;
|
||||||
_info.end_ip = fdeInfo.pcEnd;
|
_info.end_ip = fdeInfo.pcEnd;
|
||||||
@@ -1682,43 +1758,42 @@ bool UnwindCursor<A, R>::getInfoFromFdeCie(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
|
bool UnwindCursor<A, R>::getInfoFromDwarfSection(
|
||||||
const UnwindInfoSections §s,
|
typename R::link_hardened_reg_arg_t pc, const UnwindInfoSections §s,
|
||||||
uint32_t fdeSectionOffsetHint) {
|
uint32_t fdeSectionOffsetHint) {
|
||||||
typename CFI_Parser<A>::FDE_Info fdeInfo;
|
typename CFI_Parser<A>::FDE_Info fdeInfo;
|
||||||
typename CFI_Parser<A>::CIE_Info cieInfo;
|
typename CFI_Parser<A>::CIE_Info cieInfo;
|
||||||
bool foundFDE = false;
|
bool foundFDE = false;
|
||||||
bool foundInCache = false;
|
bool foundInCache = false;
|
||||||
// If compact encoding table gave offset into dwarf section, go directly there
|
// If compact encoding table gave offset into dwarf section, go directly there
|
||||||
if (fdeSectionOffsetHint != 0) {
|
if (fdeSectionOffsetHint != 0) {
|
||||||
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
foundFDE = CFI_Parser<A>::template findFDE<R>(
|
||||||
sects.dwarf_section_length,
|
_addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length,
|
||||||
sects.dwarf_section + fdeSectionOffsetHint,
|
sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo);
|
||||||
&fdeInfo, &cieInfo);
|
|
||||||
}
|
}
|
||||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
|
||||||
if (!foundFDE && (sects.dwarf_index_section != 0)) {
|
if (!foundFDE && (sects.dwarf_index_section != 0)) {
|
||||||
foundFDE = EHHeaderParser<A>::findFDE(
|
foundFDE = EHHeaderParser<A>::template findFDE<R>(
|
||||||
_addressSpace, pc, sects.dwarf_index_section,
|
_addressSpace, pc, sects.dwarf_index_section,
|
||||||
(uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo);
|
(uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!foundFDE) {
|
if (!foundFDE) {
|
||||||
// otherwise, search cache of previously found FDEs.
|
// 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) {
|
if (cachedFDE != 0) {
|
||||||
foundFDE =
|
foundFDE = CFI_Parser<A>::template findFDE<R>(
|
||||||
CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
_addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length,
|
||||||
sects.dwarf_section_length,
|
cachedFDE, &fdeInfo, &cieInfo);
|
||||||
cachedFDE, &fdeInfo, &cieInfo);
|
|
||||||
foundInCache = foundFDE;
|
foundInCache = foundFDE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundFDE) {
|
if (!foundFDE) {
|
||||||
// Still not found, do full scan of __eh_frame section.
|
// Still not found, do full scan of __eh_frame section.
|
||||||
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
|
foundFDE = CFI_Parser<A>::template findFDE<R>(
|
||||||
sects.dwarf_section_length, 0,
|
_addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length, 0,
|
||||||
&fdeInfo, &cieInfo);
|
&fdeInfo, &cieInfo);
|
||||||
}
|
}
|
||||||
if (foundFDE) {
|
if (foundFDE) {
|
||||||
if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) {
|
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)
|
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
|
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
|
||||||
const UnwindInfoSections §s) {
|
typename R::link_hardened_reg_arg_t pc, const UnwindInfoSections §s) {
|
||||||
const bool log = false;
|
const bool log = false;
|
||||||
if (log)
|
if (log)
|
||||||
fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n",
|
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));
|
personalityIndex * sizeof(uint32_t));
|
||||||
pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
|
pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
|
||||||
personality = _addressSpace.getP(personalityPointer);
|
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)
|
if (log)
|
||||||
fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
|
fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
|
||||||
"personalityDelta=0x%08X, personality=0x%08llX\n",
|
"personalityDelta=0x%08X, personality=0x%08llX\n",
|
||||||
@@ -1987,7 +2072,11 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
|
|||||||
_info.start_ip = funcStart;
|
_info.start_ip = funcStart;
|
||||||
_info.end_ip = funcEnd;
|
_info.end_ip = funcEnd;
|
||||||
_info.lsda = lsda;
|
_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.gp = 0;
|
||||||
_info.flags = 0;
|
_info.flags = 0;
|
||||||
_info.format = encoding;
|
_info.format = encoding;
|
||||||
@@ -2640,11 +2729,19 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
|||||||
_isSigReturn = false;
|
_isSigReturn = false;
|
||||||
#endif
|
#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)
|
#if defined(_LIBUNWIND_ARM_EHABI)
|
||||||
// Remove the thumb bit so the IP represents the actual instruction address.
|
// Remove the thumb bit so the IP represents the actual instruction address.
|
||||||
// This matches the behaviour of _Unwind_GetIP on arm.
|
// 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
|
#endif
|
||||||
|
|
||||||
// Exit early if at the top of the stack.
|
// 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.
|
// Ask address space object to find unwind sections for this pc.
|
||||||
UnwindInfoSections sects;
|
UnwindInfoSections sects;
|
||||||
if (_addressSpace.findUnwindSections(pc, sects)) {
|
if (_addressSpace.template findUnwindSections<R>(pc, sects)) {
|
||||||
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
|
||||||
// If there is a compact unwind encoding table, look there first.
|
// If there is a compact unwind encoding table, look there first.
|
||||||
if (sects.compact_unwind_section != 0) {
|
if (sects.compact_unwind_section != 0) {
|
||||||
@@ -2735,8 +2832,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
|
|||||||
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
|
||||||
// There is no static unwind info for this pc. Look to see if an FDE was
|
// There is no static unwind info for this pc. Look to see if an FDE was
|
||||||
// dynamically registered for it.
|
// dynamically registered for it.
|
||||||
pint_t cachedFDE = DwarfFDECache<A>::findFDE(DwarfFDECache<A>::kSearchAll,
|
pint_t cachedFDE =
|
||||||
pc);
|
DwarfFDECache<A>::template findFDE<R>(DwarfFDECache<A>::kSearchAll, pc);
|
||||||
if (cachedFDE != 0) {
|
if (cachedFDE != 0) {
|
||||||
typename CFI_Parser<A>::FDE_Info fdeInfo;
|
typename CFI_Parser<A>::FDE_Info fdeInfo;
|
||||||
typename CFI_Parser<A>::CIE_Info cieInfo;
|
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
|
// Lastly, ask AddressSpace object about platform specific ways to locate
|
||||||
// other FDEs.
|
// other FDEs.
|
||||||
pint_t fde;
|
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>::FDE_Info fdeInfo;
|
||||||
typename CFI_Parser<A>::CIE_Info cieInfo;
|
typename CFI_Parser<A>::CIE_Info cieInfo;
|
||||||
if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &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) && \
|
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \
|
||||||
defined(_LIBUNWIND_TARGET_AARCH64)
|
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>
|
template <typename A, typename R>
|
||||||
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
|
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
|
||||||
// Look for the sigreturn trampoline. The trampoline's body is two
|
// Look for the sigreturn trampoline. The trampoline's body is two
|
||||||
@@ -2796,7 +2908,7 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
|
|||||||
return false;
|
return false;
|
||||||
auto *instructions = reinterpret_cast<const uint32_t *>(pc);
|
auto *instructions = reinterpret_cast<const uint32_t *>(pc);
|
||||||
// Look for instructions: mov x8, #0x8b; svc #0x0
|
// 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;
|
return false;
|
||||||
|
|
||||||
_info = {};
|
_info = {};
|
||||||
@@ -3188,16 +3300,22 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
|
|||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
|
void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
|
||||||
if (_unwindInfoMissing)
|
if (_unwindInfoMissing)
|
||||||
memset(info, 0, sizeof(*info));
|
memset(static_cast<void *>(info), 0, sizeof(*info));
|
||||||
else
|
else
|
||||||
*info = _info;
|
*info = _info;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename A, typename R>
|
template <typename A, typename R>
|
||||||
bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
|
bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
|
||||||
unw_word_t *offset) {
|
unw_word_t *offset) {
|
||||||
return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
|
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
|
||||||
buf, bufLen, offset);
|
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)
|
#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
|
||||||
|
|||||||
Vendored
+46
-17
@@ -48,16 +48,15 @@
|
|||||||
// avoided when invoking the `jumpto()` function. To do this, we use inline
|
// avoided when invoking the `jumpto()` function. To do this, we use inline
|
||||||
// assemblies to "goto" the `jumpto()` for these architectures.
|
// assemblies to "goto" the `jumpto()` for these architectures.
|
||||||
#if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)
|
#if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)
|
||||||
#define __unw_phase2_resume(cursor, fn) \
|
#define __unw_phase2_resume(cursor, payload) \
|
||||||
do { \
|
do { \
|
||||||
(void)fn; \
|
__unw_resume_with_frames_walked((cursor), (payload)); \
|
||||||
__unw_resume((cursor)); \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
#elif defined(_LIBUNWIND_TARGET_I386)
|
#elif defined(_LIBUNWIND_TARGET_I386)
|
||||||
#define __shstk_step_size (4)
|
#define __shstk_step_size (4)
|
||||||
#define __unw_phase2_resume(cursor, fn) \
|
#define __unw_phase2_resume(cursor, payload) \
|
||||||
do { \
|
do { \
|
||||||
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
|
_LIBUNWIND_POP_SHSTK_SSP((payload)); \
|
||||||
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
|
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
|
||||||
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
|
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
|
||||||
__asm__ volatile("push %%edi\n\t" \
|
__asm__ volatile("push %%edi\n\t" \
|
||||||
@@ -67,9 +66,9 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
#elif defined(_LIBUNWIND_TARGET_X86_64)
|
#elif defined(_LIBUNWIND_TARGET_X86_64)
|
||||||
#define __shstk_step_size (8)
|
#define __shstk_step_size (8)
|
||||||
#define __unw_phase2_resume(cursor, fn) \
|
#define __unw_phase2_resume(cursor, payload) \
|
||||||
do { \
|
do { \
|
||||||
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
|
_LIBUNWIND_POP_SHSTK_SSP((payload)); \
|
||||||
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
|
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
|
||||||
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
|
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
|
||||||
__asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \
|
__asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \
|
||||||
@@ -77,19 +76,37 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
#elif defined(_LIBUNWIND_TARGET_AARCH64)
|
#elif defined(_LIBUNWIND_TARGET_AARCH64)
|
||||||
#define __shstk_step_size (8)
|
#define __shstk_step_size (8)
|
||||||
#define __unw_phase2_resume(cursor, fn) \
|
#define __unw_phase2_resume(cursor, payload) \
|
||||||
do { \
|
do { \
|
||||||
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
|
_LIBUNWIND_POP_SHSTK_SSP((payload)); \
|
||||||
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
|
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
|
||||||
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
|
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
|
||||||
__asm__ volatile("mov x0, %0\n\t" \
|
__asm__ volatile("mov x0, %0\n\t" \
|
||||||
|
"mov x1, #0\n\t" \
|
||||||
"br %1\n\t" \
|
"br %1\n\t" \
|
||||||
: \
|
: \
|
||||||
: "r"(shstkRegContext), "r"(shstkJumpAddress) \
|
: "r"(shstkRegContext), "r"(shstkJumpAddress) \
|
||||||
: "x0"); \
|
: "x0", "x1"); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#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
|
static _Unwind_Reason_Code
|
||||||
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||||
__unw_init_local(cursor, uc);
|
__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
|
// If there is a personality routine, ask it if it will want to stop at
|
||||||
// this frame.
|
// this frame.
|
||||||
if (frameInfo.handler != 0) {
|
if (frameInfo.handler != 0) {
|
||||||
_Unwind_Personality_Fn p =
|
_Unwind_Personality_Fn p = get_handler_function(&frameInfo);
|
||||||
(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
|
|
||||||
_LIBUNWIND_TRACE_UNWINDING(
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
"unwind_phase1(ex_obj=%p): calling personality function %p",
|
"unwind_phase1(ex_obj=%p): calling personality function %p",
|
||||||
(void *)exception_object, (void *)(uintptr_t)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;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
extern int __unw_step_stage2(unw_cursor_t *);
|
|
||||||
|
|
||||||
#if defined(_LIBUNWIND_USE_GCS)
|
#if defined(_LIBUNWIND_USE_GCS)
|
||||||
// Enable the GCS target feature to permit gcspop instructions to be used.
|
// Enable the GCS target feature to permit gcspop instructions to be used.
|
||||||
__attribute__((target("+gcs")))
|
__attribute__((target("+gcs")))
|
||||||
|
#else
|
||||||
|
_LIBUNWIND_TRACE_NO_INLINE
|
||||||
#endif
|
#endif
|
||||||
static _Unwind_Reason_Code
|
static _Unwind_Reason_Code
|
||||||
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
|
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;
|
++framesWalked;
|
||||||
// If there is a personality routine, tell it we are unwinding.
|
// If there is a personality routine, tell it we are unwinding.
|
||||||
if (frameInfo.handler != 0) {
|
if (frameInfo.handler != 0) {
|
||||||
_Unwind_Personality_Fn p =
|
_Unwind_Personality_Fn p = get_handler_function(&frameInfo);
|
||||||
(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
|
|
||||||
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
_Unwind_Action action = _UA_CLEANUP_PHASE;
|
||||||
if (sp == exception_object->private_2) {
|
if (sp == exception_object->private_2) {
|
||||||
// Tell personality this was the frame it marked in phase 1.
|
// 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)
|
#if defined(_LIBUNWIND_USE_GCS)
|
||||||
// Enable the GCS target feature to permit gcspop instructions to be used.
|
// Enable the GCS target feature to permit gcspop instructions to be used.
|
||||||
__attribute__((target("+gcs")))
|
__attribute__((target("+gcs")))
|
||||||
|
#else
|
||||||
|
_LIBUNWIND_TRACE_NO_INLINE
|
||||||
#endif
|
#endif
|
||||||
static _Unwind_Reason_Code
|
static _Unwind_Reason_Code
|
||||||
unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
|
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;
|
++framesWalked;
|
||||||
// If there is a personality routine, tell it we are unwinding.
|
// If there is a personality routine, tell it we are unwinding.
|
||||||
if (frameInfo.handler != 0) {
|
if (frameInfo.handler != 0) {
|
||||||
_Unwind_Personality_Fn p =
|
_Unwind_Personality_Fn p = get_handler_function(&frameInfo);
|
||||||
(_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
|
|
||||||
_LIBUNWIND_TRACE_UNWINDING(
|
_LIBUNWIND_TRACE_UNWINDING(
|
||||||
"unwind_phase2_forced(ex_obj=%p): calling personality function %p",
|
"unwind_phase2_forced(ex_obj=%p): calling personality function %p",
|
||||||
(void *)exception_object, (void *)(uintptr_t)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_cursor_t *cursor = (unw_cursor_t *)context;
|
||||||
unw_word_t result;
|
unw_word_t result;
|
||||||
__unw_get_reg(cursor, UNW_REG_IP, &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,
|
_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
|
||||||
(void *)context, result);
|
(void *)context, result);
|
||||||
return (uintptr_t)result;
|
return (uintptr_t)result;
|
||||||
|
|||||||
+46
-5
@@ -6,6 +6,8 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if !defined(__wasm__)
|
||||||
|
|
||||||
#include "assembly.h"
|
#include "assembly.h"
|
||||||
|
|
||||||
#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
|
#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)
|
#if defined(_AIX)
|
||||||
.toc
|
.toc
|
||||||
|
#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE)
|
||||||
|
.section .text,"axy",@progbits,unique,0
|
||||||
#else
|
#else
|
||||||
.text
|
.text
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)
|
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
.att_syntax
|
||||||
|
|
||||||
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
|
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
|
||||||
#
|
#
|
||||||
# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
|
# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
|
||||||
@@ -67,6 +73,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
|
|||||||
# skip gs
|
# skip gs
|
||||||
|
|
||||||
#elif defined(__x86_64__) && !defined(__arm64ec__)
|
#elif defined(__x86_64__) && !defined(__arm64ec__)
|
||||||
|
.att_syntax
|
||||||
|
|
||||||
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
|
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
|
||||||
#
|
#
|
||||||
@@ -629,18 +636,35 @@ Lnovec:
|
|||||||
|
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
|
|
||||||
|
#ifndef __has_feature
|
||||||
|
#define __has_feature(__feature) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__ARM_FEATURE_GCS_DEFAULT)
|
#if defined(__ARM_FEATURE_GCS_DEFAULT)
|
||||||
.arch_extension gcs
|
.arch_extension gcs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
|
// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *, unsigned);
|
||||||
//
|
//
|
||||||
// On entry:
|
// On entry:
|
||||||
// thread_state pointer is in x0
|
// thread_state pointer is in x0
|
||||||
|
// walked_frames counter is in x1
|
||||||
//
|
//
|
||||||
.p2align 2
|
.p2align 2
|
||||||
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
|
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
|
// skip restore of x0,x1 for now
|
||||||
ldp x2, x3, [x0, #0x010]
|
ldp x2, x3, [x0, #0x010]
|
||||||
ldp x4, x5, [x0, #0x020]
|
ldp x4, x5, [x0, #0x020]
|
||||||
@@ -657,7 +681,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
|
|||||||
ldp x24,x25, [x0, #0x0C0]
|
ldp x24,x25, [x0, #0x0C0]
|
||||||
ldp x26,x27, [x0, #0x0D0]
|
ldp x26,x27, [x0, #0x0D0]
|
||||||
ldp x28,x29, [x0, #0x0E0]
|
ldp x28,x29, [x0, #0x0E0]
|
||||||
ldr x30, [x0, #0x100] // restore pc into lr
|
|
||||||
#if defined(__ARM_FP) && __ARM_FP != 0
|
#if defined(__ARM_FP) && __ARM_FP != 0
|
||||||
ldp d0, d1, [x0, #0x110]
|
ldp d0, d1, [x0, #0x110]
|
||||||
ldp d2, d3, [x0, #0x120]
|
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
|
// 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
|
// could clobber the de-allocated portion of the stack after sp has been
|
||||||
// restored.
|
// 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
|
ldp x0, x1, [x0, #0x000] // restore x0,x1
|
||||||
mov sp,x16 // restore sp
|
mov sp,x16 // restore sp
|
||||||
#if defined(__ARM_FEATURE_GCS_DEFAULT)
|
#if defined(__ARM_FEATURE_GCS_DEFAULT)
|
||||||
@@ -694,7 +729,12 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
|
|||||||
gcspushm x30
|
gcspushm x30
|
||||||
Lnogcs:
|
Lnogcs:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_feature(ptrauth_calls)
|
||||||
|
retab
|
||||||
|
#else
|
||||||
ret x30 // jump to pc
|
ret x30 // jump to pc
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif defined(__arm__) && !defined(__APPLE__)
|
#elif defined(__arm__) && !defined(__APPLE__)
|
||||||
|
|
||||||
@@ -1253,7 +1293,8 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */
|
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
|
||||||
|
|
||||||
NO_EXEC_STACK_DIRECTIVE
|
NO_EXEC_STACK_DIRECTIVE
|
||||||
|
|
||||||
|
#endif /* !defined(__wasm__) */
|
||||||
|
|||||||
+86
-2
@@ -6,6 +6,8 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if !defined(__wasm__)
|
||||||
|
|
||||||
#include "assembly.h"
|
#include "assembly.h"
|
||||||
|
|
||||||
#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
|
#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)
|
#if defined(_AIX)
|
||||||
.toc
|
.toc
|
||||||
|
#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE)
|
||||||
|
.section .text,"axy",@progbits,unique,0
|
||||||
#else
|
#else
|
||||||
.text
|
.text
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)
|
#if !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
.att_syntax
|
||||||
|
|
||||||
#
|
#
|
||||||
# extern int __unw_getcontext(unw_context_t* thread_state)
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
@@ -107,6 +112,7 @@ DEFINE_LIBUNWIND_FUNCTION("#__unw_getcontext")
|
|||||||
.text
|
.text
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
|
.att_syntax
|
||||||
|
|
||||||
#
|
#
|
||||||
# extern int __unw_getcontext(unw_context_t* thread_state)
|
# extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
@@ -759,6 +765,10 @@ LnoR2Fix:
|
|||||||
|
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
|
|
||||||
|
#ifndef __has_feature
|
||||||
|
#define __has_feature(__feature) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// extern int __unw_getcontext(unw_context_t* thread_state)
|
// extern int __unw_getcontext(unw_context_t* thread_state)
|
||||||
//
|
//
|
||||||
@@ -767,6 +777,11 @@ LnoR2Fix:
|
|||||||
//
|
//
|
||||||
.p2align 2
|
.p2align 2
|
||||||
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
||||||
|
|
||||||
|
#if __has_feature(ptrauth_calls)
|
||||||
|
pacibsp
|
||||||
|
#endif
|
||||||
|
|
||||||
stp x0, x1, [x0, #0x000]
|
stp x0, x1, [x0, #0x000]
|
||||||
stp x2, x3, [x0, #0x010]
|
stp x2, x3, [x0, #0x010]
|
||||||
stp x4, x5, [x0, #0x020]
|
stp x4, x5, [x0, #0x020]
|
||||||
@@ -807,7 +822,74 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
|||||||
str d31, [x0, #0x208]
|
str d31, [x0, #0x208]
|
||||||
#endif
|
#endif
|
||||||
mov x0, #0 // return UNW_ESUCCESS
|
mov x0, #0 // return UNW_ESUCCESS
|
||||||
|
|
||||||
|
#if __has_feature(ptrauth_calls)
|
||||||
|
retab
|
||||||
|
#else
|
||||||
ret
|
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__)
|
#elif defined(__arm__) && !defined(__APPLE__)
|
||||||
|
|
||||||
@@ -1232,6 +1314,8 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
|||||||
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
|
WEAK_ALIAS(__unw_getcontext, unw_getcontext)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */
|
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
|
||||||
|
|
||||||
NO_EXEC_STACK_DIRECTIVE
|
NO_EXEC_STACK_DIRECTIVE
|
||||||
|
|
||||||
|
#endif /* !defined(__wasm__) */
|
||||||
|
|||||||
Vendored
+5
-1
@@ -15,7 +15,7 @@
|
|||||||
#ifndef UNWIND_ASSEMBLY_H
|
#ifndef UNWIND_ASSEMBLY_H
|
||||||
#define UNWIND_ASSEMBLY_H
|
#define UNWIND_ASSEMBLY_H
|
||||||
|
|
||||||
#if defined(__linux__) && defined(__CET__)
|
#if defined(__CET__)
|
||||||
#include <cet.h>
|
#include <cet.h>
|
||||||
#define _LIBUNWIND_CET_ENDBR _CET_ENDBR
|
#define _LIBUNWIND_CET_ENDBR _CET_ENDBR
|
||||||
#else
|
#else
|
||||||
@@ -132,6 +132,10 @@
|
|||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
|
#if defined(__aarch64__) || defined(__arm64__) || defined(__arm64e__)
|
||||||
|
#define _LIBUNWIND_TRACE_RET_INJECT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SYMBOL_IS_FUNC(name)
|
#define SYMBOL_IS_FUNC(name)
|
||||||
#define HIDDEN_SYMBOL(name) .private_extern name
|
#define HIDDEN_SYMBOL(name) .private_extern name
|
||||||
#if defined(_LIBUNWIND_HIDE_SYMBOLS)
|
#if defined(_LIBUNWIND_HIDE_SYMBOLS)
|
||||||
|
|||||||
Vendored
+9
@@ -28,6 +28,9 @@
|
|||||||
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
|
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
|
||||||
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__aarch64__) || defined(__arm64__) || defined(__arm64e__)
|
||||||
|
#define _LIBUNWIND_TRACE_RET_INJECT 1
|
||||||
|
#endif
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#ifdef __SEH__
|
#ifdef __SEH__
|
||||||
#define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
|
#define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
|
||||||
@@ -61,6 +64,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#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)
|
#if defined(_LIBUNWIND_HIDE_SYMBOLS)
|
||||||
// The CMake file passes -fvisibility=hidden to control ELF/Mach-O visibility.
|
// The CMake file passes -fvisibility=hidden to control ELF/Mach-O visibility.
|
||||||
#define _LIBUNWIND_EXPORT
|
#define _LIBUNWIND_EXPORT
|
||||||
|
|||||||
+79
-6
@@ -31,6 +31,58 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
|
|||||||
_Unwind_Personality_Fn);
|
_Unwind_Personality_Fn);
|
||||||
#endif
|
#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:
|
// Pointer encodings documented at:
|
||||||
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
|
// 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);
|
return continueUnwind(exceptionObject, context);
|
||||||
|
|
||||||
uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
|
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;
|
uintptr_t pcOffset = pc - funcStart;
|
||||||
|
|
||||||
// Parse LSDA header.
|
// 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 *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
|
||||||
const uint8_t *p = callSiteTableStart;
|
const uint8_t *p = callSiteTableStart;
|
||||||
while (p < callSiteTableEnd) {
|
while (p < callSiteTableEnd) {
|
||||||
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
|
uintptr_t __ptrauth_gcc_personality_start start =
|
||||||
size_t length = readEncodedPointer(&p, callSiteEncoding);
|
readEncodedPointer(&p, callSiteEncoding);
|
||||||
size_t landingPad = 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
|
readULEB128(&p); // action value not used for C code
|
||||||
if (landingPad == 0)
|
if (landingPadOffset == 0)
|
||||||
continue; // no landing pad for this entry
|
continue; // no landing pad for this entry
|
||||||
if ((start <= pcOffset) && (pcOffset < (start + length))) {
|
if ((start <= pcOffset) && (pcOffset < (start + length))) {
|
||||||
// Found landing pad for the PC.
|
// 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),
|
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
|
||||||
(uintptr_t)exceptionObject);
|
(uintptr_t)exceptionObject);
|
||||||
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
|
_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;
|
return _URC_INSTALL_CONTEXT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+104
-4
@@ -118,14 +118,55 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
|
|||||||
typedef LocalAddressSpace::pint_t pint_t;
|
typedef LocalAddressSpace::pint_t pint_t;
|
||||||
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||||
if (co->validReg(regNum)) {
|
if (co->validReg(regNum)) {
|
||||||
co->setReg(regNum, (pint_t)value);
|
|
||||||
// special case altering IP to re-find info (being called by personality
|
// special case altering IP to re-find info (being called by personality
|
||||||
// function)
|
// function)
|
||||||
if (regNum == UNW_REG_IP) {
|
if (regNum == UNW_REG_IP) {
|
||||||
unw_proc_info_t info;
|
unw_proc_info_t info;
|
||||||
// First, get the FDE for the old location and then update it.
|
// First, get the FDE for the old location and then update it.
|
||||||
co->getInfo(&info);
|
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.
|
// If the original call expects stack adjustment, perform this now.
|
||||||
// Normal frame unwinding would have included the offset already in the
|
// Normal frame unwinding would have included the offset already in the
|
||||||
// CFA computation.
|
// 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
|
// this should actually be - info.gp. LLVM doesn't currently support
|
||||||
// any such platforms and Clang doesn't export a macro for them.
|
// any such platforms and Clang doesn't export a macro for them.
|
||||||
if (info.gp)
|
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;
|
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)
|
_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_HIDDEN int __unw_resume(unw_cursor_t *cursor) {
|
||||||
_LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor));
|
_LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor));
|
||||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
#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)
|
#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__)
|
#endif // !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|||||||
Vendored
+7
-1
@@ -26,11 +26,16 @@ extern "C" {
|
|||||||
extern int __unw_getcontext(unw_context_t *);
|
extern int __unw_getcontext(unw_context_t *);
|
||||||
extern int __unw_init_local(unw_cursor_t *, 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(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_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_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_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_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__
|
#ifdef __arm__
|
||||||
/* Save VFP registers in FSTMX format (instead of FSTMD). */
|
/* 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_fpreg(unw_cursor_t *, unw_regnum_t);
|
||||||
extern int __unw_is_signal_frame(unw_cursor_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 int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);
|
||||||
|
extern const char *__unw_strerror(int);
|
||||||
|
|
||||||
#if defined(_AIX)
|
#if defined(_AIX)
|
||||||
extern uintptr_t __unw_get_data_rel_base(unw_cursor_t *);
|
extern uintptr_t __unw_get_data_rel_base(unw_cursor_t *);
|
||||||
|
|||||||
+2
-2
@@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#include "libunwind.h"
|
#include "libunwind.h"
|
||||||
|
|
||||||
// Currently, CET is implemented on Linux x86 platforms.
|
// Currently, CET is implemented on some ELF x86 platforms.
|
||||||
#if defined(_LIBUNWIND_TARGET_LINUX) && defined(__CET__) && defined(__SHSTK__)
|
#if defined(__CET__) && defined(__SHSTK__)
|
||||||
#define _LIBUNWIND_USE_CET 1
|
#define _LIBUNWIND_USE_CET 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user