@@ -1823,9 +1823,61 @@ extern "C" void *__libunwind_cet_get_jump_target() {
1823
1823
#endif
1824
1824
1825
1825
class _LIBUNWIND_HIDDEN Registers_arm64 {
1826
+ protected:
1827
+ // / The program counter is used effectively as a return address
1828
+ // / when the context is restored therefore protect it with PAC.
1829
+ // / The base address of the context is used with the A key for
1830
+ // / authentication and signing. Return address authentication is
1831
+ // / still managed according to the unwind info.
1832
+ inline uint64_t getAuthSalt () const {
1833
+ return reinterpret_cast <uint64_t >(this );
1834
+ }
1835
+ #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
1836
+ // Authenticate the given pointer and return with the raw value
1837
+ // if the authentication is succeeded.
1838
+ inline uint64_t auth (uint64_t ptr, uint64_t salt) const {
1839
+ register uint64_t x17 __asm (" x17" ) = ptr;
1840
+ register uint64_t x16 __asm (" x16" ) = salt;
1841
+ asm (" hint 0xc" // autia1716
1842
+ : " +r" (x17)
1843
+ : " r" (x16)
1844
+ :);
1845
+
1846
+ uint64_t checkValue = ptr;
1847
+ // Support for machines without FPAC.
1848
+ // Strip the upper bits with `XPACLRI` and compare with the
1849
+ // authenticated value.
1850
+ asm (" mov x30, %[checkValue] \r\n "
1851
+ " hint 0x7 \r\n "
1852
+ " mov %[checkValue], x30 \r\n "
1853
+ : [checkValue] " +r" (checkValue)
1854
+ :
1855
+ : " x30" );
1856
+ if (x17 != checkValue)
1857
+ _LIBUNWIND_ABORT (" IP PAC authentication failure" );
1858
+ return x17;
1859
+ }
1860
+
1861
+ // Sign the PC with the A-KEY and the current salt.
1862
+ inline void updatePC (uint64_t value) {
1863
+ register uint64_t x17 __asm (" x17" ) = value;
1864
+ register uint64_t x16 __asm (" x16" ) = getAuthSalt ();
1865
+ asm (" hint 0x8" : " +r" (x17) : " r" (x16)); // pacia1716
1866
+ _registers.__pc = x17;
1867
+ }
1868
+ #else // ! defined(_LIBUNWIND_IS_NATIVE_ONLY)
1869
+ // Remote unwinding is not supported by this protection.
1870
+ inline uint64_t auth (uint64_t ptr, uint64_t salt) const { return ptr; }
1871
+ inline void updatePC (uint64_t value) { _registers.__pc = value; }
1872
+ #endif
1873
+
1826
1874
public:
1827
1875
Registers_arm64 ();
1828
1876
Registers_arm64 (const void *registers);
1877
+ Registers_arm64 (const Registers_arm64 &other);
1878
+ Registers_arm64 (const Registers_arm64 &&other) = delete ;
1879
+ Registers_arm64 &operator =(const Registers_arm64 &other);
1880
+ Registers_arm64 &operator =(Registers_arm64 &&other) = delete ;
1829
1881
1830
1882
bool validRegister (int num) const ;
1831
1883
uint64_t getRegister (int num) const ;
@@ -1845,8 +1897,14 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
1845
1897
1846
1898
uint64_t getSP () const { return _registers.__sp ; }
1847
1899
void setSP (uint64_t value) { _registers.__sp = value; }
1848
- uint64_t getIP () const { return _registers.__pc ; }
1849
- void setIP (uint64_t value) { _registers.__pc = value; }
1900
+ uint64_t getIP () const { return auth (_registers.__pc , getAuthSalt ()); }
1901
+ void setIP (uint64_t value) {
1902
+ // First authenticate the current value of the IP to ensure the context
1903
+ // is still valid. This also ensure the setIP can't be used for signing
1904
+ // arbitrary values.
1905
+ auth (_registers.__pc , getAuthSalt ());
1906
+ updatePC (value);
1907
+ }
1850
1908
uint64_t getFP () const { return _registers.__fp ; }
1851
1909
void setFP (uint64_t value) { _registers.__fp = value; }
1852
1910
@@ -1862,8 +1920,8 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
1862
1920
1863
1921
GPRs _registers;
1864
1922
double _vectorHalfRegisters[32 ];
1865
- // Currently only the lower double in 128-bit vectore registers
1866
- // is perserved during unwinding. We could define new register
1923
+ // Currently only the lower double in 128-bit vector registers
1924
+ // is preserved during unwinding. We could define new register
1867
1925
// numbers (> 96) which mean whole vector registers, then this
1868
1926
// struct would need to change to contain whole vector registers.
1869
1927
};
@@ -1874,6 +1932,8 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
1874
1932
memcpy (&_registers, registers, sizeof (_registers));
1875
1933
static_assert (sizeof (GPRs) == 0x110 ,
1876
1934
" expected VFP registers to be at offset 272" );
1935
+ // getcontext signs the PC with the base address of the context.
1936
+ updatePC (auth (_registers.__pc , reinterpret_cast <uint64_t >(registers)));
1877
1937
memcpy (_vectorHalfRegisters,
1878
1938
static_cast <const uint8_t *>(registers) + sizeof (GPRs),
1879
1939
sizeof (_vectorHalfRegisters));
@@ -1882,6 +1942,25 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
1882
1942
inline Registers_arm64::Registers_arm64 () {
1883
1943
memset (&_registers, 0 , sizeof (_registers));
1884
1944
memset (&_vectorHalfRegisters, 0 , sizeof (_vectorHalfRegisters));
1945
+ // We don't know the PC but let's sign to indicate we have a valid
1946
+ // register set.
1947
+ updatePC (0 );
1948
+ }
1949
+
1950
+ inline Registers_arm64::Registers_arm64 (const Registers_arm64 &other) {
1951
+ memcpy (&_registers, &other._registers , sizeof (_registers));
1952
+ memcpy (&_vectorHalfRegisters, &other._vectorHalfRegisters ,
1953
+ sizeof (_vectorHalfRegisters));
1954
+ updatePC (other.getIP ());
1955
+ }
1956
+
1957
+ inline Registers_arm64 &
1958
+ Registers_arm64::operator =(const Registers_arm64 &other) {
1959
+ memcpy (&_registers, &other._registers , sizeof (_registers));
1960
+ memcpy (&_vectorHalfRegisters, &other._vectorHalfRegisters ,
1961
+ sizeof (_vectorHalfRegisters));
1962
+ updatePC (other.getIP ());
1963
+ return *this ;
1885
1964
}
1886
1965
1887
1966
inline bool Registers_arm64::validRegister (int regNum) const {
@@ -1902,7 +1981,7 @@ inline bool Registers_arm64::validRegister(int regNum) const {
1902
1981
1903
1982
inline uint64_t Registers_arm64::getRegister (int regNum) const {
1904
1983
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
1905
- return _registers. __pc ;
1984
+ return getIP () ;
1906
1985
if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
1907
1986
return _registers.__sp ;
1908
1987
if (regNum == UNW_AARCH64_RA_SIGN_STATE)
@@ -1918,7 +1997,7 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const {
1918
1997
1919
1998
inline void Registers_arm64::setRegister (int regNum, uint64_t value) {
1920
1999
if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
1921
- _registers. __pc = value;
2000
+ setIP ( value) ;
1922
2001
else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
1923
2002
_registers.__sp = value;
1924
2003
else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
0 commit comments