diff --git a/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp b/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp index 8ead6c24ba94df..b1e51f8cad6782 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp @@ -536,6 +536,8 @@ void Registers_REGDISPLAY::setFloatRegister(int num, unw_fpreg_t value) // Shim that implements methods required by libunwind over REGDISPLAY struct Registers_REGDISPLAY : REGDISPLAY { + typedef uint64_t reg_t; + inline static int getArch() { return libunwind::REGISTERS_ARM64; } static constexpr int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } diff --git a/src/native/external/llvm-libunwind-version.txt b/src/native/external/llvm-libunwind-version.txt index 118dfa206d0323..fcbda3180e207a 100644 --- a/src/native/external/llvm-libunwind-version.txt +++ b/src/native/external/llvm-libunwind-version.txt @@ -1,4 +1,4 @@ -v20.1.0 -https://github.com/llvm/llvm-project/releases/tag/llvmorg-20.1.0 +v22.1.1 +https://github.com/llvm/llvm-project/releases/tag/llvmorg-22.1.1 -Apply https://github.com/dotnet/runtime/commit/d03d1ba7835fdf9e2a6bb537d49fb5ff6584697b +Apply https://github.com/dotnet/runtime/commit/35b7d59fa1075ab0fefb921393409806a821d8ed diff --git a/src/native/external/llvm-libunwind/CMakeLists.txt b/src/native/external/llvm-libunwind/CMakeLists.txt index 3c8499fd334649..fbef71f3f74467 100644 --- a/src/native/external/llvm-libunwind/CMakeLists.txt +++ b/src/native/external/llvm-libunwind/CMakeLists.txt @@ -145,6 +145,7 @@ if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) if(LIBUNWIND_LIBDIR_SUBDIR) string(APPEND LIBUNWIND_TARGET_SUBDIR /${LIBUNWIND_LIBDIR_SUBDIR}) endif() + cmake_path(NORMAL_PATH LIBUNWIND_TARGET_SUBDIR) set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LIBUNWIND_TARGET_SUBDIR}) set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LIBUNWIND_TARGET_SUBDIR} CACHE STRING "Path where built libunwind libraries should be installed.") @@ -181,6 +182,8 @@ include(HandleLibunwindFlags) # Configure compiler. include(config-ix) +include(HandleLibC) # Setup the C library flags + if (LIBUNWIND_USE_COMPILER_RT AND NOT LIBUNWIND_HAS_NODEFAULTLIBS_FLAG) list(APPEND LIBUNWIND_LINK_FLAGS "-rtlib=compiler-rt") endif() @@ -329,6 +332,13 @@ if (C_SUPPORTS_COMMENT_LIB_PRAGMA) endif() endif() +if (RUNTIMES_EXECUTE_ONLY_CODE) + add_compile_definitions(_LIBUNWIND_EXECUTE_ONLY_CODE) +endif() + +add_custom_target(unwind-test-depends + COMMENT "Build dependencies required to run the libunwind test suite.") + #=============================================================================== # Setup Source Code #=============================================================================== diff --git a/src/native/external/llvm-libunwind/cmake/config-ix.cmake b/src/native/external/llvm-libunwind/cmake/config-ix.cmake index 126c872f0d4895..d42ceffb1f631e 100644 --- a/src/native/external/llvm-libunwind/cmake/config-ix.cmake +++ b/src/native/external/llvm-libunwind/cmake/config-ix.cmake @@ -26,62 +26,6 @@ if (NOT LIBUNWIND_USE_COMPILER_RT) endif () endif() -# libunwind is using -nostdlib++ at the link step when available, -# otherwise -nodefaultlibs is used. We want all our checks to also -# use one of these options, otherwise we may end up with an inconsistency between -# the flags we think we require during configuration (if the checks are -# performed without one of those options) and the flags that are actually -# required during compilation (which has the -nostdlib++ or -nodefaultlibs). libc is -# required for the link to go through. We remove sanitizers from the -# configuration checks to avoid spurious link errors. - -llvm_check_compiler_linker_flag(CXX "-nostdlib++" CXX_SUPPORTS_NOSTDLIBXX_FLAG) -if (CXX_SUPPORTS_NOSTDLIBXX_FLAG) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdlib++") -else() - llvm_check_compiler_linker_flag(C "-nodefaultlibs" C_SUPPORTS_NODEFAULTLIBS_FLAG) - if (C_SUPPORTS_NODEFAULTLIBS_FLAG) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") - endif() -endif() - -# Only link against compiler-rt manually if we use -nodefaultlibs, since -# otherwise the compiler will do the right thing on its own. -if (NOT CXX_SUPPORTS_NOSTDLIBXX_FLAG AND C_SUPPORTS_NODEFAULTLIBS_FLAG) - if (LIBUNWIND_HAS_C_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES c) - endif () - if (LIBUNWIND_HAS_ROOT_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES root) - endif () - if (LIBUNWIND_USE_COMPILER_RT) - include(HandleCompilerRT) - find_compiler_rt_library(builtins LIBUNWIND_BUILTINS_LIBRARY - FLAGS ${LIBUNWIND_COMPILE_FLAGS}) - list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBUNWIND_BUILTINS_LIBRARY}") - else () - if (LIBUNWIND_HAS_GCC_S_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) - endif () - if (LIBUNWIND_HAS_GCC_LIB) - list(APPEND CMAKE_REQUIRED_LIBRARIES gcc) - endif () - endif () - if (MINGW) - # Mingw64 requires quite a few "C" runtime libraries in order for basic - # programs to link successfully with -nodefaultlibs. - if (LIBUNWIND_USE_COMPILER_RT) - set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY}) - else () - set(MINGW_RUNTIME gcc_s gcc) - endif() - set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 - shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} - moldname mingwex msvcrt) - list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) - endif() -endif() - if (CXX_SUPPORTS_NOSTDLIBXX_FLAG OR C_SUPPORTS_NODEFAULTLIBS_FLAG) if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") diff --git a/src/native/external/llvm-libunwind/docs/BuildingLibunwind.rst b/src/native/external/llvm-libunwind/docs/BuildingLibunwind.rst index 8b4f1207d4ba99..c231587fd50224 100644 --- a/src/native/external/llvm-libunwind/docs/BuildingLibunwind.rst +++ b/src/native/external/llvm-libunwind/docs/BuildingLibunwind.rst @@ -91,7 +91,7 @@ libunwind specific options .. option:: LIBUNWIND_ENABLE_WERROR:BOOL - **Default**: ``ON`` + **Default**: ``OFF`` Compile with -Werror diff --git a/src/native/external/llvm-libunwind/include/CMakeLists.txt b/src/native/external/llvm-libunwind/include/CMakeLists.txt index 6796d67a3354ff..eefd4305d06cc1 100644 --- a/src/native/external/llvm-libunwind/include/CMakeLists.txt +++ b/src/native/external/llvm-libunwind/include/CMakeLists.txt @@ -21,12 +21,10 @@ if(LIBUNWIND_INSTALL_HEADERS) ) endforeach() - if(NOT CMAKE_CONFIGURATION_TYPES) + if (NOT CMAKE_CONFIGURATION_TYPES) add_custom_target(install-unwind-headers DEPENDS unwind-headers - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=unwind-headers - -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") + COMMAND "${CMAKE_COMMAND}" --install "${CMAKE_BINARY_DIR}" --component unwind-headers) add_custom_target(install-unwind-headers-stripped DEPENDS install-unwind-headers) endif() endif() diff --git a/src/native/external/llvm-libunwind/include/__libunwind_config.h b/src/native/external/llvm-libunwind/include/__libunwind_config.h index ec56ded7e2882f..1210771f4182ab 100644 --- a/src/native/external/llvm-libunwind/include/__libunwind_config.h +++ b/src/native/external/llvm-libunwind/include/__libunwind_config.h @@ -42,7 +42,7 @@ # if defined(__i386__) # define _LIBUNWIND_TARGET_I386 # define _LIBUNWIND_CONTEXT_SIZE 13 -# define _LIBUNWIND_CURSOR_SIZE 20 +# define _LIBUNWIND_CURSOR_SIZE 19 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 # elif defined(__x86_64__) # define _LIBUNWIND_TARGET_X86_64 1 @@ -178,13 +178,17 @@ #if __loongarch_grlen == 64 #define _LIBUNWIND_CONTEXT_SIZE 98 #define _LIBUNWIND_CURSOR_SIZE 110 +#elif defined(HOST_WASM) +#define _LIBUNWIND_TARGET_WASM 1 +// TODO: Determine the right values +#define _LIBUNWIND_CONTEXT_SIZE 0xbadf00d +#define _LIBUNWIND_CURSOR_SIZE 0xbadf00d #else #error "Unsupported LoongArch ABI" #endif #define _LIBUNWIND_HIGHEST_DWARF_REGISTER \ _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH #elif defined(__wasm__) -#define _LIBUNWIND_TARGET_WASM 1 // Unused #define _LIBUNWIND_CONTEXT_SIZE 0 #define _LIBUNWIND_CURSOR_SIZE 0 @@ -213,4 +217,13 @@ # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 #endif // _LIBUNWIND_IS_NATIVE_ONLY +#if defined(__has_feature) +# if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns) +# define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1 +# elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns) +# error "Either both or none of ptrauth_calls and ptrauth_returns "\ + "is allowed to be enabled" +# endif +#endif + #endif // ____LIBUNWIND_CONFIG_H__ diff --git a/src/native/external/llvm-libunwind/include/libunwind.h b/src/native/external/llvm-libunwind/include/libunwind.h index 7a8fcbcb26745a..6084196e04bea0 100644 --- a/src/native/external/llvm-libunwind/include/libunwind.h +++ b/src/native/external/llvm-libunwind/include/libunwind.h @@ -43,6 +43,109 @@ #define LIBUNWIND_AVAIL #endif +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + + #include + + // `__ptrauth_restricted_intptr` is a feature of apple clang that predates + // support for direct application of `__ptrauth` to integer types. This + // guard is necessary to support compilation with those compiler. + #if __has_extension(ptrauth_restricted_intptr_qualifier) + #define __unwind_ptrauth_restricted_intptr(...) \ + __ptrauth_restricted_intptr(__VA_ARGS__) + #else + #define __unwind_ptrauth_restricted_intptr(...) \ + __ptrauth(__VA_ARGS__) + #endif + + // ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405 + #define __ptrauth_unwind_upi_handler_disc 0x7405 + + #define __ptrauth_unwind_upi_handler \ + __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc) + + #define __ptrauth_unwind_upi_handler_intptr \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,\ + __ptrauth_unwind_upi_handler_disc) + + // ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C + #define __ptrauth_unwind_upi_startip \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C) + + // ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183 + #define __ptrauth_unwind_upi_endip \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183) + + // ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE + #define __ptrauth_unwind_upi_lsda \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE) + + // ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1 + #define __ptrauth_unwind_upi_flags \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1) + + // ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C + #define __ptrauth_unwind_upi_info \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C) + + // ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF + #define __ptrauth_unwind_upi_extra \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF) + + // ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301 + #define __ptrauth_unwind_registers_arm64_link_reg \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301) + + // ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5 + #define __ptrauth_unwind_uis_dso_base \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5) + + // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974 + #define __ptrauth_unwind_uis_dwarf_section \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974) + + // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A + #define __ptrauth_unwind_uis_dwarf_section_length \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A) + + // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B + #define __ptrauth_unwind_uis_compact_unwind_section \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B) + + // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A + #define __ptrauth_unwind_uis_compact_unwind_section_length \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A) + + // ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40 + #define __ptrauth_unwind_cie_info_personality_disc 0x6A40 + #define __ptrauth_unwind_cie_info_personality \ + __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \ + __ptrauth_unwind_cie_info_personality_disc) + + // ptrauth_string_discriminator("personality") == 0x7EAD) + #define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD + +#else + + #define __unwind_ptrauth_restricted_intptr(...) + #define __ptrauth_unwind_upi_handler + #define __ptrauth_unwind_upi_handler_intptr + #define __ptrauth_unwind_upi_startip + #define __ptrauth_unwind_upi_endip + #define __ptrauth_unwind_upi_lsda + #define __ptrauth_unwind_upi_flags + #define __ptrauth_unwind_upi_info + #define __ptrauth_unwind_upi_extra + #define __ptrauth_unwind_registers_arm64_link_reg + #define __ptrauth_unwind_uis_dso_base + #define __ptrauth_unwind_uis_dwarf_section + #define __ptrauth_unwind_uis_dwarf_section_length + #define __ptrauth_unwind_uis_compact_unwind_section + #define __ptrauth_unwind_uis_compact_unwind_section_length + #define __ptrauth_unwind_cie_info_personality + +#endif + #if defined(_WIN32) && defined(__SEH__) #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16))) #else @@ -88,17 +191,18 @@ typedef double unw_fpreg_t; #endif struct unw_proc_info_t { - unw_word_t start_ip; /* start address of function */ - unw_word_t end_ip; /* address after end of function */ - unw_word_t lsda; /* address of language specific data area, */ - /* or zero if not used */ - unw_word_t handler; /* personality routine, or zero if not used */ - unw_word_t gp; /* not used */ - unw_word_t flags; /* not used */ - uint32_t format; /* compact unwind encoding, or zero if none */ - uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */ - unw_word_t unwind_info; /* address of DWARF unwind info, or zero */ - unw_word_t extra; /* mach_header of mach-o image containing func */ + unw_word_t __ptrauth_unwind_upi_startip start_ip; /* start address of function */ + unw_word_t __ptrauth_unwind_upi_endip end_ip; /* address after end of function */ + unw_word_t __ptrauth_unwind_upi_lsda lsda; /* address of language specific data area, */ + /* or zero if not used */ + + unw_word_t __ptrauth_unwind_upi_handler_intptr handler; + unw_word_t gp; /* not used */ + unw_word_t __ptrauth_unwind_upi_flags flags; /* not used */ + uint32_t format; /* compact unwind encoding, or zero if none */ + uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */ + unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */ + unw_word_t __ptrauth_unwind_upi_extra extra; /* mach_header of mach-o image containing func */ }; typedef struct unw_proc_info_t unw_proc_info_t; @@ -150,6 +254,7 @@ extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*) LIBUNWIND_AVAIL; +extern const char *unw_strerror(int) LIBUNWIND_AVAIL; extern unw_addr_space_t unw_local_addr_space; @@ -552,6 +657,7 @@ enum { UNW_AARCH64_X31 = 31, UNW_AARCH64_SP = 31, UNW_AARCH64_PC = 32, + UNW_AARCH64_VG = 46, // reserved block UNW_AARCH64_RA_SIGN_STATE = 34, diff --git a/src/native/external/llvm-libunwind/include/unwind_arm_ehabi.h b/src/native/external/llvm-libunwind/include/unwind_arm_ehabi.h index 5fa94a167ff100..fa38def6ade841 100644 --- a/src/native/external/llvm-libunwind/include/unwind_arm_ehabi.h +++ b/src/native/external/llvm-libunwind/include/unwind_arm_ehabi.h @@ -125,8 +125,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t discriminator, _Unwind_VRS_DataRepresentation representation); +extern _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception *, + _Unwind_Context *); + #if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) -#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern +#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern __inline__ #else #define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__ #endif diff --git a/src/native/external/llvm-libunwind/src/AddressSpace.hpp b/src/native/external/llvm-libunwind/src/AddressSpace.hpp index 33f64415298264..435232dff8f423 100644 --- a/src/native/external/llvm-libunwind/src/AddressSpace.hpp +++ b/src/native/external/llvm-libunwind/src/AddressSpace.hpp @@ -48,11 +48,20 @@ struct EHABIIndexEntry { #if defined(_AIX) namespace libunwind { + char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen, unw_word_t *offset); } #endif +namespace libunwind { + +struct LocalAddressSpaceDefaultArgType { + typedef uintptr_t link_hardened_reg_arg_t; +}; + +} + #ifdef __APPLE__ struct dyld_unwind_sections @@ -130,22 +139,27 @@ struct UnwindInfoSections { defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \ defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) // No dso_base for SEH. - uintptr_t dso_base; + uintptr_t __ptrauth_unwind_uis_dso_base + dso_base = 0; #endif #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) size_t text_segment_length; #endif #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) - uintptr_t dwarf_section; - size_t dwarf_section_length; + uintptr_t __ptrauth_unwind_uis_dwarf_section + dwarf_section = 0; + size_t __ptrauth_unwind_uis_dwarf_section_length + dwarf_section_length = 0; #endif #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) uintptr_t dwarf_index_section; size_t dwarf_index_section_length; #endif #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) - uintptr_t compact_unwind_section; - size_t compact_unwind_section_length; + uintptr_t __ptrauth_unwind_uis_compact_unwind_section + compact_unwind_section = 0; + size_t __ptrauth_unwind_uis_compact_unwind_section_length + compact_unwind_section_length = 0; #endif #if defined(_LIBUNWIND_ARM_EHABI) uintptr_t arm_section; @@ -197,11 +211,20 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace { static int64_t getSLEB128(pint_t &addr, pint_t end); pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, - pint_t datarelBase = 0); + pint_t datarelBase = 0, pint_t *resultAddr = nullptr); bool findFunctionName(pint_t addr, char *buf, size_t bufLen, unw_word_t *offset); bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); bool findOtherFDE(pint_t targetAddr, pint_t &fde); + template + bool findFunctionName(typename R::link_hardened_reg_arg_t addr, char *buf, + size_t bufLen, unw_word_t *offset); + template + bool findUnwindSections(typename R::link_hardened_reg_arg_t targetAddr, + UnwindInfoSections &info); + template + bool findOtherFDE(typename R::link_hardened_reg_arg_t targetAddr, + pint_t &fde); static LocalAddressSpace sThisAddressSpace; }; @@ -270,7 +293,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, - pint_t datarelBase) { + pint_t datarelBase, pint_t *resultAddr) { pint_t startAddr = addr; const uint8_t *p = (uint8_t *)addr; pint_t result; @@ -354,8 +377,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, break; } - if (encoding & DW_EH_PE_indirect) + if (encoding & DW_EH_PE_indirect) { + if (resultAddr) + *resultAddr = result; result = getP(result); + } else { + if (resultAddr) + *resultAddr = startAddr; + } return result; } @@ -487,9 +516,9 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, #endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) - -inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, - UnwindInfoSections &info) { +template +inline bool LocalAddressSpace::findUnwindSections( + typename R::link_hardened_reg_arg_t targetAddr, UnwindInfoSections &info) { #ifdef __APPLE__ dyld_unwind_sections dyldInfo; if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { @@ -655,16 +684,36 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, return false; } +inline bool LocalAddressSpace::findUnwindSections( + pint_t targetAddr, UnwindInfoSections &info) { + return findUnwindSections(targetAddr, info); +} + +inline bool LocalAddressSpace::findFunctionName( + pint_t addr, char *buf, size_t bufLen, unw_word_t *offset) { + return findFunctionName(addr, buf, bufLen, + offset); +} + inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { + return findOtherFDE(targetAddr, fde); +} + +template +inline bool +LocalAddressSpace::findOtherFDE(typename R::link_hardened_reg_arg_t targetAddr, + pint_t &fde) { // TO DO: if OS has way to dynamically register FDEs, check that. (void)targetAddr; (void)fde; return false; } -inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, - size_t bufLen, - unw_word_t *offset) { +template +inline bool +LocalAddressSpace::findFunctionName(typename R::link_hardened_reg_arg_t addr, + char *buf, size_t bufLen, + unw_word_t *offset) { #if _LIBUNWIND_USE_DLADDR Dl_info dyldInfo; if (dladdr((void *)addr, &dyldInfo)) { diff --git a/src/native/external/llvm-libunwind/src/CMakeLists.txt b/src/native/external/llvm-libunwind/src/CMakeLists.txt index ecbd019bb29ea8..6e947039fb0d52 100644 --- a/src/native/external/llvm-libunwind/src/CMakeLists.txt +++ b/src/native/external/llvm-libunwind/src/CMakeLists.txt @@ -6,7 +6,7 @@ set(LIBUNWIND_CXX_SOURCES Unwind-seh.cpp ) -if(${CMAKE_SYSTEM_NAME} MATCHES "AIX") +if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX") list(APPEND LIBUNWIND_CXX_SOURCES Unwind_AIXExtras.cpp ) @@ -36,7 +36,6 @@ set(LIBUNWIND_HEADERS AddressSpace.hpp assembly.h CompactUnwinder.hpp - cet_unwind.h config.h dwarf2.h DwarfInstructions.hpp @@ -46,6 +45,7 @@ set(LIBUNWIND_HEADERS libunwind_ext.h Registers.hpp RWMutex.hpp + shadow_stack_unwind.h Unwind-EHABI.h UnwindCursor.hpp ../include/libunwind.h @@ -71,18 +71,6 @@ set(LIBUNWIND_SOURCES ${LIBUNWIND_ASM_SOURCES}) # Generate library list. -if (CXX_SUPPORTS_NOSTDLIBXX_FLAG) - add_link_flags_if_supported(-nostdlib++) -else() - if (LIBUNWIND_USE_COMPILER_RT) - add_library_flags("${LIBUNWIND_BUILTINS_LIBRARY}") - else() - add_library_flags_if(LIBUNWIND_HAS_GCC_S_LIB gcc_s) - add_library_flags_if(LIBUNWIND_HAS_GCC_LIB gcc) - endif() - add_library_flags_if(LIBUNWIND_HAS_C_LIB c) -endif() - if (NOT APPLE) add_library_flags_if(LIBUNWIND_HAS_DL_LIB dl) endif() @@ -118,22 +106,6 @@ if (HAIKU) add_compile_flags("-D_DEFAULT_SOURCE") add_compile_flags("-DPT_GNU_EH_FRAME=PT_EH_FRAME") - - find_path(LIBUNWIND_HAIKU_PRIVATE_HEADERS - "commpage_defs.h" - PATHS ${CMAKE_SYSTEM_INCLUDE_PATH} - PATH_SUFFIXES "/private/system" - NO_DEFAULT_PATH - REQUIRED) - - include_directories(SYSTEM "${LIBUNWIND_HAIKU_PRIVATE_HEADERS}") - if (LIBUNWIND_TARGET_TRIPLE) - if (${LIBUNWIND_TARGET_TRIPLE} MATCHES "^x86_64") - include_directories(SYSTEM "${LIBUNWIND_HAIKU_PRIVATE_HEADERS}/arch/x86_64") - endif() - else() - include_directories(SYSTEM "${LIBUNWIND_HAIKU_PRIVATE_HEADERS}/arch/${CMAKE_SYSTEM_PROCESSOR}") - endif() endif () string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}") @@ -160,9 +132,10 @@ if(CMAKE_C_COMPILER_ID STREQUAL MSVC) else() target_compile_options(unwind_shared_objects PRIVATE -fno-rtti) endif() -target_link_libraries(unwind_shared_objects PRIVATE unwind-headers ${LIBUNWIND_LIBRARIES}) target_compile_options(unwind_shared_objects PUBLIC "${LIBUNWIND_ADDITIONAL_COMPILE_FLAGS}") -target_link_libraries(unwind_shared_objects PUBLIC "${LIBUNWIND_ADDITIONAL_LIBRARIES}") +target_link_libraries(unwind_shared_objects + PUBLIC "${LIBUNWIND_ADDITIONAL_LIBRARIES}" + PRIVATE unwind-headers runtimes-libc-headers ${LIBUNWIND_LIBRARIES}) set_target_properties(unwind_shared_objects PROPERTIES CXX_EXTENSIONS OFF @@ -175,7 +148,7 @@ if (CMAKE_POSITION_INDEPENDENT_CODE OR NOT DEFINED CMAKE_POSITION_INDEPENDENT_CO endif() add_library(unwind_shared SHARED) -target_link_libraries(unwind_shared PUBLIC unwind_shared_objects) +target_link_libraries(unwind_shared PUBLIC unwind_shared_objects runtimes-libc-shared) set_target_properties(unwind_shared PROPERTIES EXCLUDE_FROM_ALL "$,FALSE,TRUE>" @@ -186,13 +159,6 @@ set_target_properties(unwind_shared SOVERSION "1" ) -if (LIBUNWIND_ENABLE_SHARED) - list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_shared") -endif() -if (LIBUNWIND_INSTALL_SHARED_LIBRARY) - list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_shared") -endif() - # Build the static library. add_library(unwind_static_objects OBJECT EXCLUDE_FROM_ALL ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS}) cxx_add_warning_flags(unwind_static_objects ${LIBUNWIND_ENABLE_WERROR} ${LIBUNWIND_ENABLE_PEDANTIC}) @@ -201,9 +167,10 @@ if(CMAKE_C_COMPILER_ID STREQUAL MSVC) else() target_compile_options(unwind_static_objects PRIVATE -fno-rtti) endif() -target_link_libraries(unwind_static_objects PRIVATE unwind-headers ${LIBUNWIND_LIBRARIES}) target_compile_options(unwind_static_objects PUBLIC "${LIBUNWIND_ADDITIONAL_COMPILE_FLAGS}") -target_link_libraries(unwind_static_objects PUBLIC "${LIBUNWIND_ADDITIONAL_LIBRARIES}") +target_link_libraries(unwind_static_objects + PUBLIC "${LIBUNWIND_ADDITIONAL_LIBRARIES}" + PRIVATE unwind-headers runtimes-libc-headers ${LIBUNWIND_LIBRARIES}) set_target_properties(unwind_static_objects PROPERTIES CXX_EXTENSIONS OFF @@ -222,7 +189,7 @@ if(LIBUNWIND_HIDE_SYMBOLS) endif() add_library(unwind_static STATIC) -target_link_libraries(unwind_static PUBLIC unwind_static_objects) +target_link_libraries(unwind_static PUBLIC unwind_static_objects runtimes-libc-static) set_target_properties(unwind_static PROPERTIES EXCLUDE_FROM_ALL "$,FALSE,TRUE>" @@ -231,35 +198,40 @@ set_target_properties(unwind_static OUTPUT_NAME "${LIBUNWIND_STATIC_OUTPUT_NAME}" ) -if (LIBUNWIND_ENABLE_STATIC) - list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_static") +# Add a meta-target for both libraries. +add_custom_target(unwind) +if (LIBUNWIND_ENABLE_SHARED) + add_dependencies(unwind unwind_shared) endif() -if (LIBUNWIND_INSTALL_STATIC_LIBRARY) - list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_static") +if (LIBUNWIND_ENABLE_STATIC) + add_dependencies(unwind unwind_static) endif() -# Add a meta-target for both libraries. -add_custom_target(unwind DEPENDS ${LIBUNWIND_BUILD_TARGETS}) - -if (LIBUNWIND_INSTALL_LIBRARY) - install(TARGETS ${LIBUNWIND_INSTALL_TARGETS} +if (LIBUNWIND_INSTALL_SHARED_LIBRARY) + install(TARGETS unwind_shared + ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind LIBRARY DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind + RUNTIME DESTINATION ${LIBUNWIND_INSTALL_RUNTIME_DIR} COMPONENT unwind) +endif() + +if (LIBUNWIND_INSTALL_STATIC_LIBRARY) + install(TARGETS unwind_static ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind + LIBRARY DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind RUNTIME DESTINATION ${LIBUNWIND_INSTALL_RUNTIME_DIR} COMPONENT unwind) endif() -if (NOT CMAKE_CONFIGURATION_TYPES AND LIBUNWIND_INSTALL_LIBRARY) +if (NOT CMAKE_CONFIGURATION_TYPES) add_custom_target(install-unwind - DEPENDS unwind - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=unwind - -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") + COMMAND "${CMAKE_COMMAND}" --install "${CMAKE_BINARY_DIR}" --component unwind) add_custom_target(install-unwind-stripped - DEPENDS unwind - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=unwind - -DCMAKE_INSTALL_DO_STRIP=1 - -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") + COMMAND "${CMAKE_COMMAND}" --install "${CMAKE_BINARY_DIR}" --component unwind --strip) + + if (LIBUNWIND_INSTALL_LIBRARY) + add_dependencies(install-unwind unwind) + add_dependencies(install-unwind-stripped unwind) + endif() + if(LIBUNWIND_INSTALL_HEADERS) add_dependencies(install-unwind install-unwind-headers) add_dependencies(install-unwind-stripped install-unwind-headers-stripped) diff --git a/src/native/external/llvm-libunwind/src/CompactUnwinder.hpp b/src/native/external/llvm-libunwind/src/CompactUnwinder.hpp index 5cb825e2fd3e9b..389bd37dcafc21 100644 --- a/src/native/external/llvm-libunwind/src/CompactUnwinder.hpp +++ b/src/native/external/llvm-libunwind/src/CompactUnwinder.hpp @@ -601,11 +601,17 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( savedRegisterLoc -= 8; } + // We load the link register prior to setting the new SP as the authentication + // schema for LR entangles the SP of the old frame into the diversifier. + Registers_arm64::reg_t linkRegister = registers.getRegister(UNW_AARCH64_LR); + // subtract stack size off of sp registers.setSP(savedRegisterLoc, 0); - // set pc to be value in lr - registers.setIP(registers.getRegister(UNW_AARCH64_LR), 0); + // Set pc to be value in lr. This needs to be performed after the new SP has + // been set, as the PC authentication schema entangles the SP of the new + // frame. + registers.setIP(linkRegister, 0); return UNW_STEP_SUCCESS; } @@ -614,7 +620,7 @@ template int CompactUnwinder_arm64::stepWithCompactEncodingFrame( compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, R ®isters) { - uint64_t savedRegisterLoc = registers.getFP() - 8; + typename R::reg_t savedRegisterLoc = registers.getFP() - 8; if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc), savedRegisterLoc); @@ -680,7 +686,8 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrame( savedRegisterLoc -= 8; } - uint64_t fp = registers.getFP(); + Registers_arm64::reg_t fp = registers.getFP(); + // fp points to old fp registers.setFP(addressSpace.get64(fp), fp); // old sp is fp less saved fp and lr diff --git a/src/native/external/llvm-libunwind/src/DwarfInstructions.hpp b/src/native/external/llvm-libunwind/src/DwarfInstructions.hpp index 32112839042b58..1fc8baa8036b07 100644 --- a/src/native/external/llvm-libunwind/src/DwarfInstructions.hpp +++ b/src/native/external/llvm-libunwind/src/DwarfInstructions.hpp @@ -22,7 +22,6 @@ #include "dwarf2.h" #include "libunwind_ext.h" - namespace libunwind { @@ -34,8 +33,10 @@ class DwarfInstructions { typedef typename A::pint_t pint_t; typedef typename A::sint_t sint_t; - static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, - R ®isters, bool &isSignalFrame, bool stage2); + static int stepWithDwarf(A &addressSpace, + pint_t pc, + pint_t fdeStart, R ®isters, bool &isSignalFrame, + bool stage2); private: @@ -65,9 +66,10 @@ class DwarfInstructions { static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, const R ®isters) { - if (prolog.cfaRegister != 0) - return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + - prolog.cfaRegisterOffset); + if (prolog.cfaRegister != 0) { + uintptr_t cfaRegister = registers.getRegister((int)prolog.cfaRegister); + return (pint_t)(cfaRegister + prolog.cfaRegisterOffset); + } if (prolog.cfaExpression != 0) return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, registers, 0); @@ -214,16 +216,16 @@ bool DwarfInstructions::isReturnAddressSignedWithPC(A &addressSpace, #endif template -int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, - pint_t fdeStart, R ®isters, - bool &isSignalFrame, bool stage2) { +int DwarfInstructions::stepWithDwarf( + A &addressSpace, pint_t pc, pint_t fdeStart, + R ®isters, bool &isSignalFrame, bool stage2) { FDE_Info fdeInfo; CIE_Info cieInfo; if (CFI_Parser::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL) { PrologInfo prolog; - if (CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, - R::getArch(), &prolog)) { + if (CFI_Parser::template parseFDEInstructions( + addressSpace, fdeInfo, cieInfo, pc, R::getArch(), &prolog)) { // get pointer to cfa (architecture specific) pint_t cfa = getCFA(addressSpace, prolog, registers); @@ -318,7 +320,16 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, isSignalFrame = cieInfo.isSignalFrame; -#if defined(_LIBUNWIND_TARGET_AARCH64) +#if defined(_LIBUNWIND_TARGET_AARCH64) && \ + !defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + // There are two ways of return address signing: pac-ret (enabled via + // -mbranch-protection=pac-ret) and ptrauth-returns (enabled as part of + // Apple's arm64e or experimental pauthtest ABI on Linux). The code + // below handles signed RA for pac-ret, while ptrauth-returns uses + // different logic. + // TODO: unify logic for both cases, see + // https://github.com/llvm/llvm-project/issues/160110 + // // If the target is aarch64 then the return address may have been signed // using the v8.3 pointer authentication extensions. The original // return address needs to be authenticated before the return address is diff --git a/src/native/external/llvm-libunwind/src/DwarfParser.hpp b/src/native/external/llvm-libunwind/src/DwarfParser.hpp index a18b7397b996cb..55c29f7103ef6e 100644 --- a/src/native/external/llvm-libunwind/src/DwarfParser.hpp +++ b/src/native/external/llvm-libunwind/src/DwarfParser.hpp @@ -23,6 +23,10 @@ #include "config.h" +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) +#include +#endif + namespace libunwind { /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. @@ -33,6 +37,7 @@ template class CFI_Parser { public: typedef typename A::pint_t pint_t; + typedef pint_t __ptrauth_unwind_cie_info_personality personality_t; /// Information encoded in a CIE (Common Information Entry) struct CIE_Info { @@ -43,7 +48,7 @@ class CFI_Parser { uint8_t lsdaEncoding; uint8_t personalityEncoding; uint8_t personalityOffsetInCIE; - pint_t personality; + personality_t personality; uint32_t codeAlignFactor; int dataAlignFactor; bool isSignalFrame; @@ -155,14 +160,17 @@ class CFI_Parser { } }; - static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, - size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, - CIE_Info *cieInfo); + template + static bool findFDE(A &addressSpace, pint_t pc, + pint_t ehSectionStart, size_t sectionLength, + pint_t fdeHint, FDE_Info *fdeInfo, CIE_Info *cieInfo); static const char *decodeFDE(A &addressSpace, pint_t fdeStart, FDE_Info *fdeInfo, CIE_Info *cieInfo, bool useCIEInfo = false); + template static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, - const CIE_Info &cieInfo, pint_t upToPC, + const CIE_Info &cieInfo, + pint_t upToPC, int arch, PrologInfo *results); static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); @@ -234,9 +242,12 @@ const char *CFI_Parser::decodeFDE(A &addressSpace, pint_t fdeStart, /// Scan an eh_frame section to find an FDE for a pc template -bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, - size_t sectionLength, pint_t fdeHint, - FDE_Info *fdeInfo, CIE_Info *cieInfo) { +template +bool CFI_Parser::findFDE(A &addressSpace, + pint_t pc, + pint_t ehSectionStart, size_t sectionLength, + pint_t fdeHint, FDE_Info *fdeInfo, + CIE_Info *cieInfo) { //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; const pint_t ehSectionEnd = (sectionLength == SIZE_MAX) @@ -369,6 +380,7 @@ const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, cieInfo->returnAddressRegister = (uint8_t)raReg; // parse augmentation data based on augmentation string const char *result = NULL; + pint_t resultAddr = 0; if (addressSpace.get8(strStart) == 'z') { // parse augmentation data length addressSpace.getULEB128(p, cieContentEnd); @@ -377,13 +389,41 @@ const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, case 'z': cieInfo->fdesHaveAugmentationData = true; break; - case 'P': + case 'P': { cieInfo->personalityEncoding = addressSpace.get8(p); ++p; cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); - cieInfo->personality = addressSpace - .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); + pint_t personality = addressSpace.getEncodedP( + p, cieContentEnd, cieInfo->personalityEncoding, + /*datarelBase=*/0, &resultAddr); +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + if (personality) { + // The GOT for the personality function was signed address + // authenticated. Manually re-sign with the CIE_Info::personality + // schema. If we could guarantee the encoding of the personality we + // could avoid this by simply giving resultAddr the correct ptrauth + // schema and performing an assignment. +#if defined(__arm64e__) + const auto oldDiscriminator = resultAddr; +#else + const auto oldDiscriminator = ptrauth_blend_discriminator( + (void *)resultAddr, __ptrauth_unwind_pauthtest_personality_disc); +#endif + const auto discriminator = ptrauth_blend_discriminator( + &cieInfo->personality, + __ptrauth_unwind_cie_info_personality_disc); + void *signedPtr = ptrauth_auth_and_resign( + (void *)personality, ptrauth_key_function_pointer, + oldDiscriminator, ptrauth_key_function_pointer, discriminator); + personality = (pint_t)signedPtr; + } +#endif + // We use memmove to set the CIE personality as we have already + // re-signed the pointer to the correct schema. + memmove((void *)&cieInfo->personality, (void *)&personality, + sizeof(personality)); break; + } case 'L': cieInfo->lsdaEncoding = addressSpace.get8(p); ++p; @@ -417,10 +457,10 @@ const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, /// "run" the DWARF instructions and create the abstract PrologInfo for an FDE template -bool CFI_Parser::parseFDEInstructions(A &addressSpace, - const FDE_Info &fdeInfo, - const CIE_Info &cieInfo, pint_t upToPC, - int arch, PrologInfo *results) { +template +bool CFI_Parser::parseFDEInstructions( + A &addressSpace, const FDE_Info &fdeInfo, const CIE_Info &cieInfo, + pint_t upToPC, int arch, PrologInfo *results) { // Alloca is used for the allocation of the rememberStack entries. It removes // the dependency on new/malloc but the below for loop can not be refactored // into functions. Entry could be saved during the processing of a CIE and @@ -808,12 +848,10 @@ bool CFI_Parser::parseFDEInstructions(A &addressSpace, results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3; results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value, initialState); - // When calculating the value of the PC, it is assumed that the CFI - // instruction is placed before the signing instruction, however it is - // placed after. Because of this, we need to take into account the CFI - // instruction is one instruction call later than expected, and reduce - // the PC value by 4 bytes to compensate. - results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4; + // When using Feat_PAuthLR, the PC value needs to be captured so that + // during unwinding, the correct PC value is used for re-authentication. + // It is assumed that the CFI is placed before the signing instruction. + results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset; _LIBUNWIND_TRACE_DWARF( "DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n", static_cast(results->ptrAuthDiversifier)); diff --git a/src/native/external/llvm-libunwind/src/EHHeaderParser.hpp b/src/native/external/llvm-libunwind/src/EHHeaderParser.hpp index 0662a1321e2c75..b5d927027f64c1 100644 --- a/src/native/external/llvm-libunwind/src/EHHeaderParser.hpp +++ b/src/native/external/llvm-libunwind/src/EHHeaderParser.hpp @@ -37,8 +37,9 @@ template class EHHeaderParser { static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo); - static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, - uint32_t sectionLength, + template + static bool findFDE(A &addressSpace, typename R::link_hardened_reg_arg_t pc, + pint_t ehHdrStart, uint32_t sectionLength, typename CFI_Parser::FDE_Info *fdeInfo, typename CFI_Parser::CIE_Info *cieInfo); @@ -112,8 +113,10 @@ bool EHHeaderParser::decodeTableEntry( } template -bool EHHeaderParser::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, - uint32_t sectionLength, +template +bool EHHeaderParser::findFDE(A &addressSpace, + typename R::link_hardened_reg_arg_t pc, + pint_t ehHdrStart, uint32_t sectionLength, typename CFI_Parser::FDE_Info *fdeInfo, typename CFI_Parser::CIE_Info *cieInfo) { pint_t ehHdrEnd = ehHdrStart + sectionLength; diff --git a/src/native/external/llvm-libunwind/src/Registers.hpp b/src/native/external/llvm-libunwind/src/Registers.hpp index 5daa35a3241885..7d7afca8e9e1d2 100644 --- a/src/native/external/llvm-libunwind/src/Registers.hpp +++ b/src/native/external/llvm-libunwind/src/Registers.hpp @@ -15,9 +15,15 @@ #include #include -#include "cet_unwind.h" #include "config.h" #include "libunwind.h" +#include "libunwind_ext.h" +#include "shadow_stack_unwind.h" + +#if __has_include() +#include +#define HAVE_SYS_AUXV_H +#endif namespace libunwind { @@ -48,7 +54,7 @@ class _LIBUNWIND_HIDDEN Registers_x86; extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); #if defined(_LIBUNWIND_USE_CET) -extern "C" void *__libunwind_cet_get_jump_target() { +extern "C" void *__libunwind_shstk_get_jump_target() { return reinterpret_cast(&__libunwind_Registers_x86_jumpto); } #endif @@ -60,6 +66,10 @@ class _LIBUNWIND_HIDDEN Registers_x86 { Registers_x86(); Registers_x86(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value, uint32_t location); @@ -319,7 +329,7 @@ class _LIBUNWIND_HIDDEN Registers_x86_64; extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); #if defined(_LIBUNWIND_USE_CET) -extern "C" void *__libunwind_cet_get_jump_target() { +extern "C" void *__libunwind_shstk_get_jump_target() { return reinterpret_cast(&__libunwind_Registers_x86_64_jumpto); } #endif @@ -329,6 +339,10 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 { Registers_x86_64(); Registers_x86_64(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value, uint64_t location); @@ -731,6 +745,10 @@ class _LIBUNWIND_HIDDEN Registers_ppc { Registers_ppc(); Registers_ppc(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); @@ -1303,6 +1321,10 @@ class _LIBUNWIND_HIDDEN Registers_ppc64 { Registers_ppc64(); Registers_ppc64(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value, uint64_t location); @@ -1949,18 +1971,33 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) { /// Registers_arm64 holds the register state of a thread in a 64-bit arm /// process. class _LIBUNWIND_HIDDEN Registers_arm64; -extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +extern "C" int64_t __libunwind_Registers_arm64_za_disable(); +extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *, + unsigned walkedFrames); #if defined(_LIBUNWIND_USE_GCS) -extern "C" void *__libunwind_cet_get_jump_target() { +extern "C" void *__libunwind_shstk_get_jump_target() { return reinterpret_cast(&__libunwind_Registers_arm64_jumpto); } #endif class _LIBUNWIND_HIDDEN Registers_arm64 { public: - Registers_arm64(); + Registers_arm64() = default; Registers_arm64(const void *registers); + Registers_arm64(const Registers_arm64 &); + Registers_arm64 &operator=(const Registers_arm64 &); + + typedef uint64_t reg_t; + typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t; + + // Use `link_hardened_reg_arg_t` to pass values of `link_reg_t` type as + // function arguments. We need to use a const l-value reference to keep + // signature of `__ptrauth`-qualified values of `link_reg_t` type on AArch64 + // PAuth-enabled ABI intact. Passing the raw pointer by value would cause + // authentication on the caller side and make the pointer prone to + // substitution if spilled to the stack in the callee. + typedef const link_reg_t &link_hardened_reg_arg_t; bool validRegister(int num) const; uint64_t getRegister(int num) const; @@ -1973,45 +2010,125 @@ class _LIBUNWIND_HIDDEN Registers_arm64 { void setVectorRegister(int num, v128 value); uint64_t getRegisterLocation(int regNum) const; static const char *getRegisterName(int num); - void jumpto() { __libunwind_Registers_arm64_jumpto(this); } + void jumpto(unsigned walkedFrames = 0) { + zaDisable(); + __libunwind_Registers_arm64_jumpto(this, walkedFrames); + } +#ifdef _LIBUNWIND_TRACE_RET_INJECT + _LIBUNWIND_TRACE_NO_INLINE + void returnto(unsigned walkedFrames) { jumpto(walkedFrames); } +#endif static constexpr int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } static int getArch() { return REGISTERS_ARM64; } uint64_t getSP() const { return _registers.__sp; } - void setSP(uint64_t value, uint64_t location) { _registers.__sp = value; } - uint64_t getIP() const { return _registers.__pc; } - void setIP(uint64_t value, uint64_t location) { _registers.__pc = value; } - uint64_t getFP() const { return _registers.__fp; } - void setFP(uint64_t value, uint64_t location) { _registers.__fp = value; } + void setSP(uint64_t value, uint64_t location) { + _registers.__sp = value; + _registerLocations.__sp = location; + } + uint64_t getIP() const { + uint64_t value = _registers.__pc; +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + // Note the value of the PC was signed to its address in the register state + // but everyone else expects it to be sign by the SP, so convert on return. + value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc, + ptrauth_key_return_address, + &_registers.__pc, + ptrauth_key_return_address, + getSP()); +#endif + return value; + } + void setIP(uint64_t value, uint64_t location) { +#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; + _registerLocations.__pc = location; + } + uint64_t getFP() const { return _registers.__fp; } + void setFP(uint64_t value, uint64_t location) { + _registers.__fp = value; + _registerLocations.__fp = location; + } + +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + void + loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister, + link_reg_t *referenceAuthedLinkRegister) { + // If we are in an arm64/arm64e frame, then the PC should have been signed + // with the SP + *referenceAuthedLinkRegister = + (uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister, + ptrauth_key_return_address, + _registers.__sp); + } +#endif private: + uint64_t lazyGetVG() const; + + void zaDisable() const { + if (!_misc_registers.__has_sme) + return; + if (__libunwind_Registers_arm64_za_disable() != 0) + _LIBUNWIND_ABORT("SME ZA disable failed"); + } + + static bool checkHasSME() { +#if defined(HAVE_SYS_AUXV_H) + constexpr int hwcap2_sme = (1 << 23); + unsigned long hwcap2 = getauxval(AT_HWCAP2); + return (hwcap2 & hwcap2_sme) != 0; +#endif + // TODO: Support other platforms. + return false; + } + struct GPRs { - uint64_t __x[29]; // x0-x28 - uint64_t __fp; // Frame pointer x29 - uint64_t __lr; // Link register x30 - uint64_t __sp; // Stack pointer x31 - uint64_t __pc; // Program counter - uint64_t __ra_sign_state; // RA sign state register + uint64_t __x[29] = {}; // x0-x28 + uint64_t __fp = 0; // Frame pointer x29 + uint64_t __lr = 0; // Link register x30 + uint64_t __sp = 0; // Stack pointer x31 + uint64_t __pc = 0; // Program counter + uint64_t __ra_sign_state = 0; // RA sign state register }; struct GPRLocations { - uint64_t __x[29]; // x0-x28 - uint64_t __fp; // Frame pointer x29 - uint64_t __lr; // Link register x30 - uint64_t __sp; // Stack pointer x31 - uint64_t __pc; // Program counter - uint64_t padding; // 16-byte align + uint64_t __x[29] = {}; // x0-x28 + uint64_t __fp = 0; // Frame pointer x29 + uint64_t __lr = 0; // Link register x30 + uint64_t __sp = 0; // Stack pointer x31 + uint64_t __pc = 0; // Program counter }; - GPRs _registers; - GPRLocations _registerLocations; - double _vectorHalfRegisters[32]; + struct Misc { + mutable uint32_t __vg = 0; // Vector Granule + bool __has_sme = checkHasSME(); + }; + + GPRs _registers = {}; + GPRLocations _registerLocations = {}; // Currently only the lower double in 128-bit vectore registers // is perserved during unwinding. We could define new register // numbers (> 96) which mean whole vector registers, then this // struct would need to change to contain whole vector registers. + double _vectorHalfRegisters[32] = {}; + + // Miscellaneous/virtual registers. These are stored below the GPRs and FPRs + // as they do not correspond to physical registers, so do not need to be + // saved/restored in UnwindRegistersRestore.S and UnwindRegistersSave.S, and + // we don't want to modify the existing offsets for GPRs and FPRs. + Misc _misc_registers; }; inline Registers_arm64::Registers_arm64(const void *registers) { @@ -2025,12 +2142,31 @@ inline Registers_arm64::Registers_arm64(const void *registers) { memcpy(_vectorHalfRegisters, static_cast(registers) + sizeof(GPRs), sizeof(_vectorHalfRegisters)); + _misc_registers.__vg = 0; + +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + // We have to do some pointer authentication fixups after this copy, + // and as part of that we need to load the source pc without + // authenticating so that we maintain the signature for the resigning + // performed by setIP. + uint64_t pcRegister = 0; + memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc), + sizeof(pcRegister)); + setIP(pcRegister, 0); +#endif } -inline Registers_arm64::Registers_arm64() { - memset(&_registers, 0, sizeof(_registers)); - memset(&_registerLocations, 0, sizeof(_registerLocations)); - memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); +inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) { + *this = other; +} + +inline Registers_arm64 & +Registers_arm64::operator=(const Registers_arm64 &other) { + memmove(static_cast(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(), other.getRegisterLocation(UNW_REG_IP)); + return *this; } inline bool Registers_arm64::validRegister(int regNum) const { @@ -2044,32 +2180,48 @@ inline bool Registers_arm64::validRegister(int regNum) const { return false; if (regNum == UNW_AARCH64_RA_SIGN_STATE) return true; + if (regNum == UNW_AARCH64_VG) + return true; if ((regNum > 32) && (regNum < 64)) return false; return true; } +inline uint64_t Registers_arm64::lazyGetVG() const { + if (!_misc_registers.__vg) { +#if defined(__aarch64__) + register uint64_t vg asm("x0"); + asm(".inst 0x04e0e3e0" // CNTD x0 + : "=r"(vg)); + _misc_registers.__vg = vg; +#else + _LIBUNWIND_ABORT("arm64 VG undefined"); +#endif + } + return _misc_registers.__vg; +} + inline uint64_t Registers_arm64::getRegister(int regNum) const { if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC) - return _registers.__pc; + return getIP(); if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP) return _registers.__sp; if (regNum == UNW_AARCH64_RA_SIGN_STATE) return _registers.__ra_sign_state; if (regNum == UNW_AARCH64_FP) - return _registers.__fp; + return getFP(); if (regNum == UNW_AARCH64_LR) return _registers.__lr; + if (regNum == UNW_AARCH64_VG) + return lazyGetVG(); if ((regNum >= 0) && (regNum < 29)) return _registers.__x[regNum]; _LIBUNWIND_ABORT("unsupported arm64 register"); } inline void Registers_arm64::setRegister(int regNum, uint64_t value, uint64_t location) { - if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC) { - _registers.__pc = value; - _registerLocations.__pc = location; - } + if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC) + setIP(value, location); else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP) { _registers.__sp = value; _registerLocations.__sp = location; @@ -2088,6 +2240,8 @@ inline void Registers_arm64::setRegister(int regNum, uint64_t value, uint64_t lo _registers.__x[regNum] = value; _registerLocations.__x[regNum] = location; } + else if (regNum == UNW_AARCH64_VG) + _misc_registers.__vg = value; else _LIBUNWIND_ABORT("unsupported arm64 register"); } @@ -2095,10 +2249,20 @@ inline void Registers_arm64::setRegister(int regNum, uint64_t value, uint64_t lo inline uint64_t Registers_arm64::getRegisterLocation(int regNum) const { if (regNum == UNW_REG_IP) return _registerLocations.__pc; + if (regNum == UNW_AARCH64_PC) + return _registerLocations.__pc; if (regNum == UNW_REG_SP) return _registerLocations.__sp; - if ((regNum >= 0) && (regNum < 32)) + if (regNum == UNW_AARCH64_SP) + return _registerLocations.__sp; + if (regNum == UNW_AARCH64_FP) + return _registerLocations.__fp; + if (regNum == UNW_AARCH64_LR) + return _registerLocations.__lr; + if ((regNum >= 0) && (regNum < 29)) return _registerLocations.__x[regNum]; + if (regNum == UNW_AARCH64_RA_SIGN_STATE || regNum == UNW_AARCH64_VG) + return 0; _LIBUNWIND_ABORT("unsupported arm64 register"); } @@ -2285,6 +2449,10 @@ class _LIBUNWIND_HIDDEN Registers_arm { Registers_arm(); Registers_arm(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value, uint32_t location); @@ -2822,6 +2990,10 @@ class _LIBUNWIND_HIDDEN Registers_or1k { Registers_or1k(); Registers_or1k(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); @@ -3021,6 +3193,10 @@ class _LIBUNWIND_HIDDEN Registers_mips_o32 { Registers_mips_o32(); Registers_mips_o32(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); @@ -3356,6 +3532,10 @@ class _LIBUNWIND_HIDDEN Registers_mips_newabi { Registers_mips_newabi(); Registers_mips_newabi(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); @@ -3659,6 +3839,10 @@ class _LIBUNWIND_HIDDEN Registers_sparc { Registers_sparc(); Registers_sparc(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); @@ -3845,6 +4029,10 @@ class _LIBUNWIND_HIDDEN Registers_sparc64 { Registers_sparc64() = default; Registers_sparc64(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); @@ -4030,6 +4218,10 @@ class _LIBUNWIND_HIDDEN Registers_hexagon { Registers_hexagon(); Registers_hexagon(const void *registers); + typedef uint32_t reg_t; + typedef uint32_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); @@ -4245,6 +4437,10 @@ class _LIBUNWIND_HIDDEN Registers_riscv { Registers_riscv(); Registers_riscv(const void *registers); + typedef ::libunwind::reg_t reg_t; + typedef ::libunwind::reg_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; reg_t getRegister(int num) const; void setRegister(int num, reg_t value, uint64_t location); @@ -4331,7 +4527,7 @@ inline reg_t Registers_riscv::getRegister(int regNum) const { return _registers[regNum]; if (regNum == UNW_RISCV_VLENB) { reg_t vlenb; - __asm__("csrr %0, 0xC22" : "=r"(vlenb)); + __asm__ volatile("csrr %0, 0xC22" : "=r"(vlenb)); return vlenb; } _LIBUNWIND_ABORT("unsupported riscv register"); @@ -4567,6 +4763,10 @@ class _LIBUNWIND_HIDDEN Registers_ve { Registers_ve(); Registers_ve(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); @@ -5010,6 +5210,10 @@ class _LIBUNWIND_HIDDEN Registers_s390x { Registers_s390x(); Registers_s390x(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); @@ -5298,6 +5502,10 @@ class _LIBUNWIND_HIDDEN Registers_loongarch { Registers_loongarch(); Registers_loongarch(const void *registers); + typedef uint64_t reg_t; + typedef uint64_t link_reg_t; + typedef const link_reg_t &link_hardened_reg_arg_t; + bool validRegister(int num) const; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value, uint64_t location); diff --git a/src/native/external/llvm-libunwind/src/Unwind-seh.cpp b/src/native/external/llvm-libunwind/src/Unwind-seh.cpp index b2bb119ed6d299..0b1930b44d1c64 100644 --- a/src/native/external/llvm-libunwind/src/Unwind-seh.cpp +++ b/src/native/external/llvm-libunwind/src/Unwind-seh.cpp @@ -51,6 +51,32 @@ static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor); static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +// Local redefinition of this type; mingw-w64 headers lack the +// DISPATCHER_CONTEXT_NONVOLREG_ARM64 type as of May 2025, so locally redefine +// it and use that definition, to avoid needing to test/guess whether the real +// type is available of not. +union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 { + BYTE Buffer[11 * sizeof(DWORD64) + 8 * sizeof(double)]; + + struct { + DWORD64 GpNvRegs[11]; + double FpNvRegs[8]; + }; +}; + +// Custom data type definition; this type is not defined in WinSDK. +union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM { + BYTE Buffer[8 * sizeof(DWORD) + 8 * sizeof(double)]; + + struct { + DWORD GpNvRegs[8]; + double FpNvRegs[8]; + }; +}; +#pragma clang diagnostic pop + /// Common implementation of SEH-style handler functions used by Itanium- /// style frames. Depending on how and why it was called, it may do one of: /// a) Delegate to the given Itanium-style personality function; or @@ -137,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 // a handler was found; otherwise, initiate phase 2 by unwinding. if (ours && ms_exc->NumberParameters > 1) - return 4 /* ExceptionExecuteHandler in mingw */; + return static_cast(4); // This should never happen in phase 2. if (IS_UNWINDING(ms_exc->ExceptionFlags)) _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); @@ -148,14 +174,15 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, } // FIXME: Indicate target frame in foreign case! // phase 2: the clean up phase - RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); + RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, disp->ContextRecord, + disp->HistoryTable); _LIBUNWIND_ABORT("RtlUnwindEx() failed"); case _URC_INSTALL_CONTEXT: { // If we were called by __libunwind_seh_personality(), indicate that // a handler was found; otherwise, it's time to initiate a collided // unwind to the target. if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) - return 4 /* ExceptionExecuteHandler in mingw */; + return static_cast(4); // This should never happen in phase 1. if (!IS_UNWINDING(ms_exc->ExceptionFlags)) _LIBUNWIND_ABORT("Personality installed context during phase 1!"); @@ -212,18 +239,32 @@ __libunwind_seh_personality(int version, _Unwind_Action state, ms_exc.ExceptionInformation[2] = state; DISPATCHER_CONTEXT *disp_ctx = __unw_seh_get_disp_ctx((unw_cursor_t *)context); +#if defined(__aarch64__) + LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 nonvol; + memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->X19, + sizeof(nonvol.GpNvRegs)); + for (int i = 0; i < 8; i++) + nonvol.FpNvRegs[i] = disp_ctx->ContextRecord->V[i + 8].D[0]; + disp_ctx->NonVolatileRegisters = nonvol.Buffer; +#elif defined(__arm__) + LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol; + memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->R4, + sizeof(nonvol.GpNvRegs)); + memcpy(&nonvol.FpNvRegs, &disp_ctx->ContextRecord->D[8], + sizeof(nonvol.FpNvRegs)); + disp_ctx->NonVolatileRegisters = nonvol.Buffer; +#endif _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() calling " "LanguageHandler %p(%p, %p, %p, %p)", (void *)disp_ctx->LanguageHandler, (void *)&ms_exc, (void *)disp_ctx->EstablisherFrame, (void *)disp_ctx->ContextRecord, (void *)disp_ctx); - EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, - (PVOID)disp_ctx->EstablisherFrame, - disp_ctx->ContextRecord, - disp_ctx); + int ms_act = static_cast( + disp_ctx->LanguageHandler(&ms_exc, (PVOID)disp_ctx->EstablisherFrame, + disp_ctx->ContextRecord, disp_ctx)); _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() LanguageHandler " "returned %d", - (int)ms_act); + ms_act); switch (ms_act) { case ExceptionContinueExecution: return _URC_END_OF_STACK; case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; diff --git a/src/native/external/llvm-libunwind/src/Unwind-wasm.c b/src/native/external/llvm-libunwind/src/Unwind-wasm.c index b18b32c5d17847..b0d6cd2d00fc59 100644 --- a/src/native/external/llvm-libunwind/src/Unwind-wasm.c +++ b/src/native/external/llvm-libunwind/src/Unwind-wasm.c @@ -37,13 +37,13 @@ struct _Unwind_LandingPadContext { // function thread_local struct _Unwind_LandingPadContext __wasm_lpad_context; -/// Calls to this function is in landing pads in compiler-generated user code. +/// Calls to this function are in landing pads in compiler-generated user code. /// In other EH schemes, stack unwinding is done by libunwind library, which -/// calls the personality function for each each frame it lands. On the other -/// hand, WebAssembly stack unwinding process is performed by a VM, and the -/// personality function cannot be called from there. So the compiler inserts -/// a call to this function in landing pads in the user code, which in turn -/// calls the personality function. +/// calls the personality function for each frame it lands. On the other hand, +/// WebAssembly stack unwinding process is performed by a VM, and the +/// personality function cannot be called from there. So the compiler inserts a +/// call to this function in landing pads in the user code, which in turn calls +/// the personality function. _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) { struct _Unwind_Exception *exception_object = (struct _Unwind_Exception *)exception_ptr; @@ -92,7 +92,7 @@ _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, /// Called by personality handler to get instruction pointer. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { - // The result will be used as an 1-based index after decrementing 1, so we + // The result will be used as a 1-based index after decrementing 1, so we // increment 2 here uintptr_t result = ((struct _Unwind_LandingPadContext *)context)->lpad_index + 2; @@ -102,8 +102,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { } /// Not used in Wasm. -_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, - uintptr_t value) {} +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t) {} /// Called by personality handler to get LSDA for current frame. _LIBUNWIND_EXPORT uintptr_t @@ -115,8 +114,7 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { } /// Not used in Wasm. -_LIBUNWIND_EXPORT uintptr_t -_Unwind_GetRegionStart(struct _Unwind_Context *context) { +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *) { return 0; } diff --git a/src/native/external/llvm-libunwind/src/UnwindCursor.hpp b/src/native/external/llvm-libunwind/src/UnwindCursor.hpp index 1b1f032baf22fd..144833d9d647ce 100644 --- a/src/native/external/llvm-libunwind/src/UnwindCursor.hpp +++ b/src/native/external/llvm-libunwind/src/UnwindCursor.hpp @@ -11,7 +11,7 @@ #ifndef __UNWINDCURSOR_HPP__ #define __UNWINDCURSOR_HPP__ -#include "cet_unwind.h" +#include "shadow_stack_unwind.h" #include #include #include @@ -31,8 +31,9 @@ #endif #if defined(_LIBUNWIND_TARGET_LINUX) && \ - (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \ - defined(_LIBUNWIND_TARGET_S390X)) + (defined(_LIBUNWIND_TARGET_AARCH64) || \ + defined(_LIBUNWIND_TARGET_LOONGARCH) || \ + defined(_LIBUNWIND_TARGET_RISCV) || defined(_LIBUNWIND_TARGET_S390X)) #include #include #include @@ -40,6 +41,13 @@ #define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1 #endif +#if defined(_LIBUNWIND_TARGET_HAIKU) && \ + (defined(_LIBUNWIND_TARGET_I386) || defined(_LIBUNWIND_TARGET_X86_64)) +#include +#include +#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1 +#endif + #include "AddressSpace.hpp" #include "CompactUnwinder.hpp" #include "config.h" @@ -82,6 +90,22 @@ struct UNWIND_INFO { uint16_t UnwindCodes[2]; }; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +union UNWIND_INFO_ARM { + DWORD HeaderData; + struct { + DWORD FunctionLength : 18; + DWORD Version : 2; + DWORD ExceptionDataPresent : 1; + DWORD EpilogInHeader : 1; + DWORD FunctionFragment : 1; + DWORD EpilogCount : 5; + DWORD CodeWords : 4; + }; +}; +#pragma clang diagnostic pop + extern "C" _Unwind_Reason_Code __libunwind_seh_personality( int, _Unwind_Action, uint64_t, _Unwind_Exception *, struct _Unwind_Context *); @@ -97,7 +121,9 @@ class _LIBUNWIND_HIDDEN DwarfFDECache { typedef typename A::pint_t pint_t; public: static constexpr pint_t kSearchAll = static_cast(-1); - static pint_t findFDE(pint_t mh, pint_t pc); + template + static pint_t findFDE(pint_t mh, typename R::link_hardened_reg_arg_t pc); + static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); static void removeAllIn(pint_t mh); static void iterateCacheEntries(void (*func)(unw_word_t ip_start, @@ -150,7 +176,9 @@ bool DwarfFDECache::_registeredForDyldUnloads = false; #endif template -typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { +template +typename DwarfFDECache::pint_t +DwarfFDECache::findFDE(pint_t mh, typename R::link_hardened_reg_arg_t pc) { pint_t result = 0; _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); for (entry *p = _buffer; p < _bufferUsed; ++p) { @@ -451,7 +479,9 @@ class _LIBUNWIND_HIDDEN AbstractUnwindCursor { virtual void getInfo(unw_proc_info_t *) { _LIBUNWIND_ABORT("getInfo not implemented"); } - virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); } + _LIBUNWIND_TRACE_NO_INLINE virtual void jumpto() { + _LIBUNWIND_ABORT("jumpto not implemented"); + } virtual bool isSignalFrame() { _LIBUNWIND_ABORT("isSignalFrame not implemented"); } @@ -468,6 +498,12 @@ class _LIBUNWIND_HIDDEN AbstractUnwindCursor { virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } #endif +#ifdef _LIBUNWIND_TRACE_RET_INJECT + virtual void setWalkedFrames(unsigned) { + _LIBUNWIND_ABORT("setWalkedFrames not implemented"); + } +#endif + #ifdef _AIX virtual uintptr_t getDataRelBase() { _LIBUNWIND_ABORT("getDataRelBase not implemented"); @@ -946,7 +982,8 @@ class UnwindCursor : public AbstractUnwindCursor{ virtual void setFloatReg(int, unw_fpreg_t); virtual int step(bool stage2 = false); virtual void getInfo(unw_proc_info_t *); - virtual void jumpto(); + _LIBUNWIND_TRACE_NO_INLINE + virtual void jumpto(); virtual bool isSignalFrame(); virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); @@ -955,6 +992,10 @@ class UnwindCursor : public AbstractUnwindCursor{ virtual void saveVFPAsX(); #endif +#ifdef _LIBUNWIND_TRACE_RET_INJECT + virtual void setWalkedFrames(unsigned); +#endif + #ifdef _AIX virtual uintptr_t getDataRelBase(); #endif @@ -1002,6 +1043,10 @@ class UnwindCursor : public AbstractUnwindCursor{ bool setInfoForSigReturn(Registers_arm64 &); int stepThroughSigReturn(Registers_arm64 &); #endif +#if defined(_LIBUNWIND_TARGET_LOONGARCH) + bool setInfoForSigReturn(Registers_loongarch &); + int stepThroughSigReturn(Registers_loongarch &); +#endif #if defined(_LIBUNWIND_TARGET_RISCV) bool setInfoForSigReturn(Registers_riscv &); int stepThroughSigReturn(Registers_riscv &); @@ -1016,7 +1061,7 @@ class UnwindCursor : public AbstractUnwindCursor{ template int stepThroughSigReturn(Registers &) { return UNW_STEP_END; } -#elif defined(_LIBUNWIND_TARGET_HAIKU) +#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) bool setInfoForSigReturn(); int stepThroughSigReturn(); #endif @@ -1024,21 +1069,34 @@ class UnwindCursor : public AbstractUnwindCursor{ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) bool getInfoFromFdeCie(const typename CFI_Parser::FDE_Info &fdeInfo, const typename CFI_Parser::CIE_Info &cieInfo, - pint_t pc, uintptr_t dso_base); + typename R::link_hardened_reg_arg_t pc, + uintptr_t dso_base); public: - bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, - uint32_t fdeSectionOffsetHint=0); + bool getInfoFromDwarfSection(typename R::link_hardened_reg_arg_t pc, + const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint = 0); + +private: 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::stepWithDwarf( - _addressSpace, (pint_t)this->getReg(UNW_REG_IP), - (pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2); + _addressSpace, pc, (pint_t)_info.unwind_info, _registers, + _isSignalFrame, stage2); } #endif #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) - bool getInfoFromCompactEncodingSection(pint_t pc, - const UnwindInfoSections §s); +public: + bool getInfoFromCompactEncodingSection(typename R::link_hardened_reg_arg_t pc, + const UnwindInfoSections §s); +private: int stepWithCompactEncoding(bool stage2 = false) { #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) if ( compactSaysUseDwarf() ) @@ -1325,9 +1383,12 @@ class UnwindCursor : public AbstractUnwindCursor{ bool _unwindInfoMissing; bool _isSignalFrame; #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \ - defined(_LIBUNWIND_TARGET_HAIKU) + defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) bool _isSigReturn = false; #endif +#ifdef _LIBUNWIND_TRACE_RET_INJECT + uint32_t _walkedFrames; +#endif }; template @@ -1346,7 +1407,7 @@ UnwindCursor::UnwindCursor(unw_context_t *context, A &as) "UnwindCursor<> does not fit in unw_cursor_t"); static_assert((alignof(UnwindCursor) <= alignof(unw_cursor_t)), "UnwindCursor<> requires more alignment than unw_cursor_t"); - memset(&_info, 0, sizeof(_info)); + memset(static_cast(&_info), 0, sizeof(_info)); } template @@ -1354,7 +1415,6 @@ UnwindCursor::UnwindCursor(A &as, void *arg) : _addressSpace(as),_registers(arg), _unwindInfoMissing(false), _isSignalFrame(false) { memset(&_info, 0, sizeof(_info)); - // FIXME // fill in _registers from thread arg } @@ -1396,7 +1456,46 @@ void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { } template void UnwindCursor::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::jumpto at UnwindCursor.hpp:1474:14 + frame #3: libunwind.1.dylib`__unw_resume at libunwind.cpp:375:7 + frame #4: libunwind.1.dylib`__unw_resume_with_frames_walked at libunwind.cpp:363:10 + frame #5: libunwind.1.dylib`unwind_phase2 at UnwindLevel1.c:328:9 + frame #6: libunwind.1.dylib`_Unwind_RaiseException at UnwindLevel1.c:480:10 + frame #7: libc++abi.dylib`__cxa_throw at cxa_exception.cpp:295:5 + ... + ``` + + If we look at the backtrace from `__libunwind_Registers_arm64_jumpto`, we see + there are 5 frames on the stack to reach `unwind_phase2`. However, only 4 of + them will never return, since `__libunwind_Registers_arm64_jumpto` returns + back to the landing pad, so we need to subtract 1 to the number of + `_EXTRA_LIBUNWIND_FRAMES_WALKED`. + */ + + static constexpr size_t _EXTRA_LIBUNWIND_FRAMES_WALKED = 5 - 1; + _registers.returnto(_walkedFrames + _EXTRA_LIBUNWIND_FRAMES_WALKED); +#else _registers.jumpto(); +#endif } #ifdef __arm__ @@ -1405,6 +1504,13 @@ template void UnwindCursor::saveVFPAsX() { } #endif +#ifdef _LIBUNWIND_TRACE_RET_INJECT +template +void UnwindCursor::setWalkedFrames(unsigned walkedFrames) { + _walkedFrames = walkedFrames; +} +#endif + #ifdef _AIX template uintptr_t UnwindCursor::getDataRelBase() { @@ -1653,11 +1759,11 @@ bool UnwindCursor::getInfoFromEHABISection( template bool UnwindCursor::getInfoFromFdeCie( const typename CFI_Parser::FDE_Info &fdeInfo, - const typename CFI_Parser::CIE_Info &cieInfo, pint_t pc, - uintptr_t dso_base) { + const typename CFI_Parser::CIE_Info &cieInfo, + typename R::link_hardened_reg_arg_t pc, uintptr_t dso_base) { typename CFI_Parser::PrologInfo prolog; - if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, - R::getArch(), &prolog)) { + if (CFI_Parser::template parseFDEInstructions( + _addressSpace, fdeInfo, cieInfo, pc, R::getArch(), &prolog)) { // Save off parsed FDE info _info.start_ip = fdeInfo.pcStart; _info.end_ip = fdeInfo.pcEnd; @@ -1677,9 +1783,9 @@ bool UnwindCursor::getInfoFromFdeCie( } template -bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, - const UnwindInfoSections §s, - uint32_t fdeSectionOffsetHint) { +bool UnwindCursor::getInfoFromDwarfSection( + typename R::link_hardened_reg_arg_t pc, const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint) { typename CFI_Parser::FDE_Info fdeInfo; typename CFI_Parser::CIE_Info cieInfo; bool foundFDE = false; @@ -1687,15 +1793,14 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, // If compact encoding table gave offset into dwarf section, go directly there if (fdeSectionOffsetHint != 0) { - foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, - sects.dwarf_section_length, - sects.dwarf_section + fdeSectionOffsetHint, - &fdeInfo, &cieInfo); + foundFDE = CFI_Parser::template findFDE( + _addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length, + sects.dwarf_section + fdeSectionOffsetHint, &fdeInfo, &cieInfo); } #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) if (!foundFDE && (sects.dwarf_index_section != 0)) { - foundFDE = EHHeaderParser::findFDE( + foundFDE = EHHeaderParser::template findFDE( _addressSpace, pc, sects.dwarf_index_section, (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo); } @@ -1703,20 +1808,20 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, if (!foundFDE) { // otherwise, search cache of previously found FDEs. - pint_t cachedFDE = DwarfFDECache::findFDE(sects.dso_base, pc); + pint_t cachedFDE = + DwarfFDECache::template findFDE(sects.dso_base, pc); if (cachedFDE != 0) { - foundFDE = - CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, - sects.dwarf_section_length, - cachedFDE, &fdeInfo, &cieInfo); + foundFDE = CFI_Parser::template findFDE( + _addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length, + cachedFDE, &fdeInfo, &cieInfo); foundInCache = foundFDE; } } if (!foundFDE) { // Still not found, do full scan of __eh_frame section. - foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, - sects.dwarf_section_length, 0, - &fdeInfo, &cieInfo); + foundFDE = CFI_Parser::template findFDE( + _addressSpace, pc, sects.dwarf_section, sects.dwarf_section_length, 0, + &fdeInfo, &cieInfo); } if (foundFDE) { if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) { @@ -1740,8 +1845,8 @@ bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) template -bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, - const UnwindInfoSections §s) { +bool UnwindCursor::getInfoFromCompactEncodingSection( + typename R::link_hardened_reg_arg_t pc, const UnwindInfoSections §s) { const bool log = false; if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", @@ -1972,6 +2077,16 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, personalityIndex * sizeof(uint32_t)); pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; personality = _addressSpace.getP(personalityPointer); +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + // The GOT for the personality function was signed address authenticated. + // Resign it as a regular function pointer. + const auto discriminator = ptrauth_blend_discriminator( + &_info.handler, __ptrauth_unwind_upi_handler_disc); + void *signedPtr = ptrauth_auth_and_resign( + (void *)personality, ptrauth_key_function_pointer, personalityPointer, + ptrauth_key_function_pointer, discriminator); + personality = (__typeof(personality))signedPtr; +#endif if (log) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " "personalityDelta=0x%08X, personality=0x%08llX\n", @@ -1985,7 +2100,11 @@ bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, _info.start_ip = funcStart; _info.end_ip = funcEnd; _info.lsda = lsda; - _info.handler = personality; + // We use memmove to copy the personality function as we have already manually + // re-signed the pointer, and assigning directly will attempt to incorrectly + // sign the already signed value. + memmove(reinterpret_cast(&_info.handler), + reinterpret_cast(&personality), sizeof(personality)); _info.gp = 0; _info.flags = 0; _info.format = encoding; @@ -2038,6 +2157,61 @@ bool UnwindCursor::getInfoFromSEH(pint_t pc) { _info.handler = 0; } } +#elif defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_ARM) + +#if defined(_LIBUNWIND_TARGET_AARCH64) +#define FUNC_LENGTH_UNIT 4 +#define XDATA_TYPE IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA +#else +#define FUNC_LENGTH_UNIT 2 +#define XDATA_TYPE UNWIND_INFO_ARM +#endif + if (unwindEntry->Flag != 0) { // Packed unwind info + _info.end_ip = + _info.start_ip + unwindEntry->FunctionLength * FUNC_LENGTH_UNIT; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + // Packed unwind info doesn't have an exception handler. + _info.lsda = 0; + _info.handler = 0; + } + } else { + XDATA_TYPE *xdata = + reinterpret_cast(base + unwindEntry->UnwindData); + _info.end_ip = _info.start_ip + xdata->FunctionLength * FUNC_LENGTH_UNIT; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + if (xdata->ExceptionDataPresent) { + uint32_t offset = 1; // The main xdata + uint32_t codeWords = xdata->CodeWords; + uint32_t epilogScopes = xdata->EpilogCount; + if (xdata->EpilogCount == 0 && xdata->CodeWords == 0) { + // The extension word has got the same layout for both ARM and ARM64 + uint32_t extensionWord = reinterpret_cast(xdata)[1]; + codeWords = (extensionWord >> 16) & 0xff; + epilogScopes = extensionWord & 0xffff; + offset++; + } + if (!xdata->EpilogInHeader) + offset += epilogScopes; + offset += codeWords; + uint32_t *exceptionHandlerInfo = + reinterpret_cast(xdata) + offset; + _dispContext.HandlerData = &exceptionHandlerInfo[1]; + _dispContext.LanguageHandler = reinterpret_cast( + base + exceptionHandlerInfo[0]); + _info.lsda = reinterpret_cast(_dispContext.HandlerData); + if (exceptionHandlerInfo[0]) + _info.handler = + reinterpret_cast(__libunwind_seh_personality); + else + _info.handler = 0; + } else { + _info.lsda = 0; + _info.handler = 0; + } + } + } #endif setLastPC(pc); return true; @@ -2579,15 +2753,23 @@ int UnwindCursor::stepWithTBTable(pint_t pc, tbtable *TBTable, template void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \ - defined(_LIBUNWIND_TARGET_HAIKU) + defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) _isSigReturn = false; #endif - pint_t pc = static_cast(this->getReg(UNW_REG_IP)); + typename R::reg_t rawPC = this->getReg(UNW_REG_IP); + #if defined(_LIBUNWIND_ARM_EHABI) // Remove the thumb bit so the IP represents the actual instruction address. // This matches the behaviour of _Unwind_GetIP on arm. - pc &= (pint_t)~0x1; + rawPC &= (pint_t)~0x1; +#endif + + typename R::link_reg_t pc; +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + _registers.loadAndAuthenticateLinkRegister(rawPC, &pc); +#else + pc = rawPC; #endif // Exit early if at the top of the stack. @@ -2622,7 +2804,7 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; - if (_addressSpace.findUnwindSections(pc, sects)) { + if (_addressSpace.template findUnwindSections(pc, sects)) { #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) // If there is a compact unwind encoding table, look there first. if (sects.compact_unwind_section != 0) { @@ -2678,8 +2860,8 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) // There is no static unwind info for this pc. Look to see if an FDE was // dynamically registered for it. - pint_t cachedFDE = DwarfFDECache::findFDE(DwarfFDECache::kSearchAll, - pc); + pint_t cachedFDE = + DwarfFDECache::template findFDE(DwarfFDECache::kSearchAll, pc); if (cachedFDE != 0) { typename CFI_Parser::FDE_Info fdeInfo; typename CFI_Parser::CIE_Info cieInfo; @@ -2691,7 +2873,7 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { // Lastly, ask AddressSpace object about platform specific ways to locate // other FDEs. pint_t fde; - if (_addressSpace.findOtherFDE(pc, fde)) { + if (_addressSpace.template findOtherFDE(pc, fde)) { typename CFI_Parser::FDE_Info fdeInfo; typename CFI_Parser::CIE_Info cieInfo; if (!CFI_Parser::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { @@ -2704,7 +2886,7 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \ - defined(_LIBUNWIND_TARGET_HAIKU) + defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) if (setInfoForSigReturn()) return; #endif @@ -2715,6 +2897,21 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \ defined(_LIBUNWIND_TARGET_AARCH64) + +/* + * The linux sigreturn restorer stub will always have the form: + * + * d2801168 movz x8, #0x8b + * d4000001 svc #0x0 + */ +#if defined(__AARCH64EB__) +#define MOVZ_X8_8B 0x681180d2 +#define SVC_0 0x010000d4 +#else +#define MOVZ_X8_8B 0xd2801168 +#define SVC_0 0xd4000001 +#endif + template bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) { // Look for the sigreturn trampoline. The trampoline's body is two @@ -2739,7 +2936,7 @@ bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) { return false; auto *instructions = reinterpret_cast(pc); // Look for instructions: mov x8, #0x8b; svc #0x0 - if (instructions[0] != 0xd2801168 || instructions[1] != 0xd4000001) + if (instructions[0] != MOVZ_X8_8B || instructions[1] != SVC_0) return false; _info = {}; @@ -2780,65 +2977,63 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) { _isSignalFrame = true; return UNW_STEP_SUCCESS; } +#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && + // defined(_LIBUNWIND_TARGET_AARCH64) -#elif defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64) -#include -#include +#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \ + defined(_LIBUNWIND_TARGET_LOONGARCH) +template +bool UnwindCursor::setInfoForSigReturn(Registers_loongarch &) { + const pint_t pc = static_cast(getReg(UNW_REG_IP)); + // The PC might contain an invalid address if the unwind info is bad, so + // directly accessing it could cause a SIGSEGV. + if (!isReadableAddr(pc)) + return false; + const auto *instructions = reinterpret_cast(pc); + // Look for the two instructions used in the sigreturn trampoline + // __vdso_rt_sigreturn: + // + // 0x03822c0b li a7,0x8b + // 0x002b0000 syscall 0 + if (instructions[0] != 0x03822c0b || instructions[1] != 0x002b0000) + return false; -extern "C" { -extern void *__gCommPageAddress; + _info = {}; + _info.start_ip = pc; + _info.end_ip = pc + 4; + _isSigReturn = true; + return true; } template -bool UnwindCursor::setInfoForSigReturn() { -#if defined(_LIBUNWIND_TARGET_X86_64) - addr_t signal_handler = - (((addr_t *)__gCommPageAddress)[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER] + - (addr_t)__gCommPageAddress); - addr_t signal_handler_ret = signal_handler + 45; -#endif - pint_t pc = static_cast(this->getReg(UNW_REG_IP)); - if (pc == signal_handler_ret) { - _info = {}; - _info.start_ip = signal_handler; - _info.end_ip = signal_handler_ret; - _isSigReturn = true; - return true; - } - return false; -} +int UnwindCursor::stepThroughSigReturn(Registers_loongarch &) { + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext_t struct: + // - 8-byte long (__uc_flags) + // - 8-byte pointer (*uc_link) + // - 24-byte uc_stack + // - 8-byte uc_sigmask + // - 120-byte of padding to allow sigset_t to be expanded in the future + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - struct sigcontext uc_mcontext + // [1] + // https://github.com/torvalds/linux/blob/master/arch/loongarch/kernel/signal.c + const pint_t kOffsetSpToSigcontext = 128 + 8 + 8 + 24 + 8 + 128; -template -int UnwindCursor::stepThroughSigReturn() { + const pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext; + _registers.setIP(_addressSpace.get64(sigctx), 0); + for (int i = UNW_LOONGARCH_R1; i <= UNW_LOONGARCH_R31; ++i) { + // skip R0 + uint64_t value = + _addressSpace.get64(sigctx + static_cast((i + 1) * 8)); + _registers.setRegister(i, value, 0); + } _isSignalFrame = true; - pint_t sp = _registers.getSP(); -#if defined(_LIBUNWIND_TARGET_X86_64) - vregs *regs = (vregs *)(sp + 0x70); - - _registers.setRegister(UNW_REG_IP, regs->rip); - _registers.setRegister(UNW_REG_SP, regs->rsp); - _registers.setRegister(UNW_X86_64_RAX, regs->rax); - _registers.setRegister(UNW_X86_64_RDX, regs->rdx); - _registers.setRegister(UNW_X86_64_RCX, regs->rcx); - _registers.setRegister(UNW_X86_64_RBX, regs->rbx); - _registers.setRegister(UNW_X86_64_RSI, regs->rsi); - _registers.setRegister(UNW_X86_64_RDI, regs->rdi); - _registers.setRegister(UNW_X86_64_RBP, regs->rbp); - _registers.setRegister(UNW_X86_64_R8, regs->r8); - _registers.setRegister(UNW_X86_64_R9, regs->r9); - _registers.setRegister(UNW_X86_64_R10, regs->r10); - _registers.setRegister(UNW_X86_64_R11, regs->r11); - _registers.setRegister(UNW_X86_64_R12, regs->r12); - _registers.setRegister(UNW_X86_64_R13, regs->r13); - _registers.setRegister(UNW_X86_64_R14, regs->r14); - _registers.setRegister(UNW_X86_64_R15, regs->r15); - // TODO: XMM -#endif - return UNW_STEP_SUCCESS; } #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && - // defined(_LIBUNWIND_TARGET_AARCH64) + // defined(_LIBUNWIND_TARGET_LOONGARCH) #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && \ defined(_LIBUNWIND_TARGET_RISCV) @@ -2997,6 +3192,96 @@ int UnwindCursor::stepThroughSigReturn(Registers_s390x &) { #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && // defined(_LIBUNWIND_TARGET_S390X) +#if defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) +template +bool UnwindCursor::setInfoForSigReturn() { + Dl_info dlinfo; + const auto isSignalHandler = [&](pint_t addr) { + if (!dladdr(reinterpret_cast(addr), &dlinfo)) + return false; + if (strcmp(dlinfo.dli_fname, "commpage")) + return false; + if (dlinfo.dli_sname == NULL || + strcmp(dlinfo.dli_sname, "commpage_signal_handler")) + return false; + return true; + }; + + pint_t pc = static_cast(this->getReg(UNW_REG_IP)); + if (!isSignalHandler(pc)) + return false; + + pint_t start = reinterpret_cast(dlinfo.dli_saddr); + + static size_t signalHandlerSize = 0; + if (signalHandlerSize == 0) { + size_t boundLow = 0; + size_t boundHigh = static_cast(-1); + + area_info areaInfo; + if (get_area_info(area_for(dlinfo.dli_saddr), &areaInfo) == B_OK) + boundHigh = areaInfo.size; + + while (boundLow < boundHigh) { + size_t boundMid = boundLow + ((boundHigh - boundLow) / 2); + pint_t test = start + boundMid; + if (test >= start && isSignalHandler(test)) + boundLow = boundMid + 1; + else + boundHigh = boundMid; + } + + signalHandlerSize = boundHigh; + } + + _info = {}; + _info.start_ip = start; + _info.end_ip = start + signalHandlerSize; + _isSigReturn = true; + + return true; +} + +template +int UnwindCursor::stepThroughSigReturn() { + _isSignalFrame = true; + +#if defined(_LIBUNWIND_TARGET_X86_64) + // Layout of the stack before function call: + // - signal_frame_data + // + siginfo_t (public struct, fairly stable) + // + ucontext_t (public struct, fairly stable) + // - mcontext_t -> Offset 0x70, this is what we want. + // - frame->ip (8 bytes) + // - frame->bp (8 bytes). Not written by the kernel, + // but the signal handler has a "push %rbp" instruction. + pint_t bp = this->getReg(UNW_X86_64_RBP); + vregs *regs = (vregs *)(bp + 0x70); + + _registers.setRegister(UNW_REG_IP, regs->rip); + _registers.setRegister(UNW_REG_SP, regs->rsp); + _registers.setRegister(UNW_X86_64_RAX, regs->rax); + _registers.setRegister(UNW_X86_64_RDX, regs->rdx); + _registers.setRegister(UNW_X86_64_RCX, regs->rcx); + _registers.setRegister(UNW_X86_64_RBX, regs->rbx); + _registers.setRegister(UNW_X86_64_RSI, regs->rsi); + _registers.setRegister(UNW_X86_64_RDI, regs->rdi); + _registers.setRegister(UNW_X86_64_RBP, regs->rbp); + _registers.setRegister(UNW_X86_64_R8, regs->r8); + _registers.setRegister(UNW_X86_64_R9, regs->r9); + _registers.setRegister(UNW_X86_64_R10, regs->r10); + _registers.setRegister(UNW_X86_64_R11, regs->r11); + _registers.setRegister(UNW_X86_64_R12, regs->r12); + _registers.setRegister(UNW_X86_64_R13, regs->r13); + _registers.setRegister(UNW_X86_64_R14, regs->r14); + _registers.setRegister(UNW_X86_64_R15, regs->r15); + // TODO: XMM +#endif // defined(_LIBUNWIND_TARGET_X86_64) + + return UNW_STEP_SUCCESS; +} +#endif // defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) + template int UnwindCursor::step(bool stage2) { (void)stage2; // Bottom of stack is defined is when unwind info cannot be found. @@ -3006,7 +3291,7 @@ template int UnwindCursor::step(bool stage2) { // Use unwinding info to modify register set as if function returned. int result; #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) || \ - defined(_LIBUNWIND_TARGET_HAIKU) + defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN) if (_isSigReturn) { result = this->stepThroughSigReturn(); } else @@ -3043,16 +3328,22 @@ template int UnwindCursor::step(bool stage2) { template void UnwindCursor::getInfo(unw_proc_info_t *info) { if (_unwindInfoMissing) - memset(info, 0, sizeof(*info)); + memset(static_cast(info), 0, sizeof(*info)); else *info = _info; } template bool UnwindCursor::getFunctionName(char *buf, size_t bufLen, - unw_word_t *offset) { - return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), - buf, bufLen, offset); + unw_word_t *offset) { +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + typename R::reg_t rawPC = this->getReg(UNW_REG_IP); + typename R::link_reg_t pc; + _registers.loadAndAuthenticateLinkRegister(rawPC, &pc); +#else + typename R::link_reg_t pc = this->getReg(UNW_REG_IP); +#endif + return _addressSpace.template findFunctionName(pc, buf, bufLen, offset); } #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) @@ -3087,7 +3378,7 @@ bool UnwindCursor::isReadableAddr(const pint_t addr) const { #endif #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS) -extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) { +extern "C" void *__libunwind_shstk_get_registers(unw_cursor_t *cursor) { AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->get_registers(); } diff --git a/src/native/external/llvm-libunwind/src/UnwindLevel1.c b/src/native/external/llvm-libunwind/src/UnwindLevel1.c index 7e785f4d31e716..7368b3cb803362 100644 --- a/src/native/external/llvm-libunwind/src/UnwindLevel1.c +++ b/src/native/external/llvm-libunwind/src/UnwindLevel1.c @@ -25,10 +25,10 @@ #include #include -#include "cet_unwind.h" #include "config.h" #include "libunwind.h" #include "libunwind_ext.h" +#include "shadow_stack_unwind.h" #include "unwind.h" #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ @@ -36,57 +36,77 @@ #ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND -// When CET is enabled, each "call" instruction will push return address to -// CET shadow stack, each "ret" instruction will pop current CET shadow stack -// top and compare it with target address which program will return. -// In exception handing, some stack frames will be skipped before jumping to -// landing pad and we must adjust CET shadow stack accordingly. -// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we -// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using -// a regular function call to avoid pushing to CET shadow stack again. +// When shadow stack is enabled, a separate stack containing only return +// addresses would be maintained. On function return, the return address would +// be compared to the popped address from shadow stack to ensure the return +// target is not tempered with. When unwinding, we're skipping the normal return +// procedure for multiple frames and thus need to pop the return addresses of +// the skipped frames from shadow stack to avoid triggering an exception (using +// `_LIBUNWIND_POP_SHSTK_SSP()`). Also, some architectures, like the x86-family +// CET, push the return adddresses onto shadow stack with common call +// instructions, so for these architectures, normal function calls should be +// avoided when invoking the `jumpto()` function. To do this, we use inline +// assemblies to "goto" the `jumpto()` for these architectures. #if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS) -#define __unw_phase2_resume(cursor, fn) \ +#define __unw_phase2_resume(cursor, payload) \ do { \ - (void)fn; \ - __unw_resume((cursor)); \ + __unw_resume_with_frames_walked((cursor), (payload)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_I386) -#define __cet_ss_step_size 4 -#define __unw_phase2_resume(cursor, fn) \ +#define __shstk_step_size (4) +#define __unw_phase2_resume(cursor, payload) \ do { \ - _LIBUNWIND_POP_CET_SSP((fn)); \ - void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ - void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ + _LIBUNWIND_POP_SHSTK_SSP((payload)); \ + void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ + void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ __asm__ volatile("push %%edi\n\t" \ "sub $4, %%esp\n\t" \ - "jmp *%%edx\n\t" :: "D"(cetRegContext), \ - "d"(cetJumpAddress)); \ + "jmp *%%edx\n\t" ::"D"(shstkRegContext), \ + "d"(shstkJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_X86_64) -#define __cet_ss_step_size 8 -#define __unw_phase2_resume(cursor, fn) \ +#define __shstk_step_size (8) +#define __unw_phase2_resume(cursor, payload) \ do { \ - _LIBUNWIND_POP_CET_SSP((fn)); \ - void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ - void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ - __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \ - "d"(cetJumpAddress)); \ + _LIBUNWIND_POP_SHSTK_SSP((payload)); \ + void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ + void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ + __asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \ + "d"(shstkJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_AARCH64) -#define __cet_ss_step_size 8 -#define __unw_phase2_resume(cursor, fn) \ +#define __shstk_step_size (8) +#define __unw_phase2_resume(cursor, payload) \ do { \ - _LIBUNWIND_POP_CET_SSP((fn)); \ - void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ - void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ + _LIBUNWIND_POP_SHSTK_SSP((payload)); \ + void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ + void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ __asm__ volatile("mov x0, %0\n\t" \ + "mov x1, #0\n\t" \ "br %1\n\t" \ : \ - : "r"(cetRegContext), "r"(cetJumpAddress) \ - : "x0"); \ + : "r"(shstkRegContext), "r"(shstkJumpAddress) \ + : "x0", "x1"); \ } while (0) #endif +// We need this helper function as the semantics of casting between integers and +// function pointers mean that we end up with a function pointer without the +// correct signature. Instead we assign to an integer with a matching schema, +// and then memmove the result into a variable of the correct type. This memmove +// is possible as `_Unwind_Personality_Fn` is a standard function pointer, and +// as such is not address diversified. +static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) { + uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, + 0, + ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn)) + reauthenticatedIntegerHandler = frameInfo->handler; + _Unwind_Personality_Fn handler; + memmove(&handler, (void *)&reauthenticatedIntegerHandler, + sizeof(_Unwind_Personality_Fn)); + return handler; +} + static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { __unw_init_local(cursor, uc); @@ -144,8 +164,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except // If there is a personality routine, ask it if it will want to stop at // this frame. if (frameInfo.handler != 0) { - _Unwind_Personality_Fn p = - (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + _Unwind_Personality_Fn p = get_handler_function(&frameInfo); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase1(ex_obj=%p): calling personality function %p", (void *)exception_object, (void *)(uintptr_t)p); @@ -181,14 +200,16 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except } return _URC_NO_REASON; } -extern int __unw_step_stage2(unw_cursor_t *); #if defined(_LIBUNWIND_USE_GCS) // Enable the GCS target feature to permit gcspop instructions to be used. -__attribute__((target("gcs"))) +__attribute__((target("+gcs"))) +#else +_LIBUNWIND_TRACE_NO_INLINE #endif static _Unwind_Reason_Code -unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { +unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object) { __unw_init_local(cursor, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p)", @@ -255,16 +276,16 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except } #endif -// In CET enabled environment, we check return address stored in normal stack -// against return address stored in CET shadow stack, if the 2 addresses don't +// In shadow stack enabled environment, we check return address stored in normal +// stack against return address stored in shadow stack, if the 2 addresses don't // match, it means return address in normal stack has been corrupted, we return // _URC_FATAL_PHASE2_ERROR. #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS) if (shadowStackTop != 0) { unw_word_t retInNormalStack; __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack); - unsigned long retInShadowStack = *( - unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked); + unsigned long retInShadowStack = + *(unsigned long *)(shadowStackTop + __shstk_step_size * framesWalked); if (retInNormalStack != retInShadowStack) return _URC_FATAL_PHASE2_ERROR; } @@ -272,8 +293,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except ++framesWalked; // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { - _Unwind_Personality_Fn p = - (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + _Unwind_Personality_Fn p = get_handler_function(&frameInfo); _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. @@ -329,12 +349,14 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except #if defined(_LIBUNWIND_USE_GCS) // Enable the GCS target feature to permit gcspop instructions to be used. -__attribute__((target("gcs"))) +__attribute__((target("+gcs"))) +#else +_LIBUNWIND_TRACE_NO_INLINE #endif static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, - _Unwind_Exception *exception_object, - _Unwind_Stop_Fn stop, void *stop_parameter) { + _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, + void *stop_parameter) { __unw_init_local(cursor, uc); // uc is initialized by __unw_getcontext in the parent frame. The first stack @@ -390,8 +412,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, ++framesWalked; // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { - _Unwind_Personality_Fn p = - (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + _Unwind_Personality_Fn p = get_handler_function(&frameInfo); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_obj=%p): calling personality function %p", (void *)exception_object, (void *)(uintptr_t)p); @@ -440,7 +461,6 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, return _URC_FATAL_PHASE2_ERROR; } - /// Called by __cxa_throw. Only returns if there is a fatal error. _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *exception_object) { @@ -594,6 +614,18 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { unw_cursor_t *cursor = (unw_cursor_t *)context; unw_word_t result; __unw_get_reg(cursor, UNW_REG_IP, &result); + +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + // If we are in an arm64e frame, then the PC should have been signed with the + // sp + { + unw_word_t sp; + __unw_get_reg(cursor, UNW_REG_SP, &sp); + result = (unw_word_t)ptrauth_auth_data((void *)result, + ptrauth_key_return_address, sp); + } +#endif + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, (void *)context, result); return (uintptr_t)result; diff --git a/src/native/external/llvm-libunwind/src/UnwindRegistersRestore.S b/src/native/external/llvm-libunwind/src/UnwindRegistersRestore.S index 1702d016c368ba..76a80344034f71 100644 --- a/src/native/external/llvm-libunwind/src/UnwindRegistersRestore.S +++ b/src/native/external/llvm-libunwind/src/UnwindRegistersRestore.S @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#if !defined(__wasm__) + #include "assembly.h" #define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 @@ -16,13 +18,17 @@ #if defined(_AIX) .toc +#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE) + .section .text,"axy",@progbits,unique,0 #else .text #endif -#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) +#if !defined(__USING_SJLJ_EXCEPTIONS__) #if defined(__i386__) +.att_syntax + DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto) # # extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); @@ -66,7 +72,8 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto) # skip fs # skip gs -#elif defined(__x86_64__) +#elif defined(__x86_64__) && !defined(__arm64ec__) +.att_syntax DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) # @@ -629,18 +636,35 @@ Lnovec: #elif defined(__aarch64__) +#ifndef __has_feature +#define __has_feature(__feature) 0 +#endif + #if defined(__ARM_FEATURE_GCS_DEFAULT) .arch_extension gcs #endif // -// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *, unsigned); // // On entry: // thread_state pointer is in x0 +// walked_frames counter is in x1 // .p2align 2 DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) + + #if defined(_LIBUNWIND_TRACE_RET_INJECT) + cbz w1, 1f + 0: + subs w1, w1, #1 + adr x16, #8 + ret x16 + + b.ne 0b + 1: + #endif + // skip restore of x0,x1 for now ldp x2, x3, [x0, #0x010] ldp x4, x5, [x0, #0x020] @@ -657,7 +681,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) ldp x24,x25, [x0, #0x0C0] ldp x26,x27, [x0, #0x0D0] ldp x28,x29, [x0, #0x0E0] - ldr x30, [x0, #0x100] // restore pc into lr + #if defined(__ARM_FP) && __ARM_FP != 0 ldp d0, d1, [x0, #0x110] ldp d2, d3, [x0, #0x120] @@ -681,7 +705,18 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) // context struct, because it is allocated on the stack, and an exception // could clobber the de-allocated portion of the stack after sp has been // restored. - ldr x16, [x0, #0x0F8] + + ldr x16, [x0, #0x0F8] // load sp into scratch + ldr lr, [x0, #0x100] // restore pc into lr + +#if __has_feature(ptrauth_calls) + // The LR is signed with its address inside the register state. Time + // to resign to be a regular ROP protected signed pointer + add x1, x0, #0x100 + autib lr, x1 + pacib lr, x16 // signed the scratch register for sp +#endif + ldp x0, x1, [x0, #0x000] // restore x0,x1 mov sp,x16 // restore sp #if defined(__ARM_FEATURE_GCS_DEFAULT) @@ -694,7 +729,12 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) gcspushm x30 Lnogcs: #endif + +#if __has_feature(ptrauth_calls) + retab +#else ret x30 // jump to pc +#endif #elif defined(__arm__) && !defined(__APPLE__) @@ -1044,9 +1084,10 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) lw $27, (4 * 27)($4) lw $28, (4 * 28)($4) lw $29, (4 * 29)($4) - lw $30, (4 * 30)($4) // load new pc into ra lw $31, (4 * 32)($4) + // MIPS 1 has load delay slot. Ensure lw $31 and jr are separated by an instruction. + lw $30, (4 * 30)($4) // jump to ra, load a0 in the delay slot jr $31 lw $4, (4 * 4)($4) @@ -1082,11 +1123,13 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv) ld $2, (8 * 2)($4) ld $3, (8 * 3)($4) // skip a0 for now - .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 + .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 ld $\i, (8 * \i)($4) .endr // load new pc into ra ld $31, (8 * 32)($4) + // MIPS 1 has load delay slot. Ensure lw $31 and jr are separated by an instruction. + ld $30, (8 * 30)($4) // jump to ra, load a0 in the delay slot jr $31 ld $4, (8 * 4)($4) @@ -1250,7 +1293,8 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv) #endif -#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */ +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ NO_EXEC_STACK_DIRECTIVE +#endif /* !defined(__wasm__) */ diff --git a/src/native/external/llvm-libunwind/src/UnwindRegistersSave.S b/src/native/external/llvm-libunwind/src/UnwindRegistersSave.S index a489a8ba6df159..f988fd461def17 100644 --- a/src/native/external/llvm-libunwind/src/UnwindRegistersSave.S +++ b/src/native/external/llvm-libunwind/src/UnwindRegistersSave.S @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#if !defined(__wasm__) + #include "assembly.h" #define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 @@ -16,13 +18,16 @@ #if defined(_AIX) .toc +#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE) + .section .text,"axy",@progbits,unique,0 #else .text #endif -#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) +#if !defined(__USING_SJLJ_EXCEPTIONS__) #if defined(__i386__) +.att_syntax # # extern int __unw_getcontext(unw_context_t* thread_state) @@ -65,7 +70,49 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) xorl %eax, %eax # return UNW_ESUCCESS ret +#elif defined(__arm64ec__) + +// +// extern int __unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in x0 +// + .section .text,"xr",discard,"#__unw_getcontext" + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION("#__unw_getcontext") + stp x8, x27, [x0, #0x000] // rax, rbx + stp x0, x1, [x0, #0x010] // rcx, rdx + stp x26,x25, [x0, #0x020] // rdi, rsi + mov x1, sp + stp fp, x1, [x0, #0x030] // rbp, rsp + stp x2, x3, [x0, #0x040] // r8, r9 + stp x4, x5, [x0, #0x050] // r10, r11 + stp x19,x20, [x0, #0x060] // r12, r13 + stp x21,x22, [x0, #0x070] // r14, r15 + str x30, [x0, #0x080] // store return address as pc + stp q0, q1, [x0, #0x0b0] // xmm0, xmm1 + stp q2, q3, [x0, #0x0d0] // xmm2, xmm3 + stp q4, q5, [x0, #0x0f0] // xmm4, xmm5 + stp q6, q7, [x0, #0x110] // xmm6, xmm7 + stp q8, q9, [x0, #0x130] // xmm8, xmm9 + stp q10,q11, [x0, #0x150] // xmm10,xmm11 + stp q12,q13, [x0, #0x170] // xmm12,xmm13 + stp q14,q15, [x0, #0x190] // xmm14,xmm15 + mov x0, #0 // return UNW_ESUCCESS + ret + + .weak_anti_dep __unw_getcontext + .set __unw_getcontext, "#__unw_getcontext" + + .section .hybmp$x,"yi" + .symidx "#__unw_getcontext" + .symidx $ientry_thunk$cdecl$i8$i8 + .word 1 + .text + #elif defined(__x86_64__) +.att_syntax # # extern int __unw_getcontext(unw_context_t* thread_state) @@ -718,6 +765,10 @@ LnoR2Fix: #elif defined(__aarch64__) +#ifndef __has_feature +#define __has_feature(__feature) 0 +#endif + // // extern int __unw_getcontext(unw_context_t* thread_state) // @@ -726,6 +777,11 @@ LnoR2Fix: // .p2align 2 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + +#if __has_feature(ptrauth_calls) + pacibsp +#endif + stp x0, x1, [x0, #0x000] stp x2, x3, [x0, #0x010] stp x4, x5, [x0, #0x020] @@ -766,7 +822,74 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) str d31, [x0, #0x208] #endif mov x0, #0 // return UNW_ESUCCESS + +#if __has_feature(ptrauth_calls) + retab +#else + ret +#endif + +// +// extern "C" int64_t __libunwind_Registers_arm64_za_disable() +// +// This function implements the requirements of the __arm_za_disable ABI +// routine, except that it will not abort; it will return a non-zero value +// to signify the routine failed. +// +// Note: This function uses SME instructions. It must only be called if SME +// has been confirmed to be available. +// +// On return: +// +// A status is placed in x0. A zero value indicates success; any non-zero +// value indicates failure. +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_za_disable) + .variant_pcs __libunwind_Registers_arm64_za_disable +#if __has_feature(ptrauth_calls) + pacibsp +#endif + // If TPIDR2_EL0 is null, the subroutine just disables ZA. + .inst 0xd53bd0b0 // mrs x16, TPIDR2_EL0 + cbz x16, 1f + + // If any of the reserved bytes in the first 16 bytes of the TPIDR2 block are + // nonzero, return a non-zero value (libunwind will then abort). + ldrh w0, [x16, #10] + cbnz w0, 2f + ldr w0, [x16, #12] + cbnz w0, 2f + + // If num_za_save_slices is zero, the subroutine just disables ZA. + ldrh w0, [x16, #8] + cbz x0, 1f + + // If za_save_buffer is NULL, the subroutine just disables ZA. + ldr x16, [x16] + cbz x16, 1f + + // Store ZA to za_save_buffer. + mov x15, xzr +0: + .inst 0xe1206200 // str za[w15,0], [x16] + .inst 0x04305830 // addsvl x16, x16, #1 + add x15, x15, #1 + cmp x0, x15 + b.ne 0b +1: + // * Set TPIDR2_EL0 to null. + .inst 0xd51bd0bf // msr TPIDR2_EL0, xzr + // * Set PSTATE.ZA to 0. + .inst 0xd503447f // smstop za + // * Return zero (success) + mov x0, xzr +2: +#if __has_feature(ptrauth_calls) + retab +#else ret +#endif #elif defined(__arm__) && !defined(__APPLE__) @@ -1181,8 +1304,18 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) #endif +#ifdef __arm64ec__ + .globl "#unw_getcontext" + .set "#unw_getcontext", "#__unw_getcontext" + .weak_anti_dep unw_getcontext + .set unw_getcontext, "#unw_getcontext" + EXPORT_SYMBOL(unw_getcontext) +#else WEAK_ALIAS(__unw_getcontext, unw_getcontext) +#endif -#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */ +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ NO_EXEC_STACK_DIRECTIVE + +#endif /* !defined(__wasm__) */ diff --git a/src/native/external/llvm-libunwind/src/Unwind_AIXExtras.cpp b/src/native/external/llvm-libunwind/src/Unwind_AIXExtras.cpp index 66194ab4a16ba2..97b6c3e5e01aea 100644 --- a/src/native/external/llvm-libunwind/src/Unwind_AIXExtras.cpp +++ b/src/native/external/llvm-libunwind/src/Unwind_AIXExtras.cpp @@ -10,6 +10,7 @@ // This file is only used for AIX. #if defined(_AIX) +#include "AddressSpace.hpp" #include "config.h" #include "libunwind_ext.h" #include diff --git a/src/native/external/llvm-libunwind/src/assembly.h b/src/native/external/llvm-libunwind/src/assembly.h index f8e83e138eff50..84c9d526f1d759 100644 --- a/src/native/external/llvm-libunwind/src/assembly.h +++ b/src/native/external/llvm-libunwind/src/assembly.h @@ -15,7 +15,7 @@ #ifndef UNWIND_ASSEMBLY_H #define UNWIND_ASSEMBLY_H -#if defined(__linux__) && defined(__CET__) +#if defined(__CET__) #include #define _LIBUNWIND_CET_ENDBR _CET_ENDBR #else @@ -132,6 +132,10 @@ #if defined(__APPLE__) +#if defined(__aarch64__) || defined(__arm64__) || defined(__arm64e__) +#define _LIBUNWIND_TRACE_RET_INJECT 1 +#endif + #define SYMBOL_IS_FUNC(name) #define HIDDEN_SYMBOL(name) .private_extern name #if defined(_LIBUNWIND_HIDE_SYMBOLS) diff --git a/src/native/external/llvm-libunwind/src/config.h b/src/native/external/llvm-libunwind/src/config.h index deb5a4d4d73d46..960e1ffe71abbd 100644 --- a/src/native/external/llvm-libunwind/src/config.h +++ b/src/native/external/llvm-libunwind/src/config.h @@ -28,6 +28,9 @@ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 #endif + #if defined(__aarch64__) || defined(__arm64__) || defined(__arm64e__) + #define _LIBUNWIND_TRACE_RET_INJECT 1 + #endif #elif defined(_WIN32) #ifdef __SEH__ #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1 @@ -61,6 +64,12 @@ #endif #endif +#ifdef _LIBUNWIND_TRACE_RET_INJECT +#define _LIBUNWIND_TRACE_NO_INLINE __attribute__((noinline, disable_tail_calls)) +#else +#define _LIBUNWIND_TRACE_NO_INLINE +#endif + #if defined(_LIBUNWIND_HIDE_SYMBOLS) // The CMake file passes -fvisibility=hidden to control ELF/Mach-O visibility. #define _LIBUNWIND_EXPORT @@ -90,9 +99,15 @@ __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \ _LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname)) #elif defined(__ELF__) || defined(_AIX) || defined(__wasm__) +#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ >= 9) +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ + __attribute__((weak, alias(#name), copy(name))); +#else #define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ __attribute__((weak, alias(#name))); +#endif #elif defined(_WIN32) #if defined(__MINGW32__) #define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ diff --git a/src/native/external/llvm-libunwind/src/libunwind.cpp b/src/native/external/llvm-libunwind/src/libunwind.cpp index fec5fe8799f91b..2f2032c6c28147 100644 --- a/src/native/external/llvm-libunwind/src/libunwind.cpp +++ b/src/native/external/llvm-libunwind/src/libunwind.cpp @@ -125,7 +125,49 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_proc_info_t info; // First, get the FDE for the old location and then update it. co->getInfo(&info); - co->setInfoBasedOnIPRegister(false); + + pint_t sp = (pint_t)co->getReg(UNW_REG_SP); + +#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING) + { + // It is only valid to set the IP within the current function. This is + // important for ptrauth, otherwise the IP cannot be correctly signed. + // The current signature of `value` is via the schema: + // __ptrauth(ptrauth_key_return_address, <>, 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(&authenticated_value), + reinterpret_cast(&opaque_value), + sizeof(authenticated_value)); + if (authenticated_value < info.start_ip || + authenticated_value > info.end_ip) + _LIBUNWIND_ABORT("PC vs frame info mismatch"); + + // PC should have been signed with the sp, so we verify that + // roundtripping does not fail. The `ptrauth_auth_and_resign` is + // guaranteed to trap on authentication failure even without FPAC + // feature. + pint_t pc = (pint_t)co->getReg(UNW_REG_IP); + if (ptrauth_auth_and_resign((void *)pc, ptrauth_key_return_address, sp, + ptrauth_key_return_address, + sp) != (void *)pc) { + _LIBUNWIND_LOG( + "Bad unwind with PAuth-enabled ABI (0x%zX, 0x%zX)->0x%zX\n", pc, + sp, + (pint_t)ptrauth_auth_data((void *)pc, ptrauth_key_return_address, + sp)); + _LIBUNWIND_ABORT("Bad unwind with PAuth-enabled ABI"); + } + } +#endif + // If the original call expects stack adjustment, perform this now. // Normal frame unwinding would have included the offset already in the // CFA computation. @@ -133,7 +175,11 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, // this should actually be - info.gp. LLVM doesn't currently support // any such platforms and Clang doesn't export a macro for them. if (info.gp) - co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp, 0); + co->setReg(UNW_REG_SP, sp + info.gp, 0); + co->setReg(UNW_REG_IP, value, (pint_t)pos); + co->setInfoBasedOnIPRegister(false); + } else { + co->setReg(regNum, (pint_t)value, (pint_t)pos); } return UNW_ESUCCESS; } @@ -220,7 +266,27 @@ _LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor, } _LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info) -/// Resume execution at cursor position (aka longjump). +/// Rebalance the execution flow by injecting the right amount of `ret` +/// instruction relatively to the amount of `walkedFrames` then resume execution +/// at cursor position (aka longjump). +_LIBUNWIND_HIDDEN int __unw_resume_with_frames_walked(unw_cursor_t *cursor, + unsigned walkedFrames) { + _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p, walkedFrames=%u)", + static_cast(cursor), walkedFrames); +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + // Inform the ASan runtime that now might be a good time to clean stuff up. + __asan_handle_no_return(); +#endif +#ifdef _LIBUNWIND_TRACE_RET_INJECT + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->setWalkedFrames(walkedFrames); +#endif + return __unw_resume(cursor); +} +_LIBUNWIND_WEAK_ALIAS(__unw_resume_with_frames_walked, + unw_resume_with_frames_walked) + +/// Legacy function. Resume execution at cursor position (aka longjump). _LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) { _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast(cursor)); #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) @@ -362,6 +428,41 @@ void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) { } #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +/// Maps the UNW_* error code to a textual representation +_LIBUNWIND_HIDDEN const char *__unw_strerror(int error_code) { + switch (error_code) { + case UNW_ESUCCESS: + return "no error"; + case UNW_EUNSPEC: + return "unspecified (general) error"; + case UNW_ENOMEM: + return "out of memory"; + case UNW_EBADREG: + return "bad register number"; + case UNW_EREADONLYREG: + return "attempt to write read-only register"; + case UNW_ESTOPUNWIND: + return "stop unwinding"; + case UNW_EINVALIDIP: + return "invalid IP"; + case UNW_EBADFRAME: + return "bad frame"; + case UNW_EINVAL: + return "unsupported operation or bad value"; + case UNW_EBADVERSION: + return "unwind info has unsupported version"; + case UNW_ENOINFO: + return "no unwind info found"; +#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY) + case UNW_ECROSSRASIGNING: + return "cross unwind with return address signing"; +#endif + } + return "invalid error code"; +} +_LIBUNWIND_WEAK_ALIAS(__unw_strerror, unw_strerror) + #endif // !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) #ifdef __APPLE__ diff --git a/src/native/external/llvm-libunwind/src/libunwind_ext.h b/src/native/external/llvm-libunwind/src/libunwind_ext.h index db55939971264e..da77ea3c4dab75 100644 --- a/src/native/external/llvm-libunwind/src/libunwind_ext.h +++ b/src/native/external/llvm-libunwind/src/libunwind_ext.h @@ -26,11 +26,16 @@ extern "C" { extern int __unw_getcontext(unw_context_t *); extern int __unw_init_local(unw_cursor_t *, unw_context_t *); extern int __unw_step(unw_cursor_t *); +extern int __unw_step_stage2(unw_cursor_t *); extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *); extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *); extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t, unw_word_t *); extern int __unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t); -extern int __unw_resume(unw_cursor_t *); +_LIBUNWIND_TRACE_NO_INLINE + extern int __unw_resume_with_frames_walked(unw_cursor_t *, unsigned); +// `__unw_resume` is a legacy function. Use `__unw_resume_with_frames_walked` instead. +_LIBUNWIND_TRACE_NO_INLINE + extern int __unw_resume(unw_cursor_t *); #ifdef __arm__ /* Save VFP registers in FSTMX format (instead of FSTMD). */ @@ -42,6 +47,7 @@ extern int __unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *); extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t); extern int __unw_is_signal_frame(unw_cursor_t *); extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *); +extern const char *__unw_strerror(int); extern int __unw_get_save_loc(unw_cursor_t *, int, unw_save_loc_t *); #if defined(_AIX) diff --git a/src/native/external/llvm-libunwind/src/cet_unwind.h b/src/native/external/llvm-libunwind/src/shadow_stack_unwind.h similarity index 83% rename from src/native/external/llvm-libunwind/src/cet_unwind.h rename to src/native/external/llvm-libunwind/src/shadow_stack_unwind.h index 47d7616a7322c3..b00ca2c9327c74 100644 --- a/src/native/external/llvm-libunwind/src/cet_unwind.h +++ b/src/native/external/llvm-libunwind/src/shadow_stack_unwind.h @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBUNWIND_CET_UNWIND_H -#define LIBUNWIND_CET_UNWIND_H +#ifndef LIBUNWIND_SHADOW_STACK_UNWIND_H +#define LIBUNWIND_SHADOW_STACK_UNWIND_H #include "libunwind.h" -// Currently, CET is implemented on Linux x86 platforms. -#if defined(_LIBUNWIND_TARGET_LINUX) && defined(__CET__) && defined(__SHSTK__) +// Currently, CET is implemented on some ELF x86 platforms. +#if defined(__CET__) && defined(__SHSTK__) #define _LIBUNWIND_USE_CET 1 #endif @@ -21,7 +21,7 @@ #include #include -#define _LIBUNWIND_POP_CET_SSP(x) \ +#define _LIBUNWIND_POP_SHSTK_SSP(x) \ do { \ unsigned long ssp = _get_ssp(); \ if (ssp != 0) { \ @@ -46,7 +46,7 @@ #define _LIBUNWIND_USE_GCS 1 #endif -#define _LIBUNWIND_POP_CET_SSP(x) \ +#define _LIBUNWIND_POP_SHSTK_SSP(x) \ do { \ if (__chkfeat(_CHKFEAT_GCS)) { \ unsigned tmp = (x); \ @@ -57,7 +57,7 @@ #endif -extern void *__libunwind_cet_get_registers(unw_cursor_t *); -extern void *__libunwind_cet_get_jump_target(void); +extern void *__libunwind_shstk_get_registers(unw_cursor_t *); +extern void *__libunwind_shstk_get_jump_target(void); #endif diff --git a/src/native/external/llvm-libunwind/test/CMakeLists.txt b/src/native/external/llvm-libunwind/test/CMakeLists.txt index c222c0bdbf5af1..2559ab34f9d5b7 100644 --- a/src/native/external/llvm-libunwind/test/CMakeLists.txt +++ b/src/native/external/llvm-libunwind/test/CMakeLists.txt @@ -8,19 +8,22 @@ macro(pythonize_bool var) endif() endmacro() +# Install targets required to run libunwind tests into a temporary location. +# +# This ensures that we run the tests against the final installed products, which +# is closer to what we actually ship than the contents of the build tree. set(LIBUNWIND_TESTING_INSTALL_PREFIX "${LIBUNWIND_BINARY_DIR}/test-suite-install") -add_custom_target(libunwind-install-unwind-for-testing - DEPENDS unwind-headers - unwind - COMMAND ${CMAKE_COMMAND} -E make_directory "${LIBUNWIND_TESTING_INSTALL_PREFIX}" - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=unwind-headers - -DCMAKE_INSTALL_PREFIX="${LIBUNWIND_TESTING_INSTALL_PREFIX}" - -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=unwind - -DCMAKE_INSTALL_PREFIX="${LIBUNWIND_TESTING_INSTALL_PREFIX}" - -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") +set(libunwind_test_suite_install_targets unwind-headers unwind) +if ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES) + list(APPEND libunwind_test_suite_install_targets cxx-headers cxx cxx-modules cxxabi-headers cxxabi) +endif() +foreach(target IN LISTS libunwind_test_suite_install_targets) + add_custom_target(libunwind-test-suite-install-${target} DEPENDS "${target}" + COMMAND "${CMAKE_COMMAND}" --install "${CMAKE_BINARY_DIR}" + --prefix "${LIBUNWIND_TESTING_INSTALL_PREFIX}" + --component "${target}") + add_dependencies(unwind-test-depends libunwind-test-suite-install-${target}) +endforeach() pythonize_bool(LIBUNWIND_ENABLE_CET) pythonize_bool(LIBUNWIND_ENABLE_GCS) @@ -62,4 +65,4 @@ configure_lit_site_cfg( add_lit_testsuite(check-unwind "Running libunwind tests" ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS libunwind-install-unwind-for-testing) + DEPENDS unwind-test-depends) diff --git a/src/native/external/llvm-libunwind/test/aarch64_vg_unwind.pass.cpp b/src/native/external/llvm-libunwind/test/aarch64_vg_unwind.pass.cpp new file mode 100644 index 00000000000000..d0c623b155092d --- /dev/null +++ b/src/native/external/llvm-libunwind/test/aarch64_vg_unwind.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: target={{aarch64-.+}} +// UNSUPPORTED: target={{.*-windows.*}} + +#include +#include +#include + +// Basic test of VG (Vector Granule) unwinding. This is meant to mimic SVE/SME +// unwind info without requiring those features for this test. + +#define VG_REGNUM 46 + +__attribute__((noinline)) void baz() { + // The previous value of VG is 2 + asm(".cfi_escape 0x16, 0x2e, 0x01, 0x32"); + + unw_context_t context; + unw_cursor_t cursor; + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + // Note: At this point VG is not defined (until we unw_step). + + uint16_t expected_vgs[]{/*qux*/ 2, /*bar*/ 2, /*foo*/ 8, /*main*/ 2}; + for (uint16_t expected_vg : expected_vgs) { + unw_step(&cursor); + unw_word_t vg; + unw_get_reg(&cursor, VG_REGNUM, &vg); + if (vg != expected_vg) + exit(1); + } + exit(0); +} + +__attribute__((noinline)) void qux() { baz(); } + +__attribute__((noinline)) void bar() { + // The previous value of VG is 8 + asm(".cfi_escape 0x16, 0x2e, 0x01, 0x38"); + // The previous value of W21 is VG (used to force an evaluation of VG). + asm(".cfi_escape 0x16, 0x15, 0x03, 0x92, 0x2e, 0x00"); + + // smstop sm + qux(); + // smstart sm +} +__attribute__((noinline)) void foo() { + // The previous value of VG is 2 + asm(".cfi_escape 0x16, 0x2e, 0x01, 0x32"); + // The previous value of W21 is VG (used to force an evaluation of VG). + asm(".cfi_escape 0x16, 0x15, 0x03, 0x92, 0x2e, 0x00"); + + // smstart sm + bar(); + // smstop sm +} + +int main(int, char **) { + foo(); + return 0; +} diff --git a/src/native/external/llvm-libunwind/test/aarch64_za_unwind.pass.cpp b/src/native/external/llvm-libunwind/test/aarch64_za_unwind.pass.cpp new file mode 100644 index 00000000000000..9f6b106a21fecb --- /dev/null +++ b/src/native/external/llvm-libunwind/test/aarch64_za_unwind.pass.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: target={{aarch64-.+}} +// UNSUPPORTED: target={{.*-windows.*}} + +#include +#include +#include +#include +#include +#include + +// Basic test of unwinding with SME lazy saves. This tests libunwind disables ZA +// (and commits a lazy save of ZA) before resuming from unwinding. + +// Note: This test requires SME (and is setup to pass on targets without SME). + +static bool checkHasSME() { + constexpr int hwcap2_sme = (1 << 23); + unsigned long hwcap2 = getauxval(AT_HWCAP2); + return (hwcap2 & hwcap2_sme) != 0; +} + +struct TPIDR2Block { + void *za_save_buffer; + uint64_t num_save_slices; +}; + +__attribute__((noinline)) void private_za() { + // Note: Lazy save active on entry to function. + unw_context_t context; + unw_cursor_t cursor; + + unw_getcontext(&context); + unw_init_local(&cursor, &context); + unw_step(&cursor); + unw_resume(&cursor); +} + +bool isZAOn() { + register uint64_t svcr asm("x20"); + asm(".inst 0xd53b4254" : "=r"(svcr)); + return (svcr & 0b10) != 0; +} + +__attribute__((noinline)) void za_function_with_lazy_save() { + register uint64_t tmp asm("x8"); + + // SMSTART ZA (should zero ZA) + asm(".inst 0xd503457f"); + + // RDSVL x8, #1 (read streaming vector length) + asm(".inst 0x04bf5828" : "=r"(tmp)); + + // Allocate and fill ZA save buffer with 0xAA. + size_t buffer_size = tmp * tmp; + uint8_t *za_save_buffer = (uint8_t *)alloca(buffer_size); + memset(za_save_buffer, 0xAA, buffer_size); + + TPIDR2Block block = {za_save_buffer, tmp}; + tmp = reinterpret_cast(&block); + + // MRS TPIDR2_EL0, x8 (setup lazy save of ZA) + asm(".inst 0xd51bd0a8" ::"r"(tmp)); + + // ZA should be on before unwinding. + if (!isZAOn()) { + fprintf(stderr, __FILE__ ": fail (ZA not on before call)\n"); + abort(); + } else { + fprintf(stderr, __FILE__ ": pass (ZA on before call)\n"); + } + + private_za(); + + // ZA should be off after unwinding. + if (isZAOn()) { + fprintf(stderr, __FILE__ ": fail (ZA on after unwinding)\n"); + abort(); + } else { + fprintf(stderr, __FILE__ ": pass (ZA off after unwinding)\n"); + } + + // MRS x8, TPIDR2_EL0 (read TPIDR2_EL0) + asm(".inst 0xd53bd0a8" : "=r"(tmp)); + // ZA should have been saved (TPIDR2_EL0 zero). + if (tmp != 0) { + fprintf(stderr, __FILE__ ": fail (TPIDR2_EL0 non-null after unwinding)\n"); + abort(); + } else { + fprintf(stderr, __FILE__ ": pass (TPIDR2_EL0 null after unwinding)\n"); + } + + // ZA (all zero) should have been saved to the buffer. + for (unsigned i = 0; i < buffer_size; ++i) { + if (za_save_buffer[i] != 0) { + fprintf(stderr, + __FILE__ ": fail (za_save_buffer non-zero after unwinding)\n"); + abort(); + } + } + fprintf(stderr, __FILE__ ": pass (za_save_buffer zero'd after unwinding)\n"); +} + +int main(int, char **) { + if (!checkHasSME()) { + fprintf(stderr, __FILE__ ": pass (no SME support)\n"); + return 0; // Pass (SME is required for this test to run). + } + za_function_with_lazy_save(); + return 0; +} diff --git a/src/native/external/llvm-libunwind/test/aix_signal_unwind.pass.sh.S b/src/native/external/llvm-libunwind/test/aix_signal_unwind.pass.sh.S index 2c0cf140fe2672..056575745ea187 100644 --- a/src/native/external/llvm-libunwind/test/aix_signal_unwind.pass.sh.S +++ b/src/native/external/llvm-libunwind/test/aix_signal_unwind.pass.sh.S @@ -126,10 +126,11 @@ extern "C" __attribute__((noinline)) void foo() { bar(); } -int main() { +int main(int, char**) { // Set signal handler for SIGSEGV. signal(SIGSEGV, handler); foo(); + return 0; } #else // Assembly code for abc(). @@ -168,7 +169,7 @@ L..abc0: .vbyte 4, 0x00000000 # Traceback table begin .byte 0x00 # Version = 0 .byte 0x09 # Language = CPlusPlus - .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue + .byte 0x20 # -IsGlobalLinkage, -IsOutOfLineEpilogOrPrologue # +HasTraceBackTableOffset, -IsInternalProcedure # -HasControlledStorage, -IsTOCless # -IsFloatingPointPresent @@ -218,7 +219,7 @@ L..abc0: .vbyte 4, 0x00000000 # Traceback table begin .byte 0x00 # Version = 0 .byte 0x09 # Language = CPlusPlus - .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue + .byte 0x20 # -IsGlobalLinkage, -IsOutOfLineEpilogOrPrologue # +HasTraceBackTableOffset, -IsInternalProcedure # -HasControlledStorage, -IsTOCless # -IsFloatingPointPresent diff --git a/src/native/external/llvm-libunwind/test/bad_unwind_info.pass.cpp b/src/native/external/llvm-libunwind/test/bad_unwind_info.pass.cpp index b3284e8daed71f..332b661d2e98f1 100644 --- a/src/native/external/llvm-libunwind/test/bad_unwind_info.pass.cpp +++ b/src/native/external/llvm-libunwind/test/bad_unwind_info.pass.cpp @@ -10,7 +10,9 @@ // Ensure that libunwind doesn't crash on invalid info; the Linux aarch64 // sigreturn frame check would previously attempt to access invalid memory in // this scenario. -// REQUIRES: target={{(aarch64|s390x|x86_64)-.+linux.*}} +// REQUIRES: target={{(aarch64|s390x|x86_64)-.+}} +// UNSUPPORTED: target={{.*-windows.*}} +// UNSUPPORTED: target={{.*-apple.*}} // GCC doesn't support __attribute__((naked)) on AArch64. // UNSUPPORTED: gcc @@ -77,4 +79,7 @@ extern "C" void stepper() { assert(unw_step(&cursor) <= 0); } -int main() { bad_unwind_info(); } +int main(int, char **) { + bad_unwind_info(); + return 0; +} diff --git a/src/native/external/llvm-libunwind/test/configs/apple-libunwind-system.cfg.in b/src/native/external/llvm-libunwind/test/configs/apple-libunwind-system.cfg.in index e5a7c983562a60..252448a756be9c 100644 --- a/src/native/external/llvm-libunwind/test/configs/apple-libunwind-system.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/apple-libunwind-system.cfg.in @@ -19,7 +19,7 @@ config.substitutions.append(('%{link_flags}', '-nostdlib++ -L %{lib} -lc++ -lunwind' )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T -- ' + '%{executor} --execdir %{temp} -- ' )) config.stdlib = 'apple-libc++' diff --git a/src/native/external/llvm-libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in b/src/native/external/llvm-libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in index e8f68a51fc53f8..6ffdd70c6177e7 100644 --- a/src/native/external/llvm-libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/armv7m-picolibc-libunwind.cfg.in @@ -8,7 +8,7 @@ config.substitutions.append(('%{compile_flags}', '-nostdinc++ -I %{include}' )) config.substitutions.append(('%{link_flags}', - '-nostdlib -nostdlib++ -L %{lib} -lunwind' + '-fuse-ld=lld -nostdlib -nostdlib++ -L %{lib} -lunwind' ' -lc -lm -lclang_rt.builtins -lsemihost -lcrt0-semihost' + ' -T {}'.format(libc_linker_script) + ' -Wl,--defsym=__flash=0x0' @@ -25,7 +25,7 @@ config.executor = ( ' --cpu cortex-m3') config.substitutions.append(('%{exec}', '%{executor}' - ' --execdir %T' + ' --execdir %{temp}' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/configs/cmake-bridge.cfg.in b/src/native/external/llvm-libunwind/test/configs/cmake-bridge.cfg.in index b804c210f0bbc0..e40497bfa99766 100644 --- a/src/native/external/llvm-libunwind/test/configs/cmake-bridge.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/cmake-bridge.cfg.in @@ -14,6 +14,7 @@ import os, site site.addsitedir(os.path.join('@LIBUNWIND_LIBCXX_PATH@', 'utils')) import libcxx.test.format +from lit.util import which # Basic configuration of the test suite config.name = os.path.basename('@LIBUNWIND_TEST_CONFIG@') @@ -33,3 +34,13 @@ config.substitutions.append(('%{install-prefix}', '@LIBUNWIND_TESTING_INSTALL_PR config.substitutions.append(('%{include}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@/include')) config.substitutions.append(('%{lib}', '@LIBUNWIND_TESTING_INSTALL_PREFIX@/@LIBUNWIND_INSTALL_LIBRARY_DIR@')) config.substitutions.append(('%{benchmark_flags}', '')) + +# Check for objcopy tools +objcopy_path = which('llvm-objcopy', '@LLVM_BUILD_BINARY_DIR@/bin') +if not objcopy_path: + objcopy_path = which('llvm-objcopy') +if not objcopy_path: + objcopy_path = which('objcopy') +if objcopy_path: + config.substitutions.append(('%{objcopy}', objcopy_path)) + config.available_features.add('objcopy-available') diff --git a/src/native/external/llvm-libunwind/test/configs/ibm-libunwind-shared.cfg.in b/src/native/external/llvm-libunwind/test/configs/ibm-libunwind-shared.cfg.in index 2221e0cf499ff2..99f4a9061d19a7 100644 --- a/src/native/external/llvm-libunwind/test/configs/ibm-libunwind-shared.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/ibm-libunwind-shared.cfg.in @@ -17,7 +17,7 @@ config.substitutions.append(('%{link_flags}', '-nostdlib++ -L %{lib} -lunwind -ldl -Wl,-bbigtoc' )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T --env LIBPATH=%{lib} -- ' + '%{executor} --execdir %{temp} --env LIBPATH=%{lib} -- ' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-merged.cfg.in b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-merged.cfg.in index fafe12962b428f..34950f6ea29360 100644 --- a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-merged.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-merged.cfg.in @@ -35,7 +35,7 @@ config.substitutions.append(('%{link_flags}', '-L %{{lib}} -Wl,-rpath,%{{lib}} -lc++ {}'.format(' '.join(link_flags)) )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T -- ' + '%{executor} --execdir %{temp} -- ' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in index b29d83fbab3053..1e77638b8cee3f 100644 --- a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared-mingw.cfg.in @@ -11,7 +11,7 @@ config.substitutions.append(('%{link_flags}', '-L %{lib} -lunwind' )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T --prepend_env PATH=%{install-prefix}/bin -- ' + '%{executor} --execdir %{temp} --prepend_env PATH=%{install-prefix}/bin -- ' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared.cfg.in b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared.cfg.in index f3e40928b525da..61d6b61cbae297 100644 --- a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-shared.cfg.in @@ -34,7 +34,7 @@ config.substitutions.append(('%{link_flags}', '-L %{{lib}} -Wl,-rpath,%{{lib}} -lunwind {}'.format(' '.join(link_flags)) )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T -- ' + '%{executor} --execdir %{temp} -- ' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in index 437c53bea2f06b..37d20a7c9a4494 100644 --- a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static-mingw.cfg.in @@ -11,7 +11,7 @@ config.substitutions.append(('%{link_flags}', '-L %{lib} -lunwind' )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T --prepend_env PATH=%{lib} -- ' + '%{executor} --execdir %{temp} --prepend_env PATH=%{lib} -- ' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static.cfg.in b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static.cfg.in index a3a65ae82591b1..194fa4f18f0e57 100644 --- a/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static.cfg.in +++ b/src/native/external/llvm-libunwind/test/configs/llvm-libunwind-static.cfg.in @@ -37,7 +37,7 @@ config.substitutions.append(('%{link_flags}', '%{{lib}}/libunwind.a {}'.format(' '.join(link_flags)) )) config.substitutions.append(('%{exec}', - '%{executor} --execdir %T -- ' + '%{executor} --execdir %{temp} -- ' )) import os, site diff --git a/src/native/external/llvm-libunwind/test/eh_frame_fde_pc_range.pass.cpp b/src/native/external/llvm-libunwind/test/eh_frame_fde_pc_range.pass.cpp new file mode 100644 index 00000000000000..32ddb769e6dcea --- /dev/null +++ b/src/native/external/llvm-libunwind/test/eh_frame_fde_pc_range.pass.cpp @@ -0,0 +1,61 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Manually marking the .eh_frame_hdr as DW_EH_PE_omit to make libunwind to do +// the linear search. +// Assuming the begining of the function is at the start of the FDE range. + +// clang-format off + +// REQUIRES: target={{x86_64-.+}} +// REQUIRES: objcopy-available +// UNSUPPORTED: target={{.*-windows.*}} +// UNSUPPORTED: target={{.*-apple.*}} + +// TODO: Figure out why this fails with Memory Sanitizer. +// XFAIL: msan + +// RUN: %{build} +// RUN: %{objcopy} --dump-section .eh_frame_hdr=%t_ehf_hdr.bin %t.exe +// RUN: printf '\377' | dd of=%t_ehf_hdr.bin bs=1 seek=2 count=2 conv=notrunc status=none +// RUN: %{objcopy} --update-section .eh_frame_hdr=%t_ehf_hdr.bin %t.exe +// RUN: %{exec} %t.exe + +// clang-format on + +#include +#include +#include +#include +#include + +void f() { + printf("123\n"); + void *pc = __builtin_return_address(0); + void *fpc = (void *)&f; + void *fpc1 = (void *)((uintptr_t)fpc + 1); + + struct dwarf_eh_bases bases; + const void *fde_pc = _Unwind_Find_FDE(pc, &bases); + const void *fde_fpc = _Unwind_Find_FDE(fpc, &bases); + const void *fde_fpc1 = _Unwind_Find_FDE(fpc1, &bases); + printf("fde_pc = %p\n", fde_pc); + printf("fde_fpc = %p\n", fde_fpc); + printf("fde_fpc1 = %p\n", fde_fpc1); + fflush(stdout); + assert(fde_pc != NULL); + assert(fde_fpc != NULL); + assert(fde_fpc1 != NULL); + assert(fde_fpc == fde_fpc1); +} + +int main(int, char **) { + f(); + return 0; +} diff --git a/src/native/external/llvm-libunwind/test/floatregister.pass.cpp b/src/native/external/llvm-libunwind/test/floatregister.pass.cpp index ce4481bdf8287e..6be3e1f3f7385f 100644 --- a/src/native/external/llvm-libunwind/test/floatregister.pass.cpp +++ b/src/native/external/llvm-libunwind/test/floatregister.pass.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -// REQUIRES: linux && target={{aarch64-.+}} +// REQUIRES: target={{aarch64-.+}} +// UNSUPPORTED: target={{.*-windows.*}} // Basic test for float registers number are accepted. @@ -52,7 +53,7 @@ __attribute__((noinline)) void foo() { _Unwind_Backtrace(frame_handler, NULL); } -__attribute__((section("main_func"))) int main() { +__attribute__((section("main_func"))) int main(int, char **) { foo(); return -2; } diff --git a/src/native/external/llvm-libunwind/test/forceunwind.pass.cpp b/src/native/external/llvm-libunwind/test/forceunwind.pass.cpp index 344034e1ea5f5e..e5437c31a0f656 100644 --- a/src/native/external/llvm-libunwind/test/forceunwind.pass.cpp +++ b/src/native/external/llvm-libunwind/test/forceunwind.pass.cpp @@ -7,7 +7,9 @@ // //===----------------------------------------------------------------------===// -// REQUIRES: linux +// UNSUPPORTED: target={{.*-apple.*}} +// UNSUPPORTED: target={{.*-aix.*}} +// UNSUPPORTED: target={{.*-windows.*}} // TODO: Figure out why this fails with Memory Sanitizer. // XFAIL: msan @@ -72,7 +74,7 @@ __attribute__((noinline)) void foo() { _Unwind_ForcedUnwind(e, stop, (void *)&foo); } -__attribute__((section("main_func"))) int main() { +__attribute__((section("main_func"))) int main(int, char **) { foo(); return -2; } diff --git a/src/native/external/llvm-libunwind/test/remember_state_leak.pass.sh.s b/src/native/external/llvm-libunwind/test/remember_state_leak.pass.sh.s index 63beb7e4701ec0..69be3f95955153 100644 --- a/src/native/external/llvm-libunwind/test/remember_state_leak.pass.sh.s +++ b/src/native/external/llvm-libunwind/test/remember_state_leak.pass.sh.s @@ -6,7 +6,9 @@ # #===------------------------------------------------------------------------===# -# REQUIRES: target={{x86_64-.+-linux-gnu}} +# REQUIRES: target={{x86_64-.+}} +# UNSUPPORTED: target={{.*-windows.*}} +# UNSUPPORTED: target={{.*-apple.*}} # Inline assembly isn't supported by Memory Sanitizer # UNSUPPORTED: msan @@ -38,6 +40,7 @@ SIZEOF_UNWIND_EXCEPTION = 32 + .att_syntax .text callback: xorl %eax, %eax diff --git a/src/native/external/llvm-libunwind/test/signal_unwind.pass.cpp b/src/native/external/llvm-libunwind/test/signal_unwind.pass.cpp index 1c1566415a4d4b..ca50f83964c118 100644 --- a/src/native/external/llvm-libunwind/test/signal_unwind.pass.cpp +++ b/src/native/external/llvm-libunwind/test/signal_unwind.pass.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// // Ensure that the unwinder can cope with the signal handler. -// REQUIRES: target={{(aarch64|riscv64|s390x|x86_64)-.+linux.*}} +// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+}} +// UNSUPPORTED: target={{.*-windows.*}} +// UNSUPPORTED: target={{.*-apple.*}} // TODO: Figure out why this fails with Memory Sanitizer. // XFAIL: msan diff --git a/src/native/external/llvm-libunwind/test/unw_resume.pass.cpp b/src/native/external/llvm-libunwind/test/unw_resume.pass.cpp index 2b7470b5cad0eb..e1f40b4a42e947 100644 --- a/src/native/external/llvm-libunwind/test/unw_resume.pass.cpp +++ b/src/native/external/llvm-libunwind/test/unw_resume.pass.cpp @@ -25,7 +25,7 @@ __attribute__((noinline)) void test_unw_resume() { unw_resume(&cursor); } -int main() { +int main(int, char **) { test_unw_resume(); return 0; } diff --git a/src/native/external/llvm-libunwind/test/unwind_leaffunction.pass.cpp b/src/native/external/llvm-libunwind/test/unwind_leaffunction.pass.cpp index 98de7dc43260c2..af791a6b2ed313 100644 --- a/src/native/external/llvm-libunwind/test/unwind_leaffunction.pass.cpp +++ b/src/native/external/llvm-libunwind/test/unwind_leaffunction.pass.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// // Ensure that leaf function can be unwund. -// REQUIRES: target={{(aarch64|riscv64|s390x|x86_64)-.+linux.*}} +// REQUIRES: target={{(aarch64|loongarch64|riscv64|s390x|x86_64)-.+}} +// UNSUPPORTED: target={{.*-windows.*}} +// UNSUPPORTED: target={{.*-apple.*}} // TODO: Figure out why this fails with Memory Sanitizer. // XFAIL: msan diff --git a/src/native/external/llvm-libunwind/test/unwind_scalable_vectors.pass.cpp b/src/native/external/llvm-libunwind/test/unwind_scalable_vectors.pass.cpp index a5c5947c870fd1..38d8bd5e002d14 100644 --- a/src/native/external/llvm-libunwind/test/unwind_scalable_vectors.pass.cpp +++ b/src/native/external/llvm-libunwind/test/unwind_scalable_vectors.pass.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -// REQUIRES: linux && target={{riscv64-.+}} +// REQUIRES: target={{riscv64-.+}} #undef NDEBUG #include @@ -34,7 +34,10 @@ __attribute__((noinline)) static void foo() { asm volatile("" ::"vr"(v)); // Dummy inline asm to use v. } -int main() { foo(); } +int main(int, char **) { + foo(); + return 0; +} #else -int main() { return 0; } +int main(int, char **) { return 0; } #endif