xref: /freebsd/tests/sys/kern/basic_signal.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
1 /*-
2  * Copyright (c) 2021 M. Warner Losh <imp@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <atf-c.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <stdbool.h>
11 #include <stdlib.h>
12 
13 #if defined(__aarch64__)
14 #include <machine/armreg.h>
15 #define	SET_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_gpregs.gp_spsr |= PSR_SS
16 #define	CLR_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_gpregs.gp_spsr &= ~PSR_SS
17 #elif defined(__amd64__)
18 #include <machine/psl.h>
19 #define	SET_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_rflags |= PSL_T
20 #define	CLR_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_rflags &= ~PSL_T
21 #elif defined(__i386__)
22 #include <machine/psl.h>
23 #define	SET_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_eflags |= PSL_T
24 #define	CLR_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_eflags &= ~PSL_T
25 #endif
26 
27 static volatile sig_atomic_t signal_fired = 0;
28 
29 static void
30 sig_handler(int signo, siginfo_t *info __unused, void *ucp __unused)
31 {
32 	signal_fired++;
33 }
34 
35 ATF_TC(signal_test);
36 
37 ATF_TC_HEAD(signal_test, tc)
38 {
39 
40 	atf_tc_set_md_var(tc, "descr", "Testing delivery of a signal");
41 }
42 
43 ATF_TC_BODY(signal_test, tc)
44 {
45 	/*
46 	 * Setup the signal handlers
47 	 */
48 	struct sigaction sa = {
49 		.sa_sigaction = sig_handler,
50 		.sa_flags = SA_SIGINFO,
51 	};
52 	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
53 	ATF_REQUIRE(sigaction(SIGUSR1, &sa, NULL) == 0);
54 	ATF_REQUIRE(sigaction(SIGUSR2, &sa, NULL) == 0);
55 	ATF_REQUIRE(sigaction(SIGALRM, &sa, NULL) == 0);
56 
57 	/*
58 	 * Fire SIGUSR1
59 	 */
60 	ATF_CHECK(signal_fired == 0);
61 	ATF_REQUIRE(raise(SIGUSR1) == 0);
62 	ATF_CHECK(signal_fired == 1);
63 
64 	/*
65 	 * Fire SIGUSR2
66 	 */
67 	ATF_REQUIRE(raise(SIGUSR2) == 0);
68 	ATF_CHECK(signal_fired == 2);
69 
70 	/*
71 	 * Fire SIGALRM after a timeout
72 	 */
73 	ATF_REQUIRE(alarm(1) == 0);
74 	ATF_REQUIRE(pause() == -1);
75 	ATF_REQUIRE(errno == EINTR);
76 	ATF_CHECK(signal_fired == 3);
77 }
78 
79 /*
80  * Check setting the machine dependent single step flag works when supported.
81  */
82 #ifdef SET_TRACE_FLAG
83 static volatile sig_atomic_t trap_signal_fired = 0;
84 
85 static void
86 trap_sig_handler(int signo, siginfo_t *info __unused, void *_ucp)
87 {
88 	ucontext_t *ucp = _ucp;
89 
90 	if (trap_signal_fired < 9) {
91 		SET_TRACE_FLAG(ucp);
92 	} else {
93 		CLR_TRACE_FLAG(ucp);
94 	}
95 	trap_signal_fired++;
96 }
97 
98 ATF_TC(trap_signal_test);
99 
100 ATF_TC_HEAD(trap_signal_test, tc)
101 {
102 
103 	atf_tc_set_md_var(tc, "descr",
104 	    "Testing signal handler setting the MD single step flag");
105 }
106 
107 ATF_TC_BODY(trap_signal_test, tc)
108 {
109 #if defined(__i386__)
110 	if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
111 		atf_tc_skip("https://bugs.freebsd.org/265889");
112 #endif
113 	/*
114 	 * Setup the signal handlers
115 	 */
116 	struct sigaction sa = {
117 		.sa_sigaction = trap_sig_handler,
118 		.sa_flags = SA_SIGINFO,
119 	};
120 	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
121 	ATF_REQUIRE(sigaction(SIGTRAP, &sa, NULL) == 0);
122 
123 	/*
124 	 * Fire SIGTRAP
125 	 */
126 	ATF_CHECK(trap_signal_fired == 0);
127 	ATF_REQUIRE(raise(SIGTRAP) == 0);
128 	ATF_CHECK(trap_signal_fired == 10);
129 }
130 #endif
131 
132 /*
133  * Special tests for 32-bit arm. We can call thumb code (really just t32) from
134  * normal (a32) mode and vice versa. Likewise, signals can interrupt a T32
135  * context with A32 code and vice versa. Make sure these all work with a simple
136  * test that raises the signal and ensures that it executed. No other platform
137  * has these requirements. Also note: we only support thumb2, so there's no T16
138  * vs T32 issues we have to test for.
139  */
140 #ifdef __arm__
141 
142 #define a32_isa __attribute__((target("arm")))
143 #define t32_isa __attribute__((target("thumb")))
144 
145 static volatile sig_atomic_t t32_fired = 0;
146 static volatile sig_atomic_t a32_fired = 0;
147 
148 a32_isa static void
149 sig_a32(int signo, siginfo_t *info __unused, void *ucp __unused)
150 {
151 	a32_fired++;
152 }
153 
154 t32_isa static void
155 sig_t32(int signo, siginfo_t *info __unused, void *ucp __unused)
156 {
157 	t32_fired++;
158 }
159 
160 
161 ATF_TC(signal_test_T32_to_A32);
162 
163 ATF_TC_HEAD(signal_test_T32_to_A32, tc)
164 {
165 
166 	atf_tc_set_md_var(tc, "descr", "Testing delivery of a signal from T32 to A32");
167 }
168 
169 t32_isa ATF_TC_BODY(signal_test_T32_to_A32, tc)
170 {
171 	/*
172 	 * Setup the signal handlers
173 	 */
174 	struct sigaction sa = {
175 		.sa_sigaction = sig_a32,
176 		.sa_flags = SA_SIGINFO,
177 	};
178 	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
179 	ATF_REQUIRE(sigaction(SIGUSR1, &sa, NULL) == 0);
180 
181 	ATF_REQUIRE((((uintptr_t)sig_a32) & 1) == 0); /* Make sure compiled as not thumb */
182 
183 	ATF_CHECK(a32_fired == 0);
184 	ATF_REQUIRE(raise(SIGUSR1) == 0);
185 	ATF_CHECK(a32_fired == 1);
186 }
187 
188 ATF_TC(signal_test_A32_to_T32);
189 
190 ATF_TC_HEAD(signal_test_A32_to_T32, tc)
191 {
192 
193 	atf_tc_set_md_var(tc, "descr", "Testing delivery of a signal from A32 to T32");
194 }
195 
196 a32_isa ATF_TC_BODY(signal_test_A32_to_T32, tc)
197 {
198 	/*
199 	 * Setup the signal handlers
200 	 */
201 	struct sigaction sa = {
202 		.sa_sigaction = sig_t32,
203 		.sa_flags = SA_SIGINFO,
204 	};
205 	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
206 	ATF_REQUIRE(sigaction(SIGUSR1, &sa, NULL) == 0);
207 
208 	ATF_REQUIRE((((uintptr_t)sig_t32) & 1) == 1);	/* Make sure compiled as thumb */
209 
210 	ATF_CHECK(t32_fired == 0);
211 	ATF_REQUIRE(raise(SIGUSR1) == 0);
212 	ATF_CHECK(t32_fired == 1);
213 }
214 #endif
215 
216 ATF_TP_ADD_TCS(tp)
217 {
218 
219 	ATF_TP_ADD_TC(tp, signal_test);
220 #ifdef SET_TRACE_FLAG
221 	ATF_TP_ADD_TC(tp, trap_signal_test);
222 #endif
223 #ifdef __arm__
224 	ATF_TP_ADD_TC(tp, signal_test_T32_to_A32);
225 	ATF_TP_ADD_TC(tp, signal_test_A32_to_T32);
226 #endif
227 
228 	return (atf_no_error());
229 }
230