diff --git a/src/coreclr/src/nativeaot/Runtime/unix/UnixContext.cpp b/src/coreclr/src/nativeaot/Runtime/unix/UnixContext.cpp index 458214bbe56f..08b98ef6365c 100644 --- a/src/coreclr/src/nativeaot/Runtime/unix/UnixContext.cpp +++ b/src/coreclr/src/nativeaot/Runtime/unix/UnixContext.cpp @@ -301,7 +301,7 @@ bool GetUnwindProcInfo(PCODE ip, unw_proc_info_t *procInfo) #elif HOST_ARM ((uint32_t*)(unwContext.data))[15] = ip; #elif HOST_ARM64 - ((uint32_t*)(unwContext.data))[32] = ip; + unwContext.data[32] = ip; #elif HOST_WASM ASSERT(false); #elif HOST_X86 @@ -618,7 +618,7 @@ bool FindProcInfo(UIntNative controlPC, UIntNative* startAddress, UIntNative* ls assert((procInfo.start_ip <= controlPC) && (controlPC < procInfo.end_ip)); -#if defined(HOST_ARM) || defined(HOST_ARM64) +#if defined(HOST_ARM) // libunwind fills by reference not by value for ARM *lsda = *((UIntNative *)procInfo.lsda); #else diff --git a/src/coreclr/src/nativeaot/Runtime/unix/UnwindHelpers.cpp b/src/coreclr/src/nativeaot/Runtime/unix/UnwindHelpers.cpp index ced22cc272cd..660220f7454e 100644 --- a/src/coreclr/src/nativeaot/Runtime/unix/UnwindHelpers.cpp +++ b/src/coreclr/src/nativeaot/Runtime/unix/UnwindHelpers.cpp @@ -475,229 +475,284 @@ void Registers_arm_rt::setRegister(int num, uint32_t value, uint32_t location) #if defined(TARGET_ARM64) -class Registers_arm64_rt: public libunwind::Registers_arm64 { -public: - Registers_arm64_rt() { abort(); }; - Registers_arm64_rt(const void *registers); +// Shim that implements methods required by libunwind over REGDISPLAY +struct Registers_REGDISPLAY : REGDISPLAY +{ + inline static int getArch() { return libunwind::REGISTERS_ARM64; } + inline static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } + + bool validRegister(int num) const; + bool validFloatRegister(int num) { return false; }; + bool validVectorRegister(int num) const; - bool validRegister(int num) {abort();}; uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value, uint64_t location); - bool validFloatRegister(int num) {abort();}; + double getFloatRegister(int num) {abort();} void setFloatRegister(int num, double value) {abort();} - bool validVectorRegister(int num) const {abort();} - libunwind::v128 getVectorRegister(int num) const {abort();}; - void setVectorRegister(int num, libunwind::v128 value) {abort();}; - void jumpto() { abort();}; + + libunwind::v128 getVectorRegister(int num) const; + void setVectorRegister(int num, libunwind::v128 value); - uint64_t getSP() const { return regs->SP;} - void setSP(uint64_t value, uint64_t location) { regs->SP = value;} - uint64_t getIP() const { return regs->IP;} + uint64_t getSP() const { return SP;} + void setSP(uint64_t value, uint64_t location) { SP = value;} + uint64_t getIP() const { return IP;} void setIP(uint64_t value, uint64_t location) - { regs->IP = value; regs->pIP = (PTR_UIntNative)location; } - void saveVFPAsX() {abort();}; -private: - REGDISPLAY *regs; + { IP = value; pIP = (PTR_UIntNative)location; } }; -inline Registers_arm64_rt::Registers_arm64_rt(const void *registers) { - regs = (REGDISPLAY *)registers; +inline bool Registers_REGDISPLAY::validRegister(int num) const { + if (num == UNW_REG_SP || num == UNW_ARM64_SP) + return true; + + if (num == UNW_ARM64_FP) + return true; + + if (num == UNW_ARM64_LR) + return true; + + if (num == UNW_REG_IP) + return true; + + if (num >= UNW_ARM64_X0 && num <= UNW_ARM64_X28) + return true; + + return false; +} + +bool Registers_REGDISPLAY::validVectorRegister(int num) const +{ + if (num >= UNW_ARM64_D8 && num <= UNW_ARM64_D15) + return true; + + return false; } -inline uint64_t Registers_arm64_rt::getRegister(int regNum) const { +inline uint64_t Registers_REGDISPLAY::getRegister(int regNum) const { if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP) - return regs->SP; + return SP; + + if (regNum == UNW_ARM64_FP) + return *pFP; if (regNum == UNW_ARM64_LR) - return *regs->pLR; + return *pLR; if (regNum == UNW_REG_IP) - return regs->IP; + return IP; switch (regNum) { case (UNW_ARM64_X0): - return *regs->pX0; + return *pX0; case (UNW_ARM64_X1): - return *regs->pX1; + return *pX1; case (UNW_ARM64_X2): - return *regs->pX2; + return *pX2; case (UNW_ARM64_X3): - return *regs->pX3; + return *pX3; case (UNW_ARM64_X4): - return *regs->pX4; + return *pX4; case (UNW_ARM64_X5): - return *regs->pX5; + return *pX5; case (UNW_ARM64_X6): - return *regs->pX6; + return *pX6; case (UNW_ARM64_X7): - return *regs->pX7; + return *pX7; case (UNW_ARM64_X8): - return *regs->pX8; + return *pX8; case (UNW_ARM64_X9): - return *regs->pX9; + return *pX9; case (UNW_ARM64_X10): - return *regs->pX10; + return *pX10; case (UNW_ARM64_X11): - return *regs->pX11; + return *pX11; case (UNW_ARM64_X12): - return *regs->pX12; + return *pX12; case (UNW_ARM64_X13): - return *regs->pX13; + return *pX13; case (UNW_ARM64_X14): - return *regs->pX14; + return *pX14; case (UNW_ARM64_X15): - return *regs->pX15; + return *pX15; case (UNW_ARM64_X16): - return *regs->pX16; + return *pX16; case (UNW_ARM64_X17): - return *regs->pX17; + return *pX17; case (UNW_ARM64_X18): - return *regs->pX18; + return *pX18; case (UNW_ARM64_X19): - return *regs->pX19; + return *pX19; case (UNW_ARM64_X20): - return *regs->pX20; + return *pX20; case (UNW_ARM64_X21): - return *regs->pX21; + return *pX21; case (UNW_ARM64_X22): - return *regs->pX22; + return *pX22; case (UNW_ARM64_X23): - return *regs->pX23; + return *pX23; case (UNW_ARM64_X24): - return *regs->pX24; + return *pX24; case (UNW_ARM64_X25): - return *regs->pX25; + return *pX25; case (UNW_ARM64_X26): - return *regs->pX26; + return *pX26; case (UNW_ARM64_X27): - return *regs->pX27; + return *pX27; case (UNW_ARM64_X28): - return *regs->pX28; + return *pX28; } PORTABILITY_ASSERT("unsupported arm64 register"); } -void Registers_arm64_rt::setRegister(int num, uint64_t value, uint64_t location) +void Registers_REGDISPLAY::setRegister(int num, uint64_t value, uint64_t location) { - if (num == UNW_REG_SP || num == UNW_ARM64_SP) { - regs->SP = (UIntNative )value; + SP = (UIntNative )value; + return; + } + + if (num == UNW_ARM64_FP) { + pFP = (PTR_UIntNative)location; return; } if (num == UNW_ARM64_LR) { - regs->pLR = (PTR_UIntNative)location; + pLR = (PTR_UIntNative)location; return; } if (num == UNW_REG_IP) { - regs->IP = value; - /* the location could be NULL, we could try to recover - pointer to value in stack from pLR */ - if ((!location) && (regs->pLR) && (*regs->pLR == value)) - regs->pIP = regs->pLR; - else - regs->pIP = (PTR_UIntNative)location; + IP = value; return; } switch (num) { case (UNW_ARM64_X0): - regs->pX0 = (PTR_UIntNative)location; + pX0 = (PTR_UIntNative)location; break; case (UNW_ARM64_X1): - regs->pX1 = (PTR_UIntNative)location; + pX1 = (PTR_UIntNative)location; break; case (UNW_ARM64_X2): - regs->pX2 = (PTR_UIntNative)location; + pX2 = (PTR_UIntNative)location; break; case (UNW_ARM64_X3): - regs->pX3 = (PTR_UIntNative)location; + pX3 = (PTR_UIntNative)location; break; case (UNW_ARM64_X4): - regs->pX4 = (PTR_UIntNative)location; + pX4 = (PTR_UIntNative)location; break; case (UNW_ARM64_X5): - regs->pX5 = (PTR_UIntNative)location; + pX5 = (PTR_UIntNative)location; break; case (UNW_ARM64_X6): - regs->pX6 = (PTR_UIntNative)location; + pX6 = (PTR_UIntNative)location; break; case (UNW_ARM64_X7): - regs->pX7 = (PTR_UIntNative)location; + pX7 = (PTR_UIntNative)location; break; case (UNW_ARM64_X8): - regs->pX8 = (PTR_UIntNative)location; + pX8 = (PTR_UIntNative)location; break; case (UNW_ARM64_X9): - regs->pX9 = (PTR_UIntNative)location; + pX9 = (PTR_UIntNative)location; break; case (UNW_ARM64_X10): - regs->pX10 = (PTR_UIntNative)location; + pX10 = (PTR_UIntNative)location; break; case (UNW_ARM64_X11): - regs->pX11 = (PTR_UIntNative)location; + pX11 = (PTR_UIntNative)location; break; case (UNW_ARM64_X12): - regs->pX12 = (PTR_UIntNative)location; + pX12 = (PTR_UIntNative)location; break; case (UNW_ARM64_X13): - regs->pX13 = (PTR_UIntNative)location; + pX13 = (PTR_UIntNative)location; break; case (UNW_ARM64_X14): - regs->pX14 = (PTR_UIntNative)location; + pX14 = (PTR_UIntNative)location; break; case (UNW_ARM64_X15): - regs->pX15 = (PTR_UIntNative)location; + pX15 = (PTR_UIntNative)location; break; case (UNW_ARM64_X16): - regs->pX16 = (PTR_UIntNative)location; + pX16 = (PTR_UIntNative)location; break; case (UNW_ARM64_X17): - regs->pX17 = (PTR_UIntNative)location; + pX17 = (PTR_UIntNative)location; break; case (UNW_ARM64_X18): - regs->pX18 = (PTR_UIntNative)location; + pX18 = (PTR_UIntNative)location; break; case (UNW_ARM64_X19): - regs->pX19 = (PTR_UIntNative)location; + pX19 = (PTR_UIntNative)location; break; case (UNW_ARM64_X20): - regs->pX20 = (PTR_UIntNative)location; + pX20 = (PTR_UIntNative)location; break; case (UNW_ARM64_X21): - regs->pX21 = (PTR_UIntNative)location; + pX21 = (PTR_UIntNative)location; break; case (UNW_ARM64_X22): - regs->pX22 = (PTR_UIntNative)location; + pX22 = (PTR_UIntNative)location; break; case (UNW_ARM64_X23): - regs->pX23 = (PTR_UIntNative)location; + pX23 = (PTR_UIntNative)location; break; case (UNW_ARM64_X24): - regs->pX24 = (PTR_UIntNative)location; + pX24 = (PTR_UIntNative)location; break; case (UNW_ARM64_X25): - regs->pX25 = (PTR_UIntNative)location; + pX25 = (PTR_UIntNative)location; break; case (UNW_ARM64_X26): - regs->pX26 = (PTR_UIntNative)location; + pX26 = (PTR_UIntNative)location; break; case (UNW_ARM64_X27): - regs->pX27 = (PTR_UIntNative)location; + pX27 = (PTR_UIntNative)location; break; case (UNW_ARM64_X28): - regs->pX28 = (PTR_UIntNative)location; + pX28 = (PTR_UIntNative)location; break; default: PORTABILITY_ASSERT("unsupported arm64 register"); } } +libunwind::v128 Registers_REGDISPLAY::getVectorRegister(int num) const +{ + num -= UNW_ARM64_D8; + + if (num < 0 || num >= sizeof(D) / sizeof(UInt64)) + { + PORTABILITY_ASSERT("unsupported arm64 vector register"); + } + + libunwind::v128 result; + + result.vec[0] = 0; + result.vec[1] = 0; + result.vec[2] = D[num] >> 32; + result.vec[3] = D[num] & 0xFFFFFFFF; + + return result; +} + +void Registers_REGDISPLAY::setVectorRegister(int num, libunwind::v128 value) +{ + num -= UNW_ARM64_D8; + + if (num < 0 || num >= sizeof(D) / sizeof(UInt64)) + { + PORTABILITY_ASSERT("unsupported arm64 vector register"); + } + + D[num] = (UInt64)value.vec[2] << 32 | (UInt64)value.vec[3]; +} + #endif // TARGET_ARM64 bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs) @@ -707,7 +762,7 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs #elif defined(TARGET_ARM) libunwind::UnwindCursor uc(_addressSpace, regs); #elif defined(TARGET_ARM64) - libunwind::UnwindCursor uc(_addressSpace, regs); + libunwind::UnwindCursor uc(_addressSpace, regs); #elif defined(HOST_X86) libunwind::UnwindCursor uc(_addressSpace, regs); #else @@ -724,10 +779,7 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs unw_proc_info_t procInfo; uc.getInfo(&procInfo); -#if defined(TARGET_ARM64) - DwarfInstructions dwarfInst; - int stepRet = dwarfInst.stepWithDwarf(_addressSpace, pc, procInfo.unwind_info, *(Registers_arm64_rt*)regs); -#elif defined(TARGET_ARM) +#if defined(TARGET_ARM) DwarfInstructions dwarfInst; int stepRet = dwarfInst.stepWithDwarf(_addressSpace, pc, procInfo.unwind_info, *(Registers_arm_rt*)regs); #else @@ -740,7 +792,10 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs return false; } +#if !defined(TARGET_ARM64) regs->pIP = PTR_PCODE(regs->SP - sizeof(TADDR)); +#endif + #elif defined(_LIBUNWIND_ARM_EHABI) uc.setInfoBasedOnIPRegister(true); int stepRet = uc.step(); diff --git a/src/coreclr/src/nativeaot/libunwind/src/DwarfInstructions.hpp b/src/coreclr/src/nativeaot/libunwind/src/DwarfInstructions.hpp index c5cc6c9d5107..1eb9c472c58e 100644 --- a/src/coreclr/src/nativeaot/libunwind/src/DwarfInstructions.hpp +++ b/src/coreclr/src/nativeaot/libunwind/src/DwarfInstructions.hpp @@ -169,6 +169,7 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, // restore registers that DWARF says were saved R newRegisters = registers; pint_t returnAddress = 0; + pint_t returnAddressLocation = 0; const int lastReg = R::lastDwarfRegNum(); assert(static_cast(CFI_Parser::kMaxRegisterNumber) >= lastReg && "register range too large"); @@ -186,10 +187,12 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); else if (i == (int)cieInfo.returnAddressRegister) { - pint_t dummyLocation; returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i], - dummyLocation); + returnAddressLocation); + if (registers.validRegister(i)) { + newRegisters.setRegister(i, returnAddress, returnAddressLocation); + } } else if (registers.validRegister(i)) { pint_t value; @@ -272,7 +275,7 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, // Return address is address after call site instruction, so setting IP to // that does simualates a return. - newRegisters.setIP(returnAddress, 0); + newRegisters.setIP(returnAddress, returnAddressLocation); // Simulate the step by replacing the register set with the new ones. registers = newRegisters;