[Lldb-commits] [lldb] [lldb][AArch64] Add Guarded Control Stack registers (PR #123720)
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Fri Jan 24 01:14:53 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.
----------------
DavidSpickett wrote:
I added bunch more explanation and moved the lock bits part so that we do that, then we cause the fault and handle it. Before they were interleaved for no particular reason.
https://github.com/llvm/llvm-project/pull/123720
More information about the lldb-commits
mailing list