[Lldb-commits] [lldb] [lldb][AArch64] Add Guarded Control Stack registers (PR #123720)
Omair Javaid via lldb-commits
lldb-commits at lists.llvm.org
Thu Jan 23 13:57:27 PST 2025
================
@@ -83,3 +83,137 @@ def test_gcs_fault(self):
"stop reason = signal SIGSEGV: control protection fault",
],
)
+
+ @skipUnlessArch("aarch64")
+ @skipUnlessPlatform(["linux"])
+ def test_gcs_registers(self):
+ if not self.isAArch64GCS():
+ self.skipTest("Target must support GCS.")
+
+ self.build()
+ self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+ self.runCmd("b test_func")
+ self.runCmd("b test_func2")
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ if self.process().GetState() == lldb.eStateExited:
+ self.fail("Test program failed to run.")
+
+ self.expect(
+ "thread list",
+ STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stopped", "stop reason = breakpoint"],
+ )
+
+ self.expect("register read --all", substrs=["Guarded Control Stack Registers:"])
+
+ def check_gcs_registers(
+ expected_gcs_features_enabled=None,
+ expected_gcs_features_locked=None,
+ expected_gcspr_el0=None,
+ ):
+ thread = self.dbg.GetSelectedTarget().process.GetThreadAtIndex(0)
+ registerSets = thread.GetFrameAtIndex(0).GetRegisters()
+ gcs_registers = registerSets.GetFirstValueByName(
+ r"Guarded Control Stack Registers"
+ )
+
+ gcs_features_enabled = gcs_registers.GetChildMemberWithName(
+ "gcs_features_enabled"
+ ).GetValueAsUnsigned()
+ if expected_gcs_features_enabled is not None:
+ self.assertEqual(expected_gcs_features_enabled, gcs_features_enabled)
+
+ gcs_features_locked = gcs_registers.GetChildMemberWithName(
+ "gcs_features_locked"
+ ).GetValueAsUnsigned()
+ if expected_gcs_features_locked is not None:
+ self.assertEqual(expected_gcs_features_locked, gcs_features_locked)
+
+ gcspr_el0 = gcs_registers.GetChildMemberWithName(
+ "gcspr_el0"
+ ).GetValueAsUnsigned()
+ if expected_gcspr_el0 is not None:
+ self.assertEqual(expected_gcspr_el0, gcspr_el0)
+
+ return gcs_features_enabled, gcs_features_locked, gcspr_el0
+
+ enabled, locked, spr_el0 = check_gcs_registers()
+
+ # Features enabled should have at least the enable bit set, it could have
+ # others depending on what the C library did.
+ self.assertTrue(enabled & 1, "Expected GCS enable bit to be set.")
+
+ # Features locked we cannot predict, we will just assert that it remains
+ # the same as we continue.
+
+ # spr_el0 will point to some memory region that is a shadow stack region.
+ self.expect(f"memory region {spr_el0}", substrs=["shadow stack: yes"])
+
+ # Continue into test_func2, where the GCS pointer should have been
+ # decremented, and the other registers remain the same.
+ self.runCmd("continue")
+
+ self.expect(
+ "thread list",
+ STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stopped", "stop reason = breakpoint"],
+ )
+
+ _, _, spr_el0 = check_gcs_registers(enabled, locked, spr_el0 - 8)
+
+ # Modify the control stack pointer to cause a fault.
+ spr_el0 += 8
+ self.runCmd(f"register write gcspr_el0 {spr_el0}")
+ self.expect(
+ "register read gcspr_el0", substrs=[f"gcspr_el0 = 0x{spr_el0:016x}"]
+ )
+
+ # If we wrote it back correctly, we will now fault but don't pass this
+ # signal to the application.
+ self.runCmd("process handle SIGSEGV --pass false")
+ self.runCmd("continue")
+
+ self.expect(
+ "thread list",
+ "Expected stopped by SIGSEGV.",
+ substrs=[
+ "stopped",
+ "stop reason = signal SIGSEGV: control protection fault",
+ ],
+ )
+
+ # Any combination of lock bits could be set. Flip then restore one of them.
----------------
omjavaid wrote:
The test logic below requires a bit of explanation. Took me a bit of digging into to figure out what is happening.
https://github.com/llvm/llvm-project/pull/123720
More information about the lldb-commits
mailing list