[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