diff --git a/lib/libunwind/include/__libunwind_config.h b/lib/libunwind/include/__libunwind_config.h index 980d11ef5d4f237f7ad10af086cc6cf711acadaf..a1179c73c5906b2df9bb3973cd7918ad1f42b28a 100644 --- a/lib/libunwind/include/__libunwind_config.h +++ b/lib/libunwind/include/__libunwind_config.h @@ -9,7 +9,7 @@ #ifndef ____LIBUNWIND_CONFIG_H__ #define ____LIBUNWIND_CONFIG_H__ -#define _LIBUNWIND_VERSION 15000 +#define _LIBUNWIND_VERSION 230000 #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) && !defined(__SEH__) diff --git a/lib/libunwind/include/libunwind.h b/lib/libunwind/include/libunwind.h index 56ca7110274a30c842d845a4c1ab8761bcd57388..6c2dfe58e53bf1f97bca6c78dacb47cc3676b8dc 100644 --- a/lib/libunwind/include/libunwind.h +++ b/lib/libunwind/include/libunwind.h @@ -122,7 +122,7 @@ __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \ __ptrauth_unwind_cie_info_personality_disc) - // ptrauth_string_discriminator("personality") == 0x7EAD) + // ptrauth_string_discriminator("personality") == 0x7EAD #define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD #else diff --git a/lib/libunwind/include/mach-o/compact_unwind_encoding.h b/lib/libunwind/include/mach-o/compact_unwind_encoding.h index 4c48e33c3c177d9cdf7e4805fc4797628ff54ac4..c495b83c40b90ae517e390fe659061a7bbbe2603 100644 --- a/lib/libunwind/include/mach-o/compact_unwind_encoding.h +++ b/lib/libunwind/include/mach-o/compact_unwind_encoding.h @@ -443,7 +443,7 @@ struct unwind_info_section_header_lsda_index_entry struct unwind_info_regular_second_level_entry { - uint32_t functionOffset; + uint32_t functionOffset; compact_unwind_encoding_t encoding; }; diff --git a/lib/libunwind/include/unwind_itanium.h b/lib/libunwind/include/unwind_itanium.h index d94a6183be2901e3167779691726b307970254a7..860ad36cdf14e2e06cd6fe2f77b9070434240434 100644 --- a/lib/libunwind/include/unwind_itanium.h +++ b/lib/libunwind/include/unwind_itanium.h @@ -32,7 +32,7 @@ struct _Unwind_Exception { // The implementation of _Unwind_Exception uses an attribute mode on the // above fields which has the side effect of causing this whole struct to // round up to 32 bytes in size (48 with SEH). To be more explicit, we add - // pad fields added for binary compatibility. + // pad fields for binary compatibility. uint32_t reserved[3]; #endif // The Itanium ABI requires that _Unwind_Exception objects are "double-word diff --git a/lib/libunwind/src/AddressSpace.hpp b/lib/libunwind/src/AddressSpace.hpp index 01185eb53c4ff40b81b351bf58d525f90782845c..3711189f57b1d115c82811b18017b56d74284e2c 100644 --- a/lib/libunwind/src/AddressSpace.hpp +++ b/lib/libunwind/src/AddressSpace.hpp @@ -666,7 +666,6 @@ inline bool LocalAddressSpace::findUnwindSections( return true; } #endif - // zig patch: https://github.com/llvm/llvm-project/issues/194228 dl_iterate_cb_data cb_data = {this, &info, static_cast(targetAddr)}; int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); return static_cast(found); diff --git a/lib/libunwind/src/CompactUnwinder.hpp b/lib/libunwind/src/CompactUnwinder.hpp index cd2e0e3431314adb770af082de1f645d1a48c8bc..929f540b662b4d661854a20820c8bd33f2a4d850 100644 --- a/lib/libunwind/src/CompactUnwinder.hpp +++ b/lib/libunwind/src/CompactUnwinder.hpp @@ -12,6 +12,7 @@ #ifndef __COMPACT_UNWINDER_HPP__ #define __COMPACT_UNWINDER_HPP__ +#include #include #include @@ -335,8 +336,8 @@ int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( default: (void)functionStart; _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " - "function starting at 0x%llX", - compactEncoding, functionStart); + "function starting at 0x%" PRIu64 "X", + compactEncoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } savedRegisters += 8; @@ -454,8 +455,8 @@ int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( break; default: _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " - "function starting at 0x%llX", - encoding, functionStart); + "function starting at 0x%" PRIu64 "X", + encoding, functionStart); _LIBUNWIND_ABORT("invalid compact unwind encoding"); } savedRegisters += 8; diff --git a/lib/libunwind/src/DwarfInstructions.hpp b/lib/libunwind/src/DwarfInstructions.hpp index 165c4a99e9a92f1deac33fb8f959481a3136b1ac..56220c327a7faacd71275d9ab3ae5bf281e3bb31 100644 --- a/lib/libunwind/src/DwarfInstructions.hpp +++ b/lib/libunwind/src/DwarfInstructions.hpp @@ -76,10 +76,14 @@ private: __builtin_unreachable(); } #if defined(_LIBUNWIND_TARGET_AARCH64) - static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa, - PrologInfo &prolog); - static bool isReturnAddressSignedWithPC(A &addressSpace, R registers, - pint_t cfa, PrologInfo &prolog); + enum RASignStatus { + RANotSigned = 0, + RASigned = 1, + RASignedWithPC = 2, + }; + static RASignStatus getReturnAddressSignStatus(A &addressSpace, R registers, + pint_t cfa, + PrologInfo &prolog); #endif }; @@ -177,7 +181,8 @@ v128 DwarfInstructions::getSavedVectorRegister( } #if defined(_LIBUNWIND_TARGET_AARCH64) template -bool DwarfInstructions::isReturnAddressSigned(A &addressSpace, +typename DwarfInstructions::RASignStatus +DwarfInstructions::getReturnAddressSignStatus(A &addressSpace, R registers, pint_t cfa, PrologInfo &prolog) { pint_t raSignState; @@ -187,24 +192,9 @@ bool DwarfInstructions::isReturnAddressSigned(A &addressSpace, else raSignState = getSavedRegister(addressSpace, registers, cfa, regloc); - // Only bit[0] is meaningful. - return raSignState & 0x01; -} - -template -bool DwarfInstructions::isReturnAddressSignedWithPC(A &addressSpace, - R registers, - pint_t cfa, - PrologInfo &prolog) { - pint_t raSignState; - auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE]; - if (regloc.location == CFI_Parser::kRegisterUnused) - raSignState = static_cast(regloc.value); - else - raSignState = getSavedRegister(addressSpace, registers, cfa, regloc); - - // Only bit[1] is meaningful. - return raSignState & 0x02; + // bits[1:0] describe how RA is signed. + assert((raSignState & 0x3) != 3 && "unexpected RA sign state"); + return static_cast(raSignState & 0x3); } #endif @@ -317,8 +307,9 @@ int DwarfInstructions::stepWithDwarf( // return address needs to be authenticated before the return address is // restored. autia1716 is used instead of autia as autia1716 assembles // to a NOP on pre-v8.3a architectures. - if ((R::getArch() == REGISTERS_ARM64) && - isReturnAddressSigned(addressSpace, registers, cfa, prolog) && + RASignStatus RAState = + getReturnAddressSignStatus(addressSpace, registers, cfa, prolog); + if ((R::getArch() == REGISTERS_ARM64) && RAState != RANotSigned && returnAddress != 0) { #if !defined(_LIBUNWIND_IS_NATIVE_ONLY) return UNW_ECROSSRASIGNING; @@ -329,7 +320,7 @@ int DwarfInstructions::stepWithDwarf( // We use the hint versions of the authentication instructions below to // ensure they're assembled by the compiler even for targets with no // FEAT_PAuth/FEAT_PAuth_LR support. - if (isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) { + if (RAState == RASignedWithPC) { register unsigned long long x15 __asm("x15") = prolog.ptrAuthDiversifier; if (cieInfo.addressesSignedWithBKey) { diff --git a/lib/libunwind/src/DwarfParser.hpp b/lib/libunwind/src/DwarfParser.hpp index 635f8369541af0b4cf9160050e8d9b85c0aca3cb..8e080fb33c5f81f833d441a11ae62fd2da9dc28f 100644 --- a/lib/libunwind/src/DwarfParser.hpp +++ b/lib/libunwind/src/DwarfParser.hpp @@ -473,7 +473,6 @@ bool CFI_Parser::parseFDEInstructions( pint_t pcoffset; }; - // zig patch: https://github.com/llvm/llvm-project/issues/194228 ParseInfo parseInfoArray[] = { {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, (pint_t)(-1)}, diff --git a/lib/libunwind/src/FrameHeaderCache.hpp b/lib/libunwind/src/FrameHeaderCache.hpp index 296064d8e2e675994a39227e2912c893892b8612..caea29e097464b29e98249b2ad44bfd0a301092d 100644 --- a/lib/libunwind/src/FrameHeaderCache.hpp +++ b/lib/libunwind/src/FrameHeaderCache.hpp @@ -24,7 +24,7 @@ #define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) #endif -// This cache should only be be used from within a dl_iterate_phdr callback. +// This cache should only be used from within a dl_iterate_phdr callback. // dl_iterate_phdr does the necessary synchronization to prevent problems // with concurrent access via the libc load lock. Adding synchronization // for other uses is possible, but not currently done. diff --git a/lib/libunwind/src/Registers.hpp b/lib/libunwind/src/Registers.hpp index 88c2d3b4e8c9bbe15c52b0e404370b4847a7ba27..c88422a6d5f4fbbcb34d9a94e2ea20c776e4a40f 100644 --- a/lib/libunwind/src/Registers.hpp +++ b/lib/libunwind/src/Registers.hpp @@ -20,6 +20,9 @@ #include "libunwind_ext.h" #include "shadow_stack_unwind.h" +#if defined(__APPLE__) +#include +#endif #if defined(_LIBUNWIND_HAVE_GETAUXVAL) || defined(_LIBUNWIND_HAVE_ELF_AUX_INFO) #include #endif @@ -1892,7 +1895,7 @@ public: 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. + // but everyone else expects it to be signed by the SP, so convert on return. value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc, ptrauth_key_return_address, &_registers.__pc, @@ -1940,7 +1943,15 @@ private: _LIBUNWIND_ABORT("SME ZA disable failed"); } -#if defined(_LIBUNWIND_HAVE_GETAUXVAL) +#if defined(__APPLE__) + static bool checkHasSME() { + int has_sme = 0; + size_t size = sizeof(has_sme); + if (sysctlbyname("hw.optional.arm.FEAT_SME", &has_sme, &size, NULL, 0)) + return false; + return has_sme != 0; + } +#elif defined(_LIBUNWIND_HAVE_GETAUXVAL) static bool checkHasSME() { constexpr int hwcap2_sme = (1 << 23); unsigned long hwcap2 = getauxval(AT_HWCAP2); @@ -3724,21 +3735,21 @@ inline void Registers_sparc::setRegister(int regNum, uint32_t value) { inline bool Registers_sparc::validFloatRegister(int) const { return false; } inline double Registers_sparc::getFloatRegister(int) const { - _LIBUNWIND_ABORT("no Sparc float registers"); + _LIBUNWIND_ABORT("no sparc float registers"); } inline void Registers_sparc::setFloatRegister(int, double) { - _LIBUNWIND_ABORT("no Sparc float registers"); + _LIBUNWIND_ABORT("no sparc float registers"); } inline bool Registers_sparc::validVectorRegister(int) const { return false; } inline v128 Registers_sparc::getVectorRegister(int) const { - _LIBUNWIND_ABORT("no Sparc vector registers"); + _LIBUNWIND_ABORT("no sparc vector registers"); } inline void Registers_sparc::setVectorRegister(int, v128) { - _LIBUNWIND_ABORT("no Sparc vector registers"); + _LIBUNWIND_ABORT("no sparc vector registers"); } inline const char *Registers_sparc::getRegisterName(int regNum) { diff --git a/lib/libunwind/src/Unwind-wasm.c b/lib/libunwind/src/Unwind-wasm.c index b0d6cd2d00fc59eae87f3366802d7470eb64a1d2..2e949d005b8f5e0d759460ed95c2f22056112eae 100644 --- a/lib/libunwind/src/Unwind-wasm.c +++ b/lib/libunwind/src/Unwind-wasm.c @@ -54,7 +54,7 @@ _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) { __wasm_lpad_context.selector = 0; // Call personality function. Wasm does not have two-phase unwinding, so we - // only do the cleanup phase. + // only do the search phase. return __gxx_personality_wasm0( 1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object, (struct _Unwind_Context *)&__wasm_lpad_context); @@ -69,6 +69,21 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) { __builtin_wasm_throw(0, exception_object); } +// Define the `__cpp_exception` symbol which `__builtin_wasm_throw` above will +// reference. This is defined here in `libunwind` as the single canonical +// definition for this API and it's required for users to ensure that there's +// only one copy of `libunwind` within a wasm module to ensure this is only +// defined once and exactly once. +__asm__(".globl __cpp_exception\n" +#if defined(__wasm32__) + ".tagtype __cpp_exception i32\n" +#elif defined(__wasm64__) + ".tagtype __cpp_exception i64\n" +#else +#error "Unsupported Wasm architecture" +#endif + "__cpp_exception:\n"); + /// Called by __cxa_end_catch. _LIBUNWIND_EXPORT void _Unwind_DeleteException(_Unwind_Exception *exception_object) { @@ -102,7 +117,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { } /// Not used in Wasm. -_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t) {} +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t value) {} /// Called by personality handler to get LSDA for current frame. _LIBUNWIND_EXPORT uintptr_t @@ -114,7 +130,8 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { } /// Not used in Wasm. -_LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *) { +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { return 0; } diff --git a/lib/libunwind/src/UnwindCursor.hpp b/lib/libunwind/src/UnwindCursor.hpp index 5838dbcaa9980adc472919dcb6ed274706d4e00e..537dbd83f4f74e57bd3385d2157c3d448674ad36 100644 --- a/lib/libunwind/src/UnwindCursor.hpp +++ b/lib/libunwind/src/UnwindCursor.hpp @@ -963,7 +963,7 @@ template bool UnwindCursor::isSignalFrame() { /// UnwindCursor contains all state (including all register values) during /// an unwind. This is normally stack allocated inside a unw_cursor_t. template -class UnwindCursor : public AbstractUnwindCursor{ +class UnwindCursor : public AbstractUnwindCursor { typedef typename A::pint_t pint_t; public: UnwindCursor(unw_context_t *context, A &as); @@ -1363,6 +1363,10 @@ private: reinterpret_cast(_info.unwind_info), _registers, _isSignalFrame); } + bool isKnownVapiNotActive() const { return _isKnownVapiNotActive; } + void setIsKnownVapiNotActive(bool val) { _isKnownVapiNotActive = val; } + static pint_t getVAPILR(); + #endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) A &_addressSpace; @@ -1377,13 +1381,23 @@ private: #ifdef _LIBUNWIND_TRACE_RET_INJECT uint32_t _walkedFrames; #endif +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + // TODO: this will need to be recorded in the unw_context_t by unw_getcontext + // to support cases where the cursor is retrieved prior to invocation of the + // Virtual API. + bool _isKnownVapiNotActive; +#endif }; - template UnwindCursor::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), - _isSignalFrame(false) { + _isSignalFrame(false) +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + , + _isKnownVapiNotActive(false) +#endif +{ static_assert((check_fit, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); static_assert((alignof(UnwindCursor) <= alignof(unw_cursor_t)), @@ -1393,13 +1407,17 @@ UnwindCursor::UnwindCursor(unw_context_t *context, A &as) template UnwindCursor::UnwindCursor(A &as, void *) - : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + , + _isKnownVapiNotActive(false) +#endif +{ memset(static_cast(&_info), 0, sizeof(_info)); // FIXME // fill in _registers from thread arg } - template bool UnwindCursor::validReg(int regNum) { return _registers.validRegister(regNum); @@ -1469,6 +1487,30 @@ template void UnwindCursor::jumpto() { static constexpr size_t _EXTRA_LIBUNWIND_FRAMES_WALKED = 5 - 1; _registers.returnto(_walkedFrames + _EXTRA_LIBUNWIND_FRAMES_WALKED); #else +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + if (isKnownVapiNotActive()) { + // If the current frame is known VAPI not active, execute the VAPI return + // glue to clear the VAPI control block. The VAPI return glue is used by + // AIX longjmp based on the VAPI active status recorded by setjmp in the + // jmp_buf, which means that the VAPI return glue can be called solely on + // the basis of the VAPI active status of the target context. + + // VAPI return glue address is the VAPI glue address - 4. +#ifdef __64BIT__ + constexpr pint_t VAPIReturnGlue = 0x8e40 - 4; +#else + constexpr pint_t VAPIReturnGlue = 0x8c40 - 4; +#endif + + _LIBUNWIND_TRACE_UNWINDING("VAPI: executing return glue %p\n", + reinterpret_cast(VAPIReturnGlue)); + register auto *registers __asm__("r30") = &_registers; + __asm__ __volatile__("bla %[retglue]" + : "+r"(registers) + : [retglue] "i"(VAPIReturnGlue)); + registers->jumpto(); + } +#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) _registers.jumpto(); #endif } @@ -2037,7 +2079,7 @@ bool UnwindCursor::getInfoFromCompactEncodingSection( if (personalityIndex != 0) { --personalityIndex; // change 1-based to zero-based index if (personalityIndex >= sectionHeader.personalityArrayCount()) { - _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " "but personality table has only %d entries", encoding, personalityIndex, sectionHeader.personalityArrayCount()); @@ -2459,6 +2501,45 @@ bool UnwindCursor::getInfoFromTBTable(pint_t pc, R ®isters) { return true; } +// VAPI glue addresses +constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8b80; +constexpr uintptr_t vapi_addr_64 = 0x8e00; +constexpr size_t vapi_size_64 = 0x0200; +constexpr uintptr_t vapi_glue_addr_begin = + vapi_glue_addr_ext_32; // Start address in 32-bit +constexpr uintptr_t vapi_glue_addr_end = + vapi_addr_64 + vapi_size_64; // End address in 64-bit + +#ifdef __64BIT__ +constexpr size_t VAPI_CB_SIZE = 256; +constexpr ptrdiff_t TLS_POINTER_OFFSET = 30 * 1024; +constexpr size_t TLSCB_BASE_SIZE = 256; + +static __inline__ __attribute__((__always_inline__)) char *tptr(void) { + char *result; + __asm__("mr %0, 13" : "=r"(result)); + return result; +} +#else // 32-bit +constexpr size_t VAPI_CB_SIZE = 128; +constexpr ptrdiff_t TLS_POINTER_OFFSET = 31 * 1024; +constexpr size_t TLSCB_BASE_SIZE = 128; + +static __inline__ __attribute__((__always_inline__)) char *tptr(void) { + char *result; + __asm__("mfspr %0, 259" : "=r"(result)); + return result; +} +#endif + +constexpr ptrdiff_t VAPI_CB_OFFSET = + TLS_POINTER_OFFSET + VAPI_CB_SIZE + TLSCB_BASE_SIZE; + +template +typename UnwindCursor::pint_t UnwindCursor::getVAPILR() { + return *reinterpret_cast(tptr() - VAPI_CB_OFFSET + 8); +} + // Step back up the stack following the frame back link. template int UnwindCursor::stepWithTBTable(pint_t pc, tbtable *TBTable, @@ -2511,6 +2592,16 @@ int UnwindCursor::stepWithTBTable(pint_t pc, tbtable *TBTable, _LIBUNWIND_TRACE_UNWINDING("Possible signal handler frame: lastStack=%p", reinterpret_cast(lastStack)); + pint_t returnAddressInStack = reinterpret_cast(lastStack)[2]; + if (vapi_glue_addr_begin <= returnAddressInStack && + returnAddressInStack < vapi_glue_addr_end) { + _LIBUNWIND_TRACE_UNWINDING( + "The return address in stack %p is within the range of VAPI address;" + " set isKnownVapiNotActive to true\n", + reinterpret_cast(returnAddressInStack)); + setIsKnownVapiNotActive(true); + } + sigcontext *sigContext = reinterpret_cast( reinterpret_cast(lastStack) + STKMINALIGN); returnAddress = sigContext->sc_jmpbuf.jmp_context.iar; @@ -2579,6 +2670,17 @@ int UnwindCursor::stepWithTBTable(pint_t pc, tbtable *TBTable, } else { // Otherwise, use the LR value in the stack link area. returnAddress = reinterpret_cast(lastStack)[2]; + + if (vapi_glue_addr_begin <= returnAddress && + returnAddress < vapi_glue_addr_end) { + _LIBUNWIND_TRACE_UNWINDING( + "The return address=%p is within the range of VAPI address;", + reinterpret_cast(returnAddress)); + setIsKnownVapiNotActive(true); + returnAddress = getVAPILR(); + _LIBUNWIND_TRACE_UNWINDING("return address=%p from VAPI\n", + reinterpret_cast(returnAddress)); + } } // Reset LR in the current context. @@ -2709,6 +2811,16 @@ int UnwindCursor::stepWithTBTable(pint_t pc, tbtable *TBTable, // Return address is the address after call site instruction. pint_t nextReturnAddress = reinterpret_cast(nextStack)[2]; + if (vapi_glue_addr_begin <= nextReturnAddress && + nextReturnAddress < vapi_glue_addr_end) { + _LIBUNWIND_TRACE_UNWINDING( + "The next return address=%p is within the range of VAPI address;", + reinterpret_cast(nextReturnAddress)); + nextReturnAddress = getVAPILR(); + _LIBUNWIND_TRACE_UNWINDING("the next return address=%p from VAPI\n", + reinterpret_cast(nextReturnAddress)); + } + if (nextReturnAddress > 0x01 && nextReturnAddress < 0x10000) { _LIBUNWIND_TRACE_UNWINDING("The next is a signal handler frame: " "nextStack=%p, next return address=%p\n", @@ -3256,7 +3368,7 @@ int UnwindCursor::stepThroughSigReturn() { template int UnwindCursor::step(bool stage2) { (void)stage2; - // Bottom of stack is defined is when unwind info cannot be found. + // Bottom of stack is defined when unwind info cannot be found. if (_unwindInfoMissing) return UNW_STEP_END; diff --git a/lib/libunwind/src/UnwindLevel1-gcc-ext.c b/lib/libunwind/src/UnwindLevel1-gcc-ext.c index 32c872ffade1fd0c02c6e9d30a56fb48c2080193..1764499b304f1ac4ed665829d7cc47793ebf9766 100644 --- a/lib/libunwind/src/UnwindLevel1-gcc-ext.c +++ b/lib/libunwind/src/UnwindLevel1-gcc-ext.c @@ -284,7 +284,7 @@ _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { // before 10.6 used keymgr to track known FDEs, but these functions // never got updated to use keymgr. // For now, we implement these as do-nothing functions to keep any existing -// applications working. We also add the not in 10.6 symbol so that nwe +// applications working. We also add the not in 10.6 symbol so that new // application won't be able to use them. #if defined(_LIBUNWIND_SUPPORT_FRAME_APIS) diff --git a/lib/libunwind/src/UnwindLevel1.c b/lib/libunwind/src/UnwindLevel1.c index 7368b3cb803362370cbc95f731538d2486beafcf..834fdae6a76d3e28bde5ece20c45f367a47b1f12 100644 --- a/lib/libunwind/src/UnwindLevel1.c +++ b/lib/libunwind/src/UnwindLevel1.c @@ -14,7 +14,7 @@ // ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are // defining inline functions to delegate the function calls to // _Unwind_VRS_{Get,Set}(). However, some applications might declare the -// function protetype directly (instead of including ), thus we need +// function prototype directly (instead of including ), thus we need // to export these functions from libunwind.so as well. #define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 diff --git a/lib/libunwind/src/UnwindRegistersRestore.S b/lib/libunwind/src/UnwindRegistersRestore.S index 76a80344034f7175e08a189e42a2dc2592845735..37e8156408cf2fac4ceeadb1ce28b5d91c7ea26c 100644 --- a/lib/libunwind/src/UnwindRegistersRestore.S +++ b/lib/libunwind/src/UnwindRegistersRestore.S @@ -678,9 +678,15 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) ldp x18,x19, [x0, #0x090] ldp x20,x21, [x0, #0x0A0] ldp x22,x23, [x0, #0x0B0] +#if defined(__LFI__) + ldr x24, [x0, #0x0C0] + // Skip reloading x25-x28; reserved by LFI ABI. + ldr x29, [x0, #0x0E8] +#else ldp x24,x25, [x0, #0x0C0] ldp x26,x27, [x0, #0x0D0] ldp x28,x29, [x0, #0x0E0] +#endif #if defined(__ARM_FP) && __ARM_FP != 0 ldp d0, d1, [x0, #0x110] @@ -941,11 +947,22 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) #elif defined(__hexagon__) # On entry: -# thread_state pointer is in r2 +# thread_state pointer is in r0 DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv) # # void libunwind::Registers_hexagon::jumpto() # +# The context layout is hexagon_thread_state_t: unsigned int __r[35] +# __r[0..31] = r0..r31, __r[32] = predicates, __r[33] = PC. +# Offsets: __r[n] is at byte offset n*4. r0 is the context pointer, so +# it is restored last; r31 is loaded with the saved PC as the jumpr target. + r2 = memw(r0+#8) + r3 = memw(r0+#12) + r4 = memw(r0+#16) + r5 = memw(r0+#20) + r6 = memw(r0+#24) + r7 = memw(r0+#28) + r8 = memw(r0+#32) r9 = memw(r0+#36) r10 = memw(r0+#40) diff --git a/lib/libunwind/src/UnwindRegistersSave.S b/lib/libunwind/src/UnwindRegistersSave.S index f988fd461def170a20b8cb2828533fb32191e84d..f44f6a1331968cf75de46a3cf64a0cc5c8f485b2 100644 --- a/lib/libunwind/src/UnwindRegistersSave.S +++ b/lib/libunwind/src/UnwindRegistersSave.S @@ -794,13 +794,20 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) stp x18,x19, [x0, #0x090] stp x20,x21, [x0, #0x0A0] stp x22,x23, [x0, #0x0B0] +#if defined(__LFI__) + str x24, [x0, #0x0C0] + // Skip spilling x25-x28; reserved by LFI ABI. + str x29, [x0, #0x0E8] +#else stp x24,x25, [x0, #0x0C0] stp x26,x27, [x0, #0x0D0] stp x28,x29, [x0, #0x0E0] +#endif str x30, [x0, #0x0F0] mov x1,sp str x1, [x0, #0x0F8] str x30, [x0, #0x100] // store return address as pc + str xzr, [x0, #0x108] // zero __ra_sign_state // skip cpsr #if defined(__ARM_FP) && __ARM_FP != 0 stp d0, d1, [x0, #0x110] @@ -1096,8 +1103,21 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) # On entry: # thread_state pointer is in r0 # +# The context layout is hexagon_thread_state_t: unsigned int __r[35] +# __r[0..31] = r0..r31, __r[32] = predicates, __r[33] = PC, __r[34] = unused +# Offsets: __r[n] is at byte offset n*4. +# #define OFFSET(offset) (offset/4) DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + // Save r1-r7 first (r0 is the context pointer, saved last) + memw(r0+#4) = r1 + memw(r0+#8) = r2 + memw(r0+#12) = r3 + memw(r0+#16) = r4 + memw(r0+#20) = r5 + memw(r0+#24) = r6 + memw(r0+#28) = r7 + memw(r0+#32) = r8 memw(r0+#36) = r9 memw(r0+#40) = r10 @@ -1127,12 +1147,17 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) memw(r0+#116) = r29 memw(r0+#120) = r30 memw(r0+#124) = r31 - r1 = c4 // Predicate register + + r1 = c4 // Predicate register memw(r0+#128) = r1 - r1 = memw(r30) // *FP == Saved FP - r1 = r31 + + r1 = r31 // Store return address as PC memw(r0+#132) = r1 + // Save r0 (the context pointer itself) last + memw(r0+#0) = r0 + + r0 = #0 // return UNW_ESUCCESS jumpr r31 #elif defined(__sparc__) && defined(__arch64__) diff --git a/lib/libunwind/src/libunwind.cpp b/lib/libunwind/src/libunwind.cpp index 7ffffc2a30c0ae61c20446a0c91d7548ba695927..0b9d56ec805bca92f0ed4b93be549c8cf982e809 100644 --- a/lib/libunwind/src/libunwind.cpp +++ b/lib/libunwind/src/libunwind.cpp @@ -32,7 +32,7 @@ using namespace libunwind; -/// internal object to represent this processes address space +/// internal object to represent this process's address space LocalAddressSpace LocalAddressSpace::sThisAddressSpace; _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = @@ -131,23 +131,19 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, { // 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"); + // + // However many JITs do not configure CFI frames, so we cannot actually + // enforce this - at least not without an extremely expensive syscall. + // + // For the forseeable future this will need to be a debug only assertion + // so we just strip and assert to avoid the unnecessary auths in release + // builds. + unw_word_t stripped_value = (unw_word_t)ptrauth_strip( + (void *)value, ptrauth_key_return_address); + if (stripped_value < info.start_ip && stripped_value > info.end_ip) + _LIBUNWIND_LOG("Badly behaved use of unw_set_reg: moving IP(0x%zX) " + "outside of CFI bounds function (0x%zX, 0x%zX)", + stripped_value, info.start_ip, info.end_ip); // PC should have been signed with the sp, so we verify that // roundtripping does not fail. The `ptrauth_auth_and_resign` is @@ -306,7 +302,7 @@ _LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor, } _LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg) -/// Checks if a register is a floating-point register. +/// Get name of specified register at cursor position in stack frame. _LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor, unw_regnum_t regNum) { _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)", diff --git a/lib/libunwind/src/libunwind_ext.h b/lib/libunwind/src/libunwind_ext.h index b3762c24d7da47b9e23595418cc095a2994d3d92..8acf2212d1eae32433764070421727d73b07e372 100644 --- a/lib/libunwind/src/libunwind_ext.h +++ b/lib/libunwind/src/libunwind_ext.h @@ -120,10 +120,10 @@ typedef int (*unw_find_dynamic_unwind_sections)( extern int __unw_add_find_dynamic_unwind_sections( unw_find_dynamic_unwind_sections find_dynamic_unwind_sections); -// Deregister a dynacim unwind-info lookup callback. +// Deregister a dynamic unwind-info lookup callback. // // Returns UNW_ESUCCESS for successful deregistrations. If the given callback -// has already been registered then UNW_EINVAL will be returned. +// is not present then UNW_EINVAL will be returned. extern int __unw_remove_find_dynamic_unwind_sections( unw_find_dynamic_unwind_sections find_dynamic_unwind_sections);