diff options
author | dtorilov <dtorilov@yandex-team.com> | 2024-02-02 17:47:32 +0300 |
---|---|---|
committer | dtorilov <dtorilov@yandex-team.com> | 2024-02-02 18:10:29 +0300 |
commit | 4c6d9b5352a2b70287e27a9ff29ef751a5bc8d08 (patch) | |
tree | 78b9da3299f4d5ad4563716a5b733f6e8c1ff21f /contrib/libs/libunwind/src/DwarfInstructions.hpp | |
parent | fdc74ce0fba102516da2237709550e3577739bb8 (diff) | |
download | ydb-4c6d9b5352a2b70287e27a9ff29ef751a5bc8d08.tar.gz |
Update contrib/libs/libunwind to 18.1.0-rc1
Diffstat (limited to 'contrib/libs/libunwind/src/DwarfInstructions.hpp')
-rw-r--r-- | contrib/libs/libunwind/src/DwarfInstructions.hpp | 81 |
1 files changed, 67 insertions, 14 deletions
diff --git a/contrib/libs/libunwind/src/DwarfInstructions.hpp b/contrib/libs/libunwind/src/DwarfInstructions.hpp index ab83b0c87a..bd9ece60ee 100644 --- a/contrib/libs/libunwind/src/DwarfInstructions.hpp +++ b/contrib/libs/libunwind/src/DwarfInstructions.hpp @@ -16,16 +16,17 @@ #include <stdio.h> #include <stdlib.h> -#include "dwarf2.h" -#include "Registers.hpp" #include "DwarfParser.hpp" +#include "Registers.hpp" #include "config.h" +#include "dwarf2.h" +#include "libunwind_ext.h" namespace libunwind { -/// DwarfInstructions maps abtract DWARF unwind instructions to a particular +/// DwarfInstructions maps abstract DWARF unwind instructions to a particular /// architecture template <typename A, typename R> class DwarfInstructions { @@ -34,7 +35,7 @@ public: typedef typename A::sint_t sint_t; static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, - R ®isters, bool &isSignalFrame); + R ®isters, bool &isSignalFrame, bool stage2); private: @@ -67,11 +68,15 @@ private: return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + prolog.cfaRegisterOffset); if (prolog.cfaExpression != 0) - return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, + return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, registers, 0); assert(0 && "getCFA(): unknown location"); __builtin_unreachable(); } +#if defined(_LIBUNWIND_TARGET_AARCH64) + static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa, + PrologInfo &prolog); +#endif }; template <typename R> @@ -166,11 +171,26 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister( } _LIBUNWIND_ABORT("unsupported restore location for vector register"); } +#if defined(_LIBUNWIND_TARGET_AARCH64) +template <typename A, typename R> +bool DwarfInstructions<A, R>::getRA_SIGN_STATE(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<A>::kRegisterUnused) + raSignState = static_cast<pint_t>(regloc.value); + else + raSignState = getSavedRegister(addressSpace, registers, cfa, regloc); + + // Only bit[0] is meaningful. + return raSignState & 0x01; +} +#endif template <typename A, typename R> int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, R ®isters, - bool &isSignalFrame) { + bool &isSignalFrame, bool stage2) { FDE_Info fdeInfo; CIE_Info cieInfo; if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, @@ -181,7 +201,39 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, // get pointer to cfa (architecture specific) pint_t cfa = getCFA(addressSpace, prolog, registers); - // restore registers that DWARF says were saved + (void)stage2; + // __unw_step_stage2 is not used for cross unwinding, so we use + // __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are + // building for AArch64 natively. +#if defined(__aarch64__) + if (stage2 && cieInfo.mteTaggedFrame) { + pint_t sp = registers.getSP(); + pint_t p = sp; + // AArch64 doesn't require the value of SP to be 16-byte aligned at + // all times, only at memory accesses and public interfaces [1]. Thus, + // a signal could arrive at a point where SP is not aligned properly. + // In that case, the kernel fixes up [2] the signal frame, but we + // still have a misaligned SP in the previous frame. If that signal + // handler caused stack unwinding, we would have an unaligned SP. + // We do not need to fix up the CFA, as that is the SP at a "public + // interface". + // [1]: + // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#622the-stack + // [2]: + // https://github.com/torvalds/linux/blob/1930a6e739c4b4a654a69164dbe39e554d228915/arch/arm64/kernel/signal.c#L718 + p &= ~0xfULL; + // CFA is the bottom of the current stack frame. + for (; p < cfa; p += 16) { + __asm__ __volatile__(".arch armv8.5-a\n" + ".arch_extension memtag\n" + "stg %[Ptr], [%[Ptr]]\n" + : + : [Ptr] "r"(p) + : "memory"); + } + } +#endif + // restore registers that DWARF says were saved R newRegisters = registers; // Typically, the CFA is the stack pointer at the call site in @@ -194,9 +246,10 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, newRegisters.setSP(cfa); pint_t returnAddress = 0; - const int lastReg = R::lastDwarfRegNum(); - assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg && - "register range too large"); + constexpr int lastReg = R::lastDwarfRegNum(); + static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= + lastReg, + "register range too large"); assert(lastReg >= (int)cieInfo.returnAddressRegister && "register range does not contain return address register"); for (int i = 0; i <= lastReg; ++i) { @@ -221,7 +274,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, return UNW_EBADREG; } else if (i == (int)cieInfo.returnAddressRegister) { // Leaf function keeps the return address in register and there is no - // explicit intructions how to restore it. + // explicit instructions how to restore it. returnAddress = registers.getRegister(cieInfo.returnAddressRegister); } } @@ -235,7 +288,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, // restored. autia1716 is used instead of autia as autia1716 assembles // to a NOP on pre-v8.3a architectures. if ((R::getArch() == REGISTERS_ARM64) && - prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value && + getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) && returnAddress != 0) { #if !defined(_LIBUNWIND_IS_NATIVE_ONLY) return UNW_ECROSSRASIGNING; @@ -311,7 +364,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, #endif // Return address is address after call site instruction, so setting IP to - // that does simualates a return. + // that does simulates a return. newRegisters.setIP(returnAddress); // Simulate the step by replacing the register set with the new ones. @@ -615,7 +668,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace, svalue = (sint_t)*sp; *sp = (pint_t)(svalue >> value); if (log) - fprintf(stderr, "shift left arithmetric\n"); + fprintf(stderr, "shift left arithmetic\n"); break; case DW_OP_xor: |