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