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

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 (without using ptrace) and we don't know what the libc
has locked
  (probably all feature bits).
This commit is contained in:
David Spickett
2025-01-28 12:05:24 +00:00
committed by GitHub
parent 83433d9361
commit c5840cc609
3 changed files with 34 additions and 2 deletions

View File

@@ -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;

View File

@@ -61,6 +61,7 @@ private:
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 @@ private:
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.

View File

@@ -223,7 +223,10 @@ class AArch64LinuxGCSTestCase(TestBase):
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 @@ class AArch64LinuxGCSTestCase(TestBase):
],
)
# 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.