Skip to content

Commit 5658bc4

Browse files
[lldb][Linux] Add Control Protection Fault signal (#122917)
This will be sent by Arm's Guarded Control Stack extension when an invalid return is executed. The signal does have an address we could show, but it's the PC at which the fault occured. The debugger has plenty of ways to show you that already, so I've left it out. ``` (lldb) c Process 460 resuming Process 460 stopped * thread #1, name = 'test', stop reason = signal SIGSEGV: control protection fault frame #0: 0x0000000000400784 test`main at main.c:57:1 54 afunc(); 55 printf("return from main\n"); 56 return 0; -> 57 } (lldb) dis <...> -> 0x400784 <+100>: ret ``` The new test case generates the signal by corrupting the link register then attempting to return. This will work whether we manually enable GCS or the C library does it for us. (in the former case you could just return from main and it would fault)
1 parent 547bfda commit 5658bc4

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

lldb/source/Plugins/Process/Utility/LinuxSignals.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#ifndef SEGV_MTESERR
2121
#define SEGV_MTESERR 9
2222
#endif
23+
#ifndef SEGV_CPERR
24+
#define SEGV_CPERR 10
25+
#endif
2326

2427
#define ADD_SIGCODE(signal_name, signal_value, code_name, code_value, ...) \
2528
static_assert(signal_name == signal_value, \
@@ -82,6 +85,7 @@ void LinuxSignals::Reset() {
8285
ADD_SIGCODE(SIGSEGV, 11, SEGV_BNDERR, 3, "failed address bounds checks", SignalCodePrintOption::Bounds);
8386
ADD_SIGCODE(SIGSEGV, 11, SEGV_MTEAERR, 8, "async tag check fault");
8487
ADD_SIGCODE(SIGSEGV, 11, SEGV_MTESERR, 9, "sync tag check fault", SignalCodePrintOption::Address);
88+
ADD_SIGCODE(SIGSEGV, 11, SEGV_CPERR, 10, "control protection fault");
8589
// Some platforms will occasionally send nonstandard spurious SI_KERNEL
8690
// codes. One way to get this is via unaligned SIMD loads. Treat it as invalid address.
8791
ADD_SIGCODE(SIGSEGV, 11, SI_KERNEL, 0x80, "invalid address", SignalCodePrintOption::Address);

lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py

+22
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,25 @@ def test_gcs_region(self):
6161

6262
# Note that we must let the debugee get killed here as it cannot exit
6363
# cleanly if GCS was manually enabled.
64+
65+
@skipUnlessArch("aarch64")
66+
@skipUnlessPlatform(["linux"])
67+
def test_gcs_fault(self):
68+
if not self.isAArch64GCS():
69+
self.skipTest("Target must support GCS.")
70+
71+
self.build()
72+
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
73+
self.runCmd("run", RUN_SUCCEEDED)
74+
75+
if self.process().GetState() == lldb.eStateExited:
76+
self.fail("Test program failed to run.")
77+
78+
self.expect(
79+
"thread list",
80+
"Expected stopped by SIGSEGV.",
81+
substrs=[
82+
"stopped",
83+
"stop reason = signal SIGSEGV: control protection fault",
84+
],
85+
)

lldb/test/API/linux/aarch64/gcs/main.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ unsigned long get_gcs_status() {
3636
return mode;
3737
}
3838

39+
void gcs_signal() {
40+
// If we enabled GCS manually, then we could just return from main to generate
41+
// a signal. However, if the C library enabled it, then we'd just exit
42+
// normally. Assume the latter, and try to return to some bogus address to
43+
// generate the signal.
44+
__asm__ __volatile__(
45+
// Corrupt the link register. This could be many numbers but 16 is a
46+
// nicely aligned value that is unlikely to result in a fault because the
47+
// PC is misaligned, which would hide the GCS fault.
48+
"add x30, x30, #10\n"
49+
"ret\n");
50+
}
51+
3952
int main() {
4053
if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS))
4154
return 1;
@@ -50,5 +63,7 @@ int main() {
5063
}
5164

5265
// By now we should have one memory region where the GCS is stored.
53-
return 0; // Set break point at this line.
66+
gcs_signal(); // Set break point at this line.
67+
68+
return 0;
5469
}

0 commit comments

Comments
 (0)