xref: /netbsd-src/tests/lib/libc/gen/t_siginfo.c (revision e885fc8ca2c6d26f6eafbe3d5a81a006c402b934)
1*e885fc8cSrin /* $NetBSD: t_siginfo.c,v 1.55 2024/09/04 03:33:29 rin Exp $ */
2de297092Spgoyette 
3de297092Spgoyette /*-
4de297092Spgoyette  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5de297092Spgoyette  * All rights reserved.
6de297092Spgoyette  *
7de297092Spgoyette  * Redistribution and use in source and binary forms, with or without
8de297092Spgoyette  * modification, are permitted provided that the following conditions
9de297092Spgoyette  * are met:
10de297092Spgoyette  * 1. Redistributions of source code must retain the above copyright
11de297092Spgoyette  *    notice, this list of conditions and the following disclaimer.
12de297092Spgoyette  * 2. Redistributions in binary form must reproduce the above copyright
13de297092Spgoyette  *    notice, this list of conditions and the following disclaimer in the
14de297092Spgoyette  *    documentation and/or other materials provided with the distribution.
15de297092Spgoyette  *
16de297092Spgoyette  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17de297092Spgoyette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18de297092Spgoyette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19de297092Spgoyette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20de297092Spgoyette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21de297092Spgoyette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22de297092Spgoyette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23de297092Spgoyette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24de297092Spgoyette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25de297092Spgoyette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26de297092Spgoyette  * POSSIBILITY OF SUCH DAMAGE.
27de297092Spgoyette  */
28de297092Spgoyette 
29de297092Spgoyette #include <atf-c.h>
30de297092Spgoyette 
31de297092Spgoyette #include <sys/resource.h>
32e1828ac1Snjoly #include <sys/sysctl.h>
33de297092Spgoyette #include <sys/time.h>
34de297092Spgoyette #include <sys/ucontext.h>
35de297092Spgoyette #include <sys/wait.h>
36de297092Spgoyette 
37de297092Spgoyette #include <assert.h>
38bcc7b2aaSmaya #include <float.h>
39bcc7b2aaSmaya #include <inttypes.h>
40bcc7b2aaSmaya #include <setjmp.h>
41de297092Spgoyette #include <signal.h>
42de297092Spgoyette #include <stdio.h>
43de297092Spgoyette #include <stdlib.h>
441680d3caSriz #include <string.h>
45de297092Spgoyette #include <unistd.h>
46de297092Spgoyette 
472aecc71dSmatt #include <fenv.h>
487303bfa7Schristos #ifdef __HAVE_FENV
49ffed0c5eSmartin #include <ieeefp.h>	/* only need for ARM Cortex/Neon hack */
502aecc71dSmatt #elif defined(_FLOAT_IEEE754)
51de297092Spgoyette #include <ieeefp.h>
52de297092Spgoyette #endif
53de297092Spgoyette 
54427032d9Schristos #include "isqemu.h"
55427032d9Schristos 
56f40ba850Skamil #ifdef ENABLE_TESTS
57c5252d32Sjym /* for sigbus */
58c06a8560Smartin volatile char *addr;
59c5252d32Sjym 
60de297092Spgoyette /* for sigchild */
61de297092Spgoyette pid_t child;
62de297092Spgoyette int code;
63de297092Spgoyette int status;
64de297092Spgoyette 
65de297092Spgoyette /* for sigfpe */
66de297092Spgoyette sig_atomic_t fltdiv_signalled = 0;
67de297092Spgoyette sig_atomic_t intdiv_signalled = 0;
68de297092Spgoyette 
69de297092Spgoyette static void
70de297092Spgoyette sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
71de297092Spgoyette {
72de297092Spgoyette 	unsigned int i;
73de297092Spgoyette 
74de297092Spgoyette 	printf("%d %p %p\n", signo, info, ctx);
75de297092Spgoyette 	if (info != NULL) {
76de297092Spgoyette 		printf("si_signo=%d\n", info->si_signo);
77de297092Spgoyette 		printf("si_errno=%d\n", info->si_errno);
78de297092Spgoyette 		printf("si_code=%d\n", info->si_code);
79de297092Spgoyette 		printf("si_value.sival_int=%d\n", info->si_value.sival_int);
80de297092Spgoyette 	}
81de297092Spgoyette 	if (ctx != NULL) {
82de297092Spgoyette 		printf("uc_flags 0x%x\n", ctx->uc_flags);
83de297092Spgoyette 		printf("uc_link %p\n", ctx->uc_link);
84de297092Spgoyette 		for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
85de297092Spgoyette 			printf("uc_sigmask[%d] 0x%x\n", i,
86de297092Spgoyette 			    ctx->uc_sigmask.__bits[i]);
87de297092Spgoyette 		printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
88de297092Spgoyette 		    (unsigned long)ctx->uc_stack.ss_size,
89de297092Spgoyette 		    ctx->uc_stack.ss_flags);
903f7804c6Spgoyette 		for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
913f7804c6Spgoyette 			printf("uc_mcontext.greg[%d] 0x%lx\n", i,
923f7804c6Spgoyette 			    (long)ctx->uc_mcontext.__gregs[i]);
93de297092Spgoyette 	}
94de297092Spgoyette }
95de297092Spgoyette 
96de297092Spgoyette static void
97de297092Spgoyette sigalrm_action(int signo, siginfo_t *info, void *ptr)
98de297092Spgoyette {
99de297092Spgoyette 
100de297092Spgoyette 	sig_debug(signo, info, (ucontext_t *)ptr);
101de297092Spgoyette 
102de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
103de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
104de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
105de297092Spgoyette 
106de297092Spgoyette 	atf_tc_pass();
107de297092Spgoyette 	/* NOTREACHED */
108de297092Spgoyette }
109de297092Spgoyette 
110de297092Spgoyette ATF_TC(sigalarm);
111de297092Spgoyette 
112de297092Spgoyette ATF_TC_HEAD(sigalarm, tc)
113de297092Spgoyette {
114de297092Spgoyette 
115de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
116de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGALRM handler");
117de297092Spgoyette }
118de297092Spgoyette 
119de297092Spgoyette ATF_TC_BODY(sigalarm, tc)
120de297092Spgoyette {
121de297092Spgoyette 	struct sigaction sa;
122de297092Spgoyette 	sa.sa_flags = SA_SIGINFO;
123de297092Spgoyette 	sa.sa_sigaction = sigalrm_action;
124de297092Spgoyette 	sigemptyset(&sa.sa_mask);
125de297092Spgoyette 	sigaction(SIGALRM, &sa, NULL);
126de297092Spgoyette 	for (;;) {
127de297092Spgoyette 		alarm(1);
128de297092Spgoyette 		sleep(1);
129de297092Spgoyette 	}
130de297092Spgoyette 	atf_tc_fail("SIGALRM handler wasn't called");
131de297092Spgoyette }
132de297092Spgoyette 
133de297092Spgoyette static void
134de297092Spgoyette sigchild_action(int signo, siginfo_t *info, void *ptr)
135de297092Spgoyette {
136de297092Spgoyette 	if (info != NULL) {
137de297092Spgoyette 		printf("info=%p\n", info);
138de297092Spgoyette 		printf("ptr=%p\n", ptr);
139de297092Spgoyette 		printf("si_signo=%d\n", info->si_signo);
140de297092Spgoyette 		printf("si_errno=%d\n", info->si_errno);
141de297092Spgoyette 		printf("si_code=%d\n", info->si_code);
142de297092Spgoyette 		printf("si_uid=%d\n", info->si_uid);
143de297092Spgoyette 		printf("si_pid=%d\n", info->si_pid);
144de297092Spgoyette 		printf("si_status=%d\n", info->si_status);
1453f7804c6Spgoyette 		printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
1463f7804c6Spgoyette 		printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
147de297092Spgoyette 	}
148de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_code, code);
149de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
150de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_uid, getuid());
151de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_pid, child);
152de297092Spgoyette 	if (WIFEXITED(info->si_status))
153de297092Spgoyette 		ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
154de297092Spgoyette 	else if (WIFSTOPPED(info->si_status))
155de297092Spgoyette 		ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
156de297092Spgoyette 	else if (WIFSIGNALED(info->si_status))
157de297092Spgoyette 		ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
158de297092Spgoyette }
159de297092Spgoyette 
160de297092Spgoyette static void
161de297092Spgoyette setchildhandler(void (*action)(int, siginfo_t *, void *))
162de297092Spgoyette {
163de297092Spgoyette 	struct sigaction sa;
164de297092Spgoyette 	sa.sa_flags = SA_SIGINFO;
165de297092Spgoyette 	sa.sa_sigaction = action;
166de297092Spgoyette 	sigemptyset(&sa.sa_mask);
167de297092Spgoyette 	sigaction(SIGCHLD, &sa, NULL);
168de297092Spgoyette }
169de297092Spgoyette 
170de297092Spgoyette static void
171de297092Spgoyette sigchild_setup(void)
172de297092Spgoyette {
173de297092Spgoyette 	sigset_t set;
174de297092Spgoyette 	struct rlimit rlim;
175de297092Spgoyette 
176de297092Spgoyette 	(void)getrlimit(RLIMIT_CORE, &rlim);
177de297092Spgoyette 	rlim.rlim_cur = rlim.rlim_max;
178de297092Spgoyette 	(void)setrlimit(RLIMIT_CORE, &rlim);
179de297092Spgoyette 
180de297092Spgoyette 	setchildhandler(sigchild_action);
181de297092Spgoyette 	sigemptyset(&set);
182de297092Spgoyette 	sigaddset(&set, SIGCHLD);
183de297092Spgoyette 	sigprocmask(SIG_BLOCK, &set, NULL);
184de297092Spgoyette }
185de297092Spgoyette 
186de297092Spgoyette ATF_TC(sigchild_normal);
187de297092Spgoyette ATF_TC_HEAD(sigchild_normal, tc)
188de297092Spgoyette {
189de297092Spgoyette 
190de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
191de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
192de297092Spgoyette 	    "when child exits normally");
193de297092Spgoyette }
194de297092Spgoyette 
195de297092Spgoyette ATF_TC_BODY(sigchild_normal, tc)
196de297092Spgoyette {
197de297092Spgoyette 	sigset_t set;
198de297092Spgoyette 
199de297092Spgoyette 	sigchild_setup();
200de297092Spgoyette 
201de297092Spgoyette 	status = 25;
202de297092Spgoyette 	code = CLD_EXITED;
203de297092Spgoyette 
204de297092Spgoyette 	switch ((child = fork())) {
205de297092Spgoyette 	case 0:
206de297092Spgoyette 		sleep(1);
207de297092Spgoyette 		exit(status);
208de297092Spgoyette 	case -1:
209de297092Spgoyette 		atf_tc_fail("fork failed");
210de297092Spgoyette 	default:
211de297092Spgoyette 		sigemptyset(&set);
212de297092Spgoyette 		sigsuspend(&set);
213de297092Spgoyette 	}
214de297092Spgoyette }
215de297092Spgoyette 
216de297092Spgoyette ATF_TC(sigchild_dump);
217de297092Spgoyette ATF_TC_HEAD(sigchild_dump, tc)
218de297092Spgoyette {
219de297092Spgoyette 
220de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
221de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
222de297092Spgoyette 	    "when child segfaults");
223de297092Spgoyette }
224de297092Spgoyette 
225de297092Spgoyette ATF_TC_BODY(sigchild_dump, tc)
226de297092Spgoyette {
227de297092Spgoyette 	sigset_t set;
228de297092Spgoyette 
229de297092Spgoyette 	sigchild_setup();
230de297092Spgoyette 
231de297092Spgoyette 	status = SIGSEGV;
232de297092Spgoyette 	code = CLD_DUMPED;
233de297092Spgoyette 
234de297092Spgoyette 	switch ((child = fork())) {
235de297092Spgoyette 	case 0:
236de297092Spgoyette 		sleep(1);
237ee3252c4Sjoerg 		*(volatile long *)0 = 0;
238de297092Spgoyette 		atf_tc_fail("Child did not segfault");
239de297092Spgoyette 		/* NOTREACHED */
240de297092Spgoyette 	case -1:
241de297092Spgoyette 		atf_tc_fail("fork failed");
242de297092Spgoyette 	default:
243de297092Spgoyette 		sigemptyset(&set);
244de297092Spgoyette 		sigsuspend(&set);
245de297092Spgoyette 	}
246de297092Spgoyette }
247de297092Spgoyette 
248de297092Spgoyette ATF_TC(sigchild_kill);
249de297092Spgoyette ATF_TC_HEAD(sigchild_kill, tc)
250de297092Spgoyette {
251de297092Spgoyette 
252de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
253de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
254de297092Spgoyette 	    "when child is killed");
255de297092Spgoyette }
256de297092Spgoyette 
257de297092Spgoyette ATF_TC_BODY(sigchild_kill, tc)
258de297092Spgoyette {
259de297092Spgoyette 	sigset_t set;
260de297092Spgoyette 
261de297092Spgoyette 	sigchild_setup();
262de297092Spgoyette 
263de297092Spgoyette 	status = SIGPIPE;
264de297092Spgoyette 	code = CLD_KILLED;
265de297092Spgoyette 
266de297092Spgoyette 	switch ((child = fork())) {
267de297092Spgoyette 	case 0:
268de297092Spgoyette 		sigemptyset(&set);
269de297092Spgoyette 		sigsuspend(&set);
270de297092Spgoyette 		break;
271de297092Spgoyette 	case -1:
272de297092Spgoyette 		atf_tc_fail("fork failed");
273de297092Spgoyette 	default:
274de297092Spgoyette 		kill(child, SIGPIPE);
275de297092Spgoyette 		sigemptyset(&set);
276de297092Spgoyette 		sigsuspend(&set);
277de297092Spgoyette 	}
278de297092Spgoyette }
279de297092Spgoyette 
2809f9ca3aaSmlelstv static sigjmp_buf sigfpe_flt_env;
281de297092Spgoyette static void
282de297092Spgoyette sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
283de297092Spgoyette {
284de297092Spgoyette 
285de297092Spgoyette 	sig_debug(signo, info, (ucontext_t *)ptr);
286de297092Spgoyette 
287de297092Spgoyette 	if (fltdiv_signalled++ != 0)
288de297092Spgoyette 		atf_tc_fail("FPE handler called more than once");
289de297092Spgoyette 
290de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
291de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
292de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_errno, 0);
2939f9ca3aaSmlelstv 
2949f9ca3aaSmlelstv 	siglongjmp(sigfpe_flt_env, 1);
295de297092Spgoyette }
296de297092Spgoyette 
297de297092Spgoyette ATF_TC(sigfpe_flt);
298de297092Spgoyette ATF_TC_HEAD(sigfpe_flt, tc)
299de297092Spgoyette {
300de297092Spgoyette 
301de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
302de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGFPE handler "
303de297092Spgoyette 	    "for floating div-by-zero");
304de297092Spgoyette }
305de297092Spgoyette 
306de297092Spgoyette ATF_TC_BODY(sigfpe_flt, tc)
307de297092Spgoyette {
308de297092Spgoyette 	struct sigaction sa;
309ddb7e404Sriastradh 	volatile double d = strtod("0", NULL);
310de297092Spgoyette 
311427032d9Schristos 	if (isQEMU())
31264d9d8eeSchristos 		atf_tc_skip("Test does not run correctly under QEMU");
313076f00a2Smartin #if (__arm__ && !__SOFTFP__) || __aarch64__
31455ba2da4Smartin 	/*
315aed5e558Skamil 	 * Some NEON fpus do not trap on IEEE 754 FP exceptions.
316dd702302Smartin 	 * skip these tests if running on them and compiled for
317dd702302Smartin 	 * hard float.
318dd702302Smartin 	 */
319dd702302Smartin 	if (0 == fpsetmask(fpsetmask(FP_X_INV)))
320b39c506bSmartin 		atf_tc_skip("FPU does not implement traps on FP exceptions");
321fc245f77Sriastradh #elif defined __riscv__
322fc245f77Sriastradh 	atf_tc_skip("RISC-V does not support floating-point exception traps");
323e110dcc9Sjmmv #endif
3249f9ca3aaSmlelstv 	if (sigsetjmp(sigfpe_flt_env, 0) == 0) {
325de297092Spgoyette 		sa.sa_flags = SA_SIGINFO;
326de297092Spgoyette 		sa.sa_sigaction = sigfpe_flt_action;
327de297092Spgoyette 		sigemptyset(&sa.sa_mask);
328de297092Spgoyette 		sigaction(SIGFPE, &sa, NULL);
3297303bfa7Schristos #ifdef __HAVE_FENV
3302aecc71dSmatt 		feenableexcept(FE_ALL_EXCEPT);
3312aecc71dSmatt #elif defined(_FLOAT_IEEE754)
332de297092Spgoyette 		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
333de297092Spgoyette #endif
334de297092Spgoyette 		printf("%g\n", 1 / d);
3359f9ca3aaSmlelstv 	}
336de297092Spgoyette 	if (fltdiv_signalled == 0)
337de297092Spgoyette 		atf_tc_fail("FPE signal handler was not invoked");
338de297092Spgoyette }
339de297092Spgoyette 
3409f9ca3aaSmlelstv static sigjmp_buf sigfpe_int_env;
341de297092Spgoyette static void
342de297092Spgoyette sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
343de297092Spgoyette {
344de297092Spgoyette 
345de297092Spgoyette 	sig_debug(signo, info, (ucontext_t *)ptr);
346de297092Spgoyette 
347de297092Spgoyette 	if (intdiv_signalled++ != 0)
348de297092Spgoyette 		atf_tc_fail("INTDIV handler called more than once");
349de297092Spgoyette 
350de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
351de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
352ddf58095Spgoyette 	atf_tc_expect_pass();
353de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_errno, 0);
3549f9ca3aaSmlelstv 
3559f9ca3aaSmlelstv 	siglongjmp(sigfpe_int_env, 1);
356de297092Spgoyette }
357de297092Spgoyette 
358de297092Spgoyette ATF_TC(sigfpe_int);
359de297092Spgoyette ATF_TC_HEAD(sigfpe_int, tc)
360de297092Spgoyette {
361de297092Spgoyette 
362de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
363de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGFPE handler "
36472ed5c06Sjruoho 	    "for integer div-by-zero (PR port-i386/43655)");
365de297092Spgoyette }
366de297092Spgoyette 
367de297092Spgoyette ATF_TC_BODY(sigfpe_int, tc)
368de297092Spgoyette {
369de297092Spgoyette 	struct sigaction sa;
370de297092Spgoyette 
371fc245f77Sriastradh #if defined(__aarch64__) || defined(__powerpc__) || defined(__sh3__) || \
372fc245f77Sriastradh     defined(__riscv__)
37351367c9bSriastradh 	atf_tc_skip("Integer division by zero doesn't trap");
374e110dcc9Sjmmv #endif
3759f9ca3aaSmlelstv 	if (sigsetjmp(sigfpe_int_env, 0) == 0) {
376de297092Spgoyette 		sa.sa_flags = SA_SIGINFO;
377de297092Spgoyette 		sa.sa_sigaction = sigfpe_int_action;
378de297092Spgoyette 		sigemptyset(&sa.sa_mask);
379de297092Spgoyette 		sigaction(SIGFPE, &sa, NULL);
3807303bfa7Schristos #ifdef __HAVE_FENV
3812aecc71dSmatt 		feenableexcept(FE_ALL_EXCEPT);
3822aecc71dSmatt #elif defined(_FLOAT_IEEE754)
383de297092Spgoyette 		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
384de297092Spgoyette #endif
3852c578257Srin 		/*
3862c578257Srin 		 * Do not use constant 1 here. GCC >= 12 optimizes
3872c578257Srin 		 * (1 / i) to (abs(i) == 1 ? i : 0), even for -O0.
3882c578257Srin 		 */
3895e6d5edbSriastradh 		volatile long unity = strtol("1", NULL, 10),
3902c578257Srin 		     zero  = strtol("0", NULL, 10);
3912c578257Srin 		printf("%ld\n", unity / zero);
3929f9ca3aaSmlelstv 	}
393de297092Spgoyette 	if (intdiv_signalled == 0)
394de297092Spgoyette 		atf_tc_fail("FPE signal handler was not invoked");
395de297092Spgoyette }
396de297092Spgoyette 
397de297092Spgoyette static void
398de297092Spgoyette sigsegv_action(int signo, siginfo_t *info, void *ptr)
399de297092Spgoyette {
400de297092Spgoyette 
401de297092Spgoyette 	sig_debug(signo, info, (ucontext_t *)ptr);
402de297092Spgoyette 
403de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
404de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_errno, 0);
405de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
406de297092Spgoyette 	ATF_REQUIRE_EQ(info->si_addr, (void *)0);
407de297092Spgoyette 
408de297092Spgoyette 	atf_tc_pass();
409de297092Spgoyette 	/* NOTREACHED */
410de297092Spgoyette }
411de297092Spgoyette 
412de297092Spgoyette ATF_TC(sigsegv);
413de297092Spgoyette ATF_TC_HEAD(sigsegv, tc)
414de297092Spgoyette {
415de297092Spgoyette 
416de297092Spgoyette 	atf_tc_set_md_var(tc, "descr",
417de297092Spgoyette 	    "Checks that signal trampoline correctly calls SIGSEGV handler");
418de297092Spgoyette }
419de297092Spgoyette 
420de297092Spgoyette ATF_TC_BODY(sigsegv, tc)
421de297092Spgoyette {
422de297092Spgoyette 	struct sigaction sa;
423de297092Spgoyette 
424de297092Spgoyette 	sa.sa_flags = SA_SIGINFO;
425de297092Spgoyette 	sa.sa_sigaction = sigsegv_action;
426de297092Spgoyette 	sigemptyset(&sa.sa_mask);
427de297092Spgoyette 	sigaction(SIGSEGV, &sa, NULL);
428de297092Spgoyette 
429ee3252c4Sjoerg 	*(volatile long *)0 = 0;
430de297092Spgoyette 	atf_tc_fail("Test did not fault as expected");
431de297092Spgoyette }
432de297092Spgoyette 
433c5252d32Sjym static void
434c5252d32Sjym sigbus_action(int signo, siginfo_t *info, void *ptr)
435c5252d32Sjym {
436c5252d32Sjym 
437c06a8560Smartin 	printf("si_addr = %p\n", info->si_addr);
438c5252d32Sjym 	sig_debug(signo, info, (ucontext_t *)ptr);
439c5252d32Sjym 
440c5252d32Sjym 	ATF_REQUIRE_EQ(info->si_signo, SIGBUS);
441c5252d32Sjym 	ATF_REQUIRE_EQ(info->si_errno, 0);
442c5252d32Sjym 	ATF_REQUIRE_EQ(info->si_code, BUS_ADRALN);
443c5252d32Sjym 
444e110dcc9Sjmmv #if defined(__i386__) || defined(__x86_64__)
445*e885fc8cSrin 	atf_tc_skip("Data address is not provided for "
446*e885fc8cSrin 	    "x86 alignment check exception, and NetBSD/x86 reports "
447*e885fc8cSrin 	    "faulting PC instead");
448e110dcc9Sjmmv #endif
449c06a8560Smartin 	ATF_REQUIRE_EQ(info->si_addr, (volatile void *)addr);
45051f1919aSmartin 
451c5252d32Sjym 	atf_tc_pass();
452c5252d32Sjym 	/* NOTREACHED */
453c5252d32Sjym }
454c5252d32Sjym 
455c5252d32Sjym ATF_TC(sigbus_adraln);
456c5252d32Sjym ATF_TC_HEAD(sigbus_adraln, tc)
457c5252d32Sjym {
458c5252d32Sjym 
459c5252d32Sjym 	atf_tc_set_md_var(tc, "descr",
460c5252d32Sjym 	    "Checks that signal trampoline correctly calls SIGBUS handler "
461c5252d32Sjym 	    "for invalid address alignment");
462c5252d32Sjym }
463c5252d32Sjym 
464c5252d32Sjym ATF_TC_BODY(sigbus_adraln, tc)
465c5252d32Sjym {
466c5252d32Sjym 	struct sigaction sa;
467c5252d32Sjym 
4687a3fd5deSmartin #if defined(__alpha__) || defined(__arm__)
469e1828ac1Snjoly 	int rv, val;
470e1828ac1Snjoly 	size_t len = sizeof(val);
471e110dcc9Sjmmv 	rv = sysctlbyname("machdep.unaligned_sigbus", &val, &len, NULL, 0);
472e1828ac1Snjoly 	ATF_REQUIRE(rv == 0);
473e1828ac1Snjoly 	if (val == 0)
4747a3fd5deSmartin 		atf_tc_skip("No SIGBUS signal for unaligned accesses");
475e110dcc9Sjmmv #endif
476e1828ac1Snjoly 
4774562851eSrin #ifdef __powerpc__
4784562851eSrin 	/*
4794562851eSrin 	 * SIGBUS is not mandatory for powerpc; most processors (not all)
4804562851eSrin 	 * can deal with unaligned accesses.
4814562851eSrin 	 */
4824562851eSrin 	atf_tc_skip("SIGBUS signal for unaligned accesses is "
4834562851eSrin 	    "not mandatory for this architecture");
4844562851eSrin #endif
4854562851eSrin 
4868f6988dbSmartin 	/* m68k (except sun2) never issue SIGBUS (PR lib/49653),
4878f6988dbSmartin 	 * same for armv8 or newer */
488dab17687Srin #if (defined(__m68k__) && !defined(__mc68010__)) || \
48975b842b8Sskrll     defined(__aarch64__) || \
49054542987Srin     defined(__riscv__) || \
49154542987Srin     defined(__vax__)
492b8d13981Sisaki 	atf_tc_skip("No SIGBUS signal for unaligned accesses");
493dab17687Srin #endif
494b8d13981Sisaki 
4958be367b3Sskrll #if defined(__mips__)
4966285957fSskrll 	/* no way of detecting if on GXemul, so disable everywhere for now */
49795cbb4a1Sskrll 	atf_tc_skip("GXemul fails to trap unaligned accesses with "
4988be367b3Sskrll 	    "correct ENTRYHI");
4998be367b3Sskrll #endif
5008be367b3Sskrll 
501c5252d32Sjym 	sa.sa_flags = SA_SIGINFO;
502c5252d32Sjym 	sa.sa_sigaction = sigbus_action;
503c5252d32Sjym 	sigemptyset(&sa.sa_mask);
504c5252d32Sjym 	sigaction(SIGBUS, &sa, NULL);
505c5252d32Sjym 
506ec88ed8bSskrll 	/* Enable alignment checks for x86. 0x40000 is PSL_AC. */
507c5252d32Sjym #if defined(__i386__)
508c5252d32Sjym 	__asm__("pushf; orl $0x40000, (%esp); popf");
509c5252d32Sjym #elif defined(__amd64__)
510c5252d32Sjym 	__asm__("pushf; orl $0x40000, (%rsp); popf");
511c5252d32Sjym #endif
512c5252d32Sjym 
513c5252d32Sjym 	addr = calloc(2, sizeof(int));
514c5252d32Sjym 	ATF_REQUIRE(addr != NULL);
515c5252d32Sjym 
51659b66922Sgson 	if (isQEMU_TCG())
517427032d9Schristos 		atf_tc_expect_fail("QEMU fails to trap unaligned accesses");
518c5252d32Sjym 
519c5252d32Sjym 	/* Force an unaligned access */
520c5252d32Sjym 	addr++;
521c06a8560Smartin 	printf("now trying to access unaligned address %p\n", addr);
522c5252d32Sjym 	ATF_REQUIRE_EQ(*(volatile int *)addr, 0);
523c5252d32Sjym 
524c5252d32Sjym 	atf_tc_fail("Test did not fault as expected");
525c5252d32Sjym }
526c5252d32Sjym 
527f40ba850Skamil #else
528f40ba850Skamil ATF_TC(dummy);
529f40ba850Skamil ATF_TC_HEAD(dummy, tc)
530f40ba850Skamil {
531f40ba850Skamil 	atf_tc_set_md_var(tc, "descr", "A dummy test");
532f40ba850Skamil }
533f40ba850Skamil 
534f40ba850Skamil ATF_TC_BODY(dummy, tc)
535f40ba850Skamil {
536f40ba850Skamil 
537f40ba850Skamil 	// Dummy, skipped
538f40ba850Skamil 	// The ATF framework requires at least a single defined test.
539f40ba850Skamil }
540f40ba850Skamil #endif
541f40ba850Skamil 
542de297092Spgoyette ATF_TP_ADD_TCS(tp)
543de297092Spgoyette {
544de297092Spgoyette 
545f40ba850Skamil #ifdef ENABLE_TESTS
546de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigalarm);
547de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigchild_normal);
548de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigchild_dump);
549de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigchild_kill);
550de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigfpe_flt);
551de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigfpe_int);
552de297092Spgoyette 	ATF_TP_ADD_TC(tp, sigsegv);
553c5252d32Sjym 	ATF_TP_ADD_TC(tp, sigbus_adraln);
554f40ba850Skamil #else
555f40ba850Skamil 	ATF_TP_ADD_TC(tp, dummy);
556f40ba850Skamil #endif
557de297092Spgoyette 
558de297092Spgoyette 	return atf_no_error();
559de297092Spgoyette }
560