[Lldb-commits] [lldb] [lldb][AArch64] Add register fields for Guarded Control Stack registers (PR #124295)

David Spickett via lldb-commits lldb-commits at lists.llvm.org
Tue Jan 28 03:51:13 PST 2025


https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/124295

>From de84dc94ee6e5f15450f9e2729bfdbafd212b7f0 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Tue, 27 Aug 2024 14:35:28 +0100
Subject: [PATCH] [lldb][AArch64] Add register fields for Guarded Control Stack
 registers

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).
---
 .../Utility/RegisterFlagsDetector_arm64.cpp      | 16 ++++++++++++++++
 .../Utility/RegisterFlagsDetector_arm64.h        |  5 ++++-
 .../API/linux/aarch64/gcs/TestAArch64LinuxGCS.py | 15 ++++++++++++++-
 3 files changed, 34 insertions(+), 2 deletions(-)

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/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py
index adbef69c5c38b0..f5a2ca356bbe81 100644
--- a/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py
+++ b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py
@@ -223,7 +223,10 @@ def test_gcs_registers(self):
         self.runCmd(f"register write gcs_features_enabled {enabled}")
         self.expect(
             "register read gcs_features_enabled",
-            substrs=[f"gcs_features_enabled = 0x{enabled:016x}"],
+            substrs=[
+                f"gcs_features_enabled = 0x{enabled:016x}",
+                f"= (PUSH = {(enabled >> 2) & 1}, WRITE = {(enabled >> 1) & 1}, ENABLE = {enabled & 1})",
+            ],
         )
 
         # With GCS disabled, the invalid guarded control stack pointer is not
@@ -399,6 +402,16 @@ def test_gcs_core_file(self):
             ],
         )
 
+        # Should get register fields for both. They have the same fields.
+        self.expect(
+            "register read gcs_features_enabled",
+            substrs=["= (PUSH = 0, WRITE = 0, ENABLE = 1)"],
+        )
+        self.expect(
+            "register read gcs_features_locked",
+            substrs=["= (PUSH = 0, WRITE = 0, ENABLE = 0)"],
+        )
+
         # Core files do not include /proc/pid/smaps, so we cannot see the
         # shadow stack "ss" flag. gcspr_el0 should at least point to some mapped
         # region.



More information about the lldb-commits mailing list