diff --git a/src/ExtraRegisters.cc b/src/ExtraRegisters.cc index 1b585cbaa16..5ba479d4a99 100644 --- a/src/ExtraRegisters.cc +++ b/src/ExtraRegisters.cc @@ -275,6 +275,21 @@ size_t ExtraRegisters::read_register(uint8_t* buf, GdbServerRegister regno, } else if (regno == DREG_FPCR) { reg_data = RegData(offsetof(ARM64Arch::user_fpsimd_state, fpcr), sizeof(uint32_t)); +#ifdef __aarch64__ + } else if (regno == DREG_PAUTH_DMASK || regno == DREG_PAUTH_CMASK) { + uint64_t ptr = 1ULL << 55; + // The XPAC instruction will copy bit 55 of the argument into the PAC mask + // bits, so ptr will be set to the mask plus bit 55. + if (regno == DREG_PAUTH_DMASK) { + __asm__ __volatile__("xpacd %0" : "+r"(ptr)); + } else { + __asm__ __volatile__("xpaci %0" : "+r"(ptr)); + } + uint64_t mask = ptr & ~(1ULL << 55); + *defined = true; + memcpy(buf, &mask, sizeof(mask)); + return sizeof(mask); +#endif } else { *defined = false; return 0; diff --git a/src/GdbServer.cc b/src/GdbServer.cc index 0d4e65a5256..12a3c943f1c 100644 --- a/src/GdbServer.cc +++ b/src/GdbServer.cc @@ -2332,6 +2332,7 @@ const vector& GdbServer::target_registers( bool have_PKU = dbg->cpu_features() & GdbServerConnection::CPU_PKU; bool have_AVX = dbg->cpu_features() & GdbServerConnection::CPU_AVX; bool have_AVX512 = dbg->cpu_features() & GdbServerConnection::CPU_AVX512; + bool have_PAUTH = dbg->cpu_features() & GdbServerConnection::CPU_PAUTH; switch (arch) { case x86: { add_range(GdbServerRegister(0), GdbServerRegister(DREG_ORIG_EAX)); @@ -2368,7 +2369,11 @@ const vector& GdbServer::target_registers( } case aarch64: add_range(GdbServerRegister::DREG_X0, - GdbServerRegister::DREG_NUM_LINUX_AARCH64); + GdbServerRegister::DREG_FPCR); + if (have_PAUTH) { + register_description.push_back(DREG_PAUTH_DMASK); + register_description.push_back(DREG_PAUTH_CMASK); + } break; default: FATAL() << "Unknown architecture"; diff --git a/src/GdbServerConnection.cc b/src/GdbServerConnection.cc index e67ee06bbfd..dd8cc628a72 100644 --- a/src/GdbServerConnection.cc +++ b/src/GdbServerConnection.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include "ScopedFd.h" #include "TargetDescription.h" #include "core.h" +#include "kernel_supplement.h" #include "log.h" using namespace std; @@ -106,6 +108,11 @@ static uint32_t get_cpu_features(SupportedArch arch) { } case aarch64: cpu_features = GdbServerConnection::CPU_AARCH64; +#ifdef __aarch64__ + if (getauxval(AT_HWCAP) & HWCAP_PACA) { + cpu_features |= GdbServerConnection::CPU_PAUTH; + } +#endif break; default: FATAL() << "Unknown architecture"; diff --git a/src/GdbServerConnection.h b/src/GdbServerConnection.h index e6204d4c09d..08db82e114c 100644 --- a/src/GdbServerConnection.h +++ b/src/GdbServerConnection.h @@ -752,7 +752,8 @@ class GdbServerConnection { CPU_AVX = 1 << 1, CPU_AARCH64 = 1 << 2, CPU_PKU = 1 << 3, - CPU_AVX512 = 1 << 4 + CPU_AVX512 = 1 << 4, + CPU_PAUTH = 1 << 5 }; void set_cpu_features(SupportedArch arch); diff --git a/src/GdbServerRegister.h b/src/GdbServerRegister.h index 0234c39349f..a17dc52ad6b 100644 --- a/src/GdbServerRegister.h +++ b/src/GdbServerRegister.h @@ -320,7 +320,11 @@ enum GdbServerRegister { DREG_FPSR, DREG_FPCR, - DREG_NUM_LINUX_AARCH64 = DREG_FPCR + 1, + // aarch64-pauth.xml + DREG_PAUTH_DMASK, + DREG_PAUTH_CMASK, + + DREG_NUM_LINUX_AARCH64, }; } // namespace rr diff --git a/src/TargetDescription.cc b/src/TargetDescription.cc index 17726c8b1ba..22f066a8a08 100644 --- a/src/TargetDescription.cc +++ b/src/TargetDescription.cc @@ -78,6 +78,9 @@ FeatureStream& operator<<(FeatureStream& stream, TargetFeature feature) { case TargetFeature::FPU: stream << "fpu.xml"; break; + case TargetFeature::PAuth: + stream << "pauth.xml"; + break; } stream << R"("/>)" << '\n'; return stream; @@ -103,6 +106,9 @@ TargetDescription::TargetDescription(rr::SupportedArch arch, case rr::aarch64: target_features.push_back(TargetFeature::Core); target_features.push_back(TargetFeature::FPU); + if (cpu_features & rr::GdbServerConnection::CPU_PAUTH) { + target_features.push_back(TargetFeature::PAuth); + } break; } diff --git a/src/TargetDescription.h b/src/TargetDescription.h index e4dcf556400..245a4ff41ed 100644 --- a/src/TargetDescription.h +++ b/src/TargetDescription.h @@ -20,6 +20,7 @@ enum class TargetFeature : uint32_t { AVX512, PKeys, FPU, + PAuth, }; class TargetDescription { diff --git a/src/kernel_supplement.h b/src/kernel_supplement.h index 0c6f8eaaea8..71bf6930f57 100644 --- a/src/kernel_supplement.h +++ b/src/kernel_supplement.h @@ -148,6 +148,10 @@ enum _ptrace_get_syscall_info_op { #define NT_ARM_PACG_KEYS 0x408 #endif +#ifndef HWCAP_PACA +#define HWCAP_PACA (1 << 30) +#endif + // These are defined by the include/linux/errno.h in the kernel tree. // Since userspace doesn't see these errnos in normal operation, that // header apparently isn't distributed with libc.