Skip to content

Commit 770d763

Browse files
committed
[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).
1 parent 00b4969 commit 770d763

File tree

3 files changed

+38
-3
lines changed

3 files changed

+38
-3
lines changed

lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define HWCAP_ASIMDHP (1ULL << 10)
1818
#define HWCAP_DIT (1ULL << 24)
1919
#define HWCAP_SSBS (1ULL << 28)
20+
#define HWCAP_GCS (1UL << 32)
2021

2122
#define HWCAP2_BTI (1ULL << 17)
2223
#define HWCAP2_MTE (1ULL << 18)
@@ -50,6 +51,21 @@ Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2) {
5051
};
5152
}
5253

54+
Arm64RegisterFlagsDetector::Fields
55+
Arm64RegisterFlagsDetector::DetectGCSFeatureFields(uint64_t hwcap,
56+
uint64_t hwcap2) {
57+
(void)hwcap2;
58+
59+
if (!(hwcap & HWCAP_GCS))
60+
return {};
61+
62+
return {
63+
{"PUSH", 2},
64+
{"WRITE", 1},
65+
{"ENABLE", 0},
66+
};
67+
}
68+
5369
Arm64RegisterFlagsDetector::Fields
5470
Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
5571
(void)hwcap;

lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class Arm64RegisterFlagsDetector {
6161
static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2);
6262
static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2);
6363
static Fields DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2);
64+
static Fields DetectGCSFeatureFields(uint64_t hwcap, uint64_t hwcap2);
6465

6566
struct RegisterEntry {
6667
RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector)
@@ -70,13 +71,15 @@ class Arm64RegisterFlagsDetector {
7071
llvm::StringRef m_name;
7172
RegisterFlags m_flags;
7273
DetectorFn m_detector;
73-
} m_registers[6] = {
74+
} m_registers[8] = {
7475
RegisterEntry("cpsr", 4, DetectCPSRFields),
7576
RegisterEntry("fpsr", 4, DetectFPSRFields),
7677
RegisterEntry("fpcr", 4, DetectFPCRFields),
7778
RegisterEntry("mte_ctrl", 8, DetectMTECtrlFields),
7879
RegisterEntry("svcr", 8, DetectSVCRFields),
7980
RegisterEntry("fpmr", 8, DetectFPMRFields),
81+
RegisterEntry("gcs_features_enabled", 8, DetectGCSFeatureFields),
82+
RegisterEntry("gcs_features_locked", 8, DetectGCSFeatureFields),
8083
};
8184

8285
// Becomes true once field detection has been run for all registers.

lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ def test_gcs_registers(self):
192192
self.runCmd(f"register write gcs_features_locked 0x{new_locked:x}")
193193
self.expect(
194194
f"register read gcs_features_locked",
195-
substrs=[f"gcs_features_locked = 0x{new_locked:016x}"],
195+
substrs=[
196+
f"gcs_features_locked = 0x{new_locked:016x}",
197+
f"= (PUSH = {(new_locked >> 2) & 1}, WRITE = {(new_locked >> 1) & 1}, ENABLE = {new_locked & 1})",
198+
],
196199
)
197200

198201
# We could prove the write made it to hardware by trying to prctl to change
@@ -208,7 +211,10 @@ def test_gcs_registers(self):
208211
self.runCmd(f"register write gcs_features_enabled {enabled}")
209212
self.expect(
210213
"register read gcs_features_enabled",
211-
substrs=[f"gcs_features_enabled = 0x{enabled:016x}"],
214+
substrs=[
215+
f"gcs_features_enabled = 0x{enabled:016x}",
216+
f"= (PUSH = {(enabled >> 2) & 1}, WRITE = {(enabled >> 1) & 1}, ENABLE = {enabled & 1})",
217+
],
212218
)
213219

214220
self.runCmd("continue")
@@ -383,6 +389,16 @@ def test_gcs_core_file(self):
383389
],
384390
)
385391

392+
# Should get register fields for both. They have the same fields.
393+
self.expect(
394+
"register read gcs_features_enabled",
395+
substrs=["= (PUSH = 0, WRITE = 0, ENABLE = 1)"],
396+
)
397+
self.expect(
398+
"register read gcs_features_locked",
399+
substrs=["= (PUSH = 0, WRITE = 0, ENABLE = 0)"],
400+
)
401+
386402
# Core files do not include /proc/pid/smaps, so we cannot see the
387403
# shadow stack "ss" flag. gcspr_el0 should at least point to some mapped
388404
# region.

0 commit comments

Comments
 (0)