diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 3f25dbc6abbbe..eaecc84df15d4 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -20,6 +20,9 @@ #ifndef SEGV_MTESERR #define SEGV_MTESERR 9 #endif +#ifndef SEGV_CPERR +#define SEGV_CPERR 10 +#endif #define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \ static_assert(signal_name == signal_value, \ @@ -82,6 +85,7 @@ void LinuxSignals::Reset() { ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds); ADD_SIGCODE(SIGSEGV, 11, SEGV_MTEAERR, 8, "async tag check fault"); ADD_SIGCODE(SIGSEGV, 11, SEGV_MTESERR, 9, "sync tag check fault", SignalCodePrintOption::Address); + ADD_SIGCODE(SIGSEGV, 11, SEGV_CPERR, 10, "control protection fault"); // Some platforms will occasionally send nonstandard spurious SI_KERNEL // codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address. ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address); diff --git a/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py index b425c9e548ee5..0928ff8e14e00 100644 --- a/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py +++ b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py @@ -61,3 +61,25 @@ def test_gcs_region(self): # Note that we must let the debugee get killed here as it cannot exit # cleanly if GCS was manually enabled. + + @skipUnlessArch("aarch64") + @skipUnlessPlatform(["linux"]) + def test_gcs_fault(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("run", RUN_SUCCEEDED) + + if self.process().GetState() == lldb.eStateExited: + self.fail("Test program failed to run.") + + self.expect( + "thread list", + "Expected stopped by SIGSEGV.", + substrs=[ + "stopped", + "stop reason = signal SIGSEGV: control protection fault", + ], + ) diff --git a/lldb/test/API/linux/aarch64/gcs/main.c b/lldb/test/API/linux/aarch64/gcs/main.c index 9633ed2838f9e..32a9b07c20743 100644 --- a/lldb/test/API/linux/aarch64/gcs/main.c +++ b/lldb/test/API/linux/aarch64/gcs/main.c @@ -36,6 +36,19 @@ unsigned long get_gcs_status() { return mode; } +void gcs_signal() { + // If we enabled GCS manually, then we could just return from main to generate + // a signal. However, if the C library enabled it, then we'd just exit + // normally. Assume the latter, and try to return to some bogus address to + // generate the signal. + __asm__ __volatile__( + // Corrupt the link register. This could be many numbers but 16 is a + // nicely aligned value that is unlikely to result in a fault because the + // PC is misaligned, which would hide the GCS fault. + "add x30, x30, #10\n" + "ret\n"); +} + int main() { if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS)) return 1; @@ -50,5 +63,7 @@ int main() { } // By now we should have one memory region where the GCS is stored. - return 0; // Set break point at this line. + gcs_signal(); // Set break point at this line. + + return 0; }