[Lldb-commits] [lldb] [lldb][AArch64] Add register fields for Guarded Control Stack registers (PR #124295)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Jan 24 07:51:05 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: David Spickett (DavidSpickett)
<details>
<summary>Changes</summary>
The features and locked registers hold the same bits, the latter
is a lock for the former. Tested with core files and live processes.
I thought about setting a non-zero lock register in the core file,
however:
* We can be pretty sure it's reading correctly because its between
the 2 other GCS registers in the same core file note.
* I can't make the test case modify lock bits because userspace
can't clear them and we don't know what the libc has locked
(probably all feature bits).
---
Patch is 42.40 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/124295.diff
15 Files Affected:
- (modified) lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp (+75)
- (modified) lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp (+104)
- (modified) lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h (+16)
- (modified) lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp (+4)
- (modified) lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h (+1)
- (modified) lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp (+16)
- (modified) lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h (+4-1)
- (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp (+38-1)
- (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h (+7)
- (modified) lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp (+17)
- (modified) lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h (+1)
- (modified) lldb/source/Plugins/Process/elf-core/RegisterUtilities.h (+4)
- (modified) lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py (+323)
- (added) lldb/test/API/linux/aarch64/gcs/corefile ()
- (modified) lldb/test/API/linux/aarch64/gcs/main.c (+57-5)
``````````diff
diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
index 93b8141e97ef86..74047ea65788cf 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
@@ -60,6 +60,69 @@ ABISysV_arm64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch)
return ABISP();
}
+static Status PushToLinuxGuardedControlStack(addr_t return_addr,
+ RegisterContext *reg_ctx,
+ Thread &thread) {
+ Status err;
+
+ // If the Guarded Control Stack extension is present we may need to put the
+ // return address onto that stack.
+ const RegisterInfo *gcs_features_enabled_info =
+ reg_ctx->GetRegisterInfoByName("gcs_features_enabled");
+ if (!gcs_features_enabled_info)
+ return err;
+
+ uint64_t gcs_features_enabled = reg_ctx->ReadRegisterAsUnsigned(
+ gcs_features_enabled_info, LLDB_INVALID_ADDRESS);
+ if (gcs_features_enabled == LLDB_INVALID_ADDRESS)
+ return Status("Could not read GCS features enabled register.");
+
+ // Only attempt this if GCS is enabled. If it's not enabled then gcspr_el0
+ // may point to unmapped memory.
+ if ((gcs_features_enabled & 1) == 0)
+ return err;
+
+ const RegisterInfo *gcspr_el0_info =
+ reg_ctx->GetRegisterInfoByName("gcspr_el0");
+ if (!gcspr_el0_info)
+ return Status("Could not get register info for gcspr_el0.");
+
+ uint64_t gcspr_el0 =
+ reg_ctx->ReadRegisterAsUnsigned(gcspr_el0_info, LLDB_INVALID_ADDRESS);
+ if (gcspr_el0 == LLDB_INVALID_ADDRESS)
+ return Status("Could not read gcspr_el0.");
+
+ // A link register entry on the GCS is 8 bytes.
+ gcspr_el0 -= 8;
+ if (!reg_ctx->WriteRegisterFromUnsigned(gcspr_el0_info, gcspr_el0))
+ return Status(
+ "Attempted to decrement gcspr_el0, but could not write to it.");
+
+ Status error;
+ size_t wrote = thread.GetProcess()->WriteMemory(gcspr_el0, &return_addr,
+ sizeof(return_addr), error);
+ if ((wrote != sizeof(return_addr) || error.Fail())) {
+ // When PrepareTrivialCall fails, the register context is not restored,
+ // unlike when an expression fails to execute. This is arguably a bug,
+ // see https://github.com/llvm/llvm-project/issues/124269.
+ // For now we are handling this here specifically. We can assume this
+ // write will work as the one to decrement the register did.
+ reg_ctx->WriteRegisterFromUnsigned(gcspr_el0_info, gcspr_el0 + 8);
+ return Status("Failed to write new Guarded Control Stack entry.");
+ }
+
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOGF(log,
+ "Pushed return address 0x%" PRIx64 " to Guarded Control Stack. "
+ "gcspr_el0 was 0%" PRIx64 ", is now 0x%" PRIx64 ".",
+ return_addr, gcspr_el0 - 8, gcspr_el0);
+
+ // gcspr_el0 will be restored to the original value by lldb-server after
+ // the call has finished, which serves as the "pop".
+
+ return err;
+}
+
bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp,
addr_t func_addr, addr_t return_addr,
llvm::ArrayRef<addr_t> args) const {
@@ -87,6 +150,18 @@ bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp,
if (args.size() > 8)
return false;
+ // Do this first, as it's got the most chance of failing (though still very
+ // low).
+ if (GetProcessSP()->GetTarget().GetArchitecture().GetTriple().isOSLinux()) {
+ Status err = PushToLinuxGuardedControlStack(return_addr, reg_ctx, thread);
+ // If we could not manage the GCS, the expression will certainly fail,
+ // and if we just carried on, that failure would be a lot more cryptic.
+ if (err.Fail()) {
+ LLDB_LOGF(log, "Failed to setup Guarded Call Stack: %s", err.AsCString());
+ return false;
+ }
+ }
+
for (size_t i = 0; i < args.size(); ++i) {
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 6056f3001fed6e..884c7d4b9e3590 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -64,8 +64,14 @@
#define NT_ARM_FPMR 0x40e /* Floating point mode register */
#endif
+#ifndef NT_ARM_GCS
+#define NT_ARM_GCS 0x410 /* Guarded Control Stack control registers */
+#endif
+
#define HWCAP_PACA (1 << 30)
+#define HWCAP_GCS (1UL << 32)
+
#define HWCAP2_MTE (1 << 18)
#define HWCAP2_FPMR (1UL << 48)
@@ -150,6 +156,8 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE);
if (*auxv_at_hwcap2 & HWCAP2_FPMR)
opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskFPMR);
+ if (*auxv_at_hwcap & HWCAP_GCS)
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskGCS);
}
opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS);
@@ -193,6 +201,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
::memset(&m_pac_mask, 0, sizeof(m_pac_mask));
::memset(&m_tls_regs, 0, sizeof(m_tls_regs));
::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs));
+ ::memset(&m_gcs_regs, 0, sizeof(m_gcs_regs));
std::fill(m_zt_reg.begin(), m_zt_reg.end(), 0);
m_mte_ctrl_reg = 0;
@@ -213,6 +222,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
m_tls_is_valid = false;
m_zt_buffer_is_valid = false;
m_fpmr_is_valid = false;
+ m_gcs_is_valid = false;
// SME adds the tpidr2 register
m_tls_size = GetRegisterInfo().IsSSVEPresent() ? sizeof(m_tls_regs)
@@ -433,6 +443,14 @@ NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info,
offset = reg_info->byte_offset - GetRegisterInfo().GetFPMROffset();
assert(offset < GetFPMRBufferSize());
src = (uint8_t *)GetFPMRBuffer() + offset;
+ } else if (IsGCS(reg)) {
+ error = ReadGCS();
+ if (error.Fail())
+ return error;
+
+ offset = reg_info->byte_offset - GetRegisterInfo().GetGCSOffset();
+ assert(offset < GetGCSBufferSize());
+ src = (uint8_t *)GetGCSBuffer() + offset;
} else
return Status::FromErrorString(
"failed - register wasn't recognized to be a GPR or an FPR, "
@@ -657,6 +675,17 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
return WriteFPMR();
+ } else if (IsGCS(reg)) {
+ error = ReadGCS();
+ if (error.Fail())
+ return error;
+
+ offset = reg_info->byte_offset - GetRegisterInfo().GetGCSOffset();
+ assert(offset < GetGCSBufferSize());
+ dst = (uint8_t *)GetGCSBuffer() + offset;
+ ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
+
+ return WriteGCS();
}
return Status::FromErrorString("Failed to write register value");
@@ -672,6 +701,7 @@ enum RegisterSetType : uint32_t {
SME, // ZA only, because SVCR and SVG are pseudo registers.
SME2, // ZT only.
FPMR,
+ GCS, // Guarded Control Stack registers.
};
static uint8_t *AddRegisterSetType(uint8_t *dst,
@@ -759,6 +789,13 @@ NativeRegisterContextLinux_arm64::CacheAllRegisters(uint32_t &cached_size) {
return error;
}
+ if (GetRegisterInfo().IsGCSPresent()) {
+ cached_size += sizeof(RegisterSetType) + GetGCSBufferSize();
+ error = ReadGCS();
+ if (error.Fail())
+ return error;
+ }
+
// tpidr is always present but tpidr2 depends on SME.
cached_size += sizeof(RegisterSetType) + GetTLSBufferSize();
error = ReadTLS();
@@ -867,6 +904,11 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
GetFPMRBufferSize());
}
+ if (GetRegisterInfo().IsGCSPresent()) {
+ dst = AddSavedRegisters(dst, RegisterSetType::GCS, GetGCSBuffer(),
+ GetGCSBufferSize());
+ }
+
dst = AddSavedRegisters(dst, RegisterSetType::TLS, GetTLSBuffer(),
GetTLSBufferSize());
@@ -1020,6 +1062,29 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
GetFPMRBuffer(), &src, GetFPMRBufferSize(), m_fpmr_is_valid,
std::bind(&NativeRegisterContextLinux_arm64::WriteFPMR, this));
break;
+ case RegisterSetType::GCS:
+ // It is not permitted to enable GCS via ptrace. We can disable it, but
+ // to keep things simple we will not revert any change to the
+ // PR_SHADOW_STACK_ENABLE bit. Instead patch in the current enable bit
+ // into the registers we are about to restore.
+ m_gcs_is_valid = false;
+ error = ReadGCS();
+ if (error.Fail())
+ return error;
+
+ uint64_t enable_bit = m_gcs_regs.features_enabled & 1UL;
+ gcs_regs new_gcs_regs = *reinterpret_cast<const gcs_regs *>(src);
+ new_gcs_regs.features_enabled =
+ (new_gcs_regs.features_enabled & ~1UL) | enable_bit;
+
+ const uint8_t *new_gcs_src =
+ reinterpret_cast<const uint8_t *>(&new_gcs_regs);
+ error = RestoreRegisters(
+ GetGCSBuffer(), &new_gcs_src, GetGCSBufferSize(), m_gcs_is_valid,
+ std::bind(&NativeRegisterContextLinux_arm64::WriteGCS, this));
+ src += GetGCSBufferSize();
+
+ break;
}
if (error.Fail())
@@ -1067,6 +1132,10 @@ bool NativeRegisterContextLinux_arm64::IsFPMR(unsigned reg) const {
return GetRegisterInfo().IsFPMRReg(reg);
}
+bool NativeRegisterContextLinux_arm64::IsGCS(unsigned reg) const {
+ return GetRegisterInfo().IsGCSReg(reg);
+}
+
llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
if (!m_refresh_hwdebug_info) {
return llvm::Error::success();
@@ -1215,6 +1284,7 @@ void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() {
m_tls_is_valid = false;
m_zt_buffer_is_valid = false;
m_fpmr_is_valid = false;
+ m_gcs_is_valid = false;
// Update SVE and ZA registers in case there is change in configuration.
ConfigureRegisterContext();
@@ -1400,6 +1470,40 @@ Status NativeRegisterContextLinux_arm64::WriteTLS() {
return WriteRegisterSet(&ioVec, GetTLSBufferSize(), NT_ARM_TLS);
}
+Status NativeRegisterContextLinux_arm64::ReadGCS() {
+ Status error;
+
+ if (m_gcs_is_valid)
+ return error;
+
+ struct iovec ioVec;
+ ioVec.iov_base = GetGCSBuffer();
+ ioVec.iov_len = GetGCSBufferSize();
+
+ error = ReadRegisterSet(&ioVec, GetGCSBufferSize(), NT_ARM_GCS);
+
+ if (error.Success())
+ m_gcs_is_valid = true;
+
+ return error;
+}
+
+Status NativeRegisterContextLinux_arm64::WriteGCS() {
+ Status error;
+
+ error = ReadGCS();
+ if (error.Fail())
+ return error;
+
+ struct iovec ioVec;
+ ioVec.iov_base = GetGCSBuffer();
+ ioVec.iov_len = GetGCSBufferSize();
+
+ m_gcs_is_valid = false;
+
+ return WriteRegisterSet(&ioVec, GetGCSBufferSize(), NT_ARM_GCS);
+}
+
Status NativeRegisterContextLinux_arm64::ReadZAHeader() {
Status error;
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
index 16190b5492582b..7ed0da85034969 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -92,6 +92,7 @@ class NativeRegisterContextLinux_arm64
bool m_pac_mask_is_valid;
bool m_tls_is_valid;
size_t m_tls_size;
+ bool m_gcs_is_valid;
struct user_pt_regs m_gpr_arm64; // 64-bit general purpose registers.
@@ -136,6 +137,12 @@ class NativeRegisterContextLinux_arm64
uint64_t m_fpmr_reg;
+ struct gcs_regs {
+ uint64_t features_enabled;
+ uint64_t features_locked;
+ uint64_t gcspr_e0;
+ } m_gcs_regs;
+
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
@@ -166,6 +173,10 @@ class NativeRegisterContextLinux_arm64
Status WriteZA();
+ Status ReadGCS();
+
+ Status WriteGCS();
+
// No WriteZAHeader because writing only the header will disable ZA.
// Instead use WriteZA and ensure you have the correct ZA buffer size set
// beforehand if you wish to disable it.
@@ -187,6 +198,7 @@ class NativeRegisterContextLinux_arm64
bool IsMTE(unsigned reg) const;
bool IsTLS(unsigned reg) const;
bool IsFPMR(unsigned reg) const;
+ bool IsGCS(unsigned reg) const;
uint64_t GetSVERegVG() { return m_sve_header.vl / 8; }
@@ -212,6 +224,8 @@ class NativeRegisterContextLinux_arm64
void *GetFPMRBuffer() { return &m_fpmr_reg; }
+ void *GetGCSBuffer() { return &m_gcs_regs; }
+
size_t GetSVEHeaderSize() { return sizeof(m_sve_header); }
size_t GetPACMaskSize() { return sizeof(m_pac_mask); }
@@ -234,6 +248,8 @@ class NativeRegisterContextLinux_arm64
size_t GetFPMRBufferSize() { return sizeof(m_fpmr_reg); }
+ size_t GetGCSBufferSize() { return sizeof(m_gcs_regs); }
+
llvm::Error ReadHardwareDebugInfo() override;
llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
index 575e9c8c81cbf5..0233837f99d097 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -63,6 +63,10 @@ bool RegisterContextPOSIX_arm64::IsFPMR(unsigned reg) const {
return m_register_info_up->IsFPMRReg(reg);
}
+bool RegisterContextPOSIX_arm64::IsGCS(unsigned reg) const {
+ return m_register_info_up->IsGCSReg(reg);
+}
+
RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm64> register_info)
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
index 35ad56c98a7aed..de46c628d836d8 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -59,6 +59,7 @@ class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext {
bool IsSME(unsigned reg) const;
bool IsMTE(unsigned reg) const;
bool IsFPMR(unsigned reg) const;
+ bool IsGCS(unsigned reg) const;
bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); }
bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); }
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
index 9f82c935c0e7ed..1438a45f37d724 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
@@ -17,6 +17,7 @@
#define HWCAP_ASIMDHP (1ULL << 10)
#define HWCAP_DIT (1ULL << 24)
#define HWCAP_SSBS (1ULL << 28)
+#define HWCAP_GCS (1UL << 32)
#define HWCAP2_BTI (1ULL << 17)
#define HWCAP2_MTE (1ULL << 18)
@@ -50,6 +51,21 @@ Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2) {
};
}
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectGCSFeatureFields(uint64_t hwcap,
+ uint64_t hwcap2) {
+ (void)hwcap2;
+
+ if (!(hwcap & HWCAP_GCS))
+ return {};
+
+ return {
+ {"PUSH", 2},
+ {"WRITE", 1},
+ {"ENABLE", 0},
+ };
+}
+
Arm64RegisterFlagsDetector::Fields
Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
(void)hwcap;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
index 0f3d53d93892bd..7daebcc71db044 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
@@ -61,6 +61,7 @@ class Arm64RegisterFlagsDetector {
static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2);
static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2);
static Fields DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2);
+ static Fields DetectGCSFeatureFields(uint64_t hwcap, uint64_t hwcap2);
struct RegisterEntry {
RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector)
@@ -70,13 +71,15 @@ class Arm64RegisterFlagsDetector {
llvm::StringRef m_name;
RegisterFlags m_flags;
DetectorFn m_detector;
- } m_registers[6] = {
+ } m_registers[8] = {
RegisterEntry("cpsr", 4, DetectCPSRFields),
RegisterEntry("fpsr", 4, DetectFPSRFields),
RegisterEntry("fpcr", 4, DetectFPCRFields),
RegisterEntry("mte_ctrl", 8, DetectMTECtrlFields),
RegisterEntry("svcr", 8, DetectSVCRFields),
RegisterEntry("fpmr", 8, DetectFPMRFields),
+ RegisterEntry("gcs_features_enabled", 8, DetectGCSFeatureFields),
+ RegisterEntry("gcs_features_locked", 8, DetectGCSFeatureFields),
};
// Becomes true once field detection has been run for all registers.
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
index f51a93e1b2dcbd..c004c0f3c3cf52 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -97,6 +97,10 @@ static lldb_private::RegisterInfo g_register_infos_sme2[] = {
static lldb_private::RegisterInfo g_register_infos_fpmr[] = {
DEFINE_EXTENSION_REG(fpmr)};
+static lldb_private::RegisterInfo g_register_infos_gcs[] = {
+ DEFINE_EXTENSION_REG(gcs_features_enabled),
+ DEFINE_EXTENSION_REG(gcs_features_locked), DEFINE_EXTENSION_REG(gcspr_el0)};
+
// Number of register sets provided by this context.
enum {
k_num_gpr_registers = gpr_w28 - gpr_x0 + 1,
@@ -109,6 +113,7 @@ enum {
// only for SME1 registers.
k_num_sme_register = 3,
k_num_fpmr_register = 1,
+ k_num_gcs_register = 3,
k_num_register_sets_default = 2,
k_num_register_sets = 3
};
@@ -221,6 +226,9 @@ static const lldb_private::RegisterSet g_reg_set_sme_arm64 = {
static const lldb_private::RegisterSet g_reg_set_fpmr_arm64 = {
"Floating Point Mode Register", "fpmr", k_num_fpmr_register, nullptr};
+static const lldb_private::RegisterSet g_reg_set_gcs_arm64 = {
+ "Guarded Control Stack Registers", "gcs", k_num_gcs_register, nullptr};
+
RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets)
: lldb_private::RegisterInfoAndSetInterface(target_arch),
@@ -273,6 +281,9 @@ RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
if (m_opt_regsets.AllSet(eRegsetMaskFPMR))
AddRegSetFPMR();
+ if (m_opt_regsets.AllSet(eRegsetMaskGCS))
+ AddRegSetGCS();
+
m_register_info_count = m_dynamic_reg_infos.size();
m_register_info_p = m_dynamic_reg_infos.data();
m_register_set_p = m_dynamic_reg_sets.data();
@@ -434,6 +445,24 @@ void RegisterInfoPOSIX_arm64::AddRegSetFPMR() {
m_dynamic_reg_sets.back().registers = m_fpmr_regnum_collection.data();
}
+void RegisterInfoPOSIX_arm64::AddRegSetGCS() {
+ uint32_t gcs_regnum = m_dynamic_reg_infos.size();
+ for (uint32_t i = 0; i < k_num_gcs_register; i++) {
+ m_gcs_regnum_collection.push_back(gcs_regnum + i);
+ m_dynamic_reg_infos.push_back(g_register_infos_gcs[i]);
+ m_dynamic_reg_infos[gcs_regnum + i].byte_offset =
+ m_dynamic_reg_infos[gcs_regnum + i - 1].byte_offset +
+ m_dynamic_reg_infos[gcs_regnum + i - 1].byte_size;
+ m_dynamic_reg_infos[gcs_regnum + i].kinds[lldb::eRegisterKindLLDB] =
+ gcs_regnum + i;
+ }
+
+ m_per_regset_regnum_range[m_register_set_count] =
+ std::make_pair(gcs_regnum, m_dynamic_reg_infos.size());
+ m_dynamic_reg_sets.push_back(g_reg_set_gcs_arm64);
+ m_dynamic_reg_sets.back().registers = m_gcs_regnum_collection.data();
+}
+
uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLengthSVE(uint32_t sve_vq) {
// sve_vq contains SVE Quad vector length in context of AArch64 SVE.
// SVE register info...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/124295
More information about the lldb-commits
mailing list