Index: include/libunwind.h =================================================================== --- include/libunwind.h +++ include/libunwind.h @@ -547,6 +547,8 @@ UNW_ARM64_X31 = 31, UNW_ARM64_SP = 31, // reserved block + UNW_ARM64_RA_SIGN_STATE = 34, + // reserved block UNW_ARM64_D0 = 64, UNW_ARM64_D1 = 65, UNW_ARM64_D2 = 66, Index: src/DwarfInstructions.hpp =================================================================== --- src/DwarfInstructions.hpp +++ src/DwarfInstructions.hpp @@ -198,6 +198,20 @@ // restoring SP means setting it to CFA. newRegisters.setSP(cfa); +#if defined(_LIBUNWIND_TARGET_AARCH64) + // 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 + // restored. autia1716 is used instead of autia as autia1716 assembles + // to a NOP on pre-v8.3a architectures. + if (prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) { + register unsigned long long x17 __asm("x17") = returnAddress; + register unsigned long long x16 __asm("x16") = cfa; + asm("autia1716": "+r"(x17): "r"(x16)); + returnAddress = x17; + } +#endif + // Return address is address after call site instruction, so setting IP to // that does simualates a return. newRegisters.setIP(returnAddress); Index: src/DwarfParser.hpp =================================================================== --- src/DwarfParser.hpp +++ src/DwarfParser.hpp @@ -666,6 +666,14 @@ _LIBUNWIND_TRACE_DWARF( "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); break; + +#if defined(_LIBUNWIND_TARGET_AARCH64) + case DW_CFA_AARCH64_negate_ra_state: + results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1; + _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); + break; +#endif + default: operand = opcode & 0x3F; switch (opcode & 0xC0) { Index: src/Registers.hpp =================================================================== --- src/Registers.hpp +++ src/Registers.hpp @@ -1819,6 +1819,8 @@ return false; if (regNum > 95) return false; + if (regNum == UNW_ARM64_RA_SIGN_STATE) + return true; if ((regNum > 31) && (regNum < 64)) return false; return true; @@ -1829,8 +1831,9 @@ return _registers.__pc; if (regNum == UNW_REG_SP) return _registers.__sp; - if ((regNum >= 0) && (regNum < 32)) + if (((regNum >= 0) && (regNum < 32)) || regNum == UNW_ARM64_RA_SIGN_STATE) return _registers.__x[regNum]; + _LIBUNWIND_ABORT("unsupported arm64 register"); } @@ -1839,7 +1842,7 @@ _registers.__pc = value; else if (regNum == UNW_REG_SP) _registers.__sp = value; - else if ((regNum >= 0) && (regNum < 32)) + else if ((regNum >= 0) && (regNum < 32) || regNum == UNW_ARM64_RA_SIGN_STATE) _registers.__x[regNum] = value; else _LIBUNWIND_ABORT("unsupported arm64 register"); Index: src/dwarf2.h =================================================================== --- src/dwarf2.h +++ src/dwarf2.h @@ -49,7 +49,10 @@ // GNU extensions DW_CFA_GNU_window_save = 0x2D, DW_CFA_GNU_args_size = 0x2E, - DW_CFA_GNU_negative_offset_extended = 0x2F + DW_CFA_GNU_negative_offset_extended = 0x2F, + + // AARCH64 extensions + DW_CFA_AARCH64_negate_ra_state = 0x2D };